Индивидуальное квотирование виртуальных почтовых ящиков для Postfix (postfix quota limit patch virtual patch)
Ключевые слова: postfix, quota, limit, patch, virtual, patch,  (найти похожие документы)
From: -=VD= <vitaliy at tdauto.ru>
Date: Mon, 20 Sep 2004 18:21:07 +0000 (UTC)
Subject: Индивидуальное квотирование виртуальных почтовых ящиков для Postfix
Оригинал: http://vitaliy.tdauto.ru   
Postfix 2. xx индивидуальное квотирование виртуальных почтовых ящиков
    Патч Postfix 2.xx + virtual + maildir + MySQL/PostgreSQL/..
                     (проверен postfix 2.0.11 - 2.0.16)
                  © 2003 by -=VD= http://vitaliy.tdauto.ru
Копию патча postfix2.0pvq.gz можно скачать здесь: 
      ftp://ftp.opennet.ru/pub/net/mail/postfix_quota/
Задача:
   необходимо выставлять виртуальным пользователям Postfix "живущим", к
   примеру, в MySQL/PostgreSQL, индивидуальную квоту. Те патчи что я
   нашел на http://www.postfix.org все же меня не совсем устроили, т.к.
   захотелось решать все это на "лету" не принимая сообщения(сэкономим
   трафик), но при этом и отправитель и получатель должны уведомляться об
   этом "скорбном" факте.
Для реализации задачи использовались:
   VMware + FreeBSD 4.8 + KDE + среда разработки KDevelop + оболочка
   отладчика KDbg + gdb 5.22 (gdb не меньше 5.22 т.к. все что младше, с
   KDbg у меня не работало).
    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.
    - изменения котрым подверглись исходники в конце документа
    - сам patch postfix2.0pvq.gz к сожалению утерян, сайт автора недоступен
                 (проверен Postfix 2.0.11 - Postfix 2.0.16)
   BUGFIXES:
   19.11.03 -> Устранена ошибка virtual_quota_user_message = пустое
   значение -> вызывало "fatal: bad string length (0 < 1):"
   19.11.03 -> Устранена проблема при совместной установке с патчем
   ssl/tls -> они не любили друг друга(помирил)
   19.11.03 -> Устранена ошибка вызывавшая возможное не срабатывание
   процедуры проверки квоты -> пользователь с локальным именем мог не
   квотироваться.
Обсуждение всех возникавших проблем здесь:
   http://www.opennet.me/openforum/vsluhforumID3/2827.html
   Отдельное спасибо HFSC помогшему устранить некоторые ошибки в логике
   кода.
   Что в результате получилось:
   После патча в main.cf, примерно как ниже, можно добавить 4 новых
   параметра:
       virtual_quota_user_message_limit = 2048
       virtual_quota_user_bounce = yes
       virtual_quota_user_message = /../../../ваш _ файл
       virtual_mailbox_limit_maps = /../../../ваш _ файл
   Из них взаимосвязаны только между собой:
       virtual_quota_user_bounce = yes ( если = no 2 нижних просто неактуальны )
       virtual_quota_user_message = /../../../ваш _ файл
       virtual_quota_user_message_limit = 2048
       virtual_mailbox_limit_maps = /../../../ваш _ файл включает сам механизм 
                               квотирования,  однако, при этом должны быть 
                               определены еще два postfix параметра:
           virtual_mailbox_maps = /../../../ваш_файл
           virtual_mailbox_base = /../../../ваш_файл
   ВНИМАНИЕ!!! Патч, на сегодняшний день, проверяет объем директори
   пользователя от имени дочернего процесса postfix(master) -> smtpd, 
   поэтому права на maildir проверяемого пользователя должны совпадать с
   правами запуска smtpd. Упрощенно, если владельца virtual_mailbox_base
   определить отличного от mail_owner = ваше_значение, для патча не
   будет возможности выяснить текущий объем maildir пользователя и
   создать ему соответствующее уведомление. На работоспособности postfix
   в целом, это конечно вообще никак не отразится, однако квота
   отрабатывать не будет.
   
   
   Возможно через некоторое время я все же решу как устранить данное
   ограничение. Хотя в принципе, на сколько я знаю, для многих это
   типичная конфигурация postfix когда mail_owner и владелец на
   virtual_mailbox_base одинаковы, но... делать так делать, было бы
   время :)
   Ниже, моя врезка в main.cf:
       virtual_mailbox_base = /var/mail/virtual
       virtual_mailbox_maps = mysql:/usr/local/etc/postfix/sql/users.cf
       # Virtual quota
       virtual_mailbox_limit_maps =
       mysql:/usr/local/etc/postfix/sql/mail_limit.cf
       virtual_quota_user_bounce = yes
       virtual_quota_user_message = /usr/local/etc/postfix/sql/message.cf
       virtual_quota_user_message_limit = 2048
   - virtual_mailbox_limit_maps по умолчанию = ""
   Путь к стандартному, вида postfix, файлу ..._maps. Опделяет
   дополнительное поле квоты.
   - virtual_quota_user_bounce по умолчанию = no
   Отсылать/нет служебное сообщение пользователю о превышении квоты.
   Изначально воспроизводится из шаблона, после чего в него добавляются
   строчки вида:
      10.10.03 | mail from: [email protected]
   - virtual_quota_user_message по умолчанию = ""
   Путь к файлу шаблона служебного сообщения.
   - virtual_quota_user_message_limit по умолчанию = 1024
   Максимальный размер(байт) файла служебного сообщения.
   Реакция postfix на индивидуальную квоту, для отправителя/пользователья:
   Если индивидуальная квота пользователем превышена, отправителю еще до
   передачи данных ответ будет в виде:
       "4 хх /5 хх Sorry, the user <[email protected]> has overdrawn diskspace
        quota, please try again later."
   (Захотите, переопределите это сообщение в исходниках.)
   Пользователь после превышения квоты получает одно служебное сообщение,
   созданное из шаблона и размером не больше чем virtual_quota_user_message_limit, 
   в нем будет отражено когда и откуда  почта не принята.
   
   В самом пиковом варианте, после превышения квоты, пользователь
   максимально сможет получить в свою maildir объем: (его квота - 1 байт)
   + (максимальный объем одного принимаемого сообщения), это связано с
   тем, что объем входящей почты в начале сеанса НЕ ВСЕГДА число
   определенное.
