Commits

Zhang Huangbin committed 8d5669f

Import iredadmin from iredmail repo.

Comments (0)

Files changed (76)

+#use glob syntax.
+syntax: glob
+*.py[co]
+*.svn
+settings.ini
+Authors:
+    * Zhang Huangbin <michaelbibby@gmail.com>
+
+Contributors:
+    * no.0023@gmail.com
+= 0.1 =
+    * Initiaize release.
Empty file added.
+* Per-user i18n.
+* Add, delete, modify user.
+* Add, delete, modify admin.
+* Ability to change user/admin password.

controllers/__init__.py

Empty file added.

controllers/ldap/__init__.py

Empty file added.

controllers/ldap/admin.py

+#!/usr/bin/env python
+# encoding: utf-8
+
+# Author: Zhang Huangbin <michaelbibby (at) gmail.com>
+
+import web
+from web import render
+from controllers.ldap import base
+from controllers.ldap.core import dbinit
+from libs.ldaplib import admin
+
+session = web.config.get('_session')
+
+adminLib = admin.Admin()
+
+#
+# Admin related.
+#
+class list(dbinit):
+    @base.check_global_admin
+    @base.protected
+    def GET(self):
+        self.admins = adminLib.list()
+        return render.admins(admins=self.admins)
+
+    @base.check_global_admin
+    @base.protected
+    def POST(self):
+        i = web.input(dn=[])
+
+        # Post method: add, delete.
+        action = i.get('action', None)
+
+        if action == 'add':
+            # Get admin list (python list obj).
+            admin = i.get('admin', None)
+            passwd = i.get('passwd', None)
+            domainGlobalAdmin = i.get('domainGlobalAdmin', 'no')
+
+            if admin is not None and passwd is not None:
+                # Try to add it.
+                results = self.dbwrap.admin_add(admin, passwd, domainGlobalAdmin)
+
+                # List admins.
+                self.admins = adminLib.list()
+                return render.admins(admins=self.admins, msg=results)
+            else:
+                # Show system message.
+                self.admins = adminLib.list()
+                return render.admins(admins=self.admins, msg='NO_DOMAIN')
+        elif action == 'delete':
+            dn = i.get('dn', [])
+
+            if len(dn) >= 1:
+                # Delete dn(s).
+                results = self.dbwrap.delete_dn(dn)
+
+                # List admins.
+                self.admins = adminLib.list()
+                return render.admins(admins=self.admins, msg=results)
+            else:
+                # Show system message.
+                return render.admins()
+        else:
+            return render.admins()
+
+class add(dbinit):
+    @base.check_global_admin
+    @base.protected
+    def GET(self):
+        return render.add()

controllers/ldap/base.py

+#!/usr/bin/env python
+# encoding: utf-8
+
+# Author: Zhang Huangbin <michaelbibby (at) gmail.com>
+
+import sys
+import web
+
+session = web.config.get('_session')
+
+class redirect:
+    '''Make url ending with or without '/' going to the same class.
+    '''
+    def GET(self, path):
+        web.redirect('/' + str(path))
+
+#
+# Decorators
+#
+def protected(func):
+    def proxyfunc(self, *args, **kw):
+        if session.get('username') != None and session.get('logged') == True:
+            return func(self, *args, **kw)
+        else:
+            session.kill()
+            web.seeother('/login?msg=loginRequired')
+    return proxyfunc
+
+def check_global_admin(func):
+    def proxyfunc(self, *args, **kw):
+        if session.get('domainGlobalAdmin') == 'yes':
+            return func(self, *args, **kw)
+        else:
+            web.seeother('/domains?msg=PERMISSION_DENIED')
+    return proxyfunc

controllers/ldap/core.py

+#!/usr/bin/env python
+# encoding: utf-8
+
+# Author: Zhang Huangbin <michaelbibby (at) gmail.com>
+
+import web, sys
+from libs.ldaplib import core, auth, domain, iredutils
+from controllers.ldap import base
+
+session = web.config.get('_session')
+render = web.render
+
+class login:
+    def GET(self):
+        if session.get('logged') is True:
+            web.seeother('/dashboard')
+        else:
+            i = web.input()
+            msg = i.get('msg', None)
+
+            # Show login page.
+            return render.login(msg=msg)
+
+    def POST(self):
+        # Get username, password.
+        i = web.input()
+
+        username = web.safestr(i.get('username').strip())
+        password = i.get('password').strip()
+        save_pass = web.safestr(i.get('save_pass', 'no').strip())
+
+        # Convert email to ldap dn.
+        userdn = iredutils.convEmailToAdminDN(username)
+
+        # Return True if auth success, otherwise return error msg.
+        self.auth_result = auth.Auth(userdn, password)
+
+        if self.auth_result == True:
+            session['username'] = username
+            session['userdn'] = userdn
+            session['logged'] = True
+
+            web.config.session_parameters['cookie_name'] = 'iRedAdmin'
+            # Session expire when client ip was changed.
+            web.config.session_parameters['ignore_change_ip'] = False
+
+            # Session timeout:
+            # number of second after a not-updated session will be considered expired
+            if save_pass == 'yes':
+                # Session timeout (in seconds).
+                web.config.session_parameters['timeout'] = 86400    # 24 hours
+            else:
+                # Expire session when browser closed.
+                web.config.session_parameters['timeout'] = 600      # 10 minutes
+
+            web.seeother('/dashboard')
+        else:
+            session['failedTimes'] += 1
+            return render.login(msg=self.auth_result, sysadmin=session.get('webmaster', ''))
+
+class logout:
+    def GET(self):
+        session.kill()
+        web.seeother('/login')
+
+class dashboard:
+    @base.protected
+    def GET(self):
+        return render.dashboard()
+
+class dbinit:
+    def __init__(self):
+        self.dbwrap = core.LDAPWrap(app=web.app, session=session)
+        self.domain = domain.Domain()

controllers/ldap/domain.py

+#!/usr/bin/env python
+# encoding: utf-8
+
+# Author: Zhang Huangbin <michaelbibby (at) gmail.com>
+
+import sys
+import web
+from web import render
+from web import iredconfig as cfg
+from controllers.ldap import base
+from controllers.ldap.core import dbinit
+from libs.ldaplib import core, admin, domain, iredutils
+
+session = web.config.get('_session')
+
+adminLib = admin.Admin()
+domainLib = domain.Domain()
+
+#
+# Domain related.
+#
+class list(dbinit):
+    '''List all virtual mail domains.'''
+    @base.protected
+    def GET(self):
+        self.domains = domainLib.list()
+        return render.domains(domains=self.domains)
+
+    @base.check_global_admin
+    @base.protected
+    def POST(self):
+        i = web.input(domainName=[])
+        domainName = i.get('domainName', None)
+        result = domainLib.delete(domainName)
+        web.seeother('/domains')
+
+class profile(dbinit):
+    @base.protected
+    def GET(self, domain):
+        domain = web.safestr(domain.split('/', 1)[0])
+        if domain is '' or domain is None:
+            web.seeother('/domains?msg=NO_SUCH_DOMAIN')
+
+        domain = web.safestr(domain)
+        profile = domainLib.profile(domain)
+        allAdmins = adminLib.list()
+        domainAdmins = domainLib.admins(domain)
+        
+        if profile:
+            return render.domain_profile(
+                    domain=domain,
+                    profile=profile,
+                    admins=allAdmins,
+                    # We need only mail address of domain admins.
+                    domainAdmins=domainAdmins[0][1].get('domainAdmin', []),
+                    )
+        else:
+            return render.domains(msg='NO_SUCH_DOMAIN')
+
+    @base.protected
+    def POST(self, domain):
+        i = web.input(enabledService=[])
+        self.result = domainLib.update(data=i)
+        if self.result:
+            web.seeother('/profile/domain/' + web.safestr(domain) + '?msg=SUCCESS')
+        else:
+            web.seeother('/profile/domain/' + web.safestr(domain))
+
+class create(dbinit):
+    @base.check_global_admin
+    @base.protected
+    def GET(self):
+        return render.domain_create()
+
+    @base.check_global_admin
+    @base.protected
+    def POST(self):
+        i = web.input()
+        domainName = i.get('domainName', None)
+        cn = i.get('cn', None)
+        result = domainLib.add(domainName=domainName, cn=cn)
+        if result is True:
+            web.seeother('/domains')
+        else:
+            return render.domain_create(msg=result)

