I've made one change to the patch below, which is the
same one I posted yesterday.

This patch makes public the following two functions
in maildirquota.c:

int readdomainquota(const char *dir, long *sizep, int *cntp);
int readuserquota(const char* dir, long *sizep, int *cntp);

These two functions read the current Maildir++ quota usage
for a domain/user given the domain or user directory.
It *adds* to the current values pointed to by sizep & cntp
the size/msgcount used by the specified domain/user.

They return 0 on success, -1 on failure.  errno would be
set to EAGAIN if the contents of the directory changed
during the calculation.

In short, the attached patch enforces the quota limits
specified in the qmailadmin-limits file/table in the vdelivermail
program.  I figured it might be better to expose the above
two functions as well, therefore the updated patch.

Thanks,

Brian

------------- Begin Forwarded Message -------------



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

------------- End Forwarded Message -------------



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 *);
+ int readdomainquota(const char *dir, long *sizep, int *cntp);
+ 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 (readdomainquota(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);
+ }
+ 
+ int readdomainquota(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;
+ }
+ 
+ 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