Zhang Huangbin avatar Zhang Huangbin committed 551aed9

Sync code with iRedAdmin-Pro, it now bases on iRedAdmin-Pro-LDAP-1.6.4, iRedAdmin-Pro-MySQL-1.3.2, iRedAdmin-Pro-PGSQL-1.0.

Comments (0)

Files changed (129)

 = 0.1.7 =
-    * New translation: cs_CZ. Thanks Karel Hink <karel.hink@pretiko.cz>
+    * Based on iRedAdmin-Pro-LDAP-1.6.4, iRedAdmin-Pro-MySQL-1.3.2,
+      iRedAdmin-Pro-PGSQL-1.0.
 
 = 0.1.6 =
     * [MySQL] Better SQL performance while listing all domains.
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
+* Installation Guide:
+  http://www.iredmail.org/wiki/index.php?title=Main_Page#Installation_Guide_2
+
+* Release Notes:
+  http://www.iredmail.org/wiki/index.php?title=Main_Page#Release_Notes_2
+
+* Upgrade Tutorials:
+  http://www.iredmail.org/wiki/index.php?title=Main_Page#Upgrade_Tutorials_2
+
+* Please report bugs in our forum:
+  http://www.iredmail.org/forum/

controllers/decorators.py

+# Author: Zhang Huangbin <zhb@iredmail.org>
+
+import web
+
+session = web.config.get('_session')
+
+
+def require_login(func):
+    def proxyfunc(self, *args, **kw):
+        if session.get('logged') is True:
+            return func(self, *args, **kw)
+        else:
+            session.kill()
+            raise web.seeother('/login?msg=loginRequired')
+    return proxyfunc
+
+
+def require_global_admin(func):
+    def proxyfunc(self, *args, **kw):
+        if session.get('domainGlobalAdmin') is True:
+            return func(self, *args, **kw)
+        else:
+            raise web.seeother('/domains?msg=PERMISSION_DENIED')
+    return proxyfunc
+
+
+def csrf_protected(f):
+    def decorated(*args, **kw):
+        inp = web.input()
+        if not ('csrf_token' in inp and \
+                inp.csrf_token == session.pop('csrf_token', None)):
+            return web.render('error_csrf.html')
+        return f(*args, **kw)
+    return decorated
+

controllers/ldap/admin.py

 # Author: Zhang Huangbin <zhb@iredmail.org>
 
 import web
-from controllers import base
-from libs import languages
-from libs.ldaplib import admin, domain as domainlib, connUtils
+from libs import languages, settings
+from libs.ldaplib import decorators, admin, domain as domainlib, connUtils
 
 cfg = web.iredconfig
 session = web.config.get('_session')
 
 
 class List:
-    @base.require_global_admin
-    @base.require_login
+    @decorators.require_global_admin
+    @decorators.require_login
     def GET(self, cur_page=1):
         i = web.input()
         cur_page = int(cur_page)
         sl = connutils.getSizelimitFromAccountLists(
             result[1],
             curPage=cur_page,
-            sizelimit=session['pageSizeLimit'],
+            sizelimit=settings.PAGE_SIZE_LIMIT,
         )
 
         if cur_page > sl.get('totalPages', 0):
         )
 
     # Delete, disable, enable admin accounts.
-    @base.require_global_admin
-    @base.require_login
+    @decorators.require_global_admin
+    @decorators.csrf_protected
+    @decorators.require_login
     def POST(self):
         i = web.input(_unicode=False, mail=[])
         self.mails = i.get('mail', [])
         adminLib = admin.Admin()
         if self.action == 'delete':
             result = adminLib.delete(mails=self.mails,)
-            msg = 'DELETED_SUCCESS'
+            msg = 'DELETED'
         elif self.action == 'disable':
             result = adminLib.enableOrDisableAccount(mails=self.mails, action='disable',)
-            msg = 'DISABLED_SUCCESS'
+            msg = 'DISABLED'
         elif self.action == 'enable':
             result = adminLib.enableOrDisableAccount(mails=self.mails, action='enable',)
-            msg = 'ENABLED_SUCCESS'
+            msg = 'ENABLED'
         else:
             result = (False, 'INVALID_ACTION')
             msg = i.get('msg', None)
 
         if result[0] is True:
-            return web.seeother('/admins?msg=%s' % msg)
+            raise web.seeother('/admins?msg=%s' % msg)
         else:
-            return web.seeother('/admins?msg=?' + result[1])
+            raise web.seeother('/admins?msg=' + result[1])
 
 
 class Create:
-    @base.require_global_admin
-    @base.require_login
+    @decorators.require_global_admin
+    @decorators.require_login
     def GET(self):
         i = web.input()
         return web.render('ldap/admin/create.html',
                           msg=i.get('msg'),
                          )
 
-    @base.require_global_admin
-    @base.require_login
+    @decorators.require_global_admin
+    @decorators.csrf_protected
+    @decorators.require_login
     def POST(self):
         i = web.input()
         self.mail = web.safestr(i.get('mail'))
 
         if result[0] is True:
             # Redirect to assign domains.
-            return web.seeother('/profile/admin/general/%s?msg=CREATED_SUCCESS' % self.mail)
+            raise web.seeother('/profile/admin/general/%s?msg=CREATED' % self.mail)
         else:
-            return web.seeother('/create/admin?msg=' + result[1])
+            raise web.seeother('/create/admin?msg=' + result[1])
 
 
 class Profile:
-    @base.require_login
+    @decorators.require_login
     def GET(self, profile_type, mail):
         self.mail = web.safestr(mail)
         self.profile_type = web.safestr(profile_type)
 
         if session.get('domainGlobalAdmin') is not True and session.get('username') != self.mail:
             # Don't allow to view/update other admins' profile.
-            return web.seeother('/profile/admin/general/%s?msg=PERMISSION_DENIED' % session.get('username'))
+            raise web.seeother('/profile/admin/general/%s?msg=PERMISSION_DENIED' % session.get('username'))
 
+        # Get admin profile.
         adminLib = admin.Admin()
-        # Get admin profile.
         result = adminLib.profile(self.mail)
         if result[0] is not True:
-            return web.seeother('/admins?msg=' + result[1])
+            raise web.seeother('/admins?msg=' + result[1])
         else:
             self.admin_profile = result[1]
 
 
                 # Check permission.
                 #if session.get('domainGlobalAdmin') is not True:
-                #    return web.seeother('/profile/admin/general/%s?msg=PERMISSION_DENIED' % self.mail)
+                #    raise web.seeother('/profile/admin/general/%s?msg=PERMISSION_DENIED' % self.mail)
 
                 # Get all domains.
                 domainLib = domainlib.Domain()
                 else:
                     return resultOfAllDomains
 
-                # Get domains under control.
-                resultOfManagedDomains = adminLib.getManagedDomains(mail=self.mail, attrs=['domainName', ])
-                if resultOfManagedDomains[0] is True:
-                    self.managedDomains = []
-                    for d in resultOfManagedDomains[1]:
-                        if 'domainName' in d[1].keys():
-                            self.managedDomains += d[1].get('domainName')
-                else:
-                    return resultOfManagedDomains
-
                 return web.render(
                     'ldap/admin/profile.html',
                     mail=self.mail,
                     profile=self.admin_profile,
                     languagemaps=languages.getLanguageMaps(),
                     allDomains=self.allDomains,
-                    managedDomains=self.managedDomains,
                     msg=i.get('msg', None),
                 )
             else:
-                return web.seeother('/profile/admin/%s/%s?msg=%s' % (self.profile_type, self.mail, result[1]))
+                raise web.seeother('/profile/admin/%s/%s?msg=%s' % (self.profile_type, self.mail, result[1]))
 
         elif self.profile_type == 'password':
             return web.render('ldap/admin/profile.html',
                               msg=i.get('msg', None),
                              )
 
