1 /*
2 ** Copyright 2001 Double Precision, Inc.
3 ** See COPYING for distribution information.
4 */
5 
6 #include	"autoresponse.h"
7 #include	"autoresponsequota.h"
8 #include	<stdlib.h>
9 #include	<string.h>
10 #include	<stdio.h>
11 #include	<ctype.h>
12 #include	<errno.h>
13 #if	HAVE_UNISTD_H
14 #include	<unistd.h>
15 #endif
16 #include <sys/types.h>
17 #if HAVE_SYS_STAT_H
18 #include <sys/stat.h>
19 #endif
20 #if HAVE_DIRENT_H
21 #include <dirent.h>
22 #define NAMLEN(dirent) strlen((dirent)->d_name)
23 #else
24 #define dirent direct
25 #define NAMLEN(dirent) (dirent)->d_namlen
26 #if HAVE_SYS_NDIR_H
27 #include <sys/ndir.h>
28 #endif
29 #if HAVE_SYS_DIR_H
30 #include <sys/dir.h>
31 #endif
32 #if HAVE_NDIR_H
33 #include <ndir.h>
34 #endif
35 #endif
36 
37 
38 struct maildir_autoresponse_quota {
39 	unsigned files;
40 	unsigned long bytes;
41 } ;
42 
43 struct temp_autoresponse_list {
44 	struct temp_autoresponse_list *next;
45 	char *filename;
46 } ;
47 
maildir_autoresponse_list(const char * maildir)48 char **maildir_autoresponse_list(const char *maildir)
49 {
50 	char *d, **a;
51 	struct temp_autoresponse_list *list=NULL;
52 	unsigned list_cnt;
53 	struct temp_autoresponse_list *p;
54 
55 	DIR *dirp;
56 
57 	if (!maildir)
58 		maildir=".";
59 
60 	d=malloc(strlen(maildir)+sizeof("/autoresponses"));
61 
62 	if (!d)
63 		return (NULL);
64 
65 	strcat(strcpy(d, maildir), "/autoresponses");
66 
67 	dirp=opendir(d);
68 	free(d);
69 
70 	list_cnt=0;
71 
72 	if (dirp)
73 	{
74 		struct dirent *de;
75 
76 		while ((de=readdir(dirp)) != NULL)
77 		{
78 			if (strchr(de->d_name, '.'))
79 				continue;
80 
81 			p=(struct temp_autoresponse_list *)
82 				malloc(sizeof(struct temp_autoresponse_list));
83 			if (p)
84 			{
85 				if ((p->filename=strdup(de->d_name)) == NULL)
86 				{
87 					free(p);
88 					p=NULL;
89 				}
90 			}
91 
92 			if (!p)
93 			{
94 				closedir(dirp);
95 
96 				while (list)
97 				{
98 					p=list;
99 					list=p->next;
100 					free(p->filename);
101 					free(p);
102 				}
103 				return (NULL);
104 			}
105 			p->next=list;
106 			list=p;
107 			++list_cnt;
108 		}
109 		closedir(dirp);
110 	}
111 
112 	a=malloc( (list_cnt+1)*sizeof(char *));
113 
114 	if (!a)
115 	{
116 		while (list)
117 		{
118 			p=list;
119 			list=p->next;
120 			free(p->filename);
121 			free(p);
122 		}
123 		return (NULL);
124 	}
125 
126 	list_cnt=0;
127 
128 	while (list)
129 	{
130 		p=list;
131 		list=p->next;
132 		a[list_cnt]=p->filename;
133 		free(p);
134 		++list_cnt;
135 	}
136 	a[list_cnt]=0;
137 	return (a);
138 }
139 
maildir_autoresponse_list_free(char ** a)140 void maildir_autoresponse_list_free(char **a)
141 {
142 	unsigned i;
143 
144 	for (i=0; a[i]; i++)
145 		free(a[i]);
146 	free(a);
147 }
148 
afilename(const char * maildir,const char * filename)149 static char *afilename(const char *maildir, const char *filename)
150 {
151 	char *p;
152 
153 	if (!maildir)
154 		maildir=".";
155 
156 	if (strchr(filename, '.') || strchr(filename, '/')
157 	    || strchr(filename, '\'') || strchr(filename, '\"')
158 	    || strchr(filename, '*') || strchr(filename, '?')
159 	    || strchr(filename, '[') || strchr(filename, ']')
160 	    || strchr(filename, ' ') || strchr(filename, '\n')
161 	    || strchr(filename, '\t') || strchr(filename, '\r')
162 	    || strchr(filename, '~') || !*filename)
163 	{
164 		errno=EINVAL;
165 		return (NULL);
166 	}
167 
168 	p=malloc(strlen(maildir)+strlen(filename)+
169 		 sizeof("/autoresponsesXXXXXXXXXXXXXXXXXXXXXXXX"));
170 
171 	if (!p)
172 		return (NULL);
173 	return (strcat(strcat(strcpy(p, maildir), "/autoresponses/"),
174 		       filename));
175 }
176 
maildir_autoresponse_validate(const char * maildir,const char * filename)177 int maildir_autoresponse_validate(const char *maildir, const char *filename)
178 {
179 	char *p=afilename(maildir, filename);
180 
181 	if (!p)
182 		return (-1);
183 	free(p);
184 	return (0);
185 }
186 
187 /* Delete autoreply scratch file (optionally the autoreply file itself) */
188 
deletefiles(const char * dir,const char * filename,int deleteall)189 static void deletefiles(const char *dir, const char *filename, int deleteall)
190 {
191 	DIR *dirp=opendir(dir);
192 	struct dirent *de;
193 	int l=strlen(filename);
194 
195 	if (!dirp)
196 		return;
197 
198 	while ((de=readdir(dirp)) != 0)
199 	{
200 		char *q;
201 
202 		if (strncmp(de->d_name, filename, l))
203 			continue;
204 
205 		if (de->d_name[l] == 0)
206 		{
207 			if (!deleteall)
208 				continue;
209 		}
210 		else if (de->d_name[l] != '.')
211 			continue;
212 
213 		q=malloc(strlen(dir)+strlen(de->d_name)+2);
214 
215 		if (q)
216 		{
217 			unlink(strcat(strcat(strcpy(q, dir), "/"),de->d_name));
218 			free(q);
219 		}
220 	}
221 	closedir(dirp);
222 }
223 
maildir_autoresponse_delete(const char * maildir,const char * filename)224 void maildir_autoresponse_delete(const char *maildir, const char *filename)
225 {
226 	char *p=afilename(maildir, filename);
227 
228 	char *q;
229 
230 	if (!p)
231 		return;
232 
233 	q=strrchr(p, '/');
234 	*q++=0;
235 
236 	deletefiles(p, q, 1);
237 	free(p);
238 }
239 
read_quota(struct maildir_autoresponse_quota * q,const char * f)240 static void read_quota(struct maildir_autoresponse_quota *q, const char *f)
241 {
242 	char buf[BUFSIZ];
243 	FILE *fp;
244 	const char *p;
245 
246 	if ((fp=fopen(f, "r")) == NULL)
247 		return;
248 	if (fgets(buf, sizeof(buf), fp) == NULL)
249 	{
250 		fclose(fp);
251 		return;
252 	}
253 	fclose(fp);
254 
255 	for (p=buf; *p; )
256 	{
257 		if (*p == 'C')
258 		{
259 			q->files=0;
260 			for ( ++p; *p; ++p)
261 			{
262 				if (!isdigit((int)(unsigned char)*p))
263 					break;
264 				q->files=q->files * 10 + (*p-'0');
265 			}
266 			continue;
267 		}
268 
269 		if (*p == 'S')
270 		{
271 			q->bytes=0;
272 			for ( ++p; *p; ++p)
273 			{
274 				if (!isdigit((int)(unsigned char)*p))
275 					break;
276 				q->bytes=q->bytes * 10 + (*p-'0');
277 			}
278 			continue;
279 		}
280 		++p;
281 	}
282 }
283 
get_quota(struct maildir_autoresponse_quota * q,const char * maildir)284 static int get_quota(struct maildir_autoresponse_quota *q, const char *maildir)
285 {
286 	char *p;
287 
288 	q->files=0;
289 	q->bytes=0;
290 	read_quota(q, AUTORESPONSEQUOTA);
291 
292 	if (!maildir)
293 		maildir=".";
294 
295 	p=malloc(strlen(maildir)+sizeof("/autoresponsesquota"));
296 	if (!p)
297 		return (-1);
298 	strcat(strcpy(p, maildir), "/autoresponsesquota");
299 	read_quota(q, p);
300 	free(p);
301 	return (0);
302 }
303 
add_quota(struct maildir_autoresponse_quota * q,const char * file,int sign)304 static void add_quota(struct maildir_autoresponse_quota *q, const char *file, int sign)
305 {
306 	struct stat stat_buf;
307 
308 	if (stat(file, &stat_buf))
309 		return;
310 	q->files += sign;
311 	q->bytes += (long)stat_buf.st_size*sign;
312 }
313 
calc_quota(struct maildir_autoresponse_quota * q,const char * maildir)314 static int calc_quota(struct maildir_autoresponse_quota *q, const char *maildir)
315 {
316 	char *p;
317 	DIR *dirp;
318 	struct dirent *de;
319 
320 	q->files=0;
321 	q->bytes=0;
322 
323 	if (!maildir)
324 		maildir=".";
325 
326 	p=malloc(strlen(maildir)+sizeof("/autoresponses"));
327 	if (!p)
328 		return (-1);
329 	strcat(strcpy(p, maildir), "/autoresponses");
330 	dirp=opendir(p);
331 	free(p);
332 	if (!dirp)
333 		return (0);
334 	while ((de=readdir(dirp)) != 0)
335 	{
336 		if (strchr(de->d_name, '.'))
337 			continue;
338 
339 		p=malloc(strlen(maildir)+strlen(de->d_name)
340 			 +sizeof("/autoresponses/"));
341 		if (!p)
342 		{
343 			closedir(dirp);
344 			return (-1);
345 		}
346 
347 		strcat(strcat(strcpy(p, maildir), "/autoresponses/"),
348 		       de->d_name);
349 		add_quota(q, p, 1);
350 		free(p);
351 	}
352 	closedir(dirp);
353 	return (0);
354 }
355 
check_quota(struct maildir_autoresponse_quota * setquota,struct maildir_autoresponse_quota * newquota)356 static int check_quota(struct maildir_autoresponse_quota *setquota,
357 		       struct maildir_autoresponse_quota *newquota)
358 {
359 	if (setquota->files > 0 && newquota->files > setquota->files)
360 		return (-1);
361 	if (setquota->bytes > 0 && newquota->bytes > setquota->bytes)
362 		return (-1);
363 	return (0);
364 }
365 
maildir_autoresponse_create(const char * maildir,const char * filename)366 FILE *maildir_autoresponse_create(const char *maildir, const char *filename)
367 {
368 	char *p=afilename(maildir, filename);
369 	FILE *fp;
370 	char *q;
371 
372 	if (!p)
373 		return (NULL);
374 
375 	strcat(p, ".tmp");
376 	fp=fopen(p, "w");
377 
378 	if (!fp)	/* Perhaps we need to create the autoresponse dir? */
379 	{
380 		q=strrchr(p, '/');
381 		*q=0;
382 		mkdir(p, 0700);
383 		*q='/';
384 		fp=fopen(p, "w");
385 	}
386 	free(p);
387 	return (fp);
388 }
389 
maildir_autoresponse_create_finish(const char * maildir,const char * filename,FILE * fp)390 int maildir_autoresponse_create_finish(const char *maildir, const char *filename,
391 			       FILE *fp)
392 {
393 	char *p, *q;
394 	struct maildir_autoresponse_quota set_quota, new_quota;
395 
396 	fclose(fp);
397 	p=afilename(maildir, filename);
398 
399 	if (!p)
400 		return (0);
401 	q=strdup(p);
402 
403 	if (q)
404 	{
405 		if (get_quota(&set_quota, maildir)
406 		    || calc_quota(&new_quota, maildir))
407 		{
408 			strcat(p, ".tmp");
409 			unlink(p);
410 			free(q);
411 			free(p);
412 			return (-1);
413 		}
414 
415 		add_quota(&new_quota, p, -1);
416 		strcat(p, ".tmp");
417 		add_quota(&new_quota, p, 1);
418 		if (check_quota(&set_quota, &new_quota))
419 		{
420 			unlink(p);
421 			free(p);
422 			free(q);
423 			errno=ENOSPC;
424 			return (-1);
425 		}
426 
427 		rename(p, q);
428 		free(q);
429 	}
430 	free(p);
431 	return (0);
432 }
433 
maildir_autoresponse_open(const char * maildir,const char * filename)434 FILE *maildir_autoresponse_open(const char *maildir, const char *filename)
435 {
436 	char *p=afilename(maildir, filename);
437 	FILE *fp;
438 
439 	if (!p)
440 		return (NULL);
441 
442 	fp=fopen(p, "r");
443 	free(p);
444 	return (fp);
445 }
446