Subversion Repositories general

Compare Revisions

Ignore whitespace Rev 1028 → Rev 1029

/hostadmiral/trunk/conf/hostadmiral_config.xml.sample
0,0 → 1,26
<?xml version='1.0' encoding='utf-8'?>
 
<!-- HostAdmiral configuration file - user definitions. -->
<hostadmiral>
<version major="1" minor="0" />
<datasource>
<settings>
<username>postgres</username>
<password>password</password>
</settings>
</datasource>
<initializations>
<initialization>
<class>ak.hostadmiral.core.listener.dummy.DummyListener</class>
</initialization>
<!--
<initialization>
<class>ak.hostadmiral.core.listener.file.FileListener</class>
<init-param>
<param-name>fileName</param-name>
<param-value>/tmp/hostadmiral</param-value>
</init-param>
</initialization>
-->
</initializations>
</hostadmiral>
/hostadmiral/trunk/conf/hostadmiral_config.xml.default
0,0 → 1,63
<?xml version='1.0' encoding='utf-8'?>
 
<!--
HostAdmiral configuration file.
There are two files - one is default, the second one is user-defined, where
default settings are overrided.
-->
<hostadmiral>
<!--
Version of this config. By changing major number the config must be converted to new
one. Minor changes allow old file using.
-->
<version major="1" minor="0" />
 
<!--
Which data source is used to store internal information.
-->
<datasource>
<!-- Data source type. Only "hibernate" is supported at the moment -->
<type>hibernate</type>
 
<!-- Hibernate and database properties -->
<settings>
<!-- DB driver -->
<driver>org.postgresql.Driver</driver>
 
<!-- DB user -->
<username>postgres</username>
 
<!-- DB password -->
<password></password>
 
<!-- DB URL: type, host and database name, format depends on DB driver -->
<url>jdbc:postgresql://localhost/hostadmiral</url>
 
<!-- DB dialect, must conform to DB driver -->
<dialect>net.sf.hibernate.dialect.PostgreSQLDialect</dialect>
</settings>
</datasource>
 
<!-- Classes which must be initialized at program startup. -->
<initializations>
<!-- Core classes -->
<initialization>
<class>ak.hostadmiral.core.model.UserManager</class>
</initialization>
<initialization>
<class>ak.hostadmiral.core.model.SystemUserManager</class>
</initialization>
<initialization>
<class>ak.hostadmiral.core.model.InetDomainManager</class>
</initialization>
<initialization>
<class>ak.hostadmiral.core.model.MailboxManager</class>
</initialization>
<initialization>
<class>ak.hostadmiral.core.model.MailAliasManager</class>
</initialization>
<initialization>
<class>ak.hostadmiral.core.model.MailAliasDestinationManager</class>
</initialization>
</initializations>
</hostadmiral>
/hostadmiral/trunk/doc/todo.txt
1,12 → 1,8
Host Admiral TODO
=================
====================================================================
 
+ Track database structure version.
Config in one place. Allow configuration of each listener.
+ Listeners for all operations.
 
Config in one place. Allow configuration of each listener.
 
Transaction control for listners.
 
+/- Save user id for all db-update operations.
27,27 → 23,18
 
+/- Cascade object deletion, confirmation page.
 
+ Store user and malbox passwords in several forms; e.g. clear text, md5, encrypt. Allow
admin to specify which forms to use.
 
Check passwords quality (make a separate project for this).
 
Show filters, search.
 
+/- Multi-page lists.
+/- Sort options for lists.
 
Sort options for lists.
 
Different user name schemes, not only user@domain. Define an interface to allow admin
implement an own one. Implement a few common ones.
 
+ Taglig to show ActionMessages in right way (add it to the StrutsX project).
 
Allow to use existing system users: enter uid or name only, check in system for full
information.
 
+ I18n. Switch language of page on the fly. Save selection in DB for each user.
 
Allow admin to define default language for server and domain.
 
Split CoreResources.properties to several files.
67,9 → 54,30
 
Catch-all mail alias. Only one per domain.
 
+ User login history.
 
Basic scripts to push changes to the system.
 
If mailbox is created, create an user and a mail alias for it in one step - as option.
Afterwards they are binded and change own name or deleted together. Bind by name? In witch directions?
 