controllers/ldap/preferences.py

+#!/usr/bin/env python
+# encoding: utf-8
+
+# Author: Zhang Huangbin <michaelbibby (at) gmail.com>
+
+import sys
+import web
+from web import render
+from controllers.ldap import base
+from controllers.ldap.core import dbinit
+from libs.ldaplib import preferences
+
+session = web.config.get('_session')
+
+prefLib = preferences.Preferences()
+
+class Preferences:
+    @base.protected
+    def GET(self):
+        self.langs = prefLib.get_langs()
+
+        return render.preferences(
+                cur_lang=self.langs.pop('cur_lang'),
+                langmaps=self.langs.pop('langmaps'),
+                msg=None,
+                )
+
+    @base.protected
+    def POST(self):
+        # Get passwords.
+        i = web.input()
+        self.result = prefLib.update(i)
+
+        self.langs = prefLib.get_langs()
+
+        return render.preferences(
+                cur_lang=self.langs.pop('cur_lang'),
+                langmaps=self.langs.pop('langmaps'),
+                msg=self.result,
+                )

controllers/ldap/urls.py

+#!/usr/bin/env python
+# encoding: utf-8
+
+# Author: Zhang Huangbin <michaelbibby (at) gmail.com>
+
+# URL schema:
+#
+# accountType:    domain, admin, user, maillist, alias
+# account:        example.com, postmaster@example.com,
+#                 www@example.com, list01@example.com,
+#                 alias01@example.com
+#
+# * Create new accounts:
+#   - /create/{accountType}
+#
+# * Delete accounts:
+#   - /delete/{accountType}/{account}
+#
+# * List all accounts:
+#   - /domains
+#   - /admins
+#
+# * Show a search form for user to choose domain.
+#   - /users
+#   - /maillists
+#   - /aliases
+#
+# * List all accounts under single domain.
+#   - /users/{domain}
+#   - /maillists/{domain}
+#   - /aliases/{domain}
+#
+# * View & Update account profile:
+#   - /profile/{accountType}/{account}
+#
+
+urls = (
+        # Make url ending with or without '/' going to the same class.
+        '/(.*)/',                           'controllers.ldap.base.redirect',
+
+        # used to display jpegPhoto.
+        '/img/(.*)',                        'controllers.ldap.utils.img',
+
+        '/',                                'controllers.ldap.core.login',
+        '/login',                           'controllers.ldap.core.login',
+        '/logout',                          'controllers.ldap.core.logout',
+        '/dashboard',                       'controllers.ldap.core.dashboard',
+
+        # Preferences.
+        '/preferences',                     'controllers.ldap.preferences.Preferences',
+
+        # Domain related.
+        '/domains',                         'controllers.ldap.domain.list',
+        '/profile/domain/(.*\..*)',         'controllers.ldap.domain.profile',
+        '/create/domain',                   'controllers.ldap.domain.create',
+        '/delete/domain',                   'controllers.ldap.domain.delete',
+
+        # Admin related.
+        '/admins',                          'controllers.ldap.admin.list',
+        '/profile/admin/(.*@.*\..*)',       'controllers.ldap.admin.profile',
+        '/create/admin',                    'controllers.ldap.admin.create',
+        '/delete/admin',                    'controllers.ldap.admin.delete',
+
+        # User related.
+        # /domain.ltd/users
+        '/users',                           'controllers.ldap.user.list',
+        '/users/(.*\..*)',                  'controllers.ldap.user.list',
+        '/profile/user/(.*@.*\..*)',        'controllers.ldap.user.profile',
+        '/create/user/(.*\..*)',            'controllers.ldap.user.create',
+        '/create/user',                     'controllers.ldap.user.create',
+        '/delete/user',                     'controllers.ldap.user.delete',
+        )

controllers/ldap/user.py

+#!/usr/bin/env python
+# encoding: utf-8
+
+# Author: Zhang Huangbin <michaelbibby (at) gmail.com>
+
+import sys
+import web
+from web import render
+from web import iredconfig as cfg
+from controllers.ldap import base
+from controllers.ldap.core import dbinit
+from libs.ldaplib import domain, user, iredldif, iredutils
+
+session = web.config.get('_session')
+
+domainLib = domain.Domain()
+userLib = user.User()
+
+#
+# User related.
+#
+class list(dbinit):
+    def __del__(self):
+        pass
+
+    @base.protected
+    def GET(self, domain=''):
+        domain = web.safestr(domain.split('/', 1)[0])
+
+        allDomains = domainLib.list()
+
+        if domain == '' or domain is None:
+            return render.users(allDomains=allDomains)
+
+        users = userLib.list(domain=domain)
+        if users is not False:
+            return render.users(
+                    users=users, cur_domain=domain,
+                    allDomains=allDomains,
+                    msg=None,
+                    )
+        else:
+            web.seeother('/domains?msg=NO_SUCH_DOMAIN')
+
+    @base.protected
+    def POST(self, domain):
+        i = web.input(_unicode=False, mail=[])
+        mails = i.mail
+        result = userLib.delete(mails=mails)
+        web.seeother('/users/' + str(domain))
+
+class profile(dbinit):
+    @base.protected
+    def GET(self, email):
+        #i = web.input()
+        email = web.safestr(email)
+
+        if len(email.split('@', 1)) == 2:
+            domain = email.split('@', 1)[1]
+            userdn = iredutils.convEmailToUserDN(email)
+
+            if userdn:
+                profile = userLib.profile(dn=userdn)
+                return render.user_profile(user_profile=profile)
+            else:
+                web.seeother('/domains')
+        else:
+            web.seeother('/domains')
+
+class create(dbinit):
+    @base.protected
+    def GET(self, domainName=None):
+        if domainName is None:
+            domainName = ''
+        else:
+            domainName = web.safestr(domainName)
+
+        default_quota = cfg.general.get('default_quota', '1024')
+        return render.user_create(
+                domainName=domainName,
+                allDomains=domainLib.list(),
+                default_quota=session.get('default_quota'),
+                )
+
+    @base.protected
+    def POST(self):
+        i = web.input()
+
+        # Get domain name, username, cn.
+        domain = i.get('domainName', None)
+        username = i.get('username', None)
+
+        if domain is None or username is None:
+            return render.user_create(
+                    domainName=domain,
+                    allDomains=domainLib.list(),
+                    )
+
+        cn = i.get('cn', None)
+        quota = i.get('quota', session.get('default_quota'))
+
+        # Check password.
+        newpw = web.safestr(i.get('newpw'))
+        confirmpw = web.safestr(i.get('confirmpw'))
+        if len(newpw) > 0 and len(confirmpw) > 0 and newpw == confirmpw:
+            passwd = iredutils.generatePasswd(newpw, pwscheme=cfg.general.get('default_pw_scheme', 'SSHA'))
+        else:
+            return render.user_create(
+                    domainName=domain,
+                    allDomains=domainLib.list(),
+                    username=username,
+                    cn=cn,
+                    msg='PW_ERROR',
+                    )
+
+        ldif = iredldif.ldif_mailuser(
+                domain=web.safestr(domain),
+                username=web.safestr(username),
+                cn=cn,
+                passwd=passwd,
+                quota=quota,
+                )
+
+        dn = iredutils.convEmailToUserDN(username + '@' + domain)
+        result = userLib.add(dn, ldif)
+        if result is True:
+            web.seeother('/users/' + domain)
+        elif result == 'ALREADY_EXISTS':
+            web.seeother('/users/' + domain + '?msg=ALREADY_EXISTS')
+        else:
+            web.seeother('/users/' + domain)
+
+class delete(dbinit):
+    @base.protected
+    def POST(self):
+        i = web.input(mail=[])
+        domain = i.get('domain', None)
+        if domain is None:
+            web.seeother('/users?msg=NO_DOMAIN')
+
+        mails = i.get('mail', [])
+        for mail in mails:
+            dn = ldap.filter.escape_filter_chars(iredutils.convEmailToUserDN(mail))
+        print >> sys.stderr, i 
+        web.seeother('/users/' + web.safestr(domain))

