Import Vilma from CVS
authorBen Klang <ben@alkaloid.net>
Wed, 16 Sep 2009 16:16:37 +0000 (12:16 -0400)
committerBen Klang <ben@alkaloid.net>
Wed, 16 Sep 2009 16:16:37 +0000 (12:16 -0400)
61 files changed:
vilma/LICENSE [new file with mode: 0644]
vilma/README [new file with mode: 0644]
vilma/config/.cvsignore [new file with mode: 0644]
vilma/config/conf.xml [new file with mode: 0644]
vilma/config/hooks.php.dist [new file with mode: 0644]
vilma/config/prefs.php.dist [new file with mode: 0644]
vilma/docs/CHANGES [new file with mode: 0644]
vilma/docs/CREDITS [new file with mode: 0644]
vilma/docs/INSTALL [new file with mode: 0644]
vilma/docs/TODO [new file with mode: 0644]
vilma/domains/delete.php [new file with mode: 0644]
vilma/domains/edit.php [new file with mode: 0644]
vilma/domains/index.php [new file with mode: 0644]
vilma/index.php [new file with mode: 0644]
vilma/lib/Driver.php [new file with mode: 0644]
vilma/lib/Driver/qmailldap.php [new file with mode: 0644]
vilma/lib/Driver/sql.php [new file with mode: 0644]
vilma/lib/Forms/DeleteDomainForm.php [new file with mode: 0644]
vilma/lib/Forms/EditDomainForm.php [new file with mode: 0644]
vilma/lib/Forms/EditUserForm.php [new file with mode: 0644]
vilma/lib/MailboxDriver.php [new file with mode: 0644]
vilma/lib/MailboxDriver/hooks.php [new file with mode: 0644]
vilma/lib/MailboxDriver/imap.php [new file with mode: 0644]
vilma/lib/MailboxDriver/maildrop.php [new file with mode: 0644]
vilma/lib/MailboxDriver/null.php [new file with mode: 0644]
vilma/lib/Vilma.php [new file with mode: 0644]
vilma/lib/api.php [new file with mode: 0644]
vilma/lib/base.php [new file with mode: 0644]
vilma/lib/tests/driver.phpt [new file with mode: 0644]
vilma/lib/version.php [new file with mode: 0644]
vilma/locale/de_DE/LC_MESSAGES/vilma.mo [new file with mode: 0644]
vilma/locale/es_ES/LC_MESSAGES/vilma.mo [new file with mode: 0644]
vilma/locale/it_IT/LC_MESSAGES/vilma.mo [new file with mode: 0644]
vilma/locale/lt_LT/LC_MESSAGES/vilma.mo [new file with mode: 0644]
vilma/po/.cvsignore [new file with mode: 0644]
vilma/po/README [new file with mode: 0644]
vilma/po/de_DE.po [new file with mode: 0644]
vilma/po/es_ES.po [new file with mode: 0644]
vilma/po/it_IT.po [new file with mode: 0644]
vilma/po/lt_LT.po [new file with mode: 0644]
vilma/po/vilma.pot [new file with mode: 0644]
vilma/scripts/.htaccess [new file with mode: 0644]
vilma/scripts/create_mailboxes.php [new file with mode: 0644]
vilma/scripts/sql/vilma.sql [new file with mode: 0644]
vilma/templates/common-header.inc [new file with mode: 0644]
vilma/templates/domains/index.html [new file with mode: 0644]
vilma/templates/main/main.html [new file with mode: 0644]
vilma/templates/users/index.html [new file with mode: 0644]
vilma/templates/virtuals/index.html [new file with mode: 0644]
vilma/test.php [new file with mode: 0644]
vilma/themes/graphics/display.png [new file with mode: 0644]
vilma/themes/graphics/domain.png [new file with mode: 0644]
vilma/themes/graphics/favicon.ico [new file with mode: 0644]
vilma/themes/graphics/sort.png [new file with mode: 0644]
vilma/themes/graphics/vilma.png [new file with mode: 0644]
vilma/users/delete.php [new file with mode: 0644]
vilma/users/edit.php [new file with mode: 0644]
vilma/users/index.php [new file with mode: 0644]
vilma/virtuals/delete.php [new file with mode: 0644]
vilma/virtuals/edit.php [new file with mode: 0644]
vilma/virtuals/index.php [new file with mode: 0644]

