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