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