diff --git a/vilma/LICENSE b/vilma/LICENSE
new file mode 100644 (file)
index 0000000..ae5539e
--- /dev/null
@@ -0,0 +1,49 @@
+Version 1.0
+
+Copyright 2001-2009 The Horde Project (http://www.horde.org/)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+3. The end-user documentation included with the redistribution, if
+any, must include the following acknowledgment:
+
+   "This product includes software developed by the Horde Project
+    (http://www.horde.org/)."
+
+Alternately, this acknowledgment may appear in the software itself, if
+and wherever such third-party acknowledgments normally appear.
+
+4. The names "Horde", "The Horde Project", and "Vilma" must not be
+used to endorse or promote products derived from this software without
+prior written permission. For written permission, please contact
+core@horde.org.
+
+5. Products derived from this software may not be called "Horde" or
+"Vilma", nor may "Horde" or "Vilma" appear in their name, without
+prior written permission of the Horde Project.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE HORDE PROJECT OR ITS CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+This software consists of voluntary contributions made by many
+individuals on behalf of the Horde Project. For more information on
+the Horde Project, please see <http://www.horde.org/>.
diff --git a/vilma/README b/vilma/README
new file mode 100644 (file)
index 0000000..d1b4882
--- /dev/null
@@ -0,0 +1,65 @@
+What is Vilma?
+--------------
+
+Vilma is a tool for administrators who need to handle various aspects
+of domain administration.
+
+
+Obtaining Vilma
+---------------
+
+Further information on Vilma and the latest version can be obtained at:
+
+  http://www.horde.org/vilma/
+
+
+Documentation
+-------------
+
+The following documentation is available in the Vilma distribution:
+
+README        - This file
+LICENSE       - Copyright and license information
+docs/CHANGES  - List of changes by release
+docs/CREDITS  - Who developed this
+docs/INSTALL  - Installation instructions
+
+
+Installation
+------------
+
+Instructions for installing Vilma can be found in the file INSTALL in the
+docs/ directory of the Vilma distribution.
+
+
+Assistance
+----------
+
+If you encounter problems with Vilma, help is available!
+
+The Horde Frequently Asked Questions List (FAQ), available on the Web at:
+
+  http://www.horde.org/faq/
+
+The Horde Project runs a number of mailing lists, for individual applications
+and for issues relating to the project as a whole. Information, archives, and
+subscription information can be found at:
+
+  http://www.horde.org/mail/
+
+Lastly, Horde developers, contributors and users also make occasional
+appearances on IRC, on the channel #horde on the Freenode Network
+(irc.freenode.net).
+
+
+Licensing
+---------
+
+For licensing and copyright information, please see the file LICENSE in the
+Vilma distribution.
+
+Thanks,
+
+The Vilma team
+
+$Horde: vilma/README,v 1.3 2007/08/05 22:37:11 mp Exp $
diff --git a/vilma/config/.cvsignore b/vilma/config/.cvsignore
new file mode 100644 (file)
index 0000000..de7b278
--- /dev/null
@@ -0,0 +1,2 @@
+conf.php
+conf.bak.php
diff --git a/vilma/config/conf.xml b/vilma/config/conf.xml
new file mode 100644 (file)
index 0000000..67674dd
--- /dev/null
@@ -0,0 +1,179 @@
+<?xml version="1.0"?>
+<!-- $Horde: vilma/config/conf.xml,v 1.24 2009/05/28 00:33:00 bklang Exp $ -->
+<configuration>
+ <configtab name="storage" desc="Domains and Accounts Driver">
+  <configsection name="storage">
+   <configdescription>
+    These are the settings for storing all the Vilma data, such as domains,
+    users within those domains, virtual addresses for users, etc.
+   </configdescription>
+   <configsection name="limits" desc="Default Limits">
+    <configstring name="defaultmaxusers" desc="Default Max Users (0 is unlimited)">0</configstring>
+    <configstring name="defaultquota" desc="Default Per-User Quota (in bytes, 0 is unlimited)">0</configstring>
+   </configsection>
+   <configswitch name="driver" desc="What storage driver should we use?">sql
+    <case name="sql" desc="SQL">
+     <configsection name="params">
+      <configsql switchname="driverconfig"/>
+      <configsection name="tables">
+
+       <configswitch name="domainsconfig" desc="Domains table specification">default
+        <case name="default" desc="Use Vilma Defaults"/>
+        <case name="custom" desc="Custom parameters">
+         <configstring name="domains" required="true" desc="Domain table name"/>
+         <configsection name="domains_fields">
+          <configstring name="domain_id" required="true" desc="Domain Id field."/>
+          <configstring name="domain_name" required="true" desc="Domain name field."/>
+          <configstring name="domain_transport" required="true" desc="Domain transport field."/>
+          <configstring name="domain_admin" required="true" desc="Domain admin field."/>
+          <configstring name="domain_max_users" required="true" desc="Domain max users field."/>
+          <configstring name="domain_quota" required="true" desc="Domain quota field."/>
+          <configstring name="domain_key" required="true" desc="Domain key field."/>
+         </configsection>
+        </case>
+       </configswitch>
+
+       <configswitch name="usersconfig" desc="Users table specification">default
+        <case name="default" desc="Use Vilma Defaults"/>
+        <case name="custom" desc="Custom parameters">
+         <configstring name="users" required="true" desc="Users table name"/>
+         <configsection name="users_fields">
+          <configstring name="user_id" required="true" desc="User Id field"/>
+          <configstring name="user_name" required="true" desc="User name field"/>
+          <configstring name="user_full_name" required="true" desc="User full name field"/>
+          <configstring name="user_home_dir" required="true" desc="User home dir field"/>
+          <configstring name="user_mail_dir" required="true" desc="User mail dir field"/>
+          <configstring name="user_mail_quota" required="true" desc="User quota field"/>
+          <configstring name="user_clear" required="true" desc="User clear password field"/>
+          <configstring name="user_crypt" required="true" desc="User crypted password field"/>
+          <configstring name="user_uid" required="true" desc="User uid field"/>
+          <configstring name="user_gid" required="true" desc="User gid field"/>
+          <configstring name="user_enabled" required="true" desc="User enabled field"/>
+         </configsection>
+        </case>
+       </configswitch>
+
+       <configswitch name="virtualsconfig" desc="Virtual addresses table specification">default
+        <case name="default" desc="Use Vilma Defaults"/>
+        <case name="custom" desc="Custom parameters">
+         <configstring name="virtuals" required="true" desc="Virtuals table name"/>
+         <configsection name="virtuals_fields">
+          <configstring name="virtual_id" required="true" desc="Virtual Id field."/>
+          <configstring name="virtual_email" required="true" desc="Virtual email field."/>
+          <configstring name="virtual_destination" required="true" desc="Virtual
+          destination field."/>
+         </configsection>
+        </case>
+       </configswitch>
+
+      </configsection>
+     </configsection>
+    </case>
+    <case name="qmailldap" desc="Qmail-LDAP">
+     <configsection name="params">
+      <configsection name="ldap">
+       <configstring name="ldaphost" desc="The hostname of the LDAP
+       server">localhost</configstring>
+       <configstring name="basedn" desc="The base DN for the LDAP server"/>
+       <configstring name="binddn" required="false" desc="The DN used to bind to
+       the LDAP server"/>
+       <configstring name="bindpw" required="false" desc="The password used to
+       bind to the LDAP server"/>
+       <configenum name="version" desc="LDAP Protocol Version">3 
+        <values>3 
+         <value desc="LDAPv2 (Deprecated)">2</value>
+         <value desc="LDAPv3">3</value>
+        </values>
+       </configenum>
+       <configstring name="dn" desc="The object search key"/>
+       <configswitch name="filter_type" desc="How to specify a filter for the
+       user lists">objectclass 
+        <case name="objectclass" desc="One or more objectclass filters">
+         <configlist name="objectclass" desc="The objectclass filter used to
+         search for users. Can be a single objectclass or a list."/>
+        </case>
+        <case name="free" desc="A complete LDAP filter expression">
+         <configstring name="filter" desc="The LDAP RFC formatted filter used to
+         search for users."/>
+        </case>
+       </configswitch>
+      </configsection>
+      <configsection name="sql">
+       <configsql switchname="driverconfig" />
+      </configsection>
+     </configsection>
+    </case>
+   </configswitch>
+  </configsection>
+ </configtab>
+
+ <configtab name="mta" desc="Mailbox Driver">
+  <configsection name="mailboxes">
+   <configheader>Mailbox settings</configheader>
+   <configswitch name="driver" desc="Driver used to create, delete, and check
+   the status of mailboxes">maildrop
+    <case name="maildrop" desc="Maildrop driver">
+     <configsection name="params" desc="Maildrop Parameters">
+      <configinteger name="uid" required="false" desc="The system UID for the
+      virtual user">1003</configinteger>
+      <configinteger name="gid" required="false" desc="The system GID for the
+      virtual user">1000</configinteger>
+      <configstring name="mail_dir_base" desc="The base directory for the
+      mailboxes">/home/vmail</configstring>
+      <configstring name="system_user" desc="User to run script to create mail
+      dir">vmail</configstring>
+      <configboolean name="usedomain" desc="Use virtual domain directory
+      (exploded) directory structure.">true</configboolean>
+     </configsection>
+    </case>
+    <case name="imap" desc="IMAP Admin driver">
+     <configsection name="params" desc="IMAP Admin Parameters">
+      <configstring name="admin_user" desc="The name of a user with admin
+      privileges"/>
+      <configstring name="admin_password" desc="The password of the
+      administrator"/>
+      <configstring name="hostspec" desc="The hostname or IP address of the
+      server">localhost</configstring>
+      <configstring name="port" desc="The server port to which we will
+      connect">143</configstring>
+      <configstring name="protocol" desc="The connection protocol
+      (e.g. 'imap', 'pop3', 'nntp').  Protocol is one of 'imap/notls' (or only
+      'imap' if you have a c-client version 2000c or older), 'imap/ssl', or
+      'imap/ssl/novalidate-cert' (for a self-signed
+      certificate)">imap</configstring>
+      <configstring name="userhierarchy" desc="The hierarchy where user
+      mailboxes are stored.  If you are using Cyrus, make sure that you are
+      using the same hierarchy separator as in imap.conf">user.</configstring>
+     </configsection>
+    </case>
+    <case name="hooks" desc="Hooks (See Documentation)">
+      <configsection name="params" desc="Hooks Parameters">
+        <configplaceholder/>
+      </configsection>
+    </case>
+    <case name="null" desc="Null driver">
+      <configsection name="params" desc="Null Parameters">
+        <configplaceholder/>
+      </configsection>
+    </case>
+   </configswitch>
+  </configsection>
+
+  <configsection name="mta">
+   <configheader>MTA Settings</configheader>
+   <configlist name="transports" desc="List of available transports (according
+   to MTA)">maildrop</configlist>
+  </configsection>
+ </configtab>
+
+ <configtab name="menu" desc="Menu Settings">
+  <configsection name="menu">
+   <configmultienum name="apps" desc="Select any applications that should be
+   linked in Vilma's menu">
+    <values>
+     <configspecial name="list-horde-apps"/>
+    </values>
+   </configmultienum>
+  </configsection>
+ </configtab>
+</configuration>
diff --git a/vilma/config/hooks.php.dist b/vilma/config/hooks.php.dist
new file mode 100644 (file)
index 0000000..101d253
--- /dev/null
@@ -0,0 +1,103 @@
+<?php
+/**
+ * Vilma Hooks configuration file.
+ *
+ * THE HOOKS PROVIDED IN THIS FILE ARE EXAMPLES ONLY.  DO NOT ENABLE THEM
+ * BLINDLY IF YOU DO NOT KNOW WHAT YOU ARE DOING.  YOU HAVE TO CUSTOMIZE THEM
+ * TO MATCH YOUR SPECIFIC NEEDS AND SYSTEM ENVIRONMENT.
+ *
+ * For more information please see the horde/config/hooks.php.dist file.
+ *
+ * $Horde: vilma/config/hooks.php.dist,v 1.3 2009/07/13 20:05:58 slusarz Exp $
+ */
+
+// Example hook for handling a new domain within Vilma.  This can be used, for
+// example, to add the new domain to qmail's "control/locals" file, which will
+// tell qmail to begin receiving mail for this new domain.
+//
+// Note: for this example function to work, the "control/locals" and the
+// "control/" directory must be writeable by the webserver process user ID.
+// An alternative to this direct method would be to repopulate the
+// "control/locals" file on an interval from cron(8) using some kind of script
+// to pull a list of domains from Horde using (for example) XML-RPC.
+
+// if (!function_exists('_vilma_hook_savedomain')) {
+//     function _vilma_hook_savedomain($info = null)
+//     {
+//         if ($info === null || !isset($info['domain_name'])) {
+//             return false;
+//         }
+//         $domain = $info['domain_name'];
+//
+//         $qmail_locals = '/tmp/locals';
+//         $domainlist = file_get_contents($qmail_locals);
+//         $domains = split("\n", $domainlist);
+//
+//         if (!in_array($domain, $domains)) {
+//            $domains[] = $domain;
+//         } else {
+//             return true;
+//         }
+//
+//         // Write to a temp file for safety and atomicity.
+//         $tmp = tempnam(dirname($qmail_locals), "locals-");
+//         $tmpfh = fopen($tmp, "w");
+//         fwrite($tmpfh, implode("\n", $domains));
+//         fclose($tmpfh);
+//
+//         // Backup the previous version and move the new one into place.
+//         unlink($qmail_locals . ".previous");
+//         rename($qmail_locals, $qmail_locals . ".previous");
+//         rename($tmp, $qmail_locals);
+//
+//         return true;
+//     }
+// }
+
+// This hook does the opposite of the above:  Remove a domain from the
+// "control/locals" file.
+
+// if (!function_exists('_vilma_hook_deletedomain')) {
+//     function _vilma_hook_deletedomain($domain = null)
+//     {
+//         if ($domain === null) {
+//             return false;
+//         }
+//
+//         $qmail_locals = '/tmp/locals';
+//         $domainlist = file_get_contents($qmail_locals);
+//         $domains = split("\n", $domainlist);
+//
+//         if ($key = array_search($domain, $domains)) {
+//            unset($domains[$key]);
+//         } else {
+//             return false;
+//         }
+//
+//         // Write to a temp file for safety and atomicity.
+//         $tmp = tempnam(dirname($qmail_locals), "locals-");
+//         $tmpfh = fopen($tmp, "w");
+//         fwrite($tmpfh, implode("\n", $domains));
+//         fclose($tmpfh);
+//
+//         // Backup the previous version and move the new one into place.
+//         unlink($qmail_locals . ".previous");
+//         rename($qmail_locals, $qmail_locals . ".previous");
+//         rename($tmp, $qmail_locals);
+//
+//         return true;
+//     }
+// }
+
+// This function will turn an array of additional LDAP attributes that will be
+// added to the attributes created by the LDAP driver.
+//if (!function_exists('_vilma_hook_getldapattrs')) {
+//    function _vilma_hook_getldapattrs($attrs)
+//    {
+//        $attrs['deliverymode'] = 'nolocal';
+//        $attrs['qmailprogrampath'] = '/opt/maildrop/bin/maildrop /opt/maildrop/etc/maildroprc.dspam';
+//        $attrs['qmaildotmode'] = 'ldapwithprog';
+//
+//        return $attrs;
+//    }
+//}
diff --git a/vilma/config/prefs.php.dist b/vilma/config/prefs.php.dist
new file mode 100644 (file)
index 0000000..db05b32
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+/**
+ * $Horde: vilma/config/prefs.php.dist,v 1.1 2006/08/24 23:49:27 bklang Exp $
+ *
+ * See horde/config/prefs.php for documentation on the structure of this file.
+ */
+
+$prefGroups['display'] = array(
+    'column' => _("Display listings"),
+    'label' => _("Display details"),
+    'desc' => _("Set default display parameters."),
+    'members' => array('addresses_perpage'));
+
+// listing
+$_prefs['addresses_perpage'] = array(
+     'value' => 20,
+     'locked' => false,
+     'shared' => false,
+     'type' => 'number',
+     'desc' => _("How many domain to display per page."));
diff --git a/vilma/docs/CHANGES b/vilma/docs/CHANGES
new file mode 100644 (file)
index 0000000..7a56b65
--- /dev/null
@@ -0,0 +1,16 @@
+--------
+v0.1-cvs
+--------
+
+[bkl] Restructure application to have Users, Aliases, Groups and Forwards.
+[bkl] Add qmailldap backend support.
+[ben] Better support for MS-SQL.
+[jan] Allow to use custom table and column names (guilleva@gmail.com,
+      Request #3244).
+[cjh] Use bind variables in SQL driver (selsky@columbia.edu, Request #1795).
+[jmf] Downcase user and virtuals.
+[jmf] Support for virtuals with external (non-local) e-mail destinations.
+[jan] Add Spanish translation (Manuel Perez Ayala <mperaya@alcazaba.unex.es>).
+[jmf] Add support for creating mailboxes via IMAP protocol.
+[jan] Add Lithuanian translation (Vilius ¦umskas <vilius@lnk.lt>).
+[jan] Add German translation.
diff --git a/vilma/docs/CREDITS b/vilma/docs/CREDITS
new file mode 100644 (file)
index 0000000..334ec6f
--- /dev/null
@@ -0,0 +1,26 @@
+=======================================
+|| Vilma Version 1.0 Development Team ||
+========================================
+
+===============
+Core Developers
+===============
+
+Marko Djukic <marko@oblo.com>
+- Initial authoring.
+
+Ben Klang <ben@alkaloid.net>
+- Rewrite for Aliases and Groups/Forwards
+
+
+============
+Localization
+============
+
+German                  Jan Schneider <jan@horde.org>
+Italian                 Marko Djukic <marko@oblo.com>
+Lithuanian              Vilius ¦umskas <vilius@lnk.lt>
+Spanish                 Manuel Perez Ayala <mperaya@alcazaba.unex.es>
+
+
+$Horde: vilma/docs/CREDITS,v 1.7 2008/03/22 10:43:53 jan Exp $
diff --git a/vilma/docs/INSTALL b/vilma/docs/INSTALL
new file mode 100644 (file)
index 0000000..3bf7b70
--- /dev/null
@@ -0,0 +1,196 @@
+==============================
+||  INSTALLING Vilma 0.1  ||
+==============================
+
+* PLEASE SEE IMPORTANT NOTE in the README file about Vilma's status
+before you try to install it and are disappointed.
+
+This document contains instructions for installing the Vilma virtual mail
+domain management application.
+
+For information on the capabilities and features of Vilma, see the
+file README in the top-level directory of the Vilma distribution.
+
+
+OBTAINING VILMA
+-----------------
+
+Vilma can be obtained from the Horde website and FTP server, at
+
+   http://www.horde.org/vilma/
+   ftp://ftp.horde.org/pub/vilma/
+
+Bleeding-edge development versions of Vilma are available via CVS; see
+the file docs/HACKING in the Horde distribution for information on
+accessing the Horde CVS repository.
+
+
+PREREQUISITES
+-------------
+
+To function properly, Vilma requires the following:
+
+  1. A working Horde installation.
+
+     Vilma runs within the Horde Application Framework, a set of
+     common tools for Web applications written in PHP. You must
+     install Horde before installing Vilma.
+
+     The Horde Framework can be obtained from the Horde website and
+     FTP server, at
+
+        http://www.horde.org/horde/
+        ftp://ftp.horde.org/pub/horde/
+
+     Many of Vilma's prerequisites are also Horde prerequisites.
+     Be sure to have completed all of the steps in the INSTALL
+     file for the Horde Framework before installing Vilma.
+
+  2. SQL support in PHP.
+
+     Vilma store its data in an SQL database. Build PHP with whichever
+     SQL driver you require; see the Horde INSTALL file for details.
+
+
+INSTALLING VILMA
+------------------
+
+Vilma is written in PHP, and must be installed in a web-accessible
+directory. The precise location of this directory will differ from
+system to system. Conventionally, Vilma is installed directly underneath
+Horde in the webserver's document tree.
+
+Since Vilma is written in PHP, there is no compilation necessary;
+simply expand the distribution where you want it to reside and rename
+the root directory of the distribution to whatever you wish to appear
+in the URL. For example, with the Apache webserver's default document
+root of '/usr/local/apache/htdocs', you would type:
+
+   cd /usr/local/apache/htdocs/horde
+   tar zxvf /path/to/vilma-0.1.tar.gz
+   mv vilma-0.1 vilma
+
+and would then find Vilma at the URL
+
+   http://your-server/horde/vilma/
+
+
+CONFIGURING VILMA
+-------------------
+
+1. Configuring Horde for Vilma
+
+   a. Register the application
+
+      In horde/config/registry.php, find the applications['vilma'] stanza.
+      The default settings here should be okay, but you can change
+      them if desired.  If you have changed the location of Vilma relative
+      to Horde, either in the URL, in the filesystem or both, you must
+      update the 'fileroot' and 'webroot' settings to their correct
+      values.
+
+2. Creating the database table
+
+   The specific steps to create the Vilma database table depend
+   on which database you've chosen to use.
+
+   First, look in scripts/drivers/ to see if a script already
+   exists for your database type. If so, you should be
+   able to simply execute that script as superuser in your
+   database. (Note that executing the script as the "horde" user will
+   probably fail when granting privileges.)
+
+   If such a script does not exist, you'll need to build your own, using
+   the file vilma.sql as a starting point. If you need
+   assistance in creating databases, you may wish to let us know on
+   the Vilma mailing list.
+
+3. Configuring Vilma.
+
+   To configure Vilma, change to the config/ directory of the
+   installed distribution, and make copies of all of the configuration
+   "dist" files without the "dist" suffix:
+
+      cd config/
+      for foo in *.dist; do cp $foo `basename $foo .dist`; done
+
+   Documentation on the format of those files can be found in each
+   file.   With the exception of the conf.* files (see below),
+   the other files in config/ need only be modified if you wish
+   to customize Vilma's appearance or behavior, as the defaults will
+   be correct for most sites.
+
+   You must login to Horde as a Horde Administrator to finish the
+   configuring of Vilma.  Use the Horde "Administration" menu item to get
+   to the Administration page, and then click on the "Configuration"
+   icon to get the Configuration page.  Select "Tasks" from the selection
+   list of applications, and click on the "Configure" button.  Fill in or
+   change any configuration values as needed.  When done click on "Generate
+   Tasks Configuration" to generate the conf.php file.  If your web server
+   doesn't have write permissions to the Vilma configuration directory or
+   file, it will not be able to write the file.  In this case, cut and
+   paste the returned configuration information into the file
+   vilma/config/conf.php.
+
+   Note for international users:  Vilma uses GNU gettext to provide local
+   translations of text displayed by applications; the translations are
+   found in the po/ directory.  If a translation is not yet available
+   for your locale (and you wish to create one), or if you're having
+   trouble using a provided translation, please see the horde/docs/TRANSLATIONS
+   file for instructions.
+
+4. Testing Vilma
+
+   Use Vilma to create, modify, and delete forms. Test at
+   least the following:
+
+     - Creating a form
+     - Modifying a form
+     - Viewing and submitting a form
+     - Deleting a form
+
+
+SAMPLE USAGE
+------------
+
+Vilma can be embedded internally within Horde in any application which
+supports the Horde Blocks API.
+
+Otherwise Vilma can be called from any web page with the following simple
+php code:
+
+   <?php
+   $form_id = 2;
+   include <pathtovilma> . '/display.php';
+   ?>
+
+
+OBTAINING SUPPORT
+-----------------
+
+If you encounter problems with Vilma, help is available!
+
+The Horde Frequently Asked Questions List (FAQ), available on the Web
+at
+
+  http://www.horde.org/faq/
+
+The Horde Project runs a number of mailing lists, for individual
+applications and for issues relating to the project as a whole.
+Information, archives, and subscription information can be found at
+
+  http://www.horde.org/mail/
+
+Lastly, Horde developers, contributors and users may also be found on IRC,
+on the channel #horde on the Freenode Network (irc.freenode.net).
+
+Please keep in mind that Vilma is free software written by volunteers.
+For information on reasonable support expectations, please read
+
+  http://www.horde.org/support.php
+
+Thanks for using Vilma!
+
+The Vilma team
+
+$Horde: vilma/docs/INSTALL,v 1.6 2007/08/30 05:10:06 chuck Exp $
diff --git a/vilma/docs/TODO b/vilma/docs/TODO
new file mode 100644 (file)
index 0000000..c367073
--- /dev/null
@@ -0,0 +1,17 @@
+===========================
+Vilma Development TODO List
+===========================
+
+* Implement an audit trail so that we know when and by whom accounts were
+  created, deleted, modified, etc.
+
+* Integrate with Beatnik to allow DNS zone and MX records to be created upon
+  domain creation
+
+* Abstract domains driver from accounts driver
+
+* Create Beatnik-integrated domains driver
+
+* Throw proper error if MySQL module not installed in PHP
+
+$Horde: vilma/docs/TODO,v 1.7 2007/08/06 00:08:29 mp Exp $
diff --git a/vilma/domains/delete.php b/vilma/domains/delete.php
new file mode 100644 (file)
index 0000000..b73bfe5
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+/**
+ * $Horde: vilma/domains/delete.php,v 1.28 2009/06/10 17:33:45 slusarz Exp $
+ *
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * @author Marko Djukic <marko@oblo.com>
+ */
+
+@define('VILMA_BASE', dirname(__FILE__) . '/..');
+require_once VILMA_BASE . '/lib/base.php';
+require_once 'Horde/Form.php';
+require_once VILMA_BASE . '/lib/Forms/DeleteDomainForm.php';
+
+/* Only admin should be using this. */
+if (!Vilma::hasPermission($domain)) {
+    Horde::authenticationFailureRedirect();
+}
+
+$vars = Horde_Variables::getDefaultVariables();
+$form = new DeleteDomainForm($vars);
+
+if ($vars->get('submitbutton') == _("Delete")) {
+    if ($form->validate($vars)) {
+        $form->getInfo($vars, $info);
+        $delete = $vilma_driver->deleteDomain($info['domain_id']);
+        if (is_a($delete, 'PEAR_Error')) {
+            Horde::logMessage($delete, __FILE__, __LINE__, PEAR_LOG_ERR);
+            $notification->push(sprintf(_("Error deleting domain. %s."), $delete->getMessage()), 'horde.error');
+        } else {
+            $notification->push(_("Domain deleted."), 'horde.success');
+            $url = Horde::applicationUrl('domains/index.php', true);
+            header('Location: ' . $url);
+            exit;
+        }
+    }
+} elseif ($vars->get('submitbutton') == _("Do not delete")) {
+    $notification->push(_("Domain not deleted."), 'horde.message');
+    header('Location: ' . Horde::applicationUrl('domains/index.php'));
+    exit;
+}
+
+/* Render the form. */
+require_once 'Horde/Form/Renderer.php';
+$renderer = new Horde_Form_Renderer();
+$main = Horde_Util::bufferOutput(array($form, 'renderActive'), $renderer, $vars, 'delete.php', 'post');
+
+$template->set('main', $main);
+$template->set('menu', Vilma::getMenu('string'));
+$template->set('notify', Horde_Util::bufferOutput(array($notification, 'notify'), array('listeners' => 'status')));
+
+require VILMA_TEMPLATES . '/common-header.inc';
+echo $template->fetch(VILMA_TEMPLATES . '/main/main.html');
+require $registry->get('templates', 'horde') . '/common-footer.inc';
diff --git a/vilma/domains/edit.php b/vilma/domains/edit.php
new file mode 100644 (file)
index 0000000..492430e
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+/**
+ * $Horde: vilma/domains/edit.php,v 1.28 2009/06/10 17:33:45 slusarz Exp $
+ *
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * @author Marko Djukic <marko@oblo.com>
+ */
+
+@define('VILMA_BASE', dirname(__FILE__) . '/..');
+require_once VILMA_BASE . '/lib/base.php';
+require_once 'Horde/Form.php';
+require_once VILMA_BASE . '/lib/Forms/EditDomainForm.php';
+
+/* Only admin should be using this. */
+if (!Vilma::hasPermission($domain)) {
+    Horde::authenticationFailureRedirect();
+}
+
+//$domain_id = Horde_Util::getFormData('domain_id');
+$vars = Horde_Variables::getDefaultVariables();
+$form = new EditDomainForm($vars);
+
+if ($form->validate($vars)) {
+    $form->getInfo($vars, $info);
+    $info['name'] = Horde_String::lower($info['name']);
+    $domain_id = $vilma_driver->saveDomain($info);
+    if (is_a($domain_id, 'PEAR_Error')) {
+        Horde::logMessage($domain_id, __FILE__, __LINE__, PEAR_LOG_ERR);
+        $notification->push(sprintf(_("Error saving domain: %s."), $domain_id->getMessage()), 'horde.error');
+    } else {
+        $notification->push(_("Domain saved."), 'horde.success');
+        $url = Horde::applicationUrl('domains/index.php', true);
+        header('Location: ' . $url);
+        exit;
+    }
+}
+
+/* Render the form. */
+require_once 'Horde/Form/Renderer.php';
+$renderer = &new Horde_Form_Renderer();
+$main = Horde_Util::bufferOutput(array($form, 'renderActive'), $renderer, $vars, 'edit.php', 'post');
+
+$template->set('main', $main);
+$template->set('menu', Vilma::getMenu('string'));
+$template->set('notify', Horde_Util::bufferOutput(array($notification, 'notify'), array('listeners' => 'status')));
+
+require VILMA_TEMPLATES . '/common-header.inc';
+echo $template->fetch(VILMA_TEMPLATES . '/main/main.html');
+require $registry->get('templates', 'horde') . '/common-footer.inc';
diff --git a/vilma/domains/index.php b/vilma/domains/index.php
new file mode 100644 (file)
index 0000000..5564137
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+/**
+ * $Horde: vilma/domains/index.php,v 1.28 2009/06/10 05:25:22 slusarz Exp $
+ *
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * @author Marko Djukic <marko@oblo.com>
+ */
+
+@define('VILMA_BASE', dirname(__FILE__) . '/..');
+require_once VILMA_BASE . '/lib/base.php';
+
+/* Only admin should be using this. */
+if (!Vilma::hasPermission($domain)) {
+    Horde::authenticationFailureRedirect();
+}
+
+// Having a current domain doesn't make sense on this page
+Vilma::setCurDomain(false);
+
+$domains = $vilma_driver->getDomains();
+if (is_a($domains, 'PEAR_Error')) {
+    $notification->push($domains, 'horde.error');
+    $domains = array();
+}
+foreach ($domains as $id => $domain) {
+    $url = Horde::applicationUrl('domains/edit.php');
+    $domains[$id]['edit_url'] = Horde_Util::addParameter($url, 'domain_id', $domain['domain_id']);
+    $url = Horde::applicationUrl('domains/delete.php');
+    $domains[$id]['del_url'] = Horde_Util::addParameter($url, 'domain_id', $domain['domain_id']);
+    $url = Horde::applicationUrl('users/index.php');
+    $domains[$id]['view_url'] = Horde_Util::addParameter($url, 'domain_id', $domain['domain_id']);
+}
+
+/* Set up the template fields. */
+$template->set('domains', $domains, true);
+$template->set('menu', Vilma::getMenu('string'));
+$template->set('notify', Horde_Util::bufferOutput(array($notification, 'notify'), array('listeners' => 'status')));
+
+/* Set up the field list. */
+$images = array('delete' => Horde::img('delete.png', _("Delete Domain"), '', $registry->getImageDir('horde')),
+                'edit' => Horde::img('edit.png', _("Edit Domain"), '', $registry->getImageDir('horde')));
+$template->set('images', $images);
+
+/* Render the page. */
+require VILMA_TEMPLATES . '/common-header.inc';
+echo $template->fetch(VILMA_TEMPLATES . '/domains/index.html');
+require $registry->get('templates', 'horde') . '/common-footer.inc';
diff --git a/vilma/index.php b/vilma/index.php
new file mode 100644 (file)
index 0000000..d3e8a86
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+/**
+ * $Horde: vilma/index.php,v 1.19 2009/01/06 18:02:26 jan Exp $
+ *
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * @author Marko Djukic <marko@oblo.com>
+ */
+
+@define('VILMA_BASE', dirname(__FILE__));
+require_once VILMA_BASE . '/lib/base.php';
+
+$vilma_configured = (@is_readable(VILMA_BASE . '/config/conf.php') &&
+                     @is_readable(VILMA_BASE . '/config/prefs.php'));
+
+if (!$vilma_configured) {
+    require VILMA_BASE . '/../lib/Test.php';
+    Horde_Test::configFilesMissing('Vilma', VILMA_BASE, array('conf.php', 'prefs.php'));
+}
+
+require VILMA_BASE . '/domains/index.php';
diff --git a/vilma/lib/Driver.php b/vilma/lib/Driver.php
new file mode 100644 (file)
index 0000000..8868336
--- /dev/null
@@ -0,0 +1,423 @@
+<?php
+/**
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * $Horde: vilma/lib/Driver.php,v 1.54 2009/05/27 23:57:31 bklang Exp $
+ *
+ * @author Marko Djukic <marko@oblo.com>
+ * @package Vilma
+ */
+class Vilma_Driver {
+
+    /**
+     * A hash containing any parameters for the current driver.
+     *
+     * @var array
+     */
+    var $_params = array();
+
+    /**
+     * Constructor
+     *
+     * @param array $params  Any parameters needed for this driver.
+     */
+    function Vilma_Driver($params)
+    {
+        $this->_params = $params;
+    }
+
+    /**
+     * Returns all the users sorted by domain and as arrays of each domain.
+     *
+     * @return array  An array of domains then users for each domain.
+     */
+    function getAllUsers()
+    {
+        /* Get all users from backend. */
+        $users = &$this->getUsers();
+
+        /* Determine the domain for each user and plug into array by domain. */
+        $users_by_domain = array();
+        foreach ($users as $user) {
+            $domain_name = Vilma::stripDomain($user['user_name']);
+            $users_by_domain[$domain_name][] = $user;
+        }
+
+        /* Sort by domain. */
+        ksort($users_by_domain);
+        /* Sort each domain's users by user name. */
+        require_once 'Horde/Array.php';
+        foreach ($users_by_domain as $key => $val) {
+            Horde_Array::arraySort($users_by_domain[$key], 'user_name');
+        }
+
+        return $users_by_domain;
+    }
+
+    /**
+     * Checks if the given domain is below the maximum allowed users.
+     *
+     * @param string $domain  The domain name to check.
+     *
+     * @return boolean  True if the domain does not have a maximum limit (0) or
+     *                  current number of users is below the maximum number
+     *                  allowed. Otherwise false.
+     */
+    function isBelowMaxUsers($domain)
+    {
+        /* Get the maximum number of users for this domain. */
+        $max_users = $this->getDomainMaxUsers($domain);
+        if ($max_users == '0') {
+            /* No maximum. */
+            return true;
+        }
+
+        /* Get the current number of users. */
+        $num_users = $this->getDomainNumUsers($domain);
+
+        return ($num_users < $max_users);
+    }
+
+    /**
+     * Gets an array of information related to the address passed in.
+     * This method may be overridden by the backend driver if there is a more
+     * efficient way to do this than a linear array search
+     *
+     * @param string $address  Address for which information will be pulled
+     * @param string $type     Address type to request
+     *                         One of 'user', 'alias', 'grpfwd' or 'any'
+     *                         Defaults to 'any'
+     *
+     * @return mixed  Array of user information on success, empty array
+     *                if the user does not exist, PEAR_Error on failure
+     */
+    function getAddressInfo($address, $type = 'all')
+    {
+        $domain = Vilma::stripDomain($address);
+        $addresses = $this->getAddresses($domain, $type);
+        foreach($addresses as $addrinfo) {
+            if ($addrinfo['id'] == $address) {
+                return $addrinfo;
+            } else if ($addrinfo['address'] == $address) {
+                return $addrinfo;
+            }
+        }
+        return PEAR::raiseError(sprintf(_("No such address %s of type %s found."), $address, $type));
+    }
+
+    /**
+     * Does a series of checks for a given user to determine the status.
+     *
+     * @param array $user  The user's details in an array as returned by the
+     *                     getUser() function.
+     *
+     * @return array  Either an array of error messages found during the checks
+     *                or an array with a single element stating that the user
+     *                is ready.
+     */
+    function getUserStatus($user)
+    {
+        /* Some needed vars. */
+        $no_error = true;
+        $status = array();
+        $domain_name = Vilma::stripDomain($user['user_name']);
+        $user_name = Vilma::stripUser($user['user_name']);
+
+        /* Check if user enabled. */
+        if ($user['user_enabled'] !== 'active') {
+            $no_error = false;
+            $err_msg = _("User disabled.");
+            $status[] = Horde::img('alerts/error.png', $err_msg, 'align="middle"', $GLOBALS['registry']->getImageDir('horde')) . '&nbsp;' . $err_msg;
+        }
+
+        /* Check if mailbox exists. */
+        $mailboxes = &Vilma::getMailboxDriver();
+        if (is_a($mailboxes, 'PEAR_Error')) {
+            $no_error = false;
+            $err_msg = $mailboxes->getMessage();
+            $status[] = Horde::img('alerts/warning.png', $err_msg, 'align="middle"', $GLOBALS['registry']->getImageDir('horde')) . '&nbsp;' . $err_msg;
+        }
+        $result = $mailboxes->checkMailbox($user_name, $domain_name);
+        if (is_a($result, 'PEAR_Error')) {
+            $no_error = false;
+            $err_msg = $result->getMessage();
+            $status[] = Horde::img('alerts/warning.png', $err_msg, 'align="middle"', $GLOBALS['registry']->getImageDir('horde')) . '&nbsp;' . $err_msg;
+        }
+
+        /* TODO: Quota checking would be nice too. */
+
+        /* If no errors have been found output a success message for this
+         * user's status. */
+        if ($no_error) {
+            $msg = _("User ready.");
+            $status = array(Horde::img('alerts/success.png', $msg, 'align="middle"', $GLOBALS['registry']->getImageDir('horde')) . '&nbsp;' . $msg);
+        }
+        return $status;
+    }
+
+    function saveUser(&$info)
+    {
+        $create = false;
+        if (empty($info['user_id'])) {
+            $create = true;
+        }
+
+        $result = $this->_saveUser($info);
+        if (is_a($result, 'PEAR_Error')) {
+            return $result;
+        }
+
+        if ($create) {
+            $mailboxes = &Vilma::getMailboxDriver();
+            if (is_a($mailboxes, 'PEAR_Error')) {
+                $this->_deleteUser($result['user_id']);
+                return $mailboxes;
+            }
+
+            $mailbox = $mailboxes->createMailbox(Vilma::stripUser($info['user_name']), Vilma::stripDomain($info['user_name']));
+            if (is_a($mailbox, 'PEAR_Error')) {
+                //echo $mailbox->getMessage() . '<br />';
+                //No 'system_user' parameter specified to maildrop driver.
+                //$this->_deleteUser($result['user_id']);
+                return $mailbox;
+            }
+        }
+
+        if (isset($GLOBALS['conf']['mta']['auth_update_script']) &&
+            !empty($info['password'])) {
+            $cmd = sprintf('%s set %s %s 2>&1',
+                           $GLOBALS['conf']['mta']['auth_update_script'],
+                           escapeshellarg($info['user_name']),
+                           escapeshellarg($info['password']));
+            $msg = system($cmd, $ec);
+            if ($msg === false) {
+                return PEAR::raiseError(_("Error running authentication update script."));
+            }
+            if ($ec != 0) {
+                if (empty($msg)) {
+                    $msg = _("Unknown error running authentication update script.");
+                }
+                return PEAR::raiseError($msg);
+            }
+        }
+
+        return true;
+    }
+
+    function deleteUser($user_id)
+    {
+        return PEAR::raiseError(_("Vilma_Driver::deleteUser(): Method Not Implemented."));
+    }
+
+    /**
+     * Saves a given domain with the provided information.
+     *
+     * @param array $info  Array of details to save the domain
+     *
+     * @return mixed  True on success, or PEAR_Error on failure.
+     */
+    function saveDomain(&$info)
+    {
+        $domain_id = $this->_saveDomain($info);
+        if (is_a($domain_id, 'PEAR_Error')) {
+            return $domain_id;
+        }
+
+        $ret = Horde::callHook('_vilma_hook_savedomain', array($info), 'vilma');
+        if (!$ret) {
+            return PEAR::raiseError(_("Domain added but an error was encountered while calling the configured hook.  Contact your administrator for futher assistance."));
+        }
+
+        return $domain_id;
+    }
+
+    /**
+     * Saves the domain record.
+     *
+     * @abstract
+     * @param array $info  Information to save the domain
+     *
+     * @return mixed True on success, or PEAR_Error on failure.
+     */
+    function _saveDomain(&$info)
+    {
+        return PEAR::raiseError(_("Not implemented."));
+    }
+
+    /**
+     * Deletes a given domain and all the users and virtuals under it.
+     *
+     * @param integer $domain_id  The id of the domain to delete.
+     *
+     * @return mixed  True on success, or PEAR_Error on failure.
+     */
+    function deleteDomain($domain_id)
+    {
+        $domain_record = $this->getDomain($domain_id);
+        if (is_a($domain_record, 'PEAR_Error')) {
+            return $domain_record;
+        }
+
+        $users = $this->getUsers($domain_record['domain_name']);
+        if (is_a($users, 'PEAR_Error')) {
+            return $users;
+        }
+
+        foreach ($users as $user) {
+            $this->_deleteUser($user['user_id']);
+        }
+
+        $ret = $this->_deleteDomain($domain_id);
+        if (is_a($ret, 'PEAR_Error')) {
+            return $ret;
+        }
+
+        $ret = Horde::callHook('_vilma_hook_deletedomain',
+                               array($domain_record['domain_name']),
+                               'vilma');
+        if (!$ret) {
+            return PEAR::raiseError(_("Error while calling hook to delete domain."));
+        }
+    }
+
+    /**
+     * Deletes the domain record.
+     *
+     * @abstract
+     * @param integer $domain_id  The ID of the domain to delete.
+     *
+     * @return mixed True on success, or PEAR_Error on failure.
+     */
+    function _deleteDomain($domain_id)
+    {
+        return PEAR::raiseError(_("Not implemented."));
+    }
+
+    /**
+     * Get the user who is the domain admin.
+     *
+     * @todo  This should be replaced by moving all permissions into Horde
+     *        permissions.
+     */
+    function getDomainAdmin($domain_name)
+    {
+        $domain = $this->getDomainByName($domain_name);
+        if (is_a($domain, 'PEAR_Error')) {
+            return $domain;
+        }
+        return $domain['domain_admin'];
+    }
+
+    /**
+     * Returns the configured quota for this domain.
+     *
+     * @param string $domain_name  The name of the domain for which to
+     *                             return the quota.
+     *
+     * @return integer  The domain's quota.
+     */
+    function getDomainQuota($domain_name)
+    {
+        $domain = $this->getDomainByName($domain_name);
+        if (is_a($domain, 'PEAR_Error')) {
+            return $domain;
+        }
+        return $domain['domain_quota'];
+    }
+
+    /**
+     * Returns the maximum number of users allowed for a given domain.
+     *
+     * @param string $domain_name  The name of the domain for which to
+     *                             return the maximum users.
+     *
+     * @return integer The maximum number of allowed users or PEAR_Error on
+     *                 failure.
+     */
+    function getDomainMaxUsers($domain_name)
+    {
+        $domain = $this->getDomainByName($domain_name);
+        if (is_a($domain, 'PEAR_Error')) {
+            return $domain;
+        }
+        return $domain['max_users'];
+    }
+
+    /**
+     * Attempts to return a concrete Vilma_Driver instance based on $driver.
+     *
+     * @param string $driver  The type of concrete Vilma_Driver subclass to
+     *                        return.
+     * @param array $params   A hash containing any additional configuration or
+     *                        connection parameters a subclass might need.
+     *
+     * @return Vilma_Driver  The newly created concrete Vilma_Driver instance,
+     *                       or false on error.
+     */
+    function factory($driver = null, $params = null)
+    {
+        if (is_null($driver)) {
+            $driver = $GLOBALS['conf']['storage']['driver'];
+        }
+        $driver = basename($driver);
+
+        if (is_null($params)) {
+            $params = Horde::getDriverConfig('storage', $driver);
+        }
+
+        include_once dirname(__FILE__) . '/Driver/' . $driver . '.php';
+        $class = 'Vilma_Driver_' . $driver;
+        if (class_exists($class)) {
+            return new $class($params);
+        } else {
+            Horde::fatal(PEAR::raiseError(sprintf(_("No such backend \"%s\" found"), $driver)), __FILE__, __LINE__);
+        }
+    }
+
+    /**
+     * Attempts to return a reference to a concrete Vilma_Driver instance
+     * based on $driver.
+     *
+     * It will only create a new instance if no Vilma_Driver instance with the
+     * same parameters currently exists.
+     *
+     * This should be used if multiple storage sources are required.
+     *
+     * This method must be invoked as: $var = &Vilma_Driver::singleton()
+     *
+     * @param string $driver  The type of concrete Vilma_Driver subclass to
+     *                        return.
+     * @param array $params   A hash containing any additional configuration or
+     *                        connection parameters a subclass might need.
+     *
+     * @return mixed  The created concrete Vilma_Driver instance, or false on
+     *                error.
+     */
+    function &singleton($driver = null, $params = null)
+    {
+        static $instances;
+
+        if (is_null($driver)) {
+            $driver = $GLOBALS['conf']['storage']['driver'];
+        }
+
+        if (is_null($params)) {
+            $params = Horde::getDriverConfig('storage', $driver);
+        }
+
+        if (!isset($instances)) {
+            $instances = array();
+        }
+
+        $signature = serialize(array($driver, $params));
+        if (!isset($instances[$signature])) {
+            $instances[$signature] = Vilma_Driver::factory($driver, $params);
+        }
+
+        return $instances[$signature];
+    }
+
+}
diff --git a/vilma/lib/Driver/qmailldap.php b/vilma/lib/Driver/qmailldap.php
new file mode 100644 (file)
index 0000000..d348613
--- /dev/null
@@ -0,0 +1,1044 @@
+<?php
+/**
+ * Copyright 2006-2007 Alkaloid Networks <http://www.alkaloid.net>
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * $Horde: vilma/lib/Driver/qmailldap.php,v 1.26 2009/07/08 20:16:22 bklang Exp $
+ *
+ * @author Ben Klang <bklang@alkaloid.net>
+ * @author David Cummings <davidcummings@acm.org>
+ * @package Vilma
+ */
+
+require_once 'Horde/SQL.php';
+
+class Vilma_Driver_qmailldap extends Vilma_Driver {
+
+    /**
+     * @var _LDAP Reference to initialized LDAP driver
+     */
+    var $_ldap;
+
+    /**
+     * @var _dbparams Configuration parameters for the LDAP driver
+     */
+    var $_ldapparams;
+
+    /**
+     * @var _db Reference to the initialized database driver
+     */
+    var $_db;
+
+    /**
+     * @var _dbparams Configuration parameters for the database driver
+     */
+    var $_dbparams;
+
+    function Vilma_Driver_qmailldap($params)
+    {
+        parent::Vilma_Driver($params);
+        $this->_ldapparams = $this->_params['ldap'];
+        $this->_sqlparams = Horde::getDriverConfig('storage', 'sql');
+        $res = $this->_connect();
+        if (is_a($res, 'PEAR_Error')) {
+            return $res;
+        }
+
+        /* Connect to the backend for tracking domains. */
+        $this->_dbinit();
+    }
+
+    /**
+     * Gets the list of domains from the backend.
+     *
+     * @return array  All the domains and their data in an array.
+     */
+    function getDomains()
+    {
+        $sql = 'SELECT domain_id, domain_name, domain_transport, ' .
+               'domain_max_users, domain_quota FROM vilma_domains ' .
+               'ORDER BY domain_name';
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return $this->_db->getAll($sql, $values, DB_FETCHMODE_ASSOC);
+    }
+
+    /**
+     * Gets the specified domain information from the backend.
+     *
+     * @param integer $domain_id  The id of the domain to fetch.
+     *
+     * @return array  The domain's information in an array.
+     */
+    function getDomain($domain_id)
+    {
+        $sql = 'SELECT domain_id, domain_name, domain_transport, ' .
+               'domain_max_users, domain_quota FROM vilma_domains ' . 
+               'WHERE domain_id=? ORDER BY domain_name';
+        $values = array($domain_id);
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return $this->_db->getRow($sql, $values, DB_FETCHMODE_ASSOC);
+    }
+
+    /**
+     * Given a domain name returns the information from the backend.
+     *
+     * @param string $name  The name of the domain to fetch.
+     *
+     * @return array  The domain's information in an array.
+     */
+    function getDomainByName($domain_name)
+    {
+        $sql = 'SELECT domain_id, domain_name, domain_transport, ' .
+               'domain_max_users, domain_quota FROM vilma_domains ' .
+               'WHERE domain_name=?';
+        $values = array($domain_name);
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return $this->_db->getRow($sql, $values, DB_FETCHMODE_ASSOC);
+    }
+
+    /**
+     * Returns a list of all users, aliases, or groups and forwards for a
+     * domain.
+     *
+     * @param string $domain      Domain on which to search.
+     * @param string $type        Only return a specific type. One of 'all',
+     *                            'user', 'alias','forward', or 'group'.
+     * @param string $key         Sort list by this key.
+     * @param integer $direction  Sort direction.
+     *
+     * @return array Account information for this domain
+     */
+    function getAddresses($domain, $type = 'all', $key = 'user_name',
+                          $direction = 0)
+    {
+        $addresses = array();
+        if ($type == 'all' || $type == 'user') {
+            $users = $this->_getUsers($domain);
+            $addresses = array_merge($addresses, $users);
+        }
+        if ($type == 'all' || $type == 'alias') {
+            $aliases = $this->_getAliases($domain);
+            $addresses = array_merge($addresses, $aliases);
+        }
+        if (($type == 'all') || ($type == 'forward')) {
+            $forwards = $this->_getGroupsAndForwards('forward',$domain);
+            $addresses = array_merge($addresses, $forwards);
+        }
+        if (($type == 'all') || ($type == 'group')) {
+            $groups = $this->_getGroupsAndForwards('group',$domain);
+            $addresses = array_merge($addresses, $groups);
+        }
+        // Sort the results
+        require_once 'Horde/Array.php';
+        Horde_Array::arraySort($addresses, $key, $direction, true);
+        return $addresses;
+    }
+    
+    function getUser($user_id) {
+        $user = $this->getUserStatus($user_id);
+
+        if (is_a($user, 'PEAR_Error')) {
+            return PEAR::raiseError(sprintf(_("Unable to qualify address: %s"), $user->getMessage()));
+        }
+        if(isset($user) && is_array($user)) {
+            return $user;
+        } else {
+            return PEAR::raiseError(_("Unable to qualify address."));
+        }
+    }    
+
+    /**
+     * Returns an array of all users, aliases, groups and forwards for this
+     * domain.
+     *
+     * @param string $domain Domain on which to search
+     * @param optional string $type Only return a specific type
+     *
+     * @return array Account information for this domain
+     */
+    function _getUsers($domain = null)
+    {
+        //$domain = $domain['domain_name'];
+        // Cache for multiple calls
+        static $users = array();
+        if (is_null($domain) && isset($users['_all'])) {
+            return $users['_all'];
+        }
+
+        if (!is_null($domain)
+               && isset($users[$domain])) {
+            return $users[$domain];
+        }
+
+        $filter = '(&';
+        if (!is_null($domain)) {
+            $filter .= '(mail=*@' . $domain . ')';
+        } else {
+            $domain = '_all';
+        }
+
+        // Make sure we don't get any forwards
+        $filter .= '(!(mailForwardingAddress=*))';
+
+        // FIXME: Check/add configured filter instead of objectclasses
+        foreach ($this->_ldapparams['objectclass'] as $objectclass) {
+            $filter .= '(objectClass=' . $objectclass . ')';
+        }
+        $filter .= ')';
+
+        Horde::logMessage($filter, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        $res = ldap_search($this->_ldap, $this->_ldapparams['basedn'], $filter);
+        if ($res === false) {
+            return PEAR::raiseError(sprintf(_("Error in LDAP search: %s"), ldap_error($this->LDAP)));
+        }
+
+        $res = ldap_get_entries($this->_ldap, $res);
+        if ($res === false) {
+            return PEAR::raiseError(sprintf(_("Error in LDAP search: %s"), ldap_error($this->LDAP)));
+        }
+
+        $users[$domain] = array();
+        $i = 0;
+        // Can't use foreach because of the array format returned by LDAP driver
+        while ($user = @$res[$i]) {
+            $users[$domain][$i]['id'] = $user['dn'];
+            $users[$domain][$i]['address'] = $user[$this->_getAttrByField('address')][0];
+            $users[$domain][$i]['type'] = 'user';
+            $users[$domain][$i]['user_name'] =
+                $user[$this->_getAttrByField('user_name')][0];
+            // We likely don't have read permission on the crypted password so
+            // avoid any warnings/errors about missing array elements
+            if (isset($user[$this->_getAttrByField('user_crypt')])) {
+                $users[$domain][$i]['user_crypt'] =
+                    $user[$this->_getAttrByField('user_crypt')][0];
+            } else {
+                $users[$domain][$i]['user_crypt'] = '';
+            }
+            $users[$domain][$i]['user_full_name'] =
+                $user[$this->_getAttrByField('user_full_name')][0];
+            // Mute assignment errors on the following optional fields
+            // These may not be present if the mail is only forwarded
+            $users[$domain][$i]['user_uid'] =
+                @$user[$this->_getAttrByField('user_uid')][0];
+            $users[$domain][$i]['user_gid'] =
+                @$user[$this->_getAttrByField('user_gid')][0];
+            $users[$domain][$i]['user_home_dir'] =
+                @$user[$this->_getAttrByField('user_home_dir')][0];
+            $users[$domain][$i]['user_mail_dir'] =
+                @$user[$this->_getAttrByField('user_mail_dir')][0];
+            $users[$domain][$i]['user_mail_quota_bytes'] =
+                @$user[$this->_getAttrByField('user_mail_quota_bytes')][0];
+            $users[$domain][$i]['user_mail_quota_count'] =
+                @$user[$this->_getAttrByField('user_mail_quota_count')][0];
+
+            // If accountStatus is blank it's the same as active
+            if (!isset($user[$this->_getAttrByField('user_enabled')][0]) ||
+                ($user[$this->_getAttrByField('user_enabled')][0] == 'active')) {
+                $users[$domain][$i]['user_enabled'] = 'active';
+            } else {
+                // accountStatus can also be:
+                // noaccess (receives but cannot pick up mail)
+                // disabled (bounce incoming and deny pickup)
+                // deleted (bounce incoming but allow pickup)
+                $users[$domain][$i]['user_enabled'] =
+                    $user[$this->_getAttrByField('user_enabled')][0];
+            }
+
+            $i++;
+        }
+
+        return $users[$domain];
+    }
+
+    function _getFields()
+    {
+        // LDAP attributes are always returned lower case!
+        static $fields = array(
+            'address' => 'mail',
+            'user_name' => 'uid',
+            'user_crypt' => 'userpassword',
+            'user_full_name' => 'cn',
+            'user_uid' => 'qmailuid',
+            'user_gid' => 'qmailgid',
+            'user_home_dir' => 'homedirectory',
+            'user_mail_dir' => 'mailmessagestore',
+            'user_mail_quota_bytes' => 'mailquotasize',
+            'user_mail_quota_count' => 'mailquotacount',
+            'user_enabled' => 'accountstatus',
+        );
+
+        return $fields;
+
+    }
+
+    function _getAttrByField($field) {
+        $fields = $this->_getFields();
+        return $fields[$field];
+    }
+
+    function _getFieldByAttr($attr) {
+        $attrs = array_flip($this->_getFields());
+        return $attrs[$attr];
+    }
+
+    /**
+     * Returns available email address aliases.  This method should not be
+     * called directly but rather by way of getAddresses().
+     *
+     * @access private
+     *
+     * @param string $target  If passed a domain then return all alias emails
+     *                        for the domain, otherwise if passed a user name
+     *                        return all virtual emails for that user.
+     *
+     * @return array  The used email aliases
+     */
+    function _getAliases($target = null)
+    {
+        // FIXME: Add static cache
+
+        $filter  = '(&'; // Begin filter (cumulative AND)
+        foreach ($this->_ldapparams['objectclass'] as $objectclass) {
+            // Add each objectClass from parameters
+            $filter .= '(objectClass=' . $objectclass . ')';
+        }
+        // FIXME: Add preconfigured filter from $this->_ldapparams
+
+        // Check if filtering only for domain.
+        if (($pos = strpos($target, '@')) === false && !empty($target)) {
+            $filter .= '(mailAlternateAddress=*@' . $target . ')';
+        // Otherwise filter for all aliases
+        } else {
+            $filter .= '(mailAlternateAddress=*)';
+            // Restrict the results to $target
+            if (!empty($target)) {
+                $filter .= '(mail=' . $target . ')'; // Add user's email
+            }
+        }
+        $filter .= ')'; // End filter
+
+        Horde::logMessage($filter, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        $res = @ldap_search($this->_ldap, $this->_ldapparams['basedn'], $filter);
+        if ($res === false) {
+            return PEAR::raiseError(sprintf(_("Error searching LDAP: %s"),
+                @ldap_error($this->_ldap)));
+        }
+
+        $res = @ldap_get_entries($this->_ldap, $res);
+        if ($res === false) {
+            return PEAR::raiseError(sprintf(_("Error returning LDAP results: %s"), @ldap_error($this->_ldap)));
+        }
+
+        $aliases = array();
+        // Can't use foreach because of the array format returned by LDAP driver
+        $i = 0; // Virtual address index
+        $e = 0; // Entry counter
+        while ($entry = @$res[$e]) {
+            // If accountStatus is blank it's the same as active
+            if (!isset($entry[$this->_getAttrByField('user_enabled')][0]) ||
+                ($entry[$this->_getAttrByField('user_enabled')][0] == 'active')) {
+                $curstatus = 'active';
+            } else {
+                // accountStatus can also be:
+                // noaccess (receives but cannot pick up mail)
+                // disabled (bounce incoming and deny pickup)
+                // deleted (bounce incoming but allow pickup)
+                $curstatus = $entry[$this->_getAttrByField('user_enabled')][0];
+            }
+            $a = 0; // Attribute counter
+            while ($mail = @$entry['mailalternateaddress'][$a]) {
+                $aliases[$i]['id'] = $mail;
+                $aliases[$i]['type'] = 'alias';
+                $aliases[$i]['user_name'] = $mail;
+                $aliases[$i]['user_full_name'] = sprintf(_("Alias for %s"), $entry['mail'][0]);
+                $aliases[$i]['destination'] = $entry['mail'][0];
+                $aliases[$i]['user_enabled'] = $curstatus;
+                $a++;
+                $i++;
+            }
+            $e++;
+        }
+
+        return $aliases;
+    }
+    /**
+     * Returns all available groups and forwards unless otherwise specified.
+     * If a domain name is passed then limit the results to groups or forwards
+     * in that domain.  This method should not be called directly, but rather by
+     * way of getAddresses()
+     * 
+     * @access private
+     *
+     * @param string $acquire The default behavior is to acquire both
+     *                        groups and forwards; a value of 'group'
+     *                        will return only groups and a value of
+     *                        'forward' will return only forwards.
+     * @param string $domain  The name of the domain from which to fetch 
+     *
+     * @return array  The available groups and forwards with details
+     */
+    function _getGroupsAndForwards($acquire = null, $domain = null)
+    {
+        // Cache
+        static $grpfwds;
+        // TODO ?
+        /*
+        if (is_null($domain) && isset($grpfwds['_all'])) {
+            return $grpfwds['_all'];
+        }
+        if (!is_null($domain) && isset($grpfwds[$domain])) {
+            return $grpfwds[$domain];
+        }
+        */
+        $filter  = '(&'; // Begin filter (cumulative AND)
+        foreach ($this->_ldapparams['objectclass'] as $objectclass) {
+            // Add each objectClass from parameters
+            $filter .= '(objectClass=' . $objectclass . ')';
+        }
+        // FIXME: Add preconfigured filter from $this->_ldapparams
+
+        // Only return results which have a forward configured
+        $filter .= '(mailForwardingAddress=*)';
+
+        if (!empty($domain)) {
+            $filter .= '(|'; // mail or mailAlternateAddress
+            $filter .= '(mail=*@' . $domain . ')';
+            $filter .= '(mailAlternateAddress=*@' . $domain . ')';
+            $filter .= ')'; // end mail or mailAlternateAddress
+        } else {
+            $domain = '_all';
+        }
+        $filter .= ')'; // End filter
+        Horde::logMessage($filter, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        $res = @ldap_search($this->_ldap, $this->_ldapparams['basedn'], $filter);
+        if ($res === false) {
+            return PEAR::raiseError(sprintf(_("Error searching LDAP: %s"),
+                @ldap_error($this->_ldap)));
+        }
+
+        $res = @ldap_get_entries($this->_ldap, $res);
+        if ($res === false) {
+            return PEAR::raiseError(sprintf(_("Error returning LDAP results: %s"), @ldap_error($this->_ldap)));
+        }
+
+        $grpfwds[$domain] = array();
+        // Can't use foreach because of the array format returned by LDAP driver
+        $i = 0; // Address index
+        $e = 0; // Entry counter
+        
+        while ($entry = @$res[$e]) {
+            $targets = array();
+            $a = 0; // Attribute counter
+            while ($attr = @$res[$e]['mailforwardingaddress'][$a]) {
+                $targets[] = $attr;
+                $a++;
+            }
+            $type = $entry['mailforwardingaddress']["count"];
+            if($type > 1) {
+                $type = 'group';
+            } else {
+                $type = 'forward';
+            }
+            if(($acquire == 'all') || ($type == $acquire)) {
+                $grpfwds[$domain][$i] = array(
+                    'id' => $entry['dn'],
+                    'type' => $type,
+                    'address' => $entry[$this->_getAttrByField('address')][0],
+                    'targets' => $targets,
+                    'user_name' => $entry[$this->_getAttrByField('user_name')][0],
+                    'user_full_name' => @$entry[$this->_getAttrByField('user_name')][0],
+                );            
+                // If accountStatus is blank it's the same as active
+                if (!isset($entry[$this->_getAttrByField('user_enabled')][0]) ||
+                    ($entry[$this->_getAttrByField('user_enabled')][0] == 'active')) {
+                    $grpfwds[$domain][$i]['user_enabled'] = 'active';
+                } else {
+                    // accountStatus can also be:
+                    // noaccess (receives but cannot pick up mail)
+                    // disabled (bounce incoming and deny pickup)
+                    // deleted (bounce incoming but allow pickup)
+                    $grpfwds[$domain][$i]['user_enabled'] =
+                        $entry[$this->_getAttrByField('user_enabled')][0];
+                }
+            } else {
+                $e++;
+                continue;
+            }
+            $e++;
+            $i++;
+        }
+        return $grpfwds[$domain];
+    }
+
+    /**
+     * Returns information for an email alias
+     *
+     * @param string $id  The email alias id for which to return information.
+     *
+     * @return array  The virtual email information.
+     */
+    function getAddressInfo($address, $type = 'all')
+    {
+        if ($type != 'alias') {
+            return parent::getAddressInfo($address, $type);
+        } else {
+            // FIXME: Which is faster?  A linear array search or an LDAP search?
+            // I think LDAP in this case because we can't assume the domain.
+            $filter = '(&'; // Begin filter (cumulative AND)
+            foreach ($this->_ldapparams['objectclass'] as $objectclass) {
+                // Add each objectClass from parameters
+                $filter .= '(objectClass=' . $objectclass . ')';
+            }
+            $filter .= '(mailAlternateAddress= ' . $address . ')';
+            $filter .= ')'; // End filter
+            Horde::logMessage($filter, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+            $res = @ldap_search($this->_ldap, $this->_ldapparams['basedn'], $filter);
+            if ($res === false) {
+                return PEAR::raiseError(sprintf(_("Error searching LDAP: %s"),
+                    @ldap_error($this->_ldap)));
+            }
+            $res = @ldap_get_entries($this->_ldap, $res);
+            if ($res === false) {
+                return PEAR::raiseError(sprintf(_("Error returning LDAP results: %s"), @ldap_error($this->_ldap)));
+            }
+    
+            if ($res['count'] !== 1) {
+                return PEAR::raiseError(_("More than one DN returned for this alias.  Please contact an administrator to resolve this error."));
+            }
+    
+            return array(
+                'id' => $res[0]['dn'],
+                'address' => $address,
+                'destination' => $res[0]['mail'][0],
+            );
+        }
+    }
+
+    /**
+     * Returns the current number of set up users for a domain.
+     *
+     * @param string $domain_name  The name of the domain for which to
+     *                             get the current number of users.
+     *
+     * @return integer  The current number of users.
+     */
+    function getDomainNumUsers($domain_name)
+    {
+        return count($this->_getUsers($domain_name));
+    }
+
+    /**
+     * Saves a domain to the backend.
+     *
+     * @param array $info  The domain information to save to the backend.
+     *
+     * @return mixed  True on success or PEAR error otherwise.
+     */
+    function _saveDomain(&$info)
+    {
+        // We store the records within Horde's configured SQL database for
+        // Vilma because LDAP has no mechanism for tracking domains
+        // that are valid for this system.
+        $values = array($info['name'], $info['transport'],
+                        (int)$info['max_users'], (int)$info['quota']);
+       
+        if (empty($info['domain_id'])) {
+            $nextid = $this->_db->nextId('vilma_domains');
+            $sql = 'INSERT INTO vilma_domains (domain_id, domain_name, ' .
+                   'domain_transport, domain_max_users, domain_quota) VALUES ' .
+                   '(?, ?, ?, ?, ?)';
+            array_unshift($values, $nextid);
+        } else {
+            $sql = 'UPDATE vilma_domains SET domain_name=?, ' .
+                   'domain_transport=?, domain_max_users=?, domain_quota=? ' .
+                   'WHERE domain_id=?';
+            array_push($values, $info['domain_id']);
+        }
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return $this->_db->query($sql, $values);
+    }
+
+    /**
+     * Deletes a given domain.
+     *
+     * @param string $domain_id  The id of the domain to delete.
+     *
+     * @return mixed  True on success or PEAR error otherwise.
+     */
+    function _deleteDomain($domain_id)
+    {
+        $domain_record = $this->getDomain($domain_id);
+        if (is_a($domain_record, 'PEAR_Error')) {
+            return $domain_record;
+        }
+
+        $domain_name = $domain_record['domain_name'];
+
+        // FIXME: Add logic to remove all users, aliases, and grpfwds for this
+        // domain
+
+        /* Finally delete the domain. */
+        $sql = 'DELETE FROM vilma_domains WHERE domain_id=?';
+        $values = array((int)$domain_id);
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return $this->_db->query($sql, $values);
+    }
+
+    /**
+     * Searchs for a given email account.
+     *
+     * @param string $email_id The id of the account to be searched for.
+     *
+     * @return Array of data for given email account on success or no 
+     *     information found; and for an error a PEAR::Error otherwise.
+     */
+    function searchForAliases($email_id) {
+        // Get the user's DN
+        $filter  = '(&'; // Begin filter (cumulative AND)
+        foreach ($this->_ldapparams['objectclass'] as $objectclass) {
+            // Add each objectClass from parameters
+            $filter .= '(objectClass=' . $objectclass . ')';
+        }
+        /*
+        // Check if filtering only for domain.
+        if (($pos = strpos($target, '@')) === false && !empty($email_id)) {
+            $filter .= '(mailAlternateAddress=*@' . $email_id . ')';
+        // Otherwise filter for all aliases
+        } else {
+            $filter .= '(mailAlternateAddress=*)';
+            // Restrict the results to $target
+            if (!empty($email_id)) {
+                $filter .= '(mail=' . $email_id . ')'; // Add user's email
+            }
+        }
+        */
+        $filter .= '(mailAlternateAddress=' . $email_id . ')';
+        $filter .= ')'; // End filter
+        //echo $filter;
+        Horde::logMessage($filter, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        $res = @ldap_search($this->_ldap, $this->_ldapparams['basedn'], $filter);
+        if ($res === false) {
+            return PEAR::raiseError(sprintf(_("Error searching LDAP: %s"),
+                @ldap_error($this->_ldap)));
+        }
+        $res = @ldap_get_entries($this->_ldap, $res);
+        if ($res === false) {
+            return PEAR::raiseError(sprintf(_("Error retrieving LDAP results: %s"), @ldap_error($this->_ldap)));
+        }
+
+        return $res; 
+    }
+
+    /**
+     * Searchs for a given email account.
+     *
+     * @param string $email_id The id of the account to be searched for.
+     *
+     * @return Array of data for given email account on success or no 
+     *     information found; and for an error a PEAR::Error otherwise.
+     */
+    function searchForUser($email_id)
+    {
+        // Get the user's DN
+        $filter  = '(&';
+        foreach ($this->_ldapparams['objectclass'] as $objectclass) {
+            // Add each objectClass from parameters
+            $filter .= '(objectclass=' . $objectclass . ')';
+        }
+        $filter .= '(mail=' . $email_id . '))';
+
+        Horde::logMessage($filter, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        $res = @ldap_search($this->_ldap, $this->_ldapparams['basedn'], $filter);
+        if ($res === false) {
+            return PEAR::raiseError(sprintf(_("Error searching LDAP: %s"),
+                @ldap_error($this->_ldap)));
+        }
+        $res = @ldap_get_entries($this->_ldap, $res);
+        if ($res === false) {
+            return PEAR::raiseError(sprintf(_("Error retrieving LDAP results: %s"), @ldap_error($this->_ldap)));
+        }
+
+        if ($res['count'] === 0) {
+            return PEAR::raiseError(_("Unable to acquire handle on DN.  Aborting delete operation."));
+        } else if($res['count'] !== 1) {
+            return PEAR::raiseError(_("More than one DN returned.  Aborting delete operation."));
+        } 
+        return $res; 
+    }
+
+    /**
+     * Deletes a given email account.
+     *
+     * @param string $email_id The id of the account to delete (not an alias)
+     *
+     * @return mixed True on success or PEAR::Error otherwise.
+     */
+    function deleteUser($email_id)
+    {
+        // Get the user's DN
+        $filter  = '(&';
+        foreach ($this->_ldapparams['objectclass'] as $objectclass) {
+            // Add each objectClass from parameters
+            $filter .= '(objectclass=' . $objectclass . ')';
+        }
+        $filter .= '(mail=' . $email_id . ')';
+        //echo $email_id . '<br>';
+        $filter .= ')';
+        Horde::logMessage($filter, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        $res = @ldap_search($this->_ldap, $this->_ldapparams['basedn'], $filter);
+        if ($res === false) {
+            return PEAR::raiseError(sprintf(_("Error searching LDAP: %s"),
+                @ldap_error($this->_ldap)));
+        }
+        $res = @ldap_get_entries($this->_ldap, $res);
+        if ($res === false) {
+            return PEAR::raiseError(sprintf(_("Error retrieving LDAP results: %s"), @ldap_error($this->_ldap)));
+        }
+
+        if ($res['count'] === 0) {
+            return PEAR::raiseError(_("Unable to acquire handle on DN.  Aborting delete operation."));
+        } else if($res['count'] !== 1) {
+            return PEAR::raiseError(_("More than one DN returned.  Aborting delete operation."));
+        } 
+        // We now have one unique DN to delete.
+        $res = @ldap_delete($this->_ldap, $res[0]['dn']);
+        if ($res === false) {
+            return PEAR::raiseError(sprintf(_("Error deleting account from LDAP: %s"), @ldap_error($this->_ldap)));
+        }
+
+        return true;
+    }
+
+    /**
+     * Modifies alias data on the backend.
+     *
+     * @param mixed $info     The alias, or an array containing the alias and supporting data.
+     * @param string $mode    The operation requested: add, update, delete.
+     *
+     * @return mixed  True on success or PEAR error otherwise.
+     */
+    function _savealias($info,$mode = null)
+    {
+        if ($mode == 'delete') {
+            $address = $info;
+
+            $user_info = $this->searchForAliases($address);
+            $aliasesList = $user_info[0]['mailalternateaddress'];
+            if (is_a($user_info, 'PEAR_Error') || ($res['count'] === 0) ) { 
+                return PEAR::raiseError(_("Error reading address information from backend."));
+            }
+            $addrinfo = $this->getAddressInfo($address);
+            if (is_a($addrinfo, 'PEAR_Error')) {
+                return $addrinfo;
+            }
+            $type = $addrinfo['type'];
+            $addrinfo = $this->getAddressInfo($address,$type);
+            if (is_a($addrinfo, 'PEAR_Error')) {
+                return $addrinfo;
+            }
+            $objectClassData = null;
+            if(isset($user_info[0]['objectclass'])) {
+                $objectClassData = $user_info[0]['objectclass'];
+            }
+            if ($this->_ldap) {
+                // bind with appropriate dn to give update access
+                $res = ldap_bind($this->_ldap, $this->_ldapparams['binddn'],
+                                 $this->_ldapparams['bindpw']);
+                if (!$res) {
+                    return PEAR::raiseError(_("Unable to bind to the LDAP server. Check authentication credentials."));
+                }
+                $tmp = array();
+                $key = null;
+                foreach($aliasesList as $key => $val) {
+                    if($val != $address) {
+                        array_push($tmp,$val);
+                    }
+                }
+                $entry["mailalternateaddress"] = $tmp;
+                
+                $rdn = 'mail=' . $addrinfo['destination'];
+                $dn = $rdn . ',' . $this->_ldapparams['basedn'];
+                $res = @ldap_modify($this->_ldap, $dn, $entry);
+                if ($res === false) {
+                    return PEAR::raiseError(sprintf(_("Error modifying account: %s"), @ldap_error($this->_ldap)));
+                } else {
+                    return TRUE;
+                }
+            }
+        }
+        
+        return  PEAR::raiseError(_("Unable to save user information."));
+    }
+
+    function _saveUser(&$info)
+    {
+        if ($info['mode'] == 'edit') {
+            $address = $info['address'];
+            if(!isset($address) || empty($address)) {
+                $user_name = $info['user_name'];
+                $domain = $info['domain'];
+                if(!(!isset($user_name) || empty($user_name)) && !(!isset($user_name) || empty($user_name))) {
+                    $address = $info['user_name'] . $info['domain'];
+                } else {
+                    return PEAR::raiseError(_("Unable to acquire handle on address."));
+                }
+            }
+            $addrinfo = $this->getAddressInfo($address);
+            if (is_a($addrinfo, 'PEAR_Error')) {
+                return $addrinfo;
+            }
+            $type = $addrinfo['type'];
+            if($type == 'user') {            
+                 //continue, this is a user.
+            } else {
+                 //return PEAR::raiseError(_("Unable to save account of type " . $type));
+            }
+
+            $user_info = $this->searchForUser($address);
+            if (is_a($user_info, 'PEAR_Error') || ($res['count'] === 0) ) { 
+                return PEAR::raiseError(_("Error reading address information from backend."));
+            }
+
+            $objectClassData = null;
+            if(isset($user_info[0]['objectclass'])) {
+                $objectClassData = $user_info[0]['objectclass'];
+            }
+
+            unset($info['mode']); // Don't want to save this to LDAP
+            // Special case for the password:  If it was provided, it needs
+            // to be crypted.  Otherwise, ignore it.
+            if (isset($info['password'])) {
+                if (!empty($user['password'])) {
+                    // FIXME: Allow choice of hash
+                    $info['user_password'] = Horde_Auth::getCryptedPassowrd($info['password'], '', 'ssha', true);
+                }
+                unset($info['password']);
+            }
+            
+            $tmp['dn'] = $addrinfo['id'];
+            foreach ($info as $key => $val) {
+                $attr = $this->_getAttrByField($key);
+                $tmp[$attr] = $val;
+            }
+
+            if ($this->_ldap) {
+                // bind with appropriate dn to give update access
+                $res = ldap_bind($this->_ldap, $this->_ldapparams['binddn'],
+                                 $this->_ldapparams['bindpw']);
+                if (!$res) {
+                    return PEAR::raiseError(_("Unable to bind to the LDAP server.  Check authentication credentials."));
+                }
+
+                // prepare data
+                $entry['cn'] = $info['user_full_name'];
+                // sn is not used operationally but we make an effort to be
+                // something sensical.  No guarantees, though.
+                $entry['sn'] = array_pop(explode(' ', $info['user_full_name']));
+// The next two lines were reversed:  which is right?
+                $entry['mail'] = $info['user_name'] . $info['domain'];
+                //                 $tmp['mail'];
+                $entry['uid'] = $entry['mail'];
+                $entry['homeDirectory'] = '/srv/vhost/mail/' . $info['domain'] .'/' . $info['user_name'];
+                if(($type != 'group') && ($type != 'forward')) {
+                    $entry["qmailUID"] = 8;
+                    $entry["qmailGID"] = 8;
+                }
+                $entry["accountstatus"] = $info["user_enabled"];
+                if(isset($info['password']) && !empty($info['password'])) {
+                    // FIXME: Allow choice of hash
+                    $entry["userPassword"] = Horde_Auth::getCryptedPassword($info['password'], '', 'ssha', true);
+                }
+                if(isset($objectClassData)) {
+                    array_shift($objectClassData);
+                    $entry['objectclass'] = $objectClassData;                    
+                } else {
+                    $entry['objectclass'] = array();
+                    $entry['objectclass'][] = 'top';
+                    $entry['objectclass'][] = 'person';
+                    $entry['objectclass'][] = 'organizationalPerson';
+                    $entry['objectclass'][] = 'inetOrgPerson';
+                    $entry['objectclass'][] = 'hordePerson';
+                    $entry['objectclass'][] = 'qmailUser';
+                }
+
+                // Stir in any site-local custom LDAP attributes
+                $entry = Horde::callHook('_vilma_hook_getldapattrs',
+                                         array($entry), 'vilma');
+
+                $rdn = 'mail=' . $entry['mail'];
+                $dn = $rdn . ',' . $this->_ldapparams['basedn'];
+                $res = @ldap_modify($this->_ldap, $dn, $entry);
+                if ($res === false) {
+                    return PEAR::raiseError(sprintf(_("Error modifying account: %s"), @ldap_error($this->_ldap)));
+                } else {
+                    return TRUE;
+                }
+            }
+        } else if($info['mode'] == 'new') {
+            if ($this->_ldap) {
+                // bind with appropriate dn to give update access
+                $res = ldap_bind($this->_ldap, $this->_ldapparams['binddn'],
+                                 $this->_ldapparams['bindpw']);
+                if (!$res) {
+                    return PEAR::raiseError(_("Unable to bind to the LDAP server.  Check authentication credentials."));
+                }
+
+                // prepare data
+                $entry['cn'] = $info['user_full_name'];
+                // sn is not used operationally but we make an effort to be
+                // something sensical.  No guarantees, though.
+                $entry['sn'] = array_pop(explode(' ', $info['user_full_name']));
+                $entry['mail'] = $info['user_name'] . '@' . $info['domain'];
+                // uid must match mail or SMTP auth fails
+                $entry['uid'] = $entry['mail'];
+                $entry['homeDirectory'] = '/srv/vhost/mail/' . $info['domain'] .'/' . $info['user_name'];
+                $entry['qmailUID'] = 8;
+                $entry['qmailGID'] = 8;
+                $entry['objectclass'] = array();
+                $entry['objectclass'][] = 'top';
+                $entry['objectclass'][] = 'person';
+                $entry['objectclass'][] = 'organizationalPerson';
+                $entry['objectclass'][] = 'inetOrgPerson';
+                $entry['objectclass'][] = 'hordePerson';
+                $entry['objectclass'][] = 'qmailUser';
+                $entry["accountstatus"] = $info["user_enabled"];
+                // FIXME: Allow choice of hash
+                $entry["userPassword"] = Horde_Auth::getCryptedPassword($info['password'], '', 'ssha', true);
+
+                // Stir in any site-local custom LDAP attributes
+                $entry = Horde::callHook('_vilma_hook_getldapattrs',
+                                         array($entry), 'vilma');
+
+                $rdn = 'mail=' . $entry['mail'];
+                $dn = $rdn . ',' . $this->_ldapparams['basedn'];
+                $res = @ldap_add($this->_ldap, $dn, $entry);
+                if ($res === false) {
+                    return PEAR::raiseError(sprintf(_("Error adding account to LDAP: %s"), @ldap_error($this->_ldap)));
+                } else {
+                    return TRUE;
+                }
+            } else {
+                return  PEAR::raiseError(_("Unable to connect to LDAP server"));
+            }  
+        }
+        
+        return  PEAR::raiseError(_("Unable to save user information."));
+    }
+
+    /**
+     * Deletes a virtual email.
+     *
+     * @param integer $virtual_id  The id of the virtual email to delete.
+     */
+    function deleteVirtual($virtual_id)
+    {
+        die("deleteVirtual()");
+    }
+
+    function getUserFormAttributes()
+    {
+        $attrs = array();
+        $attrs[] = array(
+            'label' => _("Account Status"),
+            'name' => 'user_enabled',
+            'type' => 'enum',
+            'required' => true,
+            'readonly' => false,
+            'description' => null,
+            'params' => array(
+                array(
+                    'active' => _("Account is active"),
+                    'noaccess' => _("Disable Delivery Only"),
+                    'disabled' => _("Bounce Incoming Only"),
+                    'deleted' => _("Account is disabled"),
+                ),
+             ),
+             'default' => 'active',
+        );
+
+        return $attrs;
+    }
+
+    function _connect()
+    {
+        if (!is_null($this->_ldap)) {
+            return true;
+        }
+
+        Horde::assertDriverConfig($this->_ldapparams, 'storage',
+            array('ldaphost', 'basedn', 'binddn', 'dn'));
+
+        if (!isset($this->_ldapparams['bindpw'])) {
+            $this->_ldapparams['bindpw'] = '';
+        }
+
+        $port = (isset($this->_ldapparams['port'])) ?
+            $this->_ldapparams['port'] : 389;
+
+        $this->_ldap = ldap_connect($this->_ldapparams['ldaphost'], $port);
+        if (!$this->_ldap) {
+            Horde::fatal("Unable to connect to LDAP server $hostname on $port",
+                         __FILE__, __LINE__);
+            }
+            $res = ldap_set_option($this->_ldap, LDAP_OPT_PROTOCOL_VERSION,
+                                   $this->_ldapparams['version']);
+        if (!$res) {
+            return PEAR::raiseError(_("Unable to set LDAP protocol version"));
+        }
+        $res = ldap_bind($this->_ldap, $this->_ldapparams['binddn'],
+                         $this->_ldapparams['bindpw']);
+        if (!$res) {
+            return PEAR::raiseError(_("Unable to bind to the LDAP server.  Check authentication credentials."));
+        }
+
+    }
+
+    /**
+     * Initialise this backend, connect to the SQL database.
+     *
+     * @return mixed  True on success or PEAR error otherwise.
+     */
+    function _dbinit()
+    {
+        global $registry;
+
+        Horde::assertDriverConfig($this->_sqlparams, 'storage',
+                                  array('phptype'));
+
+        if (!isset($this->_sqlparams['database'])) {
+            $this->_sqlparams['database'] = '';
+        }
+        if (!isset($this->_sqlparams['username'])) {
+            $this->_sqlparams['username'] = '';
+        }
+        if (!isset($this->_sqlparams['hostspec'])) {
+            $this->_sqlparams['hostspec'] = '';
+        }
+
+        /* Connect to the SQL server using the supplied parameters. */
+        require_once 'DB.php';
+        $this->_db = &DB::connect($this->_sqlparams,
+                                  array('persistent' => !empty($this->_sqlparams['persistent'])));
+        if (is_a($this->_db, 'PEAR_Error')) {
+            return $this->_db;
+        }
+
+        // Set DB portability options.
+        switch ($this->_db->phptype) {
+        case 'mssql':
+            $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM);
+            break;
+
+        default:
+            $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
+        }
+    }
+}
diff --git a/vilma/lib/Driver/sql.php b/vilma/lib/Driver/sql.php
new file mode 100644 (file)
index 0000000..e4468d0
--- /dev/null
@@ -0,0 +1,640 @@
+<?php
+/**
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * $Horde: vilma/lib/Driver/sql.php,v 1.54 2009/01/06 18:02:27 jan Exp $
+ *
+ * @author Marko Djukic <marko@oblo.com>
+ * @package Vilma
+ */
+class Vilma_Driver_sql extends Vilma_Driver {
+
+    /**
+     * @var DB
+     */
+    var $_db;
+
+    function Vilma_Driver_sql($params)
+    {
+        parent::Vilma_Driver($params);
+        $this->initialise();
+    }
+
+    /**
+     * Construct an SQL WHERE fragment to filter domains by domain key.
+     *
+     * @access private
+     *
+     * @param string $join  Keyword to join expression to rest of SQL statement
+     *                      (e.g. 'WHERE' or 'AND'). Default: 'WHERE'.
+     *
+     * @return array  An SQL fragment and a list of values suitable for
+     *                binding.
+     */
+    function _getDomainKeyFilter($join = 'WHERE')
+    {
+        if (empty($this->_params['tables']['domainkey'])) {
+            return array('', array());
+        }
+
+        return array(' ' . $join . ' domain_key = ?',
+                     array($this->_params['tables']['domainkey']));
+    }
+
+    /**
+     * Construct an SQL WHERE fragment to filter users by domain key.
+     *
+     * @access private
+     *
+     * @param string $join  Keyword to join expression to rest of SQL statement
+     *                      (e.g. 'WHERE' or 'AND'). Default: 'WHERE'.
+     *
+     * @return array  An SQL fragment and a list of values suitable for
+     *                binding.
+     */
+    function _getUserKeyFilter($join = 'WHERE')
+    {
+        if (empty($this->_params['tables']['domainkey'])) {
+            return array('', array());
+        }
+        $binds = $this->_getDomainKeyFilter('AND');
+
+        return array(' ' . $join . ' EXISTS (SELECT domain_name' .
+                     ' FROM ' . $this->_params['tables']['domains'] .
+                     ' WHERE ' . $this->_getTableField('users', 'user_name') .
+                     ' LIKE ? || ' . $this->_getTableField('domains', 'domain_name') .
+                     ' ' . $binds[0] . ' )',
+                     array_unshift($binds[1], '%@'));
+    }
+
+    /**
+     * Construct an SQL WHERE fragment to filter virtuals by domain key.
+     *
+     * @access private
+     *
+     * @param string $join  Keyword to join expression to rest of SQL statement
+     *                      (e.g. 'WHERE' or 'AND').  Default: 'WHERE'.
+     *
+     * @return string  An SQL fragment.
+     */
+    function _getVirtualKeyFilter($join = 'WHERE')
+    {
+        if (empty($this->_params['tables']['domainkey'])) {
+            return array('', array());
+        }
+        $binds = $this->_getDomainKeyFilter('AND');
+
+        return array(' ' . $join . ' EXISTS (SELECT domain_name' .
+                     ' FROM ' . $this->_params['tables']['domains'] .
+                     ' WHERE ' . $this->_getTableField('virtuals', 'virtual_email') .
+                     ' LIKE ? || ' . $this->_getTableField('domains', 'domain_name') .
+                     ' ' . $binds[0] . ' )',
+                     array_unshift($binds[1], '%@'));
+    }
+
+    /**
+     * Gets the list of fields from specific table for sql statement.
+     *
+     * @return string
+     */
+    function _getTableFields($table)
+    {
+        if (empty($this->_params['tables'][$table . '_fields'])){
+            return '*';
+        }
+
+        $domainsFields = $this->_params['tables'][$table . '_fields'];
+        foreach ($domainsFields as $defaultName => $customName) {
+            $fields[] = $customName . ' as ' . $defaultName;
+        }
+        return implode(', ', $fields);
+    }
+
+    /**
+     * Gets the real name of the field from specific table for sql statement.
+     *
+     * @return string
+     */
+    function _getTableField($table, $field)
+    {
+        if (empty($this->_params['tables'][$table . '_fields'])) {
+            return $field;
+        } else {
+            return $this->_params['tables'][$table . '_fields'][$field];
+        }
+    }
+
+    /**
+     *
+     *
+     * @return array
+     */
+    function _prepareRecord($table, $record)
+    {
+        if (empty($this->_params['tables'][$table . '_fields'])){
+            return $record;
+        }
+
+        $domainsFields = $this->_params['tables'][$table . '_fields'];
+        $newRecord = array();
+        foreach ($record as $defaultName => $value) {
+            $newRecord[$domainsFields[$defaultName]] = $record[$defaultName];
+        }
+        return $newRecord;
+    }
+
+    /**
+     * Gets the list of domains from the backend.
+     *
+     * @return array  All the domains and their data in an array.
+     */
+    function getDomains()
+    {
+        $binds = $this->_getDomainKeyFilter();
+        $sql = 'SELECT '. $this->_getTableFields('domains') . ' FROM ' . $this->_params['tables']['domains'] .
+               $binds[0] . ' ORDER BY domain_name';
+        $values = $binds[1];
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return $this->_db->getAll($sql, $values, DB_FETCHMODE_ASSOC);
+    }
+
+    /**
+     * Gets the specified domain information from the backend.
+     *
+     * @param integer $domain_id  The id of the domain to fetch.
+     *
+     * @return array  The domain's information in an array.
+     */
+    function getDomain($domain_id)
+    {
+        $binds = $this->_getDomainKeyFilter('AND');
+        $sql = 'SELECT '. $this->_getTableFields('domains') . ' FROM ' . $this->_params['tables']['domains'] .
+               ' WHERE ' . $this->_getTableField('domains', 'domain_id') . ' = ?' . $binds[0];
+        array_unshift($binds[1], (int)$domain_id);
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return $this->_db->getRow($sql, $binds[1], DB_FETCHMODE_ASSOC);
+    }
+
+    /**
+     * Given a domain name returns the information from the backend.
+     *
+     * @param string $name  The name of the domain to fetch.
+     *
+     * @return array  The domain's information in an array.
+     */
+    function getDomainByName($domain_name)
+    {
+        $binds = $this->_getDomainKeyFilter('AND');
+        $sql = 'SELECT '. $this->_getTableFields('domains') . ' FROM ' . $this->_params['tables']['domains'] .
+               ' WHERE ' . $this->_getTableField('domains', 'domain_name') . ' = ?' . $binds[0];
+        array_unshift($binds[1], $domain_name);
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return $this->_db->getRow($sql, $binds[1], DB_FETCHMODE_ASSOC);
+    }
+
+    /**
+     * Returns all available users, if a domain name is passed then limit the
+     * list of users only to those users.
+     *
+     * @param string $domain  The name of the domain for which to fetch the
+     *                        users.
+     *
+     * @return array  The available users and their stored information.
+     */
+    function getUsers($domain = null)
+    {
+        /* Put together the SQL statement. */
+        if (is_null($domain)) {
+            /* Fetch all users. */
+            $binds = $this->_getUserKeyFilter();
+            $sql = 'SELECT '. $this->_getTableFields('users') . ' FROM ' . $this->_params['tables']['users'] .
+                   $binds[0];
+            $values = $binds[1];
+        } else {
+            /* Fetch only users for a domain. */
+            $binds = $this->_getUserKeyFilter('AND');
+            $sql = 'SELECT '. $this->_getTableFields('users') . ' FROM ' . $this->_params['tables']['users'] .
+                   ' WHERE ' . $this->_getTableField('users', 'user_name') . ' LIKE ?' . $binds[0] .
+                   ' ORDER BY user_name';
+            array_unshift($binds[1], '%@' . $domain);
+            $values = $binds[1];
+        }
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return $this->_db->getAll($sql, $values, DB_FETCHMODE_ASSOC);
+    }
+
+    /**
+     * Returns the user information for a given user id.
+     *
+     * @param integer $user_id  The id of the user for which to fetch
+     *                          information.
+     *
+     * @return array  The user information.
+     */
+    function getUser($user_id)
+    {
+        $binds = $this->_getUserKeyFilter('AND');
+        $sql = 'SELECT '. $this->_getTableFields('users') . ' FROM ' . $this->_params['tables']['users'] .
+               ' WHERE ' . $this->_getTableField('users', 'user_id') . ' = ?' . $binds[0];
+        array_unshift($binds[1], (int)$user_id);
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return $this->_db->getRow($sql, $binds[1], DB_FETCHMODE_ASSOC);
+    }
+
+    /**
+     * Returns available virtual emails.
+     *
+     * @param string $filter  If passed a domain then return all virtual emails
+     *                        for the domain, otherwise if passed a user name
+     *                        return all virtual emails for that user.
+     *
+     * @return array  The available virtual emails.
+     */
+    function getVirtuals($filter)
+    {
+        /* Check if filtering only for domain. */
+        if (($pos = strpos($filter, '@')) === false) {
+            $where = $this->_getTableField('virtuals', 'virtual_email') . ' LIKE ?';
+            $values = array('%@' . $filter);
+        } else {
+            $where = $this->_getTableField('virtuals', 'virtual_destination') . ' = ?';
+            $values = array($filter);
+        }
+
+        $binds = $this->_getVirtualKeyFilter('AND');
+        $sql = 'SELECT '. $this->_getTableFields('virtuals') . ' FROM ' . $this->_params['tables']['virtuals'] .
+               ' WHERE ' . $where . $binds[0] .
+               ' ORDER BY virtual_destination, virtual_email';
+        $values = array_merge($values, $binds[1]);
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return $this->_db->getAll($sql, $values, DB_FETCHMODE_ASSOC);
+    }
+
+    /**
+     * Returns information for a virtual id.
+     *
+     * @param integer $virtual_id  The virtual id for which to return
+     *                             information.
+     *
+     * @return array  The virtual email information.
+     */
+    function getVirtual($virtual_id)
+    {
+        $binds = $this->_getVirtualKeyFilter('AND');
+        $sql = 'SELECT '. $this->_getTableFields('virtuals') . ' FROM ' . $this->_params['tables']['virtuals'] .
+               ' WHERE ' . $this->_getTableField('virtuals', 'virtual_id') . ' = ?' . $binds[0];
+        array_unshift($binds[1], (int)$virtual_id);
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        $virtual = $this->_db->getRow($sql, $binds[1], DB_FETCHMODE_ASSOC);
+        $virtual['stripped_email'] = Vilma::stripUser($virtual['virtual_email']);
+
+        return $virtual;
+    }
+
+    /**
+     * Returns the current number of set up users for a domain.
+     *
+     * @param string $domain_name  The name of the domain for which to
+     *                             get the current number of users.
+     *
+     * @return integer  The current number of users.
+     */
+    function getDomainNumUsers($domain_name)
+    {
+        $binds = $this->_getUserKeyFilter('AND');
+        $sql = 'SELECT count(' . $this->_getTableField('users', 'user_name') . ')' .
+               ' FROM ' . $this->_params['tables']['users'] .
+               ' WHERE ' . $this->_getTableField('users', 'user_name') . ' LIKE ?' . $binds[0];
+        array_unshift($binds[1], '%@' . $domain_name);
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return $this->_db->getOne($sql, $binds[1]);
+    }
+
+    /**
+     * Saves a domain to the backend.
+     *
+     * @param array $info  The domain information to save to the backend.
+     *
+     * @return mixed  True on success or PEAR error otherwise.
+     */
+    function _saveDomain($info)
+    {
+        require_once 'Horde/SQL.php';
+
+        $record = array('domain_name' => $info['name'],
+                        'domain_transport' => $info['transport'],
+                        'domain_max_users' => (int)$info['max_users'],
+                        'domain_quota' => (int)$info['quota']);
+
+        if (empty($info['domain_id'])) {
+            $record['domain_id'] = $this->_db->nextId($this->_params['tables']['domains']);
+            if (!empty($this->_params['tables']['domainkey'])) {
+                $record['domain_key'] = $this->_params['tables']['domainkey'];
+            }
+
+            $sql = 'INSERT INTO ' . $this->_params['tables']['domains'] .
+                ' ' . Horde_SQL::insertValues($this->_db, $this->_prepareRecord('domains', $record));
+            $values = array();
+        } else {
+            $binds = $this->_getDomainKeyFilter('AND');
+            $sql = 'UPDATE ' . $this->_params['tables']['domains'] .
+                   ' SET ' . Horde_SQL::updateValues($this->_db, $this->_prepareRecord('domains', $record)) .
+                   ' WHERE ' . $this->_getTableField('domains', 'domain_id') . ' = ?' . $binds[0];
+            array_unshift($binds[1], $info['domain_id']);
+            $values = $binds[1];
+        }
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return $this->_db->query($sql, $values);
+    }
+
+    /**
+     * Deletes a given domain.
+     *
+     * @param integer $domain_id  The id of the domain to delete.
+     *
+     * @return mixed  True on success or PEAR error otherwise.
+     */
+    function _deleteDomain($domain_id)
+    {
+        $domain_record = $this->getDomain($domain_id);
+        if (is_a($domain_record, 'PEAR_Error')) {
+            return $domain_record;
+        }
+
+        $domain_name = $domain_record['domain_name'];
+
+        /* Delete all virtual emails for this domain. */
+        $sql = 'DELETE FROM ' . $this->_params['tables']['virtuals'] .
+               ' WHERE ' . $this->_getTableField('virtuals', 'virtual_email') . ' LIKE ?';
+        $values = array('%@' . $domain_name);
+        $delete = $this->_db->query($sql, $values);
+        if (is_a($delete, 'PEAR_Error')) {
+            return $delete;
+        }
+
+        /* Delete all users for this domain. */
+        $sql = 'DELETE FROM ' . $this->_params['tables']['users'] .
+               ' WHERE ' . $this->_getTableField('users', 'user_name') . ' LIKE ?';
+        $values = array('%@' . $domain_name);
+        $delete = $this->_db->query($sql, $values);
+        if (is_a($delete, 'PEAR_Error')) {
+            return $delete;
+        }
+
+        /* Finally delete the domain. */
+        $sql = 'DELETE FROM ' . $this->_params['tables']['domains'] .
+               ' WHERE ' . $this->_getTableField('domains', 'domain_id') . ' = ?';
+        $values = array((int)$domain_id);
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return $this->_db->query($sql, $values);
+    }
+
+    /**
+     * Saves a user to the backend.
+     *
+     * @param array $info  The user information to save.
+     *
+     * @return array  The user information.
+     */
+    function _saveUser($info)
+    {
+        global $conf;
+
+        require_once 'Horde/SQL.php';
+
+        /* Access check (for domainkey). */
+        $res = $this->getDomainByName(Vilma::stripDomain($info['user_name']));
+        if (is_a($res, 'PEAR_Error')) {
+            return $res;
+        }
+
+        $mailboxes = &Vilma::getMailboxDriver();
+        if (is_a($mailboxes, 'PEAR_Error')) {
+            return $mailboxes;
+        }
+
+        if (empty($info['user_id'])) {
+            $info['user_id'] = $this->_db->nextId($this->_params['tables']['users']);
+            $create = true;
+        } else {
+            $create = false;
+        }
+
+        // Slightly hackish.
+        $mail_dir_base = isset($mailboxes->_params['mail_dir_base']) ?
+                         $mailboxes->_params['mail_dir_base'] : '?';
+
+        $tuple = array('user_id' =>         (int)$info['user_id'],
+                       'user_name' =>       $info['user_name'],
+                       'user_full_name' =>  $info['user_full_name'],
+                       'user_home_dir' =>   $mail_dir_base,
+                       'user_mail_dir' =>   Vilma::stripDomain($info['user_name']) . '/' . Vilma::stripUser($info['user_name']) . '/',
+                       'user_mail_quota' => $this->getDomainQuota(Vilma::stripDomain($info['user_name'])) * 1024 * 1024,
+                       'user_enabled' =>    (int)$info['user_enabled']);
+
+        // UID and GID are slightly hackish (specific to maildrop driver), too
+        if (!isset($mailboxes->_params['uid'])) {
+            $tuple['user_uid'] = -1;
+        } else {
+            $tuple['user_uid'] = $mailboxes->_params['uid'];
+        }
+        if (!isset($mailboxes->_params['gid'])) {
+            $tuple['user_gid'] = -1;
+        } else {
+            $tuple['user_gid'] = $mailboxes->_params['gid'];
+        }
+
+        if (!empty($info['password'])) {
+            $tuple['user_clear'] = $info['password'];
+            $tuple['user_crypt'] = crypt($info['password'],
+                                         substr($info['password'], 0, 2));
+        } elseif ($create) {
+            return PEAR::raiseError(_("Password must be supplied when creating a new user."));
+        }
+
+        if ($create) {
+            $sql = 'INSERT INTO ' .
+                $this->_params['tables']['users'] . ' ' .
+                Horde_SQL::insertValues($this->_db, $this->_prepareRecord('users', $tuple));
+        } else {
+            $sql = sprintf('UPDATE %s SET %s WHERE ' . $this->_getTableField('users', 'user_id') . ' = %d',
+                           $this->_params['tables']['users'],
+                           Horde_SQL::updateValues($this->_db, $this->_prepareRecord('users', $tuple)),
+                           (int)$info['user_id']);
+        }
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        $result = $this->_db->query($sql);
+        if (is_a($result, 'PEAR_Error')) {
+            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
+            return $result;
+        }
+
+        return $info;
+    }
+
+    /**
+     * Deletes a requested user.
+     *
+     * @param integer $user_id  The id of the user to delete.
+     *
+     * @return mixed  True, or PEAR_Error on failure.
+     */
+    function _deleteUser($user_id)
+    {
+        $user = $this->getUser($user_id);
+        if (is_a($user, 'PEAR_Error')) {
+            return $user;
+        }
+
+        /* Delete all virtual emails for this user. */
+        $sql = 'DELETE FROM ' . $this->_params['tables']['virtuals'] .
+               ' WHERE ' . $this->_getTableField('virtuals', 'virtual_destination') . ' = ?';
+        $values = array($user['user_name']);
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        $delete = $this->_db->query($sql, $values);
+        if (is_a($delete, 'PEAR_Error')) {
+            return $delete;
+        }
+
+        /* Delete the actual user. */
+        $sql = 'DELETE FROM ' . $this->_params['tables']['users'] .
+               ' WHERE ' . $this->_getTableField('users', 'user_id') . ' = ?';
+        $values = array((int)$user_id);
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        $result = $this->_db->query($sql, $values);
+        if (is_a($result, 'PEAR_Error')) {
+            return $result;
+        }
+
+        $mailboxes = &Vilma::getMailboxDriver();
+        if (is_a($mailboxes, 'PEAR_Error')) {
+            return $mailboxes;
+        }
+
+        return $mailboxes->deleteMailbox(Vilma::stripUser($user['user_name']),
+                                         Vilma::stripDomain($user['user_name']));
+    }
+
+    /**
+     * Saves virtual email address to the backend.
+     *
+     * @param array $info     The virtual email data.
+     * @param string $domain  The name of the domain for this virtual email.
+     *
+     * @return mixed  True on success or PEAR error otherwise.
+     */
+    function saveVirtual(&$info, $domain)
+    {
+        /* Access check (for domainkey) */
+        $res = $this->getDomainByName($domain);
+        if (is_a($res, 'PEAR_Error')) {
+            return $res;
+        }
+
+        if (empty($info['virtual_id'])) {
+            $info['virtual_id'] = $this->_db->nextId($this->_params['tables']['virtuals']);
+            $sql = 'INSERT INTO ' . $this->_params['tables']['virtuals'] .
+                ' (' . $this->_getTableField('virtuals', 'virtual_email') . ', ' .
+                       $this->_getTableField('virtuals', 'virtual_destination') . ', ' .
+                       $this->_getTableField('virtuals', 'virtual_id') . ') VALUES (?, ?, ?)';
+        } else {
+            $sql = 'UPDATE ' . $this->_params['tables']['virtuals'] .
+                ' SET ' . $this->_getTableField('virtuals', 'virtual_email') . ' = ?, '.
+                          $this->_getTableField('virtuals', 'virtual_destination') . ' = ?' .
+                ' WHERE ' . $this->_getTableField('virtuals', 'virtual_id') . ' = ?';
+        }
+        $values = array($info['stripped_email'] . '@' . $domain,
+                        $info['virtual_destination'],
+                        $info['virtual_id']);
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return $this->_db->query($sql, $values);
+    }
+
+    /**
+     * Deletes a virtual email.
+     *
+     * @param integer $virtual_id  The id of the virtual email to delete.
+     */
+    function deleteVirtual($virtual_id)
+    {
+        $binds = $this->_getVirtualKeyFilter('AND');
+        $sql = 'DELETE FROM ' . $this->_params['tables']['virtuals'] .
+               ' WHERE ' . $this->_getTableField('virtuals', 'virtual_id') . ' = ?' . $binds[0];
+        array_unshift($binds[1], $virtual_id);
+
+        Horde::logMessage($sql, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        return $this->_db->query($sql, $binds[1]);
+    }
+
+    /**
+     * Initialise this backend, connect to the SQL database.
+     *
+     * @return mixed  True on success or PEAR error otherwise.
+     */
+    function initialise()
+    {
+        global $registry;
+
+        Horde::assertDriverConfig($this->_params, 'storage',
+            array('phptype'));
+
+        if (!isset($this->_params['database'])) {
+            $this->_params['database'] = '';
+        }
+        if (!isset($this->_params['username'])) {
+            $this->_params['username'] = '';
+        }
+        if (!isset($this->_params['hostspec'])) {
+            $this->_params['hostspec'] = '';
+        }
+
+        /* Use default table names if these are not set. */
+        if (!isset($this->_params['tables']['domains'])) {
+            $this->_params['tables']['domains'] = 'vilma_domains';
+        }
+        if (!isset($this->_params['tables']['users'])) {
+            $this->_params['tables']['users'] = 'vilma_users';
+        }
+        if (!isset($this->_params['tables']['virtuals'])) {
+            $this->_params['tables']['virtuals'] = 'vilma_virtuals';
+        }
+
+        /* Connect to the SQL server using the supplied parameters. */
+        require_once 'DB.php';
+        $this->_db = &DB::connect($this->_params,
+                                  array('persistent' => !empty($this->_params['persistent'])));
+        if (is_a($this->_db, 'PEAR_Error')) {
+            return $this->_db;
+        }
+
+        // Set DB portability options.
+        switch ($this->_db->phptype) {
+        case 'mssql':
+            $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM);
+            break;
+
+        default:
+            $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
+        }
+
+        return true;
+    }
+
+}
diff --git a/vilma/lib/Forms/DeleteDomainForm.php b/vilma/lib/Forms/DeleteDomainForm.php
new file mode 100644 (file)
index 0000000..4601cce
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Copyright 2006-2007 Alkaloid Networks <http://www.alkaloid.net>
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * $Horde: vilma/lib/Forms/DeleteDomainForm.php,v 1.1 2008/03/12 02:52:34 bklang Exp $
+ *
+ * @author  Ben Klang <ben@alkaloid.net>
+ * @package Vilma
+ */
+class DeleteDomainForm extends Horde_Form {
+
+    function DeleteDomainForm(&$vars)
+    {
+        parent::Horde_Form($vars, _("Delete Domain"));
+
+        $domain_record = $GLOBALS['vilma_driver']->getDomain($vars->get('domain_id'));
+        if (is_a($domain_record, 'PEAR_Error')) {
+            return $domain_record;
+        }
+
+        $domain = $domain_record['domain_name'];
+        
+        /* Set up the form. */
+        $this->setButtons(array(_("Delete"), _("Do not delete")));
+        $this->addHidden('', 'domain_id', 'text', false);
+        $this->addVariable(sprintf(_("Delete domain \"%s\" and all associated email addresses?"), $domain), 'description', 'description', false);
+    }
+}
diff --git a/vilma/lib/Forms/EditDomainForm.php b/vilma/lib/Forms/EditDomainForm.php
new file mode 100644 (file)
index 0000000..79fccba
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Copyright 2006-2007 Alkaloid Networks <http://www.alkaloid.net>
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * $Horde: vilma/lib/Forms/EditDomainForm.php,v 1.10 2009/07/14 18:43:46 selsky Exp $
+ *
+ * @author  Ben Klang <ben@alkaloid.net>
+ * @package Vilma
+ */
+
+class EditDomainForm extends Horde_Form {
+
+    function EditDomainForm(&$vars)
+    {
+        /* Check if a form is being edited. */
+        $editing = $vars->exists('domain_id');
+        $domain = $_SESSION['vilma']['domain'];
+        parent::Horde_Form($vars, $editing ? _("Edit Domain") : _("New Domain"));
+        if ($editing && !$this->isSubmitted()) {
+            $domain = $GLOBALS['vilma_driver']->getDomain($vars->get('domain_id'));
+            if (is_a($domain, 'PEAR_Error')) {
+                return $domain;
+            }
+            $vars = new Horde_Variables($domain);
+        }
+        $vars->add('name', $domain['domain_name']);
+        $vars->add('transport', $domain['domain_transport']);
+        $vars->add('max_users', $domain['domain_max_users']);
+        $vars->add('quota', $domain['domain_quota']);
+        /* Set up the form. */
+        $this->setButtons(true, true);
+        $this->addHidden('', 'domain_id', 'text', false);
+        $this->addVariable(_("Domain"), 'name', 'text', true);
+        require_once 'Horde/Array.php';
+        $this->addVariable(_("Transport"), 'transport', 'enum', false, false, null, array(Horde_Array::valuesToKeys($GLOBALS['conf']['mta']['transports'])));
+        $this->addVariable(_("Max users"), 'max_users', 'int', false);
+        $this->addVariable(_("Quota"), 'quota', 'int', false, false, _("Value in MB"));
+    }
+
+}
diff --git a/vilma/lib/Forms/EditUserForm.php b/vilma/lib/Forms/EditUserForm.php
new file mode 100644 (file)
index 0000000..6579252
--- /dev/null
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Copyright 2006-2007 Alkaloid Networks <http://www.alkaloid.net>
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * $Horde: vilma/lib/Forms/EditUserForm.php,v 1.6 2009/05/27 23:57:32 bklang Exp $
+ *
+ * @author  Ben Klang <ben@alkaloid.net>
+ * @package Vilma
+ */
+
+class EditUserForm extends Horde_Form {
+
+    function EditUserForm(&$vars)
+    {
+        global $vilma_driver;
+
+        $type = $vars->get('type');
+        $editing = ($vars->get('mode') == 'edit');
+        if ($editing) {
+            if($type == 'group') {
+                $title = sprintf(_("Edit Group for \"%s\""), $vars->get('domain'));
+            } else if($type == 'forward') {
+                $title = sprintf(_("Edit Forward for \"%s\""), $vars->get('domain'));
+            } else {
+                $title = sprintf(_("Edit User for \"%s\""), $vars->get('domain'));
+            }
+        } else {
+            $title = sprintf(_("New User @%s"), $vars->get('domain'));
+        }
+        parent::Horde_Form($vars, $title);
+
+        /* Set up the form. */
+        $this->setButtons(true, true);
+        $this->addHidden('', 'address', 'text', false);
+        $this->addHidden('', 'mode', 'text', false);
+        $this->addHidden('', 'domain', 'text', false);
+        $this->addHidden('', 'id', 'text', false);
+        if ($editing) {
+            $this->addHidden('', 'user_name', 'text', false);
+        }
+        $name = "User Name";
+        $type = $vars->get('type');
+        if($type == 'group') {
+            $name = "Group Name";
+        } else if($type == 'forward') {
+            $name = "Forward Name";
+        }
+        $this->addVariable(_($name), 'user_name', 'text', true, $editing, _("Name must begin with an alphanumeric character, must contain only alphanumeric and '._-' characters, and must end with an alphanumeric character."), array('~^[a-zA-Z0-9]{1,1}[a-zA-Z0-9._-]*[a-zA-Z0-9]$~'));
+        if ($editing) {
+            $this->addVariable(_("Password"), 'password', 'passwordconfirm', false, false, _("Only enter a password if you wish to change this user's password"));
+        } else {
+            $this->addVariable(_("Password"), 'password', 'passwordconfirm', true);
+        }
+        $this->addVariable(_("Full Name"), 'user_full_name', 'text', true);
+        $attrs = $vilma_driver->getUserFormAttributes();
+        foreach ($attrs as $attr) {
+            $v = &$this->addVariable($attr['label'], $attr['name'],
+                                $attr['type'], $attr['required'],
+                                $attr['readonly'], $attr['description'],
+                                $attr['params']);
+
+            if (!isset($attr['default'])) {
+                $v->setDefault($attr['default']);
+            }
+        }
+        //$this->addVariable(_("Target(s)"), 'target', 'text', false);
+    }
+
+}
diff --git a/vilma/lib/MailboxDriver.php b/vilma/lib/MailboxDriver.php
new file mode 100644 (file)
index 0000000..dff110e
--- /dev/null
@@ -0,0 +1,110 @@
+<?php
+/**
+ * Copyright 2004-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * $Horde: vilma/lib/MailboxDriver.php,v 1.15 2009/01/06 18:02:27 jan Exp $
+ *
+ * @author  Jason M. Felice <jason.m.felice@gmail.com>
+ * @package Vilma
+ */
+class Vilma_MailboxDriver {
+
+    var $_params;
+
+    /**
+     * Constructor.
+     *
+     * @access private
+     */
+    function Vilma_MailboxDriver($params = array())
+    {
+        $this->_params = $params;
+    }
+
+    /**
+     * Creates a new mailbox driver instance.
+     *
+     * @param string $driver  The name of the driver to create an instance of.
+     * @param array $params   Driver-specific parameters.
+     *
+     * @return Vilma_MailboxDriver  The new driver instance or a PEAR_Error.
+     */
+    function &factory($driver, $params = array())
+    {
+        require_once VILMA_BASE . '/lib/MailboxDriver/' . $driver . '.php';
+        $class = 'Vilma_MailboxDriver_' . $driver;
+        $mailbox = &new $class($params);
+        return $mailbox;
+    }
+
+    /**
+     * Returns a mailbox driver instance with the specified params, creating
+     * it if necessary.
+     *
+     * @param string $driver  The name of the driver to create an instance of.
+     * @param array $params   Driver-specific parameters.
+     *
+     * @return Vilma_MailboxDriver  The new driver instance or a PEAR_Error.
+     */
+    function &singleton($driver, $params = array())
+    {
+        static $cache;
+        $key = serialize(array($driver, $params));
+        if (!isset($cache[$key])) {
+            $ret = &Vilma_MailboxDriver::factory($driver, $params);
+            if (is_a($ret, 'PEAR_Error')) {
+                return $ret;
+            }
+            $cache[$key] = &$ret;
+        }
+        return $cache[$key];
+    }
+
+    /**
+     * Creates a new mailbox.
+     *
+     * This default implementation only returns an error.
+     *
+     * @param string $user    The name of the mailbox to create
+     * @param string $domain  The name of the domain in which to create the
+     *                        mailbox
+     * @return mixed  True or PEAR_Error:: instance.
+     */
+    function createMailbox($user, $domain)
+    {
+        return PEAR::raiseError(_("This driver cannot create mailboxes."));
+    }
+
+    /**
+     * Deletes an existing mailbox.
+     *
+     * This default implementation only returns an error.
+     *
+     * @param string $user    The name of the mailbox to delete
+     * @param string $domain  The name of the domain in which to delete the
+     *                        mailbox
+     *
+     * @return mixed  True or PEAR_Error:: instance.
+     */
+    function deleteMailbox($user, $domain)
+    {
+        return PEAR::raiseError(_("This driver cannot delete mailboxes."));
+    }
+
+    /**
+     * Checks whether a mailbox exists and is set up properly.
+     *
+     * @param string $user    The name of the mailbox to check
+     * @param string $domain  The mailbox's domain
+     *
+     * @return mixed  True or PEAR_Error:: instance.
+     */
+    function checkMailbox($user, $domain)
+    {
+        return true;
+    }
+
+}
diff --git a/vilma/lib/MailboxDriver/hooks.php b/vilma/lib/MailboxDriver/hooks.php
new file mode 100644 (file)
index 0000000..253fe8c
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Copyright 2006-2007 Alkaloid Networks <http://www.alkaloid.net/>
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * $Horde: vilma/lib/MailboxDriver/hooks.php,v 1.7 2007/09/10 22:28:57 jan Exp $
+ *
+ * @author  Ben Klang <bklang@alkaloid.net>
+ * @package Vilma
+ */
+
+class Vilma_MailboxDriver_hooks extends Vilma_MailboxDriver {
+
+    function Vilma_MailboxDriver_hooks($params)
+    {
+        Horde::loadConfiguration('hooks.php', null, 'vilma');
+    }
+
+
+    function checkMailbox($user, $domain)
+    {
+        if (function_exists('_vilma_hook_checkMailbox')) {
+            return call_user_func('_vilma_hook_checkMailbox', $user, $domain);
+        } else {
+            return true;
+        }
+    }
+
+    function createMailbox($user, $domain)
+    {
+        if (function_exists('_vilma_hook_createMailbox')) {
+            return call_user_func('_vilma_hook_createMailbox', $user, $domain);
+        } else {
+            return true;
+        }
+    }
+
+    function deleteMailbox($user, $domain)
+    {
+        if (function_exists('_vilma_hook_deleteMailbox')) {
+            return call_user_func('_vilma_hook_deleteMailbox', $user, $domain);
+        } else {
+            return true;
+        }
+    }
+
+}
diff --git a/vilma/lib/MailboxDriver/imap.php b/vilma/lib/MailboxDriver/imap.php
new file mode 100644 (file)
index 0000000..e7ada11
--- /dev/null
@@ -0,0 +1,81 @@
+<?php
+/**
+ * Copyright 2004-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * $Horde: vilma/lib/MailboxDriver/imap.php,v 1.12 2009/01/06 18:02:28 jan Exp $
+ *
+ * @author  Jason M. Felice <jason.m.felice@gmail.com>
+ * @package Vilma
+ */
+class Vilma_MailboxDriver_imap extends Vilma_MailboxDriver {
+
+    var $_imapAdmin = null;
+
+    function _connect()
+    {
+        if (!is_null($this->_imapAdmin)) {
+            return false;
+        }
+
+        // Catch c-client errors.
+        register_shutdown_function('imap_errors');
+        register_shutdown_function('imap_alerts');
+
+        require_once 'Horde/IMAP/Admin.php';
+        $admin = &new IMAP_Admin($this->_params);
+        if (is_a($admin, 'PEAR_Error')) {
+            return $admin;
+        }
+
+        $this->_imapAdmin = $admin;
+        return true;
+    }
+
+    function checkMailbox($user, $domain)
+    {
+        $res = $this->_connect();
+        if (is_a($res, 'PEAR_Error')) {
+            return $res;
+        }
+
+        if (!$this->_imapAdmin->mailboxExists($user . '@' . $domain)) {
+            return PEAR::raiseError(sprintf(_("Mailbox '%s@%s' does not exist."), $user, $domain));
+        }
+    }
+
+    function createMailbox($user, $domain)
+    {
+        $res = $this->_connect();
+        if (is_a($res, 'PEAR_Error')) {
+            return $res;
+        }
+
+        $mbox = $user . '@' . $domain;
+
+        $res = $this->_imapAdmin->addMailbox($mbox);
+        if (is_a($res, 'PEAR_Error')) {
+            return $res;
+        }
+
+        return true;
+    }
+
+    function deleteMailbox($user, $domain)
+    {
+        $res = $this->_connect();
+        if (is_a($res, 'PEAR_Error')) {
+            return $res;
+        }
+
+        $res = $this->_imapAdmin->removeMailbox($user . '@' . $domain);
+        if (is_a($res, 'PEAR_Error')) {
+            return $res;
+        }
+
+        return true;
+    }
+
+}
diff --git a/vilma/lib/MailboxDriver/maildrop.php b/vilma/lib/MailboxDriver/maildrop.php
new file mode 100644 (file)
index 0000000..b9e557c
--- /dev/null
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Copyright 2004-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * $Horde: vilma/lib/MailboxDriver/maildrop.php,v 1.17 2009/05/27 23:57:32 bklang Exp $
+ *
+ * @author  Jason M. Felice <jason.m.felice@gmail.com>
+ * @package Vilma
+ */
+class Vilma_MailboxDriver_maildrop extends Vilma_MailboxDriver {
+
+    function _getMailboxDir($user, $domain)
+    {
+        if (empty($this->_params['mail_dir_base'])) {
+            require_once 'PEAR.php';
+            return PEAR::raiseError(_("No 'mail_dir_base' parameter specified to maildrop driver."));
+        }
+        $dir = $this->_params['mail_dir_base'];
+        $usedomain = isset($this->_params['usedomain']) ? $this->_params['usedomain'] : false;
+        if ($usedomain) {
+            $dir .= '/' . $domain;
+        }
+
+        return $dir . '/' . $user;
+    }
+
+    function checkMailbox($user, $domain)
+    {
+        static $exists;
+
+        $dir = $this->_getMailboxDir($user, $domain);
+        if (is_a($dir, 'PEAR_Error')) {
+            return $dir;
+        }
+
+        if (!isset($exists[$dir])) {
+            $exists[$dir] = is_dir($dir);
+        }
+
+        if (!$exists[$dir]) {
+            require_once 'PEAR.php';
+            return PEAR::raiseError(sprintf(_("Maildrop directory \"%s\" does not exist."), $dir));
+        }
+
+        return true;
+    }
+
+    function createMailbox($user, $domain)
+    {
+        $dir = $this->_getMailboxDir($user, $domain);
+        if (is_a($dir, 'PEAR_Error')) {
+            return $dir;
+        }
+        if (empty($this->_params['system_user'])) {
+            require_once 'PEAR.php';
+            return PEAR::raiseError(_("No 'system_user' parameter specified to maildrop driver."));
+        }
+
+        $create_function = sprintf('sudo -u %s maildirmake %s',
+                                   escapeshellarg($this->_params['system_user']),
+                                   escapeshellarg($dir));
+        exec($create_function);
+        return true;
+    }
+
+    /**
+     * @TODO: Implement
+     */
+    function deleteMailbox($user, $domain)
+    {
+        return true;
+    }
+
+}
diff --git a/vilma/lib/MailboxDriver/null.php b/vilma/lib/MailboxDriver/null.php
new file mode 100644 (file)
index 0000000..32557da
--- /dev/null
@@ -0,0 +1,81 @@
+<?php
+/**
+ * Copyright 2004-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * $Horde: vilma/lib/MailboxDriver/null.php,v 1.1 2009/05/28 00:33:00 bklang Exp $
+ *
+ * @author  David Cummings <davidcummings@acm.org>
+ * @package Vilma
+ */
+class Vilma_MailboxDriver_null extends Vilma_MailboxDriver {
+
+    function _getMailboxDir($user, $domain)
+    {
+        /*
+        if (empty($this->_params['mail_dir_base'])) {
+            require_once 'PEAR.php';
+            return PEAR::raiseError(_("No 'mail_dir_base' parameter specified to maildrop driver."));
+        }
+        $dir = $this->_params['mail_dir_base'];
+        $usedomain = isset($this->_params['usedomain']) ? $this->_params['usedomain'] : false;
+        if ($usedomain) {
+            $dir .= '/' . $domain;
+        }
+          
+        return $dir . '/' . $user;
+        */
+    }
+
+    function checkMailbox($user, $domain)
+    {   
+        /*
+        static $exists;
+
+        $dir = $this->_getMailboxDir($user, $domain);
+        if (is_a($dir, 'PEAR_Error')) {
+            return $dir;
+        }
+
+        if (!isset($exists[$dir])) {
+            $exists[$dir] = is_dir($dir);
+        }
+
+        if (!$exists[$dir]) {
+            require_once 'PEAR.php';
+            return PEAR::raiseError(sprintf(_("Maildrop directory \"%s\" does not exist."), $dir));
+        }
+        */
+
+        return true;
+    }
+
+    function createMailbox($user, $domain)
+    {
+        $dir = $this->_getMailboxDir($user, $domain);
+        if (is_a($dir, 'PEAR_Error')) {
+            return $dir;
+        }
+        if (empty($this->_params['system_user'])) {
+            require_once 'PEAR.php';
+            return PEAR::raiseError(_("No 'system_user' parameter specified to maildrop driver."));
+        }
+
+        $create_function = sprintf('sudo -u %s maildirmake %s',
+                                   escapeshellarg($this->_params['system_user']),
+                                   escapeshellarg($dir));
+        exec($create_function);
+        return true;
+    }
+
+    /**
+     * @TODO: Implement
+     */
+    function deleteMailbox($user, $domain)
+    {
+        return true;
+    }
+
+}
diff --git a/vilma/lib/Vilma.php b/vilma/lib/Vilma.php
new file mode 100644 (file)
index 0000000..442b5ce
--- /dev/null
@@ -0,0 +1,192 @@
+<?php
+/**
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * $Horde: vilma/lib/Vilma.php,v 1.34 2009/07/08 18:30:03 slusarz Exp $
+ *
+ * @author  Marko Djukic <marko@oblo.com>
+ * @author  David Cummings <davidcummings@acm.org>
+ * @package Vilma
+ */
+class Vilma {
+
+    /**
+     * Check whether the current user has administrative permissions over
+     * the requested domain at the given permissions level.
+     * Also checks to see if the user is a Vilma superadmin.
+     * If the user is a Horde admin they automatically have permission.
+     *
+     * @param string $domain Domain for which to check permissions
+     * @param int $permmask  Permissions that must be set for the user
+     *
+     * @return boolean       True if the user has the requested permission
+     */
+    function hasPermission($domain, $permmask = null)
+    {
+        // FIXME Should this really be the case?  Superadmin is more granular
+        if (Horde_Auth::isAdmin()) {
+            return true;
+        }
+
+        if ($permmask === null) {
+            $permmask = PERMS_SHOW|PERMS_READ;
+        }
+
+        # Default deny all permissions
+        $user = 0;
+        $superadmin = 0;
+
+        $superadmin = $GLOBALS['perms']->hasPermission('vilma:domains',
+                                                    Horde_Auth::getAuth(), $permmask);
+
+        $user = $GLOBALS['perms']->hasPermission($permname, Horde_Auth::getAuth(),
+                                                     $permmask);
+
+        return ($superadmin | $user);
+    }
+
+    function getUserMgrTypes()
+    {
+        return array(
+            'all' => array(
+                'singular' => _("All"),
+                'plural'   => _("All") ),
+            'user' => array(
+                'singular' => _("User"),
+                'plural' => _("Users"), ),
+            'alias' => array(
+                'singular' => _("Alias"),
+                'plural' => _("Aliases"), ),
+            //'grpfwd' => array(
+            //    'singular' => _("Group/Forward"),
+            //    'plural' => _("Groups and Forwards"), ), );
+            'group' => array(
+                'singular' => _("Group"),
+                'plural' => _("Groups"), ),
+            'forward' => array(
+                'singular' => _("Forward"),
+                'plural' => _("Forwards"),), );
+    }
+
+    /**
+     * Create tabs to navigate the user manager area
+     *
+     * return object Horde_UI_Tabs object
+     */
+    function getUserMgrTabs(&$vars)
+    {
+        $url = Horde::applicationUrl('users/index.php');
+        $tabs = &new Horde_UI_Tabs('section', $vars);
+        foreach (Vilma::getUserMgrTypes() as $section => $desc) {
+            $tabs->addTab($desc['plural'], $url, $section);
+        }
+        return $tabs;
+    }
+
+    /**
+     * Attempt to determine the current domain name based on current user or
+     * a domain_id passed in by form.
+     *
+     * @return mixed string domain on success, false on failure, PEAR::Error on error
+     */
+    function getCurDomain()
+    {
+        // Domain is passed in by ID, which may or may not be the
+        // the same as the actual DNS domain name
+        $domain_id = Horde_Util::getFormData('domain_id');
+
+        if (!empty($domain_id)) {
+            // FIXME: Make sure this only runs once per page-load
+            $domain = $GLOBALS['vilma_driver']->getDomain($domain_id);
+            if (is_a($domain, 'PEAR_Error')) {
+                return $domain;
+            }
+            if (empty($domain['domain_name'])) {
+                $domain = false;
+            }
+            Vilma::setCurDomain($domain);
+        } elseif (isset($_SESSION['vilma']['domain'])) {
+            $domain = $_SESSION['vilma']['domain'];
+        }
+
+        return $domain;
+    }
+
+    /**
+     * Set the current domain
+     */
+    function setCurDomain($domain)
+    {
+        $_SESSION['vilma']['domain'] = $domain;
+    }
+
+    /**
+     * Strip the domain from an email address (leaving the Username)
+     *
+     * @param string $email  Email address to strip (leaving the Username)
+     *
+     * @return string Username portion of supplied email address
+     */
+    function stripUser($email)
+    {
+        list($user, $domain) = explode('@', $email);
+        return $user;
+    }
+
+    /**
+     * Strip the username from an email address (leaving the domain)
+     *
+     * @param string $email  Email address to strip (leaving the domain)
+     *
+     * @return string Domain portion of supplied email address
+     */
+    function stripDomain($email)
+    {
+        $parts = explode('@', $email);
+        if (count($parts) == 2) {
+            $parts = explode(',', $parts[1]);
+            return $parts[0];
+        }
+        return null;
+    }
+
+    function &getMailboxDriver()
+    {
+        global $conf;
+
+        require_once VILMA_BASE . '/lib/MailboxDriver.php';
+        $driver = &Vilma_MailboxDriver::singleton($conf['mailboxes']['driver'],
+                                                  $conf['mailboxes']['params']);
+        return $driver;
+    }
+
+    /**
+     * Build Vilma's list of menu items.
+     */
+    function getMenu($returnType = 'object')
+    {
+        $menu = new Horde_Menu();
+
+        $menu->add(Horde::applicationUrl('domains/index.php'), _("_Domains"), 'domain.png');
+
+        if (Vilma::getCurDomain()) {
+            $domain = $_SESSION['vilma']['domain'];
+            $url = Horde::applicationUrl('users/index.php');
+            $tmp = Horde_Util::addParameter($url, 'domain_id', $domain['domain_id']);
+            $menu->add(Horde::applicationUrl($tmp), _($domain['domain_name']), 'domain.png');
+            $menu->add(Horde::applicationUrl('users/edit.php'), _("New _Address"), 'user.png', $GLOBALS['registry']->getImageDir('horde'));
+        } else {
+            $menu->add(Horde::applicationUrl('domains/edit.php'), _("_New Domain"), 'domain.png');
+        }
+
+        if ($returnType == 'object') {
+            return $menu;
+        } else {
+            return $menu->render();
+        }
+    }
+
+}
diff --git a/vilma/lib/api.php b/vilma/lib/api.php
new file mode 100644 (file)
index 0000000..e03c30f
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+/**
+ * Vilma external API interface.
+ *
+ * This file defines Vilma's external API interface. Other applications
+ * can interact with Vilma through this API.
+ *
+ * Copyright 2006-2007 Alkaloid Networks <http://www.alkaloid.net/>
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * $Horde: vilma/lib/api.php,v 1.10 2007/06/27 17:24:16 jan Exp $
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author  Ben Klang <bklang@alkaloid.net>
+ * @package Vilma
+ */
+@define('VILMA_BASE', dirname(__FILE__) . '/..');
+
+$_services['perms'] = array(
+    'args' => array(),
+    'type' => '{urn:horde}stringArray');
+
+
+$_services['listDomains'] = array(
+    'args' => array(),
+    'type' => '{urn:horde}stringArray');
+
+function _vilma_perms()
+{
+    static $perms = array();
+    if (!empty($perms)) {
+        return $perms;
+    }
+
+    require_once VILMA_BASE . '/lib/base.php';
+    global $vilma_driver;
+
+    $perms['tree']['vilma']['superadmin'] = false;
+    $perms['title']['vilma:superadmin'] = _("Super Administrator");
+
+    $domains = $vilma_driver->getDomains();
+
+    // Run through every domain
+    foreach ($domains as $domain) {
+        $d = $domain['domain_id'];
+        $perms['tree']['vilma']['domains'][$d] = false;
+        $perms['title']['vilma:domains:' . $d] = $domain['name'];
+    }
+
+    return $perms;
+}
+
+function _vilma_listDomains()
+{
+    require_once VILMA_BASE . '/lib/base.php';
+    global $vilma_driver;
+
+    return $vilma_driver->getDomains();
+    $domains = array();
+    foreach ($vilma_driver->getDomains() as $domain) {
+        $domains[] = $domain['domain_name'];
+    }
+    return $domains;
+}
\ No newline at end of file
diff --git a/vilma/lib/base.php b/vilma/lib/base.php
new file mode 100644 (file)
index 0000000..ca70948
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+/**
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * $Horde: vilma/lib/base.php,v 1.37 2009/07/13 20:05:58 slusarz Exp $
+ *
+ * @author Marko Djukic <marko@oblo.com>
+ * @author Ben Klang <ben@alkaloid.net>
+ * @package Vilma
+ */
+
+/* Check for a prior definition of HORDE_BASE (perhaps by an auto_prepend_file
+ * definition for site customization). */
+if (!defined('HORDE_BASE')) {
+    @define('HORDE_BASE', dirname(__FILE__) . '/../..');
+}
+
+/* Load the Horde Framework core, and set up inclusion paths. */
+require_once HORDE_BASE . '/lib/core.php';
+
+/* Registry. */
+$registry = Horde_Registry::singleton();
+try {
+    $registry->pushApp('vilma', !defined('AUTH_HANDLER'));
+} catch (Horde_Exception $e) {
+    if ($e->getCode() == 'permission_denied') {
+        Horde::authenticationFailureRedirect();
+    }
+    Horde::fatal($e, __FILE__, __LINE__, false);
+}
+$conf = &$GLOBALS['conf'];
+@define('VILMA_TEMPLATES', $registry->get('templates'));
+
+/* Find the base file path of Vilma */
+@define('VILMA_BASE', dirname(__FILE__) . '/..');
+
+/* Vilma base library */
+require_once VILMA_BASE . '/lib/Vilma.php';
+require_once VILMA_BASE . '/lib/Driver.php';
+
+/* Templates */
+$template = &new Horde_Template();
+
+/* Notification system. */
+$notification = &Horde_Notification::singleton();
+$notification->attach('status');
+
+/* Navigation Tabs */
+require_once 'Horde/UI/Tabs.php';
+
+/* Vilma driver. */
+$GLOBALS['vilma_driver'] = &Vilma_Driver::singleton();
+
+// Get the currently active domain, possibly storing a change into the session
+$curdomain = Vilma::getCurDomain();
diff --git a/vilma/lib/tests/driver.phpt b/vilma/lib/tests/driver.phpt
new file mode 100644 (file)
index 0000000..7b830a9
--- /dev/null
@@ -0,0 +1,155 @@
+--TEST--
+Vilma_Driver_sql::
+--FILE--
+<?php
+
+echo "Load... ";
+
+define('AUTH_HANDLER', false);
+define('VILMA_BASE', dirname(__FILE__) . '/..');
+require_once VILMA_BASE . '/lib/base.php';
+
+echo "ok\n";
+
+checkConstruction();
+
+/* Delete our test domains in case we bombed on an earlier trial. */
+ob_start();
+checkDeleteDomain();
+ob_end_clean();
+
+checkSaveDomain();
+checkDeleteDomain();
+
+function checkConstruction()
+{
+    global $conf;
+
+    echo "Checking construction... ";
+
+    $unfiltered_params = $conf['storage']['params'];
+    if (isset($unfiltered_params['tables']['domainkey'])) {
+        unset($unfiltered_params['tables']['domainkey']);
+    }
+
+    $GLOBALS['unfiltered'] = &Vilma_Driver::singleton('sql', $unfiltered_params);
+    if (is_a($GLOBALS['unfiltered'], 'PEAR_Error')) {
+        printf(_("ERROR(1): %s\n"), $GLOBALS['unfiltered']->getMessage());
+        return;
+    }
+
+    $filtered_params = $conf['storage']['params'];
+    $filtered_params['tables']['domainkey'] = '__FOO';
+
+    $GLOBALS['filtered'] = &Vilma_Driver::singleton('sql', $filtered_params);
+    if (is_a($GLOBALS['filtered'], 'PEAR_Error')) {
+        printf(_("ERROR(2): %s\n"), $GLOBALS['filtered']->getMessage());
+        return;
+    }
+
+    echo "ok\n";
+}
+
+function checkSaveDomain()
+{
+    global $filtered, $unfiltered;
+
+    echo "Checking saveDomain()... ";
+
+    $domain = array('domain_name'       => 'filtered.example.com',
+                    'domain_transport'  => 'cyrus',
+                    'domain_admin'      => 'test@filtered.example.com',
+                    'domain_max_users'  => 15,
+                    'domain_quota'      => 0);
+
+    $res = $filtered->saveDomain($domain);
+    if (is_a($res, 'PEAR_Error')) {
+        var_dump($res);
+        printf(_("ERROR(1): %s\n"), $res->getMessage());
+        return;
+    }
+
+    $res = $filtered->getDomainByName('filtered.example.com');
+    if (is_a($res, 'PEAR_Error')) {
+        printf(_("ERROR(2): %s\n"), $res->getMessage());
+        return;
+    }
+
+    if ($res['domain_name'] != 'filtered.example.com') {
+        echo _("ERROR(3): got wrong domain.\n");
+        return;
+    }
+    if ($res['domain_transport'] != $domain['domain_transport'] ||
+        $res['domain_admin'] != $domain['domain_admin'] ||
+        $res['domain_max_users'] != $domain['domain_max_users'] ||
+        $res['domain_quota'] != $domain['domain_quota']) {
+        echo _("ERROR(4): got some wrong info.\n");
+        return;
+    }
+
+    $domain['domain_name'] = 'unfiltered.example.com';
+    $res = $unfiltered->saveDomain($domain);
+    if (is_a($res, 'PEAR_Error')) {
+        printf(_("ERROR(5): %s\n"), $res->getMessage());
+        return;
+    }
+
+    $res = $unfiltered->getDomainByName('unfiltered.example.com');
+    if (is_a($res, 'PEAR_Error')) {
+        printf(_("ERROR(6): %s\n"), $res->getMessage());
+        return;
+    }
+
+    if ($res['domain_name'] != 'unfiltered.example.com') {
+        echo _("ERROR(7): got wrong domain.\n");
+        return;
+    }
+    if ($res['domain_transport'] != $domain['domain_transport'] ||
+        $res['domain_admin'] != $domain['domain_admin'] ||
+        $res['domain_max_users'] != $domain['domain_max_users'] ||
+        $res['domain_quota'] != $domain['domain_quota']) {
+        echo _("ERROR(8): got some wrong info.\n");
+        return;
+    }
+
+    echo "ok\n";
+}
+
+function checkDeleteDomain()
+{
+    global $filtered, $unfiltered;
+
+    echo "Checking deleteDomain()... ";
+
+    $domain = $filtered->getDomainByName('filtered.example.com');
+    if (is_a($domain, 'PEAR_Error')) {
+        printf(_("ERROR(1): %s\n"), $domain->getMessage());
+        return;
+    }
+
+    $res = $filtered->deleteDomain($domain['domain_id']);
+    if (is_a($res, 'PEAR_Error')) {
+        printf(_("ERROR(2): %s\n"), $res->getMessage());
+        return;
+    }
+
+    $domain = $unfiltered->getDomainByName('unfiltered.example.com');
+    if (is_a($domain, 'PEAR_Error')) {
+        printf(_("ERROR(3): %s\n"), $domain->getMessage());
+        return;
+    }
+
+    $res = $unfiltered->deleteDomain($domain['domain_id']);
+    if (is_a($res, 'PEAR_Error')) {
+        printf(_("ERROR(4): %s\n"), $res->getMessage());
+        return;
+    }
+
+    echo "ok\n";
+}
+
+--EXPECT--
+Load... ok
+Checking construction... ok
+Checking saveDomain()... ok
+Checking deleteDomain()... ok
diff --git a/vilma/lib/version.php b/vilma/lib/version.php
new file mode 100644 (file)
index 0000000..9749581
--- /dev/null
@@ -0,0 +1 @@
+<?php define('VILMA_VERSION', 'H4 (1.0-cvs)') ?>
diff --git a/vilma/locale/de_DE/LC_MESSAGES/vilma.mo b/vilma/locale/de_DE/LC_MESSAGES/vilma.mo
new file mode 100644 (file)
index 0000000..f74eec6
Binary files /dev/null and b/vilma/locale/de_DE/LC_MESSAGES/vilma.mo differ
diff --git a/vilma/locale/es_ES/LC_MESSAGES/vilma.mo b/vilma/locale/es_ES/LC_MESSAGES/vilma.mo
new file mode 100644 (file)
index 0000000..0b2a998
Binary files /dev/null and b/vilma/locale/es_ES/LC_MESSAGES/vilma.mo differ
diff --git a/vilma/locale/it_IT/LC_MESSAGES/vilma.mo b/vilma/locale/it_IT/LC_MESSAGES/vilma.mo
new file mode 100644 (file)
index 0000000..cbd21bd
Binary files /dev/null and b/vilma/locale/it_IT/LC_MESSAGES/vilma.mo differ
diff --git a/vilma/locale/lt_LT/LC_MESSAGES/vilma.mo b/vilma/locale/lt_LT/LC_MESSAGES/vilma.mo
new file mode 100644 (file)
index 0000000..fe6e869
Binary files /dev/null and b/vilma/locale/lt_LT/LC_MESSAGES/vilma.mo differ
diff --git a/vilma/po/.cvsignore b/vilma/po/.cvsignore
new file mode 100644 (file)
index 0000000..fd8854c
--- /dev/null
@@ -0,0 +1 @@
+messages.po
diff --git a/vilma/po/README b/vilma/po/README
new file mode 100644 (file)
index 0000000..a985e94
--- /dev/null
@@ -0,0 +1 @@
+see horde/po/README
diff --git a/vilma/po/de_DE.po b/vilma/po/de_DE.po
new file mode 100644 (file)
index 0000000..15b3d98
--- /dev/null
@@ -0,0 +1,500 @@
+# German translations for Vilma.
+# Copyright 2004-2009 The Horde Project
+# This file is distributed under the same license as the Vilma package.
+# Jan Schneider <jan@horde.org>, 2004-2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vilma 0.1-cvs\n"
+"Report-Msgid-Bugs-To: dev@lists.horde.org\n"
+"POT-Creation-Date: 2008-04-01 14:58+0200\n"
+"PO-Revision-Date: 2008-04-01 15:15+0200\n"
+"Last-Translator: Jan Schneider <jan@horde.org>\n"
+"Language-Team: i18n@lists.horde.org\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: users/edit.php:53
+#, php-format
+msgid "\"%s\" already has the maximum number of users allowed."
+msgstr "\"%s\" hat bereits die maximale Benutzerzahl erreicht."
+
+#: lib/Driver/qmailldap.php:647
+msgid "Account Status"
+msgstr "Kontostatus"
+
+#: lib/Driver/qmailldap.php:655
+msgid "Account is active"
+msgstr "Konto ist aktiviert"
+
+#: lib/Driver/qmailldap.php:658
+msgid "Account is disabled"
+msgstr "Konto ist deaktiviert"
+
+#: templates/users/index.html:13
+msgid "Address"
+msgstr "Adresse"
+
+#: lib/Vilma.php:60
+msgid "Alias"
+msgstr "Spitzname"
+
+#: lib/Driver/qmailldap.php:332
+#, php-format
+msgid "Alias for %s"
+msgstr "Alias für %s"
+
+#: lib/Vilma.php:61
+msgid "Aliases"
+msgstr "Aliase"
+
+#: lib/Vilma.php:54 lib/Vilma.php:55
+msgid "All"
+msgstr "Alle"
+
+#: lib/Driver/qmailldap.php:657
+msgid "Bounce Incoming Only"
+msgstr "Nur Eingehendes abweisen"
+
+#: domains/delete.php:27 users/delete.php:34 users/delete.php:38
+#: virtuals/delete.php:34 virtuals/delete.php:38
+#: lib/Forms/DeleteDomainForm.php:27
+msgid "Delete"
+msgstr "Löschen"
+
+#: domains/index.php:44 lib/Forms/DeleteDomainForm.php:17
+msgid "Delete Domain"
+msgstr "Domain löschen"
+
+#: users/index.php:83 users/delete.php:31 virtuals/index.php:55
+msgid "Delete User"
+msgstr "Benutzer löschen"
+
+#: virtuals/delete.php:31
+msgid "Delete Virtual Email Address"
+msgstr "Virtuelle E-Mail-Adresse löschen"
+
+#: lib/Forms/DeleteDomainForm.php:29
+#, php-format
+msgid "Delete domain \"%s\" and all associated email addresses?"
+msgstr "Domain \"%s\" und alle dazugehörigen E-Mail-Adressen löschen?"
+
+#: virtuals/delete.php:36
+#, php-format
+msgid "Delete the virtual email address \"%s\" => \"%s\"?"
+msgstr "Virtuelle E-Mail-Adresse \"%s\" => \"%s\" löschen?"
+
+#: users/delete.php:36
+#, php-format
+msgid "Delete user \"%s\" and all associated virtual email addresses?"
+msgstr ""
+"Benutzer \"%s\" und alle dazugehörigen virtuellen E-Mail-Adressen löschen?"
+
+#: virtuals/edit.php:64 templates/virtuals/index.html:20
+msgid "Destination"
+msgstr "Ziel"
+
+#: virtuals/edit.php:54
+msgid "Destination type"
+msgstr "Zieltyp"
+
+#: lib/Driver/qmailldap.php:656
+msgid "Disable Delivery Only"
+msgstr "Nur Ausgehendes abweisen"
+
+#: config/prefs.php.dist:10
+msgid "Display details"
+msgstr "Anzeigedetails"
+
+#: config/prefs.php.dist:9
+msgid "Display listings"
+msgstr "Anzeigelisten"
+
+#: domains/delete.php:41 users/delete.php:34 users/delete.php:52
+#: virtuals/delete.php:34 virtuals/delete.php:52
+#: lib/Forms/DeleteDomainForm.php:27
+msgid "Do not delete"
+msgstr "Nicht löschen"
+
+#: lib/Forms/EditDomainForm.php:32 templates/domains/index.html:16
+msgid "Domain"
+msgstr "Domain"
+
+#: lib/Driver.php:229
+msgid ""
+"Domain added but an error was encountered while calling the configured "
+"hook.  Contact your administrator for futher assistance."
+msgstr ""
+"Die Domain wurde hinzugefügt, aber beim Aufruf des konfigurierten Hooks ist "
+"ein Fehler aufgetreten. Bitte wenden Sie sich an Ihren Systemadministrator "
+"für weitere Hilfe."
+
+#: domains/delete.php:35
+msgid "Domain deleted."
+msgstr "Domain gelöscht."
+
+#: domains/delete.php:42
+msgid "Domain not deleted."
+msgstr "Domain nicht gelöscht."
+
+#: domains/edit.php:35
+msgid "Domain saved."
+msgstr "Domain gespeichert."
+
+#: domains/index.php:45 lib/Forms/EditDomainForm.php:20
+msgid "Edit Domain"
+msgstr "Domain bearbeiten"
+
+#: users/index.php:84 virtuals/index.php:56
+msgid "Edit User"
+msgstr "Benutzer bearbeiten"
+
+#: lib/Forms/EditUserForm.php:22
+#, php-format
+msgid "Edit User for \"%s\""
+msgstr "Benutzer von \"%s\" bearbeiten"
+
+#: virtuals/edit.php:47
+msgid "Edit Virtual Email Address"
+msgstr "Virtuelle E-Mail-Adresse bearbeiten"
+
+#: virtuals/edit.php:53
+#, php-format
+msgid ""
+"Enter a virtual email address @%s and then indicate below where mail sent to "
+"that address is to be delivered. The address must begin with an "
+"alphanumerical character, it must contain only alphanumerical and '._-' "
+"characters, and must end with an alphanumerical character."
+msgstr ""
+"Geben Sie eine virtuelle E-Mail-Adresse für die \"@%s\" Domain an und tragen "
+"Sie unten ein, wohin Nachrichten, die an diese Adresse geschickt werden, "
+"ausgeliefert werden sollen. E-Mail-Adressen müssen mit einem "
+"alphanumerischen Zeichen beginnen und enden und dürfen nur alphanumerische "
+"und die Zeichen \"._-\" enthalten."
+
+#: lib/Driver/qmailldap.php:593
+#, php-format
+msgid "Error deleting account from LDAP: %s"
+msgstr "Fehler beim Löschen des Kontos in LDAP: %s"
+
+#: domains/delete.php:33
+#, php-format
+msgid "Error deleting domain. %s."
+msgstr "Fehler beim Löschen der Domain. %s."
+
+#: users/delete.php:44
+#, php-format
+msgid "Error deleting user. %s."
+msgstr "Fehler beim Löschen des Benutzers. %s."
+
+#: virtuals/delete.php:44
+#, php-format
+msgid "Error deleting virtual email. %s."
+msgstr "Fehler beim Löschen der virtuellen E-Mail-Adresse. %s."
+
+#: lib/Driver/qmailldap.php:170 lib/Driver/qmailldap.php:175
+#, php-format
+msgid "Error in LDAP search: %s"
+msgstr "Fehler bei LDAP-Suche: %s"
+
+#: users/edit.php:35
+#, php-format
+msgid "Error reading address information from backend: %s"
+msgstr "Fehler beim Lesen der der Adressinformationen vom Backend: %s"
+
+#: lib/Driver/qmailldap.php:583
+#, php-format
+msgid "Error retrieving LDAP results: %s"
+msgstr "Fehler beim Lesen LDAP-Ergebnisse: %s"
+
+#: lib/Driver/qmailldap.php:308 lib/Driver/qmailldap.php:396
+#: lib/Driver/qmailldap.php:468
+#, php-format
+msgid "Error returning LDAP results: %s"
+msgstr "Fehler bei der Rückgabe der LDAP-Ergebnisse: %s"
+
+#: lib/Driver.php:195
+msgid "Error running authentication update script."
+msgstr "Fehler beim Ausführen des Update-Skripts."
+
+#: domains/edit.php:33
+#, php-format
+msgid "Error saving domain: %s."
+msgstr "Fehler beim Speichern der Domain: %s."
+
+#: users/edit.php:64
+#, php-format
+msgid "Error saving user. %s"
+msgstr "Fehler beim Speichern des Benutzers. %s"
+
+#: virtuals/edit.php:77
+#, php-format
+msgid "Error saving virtual email. %s."
+msgstr "Fehler beim Speichern der virtuellen E-Mail-Adresse. %s."
+
+#: lib/Driver/qmailldap.php:302 lib/Driver/qmailldap.php:390
+#: lib/Driver/qmailldap.php:462 lib/Driver/qmailldap.php:577
+#, php-format
+msgid "Error searching LDAP: %s"
+msgstr "Fehler bei der LDAP-Suche: %s"
+
+#: lib/Driver.php:280
+msgid "Error while calling hook to delete domain."
+msgstr "Fehler beim Aufruf des Hooks zum Löschen der Domain."
+
+#: lib/Forms/EditUserForm.php:41 templates/users/index.html:16
+msgid "Full Name"
+msgstr "Vollständiger Name"
+
+#: lib/Vilma.php:63
+msgid "Group/Forward"
+msgstr "Gruppe/Weiterleitung"
+
+#: lib/Vilma.php:64
+msgid "Groups and Forwards"
+msgstr "Gruppen und Weiterleitungen"
+
+#: config/prefs.php.dist:20
+msgid "How many domain to display per page."
+msgstr "Anzahl der Domains pro Seite."
+
+#: virtuals/edit.php:56
+msgid "Local user"
+msgstr "Lokaler Benutzer"
+
+#: lib/MailboxDriver/imap.php:45
+#, php-format
+msgid "Mailbox '%s@%s' does not exist."
+msgstr "Die Mailbox '%s@%s' existiert nicht."
+
+#: lib/MailboxDriver/maildrop.php:45
+#, php-format
+msgid "Maildrop directory \"%s\" does not exist."
+msgstr "Das Maildrop-Verzeichnis \"%s\" existiert nicht."
+
+#: templates/domains/index.html:19
+msgid "Max Users"
+msgstr "Maximale Benutzerzahl"
+
+#: lib/Forms/EditDomainForm.php:35
+msgid "Max users"
+msgstr "Maximale Benutzerzahl"
+
+#: users/index.php:70
+msgid "Maximum Users"
+msgstr "Maximale Benutzerzahl"
+
+#: lib/Driver/qmailldap.php:472
+msgid ""
+"More than one DN returned for this alias.  Please contact an administrator "
+"to resolve this error."
+msgstr ""
+"Mehr als eine DN für diesen Alias gefunden. Bitte wenden Sie sich an einen "
+"Administrator, um diesen Fehler zu beheben."
+
+#: lib/Driver/qmailldap.php:587
+msgid "More than one DN returned.  Aborting delete operation."
+msgstr "Mehr als eine DN zurückgeliefert.  Löschvorgang abgebrochen."
+
+#: lib/Forms/EditUserForm.php:35
+msgid ""
+"Name must begin with an alphanumeric character, must contain only "
+"alphanumeric and '._-' characters, and must end with an alphanumeric "
+"character."
+msgstr ""
+"Der Name muss mit einem alphanumerischen Zeichen beginnen und enden und darf "
+"nur alphanumerische und die Zeichen \"._-\" enthalten."
+
+#: lib/Forms/EditDomainForm.php:20
+msgid "New Domain"
+msgstr "Neue Domain"
+
+#: lib/Forms/EditUserForm.php:24
+#, php-format
+msgid "New User @%s"
+msgstr "Neuer Benutzer für Domain @%s"
+
+#: virtuals/index.php:48
+msgid "New Virtual Email"
+msgstr "Neue virtuelle E-Mail-Adresse"
+
+#: virtuals/edit.php:47
+msgid "New Virtual Email Address"
+msgstr "Neue virtuelle E-Mail-Adresse"
+
+#: lib/Vilma.php:169
+msgid "New _Address"
+msgstr "Neue _Adresse"
+
+#: lib/MailboxDriver/maildrop.php:19
+msgid "No 'mail_dir_base' parameter specified to maildrop driver."
+msgstr ""
+"Kein 'mail_dir_base' Parameter in der Maildrop-Treiber-Konfiguration "
+"angegeben."
+
+#: lib/MailboxDriver/maildrop.php:60
+msgid "No 'system_user' parameter specified to maildrop driver."
+msgstr ""
+"Kein 'system_user' Parameter in der Maildrop-Treiber-Konfiguration angegeben."
+"<"
+
+#: lib/Driver.php:108
+#, php-format
+msgid "No such address %s of type %s found."
+msgstr "Adresse %s vom Typ %s nicht gefunden."
+
+#: lib/Driver.php:374
+#, php-format
+msgid "No such backend \"%s\" found"
+msgstr "Ein Backend namens \"%s\" konnte nicht gefunden werden"
+
+#: users/edit.php:74
+msgid ""
+"No virtual email address set up for this user. You should set up at least "
+"one virtual email address if this user is to receive any emails."
+msgstr ""
+"Für diesen Benutzer wurden keine virtuellen E-Mail-Adressen eingerichtet. "
+"Sie sollten mindestens eine E-Mail-Adresse einrichten, wenn dieser Benutzer "
+"E-Mails empfangen können soll."
+
+#: lib/Driver.php:245 lib/Driver.php:294
+msgid "Not implemented."
+msgstr "Nicht implementiert."
+
+#: lib/Forms/EditUserForm.php:37
+msgid "Only enter a password if you wish to change this user's password"
+msgstr ""
+"Geben Sie nur ein Passwort ein, wenn Sie das Passwort dieses Benutzers "
+"ändern möchten"
+
+#: lib/Forms/EditUserForm.php:37 lib/Forms/EditUserForm.php:39
+msgid "Password"
+msgstr "Passwort"
+
+#: lib/Driver/sql.php:465
+msgid "Password must be supplied when creating a new user."
+msgstr "Passwort muss beim Erstellen eines neuen Benutzers angegeben werden."
+
+#: lib/Forms/EditDomainForm.php:36
+msgid "Quota"
+msgstr "Speicherplatz-Kontingent"
+
+#: virtuals/edit.php:57
+msgid "Remote address"
+msgstr "Externe Adresse"
+
+#: virtuals/edit.php:61
+msgid "Remote e-mail address"
+msgstr "Externe E-Mail-Adresse"
+
+#: config/prefs.php.dist:11
+msgid "Set default display parameters."
+msgstr "Legen Sie Ihre Standard-Anzeigeeinstellungen fest."
+
+#: templates/users/index.html:22
+msgid "Status"
+msgstr "Status"
+
+#: lib/api.php:43
+msgid "Super Administrator"
+msgstr "Super-Administrator"
+
+#: lib/MailboxDriver.php:78
+msgid "This driver cannot create mailboxes."
+msgstr "Dieses Treiber kann keine Mailboxen anlegen."
+
+#: lib/MailboxDriver.php:94
+msgid "This driver cannot delete mailboxes."
+msgstr "Dieser Treiber kann keine Mailboxen löschen."
+
+#: lib/Forms/EditDomainForm.php:34
+msgid "Transport"
+msgstr "Transport"
+
+#: templates/users/index.html:19
+msgid "Type"
+msgstr "Typ"
+
+#: lib/Driver/qmailldap.php:696
+msgid "Unable to bind to the LDAP server.  Check authentication credentials."
+msgstr ""
+"Anbindung an LDAP-Server fehlgeschlagen. Überprüfen Sie die "
+"Authentifizierungsdaten."
+
+#: lib/Driver/qmailldap.php:691
+msgid "Unable to set LDAP protocol version"
+msgstr "Die LDAP-Protokollversion konnte nicht gesetzt werden"
+
+#: lib/Driver.php:199
+msgid "Unknown error running authentication update script."
+msgstr "Unbekannter Fehler beim Ausführen des Update-Skripts."
+
+#: lib/Vilma.php:57
+msgid "User"
+msgstr "Benutzer"
+
+#: lib/Forms/EditUserForm.php:35
+msgid "User Name"
+msgstr "Benutzername"
+
+#: users/delete.php:46
+msgid "User deleted."
+msgstr "Benutzer gelöscht."
+
+#: users/edit.php:66
+msgid "User details saved."
+msgstr "Benutzerdetails gespeichert."
+
+#: lib/Driver.php:132
+msgid "User disabled."
+msgstr "Benutzer deaktiviert."
+
+#: users/delete.php:53
+msgid "User not deleted."
+msgstr "Benutzer wurde nicht gelöscht."
+
+#: lib/Driver.php:155
+msgid "User ready."
+msgstr "Benutzer bereit."
+
+#: virtuals/index.php:51 lib/Vilma.php:58
+msgid "Users"
+msgstr "Benutzer"
+
+#: lib/Forms/EditDomainForm.php:36
+msgid "Value in MB"
+msgstr "Wert in MB"
+
+#: lib/Driver.php:210
+msgid "Vilma_Driver::deleteUser(): Method Not Implemented."
+msgstr "Vilma_Driver::deleteUser(): Methode nicht implementiert."
+
+#: virtuals/edit.php:53
+msgid "Virtual Email"
+msgstr "Virtuelle E-Mail-Adresse"
+
+#: templates/virtuals/index.html:17
+msgid "Virtual Email Address"
+msgstr "Virtuelle E-Mail-Adresse"
+
+#: virtuals/delete.php:46
+msgid "Virtual email deleted."
+msgstr "Virtuelle E-Mail-Adresse gelöscht."
+
+#: virtuals/delete.php:53
+msgid "Virtual email not deleted."
+msgstr "Virtuelle E-Mail-Adresse nicht gelöscht."
+
+#: virtuals/edit.php:79
+msgid "Virtual email saved."
+msgstr "Virtuelle E-Mail-Adresse gespeichert."
+
+#: lib/Vilma.php:166
+msgid "_Domains"
+msgstr "_Domains"
+
+#: lib/Vilma.php:171
+msgid "_New Domain"
+msgstr "_Neue Domain"
diff --git a/vilma/po/es_ES.po b/vilma/po/es_ES.po
new file mode 100644 (file)
index 0000000..5fea8df
--- /dev/null
@@ -0,0 +1,501 @@
+# Spanish translations for vilma package
+# Traducciones al español para el paquete vilma.
+# Copyright 2008-2009 The Horde Project
+# This file is distributed under the same license as the vilma package.
+# Automatically generated, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vilma 0.2-cvs\n"
+"Report-Msgid-Bugs-To: dev@lists.horde.org\n"
+"POT-Creation-Date: 2008-03-20 09:49+0100\n"
+"PO-Revision-Date: 2008-03-20 09:49+0100\n"
+"Last-Translator: Manuel P. Ayala <mayala@unex.es>\n"
+"Language-Team: i18n@lists.horde.org\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: users/edit.php:53
+#, php-format
+msgid "\"%s\" already has the maximum number of users allowed."
+msgstr "\"%s\" ha alcanzado ya el número máximo de usuarios permitidos."
+
+#: lib/Driver/qmailldap.php:647
+msgid "Account Status"
+msgstr "Estado de la cuenta"
+
+#: lib/Driver/qmailldap.php:655
+msgid "Account is active"
+msgstr "La cuenta está activa"
+
+#: lib/Driver/qmailldap.php:658
+msgid "Account is disabled"
+msgstr "La cuenta está deshabilitada"
+
+#: templates/users/index.html:13
+msgid "Address"
+msgstr "Dirección"
+
+#: lib/Vilma.php:60
+msgid "Alias"
+msgstr "Apodo"
+
+#: lib/Driver/qmailldap.php:332
+#, php-format
+msgid "Alias for %s"
+msgstr "Apodo de %s"
+
+#: lib/Vilma.php:61
+msgid "Aliases"
+msgstr "Apodos"
+
+#: lib/Vilma.php:54 lib/Vilma.php:55
+msgid "All"
+msgstr "Todos"
+
+#: lib/Driver/qmailldap.php:657
+msgid "Bounce Incoming Only"
+msgstr "Rebotar sólo entrantes"
+
+#: virtuals/delete.php:34 virtuals/delete.php:38 users/delete.php:34
+#: users/delete.php:38 domains/delete.php:27 lib/Forms/DeleteDomainForm.php:27
+msgid "Delete"
+msgstr "Eliminar"
+
+#: domains/index.php:44 lib/Forms/DeleteDomainForm.php:17
+msgid "Delete Domain"
+msgstr "Eliminar dominio"
+
+#: virtuals/index.php:55 users/index.php:83 users/delete.php:31
+msgid "Delete User"
+msgstr "Eliminar usuario"
+
+#: virtuals/delete.php:31
+msgid "Delete Virtual Email Address"
+msgstr "Eliminar dirección electrónica virtual"
+
+#: lib/Forms/DeleteDomainForm.php:29
+#, php-format
+msgid "Delete domain \"%s\" and all associated email addresses?"
+msgstr ""
+"¿Eliminar el dominio \"%s\" y todas las direcciones electrónicas asociadas?"
+
+#: virtuals/delete.php:36
+#, php-format
+msgid "Delete the virtual email address \"%s\" => \"%s\"?"
+msgstr "¿Eliminar la dirección electrónica virtual \"%s\" => \"%s\"?"
+
+#: users/delete.php:36
+#, php-format
+msgid "Delete user \"%s\" and all associated virtual email addresses?"
+msgstr ""
+"¿Eliminar el usuario \"%s\" y todas sus direcciones electrónicas virtuales "
+"asociadas?"
+
+#: virtuals/edit.php:64 templates/virtuals/index.html:20
+msgid "Destination"
+msgstr "Destinatario"
+
+#: virtuals/edit.php:54
+msgid "Destination type"
+msgstr "Tipo de destinatario"
+
+#: lib/Driver/qmailldap.php:656
+msgid "Disable Delivery Only"
+msgstr "Desactivar sólo la distribución"
+
+#: config/.bak/prefs.php.dist:10
+msgid "Display details"
+msgstr "Mostrar detalles"
+
+#: config/.bak/prefs.php.dist:9
+msgid "Display listings"
+msgstr "Mostrar listados"
+
+#: virtuals/delete.php:34 virtuals/delete.php:52 users/delete.php:34
+#: users/delete.php:52 domains/delete.php:41 lib/Forms/DeleteDomainForm.php:27
+msgid "Do not delete"
+msgstr "No eliminar"
+
+#: lib/Forms/EditDomainForm.php:32 templates/domains/index.html:16
+msgid "Domain"
+msgstr "Dominio"
+
+#: lib/Driver.php:229
+msgid ""
+"Domain added but an error was encountered while calling the configured "
+"hook.  Contact your administrator for futher assistance."
+msgstr ""
+"Se añadió el dominio pero se produjo un error al llamar al gancho "
+"configurado. Para más información póngase en contacto con el administrador."
+
+#: domains/delete.php:35
+msgid "Domain deleted."
+msgstr "Se ha eliminado el dominio."
+
+#: domains/delete.php:42
+msgid "Domain not deleted."
+msgstr "No se ha eliminado el dominio."
+
+#: domains/edit.php:35
+msgid "Domain saved."
+msgstr "Se ha guardado el dominio."
+
+#: domains/index.php:45 lib/Forms/EditDomainForm.php:20
+msgid "Edit Domain"
+msgstr "Modificar dominio"
+
+#: virtuals/index.php:56 users/index.php:84
+msgid "Edit User"
+msgstr "Modificar usuario"
+
+#: lib/Forms/EditUserForm.php:22
+#, php-format
+msgid "Edit User for \"%s\""
+msgstr "Modificar usuario de \"%s\""
+
+#: virtuals/edit.php:47
+msgid "Edit Virtual Email Address"
+msgstr "Modificar dirección electrónica virtual"
+
+#: virtuals/edit.php:53
+#, php-format
+msgid ""
+"Enter a virtual email address @%s and then indicate below where mail sent to "
+"that address is to be delivered. The address must begin with an "
+"alphanumerical character, it must contain only alphanumerical and '._-' "
+"characters, and must end with an alphanumerical character."
+msgstr ""
+"Introduzca una dirección de correo virtual @%s e indique a continuación a "
+"dónde enviar el correo de esa dirección. Las direcciones tienen que empezar "
+"por un carácter alfanumérico, sólo pueden contener caracteres alfanuméricos "
+"y '._-' , y tienen que acabar por un carácter alfanumérico."
+
+#: lib/Driver/qmailldap.php:593
+#, php-format
+msgid "Error deleting account from LDAP: %s"
+msgstr "Error al eliminar la cuenta de LDAP: %s"
+
+#: domains/delete.php:33
+#, php-format
+msgid "Error deleting domain. %s."
+msgstr "Error al eliminar el dominio. %s."
+
+#: users/delete.php:44
+#, php-format
+msgid "Error deleting user. %s."
+msgstr "Error al eliminar el usuario. %s."
+
+#: virtuals/delete.php:44
+#, php-format
+msgid "Error deleting virtual email. %s."
+msgstr "Error al eliminar la dirección de correo virtual. %s."
+
+#: lib/Driver/qmailldap.php:170 lib/Driver/qmailldap.php:175
+#, php-format
+msgid "Error in LDAP search: %s"
+msgstr "Error en la búsqueda LDAP: %s"
+
+#: users/edit.php:35
+#, php-format
+msgid "Error reading address information from backend: %s"
+msgstr "Error leyendo la información de la dirección desde el motor: %s"
+
+#: lib/Driver/qmailldap.php:583
+#, php-format
+msgid "Error retrieving LDAP results: %s"
+msgstr "Error recuperando los resultados LDAP: %s"
+
+#: lib/Driver/qmailldap.php:308 lib/Driver/qmailldap.php:396
+#: lib/Driver/qmailldap.php:468
+#, php-format
+msgid "Error returning LDAP results: %s"
+msgstr "Error en la devolución de los resultados LDAP: %s"
+
+#: lib/Driver.php:195
+msgid "Error running authentication update script."
+msgstr "Error al ejecutar el guión de actualización de autentificación."
+
+#: domains/edit.php:33
+#, php-format
+msgid "Error saving domain: %s."
+msgstr "Error al guardar el dominio: %s."
+
+#: users/edit.php:64
+#, php-format
+msgid "Error saving user. %s"
+msgstr "Error al guardar el usuario. %s"
+
+#: virtuals/edit.php:77
+#, php-format
+msgid "Error saving virtual email. %s."
+msgstr "Error al guardar la dirección electrónica virtual. %s."
+
+#: lib/Driver/qmailldap.php:302 lib/Driver/qmailldap.php:390
+#: lib/Driver/qmailldap.php:462 lib/Driver/qmailldap.php:577
+#, php-format
+msgid "Error searching LDAP: %s"
+msgstr "Error buscando en LDAP: %s"
+
+#: lib/Driver.php:280
+msgid "Error while calling hook to delete domain."
+msgstr "Error al llamar al gancho de eliminación del dominio."
+
+#: lib/Forms/EditUserForm.php:41 templates/users/index.html:16
+msgid "Full Name"
+msgstr "Nombre completo"
+
+#: lib/Vilma.php:63
+msgid "Group/Forward"
+msgstr "Grupo/Reenvío"
+
+#: lib/Vilma.php:64
+msgid "Groups and Forwards"
+msgstr "Grupos y reenvíos"
+
+#: config/.bak/prefs.php.dist:20
+msgid "How many domain to display per page."
+msgstr "Cuántos dominios mostrar por página."
+
+#: virtuals/edit.php:56
+msgid "Local user"
+msgstr "Usuario local"
+
+#: lib/MailboxDriver/imap.php:45
+#, php-format
+msgid "Mailbox '%s@%s' does not exist."
+msgstr "No existe el buzón '%s@%s'."
+
+#: lib/MailboxDriver/maildrop.php:45
+#, php-format
+msgid "Maildrop directory \"%s\" does not exist."
+msgstr "No existe el directorio maildrop \"%s\"."
+
+#: templates/domains/index.html:19
+msgid "Max Users"
+msgstr "Número máximo de usuarios"
+
+#: lib/Forms/EditDomainForm.php:35
+msgid "Max users"
+msgstr "Número máximo de usuarios"
+
+#: users/index.php:70
+msgid "Maximum Users"
+msgstr "Número máximo de usuarios"
+
+#: lib/Driver/qmailldap.php:472
+msgid ""
+"More than one DN returned for this alias.  Please contact an administrator "
+"to resolve this error."
+msgstr ""
+"Este apodo devolvió más de un DN. Póngase en contacto con el administrador "
+"para resolver este error."
+
+#: lib/Driver/qmailldap.php:587
+msgid "More than one DN returned.  Aborting delete operation."
+msgstr "Se ha devuelto más de un DN. Anulando la operación de eliminación."
+
+#: lib/Forms/EditUserForm.php:35
+msgid ""
+"Name must begin with an alphanumeric character, must contain only "
+"alphanumeric and '._-' characters, and must end with an alphanumeric "
+"character."
+msgstr ""
+"El nombre tiene que empezar por un carácter alfanumérico, tiene que contener "
+"sólo caracteres alfanuméricos o '._-' y tiene que terminar por un carácter "
+"alfanumérico."
+
+#: lib/Forms/EditDomainForm.php:20
+msgid "New Domain"
+msgstr "Añadir dominio"
+
+#: lib/Forms/EditUserForm.php:24
+#, php-format
+msgid "New User @%s"
+msgstr "Añadir usuario @%s"
+
+#: virtuals/index.php:48
+msgid "New Virtual Email"
+msgstr "Añadir correo virtual"
+
+#: virtuals/edit.php:47
+msgid "New Virtual Email Address"
+msgstr "Añadir dirección de correo virtual"
+
+#: lib/Vilma.php:169
+msgid "New _Address"
+msgstr "Añadir _dirección"
+
+#: lib/MailboxDriver/maildrop.php:19
+msgid "No 'mail_dir_base' parameter specified to maildrop driver."
+msgstr ""
+"No se ha especificado el parámetro 'mail_dir_base' en el controlador de "
+"descarga de correo."
+
+#: lib/MailboxDriver/maildrop.php:60
+msgid "No 'system_user' parameter specified to maildrop driver."
+msgstr ""
+"No se ha especificado el parámetro 'system_user' en el controlador de "
+"descarga de correo."
+
+#: lib/Driver.php:108
+#, php-format
+msgid "No such address %s of type %s found."
+msgstr "No se encontró una dirección %s de tipo %s."
+
+#: lib/Driver.php:374
+#, php-format
+msgid "No such backend \"%s\" found"
+msgstr "No se encontró el motor \"%s\""
+
+#: users/edit.php:74
+msgid ""
+"No virtual email address set up for this user. You should set up at least "
+"one virtual email address if this user is to receive any emails."
+msgstr ""
+"A este usuario no se le ha configurado una dirección de correo vitual. Tiene "
+"que configurar al menos una si este usuario va a recibir correo."
+
+#: lib/Driver.php:245 lib/Driver.php:294
+msgid "Not implemented."
+msgstr "Sin desarrollar."
+
+#: lib/Forms/EditUserForm.php:37
+msgid "Only enter a password if you wish to change this user's password"
+msgstr ""
+"Introduzca un a contraseña sólo si desea cambiar la contraseña de este "
+"usuario"
+
+#: lib/Forms/EditUserForm.php:37 lib/Forms/EditUserForm.php:39
+msgid "Password"
+msgstr "Contraseña"
+
+#: lib/Driver/sql.php:465
+msgid "Password must be supplied when creating a new user."
+msgstr "Al crear un usuario hay que introducir una contraseña."
+
+#: lib/Forms/EditDomainForm.php:36
+msgid "Quota"
+msgstr "Espacio asignado"
+
+#: virtuals/edit.php:57
+msgid "Remote address"
+msgstr "Dirección remota"
+
+#: virtuals/edit.php:61
+msgid "Remote e-mail address"
+msgstr "Dirección electrónica remota"
+
+#: config/.bak/prefs.php.dist:11
+msgid "Set default display parameters."
+msgstr "Define parámetros de visualización por omisión."
+
+#: templates/users/index.html:22
+msgid "Status"
+msgstr "Estado"
+
+#: lib/api.php:43
+msgid "Super Administrator"
+msgstr "Super administrador"
+
+#: lib/MailboxDriver.php:78
+msgid "This driver cannot create mailboxes."
+msgstr "Este controlador no puede crear buzones."
+
+#: lib/MailboxDriver.php:94
+msgid "This driver cannot delete mailboxes."
+msgstr "Este controlador no puede eliminar buzones."
+
+#: lib/Forms/EditDomainForm.php:34
+msgid "Transport"
+msgstr "Transporte"
+
+#: templates/users/index.html:19
+msgid "Type"
+msgstr "Tipo"
+
+#: lib/Driver/qmailldap.php:696
+msgid "Unable to bind to the LDAP server.  Check authentication credentials."
+msgstr ""
+"No se pudo vincular al servidor LDAP. Compruebe las credenciales de "
+"autentificación."
+
+#: lib/Driver/qmailldap.php:691
+msgid "Unable to set LDAP protocol version"
+msgstr "No se puede establecer la versión del protocolo LDAP"
+
+#: lib/Driver.php:199
+msgid "Unknown error running authentication update script."
+msgstr ""
+"Se ha producido un error desconocido al ejecutar el guión de actualización "
+"de autentificación."
+
+#: lib/Vilma.php:57
+msgid "User"
+msgstr "Usuario"
+
+#: lib/Forms/EditUserForm.php:35
+msgid "User Name"
+msgstr "Nombre del usuario"
+
+#: users/delete.php:46
+msgid "User deleted."
+msgstr "Se ha eliminado el usuario."
+
+#: users/edit.php:66
+msgid "User details saved."
+msgstr "Se han guardado los detalles del usuario."
+
+#: lib/Driver.php:132
+msgid "User disabled."
+msgstr "Usuario deshabilitado."
+
+#: users/delete.php:53
+msgid "User not deleted."
+msgstr "No se ha eliminado el usuario"
+
+#: lib/Driver.php:155
+msgid "User ready."
+msgstr "El usuario está listo."
+
+#: virtuals/index.php:51 lib/Vilma.php:58
+msgid "Users"
+msgstr "Usuarios"
+
+#: lib/Forms/EditDomainForm.php:36
+msgid "Value in MB"
+msgstr "Valor en MB"
+
+#: lib/Driver.php:210
+msgid "Vilma_Driver::deleteUser(): Method Not Implemented."
+msgstr "Vilma_Driver::deleteUser(): Método no desarrollado."
+
+#: virtuals/edit.php:53
+msgid "Virtual Email"
+msgstr "Correo virtual"
+
+#: templates/virtuals/index.html:17
+msgid "Virtual Email Address"
+msgstr "Dirección de correo virtual"
+
+#: virtuals/delete.php:46
+msgid "Virtual email deleted."
+msgstr "Dirección virtual eliminada."
+
+#: virtuals/delete.php:53
+msgid "Virtual email not deleted."
+msgstr "No se ha eliminado la dirección virtual."
+
+#: virtuals/edit.php:79
+msgid "Virtual email saved."
+msgstr "Se ha guardado la dirección virtual."
+
+#: lib/Vilma.php:166
+msgid "_Domains"
+msgstr "_Dominios"
+
+#: lib/Vilma.php:171
+msgid "_New Domain"
+msgstr "_Añadir dominio"
diff --git a/vilma/po/it_IT.po b/vilma/po/it_IT.po
new file mode 100644 (file)
index 0000000..0548288
--- /dev/null
@@ -0,0 +1,367 @@
+# Italian translations for Mailadmin package.
+# Copyright 2003-2009 The Horde Project
+# This file is distributed under the same license as the Mailadmin package.
+# Automatically generated, 2003.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Mailadmin 0.1-cvs\n"
+"Report-Msgid-Bugs-To: dev@lists.horde.org\n"
+"POT-Creation-Date: 2004-08-30 14:11+0200\n"
+"PO-Revision-Date: 2004-02-11 18:15-0100\n"
+"Last-Translator: Marko Djukic <marko@oblo.com>\n"
+"Language-Team: Italian <tech@oblo.com>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: users/edit.php:47
+#, php-format
+msgid "'%s' already has the maximum number of users allowed."
+msgstr "'%s' gia' ha il numero massimo di utenti permessi."
+
+#: templates/domains/index.html:35
+msgid "Admin"
+msgstr "Admin"
+
+#: users/index.php:53
+msgid "All Virtual Emails"
+msgstr "Tutti gli Indirizzi Email Virtuali"
+
+#: virtuals/delete.php:37 virtuals/delete.php:41 users/delete.php:33
+#: users/delete.php:37 domains/delete.php:28 domains/delete.php:32
+msgid "Delete"
+msgstr "Elimina"
+
+#: domains/delete.php:25 domains/index.php:48
+msgid "Delete Domain"
+msgstr "Elimina Dominio"
+
+#: virtuals/index.php:52 users/delete.php:30 users/index.php:63
+msgid "Delete User"
+msgstr "Elimina Utente"
+
+#: virtuals/delete.php:34
+msgid "Delete Virtual Email Address"
+msgstr "Elimina Indirizzo Email Virtuale"
+
+#: domains/delete.php:30
+#, php-format
+msgid "Delete domain '%s', all the users and virtual email addresses?"
+msgstr "Elimina dominio '%s', tutti gli utenti e gli indirizzi email virtuali?"
+
+#: virtuals/delete.php:39
+#, php-format
+msgid "Delete the virtual email address '%s' => '%s'?"
+msgstr "Elimina l'indirizzo email virtuale '%s' => '%s'?"
+
+#: users/delete.php:35
+#, php-format
+msgid "Delete user '%s' and all associated virtual email addresses?"
+msgstr "Elimina l'utente '%s' e tutti i relativi indirizzi email virtuali?"
+
+#: templates/virtuals/index.html:37
+msgid "Destination"
+msgstr "Destinazione"
+
+#: virtuals/edit.php:55
+msgid "Destination user"
+msgstr "Utente di destinazione"
+
+#: virtuals/delete.php:37 virtuals/delete.php:55 users/delete.php:33
+#: users/delete.php:51 domains/delete.php:28 domains/delete.php:46
+msgid "Do not delete"
+msgstr "Non eliminare"
+
+#: domains/edit.php:40 templates/domains/index.html:33
+msgid "Domain"
+msgstr "Dominio"
+
+#: domains/edit.php:43
+msgid "Domain admin"
+msgstr "Amministratore dominio"
+
+#: domains/delete.php:40
+msgid "Domain deleted."
+msgstr "Dominio eliminato."
+
+#: domains/delete.php:47
+msgid "Domain not deleted."
+msgstr "Dominio non eliminato."
+
+#: domains/edit.php:54
+msgid "Domain saved."
+msgstr "Dominio salvato."
+
+#: domains/edit.php:34 domains/index.php:49
+msgid "Edit Domain"
+msgstr "Modifica Dominio"
+
+#: virtuals/index.php:53 users/index.php:64
+msgid "Edit User"
+msgstr "Modifica Utente"
+
+#: users/edit.php:52
+#, php-format
+msgid "Edit User for '%s'"
+msgstr "Modifica Utente per '%s'"
+
+#: virtuals/edit.php:48
+msgid "Edit Virtual Email Address"
+msgstr "Modifica Indirizzo Email Virtuale"
+
+#: virtuals/edit.php:54 templates/virtuals/index.html:35
+msgid "Email"
+msgstr "Email"
+
+#: users/edit.php:66
+msgid "Enabled?"
+msgstr "Attivato?"
+
+#: virtuals/edit.php:54
+#, php-format
+msgid ""
+"Enter a virtual email address for the '@%s' domain. Address must begin with "
+"an alphanumerical character, it must contain only alphanumerical and '._-' "
+"characters, and must end with an alphanumerical character."
+msgstr ""
+"Inserisci un indirizzo email virtuale per il '@%s' dominio. L'indirizzo deve "
+"iniziare con un carattere alfanumerico, deve avere solo caratteri "
+"alfanumerici e '._-' caratteri, e deve finire con un carattere alfanumerico."
+
+#: domains/delete.php:38
+#, php-format
+msgid "Error deleting domain. %s."
+msgstr "Errore durante l'eliminazione del dominio. %s."
+
+#: users/delete.php:43
+#, php-format
+msgid "Error deleting user. %s."
+msgstr "Errore durante l'eliminazione dell'utente. %s."
+
+#: virtuals/delete.php:47
+#, php-format
+msgid "Error deleting virtual email. %s."
+msgstr "Errore durante l'eliminazione del indirizzo email virtuale. %s."
+
+#: lib/Driver.php:254 lib/Driver.php:288
+msgid "Error running authentication update script."
+msgstr ""
+
+#: domains/edit.php:52
+#, php-format
+msgid "Error saving domain. %s."
+msgstr "Errore durante il salvataggio del dominio. %s."
+
+#: users/edit.php:76
+#, fuzzy, php-format
+msgid "Error saving user. %s"
+msgstr "Errore durante il salvataggio dell'utente. %s."
+
+#: virtuals/edit.php:62
+#, php-format
+msgid "Error saving virtual email. %s."
+msgstr "Errore durante il salvataggio indirizzo email virtuale. %s."
+
+#: templates/users/index.html:39
+msgid "Full Name"
+msgstr "Nome Completo"
+
+#: lib/MailboxDriver/imap.php:42
+#, fuzzy, php-format
+msgid "Mailbox '%s@%s' does not exist."
+msgstr "Messaggio inesistente."
+
+#: lib/MailboxDriver/maildrop.php:49
+#, fuzzy, php-format
+msgid "Maildrop directory '%s' does not exist."
+msgstr "Cartella VFS non esiste."
+
+#: templates/domains/index.html:37
+#, fuzzy
+msgid "Max Users"
+msgstr "Utenti max"
+
+#: domains/edit.php:44
+msgid "Max users"
+msgstr "Utenti max"
+
+#: users/index.php:46
+msgid "Maximum Users"
+msgstr "Utenti massimi"
+
+#: users/edit.php:65
+msgid "Name"
+msgstr "Nome"
+
+#: users/edit.php:59
+msgid ""
+"Name must begin with an alphanumerical character, it must contain only "
+"alphanumerical and '._-' characters, and must end with an alphanumerical "
+"character."
+msgstr ""
+"Il nome deve iniziare con un carattere alfanumerico, deve avere solo "
+"caratteri alfanumerici e '._-' caratteri, e deve finire con un carattere "
+"alfanumerico."
+
+#: domains/edit.php:34 domains/index.php:44
+msgid "New Domain"
+msgstr "Nuovo Dominio"
+
+#: users/index.php:43
+msgid "New User"
+msgstr "Nuovo Utente"
+
+#: users/edit.php:52
+#, php-format
+msgid "New User for '%s'"
+msgstr "Nuovo Utente per '%s'"
+
+#: virtuals/index.php:45 users/index.php:50
+msgid "New Virtual Email"
+msgstr "Dettagli Email Virtuale"
+
+#: virtuals/edit.php:48
+msgid "New Virtual Email Address"
+msgstr "Nuovo Indirizzo Email Virtuale"
+
+#: lib/MailboxDriver/maildrop.php:20
+msgid "No 'mail_dir_base' parameter specified to maildrop driver."
+msgstr ""
+
+#: lib/MailboxDriver/maildrop.php:64
+msgid "No 'system_user' parameter specified to maildrop driver."
+msgstr ""
+
+#: lib/Driver.php:172
+#, php-format
+msgid "No such backend '%s' found"
+msgstr "Nessun backend '%s' trovato"
+
+#: users/edit.php:86
+msgid ""
+"No virtual email address set up for this user. You should set up at least "
+"one virtual email address if this user is to receive any emails."
+msgstr ""
+"Nessun indirizzo email virtuale impostato per questo utente. Dovresti "
+"impostare al meno un indirizzo email virtuale se questo utente e' da "
+"ricevere gli email."
+
+#: lib/Driver.php:114
+msgid "No virtual emails set."
+msgstr "Nessun indirizzo email virtuale inserito."
+
+#: users/edit.php:61
+msgid "Only enter a password if you wish to change this user's password"
+msgstr ""
+"Inserisci una password solo nel caso in cui vuoi cambiare la password di "
+"questo utente."
+
+#: users/edit.php:61 users/edit.php:63
+msgid "Password"
+msgstr "Password"
+
+#: lib/Driver/sql.php:337
+msgid "Password must be supplied when creating a new user."
+msgstr ""
+
+#: domains/edit.php:45 templates/users/index.html:41
+msgid "Quota"
+msgstr "Quota"
+
+#: templates/index/notconfigured.inc:39
+#, fuzzy
+msgid "Some of Vilma's configuration files are missing:"
+msgstr "Mancano alcuni file di configurazione di Nag:"
+
+#: templates/users/index.html:43
+msgid "Status"
+msgstr "Statis"
+
+#: lib/MailboxDriver.php:77
+msgid "This driver cannot create mailboxes."
+msgstr ""
+
+#: lib/MailboxDriver.php:93
+#, fuzzy
+msgid "This driver cannot delete mailboxes."
+msgstr "Non era possibile eliminare il file:"
+
+#: templates/index/notconfigured.inc:44
+#, fuzzy
+msgid ""
+"This is the main Vilma configuration file. It contains options for all Vilma "
+"scripts."
+msgstr ""
+"Questo è il file principale di configurazione di Nag. Contiene le opzioni "
+"per tutti gli scripts di Nag."
+
+#: domains/edit.php:42
+msgid "Transport"
+msgstr "Trasporto"
+
+#: lib/Driver.php:258 lib/Driver.php:292
+msgid "Unknown error running authentication update script."
+msgstr ""
+
+#: users/edit.php:59
+msgid "User"
+msgstr "Utente"
+
+#: templates/users/index.html:37
+#, fuzzy
+msgid "User Name"
+msgstr "Nome Utente"
+
+#: users/delete.php:45
+msgid "User deleted."
+msgstr "Utente eliminato."
+
+#: users/edit.php:78
+msgid "User details saved."
+msgstr "Dettagli utente salvati."
+
+#: lib/Driver.php:107
+msgid "User disabled."
+msgstr "Utente disattivato."
+
+#: users/edit.php:67
+msgid "User is disabled"
+msgstr "L'utente e' disattivato."
+
+#: users/edit.php:66
+msgid "User is enabled"
+msgstr "L'utente e' attivato."
+
+#: users/delete.php:52
+msgid "User not deleted."
+msgstr "Utente non eliminato."
+
+#: lib/Driver.php:137
+msgid "User ready."
+msgstr "Utente pronto."
+
+#: virtuals/index.php:48
+msgid "Users"
+msgstr "Utenti"
+
+#: domains/edit.php:45
+msgid "Value in MB"
+msgstr "Valore in MB"
+
+#: templates/index/notconfigured.inc:4
+#, fuzzy
+msgid "Vilma is not properly configured"
+msgstr "Nag non è configurato correttamente."
+
+#: virtuals/delete.php:49
+msgid "Virtual email deleted."
+msgstr "Indirizzo email virtuale eliminato."
+
+#: virtuals/delete.php:56
+msgid "Virtual email not deleted."
+msgstr "Indirizzo email virtuale non eliminato."
+
+#: virtuals/edit.php:64
+msgid "Virtual email saved."
+msgstr "Indirizzo email virtuale salvato."
diff --git a/vilma/po/lt_LT.po b/vilma/po/lt_LT.po
new file mode 100644 (file)
index 0000000..6eb3034
--- /dev/null
@@ -0,0 +1,484 @@
+# Lithuanian translations for Vilma package.
+# Copyright 2007-2009 The Horde Project
+# This file is distributed under the same license as the Vilma package.
+# Vilius Sumskas <vilius@lnk.lt>, 2004, 2007.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vilma 0.2-cvs\n"
+"Report-Msgid-Bugs-To: dev@lists.horde.org\n"
+"POT-Creation-Date: 2007-11-02 15:40+0200\n"
+"PO-Revision-Date: 2007-11-11 20:02+0200\n"
+"Last-Translator: Vilius Sumskas <vilius@lnk.lt>\n"
+"Language-Team: Lithuanian <vilius@lnk.lt>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-13\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%"
+"100<10 || n%100>=20) ? 1 : 2);\n"
+
+#: users/edit.php:53
+#, php-format
+msgid "\"%s\" already has the maximum number of users allowed."
+msgstr "\"%s\" jau pasiekë maksimalø vartotojø skaièiø."
+
+#: lib/Driver/qmailldap.php:670
+msgid "Account Status"
+msgstr "Paðto dëþutës bûsena"
+
+#: lib/Driver/qmailldap.php:678
+msgid "Account is active"
+msgstr "Paðto dëþutë ájungta"
+
+#: lib/Driver/qmailldap.php:681
+msgid "Account is disabled"
+msgstr "Paðto dëþutë iðjungta"
+
+#: templates/users/index.html:13
+msgid "Address"
+msgstr "Adresas"
+
+#: lib/Vilma.php:60
+msgid "Alias"
+msgstr "Pravardë"
+
+#: lib/Driver/qmailldap.php:371
+#, php-format
+msgid "Alias for %s"
+msgstr "Su %s susieti adresai"
+
+#: lib/Vilma.php:61
+msgid "Aliases"
+msgstr "Susieti adresai"
+
+#: lib/Vilma.php:54 lib/Vilma.php:55
+msgid "All"
+msgstr "Viskà"
+
+#: lib/Driver/qmailldap.php:680
+msgid "Bounce Incoming Only"
+msgstr "Tik persiøsti gaunamus"
+
+#: domains/delete.php:29 domains/delete.php:33 users/delete.php:34
+#: users/delete.php:38 virtuals/delete.php:34 virtuals/delete.php:38
+msgid "Delete"
+msgstr "Iðtrinti"
+
+#: domains/index.php:44 domains/delete.php:26
+msgid "Delete Domain"
+msgstr "Iðtrinti domenà"
+
+#: users/index.php:82 users/delete.php:31 virtuals/index.php:55
+msgid "Delete User"
+msgstr "Iðtrinti vartotojà"
+
+#: virtuals/delete.php:31
+msgid "Delete Virtual Email Address"
+msgstr "Iðtrinti virtualø el. paðto adresà"
+
+#: domains/delete.php:31
+#, php-format
+msgid "Delete domain \"%s\", all the users and virtual email addresses?"
+msgstr ""
+"Iðtrinti domenà \"%s\", visus vartotojus ir virtualius el. paðto adresus?"
+
+#: virtuals/delete.php:36
+#, php-format
+msgid "Delete the virtual email address \"%s\" => \"%s\"?"
+msgstr "Iðtrinti virtualø el. paðto adresà \"%s\" => \"%s\"?"
+
+#: users/delete.php:36
+#, php-format
+msgid "Delete user \"%s\" and all associated virtual email addresses?"
+msgstr ""
+"Iðtrinti vartotojà \"%s\" ir visus susijusius virtualius el. paðto adresus?"
+
+#: virtuals/edit.php:64 templates/virtuals/index.html:20
+msgid "Destination"
+msgstr "Gavëjas"
+
+#: virtuals/edit.php:54
+msgid "Destination type"
+msgstr "Gavëjo tipas"
+
+#: lib/Driver/qmailldap.php:679
+msgid "Disable Delivery Only"
+msgstr "Tik iðjungti pristatymà"
+
+#: config/prefs.php.dist:10
+msgid "Display details"
+msgstr "Vaizdavimo nustatymai"
+
+#: config/prefs.php.dist:9
+msgid "Display listings"
+msgstr "Sàraðo rodymas"
+
+#: domains/delete.php:29 domains/delete.php:47 users/delete.php:34
+#: users/delete.php:52 virtuals/delete.php:34 virtuals/delete.php:52
+msgid "Do not delete"
+msgstr "Netrinti"
+
+#: lib/Forms/EditDomainForm.php:32 templates/domains/index.html:16
+msgid "Domain"
+msgstr "Domenas"
+
+#: domains/delete.php:41
+msgid "Domain deleted."
+msgstr "Domenas iðtrintas."
+
+#: domains/delete.php:48
+msgid "Domain not deleted."
+msgstr "Domenas neiðtrintas."
+
+#: domains/edit.php:35
+msgid "Domain saved."
+msgstr "Domenas iðsaugotas."
+
+#: domains/index.php:45 lib/Forms/EditDomainForm.php:20
+msgid "Edit Domain"
+msgstr "Redaguoti domenà"
+
+#: users/index.php:83 virtuals/index.php:56
+msgid "Edit User"
+msgstr "Redaguoti vartotojà"
+
+#: lib/Forms/EditUserForm.php:22
+#, php-format
+msgid "Edit User for \"%s\""
+msgstr "Redaguoti \"%s\" vartotojà"
+
+#: virtuals/edit.php:47
+msgid "Edit Virtual Email Address"
+msgstr "Redaguoti virtualius el. paðto adresus"
+
+#: virtuals/edit.php:53
+#, php-format
+msgid ""
+"Enter a virtual email address @%s and then indicate below where mail sent to "
+"that address is to be delivered. The address must begin with an "
+"alphanumerical character, it must contain only alphanumerical and '._-' "
+"characters, and must end with an alphanumerical character."
+msgstr ""
+"Áraðykite virtualø el. paðto adresà domenui @%s. Adresas turi prasidëti "
+"skaièiais arba raidëm, viduje gali turëti skaièius, raides arba '._-' "
+"simbolius, ir turi baigtis skaièiais arba raidëmis."
+
+#: lib/Driver/qmailldap.php:616
+#, php-format
+msgid "Error deleting account from LDAP: %s"
+msgstr "Klaida trinant vartotojo vardà ið LDAP: %s"
+
+#: domains/delete.php:39
+#, php-format
+msgid "Error deleting domain. %s."
+msgstr "Klaida trinant domenà. %s."
+
+#: users/delete.php:44
+#, php-format
+msgid "Error deleting user. %s."
+msgstr "Klaida trinant vartotojà. %s."
+
+#: virtuals/delete.php:44
+#, php-format
+msgid "Error deleting virtual email. %s."
+msgstr "Klaida trinant virtualø el. paðto adresà. %s."
+
+#: lib/Driver/qmailldap.php:210 lib/Driver/qmailldap.php:215
+#, php-format
+msgid "Error in LDAP search: %s"
+msgstr "Klaida atliekant LDAP paieðkà: %s"
+
+#: users/edit.php:35
+#, php-format
+msgid "Error reading address information from backend: %s"
+msgstr "Klaida ið posistemës skaitant adresø informacijà: %s"
+
+#: lib/Driver/qmailldap.php:606
+#, php-format
+msgid "Error retrieving LDAP results: %s"
+msgstr "Klaida gaunant LDAP rezultatus: %s"
+
+#: lib/Driver/qmailldap.php:347 lib/Driver/qmailldap.php:435
+#: lib/Driver/qmailldap.php:507
+#, php-format
+msgid "Error returning LDAP results: %s"
+msgstr "Klaida graþinant LDAP rezultatus: %s"
+
+#: lib/Driver.php:195
+msgid "Error running authentication update script."
+msgstr "Klaida leidþiant autentifikacijos atnaujinimo skriptà."
+
+#: domains/edit.php:33
+#, php-format
+msgid "Error saving domain: %s."
+msgstr "Klaida iðsaugant domenà: %s."
+
+#: users/edit.php:64
+#, php-format
+msgid "Error saving user. %s"
+msgstr "Klaida iðsaugant vartotojà. %s"
+
+#: virtuals/edit.php:77
+#, php-format
+msgid "Error saving virtual email. %s."
+msgstr "Klaida iðsaugant virtualø el. paðto adresà. %s."
+
+#: lib/Driver/qmailldap.php:341 lib/Driver/qmailldap.php:429
+#: lib/Driver/qmailldap.php:501 lib/Driver/qmailldap.php:600
+#, php-format
+msgid "Error searching LDAP: %s"
+msgstr "Klaida atliekant LDAP paieðkà: %s"
+
+#: lib/Forms/EditUserForm.php:41 templates/users/index.html:16
+msgid "Full Name"
+msgstr "Pilnas vardas"
+
+#: lib/Vilma.php:63
+msgid "Group/Forward"
+msgstr "Grupë/Persiuntimas"
+
+#: lib/Vilma.php:64
+msgid "Groups and Forwards"
+msgstr "Grupës ir persiuntimai"
+
+#: config/prefs.php.dist:20
+msgid "How many domain to display per page."
+msgstr "Kiek domenø rodyti viename puslapyje."
+
+#: virtuals/edit.php:56
+msgid "Local user"
+msgstr "Vietinis vartotojas"
+
+#: lib/MailboxDriver/imap.php:45
+#, php-format
+msgid "Mailbox '%s@%s' does not exist."
+msgstr "Paðto dëþutë '%s@%s' neegzistuoja."
+
+#: lib/MailboxDriver/maildrop.php:45
+#, php-format
+msgid "Maildrop directory \"%s\" does not exist."
+msgstr "Maildrop katalogas \"%s\" neegzistuoja."
+
+#: templates/domains/index.html:19
+msgid "Max Users"
+msgstr "Maks. vartotojø skaièius"
+
+#: lib/Forms/EditDomainForm.php:35
+msgid "Max users"
+msgstr "Maks. vartotojø skaièius"
+
+#: users/index.php:69
+msgid "Maximum Users"
+msgstr "Maks. vartotojø skaièius"
+
+#: lib/Driver/qmailldap.php:511
+msgid ""
+"More than one DN returned for this alias.  Please contact an administrator "
+"to resolve this error."
+msgstr ""
+"Rastas daugiau nei vienas DN atitinkantis ðá vartotojà. Susisiekite su "
+"administratoriumi."
+
+#: lib/Driver/qmailldap.php:610
+msgid "More than one DN returned.  Aborting delete operation."
+msgstr "Rastas daugiau nei vienas DN. Trynimo operacija nutraukiama."
+
+#: lib/Forms/EditUserForm.php:35
+msgid ""
+"Name must begin with an alphanumeric character, must contain only "
+"alphanumeric and '._-' characters, and must end with an alphanumeric "
+"character."
+msgstr ""
+"Vardas turi prasidëti skaièiais arba raidëm, viduje gali turëti skaièius, "
+"raides arba simbolius '._-', ir turi baigtis skaièiais arba raidëmis."
+
+#: lib/Forms/EditDomainForm.php:20
+msgid "New Domain"
+msgstr "Naujas domenas"
+
+#: lib/Forms/EditUserForm.php:24
+#, php-format
+msgid "New User @%s"
+msgstr "Naujas @%s vartotojas"
+
+#: virtuals/index.php:48
+msgid "New Virtual Email"
+msgstr "Naujas virtualus el. paðtas"
+
+#: virtuals/edit.php:47
+msgid "New Virtual Email Address"
+msgstr "Naujas virtualus el. paðto adresas"
+
+#: lib/Vilma.php:169
+msgid "New _Address"
+msgstr "Naujas adresas"
+
+#: lib/MailboxDriver/maildrop.php:19
+msgid "No 'mail_dir_base' parameter specified to maildrop driver."
+msgstr "Maildrop tvarkyklëje neáraðytas 'mail_dir_base' parametras."
+
+#: lib/MailboxDriver/maildrop.php:60
+msgid "No 'system_user' parameter specified to maildrop driver."
+msgstr "Maildrop tvarkyklëje neáraðytas 'system_user' parametras."
+
+#: lib/Driver.php:108
+#, php-format
+msgid "No such address %s of type %s found."
+msgstr "Adresas %s, kurio tipas %s, nerastas."
+
+#: lib/Driver.php:329
+#, php-format
+msgid "No such backend \"%s\" found"
+msgstr "Posistemë \"%s\" nerasta"
+
+#: users/edit.php:74
+msgid ""
+"No virtual email address set up for this user. You should set up at least "
+"one virtual email address if this user is to receive any emails."
+msgstr ""
+"Ðis vartotojas neturi virtualiø el. paðto adresø. Jeigu ðis vartotojas gauna "
+"el. laiðkus, turëtumëte nurodyti bent vienà virtualø el. paðto adresà."
+
+#: lib/Driver.php:249
+msgid "Not implemented."
+msgstr "Nerealizuota."
+
+#: lib/Forms/EditUserForm.php:37
+msgid "Only enter a password if you wish to change this user's password"
+msgstr "Slaptaþodá áraðykite tik tada, jeigu já keièiate"
+
+#: lib/Forms/EditUserForm.php:37 lib/Forms/EditUserForm.php:39
+msgid "Password"
+msgstr "Slaptaþodis"
+
+#: lib/Driver/sql.php:465
+msgid "Password must be supplied when creating a new user."
+msgstr "Kurdami naujà vartotojà, privalote áraðyti slaptaþodá."
+
+#: lib/Forms/EditDomainForm.php:36
+msgid "Quota"
+msgstr "Vieta serveryje"
+
+#: virtuals/edit.php:57
+msgid "Remote address"
+msgstr "Iðoriniai adresai"
+
+#: virtuals/edit.php:61
+msgid "Remote e-mail address"
+msgstr "Iðorinis el. paðto adresas"
+
+#: config/prefs.php.dist:11
+msgid "Set default display parameters."
+msgstr "Standartinio vaizdavimo parametrø nustatymas."
+
+#: templates/users/index.html:22
+msgid "Status"
+msgstr "Bûsena"
+
+#: lib/api.php:43
+msgid "Super Administrator"
+msgstr "Super administratorius"
+
+#: lib/MailboxDriver.php:78
+msgid "This driver cannot create mailboxes."
+msgstr "Ði tvarkyklë negali kurti paðto dëþuèiø."
+
+#: lib/MailboxDriver.php:94
+msgid "This driver cannot delete mailboxes."
+msgstr "Ði tvarkyklë negali trinti paðto dëþuèiø."
+
+#: lib/Forms/EditDomainForm.php:34
+msgid "Transport"
+msgstr "Transportas"
+
+#: templates/users/index.html:19
+msgid "Type"
+msgstr "Tipas"
+
+#: lib/Driver/qmailldap.php:715
+msgid "Unable to bind to the LDAP server.  Check authentication credentials."
+msgstr ""
+"Nepavyko autentifikuotis á LDAP serverá. Patikrinkite vartotojo vardà bei "
+"slaptaþodá."
+
+#: lib/Driver/qmailldap.php:710
+msgid "Unable to set LDAP protocol version"
+msgstr "Klaida keièiant LDAP protokolo versijà"
+
+#: lib/Driver.php:199
+msgid "Unknown error running authentication update script."
+msgstr "Bevykdant autentifikacijos atnaujinimo skriptà ávyko neþinoma klaida."
+
+#: lib/Vilma.php:57
+msgid "User"
+msgstr "Vartotojas"
+
+#: lib/Forms/EditUserForm.php:35
+msgid "User Name"
+msgstr "Vartotojo vardas"
+
+#: users/delete.php:46
+msgid "User deleted."
+msgstr "Vartotojas iðtrintas."
+
+#: users/edit.php:66
+msgid "User details saved."
+msgstr "Vartotojo apraðymas iðsaugotas."
+
+#: lib/Driver.php:132
+msgid "User disabled."
+msgstr "Vartotojas iðjungtas"
+
+#: users/delete.php:53
+msgid "User not deleted."
+msgstr "Vartotojas neiðtrintas."
+
+#: lib/Driver.php:155
+msgid "User ready."
+msgstr "Vartotojas paruoðtas."
+
+#: lib/Vilma.php:58 virtuals/index.php:51
+msgid "Users"
+msgstr "Vartotojai"
+
+#: lib/Forms/EditDomainForm.php:36
+msgid "Value in MB"
+msgstr "Reikðmë MB"
+
+#: lib/Driver.php:210
+msgid "Vilma_Driver::deleteUser(): Method Not Implemented."
+msgstr "Vilma_Driver::deleteUser(): metodas nerealizuotas."
+
+#: virtuals/edit.php:53
+msgid "Virtual Email"
+msgstr "Virtualus el. paðtas"
+
+#: templates/virtuals/index.html:17
+msgid "Virtual Email Address"
+msgstr "Virtualus el. paðto adresas"
+
+#: virtuals/delete.php:46
+msgid "Virtual email deleted."
+msgstr "Virtualus el. paðto adresas iðtrintas."
+
+#: virtuals/delete.php:53
+msgid "Virtual email not deleted."
+msgstr "Virtualus el. paðto adresas neiðtrintas."
+
+#: virtuals/edit.php:79
+msgid "Virtual email saved."
+msgstr "Virtualus el. paðto adresas iðsaugotas."
+
+#: lib/Driver/qmailldap.php:35
+msgid "You must configure a Horde DataTree backend to use Vilma."
+msgstr ""
+"Norëdami naugotis paðto valdymo sistema, turite sukonfigûruoti duomenø "
+"medþio posistemæ."
+
+#: lib/Vilma.php:166
+msgid "_Domains"
+msgstr "Domenai"
+
+#: lib/Vilma.php:171
+msgid "_New Domain"
+msgstr "Naujas domenas"
diff --git a/vilma/po/vilma.pot b/vilma/po/vilma.pot
new file mode 100644 (file)
index 0000000..be999fd
--- /dev/null
@@ -0,0 +1,476 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright YEAR Horde Project
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: dev@lists.horde.org\n"
+"POT-Creation-Date: 2008-04-01 14:58+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"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: users/edit.php:53
+#, php-format
+msgid "\"%s\" already has the maximum number of users allowed."
+msgstr ""
+
+#: lib/Driver/qmailldap.php:647
+msgid "Account Status"
+msgstr ""
+
+#: lib/Driver/qmailldap.php:655
+msgid "Account is active"
+msgstr ""
+
+#: lib/Driver/qmailldap.php:658
+msgid "Account is disabled"
+msgstr ""
+
+#: templates/users/index.html:13
+msgid "Address"
+msgstr ""
+
+#: lib/Vilma.php:60
+msgid "Alias"
+msgstr ""
+
+#: lib/Driver/qmailldap.php:332
+#, php-format
+msgid "Alias for %s"
+msgstr ""
+
+#: lib/Vilma.php:61
+msgid "Aliases"
+msgstr ""
+
+#: lib/Vilma.php:54 lib/Vilma.php:55
+msgid "All"
+msgstr ""
+
+#: lib/Driver/qmailldap.php:657
+msgid "Bounce Incoming Only"
+msgstr ""
+
+#: domains/delete.php:27 users/delete.php:34 users/delete.php:38
+#: virtuals/delete.php:34 virtuals/delete.php:38
+#: lib/Forms/DeleteDomainForm.php:27
+msgid "Delete"
+msgstr ""
+
+#: domains/index.php:44 lib/Forms/DeleteDomainForm.php:17
+msgid "Delete Domain"
+msgstr ""
+
+#: users/index.php:83 users/delete.php:31 virtuals/index.php:55
+msgid "Delete User"
+msgstr ""
+
+#: virtuals/delete.php:31
+msgid "Delete Virtual Email Address"
+msgstr ""
+
+#: lib/Forms/DeleteDomainForm.php:29
+#, php-format
+msgid "Delete domain \"%s\" and all associated email addresses?"
+msgstr ""
+
+#: virtuals/delete.php:36
+#, php-format
+msgid "Delete the virtual email address \"%s\" => \"%s\"?"
+msgstr ""
+
+#: users/delete.php:36
+#, php-format
+msgid "Delete user \"%s\" and all associated virtual email addresses?"
+msgstr ""
+
+#: virtuals/edit.php:64 templates/virtuals/index.html:20
+msgid "Destination"
+msgstr ""
+
+#: virtuals/edit.php:54
+msgid "Destination type"
+msgstr ""
+
+#: lib/Driver/qmailldap.php:656
+msgid "Disable Delivery Only"
+msgstr ""
+
+#: config/prefs.php.dist:10
+msgid "Display details"
+msgstr ""
+
+#: config/prefs.php.dist:9
+msgid "Display listings"
+msgstr ""
+
+#: domains/delete.php:41 users/delete.php:34 users/delete.php:52
+#: virtuals/delete.php:34 virtuals/delete.php:52
+#: lib/Forms/DeleteDomainForm.php:27
+msgid "Do not delete"
+msgstr ""
+
+#: lib/Forms/EditDomainForm.php:32 templates/domains/index.html:16
+msgid "Domain"
+msgstr ""
+
+#: lib/Driver.php:229
+msgid ""
+"Domain added but an error was encountered while calling the configured "
+"hook.  Contact your administrator for futher assistance."
+msgstr ""
+
+#: domains/delete.php:35
+msgid "Domain deleted."
+msgstr ""
+
+#: domains/delete.php:42
+msgid "Domain not deleted."
+msgstr ""
+
+#: domains/edit.php:35
+msgid "Domain saved."
+msgstr ""
+
+#: domains/index.php:45 lib/Forms/EditDomainForm.php:20
+msgid "Edit Domain"
+msgstr ""
+
+#: users/index.php:84 virtuals/index.php:56
+msgid "Edit User"
+msgstr ""
+
+#: lib/Forms/EditUserForm.php:22
+#, php-format
+msgid "Edit User for \"%s\""
+msgstr ""
+
+#: virtuals/edit.php:47
+msgid "Edit Virtual Email Address"
+msgstr ""
+
+#: virtuals/edit.php:53
+#, php-format
+msgid ""
+"Enter a virtual email address @%s and then indicate below where mail sent to "
+"that address is to be delivered. The address must begin with an "
+"alphanumerical character, it must contain only alphanumerical and '._-' "
+"characters, and must end with an alphanumerical character."
+msgstr ""
+
+#: lib/Driver/qmailldap.php:593
+#, php-format
+msgid "Error deleting account from LDAP: %s"
+msgstr ""
+
+#: domains/delete.php:33
+#, php-format
+msgid "Error deleting domain. %s."
+msgstr ""
+
+#: users/delete.php:44
+#, php-format
+msgid "Error deleting user. %s."
+msgstr ""
+
+#: virtuals/delete.php:44
+#, php-format
+msgid "Error deleting virtual email. %s."
+msgstr ""
+
+#: lib/Driver/qmailldap.php:170 lib/Driver/qmailldap.php:175
+#, php-format
+msgid "Error in LDAP search: %s"
+msgstr ""
+
+#: users/edit.php:35
+#, php-format
+msgid "Error reading address information from backend: %s"
+msgstr ""
+
+#: lib/Driver/qmailldap.php:583
+#, php-format
+msgid "Error retrieving LDAP results: %s"
+msgstr ""
+
+#: lib/Driver/qmailldap.php:308 lib/Driver/qmailldap.php:396
+#: lib/Driver/qmailldap.php:468
+#, php-format
+msgid "Error returning LDAP results: %s"
+msgstr ""
+
+#: lib/Driver.php:195
+msgid "Error running authentication update script."
+msgstr ""
+
+#: domains/edit.php:33
+#, php-format
+msgid "Error saving domain: %s."
+msgstr ""
+
+#: users/edit.php:64
+#, php-format
+msgid "Error saving user. %s"
+msgstr ""
+
+#: virtuals/edit.php:77
+#, php-format
+msgid "Error saving virtual email. %s."
+msgstr ""
+
+#: lib/Driver/qmailldap.php:302 lib/Driver/qmailldap.php:390
+#: lib/Driver/qmailldap.php:462 lib/Driver/qmailldap.php:577
+#, php-format
+msgid "Error searching LDAP: %s"
+msgstr ""
+
+#: lib/Driver.php:280
+msgid "Error while calling hook to delete domain."
+msgstr ""
+
+#: lib/Forms/EditUserForm.php:41 templates/users/index.html:16
+msgid "Full Name"
+msgstr ""
+
+#: lib/Vilma.php:63
+msgid "Group/Forward"
+msgstr ""
+
+#: lib/Vilma.php:64
+msgid "Groups and Forwards"
+msgstr ""
+
+#: config/prefs.php.dist:20
+msgid "How many domain to display per page."
+msgstr ""
+
+#: virtuals/edit.php:56
+msgid "Local user"
+msgstr ""
+
+#: lib/MailboxDriver/imap.php:45
+#, php-format
+msgid "Mailbox '%s@%s' does not exist."
+msgstr ""
+
+#: lib/MailboxDriver/maildrop.php:45
+#, php-format
+msgid "Maildrop directory \"%s\" does not exist."
+msgstr ""
+
+#: templates/domains/index.html:19
+msgid "Max Users"
+msgstr ""
+
+#: lib/Forms/EditDomainForm.php:35
+msgid "Max users"
+msgstr ""
+
+#: users/index.php:70
+msgid "Maximum Users"
+msgstr ""
+
+#: lib/Driver/qmailldap.php:472
+msgid ""
+"More than one DN returned for this alias.  Please contact an administrator "
+"to resolve this error."
+msgstr ""
+
+#: lib/Driver/qmailldap.php:587
+msgid "More than one DN returned.  Aborting delete operation."
+msgstr ""
+
+#: lib/Forms/EditUserForm.php:35
+msgid ""
+"Name must begin with an alphanumeric character, must contain only "
+"alphanumeric and '._-' characters, and must end with an alphanumeric "
+"character."
+msgstr ""
+
+#: lib/Forms/EditDomainForm.php:20
+msgid "New Domain"
+msgstr ""
+
+#: lib/Forms/EditUserForm.php:24
+#, php-format
+msgid "New User @%s"
+msgstr ""
+
+#: virtuals/index.php:48
+msgid "New Virtual Email"
+msgstr ""
+
+#: virtuals/edit.php:47
+msgid "New Virtual Email Address"
+msgstr ""
+
+#: lib/Vilma.php:169
+msgid "New _Address"
+msgstr ""
+
+#: lib/MailboxDriver/maildrop.php:19
+msgid "No 'mail_dir_base' parameter specified to maildrop driver."
+msgstr ""
+
+#: lib/MailboxDriver/maildrop.php:60
+msgid "No 'system_user' parameter specified to maildrop driver."
+msgstr ""
+
+#: lib/Driver.php:108
+#, php-format
+msgid "No such address %s of type %s found."
+msgstr ""
+
+#: lib/Driver.php:374
+#, php-format
+msgid "No such backend \"%s\" found"
+msgstr ""
+
+#: users/edit.php:74
+msgid ""
+"No virtual email address set up for this user. You should set up at least "
+"one virtual email address if this user is to receive any emails."
+msgstr ""
+
+#: lib/Driver.php:245 lib/Driver.php:294
+msgid "Not implemented."
+msgstr ""
+
+#: lib/Forms/EditUserForm.php:37
+msgid "Only enter a password if you wish to change this user's password"
+msgstr ""
+
+#: lib/Forms/EditUserForm.php:37 lib/Forms/EditUserForm.php:39
+msgid "Password"
+msgstr ""
+
+#: lib/Driver/sql.php:465
+msgid "Password must be supplied when creating a new user."
+msgstr ""
+
+#: lib/Forms/EditDomainForm.php:36
+msgid "Quota"
+msgstr ""
+
+#: virtuals/edit.php:57
+msgid "Remote address"
+msgstr ""
+
+#: virtuals/edit.php:61
+msgid "Remote e-mail address"
+msgstr ""
+
+#: config/prefs.php.dist:11
+msgid "Set default display parameters."
+msgstr ""
+
+#: templates/users/index.html:22
+msgid "Status"
+msgstr ""
+
+#: lib/api.php:43
+msgid "Super Administrator"
+msgstr ""
+
+#: lib/MailboxDriver.php:78
+msgid "This driver cannot create mailboxes."
+msgstr ""
+
+#: lib/MailboxDriver.php:94
+msgid "This driver cannot delete mailboxes."
+msgstr ""
+
+#: lib/Forms/EditDomainForm.php:34
+msgid "Transport"
+msgstr ""
+
+#: templates/users/index.html:19
+msgid "Type"
+msgstr ""
+
+#: lib/Driver/qmailldap.php:696
+msgid "Unable to bind to the LDAP server.  Check authentication credentials."
+msgstr ""
+
+#: lib/Driver/qmailldap.php:691
+msgid "Unable to set LDAP protocol version"
+msgstr ""
+
+#: lib/Driver.php:199
+msgid "Unknown error running authentication update script."
+msgstr ""
+
+#: lib/Vilma.php:57
+msgid "User"
+msgstr ""
+
+#: lib/Forms/EditUserForm.php:35
+msgid "User Name"
+msgstr ""
+
+#: users/delete.php:46
+msgid "User deleted."
+msgstr ""
+
+#: users/edit.php:66
+msgid "User details saved."
+msgstr ""
+
+#: lib/Driver.php:132
+msgid "User disabled."
+msgstr ""
+
+#: users/delete.php:53
+msgid "User not deleted."
+msgstr ""
+
+#: lib/Driver.php:155
+msgid "User ready."
+msgstr ""
+
+#: virtuals/index.php:51 lib/Vilma.php:58
+msgid "Users"
+msgstr ""
+
+#: lib/Forms/EditDomainForm.php:36
+msgid "Value in MB"
+msgstr ""
+
+#: lib/Driver.php:210
+msgid "Vilma_Driver::deleteUser(): Method Not Implemented."
+msgstr ""
+
+#: virtuals/edit.php:53
+msgid "Virtual Email"
+msgstr ""
+
+#: templates/virtuals/index.html:17
+msgid "Virtual Email Address"
+msgstr ""
+
+#: virtuals/delete.php:46
+msgid "Virtual email deleted."
+msgstr ""
+
+#: virtuals/delete.php:53
+msgid "Virtual email not deleted."
+msgstr ""
+
+#: virtuals/edit.php:79
+msgid "Virtual email saved."
+msgstr ""
+
+#: lib/Vilma.php:166
+msgid "_Domains"
+msgstr ""
+
+#: lib/Vilma.php:171
+msgid "_New Domain"
+msgstr ""
diff --git a/vilma/scripts/.htaccess b/vilma/scripts/.htaccess
new file mode 100644 (file)
index 0000000..3a42882
--- /dev/null
@@ -0,0 +1 @@
+Deny from all
diff --git a/vilma/scripts/create_mailboxes.php b/vilma/scripts/create_mailboxes.php
new file mode 100644 (file)
index 0000000..03ce19b
--- /dev/null
@@ -0,0 +1,53 @@
+#!/usr/bin/php
+<?php
+/**
+ * This script will check the user table and create any mail directories on the
+ * system for any new users. A cron job can be set up to run this periodically.
+ *
+ * $Horde: vilma/scripts/create_mailboxes.php,v 1.6 2009/06/10 19:58:04 slusarz Exp $
+ */
+
+// No auth.
+@define('AUTH_HANDLER', true);
+
+@define('VILMA_BASE', dirname(__FILE__) . '/..');
+require_once VILMA_BASE . '/lib/base.php';
+
+// Make sure no one runs this from the web.
+if (!Horde_Cli::runningFromCLI()) {
+    exit("Must be run from the command line\n");
+}
+
+// Load the CLI environment - make sure there's no time limit, init
+// some variables, etc.
+Horde_Cli::init();
+
+/* Make sure there's no compression. */
+@ob_end_clean();
+
+$users_by_domain = $vilma_driver->getAllUsers();
+
+foreach ($users_by_domain as $domain => $users) {
+    foreach ($users as $user) {
+        /* Check for user's home dir. */
+        if (!file_exists($user['user_home_dir'])) {
+            /* Try to make the user_home_dir, if false skip. */
+            if (!mkdir($user['user_home_dir'])) {
+                continue;
+            }
+        }
+        /* Check for the domain's dir. */
+        $domain_dir = $user['user_home_dir'] . '/' . $domain;
+        if (!file_exists($domain_dir)) {
+            /* Try to make the user_home_dir, if false skip. */
+            if (!mkdir($domain_dir)) {
+                continue;
+            }
+        }
+        /* Check for user's mailbox directory and if missing create it. */
+        $mailbox_dir = $user['user_home_dir'] . '/' . $user['user_mail_dir'];
+        if (!file_exists($mailbox_dir)) {
+            system('maildirmake ' . $mailbox_dir);
+        }
+    }
+}
diff --git a/vilma/scripts/sql/vilma.sql b/vilma/scripts/sql/vilma.sql
new file mode 100644 (file)
index 0000000..c41ad9d
--- /dev/null
@@ -0,0 +1,41 @@
+--$Horde: vilma/scripts/sql/vilma.sql,v 1.8 2007/04/17 12:44:06 jan Exp $
+-- SQL scripts.
+
+CREATE TABLE vilma_domains (
+  domain_id         INT DEFAULT 0 NOT NULL,
+  domain_name       VARCHAR(128) DEFAULT '' NOT NULL,
+  domain_transport  VARCHAR(128) DEFAULT '' NOT NULL,
+  domain_max_users  INT DEFAULT 0 NOT NULL,
+  domain_quota      INT DEFAULT 0 NOT NULL,
+  domain_key        VARCHAR(64),
+--
+  PRIMARY KEY  (domain_id),
+  UNIQUE (domain_name)
+);
+
+CREATE TABLE vilma_users (
+  user_id           INT DEFAULT 0 NOT NULL,
+  user_name         VARCHAR(255) DEFAULT '' NOT NULL,
+  user_clear        VARCHAR(255) DEFAULT '' NOT NULL,
+  user_crypt        VARCHAR(255) DEFAULT '' NOT NULL,
+  user_full_name    VARCHAR(255) DEFAULT '' NOT NULL,
+  user_uid          INT NOT NULL,
+  user_gid          INT NOT NULL,
+  user_home_dir     VARCHAR(255) DEFAULT '' NOT NULL,
+  user_mail_dir     VARCHAR(255) DEFAULT '' NOT NULL,
+  user_mail_quota   INT DEFAULT 0 NOT NULL,
+  user_ftp_dir      VARCHAR(255) DEFAULT NULL,
+  user_ftp_quota    INT DEFAULT NULL,
+  user_enabled      SMALLINT DEFAULT 1 NOT NULL,
+--
+  PRIMARY KEY (user_id),
+  UNIQUE (user_name)
+);
+
+CREATE TABLE vilma_virtuals (
+  virtual_id            INT DEFAULT 0 NOT NULL,
+  virtual_email         VARCHAR(128) DEFAULT '' NOT NULL,
+  virtual_destination   VARCHAR(128) DEFAULT '' NOT NULL,
+--
+  PRIMARY KEY (virtual_id)
+);
diff --git a/vilma/templates/common-header.inc b/vilma/templates/common-header.inc
new file mode 100644 (file)
index 0000000..55130fc
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+if (isset($language)) {
+    header('Content-type: text/html; charset=' . Horde_Nls::getCharset());
+    header('Vary: Accept-Language');
+}
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">
+<!-- Vilma: Copyright 2003-2009 The Horde Project.  Vilma is under a Horde license. -->
+<!--   Horde Project: http://www.horde.org/ | Vilma: http://www.horde.org/vilma/    -->
+<!--          Horde BSD License: http://www.horde.org/licenses/bsdl.php            -->
+<?php echo !empty($language) ? '<html lang="' . strtr($language, '_', '-') . '">' : '<html>' ?>
+<head>
+<?php
+
+$page_title = $GLOBALS['registry']->get('name');
+if (!empty($title)) $page_title .= ' :: ' . $title;
+if (!empty($refresh_time) && ($refresh_time > 0) && !empty($refresh_url)) {
+    echo "<meta http-equiv=\"refresh\" content=\"$refresh_time;url=$refresh_url\">\n";
+}
+
+Horde::includeScriptFiles();
+
+?>
+<title><?php echo htmlspecialchars($page_title) ?></title>
+<link href="<?php echo $GLOBALS['registry']->getImageDir()?>/favicon.ico" rel="SHORTCUT ICON" />
+<?php Horde::includeStylesheetFiles() ?>
+</head>
+
+<body<?php if ($bc = Horde_Util::nonInputVar('bodyClass')) echo ' class="' . $bc . '"' ?><?php if ($bi = Horde_Util::nonInputVar('bodyId')) echo ' id="' . $bi . '"'; ?>>
diff --git a/vilma/templates/domains/index.html b/vilma/templates/domains/index.html
new file mode 100644 (file)
index 0000000..6bef877
--- /dev/null
@@ -0,0 +1,37 @@
+<div id="menu">
+ <tag:menu />
+</div>
+
+<tag:notify />
+
+<p class="item">
+ <a href="<tag:actions.new_url />"><tag:actions.new_text /></a>
+</p>
+
+<if:domains>
+<table width="100%" cellspacing="1" class="linedRow">
+ <tr class="item">
+  <th>&nbsp;</th>
+  <th>
+   <gettext>Domain</gettext>
+  </th>
+  <th>
+   <gettext>Max Users</gettext>
+  </th>
+ </tr>
+ <loop:domains>
+ <tr>
+  <td>
+   <a href="<tag:domains.edit_url />"><tag:images.edit /></a>
+   <a href="<tag:domains.del_url />"><tag:images.delete /></a>
+  </td>
+  <td>
+   <a href="<tag:domains.view_url />"><tag:domains.domain_name /></a>
+  </td>
+  <td class="rightAlign">
+   <tag:domains.domain_max_users />
+  </td>
+ </tr>
+ </loop:domains>
+</table>
+</if:domains>
diff --git a/vilma/templates/main/main.html b/vilma/templates/main/main.html
new file mode 100644 (file)
index 0000000..5c3c6ce
--- /dev/null
@@ -0,0 +1,5 @@
+<div id="menu">
+ <tag:menu />
+</div>
+<tag:notify />
+<tag:main />
diff --git a/vilma/templates/users/index.html b/vilma/templates/users/index.html
new file mode 100644 (file)
index 0000000..f4dad37
--- /dev/null
@@ -0,0 +1,62 @@
+<div id="menu">
+ <tag:menu />
+</div>
+
+<tag:notify />
+
+<tag:tabs />
+<if:addresses>
+<table width="100%" cellspacing="1" class="linedRow">
+ <tr class="item">
+  <th>&nbsp;</th>
+  <th>
+   <gettext>Address</gettext>
+  </th>
+  <th>
+   <gettext>Full Name</gettext>
+  </th>
+  <th>
+   <gettext>Type</gettext>
+  </th>
+  <th>
+   <gettext>Status</gettext>
+  </th>
+ </tr>
+ <loop:addresses>
+ <tr>
+  <td>
+   <if:addresses.edit_url>
+     <a href="<tag:addresses.edit_url />"><tag:images.edit /></a>
+   </if:addresses.edit_url>
+   <a href="<tag:addresses.del_url />"><tag:images.delete /></a>
+  </td>
+  <td>
+   <if:addresses.view_url>
+     <a href="<tag:addresses.view_url />">
+   </if:addresses.view_url>
+   <if:addresses.user_name>
+     <tag:addresses.user_name />&nbsp;
+   </if:addresses.user_name>
+   <if:addresses.address>
+     &lt;<tag:addresses.address />&gt;
+   </if:addresses.address>
+   <if:addresses.view_url>
+     </a>
+   </if:addresses.view_url>
+  </td>
+  <td align="center">
+   <tag:addresses.user_full_name />
+  </td>
+  <td class="rightAlign">
+   <tag:addresses.type />
+  </td>
+  <td>
+   <loop:addresses.status>
+    <tag:addresses.status /><br />
+   </loop:addresses.status>
+  </td>
+ </tr>
+ </loop:addresses>
+</table>
+</if:addresses>
+<tag:pager />
diff --git a/vilma/templates/virtuals/index.html b/vilma/templates/virtuals/index.html
new file mode 100644 (file)
index 0000000..88294f7
--- /dev/null
@@ -0,0 +1,38 @@
+<div id="menu">
+ <tag:menu />
+</div>
+
+<tag:notify />
+
+<p class="item">
+ &nbsp;<a href="<tag:actions.new_url />"><tag:actions.new_text /></a> |
+ &nbsp;<a href="<tag:actions.users_url />"><tag:actions.users_text /></a>
+</p>
+
+<if:virtuals>
+<table width="100%" cellspacing="1" class="linedRow">
+ <tr class="item">
+  <th>&nbsp;</th>
+  <th>
+   <gettext>Virtual Email Address</gettext>
+  </th>
+  <th>
+   <gettext>Destination</gettext>
+  </th>
+ </tr>
+ <loop:virtuals>
+ <tr>
+  <td>
+   <a href="<tag:virtuals.edit_url />"><tag:images.edit /></a>
+   <a href="<tag:virtuals.del_url />"><tag:images.delete /></a>
+  </td>
+  <td>
+   <tag:virtuals.virtual_email />
+  </td>
+  <td align="center">
+   <tag:virtuals.virtual_destination />
+  </td>
+ </tr>
+ </loop:virtuals>
+</table>
+</if:virtuals>
diff --git a/vilma/test.php b/vilma/test.php
new file mode 100644 (file)
index 0000000..9da2220
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/**
+ * $Horde: vilma/test.php,v 1.16 2009/01/06 18:02:26 jan Exp $
+ *
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * @author Marko Djukic <marko@oblo.com>
+ * @package Vilma
+ */
+
+require_once './lib/version.php';
+@define('CONFIG_DIR', dirname(__FILE__) . '/config/');
+
+$setup_ok = true;
+
+$config_files = array('conf.php', 'prefs.php');
+
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">
+
+<html>
+<head>
+<title>Vilma: System Capabilities Test</title>
+</head>
+
+<body>
+
+<h1>Vilma Version</h1>
+<ul>
+ <li>Vilma: <?php echo VILMA_VERSION ?></li>
+</ul>
+
+<h1>Vilma Configuration Files</h1>
+<ul>
+<?php
+foreach ($config_files as $file) {
+    if (file_exists(CONFIG_DIR . $file)) {
+        ?><li><?php echo $file ?> - <font color="green"><strong>Yes</strong></font><?php
+    } else {
+        $setup_ok = false;
+        ?><li><?php echo $file ?> - <font color="red"><strong>No</strong></font><?php
+    }
+}
+?>
+</ul>
+</body>
+</html>
diff --git a/vilma/themes/graphics/display.png b/vilma/themes/graphics/display.png
new file mode 100644 (file)
index 0000000..3fd0567
Binary files /dev/null and b/vilma/themes/graphics/display.png differ
diff --git a/vilma/themes/graphics/domain.png b/vilma/themes/graphics/domain.png
new file mode 100644 (file)
index 0000000..7020eb9
Binary files /dev/null and b/vilma/themes/graphics/domain.png differ
diff --git a/vilma/themes/graphics/favicon.ico b/vilma/themes/graphics/favicon.ico
new file mode 100644 (file)
index 0000000..66d7b86
Binary files /dev/null and b/vilma/themes/graphics/favicon.ico differ
diff --git a/vilma/themes/graphics/sort.png b/vilma/themes/graphics/sort.png
new file mode 100644 (file)
index 0000000..a935190
Binary files /dev/null and b/vilma/themes/graphics/sort.png differ
diff --git a/vilma/themes/graphics/vilma.png b/vilma/themes/graphics/vilma.png
new file mode 100644 (file)
index 0000000..3c41916
Binary files /dev/null and b/vilma/themes/graphics/vilma.png differ
diff --git a/vilma/users/delete.php b/vilma/users/delete.php
new file mode 100644 (file)
index 0000000..aaab597
--- /dev/null
@@ -0,0 +1,165 @@
+<?php
+/**
+ * $Horde: vilma/users/delete.php,v 1.27 2009/06/10 17:33:45 slusarz Exp $
+ *
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * @author Marko Djukic <marko@oblo.com>
+ */
+
+@define('VILMA_BASE', dirname(__FILE__) . '/..');
+require_once VILMA_BASE . '/lib/base.php';
+require_once 'Horde/Form.php';
+
+/* Only admin should be using this. */
+if (!Vilma::hasPermission($domain)) {
+    Horde::authenticationFailureRedirect();
+}
+
+$vars = Horde_Variables::getDefaultVariables();
+$address = $vars->get('address');
+$section = Horde_Util::getFormData('section','all');
+
+//$addrInfo = $vilma_driver->getAddressInfo($address, 'all');
+/*
+$user_id = $vars->get('address');
+$formname = $vars->get('formname');
+$user = $vilma_driver->getUser($user_id);
+print_r($vars) . '<br />';
+echo $user_id . '<br />';
+echo $fromname . '<br />';
+print_r($user) . '<br />';
+$domain = Vilma::stripDomain($user['name']);
+$domain = $vilma_driver->getDomainByName($domain);
+*/
+$address = $vilma_driver->getAddressInfo($address);
+$type = $address['type'];
+if(($section == 'all') && ($type == 'alias')) {
+    $address = $vilma_driver->getAddressInfo($vars->get('address'),$type);
+}
+$user_id = $vars->get('address');
+$user = $vilma_driver->getUser($user_id);
+$aliases = $vilma_driver->_getAliases($user_id);
+$aliasesCount = 0;
+if(is_array($aliases)) {
+    $aliasesCount = sizeof($aliases);
+}
+$domain = Vilma::stripDomain($user_id);
+$forwards = $vilma_driver->_getGroupsAndForwards('forwards',$domain);
+$forwardsCount = 0;
+foreach($forwards as $entry) {
+    foreach($entry['targets'] as $target) {
+        if($user_id === $target) {
+            $forwardsCount++;
+        }
+    }
+}
+$groups = $vilma_driver->_getGroupsAndForwards('groups',$domain);
+$groupsCount = 0;
+foreach($groups as $entry) {
+    foreach($entry['targets'] as $target) {
+        if($user_id === $target) {
+            $groupsCount++;
+        }
+    }
+}
+if (is_a($address, 'PEAR_Error')) {
+    $notification->push(sprintf(_("Error reading address information from backend: %s"), $address->getMessage()), 'horde.error');
+    $url = '/users/index.php';
+    require VILMA_BASE . $url;
+    exit;
+}
+$user_name = $address['user_name'];
+if(!isset($user_name) || empty($user_name)) {
+    $user_name = $address['address'];
+}
+$vars->set('user_name', Vilma::stripUser($user_name));
+$domain = Vilma::stripDomain($address);
+$domain = $vilma_driver->getDomainByName($domain);
+$vars->set('domain', $domain);
+$vars->set('mode', 'edit');
+
+$form = new Horde_Form($vars, _("Delete User"));
+/* Set up the form. */
+$form->setButtons(array(_("Delete"), _("Do not delete")));
+//$form->addHidden($user_id, 'user_id', 'text', false);
+$form->addHidden($address['address'], 'address', 'text', false);
+$form->addHidden($section, 'section', 'text', false);
+
+$desc = "Delete user \"%s\"";
+$sub = " and all dependencies?";
+$tot = $aliasesCount + $groupsCount + $forwardsCount;
+if($tot > 0) {
+    $desc .= $sub;
+} else {
+    $desc .= "?";
+}
+if($aliasesCount > 0) {
+    $desc .= " Account has " . $aliasesCount . " aliases.";
+}
+if($forwardsCount > 0) {
+    $desc .= " Account is the target of  " . $forwardsCount . " forward(s).";
+}
+if($groupsCount > 0) {
+    $desc .= " Account belongs to  " . $groupsCount . " group(s).";
+}
+$form->addVariable(sprintf(_($desc), $user_name), 'description', 'description', false);
+if ($vars->get('submitbutton') == _("Delete")) {
+    if($type == 'alias') {
+        if ($form->validate($vars)) {
+            $form->getInfo($vars, $info);
+            $delete = $vilma_driver->_savealias($address['address'],'delete');
+            if (is_a($delete, 'PEAR_Error')) {
+                Horde::logMessage($delete, __FILE__, __LINE__, PEAR_LOG_ERR);
+                $notification->push(sprintf(_("Error deleting user. %s."), $delete->getMessage()), 'horde.error');
+                $url = Horde_Util::addParameter(Horde::applicationUrl('users/index.php'), 'domain_id', $domain['id'], false);
+                header('Location: ' . $url);
+                exit;
+            } else {
+                $notification->push(_("User deleted."), 'horde.success');
+                $url = Horde_Util::addParameter(Horde::applicationUrl('users/index.php'), 'domain_id', $domain['id'], false);
+                header('Location: ' . $url);
+                exit;
+            }
+        }
+    } else {
+        if ($form->validate($vars)) {
+            $form->getInfo($vars, $info);
+            //$delete = $vilma_driver->deleteUser($info['user_id']);
+            $delete = $vilma_driver->deleteUser($address['address']);
+            if (is_a($delete, 'PEAR_Error')) {
+                Horde::logMessage($delete, __FILE__, __LINE__, PEAR_LOG_ERR);
+                $notification->push(sprintf(_("Error deleting user. %s."), $delete->getMessage()), 'horde.error');
+                $url = Horde_Util::addParameter(Horde::applicationUrl('users/index.php'), 'domain_id', $domain['id'], false);
+                header('Location: ' . $url);
+                exit;
+            } else {
+                $notification->push(_("User deleted."), 'horde.success');
+                $url = Horde_Util::addParameter(Horde::applicationUrl('users/index.php'), 'domain_id', $domain['id'], false);
+                header('Location: ' . $url);
+                exit;
+            }
+        }
+    }
+} elseif ($vars->get('submitbutton') == _("Do not delete")) {
+    $notification->push(_("User not deleted."), 'horde.message');
+    $url = Horde_Util::addParameter(Horde::applicationUrl('users/index.php'), 'domain_id', $domain['domain_id'], false);
+    header('Location: ' . $url);
+    exit;
+}
+
+/* Render the form. */
+require_once 'Horde/Form/Renderer.php';
+$renderer = &new Horde_Form_Renderer();
+$main = Horde_Util::bufferOutput(array($form, 'renderActive'), $renderer, $vars, 'delete.php', 'post');
+
+$template->set('main', $main);
+$template->set('menu', Vilma::getMenu('string'));
+$template->set('notify', Horde_Util::bufferOutput(array($notification, 'notify'), array('listeners' => 'status')));
+
+require VILMA_TEMPLATES . '/common-header.inc';
+echo $template->fetch(VILMA_TEMPLATES . '/main/main.html');
+require $registry->get('templates', 'horde') . '/common-footer.inc';
diff --git a/vilma/users/edit.php b/vilma/users/edit.php
new file mode 100644 (file)
index 0000000..16d56dd
--- /dev/null
@@ -0,0 +1,113 @@
+<?php
+/**
+ * The Vilma script to add/edit users.
+ *
+ * $Horde: vilma/users/edit.php,v 1.45 2009/07/14 18:43:46 selsky Exp $
+ *
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * @author Marko Djukic <marko@oblo.com>
+ * @author David Cummings <davidcummings@acm.org>
+ */
+
+@define('VILMA_BASE', dirname(__FILE__) . '/..');
+require_once VILMA_BASE . '/lib/base.php';
+require_once 'Horde/Form.php';
+
+require_once VILMA_BASE . '/lib/Forms/EditUserForm.php';
+
+/* Only admin should be using this. */
+if (!Vilma::hasPermission($domain)) {
+    Horde::authenticationFailureRedirect();
+}
+$vars = Horde_Variables::getDefaultVariables();
+$address = $vars->get('address');
+$section = Horde_Util::getFormData('section','all');
+
+//$addrInfo = $vilma_driver->getAddressInfo($address, 'all');
+$domain = Vilma::stripDomain($address);
+
+/* Check if a form is being edited. */
+if (!$vars->exists('mode')) {
+    if ($address) {
+        $address = $vilma_driver->getAddressInfo($address,$section);
+        if (is_a($address, 'PEAR_Error')) {
+            $notification->push(sprintf(_("Error reading address information from backend: %s"), $address->getMessage()), 'horde.error');
+            $url = '/users/index.php';
+            require VILMA_BASE . $url; 
+            exit;
+        }
+        $vars = new Horde_Variables($address);
+        $user_name = //$vars->get('address');
+                     $vars->get('user_name');
+        $vars->set('user_name', Vilma::stripUser($user_name));
+        $domain = Vilma::stripDomain($user_name);
+        $vars->set('domain', $domain);
+        $vars->set('type', $address['type']);
+        $vars->set('target', 'test'); //$address['target']);
+        $vars->set('mode', 'edit');
+    } else {
+        $vars->set('mode', 'new');
+        $domain_info = $_SESSION['vilma']['domain'];
+        $domain = $domain_info['domain_name'];
+        $domain_id = $domain_info['domain_id'];       
+        $vars->set('domain', $domain);
+        $vars->set('id', $domain_id);
+        $vars->add('user_name', Horde_Util::getFormData('user_name',''));
+    }
+}
+
+$domain = Vilma::stripDomain($address['address']);
+$tmp = $vars->get('domain');
+if(!isset($tmp)) {
+    $vars->set('domain', $domain);
+}
+$form = &new EditUserForm($vars);
+if (!$vars->exists('id') && !$vilma_driver->isBelowMaxUsers($domain)) {
+    $notification->push(sprintf(_("\"%s\" already has the maximum number of users allowed."), $domain), 'horde.error');
+    require VILMA_BASE . '/users/index.php';
+    exit;
+}
+if ($form->validate($vars)) {
+    $form->getInfo($vars, $info);
+    $info['user_name'] = Horde_String::lower($info['user_name']) . '@' . $domain;
+    $user_id = $vilma_driver->saveUser($info);
+    if (is_a($user_id, 'PEAR_Error')) {
+        Horde::logMessage($user_id, __FILE__, __LINE__, PEAR_LOG_ERR);
+        $notification->push(sprintf(_("Error saving user. %s"), $user_id->getMessage()), 'horde.error');
+    } else {
+        $notification->push(_("User details saved."), 'horde.success');
+        /*
+        $virtuals = $vilma_driver->getVirtuals($info['name']);
+        if (count($virtuals)) {
+            //User has virtual email addresses set up.
+            $url = Horde::applicationUrl('users/index.php', true);
+            header('Location: ' . (Vilma::hasPermission($domain) ? $url : Horde_Util::addParameter($url, 'domain', $domain, false)));
+        } else {
+            //User does not have any virtual email addresses set up.
+            $notification->push(_("No virtual email address set up for this user. You should set up at least one virtual email address if this user is to receive any emails."), 'horde.warning');
+            $url = Horde::applicationUrl('virtuals/edit.php', true);
+            $url = Horde_Util::addParameter($url, array('domain' => $domain, 'stripped_email' => Vilma::stripUser($info['name']), 'virtual_destination' => $info['name']), null, false);
+            header('Location: ' . (Vilma::hasPermission($domain) ? $url : Horde_Util::addParameter($url, 'domain', $domain, false)));
+        }
+        */
+        //exit;
+    }
+}
+
+/* Render the form. */
+require_once 'Horde/Form/Renderer.php';
+$renderer = &new Horde_Form_Renderer();
+
+$main = Horde_Util::bufferOutput(array($form, 'renderActive'), $renderer, $vars, 'edit.php', 'post');
+
+$template->set('main', $main);
+$template->set('menu', Vilma::getMenu('string'));
+$template->set('notify', Horde_Util::bufferOutput(array($notification, 'notify'), array('listeners' => 'status')));
+
+require VILMA_TEMPLATES . '/common-header.inc';
+echo $template->fetch(VILMA_TEMPLATES . '/main/main.html');
+require $registry->get('templates', 'horde') . '/common-footer.inc';
diff --git a/vilma/users/index.php b/vilma/users/index.php
new file mode 100644 (file)
index 0000000..ac90734
--- /dev/null
@@ -0,0 +1,111 @@
+<?php
+/**
+ * $Horde: vilma/users/index.php,v 1.35 2009/06/10 17:33:45 slusarz Exp $
+ *
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * @author Marko Djukic <marko@oblo.com>
+ * @author Ben Klang <ben@alkaloid.net>
+ * @author David Cummings <davidcummings@acm.org>
+ */
+
+@define('VILMA_BASE', dirname(__FILE__) . '/..');
+require_once VILMA_BASE . '/lib/base.php';
+require_once 'Horde/Prefs/CategoryManager.php';
+
+/* Only admin should be using this. */
+if (!Vilma::hasPermission($curdomain)) {
+    Horde::authenticationFailureRedirect();
+}
+
+// Input validation: make sure we have a valid section
+$vars = Horde_Variables::getDefaultVariables();
+$section = $vars->get('section');
+$tmp = Vilma::getUserMgrTypes();
+if (!array_key_exists($section, Vilma::getUserMgrTypes())) {
+    $section = 'all';
+    $vars->set('section', $section);
+}
+$tabs = Vilma::getUserMgrTabs($vars);
+
+$addresses = $vilma_driver->getAddresses($curdomain['domain_name'], $section);
+if (is_a($addresses, 'PEAR_Error')) {
+    $notification->push($addresses);
+    header('Location: ' . Horde::applicationUrl('index.php'));
+}
+
+// Page results
+$page = Horde_Util::getGet('page', 0);
+$perpage = $prefs->getValue('addresses_perpage');
+$url = 'users/index.php';
+$url = Horde_Util::addParameter($url, 'section', $section);
+$pager = new Horde_UI_Pager('page',
+                            Horde_Variables::getDefaultVariables(),
+                            array('num' => count($addresses),
+                                  'url' => $url,
+                                  'page_count' => 10,
+                                  'perpage' => $perpage));
+$addresses = array_slice($addresses, $page*$perpage, $perpage);
+
+$types = Vilma::getUserMgrTypes();
+foreach ($addresses as $i => $address) {
+    $type = $address['type'];
+    $id = $address['id'];
+    $url = Horde::applicationUrl('users/edit.php');
+    $url = Horde_Util::addParameter($url, 'address', $id);
+    if($type === 'alias') {
+        $addresses[$i]['edit_url'] = '';
+    } else {
+        $addresses[$i]['edit_url'] = Horde_Util::addParameter($url, 'section', $section);
+    }
+    $url = Horde::applicationUrl('users/delete.php');
+    $currentAddress = $address['address'];
+    if(!isset($currentAddress) || empty($currentAddress)) {
+        $currentAddress = $address['user_name'] . $address['domain'];
+    }
+    $url = Horde_Util::addParameter($url, 'address', $currentAddress);
+    //$addresses[$i]['del_url'] = Horde_Util::addParameter($url, 'address', $id);
+    $addresses[$i]['del_url'] = Horde_Util::addParameter($url, 'section', $section);
+    //$url = Horde::applicationUrl('users/edit.php');
+    //$addresses[$i]['view_url'] = Horde_Util::addParameter($url, 'address', $address['user_name']);
+    $url = Horde::applicationUrl('users/edit.php');
+    $url = Horde_Util::addParameter($url, 'address', $id);
+    if($type === 'alias') {
+        $addresses[$i]['view_url'] = '';
+    } else {
+        $addresses[$i]['view_url'] = Horde_Util::addParameter($url, 'section', $section);
+    }
+    $addresses[$i]['type'] = $types[$address['type']]['singular'];
+    $addresses[$i]['status'] = $vilma_driver->getUserStatus($address);
+}
+
+/* Set up the template action links. */
+if ($vilma_driver->isBelowMaxUsers($curdomain['domain_name'])) {
+    $url = Horde::applicationUrl('users/edit.php');
+    $maxusers = '';
+} else {
+    $maxusers = _("Maximum Users");
+}
+
+$url = Horde::applicationUrl('virtuals/edit.php');
+
+/* Set up the template fields. */
+$template->set('addresses', $addresses, true);
+$template->set('maxusers', $maxusers, true);
+$template->set('menu', Vilma::getMenu('string'));
+$template->set('tabs', $tabs->render());
+$template->set('notify', Horde_Util::bufferOutput(array($notification, 'notify'), array('listeners' => 'status')));
+$template->set('pager', $pager->render());
+
+/* Set up the field list. */
+$images = array('delete' => Horde::img('delete.png', _("Delete User"), '', $registry->getImageDir('horde')),
+                'edit' => Horde::img('edit.png', _("Edit User"), '', $registry->getImageDir('horde')));
+$template->set('images', $images);
+
+/* Render the page. */
+require VILMA_TEMPLATES . '/common-header.inc';
+echo $template->fetch(VILMA_TEMPLATES . '/users/index.html');
+require $registry->get('templates', 'horde') . '/common-footer.inc';
diff --git a/vilma/virtuals/delete.php b/vilma/virtuals/delete.php
new file mode 100644 (file)
index 0000000..e222a1d
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+/**
+ * $Horde: vilma/virtuals/delete.php,v 1.28 2009/07/08 18:30:04 slusarz Exp $
+ *
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * @author Marko Djukic <marko@oblo.com>
+ */
+
+@define('VILMA_BASE', dirname(__FILE__) . '/..');
+require_once VILMA_BASE . '/lib/base.php';
+require_once 'Horde/Form.php';
+
+/* Only admin should be using this. */
+if (!Horde_Auth::isAdmin()) {
+    Horde::authenticationFailureRedirect();
+}
+
+$vars = Horde_Variables::getDefaultVariables();
+$virtual_id = $vars->get('virtual_id');
+$formname = $vars->get('formname');
+
+$virtual = $vilma_driver->getVirtual($virtual_id);
+$domain = Vilma::stripDomain($virtual['virtual_email']);
+$domain = $vilma_driver->getDomainByName($domain);
+
+$form = new Horde_Form($vars, _("Delete Virtual Email Address"));
+
+/* Set up the form. */
+$form->setButtons(array(_("Delete"), _("Do not delete")));
+$form->addHidden('', 'virtual_id', 'text', false);
+$form->addVariable(sprintf(_("Delete the virtual email address \"%s\" => \"%s\"?"), $virtual['virtual_email'], $virtual['virtual_destination']), 'description', 'description', false);
+
+if ($vars->get('submitbutton') == _("Delete")) {
+    if ($form->validate($vars)) {
+        $form->getInfo($vars, $info);
+        $delete = $vilma_driver->deleteVirtual($info['virtual_id']);
+        if (is_a($delete, 'PEAR_Error')) {
+            Horde::logMessage($delete, __FILE__, __LINE__, PEAR_LOG_ERR);
+            $notification->push(sprintf(_("Error deleting virtual email. %s."), $delete->getMessage()), 'horde.error');
+        } else {
+            $notification->push(_("Virtual email deleted."), 'horde.success');
+            $url = Horde_Util::addParameter(Horde::applicationUrl('virtuals/index.php'), 'domain_id', $domain['domain_id'], false);
+            header('Location: ' . $url);
+            exit;
+        }
+    }
+} elseif ($vars->get('submitbutton') == _("Do not delete")) {
+    $notification->push(_("Virtual email not deleted."), 'horde.message');
+    $url = Horde_Util::addParameter(Horde::applicationUrl('virtuals/index.php'), 'domain_id', $domain['domain_id'], false);
+    header('Location: ' . $url);
+    exit;
+}
+
+/* Render the form. */
+require_once 'Horde/Form/Renderer.php';
+$renderer = &new Horde_Form_Renderer();
+$main = Horde_Util::bufferOutput(array($form, 'renderActive'), $renderer, $vars, 'delete.php', 'post');
+
+$template->set('main', $main);
+$template->set('menu', Vilma::getMenu('string'));
+$template->set('notify', Horde_Util::bufferOutput(array($notification, 'notify'), array('listeners' => 'status')));
+
+require VILMA_TEMPLATES . '/common-header.inc';
+echo $template->fetch(VILMA_TEMPLATES . '/main/main.html');
+require $registry->get('templates', 'horde') . '/common-footer.inc';
diff --git a/vilma/virtuals/edit.php b/vilma/virtuals/edit.php
new file mode 100644 (file)
index 0000000..c961da7
--- /dev/null
@@ -0,0 +1,96 @@
+<?php
+/**
+ * $Horde: vilma/virtuals/edit.php,v 1.32 2009/07/14 18:43:46 selsky Exp $
+ *
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * @author Marko Djukic <marko@oblo.com>
+ */
+
+@define('VILMA_BASE', dirname(__FILE__) . '/..');
+require_once VILMA_BASE . '/lib/base.php';
+require_once 'Horde/Form.php';
+require_once 'Horde/Form/Action.php';
+
+/* Only admin should be using this. */
+if (!Horde_Auth::isAdmin() && !Vilma::isDomainAdmin()) {
+    Horde::authenticationFailureRedirect();
+}
+
+$domain = Vilma::getDomain();
+$vars = Horde_Variables::getDefaultVariables();
+$virtual_id = $vars->get('virtual_id');
+$user = $vars->get('user');
+$formname = $vars->get('formname');
+
+/* Check if a form is being edited. */
+$editing = false;
+if ($virtual_id && !$formname) {
+    $vars = new Horde_Variables($vilma_driver->getVirtual($virtual_id));
+    $editing = true;
+}
+
+if (empty($domain)) {
+    $domain = Vilma::stripDomain($vars->get('virtual_destination'));
+}
+$users = $vilma_driver->getUsers($domain);
+$user_list = array();
+foreach ($users as $user) {
+    $virtual_destination = substr($user['user_name'], 0, strpos($user['user_name'], '@'));
+    $user_list[$user['user_name']] = $virtual_destination;
+}
+
+$form = new Horde_Form($vars, ($editing) ? _("Edit Virtual Email Address") : _("New Virtual Email Address"));
+
+/* Set up the form. */
+$form->setButtons(true, true);
+$form->addHidden('', 'virtual_id', 'int', false);
+$form->addHidden('', 'domain', 'text', false);
+$form->addVariable(_("Virtual Email"), 'stripped_email', 'text', true, false, sprintf(_("Enter a virtual email address @%s and then indicate below where mail sent to that address is to be delivered. The address must begin with an alphanumerical character, it must contain only alphanumerical and '._-' characters, and must end with an alphanumerical character."), $domain), array('~^[a-zA-Z0-9]{1,1}[a-zA-Z0-9._-]*[a-zA-Z0-9]$~'));
+$var = &$form->addVariable(_("Destination type"), 'destination_type', 'enum',
+                           true, false, null,
+                           array(array('local' => _("Local user"),
+                                       'remote' => _("Remote address"))));
+$action = Horde_Form_Action::factory('reload');
+$var->setAction($action);
+if ($vars->get('destination_type') == 'remote') {
+    $form->addVariable(_("Remote e-mail address"), 'virtual_destination',
+                       'email', true, false);
+} else {
+    $form->addVariable(_("Destination"), 'virtual_destination', 'enum',
+                       true, false, null, array($user_list, true));
+}
+
+if ($form->validate($vars)) {
+    $form->getInfo($vars, $info);
+    $info['stripped_email'] = Horde_String::lower($info['stripped_email']);
+    if ($info['destination_type'] == 'remote') {
+        $info['virtual_destination'] = Horde_String::lower($info['virtual_destination']);
+    }
+    $virtual_id = $vilma_driver->saveVirtual($info, $domain);
+    if (is_a($virtual_id, 'PEAR_Error')) {
+        Horde::logMessage($virtual_id, __FILE__, __LINE__, PEAR_LOG_ERR);
+        $notification->push(sprintf(_("Error saving virtual email. %s."), $virtual_id->getMessage()), 'horde.error');
+    } else {
+        $notification->push(_("Virtual email saved."), 'horde.success');
+        $url = Horde::applicationUrl('virtuals/index.php', true);
+        header('Location: ' . Horde_Util::addParameter($url, 'user', $info['virtual_destination'], false));
+        exit;
+    }
+}
+
+/* Render the form. */
+require_once 'Horde/Form/Renderer.php';
+$renderer = new Horde_Form_Renderer();
+$main = Horde_Util::bufferOutput(array($form, 'renderActive'), $renderer, $vars, 'edit.php', 'post');
+
+$template->set('main', $main);
+$template->set('menu', Vilma::getMenu('string'));
+$template->set('notify', Horde_Util::bufferOutput(array($notification, 'notify'), array('listeners' => 'status')));
+
+require VILMA_TEMPLATES . '/common-header.inc';
+echo $template->fetch(VILMA_TEMPLATES . '/main/main.html');
+require $registry->get('templates', 'horde') . '/common-footer.inc';
diff --git a/vilma/virtuals/index.php b/vilma/virtuals/index.php
new file mode 100644 (file)
index 0000000..901e0cc
--- /dev/null
@@ -0,0 +1,65 @@
+<?php
+/**
+ * $Horde: vilma/virtuals/index.php,v 1.26 2009/07/08 18:30:04 slusarz Exp $
+ *
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/vilma/LICENSE.
+ *
+ * @author Marko Djukic <marko@oblo.com>
+ */
+
+@define('VILMA_BASE', dirname(__FILE__) . '/..');
+require_once VILMA_BASE . '/lib/base.php';
+
+/* Only admin should be using this. */
+if (!Horde_Auth::isAdmin() && !Vilma::isDomainAdmin()) {
+    Horde::authenticationFailureRedirect();
+}
+
+$user = Horde_Util::getFormData('user');
+if (!empty($user)) {
+    $virtuals = $vilma_driver->getVirtuals($user);
+    $domain = Vilma::stripDomain($user);
+} else {
+    $domain = Vilma::getDomain();
+    $virtuals = $vilma_driver->getVirtuals($domain);
+}
+
+if (is_a($virtuals, 'PEAR_Error')) {
+    $notification->push($virtuals);
+    header('Location: ' . Horde::applicationUrl('index.php'));
+}
+
+foreach ($virtuals as $id => $virtual) {
+    $url = Horde::applicationUrl('virtuals/edit.php');
+    $virtuals[$id]['edit_url'] = Horde_Util::addParameter($url, 'virtual_id', $virtual['virtual_id']);
+    $url = Horde::applicationUrl('virtuals/delete.php');
+    $virtuals[$id]['del_url'] = Horde_Util::addParameter($url, 'virtual_id', $virtual['virtual_id']);
+}
+
+$template->set('virtuals', $virtuals, true);
+
+/* Set up the template action links. */
+$actions = array();
+$url = Horde::applicationUrl('virtuals/edit.php');
+$actions['new_url'] = (Vilma::isDomainAdmin() ? $url : Horde_Util::addParameter($url, 'domain', $domain));
+$actions['new_text'] = _("New Virtual Email");
+$url = Horde::applicationUrl('users/index.php');
+$actions['users_url'] = (Vilma::isDomainAdmin() ? $url : Horde_Util::addParameter($url, 'domain', $domain));
+$actions['users_text'] = _("Users");
+$template->set('actions', $actions);
+
+/* Set up the field list. */
+$images = array('delete' => Horde::img('delete.png', _("Delete User"), '', $registry->getImageDir('horde')),
+                'edit' => Horde::img('edit.png', _("Edit User"), '', $registry->getImageDir('horde')));
+$template->set('images', $images);
+
+$template->set('menu', Vilma::getMenu('string'));
+$template->set('notify', Horde_Util::bufferOutput(array($notification, 'notify'), array('listeners' => 'status')));
+
+/* Render the page. */
+require VILMA_TEMPLATES . '/common-header.inc';
+echo $template->fetch(VILMA_TEMPLATES . '/virtuals/index.html');
+require $registry->get('templates', 'horde') . '/common-footer.inc';