Done
--------------------------------------------------------------------
+ Track database structure version.
+ Listeners for all operations.
 
+ User login history.
 
+ I18n. Switch language of page on the fly. Save selection in DB for each user.
 
+ Taglig to show ActionMessages in right way (add it to the StrutsX project).
 
+ Multi-page lists.
 
+ Store user and malbox passwords in several forms; e.g. clear text, md5, encrypt. Allow
admin to specify which forms to use.
 
+ Change db version to store minor version - changes which don'T affect functioonality,
e.g. indexes.
 
/hostadmiral/trunk/src/ak/hostadmiral/core/listener/file/ConfigServlet.java
File deleted
/hostadmiral/trunk/src/ak/hostadmiral/core/listener/file/FileListener.java
File deleted
/hostadmiral/trunk/src/ak/hostadmiral/core/listener/dummy/DummyListener.java
File deleted
/hostadmiral/trunk/src/ak/hostadmiral/core/taglib/list/PageLinkTag.java
10,6 → 10,7
public class PageLinkTag
extends LinkTag
{
public static String BACKPATH_KEY = BackPath.DEFAULT_KEY + "_list";
public static String PAGE_PARAM_NAME = "pg";
 
protected PageIterateTag parent;
33,7 → 34,7
{
try {
return BackPath.findBackPath((HttpServletRequest)pageContext.getRequest(),
BackPath.DEFAULT_KEY, BackPath.DEFAULT_PARAM,
BACKPATH_KEY, BackPath.DEFAULT_PARAM,
new String[] { "backpath", PAGE_PARAM_NAME },
BackPath.DEFAULT_ZIP);
}
/hostadmiral/trunk/src/ak/hostadmiral/core/taglib/list/PageTagBase.java
10,6 → 10,7
public abstract class PageTagBase
extends LinkTag
{
public static String BACKPATH_KEY = BackPath.DEFAULT_KEY + "_list";
public static String PAGE_PARAM_NAME = "pg";
 
protected String infoBean = null;
41,7 → 42,7
{
try {
return BackPath.findBackPath((HttpServletRequest)pageContext.getRequest(),
BackPath.DEFAULT_KEY, BackPath.DEFAULT_PARAM,
BACKPATH_KEY, BackPath.DEFAULT_PARAM,
new String[] { "backpath", PAGE_PARAM_NAME },
BackPath.DEFAULT_ZIP);
}
/hostadmiral/trunk/src/ak/hostadmiral/util/DatabaseVersion.java
6,19 → 6,35
*/
public class DatabaseVersion
{
private int version;
private int major;
 
/**
*
* @hibernate.id generator-class="assigned"
*/
public int getVersion()
public int getMajor()
{
return version;
return major;
}
 
protected void setVersion(int version)
protected void setMajor(int major)
{
this.version = version;
this.major = major;
}
 
private int minor;
 
/**
*
* @hibernate.field
*/
public int getMinor()
{
return minor;
}
 
protected void setMinor(int minor)
{
this.minor = minor;
}
}
/hostadmiral/trunk/src/ak/hostadmiral/util/HibernateUtil.java
15,7 → 15,7
 
public class HibernateUtil
{
public static final int DATABASE_VERSION = 1;
public static final int DATABASE_VERSION = 2;
 
private static Configuration configuration;
private static SessionFactory sessionFactory;
36,7 → 36,7
if(versions.size() > 1)
throw new ModelException("Too much entries in database structure version table");
 
int version = ((DatabaseVersion)versions.iterator().next()).getVersion();
int version = ((DatabaseVersion)versions.iterator().next()).getMajor();
if(version != DATABASE_VERSION)
throw new ModelException("Expected database structure version "
+ DATABASE_VERSION + ", found " + version);
/hostadmiral/trunk/src/ak/hostadmiral/listener/file/ConfigServlet.java
0,0 → 1,26
package ak.hostadmiral.core.listener.file;
 
import java.io.IOException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
 
import org.apache.log4j.Logger;
 
public class ConfigServlet
extends GenericServlet
{
private static final Logger logger = Logger.getLogger(ConfigServlet.class);
 
public void init()
throws ServletException
{
FileListener.setFileName(getInitParameter("fileName"));
}
 
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException
{
}
}
/hostadmiral/trunk/src/ak/hostadmiral/listener/file/FileListener.java
0,0 → 1,255
package ak.hostadmiral.core.listener.file;
 
import java.util.Collection;
import java.util.Iterator;
import java.io.Writer;
import java.io.BufferedWriter;
import java.io.FileWriter;
import ak.hostadmiral.util.ModelException;
import ak.hostadmiral.core.model.*;
 
import org.apache.log4j.Logger;
 
public class FileListener
implements
UserCreatedListener,
UserModifiedListener,
UserDeletedListener,
InetDomainCreatedListener,
InetDomainModifiedListener,
InetDomainDeletedListener,
SystemUserCreatedListener,
SystemUserModifiedListener,
SystemUserDeletedListener,
MailboxCreatedListener,
MailboxModifiedListener,
MailboxDeletedListener,
MailAliasCreatedListener,
MailAliasModifiedListener,
MailAliasDeletedListener
{
private static final Logger logger = Logger.getLogger(FileListener.class);
 
private static String fileName;
protected static Object lock = new Object();
 
public static final String PROTOCOL_NAME = "HostAdmiral_FileListener";
public static final String PROTOCOL_VERSION = "0.1";
 
public static String getFileName()
{
return fileName;
}
 
public static void setFileName(String fileName_)
{
fileName = fileName_;
}
 
protected static String escape(String s)
{
// FIXME: any other problem characters? optimize it?
s = s.replaceAll("\0", "\\\\0");
s = s.replaceAll("\\\\", "\\\\\\\\");
s = s.replaceAll("\t", "\\\\t");
s = s.replaceAll("\n", "\\\\n");
s = s.replaceAll("\r", "\\\\r");
return s;
}
 
protected static void send(String message)
throws ModelException
{
synchronized(lock) {
try {
Writer out = new BufferedWriter(new FileWriter(fileName));
if(PROTOCOL_NAME != null) {
out.write(PROTOCOL_NAME);
out.write(" ");
}
if(PROTOCOL_VERSION != null) {
out.write(PROTOCOL_VERSION);
out.write("\n");
}
out.write(message);
out.write("\n\n");
out.close();
}
catch(Exception ex) {
logger.error("Cannot save message to file", ex);
throw new ModelException("Cannot save message to file:" + ex.getMessage());
// FIMXE: or just throw "internal server error" message?
}
}
}
 
//=== user ====================================================================================
 
public void userCreated(User editor, User user)
throws ModelException
{
send("user\tcreate\t" + escape(user.getLogin()) + "\t"
+ escape(/* FIXME user.getPassword() */ "") + "\t"
+ user.getEnabled() + "\t"
+ escape(user.getComment()));
}
 
public void userModified(User editor, User user, User oldUser)
throws ModelException
{
send("user\tmodify\t" + escape(oldUser.getLogin()) + "\t"
+ escape(user.getLogin()) + "\t"
+ escape(/* FIXME user.getPassword() */ "") + "\t"
+ user.getEnabled() + "\t"
+ escape(user.getComment()));
}
 
public void userDeleted(User editor, User user)
throws ModelException
{
send("user\tdelete\t" + escape(user.getLogin()));
}
 
//=== inet domain =============================================================================
 
public void inetDomainCreated(User editor, InetDomain domain)
throws ModelException
{
send("inetDomain\tcreate\t" + escape(domain.getName()) + "\t"
+ domain.getEnabled() + "\t"
+ escape(domain.getComment()));
}
 
public void inetDomainModified(User editor, InetDomain domain, InetDomain oldDomain)
throws ModelException
{
send("inetDomain\tmodify\t" + escape(oldDomain.getName()) + "\t"
+ escape(domain.getName()) + "\t"
+ domain.getEnabled() + "\t"
+ escape(domain.getComment()));
}
 
public void inetDomainDeleted(User editor, InetDomain domain)
throws ModelException
{
send("inetDomain\tdelete\t" + escape(domain.getName()));
}
 
//=== system user =============================================================================
 
public void systemUserCreated(User editor, SystemUser systemUser)
throws ModelException
{
send("systemUser\tcreate\t" + systemUser.getUid() + "\t"
+ escape(systemUser.getName()) + "\t"
+ systemUser.getEnabled() + "\t"
+ escape(systemUser.getComment()));
}
 
public void systemUserModified(User editor, SystemUser systemUser, SystemUser oldSystemUser)
throws ModelException
{
send("systemUser\tmodify\t" + oldSystemUser.getUid() + "\t"
+ escape(oldSystemUser.getName()) + "\t"
+ systemUser.getUid() + "\t"
+ escape(systemUser.getName()) + "\t"
+ systemUser.getEnabled() + "\t"
+ escape(systemUser.getComment()));
}
 
public void systemUserDeleted(User editor, SystemUser systemUser)
throws ModelException
{
send("systemUser\tdelete\t" + systemUser.getUid() + "\t" + escape(systemUser.getName()));
}
 
//=== mailbox =================================================================================
 
public void mailboxCreated(User editor, Mailbox mailbox)
throws ModelException
{
send("mailbox\tcreate\t" + escape(mailbox.getLogin()) + "\t"
+ escape(/* FIXME user.getPassword() */ "") + "\t"
+ escape(mailbox.getDomain().getName()) + "\t"
+ mailbox.getVirusCheck() + "\t"
+ mailbox.getSpamCheck() + "\t"
+ (mailbox.getSystemUser() == null ? "" : mailbox.getSystemUser().getUid().toString())
+ "\t"
+ mailbox.getEnabled() + "\t"
+ escape(mailbox.getComment()));
}
 
public void mailboxModified(User editor, Mailbox mailbox, Mailbox oldMailbox)
throws ModelException
{
send("mailbox\tmodify\t" + escape(oldMailbox.getLogin()) + "\t"
+ escape(oldMailbox.getDomain().getName()) + "\t"
+ escape(mailbox.getLogin()) + "\t"
+ escape(/* FIXME user.getPassword() */ "") + "\t"
+ escape(mailbox.getDomain().getName()) + "\t"
+ mailbox.getVirusCheck() + "\t"
+ mailbox.getSpamCheck() + "\t"
+ (mailbox.getSystemUser() == null ? "" : mailbox.getSystemUser().getUid().toString())
+ "\t"
+ mailbox.getEnabled() + "\t"
+ escape(mailbox.getComment()));
}
 
public void mailboxDeleted(User editor, Mailbox mailbox)
throws ModelException
{
send("mailbox\tdelete\t" + escape(mailbox.getLogin()) + "\t"
+ escape(mailbox.getDomain().getName()));
}
 
//=== mail alias ==============================================================================
 
private String formMailAliasDestinations(User editor, MailAlias mailAlias)
throws ModelException
{
StringBuffer b = new StringBuffer();
 
Collection dests = mailAlias.getDestinations(editor);
if(dests != null) {
for(Iterator i = dests.iterator(); i.hasNext(); ) {
MailAliasDestination d = (MailAliasDestination)i.next();
b.append("\n\t");
if(d.getMailbox() != null)
b.append(escape(d.getMailbox().getLogin())).append("@").append(escape(d.getMailbox().getDomain().getName()));
else
b.append(escape(d.getEmail()));
}
}
 
return b.toString();
}
 
public void mailAliasCreated(User editor, MailAlias mailAlias)
throws ModelException
{
send(" mailAlias\tcreate\t" + escape(mailAlias.getAddress()) + "\t"
+ escape(mailAlias.getDomain().getName()) + "\t"
+ mailAlias.getEnabled() + "\t"
+ escape(mailAlias.getComment())
+ formMailAliasDestinations(editor, mailAlias));
}
 
public void mailAliasModified(User editor, MailAlias mailAlias, MailAlias oldMailAlias)
throws ModelException
{
send(" mailAlias\tmodify\t" + escape(oldMailAlias.getAddress()) + "\t"
+ escape(oldMailAlias.getDomain().getName()) + "\t"
+ escape(mailAlias.getAddress()) + "\t"
+ escape(mailAlias.getDomain().getName()) + "\t"
+ mailAlias.getEnabled() + "\t"
+ escape(mailAlias.getComment())
+ formMailAliasDestinations(editor, mailAlias));
}
 
public void mailAliasDeleted(User editor, MailAlias mailAlias)
throws ModelException
{
send(" mailAlias\tdelete\t" + escape(mailAlias.getAddress())+ "\t"
+ escape(mailAlias.getDomain().getName()));
}
}
/hostadmiral/trunk/src/ak/hostadmiral/listener/dummy/DummyListener.java
0,0 → 1,139
package ak.hostadmiral.core.listener.dummy;
 
import ak.hostadmiral.util.ModelException;
import ak.hostadmiral.core.model.*;
 
public class DummyListener
implements
UserCreatedListener,
UserModifiedListener,
UserDeletedListener,
InetDomainCreatedListener,
InetDomainModifiedListener,
InetDomainDeletedListener,
SystemUserCreatedListener,
SystemUserModifiedListener,
SystemUserDeletedListener,
MailboxCreatedListener,
MailboxModifiedListener,
MailboxDeletedListener,
MailAliasCreatedListener,
MailAliasModifiedListener,
MailAliasDeletedListener
{
//=== user ====================================================================================
 
public void userCreated(User editor, User user)
throws ModelException
{
System.out.println("DummyListener.userCreated: "
+ user + " by " + editor);
}
 
public void userModified(User editor, User user, User oldUser)
throws ModelException
{
System.out.println("DummyListener.userModified: from " + oldUser
+ " to " + user + " by " + editor);
}
 
public void userDeleted(User editor, User user)
throws ModelException
{
System.out.println("DummyListener.userDeleted: "
+ user + " by " + editor);
}
 
//=== inet domain =============================================================================
 
public void inetDomainCreated(User editor, InetDomain domain)
throws ModelException
{
System.out.println("DummyListener.inetDomainCreated: "
+ domain + " by " + editor);
}
 
public void inetDomainModified(User editor, InetDomain domain, InetDomain oldDomain)
throws ModelException
{
System.out.println("DummyListener.inetDomainModified: from " + oldDomain
+ " to " + domain + " by " + editor);
}
 
public void inetDomainDeleted(User editor, InetDomain domain)
throws ModelException
{
System.out.println("DummyListener.inetDomainDeleted: "
+ domain + " by " + editor);
}
 
//=== system user =============================================================================
 
public void systemUserCreated(User editor, SystemUser systemUser)
throws ModelException
{
System.out.println("DummyListener.systemUserCreated: "
+ systemUser + " by " + editor);
}
 
public void systemUserModified(User editor, SystemUser systemUser, SystemUser oldSystemUser)
throws ModelException
{
System.out.println("DummyListener.systemUserModified: from " + oldSystemUser
+ " to " + systemUser + " by " + editor);
}
 
public void systemUserDeleted(User editor, SystemUser systemUser)
throws ModelException
{
System.out.println("DummyListener.systemUserDeleted: "
+ systemUser + " by " + editor);
}
 
//=== mailbox =================================================================================
 
public void mailboxCreated(User editor, Mailbox mailbox)
throws ModelException
{
System.out.println("DummyListener.mailboxCreated: "
+ mailbox + " by " + editor);
}
 
public void mailboxModified(User editor, Mailbox mailbox, Mailbox oldMailbox)
throws ModelException
{
System.out.println("DummyListener.mailboxModified: from " + oldMailbox
+ " to " + mailbox + " by " + editor);
}
 
public void mailboxDeleted(User editor, Mailbox mailbox)
throws ModelException
{
System.out.println("DummyListener.mailboxDeleted: "
+ mailbox + " by " + editor);
}
 
//=== mail alias ==============================================================================
 
public void mailAliasCreated(User editor, MailAlias mailAlias)
throws ModelException
{
System.out.println("DummyListener.mailAliasCreated: "
+ mailAlias + " by " + editor);
}
 
public void mailAliasModified(User editor, MailAlias mailAlias, MailAlias oldMailAlias)
throws ModelException
{
System.out.println("DummyListener.mailAliasModified: from " + oldMailAlias
+ " to " + mailAlias + " by " + editor);
}
 
public void mailAliasDeleted(User editor, MailAlias mailAlias)
throws ModelException
{
System.out.println("DummyListener.mailAliasDeleted: "
+ mailAlias + " by " + editor);
}
 
}
/hostadmiral/trunk/webapp/WEB-INF/web.xml
190,7 → 190,6
</servlet-mapping>
 
 
<!-- The Usual Welcome File List -->
<welcome-file-list>
<welcome-file>index.do</welcome-file>
<welcome-file>index.html</welcome-file>
197,7 → 196,6
</welcome-file-list>
 
 
<!-- Struts Tag Library Descriptors -->
<taglib>
<taglib-uri>/tags/struts-bean</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
233,4 → 231,9
<taglib-location>/WEB-INF/hostadmiral-core.tld</taglib-location>
</taglib>
 
<taglib>
<taglib-uri>/ak/hostadmiral/list</taglib-uri>
<taglib-location>/WEB-INF/hostadmiral-list.tld</taglib-location>
</taglib>
 
</web-app>
/hostadmiral/trunk/webapp/domain/list.jsp
6,7 → 6,6
<%@ taglib uri="/WEB-INF/ak-strutsx.tld" prefix="strutsx" %>
<%@ taglib uri="/WEB-INF/hostadmiral-core.tld" prefix="core" %>
<%@ taglib uri="/WEB-INF/hostadmiral-list.tld" prefix="list" %>
<backpath:init backPathIgnore="pg" />
<html>
 
<head>
/hostadmiral/trunk/webapp/user/system/list.jsp
6,7 → 6,6
<%@ taglib uri="/WEB-INF/ak-strutsx.tld" prefix="strutsx" %>
<%@ taglib uri="/WEB-INF/hostadmiral-core.tld" prefix="core" %>
<%@ taglib uri="/WEB-INF/hostadmiral-list.tld" prefix="list" %>
<backpath:init backPathIgnore="pg" />
<html>
 
<head>
/hostadmiral/trunk/webapp/user/list.jsp
6,7 → 6,6
<%@ taglib uri="/WEB-INF/ak-strutsx.tld" prefix="strutsx" %>
<%@ taglib uri="/WEB-INF/hostadmiral-core.tld" prefix="core" %>
<%@ taglib uri="/WEB-INF/hostadmiral-list.tld" prefix="list" %>
<backpath:init backPathIgnore="pg" />
<html>
 
<head>
/hostadmiral/trunk/webapp/mail/box/list.jsp
6,7 → 6,6
<%@ taglib uri="/WEB-INF/ak-strutsx.tld" prefix="strutsx" %>
<%@ taglib uri="/WEB-INF/hostadmiral-core.tld" prefix="core" %>
<%@ taglib uri="/WEB-INF/hostadmiral-list.tld" prefix="list" %>
<backpath:init backPathIgnore="pg" />
<html>
 
<head>
/hostadmiral/trunk/webapp/mail/alias/list.jsp
6,7 → 6,6
<%@ taglib uri="/WEB-INF/ak-strutsx.tld" prefix="strutsx" %>
<%@ taglib uri="/WEB-INF/hostadmiral-core.tld" prefix="core" %>
<%@ taglib uri="/WEB-INF/hostadmiral-list.tld" prefix="list" %>
<backpath:init backPathIgnore="pg" />
<html>
 
<head>
/hostadmiral/trunk/sql/update/0001_0000-to-0002_0000.sql
0,0 → 1,15
--
-- HostAdmiral
-- update DB structure from 1 to 2.0
--
 
-- dbversion changed
 
drop table dbversion;
 
create table dbversion
(
major integer not null,
minor integer not null
);
insert into dbversion (major, minor) values (2, 0);
/hostadmiral/trunk/sql/00.tables.sql
10,9 → 10,12
-- one and only one entry is allowed
create table dbversion
(
version integer not null
major integer not null, -- incremented if old structure is now useable with new code and upgrade needed
-- e.g. new tables, fields, new field type etc. minor is reset to 0
minor integer not null -- incremented if some additional things changes and upgrade recomended but not
-- not needed, e.g. indexes
);
insert into dbversion (version) values (1);
insert into dbversion (major, minor) values (2, 0);
 
-- passwords for different objects and crypted by different digests
create table passwords