1: # include <pwd.h> 2: # include <stdio.h> 3: # include <sysexits.h> 4: # include <ctype.h> 5: # include "useful.h" 6: # include "userdbm.h" 7: 8: SCCSID(@(#)vacation.c 4.1 7/25/83); 9: 10: /* 11: ** VACATION -- return a message to the sender when on vacation. 12: ** 13: ** This program could be invoked as a message receiver 14: ** when someone is on vacation. It returns a message 15: ** specified by the user to whoever sent the mail, taking 16: ** care not to return a message too often to prevent 17: ** "I am on vacation" loops. 18: ** 19: ** For best operation, this program should run setuid to 20: ** root or uucp or someone else that sendmail will believe 21: ** a -f flag from. Otherwise, the user must be careful 22: ** to include a header on his .vacation.msg file. 23: ** 24: ** Positional Parameters: 25: ** the user to collect the vacation message from. 26: ** 27: ** Flag Parameters: 28: ** -I initialize the database. 29: ** -tT set the timeout to T. messages arriving more 30: ** often than T will be ignored to avoid loops. 31: ** 32: ** Side Effects: 33: ** A message is sent back to the sender. 34: ** 35: ** Author: 36: ** Eric Allman 37: ** UCB/INGRES 38: */ 39: 40: # define MAXLINE 256 /* max size of a line */ 41: # define MAXNAME 128 /* max size of one name */ 42: 43: # define ONEWEEK (60L*60L*24L*7L) 44: 45: time_t Timeout = ONEWEEK; /* timeout between notices per user */ 46: 47: struct dbrec 48: { 49: long sentdate; 50: }; 51: 52: main(argc, argv) 53: char **argv; 54: { 55: char *from; 56: register char *p; 57: struct passwd *pw; 58: char *homedir; 59: char *myname; 60: char buf[MAXLINE]; 61: extern struct passwd *getpwnam(); 62: extern char *newstr(); 63: extern char *getfrom(); 64: extern bool knows(); 65: extern time_t convtime(); 66: 67: /* process arguments */ 68: while (--argc > 0 && (p = *++argv) != NULL && *p == '-') 69: { 70: switch (*++p) 71: { 72: case 'I': /* initialize */ 73: initialize(); 74: exit(EX_OK); 75: 76: case 't': /* set timeout */ 77: Timeout = convtime(++p); 78: break; 79: 80: default: 81: usrerr("Unknown flag -%s", p); 82: exit(EX_USAGE); 83: } 84: } 85: 86: /* verify recipient argument */ 87: if (argc != 1) 88: { 89: usrerr("Usage: vacation username (or) vacation -I"); 90: exit(EX_USAGE); 91: } 92: 93: myname = p; 94: 95: /* find user's home directory */ 96: pw = getpwnam(myname); 97: if (pw == NULL) 98: { 99: usrerr("Unknown user %s", myname); 100: exit(EX_NOUSER); 101: } 102: homedir = newstr(pw->pw_dir); 103: (void) strcpy(buf, homedir); 104: (void) strcat(buf, "/.vacation"); 105: dbminit(buf); 106: 107: /* read message from standard input (just from line) */ 108: from = getfrom(); 109: 110: /* check if this person is already informed */ 111: if (!knows(from)) 112: { 113: /* mark this person as knowing */ 114: setknows(from); 115: 116: /* send the message back */ 117: (void) strcpy(buf, homedir); 118: (void) strcat(buf, "/.vacation.msg"); 119: sendmessage(buf, from, myname); 120: /* never returns */ 121: } 122: exit (EX_OK); 123: } 124: /* 125: ** GETFROM -- read message from standard input and return sender 126: ** 127: ** Parameters: 128: ** none. 129: ** 130: ** Returns: 131: ** pointer to the sender address. 132: ** 133: ** Side Effects: 134: ** Reads first line from standard input. 135: */ 136: 137: char * 138: getfrom() 139: { 140: static char line[MAXLINE]; 141: register char *p; 142: 143: /* read the from line */ 144: if (fgets(line, sizeof line, stdin) == NULL || 145: strncmp(line, "From ", 5) != NULL) 146: { 147: usrerr("No initial From line"); 148: exit(EX_USAGE); 149: } 150: 151: /* find the end of the sender address and terminate it */ 152: p = index(&line[5], ' '); 153: if (p == NULL) 154: { 155: usrerr("Funny From line '%s'", line); 156: exit(EX_USAGE); 157: } 158: *p = '\0'; 159: 160: /* return the sender address */ 161: return (&line[5]); 162: } 163: /* 164: ** KNOWS -- predicate telling if user has already been informed. 165: ** 166: ** Parameters: 167: ** user -- the user who sent this message. 168: ** 169: ** Returns: 170: ** TRUE if 'user' has already been informed that the 171: ** recipient is on vacation. 172: ** FALSE otherwise. 173: ** 174: ** Side Effects: 175: ** none. 176: */ 177: 178: bool 179: knows(user) 180: char *user; 181: { 182: DATUM k, d; 183: long now; 184: 185: time(&now); 186: k.dptr = user; 187: k.dsize = strlen(user) + 1; 188: d = fetch(k); 189: if (d.dptr == NULL || ((struct dbrec *) d.dptr)->sentdate + Timeout < now) 190: return (FALSE); 191: return (TRUE); 192: } 193: /* 194: ** SETKNOWS -- set that this user knows about the vacation. 195: ** 196: ** Parameters: 197: ** user -- the user who should be marked. 198: ** 199: ** Returns: 200: ** none. 201: ** 202: ** Side Effects: 203: ** The dbm file is updated as appropriate. 204: */ 205: 206: setknows(user) 207: char *user; 208: { 209: DATUM k, d; 210: struct dbrec xrec; 211: 212: k.dptr = user; 213: k.dsize = strlen(user) + 1; 214: time(&xrec.sentdate); 215: d.dptr = (char *) &xrec; 216: d.dsize = sizeof xrec; 217: store(k, d); 218: } 219: /* 220: ** SENDMESSAGE -- send a message to a particular user. 221: ** 222: ** Parameters: 223: ** msgf -- filename containing the message. 224: ** user -- user who should receive it. 225: ** 226: ** Returns: 227: ** none. 228: ** 229: ** Side Effects: 230: ** sends mail to 'user' using /usr/lib/sendmail. 231: */ 232: 233: sendmessage(msgf, user, myname) 234: char *msgf; 235: char *user; 236: char *myname; 237: { 238: FILE *f; 239: 240: /* find the message to send */ 241: f = freopen(msgf, "r", stdin); 242: if (f == NULL) 243: { 244: f = freopen("/usr/lib/vacation.def", "r", stdin); 245: if (f == NULL) 246: syserr("No message to send"); 247: } 248: 249: execl("/usr/lib/sendmail", "sendmail", "-f", myname, user, NULL); 250: syserr("Cannot exec /usr/lib/sendmail"); 251: } 252: /* 253: ** INITIALIZE -- initialize the database before leaving for vacation 254: ** 255: ** Parameters: 256: ** none. 257: ** 258: ** Returns: 259: ** none. 260: ** 261: ** Side Effects: 262: ** Initializes the files .vacation.{pag,dir} in the 263: ** caller's home directory. 264: */ 265: 266: initialize() 267: { 268: char *homedir; 269: char buf[MAXLINE]; 270: 271: setgid(getgid()); 272: setuid(getuid()); 273: homedir = getenv("HOME"); 274: if (homedir == NULL) 275: syserr("No home!"); 276: (void) strcpy(buf, homedir); 277: (void) strcat(buf, "/.vacation.dir"); 278: if (close(creat(buf, 0644)) < 0) 279: syserr("Cannot create %s", buf); 280: (void) strcpy(buf, homedir); 281: (void) strcat(buf, "/.vacation.pag"); 282: if (close(creat(buf, 0644)) < 0) 283: syserr("Cannot create %s", buf); 284: } 285: /* 286: ** USRERR -- print user error 287: ** 288: ** Parameters: 289: ** f -- format. 290: ** p -- first parameter. 291: ** 292: ** Returns: 293: ** none. 294: ** 295: ** Side Effects: 296: ** none. 297: */ 298: 299: usrerr(f, p) 300: char *f; 301: char *p; 302: { 303: fprintf(stderr, "vacation: "); 304: _doprnt(f, &p, stderr); 305: fprintf(stderr, "\n"); 306: } 307: /* 308: ** SYSERR -- print system error 309: ** 310: ** Parameters: 311: ** f -- format. 312: ** p -- first parameter. 313: ** 314: ** Returns: 315: ** none. 316: ** 317: ** Side Effects: 318: ** none. 319: */ 320: 321: syserr(f, p) 322: char *f; 323: char *p; 324: { 325: fprintf(stderr, "vacation: "); 326: _doprnt(f, &p, stderr); 327: fprintf(stderr, "\n"); 328: exit(EX_USAGE); 329: } 330: /* 331: ** NEWSTR -- copy a string 332: ** 333: ** Parameters: 334: ** s -- the string to copy. 335: ** 336: ** Returns: 337: ** A copy of the string. 338: ** 339: ** Side Effects: 340: ** none. 341: */ 342: 343: char * 344: newstr(s) 345: char *s; 346: { 347: char *p; 348: 349: p = malloc(strlen(s) + 1); 350: if (p == NULL) 351: { 352: syserr("newstr: cannot alloc memory"); 353: exit(EX_OSERR); 354: } 355: strcpy(p, s); 356: return (p); 357: }