source: trunk/athena/lib/zephyr/clients/zmailnotify/zmailnotify.c @ 10621

Revision 10621, 12.6 KB checked in by ghudson, 27 years ago (diff)
ZEPHYR_USES_KERBEROS -> HAVE_KRB4; ZEPHYR_USES_HESIOD -> HAVE_HESIOD
Line 
1/* This file is part of the Project Athena Zephyr Notification System.
2 * It contains code for the "zmailnotify" command.
3 *
4 *      Created by:     Robert French
5 *
6 *      $Id: zmailnotify.c,v 1.25 1997-10-25 21:47:11 ghudson Exp $
7 *
8 *      Copyright (c) 1987,1993 by the Massachusetts Institute of Technology.
9 *      For copying and distribution information, see the file
10 *      "mit-copyright.h".
11 */
12
13#include <sysdep.h>
14#include <zephyr/mit-copyright.h>
15#include <zephyr/zephyr.h>
16
17#ifndef lint
18static const char rcsid_zmailnotify_c[] =
19    "$Id: zmailnotify.c,v 1.25 1997-10-25 21:47:11 ghudson Exp $";
20#endif
21
22#include <sys/socket.h>
23#include <pwd.h>
24#include <netdb.h>
25#ifdef HAVE_HESIOD
26#include <hesiod.h>
27#endif
28
29#ifndef HAVE_KRB4
30#undef KPOP
31#endif
32
33#ifdef KPOP
34#include <krb.h>
35#endif
36
37#define NOTOK (-1)
38#define OK 0
39#define DONE 1
40
41FILE *sfi;
42FILE *sfo;
43char Errmsg[80];
44
45#ifdef KPOP
46char *PrincipalHostname();
47#endif
48
49void get_message(), pop_close(), mail_notify(), fatal_pop_err ();
50int pop_command __P((char *, ...));
51#define MAXMAIL 4
52
53struct _mail {
54        char *from;
55        char *to;
56        char *subj;
57} maillist[MAXMAIL];
58
59char *mailptr = NULL;
60char *prog = "zmailnotify";
61
62/* This entire program is a kludge - beware! */
63
64main(argc, argv)
65    char *argv[];
66{
67    FILE *lock;
68    int nmsgs;
69    char *user,response[512],lockfile[100];
70    char *host,*dir;
71    char *auth_cmd;
72    int i,nbytes,retval,uselock;
73    struct passwd *pwd;
74    struct _mail mymail;
75#ifdef HAVE_HESIOD
76    struct hes_postoffice *p;
77#endif
78
79    if (argv[0] && *argv[0])
80        prog = argv[0];
81       
82    if ((retval = ZInitialize()) != ZERR_NONE) {
83        com_err(prog,retval,"while initializing");
84        exit(1);
85    }
86
87    dir = (char *)getenv("HOME");
88    user = (char *)getenv("USER");
89    if (!user || !dir) {
90        pwd = (struct passwd *)getpwuid((int) getuid());
91        if (!pwd) {
92            fprintf(stderr,"%s: Can't figure out who you are!\n",
93                    prog);
94            exit(1);
95        }
96        if (!user)
97            user = pwd->pw_name;
98        if (!dir)
99            dir = pwd->pw_dir;
100    }
101    if (argc > 1)
102        user = argv[1];
103
104    (void) sprintf(lockfile,"%s/.maillock",dir);
105       
106    host = (char *)getenv("MAILHOST");
107#ifdef HAVE_HESIOD
108    if (host == NULL) {
109        p = hes_getmailhost(user);
110        if (p != NULL && strcmp(p->po_type, "POP") == 0)
111            host = p->po_host;
112        else {
113            fprintf(stderr,
114                    "%s: no POP server listed in Hesiod for %s\n",
115                    prog, user);
116            exit(1);
117        }
118    }
119#endif
120    if (host == NULL) {
121        fprintf(stderr,"%s: no MAILHOST defined\n", prog);
122        exit(1);
123    }
124
125    lock = fopen(lockfile,"r+");
126#ifdef _POSIX_VERSION
127    if (lock) {
128        struct flock fl;
129
130        /* lock the whole file exclusively */
131        fl.l_type = F_WRLCK;
132        fl.l_whence = SEEK_SET;
133        fl.l_start = 0;
134        fl.l_len = 0;
135        (void) fcntl(fileno(lock),F_SETLKW,&fl);
136    }
137#else
138    if (lock)
139        (void) flock(fileno(lock),LOCK_EX);
140#endif
141
142    if (pop_init(host) == NOTOK) {
143        fprintf(stderr,"%s: %s\n",prog, Errmsg);
144        exit(1);
145    }
146
147    if ((getline(response, sizeof response, sfi) != OK) ||
148        (*response != '+')) {
149        fprintf(stderr,"%s: %s\n",prog,response);
150        exit(1);
151    }
152
153#ifdef KPOP
154    auth_cmd = "PASS %s";
155#else
156    auth_cmd = "RPOP %s";
157#endif
158    if (pop_command("USER %s", user) == NOTOK
159        || pop_command(auth_cmd, user) == NOTOK)
160        fatal_pop_err ();
161
162    if (pop_stat(&nmsgs, &nbytes) == NOTOK)
163        fatal_pop_err ();
164
165    if (!nmsgs) {
166        if (lock) {
167#ifdef _POSIX_VERSION
168            struct flock fl;
169
170            /* unlock the whole file */
171            fl.l_type = F_UNLCK;
172            fl.l_whence = SEEK_SET;
173            fl.l_start = 0;
174            fl.l_len = 0;
175            (void) fcntl(fileno(lock),F_SETLKW,&fl);
176#else
177            (void) flock(fileno(lock),LOCK_UN);
178#endif
179            (void) fclose(lock);
180        }
181        (void) unlink(lockfile);
182        (void) pop_command("QUIT");
183        pop_close();
184        exit (0);
185    }
186
187    uselock = 0;
188    if (lock) {
189        uselock = 1;
190        mymail.to = (char *)malloc(BUFSIZ);
191        mymail.from = (char *)malloc(BUFSIZ);
192        mymail.subj = (char *)malloc(BUFSIZ);
193        if (fgets(mymail.from,BUFSIZ,lock) != NULL)
194            mymail.from[strlen(mymail.from)-1] = 0;
195        else
196            mymail.from[0]=0;
197        if (fgets(mymail.to,BUFSIZ,lock) != NULL)
198            mymail.to[strlen(mymail.to)-1] = 0;
199        else
200            mymail.to[0] = 0;
201        if (fgets(mymail.subj,BUFSIZ,lock) != NULL)
202            mymail.subj[strlen(mymail.subj)-1] = 0;
203        else
204            mymail.subj[0] = 0;
205    }
206    else {
207        lock = fopen(lockfile,"w");
208#ifdef _POSIX_VERSION
209        if (lock) {
210            struct flock fl;
211
212            /* lock the whole file exclusively */
213            fl.l_type = F_WRLCK;
214            fl.l_whence = SEEK_SET;
215            fl.l_start = 0;
216            fl.l_len = 0;
217            (void) fcntl(fileno(lock),F_SETLKW,&fl);
218        }
219#else
220        if (lock)
221            (void) flock(fileno(lock),LOCK_EX);
222#endif
223        uselock = 0;
224    }
225       
226    for (i=nmsgs;i>0;i--) {
227        if (nmsgs-i == MAXMAIL)
228            break;
229        if (get_mail(i,&maillist[nmsgs-i]))
230            exit (1);
231        if (uselock && (!strcmp(maillist[nmsgs-i].to,mymail.to) &&
232                        !strcmp(maillist[nmsgs-i].from,mymail.from) &&
233                        !strcmp(maillist[nmsgs-i].subj,mymail.subj)))
234            break;
235    }
236
237    (void) pop_command("QUIT");
238    pop_close();
239
240    i++;
241    for (;i<=nmsgs;i++)
242        mail_notify(&maillist[nmsgs-i]);
243    i--;
244    if (lock) {
245#ifdef _POSIX_VERSION
246        struct flock fl;
247
248        /* unlock the whole file */
249        fl.l_type = F_UNLCK;
250        fl.l_whence = SEEK_SET;
251        fl.l_start = 0;
252        fl.l_len = 0;
253        (void) fcntl(fileno(lock),F_SETLKW,&fl);
254#else
255        (void) flock(fileno(lock),LOCK_UN);
256#endif
257        (void) fclose(lock);
258    }
259    lock = fopen(lockfile,"w");
260    if (!lock)
261        exit (1);
262    fprintf(lock,"%s\n%s\n%s\n",
263            maillist[nmsgs-i].from,
264            maillist[nmsgs-i].to,
265            maillist[nmsgs-i].subj);
266    (void) fclose(lock);
267
268    exit(0);
269}
270
271void fatal_pop_err ()
272{
273    fprintf (stderr, "%s: %s\n", prog, Errmsg);
274    (void) pop_command ("QUIT");
275    pop_close ();
276    exit (1);
277}
278
279void get_message(i)
280        int i;
281{
282        int mbx_write();
283        if (pop_scan(i, mbx_write, 0) != OK)
284            fatal_pop_err ();
285}
286
287/* Pop stuff */
288
289void pop_close()
290{
291        if (sfi)
292                (void) fclose(sfi);
293        if (sfo)
294                (void) fclose(sfo);
295}
296
297get_mail(i,mail)
298        int i;
299        struct _mail *mail;
300{
301        char from[512],to[512],subj[512];
302        char *c,*ptr,*ptr2;
303       
304        *from = 0;
305        *to = 0;
306        *subj = 0;
307
308        if (mailptr)
309                free(mailptr);
310
311        mailptr = 0;
312       
313        get_message(i);
314
315        ptr = mailptr;
316        while (ptr) {
317                ptr2 = strchr(ptr,'\n');
318                if (ptr2)
319                        *ptr2++ = 0;
320                if (*ptr == '\0')
321                        break;
322                if (!strncmp(ptr, "From: ", 6))
323                        (void) strcpy(from, ptr+6);
324                else if (!strncmp(ptr, "To: ", 4))
325                        (void) strcpy(to, ptr+4);
326                else if (!strncmp(ptr, "Subject: ", 9))
327                        (void) strcpy(subj, ptr+9);
328                ptr = ptr2;
329        }
330
331        /* add elipsis at end of "To:" field if it continues onto */
332        /* more than one line */
333        i = strlen(to) - 2;
334        c = to+i;
335        if (*c++ == ',') {
336                *c++ = ' ';
337                *c++ = '.';
338                *c++ = '.';
339                *c++ = '.';
340                *c++ = '\n';
341                *c = 0;
342        }
343
344        mail->from = (char *)malloc((unsigned)(strlen(from)+1));
345        (void) strcpy(mail->from,from);
346        mail->to = (char *)malloc((unsigned)(strlen(to)+1));
347        (void) strcpy(mail->to,to);
348        mail->subj = (char *)malloc((unsigned)(strlen(subj)+1));
349        (void) strcpy(mail->subj,subj);
350
351        return (0);
352}
353
354void
355mail_notify(mail)
356        struct _mail *mail;
357{
358        int retval;
359        char *fields[3];
360        ZNotice_t notice;
361
362        (void) memset((char *)&notice, 0, sizeof(notice));
363        notice.z_kind = UNACKED;
364        notice.z_port = 0;
365        notice.z_class = "MAIL";
366        notice.z_class_inst = "POPRET";
367        notice.z_opcode = "NEW_MAIL";
368        notice.z_sender = 0;
369        notice.z_recipient = ZGetSender();
370        notice.z_default_format = "You have new mail:\n\nFrom: $1\nTo: $2\nSubject: $3";
371
372        fields[0] = mail->from;
373        fields[1] = mail->to;
374        fields[2] = mail->subj;
375     
376        if ((retval = ZSendList(&notice,fields,3,ZNOAUTH)) != ZERR_NONE)
377                com_err(prog,retval,"while sending notice");
378}
379
380/*
381 * These are the necessary KPOP routines snarfed from
382 * the GNU movemail program.
383 */
384
385pop_init(host)
386char *host;
387{
388    register struct hostent *hp;
389    register struct servent *sp;
390    int lport = IPPORT_RESERVED - 1;
391    struct sockaddr_in sin;
392    register int s;
393#ifdef KPOP
394    KTEXT ticket = (KTEXT)NULL;
395    int rem;
396    long authopts;
397    char *host_save;
398#endif
399    char *svc_name;
400
401    hp = gethostbyname(host);
402    if (hp == NULL) {
403        (void) sprintf(Errmsg, "MAILHOST unknown: %s", host);
404        return(NOTOK);
405    }
406
407
408#ifdef KPOP
409#ifdef ATHENA_COMPAT
410    svc_name = "knetd";
411#else
412    svc_name = "kpop";
413#endif
414#else
415    svc_name = "pop";
416#endif
417
418    sp = getservbyname (svc_name, "tcp");
419    if (sp == 0) {
420        (void) sprintf (Errmsg, "%s/tcp: unknown service", svc_name);
421        return NOTOK;
422    }
423    sin.sin_family = hp->h_addrtype;
424    (void) memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length);
425    sin.sin_port = sp->s_port;
426#ifdef KPOP
427    s = socket(AF_INET, SOCK_STREAM, 0);
428#else
429    s = rresvport(&lport);
430#endif
431    if (s < 0) {
432        (void) sprintf(Errmsg, "error creating socket: %s", strerror(errno));
433        return(NOTOK);
434    }
435
436    if (connect(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
437        (void) sprintf(Errmsg, "error during connect: %s", strerror(errno));
438        (void) close(s);
439        return(NOTOK);
440    }
441#ifdef KPOP
442    ticket = (KTEXT)malloc( sizeof(KTEXT_ST) );
443    rem=KSUCCESS;
444#ifdef ATHENA_COMPAT
445    authopts = KOPT_DO_OLDSTYLE;
446    rem = krb_sendsvc(s,"pop");
447    if (rem != KSUCCESS) {
448        (void) sprintf(Errmsg, "kerberos error: %s", krb_get_err_text(rem));
449        (void) close(s);
450        return(NOTOK);
451    }
452#else
453    authopts = 0L;
454#endif
455    host_save = malloc(strlen(hp->h_name) + 1);
456    if (!host_save) {
457        sprintf(Errmsg, "Out of memory.");
458        return(NOTOK);
459    }
460    strcpy(host_save, hp->h_name);
461    rem = krb_sendauth(authopts, s, ticket, "pop", host_save, (char *)0,
462                       0, (MSG_DAT *) 0, (CREDENTIALS *) 0,
463                       (bit_64 *) 0, (struct sockaddr_in *)0,
464                       (struct sockaddr_in *)0,"ZMAIL0.0");
465    free(host_save);
466    free(ticket);
467    if (rem != KSUCCESS) {
468        (void) sprintf(Errmsg, "kerberos error: %s",krb_get_err_text(rem));
469        (void) close(s);
470        return(NOTOK);
471    }
472#endif
473
474    sfi = fdopen(s, "r");
475    sfo = fdopen(s, "w");
476    if (sfi == NULL || sfo == NULL) {
477        (void) sprintf(Errmsg, "error in fdopen: %s", strerror(errno));
478        (void) close(s);
479        return(NOTOK);
480    }
481
482    return(OK);
483}
484
485#ifdef __STDC__
486pop_command(char *fmt, ...)
487#else
488pop_command(fmt, va_alist)
489    va_dcl
490#endif
491{
492    va_list args;
493    char buf[4096];
494
495    VA_START(args, fmt);
496    (void) vsprintf(buf, fmt, args);
497    va_end(args);
498
499    if (putline(buf, Errmsg, sfo) == NOTOK) return(NOTOK);
500
501    if (getline(buf, sizeof buf, sfi) != OK) {
502        (void) strcpy(Errmsg, buf);
503        return(NOTOK);
504    }
505
506    if (*buf != '+') {
507        (void) strcpy(Errmsg, buf);
508        return(NOTOK);
509    } else {
510        return(OK);
511    }
512}
513
514   
515pop_stat(nmsgs, nbytes)
516int *nmsgs, *nbytes;
517{
518    char buf[4096];
519
520    if (putline("STAT", Errmsg, sfo) == NOTOK) return(NOTOK);
521
522    if (getline(buf, sizeof buf, sfi) != OK) {
523        (void) strcpy(Errmsg, buf);
524        return(NOTOK);
525    }
526
527    if (*buf != '+') {
528        (void) strcpy(Errmsg, buf);
529        return(NOTOK);
530    } else {
531        if (sscanf(buf, "+OK %d %d", nmsgs, nbytes) != 2)
532            return(NOTOK);
533        return(OK);
534    }
535}
536
537pop_scan(msgno, action, arg)
538int (*action)();
539{
540    char buf[4096];
541
542#ifdef HAVE_POP3_TOP
543    (void) sprintf(buf, "TOP %d 0", msgno);
544#else
545    (void) sprintf(buf, "RETR %d", msgno);
546#endif
547    if (putline(buf, Errmsg, sfo) == NOTOK) return(NOTOK);
548
549    if (getline(buf, sizeof buf, sfi) != OK) {
550        (void) strcpy(Errmsg, buf);
551        return(NOTOK);
552    }
553
554    while (1) {
555        switch (multiline(buf, sizeof buf, sfi)) {
556        case OK:
557            (*action)(buf, arg);
558            break;
559        case DONE:
560            return (OK);
561        case NOTOK:
562            (void) strcpy(Errmsg, buf);
563            return (NOTOK);
564        }
565    }
566}
567
568getline(buf, n, f)
569char *buf;
570register int n;
571FILE *f;
572{
573    register char *p;
574
575    p = fgets(buf, n, f);
576
577    if (ferror(f)) {
578        (void) strcpy(buf, "error on connection");
579        return (NOTOK);
580    }
581
582    if (p == NULL) {
583        (void) strcpy(buf, "connection closed by foreign host\n");
584        return (DONE);
585    }
586
587    p = buf + strlen(buf);
588    if (*--p == '\n') *p = '\0';
589    if (*--p == '\r') *p = '\0';
590    return(OK);
591}
592
593multiline(buf, n, f)
594char *buf;
595register int n;
596FILE *f;
597{
598    if (getline(buf, n, f) != OK) return (NOTOK);
599    if (*buf == '.') {
600        if (*(buf+1) == '\0') {
601            return (DONE);
602        } else {
603            (void) strcpy(buf, buf+1);
604        }
605    } else if (*buf == '\0') {
606      /* suck up all future lines, since this is after all only for headers */
607        while(! ((buf[0]=='.') && (buf[1] == '\0')) ) {
608            if (getline(buf, n, f) != OK) return (NOTOK);
609        }
610        return DONE;
611    }
612    return(OK);
613}
614
615putline(buf, err, f)
616char *buf;
617char *err;
618FILE *f;
619{
620    fprintf(f, "%s\r\n", buf);
621    (void) fflush(f);
622    if (ferror(f)) {
623        (void) strcpy(err, "lost connection");
624        return(NOTOK);
625    }
626    return(OK);
627}
628
629/*ARGSUSED*/
630mbx_write(line, dummy)
631char *line;
632int dummy;                              /* for consistency with pop_scan */
633{
634        if (mailptr) {
635                mailptr = (char *)realloc(mailptr,(unsigned)(strlen(mailptr)+strlen(line)+2));
636                (void) strcat(mailptr,line);
637        }
638        else {
639                mailptr = (char *)malloc((unsigned)(strlen(line)+2));
640                (void) strcpy(mailptr,line);
641        }
642        (void) strcat(mailptr,"\n");
643        return(0);
644}
Note: See TracBrowser for help on using the repository browser.