1 # include <errno.h> 2 # include "sendmail.h" 3 4 static char SccsId[] = "@(#)collect.c 3.24 10/19/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 # ifndef NOTUNIX 74 if (!SaveFrom && strncmp(buf, "From ", 5) == 0) 75 { 76 eatfrom(buf); 77 (void) fgets(buf, sizeof buf, stdin); 78 } 79 # endif NOTUNIX 80 81 /* 82 ** Copy stdin to temp file & do message editting. 83 ** To keep certain mailers from getting confused, 84 ** and to keep the output clean, lines that look 85 ** like UNIX "From" lines are deleted in the header, 86 ** and prepended with ">" in the body. 87 */ 88 89 for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin)) 90 { 91 register char c; 92 extern bool isheader(); 93 94 /* see if the header is over */ 95 if (!isheader(buf)) 96 break; 97 98 /* get the rest of this field */ 99 while ((c = getc(stdin)) == ' ' || c == '\t') 100 { 101 p = &buf[strlen(buf)]; 102 *p++ = c; 103 if (fgets(p, sizeof buf - (p - buf), stdin) == NULL) 104 break; 105 } 106 if (!feof(stdin)) 107 (void) ungetc(c, stdin); 108 109 MsgSize += strlen(buf); 110 111 /* 112 ** Snarf header away. 113 */ 114 115 if (bitset(H_EOH, chompheader(buf, FALSE))) 116 break; 117 } 118 119 # ifdef DEBUG 120 if (Debug) 121 printf("EOH\n"); 122 # endif DEBUG 123 124 /* throw away a blank line */ 125 if (buf[0] == '\n') 126 (void) fgets(buf, sizeof buf, stdin); 127 128 /* 129 ** Collect the body of the message. 130 */ 131 132 for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin) != NULL) 133 { 134 register int i; 135 register char *bp = buf; 136 137 /* check for end-of-message */ 138 if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0')) 139 break; 140 141 /* check for transparent dot */ 142 if (Smtp && *bp == '.') 143 bp++; 144 145 # ifndef NOTUNIX 146 /* Hide UNIX-like From lines */ 147 if (strncmp(bp, "From ", 5) == 0) 148 { 149 fputs(">", tf); 150 MsgSize++; 151 } 152 # endif NOTUNIX 153 154 /* 155 ** Figure message length, output the line to the temp 156 ** file, and insert a newline if missing. 157 */ 158 159 i = strlen(bp); 160 MsgSize += i; 161 fputs(bp, tf); 162 if (bp[i - 1] != '\n') 163 fputs("\n", tf); 164 if (ferror(tf)) 165 { 166 if (errno == ENOSPC) 167 { 168 (void) freopen(InFileName, "w", tf); 169 fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf); 170 syserr("collect: Out of disk space for temp file"); 171 } 172 else 173 syserr("collect: Cannot write %s", InFileName); 174 (void) freopen("/dev/null", "w", tf); 175 } 176 } 177 (void) fclose(tf); 178 179 /* 180 ** Find out some information from the headers. 181 ** Examples are who is the from person & the date. 182 */ 183 184 /* from person */ 185 xfrom = hvalue("sender"); 186 if (xfrom == NULL) 187 xfrom = OrigFrom; 188 if (ArpaMode != ARPA_NONE) 189 setfrom(xfrom, (char *) NULL); 190 191 /* full name of from person */ 192 p = hvalue("full-name"); 193 if (p != NULL) 194 define('x', p); 195 else 196 { 197 register char *q; 198 199 /* 200 ** Try to extract the full name from a general From: 201 ** field. We take anything which is a comment as a 202 ** first choice. Failing in that, we see if there is 203 ** a "machine readable" name (in <angle brackets>); if 204 ** so we take anything preceeding that clause. 205 ** 206 ** If we blow it here it's not all that serious. 207 */ 208 209 p = hvalue("original-from"); 210 if (p == NULL) 211 p = OrigFrom; 212 q = index(p, '('); 213 if (q != NULL) 214 { 215 int parenlev = 0; 216 217 for (p = q; *p != '\0'; p++) 218 { 219 if (*p == '(') 220 parenlev++; 221 else if (*p == ')' && --parenlev <= 0) 222 break; 223 } 224 if (*p == ')') 225 { 226 *p = '\0'; 227 if (*++q != '\0') 228 define('x', newstr(q)); 229 *p = ')'; 230 } 231 } 232 else if ((q = index(p, '<')) != NULL) 233 { 234 char savec; 235 236 while (*--q == ' ') 237 continue; 238 while (isspace(*p)) 239 p++; 240 savec = *++q; 241 *q = '\0'; 242 if (*p != '\0') 243 define('x', newstr(p)); 244 *q = savec; 245 } 246 } 247 248 /* date message originated */ 249 p = hvalue("posted-date"); 250 if (p == NULL) 251 p = hvalue("date"); 252 if (p != NULL) 253 { 254 define('a', p); 255 /* we don't have a good way to do canonical conversion .... 256 define('d', newstr(arpatounix(p))); 257 .... so we will ignore the problem for the time being */ 258 } 259 260 if ((TempFile = fopen(InFileName, "r")) == NULL) 261 syserr("Cannot reopen %s", InFileName); 262 263 # ifdef DEBUG 264 if (Debug) 265 { 266 HDR *h; 267 extern char *capitalize(); 268 269 printf("----- collected header -----\n"); 270 for (h = Header; h != NULL; h = h->h_link) 271 printf("%s: %s\n", capitalize(h->h_field), h->h_value); 272 printf("----------------------------\n"); 273 } 274 # endif DEBUG 275 return; 276 } 277 /* 278 ** EATFROM -- chew up a UNIX style from line and process 279 ** 280 ** This does indeed make some assumptions about the format 281 ** of UNIX messages. 282 ** 283 ** Parameters: 284 ** fm -- the from line. 285 ** 286 ** Returns: 287 ** none. 288 ** 289 ** Side Effects: 290 ** extracts what information it can from the header, 291 ** such as the date. 292 */ 293 294 # ifndef NOTUNIX 295 296 char *DowList[] = 297 { 298 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 299 }; 300 301 char *MonthList[] = 302 { 303 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 304 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 305 NULL 306 }; 307 308 eatfrom(fm) 309 char *fm; 310 { 311 register char *p; 312 register char **dt; 313 314 # ifdef DEBUG 315 if (Debug > 1) 316 printf("eatfrom(%s)\n", fm); 317 # endif DEBUG 318 319 /* find the date part */ 320 p = fm; 321 while (*p != '\0') 322 { 323 /* skip a word */ 324 while (*p != '\0' && *p != ' ') 325 *p++; 326 while (*p == ' ') 327 *p++; 328 if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':') 329 continue; 330 331 /* we have a possible date */ 332 for (dt = DowList; *dt != NULL; dt++) 333 if (strncmp(*dt, p, 3) == 0) 334 break; 335 if (*dt == NULL) 336 continue; 337 338 for (dt = MonthList; *dt != NULL; dt++) 339 if (strncmp(*dt, &p[4], 3) == 0) 340 break; 341 if (*dt != NULL) 342 break; 343 } 344 345 if (*p != NULL) 346 { 347 char *q; 348 349 /* we have found a date */ 350 q = xalloc(25); 351 strncpy(q, p, 25); 352 q[24] = '\0'; 353 define('d', q); 354 } 355 } 356 357 # endif NOTUNIX 358