xref: /netbsd/bin/ksh/mail.c (revision bf9ec67e)
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