-    @base.require_login
+    @decorators.csrf_protected
+    @decorators.require_login
     def POST(self, profile_type, mail):
         self.profile_type = web.safestr(profile_type)
         self.mail = web.safestr(mail)
 
         if session.get('domainGlobalAdmin') is not True and session.get('username') != self.mail:
             # Don't allow to view/update other admins' profile.
-            return web.seeother('/profile/admin/general/%s?msg=PERMISSION_DENIED' % session.get('username'))
+            raise web.seeother('/profile/admin/general/%s?msg=PERMISSION_DENIED' % session.get('username'))
 
         adminLib = admin.Admin()
         result = adminLib.update(
                 )
 
         if result[0] is True:
-            return web.seeother('/profile/admin/%s/%s?msg=PROFILE_UPDATED_SUCCESS' % (self.profile_type, self.mail))
+            raise web.seeother('/profile/admin/%s/%s?msg=UPDATED' % (self.profile_type, self.mail))
         else:
-            return web.seeother('/profile/admin/%s/%s?msg=%s' % (self.profile_type, self.mail, result[1]))
+            raise web.seeother('/profile/admin/%s/%s?msg=%s' % (self.profile_type, self.mail, result[1]))

controllers/ldap/basic.py

 
 import os
 import time
+import ldap
 import web
 from socket import getfqdn
 from urllib import urlencode
-from controllers import base
-from libs import __url_iredadmin_ldap_latest__, __version__
-from libs import iredutils, languages
-from libs.ldaplib import auth, admin as adminlib, ldaputils
+from libs import __url_latest_ldap__, __version_ldap__, __no__, __id__
+from libs import iredutils, languages, settings
+from libs.ldaplib import auth, decorators, admin as adminlib, ldaputils, connUtils, attrs
+
 
 cfg = web.iredconfig
 session = web.config.get('_session')
 
 class Login:
     def GET(self):
-        if session.get('logged') is True:
-            return web.seeother('/dashboard')
-        else:
+        if session.get('logged') is False:
             i = web.input(_unicode=False)
 
             # Show login page.
                               webmaster=session.get('webmaster'),
                               msg=i.get('msg'),
                              )
+        else:
+            raise web.seeother('/dashboard')
 
     def POST(self):
         # Get username, password.
         i = web.input(_unicode=False)
 
+        # Verify bind_dn & bind_pw.
+        try:
+            # Get LDAP URI.
+            uri = cfg.ldap.get('uri')
+
+            # Detect STARTTLS support.
+            if uri.startswith('ldaps://'):
+                starttls = True
+            else:
+                starttls = False
+
+            # Set necessary option for STARTTLS.
+            if starttls:
+                ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
+
+            # Initialize connection.
+            conn = ldap.initialize(uri)
+
+            # Set LDAP protocol version: LDAP v3.
+            conn.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3)
+
+            if starttls:
+                conn.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_DEMAND)
+
+            # synchronous bind.
+            conn.bind_s(cfg.ldap.get('bind_dn'), cfg.ldap.get('bind_pw'))
+            conn.unbind_s()
+        except (ldap.INVALID_CREDENTIALS):
+            raise web.seeother('/login?msg=vmailadmin_INVALID_CREDENTIALS')
+        except Exception, e:
+            raise web.seeother('/login?msg=%s' % web.safestr(e))
+
         username = web.safestr(i.get('username', '').strip())
         password = i.get('password', '').strip()
         save_pass = web.safestr(i.get('save_pass', 'no').strip())
 
         if not iredutils.isEmail(username):
-            return web.seeother('/login?msg=INVALID_USERNAME')
+            raise web.seeother('/login?msg=INVALID_USERNAME')
 
-        if len(password) == 0:
-            return web.seeother('/login?msg=EMPTY_PASSWORD')
+        if not password:
+            raise web.seeother('/login?msg=EMPTY_PASSWORD')
 
         # Convert username to ldap dn.
         userdn = ldaputils.convKeywordToDN(username, accountType='admin')
+        if userdn[0] is False:
+            raise web.seeother('/login?msg=%s' % userdn[1])
 
         # Return True if auth success, otherwise return error msg.
-        self.auth_result = auth.Auth(cfg.ldap.get('uri', 'ldap://127.0.0.1/'), userdn, password,)
+        qr_admin_auth = auth.Auth(cfg.ldap.get('uri', 'ldap://127.0.0.1/'), userdn, password,)
 
-        if self.auth_result is True:
+        if qr_admin_auth is True:
             session['username'] = username
             session['logged'] = True
 
             else:
                 pass
 
-            web.config.session_parameters['cookie_name'] = 'iRedAdmin'
+            web.config.session_parameters['cookie_name'] = 'iRedAdmin-Pro'
             # Session expire when client ip was changed.
             web.config.session_parameters['ignore_change_ip'] = False
             # Don't ignore session expiration.
                 web.config.session_parameters['timeout'] = 600      # 10 minutes
 
             web.logger(msg="Login success", event='login',)
-            return web.seeother('/dashboard/checknew')
+            raise web.seeother('/dashboard/checknew')
         else:
             session['failedTimes'] += 1
             web.logger(msg="Login failed.", admin=username, event='login', loglevel='error',)
-            return web.seeother('/login?msg=%s' % self.auth_result)
+            raise web.seeother('/login?msg=%s' % qr_admin_auth)
 
 
 class Logout:
-    @base.require_login
+    @decorators.require_login
     def GET(self):
         session.kill()
-        return web.seeother('/login')
+        raise web.seeother('/login')
 
 
 class Dashboard:
-    @base.require_login
-    def GET(self, checknew=None):
-        i = web.input(_unicode=False,)
-
-        if checknew is not None:
-            self.checknew = True
-        else:
-            self.checknew = False
+    @decorators.require_login
+    def GET(self, checknew=False):
+        if checknew:
+            checknew = True
 
         # Get network interface related infomation.
         netif_data = {}
                     data = addr[netifaces.AF_INET][0]
                     try:
                         netif_data[iface] = {'addr': data['addr'], 'netmask': data['netmask'], }
-                    except:
+                    except Exception:
                         pass
-        except:
+        except Exception:
             pass
 
         # Check new version.
-        if session.get('domainGlobalAdmin') is True and self.checknew is True:
+        newVersionInfo = (None, )
+        if session.get('domainGlobalAdmin') is True and checknew is True:
             try:
                 curdate = time.strftime('%Y-%m-%d')
                 vars = dict(date=curdate)
                 if len(r) == 0:
                     urlInfo = {
                         'a': cfg.general.get('webmaster', session.get('username', '')),
-                        'v': __version__,
+                        'v': __version_ldap__,
+                        'o': __no__,
+                        'f': __id__,
                         'host': getfqdn(),
-                        'backend': cfg.general.get('backend', ''),
                     }
 
-                    url = __url_iredadmin_ldap_latest__ + '?' + urlencode(urlInfo)
+                    url = __url_latest_ldap__ + '?' + urlencode(urlInfo)
                     newVersionInfo = iredutils.getNewVersion(url)
 
                     # Always remove all old records, just keep the last one.
 
                     # Insert updating date.
                     web.admindb.insert('updatelog', date=curdate,)
-                else:
-                    newVersionInfo = (None, )
             except Exception, e:
                 newVersionInfo = (False, str(e))
