|
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 r
Length: 15594 (0x3cea) Types: TextFile Names: »rcvtrip.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0 └─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z« └─⟦e5a54fb17⟧ └─⟦this⟧ »pp-5.0/Uip/rcvtrip/rcvtrip.c«
/* rcvtrip.c: trip reporting program */ # ifndef lint static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Uip/rcvtrip/RCS/rcvtrip.c,v 5.0 90/09/20 16:34:22 pp Exp Locker: pp $"; # endif /* * $Header: /cs/research/pp/hubris/pp-beta/Uip/rcvtrip/RCS/rcvtrip.c,v 5.0 90/09/20 16:34:22 pp Exp Locker: pp $ * * $Log: rcvtrip.c,v $ * Revision 5.0 90/09/20 16:34:22 pp * rcsforce : 5.0 public release * */ #include "util.h" #include "retcode.h" #include "adr.h" #include "ap.h" #include "chan.h" #include "alias.h" #include <pwd.h> #define NONFATAL 0 /* Nonfatal reports */ #define FATAL 1 /* Fatal reports (exit) */ #define TRACE 2 /* General info for debug */ #define EX_SENT 1 #define EX_DUP 2 #define EX_NOT_DIR 3 #define EX_PARSE_ERR 4 #define EX_ERR 99 #define SENT 0 /* Sent out a reply */ #define UNSENT 1 /* No reply sent - just * note */ #define REPLIED '+' /* A reply was sent */ #define NOT_REPLIED '-' /* A reply wasn't sent */ #define HDR_NAM 1 #define HDR_EOH 2 #define HDR_MOR 3 #define HDR_NEW 4 #define DAYS * (60 * 60 * 24) #ifndef MAX_HEAD_LINES #define MAX_HEAD_LINES 10 #endif /* MAX_HEAD_LINES */ extern int ap_outtype; extern char *index (); extern char *strcpy (); extern char *strncpy (); extern char *fgets (); extern char *strcat (); extern char *compress (); int debug = FALSE; /* output trace messages? */ int repeat_interval = 14 DAYS; /* repeat after this interval */ int found_1 = FALSE; /* true if message was sent to */ int head_lines = 0; int exit_alg = -1; /* algorithm to deiced on the exit code */ int exit_code = 1; /* directly to recipient */ char subj_field[LINESIZE]; /* contents of subject field */ char _username[LINESIZE]; /* space for the users username */ char *username = (char *) 0; /* the users username */ char *msg_note = "tripnote";/* where to get reply message from */ char *wholoc = "triplog"; /* where to note incoming messages */ char *sigloc = ".signature";/* where to find user's name */ char *tripsig = "MESSAGE AGENT"; /* signature of the returned message */ AP_ptr from_adr = NULLAP; /* address tree for from address */ AP_ptr sndr_adr = NULLAP; /* - " - sender */ AP_ptr repl_adr = NULLAP; /* - " - reply-to */ ADDR *user_adr; char *find_sig (); static int exit_rc(); struct passwd *getpwuid (); /* * This message is output before the users file message */ char *text_message[MAX_HEAD_LINES+1] = { "\tThis is an automatic reply. Feel free to send additional", "mail, as only this one notice will be generated. The following", "is a prerecorded message, sent for ", 0 }; /* * This message is output if the users file is not readable or doesn't * exist. (This is where you can have some fun!) */ char *error_txt[] = { "\tIt appears that the person in question hasn't left a\n", "message file, so the purpose of this message is unknown.\n", "However it is assumed that as I, a daemon process,\n", "have been called into existance that the person in question\n", "is probably away for some time and won't be replying to your\n", "message straight away.\n\nCheers,\n\tThe Mail System\n", 0 }; main (argc, argv) int argc; char **argv; { init (argc, argv); parsemsg (); doreplies (); exit (exit_rc(exit_code)); } /* * Initialisation - get user, setup flags etc. */ init (argc, argv) int argc; char **argv; { register struct passwd *pwdptr; int opt; extern int optind; extern char *optarg; RP_Buf rp; uip_init (argv[0]); ap_outtype = AP_PARSE_822; /* standardise on 822 */ while ((opt = getopt (argc, argv, "de:Ff:l:n:s:t:u:")) != EOF) switch (opt) { case 'd': debug = 1; break; case 'e': exit_alg = atoi(optarg); break; case 'F': found_1 = 1; break; case 'f': tripsig = optarg; break; case 'l': wholoc = optarg; break; case 'n': msg_note = optarg; break; /* This is disapbled for the momet ... */ case 'r': opt = atoi(optarg); if (!opt && *optarg != '0') break; repeat_interval = opt DAYS; break; case 's': sigloc = optarg; break; case 't': if (head_lines < MAX_HEAD_LINES) text_message[head_lines++] = optarg; break; case 'u': username = optarg; break; } argv += optind; argc -= optind; if (argc > 0) /* we have a command line sender * address */ parse_addr (*argv, &sndr_adr); if (username) ; else if ((pwdptr = getpwuid (getuid ())) == (struct passwd *) 0) report (FATAL, EX_ERR, "Can't Identify user"); else strcpy (username = _username, pwdptr->pw_name); if (head_lines) error_txt[head_lines] = (char *) 0; user_adr = adr_new (username, AD_ANY_TYPE, 0); if (rp_isbad (ad_parse (user_adr, &rp, CH_USA_PREF))) report (FATAL, EX_PARSE_ERR, "Can't parse you as a mail user"); } /* * parse message - just a front end to the real parser */ parsemsg () { if (rp_isbad (hdr_fil (stdin))) report (FATAL, EX_PARSE_ERR, "parse of message failed"); } /*************** Routines to despatch messages ***************/ /* * Send replies to reply-to address if specified else * from and sender address. */ doreplies () { if (found_1 != TRUE) report (FATAL, EX_NOT_DIR, "Not sent directly to %s", username); if (repl_adr == NULLAP && from_adr == NULLAP && sndr_adr == NULLAP) report (FATAL, EX_PARSE_ERR, "No parsable from or sender lines"); /* * If there were any reply-to lines, use those in preference. */ if (repl_adr != NULLAP) replyto (repl_adr); else { /* send to both from && sender if * they exist */ if (from_adr != NULLAP) replyto (from_adr); if (sndr_adr != NULLAP) replyto (sndr_adr); } } /* * Actually do the work of sending the reply. */ replyto (aptr) AP_ptr aptr; { register char *cp; register char **cpp; AP_ptr user, local, domain; AP_ptr norm; char *addr; char *ref; char *person; char buffer[LINESIZE]; FILE *fp; RP_Buf rps, *rp = &rps; #ifdef PP_DEBUG report (TRACE, 0, "replyto()"); #endif norm = ap_normalize (aptr, CH_USA_PREF); ap_t2p (norm, (AP_ptr *) 0, &user, &local, &domain, (AP_ptr *) 0); ref = ap_p2s_nc (NULLAP, NULLAP, local, domain, NULLAP); #ifdef PP_DEBUG report (TRACE, 0, "normed addr = '%s'", ref); #endif if (user != NULLAP) person = user->ap_obvalue; else person = NULLCP; if (checkuser (ref)) { #ifdef PP_DEBUG report (TRACE, 0, "Seen %s before", ref); #endif noteuser (ref, UNSENT); free (ref); return; } if (ap_t2s (norm, &addr) == (AP_ptr) NOTOK) { report (NONFATAL, 0, "Parse error for %s", addr); noteuser (ref, UNSENT); free (ref); return; } buffer[0] = '\0'; if (!prefix ("re:", subj_field)) strcpy (buffer, "Re: "); strcat (buffer, subj_field); #ifdef PP_DEBUG report (TRACE, 0, "pps_1adr ('%s' %s)", buffer, addr); #endif pps_1adr (buffer, addr, rp); if (person != NULLCP) { compress (person, person); sprintf (buffer, "\nDear %s,\n", person); #ifdef PP_DEBUG report (TRACE, 0, "1st line %s", buffer); #endif pps_txt (buffer, rp); } #ifdef PP_DEBUG report (TRACE, 0, "start builtin message"); #endif for (cpp = text_message; *cpp != NULLCP; cpp++) { if (cpp != text_message) pps_txt ("\n", rp); pps_txt (*cpp, rp); } if ((cp = find_sig ()) != NULLCP) pps_txt (cp, rp); else pps_txt (username); pps_txt ("\n\n\n", rp); if ((fp = fopen (msg_note, "r")) != (FILE *) 0) { #ifdef PP_DEBUG report (TRACE, 0, "processing file %s", msg_note); #endif pps_file (fp, rp); fclose (fp); } else { #ifdef PP_DEBUG report (TRACE, 0, "Sending built in error message"); #endif for (cpp = error_txt; *cpp != NULLCP; cpp++) pps_txt (*cpp, rp); } #ifdef PP_DEBUG report (TRACE, 0, "ml_end(OK)"); #endif if (pps_end (OK, rp) == OK) noteuser (ref, SENT); else noteuser (ref, UNSENT); free (ref); free (addr); } /*************** Routines to pick apart the message ***************/ /* * The actual picking out of headers */ hdr_fil (msg) FILE *msg; /* The message file */ { char line[LINESIZE]; /* temp buffer */ char name[LINESIZE]; /* Name of header field */ char contents[LINESIZE]; /* Contents of header field */ #ifdef PP_DEBUG report (TRACE, 0, "hdr_fil()"); #endif if (msg == (FILE *) NULL) { report (FATAL, EX_PARSE_ERR, "NULL file pointer"); return (RP_NO); /* not much point doing anything * else */ } /* process the file */ for (;;) { if (fgets (line, sizeof line, msg) == NULL) { report (NONFATAL, 0, "read error on message"); return (RP_NO); /* skip and go home */ } switch (hdr_parse (line, name, contents)) { case HDR_NAM: /* No name so contine * through header */ continue; case HDR_EOH: /* End of header - lets go * home */ return (RP_OK); case HDR_NEW: case HDR_MOR: /* We have a valid field */ if (lexequ (name, "to") == 0 || lexequ (name, "cc") == 0|| lexequ (name, "resent-to") == 0 || lexequ (name, "resent-cc") == 0) { find_user (contents); break; } else if (lexequ (name, "from") == 0) { parse_addr (contents, &from_adr); break; } else if (lexequ (name, "reply-to") == 0) { parse_addr (contents, &repl_adr); break; } else if (lexequ (name, "sender") == 0) { parse_addr (contents, &sndr_adr); break; } else if (lexequ (name, "subject") == 0) { strncpy (subj_field, contents, sizeof contents - 1); break; } else continue; } } } /* * The real parser */ hdr_parse (src, name, contents) /* parse one header line */ register char *src; /* a line of header text */ char *name, /* where to put field's name */ *contents; /* where to put field's contents */ { extern char *compress (); char linetype; register char *dest; #ifdef PP_DEBUG report (TRACE, 0, "hdr_parse('%*.*s')", strlen(src)-1, strlen(src)-1, src); #endif if (isspace (*src)) { /* continuation text */ #ifdef PP_DEBUG report (TRACE, 0, "hrd_parse -> cmpnt more"); #endif if (*src == '\n') return (HDR_EOH); linetype = HDR_MOR; } else { /* copy the name */ linetype = HDR_NEW; for (dest = name; *dest = *src++; dest++) { if (*dest == ':') break; /* end of the name */ if (*dest == '\n') { /* oops, end of the line */ *dest = '\0'; return (HDR_NAM); } } *dest = '\0'; compress (name, name); /* strip extra & trailing * spaces */ #ifdef PP_DEBUG report (TRACE, 0, "hdr_parse -> cmpnt name '%s'", name); #endif } for (dest = contents; isspace (*src);) if (*src++ == '\n') { /* skip leading white space *//* u * nfulfilled promise, no * contents */ *dest = '\0'; return ((linetype == HDR_MOR) ? HDR_EOH : linetype); } /* hack to fix up illegal spaces */ while ((*dest = *src) != '\n' && *src != 0) src++, dest++; /* copy contents and then, backup */ while (isspace (*--dest)); /* to eliminate trailing * spaces */ *++dest = '\0'; return (linetype); } /*************** Parsing of addresses got from message ***************/ /* * See if user is in this field. parse address first and * compare mbox's. */ find_user (str) char *str; { AP_ptr tree, local, domain; ADDR *ad; RP_Buf rp; char *p; #ifdef PP_DEBUG report (TRACE, 0, "find_user('%s')", str); #endif if (found_1 == TRUE) { #ifdef PP_DEBUG report (TRACE, 0, "find_user() name already found\n"); #endif return; } while ((str = ap_s2p (str, &tree, (AP_ptr *) 0, (AP_ptr *) 0, &local, (AP_ptr *) &domain, (AP_ptr *) 0)) != (char *) DONE && str != (char *) NOTOK) { p = ap_p2s_nc (NULLAP, NULLAP, local, domain, NULLAP); ad = adr_new (p, AD_822_TYPE, 0); ap_sqdelete (tree, NULLAP); ap_free (tree); if (rp_isbad (ad_parse (ad, &rp, CH_USA_PREF))) { adr_free (ad); continue; } found_1 = (lexequ (ad -> ad_r822adr, user_adr -> ad_r822adr) == 0 || lexequ (p, username) == 0); #ifdef PP_DEBUG report (TRACE, 0, "find_user() -> found mbox %s (%s) ->%d", p, user_adr -> ad_r822adr, found_1); #endif free (p); if (found_1 == TRUE) return; } } /* * Attempt to parse a field into an address tree for later use. */ parse_addr (str, aptr) char *str; AP_ptr *aptr; { #ifdef PP_DEBUG report (TRACE, 0, "parse_addr('%s')", str); #endif if (*aptr != NULLAP) { #ifdef PP_DEBUG report (TRACE, 0, "field '%s' rejected, already seen one"); #endif return; } if ((*aptr = ap_s2t (str)) == (AP_ptr) NOTOK) report (NONFATAL, 0, "Can't parse address '%s'", str); } /*************** User Data Base Routines ***************/ /* * Note the fact we did/didnot reply to a given person * and include the subject line for good measure. */ noteuser (addr, mode) char *addr; int mode; { FILE *fp; time_t now; char *ctime (); int result = NOTOK; #ifdef PP_DEBUG report (TRACE, 0, "noteuser(%s,%d)", addr, mode); #endif time (&now); if ((fp = fopen (wholoc, "a")) != NULL) { (void) chmod (wholoc, 0600); fprintf (fp, "%c %-30s %19.19s >> %.20s\n", mode == SENT ? REPLIED : NOT_REPLIED, addr, ctime (&now), subj_field); (void) fflush (fp); result = ferror (fp) ? NOTOK : OK; fclose (fp); if (result == OK && mode == SENT) exit_code = 0; } return result; } /* * Have we replied to this person before? */ checkuser (addr) char *addr; { FILE *fp; char buffer[LINESIZE]; char compaddr[LINESIZE]; if (repeat_interval == 0) return FALSE; if ((fp = fopen (wholoc, "r")) == NULL) return FALSE; while (fgets (buffer, sizeof buffer, fp) != NULL) { if (buffer[0] == NOT_REPLIED) continue; /* SHOULD parse the date to see whether to repeat */ getaddress (buffer, compaddr); #ifdef PP_DEBUG report (TRACE, 0, "checkuser, = '%s' & '%s'?", compaddr, addr); #endif if (lexequ (compaddr, addr) == 0) { fclose (fp); return TRUE; } } fclose (fp); return FALSE; } /*************** Some Utility Routines ***************/ /* * Dig out a signature for the user */ char *find_sig () { FILE *fp; static char buf[LINESIZE]; static int been_here = FALSE; char *p; #ifdef PP_DEBUG report (TRACE, 0, "find_sig()"); #endif if (been_here == TRUE) /* cuts off at least 1/4 * micro-second */ return buf; if ((fp = fopen (sigloc, "r")) == NULL) return NULLCP; if (fgets (buf, sizeof (buf), fp) == NULLCP) { fclose (fp); return NULLCP; } if ((p = index (buf, '\n')) != NULLCP) *p = '\0'; fclose (fp); return buf; } getaddress (source, dest) char *source, *dest; { register char *p; int depth = 0; p = source + 2; /* skip over reply indicator */ while (*p) { switch (*p) { case '"': /* in quoted part ? */ depth = !depth; break; case ' ': case '\t': if (depth == 0) { *dest = '\0'; return; } break; case '\\': /* gobble up next char */ *dest++ = *p++; break; } *dest++ = *p++; } *dest = '\0'; } /*VARARGS2*/ report (mode, rc, fmt, a1, a2, a3, a4) int mode; int rc; char *fmt, *a1, *a2, *a3, *a4; { static FILE *log; if (debug == FALSE && mode == TRACE) return; if (debug == TRUE) { fprintf (stderr, "%s\t", mode == TRACE ? "TRACE" : (mode == FATAL ? "FATAL" : "!FATAL")); fprintf (stderr, fmt, a1, a2, a3, a4); putc ('\n', stderr); fflush (stderr); } if (mode == FATAL) exit (exit_rc(rc)); /* die a horrible death */ } static int exit_rc(num) int num; { switch (exit_alg) { case 0: return RP_MECH; case 1: return 0; case 2: return num; default:return 0; } }