Установка патча и настройка дополнительных параметров на примере 
postfix 2.0.16 + MySQL + Ваши_модули:
   Установку и настройку postfix для работы с виртуальными пользователями
   я здесь не описываю, т.к. этому уже посвящено несколько довольно
   подробных описаний, вот ссылки на некотрые из них:
   http://raven.elk.ru/unix/how-to/postfix2+cyrus-sasl2+kav+spamassassin+
   courier-imap+tls+mysql+FreeBSD4/postfix2+cyrus-sasl2+kav+spamassassin+
   courier-imap+tls+mysql+FreeBSD4.html
   http://www.opennet.me/base/net/postgresql_postfix.txt.html
   Одним словом, я предполагаю что postfix у Вас уже установлен и
   настроен и Вы так же имеете представление зачем Вам этот патч :)
   Скачиваем отсюда патч postfix2.0pvq.gz распаковываем,
       cp /куда_вы_распаковали/postfix2.0pvq /там_где_исходник/postfix 2.0.16
       cd /там_где_исходник/postfix 2.0.16
       patch < postfix2.0pvq
   Патч может отработать в зависимости от версии postfix, c offset в 7
   позиций (это конечно если патч наложен на "чистый" исходник).
   Пересоберем postfix с Вашими параметрами типа SASL MySQL и т.д.
   Собрался, значит, все готово.
   Дальше можно даже и не устанавливать его с помощью make install, т.е.
   если Вы пересобрали с параметрами что и в Вашем рабочем postfix, то
   изменилось всего 3 бинарника:
       ./src/smtpd/smtpd
       ./src/postconf/postconf
       ./src/cleanup/cleanup
   Ну а в прочем, make install хорошо сам во всем разберется (лишнего не
   удалит).
   В общем случае, осталось только отредактировать main.cf на предмет
   нововведений и все, однако, прежде чем его отредактировать,
   разбираемся на предмет текущего способа проверки пользователей и
   maildir.
   Тут дело в том, что патч отработает только при способе проверки(не
   путать с транспортом) определенном в postfix как virtual, плюс при
   условии, что у пользователей maildir, а не mailbox. На все другие
   варианты конфигурации и способы доставки этот патч влияния не
   оказывает.
   Разбираемся как обстоят дела с текущим способом проверки:
       telnet dew.tdauto.ru 25
       220 dew.tdauto.ru ESMTP Postfix (2.0.16)
       HELO vitaliy.tdauto.ru
       250 dew.tdauto.ru
       MAIL FROM: <[email protected]>
       250 Ok
       RCPT TO: <[email protected]>
       550 <[email protected]>: User unknown in virtual mailbox table
   Я взял заведомо несуществующего у меня пользователя и ключевой момент
   тут как раз "... in virtual mailbox table " т.е. " virtual mailbox
   table " , это то что нам нужно, соответственно этот патч отработает.
   Другими словами, в качестве карты maildir пользователей, должен быть
   определен:
       virtual_mailbox_maps = /.../ваш _ файл
   А вот иные варианты ответов, в которых патч не сработает:
       550 <[email protected]>: User unknown in local recipient table
       550 <[email protected]>: User unknown in relay recipient table
   А вообще, по "старшинству", адрес postfix проверяет так:
   Сперва смотрит просто на наличие как такового в:
       1. recipient_canonical_maps
       2. canonical_maps
       3. virtual_alias_maps
   Если адрес среди них есть, то postfix его принимает с 250 ОК.
   Если в тех что выше, ничего не найдено, проверяются с "пристрастием" и
   в жесткой зависимости от типа проверки:
       4. local_recipient_maps
       5. virtual_mailbox_maps
       6. relay_recipient_maps
   Тут все наоборот, если способ проверки определен, а адреса нет,
   postfix ничего не принимает и дает отбой 4хх/5хх....
   На сегодня этот патч отрабатывает virtual_alias_maps и virtual_mailbox_maps,
   остальные maps нет и смысла их включать в квотирование пока не вижу.
   Идем дальше - maildir:
   Для postfix, признак того, что у пользователей maildir - '/' в конце
   пути пользовательской почтовой директории.
   Кроме maildir, в самом конфиге, еще конечно должен быть:
   virtual_mailbox_base = /вашему/пути/к/maildir
   В общем случае:
   Квота сработает если:
       1. virtual_mailbox_maps = /.../ваш _ файл
       2. virtual_mailbox_base = /вашему/пути/к/maildir
       3. virtual_mailbox_limit_maps = /../../../ваш _ файл
       4. У пользователей путь к почте ../../vasa/
       5. Поле квоты в таблице не пустое.
   Не сработает если:
       1. local_recipient_maps = /.../ваш _ файл
       2. Или у пользователей путь к почте ../../vasa
       3. Или virtual_mailbox_limit_maps закомментарено
       4. Или поле квоты в таблице пустое
   Или этот адрес есть в:
       5. recipient_canonical_maps = /.../ваш _ файл
       6 . canonical_maps = /.../ваш _ файл
   Редакируем main.cf
   Добавляем туда примерно следующее(с Вашими путями конечно):
       # Virtual quota
       virtual_mailbox_limit_maps =
       mysql:/usr/local/etc/postfix/sql/mail_limit.cf
       virtual_quota_user_bounce = yes
       virtual_quota_user_message = /usr/local/etc/postfix/sql/message.cf
       virtual_quota_user_message_limit = 2048
   Добавляем в MySQL таблицу users еще одно поле size типа varchar(у меня
   в users по классической схеме расположены адреса и maildir
   пользователей, Вы соответственно поле size называете как Вам хочется и
   заносите его в вашу таблицу).
   Заносим в size максимальный объем maildir юзера (чило в байтах).
   Соответственно создаем новый конфиг файл, для нашего нового поля size
   (в скобках мои значения)
   /usr/local/etc/postfix/sql/mail_limit.cf
       user = ваш (***)
       password = ваш (***)
       dbname = ваша (mail)
       table = ваша (users)
       select_field = ваш (size)
       where_field = ваш (login)
       additional_conditions = ваши (and expired = '0')
       hosts = ваш (localhost)
   Настраиваем шаблон сообщения message.cf для пользователя.
   Берем мой здесь и правим как Вам нужно, или создаем файл из шаблона
   что ниже:
   /usr/local/etc/postfix/sql/message.cf
   ----------------------------------------------
       #
       # Шаблон сообщения для пользователя превысившего дисковую квоту.
       # Все строчки кроме тех что начинаются с # - значимые.
       #
       Return-Path: <[email protected]>
       X-Original-To: _RCPT_TO_
       Delivered-To: _RCPT_TO_
       From: <[email protected]>
       To: <_RCPT_TO_>
       Date: _MSG_TIME_
       Content-Type: text/plain; charset=koi8-r
       Content-Transfer-Encoding: 8bit
       Subject: ВНИМАНИЕ ! Прием Вашей почты временно приостановлен.
       На данный момент, выделенное вам дисковое пространство
       полностью израсходовано Вашей входящей почтой.
       Прием на Ваш адрес временно прекращен и будет автоматически
       возобновлен, после того как Вы заберете накопившуюся почту.
       Допустимый объем Вашей директории: _USER_QUOTA_ байт
       Текущий объем Вашей директории: _UDIR_SIZE_ байт
       За это время Вам отсылали сообщения и были уведомлены
       о временной недоступности Вашего адреса:
       _MAIL_FROM_
       С уважением:
       [email protected]
   ----------------------------------------------
   В результате отработки шаблона пользователь получит на свой ящик
   следующее:
   ----------------------------------------------
       Return-Path: <[email protected]>
       X-Original-To: [email protected]
       Delivered-To: [email protected]
       From: <[email protected]>
       To: <[email protected]>
       Date: Mon, 10 Nov 2003 13:25:43 +0300 (MSK)
       Content-Type: text/plain; charset=koi8-r
       Content-Transfer-Encoding: 8bit
       Subject: ВНИМАНИЕ ! Прием Вашей почты временно приостановлен.
    
       На данный момент, выделенное вам дисковое пространство
       полностью израсходовано Вашей входящей почтой.
       Прием на Ваш адрес временно прекращен и будет автоматически
       возобновлен, после того как Вы заберете накопившуюся почту.
       Допустимый объем Вашей директории: 2096000 байт
       Текущий объем Вашей директории: 2099124 байт
       За это время Вам отсылали сообщения и были уведомлены
       о временной недоступности Вашего адреса:
       07.10.03 13:25:57 (MSK) | mail from: [email protected]
       08.10.03 13:30:04 (MSK) | mail from: [email protected]
       09.10.03 15:00:45 (MSK) | mail from: [email protected]
       10.11.03 15:21:37 (MSK) | mail from: [email protected]
       10.11.03 22:26:41 (MSK) | mail from: [email protected]
       С уважением:
       [email protected]
   ----------------------------------------------
   Конфиг готов, проверяем что вышло, предварительно режем у адреса квоту
   до 1 байта и больше 1 байта ему в maildir положим:
       telnet dew.tdauto.ru 25
   220 dew.tdauto.ru ESMTP Postfix (2.0.16)
       HELO vitaliy.tdauto.ru
       250 dew.tdauto.ru
       MAIL FROM: <[email protected]>
       250 Ok
       RCPT TO: <[email protected]>
       550 Sorry, the user <[email protected]> has overdrawn diskspace quota,
       please try again later.
       RCPT TO: <[email protected]>
       550 Sorry, the user <[email protected]> has overdrawn diskspace quota,
       please try again later.
       RCPT TO: <[email protected]>
       550 Sorry, the user <[email protected]> has overdrawn diskspace quota,
       please try again later.
   Получили "550 Sorry..." следовательно отбой по квоте
   работает(намеренно отбой 3 раза, дабы проверить шаблон),
   проверяем ящик [email protected] - там должно быть уведомление из
   нашего шаблона с соответствующими цифрами, локальным временем и тремя:
           xx.xx.xx xx:xx:xx ( ХХХ ) | mail from: [email protected]
   Как отработает квота по алиасам:
   Квота работает только с виртуальными алиасами т.е. с теми что
   находятся в virtual_alias_maps = /../ваш_файл
   К примеру в virtual_alias_maps есть адрес [email protected] и на нем,
   после всех алиасных переопределений, реально найдется 3 пользователя:
       [email protected]
       [email protected]
       [email protected]
   Если все 3 пользователя существуют в virtual_mailbox_maps, то их
   проверят всех.
   Если кого-то там нет, следовательно, квота на него не распространяется
   (почта для него принимается).
   Если у кого нибудь из тех, кто есть в virtual_mailbox_maps квота
   превышена, то он почту не получит, а получит только служебное
   сообщение (все остальные получат почту).
   Если все 3 пользователя есть в virtual_mailbox_maps и все разом
   превысили квоту, отсылавший получит отбой:
   "550 Sorry, the user <[email protected]> has overdrawn diskspace quota,
   please try again later." и все 3 пользователя получат служебное
   сообщение.
   Как срабатывает ограничение на размер служебного сообщения:
       virtual_quota_user_message_limit = 2048
       virtual_quota_user_bounce = yes
   Файл пишется непосредственно пользователю в maildir/new/ c уникальным
   именем и пока он там существует, в него будут добавляться строчки
   вида:
       xx.xx.xx xx:xx:xx ( ХХХ ) | mail from: < ххх @ хххх . хх >
   Я сделал так, дабы не плодить кучу мелких сообщений, по одному на
   каждый отбой.
   Для контроля позиции последней записи и текущего имени служебного
   файла, в корне maildir/ пользователя, создается технический файл
   maildir/postfix.user.quota (вроде это имя ни с кем другим не
   пересекается, по крайней мере мне не известно).
   Так вот, как только размер служебного сообшения в maildir/new/
   становится = virtual_quota_user_message_limit, строчки в него
   перестают добавляться.
   Если же из maildir/new/ служебное сообщение перекочевало в
   maildir/cur/ например, пользователь просмотрел всю новую почту, но так
   ничего не забрав оставил ее на сервере, то на следующий отбой
   связанный с превышением квоты, в maildir/new/ создастся новое
   служебное сообщение, с новым уникальным именем, старое при этом
   соответственно останется в maildir/cur/
   Контролировать размеры всех служебных сообщений во всех мыслимых
   директориях, я думаю, смысла нет... Вряд ли реально произойдет
   ситуация, что пользователь будет настойчиво не забирать живую почту с
   сервера и при этом баловаться ее просмотрами, наблюдая как на
   потихоньку (примерно байт по 700-900 в день в зависимости от шаблона и
   количества ему писавших) добавляются служебные сообщения.
   На этом с настройками квоты все. Думаю что особых затруднений все это
   вызвать не должно.
   В любом случае: vitaliy at tdauto.ru
   ПРИНИМАЕТСЯ ЛЮБАЯ КОНСТРУКТИВНАЯ КРИТИКА.