-        else:
-            newVersionInfo = (None, )
 
         return web.render(
             'dashboard.html',
-            version=__version__,
+            version=__version_ldap__,
             hostname=getfqdn(),
             uptime=iredutils.getServerUptime(),
             loadavg=os.getloadavg(),

controllers/ldap/domain.py

 # Author: Zhang Huangbin <zhb@iredmail.org>
 
 import web
-from controllers import base
-from libs import iredutils
-from libs.ldaplib import domain as domainlib, connUtils, ldaputils
+from libs import iredutils, settings
+from libs.ldaplib import decorators, admin, domain as domainlib, connUtils, ldaputils
 
 cfg = web.iredconfig
 session = web.config.get('_session')
 
 class List:
     '''List all virtual mail domains.'''
-    @base.require_login
+    @decorators.require_login
     def GET(self, cur_page=1):
         i = web.input()
         cur_page = int(cur_page)
             return result
 
         connutils = connUtils.Utils()
-        sl = connutils.getSizelimitFromAccountLists(allDomains, curPage=cur_page, sizelimit=session.get('pageSizeLimit', 50),)
+        sl = connutils.getSizelimitFromAccountLists(allDomains, curPage=cur_page, sizelimit=settings.PAGE_SIZE_LIMIT,)
 
         if cur_page > sl.get('totalPages'):
             cur_page = sl.get('totalPages')
             msg=i.get('msg', None),
         )
 
-    @base.require_global_admin
-    @base.require_login
+    @decorators.require_global_admin
+    @decorators.csrf_protected
+    @decorators.require_login
     def POST(self):
         i = web.input(domainName=[], _unicode=False,)
 
 
         if self.action == 'delete':
             result = domainLib.delete(domains=self.domainName)
-            msg = 'DELETED_SUCCESS'
+            msg = 'DELETED'
         elif self.action == 'disable':
             result = domainLib.enableOrDisableAccount(domains=self.domainName, action='disable',)
-            msg = 'DISABLED_SUCCESS'
+            msg = 'DISABLED'
         elif self.action == 'enable':
             result = domainLib.enableOrDisableAccount(domains=self.domainName, action='enable',)
-            msg = 'ENABLED_SUCCESS'
+            msg = 'ENABLED'
         else:
             result = (False, 'INVALID_ACTION')
             msg = i.get('msg', None)
 
         if result[0] is True:
-            return web.seeother('/domains?msg=%s' % msg)
+            raise web.seeother('/domains?msg=%s' % msg)
         else:
-            return web.seeother('/domains?msg=' + result[1])
+            raise web.seeother('/domains?msg=' + web.urlquote(result[1]))
 
 
 class Profile:
-    @base.require_login
+    @decorators.require_login
     def GET(self, profile_type, domain):
         i = web.input()
         self.domain = web.safestr(domain.split('/', 1)[0])
         self.profile_type = web.safestr(profile_type)
 
         if not iredutils.isDomain(self.domain):
-            return web.seeother('/domains?msg=EMPTY_DOMAIN')
+            raise web.seeother('/domains?msg=EMPTY_DOMAIN')
 
         domainLib = domainlib.Domain()
         result = domainLib.profile(domain=self.domain)
 
-        if result[0] is True:
-            r = domainLib.listAccounts(attrs=['domainName'])
-            if r[0] is True:
-                allDomains = r[1]
-            else:
-                return r
+        if result[0] is False:
+            raise web.seeother('/domains?msg=' + web.urlquote(result[1]))
 
-            allAccountSettings = ldaputils.getAccountSettingFromLdapQueryResult(result[1], key='domainName',)
+        r = domainLib.listAccounts(attrs=['domainName'])
+        if r[0] is True:
+            allDomains = r[1]
+        else:
+            return r
 
-            return web.render(
-                'ldap/domain/profile.html',
-                cur_domain=self.domain,
-                allDomains=allDomains,
-                allAccountSettings=allAccountSettings,
-                profile=result[1],
-                profile_type=self.profile_type,
-                msg=i.get('msg', None),
-            )
-        else:
-            return web.seeother('/domains?msg=' + result[1])
+        allAccountSettings = ldaputils.getAccountSettingFromLdapQueryResult(result[1], key='domainName',)
 
-    @base.require_login
+        return web.render(
+            'ldap/domain/profile.html',
+            cur_domain=self.domain,
+            allDomains=allDomains,
+            allAccountSettings=allAccountSettings,
+            profile=result[1],
+            profile_type=self.profile_type,
+            msg=i.get('msg', None),
+        )
+
+    @decorators.csrf_protected
+    @decorators.require_login
     def POST(self, profile_type, domain):
         self.profile_type = web.safestr(profile_type)
         self.domain = web.safestr(domain)
 
-        i = web.input()
+        i = web.input(domainAliasName=[], enabledService=[], domainAdmin=[], defaultList=[],)
 
-        if self.domain != web.safestr(i.get('domainName', None)):
-            return web.seeother('/profile/domain/%s/%s?msg=DOMAIN_NAME_MISMATCH' % (self.profile_type, self.domain))
+        if self.domain != web.safestr(i.get('domainName', None)).lower():
+            raise web.seeother('/profile/domain/%s/%s?msg=DOMAIN_NAME_MISMATCH' % (self.profile_type, self.domain))
 
         domainLib = domainlib.Domain()
         result = domainLib.update(
                 data=i,
                 )
         if result[0] is True:
-            return web.seeother('/profile/domain/%s/%s?msg=PROFILE_UPDATED_SUCCESS' % (self.profile_type, self.domain))
+            raise web.seeother('/profile/domain/%s/%s?msg=UPDATED' % (self.profile_type, self.domain))
         elif result[0] is False:
-            return web.seeother('/profile/domain/%s/%s?msg=%s' % (self.profile_type, self.domain, result[1]))
+            raise web.seeother('/profile/domain/%s/%s?msg=%s' % (self.profile_type, self.domain, web.urlquote(result[1])))
 
 
 class Create:
-    @base.require_global_admin
-    @base.require_login
+    @decorators.require_global_admin
+    @decorators.require_login
     def GET(self):
         i = web.input()
         self.domain = web.safestr(i.get('domain', ''))
         return web.render('ldap/domain/create.html', msg=i.get('msg'), domainName=self.domain)
 
-    @base.require_global_admin
-    @base.require_login
+    @decorators.require_global_admin
+    @decorators.csrf_protected
+    @decorators.require_login
     def POST(self):
         i = web.input()
         self.domain = web.safestr(i.get('domainName')).strip().lower()
         domainLib = domainlib.Domain()
         result = domainLib.add(data=i)
         if result[0] is True:
-            return web.seeother('/profile/domain/general/%s?msg=CREATED_SUCCESS' % self.domain)
+            raise web.seeother('/profile/domain/general/%s?msg=CREATED' % self.domain)
         else:
-            return web.seeother('/create/domain?msg=%s' % result[1])
+            raise web.seeother('/create/domain?msg=%s' % web.urlquote(result[1]))

controllers/ldap/urls.py

 # Author: Zhang Huangbin <zhb@iredmail.org>
 
 from libs.iredutils import reEmail, reDomain
