* 'create_tables.pgsql'
authorPascal Volk <neverseen@users.sourceforge.net>
Tue, 09 Sep 2008 04:29:13 +0000
changeset 80 5dedc673524e
parent 79 0ae7597eed11
child 81 89b71a9abfcf
* 'create_tables.pgsql' - Removed (broken) view vmm_alias_count - Updated view vmm_domain_info * 'update_tables_0.4.x-0.5.pgsql' - No longer create view vmm_alias_count - Updated view vmm_domain_info - Updated triggers in table domain_name as in rev 75 * 'VirtualMailManager/Domain.py' * 'VirtualMailManager/VirtualMailManager.py' * 'vmm' - Integrated relocated stuff * 'po/de.po' * 'po/vmm.pot' - updated
VirtualMailManager/Domain.py
VirtualMailManager/VirtualMailManager.py
create_tables.pgsql
po/de.po
po/vmm.pot
update_tables_0.4.x-0.5.pgsql
vmm
--- a/VirtualMailManager/Domain.py	Mon Sep 08 23:47:34 2008 +0000
+++ b/VirtualMailManager/Domain.py	Tue Sep 09 04:29:13 2008 +0000
@@ -211,7 +211,8 @@
     def getInfo(self):
         """Returns a dictionary with information about the domain."""
         sql = """\
-SELECT gid, domainname, transport, domaindir, aliasdomains, accounts, aliases
+SELECT gid, domainname, transport, domaindir, aliasdomains, accounts,
+       aliases, relocated
   FROM vmm_domain_info
  WHERE gid = %i""" % self._id
         dbc = self._dbh.cursor()
@@ -223,7 +224,7 @@
                     ERR.NO_SUCH_DOMAIN)
         else:
             keys = ['gid', 'domainname', 'transport', 'domaindir',
-                    'aliasdomains', 'accounts', 'aliases']
+                    'aliasdomains', 'accounts', 'aliases', 'relocated']
             return dict(zip(keys, info))
 
     def getAccounts(self):
@@ -252,6 +253,19 @@
                 aliases.append('%s@%s' % (alias[0], self._name))
         return aliases
 
+    def getRelocated(self):
+        """Returns a list with all addresses from relocated users."""
+        dbc = self._dbh.cursor()
+        dbc.execute("SELECT address FROM relocated WHERE gid = %s\
+ ORDER BY address", self._id)
+        addresses = dbc.fetchall()
+        dbc.close()
+        relocated = []
+        if len(addresses) > 0:
+            for address in addresses:
+                relocated.append('%s@%s' % (address[0], self._name))
+        return relocated
+
     def getAliaseNames(self):
         """Returns a list with all alias names from the domain."""
         dbc = self._dbh.cursor()
--- a/VirtualMailManager/VirtualMailManager.py	Mon Sep 08 23:47:34 2008 +0000
+++ b/VirtualMailManager/VirtualMailManager.py	Tue Sep 09 04:29:13 2008 +0000
@@ -194,13 +194,6 @@
         return VirtualMailManager._exists(dbh, sql)
     relocatedExists = staticmethod(relocatedExists)
 
-    def __getAccount(self, address, password=None):
-        self.__dbConnect()
-        address = EmailAddress(address)
-        if not password is None:
-            password = self.__pwhash(password)
-        return Account(self.__dbh, address, password)
-
     def _readpass(self):
         mismatched = True
         while mismatched:
@@ -216,6 +209,13 @@
             mismatched = False
         return clear0
 
+    def __getAccount(self, address, password=None):
+        self.__dbConnect()
+        address = EmailAddress(address)
+        if not password is None:
+            password = self.__pwhash(password)
+        return Account(self.__dbh, address, password)
+
     def __getAlias(self, address, destination=None):
         self.__dbConnect()
         address = EmailAddress(address)
@@ -223,6 +223,13 @@
             destination = EmailAddress(destination)
         return Alias(self.__dbh, address, destination)
 
+    def __getRelocated(self,address, destination=None):
+        self.__dbConnect()
+        address = EmailAddress(address)
+        if destination is not None:
+            destination = EmailAddress(destination)
+        return Relocated(self.__dbh, address, destination)
+
     def __getDomain(self, domainname, transport=None):
         if transport is None:
             transport = self.__Cfg.get('misc', 'transport')
@@ -495,7 +502,7 @@
 
     def domainInfo(self, domainname, details=None):
         if details not in [None, 'accounts', 'aliasdomains', 'aliases', 'full',
-                'detailed']:
+                'relocated', 'detailed']:
             raise VMMDomainException(_(u'Invalid argument: »%s«') % details,
                 ERR.INVALID_OPTION)
         if details == 'detailed':
@@ -519,9 +526,11 @@
             return (dominfo, dom.getAliaseNames())
         elif details == 'aliases':
             return (dominfo, dom.getAliases())