-----------------------------------------------------------------------------------------------------------
ИЗМЕНЕНИЯ В ИСХОДНИКАХ
./src/global/mail_parms.h
------- Врезка ./src/global/mail_parms.h -------------------------------------------------------------------
  /*
   * Virtual maildir quota.
   */
#define VAR_VIRT_MAILBOX_LIMIT_MAPS	"virtual_mailbox_limit_maps"	/* название в main.cf */
#define DEF_VIRT_MAILBOX_LIMIT_MAPS	""				/* по умолчанию */
extern char *var_virt_mailbox_limit_maps;				/* сама глобальная переменная */
       
#define VAR_VIRT_QUOTA_USER_BOUNCE	"virtual_quota_user_bounce"
#define DEF_VIRT_QUOTA_USER_BOUNCE	0
extern bool var_virt_quota_user_bounce;
 
#define VAR_VIRT_QUOTA_USER_MSG	"virtual_quota_user_message"
#define DEF_VIRT_QUOTA_USER_MSG	""
extern char *var_virt_quota_user_message;
#define VAR_VIRT_QUOTA_USER_MSG_LIMIT	"virtual_quota_user_message_limit"
#define DEF_VIRT_QUOTA_USER_MSG_LIMIT	"1024"
extern char *var_virt_quota_user_message_limit;
 
