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