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