controllers/ldap/utils.py

+#!/usr/bin/env python
+# encoding: utf-8
+
+# Author: Zhang Huangbin <michaelbibby (at) gmail.com>
+
+import web,sys
+
+class img:
+    def GET(self, encoded_img):
+        web.header('Content-Type', 'image/jpeg')
+        return encoded_img.decode('base64')
+i18n support HOWTO
+==================
+*) Translate 'i18n/iredadmin.po' file to your language.
+*) Convert po file to mo format:
+
+    # msgfmt iredadmin.po
+
+   You will get 'iredadmin.mo' under current directory.
+
+*) Create directory under 'i18n/' and copy 'iredadmin.mo' greneated
+   above into it. e.g. for French language(fr_FR):
+
+    # cd /path/to/iRedAdmin-x.y.z/i18n/
+    # mkdir -p fr_FR/LC_MESSAGES/
+    # cp /path/to/your/iredadmin.mo fr_FR/LC_MESSAGES/
+
+   Directory format is '{LANGUAGE}/LC_MESSAGES/'.
+
+*) Configure iRedAdmin to use your translation in config/iredconf.py:
+
+    LANG = 'fr_FR'      # The name of directory name created above.
+
+*) Restart your apache web server, it should work now.
+iRedAdmin uses Jinja2 as template engine, you can read Jinja2
+<Template Designer Documentation> here:
+
+    - http://jinja.pocoo.org/2/documentation/templates
+

docs/INSTALL.debian

+*) Overview
+
+Required components:
+    - Apache (2.2+)
+    - mod_wsgi (2.1+)
+    - Python (2.4+)
+    - webpy (0.32)
+    - MySQL-python
+    - python-ldap
+
+*) Installation
+
+    - Install python related modules and packages: 
+
+        # ---- Install development files ---
+        $ sudo apt-get install gcc python-setuptools python-dev libldap2-dev libmysqlclient15-dev libsasl2-dev libssl-dev libapache2-mod-wsgi
+
+        # ---- Install python packages ----
+        $ sudo easy_install web.py Jinja2 python-ldap MySQL-python
+
+        # ---- Enable wsgi module in apache.
+        $ sudo a2enmod mod-wsgi
+
+*) Setup
+
+    - Copy iRedAdmin to apache document root /usr/share/apache2/:
+
+        $ tar xjf iRedAdmin-x.y.z.tar.bz2
+        $ sudo mv iRedAdmin-x.y.z /usr/share/apache2/
+        $ cd /usr/share/apache2/
+        $ sudo chown -R root:root iRedAdmin-x.y.z
+        $ sudo chmod -R 0755 iRedAdmin-x.y.z
+        $ sudo ln -s iRedAdmin-x.y.z iRedAdmin
+
+    - Add apache configure file: /etc/apache2/conf.d/iredadmin.conf.
+
+        # ----
+        WSGIScriptAlias /iredadmin /usr/share/apache2/iRedAdmin/iredadmin.py
+
+        Alias /iredadmin/static /usr/share/apache2/iRedAdmin/static
+        AddType text/html .py
+
+        <Directory /usr/share/apache2/iRedAdmin/>
+            Order deny,allow
+            Allow from all
+        </Directory>
+        # ----
+
+      Restart apache to enable it:
+
+        $ sudo /etc/init.d/apache2 restart
+
+    - Create MySQL database:
+
+        $ mysql -uroot -p
+        mysql> CREATE DATABASE iredadmin DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
+        mysql> USE iredadmin;
+        mysql> SOURCE /var/www/iRedAdmin/docs/samples/iredadmin.sql;
+
+      Add MySQL user and grant privileges:
+
+        mysql> GRANT SELECT,INSERT,UPDATE,DELETE ON iredadmin.* TO iredadmin@localhost IDENTIFIED BY 'secret_passwd';
+        mysql> FLUSH PRIVILEGES;
+
+*) Configuration:
+
+    - Copy example config file:
+
+        $ cd /usr/share/apache2/iRedAdmin-x.y.z/config/
+        $ cp settings.ini.sample settings.ini
+
+    - Edit settings.ini and set several variables:
+
+        [general]
+        admin = michaelbibby@gmail.com
+        debug = False
+        lang = en_US
+        backend = ldap
+        storage_base_directory = /var/vmail/vmail01
+
+        [iredadmin]
+        dbn = mysql
+        host = localhost
+        port = 3306
+        db = iredadmin
+        user = iredadmin
+        passwd = secret_passwd
+        db_table_session = sessions
+
+        [ldap]
+        uri = ldap://127.0.0.1:389
+        suffix = dc=iredmail,dc=org
+        basedn = o=domains,dc=iredmail,dc=org
+        domainadmin_dn = o=domainAdmins,dc=iredmail,dc=org
+        bind_dn = cn=vmailadmin,dc=iredmail,dc=org
+        bind_pw = passwd
+
+*) Visit below url in your web browser for test:
+
+    http://your_server_ip_address/iredadmin/

docs/INSTALL.rhel

+*) Overview
+
+Required components:
+    - Apache (2.2+), shipped within RHEL/CentOS 5.x.
+    - mod_wsgi (2.1+)
+    - Python (2.4+), shipped within RHEL/CentOS 5.x.
+    - webpy (0.32)
+    - MySQL-python
+    - python-ldap
+
+*) Installation
+
+    - Download and install webpy-0.32:
+
+        $ wget http://webpy.org/static/web.py-0.32.tar.gz
+        $ tar xzf web.py-0.32.tar.gz
+        $ cd webpy
+        $ sudo python setup.py install
+
+      Test:
+
+        $ python
+        >>> import web
+        >>>                     # <- No error here.
+
+    - Install python related modules and packages: 
+
+        # ---- For i386 ----
+        $ sudo yum install python-setuptools gcc.i386 gcc-c++.i386 openssl-devel.i386 python-devel.i386 openldap-devel.i386 mysql-devel.i386
+
+        # ---- For x86_64 ----
+        $ sudo yum install python-setuptools gcc.x86_64 gcc-c++.x86_64 openssl-devel.x86_64 python-devel.x86_64 openldap-devel.x86_64 mysql-devel.x86_64
+
+        # ---- Install python packages ----
+        $ sudo easy_install Jinja2 python-ldap MySQL-python
+
+    - Install mod_wsgi from EPEL repository:
+
+        # ---- For i386 ----
+        $ sudo rpm -ivh http://download.fedora.redhat.com/pub/epel/5/i386/mod_wsgi-2.1-2.el5.i386.rpm
+
+        # ---- For x86_64 ----
+        $ sudo rpm -ivh http://download.fedora.redhat.com/pub/epel/5/x86_64/mod_wsgi-2.1-2.el5.x86_64.rpm
+
+*) Setup
+
+    - Copy iRedAdmin to /var/www/:
+
+        $ tar xjf iRedAdmin-x.y.z.tar.bz2
+        $ sudo mv iRedAdmin-x.y.z /var/www/
+        $ cd /var/www/
+        $ sudo chown -R root:root iRedAdmin-x.y.z
+        $ sudo chmod -R 0755 iRedAdmin-x.y.z
+
+    - Add apache configure file: /etc/httpd/conf.d/iredadmin.conf.
+
+        # ----
+        WSGIScriptAlias /iredadmin /var/www/iRedAdmin/iredadmin.py
+
+        Alias /iredadmin/static /var/www/iRedAdmin/static
+        AddType text/html .py
+
+        <Directory /var/www/iRedAdmin/>
+            Order deny,allow
+            Allow from all
+        </Directory>
+        # ----
+
+      Restart apache to enable it:
+
+        $ sudo /etc/init.d/httpd restart
+
+    - Create MySQL database:
+
+        $ mysql -uroot -p
+        mysql> CREATE DATABASE iredadmin DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
+        mysql> USE iredadmin;
+        mysql> SOURCE /var/www/iRedAdmin/docs/samples/iredadmin.sql;
+
+      Add MySQL user and grant privileges:
+
+        mysql> GRANT SELECT,INSERT,UPDATE,DELETE ON iredadmin.* TO iredadmin@localhost IDENTIFIED BY 'secret_passwd';
+        mysql> FLUSH PRIVILEGES;
+
+*) Configuration:
+
+    - Copy example config file:
+
+        $ cd /var/www/iRedAdmin-x.y.z/
+        $ cp settings.ini.sample settings.ini
+
+    - Edit settings.ini and set several variables:
+
+        [general]
+        admin = michaelbibby@gmail.com
+        debug = False
+        lang = en_US
+        backend = ldap
+        storage_base_directory = /var/vmail/vmail01
+
+        [iredadmin]
+        dbn = mysql
+        host = localhost
+        port = 3306
+        db = iredadmin
+        user = iredadmin
+        passwd = secret_passwd
+        db_table_session = sessions
+
+        [ldap]
+        uri = ldap://127.0.0.1:389
+        suffix = dc=iredmail,dc=org
+        basedn = o=domains,dc=iredmail,dc=org
+        domainadmin_dn = o=domainAdmins,dc=iredmail,dc=org
+        bind_dn = cn=vmailadmin,dc=iredmail,dc=org
+        bind_pw = passwd
+
+*) Visit below url in your web browser for test:
+
+    http://your_server_ip_address/iredadmin/