- 
+
 urls = [
     # Make url ending with or without '/' going to the same class.
-    '/(.*)/',                           'controllers.base.redirect',
+    '/(.*)/',                           'controllers.utils.redirect',
 
     # used to display jpegPhoto.
-    '/img/(.*)',                        'controllers.base.img',
+    '/img/(.*)',                        'controllers.utils.img',
 
     '/',                                'controllers.ldap.basic.Login',
     '/login',                           'controllers.ldap.basic.Login',
     '/dashboard',                       'controllers.ldap.basic.Dashboard',
     '/dashboard/(checknew)',              'controllers.ldap.basic.Dashboard',
 
+    # Search.
+    '/search',                                  'controllers.ldap.basic.Search',
+
+    # Perform some operations from search page.
+    '/action/(domain|admin|user|maillist|alias)', 'controllers.ldap.basic.OperationsFromSearchPage',
+
+    # Export LDIF data.
+    '/export/ldif/(domain|catchall)/(%s$)' % reDomain,           'controllers.ldap.basic.ExportLdif',
+    '/export/ldif/(admin|user|maillist|alias)/(%s$)' % reEmail,  'controllers.ldap.basic.ExportLdif',
+
     # Domain related.
     '/domains',                                     'controllers.ldap.domain.List',
     '/domains/page/(\d+)',                          'controllers.ldap.domain.List',
-    '/profile/domain/(general)/(%s)' % reDomain,  'controllers.ldap.domain.Profile',
+    '/profile/domain/(general|aliases|relay|bcc|catchall|throttle|advanced)/(%s$)' % reDomain,  'controllers.ldap.domain.Profile',
     '/profile/domain/(%s)' % reDomain,             'controllers.ldap.domain.Profile',
     '/create/domain',                               'controllers.ldap.domain.Create',
 
     # Admin related.
     '/admins',                                      'controllers.ldap.admin.List',
-    '/profile/admin/(general|password)/(%s)' % reEmail,     'controllers.ldap.admin.Profile',
+    '/admins/page/(\d+)',                           'controllers.ldap.admin.List',
+    '/profile/admin/(general|password)/(%s$)' % reEmail,     'controllers.ldap.admin.Profile',
     '/create/admin',                                'controllers.ldap.admin.Create',
 
     #########################
     #
     # List users, delete users under same domain.
     '/users',                                       'controllers.ldap.user.List',
-    '/users/(%s)' % reDomain,                       'controllers.ldap.user.List',
+    '/users/(%s$)' % reDomain,                       'controllers.ldap.user.List',
     '/users/(%s)/page/(\d+)' % reDomain,            'controllers.ldap.user.List',
     # Create user.
-    '/create/user/(%s)' % reDomain,                'controllers.ldap.user.Create',
+    '/create/user/(%s$)' % reDomain,                'controllers.ldap.user.Create',
     '/create/user',                               'controllers.ldap.user.Create',
     # Profile pages.
-    '/profile/user/(general|password)/(%s)' % reEmail,      'controllers.ldap.user.Profile',
+    '/profile/user/(general|members|forwarding|aliases|wblist|password|throttle|advanced)/(%s$)' % reEmail,      'controllers.ldap.user.Profile',
+
+    # Import accouts.
+    '/import/user',                               'controllers.ldap.user.Import',
+    '/import/user/(%s$)' % reDomain,                'controllers.ldap.user.Import',
+    '/import/alias',                               'controllers.ldap.alias.Import',
+
+    ####################
+    # Mail list related
+    #
+    # List accounts
+    '/maillists',                                   'controllers.ldap.maillist.List',
+    '/maillists/(%s$)' % reDomain,                    'controllers.ldap.maillist.List',
+    '/maillists/(%s)/page/(\d+)' % reDomain,         'controllers.ldap.maillist.List',
+
+    # General profile.
+    '/profile/maillist/(general)/(%s$)' % reEmail,    'controllers.ldap.maillist.Profile',
+    '/profile/maillist/members/(%s$)' % reEmail,      'controllers.ldap.maillist.Members',
+    '/profile/maillist/moderators/(%s$)' % reEmail,               'controllers.ldap.maillist.Moderators',
+    '/create/maillist/(%s$)' % reDomain,            'controllers.ldap.maillist.Create',
+    '/create/maillist',                           'controllers.ldap.maillist.Create',
+
+    # Alias related.
+    '/aliases',                                         'controllers.ldap.alias.List',
+    '/aliases/(%s$)' % reDomain,                         'controllers.ldap.alias.List',
+    '/aliases/(%s)/page/(\d+)' % reDomain,              'controllers.ldap.alias.List',
+    '/profile/alias/(general)/(%s$)' % reEmail,          'controllers.ldap.alias.Profile',
+    '/create/alias/(%s$)' % reDomain,                    'controllers.ldap.alias.Create',
+    '/create/alias',                                    'controllers.ldap.alias.Create',
 ]

controllers/ldap/user.py

 # Author: Zhang Huangbin <zhb@iredmail.org>
 
 import web
-from controllers import base
-from libs import iredutils
-from libs.ldaplib import domain as domainlib, user, ldaputils, connUtils
+from libs import iredutils, settings
+from libs.ldaplib import decorators, domain as domainlib, user, ldaputils, connUtils
 
 cfg = web.iredconfig
 session = web.config.get('_session')
     def __del__(self):
         pass
 
-    @base.require_login
+    @decorators.require_login
     def GET(self, domain='', cur_page=1):
         domain = web.safestr(domain).split('/', 1)[0]
         cur_page = int(cur_page)
 
         if not iredutils.isDomain(domain):
-            return web.seeother('/domains?msg=INVALID_DOMAIN_NAME')
+            raise web.seeother('/domains?msg=INVALID_DOMAIN_NAME')
 
         if cur_page == 0:
             cur_page = 1
         i = web.input()
 
         domainLib = domainlib.Domain()
-        result = domainLib.listAccounts(attrs=['domainName', 'accountStatus',])
+        result = domainLib.listAccounts(attrs=['domainName', 'accountStatus', ])
         if result[0] is True:
             allDomains = result[1]
         else:
             sl = connutils.getSizelimitFromAccountLists(
                 result[1],
                 curPage=cur_page,
-                sizelimit=session['pageSizeLimit'],
+                sizelimit=settings.PAGE_SIZE_LIMIT,
                 accountType='user',
                 domain=domain,
             )
                 cur_page = sl.get('totalPages')
 
             # Show login date.
-            if cfg.general.get('show_login_date', 'False').lower() in ['true',]:
+            if cfg.general.get('show_login_date', 'False').lower() in ['true', ]:
                 showLoginDate = True
             else:
                 showLoginDate = False
                 msg=i.get('msg'),
             )
         else:
-            return web.seeother('/domains?msg=%s' % result[1])
+            raise web.seeother('/domains?msg=%s' % web.urlquote(result[1]))
 
     # Delete users.
-    @base.require_login
+    @decorators.csrf_protected
+    @decorators.require_login
     def POST(self, domain):
         i = web.input(_unicode=False, mail=[])
         self.domain = web.safestr(domain)
 
         if self.action == 'delete':
             result = userLib.delete(domain=self.domain, mails=self.mails,)
-            msg = 'DELETED_SUCCESS'
+            msg = 'DELETED'
         elif self.action == 'disable':
             result = userLib.enableOrDisableAccount(domain=self.domain, mails=self.mails, action='disable',)
-            msg = 'DISABLED_SUCCESS'
+            msg = 'DISABLED'
         elif self.action == 'enable':
             result = userLib.enableOrDisableAccount(domain=self.domain, mails=self.mails, action='enable',)
-            msg = 'ENABLED_SUCCESS'
+            msg = 'ENABLED'
         else:
             result = (False, 'INVALID_ACTION')
             msg = i.get('msg', None)
 
         if result[0] is True:
             cur_page = i.get('cur_page', '1')
-            return web.seeother('/users/%s/page/%s?msg=%s' % (self.domain, str(cur_page), msg, ))
+            raise web.seeother('/users/%s/page/%s?msg=%s' % (self.domain, str(cur_page), msg, ))
         else:
-            return web.seeother('/users/%s?msg=%s' % (self.domain, result[1]))
+            raise web.seeother('/users/%s?msg=%s' % (self.domain, web.urlquote(result[1])))
 
 
 class Profile:
-    @base.require_login
+    @decorators.require_login
     def GET(self, profile_type, mail):
         i = web.input(enabledService=[], telephoneNumber=[], )
         self.mail = web.safestr(mail)
 
         if self.mail.startswith('@') and iredutils.isDomain(self.cur_domain):
             # Catchall account.
-            return web.seeother('/profile/domain/catchall/%s' % (self.cur_domain))
+            raise web.seeother('/profile/domain/catchall/%s' % self.cur_domain)
 
         if not iredutils.isEmail(self.mail):
