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