home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2818 < prev    next >
Encoding:
Internet Message Format  |  1991-02-21  |  58.5 KB

  1. From: barrett@Daisy.EE.UND.AC.ZA (Alan P. Barrett)
  2. Newsgroups: alt.sources
  3. Subject: apb/mje900117 patches to smail 2.5
  4. Message-ID: <1991Feb19.213232.8300@Daisy.EE.UND.AC.ZA>
  5. Date: 19 Feb 91 21:32:32 GMT
  6.  
  7. Archive-name: smail2.5/apbmje900117
  8.  
  9. apb/mje900117 patches to smail 2.5
  10. ==================================
  11.  
  12. Here are some patches for smail version 2.5.  The diffs below are
  13. relative to the original distribution of smail2.5 (patchlevel 00).  This
  14. patch will not change the patchlevel in 'patchlevel.h', because it is
  15. not an 'official' patch, but it will change the version string in
  16. defs.h.
  17.  
  18. Changes marked [apb] are mine (Alan Barrett <barrett@ee.und.ac.za>), and
  19. changes marked [mje] are originally by Mark Elkins <mje@olsa99.UUCP>.  I
  20. have made minor modifications to his code, including adding #defines in
  21. defs.h and putting the code inside #ifdef ...  #endif where appropriate.
  22.  
  23.  
  24. How to apply the patch
  25. ----------------------
  26.  
  27. (1)  If you have a version of the 'patch' program that understands
  28.      unidiff format, just pipe this file into the standard input of a
  29.      command like "patch -l -d /usr/local/src/smail".  The '-l' option
  30.      tells patch not to be too fussy about white space (because I have
  31.      been working from sources in which the white space has been munged
  32.      -- sorry).  The '-d' option tells it to apply the patch to files in
  33.      the directory whose name appears next.  Make sure you use the right
  34.      directory name.
  35.  
  36. (2)  If your patch doesn't like unidiffs, first get Wayne Davison's
  37.      unidiff package from comp.sources.unix volume 14.
  38.  
  39. (3)  If you don't have 'patch', use an editor and lots of patience to
  40.      make all the changes, or get 'patch' first.
  41.  
  42.  
  43. List of changes
  44. ---------------
  45.  
  46. There are a few bug fixes:
  47.  
  48. (1)  The binary search routines were wrong (in two separate places,
  49.      dealing with the paths file and the fullnames file).  [apb]
  50.  
  51. (2)  Addresses that contained characters that are special to the shell
  52.      were not treated properly.  Now the address is quoted in such a way
  53.      that the shell will never clobber them.  (Changed definition of
  54.      LARG and RARG in defs.h, added calls to sh_quote() in several
  55.      places.)  [apb]
  56.  
  57. (3)  There are a few more places where the address should be checked for
  58.      "postmaster".  [apb]
  59.  
  60. (4)  The stderr file should be opened in append mode, so that stdout and
  61.      stderr don't get garbled in the "standard error follows" section of
  62.      a return-to-sender error message.  [apb]
  63.  
  64. (5)  When a line in the paths file starts with a dot then the '%s' has
  65.      to be replaced by 'domain!user', not just by the 'user' name.
  66.      [apb]
  67.  
  68. There are a few enhancements:
  69.  
  70. (1)  You can define FAILPOSTMASTER (in defs.h) to make the postmaster
  71.      get a copy of all failed mail messages.  [apb]
  72.  
  73. (2)  You can define DOT_EOF and DOT_EOF_ALL (in defs.h) to modify
  74.      smail's behaviour when it sees a message that contains a line with
  75.      only a dot on it.  The original version treated it like EOF, but
  76.      now you can tell the program to (a) always treat a dot line as EOF,
  77.      (b) treat a dot line as EOF only if input is from a tty, or (c)
  78.      tell the program to never treat a dot line as EOF.  [apb]
  79.  
  80. (3)  The arpadate function now returns a string that is legal according
  81.      to a strict interpretation of RFC822.  See the comments in the code
  82.      for details.  [apb]
  83.  
  84. (4)  "postmast" is now treated exactly like "postmaster".  This is for
  85.      compatibility with sites that have 8-character user names.  [apb]
  86.  
  87. (5)  Look for a smart-host even if routing is not set to REROUTE.  This
  88.      may not have been such a good idea, but I like it and it works
  89.      better now that change number 9 below has also been made.  [apb]
  90.  
  91. (6)  If we get a local address with a '%' in it, change the '%' to an
  92.      '@' and try again.  [apb]
  93.  
  94. (7)  If a path cannot be found in the usual way, check whether the
  95.      desired domain (or host) name is a truncated version of a known
  96.      domain name.  This will find 'abc.def.ghi' in the paths file if it
  97.      is looking for 'abc.def'.  Controlled by TRUNC_DOM in defs.h.
  98.      [mje]
  99.  
  100. (8)  If that also didn't work, see whether the leftmost part of the
  101.      desired domain (or host) name matches the leftmost part of any
  102.      domain (or host) name known to the paths file.  This will find
  103.      'abc.something.else' or plain 'abc' in tha paths file if it is
  104.      looking for 'abc.def'.  Controlled by TRUNC_DOM_LEFT in defs.h.
  105.      [mje]
  106.  
  107. (9)  If that also didn't work, see if the leftmost part of the desired
  108.      domain (or host) name matches any of the uucp neighbours reported
  109.      by the uuname command.  This will find 'abc' in your L.sys or
  110.      Systems file if it is looking for 'abc.def.ghi'.  Controlled by
  111.      UUNAME in defs.h.  [mje]
  112.  
  113. (10) Remove all explicit routing through the local system during the
  114.      alias processing stage, and be much more robust about deciding when
  115.      a domain name refers to the local system.  Now, paths like
  116.      hostname!hostname.hostdomain!hostname!user will correctly resolve
  117.      to 'user' instead of being treated as erroneous.  There are still
  118.      some problems that may show up if routing = REROUTE and the local
  119.      system name appears at the end of a path via other systems.  [apb]
  120.  
  121. (11) Try harder to be sensible about quoted local parts in addresses
  122.      like <"user"@myname>, or even <"user@some.where"@myname.mydom>.
  123.      [apb]
  124.  
  125. (12) When looking in the paths file for a route to something like
  126.      'abc.def.ghi,' first try the full name without an initial dot
  127.      ('abc.def.ghi'), before trying with an initial dot
  128.      ('.abc.def.ghi').  Both might appear in the paths file, and we want
  129.      to find the right one first.  If that is not found, then continue
  130.      as before, looking for '.def.ghi', 'def.ghi', '.ghi' and 'ghi' in
  131.      that order.  [apb]
  132.  
  133. (13) New RLFROM macro in defs.h allows the "From " line in mail from a
  134.      remote user to a local user to be different from that in mail from
  135.      a remote user to a remote user.  Useful because mail sent via uucp
  136.      should have 'remote from thishost' in the From line, but you may
  137.      not want 'remote from otherhost' in the From line of mail delivered
  138.      locally.  [apb]
  139.  
  140. (14) Get real name in the From line even if the person sending the mail
  141.      is su'ed to another user id.  [mje]
  142.  
  143. (15) Make the stderr file unbuffered, to help with debugging.  Line
  144.      buffering would also be fine, on systems where it works.  [apb]
  145.  
  146. There are a few gratuitous changes:
  147.  
  148. (1) The version name (in defs.h).
  149.  
  150. (2)  The LMAIL macro in defs.h calls /usr/local/bin/deliver, which I
  151.      prefer because it doesn't chop messages off when it sees a dot
  152.      line.  "deliver" also allows one to do some fancy stuff, but I
  153.      haven't really tried that.  [apb]
  154.  
  155. (3)  MAXCLEN in defs.h is much bigger, to allow more addresses to be
  156.      passed with a single copy of a message.  Make sure my value isn't
  157.      too big for your system, and remember that smail will actually
  158.      exceed the limit you specify here, so be conservative.  [apb]
  159.  
  160. (5) The text of the return-to-sender message is altered.  [apb]
  161.  
  162. (6)  Indentation has been changed in functions that were creeping off
  163.      the right hand side of the page.  [apb]
  164.  
  165.  
  166. ----- start of diffs -----
  167.  
  168. Index: Makefile
  169. *** old/Makefile    Thu Jan 18 17:03:41 1990
  170. --- new/Makefile    Thu Jan 18 17:04:09 1990
  171. @@ -8,7 +8,8 @@
  172.  #
  173.  #LIBS    =    -lmalloc
  174.  
  175. -OBJECTS =    main.o map.o resolve.o deliver.o misc.o alias.o pw.o headers.o getpath.o str.o getopt.o
  176. +OBJECTS =    main.o map.o resolve.o deliver.o misc.o alias.o pw.o \
  177. +        headers.o getpath.o str.o getopt.o uuname.o
  178.  
  179.  all: smail svbinmail lcasep pathproc mkfnames nptx
  180.  
  181.  
  182. Index: alias.c
  183. *** old/alias.c    Thu Jan 18 17:03:42 1990
  184. --- new/alias.c    Thu Jan 18 17:04:09 1990
  185. @@ -61,6 +61,7 @@
  186.  static int nargc = 0;
  187.  static char *nargv[MAXARGS];
  188.  
  189. +char     *postmaster();
  190.  void    add_horz();
  191.  void    load_alias(), strip_comments();
  192.  int    recipients();
  193. @@ -83,10 +84,10 @@
  194.  /*
  195.  **  alias the addresses
  196.  */
  197. -    int    i;
  198. -    char    domain[SMLBUF], ubuf[SMLBUF], *user;
  199. -    node    *addr, addrstk;
  200. -    node    *flist,  fliststk, *u;
  201. +      int    i;
  202. +      char    domain[SMLBUF], ubuf[SMLBUF], *user;
  203. +      node    *addr, addrstk;
  204. +      node    *flist,  fliststk, *u;
  205.  
  206.  #ifndef SENDMAIL
  207.      FILE    *fp;
  208. @@ -111,7 +112,8 @@
  209.      ** push all of the addresses onto a stack
  210.      */
  211.      for(i=0; i < *pargc; i++) {
  212. -        push(addr, argv[i]);
  213. +        removelocal (argv[i]);
  214. +        push (addr, argv[i]);
  215.      }
  216.  
  217.      /*
  218. @@ -166,6 +168,9 @@
  219.  #endif
  220.          user = escape(ubuf);
  221.  
  222. +        /* check for postmaster */
  223. +        user = postmaster(user);
  224. +
  225.          (void) strcpy(u->string, user);    /* local => elide domain */
  226.  #ifndef SENDMAIL
  227.          /*
  228. @@ -259,20 +264,23 @@
  229.          if (index(user, '.') != NULL)
  230.  #endif
  231.          {
  232. -            static char t_dom[SMLBUF], t_unam[SMLBUF];
  233. -            char *t_user = res_fname(user);
  234. -            if (t_user != NULL) {
  235. -                if(islocal(t_user, t_dom, t_unam) == 0) {
  236. -                    /* aliased to non-local address */
  237. -                    push(addr, t_user);
  238. -                    continue;
  239. -                }
  240. -                if(strcmp(t_unam, user) != 0) {
  241. -                    /* aliased to different local address */
  242. -                    push(addr, t_unam);
  243. -                    continue;
  244. -                }
  245. +            static char t_dom[SMLBUF], t_unam[SMLBUF];
  246. +            char t_userbuf[SMLBUF];
  247. +            char *t_user = res_fname(user);
  248. +            if (t_user != NULL) {
  249. +            (void) strcpy (t_userbuf, t_user);
  250. +            NODEBUGremovelocal (t_userbuf);
  251. +            if(islocal(t_userbuf, t_dom, t_unam) == 0) {
  252. +                /* aliased to non-local address */
  253. +                push(addr, t_userbuf);
  254. +                continue;
  255.              }
  256. +            if(strcmp(t_unam, user) != 0) {
  257. +                /* aliased to different local address */
  258. +                push(addr, t_unam);
  259. +                continue;
  260. +            }
  261. +            }
  262.          }
  263.  #endif
  264.  
  265. @@ -479,7 +487,10 @@
  266.          */
  267.          if((islocal(b, d, u) == 0)
  268.          || (strcmpic(h->string, u) != 0)) {
  269. -            add_horz(h, b);
  270. +            char temp[SMLBUF];
  271. +            (void) strcpy (temp, b);
  272. +            NODEBUGremovelocal (temp);
  273. +            add_horz (h, temp);
  274.              ret = 1;
  275.          }
  276.          SKIPSPACE(p);
  277. @@ -534,6 +545,9 @@
  278.      if((p = index(str, ':')) != NULL) {
  279.          *p = CNULL;
  280.      }
  281. +    /* check for postmaster */
  282. +    str = postmaster(str);
  283. +
  284.      if((new = (node *) malloc(sizeof(node))) != NNULL) {
  285.          if((new->string = malloc((unsigned) strlen(str)+1)) == NULL) {
  286.              free(new);
  287. @@ -560,6 +574,9 @@
  288.  {
  289.      char *malloc();
  290.      node *new;
  291. +
  292. +    /* check for postmaster */
  293. +    str = postmaster(str);
  294.  
  295.      if((new = (node *) malloc(sizeof(node))) != NNULL) {
  296.          if((new->string = malloc((unsigned) strlen(str)+1)) == NULL) {
  297.  
  298. Index: defs.h
  299. *** old/defs.h    Thu Jan 18 17:03:42 1990
  300. --- new/defs.h    Thu Jan 18 17:06:31 1990
  301. @@ -17,7 +17,7 @@
  302.  */
  303.  
  304.  #ifndef VERSION
  305. -#define    VERSION    "smail2.5"
  306. +#define    VERSION    "smail2.5+apb/mje900117"
  307.  #endif
  308.  
  309.  /*#define BSD                /* if system is a Berkeley system */
  310. @@ -97,6 +98,59 @@
  311.  #define SMARTHOST  "smart-host"    /* pathalias alias for relay host */
  312.  
  313.  /*
  314. +**  Define FAILPOSTMASTER as the string "postmaster" if you want a copy of
  315. +**  return-to-sender messages to be sent to the local postmaster.  Define
  316. +**  it as an empty string "" if you don't want copies.
  317. +*/
  318. +
  319. +#define FAILPOSTMASTER "postmaster"    /* postmaster gets failure messages */
  320. +/*#define FAILPOSTMASTER ""        /* postmaster does not get messages */
  321. +
  322. +/*
  323. +**  DOT_EOF should be defined  and DOT_EOF_ALL should be undefined if you
  324. +**  want a line containing just a dot to be treated as the end of a
  325. +**  message that is read from a terminal.
  326. +**  Both DOT_EOF and DOT_EOF_ALL should be defined if you always want
  327. +**  a dot line to end the message, even when stdin is not a terminal.
  328. +**  They should both be undefined if you never want a dot line to end
  329. +**  a message (but beware, many local delivery programs will still chop
  330. +**  the message, even if smail doesn't).
  331. +*/
  332. +
  333. +#define DOT_EOF                /* do dot lines end messages */
  334. +/*#define DOT_EOF_ALL            /* even if stdin not a tty? */
  335. +
  336. +/*
  337. +** Three symbols that control some extra 'guessing' about routes.
  338. +**
  339. +**  TRUNC_DOM should be defined if you want to try searching through the
  340. +**  paths file for a route that appears to have been truncated.
  341. +**  For example, if you are looking for a route to 'abc.def'
  342. +**  and no route can be found in the normal way, but there is a
  343. +**  route to 'abc.def.xyz.com' then that route will be used.
  344. +**  (But if there is a route to 'def.xyz.com' it still won't be found.)
  345. +**  Leave the symbol undefined if you don't want this behaviour.
  346. +**
  347. +**  TRUNC_DOM_LEFT works like TRUNC_DOM, but it checks only the leftmost
  348. +**  part of the domain name.  For example, if you are looking for
  349. +**  'abc.def', TRUNC_DOM_LEFT will allow a route to 'abc' or to
  350. +**  'abc.anything.else' to be used instead.
  351. +**
  352. +**  UUNAME should be defined as the name of a program that prints
  353. +**  the names of all uucp neighbours, one per line.
  354. +**  When an address vannot be resolved with the paths file, this is used
  355. +**  to guess whether it is a uucp neighbour.  For example, if you are
  356. +**  looking for 'abc.def' but can't resolve it using the paths file, but
  357. +**  'abc' is known to your system as a uucp neighbour, then that route
  358. +**  will be used.
  359. +**  Leave UUNAME undefined if you don't want to make this test.
  360. +*/
  361. +
  362. +#define TRUNC_DOM            /* do truncated search ? */
  363. +/* #define TRUNC_DOM_LEFT            /* also for leftmost part? */
  364. +#define UUNAME "/usr/bin/uuname"    /* uuname program */
  365. +
  366. +/*
  367.  **  ALIAS and CASEALIAS are used only if SENDMAIL is NOT defined.
  368.  **  Sites using sendmail have to let sendmail do the aliasing.
  369.  **  LOWERLOGNAME maps all local login names into lower case.  This
  370. @@ -152,6 +206,10 @@
  371.  **    LMAIL is the command to invoke the local mail transfer agent.
  372.  **    LARG is how to insulate metacharacters from LMAIL. 
  373.  **    RLARG is LARG with host! on the front - to pass a uux addr to sendmail.
  374. +**    LFROM is the From_ line in mail from a local user, and also in all
  375. +**    mail passed on to sendmail.
  376. +**    RFROM is the From_ line in mail from a remote user to a remote user.
  377. +**    RLFROM is the From_ line in mail from a remote user to a local user.
  378.  **    SENDMAIL selects one of two sets of defines below for either
  379.  **    using sendmail or /bin/lmail.
  380.  */    
  381. @@ -180,9 +239,19 @@
  382.  #define RMAIL(flags,from,sys) "%s -a%s %s - %s!rmail",UUX,from,flags,sys /* */
  383.  /*#define RMAIL(flags,from,sys) "%s %s - %s!rmail",UUX,flags,sys /* */
  384.  
  385. -#define RARG(user)        " '(%s)'",user
  386. -#define RFROM(frm,now,host)     "From %s  %.24s remote from %s\n",frm,now,host
  387. +#define RARG(user)        " \\(%s\\)",user
  388. +#define RFROM(frm,now,host)     "From %s %.24s remote from %s\n",frm,now,host
  389.  
  390. +/*
  391. +** Choose one of the following definitions of RLFROM, depending on whether
  392. +** you want the 'remote from' stuff in mail that is delivered locally.
  393. +** Mail delivered via uux to another system uses RFROM (not RLFROM), and that
  394. +** probably should contain the 'remote from' stuff.
  395. +*/
  396. +
  397. +#define RLFROM(frm,now,host)     "From %s!%s %.24s\n",host,frm,now /* */
  398. +/*#define RLFROM(frm,now,host)     RFROM(frm,now,host) /* */
  399. +
  400.  #ifdef SENDMAIL
  401.  
  402.  #define HANDLE    JUSTUUCP    /* see HANDLE definition below */
  403. @@ -189,8 +258,8 @@
  404.  #define ROUTING JUSTDOMAIN    /* see ROUTING definition below */
  405.  
  406.  #define LMAIL(frm,sys)     "%s -em -f%s",SENDMAIL,frm
  407. -#define LARG(user)        " '%s'",postmaster(user)
  408. -#define RLARG(sys,frm)        " '%s!%s'",sys,frm
  409. +#define LARG(user)        " %s",postmaster(user)
  410. +#define RLARG(sys,frm)        " %s!%s",sys,frm
  411.  #define LFROM(frm,now,host)    "From %s %.24s\n",frm,now
  412.  
  413.  #else
  414. @@ -201,11 +270,12 @@
  415.  #ifdef BSD
  416.  #define LMAIL(frm,sys)        "/bin/mail"    /* BSD local delivery agent */
  417.  #else
  418. -#define LMAIL(frm,sys)        "/bin/lmail"    /* SV  local delivery agent */
  419. +/*#define LMAIL(frm,sys)    "/bin/lmail"    /* SV  local delivery agent */
  420. +#define LMAIL(frm,sys)        "/usr/local/bin/deliver" /* deliver */
  421.  #endif
  422.  
  423. -#define LARG(user)        " '%s'",postmaster(user)
  424. -#define RLARG(sys,frm)        " '%s!%s'",sys,frm
  425. +#define LARG(user)        " %s",postmaster(user)
  426. +#define RLARG(sys,frm)        " %s!%s",sys,frm
  427.  #define LFROM(frm,now,host)    "From %s %.24s\n",frm,now
  428.  
  429.  #endif
  430. @@ -254,7 +324,7 @@
  431.  ** a small value (like 0).
  432.  */
  433.  
  434. -#define MAXCLEN            128    /* longest command allowed (approx.)
  435. +#define MAXCLEN            2048    /* longest command allowed (approx.)
  436.                      /* this is to keep other's buffers
  437.                      ** from overflowing
  438.                      */
  439.  
  440. Index: deliver.c
  441. *** old/deliver.c    Thu Jan 18 17:03:42 1990
  442. --- new/deliver.c    Thu Jan 18 17:04:10 1990
  443. @@ -32,6 +32,8 @@
  444.  extern char arpanows[];        /* local time in arpadate format*/
  445.  char stderrfile[20];        /* error file for stderr traping*/
  446.  
  447. +char *sh_quote();        /* quote string to protect it from the shell */
  448. +
  449.  /*
  450.  **
  451.  **  deliver():  hand the letter to the proper mail programs.
  452. @@ -69,6 +71,7 @@
  453.      char scommand[SMLBUF];        /* retry  command issued    */
  454.      char *command;            /* actual command        */
  455.      char buf[SMLBUF];        /* copying rest of the letter   */
  456. +    char temp[SMLBUF];        /* temp storage            */
  457.      enum eform form;        /* holds form[i] for speed     */
  458.      long size;            /* number of bytes of message     */
  459.      char *flags;            /* flags for uux        */
  460. @@ -106,10 +109,11 @@
  461.          (void) unlink(stderrfile);
  462.          (void) strcpy(stderrfile, "/tmp/stderrXXXXXX");
  463.          (void) mktemp(stderrfile);
  464. -        (void) freopen(stderrfile, "w", stderr);
  465. +        (void) freopen(stderrfile, "a", stderr);
  466.          if(debug != YES) {
  467. -            (void) freopen(stderrfile, "w", stdout);
  468. +            (void) freopen(stderrfile, "a", stdout);
  469.          }
  470. +        (void) setbuf (stderr, _IONBF);
  471.  
  472.          *lend = *rend = *send = '\0';
  473.  
  474. @@ -145,8 +149,9 @@
  475.              sflag = "";
  476.          }
  477.  
  478. -        (void) sprintf(lcommand, LMAIL(from, hostv[i]));
  479. -        (void) sprintf(rcommand, RMAIL(flags, from, hostv[i]));
  480. +        (void) sprintf(lcommand, LMAIL(sh_quote(temp,from), hostv[i]));
  481. +        (void) sprintf(rcommand, RMAIL(flags,
  482. +                sh_quote(temp,from), hostv[i]));
  483.  
  484.  /*
  485.  **  For each address with the same host name and form, append the user
  486. @@ -184,14 +189,19 @@
  487.              rend += strlen(rend);
  488.  
  489.              if (form == LOCAL) {
  490. -                (void) sprintf(lend, LARG(userv[j]));
  491. -                (void) sprintf(send, LARG(userv[j]));
  492. +                (void) sprintf(lend,
  493. +                    LARG(sh_quote(temp,userv[j])));
  494. +                (void) sprintf(send,
  495. +                    LARG(sh_quote(temp,userv[j])));
  496.              } else {
  497. -                (void) sprintf(lend, RLARG(hostv[i], userv[j]));
  498. -                (void) sprintf(send, RLARG(hostv[i], userv[j]));
  499. +                char host[SMLBUF], user[SMLBUF];
  500. +                (void) sh_quote(host, hostv[i]);
  501. +                (void) sh_quote(user, userv[i]);
  502. +                (void) sprintf(lend, RLARG(host,user));
  503. +                (void) sprintf(send, RLARG(host,user));
  504.              }
  505.  
  506. -            (void) sprintf(rend, RARG(userv[j]));
  507. +            (void) sprintf(rend, RARG(sh_quote(temp,userv[j])));
  508.              formv[j] = SENT;
  509.          }
  510.  retry:
  511. @@ -269,7 +279,14 @@
  512.  **  Output our From_ line.
  513.  */
  514.          if (form == LOCAL) {
  515. +            /*
  516. +            ** Mail to a local user
  517. +            */
  518.  #ifdef SENDMAIL
  519. +            /*
  520. +            ** LFROM will probably be:
  521. +            ** From xxxxx!yyyyy!uuuuu ttttt
  522. +            */
  523.              (void) sprintf(buf, LFROM(from, nows, hostname));
  524.              size += strlen(buf);
  525.              (void) fputs(buf, out);
  526. @@ -276,13 +293,27 @@
  527.  #else
  528.              char *p;
  529.              if((p=index(from, '!')) == NULL) {
  530. +                /*
  531. +                ** Mail from a local user to a remote user.
  532. +                **
  533. +                ** LFROM will probably be:
  534. +                ** From xxxxx!yyyyy!uuuuu ttttt
  535. +                */
  536.                  (void) sprintf(buf,
  537.                      LFROM(from, nows, hostname));
  538.                  size += strlen(buf);
  539.                  (void) fputs(buf, out);
  540.              } else {
  541. -                *p = NULL;
  542. -                (void) sprintf(buf, RFROM(p+1, nows, from));
  543. +                /*
  544. +                ** Mail from a remote user to a remote user.
  545. +                **
  546. +                ** RLFROM will probably be:
  547. +                ** From yyyyy!uuuuu ttttt remote from xxxxx
  548. +                ** or:
  549. +                ** From xxxxx!yyyyy!uuuuu ttttt
  550. +                */
  551. +                *p = '\0';
  552. +                (void) sprintf(buf, RLFROM(p+1, nows, from));
  553.                  size += strlen(buf);
  554.                  (void) fputs(buf, out);
  555.                  *p = '!';
  556. @@ -289,6 +320,12 @@
  557.              }
  558.  #endif
  559.          } else {
  560. +            /*
  561. +            ** Mail to a remote user.
  562. +            **
  563. +            ** RFROM will probably be:
  564. +            ** From xxxxx!yyyyy!uuuuu ttttt remote from hhhhh
  565. +            */
  566.              (void) sprintf(buf, RFROM(from, nows, hostname));
  567.              size += strlen(buf);
  568.              (void) fputs(buf, out);
  569. @@ -418,6 +455,7 @@
  570.  {
  571.      char buf[SMLBUF];
  572.      char domain[SMLBUF], user[SMLBUF];
  573. +    char dom[SMLBUF], usr[SMLBUF];
  574.      char *r;
  575.      FILE *fp, *out, *popen();
  576.      int i = 0;
  577. @@ -428,11 +466,16 @@
  578.      r += strlen(r);
  579.  
  580.      if(islocal(from, domain, user)) {
  581. -        (void) sprintf(r, LARG(user));
  582. +        (void) sprintf(r, LARG(sh_quote(usr,user)));
  583.      } else {
  584. -        (void) sprintf(r, RLARG(domain, user));
  585. +        (void) sh_quote(dom,domain);
  586. +        (void) sh_quote(usr,user);
  587. +        (void) sprintf(r, RLARG(dom, usr));
  588.      }
  589.  
  590. +    r += strlen(r);
  591. +    (void) sprintf (r, " %s", FAILPOSTMASTER);
  592. +
  593.      i = 0;
  594.      do {
  595.          out = popen(buf, "w");
  596. @@ -451,11 +494,16 @@
  597.          return;
  598.      }
  599.  
  600. +    (void) fprintf(out, LFROM("postmaster", nows, hostname));
  601.      (void) fprintf(out, "Date: %s\n", arpanows);
  602. -    (void) fprintf(out, "From: MAILER-DAEMON@%s\n", hostdomain);
  603. -    (void) fprintf(out, "Subject: failed mail\n");
  604. +    (void) fprintf(out, "From: Smail Mail Server <Postmaster@%s>\n", hostdomain);
  605. +    (void) fprintf(out, "Subject: Failed mail\n");
  606.      (void) fprintf(out, "To: %s\n", from);
  607.      (void) fprintf(out, "\n");
  608. +    (void) fprintf(out, "\
  609. +Your message could not be delivered, because the following command returned\n\
  610. +an error status.  Perhaps one or more of the destination addresses is\n\
  611. +incorrect.\n\n");
  612.      (void) fprintf(out, "=======     command failed      =======\n\n");
  613.      (void) fprintf(out, " COMMAND: %s\n\n", fcommand);
  614.  
  615.  
  616. Index: getpath.c
  617. *** old/getpath.c    Thu Jan 18 17:03:43 1990
  618. --- new/getpath.c    Thu Jan 18 17:04:10 1990
  619. @@ -16,87 +16,104 @@
  620.  **
  621.  */
  622.  
  623. -getpath( key, path , cost)
  624. +getpath( key, path , cost, trunk)
  625.  char *key;        /* what we are looking for */
  626.  char *path;        /* where the path results go */
  627.  int *cost;        /* where the cost results go */
  628. +int trunk;        /* Do we accept a truncated name ? */
  629.  {
  630. -    long pos, middle, hi, lo;
  631. -    static long pathlength = 0;
  632. -    register char *s;
  633. -    int c;
  634. -    static FILE *file;
  635. -    int flag;
  636. +    long pos, middle, hi, lo;
  637. +    static long pathlength = 0;
  638. +    register char *s;
  639. +    int c;
  640. +    static FILE *file;
  641. +    int flag;
  642.  
  643. -DEBUG("getpath: looking for '%s'\n", key);
  644. +DEBUG("getpath: looking for '%s'%s\n", key, (trunk?" (truncated)":""));
  645.  
  646. -    if(pathlength == 0) {    /* open file on first use */
  647. -        if((file = fopen(pathfile, "r")) == NULL) {
  648. -            (void) printf("can't access %s.\n", pathfile);
  649. -            pathlength = -1;
  650. -        } else {
  651. -            (void) fseek(file, 0L, 2);    /* find length */
  652. -            pathlength = ftell(file);
  653. -        }
  654. +    if(pathlength == 0) {    /* open file on first use */
  655. +    if((file = fopen(pathfile, "r")) == NULL) {
  656. +        (void) printf("can't access %s.\n", pathfile);
  657. +        pathlength = -1;
  658. +    } else {
  659. +        (void) fseek(file, 0L, 2);    /* find length */
  660. +        pathlength = ftell(file);
  661.      }
  662. -    if( pathlength == -1 )
  663. -        return( EX_OSFILE );
  664. +    }
  665. +    if( pathlength == -1 )
  666. +    return( EX_OSFILE );
  667.  
  668. -    lo = 0;
  669. -    hi = pathlength;
  670. -    (void) strcpy( path, key );
  671. -    (void) strcat( path, "\t" );
  672. -/*
  673. -** "Binary search routines are never written right the first time around."
  674. -** - Robert G. Sheldon.
  675. -*/
  676. -    for( ;; ) {
  677. -        pos = middle = ( hi+lo+1 )/2;
  678. -        (void) fseek(file, pos, 0);    /* find midpoint */
  679. -        if(pos != 0)
  680. -            while(((c = getc(file)) != EOF) && (c != '\n'))
  681. -                ;    /* go to beginning of next line */
  682. -        if(c == EOF) {
  683. -            return(EX_NOHOST);
  684. +    lo = 0;
  685. +    hi = pathlength;
  686. +    (void) strcpy( path, key );
  687. +    (void) strcat( path, "\t" );
  688. +    /*
  689. +    ** "Binary search routines are never written right the first time around."
  690. +    ** - Robert G. Sheldon.
  691. +    */
  692. +    for( ; lo <= hi ; ) {
  693. +    pos = middle = ( hi+lo+1 )/2;
  694. +    (void) fseek(file, pos, 0);    /* find midpoint */
  695. +    if(pos != 0)
  696. +        while(((c = getc(file)) != EOF) && (c != '\n'))
  697. +            ;    /* go to beginning of next line */
  698. +    if(c == EOF) {
  699. +        flag = 1;
  700. +    }
  701. +    else {
  702. +        for( flag = 0, s = path; flag == 0; s++ ) { /* match??? */
  703. +        if( *s == '\0' ) {
  704. +            goto solved;
  705.          }
  706. -        for( flag = 0, s = path; flag == 0; s++ ) { /* match??? */
  707. -            if( *s == '\0' ) {
  708. -                goto solved;
  709. -            }
  710. -            if((c = getc(file)) == EOF) {
  711. -                return(EX_NOHOST);
  712. -            }
  713. -            flag = lower(c) - lower(*s);
  714. -        } 
  715. -        if(lo >= middle) {        /* failure? */
  716. -            return(EX_NOHOST);
  717. +        if((c = getc(file)) == EOF) {
  718. +            flag = 1;
  719.          }
  720. -        if((c != EOF) && (flag < 0)) {    /* close window */
  721. -            lo = middle;
  722. -        } else {
  723. -            hi = middle - 1;
  724. -        }
  725. +        else {
  726. +            flag = lower(c) - lower(*s);
  727. +            /*
  728. +            ** if trunk is set, and the end of the desired key
  729. +            ** coincides with a dot in the current key,
  730. +            ** then treat this as a match.
  731. +            ** For example, desired="abc.xyz.com" and
  732. +            ** actual="abc.xyz".
  733. +            */
  734. +            if (trunk && *s =='\t' && c == '.') {
  735. +            while(((c = getc(file)) != EOF) && c!='\t');
  736. +            goto solved;
  737. +            }
  738. +        } 
  739. +        } /* end for */
  740.      }
  741. -/* 
  742. -** Now just copy the result.
  743. -*/
  744. -solved:
  745. -    while(((c  = getc(file)) != EOF) && (c != '\t') && (c != '\n')) {
  746. -        *path++ = c;
  747. +    if(flag < 0) {    /* close window */
  748. +        lo = middle + 1;
  749. +    } else {
  750. +        hi = middle - 1;
  751.      }
  752. -    *path = '\0';
  753. -/*
  754. -** See if the next field on the line is numeric.
  755. -** If so, use it as the cost for the route.
  756. -*/
  757. -    if(c == '\t') {
  758. -        int tcost = -1;
  759. -        while(((c = getc(file)) != EOF) && isdigit(c)) {
  760. -            if(tcost < 0) tcost = 0;
  761. -            tcost *= 10;
  762. -            tcost += c - '0';
  763. -        }
  764. -        if(tcost >= 0) *cost = tcost;
  765. +    }
  766. +    /*
  767. +    ** If we get here, the key was not found.
  768. +    */
  769. +    return(EX_NOHOST);
  770. +    /* 
  771. +    ** It was found.  Now just copy the result.
  772. +    */
  773. +    solved:
  774. +    while(((c  = getc(file)) != EOF) && (c != '\t') && (c != '\n')) {
  775. +    *path++ = c;
  776. +    }
  777. +    *path = '\0';
  778. +    /*
  779. +    ** See if the next field on the line is numeric.
  780. +    ** If so, use it as the cost for the route.
  781. +    */
  782. +    if(c == '\t') {
  783. +    int tcost = -1;
  784. +    while(((c = getc(file)) != EOF) && isdigit(c)) {
  785. +        if(tcost < 0) tcost = 0;
  786. +        tcost *= 10;
  787. +        tcost += c - '0';
  788.      }
  789. -    return (EX_OK);
  790. +    if(tcost >= 0) *cost = tcost;
  791. +    }
  792. +    return (EX_OK);
  793.  }
  794.  
  795. Index: headers.c
  796. *** old/headers.c    Thu Jan 18 17:03:43 1990
  797. --- new/headers.c    Thu Jan 18 17:04:11 1990
  798. @@ -45,7 +45,86 @@
  799.      NULL         ,    NULL        ,    'N'
  800.  };
  801.  
  802. +/*
  803. +**
  804. +** removelocal(): delete local domain name from an address.
  805. +**
  806. +** The following rules are applied repeatedly until they all fail.
  807. +**
  808. +** @myname:address        ==>    address
  809. +** @myname,@elsewhere:address    ==>    @elsewhere:address
  810. +** address@myname        ==>    address
  811. +** myname!address        ==>    address
  812. +** "address"            ==>    address
  813. +** address%domain        ==>    address@domain
  814. +**
  815. +**  This function modifies the input address in-place.
  816. +**
  817. +*/
  818.  
  819. +void
  820. +removelocal (address)
  821. +char *address;
  822. +{
  823. +/**
  824. +    repeat forever  {{ actually, until a 'terminate' statement }}
  825. +    parse the address to {is-local, localpart, domain}.
  826. +        {{ use the 'islocal' function to do this }}
  827. +    if is-local then
  828. +        {{ there were no '@' or '!' chars in the address, or
  829. +        there were such chars but the system name was
  830. +        recognised as the local system }}
  831. +        select
  832. +          localpart is quoted :
  833. +            address := removequotes( localpart )
  834. +          localpart is not quoted and contains "@" or "!" :
  835. +            address := localpart
  836. +          localpart is not quoted, does not contain "@" or "!",
  837. +                        but contains "%" :
  838. +            address := convert-%-to-@ ( localpart )
  839. +          localpart is not quoted and does not contain "@", "!" or "%" :
  840. +            address := localpart
  841. +            return
  842. +        endselect
  843. +    else
  844. +        return
  845. +    endif
  846. +    endrepeat
  847. +**/
  848. +    char localpart[SMLBUF], domain[SMLBUF], temp[SMLBUF], *p;
  849. +    extern int rfc822_do_unquote();
  850. +
  851. +    for (;;) {
  852. +    
  853. +    DEBUG("removelocal: checking '%s'\n", address);
  854. +
  855. +    if (islocal (address, domain, localpart)) {
  856. +        /* check if localpart is quoted */
  857. +        if ( rfc822_do_unquote (temp, localpart) ) {
  858. +        (void) strcpy (address, temp);
  859. +        }
  860. +        /* check if localpart contains '@' or '!' */
  861. +        else if (strpbrk(localpart,"@!")) {
  862. +        (void) strcpy (address, localpart);
  863. +        }
  864. +        /* check if localpart contains "%" */
  865. +        else if (p = rindex(localpart,'%')) {
  866. +        *p = '@';
  867. +        (void) strcpy (address, localpart);
  868. +        }
  869. +        /* else localpart is a truly local address */
  870. +        else {
  871. +        (void) strcpy (address, localpart);
  872. +        break; /* out of the loop */
  873. +        }
  874. +    } else {
  875. +        break; /* out of the loop */
  876. +    }
  877. +    }
  878. +  DEBUG("removelocal: result is '%s'\n", address);
  879. +  return;
  880. +}
  881. +
  882.  /*
  883.  **
  884.  ** parse(): parse <address> into <domain, user, form>.
  885. @@ -221,7 +300,14 @@
  886.  {
  887.          enum eform form, parse();
  888.          extern char hostuucp[];
  889. +        char path[SMLBUF];
  890. +        int cost;
  891. +#ifdef TRUNC_DOM_LEFT
  892. +        char leftpart[SMLBUF], *p;
  893. +#endif
  894.  
  895. +        /* DEBUG("islocal: checking '%s'\n", addr); /* */
  896. +
  897.          /*
  898.          ** parse the address
  899.          */
  900. @@ -235,9 +321,31 @@
  901.          ||(strcmpic(domain, &MYDOM[0]) == 0)    /* user@MYDOM w/ dot */
  902.          ||(strcmpic(domain, &MYDOM[1]) == 0)    /* user@MYDOM no dot */
  903.  #endif
  904. -        ||(strcmpic(domain, hostuucp)   == 0)) {/* user@hostuucp */
  905. +        ||(strcmpic(domain, hostuucp) == 0)){    /* user@hostuucp */
  906.              return(1);
  907.          }
  908. +
  909. +        /*
  910. +        ** Check the paths file.
  911. +        */
  912. +        if (NODEBUGgetpath (domain, path, &cost, 0) == EX_OK)
  913. +            return (strcmp (path, "%s") == 0);
  914. +
  915. +#ifdef TRUNC_DOM
  916. +        if (NODEBUGgetpath (domain, path, &cost, 1) == EX_OK)
  917. +            return (strcmp (path, "%s") == 0);
  918. +#endif /* TRUNC_DOM */
  919. +
  920. +#ifdef TRUNC_DOM_LEFT
  921. +        (void) strcpy (leftpart, domain);
  922. +        if (p=index(leftpart,'.')) *p = '\0';
  923. +        if (NODEBUGgetpath (leftpart, path, &cost, 1) == EX_OK)
  924. +            return (strcmp (path, "%s") == 0);
  925. +#endif /* TRUNC_DOM_LEFT */
  926. +
  927. +        /*
  928. +        ** Still not found.  It can't be local.
  929. +        */
  930.          return(0);
  931.  }
  932.  
  933. @@ -268,6 +376,11 @@
  934.      static char splbuf[SMLBUF];
  935.      char from[SMLBUF], domain[SMLBUF], user[SMLBUF];
  936.      void rline(), scanheaders(), compheaders();
  937. +#ifdef DOT_EOF
  938. +#ifndef DOT_EOF_ALL
  939. +    int is_tty = isatty(0); /* is stdin a tty ? */
  940. +#endif
  941. +#endif
  942.  
  943.      /*
  944.      ** if the mail has already been spooled by
  945. @@ -337,13 +450,26 @@
  946.  
  947.          /*
  948.          ** now, copy the rest of the letter into the spool file
  949. -        ** terminate on either EOF or '^.$'
  950. +        ** terminate on EOF.
  951. +        ** We might also terminate on a line that just
  952. +        ** contains a dot, depending on compile time options
  953. +        ** and whether the stdin is a terminal.
  954.          */
  955.  
  956.          while(ieof != NULL) {
  957.              (void) fputs(buf, spoolfp);
  958. -            if((fgets(buf, SMLBUF, stdin) == NULL)
  959. -            || (buf[0] == '.' && buf[1] == '\n')) {
  960. +#ifndef DOT_EOF
  961. +            if( fgets(buf, SMLBUF, stdin) == NULL )
  962. +#else
  963. +#if DOT_EOF_ALL
  964. +            if( (fgets(buf, SMLBUF, stdin) == NULL)
  965. +            || (buf[0] == '.' && buf[1] == '\n') )
  966. +#else
  967. +            if( (fgets(buf, SMLBUF, stdin) == NULL)
  968. +            || (is_tty && buf[0] == '.' && buf[1] == '\n') )
  969. +#endif
  970. +#endif
  971. +            {
  972.                  ieof = NULL;
  973.              }
  974.          }
  975. @@ -461,7 +587,16 @@
  976.  
  977.      if (from[0] == '\0') {
  978.          char *login;
  979. -        if ((login = pwuid(getuid())) == NULL) {
  980. +        char *tmpname;
  981. +        /*
  982. +        ** Get login name with cuserid(), then convert to uid with
  983. +        ** pwuserid().  If cuserid() fails, use getuid().
  984. +        ** When we know the uid, let pwuid() convert it to a name.
  985. +        ** (This seems very complicated.)
  986. +        */
  987. +        if ((login = pwuid(
  988. +              (tmpname=cuserid(NULL)) ? pwuserid(tmpname) : getuid()
  989. +            )) == NULL) {
  990.              (void) strcpy(from, "nobody");    /* bad news */
  991.          } else {
  992.              (void) strcpy(from, login);
  993. @@ -706,7 +841,7 @@
  994.  
  995.      char *nameptr;
  996.      char name[SMLBUF];
  997. -    char *getenv(), *login;
  998. +    char *getenv(), *login, *tmpname;
  999.      char *pwfnam(), *pwuid();
  1000.  
  1001.      if (from_addr != NULL) {
  1002. @@ -717,7 +852,9 @@
  1003.      name[0] = '\0';
  1004.      if((nameptr = getenv("NAME")) != NULL) {
  1005.          (void) strcpy(name, nameptr);
  1006. -    } else if((login = pwuid(getuid())) != NULL) {
  1007. +    } else if((login = pwuid(
  1008. +            (tmpname=cuserid(NULL)) ? pwuserid(tmpname) : getuid()
  1009. +        )) != NULL) {
  1010.          if((nameptr = pwfnam(login)) != NULL) {
  1011.              (void) strcpy(name, nameptr);
  1012.          }
  1013. @@ -755,14 +892,7 @@
  1014.              (void) strcat(bol, hostdomain);
  1015.          }
  1016.          if(i+1 < argc) {
  1017. -#if 0
  1018. -   /*** The following line was there, but ii is definitely wrong.
  1019. -    I think it should be changed to what appears after the #else.
  1020. -    [A P Barrett, 890503] ***/
  1021. -            \main);(bol);
  1022. -#else
  1023.              n = strlen(bol);
  1024. -#endif
  1025.              if(n > 50) {
  1026.                  (void) strcat(bol, ",\n\t");
  1027.                  bol = bol + strlen(bol);
  1028. @@ -774,3 +904,35 @@
  1029.          }
  1030.      }
  1031.  }
  1032. +
  1033. +/*
  1034. +** call getpath with the DEBUG flag turned off
  1035. +*/
  1036. +
  1037. +int NODEBUGgetpath (key, path , cost, trunk)
  1038. +char *key;        /* what we are looking for */
  1039. +char *path;        /* where the path results go */
  1040. +int *cost;        /* where the cost results go */
  1041. +int trunk;        /* Do we accept a truncated name ? */
  1042. +{
  1043. +    enum edebug tdebug = debug;
  1044. +    int retcode;
  1045. +    debug = NO;
  1046. +    retcode = getpath (key, path, cost, trunk);
  1047. +    debug = tdebug;
  1048. +    return retcode;
  1049. +}
  1050. +
  1051. +/*
  1052. +** call removelocal with the DEBUG flag turned off
  1053. +*/
  1054. +
  1055. +void NODEBUGremovelocal (address)
  1056. +char *address;
  1057. +{
  1058. +    enum edebug tdebug = debug;
  1059. +    debug = NO;
  1060. +    removelocal (address);
  1061. +    debug = tdebug;
  1062. +}
  1063. +
  1064.  
  1065. Index: misc.c
  1066. *** old/misc.c    Thu Jan 18 17:03:44 1990
  1067. --- new/misc.c    Thu Jan 18 17:04:12 1990
  1068. @@ -136,6 +136,17 @@
  1069.  **        Some sites are now inserting the timezone into the
  1070.  **        local date.  This routine should figure out what
  1071.  **        the format is and work appropriately.
  1072. +**
  1073. +**    Modified by A P Barrett, July 1989:
  1074. +**        1    RFC822 format should have weekday at the beginning, with
  1075. +**        a comma between it and the rest of the time, instead of
  1076. +**        in parentheses at the end.
  1077. +**        2    If the timezone is not one of the few valid RFC822 timezones,
  1078. +**        then use the difference between local and GMT to create a
  1079. +**        timezone in US Military single-character format (if
  1080. +**        #define TZ_MIL is used), or in ANSI X3.51-1975 format (+hhmm)
  1081. +**        (if TZ_MIL is not #define'd).  In both cases, put the Unix
  1082. +**        timezone in as a comment.
  1083.  */
  1084.  
  1085.  char *
  1086. @@ -150,6 +161,7 @@
  1087.  #ifndef BSD
  1088.      extern char *tzname[];
  1089.      time_t t, time();
  1090. +    extern long timezone;
  1091.  #else
  1092.      /* V7 and 4BSD */
  1093.      struct timeb t;
  1094. @@ -176,10 +188,22 @@
  1095.  
  1096.      /*
  1097.      **  Crack the UNIX date line in a singularly unoriginal way.
  1098. +    **
  1099. +    **    Unix:    Mon Sep 16 01:03:52 1979
  1100. +    **    RFC822:    Mon, 16 Sep 79 01:03:52 PST
  1101. +    **        or:    Mon, 16 Sep 79 01:03:52 H (PST)
  1102. +    **        or:    Mon, 16 Sep 79 01:03:52 -0800 (PST)
  1103.      */
  1104.  
  1105.      q = b;
  1106.  
  1107. +    p = &ud[0];        /* Mon */
  1108. +    *q++ = *p++;
  1109. +    *q++ = *p++;
  1110. +    *q++ = *p++;
  1111. +    *q++ = ',';
  1112. +    *q++ = ' ';
  1113. +
  1114.      p = &ud[8];        /* 16 */
  1115.      if (*p == ' ')
  1116.          p++;
  1117. @@ -209,36 +233,57 @@
  1118.  #else
  1119.      p = timezone(t.timezone, localtime(&t.time)->tm_isdst);
  1120.  #endif
  1121. -    if (p[3] != '\0')
  1122. +    /* Only a few timezone names are legal in RFC822 */
  1123. +    if (strcmp(p,"UT")==0 ||
  1124. +        strcmp(p,"GMT")==0 ||
  1125. +        strcmp(p,"EST")==0 ||
  1126. +        strcmp(p,"EDT")==0 ||
  1127. +        strcmp(p,"CST")==0 ||
  1128. +        strcmp(p,"CDT")==0 ||
  1129. +        strcmp(p,"MST")==0 ||
  1130. +        strcmp(p,"MDT")==0 ||
  1131. +        strcmp(p,"PST")==0 ||
  1132. +        strcmp(p,"PDT")==0 ||
  1133. +        (isalpha(*p) && *(p+1)=='\0'))
  1134.      {
  1135. -        /* hours from GMT */
  1136. -        p += 3;
  1137. -        *q++ = *p++;
  1138. -        if (p[1] == ':')
  1139. -            *q++ = '0';
  1140. -        else
  1141. -            *q++ = *p++;
  1142. -        *q++ = *p++;
  1143. -        p++;        /* skip ``:'' */
  1144. -        *q++ = *p++;
  1145. -        *q++ = *p++;
  1146. +        *q++ = ' ';
  1147. +        do { } while ( *q++ = *p++ ); q--;
  1148.      }
  1149.      else
  1150.      {
  1151. +#ifdef TZ_MIL
  1152. +        /* Make a US Military style timezone.
  1153. +         * Z=GMT, A=GMT-1, N=GMT+1, etc. (J is unused) */
  1154. +        static char mil_tz[] = "YXWVUTSRQPONZABCDEFGHIKLM";
  1155. +#ifndef BSD
  1156. +        int hr = (timezone+1800)/3600; /* round to nearest hour */
  1157. +#else
  1158. +        int hr = (t.timezone+1800)/3600; /* round to nearest hour */
  1159. +#endif
  1160.          *q++ = ' ';
  1161. -        *q++ = *p++;
  1162. -        *q++ = *p++;
  1163. -        *q++ = *p++;
  1164. +        *q++ = mil_tz[hr+12];
  1165. +#else (not TZ_MIL)
  1166. +        /* Make an ANSI X3.51-1975 timezone. +hhmm */
  1167. +#ifndef BSD
  1168. +        int hr = abs(timezone)/3600;
  1169. +        int mi = (abs(timezone)/60)%60;
  1170. +#else
  1171. +        int hr = abs(t.timezone)/3600;
  1172. +        int mi = (abs(t.timezone)/60)%60;
  1173. +#endif
  1174. +        *q++ = ' ';
  1175. +        *q++ = (timezone<0 ? '+' : '-'); /* yes, really */
  1176. +        sprintf (q,"%02.2d%02.2d",hr,mi);
  1177. +        q += 4;
  1178. +#endif
  1179. +
  1180. +        /* Add the Unix timezone as a comment */
  1181. +        *q++ = ' ';
  1182. +        *q++ = '(';
  1183. +        do { } while ( *q++ = *p++ ); q--;
  1184. +        *q++ = ')';
  1185.      }
  1186.  
  1187. -    p = &ud[0];        /* Mon */
  1188. -    *q++ = ' ';
  1189. -    *q++ = '(';
  1190. -    *q++ = *p++;
  1191. -    *q++ = *p++;
  1192. -    *q++ = *p++;
  1193. -    *q++ = ')';
  1194. -
  1195.      *q = '\0';
  1196.      return (b);
  1197.  }
  1198. @@ -249,6 +294,9 @@
  1199.   *    used to convert all case variants of "postmaster" to all lower
  1200.   *    case.  If the user name passed in is not "postmaster", it is
  1201.   *    returned unchanged.
  1202. + *
  1203. + *    Modified by A P Barrett, July 1989:
  1204. + *        Treat "postmast" just like "postmaster"
  1205.   */
  1206.  char *
  1207.  postmaster(user)
  1208. @@ -255,8 +303,9 @@
  1209.  char *user;
  1210.  {
  1211.      static char *pm = "postmaster";
  1212. +    static char *pm2 = "postmast";
  1213.  
  1214. -    if(strcmpic(user, pm) == 0) {
  1215. +    if (strcmpic(user, pm) == 0 || strcmpic(user, pm2) == 0) {
  1216.          return(pm);
  1217.      } else {
  1218.          return(user);
  1219. @@ -340,3 +389,231 @@
  1220.  
  1221.      (void) strcat(strcpy(hostuucp, hostname), ".UUCP");
  1222.  }
  1223. +
  1224. +/* rfc822_quote --
  1225. + * quotes a character string according to the RFC-822 standard.
  1226. + * Returns a pointer to the result string.
  1227. + *
  1228. + *     fred            ==>    "fred"
  1229. + *    funny'name"thing    ==>    "funny'name\"thing"
  1230. + *    "already quoted"    ==>    "\"already quoted\""
  1231. + */
  1232. +
  1233. +char *rfc822_quote (result, string)
  1234. +char *result, *string;
  1235. +  {
  1236. +    char *p = string;
  1237. +    char *q = result;
  1238. +
  1239. +    /* start with the opening quote mark {"} */
  1240. +
  1241. +    *q++ = '"';
  1242. +
  1243. +    /* process the string */
  1244. +
  1245. +    for ( ; *p != '\0' ; p++ ) {
  1246. +    if (*p=='"' || *p=='\\') {
  1247. +        /* convert embedded {"} or {\} to {\"} or {\\} */
  1248. +        *q++ = '\\';
  1249. +        *q++ = *p;
  1250. +      }
  1251. +    else {
  1252. +      *q++ = *p;
  1253. +    }
  1254. +    }
  1255. +
  1256. +    /* add last {"} */
  1257. +
  1258. +    *q++ = '"';
  1259. +
  1260. +    /* terminate with a nul */
  1261. +
  1262. +    *q = '\0';
  1263. +
  1264. +    return (result);
  1265. +  }
  1266. +
  1267. +/* rfc822_isquoted --
  1268. + * determines whether a string is quoted according to the RFC-822 standard.
  1269. + * Returns 1 for TRUE (yes, the string was quoted) or 0 for FALSE.
  1270. + *
  1271. + *    fred            ==>    FALSE
  1272. + *     "fred"            ==>    TRUE
  1273. + *    "funny'name\"thing"    ==>    TRUE
  1274. + *    "partially"quoted    ==>    FALSE
  1275. + *    unmatched"quote        ==>    FALSE
  1276. + *    "\"doubly quoted\""    ==>    TRUE
  1277. + */
  1278. +
  1279. +int rfc822_isquoted (string)
  1280. +char *string;
  1281. +  {
  1282. +    return rfc822_do_unquote (NULL, string);
  1283. +  }
  1284. +
  1285. +/* rfc822_unquote --
  1286. + * unquotes a character string according to the RFC-822 standard.
  1287. + * Returns a pointer to the result string.
  1288. + * The result is identical to the input if the input string was not
  1289. + * properly quoted.
  1290. + *
  1291. + *    fred            ==>    fred
  1292. + *     "fred"            ==>    fred
  1293. + *    "funny'name\"thing"    ==>    funny'name"thing
  1294. + *    "partially"quoted    ==>    "partially"quoted
  1295. + *    unmatched"quote        ==>    unmatched"quote
  1296. + *    "\"doubly quoted\""    ==>    "doubly quoted"
  1297. + */
  1298. +
  1299. +char *rfc822_unquote (result, string)
  1300. +char *result, *string;
  1301. +  {
  1302. +    (void) rfc822_do_unquote (result, string);
  1303. +    return result;
  1304. +  }
  1305. +
  1306. +/* rfc822_do_unquote --
  1307. + * does the work for both rfc822_isquoted and rfc822_unquote.
  1308. + * The work is the same in both cases; those functions are simply
  1309. + * wrappers that give a different calling interface to this routine.
  1310. + *
  1311. + * Unquotes the string and stores the result in 'result', unless
  1312. + * result is NULL.  Returns a flag saying whether or not tha
  1313. + * input string was quoted.
  1314. + */
  1315. +
  1316. +int rfc822_do_unquote (result, string)
  1317. +char *result, *string;
  1318. +  {
  1319. +    char *p = string;
  1320. +    char *q = result;
  1321. +    char ch;
  1322. +    int wasquoted;
  1323. +    typedef enum { start_s, /* at the start of the string */
  1324. +          inquotes_s, /* inside a quoted string */
  1325. +          backslash_s, /* seen a backslash inside the quoted string */
  1326. +          closequote_s, /* seen a quote mark that might be the close of
  1327. +                       * the quoted string */
  1328. +          endquoted_s, /* seen the end of the quoted string */
  1329. +          notquoted_s, /* decided that the string was not quoted */
  1330. +          end_s /* finished everything */ }
  1331. +        state_t;
  1332. +    state_t state;
  1333. +    int needch;
  1334. +
  1335. +    /* This finite state automaton goes through the input string and creates
  1336. +     * the output string if the input was properly quoted.  If the input
  1337. +     * was not properly quoted, it may give up processing the input before
  1338. +     * the end of string is reached, and the output will be undefined.
  1339. +     * The variable "wasquoted" is set to 1 if the input string was correctly
  1340. +     * quoted (in which case the output string will contain the correctly
  1341. +     * un-quoted version of the input); this variable is set to 0 if the
  1342. +     * input was not correctly quoted. */
  1343. +
  1344. +    for ( state = start_s, needch = 1 ; state != end_s ; ) {
  1345. +    if (needch) {
  1346. +        ch = *p++;
  1347. +        needch = 0;
  1348. +      }
  1349. +    switch (state) {
  1350. +      case start_s:
  1351. +        /* if the first character is a quote mark then it might be a
  1352. +         * properly quoted string, otherwise it cannot be a properly
  1353. +         * quoted string */
  1354. +        state = ( ch == '"' ? inquotes_s : notquoted_s );
  1355. +        needch = 1;
  1356. +        break;
  1357. +      case inquotes_s:
  1358. +        /* backslash and quote marks are special, but just copy other
  1359. +         * chars to the output */
  1360. +        switch (ch) {
  1361. +          case '\\': state = backslash_s; break;
  1362. +          case '"': state = closequote_s; break;
  1363. +          default: if(q){ *q++ = ch;}
  1364. +          }
  1365. +        needch = 1;
  1366. +        break;
  1367. +      case backslash_s:
  1368. +        /* if end of string occurs just after a backslash then string
  1369. +         * was not properly quoted.  Otherwise output the char that
  1370. +         * follows the backslash. */
  1371. +        if (ch == '\0') { state = notquoted_s; }
  1372. +        else { if(q){ *q++ = ch;} state = inquotes_s; needch = 1; }
  1373. +        break;
  1374. +      case closequote_s:
  1375. +        /* if end of string occurs just after a quote mark then
  1376. +         * string was properly quoted, otherwise it was not */
  1377. +        if (ch == '\0') { if(q){*q++ = '\0';} state = endquoted_s; }
  1378. +        else { state = notquoted_s; }
  1379. +        break;
  1380. +      case endquoted_s:
  1381. +        /* String was quoted and we have finished processing it */
  1382. +        wasquoted = 1;
  1383. +        state = end_s;
  1384. +        break;
  1385. +      case notquoted_s:
  1386. +        /* String was not quoted and we have finished processing it */
  1387. +        wasquoted = 0;
  1388. +        state = end_s;
  1389. +        break;
  1390. +      }
  1391. +      }
  1392. +    
  1393. +    /* if the input string was quoted, all the work has been done already.
  1394. +     * otherwise, make the output a copy of the input */
  1395. +
  1396. +    if (result && ! wasquoted) {
  1397. +    (void) strcpy (result, string);
  1398. +      }
  1399. +    
  1400. +    return (wasquoted);
  1401. +  }
  1402. +
  1403. +
  1404. +/* sh_quote --
  1405. + * quotes a character string so that, when /bin/sh interprets the result,
  1406. + * the interpretation will be identical to the original string.
  1407. + * Returns a pointer to the result string.
  1408. + *
  1409. + *     fred@somewhere        ==>    'fred@somewhere'
  1410. + *    "funny'name\"thing"@somewhere
  1411. + *                ==>    '"funny'"'"'name\"thing"@somewhere
  1412. + */
  1413. +
  1414. +char *sh_quote (result, string)
  1415. +char *result, *string;
  1416. +  {
  1417. +    char *p = string;
  1418. +    char *q = result;
  1419. +
  1420. +    /* start with the opening quote mark {'} */
  1421. +
  1422. +    *q++ = '\'';
  1423. +
  1424. +    /* process the string */
  1425. +
  1426. +    for ( ; *p != '\0' ; p++ ) {
  1427. +    if (*p == '\'') {
  1428. +        /* convert embedded {'} to {'"'"'} */
  1429. +        *q++ = '\'';
  1430. +        *q++ = '\"';
  1431. +        *q++ = '\'';
  1432. +        *q++ = '\"';
  1433. +        *q++ = '\'';
  1434. +      }
  1435. +    else {
  1436. +      *q++ = *p;
  1437. +    }
  1438. +    }
  1439. +
  1440. +    /* add last {'} */
  1441. +
  1442. +    *q++ = '\'';
  1443. +
  1444. +    /* terminate with a nul */
  1445. +
  1446. +    *q = '\0';
  1447. +
  1448. +    return (result);
  1449. +  }
  1450. +
  1451.  
  1452. Index: pw.c
  1453. *** old/pw.c    Thu Jan 18 17:03:45 1990
  1454. --- new/pw.c    Thu Jan 18 17:04:13 1990
  1455. @@ -54,6 +54,32 @@
  1456.      return(NULL);
  1457.  }
  1458.  
  1459. +pwuserid(user)
  1460. +char *user;
  1461. +{
  1462. +    pwlist *f;
  1463. +
  1464. +    /*
  1465. +    ** check for previously cached user
  1466. +    */
  1467. +
  1468. +    for(f=pwhead; f != NULL; f=f->vlink) {
  1469. +        if(strcmp(user, f->lname) == 0) {
  1470. +            return(f->uid);
  1471. +        }
  1472. +    }
  1473. +    /*
  1474. +    ** not found parse the password file
  1475. +    */
  1476. +
  1477. +    while((f=pwparse()) != PNULL) {
  1478. +        if(strcmp(user, f->lname) == 0) {
  1479. +            return(f->uid);
  1480. +        }
  1481. +    }
  1482. +    return(0);
  1483. +}
  1484. +
  1485.  char *
  1486.  pwuid(uid)
  1487.  int uid;
  1488. @@ -232,14 +258,16 @@
  1489.              if ( *s == '\0' ) {
  1490.                  goto solved;
  1491.              }
  1492. -            c = getc( file );
  1493. -            flag = lower( c ) - lower( *s );
  1494. +            if ((c = getc( file )) == EOF)
  1495. +                flag = 1;
  1496. +            else
  1497. +                flag = lower( c ) - lower( *s );
  1498.          } 
  1499. -        if (lo >= middle)        /* failure? */
  1500. +        if (lo > hi)        /* failure? */
  1501.              return(NULL);
  1502.  
  1503. -        if(c != EOF && flag < 0)    /* close window */
  1504. -            lo = middle;
  1505. +        if (flag < 0)    /* close window */
  1506. +            lo = middle + 1;
  1507.          else 
  1508.              hi = middle - 1;
  1509.      }
  1510.  
  1511. Index: resolve.c
  1512. *** old/resolve.c    Thu Jan 18 17:03:45 1990
  1513. --- new/resolve.c    Thu Jan 18 17:04:13 1990
  1514. @@ -50,6 +50,14 @@
  1515.  **  This is a gnarly piece of code, but it does it all.  Each section 
  1516.  **  is documented.
  1517.  **
  1518. +** **** Note:
  1519. +** Alias and fullname translation should be done whenever an address
  1520. +** resolves to a local name, but it is not.  This is only a problem
  1521. +** if routing = REROUTE and we find the local system name at the end of
  1522. +** a path through other systems; in all other cases the local system
  1523. +** name will have been removed already by the aliasing code before
  1524. +** the main program calls resolve().
  1525. +**
  1526.  */
  1527.  
  1528.  enum eform
  1529. @@ -59,13 +67,15 @@
  1530.  char *user;                /* the returned user     */
  1531.  int *cost;                /* the returned cost     */
  1532.  {
  1533. -    enum eform form;        /* the returned form    */ 
  1534. -    enum eform parse();        /* to crack addresses    */
  1535. -    int parts;            /* to ssplit addresses    */
  1536. -    char *partv[MAXPATH];        /* "  "      "        */
  1537. -    char temp[SMLBUF];        /* "  "      "        */
  1538. -    int i;
  1539. -        
  1540. +    enum eform form;            /* the returned form    */ 
  1541. +    enum eform parse();            /* to crack addresses    */
  1542. +    int parts;                /* to ssplit addresses    */
  1543. +    char *partv[MAXPATH];        /* "  "      "        */
  1544. +    char temp[SMLBUF];            /* "  "      "        */
  1545. +    int i;
  1546. +    char *p;
  1547. +        
  1548. +beginning:
  1549.  
  1550.  /*
  1551.  **  If we set REROUTE and are prepared to deliver UUCP mail, we split the 
  1552. @@ -73,32 +83,32 @@
  1553.  **  substrings until we succeed.  Otherwise, we just resolve the whole thing 
  1554.  **  once.
  1555.  */
  1556. -    if ((routing == REROUTE) && (rsvp( UUCP ) == UUCP)) {
  1557. -        parts = ssplit( address, '!', partv );
  1558. -    } else {
  1559. -        parts = 1;
  1560. -        partv[0] = address;
  1561. -    }
  1562. +    if ((routing == REROUTE) && (rsvp( UUCP ) == UUCP)) {
  1563. +    parts = ssplit( address, '!', partv );
  1564. +    } else {
  1565. +    parts = 1;
  1566. +    partv[0] = address;
  1567. +    }
  1568.  /*
  1569.  **  This for(i) loop selects successively larger
  1570.  **  righthand substrings of the address.
  1571.  */
  1572. -    for( i = parts - 1; i >= 0; i-- ) {
  1573. +    for( i = parts - 1; i >= 0; i-- ) {
  1574.  /*
  1575.  **  Parse the address.
  1576.  */
  1577. -        (void) strcpy( temp, partv[i] );
  1578. -        form = parse( temp, domain, user );
  1579. +    (void) strcpy( temp, partv[i] );
  1580. +    form = parse( temp, domain, user );
  1581.  
  1582.  DEBUG("resolve: parse address '%s' = '%s' @ '%s' (%s)\n",
  1583. -    temp,user,domain,sform(form));
  1584. +    temp,user,domain,sform(form));
  1585.  
  1586.  /*
  1587.  **  If we are looking at a substring (that's not the entire string)
  1588.  **  which parses to a LOCAL address, we skip to the next larger substring.
  1589.  */
  1590. -        if((i != 0) && (form == LOCAL))
  1591. -            continue;
  1592. +    if((i != 0) && (form == LOCAL))
  1593. +        continue;
  1594.  /*
  1595.  **  Routing, when required, is the next step.
  1596.  **  We route the address if we have a ROUTE form
  1597. @@ -105,69 +115,79 @@
  1598.  **  or if we have a UUCP form and we are told to
  1599.  **  route ALWAYS or REROUTE (i.e., routing != JUSTDOMAIN)
  1600.  */
  1601. -        if((rsvp( form ) == ROUTE)
  1602. -         ||((rsvp( form ) == UUCP) && (routing != JUSTDOMAIN ))) {
  1603. +    if((rsvp( form ) == ROUTE)
  1604. +     ||((rsvp( form ) == UUCP) && (routing != JUSTDOMAIN ))) {
  1605.  
  1606. -            int look_smart = 0;
  1607. +        int look_smart = 0;
  1608.  
  1609. -            if((routing == REROUTE) && (i == 0)) {
  1610. -                look_smart = 1; /* last chance */
  1611. -            }
  1612. +        if( /* (routing == REROUTE) && */ (i == 0)) {
  1613. +        look_smart = 1; /* last chance */
  1614. +        }
  1615.  
  1616. -            /* route() puts the new route in 'temp' */
  1617. -            if(route(domain,user,look_smart,temp,cost) != EX_OK) {
  1618. -                continue;    /* If routing fails, try
  1619. -                        /* next larger substring.
  1620. -                        /* */
  1621. -            }
  1622. +        /* route() puts the new route in 'temp' */
  1623. +        if(route(domain,user,look_smart,temp,cost) != EX_OK) {
  1624. +        continue;   /* If routing fails, try
  1625. +                /* next larger substring.
  1626. +                /* */
  1627. +        }
  1628.  /*
  1629.  **  After routing, reparse the new route into domain and user. 
  1630.  */
  1631. -            form = parse( temp, domain, user );
  1632. +        form = parse( temp, domain, user );
  1633.  
  1634.  DEBUG("resolve: parse route '%s' = '%s' @ '%s' (%s)\n",
  1635. -    temp,user,domain,sform(form));
  1636. +    temp,user,domain,sform(form));
  1637.  
  1638. -        } else if((getcost) && (rsvp(form) == UUCP)) {
  1639. -            /* get the cost of the route
  1640. -            ** even if we're not going route the mail.
  1641. -            ** this allows smart decisions about using
  1642. -            ** the -r flag to uux when we're not routing.
  1643. -            */
  1644. -            char junk[SMLBUF];
  1645. -            if(route(domain,user,0,junk,cost) != EX_OK) {
  1646. -                continue;    /* If routing fails, try
  1647. -                        /* next larger substring.
  1648. -                        /* */
  1649. -            }
  1650. -        }
  1651. -        break;    /* route is resolved */
  1652. +
  1653. +    } else if((getcost) && (rsvp(form) == UUCP)) {
  1654. +        /* get the cost of the route
  1655. +        ** even if we're not going route the mail.
  1656. +        ** this allows smart decisions about using
  1657. +        ** the -r flag to uux when we're not routing.
  1658. +        */
  1659. +        char junk[SMLBUF];
  1660. +        if(route(domain,user,0,junk,cost) != EX_OK) {
  1661. +            continue;    /* If routing fails, try
  1662. +                /* next larger substring.
  1663. +                /* */
  1664. +        }
  1665.      }
  1666. -/*
  1667. -**  For LOCAL mail in non-local format, we rewrite the full address into 
  1668. -**  <user> and leave <domain> blank.
  1669. -*/
  1670. -    if ((rsvp( form ) == LOCAL) && (form != LOCAL )) {
  1671. -        build( domain, user, form, temp );
  1672. -        (void) strcpy( user, temp );
  1673. -        (void) strcpy( domain, "" );
  1674. -        form = LOCAL;
  1675. -    }
  1676. -/*
  1677. -**  If we were supposed to route an address but failed (form == ERROR), 
  1678. -**  or after routing we are left with an address that still needs to
  1679. -**  be routed (rsvp( form ) == ROUTE), complain.
  1680. -*/
  1681. -    if ((form == ERROR) || (rsvp( form ) == ROUTE )) {
  1682. -        exitstat = EX_NOHOST;
  1683. -        ADVISE("resolve failed '%s' = '%s' @ '%s' (%s)\n",
  1684. -            address, user, domain, sform(form));
  1685. -        form = ERROR;
  1686. -    } else {
  1687. -        ADVISE("resolve '%s' = '%s' @ '%s' (%s)\n",
  1688. -            address, user, domain, sform(form));
  1689. -    }
  1690. -    return ( form );
  1691. +    break;    /* route is resolved */
  1692. +    }
  1693. +    /*
  1694. +    **  For LOCAL mail in non-local format, we rewrite the full address into 
  1695. +    **  <user> and leave <domain> blank.
  1696. +    */
  1697. +    if ((rsvp( form ) == LOCAL) && (form != LOCAL )) {
  1698. +    build( domain, user, form, temp );
  1699. +    (void) strcpy( user, temp );
  1700. +    (void) strcpy( domain, "" );
  1701. +    form = LOCAL;
  1702. +    }
  1703. +    /*
  1704. +    **  If we were supposed to route an address but failed (form == ERROR), 
  1705. +    **  or after routing we are left with an address that still needs to
  1706. +    **  be routed (rsvp( form ) == ROUTE), complain.
  1707. +    */
  1708. +    if ((form == ERROR) || (rsvp( form ) == ROUTE )) {
  1709. +    exitstat = EX_NOHOST;
  1710. +    ADVISE("resolve failed '%s' = '%s' @ '%s' (%s)\n",
  1711. +        address, user, domain, sform(form));
  1712. +    form = ERROR;
  1713. +    }
  1714. +    /*
  1715. +    ** If we have a LOCAL address that contains a % then change the %
  1716. +    ** to an @ and start again from the beginning.
  1717. +    */
  1718. +    else if ((form == LOCAL) && ((p = rindex(user,'%')) != NULL)) {
  1719. +    *p = '@';
  1720. +    strcpy (address, user);
  1721. +    goto beginning;
  1722. +    } else {
  1723. +    ADVISE("resolve '%s' = '%s' @ '%s' (%s)\n",
  1724. +        address, user, domain, sform(form));
  1725. +    }
  1726. +    return ( form );
  1727.  }
  1728.  
  1729.  /*
  1730. @@ -185,93 +205,173 @@
  1731.  char *result;            /* output route     */
  1732.  int *cost;            /* cost of output route */
  1733.  {
  1734. -    int    uucpdom = 0;
  1735. -    int    domains, step;            /* to split domain    */
  1736. -    char    *domainv[MAXDOMS];        /* "  "     "        */
  1737. -    char    temp[SMLBUF], path[SMLBUF];
  1738. +    int     uucpdom = 0;
  1739. +    int     dotkey;                 /* did getpath() find a path for a
  1740. +                       key that began with a "."? */
  1741. +    int     domains, step;                  /* to split domain      */
  1742. +    char    *domainv[MAXDOMS];              /* "  "     "           */
  1743. +    char    temp[SMLBUF], path[SMLBUF];
  1744. +    char    leftpart[SMLBUF], *up;
  1745.  
  1746. -/*
  1747. -**  Fully qualify the domain, and then strip the last (top level domain) 
  1748. -**  component off, so that we look it up separately.
  1749. -*/
  1750. -    temp[0] = '.';
  1751. -    (void) strcpy(temp+1, domain );
  1752. +    /*
  1753. +    **  Fully qualify the domain, and then strip the last (top level domain) 
  1754. +    **  component off, so that we look it up separately.
  1755. +    */
  1756. +    temp[0] = '.';
  1757. +    (void) strcpy(temp+1, domain );
  1758.  
  1759. -    domains = ssplit( temp+1, '.', domainv );
  1760. +    domains = ssplit( temp+1, '.', domainv );
  1761.  
  1762. -/*
  1763. -** check target domain for the local host name and host domain.
  1764. -** if it matches, then skip the lookup in the database.
  1765. -** this prevents mail loops for cases where SMARTHOST is defined
  1766. -** in the routing table, but the local host is not.  It also is
  1767. -** a little faster when the local host is the target domain.
  1768. -*/
  1769. -    if((strcmpic(domain, hostname) == 0)
  1770. -    || (strcmpic(domain, hostdomain) == 0)) {
  1771. -        step = 0;
  1772. -        *cost = 0;
  1773. -        (void) strcpy(path, "%s");
  1774. -DEBUG("route: '%s' is local\n", domain);
  1775. -        goto route_complete;
  1776. -    }
  1777. +    /*
  1778. +    ** check target domain for the local host name and host domain.
  1779. +    ** if it matches, then skip the lookup in the database.
  1780. +    ** this prevents mail loops for cases where SMARTHOST is defined
  1781. +    ** in the routing table, but the local host is not.  It also is
  1782. +    ** a little faster when the local host is the target domain.
  1783. +    */
  1784. +    if((strcmpic(domain, hostname) == 0)
  1785. +    || (strcmpic(domain, hostdomain) == 0)) {
  1786. +    step = 0;
  1787. +    *cost = 0;
  1788. +    (void) strcpy(path, "%s");
  1789. +    DEBUG("route: '%s' is local\n", domain);
  1790. +    goto route_complete;
  1791. +    }
  1792.  
  1793. -    /* If the domain ends in .UUCP, trim that off. */
  1794. -    if((domains > 0) && isuucp(domainv[domains-1])) {
  1795. -        domains--;
  1796. -        domainv[domains][-1] = '\0';
  1797. -        uucpdom = 1;
  1798. -    }
  1799. -/*
  1800. -**  Try to get the path for successive components of the domain.  
  1801. -**  Example for osgd.cb.att.uucp:
  1802. -**    osgd.cb.att
  1803. -**    cb.att
  1804. -**    att
  1805. -**    uucp ( remember stripping top level? )
  1806. -**    SMARTHOST
  1807. -**  Returns with error if we find no path.
  1808. -*/
  1809. -    for(step = 0; (step < domains); step++) {
  1810. -        if((getpath(domainv[step]-1, path, cost) == EX_OK) /* w/ dot */
  1811. -        || (getpath(domainv[step]  , path, cost) == EX_OK))/* no dot */
  1812. -            break;
  1813. -    }
  1814. +    /* If the domain ends in .UUCP, trim that off. */
  1815. +    if((domains > 0) && isuucp(domainv[domains-1])) {
  1816. +    domains--;
  1817. +    domainv[domains][-1] = '\0';
  1818. +    uucpdom = 1;
  1819. +    }
  1820. +    /*
  1821. +    **  Try to get the path for successive components of the domain.  
  1822. +    **  Example for osgd.cb.att.uucp:
  1823. +    **    osgd.cb.att
  1824. +    **    cb.att
  1825. +    **    att
  1826. +    **    uucp ( remember stripping top level? )
  1827. +    **  truncated name (in this case, osgd or osgd.cb in the paths file )
  1828. +    **  osgd ( using uuname to check the uucp L.sys or Systems file )
  1829. +    **    SMARTHOST
  1830. +    **  Returns with error if we find no path.
  1831. +    */
  1832. +    for(step = 0; (step < domains); step++) {
  1833. +    /*
  1834. +    ** Look in the paths file for a route to whatever portion
  1835. +    ** of the domain name interests us right now.
  1836. +    ** If we are interested in the entire name (step=0) then
  1837. +    ** try a path that doesn't start with a dot before trying
  1838. +    ** one that does start with a dot.
  1839. +    ** If we are interested in something other than the entire
  1840. +    ** domain name, try the dot path first.
  1841. +    */
  1842. +    if (step == 0) {
  1843. +        if ((dotkey=0, /* no dot */
  1844. +        getpath(domainv[step]  , path, cost, 0) == EX_OK)
  1845. +        ||  (dotkey=1, /* with dot */
  1846. +        getpath(domainv[step]-1, path, cost, 0) == EX_OK))
  1847. +            break; /* found it */
  1848. +        } else {
  1849. +        if ((dotkey=1, /* with dot */
  1850. +        getpath(domainv[step]-1, path, cost, 0) == EX_OK)
  1851. +        ||  (dotkey=0, /* no dot */
  1852. +        getpath(domainv[step]  , path, cost, 0) == EX_OK))
  1853. +            break; /* found it */
  1854. +        }
  1855. +    } /* end for */
  1856.  
  1857. -    if(step == domains) {
  1858. +    if(step == domains) {
  1859.      /*
  1860. -    ** we've looked at each component of the domain without success
  1861. +    ** We've looked at each component of the domain without success
  1862. +    **
  1863. +    ** If domain is a UUCP address, look for a UUCP gateway.
  1864.      */
  1865. +    if((uucpdom == 0)
  1866. +    || (dotkey=1, getpath(".UUCP", path, cost, 0) != EX_OK)) {
  1867. +        /*
  1868. +        ** The domain not is a UUCP address, or we can't
  1869. +        ** find a UUCP gateway.
  1870. +        */
  1871. +        /* extract the leftmost part of the domain name, for use
  1872. +        ** with TRUNC_DOM, UUNAME etc.
  1873. +        */
  1874. +        strcpy(leftpart,domain);
  1875. +        if(up=index(leftpart,'.')) *up='\0';
  1876. +#ifdef TRUNC_DOM
  1877. +        /*
  1878. +        ** See if the domain we want appears
  1879. +        ** as a truncated part of a domain in the paths file.
  1880. +        */
  1881. +        if(getpath(domain, path, cost, 1) == EX_OK) {
  1882. +        dotkey = 0;    /* no dot */
  1883. +        step = 0;    /* pretend we matched on full name */
  1884. +        goto route_complete;
  1885. +        }
  1886. +#endif /* TRUNC_DOM */
  1887. +#ifdef TRUNC_DOM_LEFT
  1888. +        /*
  1889. +        ** See if the leftmost part of the domain we want appears
  1890. +        ** as the leftmost part of a domain in the paths file.
  1891. +        */
  1892. +        if(getpath(leftpart, path, cost, 1) == EX_OK) {
  1893. +        dotkey = 0;    /* no dot */
  1894. +        step = 0;    /* pretend we matched on full name */
  1895. +        goto route_complete;
  1896. +        }
  1897. +#endif /* TRUNC_DOM_LEFT */
  1898. +#ifdef UUNAME
  1899. +        /*
  1900. +        ** See if there is a directly connected UUCP
  1901. +        ** system whose name matches the first part of
  1902. +        ** the full domain name.
  1903. +        */
  1904. +        if(look_smart == 1) {
  1905. +        DEBUG("route: '%s': look for '%s' uucp neighbour\n",
  1906. +            domain,leftpart);
  1907. +        if (uuname(leftpart)) {
  1908. +            DEBUG("route: '%s' is a uucp neighbour\n",leftpart);
  1909. +            strcpy(path,leftpart);
  1910. +            strcat(path,"!%s");    /* Create a bang path */
  1911. +            *cost = 300;    /* Average Cost ? */
  1912. +            dotkey = 0;        /* no dot */
  1913. +            step = 0;        /* pretend we matched whole name */
  1914. +            goto route_complete;
  1915. +        }
  1916. +        }
  1917. +#endif /* UUNAME */
  1918. +
  1919. +        /*
  1920. +        ** If this is our last chance,
  1921. +        ** look for a smarter host to deliver the mail.
  1922. +        */
  1923. +        if((look_smart == 0)
  1924. +        || (dotkey=0, getpath(SMARTHOST,path,cost,0) != EX_OK)) {
  1925.          /*
  1926. -        ** If domain is a UUCP address, look for a UUCP gateway.
  1927. +        ** All our efforts have been in vain.
  1928. +        ** Tell them the bad news.
  1929.          */
  1930. -        if((uucpdom == 0) || (getpath(".UUCP", path, cost) != EX_OK)) {
  1931. -            /*
  1932. -            ** The domain not is a UUCP address, or we can't
  1933. -            ** find a UUCP gateway.  If this is our last chance,
  1934. -            ** look for a smarter host to deliver the mail.
  1935. -            */
  1936. -            if((look_smart == 0)
  1937. -            || (getpath(SMARTHOST, path, cost) != EX_OK)) {
  1938. -                /*
  1939. -                ** All our efforts have been in vain.
  1940. -                ** Tell them the bad news.
  1941. -                */
  1942. -                DEBUG("route '%s' failed\n", domain);
  1943. -                return( EX_NOHOST );
  1944. -            }
  1945. -        }
  1946. +        DEBUG("route '%s' failed\n", domain);
  1947. +        return( EX_NOHOST );
  1948. +        }
  1949.      }
  1950. +    } /* end if (step==domains) */
  1951.  
  1952. -route_complete:
  1953. +    /*
  1954. +    ** If we get here, we have a route to use.
  1955. +    */
  1956. +    route_complete:
  1957.  
  1958. -DEBUG("route:  '%s' (%s) = '%s' (%d)\n", domain, domainv[step]?domainv[step]:"NULL", path, *cost);
  1959. +    DEBUG("route:  '%s' (%s) = '%s' (%d)\n", domain,
  1960. +    domainv[step]?domainv[step]:"NULL", path, *cost);
  1961.  
  1962. -/*
  1963. -**  If we matched on the entire domain name, this address is fully resolved, 
  1964. -**  and we plug <user> into it.  If we matched on only part of the domain 
  1965. -**  name, we plug <domain>!<user> in.  
  1966. -*/
  1967. -    build(domain, user, (step == 0) ? LOCAL : UUCP, temp);
  1968. -    (void) sprintf(result, path, temp);
  1969. -    return( EX_OK );
  1970. +    /*
  1971. +    **  If we matched on the entire domain name, this address is fully
  1972. +    **  resolved, and we plug <user> into it.  If we matched on only part
  1973. +    **  of the domain name, or if the match started fith a ".", we plug
  1974. +    **  <domain>!<user> in.  
  1975. +    */
  1976. +    build (domain, user, (step == 0 && dotkey == 0) ? LOCAL : UUCP, temp);
  1977. +    (void) sprintf(result, path, temp);
  1978. +    return( EX_OK );
  1979.  }
  1980.  
  1981. Index: uuname.c
  1982. *** old/uuname.c    Thu Jan 18 17:04:01 1990
  1983. --- new/uuname.c    Thu Jan 18 17:04:14 1990
  1984. ***************
  1985. *** 1 ****
  1986. --- 1,44 ----
  1987. + #include <stdio.h>
  1988. + #include "defs.h"
  1989. + /*
  1990. + **  UUNAME - function takes one argument - the name of a possible valid
  1991. + **  uucp site - thats one hop away (ie from the Systems file). If it finds
  1992. + **  name - it returns '1' (ie TRUE) - otherwise it returns a '0' (False).
  1993. + **
  1994. + ** It runs the command 'uuname' and checks the output for that sitename 
  1995. + ** (Your arguement). Why a pipe?  - This means that you don't have to have
  1996. + ** special permissions to read your Systems file - and it works happily
  1997. + ** regardless of the type of UUCP you are running. Also - its easier to
  1998. + ** fudge if things change - all you need is a program in /usr/bin/uuname!
  1999. + **
  2000. + ** Author - Mark J Elkins - mje@olsa99.UUCP
  2001. + **
  2002. + ** Modified by A P Barrett to use popen instead of pipe/fork/exec,
  2003. + ** and to use the UUNAME preprocessor symbol to define the program to run.
  2004. + */
  2005. + #ifdef UUNAME
  2006. + uuname(match)
  2007. + char *match;
  2008. + {
  2009. +     FILE *fp;
  2010. +     char buff[40], *p;
  2011. +     if ((fp = popen(UUNAME,"r")) == NULL) {
  2012. +         perror("smail: cannot popen uuname");
  2013. +         return(0);
  2014. +     }
  2015. +     while(fgets(buff,36,fp)) {
  2016. +         if(p=index(buff,'\n'))  *p = '\0';
  2017. +         if(strcmp(match,buff) == 0) { /* found */
  2018. +         (void) pclose(fp);
  2019. +         return(1);
  2020. +         }
  2021. +     }
  2022. +     (void) pclose(fp);
  2023. +     return(0);
  2024. + }
  2025. + #endif
  2026.  
  2027. ----- end of diffs -----
  2028.