Commits

Zhang Huangbin  committed 58a1263

Start working on Gentoo support.

  • Participants
  • Parent commits 8ed8354

Comments (0)

Files changed (15)

File iRedMail/conf/amavisd

     export AMAVISD_LDAP_SCHEMA_NAME='amavis.schema'
     export AMAVISD_VIRUSMAILS_DIR='/var/lib/amavis/virusmails'
 
+elif [ X"${DISTRO}" == X"GENTOO" ]; then
+    export AMAVISD_BIN='/usr/sbin/amavisd'
+    export AMAVISD_RC_SCRIPT_NAME='amavisd'
+    export AMAVISD_LDAP_SCHEMA_NAME='amavisd-new.schema'
+
+    export AMAVISD_CONF='/etc/amavisd.conf'
+    export AMAVISD_VIRUSMAILS_DIR='/var/virusmails'
+
+    export AMAVISD_DKIM_CONF="${AMAVISD_CONF}"
+    export AMAVISD_MYHOME='/var/amavis'
+    export AMAVISD_QUARANTINEDIR="${AMAVISD_MYHOME}/quarantine"
+    export AMAVISD_TEMPDIR="${AMAVISD_MYHOME}/tmp"
+
 elif [ X"${DISTRO}" == X"FREEBSD" ]; then
     # Override global setting: user/group.
     export AMAVISD_SYS_USER='vscan'

File iRedMail/conf/apache_php

     export PHP_INI='/etc/php5/apache2/php.ini'
     export PHP_INI_CONF_DIR='/etc/php5/apache2/conf.d/'
 
+elif [ X"${DISTRO}" == X"GENTOO" ]; then
+    # Apache configuration files.
+    export HTTPD_CONF_ROOT="/etc/apache2"
+    export HTTPD_CONF="${HTTPD_CONF_ROOT}/httpd.conf"
+    export HTTPD_CONF_DIR="${HTTPD_CONF_ROOT}/modules.d"
+    export HTTPD_SSL_CONF="${HTTPD_CONF_DIR}/00_default_ssl_vhost.conf"
+    export HTTPD_WSGI_CONF="${HTTPD_CONF_DIR}/wsgi.conf"
+
+    # Web data.
+    export HTTPD_SERVERROOT='/var/www'
+    export HTTPD_DOCUMENTROOT="${HTTPD_SERVERROOT}/html"
+
+    # Daemon user.
+    export HTTPD_USER='apache'
+    export HTTPD_GROUP='apache'
+
+    # Log file location.
+    export HTTPD_LOG_ACCESSLOG='/var/log/apache2/access_log'
+    export HTTPD_LOG_ERRORLOG='/var/log/apache2/error_log'
+
+    # ---- PHP ----
+    export PHP_INI='/etc/php/apache2-php5.3/php.ini'
+
 elif [ X"${DISTRO}" == X"FREEBSD" ]; then
     # Apache configuration files.
     export HTTPD_CONF_ROOT="/usr/local/etc/apache22"

File iRedMail/conf/clamav

     export CLAMD_CONF='/etc/clamav/clamd.conf'
     export FRESHCLAM_CONF='/etc/clamav/freshclam.conf'
 
+elif [ X"${DISTRO}" == X"GENTOO" ]; then
+    export CLAMD_CONF='/etc/clamd.conf'
+    export FRESHCLAM_CONF='/etc/freshclam.conf'
+
 elif [ X"${DISTRO}" == X"FREEBSD" ]; then
     export CLAMD_CONF='/usr/local/etc/clamd.conf'
     export FRESHCLAM_CONF='/usr/local/etc/freshclam.conf'
 export CLAMD_LISTEN_ADDR='127.0.0.1'            # Used to override default setting.
 
 # Clamd local socket.
