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