Since there's been alot of hype about domain quotas,
I've put my changes in the attached patch file.  This
will patch vpopmail-5.3.16 (maildirquota.c and vdelivermail.c).
There's a new file vqmaillocal.c that apparently doesn't
use Maildir++ quotas, so I didn't touch that.

The CPU usage is negligible (I saw 0-20 ms).  With this patch,
another function is added to maildirquota.c called 
domain_over_maildirquota() that extracts the domain info from
the given end-user Maildir and returns 1 if the domain is already
at/over quota, or the new message would exceed the domains quota.

Note that this patch *only* enforces Maildir++ quotas (both
size and count), and not system quotas.  The diskquota parameter
of the vlimits structure is in MB (NOT BYTES), and the maxmsgcount parameter
specifies the max messages for the whole domain.  If either value
is less than or equal to 0, it is treated as unlimited.

Ken/Bill - I've been running this for about a month now with the
published vlimits API and it seems to work well with little CPU overhead.  
All deliveries still seem to be under 1 second.  I've stripped out the
system quotas implementation and made it simply Maildir++ quota compliant.

Thanks,

Brian
Common subdirectories: vpopmail-5.3.16/attic and vpopmail-5.3.16.new/attic
Common subdirectories: vpopmail-5.3.16/cdb and vpopmail-5.3.16.new/cdb
Common subdirectories: vpopmail-5.3.16/contrib and vpopmail-5.3.16.new/contrib
Common subdirectories: vpopmail-5.3.16/convert and vpopmail-5.3.16.new/convert
Common subdirectories: vpopmail-5.3.16/doc and vpopmail-5.3.16.new/doc
Common subdirectories: vpopmail-5.3.16/ldap and vpopmail-5.3.16.new/ldap
diff -c vpopmail-5.3.16/maildirquota.c vpopmail-5.3.16.new/maildirquota.c
*** vpopmail-5.3.16/maildirquota.c      Wed Oct 23 15:53:36 2002
--- vpopmail-5.3.16.new/maildirquota.c  Wed Feb 19 17:55:36 2003
***************
*** 29,34 ****
--- 29,35 ----
  #include <errno.h>
  #include <time.h>
  #include <sys/uio.h>
+ #include "vlimits.h"
  #include "maildirquota.h"
  #include "config.h"
  
***************
*** 46,51 ****
--- 47,54 ----
        long xtra_size,
        int xtra_cnt, int *percentage);
  static int docount(const char *, time_t *, off_t *, unsigned *);
+ static int domreadquota(const char *dir, long *sizep, int *cntp);
+ static int readuserquota(const char* dir, long *sizep, int *cntp);
  int deliver_quota_warning(const char *dir);
  
  #define  NUMBUFSIZE      60
***************
*** 55,60 ****
--- 58,253 ----
  #define       MDQUOTA_COUNT   'C'     /* Total number of messages in maildir */
  
  
