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