-if [ X"${DISTRO}" == X"FREEBSD" ]; then
+if [ X"${DISTRO}" == X"GENTOO" -o X"${DISTRO}" == X"FREEBSD" ]; then
     export CLAMD_LOCAL_SOCKET='/var/run/clamav/clamd.sock'
 else
     export CLAMD_LOCAL_SOCKET='/tmp/clamd.socket'   # Used to override default setting.

File iRedMail/conf/core

     done
 }
 
+enable_service_gentoo()
+{
+    services="$@"
+    for i in $services; do
+        if [ -x /etc/init.d/$i ]; then
+            ECHO_DEBUG "Enable service: $i."
+            rc-update add $i default
+        fi
+    done
+}
+
+disable_service_gentoo()
+{
+    services="$@"
+    for i in $services; do
+        if [ -x /etc/init.d/$i ]; then
+            ECHO_DEBUG "Disable service: $i."
+            rc-update del $i default
+        fi
+    done
+}
+
 # TODO
 enable_service_freebsd()
 {
     [ X"$?" != X"0" ] && ECHO_ERROR "Package removed failed, please check the terminal output."
 }
 
+# Install/Remove binary packages on Gentoo
+install_pkg_gentoo()
+{
+    ECHO_INFO "Installing package(s): $@"
+    emerge --ask n $@
+    if [ X"$?" != X"0" ]; then
+        ECHO_ERROR "Installation failed, please check the terminal output."
+        ECHO_ERROR "If you're not sure what the problem is, try to get help in iRedMail"
+        ECHO_ERROR "forum: http://www.iredmail.org/forum/"
+        exit 255
+    fi
+}
+
+remove_pkg_gentoo()
+{
+    ECHO_INFO "Removing package(s): $@"
+    emerge -C --ask n $@
+    [ X"$?" != X"0" ] && ECHO_ERROR "Package removed failed, please check the terminal output."
+}
+
 # Create SSL certs/private files.
 gen_pem_key()
 {

File iRedMail/conf/dovecot

     export DOVECOT_LDAP_CONF='/etc/dovecot/dovecot-ldap.conf'
     export DOVECOT_MYSQL_CONF='/etc/dovecot/dovecot-mysql.conf'
     export DOVECOT_PGSQL_CONF='/etc/dovecot/dovecot-pgsql.conf'
-    export DOVECOT_REALTIME_QUOTA_CONF='/etc/dovecot/used-quota.conf'
-    export DOVECOT_SHARE_FOLDER_CONF='/etc/dovecot/share-folder.conf'
+    export DOVECOT_REALTIME_QUOTA_CONF='/etc/dovecot/dovecot-used-quota.conf'
+    export DOVECOT_SHARE_FOLDER_CONF='/etc/dovecot/dovecot-share-folder.conf'
 
     if [ X"${DISTRO_VERSION}" == X"5" ]; then
         export DOVECOT_VERSION='1.2'
     export DOVECOT_REALTIME_QUOTA_CONF='/etc/dovecot/dovecot-used-quota.conf'
     export DOVECOT_SHARE_FOLDER_CONF='/etc/dovecot/dovecot-share-folder.conf'
     export DOVECOT_DELIVER='/usr/lib/dovecot/deliver'
+
+elif [ X"${DISTRO}" == X"GENTOO" ]; then
+    export DOVECOT_VERSION='2'
+    export DOVECOT_CONF='/etc/dovecot/dovecot.conf'
+    export DOVECOT_LDAP_CONF='/etc/dovecot/dovecot-ldap.conf'
+    export DOVECOT_MYSQL_CONF='/etc/dovecot/dovecot-mysql.conf'
+    export DOVECOT_PGSQL_CONF='/etc/dovecot/dovecot-pgsql.conf'
+    export DOVECOT_REALTIME_QUOTA_CONF='/etc/dovecot/dovecot-used-quota.conf'
+    export DOVECOT_SHARE_FOLDER_CONF='/etc/dovecot/dovecot-share-folder.conf'
+
 elif [ X"${DISTRO}" == X"FREEBSD" ]; then
     export DOVECOT_VERSION='1.2'
     export DOVECOT_CONF='/usr/local/etc/dovecot.conf'

File iRedMail/conf/fail2ban

     export FAIL2BAN_SSHD_LOGFILE='/var/log/auth.log'
 elif [ X"${DISTRO}" == X"SUSE" ]; then
     export FAIL2BAN_SSHD_LOGFILE='/var/log/messages'
+elif [ X"${DISTRO}" == X"GENTOO" ]; then
+    export FAIL2BAN_SSHD_LOGFILE='/var/log/messages'
 elif [ X"${DISTRO}" == X"FREEBSD" ]; then
     export FAIL2BAN_CONF_ROOT='/usr/local/etc/fail2ban'
     export FAIL2BAN_SSHD_LOGFILE='/var/log/auth.log'

File iRedMail/conf/global

         if [ X"${DISTRO_CODENAME}" == X"squeeze" ]; then
             export SHELL_NOLOGIN='/usr/sbin/nologin'
         fi
+
+    elif [ -f /etc/gentoo-release ]; then
+        # Gentoo
+        export DISTRO='GENTOO'
+
     else
         # Not support yet.
         echo "Your distrobution is not supported yet."
     export SYSLOG_POSTROTATE_CMD='/bin/kill -HUP $(cat /var/run/syslogd.pid 2> /dev/null) 2> /dev/null || true'
 
     # Crontab related.
-    export CRON_SPOOL_DIR="/var/spool/cron"
+    export CRON_SPOOL_DIR='/var/spool/cron'
 
     # Directory /etc/sysconfig/ on RHEL/CentOS.
     export ETC_SYSCONFIG_DIR='/etc/sysconfig'
     export SYSLOG_POSTROTATE_CMD=''
 
     # Crontab related.
-    export CRON_SPOOL_DIR="/var/spool/cron/tabs"
+    export CRON_SPOOL_DIR='/var/spool/cron/tabs'
 
     # Directory /etc/sysconfig/ on RHEL/CentOS/SuSE.
     export ETC_SYSCONFIG_DIR='/etc/sysconfig'
     fi
 
     # Crontab related.
-    export CRON_SPOOL_DIR="/var/spool/cron/crontabs"
+    export CRON_SPOOL_DIR='/var/spool/cron/crontabs'
 
     # Directory /etc/default/ on Debian/Ubuntu.
     export ETC_SYSCONFIG_DIR='/etc/default'
     # Directory used to store SSL/TLS key/cert file.
     export SSL_FILE_DIR="/etc/ssl"
 
+elif [ X"${DISTRO}" == X"GENTOO" ]; then
+    # Gentoo
+    # System user: root. Note: not all OSes have group 'root'.
+    export SYS_ROOT_USER='root'
+    export SYS_ROOT_GROUP='root'
+
+    export install_pkg='install_pkg_gentoo'
+    export remove_pkg="remove_pkg_gentoo"
+    export LIST_ALL_PKGS='qlist --installed'
+    export LIST_FILES_IN_PKG='equery files'
+
+    # Service control. Defined in file: conf/core.
+    export enable_service='enable_service_gentoo'
+    export disable_service='disable_service_gentoo'
+
+    # Syslog config file: syslog-nt.
+    export SYSLOG_CONF='/etc/syslog-nt/syslog-ng.conf'
+    export SYSLOG_POSTROTATE_CMD=''
+
+    # Crontab related.
+    export CRON_SPOOL_DIR='/var/spool/cron/crontabs'
+
+    # Directory /etc/sysconfig/ on RHEL/CentOS.
+    export ETC_SYSCONFIG_DIR='/etc/sysconfig'
+
+    # Iptables rule file.
+    export IPTABLES_CONFIG="${ETC_SYSCONFIG_DIR}/iptables"
+
+    # Directory used to store SSL/TLS key/cert file.
+    export SSL_FILE_DIR="/etc/pki/tls"
+
+    # Yum repository related.
+    export YUM_REPOS_DIR='/etc/yum.repos.d'
+    export LOCAL_REPO_NAME="${PROG_NAME}"
+    export LOCAL_REPO_FILE="${YUM_REPOS_DIR}/${LOCAL_REPO_NAME}.repo"
+
+    # Override default value.
+    export PKG_DIALOG="dialog${PKG_ARCH}"
+    export PKG_BZIP2="bzip2${PKG_ARCH}"
+
 elif [ X"${DISTRO}" == X"FREEBSD" ]; then
     # System user: root.
     export SYS_ROOT_USER='root'
     export SYSLOG_POSTROTATE_CMD=''
 
     # Crontab related.
-    export CRON_SPOOL_DIR="/var/cron/tabs"
+    export CRON_SPOOL_DIR='/var/cron/tabs'
 
     # Directory /etc/defaults/ on Debian/Ubuntu.
-    export ETC_SYSCONFIG_DIR='/etc/defaults'
+    export ETC_SYSCONFIG_DIR='/etc/conf.d'
 
     # IPFW rule file.
-    export IPTABLES_CONFIG="${ETC_SYSCONFIG_DIR}/ipfw.rules"
+    export IPTABLES_CONFIG=""
 
     # Directory used to store SSL/TLS key/cert file.
     export SSL_FILE_DIR="/etc/ssl"

File iRedMail/conf/managesieve

 
 # New Linux releases use port 4190.
 # RHEL 6.
-if [ X"${DISTRO}" == X"RHEL" -a X"${DISTRO_VERSION}" == X"6" ]; then
+if [ X"${DISTRO}" == X"RHEL" ]; then
+    [ X"${DISTRO_VERSION}" == X"6" ] && export MANAGESIEVE_PORT='4190'
+elif [ X"${DISTRO}" == X"GENTOO" ]; then
     export MANAGESIEVE_PORT='4190'
 fi
 

File iRedMail/conf/mysql

     export mysql_server="${MYSQL_SERVER}"
 fi
 
+export MYSQL_MY_CNF='/etc/my.cnf'
 export MYSQL_SOCKET='/var/lib/mysql/mysql.sock'
 export MYSQL_ROOT_USER='root'
 
 # MySQL config file.
 if [ X"${DISTRO}" == X"RHEL" ]; then
-    export MYSQL_MY_CNF='/etc/my.cnf'
-    # RC script.
     export MYSQLD_INIT_SCRIPT="${DIR_RC_SCRIPTS}/mysqld"
 
 elif [ X"${DISTRO}" == X"SUSE" ]; then
-    export MYSQL_MY_CNF='/etc/my.cnf'
     export MYSQL_SOCKET='/var/run/mysql/mysql.sock'
-    # RC script.
     export MYSQLD_INIT_SCRIPT="${DIR_RC_SCRIPTS}/mysql"
 
 elif [ X"${DISTRO}" == X"UBUNTU" -o X"${DISTRO}" == X"DEBIAN" ]; then
     export MYSQL_MY_CNF='/etc/mysql/my.cnf'
-    # RC script.
+    export MYSQLD_INIT_SCRIPT="${DIR_RC_SCRIPTS}/mysql"
+
+elif [ X"${DISTRO}" == X"GENTOO" ]; then
+    export MYSQL_MY_CNF='/etc/mysql/my.cnf'
+    export MYSQL_SOCKET='/var/run/mysqld/mysql.sock'
     export MYSQLD_INIT_SCRIPT="${DIR_RC_SCRIPTS}/mysql"
 
 elif [ X"${DISTRO}" == X"FREEBSD" ]; then
-    # Override default socket location.
     export MYSQL_SOCKET='/tmp/mysql.sock'
-
-    # Location of my.cnf.
     export MYSQL_MY_CNF="/var/db/mysql/my.cnf"
-
-    # RC script.
     export MYSQLD_INIT_SCRIPT="${DIR_RC_SCRIPTS}/mysql-server"
-
 fi
 
 export MYSQL_INIT_SQL="${CONF_DIR}/mysql_init.sql"

File iRedMail/conf/openldap

 # Default LDAP data directory.
 export OPENLDAP_DATA_DIR='/var/lib/ldap'    # Do *NOT* end with '/'.
 
+export OPENLDAP_PID_FILE='/var/run/openldap/slapd.pid'
+export OPENLDAP_ARGS_FILE='/var/run/openldap/slapd.args'
+
 # Configure.
 if [ X"${DISTRO}" == X"RHEL" ]; then
     # OpenLDAP version.
     export OPENLDAP_CONF_ROOT="/etc/openldap"
     export OPENLDAP_DB_CONFIG_SAMPLE="${OPENLDAP_CONF_ROOT}/DB_CONFIG.example"
 
-    export OPENLDAP_PID_FILE='/var/run/openldap/slapd.pid'
-    export OPENLDAP_ARGS_FILE='/var/run/openldap/slapd.args'
-
     export OPENLDAP_SYSCONFIG_CONF="${ETC_SYSCONFIG_DIR}/ldap"
 
     # RC script.
     # RC script.
     export LDAP_INIT_SCRIPT="${DIR_RC_SCRIPTS}/slapd"
 
+elif [ X"${DISTRO}" == X"GENTOO" ]; then
+    # OpenLDAP version.
+    export OPENLDAP_VERSION='2.4'
+    export LDAP_RC_SCRIPT_NAME='slapd'
+
+    # LDAP daemon user & group.
+    export LDAP_USER='ldap'
+    export LDAP_GROUP='ldap'
+
+    # Configuration files.
+    export OPENLDAP_CONF_ROOT="/etc/openldap"
+    export OPENLDAP_DB_CONFIG_SAMPLE="${OPENLDAP_CONF_ROOT}/DB_CONFIG.example"
+
+    export OPENLDAP_SYSCONFIG_CONF="${ETC_SYSCONFIG_DIR}/ldap"
+
+    # RC script.
+    export LDAP_INIT_SCRIPT="${DIR_RC_SCRIPTS}/${LDAP_RC_SCRIPT_NAME}"
+
+    # Module related.
+    export OPENLDAP_MODULE_PATH='/usr/lib/openldap/openldap'
+
 elif [ X"${DISTRO}" == X"FREEBSD" ]; then
     # OpenLDAP version.
     export OPENLDAP_VERSION='2.4'
     export OPENLDAP_CONF_ROOT='/usr/local/etc/openldap'
     export OPENLDAP_DB_CONFIG_SAMPLE="${OPENLDAP_CONF_ROOT}/DB_CONFIG.example"
 
-    export OPENLDAP_PID_FILE='/var/run/openldap/slapd.pid'
-    export OPENLDAP_ARGS_FILE='/var/run/openldap/slapd.args'
 
     # Module related.
     export OPENLDAP_MODULE_PATH='/usr/local/libexec/openldap'

File iRedMail/conf/policyd

     # Path of policyd-clean
     export POLICYD_CLEANUP_BIN='/usr/lib/postfix-policyd/cleanup'
 
+elif [ X"${DISTRO}" == X"GENTOO" ]; then
+    export PKG_POLICYD='policyd'
+    export POLICYD_CONF='/etc/policyd.conf'
+    export POLICYD_THROTTLE_CONF='/etc/policyd_sender_throttle.conf'
+    export POLICYD_THROTTLE_PIDFILE='/var/run/policyd_sender_throttle.pid'
+    export POLICYD_INIT_SCRIPT="${DIR_RC_SCRIPTS}/policyd"
+
+    # Database.
+    export POLICYD_DB_NAME='policyd'
+    export POLICYD_DB_USER='policyd'
+
+    # Path of policyd-clean
+    export POLICYD_CLEANUP_BIN='/usr/sbin/policyd_cleanup'
+
 elif [ X"${DISTRO}" == X"FREEBSD" ]; then
     export PKG_POLICYD='postfix-policyd-sf'
     export POLICYD_CONF='/usr/local/etc/postfix-policyd-sf.conf'

File iRedMail/conf/postfix

     export MAILLOG_INFO='/var/log/mail.info'
     export MAILLOG_ERROR='/var/log/mail.err'
     export MAILLOG_WARN='/var/log/mail.warn'
-else
-    :
+elif [ X"${DISTRO}" == X"GENTOO" ]; then
+    # Gentoo
+    export MAILLOG='/var/log/messages'
+    export MAILLOG_INFO=''
+    export MAILLOG_ERROR=''
+    export MAILLOG_WARN=''
 fi
 
 if [ X"${DISTRO}" == X"FREEBSD" ]; then
 # Set 'message_size_limit', in 'byte'. Default is 10M.
 export MESSAGE_SIZE_LIMIT='15728640'
 
-# virtual_maildir_limit_message.
-export MAILDIR_LIMIT_MESSAGE="Sorry, the user's maildir has overdrawn the disk quota, please notice the user and try again later."
-
 # LDAP/MYSQL/PGSQL lookup configuration files.
 if [ X"${BACKEND}" == X"OPENLDAP" ]; then
     export POSTFIX_LOOKUP_DIR="${POSTFIX_ROOTDIR}/ldap"

File iRedMail/conf/postgresql

 export PGSQL_SYS_USER_HOME='/var/lib/postgresql'
 export PGSQL_DOT_PGPASS="${PGSQL_SYS_USER_HOME}/.pgpass"
 
+export PGSQL_VERSION='9.1'
 export PGSQL_INIT_SCRIPT="${DIR_RC_SCRIPTS}/postgresql"
+[ X"${DISTRO}" == X"GENTOO" ] && \
+    export PGSQL_INIT_SCRIPT="${DIR_RC_SCRIPTS}/postgresql-${PGSQL_VERSION}"
 export PGSQL_VMAIL_STRUCTURE_SAMPLE="${SAMPLE_DIR}/iredmail.pgsql"
 export PGSQL_INIT_SQL_SAMPLE="${CONF_DIR}/pgsql_init.pgsql"
 
-export PGSQL_VERSION='9.1'
-export PGSQL_CONF_DIR="/etc/postgresql/${PGSQL_VERSION}/main"
-export PGSQL_CONF_POSTGRESQL="${PGSQL_CONF_DIR}/postgresql.conf"
-export PGSQL_CONF_PG_HBA="${PGSQL_CONF_DIR}/pg_hba.conf"
-
-export PGSQL_DATA_DIR="/var/lib/postgresql/${PGSQL_VERSION}/main"
+if [ X"${DISTRO}" == X'GENTOO' ]; then
+    export PGSQL_CONF_DIR="/etc/postgresql-${PGSQL_VERSION}"
+    export PGSQL_CONF_POSTGRESQL="${PGSQL_CONF_DIR}/postgresql.conf"
+    export PGSQL_CONF_PG_HBA="${PGSQL_CONF_DIR}/pg_hba.conf"
+    export PGSQL_DATA_DIR="/var/lib/postgresql/${PGSQL_VERSION}/data"
+else
+    export PGSQL_CONF_DIR="/etc/postgresql/${PGSQL_VERSION}/main"
+    export PGSQL_CONF_POSTGRESQL="${PGSQL_CONF_DIR}/postgresql.conf"
+    export PGSQL_CONF_PG_HBA="${PGSQL_CONF_DIR}/pg_hba.conf"
+    export PGSQL_DATA_DIR="/var/lib/postgresql/${PGSQL_VERSION}/main"
+fi
 
 # SSL cert/key
 export PGSQL_SSL_CERT="${SSL_CERT_DIR}/iRedMail_CA_PostgreSQL.pem"

File iRedMail/conf/spamassassin

 
 # For SpamAssassin.
 
+export SA_CONF_DIR='/etc/mail/spamassassin'
+export SA_RULES_DIR='/usr/share/spamassassin'
+export SA_INIT_PRE="${SA_CONF_DIR}/init.pre"
+export SA_LOCAL_CF="${SA_CONF_DIR}/local.cf"
+
 if [ X"${DISTRO}" == X"FREEBSD" ]; then
     export SA_CONF_DIR='/usr/local/etc/mail/spamassassin'
     export SA_RULES_DIR='/usr/local/share/spamassassin'
     export SA_INIT_PRE="${SA_CONF_DIR}/init.pre"
     export SA_LOCAL_CF="${SA_CONF_DIR}/local.cf"
-else
-    export SA_CONF_DIR='/etc/mail/spamassassin'
-    export SA_RULES_DIR='/usr/share/spamassassin'
-    export SA_INIT_PRE="${SA_CONF_DIR}/init.pre"
-    export SA_LOCAL_CF="${SA_CONF_DIR}/local.cf"
 fi

File iRedMail/samples/iredmail.pgsql

 -- Trigger required by quota dict
 CREATE OR REPLACE FUNCTION merge_quota() RETURNS TRIGGER AS $$
 BEGIN
-  IF NEW.messages < 0 OR NEW.messages IS NULL THEN
-    -- ugly kludge: we came here from this function, really do try to insert
-    IF NEW.messages IS NULL THEN
-      NEW.messages = 0;
-    ELSE
-      NEW.messages = -NEW.messages;
-    END IF;
-    return NEW;
-  END IF;
-
-  LOOP
-    UPDATE used_quota SET bytes = bytes + NEW.bytes,
-      messages = messages + NEW.messages
-      WHERE username = NEW.username;
-    IF found THEN
-      RETURN NULL;
+    IF NEW.messages < 0 OR NEW.messages IS NULL THEN
+        -- ugly kludge: we came here from this function, really do try to insert
+        IF NEW.messages IS NULL THEN
+            NEW.messages = 0;
+        ELSE
+            NEW.messages = -NEW.messages;
+        END IF;
+        return NEW;
     END IF;
 
-    BEGIN
-      IF NEW.messages = 0 THEN
-        INSERT INTO used_quota (bytes, messages, username)
-          VALUES (NEW.bytes, NULL, NEW.username);
-      ELSE
-        INSERT INTO used_quota (bytes, messages, username)
-          VALUES (NEW.bytes, -NEW.messages, NEW.username);
-      END IF;
-      return NULL;
-    EXCEPTION WHEN unique_violation THEN
-      -- someone just inserted the record, update it
-    END;
-  END LOOP;
+    LOOP
+        UPDATE used_quota
+        SET bytes = bytes + NEW.bytes, messages = messages + NEW.messages
+        WHERE username = NEW.username;
+        IF found THEN
+            RETURN NULL;
+        END IF;
+
+        BEGIN
+            IF NEW.messages = 0 THEN
+                INSERT INTO used_quota (bytes, messages, username)
+                VALUES (NEW.bytes, NULL, NEW.username);
+            ELSE
+                INSERT INTO used_quota (bytes, messages, username)
+                VALUES (NEW.bytes, -NEW.messages, NEW.username);
+            END IF;
+            return NULL;
+            EXCEPTION WHEN unique_violation THEN
+            -- someone just inserted the record, update it
+        END;
+    END LOOP;
 END;
 $$ LANGUAGE plpgsql;
 
 CREATE TRIGGER mergequota BEFORE INSERT ON used_quota
-   FOR EACH ROW EXECUTE PROCEDURE merge_quota();
+    FOR EACH ROW EXECUTE PROCEDURE merge_quota();