1 # include <errno.h> 2 # include "sendmail.h" 3 4 static char SccsId[] = "@(#)collect.c 3.25 10/20/81"; 5 6 /* 7 ** COLLECT -- read & parse message header & make temp file. 8 ** 9 ** Creates a temporary file name and copies the standard 10 ** input to that file. While it is doing it, it looks for 11 ** "From:" and "Sender:" fields to use as the from-person 12 ** (but only if the -a flag is specified). It prefers to 13 ** to use the "Sender:" field. 14 ** 15 ** MIT seems to like to produce "Sent-By:" fields instead 16 ** of "Sender:" fields. We used to catch this, but it turns 17 ** out that the "Sent-By:" field doesn't always correspond 18 ** to someone real ("___057", for instance), as required by 19 ** the protocol. So we limp by..... 20 ** 21 ** Parameters: 22 ** none 23 ** 24 ** Returns: 25 ** none. 26 ** 27 ** Side Effects: 28 ** Temp file is created and filled. 29 ** The from person may be set. 30 */ 31 32 long MsgSize; /* size of message in bytes */ 33 FILE *TempFile; /* the tempfile (after creation) */ 34 35 collect() 36 { 37 register FILE *tf; 38 char buf[MAXFIELD+1]; 39 register char *p; 40 char *xfrom; 41 extern char *hvalue(); 42 extern char *mktemp(); 43 44 /* 45 ** Create the temp file name and create the file. 46 */ 47 48 (void) mktemp(InFileName); 49 (void) close(creat(InFileName, 0600)); 50 if ((tf = fopen(InFileName, "w")) == NULL) 51 { 52 syserr("Cannot create %s", InFileName); 53 return; 54 } 55 56 /* 57 ** Tell ARPANET to go ahead. 58 */ 59 60 if (ArpaMode == ARPA_MAIL) 61 { 62 extern char Arpa_Enter[]; 63 64 message(Arpa_Enter, "Enter mail, end with \".\" on a line by itself"); 65 } 66 67 /* 68 ** Try to read a UNIX-style From line 69 */ 70 71 if (fgets(buf, sizeof buf, stdin) == NULL) 72 return; 73 fixcrlf(buf, FALSE); 74 # ifndef NOTUNIX 75 if (!SaveFrom && strncmp(buf, "From ", 5) == 0) 76 { 77 eatfrom(buf); 78 (void) fgets(buf, sizeof buf, stdin); 79 fixcrlf(buf, FALSE); 80 } 81 # endif NOTUNIX 82 83 /* 84 ** Copy stdin to temp file & do message editting. 85 ** To keep certain mailers from getting confused, 86 ** and to keep the output clean, lines that look 87 ** like UNIX "From" lines are deleted in the header, 88 ** and prepended with ">" in the body. 89 */ 90 91 for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin)) 92 { 93 register char c; 94 extern bool isheader(); 95 96 fixcrlf(buf, FALSE); 97 98 /* see if the header is over */ 99 if (!isheader(buf)) 100 break; 101 102 /* get the rest of this field */ 103 while ((c = getc(stdin)) == ' ' || c == '\t') 104 { 105 p = &buf[strlen(buf)]; 106 *p++ = c; 107 if (fgets(p, sizeof buf - (p - buf), stdin) == NULL) 108 break; 109 fixcrlf(p, FALSE); 110 } 111 if (!feof(stdin)) 112 (void) ungetc(c, stdin); 113 114 MsgSize += strlen(buf); 115 116 /* 117 ** Snarf header away. 118 */ 119 120 if (bitset(H_EOH, chompheader(buf, FALSE))) 121 break; 122 } 123 124 # ifdef DEBUG 125 if (Debug) 126 printf("EOH\n"); 127 # endif DEBUG 128 129 /* throw away a blank line */ 130 if (buf[0] == '\n') 131 { 132 (void) fgets(buf, sizeof buf, stdin); 133 fixcrlf(buf, FALSE); 134 } 135 136 /* 137 ** Collect the body of the message. 138 */ 139 140 for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin) != NULL) 141 { 142 register int i; 143 register char *bp = buf; 144 145 fixcrlf(buf, FALSE); 146 147 /* check for end-of-message */ 148 if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0')) 149 break; 150 151 /* check for transparent dot */ 152 if (Smtp && *bp == '.') 153 bp++; 154 155 # ifndef NOTUNIX 156 /* Hide UNIX-like From lines */ 157 if (strncmp(bp, "From ", 5) == 0) 158 { 159 fputs(">", tf); 160 MsgSize++; 161 } 162 # endif NOTUNIX 163 164 /* 165 ** Figure message length, output the line to the temp 166 ** file, and insert a newline if missing. 167 */ 168 169 i = strlen(bp); 170 MsgSize += i; 171 fputs(bp, tf); 172 if (bp[i - 1] != '\n') 173 fputs("\n", tf); 174 if (ferror(tf)) 175 { 176 if (errno == ENOSPC) 177 { 178 (void) freopen(InFileName, "w", tf); 179 fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf); 180 usrerr("452 Out of disk space for temp file"); 181 } 182 else 183 syserr("collect: Cannot write %s", InFileName); 184 (void) freopen("/dev/null", "w", tf); 185 } 186 } 187 (void) fclose(tf); 188 189 /* 190 ** Find out some information from the headers. 191 ** Examples are who is the from person & the date. 192 */ 193 194 /* from person */ 195 xfrom = hvalue("sender"); 196 if (xfrom == NULL) 197 xfrom = OrigFrom; 198 if (ArpaMode != ARPA_NONE) 199 setfrom(xfrom, (char *) NULL); 200 201 /* full name of from person */ 202 p = hvalue("full-name"); 203 if (p != NULL) 204 define('x', p); 205 else 206 { 207 register char *q; 208 209 /* 210 ** Try to extract the full name from a general From: 211 ** field. We take anything which is a comment as a 212 ** first choice. Failing in that, we see if there is 213 ** a "machine readable" name (in <angle brackets>); if 214 ** so we take anything preceeding that clause. 215 ** 216 ** If we blow it here it's not all that serious. 217 */ 218 219 p = hvalue("original-from"); 220 if (p == NULL) 221 p = OrigFrom; 222 q = index(p, '('); 223 if (q != NULL) 224 { 225 int parenlev = 0; 226 227 for (p = q; *p != '\0'; p++) 228 { 229 if (*p == '(') 230 parenlev++; 231 else if (*p == ')' && --parenlev <= 0) 232 break; 233 } 234 if (*p == ')') 235 { 236 *p = '\0'; 237 if (*++q != '\0') 238 define('x', newstr(q)); 239 *p = ')'; 240 } 241 } 242 else if ((q = index(p, '<')) != NULL) 243 { 244 char savec; 245 246 while (*--q == ' ') 247 continue; 248 while (isspace(*p)) 249 p++; 250 savec = *++q; 251 *q = '\0'; 252 if (*p != '\0') 253 define('x', newstr(p)); 254 *q = savec; 255 } 256 } 257 258 /* date message originated */ 259 p = hvalue("posted-date"); 260 if (p == NULL) 261 p = hvalue("date"); 262 if (p != NULL) 263 { 264 define('a', p); 265 /* we don't have a good way to do canonical conversion .... 266 define('d', newstr(arpatounix(p))); 267 .... so we will ignore the problem for the time being */ 268 } 269 270 if ((TempFile = fopen(InFileName, "r")) == NULL) 271 syserr("Cannot reopen %s", InFileName); 272 273 # ifdef DEBUG 274 if (Debug) 275 { 276 HDR *h; 277 extern char *capitalize(); 278 279 printf("----- collected header -----\n"); 280 for (h = Header; h != NULL; h = h->h_link) 281 printf("%s: %s\n", capitalize(h->h_field), h->h_value); 282 printf("----------------------------\n"); 283 } 284 # endif DEBUG 285 return; 286 } 287 /* 288 ** EATFROM -- chew up a UNIX style from line and process 289 ** 290 ** This does indeed make some assumptions about the format 291 ** of UNIX messages. 292 ** 293 ** Parameters: 294 ** fm -- the from line. 295 ** 296 ** Returns: 297 ** none. 298 ** 299 ** Side Effects: 300 ** extracts what information it can from the header, 301 ** such as the date. 302 */ 303 304 # ifndef NOTUNIX 305 306 char *DowList[] = 307 { 308 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 309 }; 310 311 char *MonthList[] = 312 { 313 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 314 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 315 NULL 316 }; 317 318 eatfrom(fm) 319 char *fm; 320 { 321 register char *p; 322 register char **dt; 323 324 # ifdef DEBUG 325 if (Debug > 1) 326 printf("eatfrom(%s)\n", fm); 327 # endif DEBUG 328 329 /* find the date part */ 330 p = fm; 331 while (*p != '\0') 332 { 333 /* skip a word */ 334 while (*p != '\0' && *p != ' ') 335 *p++; 336 while (*p == ' ') 337 *p++; 338 if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':') 339 continue; 340 341 /* we have a possible date */ 342 for (dt = DowList; *dt != NULL; dt++) 343 if (strncmp(*dt, p, 3) == 0) 344 break; 345 if (*dt == NULL) 346 continue; 347 348 for (dt = MonthList; *dt != NULL; dt++) 349 if (strncmp(*dt, &p[4], 3) == 0) 350 break; 351 if (*dt != NULL) 352 break; 353 } 354 355 if (*p != NULL) 356 { 357 char *q; 358 359 /* we have found a date */ 360 q = xalloc(25); 361 strncpy(q, p, 25); 362 q[24] = '\0'; 363 define('d', q); 364 } 365 } 366 367 # endif NOTUNIX 368