------- Конец врезки./src/global/mail_parms.h ---------------------------------------------------------------
------- Врезка ./src/smtpd/smtpd.c  -------------------------------------------------------------------------  
  
  /*
   * Virtual Quota.
   */  
char *var_virt_mailbox_limit_maps;
bool var_virt_quota_user_bounce;
char *var_virt_quota_user_message;
char *var_virt_quota_user_message_limit;
char *var_virt_mailbox_base;
	.
	.
/*
/* смотрим main(....)  находим там инициализацию *char и BOOL
/* и добавляем туда новые переменные 
 */
int     main(int argc, char **argv)  
{
	.
	.
	.
static CONFIG_BOOL_TABLE bool_table[] = {  
	.
	.
	.
	VAR_VIRT_QUOTA_USER_BOUNCE, DEF_VIRT_QUOTA_USER_BOUNCE, &var_virt_quota_user_bounce,
	.
	.
	0,
	}; 
	  
static CONFIG_STR_TABLE str_table[] = {
	.
	.
	.
  VAR_VIRT_MAILBOX_LIMIT_MAPS, DEF_VIRT_MAILBOX_LIMIT_MAPS, &var_virt_mailbox_limit_maps, 0, 0,
  VAR_VIRT_QUOTA_USER_MSG, DEF_VIRT_QUOTA_USER_MSG, &var_virt_quota_user_message, 0, 0,
  VAR_VIRT_QUOTA_USER_MSG_LIMIT, DEF_VIRT_QUOTA_USER_MSG_LIMIT, &var_virt_quota_user_message_limit, 1, 0,
  VAR_VIRT_MAILBOX_BASE, DEF_VIRT_MAILBOX_BASE, &var_virt_mailbox_base, 0, 0,  
	0,
	};
}
------- Конец врезки ./src/smtpd/smtpd.c ---------------------------------------------------------------
	
------- Врезка ./src/smtpd/smtpd_check.c ---------------------------------------------------------------  
/* Необходимые дополнительные заголовочные файлы */
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <mail_date.h>
#include <been_here.h>
#include <quote_822_local.h>
#include <get_hostname.h>
/*
/* Новые функции и MAPS	*virt_mailbox_limit_maps;
 */
static  MAPS *virt_mailbox_limit_maps;
ARGV *smtpd_resolve_virt_alias(const char *addr, MAPS *maps, int propagate);
int  smtpd_check_virt_user_quota(SMTPD_STATE *state, const char *addr);
long check_dir_size(char *dirname);
void smtpd_rw_quota_msg(ARGV *user_mess);
void smtpd_rw_templ_msg(ARGV *user_mess, VSTREAM *fpr, VSTREAM *fpw);
void smtpd_rw_user_msg(ARGV *user_mess, VSTREAM *fpw); 
VSTRING *smtpd_cp_key_msg(VSTRING *buffer, char *cut, char *paste);
VSTRING *smtpd_quota_mail_date(time_t when);
/*  void   smtpd_check_init(void) Добавляем инициализацию *virt_mailbox_limit_maps */
void    smtpd_check_init(void) 
{
	.
	.
	.
     virt_mailbox_limit_maps = virtual8_maps_create(VAR_VIRT_MAILBOX_LIMIT_MAPS, var_virt_mailbox_limit_maps,
          DICT_FLAG_LOCK );
}
/*  static int check_rcpt_maps(SMTPD_STATE *state, const char *recipient) */
/*  Добавляем дополнительные вызовы проверки квоты. */
static int check_rcpt_maps(SMTPD_STATE *state, const char *recipient) 
{
    ARGV          *argv = 0;
    VSTRING       *temp1;
    int           cpp = 0;
    int           stat_quota = 0;
  .
	.
	.
   /* Определяем схожий с Postfix макрос. */			
#define MATCHV8(map, rcpt) \
	checkv8_maps_find(state, recipient, map, rcpt)
	.
	.
	.
 /* Проверяем квоты по виртуальным алиасам.  Тут немного добавилось 
но  при этом функциональность прежнего кода полностью сохранена */
	if (MATCH(rcpt_canon_maps, CONST_STR(reply->recipient))
 	|| MATCH(canonical_maps, CONST_STR(reply->recipient)))
  	return (0);
  
     if (MATCH(virt_alias_maps, CONST_STR(reply->recipient))		
     && (reply->flags & RESOLVE_CLASS_VIRTUAL)			/* проверка на virtual ресольв */	
    && *var_virt_mailbox_maps
    && *var_virt_mailbox_base					/* проверки всяческих катр */
    && *var_virt_mailbox_limit_maps) {          
      argv = smtpd_resolve_virt_alias(STR(reply->recipient), 	/* вызов ресольва альясов */
              virt_alias_maps , 0);				/* функция ресольва взята из postfix cleanup */	
      for (cpp = 0; cpp < argv->argc; cpp++) { 			/* в argv попадают реальные адреса */
        if ((smtpd_check_virt_user_quota(state, argv->argv[cpp]))==0) 	/* вызов своей функции проверки квоты */
          stat_quota = 1;																							
      }                                 
      if (argv)
        argv_free(argv);
      if (stat_quota)
        return (0);						/* 250 Ок если хоть один адрес не превысил квоту */
      return(smtpd_check_reject(state, MAIL_ERROR_BOUNCE,  	/* отбой если все адреса превысили квоту */
"%d Sorry, the user <%s> has overdrawn diskspace quota, \
please try again later.", var_virt_mailbox_code, 
CONST_STR(reply->recipient)));      
    }  
/*
/* Дабы не портить общую картину, если наша проверка "промахнулась", оставляю 
/* старый вариант проверки virt_alias_maps, он сработает если  
/* reply->flags не попадает на RESOLVE_CLASS_VIRTUAL и т.д.
*/
 if (MATCH(virt_alias_maps, CONST_STR(reply->recipient)))
  return (0);
	.
	.
	.
  /* Сразу после postfix проверки virtual юзеров, добавляем свою проверку квот */
    if ((reply->flags & RESOLVE_CLASS_VIRTUAL)
	&& *var_virt_mailbox_maps
  && *var_virt_mailbox_base
  && *var_virt_mailbox_limit_maps) {
    temp1 = vstring_alloc(100);
    quote_822_local(temp1, CONST_STR(reply->recipient));        
    if (smtpd_check_virt_user_quota(state, CONST_STR(temp1))) { 		/* вызов своей функции проверки квоты */              
	vstring_free(temp1);
	return(smtpd_check_reject(state, MAIL_ERROR_BOUNCE,				/* отбой если адрес превысил квоту */
"%d Sorry, the user <%s> has overdrawn diskspace quota, \
please try again later.", 
var_virt_mailbox_code, CONST_STR(reply->recipient)));	
	}	
	vstring_free(temp1);
    }
	.
	.
}
//////////////////////////////////////// 
//////* Далее Новые функции *//////////
///////////////////////////////////////
/* Ресольв альясов взят практически без изменений из cleanup, возвращает реальные адреса*/
ARGV   *smtpd_resolve_virt_alias(const char *addr,
			               MAPS *maps, int propagate)
{
    ARGV   *argv;
    ARGV   *lookup;
    VSTRING *temp1 = vstring_alloc(100);
    int     count;
    int     i;
    int     arg;
    BH_TABLE *been_here;
    char   *saved_lhs;
    char   *myname = "smtpd_resolve_virt_alias";
    /*
     * Initialize.
     */
    argv = argv_alloc(1);
    argv_add(argv, addr, ARGV_END);
    argv_terminate(argv);
    been_here = been_here_init(0, BH_FLAG_FOLD);
    /*
     * Rewrite the address vector in place. With each map lookup result,
     * split it into separate addresses, then rewrite and flatten each
     * address, and repeat the process. Beware: argv is being changed, so we
     * must index the array explicitly, instead of running along it with a
     * pointer.
     */
#define UPDATE(ptr,new)	{ myfree(ptr); ptr = mystrdup(new); }
#define MAX_RECURSION 1000
#define MAX_EXPANSION 1000
#define STR	vstring_str
#define RETURN(x) { been_here_free(been_here); return (x); }
 
  for (arg = 0; arg < argv->argc; arg++) {
    if (argv->argc > MAX_EXPANSION) {
      msg_warn("%s: unreasonable %s map expansion size for %s",
		          myname, maps->title, addr);
	    break;
	  }
	  for (count = 0; /* void */ ; count++) {
 
	    /*
	     * Don't expand an address that already expanded into itself.
	     */
	    if (been_here_check_fixed(been_here, argv->argv[arg]) != 0)
		    break;
	    if (count >= MAX_RECURSION) {
		    msg_warn("%s: unreasonable %s map nesting for %s",
			          myname, maps->title, addr);
		    break;
	    }
	    quote_822_local(temp1, argv->argv[arg]);
	    if ((lookup = mail_addr_map(maps, STR(temp1), propagate)) != 0) {
		    saved_lhs = mystrdup(argv->argv[arg]);
		    for (i = 0; i < lookup->argc; i++) {
		      unquote_822_local(temp1, lookup->argv[i]);
		      if (i == 0) {
			      UPDATE(argv->argv[arg], STR(temp1));
		      } else {
			      argv_add(argv, STR(temp1), ARGV_END);
			      argv_terminate(argv);
		      }
		    /*
		     * Allow an address to expand into itself once.
		     */
		      if (strcasecmp(saved_lhs, STR(temp1)) == 0)
			      been_here_fixed(been_here, saved_lhs);
		    }
 		    myfree(saved_lhs);
 		    argv_free(lookup);
 	    } else if (dict_errno != 0) {
 		    msg_warn("%s: %s map lookup problem for %s",
 			          myname, maps->title, addr);
 		    vstring_free (temp1);
         RETURN(argv);
 	    } else {
 		    break;
 	    }
 	  }
   }
   vstring_free (temp1);
   RETURN(argv);
 }