-            return web.seeother('/domains?msg=INVALID_USER')
+            raise web.seeother('/domains?msg=INVALID_USER')
 
         domainAccountSetting = {}
-        
+
         userLib = user.User()
         result = userLib.profile(domain=self.cur_domain, mail=self.mail)
-        if result[0] is True:
-            if self.profile_type == 'password':
-                # Get accountSetting of current domain.
-                domainLib = domainlib.Domain()
-                result_setting = domainLib.getDomainAccountSetting(domain=self.cur_domain)
-                if result_setting[0] is True:
-                    domainAccountSetting = result_setting[1]
+        if result[0] is False:
+            raise web.seeother('/users/%s?msg=%s' % (self.cur_domain, web.urlquote(result[1])))
 
-            minPasswordLength = domainAccountSetting.get('minPasswordLength', '0')
-            maxPasswordLength = domainAccountSetting.get('maxPasswordLength', '0')
+        if self.profile_type == 'password':
+            # Get accountSetting of current domain.
+            domainLib = domainlib.Domain()
+            result_setting = domainLib.getDomainAccountSetting(domain=self.cur_domain)
+            if result_setting[0] is True:
+                domainAccountSetting = result_setting[1]
 
-            return web.render(
-                'ldap/user/profile.html',
-                profile_type=self.profile_type,
-                mail=self.mail,
-                user_profile=result[1],
-                minPasswordLength=minPasswordLength,
-                maxPasswordLength=maxPasswordLength,
-                msg=i.get('msg', None),
-            )
-        else:
-            return web.seeother('/users/%s?msg=%s' % (self.cur_domain, result[1]))
+        minPasswordLength = domainAccountSetting.get('minPasswordLength', '0')
+        maxPasswordLength = domainAccountSetting.get('maxPasswordLength', '0')
 
-    @base.require_login
+        return web.render(
+            'ldap/user/profile.html',
+            profile_type=self.profile_type,
+            mail=self.mail,
+            user_profile=result[1],
+            defaultStorageBaseDirectory=cfg.general.get('storage_base_directory'),
+            minPasswordLength=minPasswordLength,
+            maxPasswordLength=maxPasswordLength,
+            domainAccountSetting=domainAccountSetting,
+            msg=i.get('msg', None),
+        )
+
+    @decorators.csrf_protected
+    @decorators.require_login
     def POST(self, profile_type, mail):
         i = web.input(
             enabledService=[],
+            mailForwardingAddress=[],
             telephoneNumber=[],
+            memberOfGroup=[],
         )
         self.profile_type = web.safestr(profile_type)
         self.mail = web.safestr(mail)
         )
 
         if result[0] is True:
-            return web.seeother('/profile/user/%s/%s?msg=PROFILE_UPDATED_SUCCESS' % (self.profile_type, self.mail))
+            raise web.seeother('/profile/user/%s/%s?msg=UPDATED' % (self.profile_type, self.mail))
         else:
-            return web.seeother('/profile/user/%s/%s?msg=%s' % (self.profile_type, self.mail, result[1]))
+            raise web.seeother('/profile/user/%s/%s?msg=%s' % (self.profile_type, self.mail, web.urlquote(result[1])))
 
 
 class Create:
-    @base.require_login
+    @decorators.require_login
     def GET(self, domainName=None):
         i = web.input()
 
             self.cur_domain = web.safestr(domainName)
 
         domainLib = domainlib.Domain()
-        result = domainLib.listAccounts(attrs=['domainName', 'accountSetting', 'domainCurrentQuotaSize',])
+        result = domainLib.listAccounts(attrs=['domainName', 'accountSetting', 'domainCurrentQuotaSize', ])
         if result[0] is True:
             allDomains = result[1]
 
             if len(allDomains) == 0:
-                return web.seeother('/domains?msg=NO_DOMAIN_AVAILABLE')
+                raise web.seeother('/domains?msg=NO_DOMAIN_AVAILABLE')
             else:
                 # Redirect to create new user under first domain, so that we
                 # can get per-domain account settings, such as number of
                 # account limit, password length control, etc.
                 if self.cur_domain == '':
-                    return web.seeother('/create/user/' + str(allDomains[0][1]['domainName'][0]))
+                    raise web.seeother('/create/user/' + str(allDomains[0][1]['domainName'][0]))
 
             # Get accountSetting of current domain.
             allAccountSettings = ldaputils.getAccountSettingFromLdapQueryResult(allDomains, key='domainName')
             domainAccountSetting = allAccountSettings.get(self.cur_domain, {})
             defaultUserQuota = domainLib.getDomainDefaultUserQuota(self.cur_domain, domainAccountSetting)
         else:
-            return web.seeother('/domains?msg=' % result[1])
+            raise web.seeother('/domains?msg=' % web.urlquote(result[1]))
 
         # Get number of account limit.
         connutils = connUtils.Utils()
                           msg=i.get('msg'),
                          )
 
-    @base.require_login
+    @decorators.csrf_protected
+    @decorators.require_login
     def POST(self):
         i = web.input()
 
         userLib = user.User()
         result = userLib.add(domain=self.cur_domain, data=i)
         if result[0] is True:
-            return web.seeother('/profile/user/general/%s?msg=CREATED_SUCCESS' % (self.username + '@' + self.cur_domain))
+            raise web.seeother('/profile/user/general/%s?msg=CREATED' % (self.username + '@' + self.cur_domain))
         else:
-            return web.seeother('/create/user/%s?msg=%s' % (self.cur_domain, result[1]))
+            raise web.seeother('/create/user/%s?msg=%s' % (self.cur_domain, web.urlquote(result[1])))

controllers/mysql/admin.py

 
 import web
 from libs import languages, iredutils
-from libs.mysql import decorators, admin as adminlib, domain as domainlib
+from libs.mysql import decorators, admin as adminlib, domain as domainlib, connUtils
 
 cfg = web.iredconfig
 session = web.config.get('_session')
 
+
 class List:
     @decorators.require_global_admin
     @decorators.require_login
         if result[0] is True:
             (total, records) = (result[1], result[2])
 
-            # Get list of global admins.
-            allGlobalAdmins = []
-            qr = adminLib.getAllGlobalAdmins()
-            if qr[0] is True:
-                allGlobalAdmins = qr[1]
-
             return web.render(
                 'mysql/admin/list.html',
                 cur_page=cur_page,
                 total=total,
                 admins=records,
-                allGlobalAdmins=allGlobalAdmins,
                 msg=i.get('msg', None),
             )
         else:
-            return web.seeother('/domains?msg=%s' % result[1])
+            raise web.seeother('/domains?msg=%s' % web.urlquote(result[1]))
 
     @decorators.require_global_admin
+    @decorators.csrf_protected
     @decorators.require_login
     def POST(self):
         i = web.input(_unicode=False, mail=[])
 
         if self.action == 'delete':
             result = adminLib.delete(mails=self.mails,)
-            msg = 'DELETED_SUCCESS'
+            msg = 'DELETED'
         elif self.action == 'disable':
             result = adminLib.enableOrDisableAccount(accounts=self.mails, active=False,)
-            msg = 'DISABLED_SUCCESS'
+            msg = 'DISABLED'
         elif self.action == 'enable':
             result = adminLib.enableOrDisableAccount(accounts=self.mails, active=True,)
-            msg = 'ENABLED_SUCCESS'
+            msg = 'ENABLED'
         else:
             result = (False, 'INVALID_ACTION')
 
         if result[0] is True:
-            return web.seeother('/admins?msg=%s' % msg)
+            raise web.seeother('/admins?msg=%s' % msg)
         else:
-            return web.seeother('/admins?msg=?' + result[1])
+            raise web.seeother('/admins?msg=?' + web.urlquote(result[1]))
+
 
 class Profile:
     @decorators.require_login
         self.profile_type = web.safestr(profile_type)
 
         if not iredutils.isEmail(self.mail):