docs/samples/iredadmin.sql

+# CREATE DATABASE iredadmin DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
+# GRANT INSERT,UPDATE,DELETE,SELECT on iredadmin.* to iredadmin@localhost identified by 'secret_passwd';
+#USE iredadmin;
+
+#
+# Session table required by webpy session module.
+#
+CREATE TABLE sessions (
+    session_id CHAR(128) UNIQUE NOT NULL,
+    atime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    data TEXT,
+    INDEX session_id_index (session_id)
+) TYPE=MyISAM;
+
+#
+# Store all operations.
+#
+CREATE TABLE log (
+    timestamp DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
+    admin VARCHAR(255) NOT NULL DEFAULT '',
+    domain VARCHAR(255) NOT NULL DEFAULT '',
+    action VARCHAR(255) NOT NULL DEFAULT '',
+    data VARCHAR(255) NOT NULL DEFAULT '',
+    KEY TIMESTAMP (TIMESTAMP),
+    INDEX timestamp_index (timestamp),
+    INDEX admin_index (admin),
+    INDEX domain_index (domain),
+    INDEX action_index (action)
+) TYPE=MyISAM;
+
+#
+# author: Who public this announcement.
+# admins: Who will see this announcement. Default is ALL admins.
+#         Multiple admins should be seperated by comma.
+# starttime: When this ann msg will be displayed. Default is NOW.
+# endtime:   When it should not be displayed.
+# subject: message subject.
+# message: content of ann msg.
+#
+CREATE TABLE announcements (
+    id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+    author VARCHAR(250) NOT NULL,
+    admins VARCHAR(250) NOT NULL DEFAULT 'ALL',
+    starttime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, 
+    endtime TIMESTAMP,
+    subject VARCHAR(250) NOT NULL,
+    message text NOT NULL,
+    PRIMARY KEY (id),
+    INDEX id_index (id),
+    INDEX author_index (author),
+    INDEX admins_index (admins),
+    INDEX starttime_index (starttime),
+    INDEX endtime_index (endtime)
+) TYPE=MyISAM;

docs/samples/ldap_init.ldif

