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