-            return web.seeother('/admins?msg=INVALID_MAIL')
+            raise web.seeother('/admins?msg=INVALID_MAIL')
 
         if session.get('domainGlobalAdmin') is not True and session.get('username') != self.mail:
             # Don't allow to view/update other admins' profile.
-            return web.seeother('/profile/admin/general/%s?msg=PERMISSION_DENIED' % session.get('username'))
+            raise web.seeother('/profile/admin/general/%s?msg=PERMISSION_DENIED' % session.get('username'))
 
         adminLib = adminlib.Admin()
         result = adminLib.profile(mail=self.mail)
             if resultOfAllDomains[0] is True:
                 self.allDomains = resultOfAllDomains[1]
 
-            # Get managed domains.
-            self.managedDomains = []
-
-            qr = adminLib.getManagedDomains(admin=self.mail, domainNameOnly=True, listedOnly=True,)
-            if qr[0] is True:
-                self.managedDomains += qr[1]
-
             return web.render(
                 'mysql/admin/profile.html',
                 mail=self.mail,
                 profile=profile,
                 languagemaps=languages.getLanguageMaps(),
                 allDomains=self.allDomains,
-                managedDomains=self.managedDomains,
                 min_passwd_length=cfg.general.get('min_passwd_length', '0'),
                 max_passwd_length=cfg.general.get('max_passwd_length', '0'),
                 msg=i.get('msg'),
             )
         else:
-            return web.seeother('/admins?msg=' + result[1])
+            raise web.seeother('/admins?msg=' + web.urlquote(result[1]))
 
-
+    @decorators.csrf_protected
     @decorators.require_login
     def POST(self, profile_type, mail):
         self.profile_type = web.safestr(profile_type)
 
         if session.get('domainGlobalAdmin') is not True and session.get('username') != self.mail:
             # Don't allow to view/update others' profile.
-            return web.seeother('/profile/admin/general/%s?msg=PERMISSION_DENIED' % session.get('username'))
+            raise web.seeother('/profile/admin/general/%s?msg=PERMISSION_DENIED' % session.get('username'))
 
         adminLib = adminlib.Admin()
         result = adminLib.update(
         )
 
         if result[0] is True:
-            return web.seeother('/profile/admin/%s/%s?msg=PROFILE_UPDATED_SUCCESS' % (self.profile_type, self.mail))
+            raise web.seeother('/profile/admin/%s/%s?msg=UPDATED' % (self.profile_type, self.mail))
         else:
-            return web.seeother('/profile/admin/%s/%s?msg=%s' % (self.profile_type, self.mail, result[1],))
+            raise web.seeother('/profile/admin/%s/%s?msg=%s' % (self.profile_type, self.mail, web.urlquote(result[1]),))
 
 
 class Create:
         )
 
     @decorators.require_global_admin
+    @decorators.csrf_protected
     @decorators.require_login
     def POST(self):
         i = web.input()
 
         if result[0] is True:
             # Redirect to assign domains.
-            return web.seeother('/profile/admin/general/%s?msg=CREATED_SUCCESS' % self.mail)
+            raise web.seeother('/profile/admin/general/%s?msg=CREATED' % self.mail)
         else:
-            return web.seeother('/create/admin?msg=' + result[1])
-
-
+            raise web.seeother('/create/admin?msg=' + web.urlquote(result[1]))

controllers/mysql/basic.py

 from socket import getfqdn
 from urllib import urlencode
 import web
-from libs import __url_iredadmin_mysql_latest__, __version__
-from libs import iredutils, languages
-from libs.mysql import core, decorators
+from libs import __url_latest_mysql__, __version_mysql__, __no__, __id__
+from libs import iredutils, settings, languages
+from libs.mysql import core, decorators, admin as adminlib, connUtils
+
 
 cfg = web.iredconfig
 session = web.config.get('_session')
 
+
 class Login:
     def GET(self):
-        if session.get('logged') is True:
-            return web.seeother('/dashboard')
-        else:
+        if session.get('logged') is False:
             i = web.input(_unicode=False)
 
             # Show login page.
                 languagemaps=languages.getLanguageMaps(),
                 msg=i.get('msg'),
             )
+        else:
+            raise web.seeother('/dashboard')
 
     def POST(self):
         # Get username, password.
                 web.config.session_parameters['timeout'] = 600      # 10 minutes
 
             web.logger(msg="Login success", event='login',)
-            return web.seeother('/dashboard/checknew')
+            raise web.seeother('/dashboard/checknew')
         else:
             session['failedTimes'] += 1
             web.logger(msg="Login failed.", admin=username, event='login', loglevel='error',)
-            return web.seeother('/login?msg=%s' % auth_result[1])
+            raise web.seeother('/login?msg=%s' % web.urlquote(auth_result[1]))
 
 
 class Logout:
     def GET(self):
         session.kill()
-        return web.seeother('/login')
+        raise web.seeother('/login')
 
 
 class Dashboard:
     @decorators.require_login
-    def GET(self, checknew=None):
+    def GET(self, checknew=False):
         i = web.input(_unicode=False,)
 
-        if checknew is not None:
-            self.checknew = True
-        else:
-            self.checknew = False
+        if checknew:
+            checknew = True
 
         # Get network interface related infomation.
         netif_data = {}
             pass
 
         # Check new version.
-        if session.get('domainGlobalAdmin') is True and self.checknew is True:
+        newVersionInfo = (None, )
+        if session.get('domainGlobalAdmin') is True and checknew is True:
             try:
                 curdate = time.strftime('%Y-%m-%d')
                 vars = dict(date=curdate)
                 if len(r) == 0:
                     urlInfo = {
                         'a': cfg.general.get('webmaster', session.get('username', '')),
-                        'v': __version__,
+                        'v': __version_mysql__,
+                        'o': __no__,
+                        'f': __id__,
                         'host': getfqdn(),
-                        'backend': cfg.general.get('backend', ''),
                     }
 
-                    url = __url_iredadmin_mysql_latest__ + '?' + urlencode(urlInfo)
+                    url = __url_latest_mysql__ + '?' + urlencode(urlInfo)
                     newVersionInfo = iredutils.getNewVersion(url)
 
                     # Always remove all old records, just keep the last one.
 
                     # Insert updating date.
                     web.admindb.insert('updatelog', date=curdate,)
-                else:
-                    newVersionInfo = (None, )
             except Exception, e:
                 newVersionInfo = (False, str(e))
-        else:
-            newVersionInfo = (None, )
 
         return web.render(
             'dashboard.html',
-            version=__version__,
+            version=__version_mysql__,
             hostname=getfqdn(),
             uptime=iredutils.getServerUptime(),
             loadavg=os.getloadavg(),

controllers/mysql/domain.py

 # Author: Zhang Huangbin <zhb@iredmail.org>
 
 import web
-from controllers import base
 from libs import iredutils
-from libs.mysql import domain as domainlib
+from libs.mysql import decorators, domain as domainlib, admin as adminlib
 
 cfg = web.iredconfig
 session = web.config.get('_session')
 
+
 #
 # Domain related.
 #
 
 class List:
     '''List all virtual mail domains.'''
-    @base.require_login
+    @decorators.require_login
     def GET(self, cur_page=1,):
         i = web.input()
 
         try:
-            cur_page = int(cur_page)
-            if cur_page == 0:
-                cur_page == 1
+            cur_page = int(cur_page) or 1
         except:
             cur_page = 1
 
         result = domainLib.listAccounts(cur_page=cur_page)
 
         if result[0] is True:
+            allDomains = result[2]
+
             return web.render(
                 'mysql/domain/list.html',
                 cur_page=cur_page,
                 total=result[1],
-                allDomains=result[2],
+                allDomains=allDomains,
                 msg=i.get('msg', None),
             )
         else:
                 msg=result[1],
             )
 