+dn: dc=iredmail,dc=org
+objectclass: dcObject
+objectclass: organization
+dc: iredmail
+o: iredmail
+
+dn: cn=vmail,dc=iredmail,dc=org
+objectClass: person
+objectClass: shadowAccount
+objectClass: top
+cn: vmail
+sn: vmail
+uid: vmail
+userPassword: passwd
+
+dn: cn=vmailadmin,dc=iredmail,dc=org
+objectClass: person
+objectClass: shadowAccount
+objectClass: top
+cn: vmailadmin
+sn: vmailadmin
+uid: vmailadmin
+userPassword: passwd
+
+dn: o=domains,dc=iredmail,dc=org
+objectClass: Organization
+o: domains
+
+dn: o=domainAdmins,dc=iredmail,dc=org
+objectClass: Organization
+o: domainAdmins
+
+dn: domainName=a.cn,o=domains,dc=iredmail,dc=org
+objectClass: mailDomain
+domainName: a.cn
+mtaTransport: dovecot
+accountStatus: active
+enabledService: mail
+
+dn: ou=Users,domainName=a.cn,o=domains,dc=iredmail,dc=org
+objectClass: organizationalUnit
+objectClass: top
+ou: Users
+
+dn: ou=Groups,domainName=a.cn,o=domains,dc=iredmail,dc=org
+objectClass: organizationalUnit
+objectClass: top
+ou: Groups
+
+dn: ou=Aliases,domainName=a.cn,o=domains,dc=iredmail,dc=org
+objectClass: organizationalUnit
+objectClass: top
+ou: Aliases
+
+dn: mail=postmaster@a.cn,o=domainAdmins,dc=iredmail,dc=org
+objectClass: mailAdmin
+objectClass: shadowAccount
+objectClass: top
+cn: postmaster
+uid: postmaster
+givenName: postmaster
+mail: postmaster@a.cn
+accountStatus: active
+userPassword: passwd
+domainGlobalAdmin: yes
+enabledService: awstats
+
+dn: mail=www@a.cn,ou=Users,domainName=a.cn,o=domains,dc=iredmail,dc=org
+objectClass: inetOrgPerson
+objectClass: shadowAccount
+objectClass: mailUser
+objectClass: top
+cn: www
+sn: www
+uid: www
+givenName: www
+mail: www@a.cn
+accountStatus: active
+mailMessageStore: a.cn/www/
+homeDirectory: /home/vmail
+mailQuota: 104857600
+userPassword: passwd
+enabledService: mail
+enabledService: smtp
+enabledService: pop3
+enabledService: imap
+enabledService: deliver
+enabledService: forward
+enabledService: senderbcc
+enabledService: recipientbcc
+enabledService: managesieve
+memberOfGroup: all@a.cn
+[jinja2: templates/**.html]
+encoding = utf-8
+line_statement_prefix = %
+#!/bin/sh
+
+# =========================================================
+# Author:    Zhang Huangbin (michaelbibby@gmail.com)
+# =========================================================
+
+ACTION="$1"
+
+POFILE="iredadmin.po"
+
+if [ X"${ACTION}" == X"extract" ]; then
+    # Extract.
+    pybabel -v extract -F babel.cfg \
+        --charset=utf-8 \
+        --sort-by-file \
+        --msgid-bugs-address=michaelbibby@gmail.com \
+        -o ${POFILE} \
+        ..
+elif [ X"${ACTION}" == X"update" ]; then
+    # Update.
+    pybabel update -i ${POFILE} \
+        --ignore-obsolete \
+        --previous \
+        -D iredadmin \
+        -d . \
+        -l zh_CN
+else
+    :
+fi

i18n/en_US/LC_MESSAGES/iredadmin.mo

Binary file added.

i18n/en_US/LC_MESSAGES/iredadmin.po

+# Translations template for PROJECT.
+# Copyright (C) 2009 ORGANIZATION
+# This file is distributed under the same license as the PROJECT project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2009.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PROJECT VERSION\n"
+"Report-Msgid-Bugs-To: michaelbibby@gmail.com\n"
+"POT-Creation-Date: 2009-06-27 11:47+0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.4\n"
+
+#: ../templates/default/ldap/admin/add.html:5
+#: ../templates/default/ldap/admin/list.html:5
+#: ../templates/punbb/ldap/admin_add.html:5
+#: ../templates/punbb/ldap/layout.html:75
+msgid "Admins"
+msgstr ""
+
+#: ../templates/default/ldap/admin/add.html:10
+#: ../templates/punbb/ldap/admin_add.html:10
+msgid "Add new admin(s):"
+msgstr ""
+
+#: ../templates/default/ldap/admin/add.html:15
+#: ../templates/punbb/ldap/admin_add.html:15
+msgid "Note: Multiple accounts must be sperated by SPACE."
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:20
+msgid "Search admin"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:24
+#: ../templates/default/ldap/group/list.html:29
+msgid "Search"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:35
+msgid "Add a new admin:"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:36
+msgid "E-Mail:"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:37
+msgid "Password:"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:38
+msgid "As Global Admin"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:38
+msgid "Add now"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:41
+#: ../templates/default/ldap/group/list.html:48
+msgid "Note:"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:43
+msgid "Do <strong>NOT</strong> specify multiple accounts."
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:57
+#: ../templates/default/ldap/domain/add.html:22
+#: ../templates/default/ldap/domain/list.html:23
+#: ../templates/default/ldap/group/list.html:62
+#: ../templates/default/ldap/preferences/chpwd.html:9
+#: ../templates/default/ldap/user/list.html:25
+#: ../templates/punbb/ldap/aliases.html:65
+#: ../templates/punbb/ldap/domain_add.html:22
+#: ../templates/punbb/ldap/domains.html:28
+#: ../templates/punbb/ldap/maillists.html:65
+msgid "System message:"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:68
+msgid "All admins:"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:79
+#: ../templates/default/ldap/domain/profile.html:69
+#: ../templates/default/ldap/user/list.html:53
+#: ../templates/punbb/ldap/admins.html:90
+#: ../templates/punbb/ldap/domain_profile.html:171
+#: ../templates/punbb/ldap/users.html:60
+msgid "Mail"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:80
+msgid "Status"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:81
+#: ../templates/punbb/ldap/admins.html:91
+msgid "Global Admin"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:82
+#: ../templates/default/ldap/domain/list.html:53
+#: ../templates/default/ldap/group/list.html:94
+#: ../templates/default/ldap/policyd/blacklist_helo.html:25
+#: ../templates/default/ldap/user/list.html:56
+#: ../templates/punbb/ldap/admins.html:92
+#: ../templates/punbb/ldap/aliases.html:90
+#: ../templates/punbb/ldap/blacklist_helo.html:25
+#: ../templates/punbb/ldap/domains.html:59
+#: ../templates/punbb/ldap/maillists.html:98
+#: ../templates/punbb/ldap/users.html:63
+msgid "Operations"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:111
+#: ../templates/default/ldap/domain/list.html:71
+#: ../templates/default/ldap/group/list.html:119
+#: ../templates/punbb/ldap/domains.html:95
+msgid "Edit"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:120
+#: ../templates/default/ldap/admin/list.html:140
+#: ../templates/default/ldap/domain/list.html:79
+#: ../templates/default/ldap/domain/list.html:90
+#: ../templates/default/ldap/domain/list.html:100
+#: ../templates/default/ldap/group/list.html:128
+#: ../templates/default/ldap/group/list.html:138
+#: ../templates/default/ldap/policyd/blacklist_helo.html:34
+#: ../templates/default/ldap/policyd/blacklist_helo.html:43
+#: ../templates/default/ldap/user/list.html:84
+#: ../templates/default/ldap/user/list.html:95
+#: ../templates/punbb/ldap/admins.html:115
+#: ../templates/punbb/ldap/admins.html:125
+#: ../templates/punbb/ldap/aliases.html:115
+#: ../templates/punbb/ldap/aliases.html:125
+#: ../templates/punbb/ldap/blacklist_helo.html:34
+#: ../templates/punbb/ldap/blacklist_helo.html:43
+#: ../templates/punbb/ldap/domains.html:106
+#: ../templates/punbb/ldap/domains.html:116
+#: ../templates/punbb/ldap/maillists.html:126
+#: ../templates/punbb/ldap/maillists.html:136
+#: ../templates/punbb/ldap/users.html:96 ../templates/punbb/ldap/users.html:106
+msgid "Delete"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:120
+#: ../templates/punbb/ldap/admins.html:115
+msgid "Delete this admin?"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:139
+#: ../templates/default/ldap/domain/list.html:99
+#: ../templates/default/ldap/group/list.html:137
+#: ../templates/default/ldap/policyd/blacklist_helo.html:42
+#: ../templates/default/ldap/user/list.html:94
+#: ../templates/punbb/ldap/admins.html:124
+#: ../templates/punbb/ldap/aliases.html:124
+#: ../templates/punbb/ldap/blacklist_helo.html:42
+#: ../templates/punbb/ldap/domains.html:115
+#: ../templates/punbb/ldap/maillists.html:135
+#: ../templates/punbb/ldap/users.html:105
+msgid "Select all"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:140
+msgid "Are you sure want to delete selected admin(s)?"
+msgstr ""
+
+#: ../templates/default/ldap/admin/list.html:140
+#: ../templates/default/ldap/domain/list.html:100
+#: ../templates/default/ldap/group/list.html:138
+#: ../templates/default/ldap/policyd/blacklist_helo.html:43
+#: ../templates/default/ldap/user/list.html:95
+#: ../templates/punbb/ldap/blacklist_helo.html:43
+msgid "Deleted"
+msgstr ""
+
+#: ../templates/default/ldap/dashboard.html:3
+#: ../templates/default/ldap/layout.html:85
+#: ../templates/default/ldap/admin/layout.html:85
+#: ../templates/default/ldap/domain/layout.html:84
+#: ../templates/default/ldap/group/layout.html:85
+#: ../templates/default/ldap/preferences/layout.html:85
+#: ../templates/default/ldap/user/layout.html:85
+#: ../templates/punbb/ldap/dashboard.html:3
+#: ../templates/punbb/ldap/layout.html:71
+msgid "Dashboard"
+msgstr ""
+
+#: ../templates/default/ldap/dashboard.html:15
+msgid "Loading..."
+msgstr ""
+
+#: ../templates/default/ldap/dashboard.html:33
+#: ../templates/default/ldap/dashboard.html:48
+msgid "iRedMail - News and Announcements"
+msgstr ""
+
+#: ../templates/default/ldap/dashboard.html:38
+#: ../templates/default/ldap/dashboard.html:53
+msgid "iRedMail - General Technical Support"
+msgstr ""
+
+#: ../templates/default/ldap/dashboard.html:43
+#: ../templates/default/ldap/dashboard.html:58
+msgid "iRedMail - Success Stories"
+msgstr ""
+
+#: ../templates/default/ldap/dashboard.html:66
+msgid "iRedMail Project News"
+msgstr ""
+
+#: ../templates/default/ldap/domain/add.html:10
+#: ../templates/punbb/ldap/domain_add.html:10
+msgid "Add new domain(s):"
+msgstr ""
+
+#: ../templates/default/ldap/domain/add.html:16
+#: ../templates/punbb/ldap/domain_add.html:16
+msgid "Note: Multiple domains must be sperated by SPACE."
+msgstr ""
+
+#: ../templates/default/ldap/domain/list.html:5
+#: ../templates/punbb/ldap/domains.html:5
+msgid "Mail domains"
+msgstr ""
+
+#: ../templates/default/ldap/domain/list.html:29
+#: ../templates/punbb/ldap/domains.html:34
+msgid "Deleted:"
+msgstr ""
+
+#: ../templates/default/ldap/domain/list.html:31
+#: ../templates/punbb/ldap/domains.html:36
+msgid "No such object:"
+msgstr ""
+
+#: ../templates/default/ldap/domain/list.html:43
+msgid "Domain(s) under your control:"
+msgstr ""
+
+#: ../templates/default/ldap/domain/list.html:50
+#: ../templates/punbb/ldap/domains.html:53
+msgid "Domain Name"
+msgstr ""
+
+#: ../templates/default/ldap/domain/list.html:51
+#: ../templates/default/ldap/domain/profile.html:60
+#: ../templates/punbb/ldap/domain_profile.html:148
+#: ../templates/punbb/ldap/domain_profile.html:150
+#: ../templates/punbb/ldap/domains.html:58
+msgid "Backup MX"
+msgstr ""
+
+#: ../templates/default/ldap/domain/list.html:52
+#: ../templates/default/ldap/domain/profile.html:41
+#: ../templates/default/ldap/user/list.html:55
+#: ../templates/default/ldap/user/profile.html:48
+#: ../templates/punbb/ldap/users.html:62
+msgid "Created Date"
+msgstr ""
+
+#: ../templates/default/ldap/domain/list.html:71
+msgid "Edit domain detail"
+msgstr ""
+
+#: ../templates/default/ldap/domain/list.html:79
+msgid "List all users"
+msgstr ""
+
+#: ../templates/default/ldap/domain/list.html:82
+msgid "List all groups"
+msgstr ""
+
+#: ../templates/default/ldap/domain/list.html:85
+msgid "List all aliases"
+msgstr ""
+
+#: ../templates/default/ldap/domain/list.html:90
+#: ../templates/punbb/ldap/domains.html:106
+msgid "Delete this domain?"
+msgstr ""
+
+#: ../templates/default/ldap/domain/list.html:90
+#: ../templates/punbb/ldap/domains.html:106
+msgid "Delete this domain"
+msgstr ""
+
+#: ../templates/default/ldap/domain/list.html:100
+msgid "Are you sure want to delete selected domain(s)?"
+msgstr ""
+
+#: ../templates/default/ldap/domain/list.html:106
+#: ../templates/default/ldap/preferences/chpwd.html:11
+#: ../templates/default/ldap/preferences/chpwd.html:13
+#: ../templates/punbb/ldap/domains.html:122
+msgid "Error:"
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:3
+#: ../templates/punbb/ldap/domain_profile.html:3
+msgid "Edit domain profile"
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:22
+msgid "Detail of domain:"
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:27
+msgid "Domain name"
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:35
+#: ../templates/default/ldap/domain/profile.html:36
+#: ../templates/punbb/ldap/domain_profile.html:72
+#: ../templates/punbb/ldap/domain_profile.html:75
+msgid "Company/Organization"
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:46
+#: ../templates/default/ldap/user/profile.html:53
+#: ../templates/punbb/ldap/domain_profile.html:66
+msgid "Last Modify Date"
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:52
+#: ../templates/default/ldap/user/profile.html:59
+msgid "Account Status"
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:54
+#: ../templates/default/ldap/user/profile.html:61
+#: ../templates/punbb/ldap/domain_profile.html:88
+#: ../templates/punbb/ldap/user_profile.html:89
+msgid "Active"
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:55
+#: ../templates/default/ldap/user/profile.html:62
+#: ../templates/punbb/ldap/domain_profile.html:92
+#: ../templates/punbb/ldap/user_profile.html:93
+msgid "Disabled"
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:62
+#: ../templates/punbb/ldap/domain_profile.html:154
+#: ../templates/punbb/ldap/user_profile.html:106
+msgid "Yes"
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:63
+#: ../templates/punbb/ldap/domain_profile.html:158
+msgid "No"
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:67
+#: ../templates/default/ldap/user/profile.html:119
+#: ../templates/punbb/ldap/domain_profile.html:165
+#: ../templates/punbb/ldap/domain_profile.html:167
+#: ../templates/punbb/ldap/user_profile.html:113
+#: ../templates/punbb/ldap/user_profile.html:115
+msgid "Enabled services"
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:71
+#: ../templates/punbb/ldap/domain_profile.html:176
+msgid "Sender Bcc"
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:73
+#: ../templates/punbb/ldap/domain_profile.html:181
+msgid "Recipient Bcc"
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:78
+#: ../templates/default/ldap/user/profile.html:146
+#: ../templates/punbb/ldap/user_profile.html:201
+msgid "Recipient Bcc Address"
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:79
+#: ../templates/default/ldap/domain/profile.html:84
+#: ../templates/default/ldap/user/profile.html:139
+#: ../templates/default/ldap/user/profile.html:150
+#: ../templates/default/ldap/user/profile.html:158
+#: ../templates/punbb/ldap/login.html:21
+#: ../templates/punbb/ldap/user_profile.html:194
+#: ../templates/punbb/ldap/user_profile.html:205
+#: ../templates/punbb/ldap/user_profile.html:213
+msgid "Must be a valid email address."
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:79
+#: ../templates/default/ldap/user/profile.html:150
+#: ../templates/punbb/ldap/user_profile.html:205
+msgid "Recipient Bcc Address."
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:83
+#: ../templates/default/ldap/user/profile.html:154
+#: ../templates/punbb/ldap/user_profile.html:209
+msgid "Sender Bcc Address"
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:84
+#: ../templates/default/ldap/user/profile.html:158
+#: ../templates/punbb/ldap/user_profile.html:213
+msgid "Sender Bcc Address."
+msgstr ""
+
+#: ../templates/default/ldap/domain/profile.html:91
+#: ../templates/default/ldap/preferences/language.html:28
+msgid "Save"
+msgstr ""
+
+#: ../templates/default/ldap/error.html:3
+#: ../templates/default/ldap/group/list.html:5
+#: ../templates/default/ldap/user/list.html:5
+#: ../templates/punbb/ldap/domains.html:55 ../templates/punbb/ldap/error.html:3
+#: ../templates/punbb/ldap/submenus.html:9
+msgid "Users"
+msgstr ""
+
+#: ../templates/default/ldap/group/list.html:25
+msgid "Search group"
+msgstr ""
+
+#: ../templates/default/ldap/group/list.html:38
+msgid "Add new group(s)"
+msgstr ""
+
+#: ../templates/default/ldap/group/list.html:50
+msgid "Do <strong>NOT</strong> include domain name."
+msgstr ""
+
+#: ../templates/default/ldap/group/list.html:51
+msgid ""
+"Multiple accounts <strong>MUST</strong> be sperated by "
+"<strong>SPACE</strong>."
+msgstr ""
+
+#: ../templates/default/ldap/group/list.html:66
+#: ../templates/default/ldap/user/list.html:29
+#: ../templates/punbb/ldap/aliases.html:69
+#: ../templates/punbb/ldap/maillists.html:69
+msgid "Permission deny."
+msgstr ""
+
+#: ../templates/default/ldap/group/list.html:68
+#: ../templates/default/ldap/user/list.html:31
+#: ../templates/punbb/ldap/aliases.html:71
+#: ../templates/punbb/ldap/maillists.html:71
+msgid "Size limit exceeded."
+msgstr ""
+
+#: ../templates/default/ldap/group/list.html:70
+#: ../templates/default/ldap/user/list.html:33
+#: ../templates/punbb/ldap/aliases.html:73
+#: ../templates/punbb/ldap/maillists.html:73
+msgid "Added success."
+msgstr ""
+
+#: ../templates/default/ldap/group/list.html:79
+#, python-format
+msgid "All groups under domain %s:"
+msgstr ""
+
+#: ../templates/default/ldap/group/list.html:91
+#: ../templates/default/ldap/user/list.html:52
+#: ../templates/default/ldap/user/profile.html:68
+#: ../templates/default/ldap/user/profile.html:69
+#: ../templates/punbb/ldap/aliases.html:88
+#: ../templates/punbb/ldap/maillists.html:94
+#: ../templates/punbb/ldap/users.html:58
+msgid "Name"
+msgstr ""
+
+#: ../templates/default/ldap/group/list.html:92
+#: ../templates/default/ldap/user/profile.html:40
+#: ../templates/punbb/ldap/aliases.html:89
+#: ../templates/punbb/ldap/maillists.html:96
+msgid "Email Address"
+msgstr ""
+
+#: ../templates/default/ldap/group/list.html:93
+#: ../templates/punbb/ldap/maillists.html:97
+msgid "Type"
+msgstr ""
+
+#: ../templates/default/ldap/group/list.html:111
+#: ../templates/punbb/ldap/aliases.html:107
+#: ../templates/punbb/ldap/maillists.html:117
+msgid "Edit group profile"
+msgstr ""
+
+#: ../templates/default/ldap/group/list.html:124
+msgid "Detail"
+msgstr ""
+
+#: ../templates/default/ldap/group/list.html:128
+#: ../templates/punbb/ldap/aliases.html:115
+#: ../templates/punbb/ldap/maillists.html:126
+msgid "Delete this group?"
+msgstr ""
+
+#: ../templates/default/ldap/group/list.html:128
+#: ../templates/punbb/ldap/aliases.html:115
+#: ../templates/punbb/ldap/maillists.html:126
+msgid "Delete this group"
+msgstr ""
+
+#: ../templates/default/ldap/group/list.html:138
+#: ../templates/punbb/ldap/admins.html:125
+#: ../templates/punbb/ldap/aliases.html:125
+#: ../templates/punbb/ldap/domains.html:116
+#: ../templates/punbb/ldap/maillists.html:136
+#: ../templates/punbb/ldap/users.html:106
+msgid "Are you sure want to delete selected group(s)?"
+msgstr ""
+
+#: ../templates/default/ldap/layout.html:70
+#: ../templates/default/ldap/admin/layout.html:70
+#: ../templates/default/ldap/domain/layout.html:69
+#: ../templates/default/ldap/group/layout.html:70
+#: ../templates/default/ldap/preferences/layout.html:70
+#: ../templates/default/ldap/preferences/preferences.html:3
+#: ../templates/default/ldap/user/layout.html:70
+#: ../templates/punbb/ldap/layout.html:77
+#: ../templates/punbb/ldap/preferences.html:3
+msgid "Preferences"
+msgstr ""
+
+#: ../templates/default/ldap/layout.html:71
+#: ../templates/default/ldap/admin/layout.html:71
+#: ../templates/default/ldap/domain/layout.html:70
+#: ../templates/default/ldap/group/layout.html:71
+#: ../templates/default/ldap/preferences/layout.html:71
+#: ../templates/default/ldap/user/layout.html:71
+#: ../templates/punbb/ldap/layout.html:78
+msgid "Logout"
+msgstr ""
+
+#: ../templates/default/ldap/layout.html:76
+#: ../templates/default/ldap/admin/layout.html:76
+#: ../templates/default/ldap/domain/layout.html:75
+#: ../templates/default/ldap/group/layout.html:76
+#: ../templates/default/ldap/preferences/layout.html:76
+#: ../templates/default/ldap/user/layout.html:76
+#: ../templates/punbb/ldap/layout.html:65
+msgid "iRedMail Management"
+msgstr ""
+
+#: ../templates/default/ldap/layout.html:86
+#: ../templates/default/ldap/admin/layout.html:86
+#: ../templates/default/ldap/domain/layout.html:85
+#: ../templates/default/ldap/group/layout.html:86
+#: ../templates/default/ldap/preferences/layout.html:86
+#: ../templates/default/ldap/user/layout.html:86
+#: ../templates/punbb/ldap/layout.html:72
+msgid "Mail Domains"
+msgstr ""
+
+#: ../templates/default/ldap/layout.html:90
+#: ../templates/default/ldap/admin/layout.html:90
+#: ../templates/default/ldap/domain/layout.html:89
+#: ../templates/default/ldap/group/layout.html:90
+#: ../templates/default/ldap/preferences/layout.html:90
+#: ../templates/default/ldap/user/layout.html:90
+msgid "Admin List"
+msgstr ""
+
+#: ../templates/default/ldap/layout.html:119
+#: ../templates/default/ldap/admin/layout.html:119
+#: ../templates/default/ldap/domain/layout.html:118
+#: ../templates/default/ldap/group/layout.html:119
+#: ../templates/default/ldap/preferences/layout.html:119
+#: ../templates/default/ldap/user/layout.html:119
+#: ../templates/punbb/ldap/layout.html:104
+msgid "Support Forum"
+msgstr ""
+
+#: ../templates/default/ldap/login.html:113
+msgid "Domain Control Panel"
+msgstr ""
+
+#: ../templates/default/ldap/login.html:136
+#: ../templates/default/ldap/login.html:190
+msgid "Login"
+msgstr ""
+
+#: ../templates/default/ldap/login.html:143
+msgid "Login required!"
+msgstr ""
+
+#: ../templates/default/ldap/login.html:145
+msgid "Username or password is incorrect."
+msgstr ""
+
+#: ../templates/default/ldap/login.html:147
+#, python-format
+msgid ""
+"LDAP server is DOWN, please contact <a href=\"mailto:%s\">system "
+"admin</a> AS SOON AS POSSIBLE."
+msgstr ""
+
+#: ../templates/default/ldap/login.html:155
+#: ../templates/punbb/ldap/login.html:21
+#: ../templates/punbb/ldap/user_profile.html:60
+#: ../templates/punbb/ldap/user_profile.html:63
+msgid "Username"
+msgstr ""
+
+#: ../templates/default/ldap/login.html:157
+msgid "Must be a valid email address"
+msgstr ""
+
+#: ../templates/default/ldap/login.html:169
+#: ../templates/punbb/ldap/login.html:28
+msgid "Password"
+msgstr ""
+
+#: ../templates/default/ldap/login.html:185
+#: ../templates/punbb/ldap/login.html:36
+msgid "Remember me"
+msgstr ""
+
+#: ../templates/default/ldap/macros.html:7
+#: ../templates/default/ldap/admin/macros.html:7
+#: ../templates/default/ldap/domain/macros.html:7
+#: ../templates/default/ldap/group/macros.html:7
+#: ../templates/default/ldap/user/macros.html:7
+#: ../templates/punbb/ldap/macros.html:7
+msgid "Status:"
+msgstr ""
+
+#: ../templates/default/ldap/pageNotFound.html:3
+#: ../templates/punbb/ldap/pageNotFound.html:3
+#: ../templates/punbb/ldap/pageNotFound.html:6
+msgid "Page not found."
+msgstr ""
+
+#: ../templates/default/ldap/policyd/blacklist_dns.html:3
+#: ../templates/default/ldap/policyd/blacklist_helo.html:3
+#: ../templates/punbb/ldap/blacklist_dns.html:3
+#: ../templates/punbb/ldap/blacklist_helo.html:3
+msgid "Spam Control"
+msgstr ""
+
+#: ../templates/default/ldap/policyd/blacklist_dns.html:7
+#: ../templates/default/ldap/policyd/blacklist_helo.html:7
+#: ../templates/punbb/ldap/blacklist_dns.html:7
+#: ../templates/punbb/ldap/blacklist_helo.html:7
+msgid "Blacklist (DNS)"
+msgstr ""
+
+#: ../templates/default/ldap/policyd/blacklist_dns.html:8
+#: ../templates/default/ldap/policyd/blacklist_helo.html:8
+#: ../templates/punbb/ldap/blacklist_dns.html:8
+#: ../templates/punbb/ldap/blacklist_helo.html:8
+msgid "Blacklist (HELO)"
+msgstr ""
+
+#: ../templates/default/ldap/policyd/blacklist_dns.html:9
+#: ../templates/default/ldap/policyd/blacklist_helo.html:9
+#: ../templates/punbb/ldap/blacklist_dns.html:9
+#: ../templates/punbb/ldap/blacklist_helo.html:9
+msgid "Blacklist (IP Address)"
+msgstr ""
+
+#: ../templates/default/ldap/policyd/blacklist_dns.html:10
+#: ../templates/default/ldap/policyd/blacklist_helo.html:10
+#: ../templates/punbb/ldap/blacklist_dns.html:10
+#: ../templates/punbb/ldap/blacklist_helo.html:10
+msgid "Whitelist (DNS)"
+msgstr ""
+
+#: ../templates/default/ldap/policyd/blacklist_dns.html:11
+#: ../templates/default/ldap/policyd/blacklist_helo.html:11
+#: ../templates/punbb/ldap/blacklist_dns.html:11
+#: ../templates/punbb/ldap/blacklist_helo.html:11
+msgid "Whitelist (IP Address)"
+msgstr ""
+
+#: ../templates/default/ldap/policyd/blacklist_helo.html:17
+#: ../templates/punbb/ldap/blacklist_helo.html:17
+msgid "Blacklisted HELO identifiers:"
+msgstr ""
+
+#: ../templates/default/ldap/policyd/blacklist_helo.html:23
+#: ../templates/punbb/ldap/blacklist_helo.html:23
+msgid "No."
+msgstr ""
+
+#: ../templates/default/ldap/policyd/blacklist_helo.html:24
+#: ../templates/punbb/ldap/blacklist_helo.html:24
+msgid "Blacklist HELO"
+msgstr ""
+
+#: ../templates/default/ldap/policyd/blacklist_helo.html:34
+#: ../templates/punbb/ldap/blacklist_helo.html:34
+msgid "Are you sure want to delete this HELO identifier?"
+msgstr ""
+
+#: ../templates/default/ldap/policyd/blacklist_helo.html:34
+#: ../templates/punbb/ldap/blacklist_helo.html:34
+msgid "Delete this HELO identifier"
+msgstr ""
+
+#: ../templates/default/ldap/policyd/blacklist_helo.html:43
+#: ../templates/punbb/ldap/blacklist_helo.html:43
+msgid "Are you sure want to delete selected item(s)?"
+msgstr ""
+
+#: ../templates/default/ldap/policyd/whitelist_add.html:3
+#: ../templates/punbb/ldap/whitelist_add.html:3
+msgid "Add whitelist host"
+msgstr ""
+
+#: ../templates/default/ldap/preferences/chpwd.html:9
+msgid "Password changed."
+msgstr ""
+
+#: ../templates/default/ldap/preferences/chpwd.html:11
+msgid "Old password is incorrect."
+msgstr ""
+
+#: ../templates/default/ldap/preferences/chpwd.html:17
+msgid "Change password for user:"
+msgstr ""
+
+#: ../templates/default/ldap/preferences/chpwd.html:22
+msgid "Current password:"
+msgstr ""
+
+#: ../templates/default/ldap/preferences/chpwd.html:26
+msgid "New password:"
+msgstr ""
+
+#: ../templates/default/ldap/preferences/chpwd.html:30
+msgid "Retype new password:"
+msgstr ""
+
+#: ../templates/default/ldap/preferences/chpwd.html:34
+msgid "Change now"
+msgstr ""
+
+#: ../templates/default/ldap/preferences/language.html:3
+#: ../templates/default/ldap/preferences/language.html:17
+#: ../templates/punbb/ldap/preferences.html:16
+#: ../templates/punbb/ldap/preferences.html:19
+msgid "Default language"
+msgstr ""
+
+#: ../templates/default/ldap/preferences/language.html:12
+msgid "Set default language:"
+msgstr ""
+
+#: ../templates/default/ldap/sidebars.html:3
+msgid "List all domains"
+msgstr ""
+
+#: ../templates/default/ldap/sidebars.html:5
+#: ../templates/default/ldap/domain/add.html:3
+#: ../templates/punbb/ldap/domain_add.html:3
+msgid "Add new domain(s)"
+msgstr ""
+
+#: ../templates/default/ldap/sidebars.html:12
+msgid "System Info"
+msgstr ""
+
+#: ../templates/default/ldap/sidebars.html:13
+msgid "Project News"
+msgstr ""
+
+#: ../templates/default/ldap/sidebars.html:19
+msgid "List all admins"
+msgstr ""
+
+#: ../templates/default/ldap/sidebars.html:20
+msgid "Add new admin(s)"
+msgstr ""
+
+#: ../templates/default/ldap/sidebars.html:26
+#: ../templates/default/ldap/preferences/chpwd.html:3
+#: ../templates/punbb/ldap/preferences.html:32
+msgid "Change password"
+msgstr ""
+
+#: ../templates/default/ldap/user/delete.html:3
+msgid "Delete user"
+msgstr ""
+
+#: ../templates/default/ldap/user/list.html:42
+#, python-format
+msgid "All users under domain %s:"
+msgstr ""
+
+#: ../templates/default/ldap/user/list.html:54
+#: ../templates/default/ldap/user/profile.html:96
+#: ../templates/punbb/ldap/user_profile.html:178
+#: ../templates/punbb/ldap/users.html:61
+msgid "Mail Quota"
+msgstr ""
+
+#: ../templates/default/ldap/user/list.html:73
+#: ../templates/default/ldap/user/profile.html:3
+#: ../templates/punbb/ldap/user_profile.html:5
+#: ../templates/punbb/ldap/users.html:83
+msgid "Edit user profile"
+msgstr ""
+
+#: ../templates/default/ldap/user/list.html:74
+#: ../templates/punbb/ldap/users.html:86
+msgid "Send mail to"
+msgstr ""
+
+#: ../templates/default/ldap/user/list.html:84
+#: ../templates/punbb/ldap/users.html:96
+msgid "Delete this user?"
+msgstr ""
+
+#: ../templates/default/ldap/user/list.html:84
+#: ../templates/punbb/ldap/users.html:96
+msgid "Delete this user"
+msgstr ""
+
+#: ../templates/default/ldap/user/list.html:95
+msgid "Are you sure want to delete selected user(s)?"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:30
+#, python-format
+msgid "Detail of user: %s (<a href=\"mailto:%s\">%s</a>)"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:35
+msgid "Avatar"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:63
+msgid "Displayed in Global Address Book"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:73
+#: ../templates/default/ldap/user/profile.html:74
+msgid "Employee ID"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:78
+#: ../templates/default/ldap/user/profile.html:81
+#: ../templates/punbb/ldap/user_profile.html:72
+#: ../templates/punbb/ldap/user_profile.html:75
+msgid "Telephone Number"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:88
+#: ../templates/punbb/ldap/user_profile.html:170
+msgid "Mailbox directory"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:90
+#: ../templates/punbb/ldap/user_profile.html:172
+msgid "Storage base directory (user's home directory)"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:90
+#: ../templates/punbb/ldap/user_profile.html:172
+msgid "Mailbox path. Format: domain.ltd/username/"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:107
+msgid "Member of groups"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:121
+msgid "POP3"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:123
+msgid "IMAP"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:125
+msgid "SMTP"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:127
+msgid "Deliver"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:129
+msgid "Managesieve"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:134
+#: ../templates/punbb/ldap/user_profile.html:189
+msgid "Mail forwarding"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:136
+#: ../templates/default/ldap/user/profile.html:148
+#: ../templates/default/ldap/user/profile.html:156
+#: ../templates/punbb/ldap/user_profile.html:191
+#: ../templates/punbb/ldap/user_profile.html:203
+#: ../templates/punbb/ldap/user_profile.html:211
+msgid "Enable"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:137
+#: ../templates/default/ldap/user/profile.html:149
+#: ../templates/default/ldap/user/profile.html:157
+#: ../templates/punbb/ldap/user_profile.html:192
+#: ../templates/punbb/ldap/user_profile.html:204
+#: ../templates/punbb/ldap/user_profile.html:212
+msgid "Disable"
+msgstr ""
+
+#: ../templates/default/ldap/user/profile.html:163
+msgid "Submit"
+msgstr ""
+
+#: ../templates/punbb/ldap/admins.html:5
+msgid "Domain admins"
+msgstr ""
+
+#: ../templates/punbb/ldap/admins.html:60
+msgid "All mail administrators."
+msgstr ""
+
+#: ../templates/punbb/ldap/admins.html:60
+#: ../templates/punbb/ldap/domains.html:21
+msgid "Total:"
+msgstr ""
+
+#: ../templates/punbb/ldap/aliases.html:6
+msgid "Mail aliases"
+msgstr ""
+
+#: ../templates/punbb/ldap/aliases.html:110
+#: ../templates/punbb/ldap/maillists.html:120
+msgid "Send mail to this group"
+msgstr ""
+
+#: ../templates/punbb/ldap/create_user.html:3
+msgid "Create new users"
+msgstr ""
+
+#: ../templates/punbb/ldap/domain_profile.html:15
+msgid "Domain profile."
+msgstr ""
+
+#: ../templates/punbb/ldap/domain_profile.html:63