1 # include <errno.h> 2 # include "sendmail.h" 3 4 SCCSID(@(#)collect.c 3.47 08/17/82); 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 ** sayok -- if set, give an ARPANET style message 23 ** to say we are ready to collect input. 24 ** 25 ** Returns: 26 ** none. 27 ** 28 ** Side Effects: 29 ** Temp file is created and filled. 30 ** The from person may be set. 31 */ 32 33 collect(sayok) 34 bool sayok; 35 { 36 register FILE *tf; 37 char buf[MAXFIELD+1]; 38 register char *p; 39 extern char *hvalue(); 40 extern char *mktemp(); 41 static char tempfname[60]; 42 extern char *macvalue(); 43 44 /* 45 ** Create the temp file name and create the file. 46 */ 47 48 (void) strcpy(tempfname, QueueDir); 49 (void) strcat(tempfname, "/dfXXXXXX"); 50 (void) mktemp(tempfname); 51 if ((tf = dfopen(tempfname, "w")) == NULL) 52 { 53 syserr("Cannot create %s", tempfname); 54 NoReturn = TRUE; 55 finis(); 56 } 57 (void) chmod(tempfname, 0600); 58 CurEnv->e_df = tempfname; 59 60 /* 61 ** Create the Mail-From line if we want to. 62 */ 63 64 if (Smtp && macvalue('s') != NULL) 65 { 66 char xbuf[50]; 67 68 (void) sprintf(xbuf, "Mail-From: %s$s received by $i at $b", 69 macvalue('r') == NULL ? "" : "$r host "); 70 expand(xbuf, buf, &buf[sizeof buf - 1], CurEnv); 71 (void) chompheader(buf, FALSE); 72 } 73 74 /* 75 ** Tell ARPANET to go ahead. 76 */ 77 78 if (sayok) 79 message("354", "Enter mail, end with \".\" on a line by itself"); 80 81 /* 82 ** Try to read a UNIX-style From line 83 */ 84 85 if (fgets(buf, sizeof buf, InChannel) == NULL) 86 return; 87 fixcrlf(buf, FALSE); 88 # ifndef NOTUNIX 89 if (!SaveFrom && strncmp(buf, "From ", 5) == 0) 90 { 91 eatfrom(buf); 92 (void) fgets(buf, sizeof buf, InChannel); 93 fixcrlf(buf, FALSE); 94 } 95 # endif NOTUNIX 96 97 /* 98 ** Copy InChannel to temp file & do message editing. 99 ** To keep certain mailers from getting confused, 100 ** and to keep the output clean, lines that look 101 ** like UNIX "From" lines are deleted in the header, 102 ** and prepended with ">" in the body. 103 */ 104 105 for (; !feof(InChannel); !feof(InChannel) && fgets(buf, sizeof buf, InChannel) != NULL) 106 { 107 register char c; 108 extern bool isheader(); 109 110 /* if the line is too long, throw the rest away */ 111 if (index(buf, '\n') == NULL) 112 { 113 while ((c = getc(InChannel)) != '\n') 114 continue; 115 /* give an error? */ 116 } 117 118 fixcrlf(buf, FALSE); 119 120 /* see if the header is over */ 121 if (!isheader(buf)) 122 break; 123 124 /* get the rest of this field */ 125 while ((c = getc(InChannel)) == ' ' || c == '\t') 126 { 127 p = &buf[strlen(buf)]; 128 *p++ = c; 129 if (fgets(p, sizeof buf - (p - buf), InChannel) == NULL) 130 break; 131 fixcrlf(p, FALSE); 132 } 133 if (!feof(InChannel)) 134 (void) ungetc(c, InChannel); 135 136 CurEnv->e_msgsize += strlen(buf); 137 138 /* 139 ** Snarf header away. 140 */ 141 142 if (bitset(H_EOH, chompheader(buf, FALSE))) 143 break; 144 } 145 146 # ifdef DEBUG 147 if (tTd(30, 1)) 148 printf("EOH\n"); 149 # endif DEBUG 150 151 /* throw away a blank line */ 152 if (buf[0] == '\n') 153 { 154 (void) fgets(buf, sizeof buf, InChannel); 155 fixcrlf(buf, FALSE); 156 } 157 158 /* 159 ** Collect the body of the message. 160 */ 161 162 for (; !feof(InChannel); !feof(InChannel) && fgets(buf, sizeof buf, InChannel) != NULL) 163 { 164 register int i; 165 register char *bp = buf; 166 167 fixcrlf(buf, FALSE); 168 169 /* check for end-of-message */ 170 if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0')) 171 break; 172 173 /* check for transparent dot */ 174 if (Smtp && *bp == '.') 175 bp++; 176 177 # ifndef NOTUNIX 178 /* Hide UNIX-like From lines */ 179 if (strncmp(bp, "From ", 5) == 0) 180 { 181 fputs(">", tf); 182 CurEnv->e_msgsize++; 183 } 184 # endif NOTUNIX 185 186 /* 187 ** Figure message length, output the line to the temp 188 ** file, and insert a newline if missing. 189 */ 190 191 i = strlen(bp); 192 CurEnv->e_msgsize += i; 193 fputs(bp, tf); 194 if (bp[i - 1] != '\n') 195 fputs("\n", tf); 196 if (ferror(tf)) 197 { 198 if (errno == ENOSPC) 199 { 200 (void) freopen(CurEnv->e_df, "w", tf); 201 fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf); 202 usrerr("452 Out of disk space for temp file"); 203 } 204 else 205 syserr("collect: Cannot write %s", CurEnv->e_df); 206 (void) freopen("/dev/null", "w", tf); 207 } 208 } 209 (void) fclose(tf); 210 211 /* 212 ** Find out some information from the headers. 213 ** Examples are who is the from person & the date. 214 */ 215 216 eatheader(); 217 218 /* 219 ** Add an Apparently-To: line if we have no recipient lines. 220 */ 221 222 if (hvalue("to") == NULL && hvalue("cc") == NULL && 223 hvalue("bcc") == NULL && hvalue("apparently-to") == NULL) 224 { 225 register ADDRESS *q; 226 227 /* create an Apparently-To: field */ 228 /* that or reject the message.... */ 229 for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next) 230 { 231 if (q->q_alias != NULL) 232 continue; 233 # ifdef DEBUG 234 if (tTd(30, 3)) 235 printf("Adding Apparently-To: %s\n", q->q_paddr); 236 # endif DEBUG 237 addheader("apparently-to", q->q_paddr, CurEnv); 238 } 239 } 240 241 /* check for hop count overflow */ 242 if (HopCount > MAXHOP) 243 syserr("Too many hops (%d max); probably forwarding loop", MAXHOP); 244 245 if ((TempFile = fopen(CurEnv->e_df, "r")) == NULL) 246 syserr("Cannot reopen %s", CurEnv->e_df); 247 248 /* 249 ** Log collection information. 250 */ 251 252 # ifdef LOG 253 if (LogLevel > 1) 254 syslog(LOG_INFO, "%s: from=%s, size=%ld, class=%d\n", MsgId, 255 CurEnv->e_from.q_paddr, CurEnv->e_msgsize, 256 CurEnv->e_class); 257 # endif LOG 258 return; 259 } 260 /* 261 ** EATFROM -- chew up a UNIX style from line and process 262 ** 263 ** This does indeed make some assumptions about the format 264 ** of UNIX messages. 265 ** 266 ** Parameters: 267 ** fm -- the from line. 268 ** 269 ** Returns: 270 ** none. 271 ** 272 ** Side Effects: 273 ** extracts what information it can from the header, 274 ** such as the date. 275 */ 276 277 # ifndef NOTUNIX 278 279 char *DowList[] = 280 { 281 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 282 }; 283 284 char *MonthList[] = 285 { 286 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 287 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 288 NULL 289 }; 290 291 eatfrom(fm) 292 char *fm; 293 { 294 register char *p; 295 register char **dt; 296 297 # ifdef DEBUG 298 if (tTd(30, 2)) 299 printf("eatfrom(%s)\n", fm); 300 # endif DEBUG 301 302 /* find the date part */ 303 p = fm; 304 while (*p != '\0') 305 { 306 /* skip a word */ 307 while (*p != '\0' && *p != ' ') 308 *p++; 309 while (*p == ' ') 310 *p++; 311 if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':') 312 continue; 313 314 /* we have a possible date */ 315 for (dt = DowList; *dt != NULL; dt++) 316 if (strncmp(*dt, p, 3) == 0) 317 break; 318 if (*dt == NULL) 319 continue; 320 321 for (dt = MonthList; *dt != NULL; dt++) 322 if (strncmp(*dt, &p[4], 3) == 0) 323 break; 324 if (*dt != NULL) 325 break; 326 } 327 328 if (*p != NULL) 329 { 330 char *q; 331 extern char *arpadate(); 332 333 /* we have found a date */ 334 q = xalloc(25); 335 strncpy(q, p, 25); 336 q[24] = '\0'; 337 define('d', q); 338 q = arpadate(q); 339 define('a', newstr(q)); 340 } 341 } 342 343 # endif NOTUNIX 344