aboutsummaryrefslogtreecommitdiff
path: root/bin/ksh/mail.c
blob: 3f642566f4925d07b295a7c1ab28473c8647730c (plain)
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
/*	$OpenBSD: mail.c,v 1.22 2015/10/19 14:42:16 mmcc Exp $	*/

/*
 * Mailbox checking code by Robert J. Gibson, adapted for PD ksh by
 * John R. MacMillan
 */

#include <sys/stat.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 time_t	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;
	time_t		 now;
	struct tbl	*vp;
	struct stat	 stbuf;

	now = time(NULL);
	if (mlastchkd == 0)
		mlastchkd = now;
	if (now - mlastchkd >= mailcheck_interval) {
		mlastchkd = now;

		if (mplist)
			mbp = mplist;
		else if ((vp = global("MAIL")) && (vp->flag & ISSET))
			mbp = &mbox;
		else
			mbp = NULL;

		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(long int 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[-1] == '\\') {
				/* use memmove() to avoid overlap problems */
				memmove(mmsg - 1, mmsg, strlen(mmsg) + 1);
				p = mmsg + 1;
				continue;
			}
			break;
		}
		/* at&t ksh says file?message */
		if (!mmsg && !Flag(FPOSIX))
			mmsg = strchr(mpath, '?');
		if (mmsg) {
			*mmsg = '\0';
			mmsg++;
		}
		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);
}