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