/* void smtpd_rw_quota_msg(ARGV *user_mess) */
/* открывает шаблон служебной мессаги или если она уже есть то открывает существующую*/
void smtpd_rw_quota_msg(ARGV *user_mess)
{ 
     VSTREAM *fpr = 0;
     VSTREAM *fpw = 0;
     VSTREAM *fpt;
     VSTRING *buf = vstring_alloc(100);
     char   *ftmp_quota;
     long   msg_send_max = atol(var_virt_quota_user_message_limit);
     long   msg_send_cur = 0; 
     time_t  starttime = time((time_t *) 0);
     struct stat st;
     
     /* user_mess->argv[0] from 
     /* user_mess->argv[1] to
     /* user_mess->argv[2] user quota
     /* user_mess->argv[3] maidir size
     /* user_mess->argv[4] maildir
      */ 
   
   ftmp_quota = concatenate(user_mess->argv[4], 			/* пробуем открыть технический файл  */ 
               "postfix.user.quota", (char *)0); 			/*  и прочесть информацию о последней записи в служебном сообщении */               
   if ((fpt = vstream_fopen(ftmp_quota, O_RDONLY | O_EXCL, 0600)) != 0) {   
     vstring_get_nonl(buf, fpt);					/* вышло - читаем путь к сообщению */
     vstream_fclose(fpt); 
     fpw = vstream_fopen(STR(buf), O_RDWR | O_EXCL, 0600);    		/* закрываем ибо пока не нужен */
   } 
   
   myfree(ftmp_quota);
   
   if (fpw ==0) { 							/* технического файла нет, открываем шаблон */
     if ((fpr = vstream_fopen(var_virt_quota_user_message, 
                 O_RDONLY, 0)) == 0) {        
       msg_warn("cannot open file %s:", var_virt_quota_user_message);
       vstring_free(buf);
       return;
     }
     
     vstring_sprintf(buf, "%snew/%lu.VQUOTA%lxI%lx.%s", user_mess->argv[4],
 			(unsigned long) starttime, (unsigned long) st.st_dev,
 			(unsigned long) st.st_ino, get_hostname()); 	/* создаем уникальное имя файла */											/* из текущего времени + st_dev + st.st_ino + хост*/
     if ((fpw = vstream_fopen(STR(buf), 
                 O_CREAT | O_RDWR | O_EXCL, 0600)) == 0) {  		/* создаем служебное сообщение*/
       msg_warn("cannot create file %s:", STR(buf));			/* в юзер maildir/new/ */
       vstring_free(buf);
       vstream_fclose(fpr); 
       return;
     } 
     smtpd_rw_templ_msg(user_mess, fpr, fpw); 				/* читаем шаблон - пишем сообщение */
     vstring_free(buf);
     vstream_fclose(fpr);
     vstream_fclose(fpw);
     return;  
   }        
   
   if ( fpw && ((msg_send_cur = vstream_fseek(fpw, 			/* проверка объема служебного сообщения */
                     0, SEEK_END)) < msg_send_max)) {
     vstream_fseek(fpw, 0, SEEK_SET);
     smtpd_rw_user_msg(user_mess, fpw); 				/* читаем сообщение, добавляем туда строчку*/
     vstream_fclose(fpw);
   } 
   vstring_free(buf);    
   return; 	  
}
/*VSTRING *smtpd_cp_key_msg(VSTRING *buffer, char *cut, char *paste) */
/* вырезает из строки то что нам нужно и вставляет то что хотим и возвращает строку*/
VSTRING *smtpd_cp_key_msg(VSTRING *buffer, char *cut, char *paste)
{
  char *save;
  char *cp;
  
  while ((cp = strstr(vstring_str(buffer), cut))!=0) {    
    save = mystrdup(cp + strlen(cut));
    vstring_truncate (buffer, (VSTRING_LEN(buffer) - strlen(cp)));
    VSTRING_TERMINATE(buffer);
    vstring_sprintf_append(buffer, "%s%s", paste, save);  
    myfree(save);
  }
  return (buffer);
}
/*void smtpd_rw_templ_msg(ARGV *user_mess, VSTREAM *fpr, VSTREAM *fpw)*/
/* читает шаблон, пишет в юзер maildir/new/ служебное сообщение*/
void smtpd_rw_templ_msg(ARGV *user_mess, VSTREAM *fpr, VSTREAM *fpw)
{
   int cp;
   int cnt = 0;
   VSTRING *buffer;
   VSTRING *lt;
   VSTREAM *fpt;
   char *save;
   char *ftmp_quota;
   char *key;
   char *kmf = "_MAIL_FROM_"; 			/* ключевые поля подстановки*/
   char *krt = "_RCPT_TO_";
   char *kuq = "_USER_QUOTA_";
   char *kus = "_UDIR_SIZE_";  
   char *ktm = "_MSG_TIME_";
     
     /* user_mess->argv[0] from 
     /* user_mess->argv[1] to
     /* user_mess->argv[2] user quota
     /* user_mess->argv[3] maidir size
     /* user_mess->argv[4] maildir
      */
          
   buffer = vstring_alloc(100);
   do {
     cp = vstring_get(buffer, fpr);
     if (buffer->vbuf.data[0] == '#') 				/* режем комментарии*/
       continue;
          
     if ((key = strstr(vstring_str(buffer), krt))!=0) 		/*ищем ключи и заменяем их на реальные значения*/
        smtpd_cp_key_msg(buffer, krt, user_mess->argv[1]);
     if ((key = strstr(vstring_str(buffer), kuq))!=0)
        smtpd_cp_key_msg(buffer, kuq, user_mess->argv[2]);
     if ((key = strstr(vstring_str(buffer), kus))!=0)
        smtpd_cp_key_msg(buffer, kus, user_mess->argv[3]);
     if ((key = strstr(vstring_str(buffer), ktm))!=0)
        smtpd_cp_key_msg(buffer, ktm, (char *)mail_date(time((time_t *) 0)));       
     if ((key = strstr(vstring_str(buffer), kmf))!=0) {  
       ftmp_quota = concatenate(user_mess->argv[4], 
               "postfix.user.quota", (char *)0);  		/*создаем технический файл postfix.user.quota*/
       if ((fpt = vstream_fopen(ftmp_quota, 
             O_CREAT | O_WRONLY | O_TRUNC, 0600)) == 0) {
         vstring_free(buffer);
         msg_warn("cannot create file %s:", ftmp_quota);
         myfree(ftmp_quota);
         return;
       }
        lt = smtpd_quota_mail_date(time((time_t *) 0)); 
        save = concatenate(vstring_str(lt), " | mail from: ", 
               user_mess->argv[0], (char *)0);
        smtpd_cp_key_msg(buffer, kmf, save);  
        vstream_fprintf(fpt, "%s\n%d\n%d\n%d\n", VSTREAM_PATH(fpw), cnt, 	/* вписываем в postfix.user.quota*/
                 key - vstring_str(buffer),					/* путь к служебному сообщению*/
                 (key - vstring_str(buffer)) + strlen(save));			/* номер строки с последним _MAIL_FROM_*/
        myfree(ftmp_quota);							/* позицию _MAIL_FROM_ в строке */
        myfree(save);
        vstring_free(lt);
        vstream_fclose(fpt);   
     }                        
     vstream_fputs(vstring_str(buffer), fpw);
     cnt++;
   } while(cp != VSTREAM_EOF); 
   vstring_free(buffer);
   return;
}
 
