xref: /netbsd-src/bin/ksh/mail.c (revision 76dfffe33547c37f8bdd446e3e4ab0f3c16cea4b)
1 /*
2  * Mailbox checking code by Robert J. Gibson, adapted for PD ksh by
3  * John R. MacMillan
4  */
5 
6 #include "config.h"
7 
8 #ifdef KSH
9 #include "sh.h"
10 #include "ksh_stat.h"
11 #include "ksh_time.h"
12 
13 #define MBMESSAGE	"you have mail in $_"
14 
15 typedef struct mbox {
16 	struct mbox    *mb_next;	/* next mbox in list */
17 	char	       *mb_path;	/* path to mail file */
18 	char	       *mb_msg;		/* to announce arrival of new mail */
19 	time_t		mb_mtime;	/* mtime of mail file */
20 } mbox_t;
21 
22 /*
23  * $MAILPATH is a linked list of mboxes.  $MAIL is a treated as a
24  * special case of $MAILPATH, where the list has only one node.  The
25  * same list is used for both since they are exclusive.
26  */
27 
28 static mbox_t  *mplist;
29 static mbox_t  mbox;
30 static time_t	mlastchkd;	/* when mail was last checked */
31 
32 static void     munset      ARGS((mbox_t *mlist)); /* free mlist and mval */
33 static mbox_t * mballoc     ARGS((char *p, char *m)); /* allocate a new mbox */
34 static void     mprintit    ARGS((mbox_t *mbp));
35 
36 void
37 mcheck()
38 {
39 	register mbox_t	*mbp;
40 	time_t		 now;
41 	long		 mailcheck;
42 	struct tbl	*vp;
43 	struct stat	 stbuf;
44 
45 	if (getint(global("MAILCHECK"), &mailcheck) < 0)
46 		return;
47 
48 	now = time((time_t *) 0);
49 	if (mlastchkd == 0)
50 		mlastchkd = now;
51 	if (now - mlastchkd >= mailcheck) {
52 		mlastchkd = now;
53 
54 		vp = global("MAILPATH");
55 		if (vp && (vp->flag & ISSET))
56 			mbp = mplist;
57 		else if ((vp = global("MAIL")) && (vp->flag & ISSET))
58 			mbp = &mbox;
59 		else
60 			mbp = NULL;
61 
62 		while (mbp) {
63 			if (mbp->mb_path && stat(mbp->mb_path, &stbuf) == 0
64 			    && S_ISREG(stbuf.st_mode))
65 			{
66 				if (stbuf.st_size
67 				    && mbp->mb_mtime != stbuf.st_mtime
68 				    && stbuf.st_atime <= stbuf.st_mtime)
69 					mprintit(mbp);
70 				mbp->mb_mtime = stbuf.st_mtime;
71 			} else {
72 				/*
73 				 * Some mail readers remove the mail
74 				 * file if all mail is read.  If file
75 				 * does not exist, assume this is the
76 				 * case and set mtime to zero.
77 				 */
78 				mbp->mb_mtime = 0;
79 			}
80 			mbp = mbp->mb_next;
81 		}
82 	}
83 }
84 
85 void
86 mbset(p)
87 	register char	*p;
88 {
89 	struct stat	stbuf;
90 
91 	if (mbox.mb_msg)
92 		afree((void *)mbox.mb_msg, APERM);
93 	mbox.mb_path = p;
94 	mbox.mb_msg = NULL;
95 	if (p && stat(p,&stbuf) == 0 && S_ISREG(stbuf.st_mode))
96 		mbox.mb_mtime = stbuf.st_mtime;
97 	else
98 		mbox.mb_mtime = 0;
99 }
100 
101 void
102 mpset(mptoparse)
103 	register char	*mptoparse;
104 {
105 	register mbox_t	*mbp;
106 	register char	*mpath, *mmsg, *mval;
107 	char *p;
108 
109 	munset( mplist );
110 	mplist = NULL;
111 	mval = str_save(mptoparse, APERM);
112 	while (mval) {
113 		mpath = mval;
114 		if ((mval = strchr(mval, PATHSEP)) != NULL) {
115 			*mval = '\0', mval++;
116 		}
117 		/* POSIX/bourne-shell say file%message */
118 		for (p = mpath; (mmsg = strchr(p, '%')); ) {
119 			/* a literal percent? (POSIXism) */
120 			if (mmsg[-1] == '\\') {
121 				/* use memmove() to avoid overlap problems */
122 				memmove(mmsg - 1, mmsg, strlen(mmsg) + 1);
123 				p = mmsg + 1;
124 				continue;
125 			}
126 			break;
127 		}
128 		/* at&t ksh says file?message */
129 		if (!mmsg && !Flag(FPOSIX))
130 			mmsg = strchr(mpath, '?');
131 		if (mmsg) {
132 			*mmsg = '\0';
133 			mmsg++;
134 		}
135 		mbp = mballoc(mpath, mmsg);
136 		mbp->mb_next = mplist;
137 		mplist = mbp;
138 	}
139 }
140 
141 static void
142 munset(mlist)
143 register mbox_t	*mlist;
144 {
145 	register mbox_t	*mbp;
146 
147 	while (mlist != NULL) {
148 		mbp = mlist;
149 		mlist = mbp->mb_next;
150 		if (!mlist)
151 			afree((void *)mbp->mb_path, APERM);
152 		afree((void *)mbp, APERM);
153 	}
154 }
155 
156 static mbox_t *
157 mballoc(p, m)
158 	char	*p;
159 	char	*m;
160 {
161 	struct stat	stbuf;
162 	register mbox_t	*mbp;
163 
164 	mbp = (mbox_t *)alloc(sizeof(mbox_t), APERM);
165 	mbp->mb_next = NULL;
166 	mbp->mb_path = p;
167 	mbp->mb_msg = m;
168 	if (stat(mbp->mb_path, &stbuf) == 0 && S_ISREG(stbuf.st_mode))
169 		mbp->mb_mtime = stbuf.st_mtime;
170 	else
171 		mbp->mb_mtime = 0;
172 	return(mbp);
173 }
174 
175 static void
176 mprintit( mbp )
177 mbox_t	*mbp;
178 {
179 	struct tbl	*vp;
180 
181 	setstr((vp = local("_", FALSE)), mbp->mb_path);
182 
183 	shellf("%s\n", substitute(mbp->mb_msg ? mbp->mb_msg : MBMESSAGE, 0));
184 
185 	unset(vp, 0);
186 }
187 #endif /* KSH */
188