1: /* 2: ** Vacation 3: ** Copyright (c) 1983 Eric P. Allman 4: ** Berkeley, California 5: ** 6: ** Copyright (c) 1983 Regents of the University of California. 7: ** All rights reserved. The Berkeley software License Agreement 8: ** specifies the terms and conditions for redistribution. 9: */ 10: 11: #ifndef lint 12: static char SccsId[] = "@(#)vacation.c 5.3 (Berkeley) 7/1/85"; 13: #endif not lint 14: 15: # include <sys/types.h> 16: # include <pwd.h> 17: # include <stdio.h> 18: # include <sysexits.h> 19: # include <ctype.h> 20: 21: /* 22: ** VACATION -- return a message to the sender when on vacation. 23: ** 24: ** This program could be invoked as a message receiver 25: ** when someone is on vacation. It returns a message 26: ** specified by the user to whoever sent the mail, taking 27: ** care not to return a message too often to prevent 28: ** "I am on vacation" loops. 29: ** 30: ** Positional Parameters: 31: ** the user to collect the vacation message from. 32: ** 33: ** Flag Parameters: 34: ** -I initialize the database. 35: ** -d turn on debugging. 36: ** 37: ** Side Effects: 38: ** A message is sent back to the sender. 39: ** 40: ** Author: 41: ** Eric Allman 42: ** UCB/INGRES 43: */ 44: 45: typedef int bool; 46: 47: # define TRUE 1 48: # define FALSE 0 49: 50: # define MAXLINE 256 /* max size of a line */ 51: # define MAXNAME 128 /* max size of one name */ 52: 53: # define ONEWEEK (60L*60L*24L*7L) 54: 55: time_t Timeout = ONEWEEK; /* timeout between notices per user */ 56: 57: struct dbrec 58: { 59: long sentdate; 60: }; 61: 62: typedef struct 63: { 64: char *dptr; 65: int dsize; 66: } DATUM; 67: 68: extern DATUM fetch(); 69: 70: 71: 72: bool Debug = FALSE; 73: 74: main(argc, argv) 75: char **argv; 76: { 77: char *from; 78: register char *p; 79: struct passwd *pw; 80: char *homedir; 81: char *myname; 82: char buf[MAXLINE]; 83: extern struct passwd *getpwnam(); 84: extern char *newstr(); 85: extern char *getfrom(); 86: extern bool knows(); 87: extern bool junkmail(); 88: extern time_t convtime(); 89: 90: /* process arguments */ 91: while (--argc > 0 && (p = *++argv) != NULL && *p == '-') 92: { 93: switch (*++p) 94: { 95: case 'I': /* initialize */ 96: initialize(); 97: exit(EX_OK); 98: 99: case 'd': /* debug */ 100: Debug = TRUE; 101: break; 102: 103: default: 104: usrerr("Unknown flag -%s", p); 105: exit(EX_USAGE); 106: } 107: } 108: 109: /* verify recipient argument */ 110: if (argc != 1) 111: { 112: usrerr("Usage: vacation username (or) vacation -I"); 113: exit(EX_USAGE); 114: } 115: 116: myname = p; 117: 118: /* find user's home directory */ 119: pw = getpwnam(myname); 120: if (pw == NULL) 121: { 122: usrerr("Unknown user %s", myname); 123: exit(EX_NOUSER); 124: } 125: homedir = newstr(pw->pw_dir); 126: (void) strcpy(buf, homedir); 127: (void) strcat(buf, "/.vacation"); 128: dbminit(buf); 129: 130: /* read message from standard input (just from line) */ 131: from = getfrom(); 132: 133: /* check if junk mail or this person is already informed */ 134: if (!junkmail(from) && !knows(from)) 135: { 136: /* mark this person as knowing */ 137: setknows(from); 138: 139: /* send the message back */ 140: (void) strcpy(buf, homedir); 141: (void) strcat(buf, "/.vacation.msg"); 142: if (Debug) 143: printf("Sending %s to %s\n", buf, from); 144: else 145: { 146: sendmessage(buf, from, myname); 147: /*NOTREACHED*/ 148: } 149: } 150: exit (EX_OK); 151: } 152: /* 153: ** GETFROM -- read message from standard input and return sender 154: ** 155: ** Parameters: 156: ** none. 157: ** 158: ** Returns: 159: ** pointer to the sender address. 160: ** 161: ** Side Effects: 162: ** Reads first line from standard input. 163: */ 164: 165: char * 166: getfrom() 167: { 168: static char line[MAXLINE]; 169: register char *p; 170: extern char *index(); 171: 172: /* read the from line */ 173: if (fgets(line, sizeof line, stdin) == NULL || 174: strncmp(line, "From ", 5) != NULL) 175: { 176: usrerr("No initial From line"); 177: exit(EX_USAGE); 178: } 179: 180: /* find the end of the sender address and terminate it */ 181: p = index(&line[5], ' '); 182: if (p == NULL) 183: { 184: usrerr("Funny From line '%s'", line); 185: exit(EX_USAGE); 186: } 187: *p = '\0'; 188: 189: /* return the sender address */ 190: return (&line[5]); 191: } 192: /* 193: ** JUNKMAIL -- read the header and tell us if this is junk/bulk mail. 194: ** 195: ** Parameters: 196: ** from -- the Return-Path of the sender. We assume that 197: ** anything from "*-REQUEST@*" is bulk mail. 198: ** 199: ** Returns: 200: ** TRUE -- if this is junk or bulk mail (that is, if the 201: ** sender shouldn't receive a response). 202: ** FALSE -- if the sender deserves a response. 203: ** 204: ** Side Effects: 205: ** May read the header from standard input. When this 206: ** returns the position on stdin is undefined. 207: */ 208: 209: bool 210: junkmail(from) 211: char *from; 212: { 213: register char *p; 214: char buf[MAXLINE+1]; 215: extern char *index(); 216: extern char *rindex(); 217: extern bool sameword(); 218: 219: /* test for inhuman sender */ 220: p = rindex(from, '@'); 221: if (p != NULL) 222: { 223: *p = '\0'; 224: if (sameword(&p[-8], "-REQUEST") || 225: sameword(&p[-10], "Postmaster") || 226: sameword(&p[-13], "MAILER-DAEMON")) 227: { 228: *p = '@'; 229: return (TRUE); 230: } 231: *p = '@'; 232: } 233: 234: /* read the header looking for a "Precedence:" line */ 235: while (fgets(buf, MAXLINE, stdin) != NULL && buf[0] != '\n') 236: { 237: /* should ignore case, but this is reasonably safe */ 238: if (strncmp(buf, "Precedence", 10) != 0 || 239: !(buf[10] == ':' || buf[10] == ' ' || buf[10] == '\t')) 240: { 241: continue; 242: } 243: 244: /* find the value of this field */ 245: p = index(buf, ':'); 246: if (p == NULL) 247: continue; 248: while (*++p != '\0' && isspace(*p)) 249: continue; 250: if (*p == '\0') 251: continue; 252: 253: /* see if it is "junk" or "bulk" */ 254: p[4] = '\0'; 255: if (sameword(p, "junk") || sameword(p, "bulk")) 256: return (TRUE); 257: } 258: return (FALSE); 259: } 260: /* 261: ** KNOWS -- predicate telling if user has already been informed. 262: ** 263: ** Parameters: 264: ** user -- the user who sent this message. 265: ** 266: ** Returns: 267: ** TRUE if 'user' has already been informed that the 268: ** recipient is on vacation. 269: ** FALSE otherwise. 270: ** 271: ** Side Effects: 272: ** none. 273: */ 274: 275: bool 276: knows(user) 277: char *user; 278: { 279: DATUM k, d; 280: long now; 281: auto long then; 282: 283: time(&now); 284: k.dptr = user; 285: k.dsize = strlen(user) + 1; 286: d = fetch(k); 287: if (d.dptr == NULL) 288: return (FALSE); 289: 290: /* be careful on 68k's and others with alignment restrictions */ 291: bcopy((char *) &((struct dbrec *) d.dptr)->sentdate, (char *) &then, sizeof then); 292: if (then + Timeout < now) 293: return (FALSE); 294: return (TRUE); 295: } 296: /* 297: ** SETKNOWS -- set that this user knows about the vacation. 298: ** 299: ** Parameters: 300: ** user -- the user who should be marked. 301: ** 302: ** Returns: 303: ** none. 304: ** 305: ** Side Effects: 306: ** The dbm file is updated as appropriate. 307: */ 308: 309: setknows(user) 310: char *user; 311: { 312: DATUM k, d; 313: struct dbrec xrec; 314: 315: k.dptr = user; 316: k.dsize = strlen(user) + 1; 317: time(&xrec.sentdate); 318: d.dptr = (char *) &xrec; 319: d.dsize = sizeof xrec; 320: store(k, d); 321: } 322: /* 323: ** SENDMESSAGE -- send a message to a particular user. 324: ** 325: ** Parameters: 326: ** msgf -- filename containing the message. 327: ** user -- user who should receive it. 328: ** 329: ** Returns: 330: ** none. 331: ** 332: ** Side Effects: 333: ** sends mail to 'user' using /usr/lib/sendmail. 334: */ 335: 336: sendmessage(msgf, user, myname) 337: char *msgf; 338: char *user; 339: char *myname; 340: { 341: FILE *f; 342: 343: /* find the message to send */ 344: f = freopen(msgf, "r", stdin); 345: if (f == NULL) 346: { 347: f = freopen("/usr/lib/vacation.def", "r", stdin); 348: if (f == NULL) 349: syserr("No message to send"); 350: } 351: 352: execl("/usr/lib/sendmail", "sendmail", "-f", myname, user, NULL); 353: syserr("Cannot exec /usr/lib/sendmail"); 354: } 355: /* 356: ** INITIALIZE -- initialize the database before leaving for vacation 357: ** 358: ** Parameters: 359: ** none. 360: ** 361: ** Returns: 362: ** none. 363: ** 364: ** Side Effects: 365: ** Initializes the files .vacation.{pag,dir} in the 366: ** caller's home directory. 367: */ 368: 369: initialize() 370: { 371: char *homedir; 372: char buf[MAXLINE]; 373: extern char *getenv(); 374: 375: setgid(getgid()); 376: setuid(getuid()); 377: homedir = getenv("HOME"); 378: if (homedir == NULL) 379: syserr("No home!"); 380: (void) strcpy(buf, homedir); 381: (void) strcat(buf, "/.vacation.dir"); 382: if (close(creat(buf, 0644)) < 0) 383: syserr("Cannot create %s", buf); 384: (void) strcpy(buf, homedir); 385: (void) strcat(buf, "/.vacation.pag"); 386: if (close(creat(buf, 0644)) < 0) 387: syserr("Cannot create %s", buf); 388: } 389: /* 390: ** USRERR -- print user error 391: ** 392: ** Parameters: 393: ** f -- format. 394: ** p -- first parameter. 395: ** 396: ** Returns: 397: ** none. 398: ** 399: ** Side Effects: 400: ** none. 401: */ 402: 403: usrerr(f, p) 404: char *f; 405: char *p; 406: { 407: fprintf(stderr, "vacation: "); 408: _doprnt(f, &p, stderr); 409: fprintf(stderr, "\n"); 410: } 411: /* 412: ** SYSERR -- print system error 413: ** 414: ** Parameters: 415: ** f -- format. 416: ** p -- first parameter. 417: ** 418: ** Returns: 419: ** none. 420: ** 421: ** Side Effects: 422: ** none. 423: */ 424: 425: syserr(f, p) 426: char *f; 427: char *p; 428: { 429: fprintf(stderr, "vacation: "); 430: _doprnt(f, &p, stderr); 431: fprintf(stderr, "\n"); 432: exit(EX_USAGE); 433: } 434: /* 435: ** NEWSTR -- copy a string 436: ** 437: ** Parameters: 438: ** s -- the string to copy. 439: ** 440: ** Returns: 441: ** A copy of the string. 442: ** 443: ** Side Effects: 444: ** none. 445: */ 446: 447: char * 448: newstr(s) 449: char *s; 450: { 451: char *p; 452: extern char *malloc(); 453: 454: p = malloc(strlen(s) + 1); 455: if (p == NULL) 456: { 457: syserr("newstr: cannot alloc memory"); 458: exit(EX_OSERR); 459: } 460: strcpy(p, s); 461: return (p); 462: } 463: /* 464: ** SAMEWORD -- return TRUE if the words are the same 465: ** 466: ** Ignores case. 467: ** 468: ** Parameters: 469: ** a, b -- the words to compare. 470: ** 471: ** Returns: 472: ** TRUE if a & b match exactly (modulo case) 473: ** FALSE otherwise. 474: ** 475: ** Side Effects: 476: ** none. 477: */ 478: 479: bool 480: sameword(a, b) 481: register char *a, *b; 482: { 483: char ca, cb; 484: 485: do 486: { 487: ca = *a++; 488: cb = *b++; 489: if (isascii(ca) && isupper(ca)) 490: ca = ca - 'A' + 'a'; 491: if (isascii(cb) && isupper(cb)) 492: cb = cb - 'A' + 'a'; 493: } while (ca != '\0' && ca == cb); 494: return (ca == cb); 495: }