1: /* 2: * v6mail 3: */ 4: #include <sysexits.h> 5: 6: #include <sys/param.h> 7: #include <sys/stat.h> 8: #include <sys/dir.h> 9: #include <sys/times.h> 10: #include <ctype.h> 11: #include <errno.h> 12: #include <pwd.h> 13: #include <signal.h> 14: 15: char *ctime(), *index(), *rindex(), *ctime(), *strcpy(), *getlogin(); 16: char *mktemp(), *sprintf(); 17: struct passwd *getpwnam(), *getpwuid(); 18: time_t time(); 19: struct utmp *getutmp(); 20: char *getdate(); 21: int errno; 22: 23: #include <stdio.h> 24: 25: #define MAILMODE 0644 26: #define MSGSCMD "/usr/ucb/msgs" 27: #define MAILDIR "/usr/spool/mail" 28: 29: char lettmp[] = "/tmp/MaXXXXX"; /* keep letter before sending it */ 30: char preptmp[] = "/tmp/mbXXXXX"; /* if prepending msg, use this file */ 31: int chew; /* if true, strip extra from lines */ 32: int dflag; /* if true, don't call sendmail */ 33: char shopcnt[30] = "0"; /* hop count parameter for rmt mail */ 34: int errs; /* no of errs in sending */ 35: char deleteonly; /* if true, just delete mailbox */ 36: char remname[50]; /* if non-empty, from line extra */ 37: 38: main(argc, argv) 39: int argc; 40: char **argv; 41: { 42: register int myuid; 43: int delexit(); 44: char namebuf[128], *sn = NULL, logindir[60]; 45: struct passwd *pwd; 46: 47: (void) mktemp(lettmp); 48: (void) mktemp(preptmp); 49: (void) unlink(lettmp); 50: (void) unlink(preptmp); 51: myuid = getuid(); 52: logindir[0] = 0; 53: sn = getlogin(); 54: if (sn == NULL || *sn == 0 || *sn == ' ') { 55: pwd = getpwuid(myuid); /* will read passwd file */ 56: if (pwd != NULL){ 57: sn = pwd->pw_name; 58: (void) strcpy(logindir, pwd->pw_dir); 59: } 60: if (sn == NULL) { 61: fprintf(stderr, "Who are you?\n"); 62: delexit(EX_OSFILE); 63: } 64: } 65: (void) strcpy(namebuf, sn); 66: if (argc < 2) 67: goto hitit; 68: for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) 69: switch (argv[0][1]) { 70: 71: case 'y': 72: case 'n': 73: argc++, argv--; 74: hitit: 75: printmail(argc, argv, namebuf, logindir); 76: delexit(EX_OK); 77: 78: case 'r': /* one-arg -r-- -r addr */ 79: if (argc < 2) 80: continue; 81: /* ignore -r if not network or root */ 82: if (strcmp("network", namebuf) == 0 || myuid == 0 || 83: /*###86 [lint] index arg. 1 used inconsistently v6mail.c(86) :: v6mail.c(244)%%%*/ 84: /*###86 [lint] index arg. 2 used inconsistently v6mail.c(86) :: v6mail.c(244)%%%*/ 85: strcmp("uucp", namebuf) == 0 || index('!', argv[1])) { 86: (void) strcpy(namebuf, argv[1]); 87: chew++; /* eat From lines */ 88: } 89: else 90: (void) strcpy(remname, argv[1]); 91: argc--, argv++; 92: continue; 93: 94: case 'h': /* hop count - used by network */ 95: if (argc < 2) 96: continue; 97: (void) strcpy(shopcnt, argv[1]); 98: argc--, argv++; 99: continue; 100: 101: case 'd': /* really deliver this message */ 102: dflag++; 103: continue; 104: 105: case 'D': /* only delete the invokers mailbox */ 106: deleteonly++; 107: goto hitit; /* delete mail box, thats all */ 108: } 109: /* if we are already ignoring signals, catch sigint */ 110: if (signal(SIGINT, SIG_IGN) != SIG_IGN) 111: (void) signal(SIGINT, delexit); 112: argc++, argv--; 113: bulkmail(argc, argv, namebuf); 114: delexit(EX_OK); 115: } 116: 117: printmail(argc, argv, name, logindir) 118: int argc; 119: char **argv; 120: char *name, *logindir; 121: { 122: register int c; 123: FILE *fdin; 124: char sfnmail[60], mbox[120]; 125: struct stat stb; 126: 127: (void) sprintf(sfnmail, "%s/%s", MAILDIR, name); 128: if (deleteonly) { 129: remove(sfnmail); 130: return; 131: } 132: fdin = fopen(sfnmail, "r"); 133: if (fdin < 0 || fstat(fileno(fdin), &stb) < 0 || stb.st_size == 0) { 134: printf("No mail.\n"); 135: return; 136: } 137: if (stb.st_nlink > 1) { 138: printf("%s: Too many links.\n", sfnmail); 139: return; 140: } 141: (void) getput(fdin, stdout); 142: (void) fclose(fdin); 143: (void) fflush(stdout); 144: c = 'y'; 145: if (argc < 2) { 146: if (isatty(0)) { 147: printf("Save (y or n) ?"); (void) fflush(stdout); 148: c = getchar(); 149: } 150: } else 151: c = argv[1][1]; 152: switch (c) { 153: 154: default: 155: delexit(EX_OK); 156: /*NOTREACHED*/ 157: 158: case 'x': 159: return; 160: 161: case 'y': 162: (void) sprintf(mbox, "%s/mbox", logindir); 163: if (writeable(mbox)) { 164: perror(mbox); 165: return; 166: } 167: printf("Saving mail in %s.\n", mbox); 168: if (append(sfnmail, mbox, getuid(), getgid()) == 0) 169: return; 170: /* fall into... */ 171: 172: case 'n': 173: remove(sfnmail); 174: return; 175: } 176: } 177: 178: bulkmail(argc, argv, from) 179: char **argv, *from; 180: { 181: char linebuf[BUFSIZ]; 182: FILE *fdout; 183: 184: if (dflag == 0) { 185: argv[0] = "sendmail"; 186: argv[argc] = 0; 187: execv("/usr/lib/sendmail", argv); 188: perror("/usr/lib/sendmail"); 189: _exit(1); 190: } 191: fdout = fopen(lettmp, "w"); 192: if (fdout == NULL) { 193: perror(lettmp); 194: delexit(EX_OSFILE); 195: } 196: 197: /* 198: * If delivering mail from the network via mail -r, 199: * Strip the leading line and throw it away, as long 200: * as it begins with "From ..." (and preserve the date if poss.) 201: */ 202: if (chew) { 203: if (fgets(linebuf, BUFSIZ, stdin) == 0) 204: goto skip; 205: if (!strncmp(linebuf, "From ", 5) != 0) 206: printfromline(fdout, getdate(linebuf), from); 207: else { 208: printfromline(fdout, (char *)0, from); 209: fprintf(fdout, "%s", linebuf); 210: } 211: } else 212: printfromline(fdout, (char *)0, from); 213: skip: 214: if (remname[0]) 215: fprintf(fdout, "(from %s)\n", remname); 216: if (getput(stdin, fdout) == 0) 217: delexit(EX_OSERR); 218: putc('\n', fdout); 219: (void) fclose(fdout); 220: while (--argc > 0) 221: sendto(*++argv); 222: delexit(errs); 223: } 224: 225: printfromline(fdout, date, from) 226: FILE *fdout; 227: char *date, *from; 228: { 229: time_t t; 230: 231: if (date == NULL) { 232: t = time((time_t *)0); 233: date = ctime(&t); 234: } 235: fprintf(fdout, "From %s %s", from, date); 236: } 237: 238: /* look over linebuf and return ptr to date, NULL if error */ 239: char * 240: getdate(linebuf) 241: char *linebuf; 242: { 243: register char *s = linebuf; 244: 245: /*###244 [lint] index arg. 2 used inconsistently v6mail.c(86) :: v6mail.c(244)%%%*/ 246: /*###244 [lint] index arg. 1 used inconsistently v6mail.c(86) :: v6mail.c(244)%%%*/ 247: while (s = index(' ', s)) 248: if (!strncmp(s, " Sun ", 5) || 249: !strncmp(s, " Mon ", 5) || 250: !strncmp(s, " Tue ", 5) || 251: !strncmp(s, " Wed ", 5) || 252: !strncmp(s, " Thu ", 5) || 253: !strncmp(s, " Fri ", 5) || 254: !strncmp(s, " Sat ", 5)) 255: return (s + 1); 256: return (0); 257: } 258: 259: int saved = 0; 260: 261: sendto(person) 262: char *person; 263: { 264: char mailboxname[BUFSIZ]; 265: struct passwd *pwd; 266: 267: if (index('/', person)) { 268: if (!writeable(person)) { 269: perror(person); 270: return; 271: } 272: lock(person); 273: (void) append(lettmp, person, -1, -1); 274: unlock(); 275: return; 276: } 277: pwd = getpwnam(person); 278: if (pwd) { 279: (void) sprintf(mailboxname, "%s/%s", MAILDIR, person); 280: lock(mailboxname); 281: (void) append(lettmp, mailboxname, pwd->pw_uid, pwd->pw_gid); 282: unlock(); 283: return; 284: } 285: fprintf(stderr, "Can't send to %s.\n", person); 286: errs++; 287: if (!isatty(0) || saved) 288: return; 289: saved++; 290: if (!writeable("dead.letter")) { 291: perror("dead.letter"); 292: return; 293: } 294: printf("Letter saved in 'dead.letter'\n"); 295: (void) append(lettmp, "dead.letter", getuid(), getgid()); 296: } 297: 298: #include <sys/socket.h> 299: #include <net/in.h> 300: 301: struct sockaddr_in biffaddr = { AF_INET, IPPORT_BIFFUDP }; 302: 303: append(from, to, uid, gid) 304: char *from, *to; 305: int uid, gid; 306: { 307: register FILE *fdin, *fdout; 308: int ret; 309: struct stat stb; 310: char *cp, buf[100]; int f; 311: 312: if (stat(to, &stb) >= 0 && (stb.st_mode&S_IFMT) != S_IFREG) { 313: fprintf(stderr, "Not a plain file: %s\n", to); 314: goto fail; 315: } 316: fdout = fopen(to, "a"); 317: if (fdout == NULL) { 318: perror(to); 319: goto fail; 320: } 321: if (uid != -1) { 322: (void) chown(to, uid, gid); 323: (void) chmod(to, MAILMODE); 324: } 325: if ((fdin = fopen(from, "r")) == NULL) { 326: perror(from); 327: return (0); 328: } 329: cp = rindex(to, '/'); 330: if (cp) { 331: char *host = "localhost"; 332: biffaddr.sin_addr.s_addr = rhost(&host); 333: #if vax || pdp11 334: biffaddr.sin_port = 335: (biffaddr.sin_port<<8) | ((biffaddr.sin_port>>8) & 0xff); 336: #endif 337: f = socket(SOCK_DGRAM, 0, 0, 0); 338: (void) sprintf(buf, "%s@%d\n", cp+1, ftell(fdout)); 339: } 340: ret = getput(fdin, fdout); 341: (void) fclose(fdin); 342: (void) fclose(fdout); 343: if (cp && f >= 0) { 344: send(f, &biffaddr, buf, strlen(buf)+1); 345: (void) close(f); 346: } 347: return (ret); 348: fail: 349: errs++; 350: return (0); 351: } 352: 353: delexit(status) 354: int status; 355: { 356: 357: (void) unlink(lettmp); 358: (void) unlink(preptmp); 359: exit(status); 360: } 361: 362: getput(fdin, fdout) 363: register FILE *fdin, *fdout; 364: { 365: register int c; 366: 367: while ((c = getc(fdin)) != EOF) { 368: errno = 0; 369: putc(c, fdout); 370: if (errno) { 371: perror("mail"); 372: return (0); 373: } 374: } 375: return (1); 376: } 377: 378: writeable(name) 379: char *name; 380: { 381: struct stat stb; 382: char *cp; 383: int ok; 384: 385: if (stat(name, &stb) < 0) { 386: cp = rindex(name, '/'); 387: if (cp) 388: *cp = 0; 389: ok = access(cp ? "." : name, 2) == 0; 390: if (cp) 391: *cp = '/'; 392: return (ok); 393: } 394: return (access(name, 2) == 0); 395: } 396: 397: char locktmp[30]; /* Usable lock temporary */ 398: char curlock[50]; /* Last used name of lock */ 399: int locked; /* To note that we locked it */ 400: 401: /* 402: * Lock the specified mail file by setting the file mailfile.lock. 403: * We must, of course, be careful to unlink the lock file by a call 404: * to unlock before we stop. The algorithm used here is to see if 405: * the lock exists, and if it does, to check its modify time. If it 406: * is older than 30 seconds, we assume error and set our own file. 407: * Otherwise, we wait for 5 seconds and try again. 408: */ 409: lock(file) 410: char *file; 411: { 412: register int f; 413: struct stat statbuf; 414: time_t curtime; 415: 416: if (locked) 417: return; 418: (void) sprintf(curlock, "%s%s", file, ".lock"); 419: (void) sprintf(locktmp, "%s/tmXXXXXX", MAILDIR); 420: (void) mktemp(locktmp); 421: (void) unlink(locktmp); 422: for (;;) { 423: f = lock1(locktmp, curlock); 424: if (f == 0) { 425: locked = 1; 426: return; 427: } 428: if (stat(curlock, &statbuf) < 0) 429: return; 430: (void) time(&curtime); 431: if (curtime < statbuf.st_mtime + 30) { 432: sleep(5); 433: continue; 434: } 435: (void) unlink(curlock); 436: } 437: } 438: 439: unlock() 440: { 441: 442: if (locked) 443: (void) unlink(curlock); 444: locked = 0; 445: } 446: 447: /* 448: * Attempt to set the lock by creating the temporary file, 449: * then doing a link/unlink. If it fails, return -1 else 0 450: */ 451: lock1(tempfile, name) 452: char tempfile[], name[]; 453: { 454: int fno; 455: 456: fno = creat(tempfile, 0400); 457: if (fno < 0) 458: return (-1); 459: (void) close(fno); 460: if (link(tempfile, name) < 0) { 461: (void) unlink(tempfile); 462: return (-1); 463: } 464: (void) unlink(tempfile); 465: return (0); 466: } 467: 468: remove(sfn) 469: char *sfn; 470: { 471: int i; 472: 473: if (unlink(sfn) < 0) { 474: i = creat(sfn, MAILMODE); 475: if (i >= 0) 476: (void) close(i); 477: } 478: }