1: # 2: 3: /* 4: * mail command usage 5: * mail [-yn] 6: * prints your mail 7: * mail people 8: * sends standard input to people 9: * 10: * mail -r machine user people 11: * sends mail from the network 12: * 13: * if NOTROOT is defined, don't run as root. 14: */ 15: 16: #define SIGINT 2 17: #define DIRECT 040000 18: #define RMAILCMD "/usr/net/bin/sendmail" 19: #define GETUID() (getuid() & 0377) 20: #define SPOOLDIR "/usr/spool/mail/" 21: #define NOTROOT $ 22: 23: struct inode { 24: char minor; 25: char major; 26: int inumber; 27: int flags; 28: char nlinks; 29: char uid; 30: char gid; 31: char size0; 32: int size1; 33: int addr[8]; 34: int actime[2]; 35: int modtime[2]; 36: } inode; 37: 38: char lettmp[] "/tmp/maXXXXX"; 39: char preptmp[] "/tmp/mbXXXXX"; 40: int pwfil; 41: int chew; 42: int errs; 43: char *strcat(), *strcpy(); 44: 45: main(argc, argv) 46: char **argv; 47: { 48: register int me; 49: extern int fout; 50: int uf, delexit(); 51: char namebuf[20]; 52: 53: mktemp(lettmp); 54: mktemp(preptmp); 55: unlink(lettmp); 56: unlink(preptmp); 57: me = GETUID(); 58: if (getname(me, namebuf) < 0) { 59: printf("Who are you?\n"); 60: delexit(1); 61: } 62: if (argc < 2) 63: goto hitit; 64: for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) 65: switch(argv[0][1]) { 66: register char *cp, *np; 67: 68: case 'y': 69: case 'n': 70: argc++, argv--; 71: hitit: 72: printmail(argc, argv, namebuf); 73: delexit(0); 74: 75: case 'r': 76: if (argc < 2) 77: continue; 78: case 'f': 79: if (argc < 1) 80: continue; 81: if (!equal("network", namebuf) && me != 0) { 82: printf("Nice try!\n"); 83: delexit(1); 84: } 85: chew++; 86: np = namebuf; 87: for (cp = argv[1]; *cp; cp++) 88: *np++ = *cp; 89: if (argv[0][1] == 'r') 90: { 91: argc--, argv++; 92: *np++ = ':'; 93: for (cp = argv[1]; *cp; cp++) 94: *np++ = *cp; 95: } 96: *np++ = 0; 97: argc--, argv++; 98: continue; 99: } 100: if ((signal(SIGINT, 01) & 01) == 0) 101: signal(SIGINT, delexit); 102: unlink(lettmp); 103: # ifdef NOTROOT 104: fout = creat(lettmp, 0666); 105: # else 106: fout = creat(lettmp, 0600); 107: # endif 108: if (fout < 0) { 109: fout = 1; 110: perror(lettmp); 111: delexit(1); 112: } 113: argc++, argv--; 114: bulkmail(argc, argv, namebuf); 115: delexit(0); 116: } 117: 118: printmail(argc, argv, name) 119: char **argv; 120: char *name; 121: { 122: extern int fin, fout; 123: register n, c, f; 124: char *mname; 125: 126: mname = cat(SPOOLDIR, name); 127: if (stat(mname, &inode)>=0 && inode.nlinks==1 && 128: fopen(mname, &fin)>=0 && (c = getchar())) { 129: putchar(c); 130: getput(); 131: close(fin); 132: c = 'x'; 133: if (argc<2) { 134: if (ttyn(0)!='x') { 135: printf("Save?"); 136: fin = 0; 137: c = getchar(); 138: } 139: } else 140: c = argv[1][1]; 141: if (!any(c, "yn")) 142: delexit(0); 143: if (c == 'y') { 144: if (accesss("mbox")) { 145: printf("Saved mail in 'mbox'\n"); 146: prepend(mname, "mbox", GETUID()); 147: unlink(mname); 148: } else 149: printf("In wrong directory\n"); 150: } else 151: unlink(mname); 152: } else 153: printf("No mail.\n"); 154: } 155: 156: bulkmail(argc, argv, from) 157: char **argv, *from; 158: { 159: extern int fin, fout; 160: register int c; 161: register char *cp; 162: char linebuf[128]; 163: int tbuf[2], ttyn1; 164: 165: fin = 0; 166: (&fin)[1] = 0; 167: time(tbuf); 168: ttyn1 = ttyn(1); 169: if (ttyn1 < 033) { 170: ttyn1 =+ 'a' - 1; 171: ttyn1 =<< 8; 172: ttyn1 =| '^'; 173: } 174: printf("From %s tty%c %s", from, ttyn1, ctime(tbuf)); 175: 176: /* 177: * If delivering mail from the network via mail -r, 178: * Strip the leading line and throw it away, as long 179: * as it begins with "From ..." 180: */ 181: 182: if (chew) { 183: cp = linebuf; 184: do { 185: c = getchar(); 186: if (cp - linebuf < 120) 187: *cp++ = c; 188: } while (c != '\n' && c != 0); 189: *cp = '\0'; 190: if (linebuf[0] != 'F' || linebuf[1] != 'r' || 191: linebuf[2] != 'o' || linebuf[3] != 'm') 192: printf("%s", linebuf); 193: } 194: getput(); 195: putchar('\n'); 196: flush(); 197: close(fout); 198: while (--argc > 0) 199: sendto(*++argv); 200: delexit(errs); 201: } 202: 203: sendto(person) 204: char *person; 205: { 206: static int saved; 207: extern int fout, fin; 208: register char *filep; 209: register int him; 210: int i; 211: 212: if ((person[0] == 'i' || person[0] == 'I') && person[1] == ':') 213: person += 2; 214: for (i = 0; person[i] != '\0'; i++) 215: { 216: if (person[i] == ':') 217: { 218: person[i] = '\0'; 219: if (equal(person, "ing70") || equal(person, "ingres")) 220: person += i + 1; 221: else 222: person[i] = ':'; 223: break; 224: } 225: } 226: if (person[i] == ':' || equal(person, "msgs")) 227: { 228: int i = fork(); 229: int s; 230: 231: if (i < 0) { 232: perror("fork"); 233: goto assback; 234: } 235: if (i == 0) { 236: close(0); 237: open(lettmp, 0); 238: if (any(':', person)) { 239: execl(RMAILCMD, "sendmail", person, 0); 240: execl("/usr/bin/sendmail", "sendmail", person, 0); 241: execl("/bin/sendmail", "sendmail", person, 0); 242: perror("sendmail"); 243: } else { 244: execl("/usr/new/msgs", "msgs", "-s", 0); 245: execl("/usr/ucb/msgs", "msgs", "-s", 0); 246: execl("/usr/bin/msgs", "msgs", "-s", 0); 247: } 248: exit(12); 249: } 250: for (;;) { 251: register int j = wait(&s); 252: if (j == -1) 253: goto assback; 254: if (j == i) 255: break; 256: } 257: if ((s & 0377) != 0 || (s >> 8) == 12) 258: goto assback; 259: return; 260: } 261: 262: if ((him = getuserid(person)) == -1) { 263: assback: 264: fout = 1; 265: flush(); 266: printf("Can't send to %s.\n", person); 267: errs++; 268: if (ttyn(0)!='x' && saved==0) { 269: saved++; 270: if (accesss("dead.letter")) { 271: printf("Letter saved in 'dead.letter'\n"); 272: prepend(lettmp, "dead.letter", GETUID()); 273: } else 274: printf("In wrong directory\n"); 275: } 276: return; 277: } 278: filep = cat(SPOOLDIR, person); 279: lock(filep); 280: prepend(lettmp, filep, him); 281: unlock(); 282: } 283: 284: prepend(from, to, own) 285: char *from, *to; 286: { 287: extern int fin, fout; 288: register int sig; 289: int statb[18]; 290: 291: if (stat(to, statb) >= 0 && (statb[2] & 060000) != 0) { 292: write(2, "Exotic destination\n", 19); 293: delexit(1); 294: } 295: unlink(preptmp); 296: if (fcreat(preptmp, &fout) < 0) { 297: fout = 1; 298: perror("mail"); 299: delexit(1); 300: } 301: chmod(preptmp, 0600); 302: if (fopen(from, &fin) < 0) { 303: close(fout); 304: fout = 1; 305: perror("mail"); 306: unlink(preptmp); 307: return(0); 308: } 309: getput(); 310: close(fin); 311: fopen(to, &fin); 312: getput(); 313: close(fin); 314: flush(); 315: close(fout); 316: sig = signal(SIGINT, 01); 317: unlink(to); 318: if (fcreat(to, &fout) < 0) { 319: unlink(preptmp); 320: fout = 1; 321: signal(SIGINT, sig); 322: return(0); 323: } 324: # ifdef NOTROOT 325: chmod(to, 0666); 326: # else 327: chmod(to, 0600); 328: chown(to, own); 329: # endif 330: if(stat(to, &inode) < 0 || inode.nlinks != 1) { 331: close(fout); 332: fout = 1; 333: unlink(preptmp); 334: signal(SIGINT, sig); 335: return(0); 336: } 337: if (fopen(preptmp, &fin) < 0) { 338: fout = 1; 339: perror("mail"); 340: signal(SIGINT, sig); 341: errs++; 342: return(0); 343: } 344: getput(); 345: flush(); 346: close(fout); 347: close(fin); 348: fout = 1; 349: signal(SIGINT, sig); 350: return(1); 351: } 352: 353: delexit(ex) 354: { 355: unlock(); 356: unlink(lettmp); 357: unlink(preptmp); 358: exit(ex); 359: } 360: 361: equal(as1, as2) 362: { 363: register char *s1, *s2; 364: 365: s1 = as1; 366: s2 = as2; 367: while (*s1++ == *s2) 368: if (*s2++ == 0) 369: return(1); 370: return(0); 371: } 372: 373: cat(ap1, ap2) 374: char *ap1, *ap2; 375: { 376: register char *p1, *p2; 377: static char fn[32]; 378: 379: p1 = ap1; 380: p2 = fn; 381: while (*p2++ = *p1++); 382: p2--; 383: p1 = ap2; 384: while (*p2++ = *p1++); 385: return(fn); 386: } 387: 388: getput() 389: { 390: extern int errno; 391: register c; 392: 393: while(c = getchar()) { 394: errno = 0; 395: putchar(c); 396: if(errno) { 397: perror("mail"); 398: delexit(1); 399: } 400: } 401: } 402: 403: accesss(s1) 404: { 405: if (access(".", 2) != -1 && (stat(s1, &inode)<0 || access(s1, 2)==0)) 406: return(1); 407: return(0); 408: } 409: 410: any(c, str) 411: char *str; 412: { 413: register char *f; 414: 415: f = str; 416: while (*f) 417: if (c == *f++) 418: return(1); 419: return(0); 420: } 421: 422: char *maillock = ".lock"; /* Lock suffix for mailname */ 423: char *lockname = "/usr/spool/mail/tmXXXXXX"; 424: char locktmp[30]; /* Usable lock temporary */ 425: char curlock[50]; /* Last used name of lock */ 426: int locked; /* To note that we locked it */ 427: 428: /* 429: * Lock the specified mail file by setting the file mailfile.lock. 430: * We must, of course, be careful to unlink the lock file by a call 431: * to unlock before we stop. The algorithm used here is to see if 432: * the lock exists, and if it does, to check its modify time. If it 433: * is older than 30 seconds, we assume error and set our own file. 434: * Otherwise, we wait for 5 seconds and try again. 435: */ 436: 437: lock(file) 438: char *file; 439: { 440: register int f; 441: long age; 442: struct inode sbuf; 443: long curtime; 444: 445: if (file == (char *) 0) { 446: printf("Locked = %d\n", locked); 447: return(0); 448: } 449: if (locked) 450: return(0); 451: strcpy(curlock, file); 452: strcat(curlock, maillock); 453: strcpy(locktmp, lockname); 454: mktemp(locktmp); 455: unlink(locktmp); 456: for (;;) { 457: f = lock1(locktmp, curlock); 458: if (f == 0) { 459: locked = 1; 460: return(0); 461: } 462: if (stat(curlock, &sbuf) < 0) 463: return(0); 464: time(&curtime); 465: age = * ((long *) sbuf.modtime); 466: if (curtime < age + 30) { 467: sleep(5); 468: continue; 469: } 470: unlink(curlock); 471: } 472: } 473: 474: /* 475: * Remove the mail lock, and note that we no longer 476: * have it locked. 477: */ 478: 479: unlock() 480: { 481: 482: if (locked) 483: unlink(curlock); 484: locked = 0; 485: } 486: 487: /* 488: * Attempt to set the lock by creating the temporary file, 489: * then doing a link/unlink. If it fails, return -1 else 0 490: */ 491: 492: lock1(tempfile, name) 493: char tempfile[], name[]; 494: { 495: register int fd; 496: 497: fd = creat(tempfile, 0); 498: if (fd < 0) 499: return(-1); 500: close(fd); 501: if (link(tempfile, name) < 0) { 502: unlink(tempfile); 503: return(-1); 504: } 505: unlink(tempfile); 506: return(0); 507: } 508: 509: /* 510: * Concatenate s2 on the end of s1. S1's space must be large enough. 511: * Return s1. 512: */ 513: 514: char * 515: strcat(s1, s2) 516: register char *s1, *s2; 517: { 518: register os1; 519: 520: os1 = s1; 521: while (*s1++) 522: ; 523: *--s1; 524: while (*s1++ = *s2++) 525: ; 526: return(os1); 527: } 528: 529: /* 530: * Copy string s2 to s1. s1 must be large enough. 531: * return s1 532: */ 533: 534: char * 535: strcpy(s1, s2) 536: register char *s1, *s2; 537: { 538: register os1; 539: 540: os1 = s1; 541: while (*s1++ = *s2++) 542: ; 543: return(os1); 544: }