/*VSTRING *smtpd_quota_mail_date(time_t when)*/
/* возвращает сформатированное локальное время и зону*/
VSTRING *smtpd_quota_mail_date(time_t when)
{
   VSTRING *vp;
   struct tm *lt;
   
   vp = vstring_alloc(100);
   
 #define STRFTIME_FMT "%d.%m.%y %H:%M:%S"    
     
   lt = localtime(&when);  
   while (strftime(vstring_end(vp), vstring_avail(vp), STRFTIME_FMT, lt) == 0)
     VSTRING_SPACE(vp, 100);
   VSTRING_SKIP(vp);
     
   while (strftime(vstring_end(vp), vstring_avail(vp), " (%Z)", lt) == 0)
     VSTRING_SPACE(vp, 100);
   VSTRING_SKIP(vp);
   return (vp);    
}
/*void smtpd_rw_user_msg(ARGV *user_mess, VSTREAM *fpw)*/
/*читает служебное сообщение если оно уже есть и добавляет туда новую строчку*/
void smtpd_rw_user_msg(ARGV *user_mess, VSTREAM *fpw)
{ 
   int line, pos_s, pos_e = 0; 
   int cnt = 0;
   int cp;
   int ch;
   long offset;
   VSTRING *buffer;
   VSTRING *lt;
   VSTREAM *fpt;
   char *ftmp_quota;
   char *patch;
   char *save;
   char *new;
     
   ftmp_quota = concatenate(user_mess->argv[4], 			/* открываем postfix.user.quota */
               "postfix.user.quota", (char *)0);  
   if ((fpt = vstream_fopen(ftmp_quota, O_RDWR | O_EXCL, 0600)) == 0) {  
     myfree(ftmp_quota);  
     return;
   }    
   
   buffer = vstring_alloc(100);
   
   vstring_get_nonl(buffer, fpt); 
   patch = mystrdup(STR(buffer)); 					/* путь к  служебному сообщению*/
   vstring_get_nonl(buffer, fpt);
   line = atoi(vstring_str(buffer)); 					/*номер строки*/
   vstring_get_nonl(buffer, fpt);
   pos_s = atoi(vstring_str(buffer)); 					/*позиция начала последней добавки*/
   vstring_get_nonl(buffer, fpt);			
   pos_e = atoi(vstring_str(buffer)); 					/*позиция конца последней добавки*/
              
  do { 									/* читаем до нужной строчки, сохраняем все что идет после нее и добавляем новую строку*/
     cp = vstring_get(buffer, fpw);
     if (line == cnt) {
       lt = smtpd_quota_mail_date(time((time_t *) 0)); 
       new = concatenate(vstring_str(lt), " | mail from: ",  		/*новая строка*/
             user_mess->argv[0], (char *)0);
       vstring_free(lt);
       save = mystrndup(vstring_str(buffer)+pos_s, pos_e - pos_s);
       smtpd_cp_key_msg(buffer, save, new);  
       vstream_fseek(fpt, 0, SEEK_SET);
       vstream_fflush(fpt);
       vstream_fprintf(fpt, "%s\n%d\n%d\n%d\n", patch, cnt+1, 		/* обновляем postfix.user.quota*/
                 pos_s, pos_s + strlen(new));
       myfree(patch);
       myfree(save);                                            
       myfree(new);
       offset = vstream_ftell(fpw);
       VSTRING_SKIP(buffer);
       while ((cp = VSTREAM_GETC(fpw))!= VSTREAM_EOF) 
 	      VSTRING_ADDCH(buffer, cp);
       VSTRING_TERMINATE(buffer);
       vstream_fseek(fpw, offset, SEEK_SET);
       save = buffer->vbuf.data;
       while ((ch = *buffer->vbuf.data++) != 0)
 	      VSTREAM_PUTC(ch, fpw);
       buffer->vbuf.data = save;            
       break;  
     }
     cnt++;
   } while(cp != VSTREAM_EOF); 
   vstring_free(buffer);
   myfree(ftmp_quota);
   vstream_fclose(fpt);
   return;
}   
/* long check_dir_size(char *dirname) */
/* Взято из EXIM практически без изменений*/
/* возвращает объем директории в байтах*/
long check_dir_size(char *dirname)
{
    DIR    *dir;
    long   sum = 0;
    struct dirent *ent;
    struct stat   statbuf;
 
    dir = opendir(dirname);
    if (dir == NULL) {
      msg_warn("check_dir_size: cannot open directory : %s", dirname);
      return 0;
    }      
    
    while ((ent = readdir(dir)) != NULL) {
      char *name = ent->d_name;
      VSTRING *buffer;
 
      if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) continue;
 
        buffer = vstring_alloc(1024);
 
        vstring_sprintf(buffer,"%s/%s",dirname,name);
        if (stat(vstring_str(buffer), &statbuf) < 0) {
          vstring_free(buffer);
          continue;
        }
        if ((statbuf.st_mode & S_IFREG) != 0)
          sum += statbuf.st_size;
        else if ((statbuf.st_mode & S_IFDIR) != 0)
 	       sum += check_dir_size(vstring_str(buffer));
          vstring_free(buffer);
      
    }
    closedir(dir);
    if (msg_verbose)
       msg_info("check_dir_size: dir=%s sum=%ld", dirname, sum);
    return sum;
}
/* int smtpd_check_virt_user_quota(SMTPD_STATE *state, const char *addr) */
/* проверяет квоту юзера в virtual_mailbox_maps */
/* возвращает 0 если все в порядке и 1 если квота превышена*/
int smtpd_check_virt_user_quota(SMTPD_STATE *state, const char *addr)
 {
   ARGV *argv;
   char  *user_quota;
   char  *maildir;
   char *myname = "smtpd_check_virt_user_quota";
   VSTRING *vb;
   int   dir_size = 0;
   int   size_quota = 0;
 
#define GETV8(map, rcpt) \
     checkv8_maps_find(state, rcpt, map, rcpt)  
 
#define LAST_CHAR(s) (s[strlen(s) - 1])  
     
   /* Sanity check. */
      
     if (*var_virt_mailbox_base != '/') 				/* проверка  virt_mailbox_base на корректность*/
 	msg_fatal("do not specify relative pathname: %s = %s",
 		  VAR_VIRT_MAILBOX_BASE, var_virt_mailbox_base);
   
		if ((maildir = GETV8(virt_mailbox_maps, addr)) !=0 ) 
			maildir = concatenate(var_virt_mailbox_base, "/",
            		maildir, (char *) 0);
		else
			return (0);
 
   /* Check maildir. */
 
   if (LAST_CHAR(maildir) != '/') { 					/* проверка юзера на maildir*/
   	msg_info("%s do not specify maildir pathname: %s",
 		    myname, maildir);
     myfree(maildir);
     return (0);  
   }
                   
   if ((user_quota = mystrdup(GETV8(virt_mailbox_limit_maps, addr))) 	/*смотрим квоту*/
   && ((size_quota = atoi(user_quota)) > 0)) {           
     dir_size = check_dir_size(maildir);              
     if ((dir_size >= 0) && (dir_size < size_quota)) {  
       myfree(maildir);
       myfree (user_quota);
       return (0);
     } else {     
       if (var_virt_quota_user_bounce { 				/* если надо, шлем служебное сообщение */
         && *var_virt_quota_user_message)
    	 vb = vstring_alloc(100);
         argv = argv_alloc(1);
         vstring_sprintf(vb, "%d", dir_size);
         argv_add(argv, state->sender, ARGV_END);
         argv_add(argv, addr, ARGV_END);
         argv_add(argv, user_quota, ARGV_END);
         argv_add(argv, vstring_str(vb), ARGV_END);
         argv_add(argv, maildir, ARGV_END);       
         argv_terminate(argv);	    	    
         smtpd_rw_quota_msg(argv);
         argv_free(argv);
         vstring_free(vb);  
       }
       myfree(maildir);
       myfree (user_quota);                  
       return (1);
     }
   }                              
   return (0);     
} 
                                                                                                                                                                                                                                                                                  
