xref: /netbsd-src/bin/ksh/mail.c (revision 2a399c6883d870daece976daec6ffa7bb7f934ce)
1 /*	$NetBSD: mail.c,v 1.2 1997/01/12 19:12:06 tls 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 
34 static void     munset      ARGS((mbox_t *mlist)); /* free mlist and mval */
35 static mbox_t * mballoc     ARGS((char *p, char *m)); /* allocate a new mbox */
36 static void     mprintit    ARGS((mbox_t *mbp));
37 
38 void
39 mcheck()
40 {
41 	register mbox_t	*mbp;
42 	time_t		 now;
43 	long		 mailcheck;
44 	struct tbl	*vp;
45 	struct stat	 stbuf;
46 
47 	if (getint(global("MAILCHECK"), &mailcheck) < 0)
48 		return;
49 
50 	now = time((time_t *) 0);
51 	if (mlastchkd == 0)
52 		mlastchkd = now;
53 	if (now - mlastchkd >= mailcheck) {
54 		mlastchkd = now;
55 
56 		vp = global("MAILPATH");
57 		if (vp && (vp->flag & ISSET))
58 			mbp = mplist;
59 		else if ((vp = global("MAIL")) && (vp->flag & ISSET))
60 			mbp = &mbox;
61 		else
62 			mbp = NULL;
63 
64 		while (mbp) {
65 			if (mbp->mb_path && stat(mbp->mb_path, &stbuf) == 0
66 			    && S_ISREG(stbuf.st_mode))
67 			{
68 				if (stbuf.st_size
69 				    && mbp->mb_mtime != stbuf.st_mtime
70 				    && stbuf.st_atime <= stbuf.st_mtime)
71 					mprintit(mbp);
72 				mbp->mb_mtime = stbuf.st_mtime;
73 			} else {
74 				/*
75 				 * Some mail readers remove the mail
76 				 * file if all mail is read.  If file
77 				 * does not exist, assume this is the
78 				 * case and set mtime to zero.
79 				 */
80 				mbp->mb_mtime = 0;
81 			}
82 			mbp = mbp->mb_next;
83 		}
84 	}
85 }
86 
87 void
88 mbset(p)
89 	register char	*p;
90 {
91 	struct stat	stbuf;
92 
93 	if (mbox.mb_msg)
94 		afree((void *)mbox.mb_msg, APERM);
95 	mbox.mb_path = p;
96 	mbox.mb_msg = NULL;
97 	if (p && stat(p,&stbuf) == 0 && S_ISREG(stbuf.st_mode))
98 		mbox.mb_mtime = stbuf.st_mtime;
99 	else
100 		mbox.mb_mtime = 0;
101 }
102 
103 void
104 mpset(mptoparse)
105 	register char	*mptoparse;
106 {
107 	register mbox_t	*mbp;
108 	register char	*mpath, *mmsg, *mval;
109 	char *p;
110 
111 	munset( mplist );
112 	mplist = NULL;
113 	mval = str_save(mptoparse, APERM);
114 	while (mval) {
115 		mpath = mval;
116 		if ((mval = strchr(mval, PATHSEP)) != NULL) {
117 			*mval = '\0', mval++;
118 		}
119 		/* POSIX/bourne-shell say file%message */
120 		for (p = mpath; (mmsg = strchr(p, '%')); ) {
121 			/* a literal percent? (POSIXism) */
122 			if (mmsg[-1] == '\\') {
123 				/* use memmove() to avoid overlap problems */
124 				memmove(mmsg - 1, mmsg, strlen(mmsg) + 1);
125 				p = mmsg + 1;
126 				continue;
127 			}
128 			break;
129 		}
130 		/* at&t ksh says file?message */
131 		if (!mmsg && !Flag(FPOSIX))
132 			mmsg = strchr(mpath, '?');
133 		if (mmsg) {
134 			*mmsg = '\0';
135 			mmsg++;
136 		}
137 		mbp = mballoc(mpath, mmsg);
138 		mbp->mb_next = mplist;
139 		mplist = mbp;
140 	}
141 }
142 
143 static void
144 munset(mlist)
145 register mbox_t	*mlist;
146 {
147 	register mbox_t	*mbp;
148 
149 	while (mlist != NULL) {
150 		mbp = mlist;
151 		mlist = mbp->mb_next;
152 		if (!mlist)
153 			afree((void *)mbp->mb_path, APERM);
154 		afree((void *)mbp, APERM);
155 	}
156 }
157 
158 static mbox_t *
159 mballoc(p, m)
160 	char	*p;
161 	char	*m;
162 {
163 	struct stat	stbuf;
164 	register mbox_t	*mbp;
165 
166 	mbp = (mbox_t *)alloc(sizeof(mbox_t), APERM);
167 	mbp->mb_next = NULL;
168 	mbp->mb_path = p;
169 	mbp->mb_msg = m;
170 	if (stat(mbp->mb_path, &stbuf) == 0 && S_ISREG(stbuf.st_mode))
171 		mbp->mb_mtime = stbuf.st_mtime;
172 	else
173 		mbp->mb_mtime = 0;
174 	return(mbp);
175 }
176 
177 static void
178 mprintit( mbp )
179 mbox_t	*mbp;
180 {
181 	struct tbl	*vp;
182 
183 	setstr((vp = local("_", FALSE)), mbp->mb_path);
184 
185 	shellf("%s\n", substitute(mbp->mb_msg ? mbp->mb_msg : MBMESSAGE, 0));
186 
187 	unset(vp, 0);
188 }
189 #endif /* KSH */
190