📄 maildirquota.c
字号:
/* * $Id: maildirquota.c,v 1.7 2003/12/19 05:16:36 tomcollins Exp $ * Copyright (C) 1999-2003 Inter7 Internet Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * *//* include files */#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <dirent.h>#include <errno.h>#include <time.h>#include <sys/uio.h>#include "vauth.h"#include "vpopmail.h"#include "vlimits.h"#include "maildirquota.h"#include "config.h"/* private functions - no name clashes with courier */static char *makenewmaildirsizename(const char *, int *);static int countcurnew(const char *, time_t *, off_t *, unsigned *);static int countsubdir(const char *, const char *, time_t *, off_t *, unsigned *);static int statcurnew(const char *, time_t *);static int statsubdir(const char *, const char *, time_t *);static int doaddquota(const char *, int, const char *, long, int, int);static int docheckquota(const char *dir, int *maildirsize_fdptr, const char *quota_type, long xtra_size, int xtra_cnt, int *percentage);static int docount(const char *, time_t *, off_t *, unsigned *);static int maildir_checkquota(const char *dir, int *maildirsize_fdptr, const char *quota_type, long xtra_size, int xtra_cnt);static int maildir_addquota(const char *dir, int maildirsize_fd, const char *quota_type, long maildirsize_size, int maildirsize_cnt);static int maildir_safeopen(const char *path, int mode, int perm);static char *str_pid_t(pid_t t, char *arg);static char *str_time_t(time_t t, char *arg);static int maildir_parsequota(const char *n, unsigned long *s);#define NUMBUFSIZE 60#define MDQUOTA_SIZE 'S' /* Total size of all messages in maildir */#define MDQUOTA_BLOCKS 'B' /* Total # of blocks for all messages in maildir -- NOT IMPLEMENTED */#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;char domdir[MAX_PW_DIR];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 */ p = maildir_to_email(userdir); if (p == NULL) return -1; p = strchr (p, '@'); if (p == NULL) return -1; strcpy(domain, p + 1); /* get the domain quota */ if (vget_limits(domain, &limits)) return 0; /* convert from MB to bytes */ maxsize = limits.diskquota * 1024 * 1024; maxcnt = limits.maxmsgcount; if (vget_assign (domain, domdir, sizeof(domdir), NULL, NULL) == NULL) return -1; /* get the domain usage */ if (readdomainquota(domdir, &size, &cnt)) return -1; /* check if either quota (size/count) would be exceeded */ if (maxsize > 0 && (size + stat_buf.st_size) > maxsize) return 1; else if (maxcnt > 0 && cnt >= maxcnt) return 1; } return 0;}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;#ifdef USERS_BIG_DIR if (strlen(de->d_name) == 1) { /* recursive call for hashed directory */ snprintf (checkdir, sizeof(checkdir), "%s/%s", dir, de->d_name); if (readdomainquota (checkdir, sizep, cntp) == -1) { return -1; } } else#endif { snprintf(checkdir, sizeof(checkdir), "%s/%s/Maildir/", dir, de->d_name); 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 wrapreaduserquota(const char* dir, off_t *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 readuserquota(const char* dir, long *sizep, int *cntp){ int retval; off_t s; s = (off_t) *sizep; retval = wrapreaduserquota(dir, &s, cntp); *sizep = (long) s; return retval;}int user_over_maildirquota( const char *dir, const char *q){struct stat stat_buf;int quotafd;int ret_value; if (fstat(0, &stat_buf) == 0 && S_ISREG(stat_buf.st_mode) && stat_buf.st_size > 0 && *q) { if (maildir_checkquota(dir, "afd, q, stat_buf.st_size, 1) && errno != EAGAIN) { if (quotafd >= 0) close(quotafd); ret_value = 1; } else { maildir_addquota(dir, quotafd, q, stat_buf.st_size, 1); if (quotafd >= 0) close(quotafd); ret_value = 0; } } else { ret_value = 0; } return(ret_value);}void add_warningsize_to_quota( const char *dir, const char *q){struct stat stat_buf;int quotafd;char quotawarnmsg[500]; snprintf(quotawarnmsg, sizeof(quotawarnmsg), "%s/%s/.quotawarn.msg", VPOPMAILDIR, DOMAINS_DIR); if (stat(quotawarnmsg, &stat_buf) == 0 && S_ISREG(stat_buf.st_mode) && stat_buf.st_size > 0 && *q) { maildir_checkquota(dir, "afd, q, stat_buf.st_size, 1); if (quotafd >= 0) close(quotafd); maildir_addquota(dir, quotafd, q, stat_buf.st_size, 1); if (quotafd >= 0) close(quotafd); }}/* Read the maildirsize file */static int maildirsize_read(const char *filename, /* The filename */ int *fdptr, /* Keep the file descriptor open */ off_t *sizeptr, /* Grand total of maildir size */ unsigned *cntptr, /* Grand total of message count */ unsigned *nlines, /* # of lines in maildirsize */ struct stat *statptr) /* The stats on maildirsize */{ char buf[5120]; int f; char *p; unsigned l; int n; int first; if ((f=maildir_safeopen(filename, O_RDWR|O_APPEND, 0)) < 0) return (-1); p=buf; l=sizeof(buf); while (l) { n=read(f, p, l); if (n < 0) { close(f); return (-1); } if (n == 0) break; p += n; l -= n; } if (l == 0 || fstat(f, statptr)) /* maildir too big */ { close(f); return (-1); } *sizeptr=0; *cntptr=0; *nlines=0; *p=0; p=buf; first=1; while (*p) { long n=0; int c=0; char *q=p; while (*p) if (*p++ == '\n') { p[-1]=0; break; } if (first) { first=0; continue; } sscanf(q, "%ld %d", &n, &c); *sizeptr += n; *cntptr += c; ++ *nlines; } *fdptr=f; return (0);}static int qcalc(off_t s, unsigned n, const char *quota, int *percentage){off_t i;int spercentage=0;int npercentage=0; errno=ENOSPC; while (quota && *quota) { int x=1; if (*quota < '0' || *quota > '9') { ++quota; continue; } i=0; while (*quota >= '0' && *quota <= '9') i=i*10 + (*quota++ - '0'); switch (*quota) { default: if (i < s) { *percentage=100; return (-1); } /* ** For huge quotas, over 20mb, ** divide numerator & denominator by 1024 to prevent ** an overflow when multiplying by 100 */ x=1; if (i > 20000000) x=1024; spercentage = i ? (s/x) * 100 / (i/x):100; break; case 'C': if (i < n) { *percentage=100; return (-1); } /* Ditto */ x=1; if (i > 20000000) x=1024; npercentage = i ? ((off_t)n/x) * 100 / (i/x):100; break; } } *percentage = spercentage > npercentage ? spercentage:npercentage; return (0);}static int maildir_checkquota(const char *dir, int *maildirsize_fdptr, const char *quota_type, long xtra_size, int xtra_cnt){int dummy; return (docheckquota(dir, maildirsize_fdptr, quota_type, xtra_size, xtra_cnt, &dummy));}int vmaildir_readquota(const char *dir, const char *quota_type){int percentage=0;int fd=-1; (void)docheckquota(dir, &fd, quota_type, 0, 0, &percentage); if (fd >= 0) close(fd); return (percentage);}static int docheckquota(const char *dir, int *maildirsize_fdptr, const char *quota_type, long xtra_size, int xtra_cnt, int *percentage){char *checkfolder=(char *)malloc(strlen(dir)+sizeof("/maildirfolder"));char *newmaildirsizename;struct stat stat_buf;int maildirsize_fd;off_t maildirsize_size;unsigned maildirsize_cnt;unsigned maildirsize_nlines;int n;time_t tm;time_t maxtime;DIR *dirp;struct dirent *de; if (checkfolder == 0) return (-1); *maildirsize_fdptr= -1; strcat(strcpy(checkfolder, dir), "/maildirfolder"); if (stat(checkfolder, &stat_buf) == 0) /* Go to parent */ { strcat(strcpy(checkfolder, dir), "/.."); n=docheckquota(checkfolder, maildirsize_fdptr, quota_type, xtra_size, xtra_cnt, percentage); free(checkfolder); return (n); } if (!quota_type || !*quota_type) return (0); strcat(strcpy(checkfolder, dir), "/maildirsize"); time(&tm); if (maildirsize_read(checkfolder, &maildirsize_fd, &maildirsize_size, &maildirsize_cnt, &maildirsize_nlines, &stat_buf) == 0) { n=qcalc(maildirsize_size+xtra_size, maildirsize_cnt+xtra_cnt, quota_type, percentage); if (n == 0) { free(checkfolder); *maildirsize_fdptr=maildirsize_fd; return (0); } close(maildirsize_fd);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -