xref: /minix3/bin/ksh/mail.c (revision 2718b5688b1550d32bf379153192626eee37752d)
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