1: #include <stdio.h> 2: #include <pwd.h> 3: #include <utmp.h> 4: #include <signal.h> 5: #include <sys/types.h> 6: #include <sys/stat.h> 7: #include <setjmp.h> 8: #include <whoami.h> 9: 10: /*copylet flags */ 11: /*remote mail, add rmtmsg */ 12: #define REMOTE 1 13: /* zap header and trailing empty line */ 14: #define ZAP 3 15: #define ORDINARY 2 16: #define FORWARD 4 17: #define LSIZE 256 18: #define MAXLET 300 /* maximum number of letters */ 19: #define MAILMODE (~0644) /* mode of created mail */ 20: 21: char line[LSIZE]; 22: char resp[LSIZE]; 23: struct let { 24: long adr; 25: char change; 26: } let[MAXLET]; 27: int nlet = 0; 28: char lfil[50]; 29: long iop, time(); 30: char lettmp[] = "/tmp/maXXXXX"; 31: char maildir[] = "/usr/spool/mail/"; 32: char mailfile[] = "/usr/spool/mail/xxxxxxxxxxxxxxxxxxxxxxx"; 33: char dead[] = "dead.letter"; 34: char *thissys = sysname; 35: char forwmsg[] = " forwarded\n"; 36: char *curlock; 37: int lockerror; 38: FILE *tmpf; 39: FILE *malf; 40: char *my_name; 41: char *getlogin(); 42: struct passwd *getpwuid(); 43: int error; 44: int locked; 45: int changed; 46: int forward; 47: char from[] = "From "; 48: long ftell(); 49: int delete(); 50: char *ctime(); 51: int flgf; 52: int flgp; 53: int delflg = 1; 54: jmp_buf sjbuf; 55: 56: main(argc, argv) 57: char **argv; 58: { 59: register i; 60: char sobuf[BUFSIZ]; 61: 62: setbuf(stdout, sobuf); 63: mktemp(lettmp); 64: unlink(lettmp); 65: my_name = getlogin(); 66: if (my_name == NULL) { 67: struct passwd *pwent; 68: pwent = getpwuid(getuid()); 69: if (pwent==NULL) 70: my_name = "???"; 71: else 72: my_name = pwent->pw_name; 73: } 74: if(setjmp(sjbuf)) done(); 75: for (i=0; i<20; i++) 76: setsig(i, delete); 77: tmpf = fopen(lettmp, "w"); 78: if (tmpf == NULL) { 79: fprintf(stderr, "mail: cannot open %s for writing\n", lettmp); 80: done(); 81: } 82: if (argv[0][0] != 'r' && /* no favors for rmail*/ 83: (argc == 1 || argv[1][0] == '-')) 84: printmail(argc, argv); 85: else 86: sendmail(argc, argv); 87: done(); 88: } 89: 90: setsig(i, f) 91: int i; 92: int (*f)(); 93: { 94: if(signal(i, SIG_IGN)!=SIG_IGN) 95: signal(i, f); 96: } 97: 98: printmail(argc, argv) 99: char **argv; 100: { 101: int flg, i, j, print; 102: char *p, *getarg(); 103: 104: setuid(getuid()); 105: cat(mailfile, maildir, my_name); 106: for (; argc>1; argv++, argc--) { 107: if (argv[1][0]=='-') { 108: if (argv[1][1]=='q') 109: delflg = 0; 110: else if (argv[1][1]=='p') { 111: flgp++; 112: delflg = 0; 113: } else if (argv[1][1]=='f') { 114: if (argc>=3) { 115: strcpy(mailfile, argv[2]); 116: argv++; 117: argc--; 118: } 119: } else if (argv[1][1]=='r') { 120: forward = 1; 121: } else { 122: fprintf(stderr, "mail: unknown option %c\n", argv[1][1]); 123: done(); 124: } 125: } else 126: break; 127: } 128: malf = fopen(mailfile, "r"); 129: if (malf == NULL) { 130: fprintf(stdout, "No mail.\n"); 131: return; 132: } 133: lock(mailfile); 134: copymt(malf, tmpf); 135: fclose(malf); 136: fclose(tmpf); 137: unlock(); 138: tmpf = fopen(lettmp, "r"); 139: 140: changed = 0; 141: print = 1; 142: for (i = 0; i < nlet; ) { 143: j = forward ? i : nlet - i - 1; 144: if(setjmp(sjbuf)) { 145: print=0; 146: } else { 147: if (print) 148: copylet(j, stdout, ORDINARY); 149: print = 1; 150: } 151: if (flgp) { 152: i++; 153: continue; 154: } 155: setjmp(sjbuf); 156: fprintf(stdout, "? "); 157: fflush(stdout); 158: if (fgets(resp, LSIZE, stdin) == NULL) 159: break; 160: switch (resp[0]) { 161: 162: default: 163: fprintf(stderr, "usage\n"); 164: case '?': 165: print = 0; 166: fprintf(stderr, "q\tquit\n"); 167: fprintf(stderr, "x\texit without changing mail\n"); 168: fprintf(stderr, "p\tprint\n"); 169: fprintf(stderr, "s[file]\tsave (default mbox)\n"); 170: fprintf(stderr, "w[file]\tsame without header\n"); 171: fprintf(stderr, "-\tprint previous\n"); 172: fprintf(stderr, "d\tdelete\n"); 173: fprintf(stderr, "+\tnext (no delete)\n"); 174: fprintf(stderr, "m user\tmail to user\n"); 175: fprintf(stderr, "! cmd\texecute cmd\n"); 176: break; 177: 178: case '+': 179: case 'n': 180: case '\n': 181: i++; 182: break; 183: case 'x': 184: changed = 0; 185: case 'q': 186: goto donep; 187: case 'p': 188: break; 189: case '^': 190: case '-': 191: if (--i < 0) 192: i = 0; 193: break; 194: case 'y': 195: case 'w': 196: case 's': 197: flg = 0; 198: if (resp[1] != '\n' && resp[1] != ' ') { 199: printf("illegal\n"); 200: flg++; 201: print = 0; 202: continue; 203: } 204: if (resp[1] == '\n' || resp[1] == '\0') 205: cat(resp+1, "mbox", ""); 206: for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) { 207: malf = fopen(lfil, "a"); 208: if (malf == NULL) { 209: fprintf(stdout, "mail: cannot append to %s\n", lfil); 210: flg++; 211: continue; 212: } 213: copylet(j, malf, resp[0]=='w'? ZAP: ORDINARY); 214: fclose(malf); 215: } 216: if (flg) 217: print = 0; 218: else { 219: let[j].change = 'd'; 220: changed++; 221: i++; 222: } 223: break; 224: case 'm': 225: flg = 0; 226: if (resp[1] == '\n' || resp[1] == '\0') { 227: i++; 228: continue; 229: } 230: if (resp[1] != ' ') { 231: printf("invalid command\n"); 232: flg++; 233: print = 0; 234: continue; 235: } 236: for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) 237: if (!sendrmt(j, lfil)) /* couldn't send it */ 238: flg++; 239: if (flg) 240: print = 0; 241: else { 242: let[j].change = 'd'; 243: changed++; 244: i++; 245: } 246: break; 247: case '!': 248: system(resp+1); 249: printf("!\n"); 250: print = 0; 251: break; 252: case 'd': 253: let[j].change = 'd'; 254: changed++; 255: i++; 256: if (resp[1] == 'q') 257: goto donep; 258: break; 259: } 260: } 261: donep: 262: if (changed) 263: copyback(); 264: } 265: 266: copyback() /* copy temp or whatever back to /usr/spool/mail */ 267: { 268: register i, n, c; 269: int new = 0; 270: struct stat stbuf; 271: 272: signal(SIGINT, SIG_IGN); 273: signal(SIGHUP, SIG_IGN); 274: signal(SIGQUIT, SIG_IGN); 275: lock(mailfile); 276: stat(mailfile, &stbuf); 277: if (stbuf.st_size != let[nlet].adr) { /* new mail has arrived */ 278: malf = fopen(mailfile, "r"); 279: if (malf == NULL) { 280: fprintf(stdout, "mail: can't re-read %s\n", mailfile); 281: done(); 282: } 283: fseek(malf, let[nlet].adr, 0); 284: fclose(tmpf); 285: tmpf = fopen(lettmp, "a"); 286: fseek(tmpf, let[nlet].adr, 0); 287: while ((c = fgetc(malf)) != EOF) 288: fputc(c, tmpf); 289: fclose(malf); 290: fclose(tmpf); 291: tmpf = fopen(lettmp, "r"); 292: let[++nlet].adr = stbuf.st_size; 293: new = 1; 294: } 295: malf = fopen(mailfile, "w"); 296: if (malf == NULL) { 297: fprintf(stderr, "mail: can't rewrite %s\n", lfil); 298: done(); 299: } 300: n = 0; 301: for (i = 0; i < nlet; i++) 302: if (let[i].change != 'd') { 303: copylet(i, malf, ORDINARY); 304: n++; 305: } 306: fclose(malf); 307: if (new) 308: fprintf(stdout, "new mail arrived\n"); 309: unlock(); 310: } 311: 312: copymt(f1, f2) /* copy mail (f1) to temp (f2) */ 313: FILE *f1, *f2; 314: { 315: long nextadr; 316: 317: nlet = nextadr = 0; 318: let[0].adr = 0; 319: while (fgets(line, LSIZE, f1) != NULL) { 320: if (isfrom(line)) 321: let[nlet++].adr = nextadr; 322: nextadr += strlen(line); 323: fputs(line, f2); 324: } 325: let[nlet].adr = nextadr; /* last plus 1 */ 326: } 327: 328: copylet(n, f, type) FILE *f; 329: { int ch, k; 330: fseek(tmpf, let[n].adr, 0); 331: k = let[n+1].adr - let[n].adr; 332: while(k-- > 1 && (ch=fgetc(tmpf))!='\n') 333: if(type!=ZAP) fputc(ch,f); 334: if(type==REMOTE) 335: fprintf(f, " remote from %s\n", thissys); 336: else if (type==FORWARD) 337: fprintf(f, forwmsg); 338: else if(type==ORDINARY) 339: fputc(ch,f); 340: while(k-->1) 341: fputc(ch=fgetc(tmpf), f); 342: if(type!=ZAP || ch!= '\n') 343: fputc(fgetc(tmpf), f); 344: } 345: 346: isfrom(lp) 347: register char *lp; 348: { 349: register char *p; 350: 351: for (p = from; *p; ) 352: if (*lp++ != *p++) 353: return(0); 354: return(1); 355: } 356: 357: sendmail(argc, argv) 358: char **argv; 359: { 360: 361: time(&iop); 362: fprintf(tmpf, "%s%s %s", from, my_name, ctime(&iop)); 363: iop = ftell(tmpf); 364: flgf = 1; 365: while (fgets(line, LSIZE, stdin) != NULL) { 366: if (line[0] == '.' && line[1] == '\n') 367: break; 368: if (isfrom(line)) 369: fputs(">", tmpf); 370: fputs(line, tmpf); 371: flgf = 0; 372: } 373: fputs("\n", tmpf); 374: nlet = 1; 375: let[0].adr = 0; 376: let[1].adr = ftell(tmpf); 377: fclose(tmpf); 378: if (flgf) 379: return; 380: tmpf = fopen(lettmp, "r"); 381: if (tmpf == NULL) { 382: fprintf(stderr, "mail: cannot reopen %s for reading\n", lettmp); 383: return; 384: } 385: while (--argc > 0) 386: if (!send(0, *++argv)) /* couldn't send to him */ 387: error++; 388: if (error) { 389: setuid(getuid()); 390: malf = fopen(dead, "w"); 391: if (malf == NULL) { 392: fprintf(stdout, "mail: cannot open %s\n", dead); 393: fclose(tmpf); 394: return; 395: } 396: copylet(0, malf, ZAP); 397: fclose(malf); 398: fprintf(stdout, "Mail saved in %s\n", dead); 399: } 400: fclose(tmpf); 401: } 402: 403: sendrmt(n, name) 404: char *name; 405: { 406: FILE *rmf, *popen(); 407: register char *p; 408: char rsys[64], cmd[64]; 409: register local, pid; 410: int sts; 411: 412: local = 0; 413: if (*name=='!') 414: name++; 415: for(p=rsys; *name!='!'; *p++ = *name++) 416: if (*name=='\0') { 417: local++; 418: break; 419: } 420: *p = '\0'; 421: if ((!local && *name=='\0') || (local && *rsys=='\0')) { 422: fprintf(stdout, "null name\n"); 423: return(0); 424: } 425: if ((pid = fork()) == -1) { 426: fprintf(stderr, "mail: can't create proc for remote\n"); 427: return(0); 428: } 429: if (pid) { 430: while (wait(&sts) != pid) { 431: if (wait(&sts)==-1) 432: return(0); 433: } 434: return(!sts); 435: } 436: setuid(getuid()); 437: if (local) 438: sprintf(cmd, "mail %s", rsys); 439: else { 440: if (index(name+1, '!')) 441: sprintf(cmd, "uux - %s!rmail \\(%s\\)", rsys, name+1); 442: else 443: sprintf(cmd, "uux - %s!rmail %s", rsys, name+1); 444: } 445: if ((rmf=popen(cmd, "w")) == NULL) 446: exit(1); 447: copylet(n, rmf, local? FORWARD: REMOTE); 448: pclose(rmf); 449: exit(0); 450: } 451: 452: send(n, name) /* send letter n to name */ 453: int n; 454: char *name; 455: { 456: char file[50]; 457: register char *p; 458: register mask; 459: struct passwd *pw, *getpwnam(); 460: 461: for(p=name; *p!='!' &&*p!='\0'; p++) 462: ; 463: if (*p == '!') 464: return(sendrmt(n, name)); 465: if ((pw = getpwnam(name)) == NULL) { 466: fprintf(stdout, "mail: can't send to %s\n", name); 467: return(0); 468: } 469: cat(file, maildir, name); 470: mask = umask(MAILMODE); 471: malf = fopen(file, "a"); 472: umask(mask); 473: if (malf == NULL) { 474: fprintf(stdout, "mail: cannot append to %s\n", file); 475: return(0); 476: } 477: lock(file); 478: chown(file, pw->pw_uid, pw->pw_gid); 479: copylet(n, malf, ORDINARY); 480: fclose(malf); 481: unlock(); 482: return(1); 483: } 484: 485: delete(i) 486: { 487: setsig(i, delete); 488: fprintf(stderr, "\n"); 489: if(delflg) 490: longjmp(sjbuf, 1); 491: done(); 492: } 493: 494: done() 495: { 496: if(!lockerror) 497: unlock(); 498: unlink(lettmp); 499: exit(error+lockerror); 500: } 501: 502: lock(file) 503: char *file; 504: { 505: struct stat stbuf; 506: 507: if (locked || flgf) 508: return; 509: if (stat(file, &stbuf)<0) 510: return; 511: if (stbuf.st_mode&01) { /* user x bit is the lock */ 512: if (stbuf.st_ctime+60 >= time((long *)0)) { 513: fprintf(stderr, "%s busy; try again in a minute\n", file); 514: lockerror++; 515: done(); 516: } 517: } 518: locked = stbuf.st_mode & ~01; 519: curlock = file; 520: chmod(file, stbuf.st_mode|01); 521: } 522: 523: unlock() 524: { 525: if (locked) 526: chmod(curlock, locked); 527: locked = 0; 528: } 529: 530: cat(to, from1, from2) 531: char *to, *from1, *from2; 532: { 533: int i, j; 534: 535: j = 0; 536: for (i=0; from1[i]; i++) 537: to[j++] = from1[i]; 538: for (i=0; from2[i]; i++) 539: to[j++] = from2[i]; 540: to[j] = 0; 541: } 542: 543: char *getarg(s, p) /* copy p... into s, update p */ 544: register char *s, *p; 545: { 546: while (*p == ' ' || *p == '\t') 547: p++; 548: if (*p == '\n' || *p == '\0') 549: return(NULL); 550: while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 551: *s++ = *p++; 552: *s = '\0'; 553: return(p); 554: }