1*2718b568SThomas Cort /* $NetBSD: mail.c,v 1.5 2006/01/15 18:16:30 jschauma Exp $ */
2*2718b568SThomas Cort
3*2718b568SThomas Cort /*
4*2718b568SThomas Cort * Mailbox checking code by Robert J. Gibson, adapted for PD ksh by
5*2718b568SThomas Cort * John R. MacMillan
6*2718b568SThomas Cort */
7*2718b568SThomas Cort #include <sys/cdefs.h>
8*2718b568SThomas Cort
9*2718b568SThomas Cort #ifndef lint
10*2718b568SThomas Cort __RCSID("$NetBSD: mail.c,v 1.5 2006/01/15 18:16:30 jschauma Exp $");
11*2718b568SThomas Cort #endif
12*2718b568SThomas Cort
13*2718b568SThomas Cort
14*2718b568SThomas Cort #include "config.h"
15*2718b568SThomas Cort
16*2718b568SThomas Cort #ifdef KSH
17*2718b568SThomas Cort #include "sh.h"
18*2718b568SThomas Cort #include "ksh_stat.h"
19*2718b568SThomas Cort #include "ksh_time.h"
20*2718b568SThomas Cort
21*2718b568SThomas Cort #define MBMESSAGE "You have mail in $_"
22*2718b568SThomas Cort
23*2718b568SThomas Cort typedef struct mbox {
24*2718b568SThomas Cort struct mbox *mb_next; /* next mbox in list */
25*2718b568SThomas Cort char *mb_path; /* path to mail file */
26*2718b568SThomas Cort char *mb_msg; /* to announce arrival of new mail */
27*2718b568SThomas Cort time_t mb_mtime; /* mtime of mail file */
28*2718b568SThomas Cort } mbox_t;
29*2718b568SThomas Cort
30*2718b568SThomas Cort /*
31*2718b568SThomas Cort * $MAILPATH is a linked list of mboxes. $MAIL is a treated as a
32*2718b568SThomas Cort * special case of $MAILPATH, where the list has only one node. The
33*2718b568SThomas Cort * same list is used for both since they are exclusive.
34*2718b568SThomas Cort */
35*2718b568SThomas Cort
36*2718b568SThomas Cort static mbox_t *mplist;
37*2718b568SThomas Cort static mbox_t mbox;
38*2718b568SThomas Cort static time_t mlastchkd; /* when mail was last checked */
39*2718b568SThomas Cort static time_t mailcheck_interval;
40*2718b568SThomas Cort
41*2718b568SThomas Cort static void munset ARGS((mbox_t *mlist)); /* free mlist and mval */
42*2718b568SThomas Cort static mbox_t * mballoc ARGS((char *p, char *m)); /* allocate a new mbox */
43*2718b568SThomas Cort static void mprintit ARGS((mbox_t *mbp));
44*2718b568SThomas Cort
45*2718b568SThomas Cort void
mcheck()46*2718b568SThomas Cort mcheck()
47*2718b568SThomas Cort {
48*2718b568SThomas Cort register mbox_t *mbp;
49*2718b568SThomas Cort time_t now;
50*2718b568SThomas Cort struct tbl *vp;
51*2718b568SThomas Cort struct stat stbuf;
52*2718b568SThomas Cort
53*2718b568SThomas Cort now = time((time_t *) 0);
54*2718b568SThomas Cort if (mlastchkd == 0)
55*2718b568SThomas Cort mlastchkd = now;
56*2718b568SThomas Cort if (now - mlastchkd >= mailcheck_interval) {
57*2718b568SThomas Cort mlastchkd = now;
58*2718b568SThomas Cort
59*2718b568SThomas Cort if (mplist)
60*2718b568SThomas Cort mbp = mplist;
61*2718b568SThomas Cort else if ((vp = global("MAIL")) && (vp->flag & ISSET))
62*2718b568SThomas Cort mbp = &mbox;
63*2718b568SThomas Cort else
64*2718b568SThomas Cort mbp = NULL;
65*2718b568SThomas Cort
66*2718b568SThomas Cort while (mbp) {
67*2718b568SThomas Cort if (mbp->mb_path && stat(mbp->mb_path, &stbuf) == 0
68*2718b568SThomas Cort && S_ISREG(stbuf.st_mode))
69*2718b568SThomas Cort {
70*2718b568SThomas Cort if (stbuf.st_size
71*2718b568SThomas Cort && mbp->mb_mtime != stbuf.st_mtime
72*2718b568SThomas Cort && stbuf.st_atime <= stbuf.st_mtime)
73*2718b568SThomas Cort mprintit(mbp);
74*2718b568SThomas Cort mbp->mb_mtime = stbuf.st_mtime;
75*2718b568SThomas Cort } else {
76*2718b568SThomas Cort /*
77*2718b568SThomas Cort * Some mail readers remove the mail
78*2718b568SThomas Cort * file if all mail is read. If file
79*2718b568SThomas Cort * does not exist, assume this is the
80*2718b568SThomas Cort * case and set mtime to zero.
81*2718b568SThomas Cort */
82*2718b568SThomas Cort mbp->mb_mtime = 0;
83*2718b568SThomas Cort }
84*2718b568SThomas Cort mbp = mbp->mb_next;
85*2718b568SThomas Cort }
86*2718b568SThomas Cort }
87*2718b568SThomas Cort }
88*2718b568SThomas Cort
89*2718b568SThomas Cort void
mcset(interval)90*2718b568SThomas Cort mcset(interval)
91*2718b568SThomas Cort long interval;
92*2718b568SThomas Cort {
93*2718b568SThomas Cort mailcheck_interval = interval;
94*2718b568SThomas Cort }
95*2718b568SThomas Cort
96*2718b568SThomas Cort void
mbset(p)97*2718b568SThomas Cort mbset(p)
98*2718b568SThomas Cort register char *p;
99*2718b568SThomas Cort {
100*2718b568SThomas Cort struct stat stbuf;
101*2718b568SThomas Cort
102*2718b568SThomas Cort if (mbox.mb_msg)
103*2718b568SThomas Cort afree((void *)mbox.mb_msg, APERM);
104*2718b568SThomas Cort if (mbox.mb_path)
105*2718b568SThomas Cort afree((void *)mbox.mb_path, APERM);
106*2718b568SThomas Cort /* Save a copy to protect from export (which munges the string) */
107*2718b568SThomas Cort mbox.mb_path = str_save(p, APERM);
108*2718b568SThomas Cort mbox.mb_msg = NULL;
109*2718b568SThomas Cort if (p && stat(p, &stbuf) == 0 && S_ISREG(stbuf.st_mode))
110*2718b568SThomas Cort mbox.mb_mtime = stbuf.st_mtime;
111*2718b568SThomas Cort else
112*2718b568SThomas Cort mbox.mb_mtime = 0;
113*2718b568SThomas Cort }
114*2718b568SThomas Cort
115*2718b568SThomas Cort void
mpset(mptoparse)116*2718b568SThomas Cort mpset(mptoparse)
117*2718b568SThomas Cort register char *mptoparse;
118*2718b568SThomas Cort {
119*2718b568SThomas Cort register mbox_t *mbp;
120*2718b568SThomas Cort register char *mpath, *mmsg, *mval;
121*2718b568SThomas Cort char *p;
122*2718b568SThomas Cort
123*2718b568SThomas Cort munset( mplist );
124*2718b568SThomas Cort mplist = NULL;
125*2718b568SThomas Cort mval = str_save(mptoparse, APERM);
126*2718b568SThomas Cort while (mval) {
127*2718b568SThomas Cort mpath = mval;
128*2718b568SThomas Cort if ((mval = strchr(mval, PATHSEP)) != NULL) {
129*2718b568SThomas Cort *mval = '\0', mval++;
130*2718b568SThomas Cort }
131*2718b568SThomas Cort /* POSIX/bourne-shell say file%message */
132*2718b568SThomas Cort for (p = mpath; (mmsg = strchr(p, '%')); ) {
133*2718b568SThomas Cort /* a literal percent? (POSIXism) */
134*2718b568SThomas Cort if (mmsg[-1] == '\\') {
135*2718b568SThomas Cort /* use memmove() to avoid overlap problems */
136*2718b568SThomas Cort memmove(mmsg - 1, mmsg, strlen(mmsg) + 1);
137*2718b568SThomas Cort p = mmsg + 1;
138*2718b568SThomas Cort continue;
139*2718b568SThomas Cort }
140*2718b568SThomas Cort break;
141*2718b568SThomas Cort }
142*2718b568SThomas Cort /* at&t ksh says file?message */
143*2718b568SThomas Cort if (!mmsg && !Flag(FPOSIX))
144*2718b568SThomas Cort mmsg = strchr(mpath, '?');
145*2718b568SThomas Cort if (mmsg) {
146*2718b568SThomas Cort *mmsg = '\0';
147*2718b568SThomas Cort mmsg++;
148*2718b568SThomas Cort }
149*2718b568SThomas Cort mbp = mballoc(mpath, mmsg);
150*2718b568SThomas Cort mbp->mb_next = mplist;
151*2718b568SThomas Cort mplist = mbp;
152*2718b568SThomas Cort }
153*2718b568SThomas Cort }
154*2718b568SThomas Cort
155*2718b568SThomas Cort static void
munset(mlist)156*2718b568SThomas Cort munset(mlist)
157*2718b568SThomas Cort register mbox_t *mlist;
158*2718b568SThomas Cort {
159*2718b568SThomas Cort register mbox_t *mbp;
160*2718b568SThomas Cort
161*2718b568SThomas Cort while (mlist != NULL) {
162*2718b568SThomas Cort mbp = mlist;
163*2718b568SThomas Cort mlist = mbp->mb_next;
164*2718b568SThomas Cort if (!mlist)
165*2718b568SThomas Cort afree((void *)mbp->mb_path, APERM);
166*2718b568SThomas Cort afree((void *)mbp, APERM);
167*2718b568SThomas Cort }
168*2718b568SThomas Cort }
169*2718b568SThomas Cort
170*2718b568SThomas Cort static mbox_t *
mballoc(p,m)171*2718b568SThomas Cort mballoc(p, m)
172*2718b568SThomas Cort char *p;
173*2718b568SThomas Cort char *m;
174*2718b568SThomas Cort {
175*2718b568SThomas Cort struct stat stbuf;
176*2718b568SThomas Cort register mbox_t *mbp;
177*2718b568SThomas Cort
178*2718b568SThomas Cort mbp = (mbox_t *)alloc(sizeof(mbox_t), APERM);
179*2718b568SThomas Cort mbp->mb_next = NULL;
180*2718b568SThomas Cort mbp->mb_path = p;
181*2718b568SThomas Cort mbp->mb_msg = m;
182*2718b568SThomas Cort if (stat(mbp->mb_path, &stbuf) == 0 && S_ISREG(stbuf.st_mode))
183*2718b568SThomas Cort mbp->mb_mtime = stbuf.st_mtime;
184*2718b568SThomas Cort else
185*2718b568SThomas Cort mbp->mb_mtime = 0;
186*2718b568SThomas Cort return(mbp);
187*2718b568SThomas Cort }
188*2718b568SThomas Cort
189*2718b568SThomas Cort static void
mprintit(mbp)190*2718b568SThomas Cort mprintit( mbp )
191*2718b568SThomas Cort mbox_t *mbp;
192*2718b568SThomas Cort {
193*2718b568SThomas Cort struct tbl *vp;
194*2718b568SThomas Cort
195*2718b568SThomas Cort /* Ignore setstr errors here (arbitrary) */
196*2718b568SThomas Cort setstr((vp = local("_", FALSE)), mbp->mb_path, KSH_RETURN_ERROR);
197*2718b568SThomas Cort
198*2718b568SThomas Cort shellf("%s\n", substitute(mbp->mb_msg ? mbp->mb_msg : MBMESSAGE, 0));
199*2718b568SThomas Cort
200*2718b568SThomas Cort unset(vp, 0);
201*2718b568SThomas Cort }
202*2718b568SThomas Cort #endif /* KSH */
203