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: }

Defined functions

cat defined in line 530; used 3 times
copyback defined in line 266; used 1 times
copylet defined in line 328; used 6 times
copymt defined in line 312; used 1 times
delete defined in line 485; used 3 times
done defined in line 494; used 8 times
getarg defined in line 543; used 3 times
isfrom defined in line 346; used 2 times
lock defined in line 502; used 3 times
main defined in line 56; never used
printmail defined in line 98; used 1 times
  • in line 84
send defined in line 452; used 1 times
sendmail defined in line 357; used 1 times
  • in line 86
sendrmt defined in line 403; used 2 times
setsig defined in line 90; used 2 times
unlock defined in line 523; used 4 times

Defined variables

changed defined in line 45; used 6 times
curlock defined in line 36; used 2 times
dead defined in line 33; used 3 times
delflg defined in line 53; used 3 times
error defined in line 43; used 3 times
flgf defined in line 51; used 4 times
flgp defined in line 52; used 2 times
forward defined in line 46; used 2 times
forwmsg defined in line 35; used 1 times
from defined in line 47; used 2 times
iop defined in line 29; used 3 times
let defined in line 26; used 16 times
lettmp defined in line 30; used 10 times
lfil defined in line 28; used 6 times
line defined in line 21; used 9 times
locked defined in line 44; used 5 times
lockerror defined in line 37; used 3 times
maildir defined in line 31; used 2 times
mailfile defined in line 32; used 9 times
my_name defined in line 40; used 6 times
nlet defined in line 27; used 11 times
resp defined in line 22; used 15 times
sjbuf defined in line 54; used 4 times
thissys defined in line 34; used 1 times

Defined struct's

let defined in line 23; never used

Defined macros

FORWARD defined in line 16; used 2 times
LSIZE defined in line 17; used 5 times
MAILMODE defined in line 19; used 1 times
MAXLET defined in line 18; used 1 times
  • in line 26
ORDINARY defined in line 15; used 5 times
REMOTE defined in line 12; used 2 times
ZAP defined in line 14; used 4 times
Last modified: 1979-05-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1679
Valid CSS Valid XHTML 1.0 Strict