------ Конец врезки ./src/smtpd/smtpd_check.c -------------------------------------------------------                                                                                                                                                                                                                                                                                              
------ Врезка ./src/cleanup/cleanup.h ---------------------------------------------------------------                                                                                                                                                                                                                                                                                               
 /*
  * Virtual maildir quota.
  */
extern MAPS	*cleanup_virt_mailbox_limit_maps;
extern MAPS	*cleanup_virt_mailbox_maps;
------ Конец врезки ./src/cleanup/cleanup.h ----------------------------------------------------------                                                                                                                                                                                                                                                                                               
В cleanup postfix сам ресольвит альясы и тут я просто не пропускаю превысившие квоту адреса
------ Врезка ./src/cleanup/cleanup_init.c -----------------------------------------------------------                                                                                                                                                                                                                                                                                              
/* Virtual maildir quota. */
#include <virtual8_maps.h>
 /*
  * Virtual maildir quota.
  */
char *var_virt_mailbox_limit_maps;
char *var_virt_mailbox_maps;
char *var_virt_mailbox_base;
MAPS *cleanup_virt_mailbox_limit_maps;
MAPS *cleanup_virt_mailbox_maps;
CONFIG_STR_TABLE cleanup_str_table[] = { 		/* инициализация новых переменных */
	.
	.
	.
    VAR_VIRT_MAILBOX_LIMIT_MAPS, DEF_VIRT_MAILBOX_LIMIT_MAPS, &var_virt_mailbox_limit_maps, 0, 0,
    VAR_VIRT_MAILBOX_BASE, DEF_VIRT_MAILBOX_BASE, &var_virt_mailbox_base, 0, 0,
    VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0,
    0,
};
void    cleanup_pre_jail(char *unused_name, char **unused_argv)
{
	.
	.
	.
	if (*var_virt_mailbox_limit_maps)           
   cleanup_virt_mailbox_limit_maps = 
       virtual8_maps_create(VAR_VIRT_MAILBOX_LIMIT_MAPS, 
           var_virt_mailbox_limit_maps,
           DICT_FLAG_LOCK );
     if (*var_virt_mailbox_maps) 
   cleanup_virt_mailbox_maps = 
       virtual8_maps_create(VAR_VIRT_MAILBOX_MAPS, var_virt_mailbox_maps,
 	DICT_FLAG_LOCK);               
}
------ Конец врезки ./src/cleanup/cleanup_init.c ---------------------------------------------------------------                                                                                                                                                                                                                                                                                               
------ Врезка ./src/cleanup/cleanup_out_recipient.c ---------------------------------------------------------------                                                                                                                                                                                                                                                                                               
/* Virtual maildir quota. */
 
