|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T p
Length: 99524 (0x184c4) Types: TextFile Names: »phquery.c,v«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit └─⟦bfebc70e2⟧ »EurOpenD3/mail/sendmail-5.65b+IDA-1.4.3.tar.Z« └─⟦f9e35cd84⟧ └─⟦this⟧ »sendmail/uiuc/RCS/phquery.c,v«
head 1.20; access; symbols; locks paul:1.20; strict; comment @ * @; 1.20 date 91.01.26.21.10.29; author paul; state Exp; branches; next 1.19; 1.19 date 90.12.11.12.25.50; author paul; state Exp; branches; next 1.18; 1.18 date 90.12.10.21.58.27; author paul; state Exp; branches; next 1.17; 1.17 date 90.12.10.14.09.03; author paul; state Exp; branches; next 1.16; 1.16 date 90.06.11.10.52.40; author paul; state Exp; branches; next 1.15; 1.15 date 90.01.30.23.51.30; author paul; state Exp; branches; next 1.14; 1.14 date 89.07.28.10.05.12; author paul; state Exp; branches; next 1.13; 1.13 date 89.07.27.23.19.22; author paul; state Exp; branches; next 1.12; 1.12 date 89.05.24.00.11.48; author paul; state Exp; branches; next 1.11; 1.11 date 89.05.16.16.59.36; author paul; state Exp; branches; next 1.10; 1.10 date 89.05.11.17.20.48; author paul; state Exp; branches; next 1.9; 1.9 date 89.05.10.11.50.49; author paul; state Exp; branches; next 1.8; 1.8 date 89.05.10.00.57.49; author paul; state Exp; branches; next 1.7; 1.7 date 89.05.09.22.53.57; author paul; state Exp; branches; next 1.6; 1.6 date 89.05.08.23.21.20; author paul; state Exp; branches; next 1.5; 1.5 date 89.05.08.20.40.14; author paul; state Exp; branches; next 1.4; 1.4 date 89.05.05.11.26.06; author paul; state Exp; branches; next 1.3; 1.3 date 89.05.05.00.11.03; author paul; state Exp; branches; next 1.2; 1.2 date 89.05.01.15.26.34; author paul; state Exp; branches; next 1.1; 1.1 date 89.02.13.16.07.39; author paul; state Exp; branches; next ; desc @Fuzzy address resolver. Links sendmail with ph/qi. @ 1.20 log @Changes for 4.4 BSD and to handle backup QI server (QI_ALT in Makefile). @ text @/* * Copyright (c) 1989 Paul Pomes * Copyright (c) 1989 University of Illinois Board of Trustees * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of Illinois, Urbana. In addition, redistribution * and use must conform to the terms listed in the CopyLeft text below. * * The name of the University may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef lint 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 $"; #endif /* lint */ #include <stdio.h> #include <assert.h> #include <sys/types.h> #include <sys/param.h> #if defined(pyr) || defined(is68k) || defined(NeXT) || defined(__convex__) \ || defined(BSD4_4) # include <sys/time.h> # include <sys/vnode.h> # define IREAD VREAD # define IWRITE VWRITE #else /* ! pyr && ! is68k */ # if defined(sun) || defined(convex) # include <sys/stat.h> # define IREAD S_IREAD # define IWRITE S_IWRITE # else /* ! sun && ! convex */ # include <sys/inode.h> # endif /* sun || convex */ #endif /* pyr || is68k */ #include <netdb.h> #include <ctype.h> #include <sys/socket.h> #include <sys/syslog.h> #include <sys/errno.h> #include <sys/wait.h> #include <netinet/in.h> #include <sysexits.h> #include <strings.h> #include "phquery.h" #define VERSION "3.6" /* Domain to append to ph aliases when creating Reply-To: fields */ #ifndef DOMAIN # define DOMAIN "uiuc.edu" #endif /* DOMAIN */ /* Designated server port */ #define QISERVICE "ns" /* Mail transport agent of choice */ #if defined(BSD4_4) #define SENDMAIL "/usr/sbin/sendmail" #else /* !BSD4_4 */ #define SENDMAIL "/usr/lib/sendmail" #endif /* BSD4_4 */ /* How to print/log error messages */ #define DANGER_WILL_ROBINSON(KateBush) \ { if (Debug) \ perror (KateBush); \ if (Log) \ syslog (LOG_ERR, strcat (KateBush, ": %m")); \ finis (); } /* ** PHQUERY -- Resolve fuzzy addresses to specific a user@@FQDN ** ** FQDN := Fully Qualified Domain Name ** Phquery is invoked as a mailer (not a final mailer!) by sendmail ** to resolve addresses of the form user@@DOMAINMASTER where DOMAINMASTER ** is a m4 define used in building an IDA sendmail.cf file. At UIUC ** this would be user@@uiuc.edu . The user token is interpreted first ** as a QI alias, then as a full name if that fails. QI is the CSnet ** Query Interpreter. At UIUC it contains the entire campus phone ** directory plus the unit directory. A user entry has about as many ** fields as ls has option letters. The most important are alias, name, ** email, phone, department, and curriculum. In the simplest case, ** matching an alias (guaranteed unique) returns the email address. ** ** Since life is seldom simple, the alternate cases/actions are summarized ** ** a) alias match, email found ** write a X-PH-To: header with the email address found, copy the ** rest of the message, and re-invoke sendmail ** OR ** write a X-PH: VX.Y@@<host> and re-invoke sendmail. This is ** useful for sites that don't wish to expand alias lists in the ** header block. ** b) alias match, no email field: ** return public fields of ph entry and suggest phone usage ** c) alias match, bogus email field: ** sendmail catches this one. The user will see the X-PH-To: ** header. Not the best so far..... ** d) alias fail: ** try name field ** e) single name match, email present: ** deliver as in a) ** f) single name match, no email field: ** handle as in b) ** g) single name match, bogus email field: ** handle as in c) ** h) multiple (<5) name matches: ** return alias, name, email, and dept fields of matches ** i) multiple (>5) name matches: ** return "too ambiguous" message ** ** Phquery is also used to create return addresses of the form ** ph-alias@@DOMAINMASTER. This is implemented by adding the fields ** ** Resent-From: postmaster@@<host> ** Reply-To: ph-alias@@DOMAINMASTER ** Comment: Reply-To: added by phquery (Vx.y) ** ** N.B., RFC-822, Section 4.4.1 requires that the From / Resent-From ** fields be a single, authenticated machine address. */ /* some handy defines */ #define CHNULL ('\0') #define CPNULL ((char *) NULL) #define FILE_NULL ((FILE *) NULL) #define NADD_NULL ((struct NewAddress *) NULL) #define QIR_NULL ((struct QI_response *) NULL) /* some handy compare operators */ #define nequal(s1,s2,n) (strncasecmp (s1, s2, n) == 0) #define equal(s1,s2) (strcasecmp (s1, s2) == 0) /* large string size */ #define MAXSTR 250 /* Bit flags to control printing of informative messages in ErrorReturn() */ #define NO_MATCH_MSG 0x1 #define MULTI_MSG 0x2 #define ABSENT_MSG 0x4 #define TOO_MANY_MSG 0x8 #define PHONE_MSG 0x10 /* Messages for ErrorReturn(). How simple, yet stupid, do we have to be? */ char *NoMatchMsg[] = { " The message, \"No matches to nameserver query,\" is generated whenever", " the ph nameserver fails to locate either a ph alias or name field that", " matches the supplied name. The usual causes are typographical errors or", " the use of nicknames. Recommended action is to use the ph program to", " determine the correct ph alias for the individuals addressed. If ph is", " not available, try sending to the most explicit form of the name, e.g.,", " if mike-fox fails, try michael-j-fox.", " ", CPNULL }; char *MultiMsg[] = { " The message, \"Multiple matches found for nameserver query,\" is generated", " whenever the ph nameserver finds multiple matches for the supplied name.", " The steering philosophy is that mail should be delivered only to the", " addressed individual. Since the supplied information is insufficient", " to locate a specific individual, your message is being returned.", " To help you locate the correct individual, selected fields from the", " possible matches are included below. The alias field is the only one", " guaranteed unique within a given ph community.", " ", CPNULL }; char *TooManyMsg[] = { " The message, \"Too many matches found to nameserver query,\" is generated", " whenever the supplied name or alias matched over twenty ph nameserver", " entries. In this case no information will be returned about possible", " matches. Recommended action is to supply more specific names, e.g.,", " john-b-smith instead of john-smith, or use the per-person unique ph alias.", " You may have thought that you had used a ph alias and not a name. This is", " an artifact of the address resolution process. If the address fails as an", " alias, it is retried first as a callsign and then as a name. While aliases", " are guaranteed unique, names can match multiple individuals depending on", " how common the name is.", " ", CPNULL }; char *AbsentMsg[] = { " The message, \"E-mail field not present in nameserver entry,\" is generated", " whenever the ph nameserver matched the supplied name or alias with an", " entry that lacked an email address field. In this case no delivery can", " be made. Recommended action is to contact the individual by alternate", " means via the information included below. If the individual already has", " an email address, s/he should edit their ph entry to include it.", " ", CPNULL }; char *PhoneMsg[] = { " A note regarding phone numbers: the UIUC area code is 217. There are three", " exchanges used by UIUC: 333, 332, and 244. UIUC phone numbers are often", " abbreviated by omitting the first two digits of the exchange. Thus the", " example phone number 3-6262 can be reached by dialing 1 217 333 6262.", " ", CPNULL }; FILE *ToQI = FILE_NULL; /* write to the QI */ FILE *FromQI = FILE_NULL; /* read from the QI */ extern int errno; /* Set to carbon-copy postmaster on error returns */ int PostmasterCC = 0; /* Set if the reply-to: field on outgoing mail is to inserted */ int ReplyTo = 0; /* Hostname of this machine */ char HostNameBuf[100]; /* How program was invoked (argv[0]) for error messages */ char *MyName; /* Exit status for finis() reporting to calling process */ int ExitStat = EX_TEMPFAIL; /* Temporary message file */ char TmpFile[] = "/tmp/PhMailXXXXXXX"; /* Temporary file for creating error messages */ char ErrorFile[] = "/tmp/PhErrMailXXXXXXX"; /* Temporary file for rewriting messages */ char NewFile[] = "/tmp/PhNewMailXXXXXXX"; /* * The types of nameserver queries to make. * N.B., Query() assumes that "name" is the last token in this list. * Also be sure to duplicate any extra keywords added to TryList to the * query fprintf near the top of Query(). */ char *TryList[] = { "alias", "callsign", "name", CPNULL }; /* * How to report events: Debug set for stderr messages, Log for syslog. * Setting Debug disables vfork/execve in ReMail. */ int Debug = 0; int Log = 1; /* From address supplied by caller */ char *From = CPNULL; char *usage[] = { "usage: %s [-d] [-p] [-s] [-l] [-R] [-i] [-x service] [-f FromAddress] address1 [address2]", CPNULL }; char *Malloc(), *Realloc(); #if !defined(__STDC__) char *malloc(), *realloc(); #endif /* !__STDC__ */ char *CopyLeft[] = { " Written by Paul Pomes, University of Illinois, Computing Services Office", " Copyright (C) 1989 by Paul Pomes and the University of Illinois Board", " of Trustees", " ", " This program is distributed in the hope that it will be useful, but without", " any warranty. No author or distributor accepts responsibility to anyone", " for the consequences of using it, no matter how awful, or for whether it", " serves any particular purpose or works at all, unless s/he says so in", " writing.", " ", " Everyone is granted permission to copy, modify and redistribute this", " program under the following conditions:", " ", " Permission is granted to anyone to make or distribute copies of program", " source code, either as received or modified, in any medium, provided", " that all copyright notices, permission and nonwarranty notices are", " preserved, and that the distributor grants the recipient permission for", " further redistribution as permitted by this document, and gives him and", " points out to him an exact copy of this document to inform him of his", " rights.", " ", " Permission is granted to distribute this program in compiled or", " executable form under the same conditions applying for source code,", " provided that either", " ", " A. it is accompanied by the corresponding machine-readable source code,", " or", " B. it is accompanied by a written offer, with no time limit, to give", " anyone a machine-readable copy of the corresponding source code in", " return for reimbursement of the cost of distribution. This written", " offer must permit verbatim duplication by anyone.", " C. it is distributed by someone who received only the executable form,", " and is accompanied by a copy of the written offer of source code", " which he received along with it.", " ", " In other words, you are welcome to use, share and improve this program.", " You are forbidden to forbid anyone else to use, share and improve what", " you give them. Help stamp out software-hoarding!", " ", "UUCP: {att,iuvax,uunet}!uiucuxc!paul ICBM: 40 06 47 N / 88 13 35 W", "Internet, BITNET: paul@@uxc.cso.uiuc.edu Phone: 217 333 6262", "US Mail: UofIllinois, CSO, 1304 W Springfield Ave, Urbana, IL 61801-2910", CPNULL }; main(argc, argv, envp) int argc; char *argv[], *envp[]; { extern int optind; /* from getopt () */ extern char *optarg; /* from getopt () */ int option; /* option "letter" */ int i; /* good ol' i */ char *Service = CPNULL; /* ph alias from -x */ FILE *Msg; /* stream pointer for temp file */ NADD *New, *NewP; /* translated addresses */ char Buf[MAXSTR]; extern char HostNameBuf[]; extern FILE *OpenTemp(); MyName = ((MyName = rindex (*argv, '/')) == CPNULL) ? *argv : (MyName + 1); while ((option = getopt (argc, argv, "f:r:x:pRsdli")) != EOF) { switch (option) { case 'f': From = optarg; break; case 'x': Service = optarg; break; case 'R': /* Re-write outgoing address with Reply-To: field */ ReplyTo++; break; case 's': /* Designated humor section for humor-less CSO types */ if (Debug) { fprintf (stderr, "Checking Figure 1 ......"); (void) fflush (stderr); sleep (2); fprintf (stderr, "done.\n"); } break; case 'r': From = optarg; break; case 'p': PostmasterCC++; break; case 'l': Log++; break; case 'd': Debug++; if (Debug == 1) PrtUsage (1); Log = 0; break; case 'i': PrtUsage (1); finis (); break; default: PrtUsage (0); finis (); break; } } argc -= optind; /* skip options */ argv += optind; /* Fire up logging, or not, as the flags may be */ if (Log) #ifdef LOG_MAIL # ifndef SYSLOG # define SYSLOG LOG_MAIL # endif openlog(MyName, LOG_PID, SYSLOG); #else openlog(MyName, LOG_PID); #endif if (Log) syslog (LOG_DEBUG, "From %s", From); /* fetch our host name, some use will be found for it.... */ if (gethostname (HostNameBuf, 100-1) != 0) DANGER_WILL_ROBINSON("gethostname") /* Open the temp file, copy the message into it */ if ((Msg = OpenTemp (TmpFile)) == FILE_NULL) finis (); while ((i = fread (Buf, sizeof (char), MAXSTR, stdin)) != 0) if (fwrite (Buf, sizeof (char), i, Msg) != i) DANGER_WILL_ROBINSON("Msg copy") (void) fflush (Msg); /* * Remaining arguments are addresses. If From == CHNULL, * then submission was done locally and return address has * to be on the From: line. */ if (From == CPNULL || (From != CPNULL && From == CHNULL)) FindFrom (Msg); if (ReplyTo) { /* * Check with QI to see if this person has a email entry. * If so add the Resent-From, Reply-To, and Comment fields. * Then invoke ReMail with xyzzy appended to the From address * so that sendmail won't send it back to us. If a * Reply-To: field is already present, handle as though no * email field was found. */ /* * Allocate NewAddress structs for from address, to addresses, * plus 1 for terminal null. */ New = (NADD *) Malloc ((unsigned) ((argc+2) * sizeof (NADD))); (New + argc + 1)->original = CPNULL; NewP = New; RevQuery (NewP); assert (NewP->new != CPNULL); /* If a single alias was found, append the domain */ if (abs (NewP->code) == LR_OK) { NewP->new = Realloc (NewP->new, (unsigned) (strlen (NewP->new) + strlen (DOMAIN) + 2)); (void) strcat (NewP->new, "@@"); (void) strcat (NewP->new, DOMAIN); } /* Add To: addresses to NewP array */ NewP++; while (argc > 0) { NewP->original = *argv; NewP->new = CPNULL; NewP++; argv++; argc--; } /* ReMail will add the new headers and call sendmail */ ReMail (New, Msg, envp); /* We done good. */ ExitStat = EX_OK; finis (); } /* * If not a ReplyTo ... * Allocate NewAddress structs for addresses (or just one if this * is a service forward. */ i = (Service == CPNULL) ? argc : 1; New = (NADD *) Malloc ((unsigned) ((i+1) * sizeof (NADD))); (New + i)->original = CPNULL; NewP = New; if (Service != CPNULL) { NewP->original = Service; NewP->new = CPNULL; Query (NewP); assert (NewP->new != CPNULL); if (Debug) printf ("code %d, %s --> %s\n", NewP->code, NewP->original, NewP->new); if (Log) syslog (LOG_INFO, "%s --> %s", NewP->original, NewP->new); } else /* Loop on addresses in argv building up translation table */ while (argc > 0) { NewP->original = *argv; NewP->new = CPNULL; Query (NewP); assert (NewP->new != CPNULL); if (Debug) printf ("code %d, %s --> %s\n", NewP->code, NewP->original, NewP->new); if (Log) syslog (LOG_INFO, "%s --> %s", NewP->original, NewP->new); NewP++; argv++; argc--; } /* * Now re-invoke sendmail with the translated addresses. * Make one pass for collecting error returns into one message. */ for (NewP = New; NewP->original != CPNULL; NewP++) if (abs (NewP->code) != LR_OK) { ErrorReturn (NewP, Msg, envp); break; } /* Any good addresses? */ for (NewP = New; NewP->original != CPNULL; NewP++) if (abs (NewP->code) == LR_OK) { ReMail (NewP, Msg, envp); break; } /* exit */ ExitStat = EX_OK; finis (); } \f /* ** ContactQI -- Connect to the QI server ** ** Examine the ToQI and FromQI file descriptors. If NULL, open ** socket connections to the QI server. Exits on any error. ** ** Parameters: ** none ** ** Returns: ** None ** ** Side Effects: ** Changes ToQI and FromQI if an open is done. */ ContactQI () { int sock; /* our socket */ struct sockaddr_in QI; /* the address of the nameserver */ struct servent *Ns; /* nameserver service entry */ struct hostent *Host; /* host entry for nameserver */ char *QiHost = QI_HOST; /* Initial Qi server */ extern FILE *ToQI, *FromQI; /* read/write streams to QI */ /* Already opened... */ if (ToQI != FILE_NULL && FromQI != FILE_NULL) { if (Debug) printf("ToQI/FromQI already opened\n"); return; } if (Debug) printf("opening ToQI/FromQI\n"); /* Locate the proper port */ if (Ns = getservbyname (QISERVICE, "tcp")) { QI.sin_port = Ns->s_port; } else { if (Debug) fprintf (stderr, "server \"%s\" unknown - using 105", QISERVICE); if (Log) syslog (LOG_ERR, "server \"%s\" unknown - using 105", QISERVICE); QI.sin_port = 105; } QI.sin_family = AF_INET; again: /* Get a socket for the QI connection */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { if (Log) syslog (LOG_ERR, "ContactQI: socket(): %m"); if (Debug) fprintf (stderr, "ContactQI: can't create socket"); finis(); } /* Locate the proper host */ if (Host = gethostbyname (QiHost)) { bcopy (Host->h_addr, (char *) &QI.sin_addr.s_addr, 4); } else { if (Log) syslog (LOG_ERR, "ContactQI: gethostbyname(%s): %m", QiHost); if (Debug) { fprintf (stderr, "gethostbyname(%s):", QiHost); perror (""); } finis(); } /* Connect to the nameserver */ if (connect (sock, (struct sockaddr *) &QI, sizeof (QI)) < 0) { if (Log) syslog (LOG_INFO, "ContactQI: connect(%s): %m", QiHost); if (Debug) { fprintf (stderr, "ContactQI: connect(%s):", QiHost); perror (""); } (void) close(sock); #ifdef QI_ALT if (!equal (QiHost, QI_ALT)) { QiHost = QI_ALT; goto again; } #endif /* QI_ALT */ finis (); } /* Connection ok, change to canonical form */ ToQI = fdopen (sock, "w"); FromQI = fdopen (sock, "r"); return; } \f /* ** ErrorReturn -- Create and send informative mail messages ** ** The envelope from address should be set to null as per RFC-821 ** in regard to notification messages (Section 3.6). ** ** Parameters: ** Addr -- pointer to NewAddress structure with addresses ** and messages ** Omsg -- stream pointer to original message ** envp -- environment pointer for vfork/execve ** ** Returns: ** Nothing ** ** Side Effects: ** None */ char *ap[] = { "-sendmail", "-f", "MAILER-DAEMON", "-t", 0}; ErrorReturn (Addr, Omsg, envp) NADD *Addr; FILE *Omsg; char *envp[]; { int i; /* Good ol' i */ char Buf[MAXSTR]; /* Temp for copying msg test */ FILE *Emsg; /* For creating the error msg */ int pid; /* For vfork() */ int flags = 0; /* Controls printing of msgs */ int SubCode; /* Printing control */ int ByteLimit = 15000; /* Limit returned msg size */ NADD *AddrP; /* Loop variable */ QIR *QIp; /* Another loop variable */ extern char *ap[]; extern FILE *OpenTemp(); /* Open the error file */ if ((Emsg = OpenTemp (ErrorFile)) == FILE_NULL) finis (); /* Insert the headers */ if (fprintf (Emsg, "To: %s\n", From) < 0) finis (); if (PostmasterCC) fprintf (Emsg, "Cc: Postmaster\n"); fprintf (Emsg, "Subject: Returned mail - nameserver error report\n\n"); fprintf (Emsg, " --------Message not delivered to the following:\n\n"); for (AddrP = Addr; AddrP->original != CPNULL; AddrP++) if (abs (AddrP->code) != LR_OK) fprintf (Emsg, " %15s %s\n", AddrP->original, AddrP->new); fprintf (Emsg, "\n --------Error Detail (phquery V%s):\n\n", VERSION); /* Loop again to insert messages */ for (AddrP = Addr; AddrP->original != CPNULL; AddrP++) if (abs (AddrP->code) == LR_NOMATCH) { if (! (flags & NO_MATCH_MSG)) { PrintMsg (Emsg, NoMatchMsg); flags |= NO_MATCH_MSG; break; } } for (AddrP = Addr; AddrP->original != CPNULL; AddrP++) if (abs (AddrP->code) == LR_ABSENT) { if (! (flags & ABSENT_MSG)) { PrintMsg (Emsg, AbsentMsg); flags |= ABSENT_MSG; if (! (flags & PHONE_MSG)) { PrintMsg (Emsg, PhoneMsg); flags |= PHONE_MSG; } } for (QIp = AddrP->QIalt; QIp->code < 0; QIp++) if (abs (QIp->code) == LR_OK) fprintf (Emsg, " %s: %s\n", Fields[QIp->field].value, QIp->message); (void) putc ('\n', Emsg); } for (AddrP = Addr; AddrP->original != CPNULL; AddrP++) if (abs (AddrP->code) == LR_TOOMANY) { if (! (flags & TOO_MANY_MSG)) { PrintMsg (Emsg, TooManyMsg); flags |= TOO_MANY_MSG; break; } } for (AddrP = Addr; AddrP->original != CPNULL; AddrP++) if (abs (AddrP->code) == LR_AMBIGUOUS) { if (! (flags & MULTI_MSG)) { PrintMsg (Emsg, MultiMsg); flags |= MULTI_MSG; if (! (flags & PHONE_MSG)) { PrintMsg (Emsg, PhoneMsg); flags |= PHONE_MSG; } } for (QIp = AddrP->QIalt, SubCode = QIp->subcode; QIp->code < 0; QIp++) { if (QIp->subcode != SubCode) { SubCode = QIp->subcode; (void) putc ('\n', Emsg); } if (abs (QIp->code) == LR_OK) fprintf (Emsg, " %s: %s\n", Fields[QIp->field].value, QIp->message); } (void) putc ('\n', Emsg); } fprintf (Emsg, "\n --------Unsent Message below:\n\n"); rewind (Omsg); while ((i = fread (Buf, sizeof (char), MAXSTR, Omsg)) != 0 && ByteLimit > 0) { if (fwrite (Buf, sizeof (char), i, Emsg) != i) DANGER_WILL_ROBINSON("ErrorReturn: Emsg copy") else ByteLimit -= i; } fprintf (Emsg, "\n --------End of Unsent Message\n"); (void) fflush (Emsg); (void) fclose (Emsg); if (freopen (ErrorFile, "r", stdin) == FILE_NULL) DANGER_WILL_ROBINSON("ErrorReturn: ErrorFile freopen") /* Zap file so it disappears automagically */ if (! Debug) (void) unlink (ErrorFile); /* * vfork, then execve sendmail for delivery */ pid = 0; if (! Debug && (pid = vfork ()) == -1) DANGER_WILL_ROBINSON("ErrorReturn: fork") if (pid) { pid = wait(0); return; } else if (! Debug) execve (SENDMAIL, ap, envp); } \f /* ** FindFrom -- Find From: address in message headers ** ** Parameters: ** MsgFile -- stream pointer to message ** ** Returns: ** Nothing ** ** Side Effects: ** Global From pointer is adjusted to point at either a ** malloc'ed area containing the address, or to the ** constant string "Postmaster" if none is found. */ FindFrom (MsgFile) FILE *MsgFile; { char *p1, *p2; extern char *From; char Buf[MAXSTR]; rewind (MsgFile); while (fgets (Buf, MAXSTR, MsgFile) != CPNULL && *Buf != '\n') { if (strncasecmp (Buf, "From:", 5)) continue; else { if ((p1 = index (Buf, '<')) != CPNULL) { p1++; if ((p2 = index (Buf, '>')) != CPNULL) { From = Malloc ((unsigned) ((p2-p1)+1)); (void) strncpy (From, p1, (p2-p1)); } else { if (Debug) fprintf (stderr, "Unbalanced <> in From: address\n"); if (Log) syslog (LOG_ERR, "Unbalanced <> in From: address\n"); From = "Postmaster"; } } else { /* * Punt to postmaster. If there's too * many, I'll fix this someday. */ if (Debug) fprintf (stderr, "No <> in From: address\n"); if (Log) syslog (LOG_ERR, "No <> in From: address\n"); From = "Postmaster"; } break; } } if (From == CPNULL) { if (Debug) fprintf (stderr, "No From: address in message\n"); if (Log) syslog (LOG_ERR, "No From: address in message\n"); From = "Postmaster"; } } \f /* ** ReMail -- Forward message to recipients after adding phquery headers ** ** Parameters: ** Addr -- pointer to NewAddress structure with addresses ** and messages ** Omsg -- stream pointer to original message ** envp -- environment pointer for vfork/execve ** ** Returns: ** Nothing ** ** Side Effects: ** None */ ReMail (Addr, Omsg, envp) NADD *Addr; FILE *Omsg; char *envp[]; { int napi = 0; int i; char Buf[MAXSTR]; NADD *AddrP; FILE *Nmsg; int pid = 0; char *nap[50], nFrom[100]; extern FILE *OpenTemp(); extern char *From, HostNameBuf[]; extern int ReplyTo; /* Open the rewrite file */ if ((Nmsg = OpenTemp (NewFile)) == FILE_NULL) finis (); /* Fill out the first portion of the sendmail argument vector */ nap[napi++] = "-sendmail"; nap[napi++] = "-f"; if (ReplyTo == 0) nap[napi++] = From; for (AddrP = Addr; AddrP->original != CPNULL; AddrP++) if (abs (AddrP->code) == LR_OK) nap[napi++] = AddrP->new; else { /* * Tack on .xyzzy to the From address so sendmail will know * it's been here. */ (void) strcpy (nFrom, From); (void) strcat (nFrom, ".xyzzy"); nap[napi++] = nFrom; } /* Read and copy the header block, adding X-PH-To: or X-PH: header */ rewind (Omsg); while (fgets (Buf, MAXSTR, Omsg) != CPNULL && *Buf != '\n') { if ((nequal (Buf, "To:", 3) || nequal (Buf, "Cc:", 3) || nequal (Buf, "From:", 5)) && pid == 0) { int LineLength = 0; if (ReplyTo == 0) { /* Write the PH header and add to argv */ #ifdef EXPAND_TO if (fprintf (Nmsg, "X-PH(%s)-To:", VERSION) < 0) finis (); LineLength = 8; for (AddrP = Addr; AddrP->original != CPNULL; AddrP++) if (abs (AddrP->code) == LR_OK) { if ((LineLength + strlen (AddrP->new)) > 75) { fprintf (Nmsg, "\n\t"); LineLength = 8; } fprintf (Nmsg, " %s", AddrP->new); } (void) putc ('\n', Nmsg); #else /* ! EXPAND_TO */ fprintf (Nmsg, "X-PH: V%s@@%s\n", VERSION, HostNameBuf); #endif /* EXPAND_TO */ pid++; } else if (ReplyTo == 1) { /* Add the Reply-To: fields */ AddrP = Addr; if (fprintf (Nmsg, "Comment: Reply-To: added by phquery (V%s)\n", VERSION) < 0) finis (); fprintf (Nmsg, "Resent-From: postmaster@@%s\n", HostNameBuf); fprintf (Nmsg, "Reply-To: %s\n", AddrP->new); AddrP++; for (; AddrP->original != CPNULL; AddrP++) nap[napi++] = AddrP->original; pid++; } } fputs (Buf, Nmsg); } (void) fputs (Buf, Nmsg); nap[napi++] = CPNULL; if (Debug) { printf ("Final send vector:"); for (i = 0; nap[i] != CPNULL; i++) printf (" %s", nap[i]); (void) putchar ('\n'); } /* Copy the remainder of the message */ while ((i = fread (Buf, sizeof (char), MAXSTR, Omsg)) != 0) if (fwrite (Buf, sizeof (char), i, Nmsg) != i) DANGER_WILL_ROBINSON("ReMail: nmsg copy") /* Re-arrange the stream pointers and invoke sendmail */ (void) fflush (Nmsg); (void) fclose (Nmsg); if (freopen (NewFile, "r", stdin) == FILE_NULL) DANGER_WILL_ROBINSON("ReMail: NewFile freopen") /* Zap file so it disappears automagically */ if (! Debug) (void) unlink (NewFile); /* * vfork, then execve sendmail for delivery */ pid = 0; if (! Debug && (pid = vfork ()) == -1) DANGER_WILL_ROBINSON("ReMail: fork") if (pid) { pid = wait(0); return; } else if (! Debug) execve (SENDMAIL, nap, envp); } \f /* ** CodeString -- Return text string corresponding to supplied reply code ** ** Parameters: ** code -- reply value ** ** Returns: ** char pointer to text string or NULL pointer if no matching ** key is located. ** ** Side Effects: ** None */ char * CodeString (code) int code; { struct ReplyCodes *Cpnt; extern struct ReplyCodes Codes[]; for (Cpnt = Codes; Cpnt->key != -1; Cpnt++) if (Cpnt->key == abs (code)) return (Cpnt->value); return (CPNULL); } \f /* ** OpenTemp -- Create and open a temporary file ** ** For the supplied file name, create, open, and chmod the file ** ** Parameters: ** Name -- pathname of file to create in mkstemp format ** ** Returns: ** Stream descriptor of resulting file, or NULL if error ** ** Side Effects: ** mkstemp modifies calling argument */ FILE * OpenTemp (Name) char *Name; { int fd; FILE *Stream; if ((fd = mkstemp (Name)) == -1) DANGER_WILL_ROBINSON("OpenTemp: mkstemp") /* Protect it */ if (fchmod (fd, IREAD|IWRITE) == -1) DANGER_WILL_ROBINSON("OpenTemp: fchmod") /* Make fd a stream */ if ((Stream = fdopen (fd, "r+")) == FILE_NULL) DANGER_WILL_ROBINSON("OpenTemp: fdopen") return (Stream); } \f /* ** PickField -- Find the QI_response with the named field ** ** Cycle through a chain of QI_response's looking for one with the ** named field. Return a pointer to that one or NULL if not present. ** Assumes that the last QI_response.code > 0. ** ** Parameters: ** qp -- QI_response chain pointer ** field -- QI field to search for ** ** Returns: ** pointer to located QI_response or NULL if not found ** ** Side Effects: ** None */ QIR * PickField (qp, field) QIR *qp; int field; { do { if (qp->field == field) return (qp); } while ((qp++)->code < 0); return (QIR_NULL); } \f /* ** Query -- Create queries to send to the CSnet central server ** ** Using the alias, call-sign, and full name fields, as known by the ** CSnet central name server Query Interpreter, Query creates variants ** of the supplied name (New->original) if a straight alias lookup fails. ** For each variant, SendQuery() is called until either one succeeds or ** all variants are exhausted. ** ** Parameters: ** New -- pointer to NewAddress struct ** ** Returns: ** None ** ** Side Effects: ** Modifies contents under New pointer. */ Query(New) NADD *New; { char scratch[MAXSTR]; /* copy of FullName w.o. punct */ char *sp, *sp2; /* work ptrs for scratch */ char **Lpnt = TryList; /* Loop pointer for TryList */ int NoMore = -1; /* set if all name variants done */ /* * Try the query as an alias lookup first, then as a full name lookup. */ do { /* * Convert punctuation/separators in scratch to space * characters one at a time if testing for name. If * WILDNAMES is #define'd, a wildcard char '*' will be * appended after each single character name, e.g. p-pomes * is tried as p* pomes. This has risks as follows: assume * Duncan Lawrie sets his alias to "lawrie". A query for * d-lawrie will fail as a alias lookup but succeed as a * name lookup when written as "d* lawrie". This works until * Joe Student sets his alias to "d-lawrie". Whoops. * Still in a non-hostile environment, this function may be * more useful than dangerous. */ if (equal (*Lpnt, "name")) { /* Try as is first time for hyphenated names */ if (NoMore == -1) { (void) strcpy (scratch, New->original); if (SendQuery (New, *Lpnt, scratch)) return; NoMore = 0; } else { char stemp[MAXSTR], *st = stemp; for (sp = scratch; *sp != CHNULL; ) { /* copy until non-space punct char */ if (!ispunct (*sp) || *sp == ' ' || *sp == '*') { sp2 = sp; *st++ = *sp++; if (*sp == CHNULL) NoMore++; continue; } #ifdef WILDNAMES /* if one non-punct char, append * */ if ((sp - sp2) == 1) *st++ = '*'; #endif /* WILDNAMES */ *st++ = ' '; sp++; break; } while (*sp != CHNULL) *st++ = *sp++; *st = CHNULL; (void) strcpy (scratch, stemp); if (SendQuery (New, *Lpnt, scratch)) return; if (NoMore > 0) Lpnt++; continue; } } /* * Convert punctuation/separators in scratch to hyphen * characters if testing for alias. */ else if (equal (*Lpnt, "alias")) { (void) strcpy (scratch, New->original); for (sp = scratch; *sp != CHNULL; sp++) if (ispunct(*sp)) *sp = '-'; if (SendQuery (New, *Lpnt, scratch)) return; Lpnt++; } else { (void) strcpy (scratch, New->original); if (SendQuery (New, *Lpnt, scratch)) return; Lpnt++; } } while (*Lpnt != CPNULL); } \f /* ** SendQuery -- Send queries to the local CSnet central name server ** ** Takes a field type (alias, call-sign, full name, etc), as known by ** the CSnet central name server Query Interpreter, and looks up the ** corresponding email address "usercode@@host". Cases where the ** alias/name aren't found, are ambiguous, or lack an email address ** return a message instead of the address. Additional information is ** returned as an array of QIR records pointed to by New->QIalt. ** ** Parameters: ** New -- pointer to NewAddress struct ** Field -- type of field (name, alias, etc) for Value ** Value -- name to lookup ** ** Returns: ** 1 if a match(es) is found including too many ** 0 otherwise ** ** Side Effects: ** Will call ContactQI() if the connection is closed. ** Modifies contents under New pointer. */ SendQuery(New, Field, Value) NADD *New; char *Field, *Value; { QIR *EmailQ, *QIp; /* For handling ReadQI() responses */ int i; /* good ol' i */ QIR *ReadQI(); char *Realloc(); /* Open the ToQI and FromQI descriptors if necessary */ ContactQI(); /* Make a query out of the arguments */ fprintf (ToQI, "query %s=%s return name alias callsign phone department curriculum email\n", Field, Value); if (Debug) printf ("querying for %s \"%s\"\n", Field, Value); if (Log) syslog (LOG_DEBUG, "querying for %s \"%s\"\n", Field, Value); (void) fflush (ToQI); /* * Grab the responses and let the fun begin. * The possibilities are: * * 102:There were N matches to your query * -200:1: alias: Paul-Pomes * -200:1: name: pomes paul b * -200:1: callsign: See Figure 1 * -508:1: curriculum: Not present in entry. * -200:1: department: Computing Services Office * -200:1: email: paul@@uxc.cso.uiuc.edu * 200:Ok. * * 501:No matches to your query. * * 502:Too many matches to request. */ EmailQ = ReadQI (FromQI); /* * If we read a preliminary response (99<x<200), garbage * collect and read some more. */ i = abs (EmailQ->code); if (i > 99 && i < 200) { GarbageCollect (EmailQ); EmailQ = ReadQI (FromQI); } /* * If we read a temporary error, be a nice program and defer. */ else if (i > 399 && i < 500) finis (); /* * No matches at all? Too many? Note that single line errors * will have code > 0. */ if (EmailQ->code > 0) { New->new = CodeString (EmailQ->code); New->code = EmailQ->code; New->QIalt = QIR_NULL; GarbageCollect (EmailQ); if (New->code == LR_TOOMANY) return (1); return (0); } /* anything else must be multi-line */ assert (EmailQ->code < 0); /* Are there multiple responses (subcode > 1)? */ for (QIp = EmailQ; QIp->code < 0; QIp++) if (QIp->subcode > 1) { New->code = LR_AMBIGUOUS; New->new = CodeString (LR_AMBIGUOUS); New->QIalt = EmailQ; return (1); } /* If one person, handle as single match alias */ QIp = PickField (EmailQ, EMAIL); assert (QIp->field == EMAIL); New->code = abs (QIp->code); New->QIalt = EmailQ; switch (abs (QIp->code)) { case LR_ABSENT: New->new = CodeString (QIp->code); return (1); case LR_OK: New->new = QIp->message; return (1); default: if (Debug) fprintf (stderr, "unexpected code %d\n", QIp->code); if (Log) syslog (LOG_ERR, "Query: %s: unexpected code %d", Field, QIp->code); finis (); } GarbageCollect (EmailQ); return (0); } \f /* ** RevQuery -- Reverse query, email to ph alias ** ** Takes a email address as known by the CSnet central name server ** Query Interpreter, and looks up the corresponding alias. Cases ** where the email address matches multiple aliases return the ** original address. In addition the global variable ReplyTo is ** set to -1. ** ** Parameters: ** New -- pointer to NewAddress struct ** ** Returns: ** None ** ** Side Effects: ** Will call ContactQI() if the connection is closed. ** Modifies contents under New pointer. ** ReplyTo set to -1 if QI returns multiple aliases or ** no match. */ RevQuery(New) NADD *New; { int i; QIR *AliasQ, *QIp; extern int ReplyTo; extern char *From, HostNameBuf[]; extern FILE *ToQI, *FromQI; extern QIR *ReadQI(); /* Open the ToQI and FromQI descriptors if necessary */ ContactQI(); /* * We have to have a from address here. If it doesn't have * a fully qualified form, convert it to name@@domain by * appending our Fully Qualified Domain Name. FQDN, the * litany of the new Internet Age. */ assert (From != CPNULL); if (index (From, '@@') == CPNULL) { char *nFrom; /* * We can't Realloc(From) since it may point to * an area on the stack. */ nFrom = Malloc ((unsigned)(strlen (From) + 1)); (void) strcpy (nFrom, From); From = Realloc (nFrom, (unsigned)(strlen(nFrom) + strlen(HostNameBuf) + 5)); (void) strcat (From, "@@"); (void) strcat (From, HostNameBuf); } New->original = From; /* Send the query * I'd check for a -1 here, but am unsure how network errors really * are manifested. */ fprintf (ToQI, "query email=%s return alias \n", From); if (Debug) printf ("querying alias corresponding to \"%s\"\n", From); if (Log) syslog (LOG_DEBUG, "querying alias for \"%s\"\n", From); (void) fflush (ToQI); /* * Grab the responses and let the fun begin. * The possibilities are: * * 102:There was N matches to your query. * * -200:1: alias: rrv * 200:Ok. * * -200:1: alias: Paul-Pomes * -200:2: alias: PostMaster * 200:Ok. * * 501:No matches to your query. * * 502:Too many matches to request. * * For anything other than the first case, set ReplyTo to -1 and * set New->new = New->original . */ AliasQ = ReadQI (FromQI); /* * If we read a preliminary response (99<x<200), garbage * collect and read some more. */ i = abs (AliasQ->code); if (i > 99 && i < 200) { GarbageCollect (AliasQ); AliasQ = ReadQI (FromQI); } /* Handle the 501, 502 codes */ if (AliasQ->code > 0) { ReplyTo = -1; New->new = New->original; GarbageCollect (AliasQ); return; } /* Are there multiple responses (subcode > 1)? */ for (QIp = AliasQ; QIp->code < 0; QIp++) if (QIp->subcode > 1) { ReplyTo = -1; New->new = New->original; GarbageCollect (AliasQ); return; } QIp = AliasQ; assert (abs (QIp->code) == LR_OK && QIp->field == ALIAS); New->code = abs (QIp->code); New->new = QIp->message; return; } \f /* ** ReadQI -- Read and store response from QI server ** ** A QI response has one of the following structures: ** ** <-><code>:<subcode><ws><field name>:<string> ** 5XX:Error message ** 200:Ok. ** ** The leading '-' marks a continuation line. The last line of a ** response will not have the '-'. ** ** <code> is the response code. Response codes are listed in phquery.h ** and closely follow the conventions of SMTP (RFC-821): ** ** 1XX - status ** 2XX - information ** 3XX - additional information or action needed ** 4XX - temporary errors ** 5XX - permanent errors ** 6XX - phquery specific codes ** ** <subcode> links multiple fields (e.g., email and pager) to a single ** individual. If a name query results in a multiple match, subcode ** increments by 1 for each person but has the same value for all response ** lines for that individual. ** ** <ws> is sufficient white space to right adjust <field name>: to the ** same position on each line. ** ** <field name> is one of the field type in phquery.h (e.g., department, ** mailcode, etc). ** ** <string> is either the value for <field name>, if <code> == 200 (LR_OK), ** or an error message it <code> is anything else. ** ** Parameters: ** InFile - stream pointer for input ** ** Returns: ** A pointer to a malloc()'ed block of QI_response structs that ** is terminated with QI_response.code > 0. ** ** Side Effects: ** Creates a block of data that must be later free()'d. ** Advances FromQI. */ QIR * ReadQI (InFile) FILE *InFile; { int i, code; int loopcnt = 1; char *tp; unsigned size = sizeof (QIR); char fstring[MAXSTR]; /* field string */ char message[MAXSTR]; /* field value */ char Temp[MAXSTR]; register QIR *Base, *RepChain; char *Malloc(), *Realloc(); Base = RepChain = (QIR *) Malloc (size); RepChain->field = -1; Base->message = CPNULL; do { *fstring = *message = CHNULL; if (fgets (Temp, MAXSTR-1, InFile) == CPNULL) { if (Debug) fprintf (stderr, "premature EOF\n"); if (Log) syslog (LOG_ERR, "ReadQI: premature EOF"); finis (); } if (Debug > 1) printf ("ReadQI read =%s=\n", Temp); code = atoi (Temp); /* Positive response codes are formatted "<code>:<message>" */ if (code > 0) { RepChain->subcode = NONE_OF_ABOVE; if (sscanf (Temp, "%d:%[^\n]", &RepChain->code, message) != 2 || *message == CHNULL) { if (Debug) fprintf (stderr, "ReadQI: short #1 sscanf\n"); if (Log) syslog (LOG_ERR, "ReadQI: short #1 sscanf read: %m"); finis (); } } /* Otherwise they are the 4 field type */ else if (( i = sscanf (Temp, "%d:%d:%[^:]: %[^\n]", &RepChain->code, &RepChain->subcode, fstring, message)) != 4 || *fstring == CHNULL || *message == CHNULL) { if (Debug) fprintf (stderr, "ReadQI: short #2 sscanf, expected 4 got %d\n", i); if (Log) syslog (LOG_ERR, "ReadQI: short #2 sscanf, expected 4 got %d", i); /* * The short sscanf() read may be due to a embedded * newline. If so, continue for a bit to fill out the * code field before reading another line. */ if (!(i == 3 && *message == CHNULL)) finis (); } /* * Some fields go over multiple response lines. In that case * the field is all blanks. Copy the response field from the * previous response if not already set. */ if (RepChain->field == -1) { for (tp = fstring; tp <= fstring + (MAXSTR-1) && *tp == ' '; tp++) ; if (RepChain->code < 0 && *tp == CHNULL) RepChain->field = (RepChain - 1)->field; else RepChain->field = FieldValue (tp); } /* Now get a new line if message was empty. */ if (*message == CHNULL) continue; RepChain->message = Malloc ((unsigned) (strlen (message) + 1)); (void) strcpy (RepChain->message, message); if (RepChain->code > 0) break; size += sizeof (QIR); Base = (QIR *) Realloc ((char *) Base, size); RepChain = Base + loopcnt; RepChain->field = -1; } while (loopcnt++); if (Debug) for (RepChain = Base; RepChain->code < 0; RepChain++) printf ("code %d, subcode %d, field %s, message: %s\n", RepChain->code, RepChain->subcode, Fields[RepChain->field].value, RepChain->message); return (Base); } \f /* ** FieldValue -- Locate argument in Fields[] and return integer value ** ** Parameters: ** field -- character string to locate in Fields[] ** ** Returns: ** integer value of field or NONE_OF_ABOVE (-1) if not found. ** ** Side Effects: ** none */ FieldValue (field) char *field; { struct QI_fields *QIp = Fields; /* Guard against stupid mistakes (so they show up somewhere else?) */ if (field == CPNULL || *field == CHNULL) return (NONE_OF_ABOVE); /* Replace this with a binary search if profiling peaks here. XXX */ do { if (equal (field, QIp->value)) break; } while ((++QIp)->key != NONE_OF_ABOVE); return (QIp->key); } \f /* ** GarbageCollect -- Free space allocated within QI_response array ** ** Parameters: ** QIp -- pointer to array of QI_response ** ** Returns: ** None ** ** Side Effects: ** none */ GarbageCollect (QIp) QIR *QIp; { QIR *QIsave = QIp; assert (QIp != QIR_NULL); do { if (QIp->message != CPNULL) free (QIp->message); QIp->message = CPNULL; } while ((QIp++)->code < 0); free ((char *) QIsave); QIsave = QIR_NULL; } \f /* ** Malloc -- malloc with error checking ** ** Parameters: ** size -- number of bytes to get ** ** Returns: ** (char *) of first char of block, or ** finis() if any error ** ** Side Effects: ** none */ char * Malloc (size) unsigned size; /* Bytes to get */ { char *cp; /* Pointer to memory */ if ((cp = malloc (size)) == CPNULL) { if (Debug) { fprintf (stderr, "malloc of %u bytes failed:", size); perror(""); } if (Log) syslog (LOG_ERR, "malloc of %u bytes failed: %m", size); finis (); } return (cp); } \f /* ** PrintMsg -- Print a message on the named stream ** ** Parameters: ** OutFile -- stream to print message to ** Msg - array of char pointers that make up message, ** null terminated ** ** Returns: ** None ** ** Side Effects: ** none */ PrintMsg (OutFile, Msg) FILE *OutFile; char *Msg[]; { while (*Msg != CPNULL) { if (fprintf (OutFile, "%s\n", *Msg) < 0) finis (); Msg++; } } \f /* ** Realloc -- realloc with error checking ** ** Parameters: ** ptr -- pointer to existing data ** size -- number of bytes to get ** ** Returns: ** (char *) of first char of block, or ** finis() if any error ** ** Side Effects: ** none */ char * Realloc (ptr, size) char *ptr; unsigned size; { char *cp; /* pointer to memory */ if ((cp = realloc (ptr, size)) == CPNULL) { if (Debug) { fprintf (stderr, "realloc of %u bytes failed:", size); perror(""); } if (Log) syslog (LOG_ERR, "realloc of %u bytes failed: %m", size); finis (); } return (cp); } \f /* ** PrtUsage -- Print how to use message ** ** Print usage messages (char *usage[]) to stderr and exit nonzero. ** Each message is followed by a newline. ** ** Parameters: ** FullText -- prints the copyright statement if set ** ** Returns: ** none ** ** Side Effects: ** none */ PrtUsage (FullText) int FullText; { int which = 0; /* current line */ while (usage[which] != CPNULL) { fprintf (stderr, usage[which++], MyName); (void) putc ('\n', stderr); } (void) fflush (stdout); which = 0; if (FullText) PrintMsg (stdout, CopyLeft); } \f /* ** finis -- Clean up and exit. ** ** Parameters: ** none ** ** Returns: ** never ** ** Side Effects: ** exits sendmail */ finis() { extern FILE *ToQI, *FromQI; /* clean up temp files */ if (ToQI != FILE_NULL) (void) fclose (ToQI); if (FromQI != FILE_NULL) (void) fclose (FromQI); ToQI = FromQI = FILE_NULL; if (! Debug) { (void) unlink (TmpFile); (void) unlink (ErrorFile); (void) unlink (NewFile); } /* and exit */ exit (ExitStat); } @ 1.19 log @Corrected handling of hyphenated names. Added WILDNAMES #define for more aggressive matching of full name lookups. See the comments in phquery.h. @ text @d23 1 a23 1 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 $"; d30 2 a31 1 #if defined(pyr) || defined(is68k) || defined(NeXT) || defined(__convex__) d56 1 a56 1 #define VERSION "3.5" d67 3 d71 1 a553 1 int sav_errno; /* errno value preserver */ d557 1 a568 12 /* Get a socket for the QI connection */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { if (Debug) fprintf (stderr, "ContactQI: can't create socket"); severe: if (Log) syslog (LOG_ERR, "ContactQI: cannot get connection"); finis(); } QI.sin_family = AF_INET; d579 12 d593 1 a593 1 if (Host = gethostbyname (QI_HOST)) { d596 7 a602 3 if (Debug) fprintf (stderr, "host name lookup failure: \"%s\"", QI_HOST); goto severe; d606 7 a612 3 if (connect(sock, (struct sockaddr *) &QI, sizeof (QI)) < 0) { sav_errno = errno; d614 4 a617 31 errno = sav_errno; switch (errno) { case EISCONN: case ETIMEDOUT: case EINPROGRESS: case EALREADY: case EADDRINUSE: case EHOSTDOWN: case ENETDOWN: case ENETRESET: case ENOBUFS: case ECONNREFUSED: case ECONNRESET: case EHOSTUNREACH: case ENETUNREACH: /* There are others, I'm sure..... */ finis (); case EPERM: /* Why is this happening? */ if (Debug) fprintf (stderr, "ContactQI: funny failure, addr=%lx, port=%x", QI.sin_addr.s_addr, QI.sin_port); finis (); default: if (Debug) fprintf (stderr, "ContactQI: default failure, addr=%lx, port=%x", QI.sin_addr.s_addr, QI.sin_port); finis (); d619 2 d622 1 @ 1.18 log @Fixed handling of imbedded newlines. @ text @d23 1 a23 1 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 $"; d55 1 a55 1 #define VERSION "3.4" a248 3 /* Characters that can act as separators in full name requests */ char PunctChars[] = "-_.,+=#$"; d373 1 a373 1 Usage (1); d378 1 a378 1 Usage (1); d383 1 a383 1 Usage (0); d836 7 d885 3 a918 1 nap[napi++] = AddrP->new; a921 3 for (AddrP = Addr; AddrP->original != CPNULL; AddrP++) if (abs (AddrP->code) == LR_OK) nap[napi++] = AddrP->new; d1071 1 a1071 1 ** Query -- Make calls to the local CSnet central name server d1073 5 a1077 6 ** Takes a alias, call-sign, or full name, as known by the CSnet central ** name server Query Interpreter, and looks up the corresponding ** email address "usercode@@host". Cases where the alias/name aren't ** found, are ambiguous, or lack an email address return a message ** instead of the address. Additional information is returned as an ** array of QIR records pointed to by New->QIalt. a1085 1 ** Will call ContactQI() if the connection is closed. a1086 2 ** Looks up the user specified in nbuf. If the name is ** found, replace the contents of nbuf with the email address. d1092 4 a1095 12 QIR *EmailQ, *QIp; /* For handling ReadQI() responses */ char scratch[MAXSTR]; /* copy of FullName w.o. punct */ char *sp; /* work ptr for scratch */ char **Lpnt; /* Loop pointer for TryList */ int multi; /* Set if more than 1 person */ int i; /* good ol' i */ extern char *TryList[]; extern FILE *ToQI, *FromQI; extern char PunctChars[]; extern int ReplyTo; QIR *ReadQI(); char *Realloc(); a1096 3 /* Open the ToQI and FromQI descriptors if necessary */ ContactQI(); d1101 1 a1101 3 for (Lpnt = TryList; *Lpnt != CPNULL; Lpnt++) { (void) strcpy (scratch, New->original); d1104 10 a1113 1 * characters if testing for name. d1115 1 a1115 7 if (equal (*Lpnt, "name")) for (i = 0; PunctChars[i] != CHNULL; i++) { if (PunctChars[i] == ' ') continue; while ((sp = index (scratch, PunctChars[i])) != CPNULL) *sp = ' '; } d1117 6 a1122 10 /* * Convert punctuation/separators in scratch to hyphen * characters if testing for alias. */ else if (equal (*Lpnt, "alias")) for (i = 0; PunctChars[i] != CHNULL; i++) { if (PunctChars[i] == '-') continue; while ((sp = index (scratch, PunctChars[i])) != CPNULL) *sp = '-'; d1124 2 d1127 1 a1127 29 /* Make a query out of the arguments */ fprintf (ToQI, "query %s=%s return name alias callsign phone department curriculum email\n", *Lpnt, scratch); if (Debug) printf ("querying for %s \"%s\"\n", *Lpnt, scratch); if (Log) syslog (LOG_DEBUG, "querying for %s \"%s\"\n", *Lpnt, scratch); (void) fflush (ToQI); /* * Grab the responses and let the fun begin. * The possibilities are: * * 102:There were N matches to your query * -200:1: alias: Paul-Pomes * -200:1: name: pomes paul b * -200:1: callsign: See Figure 1 * -508:1: curriculum: Not present in entry. * -200:1: department: Computing Services Office * -200:1: email: paul@@uxc.cso.uiuc.edu * 200:Ok. * * 501:No matches to your query. * * 502:Too many matches to request. */ EmailQ = ReadQI (FromQI); d1129 28 a1156 8 /* * If we read a preliminary response (99<x<200), garbage * collect and read some more. */ i = abs (EmailQ->code); if (i > 99 && i < 200) { GarbageCollect (EmailQ); EmailQ = ReadQI (FromQI); d1160 2 a1161 1 * If we read a temporary error, be a nice program and defer. d1163 6 a1168 13 else if (i > 399 && i < 500) finis (); /* * No matches at all? Too many? Note that single line errors * will have code > 0. This test should only be done for the * last iteration of this loop. */ if (EmailQ->code > 0) { if (equal (*Lpnt, "name")) { New->new = CodeString (EmailQ->code); New->code = EmailQ->code; New->QIalt = QIR_NULL; d1170 1 a1170 5 } else { GarbageCollect (EmailQ); continue; } d1172 31 d1204 8 a1211 2 /* anything else must be multi-line */ assert (EmailQ->code < 0); d1213 2 a1214 6 /* Are there multiple responses (subcode > 1)? */ for (QIp = EmailQ, multi = 0; QIp->code < 0; QIp++) if (QIp->subcode > 1) { multi++; break; } d1216 29 a1244 10 /* If one person, handle as single match alias */ if (multi == 0) { QIp = PickField (EmailQ, EMAIL); assert (QIp->field == EMAIL); New->code = abs (QIp->code); New->QIalt = EmailQ; switch (abs (QIp->code)) { case LR_ABSENT: New->new = CodeString (QIp->code); return; d1246 9 a1254 3 case LR_OK: New->new = QIp->message; return; d1256 5 a1260 9 default: if (Debug) fprintf (stderr, "unexpected code %d\n", QIp->code); if (Log) syslog (LOG_ERR, "Query: %s: unexpected code %d", *Lpnt, QIp->code); finis (); } } d1262 20 a1281 2 /* Multiple matches. */ else { d1285 1 a1285 1 return; d1287 22 a1308 1 GarbageCollect (EmailQ); d1310 2 d1728 1 a1728 1 ** Usage -- Print how to use message d1743 1 a1743 1 Usage (FullText) @ 1.17 log @Portability enhancements @ text @d23 1 a23 1 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 $"; d55 1 a55 1 #define VERSION "3.3" d270 1 a270 1 #endif /* !__STDC__ && !__stdc__ */ d314 1 a314 1 "US Mail: UofIllinois, CSO, 1304 W Springfield Ave, Urbana, IL 61801-2987", d375 2 a376 1 Usage (1); d1437 1 d1473 8 a1480 1 finis (); d1486 1 a1486 1 * previous response. d1488 12 a1499 6 for (tp = fstring; tp <= fstring + (MAXSTR-1) && *tp == ' '; tp++) ; if (RepChain->code < 0 && *tp == CHNULL) RepChain->field = (RepChain - 1)->field; else RepChain->field = FieldValue (tp); d1507 1 @ 1.16 log @Simplify headers, add support for service lookups (fax, etc). @ text @d23 1 a23 1 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 $"; d29 2 a30 1 #ifdef pyr d35 2 a36 2 #else /* ! pyr */ # ifdef sun d40 1 a40 1 # else /* ! sun */ d42 2 a43 2 # endif sun #endif pyr d55 1 a55 1 #define VERSION "3.2" d267 5 a330 1 extern char *Malloc(), *rindex(), *Realloc(); d684 2 a685 1 fprintf (Emsg, "To: %s\n", From); d777 1 a777 1 pid = wait((union wait *)NULL); d901 2 a902 1 fprintf (Nmsg, "X-PH(%s)-To:", VERSION); d926 2 a927 1 fprintf (Nmsg, "Comment: Reply-To: added by phquery (V%s)\n", VERSION); d971 1 a971 1 pid = wait((union wait *)NULL); d1286 2 a1287 1 * appending our fully qualified domain name. d1307 4 a1310 1 /* Send the query */ d1425 1 a1425 1 int code; d1464 2 a1465 2 else if (sscanf (Temp, "%d:%d:%[^:]: %[^\n]", &RepChain->code, &RepChain->subcode, fstring, message) d1468 1 a1468 1 fprintf (stderr, "ReadQI: short #2 sscanf\n"); d1470 1 a1470 1 syslog (LOG_ERR, "ReadQI: short #2 sscanf read: %m"); d1479 1 a1479 1 for (tp = fstring; tp < fstring + MAXSTR && *tp == ' '; tp++) a1576 1 extern char *malloc(); d1609 2 a1610 1 fprintf (OutFile, "%s\n", *Msg); a1634 1 extern char *realloc(); @ 1.15 log @Different kinds of massaging is done to argument string depending on lookup type. @ text @d23 1 a23 1 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 $"; d54 1 a54 1 #define VERSION "3.1" d95 4 d120 1 a120 1 ** Resent-From: postmaster@@DOMAINMASTER d122 1 a122 1 ** Comment: From: field converted to Reply-To: by phquery (Vx.y) at <host> d262 1 a262 1 "usage: %s [-d] [-p] [-s] [-l] [-R] [-i] [-f FromAddress] address1 [address2]", d320 1 d331 1 a331 1 while ((option = getopt (argc, argv, "f:r:pRsdli")) != EOF) { d337 4 d470 2 a471 1 * Allocate NewAddress structs for addresses d473 3 a475 2 New = (NADD *) Malloc ((unsigned) ((argc+1) * sizeof (NADD))); (New + argc)->original = CPNULL; d478 2 a479 3 /* Loop on addresses in argv building up translation table */ while (argc > 0) { NewP->original = *argv; a488 1 NewP++; argv++; argc--; d490 15 d884 1 a884 1 /* Read and copy the header block, adding the X-PH-To: header */ d894 1 d907 6 a1146 1 * d1208 1 a1208 1 assert (QIp->field == EMAIL) @ 1.14 log @Minor fixes and de-linting. @ text @d23 1 a23 1 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 $"; d54 1 a54 1 #define VERSION "3.0" d224 1 a224 1 /* Exit status for reporting to calling process */ d1081 6 a1086 3 for (i = 0; PunctChars[i] != CHNULL; i++) while ((sp = index (scratch, PunctChars[i])) != CPNULL) *sp = ' '; d1088 12 d1115 2 d1132 16 d1235 1 d1280 2 d1297 10 @ 1.13 log @First working version of -R (reply-to:) processing. @ text @d23 1 a23 1 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 $"; d424 5 a428 2 /* Allocate NewAddress structs for addresses plus 1 */ New = (NADD *) Malloc ((unsigned) ((argc+1) * sizeof (NADD))); a430 1 d434 1 a434 2 NewP->new = Realloc (NewP->new, (unsigned)(strlen (NewP->new) + strlen (DOMAIN) + 3)); d436 3 d451 1 d459 4 a462 1 /* Allocate NewAddress structs for addresses */ d647 1 @ 1.12 log @Changed #include's to cope with SUN systems. -pbp @ text @d23 1 a23 3 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 $"; #else /* not lint */ # define QI_HOST "some string" d54 1 a54 1 #define VERSION "2.0" d56 5 d67 8 d112 10 d149 6 a154 6 " the ph nameserver fails to locate either a ph ALIAS or NAME that matches", " the supplied name. The usual causes are typographical errors or the use of", " nicknames. Recommended action is to use the ph program to determine the", " correct ph alias for the individuals addressed. If ph is not available,", " try sending to the most explicit form of the name, e.g., if mike-fox fails,", " try michael-j-fox.", d215 6 d258 1 a258 1 "usage: %s [-d] [-p] [-s] [-l] [-i] [-f FromAddress] address1 [address2]", d319 2 a320 1 extern char *malloc(), *rindex(); d326 1 a326 1 while ((option = getopt (argc, argv, "f:r:psdli")) != EOF) { d332 5 d393 4 d401 2 a402 7 if (fwrite (Buf, sizeof (char), i, Msg) != i) { if (Debug) perror("Msg copy"); if (Log) syslog (LOG_ERR, "Msg copy: %m"); finis (); } d413 38 a450 7 /* Allocate NewAddress structs for addresses */ if ((New = (NADD *) malloc ((unsigned) ((argc+1) * sizeof (NADD)))) == NADD_NULL) { if (Debug) perror ("malloc"); if (Log) syslog (LOG_ERR, "malloc: %m"); d453 3 d715 2 a716 7 if (fwrite (Buf, sizeof (char), i, Emsg) != i) { if (Debug) perror("Emsg copy"); if (Log) syslog (LOG_ERR, "Emsg copy: %m"); finis (); } d723 2 a724 7 if (freopen (ErrorFile, "r", stdin) == FILE_NULL) { if (Debug) perror ("ErrorFile freopen"); if (Log) syslog (LOG_ERR, "freopen of %s: %m", ErrorFile); finis (); } d735 2 a736 7 if (! Debug && (pid = vfork ()) == -1) { if (Debug) perror ("ErrorReturn fork:"); if (Log) syslog (LOG_ERR, "ErrorReturn fork: %m"); finis (); } d774 1 a774 1 From = malloc ((unsigned) ((p2-p1)+1)); d827 1 a827 1 char *nap[50]; d829 2 a830 1 extern char *From; d839 11 a849 1 nap[napi++] = From; d858 13 a870 8 /* Write the PH header and add to argv */ fprintf (Nmsg, "X-PH(%s)-To:", VERSION); LineLength = 8; for (AddrP = Addr; AddrP->original != CPNULL; AddrP++) if (abs (AddrP->code) == LR_OK) { if ((LineLength + strlen (AddrP->new)) > 75) { fprintf (Nmsg, "\n\t"); LineLength = 8; d872 15 a886 5 fprintf (Nmsg, " %s", AddrP->new); nap[napi++] = AddrP->new; } (void) putc ('\n', Nmsg); pid++; d901 3 a903 9 while ((i = fread (Buf, sizeof (char), MAXSTR, Omsg)) != 0) { if (fwrite (Buf, sizeof (char), i, Nmsg) != i) { if (Debug) perror("ReMail: nmsg copy"); if (Log) syslog (LOG_ERR, "Nmsg copy: %m"); finis (); } } d908 2 a909 7 if (freopen (NewFile, "r", stdin) == FILE_NULL) { if (Debug) perror ("NewFile freopen"); if (Log) syslog (LOG_ERR, "freopen of %s: %m", NewFile); finis (); } d920 2 a921 7 if (! Debug && (pid = vfork ()) == -1) { if (Debug) perror ("ReMail fork:"); if (Log) syslog (LOG_ERR, "ReMail fork: %m"); finis (); } d977 2 a978 7 if ((fd = mkstemp (Name)) == -1) { if (Debug) perror (Name); if (Log) syslog (LOG_ERR, "mkstemp(\"%s\"): %m", Name); finis (); } d981 2 a982 7 if (fchmod (fd, IREAD|IWRITE) == -1) { if (Debug) perror (Name); if (Log) syslog (LOG_ERR, "fchmod(\"%s\"): %m", Name); finis (); } d985 2 a986 7 if ((Stream = fdopen (fd, "r+")) == FILE_NULL) { if (Debug) perror (Name); if (Log) syslog (LOG_ERR, "fdopen(\"%s\"): %m", Name); finis (); } d1053 1 d1167 108 @ 1.11 log @Maded openlog facility definable in Makefile. -pbp @ text @d23 1 a23 1 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 $"; d37 7 a43 1 # include <sys/inode.h> d470 1 a470 1 syslog(LOG_ERR, "ContactQI: cannot get connection"); d480 4 a483 2 fprintf (stderr, "server \"%s\" unknown", QISERVICE); goto severe; @ 1.10 log @Pyramid specific changes. -pbp @ text @d23 1 a23 1 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 $"; d343 4 a346 1 openlog(MyName, LOG_PID, LOG_MAIL); @ 1.9 log @Sundry formatting changes, added more text to messages. -pbp @ text @d23 1 a23 1 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 $"; d31 8 a38 1 #include <sys/inode.h> d147 1 a147 1 " whenever the supplied name or alias matched over thirty ph nameserver", @ 1.8 log @Final Wednesday morning clean-ups, typo-corrections, and semi-major re-write of Query(). Now handles callsigns which was easier than changing the extant documentation. Erasing people's minds would have been tough too. -pbp @ text @d23 1 a23 1 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 $"; d43 2 d91 5 a95 5 #define CHNULL ('\0') #define CPNULL ((char *) NULL) #define FILE_NULL ((FILE *) NULL) #define NADD_NULL ((struct NewAddress *) NULL) #define QIR_NULL ((struct QI_response *) NULL) d97 1 d101 2 a102 5 /* Flags to control printing of informative messages in ErrorReturn() */ #define NO_MATCH 1 #define MULTI 2 #define ABSENT 4 #define TOO_MANY 8 d104 7 d116 5 a120 3 " the supplied name. The usual cause is typographical errors. Recommended", " action is to use the ph program to determine the correct ph alias for the", " individuals addressed.", d164 8 a171 2 /* large string size */ #define MAXSTR 250 d173 2 a174 2 FILE *ToQI = FILE_NULL; /* write to the QI */ FILE *FromQI = FILE_NULL; /* read from the QI */ d179 1 a179 1 int PostmasterCC = 0; d185 1 a185 1 int ExitStat = EX_TEMPFAIL; d188 1 a188 1 char TmpFile[] = "/tmp/PhMailXXXXXXX"; d191 1 a191 1 char ErrorFile[] = "/tmp/PhErrMailXXXXXXX"; d194 1 a194 1 char NewFile[] = "/tmp/PhNewMailXXXXXXX"; d202 1 a202 1 char *TryList[] = { "alias", "callsign", "name", CPNULL }; d205 1 a205 1 char PunctChars[] = "-_.,+=#$"; d211 2 a212 2 int Debug = 0; int Log = 1; d215 1 a215 1 char *From = CPNULL; d570 1 a570 1 fprintf (Emsg, "\n --------Error Detail:\n\n"); d575 1 a575 1 if (! (flags & NO_MATCH)) { d577 1 a577 1 flags |= NO_MATCH; d583 1 a583 1 if (! (flags & ABSENT)) { d585 5 a589 1 flags |= ABSENT; d599 1 a599 1 if (! (flags & TOO_MANY)) { d601 1 a601 1 flags |= TOO_MANY; d607 1 a607 1 if (! (flags & MULTI)) { d609 5 a613 1 flags |= MULTI; d779 1 a779 1 fprintf (Nmsg, "X-PH-To:"); @ 1.7 log @First working version up to spec. -pbp @ text @d23 1 a23 1 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 $"; d107 1 a107 1 " The message, \"No matches to nameserver request,\" is generated whenever", d130 1 a130 1 " The message, \"Too many matches found to nameserver request,\" is generated", d135 1 a135 1 " You may have though that you had used a ph alias and not a name. This is", d137 3 a139 2 " alias, it is retried as a name. While aliases are guaranteed unique, names", " can match multiple individuals depending on how common the name is.", d181 8 d960 1 d963 1 d976 2 a977 9 /* Make a query out of the arguments for a alias lookup */ fprintf (ToQI, "query alias=%s return name alias phone department curriculum email\n", New->original); if (Debug) printf ("querying for alias \"%s\"\n", New->original); if (Log) syslog (LOG_DEBUG, "querying for alias \"%s\"\n", New->original); (void) fflush (ToQI); d979 8 a986 22 /* * Get response. The possibilities are * * -200:1: alias: Paul-Pomes * -200:1: name: pomes paul b * -508:1: curriculum: Not present in entry. * -200:1: department: Computing Services Office * -200:1: email: paul@@uxc.cso.uiuc.edu * 200:Ok. * * 501:No matches to your query. */ EmailQ = ReadQI (FromQI); if (EmailQ->code != LR_NOMATCH) { QIp = PickField (EmailQ, EMAIL); assert (QIp->field == EMAIL) New->code = abs (QIp->code); New->QIalt = EmailQ; switch (abs (QIp->code)) { case LR_ABSENT: New->new = CodeString (QIp->code); return; d988 28 a1015 3 case LR_OK: New->new = QIp->message; return; d1017 16 a1032 7 default: if (Debug) fprintf (stderr, "unexpected code %d\n", QIp->code); if (Log) syslog (LOG_ERR, "Query: Alias: unexpected code %d", QIp->code); finis (); a1033 2 } GarbageCollect (EmailQ); d1035 2 a1036 3 /* * Try as a full name. */ d1038 6 a1043 5 /* Convert punctuation/separators in the name to space characters. */ (void) strcpy (scratch, New->original); for (i = 0; PunctChars[i] != CHNULL; i++) while ((sp = index (scratch, PunctChars[i])) != CPNULL) *sp = ' '; d1045 10 a1054 12 /* Make a query out of the arguments */ fprintf (ToQI, "query name=%s return name alias phone department curriculum email\n", scratch); if (Debug) printf ("querying for name \"%s\"\n", scratch); if (Log) syslog (LOG_DEBUG, "querying for name \"%s\"\n", scratch); (void) fflush (ToQI); /* Grab the responses and let the fun begin */ EmailQ = ReadQI (FromQI); d1056 3 a1058 10 /* * No matches at all? Too many? Note that single line errors will * have code > 0. */ if (EmailQ->code > 0) { New->new = CodeString (EmailQ->code); New->code = EmailQ->code; New->QIalt = QIR_NULL; return; } d1060 8 a1067 8 /* anything else must be multi-line */ assert (EmailQ->code < 0); /* Are there multiple responses (subcode > 1)? */ for (QIp = EmailQ, multi = 0; QIp->code < 0; QIp++) if (QIp->subcode > 1) { multi++; break; d1070 5 a1074 9 /* If one person, handle as single match alias */ if (multi == 0) { QIp = PickField (EmailQ, EMAIL); assert (QIp->field == EMAIL) New->code = abs (QIp->code); New->QIalt = EmailQ; switch (abs (QIp->code)) { case LR_ABSENT: New->new = CodeString (QIp->code); a1075 12 case LR_OK: New->new = QIp->message; return; default: if (Debug) fprintf (stderr, "unexpected code %d\n", QIp->code); if (Log) syslog (LOG_ERR, "Query: Fullname: unexpected code %d", QIp->code); finis (); d1077 1 a1078 8 /* Multiple matches. */ else { New->code = LR_AMBIGUOUS; New->new = CodeString (LR_AMBIGUOUS); New->QIalt = EmailQ; } return; d1143 1 d1260 1 d1263 1 @ 1.6 log @First working version of fullname code. Still to come: alternates response and callsign. -pbp @ text @d23 1 a23 1 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 $"; d60 2 a61 2 ** fields as ls has option letters. The most important are alias, email, ** name, and, if I get around to it, callsign. In the simplest case, d98 56 d241 1 a241 1 0 d302 2 d356 3 a358 2 (void) strcpy (Buf, *argv); NewP->code = Query (Buf, sizeof Buf); d360 2 a361 1 printf ("code %d, %s --> %s\n", NewP->code, *argv, Buf); d363 2 a364 14 syslog (LOG_INFO, "%s --> %s", *argv, Buf); if (*Buf == CHNULL) { /* really bad news... */ if (Debug) fprintf (stderr, "LR_OK & null address\n"); if (Log) syslog (LOG_ERR, "LR_OK & null address"); ExitStat = EX_SOFTWARE; finis (); } else { NewP->new = malloc ((unsigned) (strlen (Buf) + 1)); (void) strcpy (NewP->new, Buf); } d393 1 a393 1 ** socket connections to the QI server. d399 1 a399 1 ** 0 on success, the appropriate sysexit code if not. d418 1 a418 1 return (0); d494 1 a494 1 return (0); d522 9 a530 5 int i; char Buf[MAXSTR]; FILE *Emsg; int pid; int ByteLimit = 15000; d543 52 a594 4 for (; Addr->original != CPNULL; Addr++) if (abs (Addr->code) != LR_OK) fprintf (Emsg, " %15s %s\n", Addr->original, Addr->new); /* XXX Loop again here to insert alternatives plus message */ a818 155 ** AliasToMail -- format and send a alias lookup to the QI ** ** Takes a presumed QI alias and formats it into a query for the QI. ** The response is read by ReadQI, garbage collection is done, and ** a pointer to a QI_response struct is returned. ** ** Parameters: ** Alias -- a buffer containing a QI alias ** ** Returns: ** Pointer to malloc()'ed data with the email address or error ** message if any error is found. ** ** Side Effects: ** none */ QIR * AliasToMail (Alias) char *Alias; { QIR *QIp; /* response chain pointer */ QIR *tp; /* garbage collection temp */ QIR *ReadQI(); char *Realloc(); /* Make a query out of the arguments */ fprintf (ToQI, "query alias=%s return email\n", Alias); if (Debug) printf ("querying for alias \"%s\"\n", Alias); if (Log) syslog (LOG_DEBUG, "querying for alias \"%s\"\n", Alias); (void) fflush (ToQI); /* * Get response. The possibilities are * * -200: email: <address> * 200:Ok. * * -508:1: email: Not present in entry. * 200:Ok. * * 501:No matches to your query. * * In any case, ignore anything after first response. */ QIp = ReadQI (FromQI); /* garbage collect */ if (QIp->code < 0) { /* Mark this as the last by making code > 0 */ QIp->code *= -1; /* Loop and free message pointers */ tp = QIp; do { tp++; if (tp->message != CHNULL) free (tp->message); } while (tp->code < 0); /* Zap all other than first record */ QIp = (QIR *) Realloc ((char *) QIp, sizeof (QIR)); } return (QIp); } \f /* ** CallsignToMail -- Format and send a callsign lookup to the QI ** ** Takes a presumed QI callsign and formats it into a query for the QI. ** A pointer to a static array containing the answer or error message ** text is returned. The calling procedure should examine ResponseCode. ** ** Parameters: ** CallSign -- a buffer containing a QI callsign ** ResponseCode -- integer pointer for result codes ** ** Returns: ** Pointer to static data with the email address or error ** message if any error is found. ** ** Side Effects: ** Modifies ResponseCode to report back errors. */ char * CallsignToMail (CallSign, ResponseCode) char *CallSign; int *ResponseCode; { static char NameVar[MAXSTR]; /* Make a query out of the arguments */ fprintf (ToQI, "query callsign=%s return email\n", CallSign); if (Debug) printf ("querying for alias \"%s\"\n", CallSign); (void) fflush (ToQI); /* *ResponseCode = XXX; */ return (NameVar); } \f /* ** FullnameToMail -- Format and send a full name lookup to the QI ** ** Takes a presumed QI full name and formats it into a query for the QI. ** The response is read by ReadQI, garbage collection is done, and ** a pointer to a QI_response struct is returned. ** ** Parameters: ** FullName -- a buffer containing a QI name ** ** Returns: ** Pointer to malloc()'ed data with the email address and other ** data (alias, name, department and curriculum). If the name ** is ambiguous, multiple records chained after the returned ** pointer are included. ** ** Side Effects: ** None */ QIR * FullnameToMail (FullName) char *FullName; { QIR *QIp; /* response chain pointer */ char scratch[MAXSTR]; /* copy of FullName w.o. punct */ char *sp; /* work ptr for scratch */ int i; /* good ol' i */ extern char PunctChars[]; QIR *ReadQI(); char *Realloc(); /* Convert punctuation/separators in the name to space characters. */ (void) strcpy (scratch, FullName); for (i = 0; PunctChars[i] != CHNULL; i++) while ((sp = index (scratch, PunctChars[i])) != CPNULL) *sp = ' '; /* Make a query out of the arguments */ fprintf (ToQI, "query name=%s return alias name department curriculum email\n", scratch); if (Debug) printf ("querying for name \"%s\"\n", scratch); if (Log) syslog (LOG_DEBUG, "querying for name \"%s\"\n", scratch); (void) fflush (ToQI); /* Grab the responses and let the fun begin */ QIp = ReadQI (FromQI); /* Let Query() (the calling routine) sort things out */ return (QIp); } \f /* d894 29 d929 2 a930 1 ** instead of the address. d933 1 a933 2 ** nbuf -- a buffer containing a QI user name/alias. ** nbsize -- the size of nbuf. d936 1 a936 2 ** An exit code telling if the username was found and ** whether an email address was found. d940 1 d945 2 a946 3 Query(nbuf, nbsize) char *nbuf; int nbsize; d948 5 a952 3 QIR *EmailQ, *QIp; int code; /* Response from ContactQI */ int multi; /* Set if more than 1 person */ d954 3 a956 3 QIR *AliasToMail(); char *CallsignToMail(); QIR *FullnameToMail(); d959 1 a959 2 if ((code = ContactQI())) return (code); d962 1 a962 2 * Try the query as an alias lookup first, then as one of a * possible full name combinations. d965 9 a973 6 EmailQ = AliasToMail (nbuf); switch (abs (EmailQ->code)) { case LR_OK: (void) strncpy (nbuf, EmailQ->message, nbsize-2); nbuf[nbsize-1] = CHNULL; return (EmailQ->code); d975 35 a1009 4 case LR_ABSENT: (void) strncpy (nbuf, CodeString (EmailQ->code), nbsize-2); nbuf[nbsize-1] = CHNULL; return (EmailQ->code); d1011 1 d1013 19 a1031 9 #ifdef notdef /* try as a callsign */ EmailP = CallsignToMail (nbuf, &code); if (code != LR_NOMATCH) { (void) strncpy (nbuf, EmailP, nbsize-2); nbuf[nbsize-1] = CHNULL; return (code); } #endif notdef d1033 3 d1037 2 a1038 2 * Try as a fullname. This must be last since no test of * code is done. d1040 5 a1044 7 EmailQ = FullnameToMail (nbuf); /* No matches at all? */ if (EmailQ->code > 0 && EmailQ->code == LR_NOMATCH) { (void) strncpy (nbuf, CodeString (EmailQ->code), nbsize-2); nbuf[nbsize-1] = CHNULL; return (abs (EmailQ->code)); d1047 1 a1047 1 /* anything must be multi-line */ d1051 2 a1052 2 for (QIp = EmailQ, multi = 0; QIp->code < 0 && multi == 0; QIp++) if (QIp->subcode > 1) d1054 2 d1057 1 a1057 1 /* If one person, search for email field */ d1059 8 a1066 4 for (QIp = EmailQ; QIp->code < 0 && QIp->field != EMAIL; QIp++) ; /* if not EMAIL, something went wrong in the query process */ assert (QIp->field == EMAIL); d1068 11 a1078 4 if (abs (QIp->code) != LR_OK) { (void) strncpy (nbuf, CodeString (QIp->code), nbsize-2); nbuf[nbsize-1] = CHNULL; return (abs (EmailQ->code)); a1079 5 else { (void) strncpy (nbuf, QIp->message, nbsize-2); nbuf[nbsize-1] = CHNULL; return (abs (QIp->code)); } d1082 1 a1082 2 /* Multiple matches. Create the error message listing alternatives. */ /* XXX for now, just say that it's a no-no. */ d1084 3 a1086 3 (void) strncpy (nbuf, CodeString (LR_TOOMANY), nbsize-2); nbuf[nbsize-1] = CHNULL; return (LR_TOOMANY); d1088 1 d1110 1 d1248 25 d1305 24 d1389 2 a1390 4 if (FullText) { while (CopyLeft[which] != CPNULL) printf ("%s\n", CopyLeft[which++]); } @ 1.5 log @Added ReadQI() function. Working version ready for CallsignToMail() and FullnameToMail() to be done. Famous last words. -pbp @ text @d29 1 d124 3 d271 1 a271 1 finis (); d325 1 a325 1 if (NewP->code != LR_OK) { d332 1 a332 1 if (NewP->code == LR_OK) { d492 1 a492 1 if (Addr->code != LR_OK) d517 1 d534 1 d650 1 a650 1 if (AddrP->code == LR_OK) { d692 1 d709 1 d825 2 a826 2 ** A pointer to a static array containing the answer or error message ** text is returned. The calling procedure should examine ResponseCode. a829 1 ** ResponseCode -- integer pointer for result codes d832 4 a835 2 ** Pointer to static data with the email address or error ** message if any error is found. d838 1 a838 1 ** Modifies ResponseCode to report back errors. d841 2 a842 2 char * FullnameToMail (FullName, ResponseCode) a843 1 int *ResponseCode; d845 7 a851 1 static char NameVar[MAXSTR]; d853 6 d860 1 a860 1 fprintf (ToQI, "query name=%s return email\n", FullName); d862 3 a864 1 printf ("querying for alias \"%s\"\n", FullName); d866 6 a871 2 /* *ResponseCode = XXX; */ return (NameVar); d895 1 a895 1 if (Cpnt->key == code) d926 1 a926 1 return (FILE_NULL); d935 1 a935 1 return (FILE_NULL); d944 1 a944 1 return (FILE_NULL); d975 3 a977 2 QIR *EmailQ; int code; d981 1 a981 1 char *FullnameToMail(); d993 1 a993 1 switch (EmailQ->code) { d999 1 a999 1 case LR_NOMATCH: d1007 1 a1007 1 EMailP = CallsignToMail (nbuf, &code); d1009 1 a1009 1 (void) strncpy (nbuf, EMailP, nbsize-2); d1013 1 d1019 43 a1061 5 EMailP = FullnameToMail (nbuf, &code); (void) strncpy (nbuf, EMailP, nbsize-2); nbuf[nbsize-1] = CHNULL; #endif notdef return (code); d1132 1 d1144 1 a1144 1 fprintf (stderr, "ReadQI: short #1 fscanf\n"); d1146 2 a1147 1 syslog (LOG_ERR, "ReadQI: short #1 fscanf read: %m"); d1156 1 a1156 1 fprintf (stderr, "ReadQI: short fscanf\n"); d1158 2 a1159 1 syslog (LOG_ERR, "ReadQI: short fscanf read: %m"); d1247 1 d1281 1 @ 1.4 log @Formatting niceties. @ text @d13 1 d16 1 d23 1 a23 1 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 $"; d42 1 a42 1 /* designated server port */ d45 1 a45 1 /* the mail transport agent of choice */ a47 2 int PostmasterCC = 0; d49 1 a49 1 ** PHQUERY -- resolve fuzzy addresses to specific a user@@FQDN d90 3 a92 2 #define FILENULL ((FILE *) NULL) #define NADDNULL ((struct NewAddress *) NULL) d94 3 d100 2 a101 2 FILE *ToQI = FILENULL; /* write to the QI */ FILE *FromQI = FILENULL; /* read from the QI */ d105 4 a108 1 /* how program was invoked (argv[0]) for error messages */ d111 1 a111 1 /* exit status for reporting to calling process */ d114 1 a114 1 /* temporary message file */ d117 1 a117 1 /* temporary file for creating error messages */ d120 1 a120 1 /* temporary file for rewriting messages */ d123 4 a126 1 /* how to report events: Debug set for stderr messages, Log for syslog */ d130 1 a130 1 /* from address supplied by caller */ d143 5 a147 5 " This program is distributed in the hope that it will be useful,", " but without any warranty. No author or distributor accepts", " responsibility to anyone for the consequences of using it or for", " whether it serves any particular purpose or works at all, unless", " s/he says so in writing.", d149 2 a150 2 " Everyone is granted permission to copy, modify and redistribute", " this program under the following conditions:", d152 7 a158 7 " Permission is granted to anyone to make or distribute copies", " of program source code, either as received or modified, in any", " medium, provided that all copyright notices, permission and", " nonwarranty notices are preserved, and that the distributor", " grants the recipient permission for further redistribution as", " permitted by this document, and gives him and points out to", " him an exact copy of this document to inform him of his rights.", d160 3 a162 13 " Permission is granted to distribute this program in compiled", " or executable form under the same conditions applying for", " source code, provided that either", " A. it is accompanied by the corresponding machine-readable", " source code, or", " B. it is accompanied by a written offer, with no time limit,", " to give anyone a machine-readable copy of the corresponding", " source code in return for reimbursement of the cost of", " distribution. This written offer must permit verbatim", " duplication by anyone.", " C. it is distributed by someone who received only the", " executable form, and is accompanied by a copy of the", " written offer of source code which he received along with it.", d164 9 a172 3 " In other words, you are welcome to use, share and improve this", " program. You are forbidden to forbid anyone else to use, share", " and improve what you give them. Help stamp out software-hoarding!", d174 4 d179 1 a179 1 "Internet, BITNET: paul@@uxc.cso.uiuc.edu Phone: 217 359 0881", d196 1 a196 1 extern FILE *OpenTemp(); d200 1 d247 1 a247 1 /* fire up logging, or not, as the flags may be */ d258 2 a259 2 /* open the temp file, copy the message into it */ if ((Msg = OpenTemp (TmpFile)) == FILENULL) d279 1 a279 1 /* allocate NewAddress structs for addresses */ d281 1 a281 1 * sizeof (NADD)))) == NADDNULL) { d291 1 a291 1 /* loop on addresses in argv building up translation table */ d297 1 a297 2 fprintf (stderr, "code %d, %s --> %s\n", NewP->code, *argv, Buf); d317 2 a318 2 * now re-invoke sendmail with the translated addresses. * make one pass for collecting error returns into one message. d326 1 a326 1 /* any good addresses? */ d338 1 a338 1 ** ContactQI -- connect to the QI server d362 2 a363 2 /* already opened */ if (ToQI != FILENULL && FromQI != FILENULL) { d371 1 a371 1 /* get a socket for the QI connection */ d383 1 a383 1 /* find the proper port */ d392 1 a392 1 /* find the proper host */ d401 1 a401 1 /* connect to the nameserver */ d422 1 a422 1 /* there are others, I'm sure..... */ d426 1 a426 1 /* why is this happening? */ d439 1 a439 1 /* connection ok, change to canonical form */ d447 3 a454 1 ** MsgSelect -- select which error messages to include d465 1 a465 1 ErrorReturn (Addr, Omsg, envp, MsgSelect) a468 1 int MsgSelect; d477 2 a478 2 /* open the error file */ if ((Emsg = OpenTemp (ErrorFile)) == FILENULL) d481 1 a481 1 /* insert the headers */ d508 1 a508 1 if (freopen (ErrorFile, "r", stdin) == FILENULL) { d515 1 a515 1 /* zap file so it disappears automagically */ d580 1 a580 1 * punt to postmaster. if there's too a608 2 #define nequal(s1,s2,n) (strncasecmp (s1, s2, n) == 0) d614 9 a622 9 int napi = 0; int i; char Buf[MAXSTR]; NADD *AddrP; FILE *Nmsg; int pid = 0; char *nap[50]; extern FILE *OpenTemp(); extern char *From; d624 2 a625 2 /* open the rewrite file */ if ((Nmsg = OpenTemp (NewFile)) == FILENULL) d628 1 a628 1 /* fill out the first portion of the sendmail argument vector */ d633 1 a633 1 /* read and copy the header block, adding the X-PH-To: header */ d640 1 a640 1 /* write the PH header and add to argv */ d660 8 a667 1 /* copy the remainder of the message */ d671 1 a671 1 perror("Nmsg copy"); d678 1 a678 1 /* re-arrange the stream pointers and invoke sendmail */ d681 1 a681 1 if (freopen (NewFile, "r", stdin) == FILENULL) { d688 1 a688 1 /* zap file so it disappears automagically */ d714 2 a715 2 ** A pointer to a static array containing the answer or error message ** text is returned. The calling procedure should examine ResponseCode. a718 1 ** ResponseCode -- integer pointer for result codes d721 1 a721 1 ** Pointer to static data with the email address or error d725 1 a725 1 ** Modifies ResponseCode to report back errors. d728 2 a729 4 #define GetQValue(Line) (index(index(index(Line,':')+1,':')+1,':')+2) char * AliasToMail (Alias, ResponseCode) a730 1 int *ResponseCode; d732 4 a735 9 /* pointer to NameVar returned by this function */ static char NameVar[MAXSTR]; char scratch[MAXSTR]; /* some space */ int Scode = -1; /* QI code temporary */ int code; /* value set by GetNonCom() */ int GotOne = 0; /* for picking best QI value */ int Leave = 0; int InRep = 0; char *CodeString(); /* explicit error messages */ d737 1 a737 1 /* make a query out of the arguments */ d741 2 a742 1 syslog (LOG_DEBUG, "querying for alias \"%s\"\n", Alias); d745 14 a758 21 do { /* break on read error. the QI will not return a -1 code */ if ((code = GetNonCom(scratch, MAXSTR, FromQI)) == -1) break; /* * test the code from the first field in a qi response. * continuation lines have a leading '-' so the code < 0 . */ if (code < 0) { InRep++; Scode = code *= -1; } else InRep = 0; switch (code) { case LR_PROGRESS: case LR_ECHO: case LR_RONLY: Leave = (! InRep) ? 1 : 0; break; d760 2 a761 17 case LR_OK: /* * If this is a terminal OK, return previous code if * there was one. */ if (! InRep) { code = (Scode > -1) ? Scode : code; Leave++; } else if (! GotOne) { /* record sought after response */ (void) strcpy (NameVar, GetQValue (scratch)); /* strip newline */ NameVar[strlen (NameVar) - 1] = '\0'; GotOne++; } break; d763 2 a764 5 case LR_TEMP: case LR_INTERNAL: case LR_LOCK: /* supposedly temporary errors */ finis (); d766 7 a772 28 case LR_LOGIN: case LR_MORE: case LR_ERROR: case LR_NOMATCH: case LR_TOOMANY: case LR_AINFO: case LR_ASEARCH: case LR_ACHANGE: case LR_NOTLOG: case LR_FIELD: case LR_ABSENT: case LR_ALIAS: case LR_AENTRY: case LR_ADD: case LR_VALUE: case LR_OPTION: case LR_UNKNOWN: case LR_NOKEY: case LR_AUTH: case LR_READONLY: case LR_LIMIT: case LR_HISTORY: case LR_SYNTAX: /* print up a friendly error message */ (void) sprintf (NameVar, "%d: %s", code, CodeString (code)); Leave = (! InRep) ? 1 : 0; break; d774 4 a777 10 default: (void) sprintf (NameVar, "%d: Unknown nameserver error", code); PostmasterCC++; Leave = (! InRep) ? 1 : 0; break; } } while (code < 0 || ! Leave); *ResponseCode = (Scode > -1) ? Scode : code; return (NameVar); d780 1 a780 1 ** CallsignToMail -- format and send a callsign lookup to the QI d805 1 a805 1 /* make a query out of the arguments */ d814 1 a814 1 ** FullnameToMail -- format and send a full name lookup to the QI d839 1 a839 1 /* make a query out of the arguments */ a873 39 ** GetNonCom -- Get a non-comment line from a stream ** ** Read a stream descriptor until a non-comment line is found or EOF. ** ** Parameters: ** String - pointer to line storage ** maxChars - maximum number of characters to read ** InFile - stream to read from ** ** Returns: ** integer value of first field in string, ** or -1 on EOF or error ** ** Side Effects: ** none */ GetNonCom (String, maxChars, InFile) char *String; int maxChars; FILE *InFile; { for (;;) { if (fgets (String, maxChars, InFile) == NULL) return (-1); else if (*String == '#') continue; else if (*String != '-' && ! isdigit (*String)) { if (Debug) fprintf (stderr, "GetNonCom: bad string: %s", String); syslog (LOG_ERR, "GetNonCom: bad string: %s", String); continue; } else return (atoi(String)); /* success */ } } \f /* d900 1 a900 1 return (FILENULL); d903 1 a903 1 /* protect it */ d909 1 a909 1 return (FILENULL); d912 2 a913 2 /* make fd a stream */ if ((Stream = fdopen (fd, "r+")) == FILENULL) { d918 1 a918 1 return (FILENULL); d949 1 a949 1 char *EMailP; d952 1 a952 1 char *AliasToMail(); d965 6 a970 2 if ((EMailP = AliasToMail (nbuf, &code)) != CPNULL) (void) strncpy (nbuf, EMailP, nbsize-1); d972 7 d980 6 a985 2 else if ((EMailP = CallsignToMail (nbuf, &code)) != CPNULL) (void) strncpy (nbuf, EMailP, nbsize-1); d987 8 a994 5 /* try as a fullname */ else if ((EMailP = FullnameToMail (nbuf, &code)) != CPNULL) (void) strncpy (nbuf, EMailP, nbsize-1); /* return the answer */ d998 217 d1264 1 a1264 1 if (ToQI != FILENULL) d1266 1 a1266 1 if (FromQI != FILENULL) d1268 1 a1268 1 ToQI = FromQI = FILENULL; @ 1.3 log @AliasToMail and PutResponse combined. Next Fullname/CallsignToMail. -pbp @ text @d21 1 a21 1 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 $"; d96 2 a97 2 FILE *ToQI = FILENULL; /* write to the QI */ FILE *FromQI = FILENULL; /* read from the QI */ d169 1 a169 1 "Internet, BITNET: paul@@uxc.cso.uiuc.edu", d178 8 a185 8 extern int optind; /* from getopt () */ extern char *optarg; /* from getopt () */ int option; /* option "letter" */ int i; /* good ol' i */ FILE *Msg; /* stream pointer for temp file */ NADD *New, *NewP; /* translated addresses */ char Buf[MAXSTR]; extern char *malloc(), *rindex(); d197 1 d345 6 a350 6 int sock; /* our socket */ int sav_errno; struct sockaddr_in QI; /* the address of the nameserver */ struct servent *theNs; /* nameserver service entry */ struct hostent *theHost;/* host entry for nameserver */ extern FILE *ToQI, *FromQI; d358 1 a358 1 if (Debug > 1) d362 1 a362 2 sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) d374 2 a375 2 if (theNs = getservbyname (QISERVICE, "tcp")) { QI.sin_port = theNs->s_port; d383 2 a384 2 if (theHost = gethostbyname (QI_HOST)) { bcopy (theHost->h_addr, (char *) &QI.sin_addr.s_addr, 4); d429 1 a429 1 /* connection ok, put it into canonical form */ d442 1 d453 1 a453 1 ErrorReturn (Addr, Omsg, envp) d457 1 d459 6 a464 6 int i; char Buf[MAXSTR]; FILE *Emsg; int pid; int ByteLimit = 15000; extern FILE *OpenTemp(); d479 1 d702 1 a702 1 ** theAlias -- a buffer containing a QI alias d716 2 a717 2 AliasToMail (theAlias, ResponseCode) char *theAlias; d731 1 a731 1 fprintf (ToQI, "query alias=%s return email\n", theAlias); d733 2 a734 2 printf ("querying for alias \"%s\"\n", theAlias); syslog (LOG_DEBUG, "querying for alias \"%s\"\n", theAlias); d847 1 a847 1 static char NameVar[MAXSTR]; d881 1 a881 1 static char NameVar[MAXSTR]; d909 2 a910 2 struct ReplyCodes *Cpnt; extern struct ReplyCodes Codes[]; d923 1 a923 1 ** theString - pointer to line storage d925 1 a925 1 ** theFile - stream to read from d935 2 a936 2 GetNonCom (theString, maxChars, theFile) char *theString; d938 1 a938 1 FILE *theFile; d941 1 a941 1 if (fgets (theString, maxChars, theFile) == NULL) d943 1 a943 1 else if (*theString == '#') d945 1 a945 1 else if (*theString != '-' && ! isdigit (*theString)) { d948 2 a949 2 theString); syslog (LOG_ERR, "GetNonCom: bad string: %s", theString); d953 1 a953 1 return (atoi(theString)); /* success */ d1032 6 a1037 6 char *EMailP; int code; extern FILE *ToQI, *FromQI; char *AliasToMail(); char *CallsignToMail(); char *FullnameToMail(); d1081 1 a1081 1 int which = 0; /* current line */ d1109 1 a1109 1 extern FILE *ToQI, *FromQI; @ 1.2 log @Checking in clean-ups before renovation. -pbp @ text @d22 3 a24 1 #endif /* not lint */ a103 3 /* global status variable */ int ResponseCode; d219 1 d225 1 d392 1 a392 1 if (connect(sock, &QI, sizeof (QI)) < 0) a579 120 ** PutResponse -- insert first successful response from QI into a string ** ** Take the result returned from a QI query and and pack it into the ** argument string. This can be either the email address or the error ** message. The return code must be examined to tell which. ** Because the QI returns different formats depending on the answer, ** a FSM is used to process the response. ** ** Parameters: ** NameVar - string to store the QI response into ** ** Returns: ** The code status from QI ** ** Side Effects: ** none */ #define GetQValue(aLine) (index(index(index(aLine,':')+1,':')+1,':')+2) PutResponse (NameVar) char *NameVar; { char scratch[MAXSTR]; /* some space */ int Scode = -1; int code; int GotOne = 0; int Leave = 0; int InRep = 0; int i; char *CodeString(); while ((i = GetGood(scratch, MAXSTR, FromQI)) >= 0) { /* read it */ /* break on read error */ if (i == -1) break; /* * get the code from the first field in scratch. continuation * lines have a leading '-' so the code will be negative for * them. */ if ((code = atoi (scratch)) < 0) { InRep++; code *= -1; Scode = code; } else InRep = 0; switch (code) { case LR_PROGRESS: case LR_ECHO: case LR_RONLY: Leave = (! InRep) ? 1 : 0; break; case LR_OK: /* * if this is a terminal OK, return previous code if * there was one */ if (! InRep) return ((Scode > -1) ? Scode : code); else if (! GotOne) { /* record sought after response */ (void) strcpy (NameVar, GetQValue (scratch)); /* strip newline */ NameVar[strlen (NameVar) - 1] = '\0'; GotOne++; } break; case LR_TEMP: case LR_INTERNAL: case LR_LOCK: /* supposedly temporary errors */ finis (); case LR_LOGIN: case LR_MORE: case LR_ERROR: case LR_NOMATCH: case LR_TOOMANY: case LR_AINFO: case LR_ASEARCH: case LR_ACHANGE: case LR_NOTLOG: case LR_FIELD: case LR_ABSENT: case LR_ALIAS: case LR_AENTRY: case LR_ADD: case LR_VALUE: case LR_OPTION: case LR_UNKNOWN: case LR_NOKEY: case LR_AUTH: case LR_READONLY: case LR_LIMIT: case LR_HISTORY: case LR_SYNTAX: (void) sprintf (NameVar, "%d: %s", code, CodeString (code)); Leave = (! InRep) ? 1 : 0; break; default: (void) sprintf (NameVar, "%d: Unknown nameserver error", code); PostmasterCC++; Leave = (! InRep) ? 1 : 0; break; } if (Leave) break; } return ((Scode > -1) ? Scode : code); } \f /* d643 1 a643 9 if (nequal (Buf, "Message-id:", 11)) fprintf (Nmsg, "X-Old-%s", Buf); else if (fputs (Buf, Nmsg) == EOF) { if (Debug) perror ("ReMail"); if (Log) syslog (LOG_ERR, "ReMail: %m"); finis (); } d695 2 a696 3 ** A pointer to a static array containing the answer is returned. ** If the NULL pointer is returned, the calling procedure should ** examine ResponseCode. d700 1 d707 1 a707 2 ** Will call ContactQI() if the connection is closed. ** Uses ResponseCode to report back errors. d710 2 d713 1 a713 1 AliasToMail (theAlias) d715 1 d717 9 a725 1 static char NameVar[MAXSTR]; a726 3 if ((ResponseCode = ContactQI())) return (CPNULL); d731 1 d733 85 a817 1 ResponseCode = PutResponse (NameVar); d821 68 d915 1 a915 1 ** GetGood -- Get a non-comment line from a stream d925 2 a926 1 ** 1 on success, 0 if comment, -1 on EOF or error d932 1 a932 1 GetGood (theString, maxChars, theFile) d940 11 a950 4 if (*theString == '#') return (0); /* a comment */ else return (1); /* success */ d1020 1 d1033 2 d1036 4 d1045 1 a1045 2 if ((EMailP = AliasToMail (nbuf)) != CPNULL) { code = ResponseCode; a1046 1 } a1047 1 #ifdef notdef d1049 1 a1049 2 else if ((EMailP = CallsignToMail (nbuf)) != CPNULL) { code = ResponseCode; a1050 1 } d1053 1 a1053 2 else if ((EMailP = FullnameToMail (nbuf)) != CPNULL) { code = ResponseCode; a1054 2 } #endif notdef a1055 5 /* give it up, return code */ else { code = ResponseCode; } d1069 1 a1069 1 ** none, exit (1) d1072 1 a1072 1 ** program terminates a1089 1 finis (); @ 1.1 log @Initial revision @ text @d21 1 a21 1 static char rcsid[] = "@@(#)$Header$"; a33 1 #include <errno.h> d89 1 d102 3 d125 1 a125 1 "usage: %s [-d] [-p] [-l] [-i] [-f FromAddress] address1 [address2]", a128 8 struct NewAddress { char *original; char *new; int code; }; typedef struct NewAddress NADD; d191 1 a191 1 while ((option = getopt (argc, argv, "f:r:pdli")) != EOF) { d197 9 d268 1 a268 1 * sizeof (NADD)))) == (NADD *) NULL) { d824 1 a824 1 ** examine errno. d835 1 a835 1 ** Uses errno to report back errors. d844 1 a844 1 if ((errno = ContactQI())) d852 1 a852 1 errno = PutResponse (NameVar); d964 1 a964 1 ** Takes a full name or user alias, as known by the CSnet central d987 1 a987 1 char *email_p; d997 3 a999 3 if ((email_p = AliasToMail(nbuf)) != CPNULL) { code = errno; (void) strncpy (nbuf, email_p, nbsize-1); d1002 14 a1015 4 /* * try formatting the name into a full name */ d1018 1 a1018 1 code = errno; @