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.7 05/31/82); 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 long 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 long 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, buf); 115 116 /* send the message back */ 117 (void) strcat(buf, ".msg"); 118 sendmessage(buf, from, myname); 119 /* never returns */ 120 } 121 exit (EX_OK); 122 } 123 /* 124 ** GETFROM -- read message from standard input and return sender 125 ** 126 ** Parameters: 127 ** none. 128 ** 129 ** Returns: 130 ** pointer to the sender address. 131 ** 132 ** Side Effects: 133 ** Reads first line from standard input. 134 */ 135 136 char * 137 getfrom() 138 { 139 static char line[MAXLINE]; 140 register char *p; 141 142 /* read the from line */ 143 if (fgets(line, sizeof line, stdin) == NULL || 144 strncmp(line, "From ", 5) != NULL) 145 { 146 usrerr("No initial From line"); 147 exit(EX_USAGE); 148 } 149 150 /* find the end of the sender address and terminate it */ 151 p = index(&line[5], ' '); 152 if (p == NULL) 153 { 154 usrerr("Funny From line '%s'", line); 155 exit(EX_USAGE); 156 } 157 *p = '\0'; 158 159 /* return the sender address */ 160 return (&line[5]); 161 } 162 /* 163 ** KNOWS -- predicate telling if user has already been informed. 164 ** 165 ** Parameters: 166 ** user -- the user who sent this message. 167 ** 168 ** Returns: 169 ** TRUE if 'user' has already been informed that the 170 ** recipient is on vacation. 171 ** FALSE otherwise. 172 ** 173 ** Side Effects: 174 ** none. 175 */ 176 177 bool 178 knows(user) 179 char *user; 180 { 181 DATUM k, d; 182 long now; 183 184 time(&now); 185 k.dptr = user; 186 k.dsize = strlen(user) + 1; 187 d = fetch(k); 188 if (d.dptr == NULL || ((struct dbrec *) d.dptr)->sentdate + Timeout < now) 189 return (FALSE); 190 return (TRUE); 191 } 192 /* 193 ** SETKNOWS -- set that this user knows about the vacation. 194 ** 195 ** Parameters: 196 ** user -- the user who should be marked. 197 ** 198 ** Returns: 199 ** none. 200 ** 201 ** Side Effects: 202 ** The dbm file is updated as appropriate. 203 */ 204 205 setknows(user) 206 char *user; 207 { 208 register int i; 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, "-n", 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