diff -uNr release-20010228/src/local/maildir.c release-20010228.patched/src/local/maildir.c --- release-20010228/src/local/maildir.c Tue Jan 30 21:30:03 2001 +++ release-20010228.patched/src/local/maildir.c Mon Aug 13 11:59:04 2001 @@ -62,11 +62,86 @@ #include #include #include +#include +#include +#include +#include +#if defined(NeXT) +#include +#define dirent direct +#endif /* NeXT */ +#include /* Application-specific. */ #include "local.h" +static long calculate_maildir_usage( char *newd, char *curd ) +{ + long size = 0; + char filename[512]; + struct dirent *dp; + struct stat fileinfo; + DIR *dirp; + + + if ( (dirp=opendir((char *)curd)) != NULL) { + while ((dp = readdir(dirp)) != NULL) { + if (dp->d_name[0]=='.') continue; + snprintf(filename,512,"%s%s",curd,dp->d_name); + stat(filename, &fileinfo); + size += fileinfo.st_size; + } /* while */ + closedir(dirp); + } /* dirp != NULL */ + + if ( (dirp=opendir((char *)newd)) != NULL) { + while ((dp = readdir(dirp)) != NULL) { + if (dp->d_name[0]=='.') continue; + snprintf(filename,512,"%s%s",newd,dp->d_name); + stat(filename, &fileinfo); + size += fileinfo.st_size; + } /* while */ + closedir(dirp); + } /* dirp != NULL */ + + return(size); +} + +static long lookup_mailbox_size( char *map_names, char *user ) +{ + const char *value; + static MAPS *m=NULL; + + if (!m) + m = maps_create( + "mailbox size lookup", + map_names, + DICT_FLAG_LOCK + ); + value = maps_find(m, user, DICT_FLAG_FIXED); + return(value ? atol(value) : -1); +} + +static long mailbox_size( char *user ) +{ + long size; + + /* lookup per-user mailbox size */ + size = *var_mailbox_size_map ? + lookup_mailbox_size(var_mailbox_size_map, user) : + -1; + + /* no var_mailbox_size_map or per-user case specified. apply default */ + if( size == -1 ) + size = var_default_mailbox_size; + + /* turn into bytes */ + size <<= 10; + + return(size); +} + /* deliver_maildir - delivery to maildir-style mailbox */ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path) @@ -83,6 +158,11 @@ int status; int copy_flags; static int count; + int rec_type; + VSTRING *buffer; + long msg_size; + long size_limit; + long maildir_size; /* * Make verbose logging easier to understand. @@ -95,6 +175,27 @@ * Initialize. Assume the operation will fail. Set the delivered * attribute to reflect the final recipient. */ + buffer = vstring_alloc(10); + rec_type = 0; + msg_size = 0; + size_limit = mailbox_size(state.msg_attr.user); + if (size_limit) + if (msg_verbose) + msg_info("%s: maildir size limit for %s is %ld bytes.", + myname, state.msg_attr.user, size_limit); + if (vstream_fseek(state.msg_attr.fp, (off_t) 0, SEEK_SET) < 0) + msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp)); + for (;;) { + rec_type = rec_get(state.msg_attr.fp, buffer, 0); + if (rec_type == REC_TYPE_ERROR) + msg_fatal("record read error"); + if (rec_type == REC_TYPE_EOF) + break; + if (rec_type == REC_TYPE_SIZE) { + msg_size = atol(vstring_str(buffer)); + break; + } + } if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0) msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp)); state.msg_attr.delivered = state.msg_attr.recipient; @@ -137,6 +238,13 @@ || (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) { vstring_sprintf(why, "create %s: %m", tmpfile); } else { + maildir_size = calculate_maildir_usage(newdir, curdir); + /* Check if new message would put user over max maildir size */ + if (size_limit && msg_size + maildir_size > size_limit) { + vstream_fclose(dst); + vstring_sprintf(why, "Maildir is over size limit (m=%ld;t=%ld;l=%ld)",msg_size,msg_size+maildir_size,size_limit); + errno = EFBIG; + } else { if (mail_copy(COPY_ATTR(state.msg_attr), dst, copy_flags, "\n", why) == 0) { if (sane_link(tmpfile, newfile) < 0 && (errno != ENOENT @@ -147,6 +255,7 @@ status = 0; } } + } /* size_limit else */ if (unlink(tmpfile) < 0) msg_warn("remove %s: %m", tmpfile); }