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 3.9 01/23/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 } 358