📄 headers.c
字号:
/* * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. 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'' without express or implied warranty. * * Sendmail * Copyright (c) 1983 Eric P. Allman * Berkeley, California */# include <errno.h># include "sendmail.h"SCCSID(@(#)headers.c 1.1 92/07/30); /* from UCB 5.9 9/21/88 *//*** CHOMPHEADER -- process and save a header line.**** Called by collect and by readcf to deal with header lines.**** Parameters:** line -- header as a text line.** def -- if set, this is a default value.**** Returns:** flags for this header.**** Side Effects:** The header is saved on the header list.** Contents of 'line' are destroyed.*/chompheader(line, def) char *line; bool def;{ register char *p; register HDR *h; HDR **hp; char *fname; char *fvalue; struct hdrinfo *hi; bool cond = FALSE; BITMAP mopts; extern char *crackaddr();# ifdef DEBUG if (tTd(31, 6)) printf("chompheader: %s\n", line);# endif DEBUG /* strip off options */ clrbitmap(mopts); p = line; if (*p == '?') { /* have some */ register char *q = index(p + 1, *p); if (q != NULL) { *q++ = '\0'; while (*++p != '\0') setbitn(*p, mopts); p = q; } else syserr("chompheader: syntax error, line \"%s\"", line); cond = TRUE; } /* find canonical name */ fname = p; p = index(p, ':'); if (p == NULL) { syserr("chompheader: syntax error, line \"%s\"", line); return (0); } fvalue = &p[1]; while (isspace(*--p)) continue; *++p = '\0'; makelower(fname); /* strip field value on front */ if (*fvalue == ' ') fvalue++; /* see if it is a known type */ for (hi = HdrInfo; hi->hi_field != NULL; hi++) { if (strcmp(hi->hi_field, fname) == 0) break; } /* see if this is a resent message */ if (!def && bitset(H_RESENT, hi->hi_flags)) CurEnv->e_flags |= EF_RESENT; /* if this means "end of header" quit now */ if (bitset(H_EOH, hi->hi_flags)) return (hi->hi_flags); /* drop explicit From: if same as what we would generate -- for MH */ p = "resent-from"; if (!bitset(EF_RESENT, CurEnv->e_flags)) p += 7; if (!def && !QueueRun && strcmp(fname, p) == 0) { if (CurEnv->e_from.q_paddr != NULL && strcmp(fvalue, CurEnv->e_from.q_paddr) == 0) return (hi->hi_flags); } /* delete default value for this header */ for (hp = &CurEnv->e_header; (h = *hp) != NULL; hp = &h->h_link) { if (strcmp(fname, h->h_field) == 0 && bitset(H_DEFAULT, h->h_flags) && !bitset(H_FORCE, h->h_flags)) h->h_value = NULL; } /* create a new node */ h = (HDR *) xalloc(sizeof *h); h->h_field = newstr(fname); h->h_value = NULL; h->h_link = NULL; bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts); *hp = h; h->h_flags = hi->hi_flags; if (def) h->h_flags |= H_DEFAULT; if (cond) h->h_flags |= H_CHECK; if (h->h_value != NULL) free((char *) h->h_value); h->h_value = newstr(fvalue); /* hack to see if this is a new format message */ if (!def && bitset(H_RCPT|H_FROM, h->h_flags) && (index(fvalue, ',') != NULL || index(fvalue, '(') != NULL || index(fvalue, '<') != NULL || index(fvalue, ';') != NULL)) { CurEnv->e_flags &= ~EF_OLDSTYLE; } return (h->h_flags);}/*** ADDHEADER -- add a header entry to the end of the queue.**** This bypasses the special checking of chompheader.**** Parameters:** field -- the name of the header field.** value -- the value of the field. It must be lower-cased.** e -- the envelope to add them to.**** Returns:** none.**** Side Effects:** adds the field on the list of headers for this envelope.*/addheader(field, value, e) char *field; char *value; ENVELOPE *e;{ register HDR *h; register struct hdrinfo *hi; HDR **hp; /* find info struct */ for (hi = HdrInfo; hi->hi_field != NULL; hi++) { if (strcmp(field, hi->hi_field) == 0) break; } /* find current place in list -- keep back pointer? */ for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) { if (strcmp(field, h->h_field) == 0) break; } /* allocate space for new header */ h = (HDR *) xalloc(sizeof *h); h->h_field = field; h->h_value = newstr(value); h->h_link = *hp; h->h_flags = hi->hi_flags | H_DEFAULT; clrbitmap(h->h_mflags); *hp = h;}/*** HVALUE -- return value of a header.**** Only "real" fields (i.e., ones that have not been supplied** as a default) are used.**** Parameters:** field -- the field name.**** Returns:** pointer to the value part.** NULL if not found.**** Side Effects:** none.*/char *hvalue(field) char *field;{ register HDR *h; for (h = CurEnv->e_header; h != NULL; h = h->h_link) { if (!bitset(H_DEFAULT, h->h_flags) && strcmp(h->h_field, field) == 0) return (h->h_value); } return (NULL);}/*** ISHEADER -- predicate telling if argument is a header.**** A line is a header if it has a single word followed by** optional white space followed by a colon.**** Parameters:** s -- string to check for possible headerness.**** Returns:** TRUE if s is a header.** FALSE otherwise.**** Side Effects:** none.*/boolisheader(s) register char *s;{ while (*s > ' ' && *s != ':' && *s != '\0') s++; /* following technically violates RFC822 */ while (isspace(*s)) s++; return (*s == ':');}/*** EATHEADER -- run through the stored header and extract info.**** Parameters:** e -- the envelope to process.**** Returns:** none.**** Side Effects:** Sets a bunch of global variables from information** in the collected header.** Aborts the message if the hop count is exceeded.*/eatheader(e) register ENVELOPE *e;{ register HDR *h; register char *p; int hopcnt = 0;#ifdef DEBUG if (tTd(32, 1)) printf("----- collected header -----\n");#endif DEBUG for (h = e->e_header; h != NULL; h = h->h_link) {#ifdef DEBUG extern char *capitalize(); if (tTd(32, 1)) printf("%s: %s\n", capitalize(h->h_field), h->h_value);#endif DEBUG /* count the number of times it has been processed */ if (bitset(H_TRACE, h->h_flags)) hopcnt++; /* send to this person if we so desire */ if (GrabTo && bitset(H_RCPT, h->h_flags) && !bitset(H_DEFAULT, h->h_flags) && (!bitset(EF_RESENT, CurEnv->e_flags) || bitset(H_RESENT, h->h_flags))) { sendtolist(h->h_value, (ADDRESS *) NULL, &CurEnv->e_sendqueue); } /* log the message-id */#ifdef LOG if (!QueueRun && LogLevel > 8 && h->h_value != NULL && strcmp(h->h_field, "message-id") == 0) { char buf[MAXNAME]; p = h->h_value; if (bitset(H_DEFAULT, h->h_flags)) { expand(p, buf, &buf[sizeof buf], e); p = buf; } syslog(LOG_INFO, "%s: message-id=%s", e->e_id, p); }#endif LOG }#ifdef DEBUG if (tTd(32, 1)) printf("----------------------------\n");#endif DEBUG /* store hop count */ if (hopcnt > e->e_hopcount) e->e_hopcount = hopcnt; /* message priority */ p = hvalue("precedence"); if (p != NULL) e->e_class = priencode(p); if (!QueueRun) e->e_msgpriority = e->e_msgsize - e->e_class * WkClassFact + e->e_nrcpts * WkRecipFact; /* return receipt to */ p = hvalue("return-receipt-to"); if (p != NULL) e->e_receiptto = p; /* errors to */ p = hvalue("errors-to"); if (p != NULL) sendtolist(p, (ADDRESS *) NULL, &e->e_errorqueue); /* from person */ if (OpMode == MD_ARPAFTP) { register struct hdrinfo *hi = HdrInfo; for (p = NULL; p == NULL && hi->hi_field != NULL; hi++) { if (bitset(H_FROM, hi->hi_flags)) p = hvalue(hi->hi_field); } if (p != NULL) setsender(p); } /* full name of from person */ p = hvalue("full-name"); if (p != NULL) define('x', p, e); /* date message originated */ p = hvalue("posted-date"); if (p == NULL) p = hvalue("date"); if (p != NULL) { define('a', p, e); /* we don't have a good way to do canonical conversion .... define('d', newstr(arpatounix(p)), e); .... so we will ignore the problem for the time being */ } /* ** Log collection information. */# ifdef LOG if (!QueueRun && LogLevel > 1) { syslog(LOG_INFO, "%s: from=%s, size=%ld, class=%d\n", CurEnv->e_id, CurEnv->e_from.q_paddr, CurEnv->e_msgsize, CurEnv->e_class); }# endif LOG}/*** PRIENCODE -- encode external priority names into internal values.**** Parameters:** p -- priority in ascii.**** Returns:** priority as a numeric level.**** Side Effects:** none.*/priencode(p) char *p;{ register int i; for (i = 0; i < NumPriorities; i++) { if (!strcasecmp(p, Priorities[i].pri_name)) return (Priorities[i].pri_val); } /* unknown priority */ return (0);}/*** CRACKADDR -- parse an address and turn it into a macro**** This doesn't actually parse the address -- it just extracts** it and replaces it with "$g". The parse is totally ad hoc** and isn't even guaranteed to leave something syntactically** identical to what it started with. However, it does leave** something semantically identical.**** The process is kind of strange. There are a number of** interesting cases:** 1. comment <address> comment ==> comment <$g> comment** 2. address ==> address** 3. address (comment) ==> $g (comment)** 4. (comment) address ==> (comment) $g** And then there are the hard cases....** 5. add (comment) ress ==> $g (comment)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -