1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that this notice is preserved and that due credit is given 7 * to the University of California at Berkeley. The name of the University 8 * may not be used to endorse or promote products derived from this 9 * software without specific prior written permission. This software 10 * is provided ``as is'' without express or implied warranty. 11 * 12 * Sendmail 13 * Copyright (c) 1983 Eric P. Allman 14 * Berkeley, California 15 */ 16 17 #ifndef lint 18 static char sccsid[] = "@(#)collect.c 5.3 (Berkeley) 03/13/88"; 19 #endif /* not lint */ 20 21 # include <errno.h> 22 # include "sendmail.h" 23 24 /* 25 ** COLLECT -- read & parse message header & make temp file. 26 ** 27 ** Creates a temporary file name and copies the standard 28 ** input to that file. Leading UNIX-style "From" lines are 29 ** stripped off (after important information is extracted). 30 ** 31 ** Parameters: 32 ** sayok -- if set, give an ARPANET style message 33 ** to say we are ready to collect input. 34 ** 35 ** Returns: 36 ** none. 37 ** 38 ** Side Effects: 39 ** Temp file is created and filled. 40 ** The from person may be set. 41 */ 42 43 collect(sayok) 44 bool sayok; 45 { 46 register FILE *tf; 47 char buf[MAXFIELD+2]; 48 register char *p; 49 extern char *hvalue(); 50 51 /* 52 ** Create the temp file name and create the file. 53 */ 54 55 CurEnv->e_df = newstr(queuename(CurEnv, 'd')); 56 if ((tf = dfopen(CurEnv->e_df, "w")) == NULL) 57 { 58 syserr("Cannot create %s", CurEnv->e_df); 59 NoReturn = TRUE; 60 finis(); 61 } 62 (void) chmod(CurEnv->e_df, FileMode); 63 64 /* 65 ** Tell ARPANET to go ahead. 66 */ 67 68 if (sayok) 69 message("354", "Enter mail, end with \".\" on a line by itself"); 70 71 /* 72 ** Try to read a UNIX-style From line 73 */ 74 75 (void) sfgets(buf, sizeof buf, InChannel); 76 fixcrlf(buf, FALSE); 77 # ifndef NOTUNIX 78 if (!SaveFrom && strncmp(buf, "From ", 5) == 0) 79 { 80 eatfrom(buf); 81 (void) sfgets(buf, sizeof buf, InChannel); 82 fixcrlf(buf, FALSE); 83 } 84 # endif NOTUNIX 85 86 /* 87 ** Copy InChannel to temp file & do message editing. 88 ** To keep certain mailers from getting confused, 89 ** and to keep the output clean, lines that look 90 ** like UNIX "From" lines are deleted in the header. 91 */ 92 93 do 94 { 95 int c; 96 extern bool isheader(); 97 98 /* drop out on error */ 99 if (ferror(InChannel)) 100 break; 101 102 /* if the line is too long, throw the rest away */ 103 if (index(buf, '\n') == NULL) 104 { 105 while ((c = getc(InChannel)) != '\n' && c != EOF) 106 continue; 107 /* give an error? */ 108 } 109 110 fixcrlf(buf, TRUE); 111 112 /* see if the header is over */ 113 if (!isheader(buf)) 114 break; 115 116 /* get the rest of this field */ 117 while ((c = getc(InChannel)) == ' ' || c == '\t') 118 { 119 p = &buf[strlen(buf)]; 120 *p++ = '\n'; 121 *p++ = c; 122 if (sfgets(p, MAXFIELD - (p - buf), InChannel) == NULL) 123 break; 124 fixcrlf(p, TRUE); 125 } 126 if (!feof(InChannel) && !ferror(InChannel)) 127 (void) ungetc(c, InChannel); 128 129 CurEnv->e_msgsize += strlen(buf); 130 131 /* 132 ** Snarf header away. 133 */ 134 135 if (bitset(H_EOH, chompheader(buf, FALSE))) 136 break; 137 } while (sfgets(buf, MAXFIELD, InChannel) != NULL); 138 139 # ifdef DEBUG 140 if (tTd(30, 1)) 141 printf("EOH\n"); 142 # endif DEBUG 143 144 /* throw away a blank line */ 145 if (buf[0] == '\0') 146 (void) sfgets(buf, MAXFIELD, InChannel); 147 148 /* 149 ** Collect the body of the message. 150 */ 151 152 do 153 { 154 register char *bp = buf; 155 156 fixcrlf(buf, TRUE); 157 158 /* check for end-of-message */ 159 if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0')) 160 break; 161 162 /* check for transparent dot */ 163 if (OpMode == MD_SMTP && !IgnrDot && bp[0] == '.' && bp[1] == '.') 164 bp++; 165 166 /* 167 ** Figure message length, output the line to the temp 168 ** file, and insert a newline if missing. 169 */ 170 171 CurEnv->e_msgsize += strlen(bp) + 1; 172 fputs(bp, tf); 173 fputs("\n", tf); 174 if (ferror(tf)) 175 tferror(tf); 176 } while (sfgets(buf, MAXFIELD, InChannel) != NULL); 177 if (fflush(tf) != 0) 178 tferror(tf); 179 (void) fclose(tf); 180 181 /* An EOF when running SMTP is an error */ 182 if ((feof(InChannel) || ferror(InChannel)) && OpMode == MD_SMTP) 183 { 184 syserr("collect: unexpected close, from=%s", CurEnv->e_from.q_paddr); 185 186 /* don't return an error indication */ 187 CurEnv->e_to = NULL; 188 CurEnv->e_flags &= ~EF_FATALERRS; 189 190 /* and don't try to deliver the partial message either */ 191 finis(); 192 } 193 194 /* 195 ** Find out some information from the headers. 196 ** Examples are who is the from person & the date. 197 */ 198 199 eatheader(CurEnv); 200 201 /* 202 ** Add an Apparently-To: line if we have no recipient lines. 203 */ 204 205 if (hvalue("to") == NULL && hvalue("cc") == NULL && 206 hvalue("bcc") == NULL && hvalue("apparently-to") == NULL) 207 { 208 register ADDRESS *q; 209 210 /* create an Apparently-To: field */ 211 /* that or reject the message.... */ 212 for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next) 213 { 214 if (q->q_alias != NULL) 215 continue; 216 # ifdef DEBUG 217 if (tTd(30, 3)) 218 printf("Adding Apparently-To: %s\n", q->q_paddr); 219 # endif DEBUG 220 addheader("apparently-to", q->q_paddr, CurEnv); 221 } 222 } 223 224 if ((CurEnv->e_dfp = fopen(CurEnv->e_df, "r")) == NULL) 225 syserr("Cannot reopen %s", CurEnv->e_df); 226 } 227 /* 228 ** TFERROR -- signal error on writing the temporary file. 229 ** 230 ** Parameters: 231 ** tf -- the file pointer for the temporary file. 232 ** 233 ** Returns: 234 ** none. 235 ** 236 ** Side Effects: 237 ** Gives an error message. 238 ** Arranges for following output to go elsewhere. 239 */ 240 241 tferror(tf) 242 FILE *tf; 243 { 244 if (errno == ENOSPC) 245 { 246 (void) freopen(CurEnv->e_df, "w", tf); 247 fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf); 248 usrerr("452 Out of disk space for temp file"); 249 } 250 else 251 syserr("collect: Cannot write %s", CurEnv->e_df); 252 (void) freopen("/dev/null", "w", tf); 253 } 254 /* 255 ** EATFROM -- chew up a UNIX style from line and process 256 ** 257 ** This does indeed make some assumptions about the format 258 ** of UNIX messages. 259 ** 260 ** Parameters: 261 ** fm -- the from line. 262 ** 263 ** Returns: 264 ** none. 265 ** 266 ** Side Effects: 267 ** extracts what information it can from the header, 268 ** such as the date. 269 */ 270 271 # ifndef NOTUNIX 272 273 char *DowList[] = 274 { 275 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 276 }; 277 278 char *MonthList[] = 279 { 280 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 281 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 282 NULL 283 }; 284 285 eatfrom(fm) 286 char *fm; 287 { 288 register char *p; 289 register char **dt; 290 291 # ifdef DEBUG 292 if (tTd(30, 2)) 293 printf("eatfrom(%s)\n", fm); 294 # endif DEBUG 295 296 /* find the date part */ 297 p = fm; 298 while (*p != '\0') 299 { 300 /* skip a word */ 301 while (*p != '\0' && *p != ' ') 302 p++; 303 while (*p == ' ') 304 p++; 305 if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':') 306 continue; 307 308 /* we have a possible date */ 309 for (dt = DowList; *dt != NULL; dt++) 310 if (strncmp(*dt, p, 3) == 0) 311 break; 312 if (*dt == NULL) 313 continue; 314 315 for (dt = MonthList; *dt != NULL; dt++) 316 if (strncmp(*dt, &p[4], 3) == 0) 317 break; 318 if (*dt != NULL) 319 break; 320 } 321 322 if (*p != NULL) 323 { 324 char *q; 325 extern char *arpadate(); 326 327 /* we have found a date */ 328 q = xalloc(25); 329 (void) strncpy(q, p, 25); 330 q[24] = '\0'; 331 define('d', q, CurEnv); 332 q = arpadate(q); 333 define('a', newstr(q), CurEnv); 334 } 335 } 336 337 # endif NOTUNIX 338