+        elif details == 'relocated':
+            return(dominfo, dom.getRelocated())
         else:
             return (dominfo, dom.getAliaseNames(), dom.getAccounts(),
-                    dom.getAliases())
+                    dom.getAliases(), dom.getRelocated())
 
     def aliasDomainAdd(self, aliasname, domainname):
         """Adds an alias domain to the domain.
@@ -663,6 +672,18 @@
         acc = self.__getAccount(emailaddress)
         acc.enable(service)
 
+    def relocatedAdd(self, emailaddress, targetaddress):
+        relocated = self.__getRelocated(emailaddress, targetaddress)
+        relocated.save()
+
+    def relocatedInfo(self, emailaddress):
+        relocated = self.__getRelocated(emailaddress)
+        return relocated.getInfo()
+
+    def relocatedDelete(self, emailaddress):
+        relocated = self.__getRelocated(emailaddress)
+        relocated.delete()
+
     def __del__(self):
         if not self.__dbh is None and self.__dbh._isOpen:
             self.__dbh.close()
--- a/create_tables.pgsql	Mon Sep 08 23:47:34 2008 +0000
+++ b/create_tables.pgsql	Tue Sep 09 04:29:13 2008 +0000
@@ -149,15 +149,15 @@
            LEFT JOIN transport USING (tid)
            LEFT JOIN domain_name USING (gid);
 
-CREATE OR REPLACE VIEW vmm_alias_count AS
-    SELECT count(DISTINCT address) AS aliases, gid
-      FROM alias 
-  GROUP BY gid;
-
 CREATE OR REPLACE VIEW vmm_domain_info AS
     SELECT gid, domainname, transport, domaindir,
            count(uid) AS accounts,
-           aliases,
+           (SELECT count(DISTINCT address)
+              FROM alias
+             WHERE alias.gid = domain_data.gid) AS aliases,
+           (SELECT count(gid)
+              FROM relocated
+             WHERE relocated.gid = domain_data.gid) AS relocated,
            (SELECT count(gid)
               FROM domain_name
              WHERE domain_name.gid = domain_data.gid
@@ -166,9 +166,8 @@
            LEFT JOIN domain_name USING (gid)
            LEFT JOIN transport USING (tid)
            LEFT JOIN users USING (gid)
-           LEFT JOIN vmm_alias_count USING (gid)
      WHERE domain_name.is_primary
-  GROUP BY gid, domainname, transport, domaindir, aliases;
+  GROUP BY gid, domainname, transport, domaindir;
 
 
 CREATE LANGUAGE plpgsql;
--- a/po/de.po	Mon Sep 08 23:47:34 2008 +0000
+++ b/po/de.po	Tue Sep 09 04:29:13 2008 +0000
@@ -6,8 +6,8 @@
 msgstr ""
 "Project-Id-Version: vmm 0.5\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-09-08 20:36+0200\n"
-"PO-Revision-Date: 2008-09-09 00:35+0200\n"
+"POT-Creation-Date: 2008-09-09 06:05+0200\n"
+"PO-Revision-Date: 2008-09-09 06:15+0200\n"
 "Last-Translator: Pascal Volk <p.volk@veb-it.de>\n"
 "Language-Team: German\n"
 "MIME-Version: 1.0\n"
@@ -27,7 +27,7 @@
 
 #: VirtualMailManager/Account.py:64 VirtualMailManager/Alias.py:64
 #: VirtualMailManager/Domain.py:168 VirtualMailManager/Domain.py:192
-#: VirtualMailManager/Domain.py:222 VirtualMailManager/Relocated.py:63
+#: VirtualMailManager/Domain.py:223 VirtualMailManager/Relocated.py:63
 #, python-format
 msgid "The domain »%s« doesn't exist yet."
 msgstr "Die Domain »%s« existiert noch nicht."
@@ -310,45 +310,45 @@
 msgid "The domain name »%s« is invalid."
 msgstr "Der Domain-Name »%s« ist ungültig."
 
-#: VirtualMailManager/VirtualMailManager.py:207
+#: VirtualMailManager/VirtualMailManager.py:200
 msgid "Enter new password: "
 msgstr "Neues Passwort eingeben: "
 
-#: VirtualMailManager/VirtualMailManager.py:208
+#: VirtualMailManager/VirtualMailManager.py:201
 msgid "Retype new password: "
 msgstr "Neues Passwort wiederholen: "
 
-#: VirtualMailManager/VirtualMailManager.py:210
+#: VirtualMailManager/VirtualMailManager.py:203
 msgid "Sorry, passwords do not match"
 msgstr "Entschuldigung, die Passwörter stimmen nicht überein"
 
-#: VirtualMailManager/VirtualMailManager.py:214
+#: VirtualMailManager/VirtualMailManager.py:207
 msgid "Sorry, empty passwords are not permitted"
 msgstr "Entschuldigung, leere Passwörter sind nicht zulässig"
 
-#: VirtualMailManager/VirtualMailManager.py:248
-#: VirtualMailManager/VirtualMailManager.py:336
+#: VirtualMailManager/VirtualMailManager.py:255
+#: VirtualMailManager/VirtualMailManager.py:343
 #, python-format
 msgid "No such directory: %s"
 msgstr "Verzeichnis nicht gefunden: %s"
 
-#: VirtualMailManager/VirtualMailManager.py:324
+#: VirtualMailManager/VirtualMailManager.py:331
 msgid "Found \"..\" in home directory path."
 msgstr "\"..\" im Pfad zum Benutzerverzeichnis entdeckt."
 
-#: VirtualMailManager/VirtualMailManager.py:332
+#: VirtualMailManager/VirtualMailManager.py:339
 msgid "Owner/group mismatch in home directory detected."
 msgstr "Benutzerverzeichnis gehört dem/der falschen Benutzer/Gruppe."
 
-#: VirtualMailManager/VirtualMailManager.py:347
+#: VirtualMailManager/VirtualMailManager.py:354
 msgid "FATAL: \"..\" in domain directory path detected."
 msgstr "FATAL: \"..\" im Pfad zum Domain-Verzeichnis entdeckt."
 
-#: VirtualMailManager/VirtualMailManager.py:353
+#: VirtualMailManager/VirtualMailManager.py:360
 msgid "FATAL: group mismatch in domain directory detected"
 msgstr "FATAL: Domain-Verzeichnis gehört der falschen Gruppe"
 
-#: VirtualMailManager/VirtualMailManager.py:440
+#: VirtualMailManager/VirtualMailManager.py:447
 #, python-format
 msgid ""
 "Configurtion error: \"%s\"\n"
@@ -357,24 +357,24 @@
 "Konfigurations Fehler: \"%s\"\n"
 "(im Abschnitt \"connfig\", Option \"done\") Siehe auch: vmm.cfg(5)\n"
 
-#: VirtualMailManager/VirtualMailManager.py:460
+#: VirtualMailManager/VirtualMailManager.py:467
 #, python-format
 msgid "Invalid section: '%s'"
 msgstr "Ungültiger Abschnitt: '%s'"
 
-#: VirtualMailManager/VirtualMailManager.py:470
+#: VirtualMailManager/VirtualMailManager.py:477
 #, python-format
 msgid "Invalid argument: '%s'"
 msgstr "Ungültiges Argument: '%s'"
 
-#: VirtualMailManager/VirtualMailManager.py:480
-#: VirtualMailManager/VirtualMailManager.py:499
-#: VirtualMailManager/VirtualMailManager.py:601
+#: VirtualMailManager/VirtualMailManager.py:487
+#: VirtualMailManager/VirtualMailManager.py:506
+#: VirtualMailManager/VirtualMailManager.py:610
 #, python-format
 msgid "Invalid argument: »%s«"
 msgstr "Ungültiges Argument: »%s«"
 
-#: VirtualMailManager/VirtualMailManager.py:503
+#: VirtualMailManager/VirtualMailManager.py:510
 msgid ""
 "The keyword »detailed« is deprecated and will be removed in a future "
 "release.\n"
@@ -384,12 +384,12 @@
 "    Version entfernt werden.\n"
 "    Verwenden Sie bitte das Schlüsselwort »full«, um alle Details zu erhalten."
 
-#: VirtualMailManager/VirtualMailManager.py:578
+#: VirtualMailManager/VirtualMailManager.py:587
 #, python-format
 msgid "The pattern »%s« contains invalid characters."
 msgstr "Das Muster »%s« enthält ungültige Zeichen."
 
-#: VirtualMailManager/VirtualMailManager.py:613
+#: VirtualMailManager/VirtualMailManager.py:622
 #, python-format
 msgid ""
 "The account has been successfully deleted from the database.\n"
@@ -402,7 +402,7 @@
 "    »%(directory)s«\n"
 "    Grund: %(raeson)s"
 
-#: VirtualMailManager/VirtualMailManager.py:645
+#: VirtualMailManager/VirtualMailManager.py:654
 msgid "Account doesn't exists"
 msgstr "Der Account existiert nicht"
 
@@ -411,54 +411,63 @@
 msgid ""
 "Usage: %s SUBCOMMAND OBJECT ARGS*\n"
 "  short long\n"
-"  subcommand               object            args (* = optional)\n"
+"  subcommand               object             args (* = optional)\n"
 msgstr ""
 "Verwendung: %s UNTERBEFEHL OBJEKT ARGS*\n"
 "  kurz  lang\n"
-"  Unterbefehl              Objekt            args (* = optional)\n"
+"  Unterbefehl              Objekt             args (* = optional)\n"
 
-#: vmm:76 vmm:87 vmm:446
+#: vmm:79 vmm:90 vmm:487
 msgid "Error"
 msgstr "Fehler"
 
-#: vmm:109
+#: vmm:112
 msgid "information"
 msgstr "Informationen"
 
-#: vmm:119
+#: vmm:122
 msgid "Available"
 msgstr "Verfügbare"
 
-#: vmm:122 vmm:215 vmm:219
+#: vmm:125 vmm:224 vmm:230
 msgid "alias domains"
 msgstr "Alias-Domains"
 
-#: vmm:132 vmm:143 vmm:161
+#: vmm:135 vmm:146 vmm:170
 msgid "\tNone"
 msgstr "\tKeine"
 
-#: vmm:136
+#: vmm:139
 msgid "Alias information"
 msgstr "Alias Informationen"
 
-#: vmm:138
+#: vmm:141
 #, python-format
 msgid "\tMail for %s will be redirected to:"
 msgstr "\tE-Mails für %s werden weitergeleitet an:"
 
-#: vmm:156
+#: vmm:150
+msgid "Relocated information"
+msgstr "Information zum umgezogenen Benutzer"
+
+#: vmm:152
+#, python-format
+msgid "\tUser »%(addr)s« has moved to »%(dest)s«"
+msgstr "\tDer Benutzer »%(addr)s« ist umgezogenen nach »%(dest)s«"
+
+#: vmm:165
 msgid "Available domains"
 msgstr "Verfügbare Domains"
 
-#: vmm:158
+#: vmm:167
 msgid "Matching domains"
 msgstr "Übereinstimmende Domains"
 
-#: vmm:172
+#: vmm:181
 msgid "Alias domain information"
 msgstr "Alias-Domain Informationen"
 
-#: vmm:178
+#: vmm:187
 #, python-format
 msgid ""
 "\tThe alias domain %(alias)s belongs to:\n"
@@ -467,99 +476,110 @@
 "\tDie Alias-Domain %(alias)s gehört zu:\n"
 "\t    * %(domain)s"
 
-#: vmm:189 vmm:197 vmm:205
+#: vmm:198 vmm:206 vmm:214
 msgid "Missing domain name."
 msgstr "Kein Domain-Name angegeben."
 
-#: vmm:207 vmm:211
+#: vmm:216 vmm:220
 msgid "Domain"
 msgstr "Domain"
 
-#: vmm:213 vmm:220
+#: vmm:222 vmm:231
 msgid "accounts"
 msgstr "Accounts"
 
-#: vmm:217 vmm:221
+#: vmm:226 vmm:232
 msgid "aliases"
 msgstr "Aliase"
 
-#: vmm:225
+#: vmm:228 vmm:233
+msgid "relocated users"
+msgstr "umgezogenen Benutzer"
+
+#: vmm:237
 msgid "Missing domain name and new transport."
 msgstr "Domain-Name und neuer Transport fehlen."
 
-#: vmm:227
+#: vmm:239
 msgid "Missing new transport."
 msgstr "Neuer Transport fehlt."
 
-#: vmm:236 vmm:251
+#: vmm:248 vmm:263
 msgid "Missing alias domain name and target domain name."
 msgstr "Domain-Namen für Alias- und Ziel-Domain fehlen."
 
-#: vmm:238 vmm:253
+#: vmm:250 vmm:265
 msgid "Missing target domain name."
 msgstr "Keine Ziel-Domain angegeben."
 
-#: vmm:244 vmm:259
+#: vmm:256 vmm:271
 msgid "Missing alias domain name."
 msgstr "Keine Alias-Domain angegeben."
 
-#: vmm:265 vmm:274 vmm:282 vmm:306 vmm:314 vmm:322
+#: vmm:277 vmm:286 vmm:294 vmm:318 vmm:326 vmm:334
 msgid "Missing e-mail address."
 msgstr "E-Mail-Adresse fehlt."
 
-#: vmm:290
+#: vmm:302
 msgid "Missing e-mail address and users name."
 msgstr "E-Mail-Adresse und der Name des Benutzers fehlen."
 
-#: vmm:292
+#: vmm:304
 msgid "Missing users name."
 msgstr "Name des Benutzers fehlt."
 
-#: vmm:298
+#: vmm:310
 msgid "Missing e-mail address and transport."
 msgstr "E-Mail-Adresse und Transport fehlen."
 
-#: vmm:300
+#: vmm:312
 msgid "Missing transport."
 msgstr "Transport fehlt."
 
-#: vmm:331
+#: vmm:343
 msgid "Missing alias address and destination."
 msgstr "Alias- und Ziel-Adresse fehlen."
 
-#: vmm:333
+#: vmm:345 vmm:368
 msgid "Missing destination address."
 msgstr "Die Ziel-Adresse fehlt."
 
-#: vmm:339 vmm:345
+#: vmm:351 vmm:357
 msgid "Missing alias address"
 msgstr "Die Alias-Adresse fehlt."
 
-#: vmm:353
+#: vmm:366
+msgid "Missing relocated address and destination."
+msgstr "Die Adresse des umgezogenen Benutzers und Ziel-Adresse fehlen."
+
+#: vmm:374 vmm:382
+msgid "Missing relocated address"
+msgstr "Die Adresse des umgezogenen Benutzers fehlt."
+
+#: vmm:388
 msgid "Missing userid"
 msgstr "Keine UID angegeben."
 
-#: vmm:366
+#: vmm:401
 msgid "Warnings:"
 msgstr "Warnungen:"
 
-#: vmm:371
+#: vmm:406
 msgid "version"
 msgstr "Version"
 
-#: vmm:372
+#: vmm:407
 msgid "from"
 msgstr "vom"
 
-#: vmm:374
+#: vmm:409
 msgid "on"
 msgstr "auf"
 
-#: vmm:441
+#: vmm:482
 msgid "Unknown subcommand"
 msgstr "Unbekannter Unterbefehl"
 
-#: vmm:444
+#: vmm:485
 msgid "Ouch"
 msgstr "Autsch"
-
--- a/po/vmm.pot	Mon Sep 08 23:47:34 2008 +0000
+++ b/po/vmm.pot	Tue Sep 09 04:29:13 2008 +0000
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: vmm 0.5\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-09-08 20:36+0200\n"
+"POT-Creation-Date: 2008-09-09 06:05+0200\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"
@@ -28,7 +28,7 @@
 
 #: VirtualMailManager/Account.py:64 VirtualMailManager/Alias.py:64
 #: VirtualMailManager/Domain.py:168 VirtualMailManager/Domain.py:192
-#: VirtualMailManager/Domain.py:222 VirtualMailManager/Relocated.py:63
+#: VirtualMailManager/Domain.py:223 VirtualMailManager/Relocated.py:63
 #, python-format
 msgid "The domain »%s« doesn't exist yet."
 msgstr ""
@@ -298,81 +298,81 @@
 msgid "The domain name »%s« is invalid."
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:207
+#: VirtualMailManager/VirtualMailManager.py:200
 msgid "Enter new password: "
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:208
+#: VirtualMailManager/VirtualMailManager.py:201
 msgid "Retype new password: "
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:210
+#: VirtualMailManager/VirtualMailManager.py:203
 msgid "Sorry, passwords do not match"
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:214
+#: VirtualMailManager/VirtualMailManager.py:207
 msgid "Sorry, empty passwords are not permitted"
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:248
-#: VirtualMailManager/VirtualMailManager.py:336
+#: VirtualMailManager/VirtualMailManager.py:255
+#: VirtualMailManager/VirtualMailManager.py:343
 #, python-format
 msgid "No such directory: %s"
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:324
+#: VirtualMailManager/VirtualMailManager.py:331
 msgid "Found \"..\" in home directory path."
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:332
+#: VirtualMailManager/VirtualMailManager.py:339
 msgid "Owner/group mismatch in home directory detected."
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:347
+#: VirtualMailManager/VirtualMailManager.py:354
 msgid "FATAL: \"..\" in domain directory path detected."
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:353
+#: VirtualMailManager/VirtualMailManager.py:360
 msgid "FATAL: group mismatch in domain directory detected"
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:440
+#: VirtualMailManager/VirtualMailManager.py:447
 #, python-format
 msgid ""
 "Configurtion error: \"%s\"\n"
 "(in section \"connfig\", option \"done\") see also: vmm.cfg(5)\n"
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:460
+#: VirtualMailManager/VirtualMailManager.py:467
 #, python-format
 msgid "Invalid section: '%s'"
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:470
+#: VirtualMailManager/VirtualMailManager.py:477
 #, python-format
 msgid "Invalid argument: '%s'"
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:480
-#: VirtualMailManager/VirtualMailManager.py:499
-#: VirtualMailManager/VirtualMailManager.py:601
+#: VirtualMailManager/VirtualMailManager.py:487
+#: VirtualMailManager/VirtualMailManager.py:506
+#: VirtualMailManager/VirtualMailManager.py:610
 #, python-format
 msgid "Invalid argument: »%s«"
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:503
+#: VirtualMailManager/VirtualMailManager.py:510
 msgid ""
 "The keyword »detailed« is deprecated and will be removed in a future "
 "release.\n"
 "    Please use the keyword »full« to get full details."
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:578
+#: VirtualMailManager/VirtualMailManager.py:587
 #, python-format
 msgid "The pattern »%s« contains invalid characters."
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:613
+#: VirtualMailManager/VirtualMailManager.py:622
 #, python-format
 msgid ""
 "The account has been successfully deleted from the database.\n"
@@ -381,7 +381,7 @@
 "    Reason: %(raeson)s"
 msgstr ""
 
-#: VirtualMailManager/VirtualMailManager.py:645
+#: VirtualMailManager/VirtualMailManager.py:654
 msgid "Account doesn't exists"
 msgstr ""
 
@@ -390,149 +390,170 @@
 msgid ""
 "Usage: %s SUBCOMMAND OBJECT ARGS*\n"
 "  short long\n"
-"  subcommand               object            args (* = optional)\n"
+"  subcommand               object             args (* = optional)\n"
 msgstr ""
 
-#: vmm:76 vmm:87 vmm:446
+#: vmm:79 vmm:90 vmm:487
 msgid "Error"
 msgstr ""
 
-#: vmm:109
+#: vmm:112
 msgid "information"
 msgstr ""
 
-#: vmm:119
+#: vmm:122
 msgid "Available"
 msgstr ""
 
-#: vmm:122 vmm:215 vmm:219
+#: vmm:125 vmm:224 vmm:230
 msgid "alias domains"
 msgstr ""
 
-#: vmm:132 vmm:143 vmm:161
+#: vmm:135 vmm:146 vmm:170
 msgid "\tNone"
 msgstr ""
 
-#: vmm:136
+#: vmm:139
 msgid "Alias information"
 msgstr ""
 
-#: vmm:138
+#: vmm:141
 #, python-format
 msgid "\tMail for %s will be redirected to:"
 msgstr ""
 
-#: vmm:156
+#: vmm:150
+msgid "Relocated information"
+msgstr ""
+
+#: vmm:152
+#, python-format
+msgid "\tUser »%(addr)s« has moved to »%(dest)s«"
+msgstr ""
+
+#: vmm:165
 msgid "Available domains"
 msgstr ""
 
-#: vmm:158
+#: vmm:167
 msgid "Matching domains"
 msgstr ""
 
-#: vmm:172
+#: vmm:181
 msgid "Alias domain information"
 msgstr ""
 
-#: vmm:178
+#: vmm:187
 #, python-format
 msgid ""
 "\tThe alias domain %(alias)s belongs to:\n"
 "\t    * %(domain)s"
 msgstr ""
 
-#: vmm:189 vmm:197 vmm:205
+#: vmm:198 vmm:206 vmm:214
 msgid "Missing domain name."
 msgstr ""
 
-#: vmm:207 vmm:211
+#: vmm:216 vmm:220
 msgid "Domain"
 msgstr ""
 
-#: vmm:213 vmm:220
+#: vmm:222 vmm:231
 msgid "accounts"
 msgstr ""
 
-#: vmm:217 vmm:221
+#: vmm:226 vmm:232
 msgid "aliases"
 msgstr ""
 
-#: vmm:225
+#: vmm:228 vmm:233
+msgid "relocated users"
+msgstr ""
+
+#: vmm:237
 msgid "Missing domain name and new transport."
 msgstr ""
 
-#: vmm:227
+#: vmm:239
 msgid "Missing new transport."
 msgstr ""
 
-#: vmm:236 vmm:251
+#: vmm:248 vmm:263
 msgid "Missing alias domain name and target domain name."
 msgstr ""
 
-#: vmm:238 vmm:253
+#: vmm:250 vmm:265
 msgid "Missing target domain name."
 msgstr ""
 
-#: vmm:244 vmm:259
+#: vmm:256 vmm:271
 msgid "Missing alias domain name."
 msgstr ""
 
-#: vmm:265 vmm:274 vmm:282 vmm:306 vmm:314 vmm:322
+#: vmm:277 vmm:286 vmm:294 vmm:318 vmm:326 vmm:334
 msgid "Missing e-mail address."
 msgstr ""
 
-#: vmm:290
+#: vmm:302
 msgid "Missing e-mail address and users name."
 msgstr ""
 
-#: vmm:292
+#: vmm:304
 msgid "Missing users name."
 msgstr ""
 
-#: vmm:298
+#: vmm:310
 msgid "Missing e-mail address and transport."
 msgstr ""
 
-#: vmm:300
+#: vmm:312
 msgid "Missing transport."
 msgstr ""
 
-#: vmm:331
+#: vmm:343
 msgid "Missing alias address and destination."
 msgstr ""
 
-#: vmm:333
+#: vmm:345 vmm:368
 msgid "Missing destination address."
 msgstr ""
 
-#: vmm:339 vmm:345
+#: vmm:351 vmm:357
 msgid "Missing alias address"
 msgstr ""
 
-#: vmm:353
+#: vmm:366
+msgid "Missing relocated address and destination."
+msgstr ""
+
+#: vmm:374 vmm:382
+msgid "Missing relocated address"
+msgstr ""
+
+#: vmm:388
 msgid "Missing userid"
 msgstr ""
 
-#: vmm:366
+#: vmm:401
 msgid "Warnings:"
 msgstr ""
 
-#: vmm:371
+#: vmm:406
 msgid "version"
 msgstr ""
 
-#: vmm:372
+#: vmm:407
 msgid "from"
 msgstr ""
 
-#: vmm:374
+#: vmm:409
 msgid "on"
 msgstr ""
 
-#: vmm:441
+#: vmm:482
 msgid "Unknown subcommand"
 msgstr ""
 
-#: vmm:444
+#: vmm:485
 msgid "Ouch"
 msgstr ""
--- a/update_tables_0.4.x-0.5.pgsql	Mon Sep 08 23:47:34 2008 +0000
+++ b/update_tables_0.4.x-0.5.pgsql	Tue Sep 09 04:29:13 2008 +0000
@@ -107,15 +107,15 @@
            LEFT JOIN transport USING (tid)
            LEFT JOIN domain_name USING (gid);
 
-CREATE OR REPLACE VIEW vmm_alias_count AS
-    SELECT count(DISTINCT address) AS aliases, gid
-      FROM alias 
-  GROUP BY gid;
-
 CREATE OR REPLACE VIEW vmm_domain_info AS
     SELECT gid, domainname, transport, domaindir,
            count(uid) AS accounts,
-           aliases,
+           (SELECT count(DISTINCT address)
+              FROM alias
+             WHERE alias.gid = domain_data.gid) AS aliases,
+           (SELECT count(gid)
+              FROM relocated
+             WHERE relocated.gid = domain_data.gid) AS relocated,
            (SELECT count(gid)
               FROM domain_name
              WHERE domain_name.gid = domain_data.gid
@@ -124,9 +124,8 @@
            LEFT JOIN domain_name USING (gid)
            LEFT JOIN transport USING (tid)
            LEFT JOIN users USING (gid)
-           LEFT JOIN vmm_alias_count USING (gid)
      WHERE domain_name.is_primary
-  GROUP BY gid, domainname, transport, domaindir, aliases;
+  GROUP BY gid, domainname, transport, domaindir;
 
 
 DROP TABLE domains;
@@ -151,5 +150,8 @@
 END;
 $$ LANGUAGE plpgsql STABLE;
 
-CREATE TRIGGER primary_count BEFORE INSERT OR UPDATE ON domain_name
+CREATE TRIGGER primary_count_ins BEFORE INSERT ON domain_name
     FOR EACH ROW EXECUTE PROCEDURE domain_primary_trigger();
+
+CREATE TRIGGER primary_count_upd AFTER UPDATE ON domain_name
+    FOR EACH ROW EXECUTE PROCEDURE domain_primary_trigger();
--- a/vmm	Mon Sep 08 23:47:34 2008 +0000
+++ b/vmm	Tue Sep 09 04:29:13 2008 +0000
@@ -40,32 +40,35 @@
     u_head = _("""\
 Usage: %s SUBCOMMAND OBJECT ARGS*
   short long