+ /* bk: add domain limits functionality */
+ int domain_over_maildirquota(const char *userdir)
+ {
+ struct  stat    stat_buf;
+ int     ret_value = 0;
+ char  *domdir=(char *)malloc(strlen(userdir)+1);
+ char  *p;
+ char  domain[256];
+ unsigned long size = 0;
+ unsigned long maxsize = 0;
+ int   cnt = 0;
+ int   maxcnt = 0;
+ struct vlimits limits;
+ 
+         if (fstat(0, &stat_buf) == 0 && S_ISREG(stat_buf.st_mode) &&
+                 stat_buf.st_size > 0)
+         {
+ 
+               /* locate the domain directory */
+               strcpy(domdir, userdir);
+               if ((p = strstr(domdir, "/Maildir/")) != NULL)
+               {
+                       while (*(--p) != '/')
+                               ;
+                       *(p+1) = '\0';
+               }
+ 
+               /* locate the domainname */
+               while (*(--p) != '/')
+                       ;
+               strncpy(domain, ++p, sizeof(domain));
+               if ((p = strchr(domain, '/')) != NULL)
+                       *p = '\0';
+ 
+               /* get the domain quota */
+               if (vget_limits(domain, &limits))
+               {
+                       free(domdir);
+                       return 0;
+               }
+ 
+               /* convert from MB to bytes */
+               maxsize = limits.diskquota * 1024 * 1024;
+               maxcnt = limits.maxmsgcount;
+ 
+               /* get the domain usage */
+               if (domreadquota(domdir, &size, &cnt))
+               {
+                       free(domdir);
+                       return -1;
+               }
+ 
+               /* check if either quota (size/count) would be exceeded */
+               if (maxsize > 0 && (size + stat_buf.st_size) > maxsize)
+               {
+                       ret_value = 1;
+               }
+               else if (maxcnt > 0 && cnt >= maxcnt)
+               {
+                       ret_value = 1;
+               }
+         }
+ 
+       free(domdir);
+ 
+         return(ret_value);
+ }
+ 
+ static int domreadquota(const char *dir, long *sizep, int *cntp)
+ {
+ int tries;
+ char  checkdir[256];
+ DIR   *dirp;
+ struct dirent *de;
+ 
+ 
+       if (dir == NULL || sizep == NULL || cntp == NULL)
+               return -1;
+ 
+       *sizep = 0;
+       *cntp = 0;
+ 
+       dirp=opendir(dir);
+       while (dirp && (de=readdir(dirp)) != 0)
+       {
+               if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+                       continue;
+ 
+               strncpy(checkdir, dir, sizeof(checkdir));
+               strncat(checkdir, de->d_name, sizeof(checkdir));
+               strncat(checkdir, "/Maildir/", sizeof(checkdir));
+               tries = 5;
+               while (tries-- && readuserquota(checkdir, sizep, cntp))
+               {
+                       if (errno != EAGAIN)
+                               return -1;
+                       sleep(1);
+               }
+               if (tries <= 0)
+                       return -1;
+       }
+       if (dirp)
+       {
+ #if   CLOSEDIR_VOID
+               closedir(dirp);
+ #else
+               if (closedir(dirp))
+               {
+                       return (-1);
+               }
+ #endif
+       }
+ 
+       return 0;
+ }
+ 
+ static int readuserquota(const char* dir, long *sizep, int *cntp)
+ {
+ time_t        tm;
+ time_t        maxtime;
+ DIR   *dirp;
+ struct dirent *de;
+ 
+       maxtime=0;
+ 
+       if (countcurnew(dir, &maxtime, sizep, cntp))
+       {
+               return (-1);
+       }
+ 
+       dirp=opendir(dir);
+       while (dirp && (de=readdir(dirp)) != 0)
+       {
+               if (countsubdir(dir, de->d_name, &maxtime, sizep, cntp))
+               {
+                       closedir(dirp);
+                       return (-1);
+               }
+       }
+       if (dirp)
+       {
+ #if   CLOSEDIR_VOID
+               closedir(dirp);
+ #else
+               if (closedir(dirp))
+               {
+                       return (-1);
+               }
+ #endif
+       }
+ 
+       /* make sure nothing changed while calculating this... */
+       tm=0;
+ 
+       if (statcurnew(dir, &tm))
+       {
+               return (-1);
+       }
+ 
+       dirp=opendir(dir);
+       while (dirp && (de=readdir(dirp)) != 0)
+       {
+               if (statsubdir(dir, de->d_name, &tm))
+               {
+                       closedir(dirp);
+                       return (-1);
+               }
+       }
+       if (dirp)
+       {
+ #if   CLOSEDIR_VOID
+               closedir(dirp);
+ #else
+               if (closedir(dirp))
+               {
+                       return (-1);
+               }
+ #endif
+       }
+ 
+       if (tm != maxtime)      /* Race condition, someone changed something */
+       {
+               errno=EAGAIN;
+               return (-1);
+       }
+       errno=0;
+ 
+       return 0;
+ }
+ 
  int user_over_maildirquota( const char *dir, const char *q)
  {
  struct  stat    stat_buf;
Common subdirectories: vpopmail-5.3.16/oracle and vpopmail-5.3.16.new/oracle
diff -c vpopmail-5.3.16/vdelivermail.c vpopmail-5.3.16.new/vdelivermail.c
*** vpopmail-5.3.16/vdelivermail.c      Wed Oct 23 16:42:36 2002
--- vpopmail-5.3.16.new/vdelivermail.c  Wed Feb 19 15:56:58 2003
***************
*** 93,102 ****
  /* functions in maildirquota.c */
  int deliver_quota_warning(const char *dir, const char *q);
  int user_over_maildirquota(char *address, char *quota);
  void add_warningsize_to_quota( const char *dir, const char *q);
  char *format_maildirquota(const char *q);
  
- 
  static char local_file[156];
  static char local_file_new[156];
  
--- 93,102 ----
  /* functions in maildirquota.c */
  int deliver_quota_warning(const char *dir, const char *q);
  int user_over_maildirquota(char *address, char *quota);
+ int domain_over_maildirquota(char *userdir);
  void add_warningsize_to_quota( const char *dir, const char *q);
  char *format_maildirquota(const char *q);
  
  static char local_file[156];
  static char local_file_new[156];
  
***************
*** 494,499 ****
--- 494,522 ----
              }
          }
  
+       /* bk: check domain quota */
+         if (domain_over_maildirquota(address)==1)
+         {
+             /* check for over quota message in domain */
+             sprintf(tmp_file, "%s/.over-quota.msg",TheDomainDir);
+             if ( (fs=fopen(tmp_file, "r")) == NULL ) {
+                 /* if no domain over quota then check in vpopmail dir */
+                 sprintf(tmp_file, "%s/domains/.over-quota.msg",VPOPMAILDIR);
+                 fs=fopen(tmp_file, "r");
+             }
+ 
+             if ( fs == NULL ) {
+                 printf("domain is over quota\n");
+             } else {
+                 while( fgets( tmp_file, 256, fs ) != NULL ) {
+                     fputs(tmp_file, stdout);
+                 }
+                 fclose(fs);
+             }
+             deliver_quota_warning(address, format_maildirquota(quota));
+             return(-1);
+         }
+ 
          /* Format the email file name */
          gethostname(hostname,sizeof(hostname));
          pid=getpid();

Reply via email to