diff options
Diffstat (limited to 'maildir/autoresponse.c')
| -rw-r--r-- | maildir/autoresponse.c | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/maildir/autoresponse.c b/maildir/autoresponse.c new file mode 100644 index 0000000..106f98f --- /dev/null +++ b/maildir/autoresponse.c @@ -0,0 +1,445 @@ +/* +** Copyright 2001 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +#include "autoresponse.h" +#include "autoresponsequota.h" +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <sys/types.h> +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_DIRENT_H +#include <dirent.h> +#define NAMLEN(dirent) strlen((dirent)->d_name) +#else +#define dirent direct +#define NAMLEN(dirent) (dirent)->d_namlen +#if HAVE_SYS_NDIR_H +#include <sys/ndir.h> +#endif +#if HAVE_SYS_DIR_H +#include <sys/dir.h> +#endif +#if HAVE_NDIR_H +#include <ndir.h> +#endif +#endif + + +struct maildir_autoresponse_quota { + unsigned files; + unsigned long bytes; +} ; + +struct temp_autoresponse_list { + struct temp_autoresponse_list *next; + char *filename; +} ; + +char **maildir_autoresponse_list(const char *maildir) +{ + char *d, **a; + struct temp_autoresponse_list *list=NULL; + unsigned list_cnt; + struct temp_autoresponse_list *p; + + DIR *dirp; + + if (!maildir) + maildir="."; + + d=malloc(strlen(maildir)+sizeof("/autoresponses")); + + if (!d) + return (NULL); + + strcat(strcpy(d, maildir), "/autoresponses"); + + dirp=opendir(d); + free(d); + + list_cnt=0; + + if (dirp) + { + struct dirent *de; + + while ((de=readdir(dirp)) != NULL) + { + if (strchr(de->d_name, '.')) + continue; + + p=(struct temp_autoresponse_list *) + malloc(sizeof(struct temp_autoresponse_list)); + if (p) + { + if ((p->filename=strdup(de->d_name)) == NULL) + { + free(p); + p=NULL; + } + } + + if (!p) + { + closedir(dirp); + + while (list) + { + p=list; + list=p->next; + free(p->filename); + free(p); + } + return (NULL); + } + p->next=list; + list=p; + ++list_cnt; + } + closedir(dirp); + } + + a=malloc( (list_cnt+1)*sizeof(char *)); + + if (!a) + { + while (list) + { + p=list; + list=p->next; + free(p->filename); + free(p); + } + return (NULL); + } + + list_cnt=0; + + while (list) + { + p=list; + list=p->next; + a[list_cnt]=p->filename; + free(p); + ++list_cnt; + } + a[list_cnt]=0; + return (a); +} + +void maildir_autoresponse_list_free(char **a) +{ + unsigned i; + + for (i=0; a[i]; i++) + free(a[i]); + free(a); +} + +static char *afilename(const char *maildir, const char *filename) +{ + char *p; + + if (!maildir) + maildir="."; + + if (strchr(filename, '.') || strchr(filename, '/') + || strchr(filename, '\'') || strchr(filename, '\"') + || strchr(filename, '*') || strchr(filename, '?') + || strchr(filename, '[') || strchr(filename, ']') + || strchr(filename, ' ') || strchr(filename, '\n') + || strchr(filename, '\t') || strchr(filename, '\r') + || strchr(filename, '~') || !*filename) + { + errno=EINVAL; + return (NULL); + } + + p=malloc(strlen(maildir)+strlen(filename)+ + sizeof("/autoresponsesXXXXXXXXXXXXXXXXXXXXXXXX")); + + if (!p) + return (NULL); + return (strcat(strcat(strcpy(p, maildir), "/autoresponses/"), + filename)); +} + +int maildir_autoresponse_validate(const char *maildir, const char *filename) +{ + char *p=afilename(maildir, filename); + + if (!p) + return (-1); + free(p); + return (0); +} + +/* Delete autoreply scratch file (optionally the autoreply file itself) */ + +static void deletefiles(const char *dir, const char *filename, int deleteall) +{ + DIR *dirp=opendir(dir); + struct dirent *de; + int l=strlen(filename); + + if (!dirp) + return; + + while ((de=readdir(dirp)) != 0) + { + char *q; + + if (strncmp(de->d_name, filename, l)) + continue; + + if (de->d_name[l] == 0) + { + if (!deleteall) + continue; + } + else if (de->d_name[l] != '.') + continue; + + q=malloc(strlen(dir)+strlen(de->d_name)+2); + + if (q) + { + unlink(strcat(strcat(strcpy(q, dir), "/"),de->d_name)); + free(q); + } + } + closedir(dirp); +} + +void maildir_autoresponse_delete(const char *maildir, const char *filename) +{ + char *p=afilename(maildir, filename); + + char *q; + + if (!p) + return; + + q=strrchr(p, '/'); + *q++=0; + + deletefiles(p, q, 1); + free(p); +} + +static void read_quota(struct maildir_autoresponse_quota *q, const char *f) +{ + char buf[BUFSIZ]; + FILE *fp; + const char *p; + + if ((fp=fopen(f, "r")) == NULL) + return; + if (fgets(buf, sizeof(buf), fp) == NULL) + { + fclose(fp); + return; + } + fclose(fp); + + for (p=buf; *p; ) + { + if (*p == 'C') + { + q->files=0; + for ( ++p; *p; ++p) + { + if (!isdigit((int)(unsigned char)*p)) + break; + q->files=q->files * 10 + (*p-'0'); + } + continue; + } + + if (*p == 'S') + { + q->bytes=0; + for ( ++p; *p; ++p) + { + if (!isdigit((int)(unsigned char)*p)) + break; + q->bytes=q->bytes * 10 + (*p-'0'); + } + continue; + } + ++p; + } +} + +static int get_quota(struct maildir_autoresponse_quota *q, const char *maildir) +{ + char *p; + + q->files=0; + q->bytes=0; + read_quota(q, AUTORESPONSEQUOTA); + + if (!maildir) + maildir="."; + + p=malloc(strlen(maildir)+sizeof("/autoresponsesquota")); + if (!p) + return (-1); + strcat(strcpy(p, maildir), "/autoresponsesquota"); + read_quota(q, p); + free(p); + return (0); +} + +static void add_quota(struct maildir_autoresponse_quota *q, const char *file, int sign) +{ + struct stat stat_buf; + + if (stat(file, &stat_buf)) + return; + q->files += sign; + q->bytes += (long)stat_buf.st_size*sign; +} + +static int calc_quota(struct maildir_autoresponse_quota *q, const char *maildir) +{ + char *p; + DIR *dirp; + struct dirent *de; + + q->files=0; + q->bytes=0; + + if (!maildir) + maildir="."; + + p=malloc(strlen(maildir)+sizeof("/autoresponses")); + if (!p) + return (-1); + strcat(strcpy(p, maildir), "/autoresponses"); + dirp=opendir(p); + free(p); + if (!dirp) + return (0); + while ((de=readdir(dirp)) != 0) + { + if (strchr(de->d_name, '.')) + continue; + + p=malloc(strlen(maildir)+strlen(de->d_name) + +sizeof("/autoresponses/")); + if (!p) + { + closedir(dirp); + return (-1); + } + + strcat(strcat(strcpy(p, maildir), "/autoresponses/"), + de->d_name); + add_quota(q, p, 1); + free(p); + } + closedir(dirp); + return (0); +} + +static int check_quota(struct maildir_autoresponse_quota *setquota, + struct maildir_autoresponse_quota *newquota) +{ + if (setquota->files > 0 && newquota->files > setquota->files) + return (-1); + if (setquota->bytes > 0 && newquota->bytes > setquota->bytes) + return (-1); + return (0); +} + +FILE *maildir_autoresponse_create(const char *maildir, const char *filename) +{ + char *p=afilename(maildir, filename); + FILE *fp; + char *q; + + if (!p) + return (NULL); + + strcat(p, ".tmp"); + fp=fopen(p, "w"); + + if (!fp) /* Perhaps we need to create the autoresponse dir? */ + { + q=strrchr(p, '/'); + *q=0; + mkdir(p, 0700); + *q='/'; + fp=fopen(p, "w"); + } + free(p); + return (fp); +} + +int maildir_autoresponse_create_finish(const char *maildir, const char *filename, + FILE *fp) +{ + char *p, *q; + struct maildir_autoresponse_quota set_quota, new_quota; + + fclose(fp); + p=afilename(maildir, filename); + + if (!p) + return (0); + q=strdup(p); + + if (q) + { + if (get_quota(&set_quota, maildir) + || calc_quota(&new_quota, maildir)) + { + strcat(p, ".tmp"); + unlink(p); + free(q); + free(p); + return (-1); + } + + add_quota(&new_quota, p, -1); + strcat(p, ".tmp"); + add_quota(&new_quota, p, 1); + if (check_quota(&set_quota, &new_quota)) + { + unlink(p); + free(p); + free(q); + errno=ENOSPC; + return (-1); + } + + rename(p, q); + free(q); + } + free(p); + return (0); +} + +FILE *maildir_autoresponse_open(const char *maildir, const char *filename) +{ + char *p=afilename(maildir, filename); + FILE *fp; + + if (!p) + return (NULL); + + fp=fopen(p, "r"); + free(p); + return (fp); +} |