-  subcommand               object            args (* = optional)\n""")\
+  subcommand               object             args (* = optional)\n""")\
           % __prog__
 
     u_body = """\
-  da    domainadd          domain.tld        transport*
-  di    domaininfo         domain.tld        details*
-  dt    domaintransport    domain.tld        transport force*
-  dd    domaindelete       domain.tld        delalias*|deluser*|delall*
-  ada   aliasdomainadd     aliasdomain.tld   domain.tld
+  da    domainadd          domain.tld         transport*
+  di    domaininfo         domain.tld         details*
+  dt    domaintransport    domain.tld         transport force*
+  dd    domaindelete       domain.tld         delalias*|deluser*|delall*
+  ada   aliasdomainadd     aliasdomain.tld    domain.tld
   adi   aliasdomaininfo    aliasdomain.tld
-  ads   aliasdomainswitch  aliasdomain.tld   domain.tld
+  ads   aliasdomainswitch  aliasdomain.tld    domain.tld
   add   aliasdomaindelete  aliasdomain.tld
-  ua    useradd            user@domain.tld   password*
-  ui    userinfo           user@domain.tld   du*
-  un    username           user@domain.tld   'Users Name'
-  up    userpassword       user@domain.tld   password*
-  ut    usertransport      user@domain.tld   transport
-  u0    userdisable        user@domain.tld   service*
-  u1    userenable         user@domain.tld   service*
-  ud    userdelete         user@domain.tld   delalias*
-  aa    aliasadd           alias@domain.tld  user@domain.tld
+  ua    useradd            user@domain.tld    password*
+  ui    userinfo           user@domain.tld    du*
+  un    username           user@domain.tld    'Users Name'
+  up    userpassword       user@domain.tld    password*
+  ut    usertransport      user@domain.tld    transport
+  u0    userdisable        user@domain.tld    service*
+  u1    userenable         user@domain.tld    service*
+  ud    userdelete         user@domain.tld    delalias*
+  aa    aliasadd           alias@domain.tld   user@domain.tld
   ai    aliasinfo          alias@domain.tld
-  ad    aliasdelete        alias@domain.tld  user@domain.tld*
+  ad    aliasdelete        alias@domain.tld   user@domain.tld*
+  ra    relocatedadd       exaddr@domain.tld  user@domain.tld
+  ri    relocatedinfo      exaddr@domain.tld
+  rf    relocateddelete    exaddr@domain.tld
   gu    getuser            userid
-  ld    listdomains                          pattern*
-  cf    configure                            section*
+  ld    listdomains                           pattern*
+  cf    configure                             section*
   h     help
   v     version
 """
