home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65c+IDA-1.4.4.1 / uiuc / RCS / phquery.c,v < prev    next >
Encoding:
Text File  |  1991-08-15  |  102.2 KB  |  4,579 lines

  1. head    1.25;
  2. access;
  3. symbols
  4.     RELEASE:1.25;
  5. locks
  6.     paul:1.25; strict;
  7. comment    @ * @;
  8.  
  9.  
  10. 1.25
  11. date    91.05.10.02.21.27;    author paul;    state Exp;
  12. branches;
  13. next    1.24;
  14.  
  15. 1.24
  16. date    91.05.08.17.05.59;    author paul;    state Exp;
  17. branches;
  18. next    1.23;
  19.  
  20. 1.23
  21. date    91.04.03.22.24.44;    author paul;    state Exp;
  22. branches;
  23. next    1.22;
  24.  
  25. 1.22
  26. date    91.03.18.15.38.00;    author paul;    state Exp;
  27. branches;
  28. next    1.21;
  29.  
  30. 1.21
  31. date    91.03.16.17.28.21;    author paul;    state Exp;
  32. branches;
  33. next    1.20;
  34.  
  35. 1.20
  36. date    91.01.26.21.10.29;    author paul;    state Exp;
  37. branches;
  38. next    1.19;
  39.  
  40. 1.19
  41. date    90.12.11.12.25.50;    author paul;    state Exp;
  42. branches;
  43. next    1.18;
  44.  
  45. 1.18
  46. date    90.12.10.21.58.27;    author paul;    state Exp;
  47. branches;
  48. next    1.17;
  49.  
  50. 1.17
  51. date    90.12.10.14.09.03;    author paul;    state Exp;
  52. branches;
  53. next    1.16;
  54.  
  55. 1.16
  56. date    90.06.11.10.52.40;    author paul;    state Exp;
  57. branches;
  58. next    1.15;
  59.  
  60. 1.15
  61. date    90.01.30.23.51.30;    author paul;    state Exp;
  62. branches;
  63. next    1.14;
  64.  
  65. 1.14
  66. date    89.07.28.10.05.12;    author paul;    state Exp;
  67. branches;
  68. next    1.13;
  69.  
  70. 1.13
  71. date    89.07.27.23.19.22;    author paul;    state Exp;
  72. branches;
  73. next    1.12;
  74.  
  75. 1.12
  76. date    89.05.24.00.11.48;    author paul;    state Exp;
  77. branches;
  78. next    1.11;
  79.  
  80. 1.11
  81. date    89.05.16.16.59.36;    author paul;    state Exp;
  82. branches;
  83. next    1.10;
  84.  
  85. 1.10
  86. date    89.05.11.17.20.48;    author paul;    state Exp;
  87. branches;
  88. next    1.9;
  89.  
  90. 1.9
  91. date    89.05.10.11.50.49;    author paul;    state Exp;
  92. branches;
  93. next    1.8;
  94.  
  95. 1.8
  96. date    89.05.10.00.57.49;    author paul;    state Exp;
  97. branches;
  98. next    1.7;
  99.  
  100. 1.7
  101. date    89.05.09.22.53.57;    author paul;    state Exp;
  102. branches;
  103. next    1.6;
  104.  
  105. 1.6
  106. date    89.05.08.23.21.20;    author paul;    state Exp;
  107. branches;
  108. next    1.5;
  109.  
  110. 1.5
  111. date    89.05.08.20.40.14;    author paul;    state Exp;
  112. branches;
  113. next    1.4;
  114.  
  115. 1.4
  116. date    89.05.05.11.26.06;    author paul;    state Exp;
  117. branches;
  118. next    1.3;
  119.  
  120. 1.3
  121. date    89.05.05.00.11.03;    author paul;    state Exp;
  122. branches;
  123. next    1.2;
  124.  
  125. 1.2
  126. date    89.05.01.15.26.34;    author paul;    state Exp;
  127. branches;
  128. next    1.1;
  129.  
  130. 1.1
  131. date    89.02.13.16.07.39;    author paul;    state Exp;
  132. branches;
  133. next    ;
  134.  
  135.  
  136. desc
  137. @Fuzzy address resolver.  Links sendmail with ph/qi.
  138. @
  139.  
  140.  
  141. 1.25
  142. log
  143. @Eliminated limit on returned message size.
  144. @
  145. text
  146. @/*
  147.  * Copyright (c) 1989 Paul Pomes
  148.  * Copyright (c) 1989 University of Illinois Board of Trustees
  149.  * All rights reserved.
  150.  *
  151.  * Redistribution and use in source and binary forms are permitted
  152.  * provided that the above copyright notice and this paragraph are
  153.  * duplicated in all such forms and that any documentation,
  154.  * advertising materials, and other materials related to such
  155.  * distribution and use acknowledge that the software was developed
  156.  * by the University of Illinois, Urbana.  In addition, redistribution
  157.  * and use must conform to the terms listed in the CopyLeft text below.
  158.  *
  159.  * The name of the University may not be used to endorse or promote products
  160.  * derived from this software without specific prior written permission.
  161.  *
  162.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  163.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  164.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  165.  */
  166.  
  167. #ifndef lint
  168. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.24 1991/05/08 17:05:59 paul Exp paul $";
  169. #endif /* lint */
  170.  
  171. #include <stdio.h>
  172. #include <assert.h>
  173. #include <sys/types.h>
  174. #include <sys/param.h>
  175. #if defined(pyr) || defined(is68k) || defined(NeXT) || defined(__convex__) \
  176.     || defined(BSD4_4) || defined(ibm032)
  177. # include <sys/time.h>
  178. # include <sys/vnode.h>
  179. # define    IREAD        VREAD
  180. # define    IWRITE        VWRITE
  181. #else    /* ! pyr && ! is68k */
  182. # if defined(sun) || defined(convex) || defined(apollo)
  183. #  include <sys/stat.h>
  184. #  define    IREAD        S_IREAD
  185. #  define    IWRITE        S_IWRITE
  186. # else    /* ! sun && ! convex */
  187. #  include <sys/inode.h>
  188. # endif    /* sun || convex */
  189. #endif    /* pyr || is68k */
  190. #include <netdb.h>
  191. #include <ctype.h>
  192. #include <sys/socket.h>
  193. #include <sys/syslog.h>
  194. #include <sys/errno.h>
  195. #include <sys/wait.h>
  196. #include <netinet/in.h>
  197. #include <sysexits.h>
  198. #include <strings.h>
  199. #include "phquery.h"
  200. #include "messages.h"
  201.  
  202. #define        VERSION        "3.8"
  203.  
  204. /* Domain to append to ph aliases when creating Reply-To: fields */
  205. #ifndef    DOMAIN
  206. # define    DOMAIN        "uiuc.edu"
  207. #endif    /* DOMAIN */
  208.  
  209. /* Designated server port */
  210. #ifndef    QISERVICE
  211. # define    QISERVICE    "ns"
  212. #endif    /* QISERVICE */
  213.  
  214. /* Mail transport agent of choice */
  215. #if defined(BSD4_4)
  216. #define        SENDMAIL    "/usr/sbin/sendmail"
  217. #else /* !BSD4_4 */
  218. #define        SENDMAIL    "/usr/lib/sendmail"
  219. #endif /* BSD4_4 */
  220.  
  221. /* How to print/log error messages */
  222. #define        DANGER_WILL_ROBINSON(KateBush) \
  223.     { if (Debug) \
  224.         perror (KateBush); \
  225.     if (Log) \
  226.         syslog (LOG_ERR, strcat (KateBush, ": %m")); \
  227.     finis (); }
  228.  
  229. /*
  230. **  PHQUERY -- Resolve fuzzy addresses to specific a user@@FQDN
  231. **
  232. **    FQDN := Fully Qualified Domain Name
  233. **    Phquery is invoked as a mailer (not a final mailer!) by sendmail
  234. **    to resolve addresses of the form user@@DOMAINMASTER where DOMAINMASTER
  235. **    is a m4 define used in building an IDA sendmail.cf file.  At UIUC
  236. **    this would be user@@uiuc.edu .  The user token is interpreted first
  237. **    as a QI alias, then as a full name if that fails.  QI is the CSnet
  238. **    Query Interpreter.  At UIUC it contains the entire campus phone
  239. **    directory plus the unit directory.  A user entry has about as many
  240. **    fields as ls has option letters.  The most important are alias, name,
  241. **    email, phone, department, and curriculum.  In the simplest case,
  242. **    matching an alias (guaranteed unique) returns the email address.
  243. **
  244. **    Since life is seldom simple, the alternate cases/actions are summarized
  245. **
  246. **    a) alias match, email found
  247. **        write a X-PH-To: header with the email address found, copy the
  248. **        rest of the message, and re-invoke sendmail
  249. **         OR
  250. **        write a X-PH: VX.Y@@<host> and re-invoke sendmail.  This is
  251. **        useful for sites that don't wish to expand alias lists in the
  252. **        header block.
  253. **    b) alias match, no email field:
  254. **        return public fields of ph entry and suggest phone usage
  255. **    c) alias match, bogus email field:
  256. **        sendmail catches this one.  The user will see the X-PH-To:
  257. **        header.  Not the best so far.....
  258. **    d) alias fail:
  259. **        try name field
  260. **    e) single name match, email present:
  261. **        deliver as in a)
  262. **    f) single name match, no email field:
  263. **        handle as in b)
  264. **    g) single name match, bogus email field:
  265. **        handle as in c)
  266. **    h) multiple (<5) name matches:
  267. **        return alias, name, email, and dept fields of matches
  268. **    i) multiple (>5) name matches:
  269. **        return "too ambiguous" message
  270. **
  271. **    Phquery is also used to create return addresses of the form
  272. **    ph-alias@@DOMAINMASTER.  This is implemented by adding the fields
  273. **
  274. **    Resent-From: postmaster@@<host>
  275. **    Reply-To: ph-alias@@DOMAINMASTER
  276. **    Comment: Reply-To: added by phquery (Vx.y)
  277. **
  278. **    N.B., RFC-822, Section 4.4.1 requires that the From / Resent-From
  279. **    fields be a single, authenticated machine address.  
  280. */
  281.  
  282. /* some handy defines */
  283. #define        CHNULL            ('\0')
  284. #define        CPNULL            ((char *) NULL)
  285. #define        FILE_NULL        ((FILE *) NULL)
  286. #define        NADD_NULL        ((struct NewAddress *) NULL)
  287. #define        QIR_NULL        ((struct QI_response *) NULL)
  288.  
  289. /* some handy compare operators */
  290. #define        nequal(s1,s2,n)        (strncasecmp (s1, s2, n) == 0)
  291. #define        equal(s1,s2)        (strcasecmp (s1, s2) == 0)
  292.  
  293. /* large string size */
  294. #define        MAXSTR            250
  295.  
  296. /* Bit flags to control printing of informative messages in ErrorReturn() */
  297. #define        NO_MATCH_MSG        0x1
  298. #define        MULTI_MSG        0x2
  299. #define        ABSENT_MSG        0x4
  300. #define        TOO_MANY_MSG        0x8
  301. #define        PHONE_MSG        0x10
  302.  
  303. FILE    *ToQI =        FILE_NULL;    /* write to the QI */
  304. FILE    *FromQI =    FILE_NULL;    /* read from the QI */
  305.  
  306. extern int    errno;
  307.  
  308. /* Set to carbon-copy postmaster on error returns */
  309. int    PostmasterCC =    0;
  310.  
  311. /* Set if the reply-to: field on outgoing mail is to inserted */
  312. int    ReplyTo = 0;
  313.  
  314. /* Hostname of this machine */
  315. char    HostNameBuf[100];
  316.  
  317. /* How program was invoked (argv[0]) for error messages */
  318. char    *MyName;
  319.  
  320. /* Exit status for finis() reporting to calling process */
  321. int    ExitStat =    EX_TEMPFAIL;
  322.  
  323. /* Temporary message file */
  324. char    TmpFile[] =    "/tmp/PhMailXXXXXXX";
  325.  
  326. /* Temporary file for creating error messages */
  327. char    ErrorFile[] =    "/tmp/PhErrMailXXXXXXX";
  328.  
  329. /* Temporary file for rewriting messages */
  330. char    NewFile[] =    "/tmp/PhNewMailXXXXXXX";
  331.  
  332. /*
  333.  * The types of nameserver queries to make.
  334.  * N.B., Query() assumes that "name" is the last token in this list.
  335.  * Also be sure to duplicate any extra keywords added to TryList to the
  336.  * query fprintf near the top of Query().
  337.  */
  338. char    *TryList[] =    { "alias", "callsign", "name", CPNULL };
  339.  
  340. /*
  341.  * How to report events: Debug set for stderr messages, Log for syslog.
  342.  * Setting Debug disables fork/execve in ReMail.
  343.  */
  344. int    Debug =        0;
  345. int    Log =        1;
  346.  
  347. /* From address supplied by caller */
  348. char    *From =        CPNULL;
  349.  
  350. char    *usage[] = {
  351.     "usage: %s [-d] [-p] [-s] [-l] [-R] [-i] [-x service] [-f FromAddress] address1 [address2]",
  352.     CPNULL
  353. };
  354.  
  355. #ifdef __STDC__
  356. # include <unistd.h>
  357. # include <stdlib.h>
  358. void ErrorReturn(NADD *, FILE *, char *[]);
  359. void FindFrom(FILE *);
  360. void ReMail(NADD *, FILE *, char *[]);
  361. char * CodeString(int);
  362. FILE * OpenTemp(const char *);
  363. QIR * PickField (QIR *, int);
  364. void Query(NADD *);
  365. int SendQuery(NADD *, const char *, const char *);
  366. void RevQuery(NADD *);
  367. QIR * ReadQI(FILE *);
  368. int FieldValue(const char *);
  369. void GarbageCollect(QIR *);
  370. char * Malloc(unsigned int);
  371. void PrintMsg(FILE *, char *[]);
  372. char * Realloc(char *, unsigned int);
  373. void PrtUsage(int);
  374. void finis();
  375. #else /* !__STDC__ */
  376. # define    const
  377. void ErrorReturn();
  378. void FindFrom();
  379. void ReMail();
  380. char * CodeString();
  381. FILE * OpenTemp();
  382. QIR * PickField ();
  383. void Query();
  384. int SendQuery();
  385. void RevQuery();
  386. QIR * ReadQI();
  387. int FieldValue();
  388. void GarbageCollect();
  389. char * Malloc();
  390. void PrintMsg();
  391. char * Realloc();
  392. void PrtUsage();
  393. void finis();
  394. #endif /* !__STDC__ */
  395. void ContactQI();
  396.  
  397. char    *CopyLeft[] = {
  398.  " Written by Paul Pomes, University of Illinois, Computing Services Office",
  399.  " Copyright (C) 1989 by Paul Pomes and the University of Illinois Board",
  400.  " of Trustees",
  401.  " ",
  402.  " This program is distributed in the hope that it will be useful, but without",
  403.  " any warranty.  No author or distributor accepts responsibility to anyone",
  404.  " for the consequences of using it, no matter how awful, or for whether it",
  405.  " serves any particular purpose or works at all, unless s/he says so in",
  406.  " writing.",
  407.  " ",
  408.  " Everyone is granted permission to copy, modify and redistribute this",
  409.  " program under the following conditions:",
  410.  " ",
  411.  "    Permission is granted to anyone to make or distribute copies of program",
  412.  "    source code, either as received or modified, in any medium, provided",
  413.  "    that all copyright notices, permission and nonwarranty notices are",
  414.  "    preserved, and that the distributor grants the recipient permission for",
  415.  "    further redistribution as permitted by this document, and gives him and",
  416.  "    points out to him an exact copy of this document to inform him of his",
  417.  "    rights.",
  418.  " ",
  419.  "    Permission is granted to distribute this program in compiled or",
  420.  "    executable form under the same conditions applying for source code,",
  421.  "    provided that either",
  422.  " ",
  423.  "    A. it is accompanied by the corresponding machine-readable source code,",
  424.  "       or",
  425.  "    B. it is accompanied by a written offer, with no time limit, to give",
  426.  "       anyone a machine-readable copy of the corresponding source code in",
  427.  "       return for reimbursement of the cost of distribution.  This written",
  428.  "       offer must permit verbatim duplication by anyone.",
  429.  "    C. it is distributed by someone who received only the executable form,",
  430.  "       and is accompanied by a copy of the written offer of source code",
  431.  "       which he received along with it.",
  432.  " ",
  433.  " In other words, you are welcome to use, share and improve this program.",
  434.  " You are forbidden to forbid anyone else to use, share and improve what",
  435.  " you give them.   Help stamp out software-hoarding!",
  436.  " ",
  437.  "UUCP:     {att,iuvax,uunet}!uiucuxc!paul     ICBM: 40 06 47 N / 88 13 35 W",
  438.  "Internet, BITNET: paul@@uxc.cso.uiuc.edu      Phone: 217 333 6262",
  439.  "US Mail:  UofIllinois, CSO, 1304 W Springfield Ave, Urbana, IL  61801-2910",
  440.  CPNULL
  441. };
  442.  
  443. main(argc, argv, envp)
  444. int    argc;
  445. char    *argv[], *envp[];
  446. {
  447.     extern    int    optind;        /* from getopt () */
  448.     extern    char    *optarg;    /* from getopt () */
  449.         int    option;        /* option "letter" */
  450.         int    i;        /* good ol' i */
  451.         char    *Service = CPNULL; /* ph alias from -x */
  452.         FILE    *Msg;        /* stream pointer for temp file */
  453.         NADD    *New, *NewP;    /* translated addresses */
  454.         char    Buf[MAXSTR];
  455.     extern    char    HostNameBuf[];
  456.  
  457.     MyName = ((MyName = rindex (*argv, '/')) == CPNULL)
  458.         ? *argv : (MyName + 1);
  459.  
  460.     while ((option = getopt (argc, argv, "f:r:x:pRsdli")) != EOF) {
  461.         switch (option) {
  462.             case 'f':
  463.             From = optarg;
  464.             break;
  465.  
  466.             case 'x':
  467.             Service = optarg;
  468.             break;
  469.  
  470.             case 'R':
  471.             /* Re-write outgoing address with Reply-To: field */
  472.             ReplyTo++;
  473.             break;
  474.  
  475.             case 's':
  476.             /* Designated humor section for humor-less CSO types */
  477.             if (Debug) {
  478.                 fprintf (stderr, "Checking Figure 1 ......");
  479.                 (void) fflush (stderr);
  480.                 sleep (2);
  481.                 fprintf (stderr, "done.\n");
  482.             }
  483.             break;
  484.  
  485.             case 'r':
  486.             From = optarg;
  487.             break;
  488.  
  489.             case 'p':
  490.             PostmasterCC++;
  491.             break;
  492.  
  493.             case 'l':
  494.             Log++;
  495.             break;
  496.  
  497.             case 'd':
  498.             Debug++;
  499.             if (Debug == 1)
  500.                 PrtUsage (1);
  501.             Log = 0;
  502.             break;
  503.  
  504.             case 'i':
  505.             PrtUsage (1);
  506.             finis ();
  507.             break;
  508.  
  509.             default:
  510.             PrtUsage (0);
  511.             finis ();
  512.             break;
  513.         }
  514.     }
  515.     argc -= optind;            /* skip options */
  516.     argv += optind;
  517.  
  518.     /* Fire up logging, or not, as the flags may be */
  519.     if (Log)
  520. #ifdef LOG_MAIL
  521. # ifndef SYSLOG
  522. #  define    SYSLOG        LOG_MAIL
  523. # endif
  524.         openlog(MyName, LOG_PID, SYSLOG);
  525. #else
  526.         openlog(MyName, LOG_PID);
  527. #endif
  528.  
  529.     if (Log)
  530.         syslog (LOG_DEBUG, "From %s", From);
  531.  
  532.     /* fetch our host name, some use will be found for it.... */
  533.     if (gethostname (HostNameBuf, 100-1) != 0)
  534.         DANGER_WILL_ROBINSON("gethostname")
  535.  
  536.     /* Open the temp file, copy the message into it */
  537.     if ((Msg = OpenTemp (TmpFile)) == FILE_NULL)
  538.         finis ();
  539.     while ((i = fread (Buf, sizeof (char), MAXSTR, stdin)) != 0)
  540.         if (fwrite (Buf, sizeof (char), i, Msg) != i)
  541.             DANGER_WILL_ROBINSON("Msg copy")
  542.     (void) fflush (Msg);
  543.  
  544.     /*
  545.      * Remaining arguments are addresses.  If From == CHNULL,
  546.      * then submission was done locally and return address has
  547.      * to be on the From: line.
  548.      */
  549.     if (From == CPNULL || (From != CPNULL && From == CHNULL))
  550.         FindFrom (Msg);
  551.  
  552.     if (ReplyTo) {
  553.  
  554.         /*
  555.          * Check with QI to see if this person has a email entry.
  556.          * If so add the Resent-From, Reply-To, and Comment fields.
  557.          * Then invoke ReMail with xyzzy appended to the From address
  558.          * so that sendmail won't send it back to us.  If a 
  559.          * Reply-To: field is already present, handle as though no
  560.          * email field was found.
  561.          */
  562.  
  563.         /*
  564.          * Allocate NewAddress structs for from address, to addresses,
  565.          * plus 1 for terminal null.
  566.          */
  567.         New = (NADD *) Malloc ((unsigned) ((argc+2) * sizeof (NADD)));
  568.         (New + argc + 1)->original = CPNULL;
  569.         NewP = New;
  570.         RevQuery (NewP);
  571.         assert (NewP->new != CPNULL);
  572.  
  573.         /* If a single alias was found, append the domain */
  574.         if (abs (NewP->code) == LR_OK) {
  575.             NewP->new =
  576.                 Realloc (NewP->new, (unsigned) (strlen (NewP->new)
  577.                             + strlen (DOMAIN) + 2));
  578.             (void) strcat (NewP->new, "@@");
  579.             (void) strcat (NewP->new, DOMAIN);
  580.         }
  581.  
  582.         /* Add To: addresses to NewP array */
  583.         NewP++;
  584.         while (argc > 0) {
  585.             NewP->original = *argv;
  586.             NewP->new = CPNULL;
  587.             NewP++; argv++; argc--;
  588.         }
  589.  
  590.         /* ReMail will add the new headers and call sendmail */
  591.         ReMail (New, Msg, envp);
  592.  
  593.         /* We done good. */
  594.         ExitStat = EX_OK;
  595.         finis ();
  596.     }
  597.  
  598.     /*
  599.      * If not a ReplyTo ...
  600.      * Allocate NewAddress structs for addresses (or just one if this
  601.      * is a service forward.
  602.      */
  603.     i = (Service == CPNULL) ? argc : 1;
  604.     New = (NADD *) Malloc ((unsigned) ((i+1) * sizeof (NADD)));
  605.     (New + i)->original = CPNULL;
  606.     NewP = New;
  607.  
  608.     if (Service != CPNULL) {
  609.         NewP->original = Service;
  610.         NewP->new = CPNULL;
  611.         Query (NewP);
  612.         assert (NewP->new != CPNULL);
  613.         if (Debug)
  614.             printf ("code %d, %s --> %s\n",
  615.                 NewP->code, NewP->original, NewP->new);
  616.         if (Log)
  617.             syslog (LOG_DEBUG, "%s --> %s",
  618.                 NewP->original, NewP->new);
  619.     }
  620.     else
  621.         /* Loop on addresses in argv building up translation table */
  622.         while (argc > 0) {
  623.             NewP->original = *argv;
  624.             NewP->new = CPNULL;
  625.             Query (NewP);
  626.             assert (NewP->new != CPNULL);
  627.             if (Debug)
  628.                 printf ("code %d, %s --> %s\n",
  629.                     NewP->code, NewP->original, NewP->new);
  630.             if (Log)
  631.                 syslog (LOG_DEBUG, "%s --> %s",
  632.                     NewP->original, NewP->new);
  633.             NewP++; argv++; argc--;
  634.         }
  635.  
  636.     /*
  637.      * Now re-invoke sendmail with the translated addresses.
  638.      * Make one pass for collecting error returns into one message.
  639.      */
  640.     for (NewP = New; NewP->original != CPNULL; NewP++)
  641.         if (abs (NewP->code) != LR_OK) {
  642.             ErrorReturn (NewP, Msg, envp);
  643.             break;
  644.         }
  645.  
  646.     /* Any good addresses? */
  647.     for (NewP = New; NewP->original != CPNULL; NewP++)
  648.         if (abs (NewP->code) == LR_OK) {
  649.             ReMail (NewP, Msg, envp);
  650.             break;
  651.         }
  652.  
  653.     /* exit */
  654.     ExitStat = EX_OK;
  655.     finis ();
  656. }
  657. /*
  658. **  ContactQI -- Connect to the QI server
  659. **
  660. **    Examine the ToQI and FromQI file descriptors.  If NULL, open
  661. **    socket connections to the QI server.  Exits on any error.
  662. **
  663. **    Parameters:
  664. **        none
  665. **
  666. **    Returns:
  667. **        None
  668. **
  669. **    Side Effects:
  670. **        Changes ToQI and FromQI if an open is done.
  671. */
  672.  
  673. void
  674. ContactQI ()
  675. {
  676.         int    sock;        /* our socket */
  677.     struct    sockaddr_in QI;        /* the address of the nameserver */
  678.     struct    servent    *Ns;        /* nameserver service entry */
  679.     struct    hostent    *Host;        /* host entry for nameserver */
  680.         char    *QiHost = QI_HOST; /* Initial Qi server */
  681.     extern    FILE    *ToQI, *FromQI;    /* read/write streams to QI */
  682.  
  683.     /* Already opened... */
  684.     if (ToQI != FILE_NULL && FromQI != FILE_NULL) {
  685.         if (Debug)
  686.             printf("ToQI/FromQI already opened\n");
  687.         return;
  688.     }
  689.     if (Debug)
  690.         printf("opening ToQI/FromQI\n");
  691.  
  692.     /* Locate the proper port */
  693.     if (Ns = getservbyname (QISERVICE, "tcp")) {
  694.         QI.sin_port = Ns->s_port;
  695.     } else {
  696.         if (Debug)
  697.             fprintf (stderr, "server \"%s\" unknown - using 105", QISERVICE);
  698.         if (Log)
  699.             syslog (LOG_ERR, "server \"%s\" unknown - using 105", QISERVICE);
  700.         QI.sin_port = 105;
  701.     }
  702.     QI.sin_family = AF_INET;
  703.  
  704. again:
  705.     /* Get a socket for the QI connection */
  706.     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  707.     {
  708.         if (Log)
  709.             syslog (LOG_ERR, "ContactQI: socket(): %m");
  710.         if (Debug)
  711.             fprintf (stderr, "ContactQI: can't create socket");
  712.         finis();
  713.     }
  714.  
  715.     /* Locate the proper host */
  716.     if (Host = gethostbyname (QiHost)) {
  717.         bcopy (Host->h_addr, (char *) &QI.sin_addr.s_addr, 4);
  718.     } else {
  719.         if (Log)
  720.             syslog (LOG_ERR, "ContactQI: gethostbyname(%s): %m", QiHost);
  721.         if (Debug) {
  722.             fprintf (stderr, "gethostbyname(%s):", QiHost);
  723.             perror ("");
  724.         }
  725.         finis();
  726.     }
  727.  
  728.     /* Connect to the nameserver */
  729.     if (connect (sock, (struct sockaddr *) &QI, sizeof (QI)) < 0) {
  730.         if (Log)
  731.             syslog (LOG_INFO, "ContactQI: connect(%s): %m", QiHost);
  732.         if (Debug) {
  733.             fprintf (stderr, "ContactQI: connect(%s):", QiHost);
  734.             perror ("");
  735.         }
  736.         (void) close(sock);
  737. #ifdef QI_ALT
  738.         if (!equal (QiHost, QI_ALT)) {
  739.             QiHost = QI_ALT;
  740.             goto again;
  741.         }
  742. #endif /* QI_ALT */
  743.         finis ();
  744.     }
  745.  
  746.     /* Connection ok, change to canonical form */
  747.     ToQI = fdopen (sock, "w");
  748.     FromQI = fdopen (sock, "r");
  749.     return;
  750. }
  751. /*
  752. **  ErrorReturn -- Create and send informative mail messages
  753. **
  754. **    The envelope from address should be set to null as per RFC-821
  755. **    in regard to notification messages (Section 3.6).
  756. **
  757. **    Parameters:
  758. **        Addr -- pointer to NewAddress structure with addresses
  759. **            and messages
  760. **        Omsg -- stream pointer to original message
  761. **        envp -- environment pointer for fork/execve
  762. **
  763. **    Returns:
  764. **        Nothing
  765. **
  766. **    Side Effects:
  767. **        None
  768. */
  769.  
  770. char    *ap[] = { "-sendmail", "-f", "MAILER-DAEMON", "-t", 0};
  771.  
  772. void
  773. ErrorReturn (Addr, Omsg, envp)
  774.     NADD    *Addr;
  775.     FILE    *Omsg;
  776.     char    *envp[];
  777. {
  778.         int    i;            /* Good ol' i */
  779.         char    Buf[MAXSTR];        /* Temp for copying msg test */
  780.         FILE    *Emsg;            /* For creating the error msg */
  781.         int    pid;            /* For fork() */
  782.         int    flags = 0;        /* Controls printing of msgs */
  783.         int    SubCode;        /* Printing control */
  784.         NADD    *AddrP;            /* Loop variable */
  785.         QIR    *QIp;            /* Another loop variable */
  786.     extern    char    *ap[];
  787.  
  788.     /* Open the error file */
  789.     if ((Emsg = OpenTemp (ErrorFile)) == FILE_NULL)
  790.         finis ();
  791.     
  792.     /* Insert the headers */
  793.     if (fprintf (Emsg, "To: %s\n", From) < 0)
  794.         finis ();
  795.     if (PostmasterCC)
  796.         fprintf (Emsg, "Cc: Postmaster\n");
  797.     fprintf (Emsg, "Subject: Returned mail - nameserver error report\n\n");
  798.     fprintf (Emsg, " --------Message not delivered to the following:\n\n");
  799.     for (AddrP = Addr; AddrP->original != CPNULL; AddrP++)
  800.         if (abs (AddrP->code) != LR_OK)
  801.             fprintf (Emsg, " %15s    %s\n", AddrP->original, AddrP->new);
  802.     fprintf (Emsg, "\n --------Error Detail (phquery V%s):\n\n", VERSION);
  803.  
  804.     /* Loop again to insert messages */
  805.     for (AddrP = Addr; AddrP->original != CPNULL; AddrP++)
  806.         if (abs (AddrP->code) == LR_NOMATCH) {
  807.             if (! (flags & NO_MATCH_MSG)) {
  808.                 PrintMsg (Emsg, NoMatchMsg);
  809.                 flags |= NO_MATCH_MSG;
  810.                 break;
  811.             }
  812.         }
  813.     for (AddrP = Addr; AddrP->original != CPNULL; AddrP++)
  814.         if (abs (AddrP->code) == LR_ABSENT) {
  815.             if (! (flags & ABSENT_MSG)) {
  816.                 PrintMsg (Emsg, AbsentMsg);
  817.                 flags |= ABSENT_MSG;
  818.                     if (! (flags & PHONE_MSG)) {
  819.                         PrintMsg (Emsg, PhoneMsg);
  820.                         flags |= PHONE_MSG;
  821.                     }
  822.             }
  823.             for (QIp = AddrP->QIalt; QIp->code < 0; QIp++)
  824.                 if (abs (QIp->code) == LR_OK)
  825.                     fprintf (Emsg, " %s: %s\n",
  826.                         Fields[QIp->field].value, QIp->message);
  827.             (void) putc ('\n', Emsg);
  828.         }
  829.     for (AddrP = Addr; AddrP->original != CPNULL; AddrP++)
  830.         if (abs (AddrP->code) == LR_TOOMANY) {
  831.             if (! (flags & TOO_MANY_MSG)) {
  832.                 PrintMsg (Emsg, TooManyMsg);
  833.                 flags |= TOO_MANY_MSG;
  834.                 break;
  835.             }
  836.         }
  837.     for (AddrP = Addr; AddrP->original != CPNULL; AddrP++)
  838.         if (abs (AddrP->code) == LR_AMBIGUOUS) {
  839.             if (! (flags & MULTI_MSG)) {
  840.                 PrintMsg (Emsg, MultiMsg);
  841.                 flags |= MULTI_MSG;
  842.                     if (! (flags & PHONE_MSG)) {
  843.                         PrintMsg (Emsg, PhoneMsg);
  844.                         flags |= PHONE_MSG;
  845.                     }
  846.             }
  847.             for (QIp = AddrP->QIalt, SubCode = QIp->subcode;
  848.                 QIp->code < 0; QIp++) {
  849.                 if (QIp->subcode != SubCode) {
  850.                     SubCode = QIp->subcode;
  851.                     (void) putc ('\n', Emsg);
  852.                 }
  853.                 if (abs (QIp->code) == LR_OK)
  854.                     fprintf (Emsg, " %s: %s\n",
  855.                         Fields[QIp->field].value, QIp->message);
  856.             }
  857.             (void) putc ('\n', Emsg);
  858.         }
  859.     fprintf (Emsg, "\n --------Unsent Message below:\n\n");
  860.     rewind (Omsg);
  861.     while ((i = fread (Buf, sizeof (char), MAXSTR, Omsg)) != 0) {
  862.         if (fwrite (Buf, sizeof (char), i, Emsg) != i)
  863.             DANGER_WILL_ROBINSON("ErrorReturn: Emsg copy")
  864.     }
  865.     fprintf (Emsg, "\n --------End of Unsent Message\n");
  866.     (void) fflush (Emsg);
  867.     (void) fclose (Emsg);
  868.     if (freopen (ErrorFile, "r", stdin) == FILE_NULL)
  869.         DANGER_WILL_ROBINSON("ErrorReturn: ErrorFile freopen")
  870.  
  871.     /* Zap file so it disappears automagically */
  872.     if (! Debug)
  873.         (void) unlink (ErrorFile);
  874.  
  875.     /*
  876.      * fork, then execve sendmail for delivery
  877.      */
  878.  
  879.     pid = 0;
  880.     if (! Debug && (pid = fork ()) == -1)
  881.         DANGER_WILL_ROBINSON("ErrorReturn: fork")
  882.     if (pid) {
  883.         (void) wait(0);
  884.         return;
  885.     }
  886.     else if (! Debug)
  887.         execve (SENDMAIL, ap, envp);
  888. }
  889. /*
  890. **  FindFrom -- Find From: address in message headers
  891. **
  892. **    Parameters:
  893. **        MsgFile -- stream pointer to message
  894. **
  895. **    Returns:
  896. **        Nothing
  897. **
  898. **    Side Effects:
  899. **        Global From pointer is adjusted to point at either a 
  900. **        malloc'ed area containing the address, or to the
  901. **        constant string "Postmaster" if none is found.
  902. */
  903.  
  904. void
  905. FindFrom (MsgFile)
  906.     FILE    *MsgFile;
  907. {
  908.     char        *p1, *p2;
  909.     extern char    *From;
  910.     char        Buf[MAXSTR];
  911.  
  912.     rewind (MsgFile);
  913.     while (fgets (Buf, MAXSTR, MsgFile) != CPNULL && *Buf != '\n') {
  914.         if (strncasecmp (Buf, "From:", 5))
  915.             continue;
  916.         else {
  917.             if ((p1 = index (Buf, '<')) != CPNULL) {
  918.                 p1++;
  919.                 if ((p2 = index (Buf, '>')) != CPNULL) {
  920.                     From = Malloc ((unsigned) ((p2-p1)+1));
  921.                     (void) strncpy (From, p1, (p2-p1));
  922.                 }
  923.                 else {
  924.                     if (Debug)
  925.                         fprintf (stderr, "Unbalanced <> in From: address\n");
  926.                     if (Log)
  927.                         syslog (LOG_ERR, "Unbalanced <> in From: address\n");
  928.                     From = "Postmaster";
  929.                 }
  930.             }
  931.             else {
  932.                 /*
  933.                  * Punt to postmaster.  If there's too
  934.                  * many, I'll fix this someday.
  935.                  */
  936.                 if (Debug)
  937.                     fprintf (stderr, "No <> in From: address\n");
  938.                 if (Log)
  939.                     syslog (LOG_ERR, "No <> in From: address\n");
  940.                 From = "Postmaster";
  941.             }
  942.             break;
  943.         }
  944.     }
  945.     if (From == CPNULL) {
  946.         if (Debug)
  947.             fprintf (stderr, "No From: address in message\n");
  948.         if (Log)
  949.             syslog (LOG_ERR, "No From: address in message\n");
  950.         From = "Postmaster";
  951.     }
  952. }
  953. /*
  954. **  ReMail -- Forward message to recipients after adding phquery headers
  955. **
  956. **    Parameters:
  957. **        Addr -- pointer to NewAddress structure with addresses
  958. **            and messages
  959. **        Omsg -- stream pointer to original message
  960. **        envp -- environment pointer for fork/execve
  961. **
  962. **    Returns:
  963. **        Nothing
  964. **
  965. **    Side Effects:
  966. **        None
  967. */
  968.  
  969. void
  970. ReMail (Addr, Omsg, envp)
  971.     NADD    *Addr;
  972.     FILE    *Omsg;
  973.     char    *envp[];
  974. {
  975.         int    napi = 0;
  976.         int    i;
  977.         char    Buf[MAXSTR];
  978.         NADD    *AddrP;
  979.         FILE    *Nmsg;
  980.         int    pid = 0;
  981.         char    *nap[50], nFrom[100];
  982.     extern    char    *From, HostNameBuf[];
  983.     extern    int    ReplyTo;
  984.  
  985.     /* Open the rewrite file */
  986.     if ((Nmsg = OpenTemp (NewFile)) == FILE_NULL)
  987.         finis ();
  988.  
  989.     /* Fill out the first portion of the sendmail argument vector */
  990.     nap[napi++] = "-sendmail";
  991.     nap[napi++] = "-f";
  992.     if (ReplyTo == 0)
  993.         nap[napi++] = From;
  994.         for (AddrP = Addr; AddrP->original != CPNULL; AddrP++)
  995.             if (abs (AddrP->code) == LR_OK)
  996.                 nap[napi++] = AddrP->new;
  997.     else {
  998.         /*
  999.          * Tack on .xyzzy to the From address so sendmail will know
  1000.          * it's been here.
  1001.          */
  1002.         (void) strcpy (nFrom, From);
  1003.         (void) strcat (nFrom, ".xyzzy");
  1004.         nap[napi++] = nFrom;
  1005.     }
  1006.  
  1007.     /* Read and copy the header block, adding X-PH-To: or X-PH: header */
  1008.     rewind (Omsg);
  1009.     while (fgets (Buf, MAXSTR, Omsg) != CPNULL && *Buf != '\n') {
  1010.         if ((nequal (Buf, "To:", 3) || nequal (Buf, "Cc:", 3)
  1011.             || nequal (Buf, "From:", 5)) && pid == 0) {
  1012.             int    LineLength;
  1013.  
  1014.             if (ReplyTo == 0) {
  1015.  
  1016.                 /* Write the PH header and add to argv */
  1017. #ifdef    EXPAND_TO
  1018.                 if (fprintf (Nmsg, "X-PH(%s)-To:", VERSION) < 0)
  1019.                     finis ();
  1020.                 LineLength = 8;
  1021.                 for (AddrP = Addr; AddrP->original != CPNULL; AddrP++)
  1022.                     if (abs (AddrP->code) == LR_OK) {
  1023.                         if ((LineLength + strlen (AddrP->new)) > 75) {
  1024.                             fprintf (Nmsg, "\n\t");
  1025.                             LineLength = 8;
  1026.                         }
  1027.                         fprintf (Nmsg, " %s", AddrP->new);
  1028.                     }
  1029.                 (void) putc ('\n', Nmsg);
  1030. #else /* ! EXPAND_TO */
  1031.                 fprintf (Nmsg, "X-PH: V%s@@%s\n", VERSION, HostNameBuf);
  1032. #endif /* EXPAND_TO */
  1033.                 pid++;
  1034.             }
  1035.             else if (ReplyTo == 1) {
  1036.  
  1037.                 /* Add the Reply-To: fields */
  1038.                 AddrP = Addr;
  1039.                 if (fprintf (Nmsg, "Comment: Reply-To: added by phquery (V%s)\n", VERSION) < 0)
  1040.                     finis ();
  1041.                 fprintf (Nmsg, "Resent-From: postmaster@@%s\n", HostNameBuf);
  1042.                 fprintf (Nmsg, "Reply-To: %s\n", AddrP->new);
  1043.                 AddrP++;
  1044.                 for (; AddrP->original != CPNULL; AddrP++)
  1045.                     nap[napi++] = AddrP->original;
  1046.                 pid++;
  1047.             }
  1048.         }
  1049.         fputs (Buf, Nmsg);
  1050.     }
  1051.     (void) fputs (Buf, Nmsg);
  1052.     nap[napi] = CPNULL;
  1053.  
  1054.     if (Debug) {
  1055.         printf ("Final send vector:");
  1056.         for (i = 0; nap[i] != CPNULL; i++)
  1057.             printf (" %s", nap[i]);
  1058.         (void) putchar ('\n');
  1059.     }
  1060.  
  1061.     /* Copy the remainder of the message */
  1062.     while ((i = fread (Buf, sizeof (char), MAXSTR, Omsg)) != 0)
  1063.         if (fwrite (Buf, sizeof (char), i, Nmsg) != i)
  1064.             DANGER_WILL_ROBINSON("ReMail: nmsg copy")
  1065.  
  1066.     /* Re-arrange the stream pointers and invoke sendmail */
  1067.     (void) fflush (Nmsg);
  1068.     (void) fclose (Nmsg);
  1069.     if (freopen (NewFile, "r", stdin) == FILE_NULL)
  1070.         DANGER_WILL_ROBINSON("ReMail: NewFile freopen")
  1071.  
  1072.     /* Zap file so it disappears automagically */
  1073.     if (! Debug)
  1074.         (void) unlink (NewFile);
  1075.  
  1076.     /*
  1077.      * fork, then execve sendmail for delivery
  1078.      */
  1079.  
  1080.     pid = 0;
  1081.     if (! Debug && (pid = fork ()) == -1)
  1082.         DANGER_WILL_ROBINSON("ReMail: fork")
  1083.     if (pid) {
  1084.         (void) wait(0);
  1085.         return;
  1086.     }
  1087.     else if (! Debug)
  1088.         execve (SENDMAIL, nap, envp);
  1089. }
  1090. /*
  1091. **  CodeString -- Return text string corresponding to supplied reply code
  1092. **
  1093. **    Parameters:
  1094. **        code -- reply value
  1095. **
  1096. **    Returns:
  1097. **        char pointer to text string or NULL pointer if no matching
  1098. **        key is located.
  1099. **
  1100. **    Side Effects:
  1101. **        None
  1102. */
  1103.  
  1104. char *
  1105. CodeString (code)
  1106.     int    code;
  1107. {
  1108.     struct    ReplyCodes        *Cpnt;
  1109.     extern    struct ReplyCodes    Codes[];
  1110.  
  1111.     for (Cpnt = Codes; Cpnt->key != -1; Cpnt++)
  1112.         if (Cpnt->key == abs (code))
  1113.             return (Cpnt->value);
  1114.     return (CPNULL);
  1115. }
  1116. /*
  1117. **  OpenTemp -- Create and open a temporary file
  1118. **
  1119. **    For the supplied file name, create, open, and chmod the file
  1120. **
  1121. **    Parameters:
  1122. **        Name -- pathname of file to create in mkstemp format
  1123. **
  1124. **    Returns:
  1125. **        Stream descriptor of resulting file, or NULL if error
  1126. **
  1127. **    Side Effects:
  1128. **        mkstemp modifies calling argument
  1129. */
  1130.  
  1131. FILE *
  1132. OpenTemp (Name)
  1133.     const char *Name;
  1134. {
  1135.     int    fd;
  1136.     FILE    *Stream;
  1137.  
  1138.     if ((fd = mkstemp (Name)) == -1)
  1139.         DANGER_WILL_ROBINSON("OpenTemp: mkstemp")
  1140.  
  1141.     /* Protect it */
  1142.     if (fchmod (fd, IREAD|IWRITE) == -1)
  1143.         DANGER_WILL_ROBINSON("OpenTemp: fchmod")
  1144.  
  1145.     /* Make fd a stream */
  1146.     if ((Stream = fdopen (fd, "r+")) == FILE_NULL)
  1147.         DANGER_WILL_ROBINSON("OpenTemp: fdopen")
  1148.     return (Stream);
  1149. }
  1150. /*
  1151. **  PickField -- Find the QI_response with the named field
  1152. **
  1153. **    Cycle through a chain of QI_response's looking for one with the
  1154. **    named field.  Return a pointer to that one or NULL if not present.
  1155. **    Assumes that the last QI_response.code > 0.
  1156. **
  1157. **    Parameters:
  1158. **        qp -- QI_response chain pointer
  1159. **        field -- QI field to search for
  1160. **
  1161. **    Returns:
  1162. **        pointer to located QI_response or NULL if not found
  1163. **
  1164. **    Side Effects:
  1165. **        None
  1166. */
  1167.  
  1168. QIR *
  1169. PickField (qp, field)
  1170.     QIR    *qp;
  1171.     int    field;
  1172. {
  1173.     do {
  1174.         if (qp->field == field)
  1175.             return (qp);
  1176.     } while ((qp++)->code < 0);
  1177.     return (QIR_NULL);
  1178. }
  1179. /*
  1180. **  Query -- Create queries to send to the CSnet central server
  1181. **
  1182. **    Using the alias, call-sign, and full name fields, as known by the
  1183. **    CSnet central name server Query Interpreter, Query creates variants
  1184. **    of the supplied name (New->original) if a straight alias lookup fails.
  1185. **    For each variant, SendQuery() is called until either one succeeds or
  1186. **    all variants are exhausted.
  1187. **
  1188. **    Parameters:
  1189. **        New -- pointer to NewAddress struct
  1190. **
  1191. **    Returns:
  1192. **        None
  1193. **
  1194. **    Side Effects:
  1195. **        Modifies contents under New pointer.
  1196. */
  1197.  
  1198. void
  1199. Query(New)
  1200.     NADD    *New;
  1201. {
  1202.     char    scratch[MAXSTR];    /* copy of FullName w.o. punct */
  1203.     char    *sp;            /* work ptrs for scratch */
  1204. #ifdef    WILDNAMES
  1205.     char    *sp2;            /* work ptrs for scratch */
  1206. #endif /* WILDNAMES */
  1207.     char    **Lpnt = TryList;    /* Loop pointer for TryList */
  1208.     int    NoMore = -1;        /* set if all name variants done */
  1209.  
  1210.     /*
  1211.      * Try the query as an alias lookup first, then as a full name lookup.
  1212.      */
  1213.  
  1214.     do {
  1215.         /*
  1216.          * Convert punctuation/separators in scratch to space
  1217.          * characters one at a time if testing for name.  If
  1218.          * WILDNAMES is #define'd, a wildcard char '*' will be
  1219.          * appended after each single character name, e.g. p-pomes
  1220.          * is tried as p* pomes.  This has risks as follows:  assume
  1221.          * Duncan Lawrie sets his alias to "lawrie".  A query for
  1222.          * d-lawrie will fail as a alias lookup but succeed as a
  1223.          * name lookup when written as "d* lawrie".  This works until
  1224.          * Joe Student sets his alias to "d-lawrie".  Whoops.
  1225.          * Still in a non-hostile environment, this function may be
  1226.          * more useful than dangerous.
  1227.          */
  1228.         if (equal (*Lpnt, "name")) {
  1229.  
  1230.             /* Try as is first time for hyphenated names */
  1231.             if (NoMore == -1) {
  1232.                 (void) strcpy (scratch, New->original);
  1233.                 if (SendQuery (New, *Lpnt, scratch))
  1234.                     return;
  1235.                 NoMore = 0;
  1236.             }
  1237.             else {
  1238.                 char stemp[MAXSTR], *st = stemp;
  1239.  
  1240.                 for (sp = scratch; *sp != CHNULL; ) {
  1241.  
  1242.                     /* copy until non-space punct char */
  1243.                     if (!ispunct (*sp) || *sp == ' ' || *sp == '*') {
  1244. #ifdef    WILDNAMES
  1245.                         sp2 = sp;
  1246. #endif /* WILDNAMES */
  1247.                         *st++ = *sp++;
  1248.                         if (*sp == CHNULL)
  1249.                             NoMore++;
  1250.                         continue;
  1251.                     }
  1252.  
  1253. #ifdef    WILDNAMES
  1254.                     /* if one non-punct char, append * */
  1255.                     if ((sp - sp2) == 1)
  1256.                         *st++ = '*';
  1257. #endif /* WILDNAMES */
  1258.                     *st++ = ' ';
  1259.                     sp++;
  1260.                     break;
  1261.                 }
  1262.                 while (*sp != CHNULL)
  1263.                     *st++ = *sp++;
  1264.                 *st = CHNULL;
  1265.                 (void) strcpy (scratch, stemp);
  1266.                 if (SendQuery (New, *Lpnt, scratch))
  1267.                     return;
  1268.                 if (NoMore > 0)
  1269.                     Lpnt++;
  1270.                 continue;
  1271.             }
  1272.         }
  1273.  
  1274.         /*
  1275.          * Convert punctuation/separators in scratch to hyphen
  1276.          * characters if testing for alias.
  1277.          */
  1278.         else if (equal (*Lpnt, "alias")) {
  1279.             (void) strcpy (scratch, New->original);
  1280.             for (sp = scratch; *sp != CHNULL; sp++)
  1281.                 if (ispunct(*sp))
  1282.                     *sp = '-';
  1283.             if (SendQuery (New, *Lpnt, scratch))
  1284.                 return;
  1285.             Lpnt++;
  1286.         }
  1287.         else {
  1288.             (void) strcpy (scratch, New->original);
  1289.             if (SendQuery (New, *Lpnt, scratch))
  1290.                 return;
  1291.             Lpnt++;
  1292.         }
  1293.     } while (*Lpnt != CPNULL);
  1294. }
  1295. /*
  1296. **  SendQuery -- Send queries to the local CSnet central name server
  1297. **
  1298. **    Takes a field type (alias, call-sign, full name, etc), as known by
  1299. **    the CSnet central name server Query Interpreter, and looks up the
  1300. **    corresponding email address "usercode@@host".  Cases where the
  1301. **    alias/name aren't found, are ambiguous, or lack an email address
  1302. **    return a message instead of the address.  Additional information is
  1303. **    returned as an array of QIR records pointed to by New->QIalt.
  1304. **
  1305. **    Parameters:
  1306. **        New -- pointer to NewAddress struct
  1307. **        Field -- type of field (name, alias, etc) for Value
  1308. **        Value -- name to lookup
  1309. **
  1310. **    Returns:
  1311. **        1 if a match(es) is found including too many
  1312. **        0 otherwise 
  1313. **
  1314. **    Side Effects:
  1315. **        Will call ContactQI() if the connection is closed.
  1316. **        Modifies contents under New pointer.
  1317. */
  1318.  
  1319. SendQuery(New, Field, Value)
  1320.     NADD    *New;
  1321.     const char *Field, *Value;
  1322. {
  1323.     QIR    *EmailQ, *QIp;    /* For handling ReadQI() responses */
  1324.     int    i;        /* good ol' i */
  1325.  
  1326.     /* Open the ToQI and FromQI descriptors if necessary */
  1327.     ContactQI();
  1328.  
  1329.     /* Make a query out of the arguments */
  1330.     fprintf (ToQI,
  1331.         "query %s=%s return name alias callsign phone department curriculum email\n",
  1332.         Field, Value);
  1333.     if (Debug)
  1334.         printf ("querying for %s \"%s\"\n", Field, Value);
  1335.     if (Log)
  1336.         syslog (LOG_DEBUG, "querying for %s \"%s\"\n",
  1337.             Field, Value);
  1338.     (void) fflush (ToQI);
  1339.     
  1340.     /*
  1341.      * Grab the responses and let the fun begin.
  1342.      * The possibilities are:
  1343.      *
  1344.      * 102:There were N matches to your query
  1345.      * -200:1:         alias: Paul-Pomes
  1346.      * -200:1:          name: pomes paul b
  1347.      * -200:1:      callsign: See Figure 1
  1348.      * -508:1:    curriculum: Not present in entry.
  1349.      * -200:1:    department: Computing Services Office
  1350.      * -200:1:         email: paul@@uxc.cso.uiuc.edu
  1351.      * 200:Ok.
  1352.      *
  1353.      * 501:No matches to your query.
  1354.      *
  1355.      * 502:Too many matches to request.
  1356.      */
  1357.     EmailQ = ReadQI (FromQI);
  1358.  
  1359.     /*
  1360.      * If we read a preliminary response (99<x<200), garbage
  1361.      * collect and read some more.
  1362.      */
  1363.     i = abs (EmailQ->code);
  1364.     if (i > 99 && i < 200) {
  1365.         GarbageCollect (EmailQ);
  1366.         EmailQ = ReadQI (FromQI);
  1367.     }
  1368.  
  1369.     /*
  1370.      * If we read a temporary error, be a nice program and defer.
  1371.      */
  1372.     else if (i > 399 && i < 500)
  1373.         finis ();
  1374.  
  1375.     /*
  1376.      * No matches at all?  Too many?  Note that single line errors
  1377.      * will have code > 0.
  1378.      */
  1379.     if (EmailQ->code > 0) {
  1380.         New->new = CodeString (EmailQ->code);
  1381.         New->code = EmailQ->code;
  1382.         New->QIalt = QIR_NULL;
  1383.         GarbageCollect (EmailQ);
  1384.         if (New->code == LR_TOOMANY)
  1385.             return (1);
  1386.         return (0);
  1387.     }
  1388.  
  1389.     /* anything else must be multi-line */
  1390.     assert (EmailQ->code < 0);
  1391.  
  1392.     /* Are there multiple responses (subcode > 1)? */
  1393.     for (QIp = EmailQ; QIp->code < 0; QIp++)
  1394.         if (QIp->subcode > 1) {
  1395.             New->code = LR_AMBIGUOUS;
  1396.             New->new = CodeString (LR_AMBIGUOUS);
  1397.             New->QIalt = EmailQ;
  1398.             return (1);
  1399.         }
  1400.  
  1401.     /* If one person, handle as single match alias */
  1402.     QIp = PickField (EmailQ, EMAIL);
  1403.     if (QIp->field != EMAIL) {
  1404.         if (Log)
  1405.             syslog (LOG_ERR, "Email field for %s (%s) in ph/qi database is present but null",
  1406.                 Value, Field);
  1407.         if (Debug)
  1408.             fprintf (stderr, "Email field for %s (%s) in ph/qi database is present but null",
  1409.                 Value, Field);
  1410.         New->code = LR_ABSENT;
  1411.         New->new = CodeString (LR_ABSENT);
  1412.         return (1);
  1413.     }
  1414.     New->code = abs (QIp->code);
  1415.     New->QIalt = EmailQ;
  1416.     switch (abs (QIp->code)) {
  1417.         case LR_ABSENT:
  1418.         New->new = CodeString (QIp->code);
  1419.         return (1);
  1420.  
  1421.         case LR_OK:
  1422.         New->new = QIp->message;
  1423.         return (1);
  1424.  
  1425.         default:
  1426.         if (Debug)
  1427.             fprintf (stderr, "unexpected code %d\n",
  1428.                 QIp->code);
  1429.         if (Log)
  1430.             syslog (LOG_ERR, "Query: %s: unexpected code %d", Field, QIp->code);
  1431.         finis ();
  1432.     }
  1433.     GarbageCollect (EmailQ);
  1434.     return (0);
  1435. }
  1436. /*
  1437. **  RevQuery -- Reverse query, email to ph alias
  1438. **
  1439. **    Takes a email address as known by the CSnet central name server
  1440. **    Query Interpreter, and looks up the corresponding alias. Cases
  1441. **    where the email address matches multiple aliases return the
  1442. **    original address.  In addition the global variable ReplyTo is
  1443. **    set to -1.
  1444. **
  1445. **    Parameters:
  1446. **        New -- pointer to NewAddress struct
  1447. **
  1448. **    Returns:
  1449. **        None
  1450. **
  1451. **    Side Effects:
  1452. **        Will call ContactQI() if the connection is closed.
  1453. **        Modifies contents under New pointer.
  1454. **        ReplyTo set to -1 if QI returns multiple aliases or
  1455. **        no match.
  1456. */
  1457.  
  1458. void
  1459. RevQuery(New)
  1460.     NADD    *New;
  1461. {
  1462.         int    i;
  1463.         QIR    *AliasQ, *QIp;
  1464.     extern    int    ReplyTo;
  1465.     extern    char    *From, HostNameBuf[];
  1466.     extern    FILE    *ToQI, *FromQI;
  1467.  
  1468.     /* Open the ToQI and FromQI descriptors if necessary */
  1469.     ContactQI();
  1470.  
  1471.     /*
  1472.      * We have to have a from address here.  If it doesn't have
  1473.      * a fully qualified form, convert it to name@@domain by
  1474.      * appending our Fully Qualified Domain Name.  FQDN, the
  1475.      * litany of the new Internet Age.
  1476.      */
  1477.     
  1478.     assert (From != CPNULL);
  1479.     if (index (From, '@@') == CPNULL) {
  1480.         char    *nFrom;
  1481.  
  1482.         /*
  1483.          * We can't Realloc(From) since it may point to
  1484.          * an area on the stack.
  1485.          */
  1486.         nFrom = Malloc ((unsigned)(strlen (From) + 1));
  1487.         (void) strcpy (nFrom, From);
  1488.         From = Realloc (nFrom, (unsigned)(strlen(nFrom) +
  1489.                        strlen(HostNameBuf) + 5));
  1490.         (void) strcat (From, "@@");
  1491.         (void) strcat (From, HostNameBuf);
  1492.     }
  1493.     New->original = From;
  1494.  
  1495.     /* Send the query 
  1496.      * I'd check for a -1 here, but am unsure how network errors really
  1497.      * are manifested.
  1498.      */
  1499.     fprintf (ToQI, "query email=%s return alias \n", From);
  1500.     if (Debug)
  1501.         printf ("querying alias corresponding to \"%s\"\n", From);
  1502.     if (Log)
  1503.         syslog (LOG_DEBUG, "querying alias for \"%s\"\n", From);
  1504.     (void) fflush (ToQI);
  1505.  
  1506.     /*
  1507.      * Grab the responses and let the fun begin.
  1508.      * The possibilities are:
  1509.      *
  1510.      * 102:There was N matches to your query.
  1511.      *
  1512.      * -200:1:         alias: rrv
  1513.      * 200:Ok.
  1514.      *
  1515.      * -200:1:         alias: Paul-Pomes
  1516.      * -200:2:         alias: PostMaster
  1517.      * 200:Ok.
  1518.      *
  1519.      * 501:No matches to your query.
  1520.      *
  1521.      * 502:Too many matches to request.
  1522.      *
  1523.      * For anything other than the first case, set ReplyTo to -1 and
  1524.      * set New->new = New->original .
  1525.      */
  1526.     AliasQ = ReadQI (FromQI);
  1527.  
  1528.     /*
  1529.      * If we read a preliminary response (99<x<200), garbage
  1530.      * collect and read some more.
  1531.      */
  1532.     i = abs (AliasQ->code);
  1533.     if (i > 99 && i < 200) {
  1534.         GarbageCollect (AliasQ);
  1535.         AliasQ = ReadQI (FromQI);
  1536.     }
  1537.  
  1538.     /* Handle the 501, 502 codes */
  1539.     if (AliasQ->code > 0) {
  1540.         ReplyTo = -1;
  1541.         New->new = New->original;
  1542.         GarbageCollect (AliasQ);
  1543.         return;
  1544.     }
  1545.  
  1546.     /* Are there multiple responses (subcode > 1)? */
  1547.     for (QIp = AliasQ; QIp->code < 0; QIp++)
  1548.         if (QIp->subcode > 1) {
  1549.             ReplyTo = -1;
  1550.             New->new = New->original;
  1551.             GarbageCollect (AliasQ);
  1552.             return;
  1553.         }
  1554.     
  1555.     QIp = AliasQ;
  1556.     assert (abs (QIp->code) == LR_OK && QIp->field == ALIAS);
  1557.     New->code = abs (QIp->code);
  1558.     New->new = QIp->message;
  1559.     return;
  1560. }
  1561. /*
  1562. **  ReadQI -- Read and store response from QI server
  1563. **
  1564. **    A QI response has one of the following structures:
  1565. **
  1566. **    <-><code>:<subcode><ws><field name>:<string>
  1567. **    5XX:Error message
  1568. **    200:Ok.
  1569. **
  1570. **    The leading '-' marks a continuation line.  The last line of a
  1571. **    response will not have the '-'.
  1572. **
  1573. **    <code> is the response code.  Response codes are listed in phquery.h
  1574. **    and closely follow the conventions of SMTP (RFC-821):
  1575. **
  1576. **    1XX - status
  1577. **    2XX - information
  1578. **    3XX - additional information or action needed
  1579. **    4XX - temporary errors
  1580. **    5XX - permanent errors
  1581. **    6XX - phquery specific codes
  1582. **
  1583. **    <subcode> links multiple fields (e.g., email and pager) to a single
  1584. **    individual.  If a name query results in a multiple match, subcode
  1585. **    increments by 1 for each person but has the same value for all response
  1586. **    lines for that individual.
  1587. **
  1588. **    <ws> is sufficient white space to right adjust <field name>: to the
  1589. **    same position on each line.
  1590. **
  1591. **    <field name> is one of the field type in phquery.h (e.g., department,
  1592. **    mailcode, etc).
  1593. **
  1594. **    <string> is either the value for <field name>, if <code> == 200 (LR_OK),
  1595. **    or an error message it <code> is anything else.
  1596. **
  1597. **    Parameters:
  1598. **        InFile - stream pointer for input
  1599. **
  1600. **    Returns:
  1601. **        A pointer to a malloc()'ed block of QI_response structs that
  1602. **        is terminated with QI_response.code > 0.
  1603. **
  1604. **    Side Effects:
  1605. **        Creates a block of data that must be later free()'d.
  1606. **        Advances FromQI.
  1607. */
  1608.  
  1609. QIR *
  1610. ReadQI (InFile)
  1611.     FILE    *InFile;
  1612. {
  1613.         int    i, code;
  1614.         int    loopcnt = 1;
  1615.         char    *tp;
  1616.         unsigned size = sizeof (QIR);
  1617.         char    fstring[MAXSTR];    /* field string */
  1618.         char    message[MAXSTR];    /* field value */
  1619.         char    Temp[MAXSTR];
  1620.     register QIR    *Base, *RepChain;
  1621.  
  1622.     Base = RepChain = (QIR *) Malloc (size);
  1623.     RepChain->field = -1;
  1624.     Base->message = CPNULL;
  1625.     do {
  1626.         *fstring = *message = CHNULL;
  1627.         if (fgets (Temp, MAXSTR-1, InFile) == CPNULL) {
  1628.             if (Debug)
  1629.                 fprintf (stderr, "premature EOF\n");
  1630.             if (Log)
  1631.                 syslog (LOG_ERR, "ReadQI: premature EOF");
  1632.             finis ();
  1633.         }
  1634.         if (Debug > 1)
  1635.             printf ("ReadQI read =%s=\n", Temp);
  1636.         code = atoi (Temp);
  1637.  
  1638.         /* Positive response codes are formatted "<code>:<message>" */
  1639.         if (code > 0) {
  1640.             RepChain->subcode = NONE_OF_ABOVE;
  1641.             if (sscanf (Temp, "%d:%[^\n]", &RepChain->code, message)
  1642.                 != 2 || *message == CHNULL) {
  1643.                 if (Debug)
  1644.                     fprintf (stderr, "ReadQI: short #1 sscanf\n");
  1645.                 if (Log)
  1646.                     syslog (LOG_ERR, "ReadQI: short #1 sscanf read: %m");
  1647.                 finis ();
  1648.             }
  1649.         }
  1650.  
  1651.         /* Otherwise they are the 4 field type */
  1652.         else if (( i = sscanf (Temp, "%d:%d:%[^:]: %[^\n]",
  1653.             &RepChain->code, &RepChain->subcode, fstring, message))
  1654.             != 4 || *fstring == CHNULL || *message == CHNULL) {
  1655.             if (Debug)
  1656.                 fprintf (stderr, "ReadQI: short #2 sscanf, expected 4 got %d\n", i);
  1657.             if (Log)
  1658.                 syslog (LOG_ERR, "ReadQI: short #2 sscanf, expected 4 got %d", i);
  1659.  
  1660.             /*
  1661.              * The short sscanf() read may be due to a embedded
  1662.              * newline.  If so, continue for a bit to fill out the
  1663.              * code field before reading another line.
  1664.              */
  1665.             if (!(i == 3 && *message == CHNULL))
  1666.                 finis ();
  1667.         }
  1668.  
  1669.         /*
  1670.          * Some fields go over multiple response lines.  In that case
  1671.          * the field is all blanks.  Copy the response field from the
  1672.          * previous response if not already set.
  1673.          */
  1674.         if (RepChain->field == -1) {
  1675.             for (tp = fstring; tp <= fstring + (MAXSTR-1) &&
  1676.                       *tp == ' '; tp++) ;
  1677.             if (RepChain->code < 0 && *tp == CHNULL)
  1678.                 RepChain->field = (RepChain - 1)->field;
  1679.             else
  1680.                 RepChain->field = FieldValue (tp);
  1681.         }
  1682.  
  1683.         /* Now get a new line if message was empty. */
  1684.         if (*message == CHNULL)
  1685.             continue;
  1686.         RepChain->message = Malloc ((unsigned) (strlen (message) + 1));
  1687.         (void) strcpy (RepChain->message, message);
  1688.         if (RepChain->code > 0)
  1689.             break;
  1690.         size += sizeof (QIR);
  1691.         Base = (QIR *) Realloc ((char *) Base, size);
  1692.         RepChain = Base + loopcnt;
  1693.         RepChain->field = -1;
  1694.     } while (loopcnt++);
  1695.     if (Debug)
  1696.         for (RepChain = Base; RepChain->code < 0; RepChain++)
  1697.             printf ("code %d, subcode %d, field %s, message: %s\n",
  1698.                 RepChain->code,
  1699.                 RepChain->subcode,
  1700.                 Fields[RepChain->field].value,
  1701.                 RepChain->message);
  1702.     return (Base);
  1703. }
  1704. /*
  1705. ** FieldValue -- Locate argument in Fields[] and return integer value
  1706. **
  1707. **    Parameters:
  1708. **        field -- character string to locate in Fields[]
  1709. **
  1710. **    Returns:
  1711. **        integer value of field or NONE_OF_ABOVE (-1) if not found.
  1712. **
  1713. **    Side Effects:
  1714. **        none
  1715. */
  1716.  
  1717. FieldValue (field)
  1718.     const char    *field;
  1719. {
  1720.     struct    QI_fields    *QIp = Fields;
  1721.  
  1722.     /* Guard against stupid mistakes (so they show up somewhere else?) */
  1723.     if (field == CPNULL || *field == CHNULL)
  1724.         return (NONE_OF_ABOVE);
  1725.  
  1726.     /* Replace this with a binary search if profiling peaks here.  XXX */
  1727.     do {
  1728.         if (equal (field, QIp->value))
  1729.             break;
  1730.     } while ((++QIp)->key != NONE_OF_ABOVE);
  1731.     return (QIp->key);
  1732. }
  1733. /*
  1734. ** GarbageCollect -- Free space allocated within QI_response array
  1735. **
  1736. **    Parameters:
  1737. **        QIp -- pointer to array of QI_response
  1738. **
  1739. **    Returns:
  1740. **        None
  1741. **
  1742. **    Side Effects:
  1743. **        none
  1744. */
  1745.  
  1746. void
  1747. GarbageCollect (QIp)
  1748.     QIR    *QIp;
  1749. {
  1750.     QIR    *QIsave = QIp;
  1751.  
  1752.     assert (QIp != QIR_NULL);
  1753.     do {
  1754.         if (QIp->message != CPNULL)
  1755.             free (QIp->message);
  1756.         QIp->message = CPNULL;
  1757.     } while ((QIp++)->code < 0);
  1758.     free ((char *) QIsave);
  1759. }
  1760. /*
  1761. ** Malloc -- malloc with error checking
  1762. **
  1763. **    Parameters:
  1764. **        size -- number of bytes to get
  1765. **
  1766. **    Returns:
  1767. **        (char *) of first char of block, or
  1768. **        finis() if any error
  1769. **
  1770. **    Side Effects:
  1771. **        none
  1772. */
  1773.  
  1774. char *
  1775. Malloc (size)
  1776.     unsigned    size;            /* Bytes to get */
  1777. {
  1778.         char    *cp;        /* Pointer to memory */
  1779.  
  1780.     if ((cp = (char *) malloc (size)) == CPNULL) {
  1781.         if (Debug) {
  1782.             fprintf (stderr, "malloc of %u bytes failed:", size);
  1783.             perror("");
  1784.         }
  1785.         if (Log)
  1786.             syslog (LOG_ERR, "malloc of %u bytes failed: %m", size);
  1787.         finis ();
  1788.     }
  1789.     return (cp);
  1790. }
  1791. /*
  1792. ** PrintMsg -- Print a message on the named stream
  1793. **
  1794. **    Parameters:
  1795. **        OutFile -- stream to print message to
  1796. **        Msg - array of char pointers that make up message,
  1797. **              null terminated
  1798. **
  1799. **    Returns:
  1800. **        None
  1801. **
  1802. **    Side Effects:
  1803. **        none
  1804. */
  1805.  
  1806. void
  1807. PrintMsg (OutFile, Msg)
  1808.     FILE    *OutFile;
  1809.     char    *Msg[];
  1810. {
  1811.     while (*Msg != CPNULL) {
  1812.         if (fprintf (OutFile, "%s\n", *Msg) < 0)
  1813.             finis ();
  1814.         Msg++;
  1815.     }
  1816. }
  1817. /*
  1818. ** Realloc -- realloc with error checking
  1819. **
  1820. **    Parameters:
  1821. **        ptr -- pointer to existing data
  1822. **        size -- number of bytes to get
  1823. **
  1824. **    Returns:
  1825. **        (char *) of first char of block, or
  1826. **        finis() if any error
  1827. **
  1828. **    Side Effects:
  1829. **        none
  1830. */
  1831.  
  1832. char *
  1833. Realloc (ptr, size)
  1834.     char        *ptr;
  1835.     unsigned    size;
  1836. {
  1837.         char    *cp;        /* pointer to memory */
  1838.  
  1839.     if ((cp = (char *) realloc (ptr, size)) == CPNULL) {
  1840.         if (Debug) {
  1841.             fprintf (stderr, "realloc of %u bytes failed:", size);
  1842.             perror("");
  1843.         }
  1844.         if (Log)
  1845.             syslog (LOG_ERR, "realloc of %u bytes failed: %m", size);
  1846.         finis ();
  1847.     }
  1848.     return (cp);
  1849. }
  1850. /*
  1851. ** PrtUsage -- Print how to use message
  1852. **
  1853. **    Print usage messages (char *usage[]) to stderr and exit nonzero.
  1854. **    Each message is followed by a newline.
  1855. **
  1856. **    Parameters:
  1857. **        FullText -- prints the copyright statement if set
  1858. **
  1859. **    Returns:
  1860. **        none
  1861. **
  1862. **    Side Effects:
  1863. **        none
  1864. */
  1865.  
  1866. void
  1867. PrtUsage (FullText)
  1868.     int    FullText;
  1869. {
  1870.     int    which = 0;        /* current line */
  1871.  
  1872.     while (usage[which] != CPNULL) {
  1873.         fprintf (stderr, usage[which++], MyName);
  1874.         (void) putc ('\n', stderr);
  1875.     }
  1876.     (void) fflush (stdout);
  1877.     if (FullText)
  1878.         PrintMsg (stdout, CopyLeft);
  1879. }
  1880. /*
  1881. **  finis -- Clean up and exit.
  1882. **
  1883. **    Parameters:
  1884. **        none
  1885. **
  1886. **    Returns:
  1887. **        never
  1888. **
  1889. **    Side Effects:
  1890. **        exits sendmail
  1891. */
  1892.  
  1893. void
  1894. finis()
  1895. {
  1896.     extern    FILE    *ToQI, *FromQI;
  1897.  
  1898.     /* clean up temp files */
  1899.     if (ToQI != FILE_NULL)
  1900.         (void) fclose (ToQI);
  1901.     if (FromQI != FILE_NULL)
  1902.         (void) fclose (FromQI);
  1903.     ToQI = FromQI = FILE_NULL;
  1904.  
  1905.     if (! Debug) {
  1906.         (void) unlink (TmpFile);
  1907.         (void) unlink (ErrorFile);
  1908.         (void) unlink (NewFile);
  1909.     }
  1910.  
  1911.     /* and exit */
  1912.     exit (ExitStat);
  1913. }
  1914. @
  1915.  
  1916.  
  1917. 1.24
  1918. log
  1919. @Ackk!  vfork() on SPARCs is very anti-social when the -O compile option
  1920. is used.  Modified register values get sent back to the parent.  Fixed
  1921. by converting all instances of vfork() to fork().
  1922. @
  1923. text
  1924. @d23 1
  1925. a23 1
  1926. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.23 1991/04/03 22:24:44 paul Exp paul $";
  1927. d57 1
  1928. a57 1
  1929. #define        VERSION        "3.7"
  1930. a638 1
  1931.         int    ByteLimit = 15000;    /* Limit returned msg size */
  1932. d716 1
  1933. a716 2
  1934.     while ((i = fread (Buf, sizeof (char), MAXSTR, Omsg)) != 0
  1935.         && ByteLimit > 0) {
  1936. a718 2
  1937.         else
  1938.             ByteLimit -= i;
  1939. @
  1940.  
  1941.  
  1942. 1.23
  1943. log
  1944. @Handle case when qi has a present but null email entry for someone.
  1945. @
  1946. text
  1947. @d23 1
  1948. a23 1
  1949. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.22 1991/03/18 15:38:00 paul Exp paul $";
  1950. d197 1
  1951. a197 1
  1952.  * Setting Debug disables vfork/execve in ReMail.
  1953. d616 1
  1954. a616 1
  1955. **        envp -- environment pointer for vfork/execve
  1956. d636 1
  1957. a636 1
  1958.         int    pid;            /* For vfork() */
  1959. d735 1
  1960. a735 1
  1961.      * vfork, then execve sendmail for delivery
  1962. d739 1
  1963. a739 1
  1964.     if (! Debug && (pid = vfork ()) == -1)
  1965. d819 1
  1966. a819 1
  1967. **        envp -- environment pointer for vfork/execve
  1968. d936 1
  1969. a936 1
  1970.      * vfork, then execve sendmail for delivery
  1971. d940 1
  1972. a940 1
  1973.     if (! Debug && (pid = vfork ()) == -1)
  1974. @
  1975.  
  1976.  
  1977. 1.22
  1978. log
  1979. @Broke UIUC-specific part into a messages.h file.
  1980. @
  1981. text
  1982. @d23 1
  1983. a23 1
  1984. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.21 1991/03/16 17:28:21 paul Exp paul $";
  1985. d472 1
  1986. a472 1
  1987.             syslog (LOG_INFO, "%s --> %s",
  1988. d486 1
  1989. a486 1
  1990.                 syslog (LOG_INFO, "%s --> %s",
  1991. d1262 11
  1992. a1272 1
  1993.     assert (QIp->field == EMAIL);
  1994. @
  1995.  
  1996.  
  1997. 1.21
  1998. log
  1999. @ANSIfied.
  2000. @
  2001. text
  2002. @d23 1
  2003. a23 1
  2004. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.21 1991/03/05 19:08:39 paul Exp $";
  2005. d55 1
  2006. d65 3
  2007. a67 1
  2008. #define        QISERVICE    "ns"
  2009. a156 62
  2010.  
  2011. /* Messages for ErrorReturn().  How simple, yet stupid, do we have to be? */
  2012.  
  2013. char    *NoMatchMsg[] = {
  2014.  " The message, \"No matches to nameserver query,\" is generated whenever",
  2015.  " the ph nameserver fails to locate either a ph alias or name field that",
  2016.  " matches the supplied name.  The usual causes are typographical errors or",
  2017.  " the use of nicknames.  Recommended action is to use the ph program to",
  2018.  " determine the correct ph alias for the individuals addressed.  If ph is",
  2019.  " not available, try sending to the most explicit form of the name, e.g.,",
  2020.  " if mike-fox fails, try michael-j-fox.",
  2021.  " ",
  2022.  CPNULL
  2023. };
  2024.  
  2025. char    *MultiMsg[] = {
  2026.  " The message, \"Multiple matches found for nameserver query,\" is generated",
  2027.  " whenever the ph nameserver finds multiple matches for the supplied name.",
  2028.  " The steering philosophy is that mail should be delivered only to the",
  2029.  " addressed individual.  Since the supplied information is insufficient",
  2030.  " to locate a specific individual, your message is being returned.",
  2031.  " To help you locate the correct individual, selected fields from the",
  2032.  " possible matches are included below.  The alias field is the only one",
  2033.  " guaranteed unique within a given ph community.",
  2034.  " ",
  2035.  CPNULL
  2036. };
  2037.  
  2038. char    *TooManyMsg[] = {
  2039.  " The message, \"Too many matches found to nameserver query,\" is generated",
  2040.  " whenever the supplied name or alias matched over twenty ph nameserver",
  2041.  " entries.  In this case no information will be returned about possible",
  2042.  " matches.  Recommended action is to supply more specific names, e.g.,",
  2043.  " john-b-smith instead of john-smith, or use the per-person unique ph alias.",
  2044.  " You may have thought that you had used a ph alias and not a name.  This is",
  2045.  " an artifact of the address resolution process.  If the address fails as an",
  2046.  " alias, it is retried first as a callsign and then as a name.  While aliases",
  2047.  " are guaranteed unique, names can match multiple individuals depending on",
  2048.  " how common the name is.",
  2049.  " ",
  2050.  CPNULL
  2051. };
  2052.  
  2053. char    *AbsentMsg[] = {
  2054.  " The message, \"E-mail field not present in nameserver entry,\" is generated",
  2055.  " whenever the ph nameserver matched the supplied name or alias with an",
  2056.  " entry that lacked an email address field.  In this case no delivery can",
  2057.  " be made.  Recommended action is to contact the individual by alternate",
  2058.  " means via the information included below.  If the individual already has",
  2059.  " an email address, s/he should edit their ph entry to include it.",
  2060.  " ",
  2061.  CPNULL
  2062. };
  2063.  
  2064. char    *PhoneMsg[] = {
  2065.  " A note regarding phone numbers: the UIUC area code is 217.  There are three",
  2066.  " exchanges used by UIUC: 333, 332, and 244.  UIUC phone numbers are often",
  2067.  " abbreviated by omitting the first two digits of the exchange.  Thus the",
  2068.  " example phone number 3-6262 can be reached by dialing 1 217 333 6262.",
  2069.  " ",
  2070.  CPNULL
  2071. };
  2072. @
  2073.  
  2074.  
  2075. 1.20
  2076. log
  2077. @Changes for 4.4 BSD and to handle backup QI server (QI_ALT in Makefile).
  2078. @
  2079. text
  2080. @d23 1
  2081. a23 1
  2082. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.19 1990/12/11 12:25:50 paul Exp paul $";
  2083. d31 1
  2084. a31 1
  2085.     || defined(BSD4_4)
  2086. d37 1
  2087. a37 1
  2088. # if defined(sun) || defined(convex)
  2089. d56 1
  2090. a56 1
  2091. #define        VERSION        "3.6"
  2092. d269 39
  2093. a307 3
  2094. char    *Malloc(), *Realloc();
  2095. #if !defined(__STDC__)
  2096. char    *malloc(), *realloc();
  2097. d309 1
  2098. a369 1
  2099.     extern    FILE    *OpenTemp();
  2100. d587 1
  2101. d686 1
  2102. d688 3
  2103. a690 3
  2104. NADD    *Addr;
  2105. FILE    *Omsg;
  2106. char    *envp[];
  2107. a701 1
  2108.     extern    FILE    *OpenTemp();
  2109. d801 1
  2110. a801 1
  2111.         pid = wait(0);
  2112. d822 1
  2113. d824 1
  2114. a824 1
  2115. FILE    *MsgFile;
  2116. d887 1
  2117. d889 3
  2118. a891 3
  2119. NADD    *Addr;
  2120. FILE    *Omsg;
  2121. char    *envp[];
  2122. a899 1
  2123.     extern    FILE    *OpenTemp();
  2124. d930 1
  2125. a930 1
  2126.             int    LineLength = 0;
  2127. d970 1
  2128. a970 1
  2129.     nap[napi++] = CPNULL;
  2130. d1002 1
  2131. a1002 1
  2132.         pid = wait(0);
  2133. d1024 1
  2134. a1024 1
  2135. int    code;
  2136. d1051 1
  2137. a1051 1
  2138. char    *Name;
  2139. d1088 2
  2140. a1089 2
  2141. QIR    *qp;
  2142. int    field;
  2143. d1116 1
  2144. d1118 1
  2145. a1118 1
  2146. NADD    *New;
  2147. d1121 4
  2148. a1124 1
  2149.     char    *sp, *sp2;        /* work ptrs for scratch */
  2150. d1162 1
  2151. d1164 1
  2152. d1238 2
  2153. a1239 2
  2154. NADD    *New;
  2155. char    *Field, *Value;
  2156. a1242 2
  2157.     QIR    *ReadQI();
  2158.     char    *Realloc();
  2159. d1366 1
  2160. d1368 1
  2161. a1368 1
  2162. NADD    *New;
  2163. a1374 1
  2164.     extern    QIR    *ReadQI();
  2165. d1519 1
  2166. a1519 1
  2167. FILE    *InFile;
  2168. a1528 1
  2169.         char    *Malloc(), *Realloc();
  2170. d1626 1
  2171. a1626 1
  2172. char    *field;
  2173. d1654 1
  2174. d1656 1
  2175. a1656 1
  2176. QIR    *QIp;
  2177. a1666 1
  2178.     QIsave = QIR_NULL;
  2179. d1684 1
  2180. a1684 1
  2181. unsigned    size;            /* Bytes to get */
  2182. d1688 1
  2183. a1688 1
  2184.     if ((cp = malloc (size)) == CPNULL) {
  2185. d1714 1
  2186. d1716 2
  2187. a1717 2
  2188. FILE    *OutFile;
  2189. char    *Msg[];
  2190. d1742 2
  2191. a1743 2
  2192. char        *ptr;
  2193. unsigned    size;
  2194. d1747 1
  2195. a1747 1
  2196.     if ((cp = realloc (ptr, size)) == CPNULL) {
  2197. d1774 1
  2198. d1776 1
  2199. a1776 1
  2200. int    FullText;
  2201. a1784 1
  2202.     which = 0;
  2203. d1801 1
  2204. @
  2205.  
  2206.  
  2207. 1.19
  2208. log
  2209. @Corrected handling of hyphenated names.  Added WILDNAMES #define for more
  2210. aggressive matching of full name lookups.  See the comments in phquery.h.
  2211. @
  2212. text
  2213. @d23 1
  2214. a23 1
  2215. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.18 90/12/10 21:58:27 paul Exp Locker: paul $";
  2216. d30 2
  2217. a31 1
  2218. #if defined(pyr) || defined(is68k) || defined(NeXT) || defined(__convex__)
  2219. d56 1
  2220. a56 1
  2221. #define        VERSION        "3.5"
  2222. d67 3
  2223. d71 1
  2224. a553 1
  2225.         int    sav_errno;    /* errno value preserver */
  2226. d557 1
  2227. a568 12
  2228.     /* Get a socket for the QI connection */
  2229.     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  2230.     {
  2231.         if (Debug)
  2232.             fprintf (stderr, "ContactQI: can't create socket");
  2233.     severe:
  2234.         if (Log)
  2235.             syslog (LOG_ERR, "ContactQI: cannot get connection");
  2236.         finis();
  2237.     }
  2238.     QI.sin_family = AF_INET;
  2239.  
  2240. d579 12
  2241. d593 1
  2242. a593 1
  2243.     if (Host = gethostbyname (QI_HOST)) {
  2244. d596 7
  2245. a602 3
  2246.         if (Debug)
  2247.             fprintf (stderr, "host name lookup failure: \"%s\"", QI_HOST);
  2248.         goto severe;
  2249. d606 7
  2250. a612 3
  2251.     if (connect(sock, (struct sockaddr *) &QI, sizeof (QI)) < 0)
  2252.     {
  2253.         sav_errno = errno;
  2254. d614 4
  2255. a617 31
  2256.         errno = sav_errno;
  2257.         switch (errno)
  2258.         {
  2259.           case EISCONN:
  2260.           case ETIMEDOUT:
  2261.           case EINPROGRESS:
  2262.           case EALREADY:
  2263.           case EADDRINUSE:
  2264.           case EHOSTDOWN:
  2265.           case ENETDOWN:
  2266.           case ENETRESET:
  2267.           case ENOBUFS:
  2268.           case ECONNREFUSED:
  2269.           case ECONNRESET:
  2270.           case EHOSTUNREACH:
  2271.           case ENETUNREACH:
  2272.             /* There are others, I'm sure..... */
  2273.             finis ();
  2274.  
  2275.           case EPERM:
  2276.             /* Why is this happening? */
  2277.             if (Debug)
  2278.                 fprintf (stderr, "ContactQI: funny failure, addr=%lx, port=%x",
  2279.                 QI.sin_addr.s_addr, QI.sin_port);
  2280.             finis ();
  2281.  
  2282.           default:
  2283.             if (Debug)
  2284.                 fprintf (stderr, "ContactQI: default failure, addr=%lx, port=%x",
  2285.                 QI.sin_addr.s_addr, QI.sin_port);
  2286.             finis ();
  2287. d619 2
  2288. d622 1
  2289. @
  2290.  
  2291.  
  2292. 1.18
  2293. log
  2294. @Fixed handling of imbedded newlines.
  2295. @
  2296. text
  2297. @d23 1
  2298. a23 1
  2299. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.17 90/12/10 14:09:03 paul Exp Locker: paul $";
  2300. d55 1
  2301. a55 1
  2302. #define        VERSION        "3.4"
  2303. a248 3
  2304. /* Characters that can act as separators in full name requests */
  2305. char    PunctChars[] =    "-_.,+=#$";
  2306.  
  2307. d373 1
  2308. a373 1
  2309.                 Usage (1);
  2310. d378 1
  2311. a378 1
  2312.             Usage (1);
  2313. d383 1
  2314. a383 1
  2315.             Usage (0);
  2316. d836 7
  2317. d885 3
  2318. a918 1
  2319.                         nap[napi++] = AddrP->new;
  2320. a921 3
  2321.                 for (AddrP = Addr; AddrP->original != CPNULL; AddrP++)
  2322.                     if (abs (AddrP->code) == LR_OK)
  2323.                         nap[napi++] = AddrP->new;
  2324. d1071 1
  2325. a1071 1
  2326. **  Query -- Make calls to the local CSnet central name server
  2327. d1073 5
  2328. a1077 6
  2329. **    Takes a alias, call-sign, or full name, as known by the CSnet central
  2330. **    name server Query Interpreter, and looks up the corresponding
  2331. **    email address "usercode@@host".  Cases where the alias/name aren't
  2332. **    found, are ambiguous, or lack an email address return a message
  2333. **    instead of the address.  Additional information is returned as an
  2334. **    array of QIR records pointed to by New->QIalt.
  2335. a1085 1
  2336. **        Will call ContactQI() if the connection is closed.
  2337. a1086 2
  2338. **        Looks up the user specified in nbuf.  If the name is
  2339. **        found, replace the contents of nbuf with the email address.
  2340. d1092 4
  2341. a1095 12
  2342.         QIR    *EmailQ, *QIp;    /* For handling ReadQI() responses */
  2343.         char    scratch[MAXSTR]; /* copy of FullName w.o. punct */
  2344.         char    *sp;        /* work ptr for scratch */
  2345.         char    **Lpnt;        /* Loop pointer for TryList */
  2346.         int    multi;        /* Set if more than 1 person */
  2347.         int    i;        /* good ol' i */
  2348.     extern    char    *TryList[];
  2349.     extern    FILE    *ToQI, *FromQI;
  2350.     extern    char    PunctChars[];
  2351.     extern    int    ReplyTo;
  2352.         QIR    *ReadQI();
  2353.         char    *Realloc();
  2354. a1096 3
  2355.     /* Open the ToQI and FromQI descriptors if necessary */
  2356.     ContactQI();
  2357.  
  2358. d1101 1
  2359. a1101 3
  2360.     for (Lpnt = TryList; *Lpnt != CPNULL; Lpnt++) {
  2361.         (void) strcpy (scratch, New->original);
  2362.  
  2363. d1104 10
  2364. a1113 1
  2365.          * characters if testing for name.
  2366. d1115 1
  2367. a1115 7
  2368.         if (equal (*Lpnt, "name"))
  2369.             for (i = 0; PunctChars[i] != CHNULL; i++) {
  2370.                 if (PunctChars[i] == ' ')
  2371.                     continue;
  2372.                 while ((sp = index (scratch, PunctChars[i])) != CPNULL)
  2373.                     *sp = ' ';
  2374.             }
  2375. d1117 6
  2376. a1122 10
  2377.         /*
  2378.          * Convert punctuation/separators in scratch to hyphen
  2379.          * characters if testing for alias.
  2380.          */
  2381.         else if (equal (*Lpnt, "alias"))
  2382.             for (i = 0; PunctChars[i] != CHNULL; i++) {
  2383.                 if (PunctChars[i] == '-')
  2384.                     continue;
  2385.                 while ((sp = index (scratch, PunctChars[i])) != CPNULL)
  2386.                     *sp = '-';
  2387. d1124 2
  2388. d1127 1
  2389. a1127 29
  2390.         /* Make a query out of the arguments */
  2391.         fprintf (ToQI,
  2392.             "query %s=%s return name alias callsign phone department curriculum email\n",
  2393.             *Lpnt, scratch);
  2394.         if (Debug)
  2395.             printf ("querying for %s \"%s\"\n", *Lpnt, scratch);
  2396.         if (Log)
  2397.             syslog (LOG_DEBUG, "querying for %s \"%s\"\n",
  2398.                 *Lpnt, scratch);
  2399.         (void) fflush (ToQI);
  2400.         
  2401.         /*
  2402.          * Grab the responses and let the fun begin.
  2403.          * The possibilities are:
  2404.          *
  2405.          * 102:There were N matches to your query
  2406.          * -200:1:         alias: Paul-Pomes
  2407.          * -200:1:          name: pomes paul b
  2408.          * -200:1:      callsign: See Figure 1
  2409.          * -508:1:    curriculum: Not present in entry.
  2410.          * -200:1:    department: Computing Services Office
  2411.          * -200:1:         email: paul@@uxc.cso.uiuc.edu
  2412.          * 200:Ok.
  2413.          *
  2414.          * 501:No matches to your query.
  2415.          *
  2416.          * 502:Too many matches to request.
  2417.          */
  2418.         EmailQ = ReadQI (FromQI);
  2419. d1129 28
  2420. a1156 8
  2421.         /*
  2422.          * If we read a preliminary response (99<x<200), garbage
  2423.          * collect and read some more.
  2424.          */
  2425.         i = abs (EmailQ->code);
  2426.         if (i > 99 && i < 200) {
  2427.             GarbageCollect (EmailQ);
  2428.             EmailQ = ReadQI (FromQI);
  2429. d1160 2
  2430. a1161 1
  2431.          * If we read a temporary error, be a nice program and defer.
  2432. d1163 6
  2433. a1168 13
  2434.         else if (i > 399 && i < 500)
  2435.             finis ();
  2436.  
  2437.         /*
  2438.          * No matches at all?  Too many?  Note that single line errors
  2439.          * will have code > 0.  This test should only be done for the
  2440.          * last iteration of this loop.
  2441.          */
  2442.         if (EmailQ->code > 0) {
  2443.             if (equal (*Lpnt, "name")) {
  2444.                 New->new = CodeString (EmailQ->code);
  2445.                 New->code = EmailQ->code;
  2446.                 New->QIalt = QIR_NULL;
  2447. d1170 1
  2448. a1170 5
  2449.             }
  2450.             else {
  2451.                 GarbageCollect (EmailQ);
  2452.                 continue;
  2453.             }
  2454. d1172 31
  2455. d1204 8
  2456. a1211 2
  2457.         /* anything else must be multi-line */
  2458.         assert (EmailQ->code < 0);
  2459. d1213 2
  2460. a1214 6
  2461.         /* Are there multiple responses (subcode > 1)? */
  2462.         for (QIp = EmailQ, multi = 0; QIp->code < 0; QIp++)
  2463.             if (QIp->subcode > 1) {
  2464.                 multi++;
  2465.                 break;
  2466.             }
  2467. d1216 29
  2468. a1244 10
  2469.         /* If one person, handle as single match alias */
  2470.         if (multi == 0) {
  2471.             QIp = PickField (EmailQ, EMAIL);
  2472.             assert (QIp->field == EMAIL);
  2473.             New->code = abs (QIp->code);
  2474.             New->QIalt = EmailQ;
  2475.             switch (abs (QIp->code)) {
  2476.                 case LR_ABSENT:
  2477.                 New->new = CodeString (QIp->code);
  2478.                 return;
  2479. d1246 9
  2480. a1254 3
  2481.                 case LR_OK:
  2482.                 New->new = QIp->message;
  2483.                 return;
  2484. d1256 5
  2485. a1260 9
  2486.                 default:
  2487.                 if (Debug)
  2488.                     fprintf (stderr, "unexpected code %d\n",
  2489.                         QIp->code);
  2490.                 if (Log)
  2491.                     syslog (LOG_ERR, "Query: %s: unexpected code %d", *Lpnt, QIp->code);
  2492.                 finis ();
  2493.             }
  2494.         }
  2495. d1262 20
  2496. a1281 2
  2497.         /* Multiple matches. */
  2498.         else {
  2499. d1285 1
  2500. a1285 1
  2501.             return;
  2502. d1287 22
  2503. a1308 1
  2504.         GarbageCollect (EmailQ);
  2505. d1310 2
  2506. d1728 1
  2507. a1728 1
  2508. ** Usage -- Print how to use message
  2509. d1743 1
  2510. a1743 1
  2511. Usage (FullText)
  2512. @
  2513.  
  2514.  
  2515. 1.17
  2516. log
  2517. @Portability enhancements
  2518. @
  2519. text
  2520. @d23 1
  2521. a23 1
  2522. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.16 90/06/11 10:52:40 paul Exp Locker: paul $";
  2523. d55 1
  2524. a55 1
  2525. #define        VERSION        "3.3"
  2526. d270 1
  2527. a270 1
  2528. #endif /* !__STDC__ && !__stdc__ */
  2529. d314 1
  2530. a314 1
  2531.  "US Mail:  UofIllinois, CSO, 1304 W Springfield Ave, Urbana, IL  61801-2987",
  2532. d375 2
  2533. a376 1
  2534.             Usage (1);
  2535. d1437 1
  2536. d1473 8
  2537. a1480 1
  2538.             finis ();
  2539. d1486 1
  2540. a1486 1
  2541.          * previous response.
  2542. d1488 12
  2543. a1499 6
  2544.         for (tp = fstring; tp <= fstring + (MAXSTR-1) && *tp == ' '; tp++)
  2545.             ;
  2546.         if (RepChain->code < 0 && *tp == CHNULL)
  2547.             RepChain->field = (RepChain - 1)->field;
  2548.         else
  2549.             RepChain->field = FieldValue (tp);
  2550. d1507 1
  2551. @
  2552.  
  2553.  
  2554. 1.16
  2555. log
  2556. @Simplify headers, add support for service lookups (fax, etc).
  2557. @
  2558. text
  2559. @d23 1
  2560. a23 1
  2561. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.15 90/01/30 23:51:30 paul Exp Locker: paul $";
  2562. d29 2
  2563. a30 1
  2564. #ifdef    pyr
  2565. d35 2
  2566. a36 2
  2567. #else    /* ! pyr */
  2568. # ifdef sun
  2569. d40 1
  2570. a40 1
  2571. # else    /* ! sun */
  2572. d42 2
  2573. a43 2
  2574. # endif    sun
  2575. #endif    pyr
  2576. d55 1
  2577. a55 1
  2578. #define        VERSION        "3.2"
  2579. d267 5
  2580. a330 1
  2581.     extern    char    *Malloc(), *rindex(), *Realloc();
  2582. d684 2
  2583. a685 1
  2584.     fprintf (Emsg, "To: %s\n", From);
  2585. d777 1
  2586. a777 1
  2587.         pid = wait((union wait *)NULL);
  2588. d901 2
  2589. a902 1
  2590.                 fprintf (Nmsg, "X-PH(%s)-To:", VERSION);
  2591. d926 2
  2592. a927 1
  2593.                 fprintf (Nmsg, "Comment: Reply-To: added by phquery (V%s)\n", VERSION);
  2594. d971 1
  2595. a971 1
  2596.         pid = wait((union wait *)NULL);
  2597. d1286 2
  2598. a1287 1
  2599.      * appending our fully qualified domain name.
  2600. d1307 4
  2601. a1310 1
  2602.     /* Send the query */
  2603. d1425 1
  2604. a1425 1
  2605.         int    code;
  2606. d1464 2
  2607. a1465 2
  2608.         else if (sscanf (Temp, "%d:%d:%[^:]: %[^\n]",
  2609.             &RepChain->code, &RepChain->subcode, fstring, message)
  2610. d1468 1
  2611. a1468 1
  2612.                 fprintf (stderr, "ReadQI: short #2 sscanf\n");
  2613. d1470 1
  2614. a1470 1
  2615.                 syslog (LOG_ERR, "ReadQI: short #2 sscanf read: %m");
  2616. d1479 1
  2617. a1479 1
  2618.         for (tp = fstring; tp < fstring + MAXSTR && *tp == ' '; tp++)
  2619. a1576 1
  2620.     extern    char    *malloc();
  2621. d1609 2
  2622. a1610 1
  2623.         fprintf (OutFile, "%s\n", *Msg);
  2624. a1634 1
  2625.     extern    char    *realloc();
  2626. @
  2627.  
  2628.  
  2629. 1.15
  2630. log
  2631. @Different kinds of massaging is done to argument string depending
  2632. on lookup type.
  2633. @
  2634. text
  2635. @d23 1
  2636. a23 1
  2637. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.14 89/07/28 10:05:12 paul Exp Locker: paul $";
  2638. d54 1
  2639. a54 1
  2640. #define        VERSION        "3.1"
  2641. d95 4
  2642. d120 1
  2643. a120 1
  2644. **    Resent-From: postmaster@@DOMAINMASTER
  2645. d122 1
  2646. a122 1
  2647. **    Comment: From: field converted to Reply-To: by phquery (Vx.y) at <host>
  2648. d262 1
  2649. a262 1
  2650.     "usage: %s [-d] [-p] [-s] [-l] [-R] [-i] [-f FromAddress] address1 [address2]",
  2651. d320 1
  2652. d331 1
  2653. a331 1
  2654.     while ((option = getopt (argc, argv, "f:r:pRsdli")) != EOF) {
  2655. d337 4
  2656. d470 2
  2657. a471 1
  2658.      * Allocate NewAddress structs for addresses
  2659. d473 3
  2660. a475 2
  2661.     New = (NADD *) Malloc ((unsigned) ((argc+1) * sizeof (NADD)));
  2662.     (New + argc)->original = CPNULL;
  2663. d478 2
  2664. a479 3
  2665.     /* Loop on addresses in argv building up translation table */
  2666.     while (argc > 0) {
  2667.         NewP->original = *argv;
  2668. a488 1
  2669.         NewP++; argv++; argc--;
  2670. d490 15
  2671. d884 1
  2672. a884 1
  2673.     /* Read and copy the header block, adding the X-PH-To: header */
  2674. d894 1
  2675. d907 6
  2676. a1146 1
  2677.          *
  2678. d1208 1
  2679. a1208 1
  2680.             assert (QIp->field == EMAIL)
  2681. @
  2682.  
  2683.  
  2684. 1.14
  2685. log
  2686. @Minor fixes and de-linting.
  2687. @
  2688. text
  2689. @d23 1
  2690. a23 1
  2691. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.13 89/07/27 23:19:22 paul Exp Locker: paul $";
  2692. d54 1
  2693. a54 1
  2694. #define        VERSION        "3.0"
  2695. d224 1
  2696. a224 1
  2697. /* Exit status for reporting to calling process */
  2698. d1081 6
  2699. a1086 3
  2700.             for (i = 0; PunctChars[i] != CHNULL; i++)
  2701.             while ((sp = index (scratch, PunctChars[i])) != CPNULL)
  2702.                 *sp = ' ';
  2703. d1088 12
  2704. d1115 2
  2705. d1132 16
  2706. d1235 1
  2707. d1280 2
  2708. d1297 10
  2709. @
  2710.  
  2711.  
  2712. 1.13
  2713. log
  2714. @First working version of -R (reply-to:) processing.
  2715. @
  2716. text
  2717. @d23 1
  2718. a23 1
  2719. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.12 89/05/24 00:11:48 paul Exp Locker: paul $";
  2720. d424 5
  2721. a428 2
  2722.         /* Allocate NewAddress structs for addresses plus 1 */
  2723.         New = (NADD *) Malloc ((unsigned) ((argc+1) * sizeof (NADD)));
  2724. a430 1
  2725.  
  2726. d434 1
  2727. a434 2
  2728.         NewP->new = Realloc (NewP->new, (unsigned)(strlen (NewP->new) +
  2729.                 strlen (DOMAIN) + 3));
  2730. d436 3
  2731. d451 1
  2732. d459 4
  2733. a462 1
  2734.     /* Allocate NewAddress structs for addresses */
  2735. d647 1
  2736. @
  2737.  
  2738.  
  2739. 1.12
  2740. log
  2741. @Changed #include's to cope with SUN systems.  -pbp
  2742. @
  2743. text
  2744. @d23 1
  2745. a23 3
  2746. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.11 89/05/16 16:59:36 paul Exp Locker: paul $";
  2747. #else /* not lint */
  2748. # define    QI_HOST        "some string"
  2749. d54 1
  2750. a54 1
  2751. #define        VERSION        "2.0"
  2752. d56 5
  2753. d67 8
  2754. d112 10
  2755. d149 6
  2756. a154 6
  2757.  " the ph nameserver fails to locate either a ph ALIAS or NAME that matches",
  2758.  " the supplied name.  The usual causes are typographical errors or the use of",
  2759.  " nicknames.  Recommended action is to use the ph program to determine the",
  2760.  " correct ph alias for the individuals addressed.  If ph is not available,",
  2761.  " try sending to the most explicit form of the name, e.g., if mike-fox fails,",
  2762.  " try michael-j-fox.",
  2763. d215 6
  2764. d258 1
  2765. a258 1
  2766.     "usage: %s [-d] [-p] [-s] [-l] [-i] [-f FromAddress] address1 [address2]",
  2767. d319 2
  2768. a320 1
  2769.     extern    char    *malloc(), *rindex();
  2770. d326 1
  2771. a326 1
  2772.     while ((option = getopt (argc, argv, "f:r:psdli")) != EOF) {
  2773. d332 5
  2774. d393 4
  2775. d401 2
  2776. a402 7
  2777.         if (fwrite (Buf, sizeof (char), i, Msg) != i) {
  2778.             if (Debug)
  2779.                 perror("Msg copy");
  2780.             if (Log)
  2781.                 syslog (LOG_ERR, "Msg copy: %m");
  2782.             finis ();
  2783.         }
  2784. d413 38
  2785. a450 7
  2786.     /* Allocate NewAddress structs for addresses */
  2787.     if ((New = (NADD *) malloc ((unsigned) ((argc+1)
  2788.         * sizeof (NADD)))) == NADD_NULL) {
  2789.         if (Debug)
  2790.             perror ("malloc");
  2791.         if (Log)
  2792.             syslog (LOG_ERR, "malloc: %m");
  2793. d453 3
  2794. d715 2
  2795. a716 7
  2796.         if (fwrite (Buf, sizeof (char), i, Emsg) != i) {
  2797.             if (Debug)
  2798.                 perror("Emsg copy");
  2799.             if (Log)
  2800.                 syslog (LOG_ERR, "Emsg copy: %m");
  2801.             finis ();
  2802.         }
  2803. d723 2
  2804. a724 7
  2805.     if (freopen (ErrorFile, "r", stdin) == FILE_NULL) {
  2806.         if (Debug)
  2807.             perror ("ErrorFile freopen");
  2808.         if (Log)
  2809.             syslog (LOG_ERR, "freopen of %s: %m", ErrorFile);
  2810.         finis ();
  2811.     }
  2812. d735 2
  2813. a736 7
  2814.     if (! Debug && (pid = vfork ()) == -1) {
  2815.         if (Debug)
  2816.             perror ("ErrorReturn fork:");
  2817.         if (Log)
  2818.             syslog (LOG_ERR, "ErrorReturn fork: %m");
  2819.         finis ();
  2820.     }
  2821. d774 1
  2822. a774 1
  2823.                     From = malloc ((unsigned) ((p2-p1)+1));
  2824. d827 1
  2825. a827 1
  2826.         char    *nap[50];
  2827. d829 2
  2828. a830 1
  2829.     extern    char    *From;
  2830. d839 11
  2831. a849 1
  2832.     nap[napi++] = From;
  2833. d858 13
  2834. a870 8
  2835.             /* Write the PH header and add to argv */
  2836.             fprintf (Nmsg, "X-PH(%s)-To:", VERSION);
  2837.             LineLength = 8;
  2838.             for (AddrP = Addr; AddrP->original != CPNULL; AddrP++)
  2839.                 if (abs (AddrP->code) == LR_OK) {
  2840.                     if ((LineLength + strlen (AddrP->new)) > 75) {
  2841.                         fprintf (Nmsg, "\n\t");
  2842.                         LineLength = 8;
  2843. d872 15
  2844. a886 5
  2845.                     fprintf (Nmsg, " %s", AddrP->new);
  2846.                     nap[napi++] = AddrP->new;
  2847.                 }
  2848.             (void) putc ('\n', Nmsg);
  2849.             pid++;
  2850. d901 3
  2851. a903 9
  2852.     while ((i = fread (Buf, sizeof (char), MAXSTR, Omsg)) != 0) {
  2853.         if (fwrite (Buf, sizeof (char), i, Nmsg) != i) {
  2854.             if (Debug)
  2855.                 perror("ReMail: nmsg copy");
  2856.             if (Log)
  2857.                 syslog (LOG_ERR, "Nmsg copy: %m");
  2858.             finis ();
  2859.         }
  2860.     }
  2861. d908 2
  2862. a909 7
  2863.     if (freopen (NewFile, "r", stdin) == FILE_NULL) {
  2864.         if (Debug)
  2865.             perror ("NewFile freopen");
  2866.         if (Log)
  2867.             syslog (LOG_ERR, "freopen of %s: %m", NewFile);
  2868.         finis ();
  2869.     }
  2870. d920 2
  2871. a921 7
  2872.     if (! Debug && (pid = vfork ()) == -1) {
  2873.         if (Debug)
  2874.             perror ("ReMail fork:");
  2875.         if (Log)
  2876.             syslog (LOG_ERR, "ReMail fork: %m");
  2877.         finis ();
  2878.     }
  2879. d977 2
  2880. a978 7
  2881.     if ((fd = mkstemp (Name)) == -1) {
  2882.         if (Debug)
  2883.             perror (Name);
  2884.         if (Log)
  2885.             syslog (LOG_ERR, "mkstemp(\"%s\"): %m", Name);
  2886.         finis ();
  2887.     }
  2888. d981 2
  2889. a982 7
  2890.     if (fchmod (fd, IREAD|IWRITE) == -1) {
  2891.         if (Debug)
  2892.             perror (Name);
  2893.         if (Log)
  2894.             syslog (LOG_ERR, "fchmod(\"%s\"): %m", Name);
  2895.         finis ();
  2896.     }
  2897. d985 2
  2898. a986 7
  2899.     if ((Stream = fdopen (fd, "r+")) == FILE_NULL) {
  2900.         if (Debug)
  2901.             perror (Name);
  2902.         if (Log)
  2903.             syslog (LOG_ERR, "fdopen(\"%s\"): %m", Name);
  2904.         finis ();
  2905.     }
  2906. d1053 1
  2907. d1167 108
  2908. @
  2909.  
  2910.  
  2911. 1.11
  2912. log
  2913. @Maded openlog facility definable in Makefile.  -pbp
  2914. @
  2915. text
  2916. @d23 1
  2917. a23 1
  2918. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.10 89/05/11 17:20:48 paul Exp Locker: paul $";
  2919. d37 7
  2920. a43 1
  2921. # include <sys/inode.h>
  2922. d470 1
  2923. a470 1
  2924.             syslog(LOG_ERR, "ContactQI: cannot get connection");
  2925. d480 4
  2926. a483 2
  2927.             fprintf (stderr, "server \"%s\" unknown", QISERVICE);
  2928.         goto severe;
  2929. @
  2930.  
  2931.  
  2932. 1.10
  2933. log
  2934. @Pyramid specific changes.  -pbp
  2935. @
  2936. text
  2937. @d23 1
  2938. a23 1
  2939. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.9 89/05/10 11:50:49 paul Exp Locker: paul $";
  2940. d343 4
  2941. a346 1
  2942.         openlog(MyName, LOG_PID, LOG_MAIL);
  2943. @
  2944.  
  2945.  
  2946. 1.9
  2947. log
  2948. @Sundry formatting changes, added more text to messages.  -pbp
  2949. @
  2950. text
  2951. @d23 1
  2952. a23 1
  2953. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.8 89/05/10 00:57:49 paul Exp Locker: paul $";
  2954. d31 8
  2955. a38 1
  2956. #include <sys/inode.h>
  2957. d147 1
  2958. a147 1
  2959.  " whenever the supplied name or alias matched over thirty ph nameserver",
  2960. @
  2961.  
  2962.  
  2963. 1.8
  2964. log
  2965. @Final Wednesday morning clean-ups, typo-corrections, and semi-major
  2966. re-write of Query().  Now handles callsigns which was easier than changing
  2967. the extant documentation.  Erasing people's minds would have been tough too.
  2968. -pbp
  2969. @
  2970. text
  2971. @d23 1
  2972. a23 1
  2973. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.7 89/05/09 22:53:57 paul Exp Locker: paul $";
  2974. d43 2
  2975. d91 5
  2976. a95 5
  2977. #define        CHNULL        ('\0')
  2978. #define        CPNULL        ((char *) NULL)
  2979. #define        FILE_NULL    ((FILE *) NULL)
  2980. #define        NADD_NULL    ((struct NewAddress *) NULL)
  2981. #define        QIR_NULL    ((struct QI_response *) NULL)
  2982. d97 1
  2983. d101 2
  2984. a102 5
  2985. /* Flags to control printing of informative messages in ErrorReturn() */
  2986. #define        NO_MATCH    1
  2987. #define        MULTI        2
  2988. #define        ABSENT        4
  2989. #define        TOO_MANY    8
  2990. d104 7
  2991. d116 5
  2992. a120 3
  2993.  " the supplied name.  The usual cause is typographical errors.  Recommended",
  2994.  " action is to use the ph program to determine the correct ph alias for the",
  2995.  " individuals addressed.",
  2996. d164 8
  2997. a171 2
  2998. /* large string size */
  2999. #define        MAXSTR        250
  3000. d173 2
  3001. a174 2
  3002. FILE    *ToQI = FILE_NULL;    /* write to the QI */
  3003. FILE    *FromQI = FILE_NULL;    /* read from the QI */
  3004. d179 1
  3005. a179 1
  3006. int    PostmasterCC = 0;
  3007. d185 1
  3008. a185 1
  3009. int    ExitStat = EX_TEMPFAIL;
  3010. d188 1
  3011. a188 1
  3012. char    TmpFile[] = "/tmp/PhMailXXXXXXX";
  3013. d191 1
  3014. a191 1
  3015. char    ErrorFile[] = "/tmp/PhErrMailXXXXXXX";
  3016. d194 1
  3017. a194 1
  3018. char    NewFile[] = "/tmp/PhNewMailXXXXXXX";
  3019. d202 1
  3020. a202 1
  3021. char    *TryList[] = { "alias", "callsign", "name", CPNULL };
  3022. d205 1
  3023. a205 1
  3024. char    PunctChars[] = "-_.,+=#$";
  3025. d211 2
  3026. a212 2
  3027. int    Debug = 0;
  3028. int    Log = 1;
  3029. d215 1
  3030. a215 1
  3031. char    *From = CPNULL;
  3032. d570 1
  3033. a570 1
  3034.     fprintf (Emsg, "\n --------Error Detail:\n\n");
  3035. d575 1
  3036. a575 1
  3037.             if (! (flags & NO_MATCH)) {
  3038. d577 1
  3039. a577 1
  3040.                 flags |= NO_MATCH;
  3041. d583 1
  3042. a583 1
  3043.             if (! (flags & ABSENT)) {
  3044. d585 5
  3045. a589 1
  3046.                 flags |= ABSENT;
  3047. d599 1
  3048. a599 1
  3049.             if (! (flags & TOO_MANY)) {
  3050. d601 1
  3051. a601 1
  3052.                 flags |= TOO_MANY;
  3053. d607 1
  3054. a607 1
  3055.             if (! (flags & MULTI)) {
  3056. d609 5
  3057. a613 1
  3058.                 flags |= MULTI;
  3059. d779 1
  3060. a779 1
  3061.             fprintf (Nmsg, "X-PH-To:");
  3062. @
  3063.  
  3064.  
  3065. 1.7
  3066. log
  3067. @First working version up to spec.  -pbp
  3068. @
  3069. text
  3070. @d23 1
  3071. a23 1
  3072. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.6 89/05/08 23:21:20 paul Exp Locker: paul $";
  3073. d107 1
  3074. a107 1
  3075.  " The message, \"No matches to nameserver request,\" is generated whenever",
  3076. d130 1
  3077. a130 1
  3078.  " The message, \"Too many matches found to nameserver request,\" is generated",
  3079. d135 1
  3080. a135 1
  3081.  " You may have though that you had used a ph alias and not a name.  This is",
  3082. d137 3
  3083. a139 2
  3084.  " alias, it is retried as a name.  While aliases are guaranteed unique, names",
  3085.  " can match multiple individuals depending on how common the name is.",
  3086. d181 8
  3087. d960 1
  3088. d963 1
  3089. d976 2
  3090. a977 9
  3091.     /* Make a query out of the arguments for a alias lookup */
  3092.     fprintf (ToQI,
  3093.         "query alias=%s return name alias phone department curriculum email\n",
  3094.         New->original);
  3095.     if (Debug)
  3096.         printf ("querying for alias \"%s\"\n", New->original);
  3097.     if (Log)
  3098.         syslog (LOG_DEBUG, "querying for alias \"%s\"\n", New->original);
  3099.     (void) fflush (ToQI);
  3100. d979 8
  3101. a986 22
  3102.     /*
  3103.      * Get response.  The possibilities are
  3104.      *
  3105.      * -200:1:         alias: Paul-Pomes
  3106.      * -200:1:          name: pomes paul b
  3107.      * -508:1:    curriculum: Not present in entry.
  3108.      * -200:1:    department: Computing Services Office
  3109.      * -200:1:         email: paul@@uxc.cso.uiuc.edu
  3110.      * 200:Ok.
  3111.      *
  3112.      * 501:No matches to your query.
  3113.      */
  3114.     EmailQ = ReadQI (FromQI);
  3115.     if (EmailQ->code != LR_NOMATCH) {
  3116.         QIp = PickField (EmailQ, EMAIL);
  3117.         assert (QIp->field == EMAIL)
  3118.         New->code = abs (QIp->code);
  3119.         New->QIalt = EmailQ;
  3120.         switch (abs (QIp->code)) {
  3121.             case LR_ABSENT:
  3122.             New->new = CodeString (QIp->code);
  3123.             return;
  3124. d988 28
  3125. a1015 3
  3126.             case LR_OK:
  3127.             New->new = QIp->message;
  3128.             return;
  3129. d1017 16
  3130. a1032 7
  3131.             default:
  3132.             if (Debug)
  3133.                 fprintf (stderr, "unexpected code %d\n",
  3134.                     QIp->code);
  3135.             if (Log)
  3136.                 syslog (LOG_ERR, "Query: Alias: unexpected code %d", QIp->code);
  3137.             finis ();
  3138. a1033 2
  3139.     }
  3140.     GarbageCollect (EmailQ);
  3141. d1035 2
  3142. a1036 3
  3143.     /*
  3144.      * Try as a full name.
  3145.      */
  3146. d1038 6
  3147. a1043 5
  3148.     /* Convert punctuation/separators in the name to space characters. */
  3149.     (void) strcpy (scratch, New->original);
  3150.     for (i = 0; PunctChars[i] != CHNULL; i++)
  3151.         while ((sp = index (scratch, PunctChars[i])) != CPNULL)
  3152.             *sp = ' ';
  3153. d1045 10
  3154. a1054 12
  3155.     /* Make a query out of the arguments */
  3156.     fprintf (ToQI,
  3157.         "query name=%s return name alias phone department curriculum email\n",
  3158.         scratch);
  3159.     if (Debug)
  3160.         printf ("querying for name \"%s\"\n", scratch);
  3161.     if (Log)
  3162.         syslog (LOG_DEBUG, "querying for name \"%s\"\n", scratch);
  3163.     (void) fflush (ToQI);
  3164.     
  3165.     /* Grab the responses and let the fun begin */
  3166.     EmailQ = ReadQI (FromQI);
  3167. d1056 3
  3168. a1058 10
  3169.     /*
  3170.      * No matches at all?  Too many?  Note that single line errors will
  3171.      * have code > 0.
  3172.      */
  3173.     if (EmailQ->code > 0) {
  3174.         New->new = CodeString (EmailQ->code);
  3175.         New->code = EmailQ->code;
  3176.         New->QIalt = QIR_NULL;
  3177.         return;
  3178.     }
  3179. d1060 8
  3180. a1067 8
  3181.     /* anything else must be multi-line */
  3182.     assert (EmailQ->code < 0);
  3183.  
  3184.     /* Are there multiple responses (subcode > 1)? */
  3185.     for (QIp = EmailQ, multi = 0; QIp->code < 0; QIp++)
  3186.         if (QIp->subcode > 1) {
  3187.             multi++;
  3188.             break;
  3189. d1070 5
  3190. a1074 9
  3191.     /* If one person, handle as single match alias */
  3192.     if (multi == 0) {
  3193.         QIp = PickField (EmailQ, EMAIL);
  3194.         assert (QIp->field == EMAIL)
  3195.         New->code = abs (QIp->code);
  3196.         New->QIalt = EmailQ;
  3197.         switch (abs (QIp->code)) {
  3198.             case LR_ABSENT:
  3199.             New->new = CodeString (QIp->code);
  3200. a1075 12
  3201.  
  3202.             case LR_OK:
  3203.             New->new = QIp->message;
  3204.             return;
  3205.  
  3206.             default:
  3207.             if (Debug)
  3208.                 fprintf (stderr, "unexpected code %d\n",
  3209.                     QIp->code);
  3210.             if (Log)
  3211.                 syslog (LOG_ERR, "Query: Fullname: unexpected code %d", QIp->code);
  3212.             finis ();
  3213. d1077 1
  3214. a1078 8
  3215.  
  3216.     /* Multiple matches. */
  3217.     else {
  3218.         New->code = LR_AMBIGUOUS;
  3219.         New->new = CodeString (LR_AMBIGUOUS);
  3220.         New->QIalt = EmailQ;
  3221.     }
  3222.     return;
  3223. d1143 1
  3224. d1260 1
  3225. d1263 1
  3226. @
  3227.  
  3228.  
  3229. 1.6
  3230. log
  3231. @First working version of fullname code.  Still to come: alternates
  3232. response and callsign.  -pbp
  3233. @
  3234. text
  3235. @d23 1
  3236. a23 1
  3237. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.4 89/05/05 11:26:06 paul Exp Locker: paul $";
  3238. d60 2
  3239. a61 2
  3240. **    fields as ls has option letters.  The most important are alias, email,
  3241. **    name, and, if I get around to it, callsign.  In the simplest case,
  3242. d98 56
  3243. d241 1
  3244. a241 1
  3245.  0
  3246. d302 2
  3247. d356 3
  3248. a358 2
  3249.         (void) strcpy (Buf, *argv);
  3250.         NewP->code = Query (Buf, sizeof Buf);
  3251. d360 2
  3252. a361 1
  3253.             printf ("code %d, %s --> %s\n", NewP->code, *argv, Buf);
  3254. d363 2
  3255. a364 14
  3256.             syslog (LOG_INFO, "%s --> %s", *argv, Buf);
  3257.         if (*Buf == CHNULL) {
  3258.             /* really bad news... */
  3259.             if (Debug)
  3260.                 fprintf (stderr, "LR_OK & null address\n");
  3261.             if (Log)
  3262.                 syslog (LOG_ERR, "LR_OK & null address");
  3263.             ExitStat = EX_SOFTWARE;
  3264.             finis ();
  3265.         }
  3266.         else {
  3267.             NewP->new = malloc ((unsigned) (strlen (Buf) + 1));
  3268.             (void) strcpy (NewP->new, Buf);
  3269.         }
  3270. d393 1
  3271. a393 1
  3272. **    socket connections to the QI server.
  3273. d399 1
  3274. a399 1
  3275. **        0 on success, the appropriate sysexit code if not.
  3276. d418 1
  3277. a418 1
  3278.         return (0);
  3279. d494 1
  3280. a494 1
  3281.     return (0);
  3282. d522 9
  3283. a530 5
  3284.         int    i;
  3285.         char    Buf[MAXSTR];
  3286.         FILE    *Emsg;
  3287.         int    pid;
  3288.         int    ByteLimit = 15000;
  3289. d543 52
  3290. a594 4
  3291.     for (; Addr->original != CPNULL; Addr++)
  3292.         if (abs (Addr->code) != LR_OK)
  3293.             fprintf (Emsg, " %15s    %s\n", Addr->original, Addr->new);
  3294.     /* XXX Loop again here to insert alternatives plus message */
  3295. a818 155
  3296. **  AliasToMail -- format and send a alias lookup to the QI
  3297. **
  3298. **    Takes a presumed QI alias and formats it into a query for the QI.
  3299. **    The response is read by ReadQI, garbage collection is done, and
  3300. **    a pointer to a QI_response struct is returned.
  3301. **
  3302. **    Parameters:
  3303. **        Alias -- a buffer containing a QI alias
  3304. **
  3305. **    Returns:
  3306. **        Pointer to malloc()'ed data with the email address or error
  3307. **        message if any error is found.
  3308. **
  3309. **    Side Effects:
  3310. **        none
  3311. */
  3312.  
  3313. QIR *
  3314. AliasToMail (Alias)
  3315. char    *Alias;
  3316. {
  3317.     QIR    *QIp;            /* response chain pointer */
  3318.     QIR    *tp;            /* garbage collection temp */
  3319.     QIR    *ReadQI();
  3320.     char    *Realloc();
  3321.  
  3322.     /* Make a query out of the arguments */
  3323.     fprintf (ToQI, "query alias=%s return email\n", Alias);
  3324.     if (Debug)
  3325.         printf ("querying for alias \"%s\"\n", Alias);
  3326.     if (Log)
  3327.         syslog (LOG_DEBUG, "querying for alias \"%s\"\n", Alias);
  3328.     (void) fflush (ToQI);
  3329.  
  3330.     /*
  3331.      * Get response.  The possibilities are
  3332.      *
  3333.      * -200: email: <address>
  3334.      * 200:Ok.
  3335.      *
  3336.      * -508:1: email: Not present in entry.
  3337.      * 200:Ok.
  3338.      *
  3339.      * 501:No matches to your query.
  3340.      *
  3341.      * In any case, ignore anything after first response.
  3342.      */
  3343.     QIp = ReadQI (FromQI);
  3344.  
  3345.     /* garbage collect */
  3346.     if (QIp->code < 0) {
  3347.  
  3348.         /* Mark this as the last by making code > 0 */
  3349.         QIp->code *= -1;
  3350.  
  3351.         /* Loop and free message pointers */
  3352.         tp = QIp;
  3353.         do {
  3354.             tp++;
  3355.             if (tp->message != CHNULL)
  3356.                 free (tp->message);
  3357.         } while (tp->code < 0);
  3358.  
  3359.         /* Zap all other than first record */
  3360.         QIp = (QIR *) Realloc ((char *) QIp, sizeof (QIR));
  3361.     }
  3362.     return (QIp);
  3363. }
  3364. /*
  3365. **  CallsignToMail -- Format and send a callsign lookup to the QI
  3366. **
  3367. **    Takes a presumed QI callsign and formats it into a query for the QI.
  3368. **    A pointer to a static array containing the answer or error message
  3369. **    text is returned.  The calling procedure should examine ResponseCode.
  3370. **
  3371. **    Parameters:
  3372. **        CallSign -- a buffer containing a QI callsign
  3373. **        ResponseCode -- integer pointer for result codes
  3374. **
  3375. **    Returns:
  3376. **        Pointer to static data with the email address or error
  3377. **        message if any error is found.
  3378. **
  3379. **    Side Effects:
  3380. **        Modifies ResponseCode to report back errors.
  3381. */
  3382.  
  3383. char *
  3384. CallsignToMail (CallSign, ResponseCode)
  3385. char    *CallSign;
  3386. int    *ResponseCode;
  3387. {
  3388.     static    char    NameVar[MAXSTR];
  3389.  
  3390.     /* Make a query out of the arguments */
  3391.     fprintf (ToQI, "query callsign=%s return email\n", CallSign);
  3392.     if (Debug)
  3393.         printf ("querying for alias \"%s\"\n", CallSign);
  3394.     (void) fflush (ToQI);
  3395.     /* *ResponseCode = XXX; */
  3396.     return (NameVar);
  3397. }
  3398. /*
  3399. **  FullnameToMail -- Format and send a full name lookup to the QI
  3400. **
  3401. **    Takes a presumed QI full name and formats it into a query for the QI.
  3402. **    The response is read by ReadQI, garbage collection is done, and
  3403. **    a pointer to a QI_response struct is returned.
  3404. **
  3405. **    Parameters:
  3406. **        FullName -- a buffer containing a QI name
  3407. **
  3408. **    Returns:
  3409. **        Pointer to malloc()'ed data with the email address and other
  3410. **        data (alias, name, department and curriculum).  If the name
  3411. **        is ambiguous, multiple records chained after the returned
  3412. **        pointer are included.
  3413. **
  3414. **    Side Effects:
  3415. **        None
  3416. */
  3417.  
  3418. QIR *
  3419. FullnameToMail (FullName)
  3420. char    *FullName;
  3421. {
  3422.         QIR    *QIp;        /* response chain pointer */
  3423.         char    scratch[MAXSTR]; /* copy of FullName w.o. punct */
  3424.         char    *sp;        /* work ptr for scratch */
  3425.         int    i;        /* good ol' i */
  3426.     extern    char    PunctChars[];
  3427.         QIR    *ReadQI();
  3428.         char    *Realloc();
  3429.  
  3430.     /* Convert punctuation/separators in the name to space characters. */
  3431.     (void) strcpy (scratch, FullName);
  3432.     for (i = 0; PunctChars[i] != CHNULL; i++)
  3433.         while ((sp = index (scratch, PunctChars[i])) != CPNULL)
  3434.             *sp = ' ';
  3435.  
  3436.     /* Make a query out of the arguments */
  3437.     fprintf (ToQI, "query name=%s return alias name department curriculum email\n", scratch);
  3438.     if (Debug)
  3439.         printf ("querying for name \"%s\"\n", scratch);
  3440.     if (Log)
  3441.         syslog (LOG_DEBUG, "querying for name \"%s\"\n", scratch);
  3442.     (void) fflush (ToQI);
  3443.     
  3444.     /* Grab the responses and let the fun begin */
  3445.     QIp = ReadQI (FromQI);
  3446.  
  3447.     /* Let Query() (the calling routine) sort things out */
  3448.     return (QIp);
  3449. }
  3450. /*
  3451. d894 29
  3452. d929 2
  3453. a930 1
  3454. **    instead of the address.
  3455. d933 1
  3456. a933 2
  3457. **        nbuf -- a buffer containing a QI user name/alias.
  3458. **        nbsize -- the size of nbuf.
  3459. d936 1
  3460. a936 2
  3461. **        An exit code telling if the username was found and
  3462. **        whether an email address was found.
  3463. d940 1
  3464. d945 2
  3465. a946 3
  3466. Query(nbuf, nbsize)
  3467. char    *nbuf;
  3468. int    nbsize;
  3469. d948 5
  3470. a952 3
  3471.         QIR    *EmailQ, *QIp;
  3472.         int    code;            /* Response from ContactQI */
  3473.         int    multi;            /* Set if more than 1 person */
  3474. d954 3
  3475. a956 3
  3476.         QIR    *AliasToMail();
  3477.         char    *CallsignToMail();
  3478.         QIR    *FullnameToMail();
  3479. d959 1
  3480. a959 2
  3481.     if ((code = ContactQI()))
  3482.         return (code);
  3483. d962 1
  3484. a962 2
  3485.      * Try the query as an alias lookup first, then as one of a
  3486.      * possible full name combinations.
  3487. d965 9
  3488. a973 6
  3489.     EmailQ = AliasToMail (nbuf);
  3490.     switch (abs (EmailQ->code)) {
  3491.         case LR_OK:
  3492.         (void) strncpy (nbuf, EmailQ->message, nbsize-2);
  3493.         nbuf[nbsize-1] = CHNULL;
  3494.         return (EmailQ->code);
  3495. d975 35
  3496. a1009 4
  3497.         case LR_ABSENT:
  3498.         (void) strncpy (nbuf, CodeString (EmailQ->code), nbsize-2);
  3499.         nbuf[nbsize-1] = CHNULL;
  3500.         return (EmailQ->code);
  3501. d1011 1
  3502. d1013 19
  3503. a1031 9
  3504. #ifdef notdef
  3505.     /* try as a callsign */
  3506.     EmailP = CallsignToMail (nbuf, &code);
  3507.     if (code != LR_NOMATCH) {
  3508.         (void) strncpy (nbuf, EmailP, nbsize-2);
  3509.         nbuf[nbsize-1] = CHNULL;
  3510.         return (code);
  3511.     }
  3512. #endif notdef
  3513. d1033 3
  3514. d1037 2
  3515. a1038 2
  3516.      * Try as a fullname.  This must be last since no test of
  3517.      * code is done.
  3518. d1040 5
  3519. a1044 7
  3520.     EmailQ = FullnameToMail (nbuf);
  3521.  
  3522.     /* No matches at all? */
  3523.     if (EmailQ->code > 0 && EmailQ->code == LR_NOMATCH) {
  3524.         (void) strncpy (nbuf, CodeString (EmailQ->code), nbsize-2);
  3525.         nbuf[nbsize-1] = CHNULL;
  3526.         return (abs (EmailQ->code));
  3527. d1047 1
  3528. a1047 1
  3529.     /* anything must be multi-line */
  3530. d1051 2
  3531. a1052 2
  3532.     for (QIp = EmailQ, multi = 0; QIp->code < 0 && multi == 0; QIp++)
  3533.         if (QIp->subcode > 1)
  3534. d1054 2
  3535. d1057 1
  3536. a1057 1
  3537.     /* If one person, search for email field */
  3538. d1059 8
  3539. a1066 4
  3540.         for (QIp = EmailQ; QIp->code < 0 && QIp->field != EMAIL; QIp++)
  3541.             ;
  3542.         /* if not EMAIL, something went wrong in the query process */
  3543.         assert (QIp->field == EMAIL);
  3544. d1068 11
  3545. a1078 4
  3546.         if (abs (QIp->code) != LR_OK) {
  3547.             (void) strncpy (nbuf, CodeString (QIp->code), nbsize-2);
  3548.             nbuf[nbsize-1] = CHNULL;
  3549.             return (abs (EmailQ->code));
  3550. a1079 5
  3551.         else {
  3552.             (void) strncpy (nbuf, QIp->message, nbsize-2);
  3553.             nbuf[nbsize-1] = CHNULL;
  3554.             return (abs (QIp->code));
  3555.         }
  3556. d1082 1
  3557. a1082 2
  3558.     /* Multiple matches.  Create the error message listing alternatives. */
  3559.     /* XXX for now, just say that it's a no-no. */
  3560. d1084 3
  3561. a1086 3
  3562.         (void) strncpy (nbuf, CodeString (LR_TOOMANY), nbsize-2);
  3563.         nbuf[nbsize-1] = CHNULL;
  3564.         return (LR_TOOMANY);
  3565. d1088 1
  3566. d1110 1
  3567. d1248 25
  3568. d1305 24
  3569. d1389 2
  3570. a1390 4
  3571.     if (FullText) {
  3572.         while (CopyLeft[which] != CPNULL)
  3573.             printf ("%s\n", CopyLeft[which++]);
  3574.     }
  3575. @
  3576.  
  3577.  
  3578. 1.5
  3579. log
  3580. @Added ReadQI() function.  Working version ready for CallsignToMail()
  3581. and FullnameToMail() to be done.  Famous last words.  -pbp
  3582. @
  3583. text
  3584. @d29 1
  3585. d124 3
  3586. d271 1
  3587. a271 1
  3588.         finis ();
  3589. d325 1
  3590. a325 1
  3591.         if (NewP->code != LR_OK) {
  3592. d332 1
  3593. a332 1
  3594.         if (NewP->code == LR_OK) {
  3595. d492 1
  3596. a492 1
  3597.         if (Addr->code != LR_OK)
  3598. d517 1
  3599. d534 1
  3600. d650 1
  3601. a650 1
  3602.                 if (AddrP->code == LR_OK) {
  3603. d692 1
  3604. d709 1
  3605. d825 2
  3606. a826 2
  3607. **    A pointer to a static array containing the answer or error message
  3608. **    text is returned.  The calling procedure should examine ResponseCode.
  3609. a829 1
  3610. **        ResponseCode -- integer pointer for result codes
  3611. d832 4
  3612. a835 2
  3613. **        Pointer to static data with the email address or error
  3614. **        message if any error is found.
  3615. d838 1
  3616. a838 1
  3617. **        Modifies ResponseCode to report back errors.
  3618. d841 2
  3619. a842 2
  3620. char *
  3621. FullnameToMail (FullName, ResponseCode)
  3622. a843 1
  3623. int    *ResponseCode;
  3624. d845 7
  3625. a851 1
  3626.     static    char    NameVar[MAXSTR];
  3627. d853 6
  3628. d860 1
  3629. a860 1
  3630.     fprintf (ToQI, "query name=%s return email\n", FullName);
  3631. d862 3
  3632. a864 1
  3633.         printf ("querying for alias \"%s\"\n", FullName);
  3634. d866 6
  3635. a871 2
  3636.     /* *ResponseCode = XXX; */
  3637.     return (NameVar);
  3638. d895 1
  3639. a895 1
  3640.         if (Cpnt->key == code)
  3641. d926 1
  3642. a926 1
  3643.         return (FILE_NULL);
  3644. d935 1
  3645. a935 1
  3646.         return (FILE_NULL);
  3647. d944 1
  3648. a944 1
  3649.         return (FILE_NULL);
  3650. d975 3
  3651. a977 2
  3652.         QIR    *EmailQ;
  3653.         int    code;
  3654. d981 1
  3655. a981 1
  3656.         char    *FullnameToMail();
  3657. d993 1
  3658. a993 1
  3659.     switch (EmailQ->code) {
  3660. d999 1
  3661. a999 1
  3662.         case LR_NOMATCH:
  3663. d1007 1
  3664. a1007 1
  3665.     EMailP = CallsignToMail (nbuf, &code);
  3666. d1009 1
  3667. a1009 1
  3668.         (void) strncpy (nbuf, EMailP, nbsize-2);
  3669. d1013 1
  3670. d1019 43
  3671. a1061 5
  3672.     EMailP = FullnameToMail (nbuf, &code);
  3673.     (void) strncpy (nbuf, EMailP, nbsize-2);
  3674.     nbuf[nbsize-1] = CHNULL;
  3675. #endif notdef
  3676.     return (code);
  3677. d1132 1
  3678. d1144 1
  3679. a1144 1
  3680.                     fprintf (stderr, "ReadQI: short #1 fscanf\n");
  3681. d1146 2
  3682. a1147 1
  3683.                     syslog (LOG_ERR, "ReadQI: short #1 fscanf read: %m");
  3684. d1156 1
  3685. a1156 1
  3686.                 fprintf (stderr, "ReadQI: short fscanf\n");
  3687. d1158 2
  3688. a1159 1
  3689.                 syslog (LOG_ERR, "ReadQI: short fscanf read: %m");
  3690. d1247 1
  3691. d1281 1
  3692. @
  3693.  
  3694.  
  3695. 1.4
  3696. log
  3697. @Formatting niceties.
  3698. @
  3699. text
  3700. @d13 1
  3701. d16 1
  3702. d23 1
  3703. a23 1
  3704. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.3 89/05/05 00:11:03 paul Exp Locker: paul $";
  3705. d42 1
  3706. a42 1
  3707. /* designated server port */
  3708. d45 1
  3709. a45 1
  3710. /* the mail transport agent of choice */
  3711. a47 2
  3712. int    PostmasterCC = 0;
  3713.  
  3714. d49 1
  3715. a49 1
  3716. **  PHQUERY -- resolve fuzzy addresses to specific a user@@FQDN
  3717. d90 3
  3718. a92 2
  3719. #define        FILENULL    ((FILE *) NULL)
  3720. #define        NADDNULL    ((struct NewAddress *) NULL)
  3721. d94 3
  3722. d100 2
  3723. a101 2
  3724. FILE    *ToQI = FILENULL;    /* write to the QI */
  3725. FILE    *FromQI = FILENULL;    /* read from the QI */
  3726. d105 4
  3727. a108 1
  3728. /* how program was invoked (argv[0]) for error messages */
  3729. d111 1
  3730. a111 1
  3731. /* exit status for reporting to calling process */
  3732. d114 1
  3733. a114 1
  3734. /* temporary message file */
  3735. d117 1
  3736. a117 1
  3737. /* temporary file for creating error messages */
  3738. d120 1
  3739. a120 1
  3740. /* temporary file for rewriting messages */
  3741. d123 4
  3742. a126 1
  3743. /* how to report events: Debug set for stderr messages, Log for syslog */
  3744. d130 1
  3745. a130 1
  3746. /* from address supplied by caller */
  3747. d143 5
  3748. a147 5
  3749.  " This program is distributed in the hope that it will be useful,",
  3750.  " but without any warranty.  No author or distributor accepts",
  3751.  " responsibility to anyone for the consequences of using it or for",
  3752.  " whether it serves any particular purpose or works at all, unless",
  3753.  " s/he says so in writing.",
  3754. d149 2
  3755. a150 2
  3756.  " Everyone is granted permission to copy, modify and redistribute",
  3757.  " this program under the following conditions:",
  3758. d152 7
  3759. a158 7
  3760.  "    Permission is granted to anyone to make or distribute copies",
  3761.  "    of program source code, either as received or modified, in any",
  3762.  "    medium, provided that all copyright notices, permission and",
  3763.  "    nonwarranty notices are preserved, and that the distributor",
  3764.  "    grants the recipient permission for further redistribution as",
  3765.  "    permitted by this document, and gives him and points out to",
  3766.  "    him an exact copy of this document to inform him of his rights.",
  3767. d160 3
  3768. a162 13
  3769.  "    Permission is granted to distribute this program in compiled",
  3770.  "    or executable form under the same conditions applying for",
  3771.  "    source code, provided that either",
  3772.  "    A. it is accompanied by the corresponding machine-readable",
  3773.  "       source code, or",
  3774.  "    B. it is accompanied by a written offer, with no time limit,",
  3775.  "       to give anyone a machine-readable copy of the corresponding",
  3776.  "       source code in return for reimbursement of the cost of",
  3777.  "       distribution.  This written offer must permit verbatim",
  3778.  "       duplication by anyone.",
  3779.  "    C. it is distributed by someone who received only the",
  3780.  "       executable form, and is accompanied by a copy of the",
  3781.  "       written offer of source code which he received along with it.",
  3782. d164 9
  3783. a172 3
  3784.  " In other words, you are welcome to use, share and improve this",
  3785.  " program.  You are forbidden to forbid anyone else to use, share",
  3786.  " and improve what you give them.   Help stamp out software-hoarding!",
  3787. d174 4
  3788. d179 1
  3789. a179 1
  3790.  "Internet, BITNET: paul@@uxc.cso.uiuc.edu      Phone: 217 359 0881",
  3791. d196 1
  3792. a196 1
  3793.     extern FILE    *OpenTemp();
  3794. d200 1
  3795. d247 1
  3796. a247 1
  3797.     /* fire up logging, or not, as the flags may be */
  3798. d258 2
  3799. a259 2
  3800.     /* open the temp file, copy the message into it */
  3801.     if ((Msg = OpenTemp (TmpFile)) == FILENULL)
  3802. d279 1
  3803. a279 1
  3804.     /* allocate NewAddress structs for addresses */
  3805. d281 1
  3806. a281 1
  3807.         * sizeof (NADD)))) == NADDNULL) {
  3808. d291 1
  3809. a291 1
  3810.     /* loop on addresses in argv building up translation table */
  3811. d297 1
  3812. a297 2
  3813.             fprintf (stderr, "code %d, %s --> %s\n",
  3814.                 NewP->code, *argv, Buf);
  3815. d317 2
  3816. a318 2
  3817.      * now re-invoke sendmail with the translated addresses.
  3818.      * make one pass for collecting error returns into one message.
  3819. d326 1
  3820. a326 1
  3821.     /* any good addresses? */
  3822. d338 1
  3823. a338 1
  3824. **  ContactQI -- connect to the QI server
  3825. d362 2
  3826. a363 2
  3827.     /* already opened */
  3828.     if (ToQI != FILENULL && FromQI != FILENULL) {
  3829. d371 1
  3830. a371 1
  3831.     /* get a socket for the QI connection */
  3832. d383 1
  3833. a383 1
  3834.     /* find the proper port */
  3835. d392 1
  3836. a392 1
  3837.     /* find the proper host */
  3838. d401 1
  3839. a401 1
  3840.     /* connect to the nameserver */
  3841. d422 1
  3842. a422 1
  3843.             /* there are others, I'm sure..... */
  3844. d426 1
  3845. a426 1
  3846.             /* why is this happening? */
  3847. d439 1
  3848. a439 1
  3849.     /* connection ok, change to canonical form */
  3850. d447 3
  3851. a454 1
  3852. **        MsgSelect -- select which error messages to include
  3853. d465 1
  3854. a465 1
  3855. ErrorReturn (Addr, Omsg, envp, MsgSelect)
  3856. a468 1
  3857. int    MsgSelect;
  3858. d477 2
  3859. a478 2
  3860.     /* open the error file */
  3861.     if ((Emsg = OpenTemp (ErrorFile)) == FILENULL)
  3862. d481 1
  3863. a481 1
  3864.     /* insert the headers */
  3865. d508 1
  3866. a508 1
  3867.     if (freopen (ErrorFile, "r", stdin) == FILENULL) {
  3868. d515 1
  3869. a515 1
  3870.     /* zap file so it disappears automagically */
  3871. d580 1
  3872. a580 1
  3873.                  * punt to postmaster.  if there's too
  3874. a608 2
  3875. #define        nequal(s1,s2,n)        (strncasecmp (s1, s2, n) == 0)
  3876.  
  3877. d614 9
  3878. a622 9
  3879.     int        napi = 0;
  3880.     int        i;
  3881.     char        Buf[MAXSTR];
  3882.     NADD        *AddrP;
  3883.     FILE        *Nmsg;
  3884.     int        pid = 0;
  3885.     char        *nap[50];
  3886.     extern FILE    *OpenTemp();
  3887.     extern char    *From;
  3888. d624 2
  3889. a625 2
  3890.     /* open the rewrite file */
  3891.     if ((Nmsg = OpenTemp (NewFile)) == FILENULL)
  3892. d628 1
  3893. a628 1
  3894.     /* fill out the first portion of the sendmail argument vector */
  3895. d633 1
  3896. a633 1
  3897.     /* read and copy the header block, adding the X-PH-To: header */
  3898. d640 1
  3899. a640 1
  3900.             /* write the PH header and add to argv */
  3901. d660 8
  3902. a667 1
  3903.     /* copy the remainder of the message */
  3904. d671 1
  3905. a671 1
  3906.                 perror("Nmsg copy");
  3907. d678 1
  3908. a678 1
  3909.     /* re-arrange the stream pointers and invoke sendmail */
  3910. d681 1
  3911. a681 1
  3912.     if (freopen (NewFile, "r", stdin) == FILENULL) {
  3913. d688 1
  3914. a688 1
  3915.     /* zap file so it disappears automagically */
  3916. d714 2
  3917. a715 2
  3918. **    A pointer to a static array containing the answer or error message
  3919. **    text is returned.  The calling procedure should examine ResponseCode.
  3920. a718 1
  3921. **        ResponseCode -- integer pointer for result codes
  3922. d721 1
  3923. a721 1
  3924. **        Pointer to static data with the email address or error
  3925. d725 1
  3926. a725 1
  3927. **        Modifies ResponseCode to report back errors.
  3928. d728 2
  3929. a729 4
  3930. #define GetQValue(Line) (index(index(index(Line,':')+1,':')+1,':')+2)
  3931.  
  3932. char *
  3933. AliasToMail (Alias, ResponseCode)
  3934. a730 1
  3935. int    *ResponseCode;
  3936. d732 4
  3937. a735 9
  3938.     /* pointer to NameVar returned by this function */
  3939.     static    char    NameVar[MAXSTR];
  3940.         char    scratch[MAXSTR];    /* some space */
  3941.         int    Scode = -1;        /* QI code temporary */
  3942.         int    code;            /* value set by GetNonCom() */
  3943.         int    GotOne = 0;        /* for picking best QI value */
  3944.         int    Leave = 0;
  3945.         int    InRep = 0;
  3946.         char    *CodeString();        /* explicit error messages */
  3947. d737 1
  3948. a737 1
  3949.     /* make a query out of the arguments */
  3950. d741 2
  3951. a742 1
  3952.     syslog (LOG_DEBUG, "querying for alias \"%s\"\n", Alias);
  3953. d745 14
  3954. a758 21
  3955.     do {
  3956.         /* break on read error.  the QI will not return a -1 code */
  3957.         if ((code = GetNonCom(scratch, MAXSTR, FromQI)) == -1)
  3958.             break;
  3959.     
  3960.         /*
  3961.          * test the code from the first field in a qi response.
  3962.          * continuation lines have a leading '-' so the code < 0 .
  3963.          */
  3964.         if (code < 0) {
  3965.             InRep++;
  3966.             Scode = code *= -1;
  3967.         }
  3968.         else
  3969.             InRep = 0;
  3970.         switch (code) {
  3971.             case LR_PROGRESS:
  3972.             case LR_ECHO:
  3973.             case LR_RONLY:
  3974.             Leave = (! InRep) ? 1 : 0;
  3975.             break;
  3976. d760 2
  3977. a761 17
  3978.             case LR_OK:
  3979.             /*
  3980.              * If this is a terminal OK, return previous code if
  3981.              * there was one.
  3982.              */
  3983.             if (! InRep) {
  3984.                 code = (Scode > -1) ? Scode : code;
  3985.                 Leave++;
  3986.             }
  3987.             else if (! GotOne) {
  3988.                 /* record sought after response */
  3989.                 (void) strcpy (NameVar, GetQValue (scratch));
  3990.                 /* strip newline */
  3991.                 NameVar[strlen (NameVar) - 1] = '\0';
  3992.                 GotOne++;
  3993.             }
  3994.             break;
  3995. d763 2
  3996. a764 5
  3997.             case LR_TEMP:
  3998.             case LR_INTERNAL:
  3999.             case LR_LOCK:
  4000.             /* supposedly temporary errors */
  4001.             finis ();
  4002. d766 7
  4003. a772 28
  4004.             case LR_LOGIN:
  4005.             case LR_MORE:
  4006.             case LR_ERROR:
  4007.             case LR_NOMATCH:
  4008.             case LR_TOOMANY:
  4009.             case LR_AINFO:
  4010.             case LR_ASEARCH:
  4011.             case LR_ACHANGE:
  4012.             case LR_NOTLOG:
  4013.             case LR_FIELD:
  4014.             case LR_ABSENT:
  4015.             case LR_ALIAS:
  4016.             case LR_AENTRY:
  4017.             case LR_ADD:
  4018.             case LR_VALUE:
  4019.             case LR_OPTION:
  4020.             case LR_UNKNOWN:
  4021.             case LR_NOKEY:
  4022.             case LR_AUTH:
  4023.             case LR_READONLY:
  4024.             case LR_LIMIT:
  4025.             case LR_HISTORY:
  4026.             case LR_SYNTAX:
  4027.             /* print up a friendly error message */
  4028.             (void) sprintf (NameVar, "%d: %s",
  4029.                 code, CodeString (code));
  4030.             Leave = (! InRep) ? 1 : 0;
  4031.             break;
  4032. d774 4
  4033. a777 10
  4034.             default:
  4035.             (void) sprintf (NameVar, "%d: Unknown nameserver error",
  4036.                 code);
  4037.             PostmasterCC++;
  4038.             Leave = (! InRep) ? 1 : 0;
  4039.             break;
  4040.         }
  4041.     } while (code < 0 || ! Leave);
  4042.     *ResponseCode = (Scode > -1) ? Scode : code;
  4043.     return (NameVar);
  4044. d780 1
  4045. a780 1
  4046. **  CallsignToMail -- format and send a callsign lookup to the QI
  4047. d805 1
  4048. a805 1
  4049.     /* make a query out of the arguments */
  4050. d814 1
  4051. a814 1
  4052. **  FullnameToMail -- format and send a full name lookup to the QI
  4053. d839 1
  4054. a839 1
  4055.     /* make a query out of the arguments */
  4056. a873 39
  4057. **  GetNonCom -- Get a non-comment line from a stream
  4058. **
  4059. **    Read a stream descriptor until a non-comment line is found or EOF.
  4060. **
  4061. **    Parameters:
  4062. **        String - pointer to line storage
  4063. **        maxChars - maximum number of characters to read
  4064. **        InFile - stream to read from
  4065. **
  4066. **    Returns:
  4067. **        integer value of first field in string,
  4068. **        or -1 on EOF or error
  4069. **
  4070. **    Side Effects:
  4071. **        none
  4072. */
  4073.  
  4074. GetNonCom (String, maxChars, InFile)
  4075. char    *String;
  4076. int    maxChars;    
  4077. FILE    *InFile;
  4078. {
  4079.     for (;;) {
  4080.         if (fgets (String, maxChars, InFile) == NULL)
  4081.             return (-1);
  4082.         else if (*String == '#')
  4083.             continue;
  4084.         else if (*String != '-' && ! isdigit (*String)) {
  4085.             if (Debug)
  4086.                 fprintf (stderr, "GetNonCom: bad string: %s",
  4087.                     String);
  4088.             syslog (LOG_ERR, "GetNonCom: bad string: %s", String);
  4089.             continue;
  4090.         }
  4091.         else
  4092.             return (atoi(String));    /* success */
  4093.     }
  4094. }
  4095. /*
  4096. d900 1
  4097. a900 1
  4098.         return (FILENULL);
  4099. d903 1
  4100. a903 1
  4101.     /* protect it */
  4102. d909 1
  4103. a909 1
  4104.         return (FILENULL);
  4105. d912 2
  4106. a913 2
  4107.     /* make fd a stream */
  4108.     if ((Stream = fdopen (fd, "r+")) == FILENULL) {
  4109. d918 1
  4110. a918 1
  4111.         return (FILENULL);
  4112. d949 1
  4113. a949 1
  4114.         char    *EMailP;
  4115. d952 1
  4116. a952 1
  4117.         char    *AliasToMail();
  4118. d965 6
  4119. a970 2
  4120.     if ((EMailP = AliasToMail (nbuf, &code)) != CPNULL)
  4121.         (void) strncpy (nbuf, EMailP, nbsize-1);
  4122. d972 7
  4123. d980 6
  4124. a985 2
  4125.     else if ((EMailP = CallsignToMail (nbuf, &code)) != CPNULL)
  4126.         (void) strncpy (nbuf, EMailP, nbsize-1);
  4127. d987 8
  4128. a994 5
  4129.     /* try as a fullname */
  4130.     else if ((EMailP = FullnameToMail (nbuf, &code)) != CPNULL)
  4131.         (void) strncpy (nbuf, EMailP, nbsize-1);
  4132.     
  4133.     /* return the answer */
  4134. d998 217
  4135. d1264 1
  4136. a1264 1
  4137.     if (ToQI != FILENULL)
  4138. d1266 1
  4139. a1266 1
  4140.     if (FromQI != FILENULL)
  4141. d1268 1
  4142. a1268 1
  4143.     ToQI = FromQI = FILENULL;
  4144. @
  4145.  
  4146.  
  4147. 1.3
  4148. log
  4149. @AliasToMail and PutResponse combined.  Next Fullname/CallsignToMail.  -pbp
  4150. @
  4151. text
  4152. @d21 1
  4153. a21 1
  4154. static char rcsid[] = "@@(#)$Header: /usr/local/src/mail/sendmail/uiuc/RCS/phquery.c,v 1.1 89/02/13 16:07:39 paul Exp Locker: paul $";
  4155. d96 2
  4156. a97 2
  4157. FILE    *ToQI = FILENULL;        /* write to the QI */
  4158. FILE    *FromQI = FILENULL;        /* read from the QI */
  4159. d169 1
  4160. a169 1
  4161.  "Internet, BITNET: paul@@uxc.cso.uiuc.edu",
  4162. d178 8
  4163. a185 8
  4164.     extern int    optind;        /* from getopt () */
  4165.     extern char    *optarg;    /* from getopt () */
  4166.     int        option;        /* option "letter" */
  4167.     int        i;        /* good ol' i */
  4168.     FILE        *Msg;        /* stream pointer for temp file */
  4169.     NADD        *New, *NewP;    /* translated addresses */
  4170.     char        Buf[MAXSTR];
  4171.     extern char    *malloc(), *rindex();
  4172. d197 1
  4173. d345 6
  4174. a350 6
  4175.     int             sock;    /* our socket */
  4176.     int        sav_errno;
  4177.     struct sockaddr_in QI;    /* the address of the nameserver */
  4178.     struct servent *theNs;    /* nameserver service entry */
  4179.     struct hostent *theHost;/* host entry for nameserver */
  4180.     extern FILE    *ToQI, *FromQI;
  4181. d358 1
  4182. a358 1
  4183.     if (Debug > 1)
  4184. d362 1
  4185. a362 2
  4186.     sock = socket(AF_INET, SOCK_STREAM, 0);
  4187.     if (sock < 0)
  4188. d374 2
  4189. a375 2
  4190.     if (theNs = getservbyname (QISERVICE, "tcp")) {
  4191.         QI.sin_port = theNs->s_port;
  4192. d383 2
  4193. a384 2
  4194.     if (theHost = gethostbyname (QI_HOST)) {
  4195.         bcopy (theHost->h_addr, (char *) &QI.sin_addr.s_addr, 4);
  4196. d429 1
  4197. a429 1
  4198.     /* connection ok, put it into canonical form */
  4199. d442 1
  4200. d453 1
  4201. a453 1
  4202. ErrorReturn (Addr, Omsg, envp)
  4203. d457 1
  4204. d459 6
  4205. a464 6
  4206.     int        i;
  4207.     char        Buf[MAXSTR];
  4208.     FILE        *Emsg;
  4209.     int        pid;
  4210.     int        ByteLimit = 15000;
  4211.     extern FILE    *OpenTemp();
  4212. d479 1
  4213. d702 1
  4214. a702 1
  4215. **        theAlias -- a buffer containing a QI alias
  4216. d716 2
  4217. a717 2
  4218. AliasToMail (theAlias, ResponseCode)
  4219. char    *theAlias;
  4220. d731 1
  4221. a731 1
  4222.     fprintf (ToQI, "query alias=%s return email\n", theAlias);
  4223. d733 2
  4224. a734 2
  4225.         printf ("querying for alias \"%s\"\n", theAlias);
  4226.     syslog (LOG_DEBUG, "querying for alias \"%s\"\n", theAlias);
  4227. d847 1
  4228. a847 1
  4229.     static char NameVar[MAXSTR];
  4230. d881 1
  4231. a881 1
  4232.     static char NameVar[MAXSTR];
  4233. d909 2
  4234. a910 2
  4235.     struct ReplyCodes        *Cpnt;
  4236.     extern struct ReplyCodes    Codes[];
  4237. d923 1
  4238. a923 1
  4239. **        theString - pointer to line storage
  4240. d925 1
  4241. a925 1
  4242. **        theFile - stream to read from
  4243. d935 2
  4244. a936 2
  4245. GetNonCom (theString, maxChars, theFile)
  4246. char    *theString;
  4247. d938 1
  4248. a938 1
  4249. FILE    *theFile;
  4250. d941 1
  4251. a941 1
  4252.         if (fgets (theString, maxChars, theFile) == NULL)
  4253. d943 1
  4254. a943 1
  4255.         else if (*theString == '#')
  4256. d945 1
  4257. a945 1
  4258.         else if (*theString != '-' && ! isdigit (*theString)) {
  4259. d948 2
  4260. a949 2
  4261.                     theString);
  4262.             syslog (LOG_ERR, "GetNonCom: bad string: %s", theString);
  4263. d953 1
  4264. a953 1
  4265.             return (atoi(theString));    /* success */
  4266. d1032 6
  4267. a1037 6
  4268.     char        *EMailP;
  4269.     int        code;
  4270.     extern FILE    *ToQI, *FromQI;
  4271.     char        *AliasToMail();
  4272.     char        *CallsignToMail();
  4273.     char        *FullnameToMail();
  4274. d1081 1
  4275. a1081 1
  4276.     int        which = 0;        /* current line */
  4277. d1109 1
  4278. a1109 1
  4279.     extern FILE    *ToQI, *FromQI;
  4280. @
  4281.  
  4282.  
  4283. 1.2
  4284. log
  4285. @Checking in clean-ups before renovation.  -pbp
  4286. @
  4287. text
  4288. @d22 3
  4289. a24 1
  4290. #endif /* not lint */
  4291. a103 3
  4292. /* global status variable */
  4293. int    ResponseCode;
  4294.  
  4295. d219 1
  4296. d225 1
  4297. d392 1
  4298. a392 1
  4299.     if (connect(sock, &QI, sizeof (QI)) < 0)
  4300. a579 120
  4301. **  PutResponse  -- insert first successful response from QI into a string
  4302. **
  4303. **    Take the result returned from a QI query and and pack it into the
  4304. **    argument string.  This can be either the email address or the error
  4305. **    message.  The return code must be examined to tell which.
  4306. **    Because the QI returns different formats depending on the answer,
  4307. **    a FSM is used to process the response.
  4308. **
  4309. **    Parameters:
  4310. **        NameVar - string to store the QI response into
  4311. **
  4312. **    Returns:
  4313. **        The code status from QI
  4314. **
  4315. **    Side Effects:
  4316. **        none
  4317. */
  4318.  
  4319. #define GetQValue(aLine) (index(index(index(aLine,':')+1,':')+1,':')+2)
  4320.  
  4321. PutResponse (NameVar)
  4322. char    *NameVar;
  4323. {
  4324.     char            scratch[MAXSTR];    /* some space */
  4325.     int             Scode = -1;
  4326.     int        code;
  4327.     int             GotOne = 0;
  4328.     int        Leave = 0;
  4329.     int        InRep = 0;
  4330.     int        i;
  4331.     char        *CodeString();
  4332.  
  4333.     while ((i = GetGood(scratch, MAXSTR, FromQI)) >= 0) {    /* read it */
  4334.  
  4335.         /* break on read error */
  4336.         if (i == -1)
  4337.             break;
  4338.     
  4339.         /*
  4340.          * get the code from the first field in scratch.  continuation
  4341.          * lines have a leading '-' so the code will be negative for
  4342.          * them.
  4343.          */
  4344.         if ((code = atoi (scratch)) < 0) {
  4345.             InRep++;
  4346.             code *= -1;
  4347.             Scode = code;
  4348.         }
  4349.         else
  4350.             InRep = 0;
  4351.         switch (code) {
  4352.             case LR_PROGRESS:
  4353.             case LR_ECHO:
  4354.             case LR_RONLY:
  4355.             Leave = (! InRep) ? 1 : 0;
  4356.             break;
  4357.  
  4358.             case LR_OK:
  4359.             /*
  4360.              * if this is a terminal OK, return previous code if
  4361.              * there was one
  4362.              */
  4363.             if (! InRep)
  4364.                 return ((Scode > -1) ? Scode : code);
  4365.             else if (! GotOne) {
  4366.                 /* record sought after response */
  4367.                 (void) strcpy (NameVar, GetQValue (scratch));
  4368.                 /* strip newline */
  4369.                 NameVar[strlen (NameVar) - 1] = '\0';
  4370.                 GotOne++;
  4371.             }
  4372.             break;
  4373.  
  4374.             case LR_TEMP:
  4375.             case LR_INTERNAL:
  4376.             case LR_LOCK:
  4377.             /* supposedly temporary errors */
  4378.             finis ();
  4379.  
  4380.             case LR_LOGIN:
  4381.             case LR_MORE:
  4382.             case LR_ERROR:
  4383.             case LR_NOMATCH:
  4384.             case LR_TOOMANY:
  4385.             case LR_AINFO:
  4386.             case LR_ASEARCH:
  4387.             case LR_ACHANGE:
  4388.             case LR_NOTLOG:
  4389.             case LR_FIELD:
  4390.             case LR_ABSENT:
  4391.             case LR_ALIAS:
  4392.             case LR_AENTRY:
  4393.             case LR_ADD:
  4394.             case LR_VALUE:
  4395.             case LR_OPTION:
  4396.             case LR_UNKNOWN:
  4397.             case LR_NOKEY:
  4398.             case LR_AUTH:
  4399.             case LR_READONLY:
  4400.             case LR_LIMIT:
  4401.             case LR_HISTORY:
  4402.             case LR_SYNTAX:
  4403.             (void) sprintf (NameVar, "%d: %s",
  4404.                 code, CodeString (code));
  4405.             Leave = (! InRep) ? 1 : 0;
  4406.             break;
  4407.  
  4408.             default:
  4409.             (void) sprintf (NameVar, "%d: Unknown nameserver error",
  4410.                 code);
  4411.             PostmasterCC++;
  4412.             Leave = (! InRep) ? 1 : 0;
  4413.             break;
  4414.         }
  4415.         if (Leave)
  4416.             break;
  4417.     }
  4418.     return ((Scode > -1) ? Scode : code);
  4419. }
  4420. /*
  4421. d643 1
  4422. a643 9
  4423.         if (nequal (Buf, "Message-id:", 11))
  4424.             fprintf (Nmsg, "X-Old-%s", Buf);
  4425.         else if (fputs (Buf, Nmsg) == EOF) {
  4426.             if (Debug)
  4427.                 perror ("ReMail");
  4428.             if (Log)
  4429.                 syslog (LOG_ERR, "ReMail: %m");
  4430.             finis ();
  4431.         }
  4432. d695 2
  4433. a696 3
  4434. **    A pointer to a static array containing the answer is returned.
  4435. **    If the NULL pointer is returned, the calling procedure should
  4436. **    examine ResponseCode.
  4437. d700 1
  4438. d707 1
  4439. a707 2
  4440. **        Will call ContactQI() if the connection is closed.
  4441. **        Uses ResponseCode to report back errors.
  4442. d710 2
  4443. d713 1
  4444. a713 1
  4445. AliasToMail (theAlias)
  4446. d715 1
  4447. d717 9
  4448. a725 1
  4449.     static char NameVar[MAXSTR];
  4450. a726 3
  4451.     if ((ResponseCode = ContactQI()))
  4452.         return (CPNULL);
  4453.  
  4454. d731 1
  4455. d733 85
  4456. a817 1
  4457.     ResponseCode = PutResponse (NameVar);
  4458. d821 68
  4459. d915 1
  4460. a915 1
  4461. **  GetGood -- Get a non-comment line from a stream
  4462. d925 2
  4463. a926 1
  4464. **        1 on success, 0 if comment, -1 on EOF or error
  4465. d932 1
  4466. a932 1
  4467. GetGood (theString, maxChars, theFile)
  4468. d940 11
  4469. a950 4
  4470.         if (*theString == '#')
  4471.             return (0);    /* a comment */
  4472.         else 
  4473.             return (1);    /* success */
  4474. d1020 1
  4475. d1033 2
  4476. d1036 4
  4477. d1045 1
  4478. a1045 2
  4479.     if ((EMailP = AliasToMail (nbuf)) != CPNULL) {
  4480.         code = ResponseCode;
  4481. a1046 1
  4482.     }
  4483. a1047 1
  4484. #ifdef notdef
  4485. d1049 1
  4486. a1049 2
  4487.     else if ((EMailP = CallsignToMail (nbuf)) != CPNULL) {
  4488.         code = ResponseCode;
  4489. a1050 1
  4490.     }
  4491. d1053 1
  4492. a1053 2
  4493.     else if ((EMailP = FullnameToMail (nbuf)) != CPNULL) {
  4494.         code = ResponseCode;
  4495. a1054 2
  4496.     }
  4497. #endif notdef
  4498. a1055 5
  4499.     /* give it up, return code */
  4500.     else {
  4501.         code = ResponseCode;
  4502.     }
  4503.  
  4504. d1069 1
  4505. a1069 1
  4506. **        none, exit (1)
  4507. d1072 1
  4508. a1072 1
  4509. **        program terminates
  4510. a1089 1
  4511.     finis ();
  4512. @
  4513.  
  4514.  
  4515. 1.1
  4516. log
  4517. @Initial revision
  4518. @
  4519. text
  4520. @d21 1
  4521. a21 1
  4522. static char rcsid[] = "@@(#)$Header$";
  4523. a33 1
  4524. #include <errno.h>
  4525. d89 1
  4526. d102 3
  4527. d125 1
  4528. a125 1
  4529.     "usage: %s [-d] [-p] [-l] [-i] [-f FromAddress] address1 [address2]",
  4530. a128 8
  4531. struct    NewAddress {
  4532.     char    *original;
  4533.     char    *new;
  4534.     int    code;
  4535. };
  4536.  
  4537. typedef    struct NewAddress NADD;
  4538.  
  4539. d191 1
  4540. a191 1
  4541.     while ((option = getopt (argc, argv, "f:r:pdli")) != EOF) {
  4542. d197 9
  4543. d268 1
  4544. a268 1
  4545.         * sizeof (NADD)))) == (NADD *) NULL) {
  4546. d824 1
  4547. a824 1
  4548. **    examine errno.
  4549. d835 1
  4550. a835 1
  4551. **        Uses errno to report back errors.
  4552. d844 1
  4553. a844 1
  4554.     if ((errno = ContactQI()))
  4555. d852 1
  4556. a852 1
  4557.     errno = PutResponse (NameVar);
  4558. d964 1
  4559. a964 1
  4560. **    Takes a full name or user alias, as known by the CSnet central
  4561. d987 1
  4562. a987 1
  4563.     char        *email_p;
  4564. d997 3
  4565. a999 3
  4566.     if ((email_p = AliasToMail(nbuf)) != CPNULL) {
  4567.         code = errno;
  4568.         (void) strncpy (nbuf, email_p, nbsize-1);
  4569. d1002 14
  4570. a1015 4
  4571.     /*
  4572.      * try formatting the name into a full name
  4573.      */
  4574.  
  4575. d1018 1
  4576. a1018 1
  4577.         code = errno;
  4578. @
  4579.