-    @base.require_global_admin
-    @base.require_login
+    @decorators.require_global_admin
+    @decorators.csrf_protected
+    @decorators.require_login
     def POST(self):
         i = web.input(domainName=[], _unicode=False,)
         domainName = i.get('domainName', None)
         domainLib = domainlib.Domain()
         if self.action == 'delete':
             result = domainLib.delete(domains=domainName)
-            msg = 'DELETED_SUCCESS'
+            msg = 'DELETED'
         elif self.action == 'disable':
             result = domainLib.enableOrDisableAccount(accounts=domainName, active=False,)
-            msg = 'DISABLED_SUCCESS'
+            msg = 'DISABLED'
         elif self.action == 'enable':
             result = domainLib.enableOrDisableAccount(accounts=domainName, active=True,)
-            msg = 'ENABLED_SUCCESS'
+            msg = 'ENABLED'
         else:
             result = (False, 'INVALID_ACTION')
             msg = i.get('msg', None)
 
         if result[0] is True:
-            return web.seeother('/domains?msg=%s' % msg)
+            raise web.seeother('/domains?msg=%s' % msg)
         else:
-            return web.seeother('/domains?msg=' + result[1])
+            raise web.seeother('/domains?msg=' + web.urlquote(result[1]))
+
 
 class Profile:
-    @base.require_login
+    @decorators.require_login
     def GET(self, profile_type, domain):
         i = web.input()
         self.domain = web.safestr(domain.split('/', 1)[0])
         self.profile_type = web.safestr(profile_type)
 
         if not iredutils.isDomain(self.domain):
-            return web.seeother('/domains?msg=EMPTY_DOMAIN')
+            raise web.seeother('/domains?msg=EMPTY_DOMAIN')
 
         domainLib = domainlib.Domain()
         result = domainLib.profile(domain=self.domain)
 
         if result[0] is not True:
-            return web.seeother('/domains?msg=' + result[1])
+            raise web.seeother('/domains?msg=' + web.urlquote(result[1]))
         else:
             self.profile = result[1]
 
             msg=i.get('msg'),
         )
 
-    @base.require_login
+    @decorators.csrf_protected
+    @decorators.require_login
     def POST(self, profile_type, domain):
         self.profile_type = str(profile_type)
         self.domain = str(domain)
 
-        i = web.input()
+        i = web.input(domainAliasName=[], domainAdmin=[], defaultList=[],)
 
         domainLib = domainlib.Domain()
         result = domainLib.update(
         )
 
         if result[0] is True:
-            return web.seeother('/profile/domain/%s/%s?msg=PROFILE_UPDATED_SUCCESS' % (self.profile_type, self.domain))
+            raise web.seeother('/profile/domain/%s/%s?msg=UPDATED' % (self.profile_type, self.domain))
         else:
-            return web.seeother('/profile/domain/%s/%s?msg=%s' % (self.profile_type, self.domain, result[1],))
+            raise web.seeother('/profile/domain/%s/%s?msg=%s' % (self.profile_type, self.domain, web.urlquote(result[1]),))
 
 
 class Create:
-    @base.require_global_admin
-    @base.require_login
+    @decorators.require_global_admin
+    @decorators.require_login
     def GET(self):
         i = web.input()
         return web.render(
             msg=i.get('msg'),
         )
 
-    @base.require_global_admin
-    @base.require_login
+    @decorators.require_global_admin
+    @decorators.csrf_protected
+    @decorators.require_login
     def POST(self):
         i = web.input()
         self.domain = web.safestr(i.get('domainName')).strip().lower()
         domainLib = domainlib.Domain()
         result = domainLib.add(data=i)
         if result[0] is True:
-            return web.seeother('/profile/domain/general/%s?msg=CREATED_SUCCESS' % self.domain)
+            raise web.seeother('/profile/domain/general/%s?msg=CREATED' % self.domain)
         else:
-            return web.seeother('/create/domain?msg=%s' % result[1])
+            raise web.seeother('/create/domain?msg=%s' % web.urlquote(result[1]))

controllers/mysql/urls.py

 
 urls = [
     # Make url ending with or without '/' going to the same class.
-    '/(.*)/',                           'controllers.base.redirect',
+    '/(.*)/',                           'controllers.utils.redirect',
 
     # used to display jpegPhoto.
-    '/img/(.*)',                        'controllers.base.img',
+    '/img/(.*)',                        'controllers.utils.img',
 
     '/',                                'controllers.mysql.basic.Login',
     '/login',                           'controllers.mysql.basic.Login',
     '/dashboard',                       'controllers.mysql.basic.Dashboard',
     '/dashboard/(checknew)',            'controllers.mysql.basic.Dashboard',
 
+    # Search.
+    '/search',                          'controllers.mysql.basic.Search',
+
+    # Perform some operations from search page.
+    '/action/(user|alias)',   'controllers.mysql.basic.OperationsFromSearchPage',
+
     # Domain related.
-    '/domains',                                    'controllers.mysql.domain.List',
-    '/domains/page/(\d+)',                          'controllers.mysql.domain.List',
-    '/profile/domain/(general)/(%s)' % reDomain,  'controllers.mysql.domain.Profile',
-    '/profile/domain/(%s)' % reDomain,             'controllers.mysql.domain.Profile',
-    '/create/domain',                               'controllers.mysql.domain.Create',
+    '/domains',                         'controllers.mysql.domain.List',
+    '/domains/page/(\d+)',              'controllers.mysql.domain.List',
+    '/profile/domain/(general|aliases|relay|bcc|catchall|throttle|advanced)/(%s$)' % reDomain,  'controllers.mysql.domain.Profile',
+    '/profile/domain/(%s)' % reDomain,  'controllers.mysql.domain.Profile',
+    '/create/domain',                   'controllers.mysql.domain.Create',
 
     # Admin related.
-    '/admins',                                      'controllers.mysql.admin.List',
-    '/admins/page/(\d+)',                           'controllers.mysql.admin.List',
-    '/profile/admin/(general|password)/(%s)' % reEmail,     'controllers.mysql.admin.Profile',
-    '/create/admin',                                'controllers.mysql.admin.Create',
+    '/admins',                          'controllers.mysql.admin.List',
+    '/admins/page/(\d+)',               'controllers.mysql.admin.List',
+    '/profile/admin/(general|password)/(%s$)' % reEmail,     'controllers.mysql.admin.Profile',
+    '/create/admin',                    'controllers.mysql.admin.Create',
 
     # User related.
     # /domain.ltd/users
-    '/users',                                       'controllers.mysql.user.List',
-    '/users/(%s)' % reDomain,                      'controllers.mysql.user.List',
-    '/users/(%s)/page/(\d+)' % reDomain,            'controllers.mysql.user.List',
+    '/users',                           'controllers.mysql.user.List',
+    '/users/(%s$)' % reDomain,           'controllers.mysql.user.List',
+    '/users/(%s)/page/(\d+)' % reDomain, 'controllers.mysql.user.List',
     # Create user.
-    '/create/user/(%s)' % reDomain,                'controllers.mysql.user.Create',
-    '/create/user',                               'controllers.mysql.user.Create',
+    '/create/user/(%s$)' % reDomain,     'controllers.mysql.user.Create',
+    '/create/user',                     'controllers.mysql.user.Create',
     # Profile pages.
-    '/profile/user/(general|password)/(%s)' % reEmail,      'controllers.mysql.user.Profile',
+    '/profile/user/(general|forwarding|bcc|relay|wblist|password|throttle|advanced)/(%s$)' % reEmail,      'controllers.mysql.user.Profile',
+
+    # Import accouts.
+    '/import/user',                     'controllers.mysql.user.ImportUser',
+
+    # Alias related.
+    '/aliases',                         'controllers.mysql.alias.List',
+    '/aliases/(%s$)' % reDomain,                         'controllers.mysql.alias.List',
+    '/aliases/(%s)/page/(\d+)' % reDomain,              'controllers.mysql.alias.List',
+    '/profile/alias/(general|members)/(%s$)' % reEmail,  'controllers.mysql.alias.Profile',
+    '/create/alias/(%s$)' % reDomain,                    'controllers.mysql.alias.Create',
+    '/create/alias',                                    'controllers.mysql.alias.Create',
 ]