@@ -91,7 +94,7 @@
     if argv[1] in ['di', 'domaininfo']:
         order = (('domainname', 0), ('gid', 1), ('transport', 0),
                 ('domaindir', 0), ('aliasdomains', 0), ('accounts', 0),
-                ('aliases', 0))
+                ('aliases', 0), ('relocated', 0))
     elif argv[1] in ['ui', 'userinfo']:
         if argc == 4 or vmm.cfgGetBoolean('maildir', 'diskusage'):
             order = (('address', 0), ('name', 0), ('uid', 1), ('gid', 1),
@@ -143,6 +146,12 @@
         w_std(_('\tNone'))
     print
 
+def _printRelocated(addr_dest):
+    msg = _(u'Relocated information')
+    w_std('%s\n%s' % (msg, '-'*len(msg)))
+    w_std(_(u'\tUser »%(addr)s« has moved to »%(dest)s«') % addr_dest)
+    print
+
 def _formatDom(domain, main=True):
     if domain.startswith('xn--'):
         domain = '%s (%s)' % (domain, vmm.ace2idna(domain))
@@ -215,10 +224,13 @@
             _printList(infos[1], _('alias domains'))
         elif details == 'aliases':
             _printList(infos[1], _('aliases'))
+        elif details == 'relocated':
+            _printList(infos[1], _('relocated users'))
         else:
             _printList(infos[1], _('alias domains'))
             _printList(infos[2], _('accounts'))
             _printList(infos[3], _('aliases'))
+            _printList(infos[4], _('relocated users'))
 
 def domain_transport():
     if argc < 3:
@@ -338,7 +350,7 @@
     if argc < 3:
         usage(EXIT.MISSING_ARGS, _(u'Missing alias address'))
     else:
-        _printAliases(argv[2], vmm.aliasInfo(argv[2].lower()))
+        _printAliases(argv[2].lower(), vmm.aliasInfo(argv[2].lower()))
 
 def alias_delete():
     if argc < 3:
@@ -348,6 +360,29 @@
     else:
         vmm.aliasDelete(argv[2].lower(), argv[3].lower())
 
+def relocated_add():
+    if argc < 3:
+        usage(EXIT.MISSING_ARGS,
+                _(u'Missing relocated address and destination.'))
+    elif argc < 4:
+        usage(EXIT.MISSING_ARGS, _(u'Missing destination address.'))
+    else:
+        vmm.relocatedAdd(argv[2].lower(), argv[3])
+
+def relocated_info():
+    if argc < 3:
+        usage(EXIT.MISSING_ARGS, _(u'Missing relocated address'))
+    else:
+        relocated = argv[2].lower()
+        _printRelocated({'addr': relocated,
+            'dest': vmm.relocatedInfo(relocated)})
+
+def relocated_delete():
+    if argc < 3:
+        usage(EXIT.MISSING_ARGS, _(u'Missing relocated address'))
+    else:
+        vmm.relocatedDelete(argv[2].lower())
+
 def user_byID():
     if argc < 3:
         usage(EXIT.MISSING_ARGS, _(u'Missing userid'))
@@ -428,6 +463,12 @@
             alias_info()
         elif argv[1] in ['ad', 'aliasdelete']:
             alias_delete()
+        elif argv[1] in ['ra', 'relocatedadd']:
+            relocated_add()
+        elif argv[1] in ['ri', 'relocatedinfo']:
+            relocated_info()
+        elif argv[1] in ['rd', 'relocateddelete']:
+            relocated_delete()
         elif argv[1] in ['gu', 'getuser']:
             user_byID()
         elif argv[1] in ['ld', 'listdomains']: