1 # include <stdio.h> 2 # include <ctype.h> 3 # include <errno.h> 4 # include "sendmail.h" 5 6 static char SccsId[] = "@(#)collect.c 3.10 03/28/81"; 7 8 /* 9 ** COLLECT -- read & parse message header & make temp file. 10 ** 11 ** Creates a temporary file name and copies the standard 12 ** input to that file. While it is doing it, it looks for 13 ** "From:" and "Sender:" fields to use as the from-person 14 ** (but only if the -a flag is specified). It prefers to 15 ** to use the "Sender:" field. 16 ** 17 ** MIT seems to like to produce "Sent-By:" fields instead 18 ** of "Sender:" fields. We used to catch this, but it turns 19 ** out that the "Sent-By:" field doesn't always correspond 20 ** to someone real ("___057", for instance), as required by 21 ** the protocol. So we limp by..... 22 ** 23 ** Parameters: 24 ** none 25 ** 26 ** Returns: 27 ** Name of temp file. 28 ** 29 ** Side Effects: 30 ** Temp file is created and filled. 31 ** 32 ** Called By: 33 ** main 34 ** 35 ** Notes: 36 ** This is broken off from main largely so that the 37 ** temp buffer can be deallocated. 38 */ 39 40 long MsgSize; /* size of message in bytes */ 41 42 char * 43 collect() 44 { 45 register FILE *tf; 46 char buf[MAXFIELD+1]; 47 register char *p; 48 char c; 49 extern int errno; 50 extern bool isheader(); 51 extern char *newstr(); 52 extern char *xalloc(); 53 extern char *index(), *rindex(); 54 char *xfrom; 55 extern char *hvalue(); 56 extern char *strcpy(), *strcat(), *mktemp(); 57 HDR *h; 58 59 /* 60 ** Create the temp file name and create the file. 61 */ 62 63 mktemp(InFileName); 64 close(creat(InFileName, 0600)); 65 if ((tf = fopen(InFileName, "w")) == NULL) 66 { 67 syserr("Cannot create %s", InFileName); 68 return (NULL); 69 } 70 71 /* try to read a UNIX-style From line */ 72 if (fgets(buf, sizeof buf, stdin) == NULL) 73 return (NULL); 74 if (strncmp(buf, "From ", 5) == 0) 75 { 76 eatfrom(buf); 77 fgets(buf, sizeof buf, stdin); 78 } 79 80 /* 81 ** Copy stdin to temp file & do message editting. 82 ** To keep certain mailers from getting confused, 83 ** and to keep the output clean, lines that look 84 ** like UNIX "From" lines are deleted in the header, 85 ** and prepended with ">" in the body. 86 */ 87 88 for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin)) 89 { 90 /* see if the header is over */ 91 if (!isheader(buf)) 92 break; 93 94 /* get the rest of this field */ 95 while ((c = getc(stdin)) == ' ' || c == '\t') 96 { 97 p = &buf[strlen(buf)]; 98 *p++ = c; 99 if (fgets(p, sizeof buf - (p - buf), stdin) == NULL) 100 break; 101 } 102 if (c != EOF) 103 ungetc(c, stdin); 104 105 MsgSize += strlen(buf); 106 107 /* 108 ** Snarf header away. 109 */ 110 111 if (bitset(H_EOH, chompheader(buf, FALSE))) 112 break; 113 } 114 115 # ifdef DEBUG 116 if (Debug) 117 printf("EOH\n"); 118 # endif DEBUG 119 120 /* throw away a blank line */ 121 if (buf[0] == '\n') 122 fgets(buf, sizeof buf, stdin); 123 124 /* 125 ** Collect the body of the message. 126 */ 127 128 for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin) != NULL) 129 { 130 /* check for end-of-message */ 131 if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0')) 132 break; 133 134 /* Hide UNIX-like From lines */ 135 if (strncmp(buf, "From ", 5) == 0) 136 { 137 fputs(">", tf); 138 MsgSize++; 139 } 140 MsgSize += strlen(buf); 141 fputs(buf, tf); 142 if (ferror(tf)) 143 { 144 if (errno == ENOSPC) 145 { 146 freopen(InFileName, "w", tf); 147 fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf); 148 syserr("Out of disk space for temp file"); 149 } 150 else 151 syserr("Cannot write %s", InFileName); 152 freopen("/dev/null", "w", tf); 153 } 154 } 155 fclose(tf); 156 157 /* 158 ** Find out some information from the headers. 159 ** Examples are who is the from person & the date. 160 */ 161 162 /* from person */ 163 xfrom = hvalue("sender"); 164 if (xfrom == NULL) 165 xfrom = hvalue("from"); 166 167 /* full name of from person */ 168 p = hvalue("full-name"); 169 if (p != NULL) 170 define('x', p); 171 172 /* date message originated */ 173 p = hvalue("date"); 174 if (p != NULL) 175 { 176 define('a', p); 177 /* we don't have a good way to do canonical conversion .... 178 define('d', newstr(arpatounix(p))); 179 .... so we will ignore the problem for the time being */ 180 } 181 182 if (freopen(InFileName, "r", stdin) == NULL) 183 syserr("Cannot reopen %s", InFileName); 184 185 # ifdef DEBUG 186 if (Debug) 187 { 188 printf("----- collected header -----\n"); 189 for (h = Header; h != NULL; h = h->h_link) 190 printf("%s: %s\n", capitalize(h->h_field), h->h_value); 191 printf("----------------------------\n"); 192 } 193 # endif DEBUG 194 return (ArpaFmt ? xfrom : NULL); 195 } 196 /* 197 ** EATFROM -- chew up a UNIX style from line and process 198 ** 199 ** This does indeed make some assumptions about the format 200 ** of UNIX messages. 201 ** 202 ** Parameters: 203 ** fm -- the from line. 204 ** 205 ** Returns: 206 ** none. 207 ** 208 ** Side Effects: 209 ** extracts what information it can from the header, 210 ** such as the date. 211 */ 212 213 char *MonthList[] = 214 { 215 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 216 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 217 NULL 218 }; 219 220 eatfrom(fm) 221 char *fm; 222 { 223 register char *p; 224 register char **dt; 225 226 /* find the date part */ 227 p = fm; 228 while (*p != '\0') 229 { 230 /* skip a word */ 231 while (*p != '\0' && *p != ' ') 232 *p++; 233 while (*p == ' ') 234 *p++; 235 if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':') 236 continue; 237 238 /* we have a possible date */ 239 for (dt = MonthList; *dt != NULL; dt++) 240 if (strncmp(*dt, p, 3) == 0) 241 break; 242 243 if (*dt != NULL) 244 break; 245 } 246 247 if (*p != NULL) 248 { 249 char *q; 250 251 /* we have found a date */ 252 q = xalloc(25); 253 strncpy(q, p, 25); 254 q[24] = '\0'; 255 define('d', q); 256 } 257 } 258 /* 259 ** HVALUE -- return value of a header. 260 ** 261 ** Only "real" fields (i.e., ones that have not been supplied 262 ** as a default) are used. 263 ** 264 ** Parameters: 265 ** field -- the field name. 266 ** 267 ** Returns: 268 ** pointer to the value part. 269 ** NULL if not found. 270 ** 271 ** Side Effects: 272 ** sets the H_USED bit in the header if found. 273 */ 274 275 char * 276 hvalue(field) 277 char *field; 278 { 279 register HDR *h; 280 281 for (h = Header; h != NULL; h = h->h_link) 282 { 283 if (!bitset(H_DEFAULT, h->h_flags) && strcmp(h->h_field, field) == 0) 284 { 285 h->h_flags |= H_USED; 286 return (h->h_value); 287 } 288 } 289 return (NULL); 290 } 291 /* 292 ** ISHEADER -- predicate telling if argument is a header. 293 ** 294 ** Parameters: 295 ** s -- string to check for possible headerness. 296 ** 297 ** Returns: 298 ** TRUE if s is a header. 299 ** FALSE otherwise. 300 ** 301 ** Side Effects: 302 ** none. 303 */ 304 305 bool 306 isheader(s) 307 register char *s; 308 { 309 if (!isalnum(*s)) 310 return (FALSE); 311 while (!isspace(*s) && *s != ':') 312 s++; 313 while (isspace(*s)) 314 s++; 315 return (*s == ':'); 316 } 317 /* 318 ** CHOMPHEADER -- process and save a header line. 319 ** 320 ** Called by collect and by readcf to deal with header lines. 321 ** 322 ** Parameters: 323 ** line -- header as a text line. 324 ** def -- if set, this is a default value. 325 ** 326 ** Returns: 327 ** flags for this header. 328 ** 329 ** Side Effects: 330 ** The header is saved on the header list. 331 */ 332 333 chompheader(line, def) 334 char *line; 335 bool def; 336 { 337 register char *p; 338 extern int errno; 339 register HDR *h; 340 HDR **hp; 341 extern bool isheader(); 342 extern char *newstr(); 343 extern char *xalloc(); 344 char *fname; 345 char *fvalue; 346 extern char *index(), *rindex(); 347 struct hdrinfo *hi; 348 extern char *strcpy(), *strcat(), *mktemp(); 349 350 /* strip off trailing newline */ 351 p = rindex(line, '\n'); 352 if (p != NULL) 353 *p = '\0'; 354 355 /* find canonical name */ 356 fname = line; 357 p = index(line, ':'); 358 fvalue = &p[1]; 359 while (isspace(*--p)) 360 continue; 361 *++p = '\0'; 362 makelower(fname); 363 364 /* strip field value on front */ 365 if (*fvalue == ' ') 366 fvalue++; 367 368 /* search header list for this header */ 369 for (hp = &Header, h = Header; h != NULL; hp = &h->h_link, h = h->h_link) 370 { 371 if (strcmp(fname, h->h_field) == 0 && bitset(H_DEFAULT, h->h_flags)) 372 break; 373 } 374 375 /* see if it is a known type */ 376 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 377 { 378 if (strcmp(hi->hi_field, fname) == 0) 379 break; 380 } 381 382 /* if this means "end of header" quit now */ 383 if (bitset(H_EOH, hi->hi_flags)) 384 return (hi->hi_flags); 385 386 /* create/fill in a new node */ 387 if (h == NULL) 388 { 389 /* create a new node */ 390 *hp = h = (HDR *) xalloc(sizeof *h); 391 h->h_field = newstr(fname); 392 h->h_value = NULL; 393 h->h_link = NULL; 394 h->h_flags = hi->hi_flags; 395 h->h_mflags = hi->hi_mflags; 396 } 397 if (def) 398 h->h_flags |= H_DEFAULT; 399 else 400 h->h_flags &= ~H_CHECK; 401 if (h->h_value != NULL) 402 free(h->h_value); 403 h->h_value = newstr(fvalue); 404 405 return (h->h_flags); 406 } 407