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