controllers/mysql/user.py

 
 import web
 from libs import iredutils
-from libs.mysql import decorators, user as userlib, domain as domainlib
+from libs.mysql import decorators, user as userlib, domain as domainlib, connUtils
 
 cfg = web.iredconfig
 session = web.config.get('_session')
 
+
 class List:
     @decorators.require_login
     def GET(self, domain, cur_page=1):
         cur_page = int(cur_page)
 
         if not iredutils.isDomain(self.domain):
-            return web.seeother('/domains?msg=INVALID_DOMAIN_NAME')
+            raise web.seeother('/domains?msg=INVALID_DOMAIN_NAME')
 
         if cur_page == 0:
             cur_page = 1
                 msg=web.input().get('msg', None),
             )
         else:
-            return web.seeother('/domains?msg=%s' % result[1])
+            raise web.seeother('/domains?msg=%s' % web.urlquote(result[1]))
 
+    @decorators.csrf_protected
     @decorators.require_login
     def POST(self, domain):
-        i = web.input(_unicode=False, username=[])
+        i = web.input(_unicode=False, mail=[])
 
         self.domain = str(domain)
 
         if not iredutils.isDomain(self.domain):
-            return web.seeother('/domains?msg=INVALID_DOMAIN_NAME')
+            raise web.seeother('/domains?msg=INVALID_DOMAIN_NAME')
 
         self.mails = [str(v)
-                      for v in i.get('username', [])
+                      for v in i.get('mail', [])
                       if iredutils.isEmail(v)
-                      and str(v).endswith('@'+self.domain)
+                      and str(v).endswith('@' + self.domain)
                      ]
 
         self.action = i.get('action', None)
 
         if self.action == 'delete':
             result = userLib.delete(domain=self.domain, mails=self.mails,)
-            msg = 'DELETED_SUCCESS'
+            msg = 'DELETED'
         elif self.action == 'disable':
             result = userLib.enableOrDisableAccount(domain=self.domain, accounts=self.mails, active=False,)
-            msg = 'DISABLED_SUCCESS'
+            msg = 'DISABLED'
         elif self.action == 'enable':
             result = userLib.enableOrDisableAccount(domain=self.domain, accounts=self.mails, active=True,)
-            msg = 'ENABLED_SUCCESS'
+            msg = 'ENABLED'
         else:
             result = (False, 'INVALID_ACTION')
 
         if result[0] is True:
-            return web.seeother('/users/%s?msg=%s' % (self.domain, msg,))
+            raise web.seeother('/users/%s?msg=%s' % (self.domain, msg,))
         else:
-            return web.seeother('/users/%s?msg=%s' % (self.domain, result[1],))
+            raise web.seeother('/users/%s?msg=%s' % (self.domain, web.urlquote(result[1]),))
+
 
 class Profile:
     @decorators.require_login
 
         if self.mail.startswith('@') and iredutils.isDomain(self.cur_domain):
             # Catchall account.
-            return web.seeother('/profile/domain/catchall/%s' % (self.cur_domain))
+            raise web.seeother('/profile/domain/catchall/%s' % self.cur_domain)
 
         if not iredutils.isEmail(self.mail):
-            return web.seeother('/domains?msg=INVALID_USER')
+            raise web.seeother('/domains?msg=INVALID_USER')
 
         if not iredutils.isDomain(self.cur_domain):
-            return web.seeother('/domains?msg=INVALID_DOMAIN_NAME')
+            raise web.seeother('/domains?msg=INVALID_DOMAIN_NAME')
 
         userLib = userlib.User()
         qr = userLib.profile(domain=self.cur_domain, mail=self.mail)
         if qr[0] is True:
             self.profile = qr[1]
         else:
-            return web.seeother('/users/%s?msg=%s' % (self.cur_domain, qr[1]))
+            raise web.seeother('/users/%s?msg=%s' % (self.cur_domain, web.urlquote(qr[1])))
 
         return web.render(
             'mysql/user/profile.html',
             msg=i.get('msg'),
         )
 
+    @decorators.csrf_protected
     @decorators.require_login
     def POST(self, profile_type, mail):
         i = web.input(
             enabledService=[],
+            #mailForwardingAddress=[],
+            shadowAddress=[],
             telephoneNumber=[],
+            memberOfGroup=[],
+            oldMemberOfAlias=[],
+            memberOfAlias=[],
+            #whitelistSender=[],
+            #blacklistSender=[],
+            #whitelistRecipient=[],
+            #blacklistRecipient=[],
         )
         self.profile_type = web.safestr(profile_type)
         self.mail = str(mail).lower()
         )
 
         if result[0] is True:
-            return web.seeother('/profile/user/%s/%s?msg=PROFILE_UPDATED_SUCCESS' % (self.profile_type, self.mail))
+            raise web.seeother('/profile/user/%s/%s?msg=UPDATED' % (self.profile_type, self.mail))
         else:
-            return web.seeother('/profile/user/%s/%s?msg=%s' % (self.profile_type, self.mail, result[1]))
+            raise web.seeother('/profile/user/%s/%s?msg=%s' % (self.profile_type, self.mail, web.urlquote(result[1])))
 
 
 class Create:
         else:
             self.cur_domain = str(domain)
             if not iredutils.isDomain(self.cur_domain):
-                return web.seeother('/domains?msg=INVALID_DOMAIN_NAME')
+                raise web.seeother('/domains?msg=INVALID_DOMAIN_NAME')
 
         i = web.input()
 
         # Get all managed domains.
-        domainLib = domainlib.Domain()
-        result = domainLib.getAllDomains(columns=[
-            'domain', 'description',
-            'maxquota', 'mailboxes', 'defaultuserquota',
-            'minpasswordlength', 'maxpasswordlength',
-        ])
+        connutils = connUtils.Utils()
+        qr = connutils.getManagedDomains(admin=session.get('username'), domainNameOnly=True,)
 
-        if result[0] is True:
-            allDomains=result[1]
+        if qr[0] is True:
+            allDomains = qr[1]
         else:
-            return web.seeother('/domains?msg=' % result[1])
+            raise web.seeother('/domains?msg=' % web.urlquote(qr[1]))
 
         # Set first domain as current domain.
         if self.cur_domain is None:
             if len(allDomains) > 0:
-                return web.seeother('/create/user/%s' % str(allDomains[0].domain))
+                raise web.seeother('/create/user/%s' % str(allDomains[0]))
             else:
-                return web.seeother('/domains?msg=NO_DOMAIN_AVAILABLE')
+                raise web.seeother('/domains?msg=NO_DOMAIN_AVAILABLE')
 
         # Get domain profile.
+        domainLib = domainlib.Domain()
         resultOfProfile = domainLib.profile(domain=self.cur_domain)
         if resultOfProfile[0] is True:
             self.profile = resultOfProfile[1]
         else:
-            return web.seeother('/domains?msg=%s' % resultOfProfile[1])
-
-        # Cet total number and allocated quota size of existing users under domain.
-        self.numberOfExistAccounts = 0
-        self.usedQuotaSize = 0
-
-        qr = domainLib.getCountsOfExistAccountsUnderDomain(
-            domain=self.cur_domain,
-            accountType='user',
-        )
-        if qr[0] is True: