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