#include <sys/types.h>	/* opendir(3), stat(2) */
#include <sys/stat.h>	/* stat(2) */
#include <dirent.h>	/* opendir(3) */
#include <mail_addr_find.h> /*mail_addr_find*/
#include <stdlib.h>  /*atoi*/
#include <stringops.h> /*concatenate*/
#include <msg.h> /*msg_info*/
/* Virtual maildir quota. */
int     cleanup_check_virt_user_quota(char *recip);
long    check_dir_size(char *dirname);
/* Здесь postfix ресольвит альясы */
void    cleanup_out_recipient(CLEANUP_STATE *state, const char *orcpt,
			              const char *recip)
{
	.
	.
	.
    if (cleanup_virt_alias_maps == 0) {
	if (been_here(state->dups, "%s\n%s", orcpt, recip) == 0) {
	    cleanup_out_string(state, REC_TYPE_ORCP, orcpt);
	    cleanup_out_string(state, REC_TYPE_RCPT, recip);
	    state->rcpt_count++;
	}
    } else {
	argv = cleanup_map1n_internal(state, recip, cleanup_virt_alias_maps,
				  cleanup_ext_prop_mask & EXT_PROP_VIRTUAL);
	for (cpp = argv->argv; *cpp; cpp++) {
	    if (been_here(state->dups, "%s\n%s", orcpt, *cpp) == 0) {
			
/////////* вклинился здесь с вот этим*///////////////
      if (*var_virt_mailbox_maps
      && *var_virt_mailbox_limit_maps
      && *var_virt_mailbox_base
      && (cleanup_check_virt_user_quota(*cpp)))
        continue;       
/////////////////////////////////////////////////////
		cleanup_out_string(state, REC_TYPE_ORCP, orcpt);
		cleanup_out_string(state, REC_TYPE_RCPT, *cpp);
		state->rcpt_count++;
	    }
	}
	argv_free(argv);
    }
}
/* long check_dir_size(char *dirname)*/
/* Подсчет директории, тут все без изменений как и в smtpd_check.c*/
long check_dir_size(char *dirname)
{
   DIR    *dir;
   long   sum = 0;
   struct dirent *ent;
   struct stat   statbuf;
 
    dir = opendir(dirname);
    if (dir == NULL)
      return 0;      
    
    while ((ent = readdir(dir)) != NULL)
    {
      char *name = ent->d_name;
      VSTRING *buffer;
 
      if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) continue;
 
        buffer = vstring_alloc(1024);
 
        vstring_sprintf(buffer,"%s/%s",dirname,name);
        if (stat(vstring_str(buffer), &statbuf) < 0)
        {
          vstring_free(buffer);
          continue;
        }
        if ((statbuf.st_mode & S_IFREG) != 0)
          sum += statbuf.st_size;
        else if ((statbuf.st_mode & S_IFDIR) != 0)
 	       sum += check_dir_size(vstring_str(buffer));
          vstring_free(buffer);
      
    }
    closedir(dir);
    return sum;
}
/* int cleanup_check_virt_user_quota(char *recip) */
/* все как и в smtpd_check.c за исключением того что служебное сообщение теперь не шлется*/
int cleanup_check_virt_user_quota(char *recip)
{
   char  *maildir;
   char  *user_quota;
   char  *myname = "cleanup_check_virt_user_quota";
   int   dir_size = 0;
   int   size_quota = 0;
   
#define GETV8(map, rcpt) \
     (char *)mail_addr_find(map, rcpt, (char **) 0)  
 
#define LAST_CHAR(s) (s[strlen(s) - 1]) 
       
   /* Sanity check. */
      
     if (*var_virt_mailbox_base != '/')
 	msg_fatal("do not specify relative pathname: %s = %s",
 		  VAR_VIRT_MAILBOX_BASE, var_virt_mailbox_base);
   
		if ((maildir = GETV8(cleanup_virt_mailbox_maps, recip)) !=0 )
   maildir = concatenate(var_virt_mailbox_base, "/",
             maildir, (char *) 0);
		else
			return (0);
   /* Check maildir. */
 
   if (LAST_CHAR(maildir) != '/') {
   	msg_info("%s do not specify maildir pathname: %s",
 		    myname, maildir);
     myfree(maildir);
     return (0);  
   }
   
   if ((user_quota = GETV8(cleanup_virt_mailbox_limit_maps, recip))
   && ((size_quota = atoi(user_quota)) > 0)) {                    
     dir_size = check_dir_size(maildir);              
     if ((dir_size >= 0) && (dir_size < size_quota)) {  
       myfree(maildir);
       return (0);
     } else {     
       myfree(maildir);                  
       return (1);
     }
   }                              
   return (0);     
}
------ Конец врезки ./src/cleanup/cleanup_out_recipient.c ---------------------------------------------------------------                                                                                                                                                                                                                                                                                               
| 
 | 1.2, Gezm0 (ok), 21:57, 22/04/2005  [ответить] [﹢﹢﹢] [ · · · ] | +/– |  |  Сайт автора недоступен, самого автора найти нет возможности =( Кто-нибудь прикручивал этот патч к текущей версии т.е. postfix 2.2 ? |  |  | 
 
 | 1.3, Антон (??), 19:06, 27/12/2005  [ответить] [﹢﹢﹢] [ · · · ] | +/– |  |  Ну в моем случае было проще написать свой патч, для проверки сободного места в базе и отлупа если письмо больше свободного места. то есть я оставил только команду вида:
virtual_mailbox_limit_maps = cdb:/etc/postfix/db/users_quota
 работает на ура. |  |  | 
 
 
 
 |