1 # 2 3 #include "rcv.h" 4 #ifdef VMUNIX 5 #include <wait.h> 6 #endif 7 8 /* 9 * Mail -- a mail program 10 * 11 * Mail to others. 12 */ 13 14 static char *SccsId = "@(#)send.c 1.1 10/08/80"; 15 16 /* 17 * Send message described by the passed pointer to the 18 * passed output buffer. Return -1 on error, but normally 19 * the number of lines written. 20 */ 21 22 send(mailp, obuf) 23 struct message *mailp; 24 FILE *obuf; 25 { 26 register struct message *mp; 27 register int t; 28 unsigned int c; 29 FILE *ibuf; 30 int lc; 31 32 mp = mailp; 33 ibuf = setinput(mp); 34 c = msize(mp); 35 lc = 0; 36 while (c-- > 0) { 37 putc(t = getc(ibuf), obuf); 38 if (t == '\n') 39 lc++; 40 if (ferror(obuf)) 41 return(-1); 42 } 43 return(lc); 44 } 45 46 /* 47 * Interface between the argument list and the mail1 routine 48 * which does all the dirty work. 49 */ 50 51 mail(people) 52 char **people; 53 { 54 register char *cp2; 55 register int s; 56 char *buf, **ap; 57 struct header head; 58 59 for (s = 0, ap = people; *ap != (char *) -1; ap++) 60 s += strlen(*ap) + 1; 61 buf = salloc(s+1); 62 cp2 = buf; 63 for (ap = people; *ap != (char *) -1; ap++) { 64 cp2 = copy(*ap, cp2); 65 *cp2++ = ' '; 66 } 67 if (cp2 != buf) 68 cp2--; 69 *cp2 = '\0'; 70 head.h_to = buf; 71 head.h_subject = NOSTR; 72 head.h_cc = NOSTR; 73 head.h_bcc = NOSTR; 74 head.h_seq = 0; 75 mail1(&head); 76 return(0); 77 } 78 79 80 /* 81 * Send mail to a bunch of user names. The interface is through 82 * the mail routine below. 83 */ 84 85 sendmail(str) 86 char *str; 87 { 88 register char **ap; 89 char *bufp; 90 register int t; 91 struct header head; 92 93 if (blankline(str)) 94 head.h_to = NOSTR; 95 else 96 head.h_to = str; 97 head.h_subject = NOSTR; 98 head.h_cc = NOSTR; 99 head.h_bcc = NOSTR; 100 head.h_seq = 0; 101 mail1(&head); 102 return(0); 103 } 104 105 /* 106 * Mail a message on standard input to the people indicated 107 * in the passed header. (Internal interface). 108 */ 109 110 mail1(hp) 111 struct header *hp; 112 { 113 register char *cp; 114 int pid, i, s, p, gotcha; 115 char **namelist; 116 struct name *to, *np; 117 FILE *mtf, *postage; 118 int remote = rflag != NOSTR || rmail; 119 char **t; 120 121 /* 122 * Collect user's mail from standard input. 123 * Get the result as mtf. 124 */ 125 126 pid = -1; 127 if ((mtf = collect(hp)) == NULL) 128 return(-1); 129 hp->h_seq = 1; 130 if (hp->h_subject == NOSTR) 131 hp->h_subject = sflag; 132 if (fsize(mtf) == 0 && hp->h_subject == NOSTR) { 133 printf("No message !?!\n"); 134 goto out; 135 } 136 if (intty && value("askcc") != NOSTR) 137 grabh(hp, GCC); 138 else if (intty) { 139 printf("EOT\n"); 140 flush(); 141 } 142 143 /* 144 * Now, take the user names from the combined 145 * to and cc lists and do all the alias 146 * processing. 147 */ 148 149 senderr = 0; 150 to = usermap(cat(extract(hp->h_bcc, GBCC), 151 cat(extract(hp->h_to, GTO), extract(hp->h_cc, GCC)))); 152 if (to == NIL) { 153 printf("No recipients specified\n"); 154 goto topdog; 155 } 156 157 /* 158 * Look through the recipient list for names with /'s 159 * in them which we write to as files directly. 160 */ 161 162 to = outof(to, mtf, hp); 163 rewind(mtf); 164 to = verify(to); 165 if (senderr && !remote) { 166 topdog: 167 168 if (fsize(mtf) != 0) { 169 remove(deadletter); 170 exwrite(deadletter, mtf, 1); 171 rewind(mtf); 172 } 173 } 174 for (gotcha = 0, np = to; np != NIL; np = np->n_flink) 175 if ((np->n_type & GDEL) == 0) { 176 gotcha++; 177 break; 178 } 179 if (!gotcha) 180 goto out; 181 to = elide(to); 182 mechk(to); 183 if (count(to) > 1) 184 hp->h_seq++; 185 if (hp->h_seq > 0 && !remote) { 186 fixhead(hp, to); 187 if (fsize(mtf) == 0) 188 printf("Null message body; hope that's ok\n"); 189 if ((mtf = infix(hp, mtf)) == NULL) { 190 fprintf(stderr, ". . . message lost, sorry.\n"); 191 return(-1); 192 } 193 } 194 namelist = unpack(to); 195 if (debug) { 196 printf("Recipients of message:\n"); 197 for (t = namelist; *t != NOSTR; t++) 198 printf(" \"%s\"", *t); 199 printf("\n"); 200 fflush(stdout); 201 return; 202 } 203 if ((cp = value("record")) != NOSTR) 204 savemail(expand(cp), hp, mtf); 205 206 /* 207 * Wait, to absorb a potential zombie, then 208 * fork, set up the temporary mail file as standard 209 * input for "mail" and exec with the user list we generated 210 * far above. Return the process id to caller in case he 211 * wants to await the completion of mail. 212 */ 213 214 #ifdef VMUNIX 215 while (wait3(&s, WNOHANG, 0) > 0) 216 ; 217 #else 218 wait(&s); 219 #endif 220 rewind(mtf); 221 pid = fork(); 222 if (pid == -1) { 223 perror("fork"); 224 remove(deadletter); 225 exwrite(deadletter, mtf, 1); 226 goto out; 227 } 228 if (pid == 0) { 229 #ifdef SIGTSTP 230 if (remote == 0) { 231 signal(SIGTSTP, SIG_IGN); 232 signal(SIGTTIN, SIG_IGN); 233 signal(SIGTTOU, SIG_IGN); 234 } 235 #endif 236 for (i = SIGHUP; i <= SIGQUIT; i++) 237 signal(i, SIG_IGN); 238 if ((postage = fopen("/crp/kurt/postage", "a")) != NULL) { 239 fprintf(postage, "%s %d %d\n", myname, 240 count(to), fsize(mtf)); 241 fclose(postage); 242 } 243 s = fileno(mtf); 244 for (i = 3; i < 15; i++) 245 if (i != s) 246 close(i); 247 close(0); 248 dup(s); 249 close(s); 250 #ifdef CC 251 submit(getpid()); 252 #endif CC 253 #ifdef DELIVERMAIL 254 execv(DELIVERMAIL, namelist); 255 #endif DELIVERMAIL 256 execv(MAIL, namelist); 257 perror(MAIL); 258 exit(1); 259 } 260 261 out: 262 if (remote) { 263 while ((p = wait(&s)) != pid && p != -1) 264 ; 265 if (s != 0) 266 senderr++; 267 pid = 0; 268 } 269 fclose(mtf); 270 return(pid); 271 } 272 273 /* 274 * Fix the header by glopping all of the expanded names from 275 * the distribution list into the appropriate fields. 276 * If there are any ARPA net recipients in the message, 277 * we must insert commas, alas. 278 */ 279 280 fixhead(hp, tolist) 281 struct header *hp; 282 struct name *tolist; 283 { 284 register struct name *nlist; 285 register int f; 286 register struct name *np; 287 288 for (f = 0, np = tolist; np != NIL; np = np->n_flink) 289 if (any('@', np->n_name)) { 290 f |= GCOMMA; 291 break; 292 } 293 294 if (debug && f & GCOMMA) 295 fprintf(stderr, "Should be inserting commas in recip lists\n"); 296 hp->h_to = detract(tolist, GTO|f); 297 hp->h_cc = detract(tolist, GCC|f); 298 } 299 300 /* 301 * Prepend a header in front of the collected stuff 302 * and return the new file. 303 */ 304 305 FILE * 306 infix(hp, fi) 307 struct header *hp; 308 FILE *fi; 309 { 310 extern char tempMail[]; 311 register FILE *nfo, *nfi; 312 register int c; 313 314 if ((nfo = fopen(tempMail, "w")) == NULL) { 315 perror(tempMail); 316 return(fi); 317 } 318 if ((nfi = fopen(tempMail, "r")) == NULL) { 319 perror(tempMail); 320 fclose(nfo); 321 return(fi); 322 } 323 remove(tempMail); 324 puthead(hp, nfo, GTO|GSUBJECT|GCC|GNL); 325 rewind(fi); 326 c = getc(fi); 327 while (c != EOF) { 328 putc(c, nfo); 329 c = getc(fi); 330 } 331 if (ferror(fi)) { 332 perror("read"); 333 fprintf(stderr, "Please notify Kurt Shoens\n"); 334 return(fi); 335 } 336 fflush(nfo); 337 if (ferror(nfo)) { 338 perror(tempMail); 339 fclose(nfo); 340 fclose(nfi); 341 return(fi); 342 } 343 fclose(nfo); 344 fclose(fi); 345 rewind(nfi); 346 return(nfi); 347 } 348 349 /* 350 * Dump the to, subject, cc header on the 351 * passed file buffer. 352 */ 353 354 puthead(hp, fo, w) 355 struct header *hp; 356 FILE *fo; 357 { 358 register int gotcha; 359 360 gotcha = 0; 361 if (hp->h_to != NOSTR && w & GTO) 362 fprintf(fo, "To: "), fmt(hp->h_to, fo), gotcha++; 363 if (hp->h_subject != NOSTR && w & GSUBJECT) 364 fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; 365 if (hp->h_cc != NOSTR && w & GCC) 366 fprintf(fo, "Cc: "), fmt(hp->h_cc, fo), gotcha++; 367 if (hp->h_bcc != NOSTR && w & GBCC) 368 fprintf(fo, "Bcc: "), fmt(hp->h_bcc, fo), gotcha++; 369 if (gotcha && w & GNL) 370 putc('\n', fo); 371 return(0); 372 } 373 374 /* 375 * Format the given text to not exceed 72 characters. 376 */ 377 378 fmt(str, fo) 379 register char *str; 380 register FILE *fo; 381 { 382 register int col; 383 register char *cp; 384 385 cp = str; 386 col = 0; 387 while (*cp) { 388 if (*cp == ' ' && col > 65) { 389 fprintf(fo, "\n "); 390 col = 4; 391 cp++; 392 continue; 393 } 394 putc(*cp++, fo); 395 col++; 396 } 397 putc('\n', fo); 398 } 399 400 /* 401 * Save the outgoing mail on the passed file. 402 */ 403 404 savemail(name, hp, fi) 405 char name[]; 406 struct header *hp; 407 FILE *fi; 408 { 409 register FILE *fo; 410 register int c; 411 long now; 412 char *n; 413 414 if ((fo = fopen(name, "a")) == NULL) { 415 perror(name); 416 return(-1); 417 } 418 time(&now); 419 n = rflag; 420 if (n == NOSTR) 421 n = myname; 422 fprintf(fo, "From %s %s", n, ctime(&now)); 423 rewind(fi); 424 for (c = getc(fi); c != EOF; c = getc(fi)) 425 putc(c, fo); 426 fprintf(fo, "\n"); 427 fflush(fo); 428 if (ferror(fo)) 429 perror(name); 430 fclose(fo); 431 return(0); 432 } 433