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