head	1.7;
access;
symbols
	TIGRIS_NOV_12_2000:1.6
	OLDHELM:1.6.0.4
	TIGRIS_NOV_11_2000:1.6
	TIGRIS_SEP_13_2000:1.6.0.2
	TIGRIS_BASELINE:1.6;
locks; strict;
comment	@# @;


1.7
date	2000.11.12.23.16.10;	author dlr;	state dead;
branches;
next	1.6;

1.6
date	2000.09.20.03.13.17;	author brian;	state Exp;
branches;
next	1.5;

1.5
date	2000.06.30.22.30.15;	author dlr;	state Exp;
branches;
next	1.4;

1.4
date	2000.06.01.01.05.04;	author ed;	state Exp;
branches;
next	1.3;

1.3
date	2000.04.18.00.10.35;	author jrobbins;	state Exp;
branches;
next	1.2;

1.2
date	2000.02.03.04.21.33;	author jrobbins;	state Exp;
branches;
next	1.1;

1.1
date	2000.01.30.01.59.39;	author jrobbins;	state Exp;
branches;
next	;


desc
@@


1.7
log
@Moved to mail sub-package.
@
text
@/* ================================================================
 * Copyright (c) 2000 Collab.Net.  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 acknowlegement: "This product includes
 * software developed by Collab.Net (http://www.Collab.Net/)."
 * Alternately, this acknowlegement may appear in the software itself, if
 * and wherever such third-party acknowlegements normally appear.
 * 
 * 4. The hosted project names must not be used to endorse or promote
 * products derived from this software without prior written
 * permission. For written permission, please contact info@@collab.net.
 * 
 * 5. Products derived from this software may not use the "Tigris" name
 * nor may "Tigris" appear in their names without prior written
 * permission of Collab.Net.
 * 
 * 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 COLLAB.NET 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 Collab.Net.
 */


package org.tigris.helm.tool;

import java.util.*;
import com.sun.java.util.collections.*;
import java.sql.*;
import org.tigris.helm.tool.UpdateException;
import org.tigris.helm.tool.TigrisUpdate;

/**
 * This class provides facilities for dealing with mailing lists. An instance
 * of this class represents the settings given to an existing mailing list.
 * Static methods provided in the class allow for creating, listing, and
 * deleting mailing lists from a project.
 *
 * <p>This class subclasses from TigrisPrivs, even though it is not actually
 * a privileges class. However, the mailing list options idiom is nearly
 * identical to the mailing list one, so we use it.
 *
 * <p>Note that the setPrivilege() method, which should be used to change
 * the boolean options, does not call update, nor do the setOwner() and
 * setSubList() methods in this class. You must call TigrisUpdate.update()
 * directly following these changes.
 */
public class MailingList {
    /**
     * An array of the names of the options
     */
    private static String[] optList = {
        "archived", "digest", "prefix", "guard_archive", "indexed",
        "kill_opt", "list_subs", "message_moderation", "new_text_file",
        "public", "request_address", "remote_admin", "sub_moderation",
        "trailer", "user_posts_only", "address_restriction", "extra"
    };
    protected List initPrivList() {
        return Arrays.asList(optList);
    }
 
    public static int DISPLAY_ALL = 7;
    public static int DISPLAY_ADVANCED = 4;
    public static int DISPLAY_BEGINER = 2;
    public static int DISPLAY_NONE = 0;

    protected int level; // this is matched against the DISPLAY_* bits above
                         // to decide which options to show at a given level.

    public static class ListOption {
        String description;
        String name;
        boolean defaultFlag;
        int displayLevel;

        public ListOption(String name, String description, boolean defaultFlag,
                int displayLevel) {
            this.name = name;
            this.description = description;
            this.defaultFlag = defaultFlag;
            this.displayLevel = displayLevel;
        }

        public boolean shouldDisplay (int level) {
            return (level & displayLevel) != 0;
        }

        public String getName () {
            return name;
        }

        public String getDescription () {
            return description;
        }

        public boolean getDefault () {
            return defaultFlag;
        }

        public int getDisplayLevel () {
            return displayLevel;
        }
    }

    private static HashMap optTable;
    static {
        // Initialize the list of privileges. Eventually this should probably
        // be serialized. For now this will do.
        optTable = new HashMap(optList.length);
        optTable.put("archived",
            new ListOption("archived", "Archived",
                           true, DISPLAY_ALL));
        optTable.put("digest",
            new ListOption("digest","Digest",
                           true, DISPLAY_ALL));
        optTable.put("prefix",
            new ListOption("prefix","Prefix",
                           true, DISPLAY_ALL));
        optTable.put("guard_archive",
            new ListOption("guard_archive","Guard archive",
                           true, DISPLAY_ADVANCED));
        optTable.put("indexed",
            new ListOption("indexed","Indexed", 
                           true, DISPLAY_ADVANCED));
        optTable.put("kill_opt",
            new ListOption("kill_opt","Kill", 
                           true, DISPLAY_ADVANCED));
        optTable.put("list_subs",
            new ListOption("list_subs","List subscribers", 
                           true, DISPLAY_ADVANCED));
        optTable.put("message_moderation",
            new ListOption("message_moderation","Message moderation", 
                           false, DISPLAY_ADVANCED));
        optTable.put("new_text_file",
            new ListOption("new_text_file","New text file", 
                           true, DISPLAY_ADVANCED));
        optTable.put("public",
            new ListOption("public","Public", 
                           true, DISPLAY_ADVANCED));
        optTable.put("request_address",
            new ListOption("request_address","Request address is serviced", 
                           true, DISPLAY_ADVANCED));
        optTable.put("remote_admin",
            new ListOption("remote_admin","Remote admin", 
                           true, DISPLAY_ADVANCED));
        optTable.put("sub_moderation",
            new ListOption("sub_moderation","Subscription moderation", 
                           false, DISPLAY_ALL));
        optTable.put("trailer",
            new ListOption("trailer","Trailer", 
                           true, DISPLAY_ADVANCED));
        optTable.put("user_posts_only",
            new ListOption("user_posts_only","User posts only", 
                           true, DISPLAY_ADVANCED));
        optTable.put("address_restriction",
            new ListOption("address_restriction","Address restriction", 
                           false, DISPLAY_ADVANCED));
        optTable.put("extra",
            new ListOption("extra","A few extras", 
                           true, DISPLAY_ADVANCED));
    };
    protected Map initPrivTable() {
        return optTable;
    }

    public static class MLEntry {
        private ListOption option;
        private boolean value;
        private int level;

        MLEntry(ListOption option, boolean value, int level) {
            this.value = value;
            this.option = option;
            this.level = level;
        }

        /**
         * Get the internal name of this option. This generally corresponds
         * to the database column this name is found under
         */
        public String getName() { return option.getName(); }
        /**
         * Returns a short description of this option, usually about
         * a sentence in length.
         */
        public String getText() { return option.getDescription(); }
        /**
         * Obtain the default value of this option.
         *
         * @@return true if and only if the option exists and is valid
         */
        public boolean getValue() { return value; }

        public boolean getShouldDisplay () {
            return option.shouldDisplay(level);
        }
    } /* end class MLEntry */

    /**
     * Returns a List of MailingList.MLEntry entries for the
     * default values for a mailing list for the boolean options.
     */
    public static List getDefaultValues() {
        return Arrays.asList(getDefaultValuesArray(DISPLAY_BEGINER));
    }

    public static MLEntry[] getDefaultValuesArray() {
        return getDefaultValuesArray(DISPLAY_BEGINER);
    }

    public static MLEntry[] getDefaultValuesArray(int level) {
        MLEntry[] opts = new MLEntry[optList.length];
        for (int i = 0; i < optList.length; i++) {
            ListOption option =(ListOption)optTable.get(optList[i]);
            opts[i] = new MLEntry(option, option.getDefault(), level);
        }
        return opts;
    }

    /**
     * A list of the names of the privileges. They should correspond
     * to the columns of the privilege table, and should map to the keys
     * of the privTable table below.
     */
    private List privList = initPrivList();

    /**
     * The current privileges. The keys are the names of the privs.
     * The values are instances of class Boolean (true for Y)
     */
    private HashMap privValues;

  
    /**
     * A map with the (db) names of the privileges as keys and
     * a short description of them as values.
     */
    private Map privTable = initPrivTable();

    /**
     * Does a row for this set of privileges exist in the table?
     */
    protected boolean rowExists;

    /**
     * The table used to find the current privileges in.
     */
    private String tableName;
  
    /**
     * Non-boolean list option: list owner (null if none)
     */
    private String owner;

    /**
     * Non-boolean list option: sublist of another list (null if main list)
     */
    private String subList;

    private Connection connection;

    /**
     * A Map containing as keys Strings naming the columns of the
     * database table named in tableName used to identify uniquely
     * the row of the table for this instance, and as values Strings
     * giving the proper value for the mapped key.
     */
    private Map queryMap;

    public static class DoesNotExist extends Exception {
        private DoesNotExist(String project, String list) {
            super("List " + list + " does not exist in project " + project);
        }
        private DoesNotExist() {
            super("List does not exist in project");
        }
    } /* end class DoesNotExist */ 

    /**
     * Create a new MailingList object based on the given mailing list. 
     *
     * @@param project the project the mailing list belongs to
     * @@param list the name of the mailing list
     *
     * @@exception DoesNotExist if the mailing list does not exist
     * @@exception SQLException if there is a database error
     */
    public MailingList(Connection connection, String project, String list)
            throws SQLException, DoesNotExist {
    
        queryMap = mlistQueryMap(project,list);
        tableName = "project_mlists";
        this.connection = connection;
    
        StringBuffer cols = new StringBuffer();
        for (Iterator i = privList.iterator(); i.hasNext();) {
            cols.append((String)i.next());
            if (i.hasNext())
                cols.append(',');
        }
    
        Statement s = connection.createStatement();
        ResultSet r = s.executeQuery("SELECT " + cols + " " +
                                     "FROM " + tableName + " " + 
                                     "WHERE " + whereQuery());
    
        rowExists = r.next();
    
        // Fill up the privValues table with either the results from the
        // database, or default values if no row exists
        privValues = new HashMap(privList.size());
        for (ListIterator i = privList.listIterator(); i.hasNext();) {
            int idx = i.nextIndex();
            String name = (String)i.next();
            Boolean result = new Boolean(rowExists ? 
                    r.getString(idx+1).equals("Y") : defaultPriv(name));
            privValues.put(name, result);
        }
    
        // if the row exists, then we mine it for the non-boolean options
        if (rowExists) {
            r = s.executeQuery("SELECT owner,sublist FROM project_mlists " +
                               "WHERE " + whereQuery());
            if (r.next()) {    // This should always be true, btw
                owner = r.getString(1);
                subList = r.getString(2);
            }
        } else {
            // Unlike privs, we care that our row exists
            throw new DoesNotExist(project, list);
        }
    }

    private static Map mlistQueryMap(String project, String list) {
        HashMap queryMap = new HashMap(1);
        queryMap.put("project", project);
        queryMap.put("list", list);
        return queryMap;
    }

    /**
     * Several mailing list options are, by default, on. Indicate this
     * to the privs mechanism
     */
    protected static boolean defaultPriv(String optName) {
        if (optName.equals("archived"))
            return true;
        if (optName.equals("indexed"))
            return true;
        if (optName.equals("public"))
            return true;
        if (optName.equals("remote_admin"))
            return true;
        if (optName.equals("new_text_file"))
            return true;

        return false;
    }

    /**
     * Returns a List of PrivilegeEntry objects that represent the
     * domain privileges for this object
     *
     * @@see TigrisPrivs.PrivilegeEntry
     */
    public List getPrivList() {
        return Arrays.asList(getPrivArray());
    }

    public MLEntry[] getPrivArray() {
        return getPrivArray(DISPLAY_BEGINER);
    }

    public MLEntry[] getPrivArray(int level) {
        MLEntry[] privs = new MLEntry[privList.size()];
        for (ListIterator i = privList.listIterator(); i.hasNext();) {
            int idx = i.nextIndex();
            ListOption opt = (ListOption) optTable.get(i.next());
            privs[idx] = new MLEntry(opt,
                    Boolean.TRUE.equals(privValues.get(opt.getName())), level);
        }
        return privs;
    }

    public Boolean privValue(String name) {
        return (Boolean)privValues.get(name);
    }

    /**
     * Returns a List of Strings corresponding to the names of the
     * privileges
     */
    public List getPrivNames() {
        return Collections.unmodifiableList(privList);
    }

    /**
     * Changes a privilege. This method presumes the privilege is a
     * valid name; if not, an SQL error may occur.
     *
     * @@param privilege the name of the privilege to change
     * @@param value true if and only if the given privilege should exist
     */
    public void setPrivilege(String privilege, boolean value)
            throws SQLException {
        Statement s = connection.createStatement();
    
        // only bother changing if we're making a change
        if (value == getPrivilege(privilege))
            return;
    
        if (rowExists) {
            s.executeUpdate("UPDATE " + tableName + " SET " + privilege +
                    " = '" + (value ? 'Y' : 'N') + "' WHERE " + whereQuery());
        } else {
            StringBuffer insertCols = new StringBuffer();
            StringBuffer insertVals = new StringBuffer();
            insertQuery(insertCols, insertVals);
      
            // Note that both strings now end with a comma. We use this fact
            // below.
      
            s.executeUpdate("INSERT INTO " + tableName + " (" + insertCols +
                    privilege + ") VALUES (" + insertVals +
                    (value ? "'Y'" : "'N'") + ')');
            rowExists = true;
        }
    
        privValues.put(privilege, new Boolean(value));
    }

    /**
     * Generate the appropriate columns and values for an INSERT statement.
     * Matching comma-seperated lists of colums and values will be written
     * into the StringBuffer objects passed as arguments. Both strings
     * will be comma-terminated, to allow for another column/value to
     * be present after them with ease.
     *
     * <p>The StringBuffer arguments should be empty when this function
     * is called; the function simply appends to them, and does not clear
     * the values first.
     *
     * @@param insertCols an allocated StringBuffer for the columns
     * @@param insertVals an allocated StringBuffer for the values
     */
    protected void insertQuery(StringBuffer insertCols,
                               StringBuffer insertVals) {
        Iterator i = queryMap.entrySet().iterator();
        while (i.hasNext()) {
            Map.Entry entry = (Map.Entry)i.next();
            insertCols.append((String)entry.getKey());
            insertCols.append(',');
            insertVals.append('\'');
            insertVals.append((String)entry.getValue());
            insertVals.append("',");
        }
    }

    /**
     * Generate the appropriate WHERE statement for this query, not
     * including the "WHERE" phrase. For example, for the privileges
     * for user <code>akosut</code>, this method would return
     * "username = 'akosut'"
     */
    protected String whereQuery() {
        StringBuffer query = new StringBuffer();
    
        Iterator i = queryMap.entrySet().iterator(); 
        while (i.hasNext()) {
            Map.Entry entry = (Map.Entry)i.next();
            query.append((String)entry.getKey());
            query.append(" = '");
            query.append((String)entry.getValue());
            query.append('\'');
            if (i.hasNext())
                query.append(" AND ");
        }
    
        return query.toString();
    }


  
    /**
     * Return the owner of this mailing list, or null if none specified
     */
    public String getOwner() {
        return owner;
    }

    /**
     * If this list is a sublist of another mailing list, return the main
     * list. Otherwise, return null
     */
    public String getSubList() {
        return subList;
    }

    /**
     * Set the owner of this mailing list. Note that UpdateTigris.update()
     * is not called, and should be invoked by the caller.
     *
     * @@param owner The new owner, or null for none
     *
     * @@exception SQLException if there is a database error
     * @@exception DoesNotExist if the mailing list does not exist
     */
    public void setOwner(String owner) throws SQLException,DoesNotExist {
        setStringOption("owner", owner, this.owner);
        this.owner = owner;
    }

    /**
     * Set the main list of this sublist. Note that UpdateTigris.update()
     * is not called, and should be invoked by the caller.
     *
     * @@param sublist The main list, or null if this list is not a sublist
     *
     * @@exception DoesNotExist if the mailing list does not exist
     * @@exception SQLException if there is a database error
     */
    public void setSubList(String subList) throws SQLException, DoesNotExist {
        setStringOption("sublist", subList, this.subList);
        this.subList = subList;
    }

    /**
     * Change a string option. Note that although the instance variable
     * is passed to this method (so it can see if a change is needed),
     * it <b>is not changed</b>. Methods calling this one should change
     * the member variable after (not before) this function returns.
     *
     * @@param option the name of the option (database column) to change
     * @@param value the new value for the option, possibly null
     * @@param curVal the current value for the option, possibly null
     *
     * @@exception DoesNotExist if the mailing list does not exist
     * @@exception SQLException if there is a database error
     */
    private void setStringOption(String option, String value, String curVal)
            throws SQLException, DoesNotExist {
        // If we're not making a change, don't do anything
        if ((value == null && curVal == null)
                || (value != null && curVal != null && value.equals(curVal))) {
            return;
        }

        if (!rowExists) {
            throw new DoesNotExist();
        }

        // Properly quote string or SQL NULL
        if (value != null)
            value = '\'' + value + '\'';
        else
            value = "NULL";

        Statement s = connection.createStatement();
        s.executeUpdate("UPDATE project_mlists SET " + option + " = " +
                value + " WHERE " + whereQuery());
    }

    /**
     * This exception indicates that the given mailing list already exists.
     */
    public static class AlreadyExists extends Exception {
        private String project, list;

        /**
         * Create a new "list already exists" exception
         *
         * @@param project the project the list is in
         * @@param list the list that already exists
         */
        public AlreadyExists(String project, String list) {
            super("List " +list + " already exists in project " + project);
            this.project = project;
            this.list = list;
        }

        /**
         * Return the project of the list
         */
        public String getProject() {
            return project;
        }

        /**
         * The name of hte list that already exists
         */
        public String getList() {
            return list;
        }
    } /* end class AlreadyExists */

    /**
     * Returns the value of the given privilege
     *
     * @@param privilege the name of the privilege to query
     * @@return true if and only if the privilege exists and is valid
     */
    public boolean getPrivilege(String privilege) {
        try {
            return ((Boolean)privValues.get(privilege)).booleanValue();
        } catch (NullPointerException e) {
            return false;
        }
    }
  
    /**
     * Returns a short (sentence-long) description of the abilities
     * granted by the given privilege
     *
     * @@param privilege the name of the privilege to describe
     * @@return a description, or null if the named privilege does not exist
     */
    public String getDescription(String privilege) {
        ListOption option = (ListOption)privTable.get(privilege);
        return option.getDescription();
    }
  
    
    /**
     * A mailing list entry from the Tigris database
     */
    public static class Entry {
        private String project, list;
    
        /**
         * Create a new list entry with the given project and list name
         * 
         * @@param project the project this list belongs to
         * @@param list the name of the list
         */
        public Entry(String project, String list) {
            this.project = project;
            this.list = list;
        }

        public String getProject() {
            return project;
        }

        public String getList() {
            return list;
        }
    } /* end class Entry */

    /**
     * Create a new mailing list.
     *
     * @@param tigris the Tigris context
     * @@param project the project this list belongs to
     * @@param list the name of the list
     * @@param update whether or not to call the update program
     *        after creating the mailing list
     *
     * @@exception SQLException if there was a database error
     * @@exception UpdateException if the update program could not be run
     * @@exception AlreadyExists if a list by this name already exists
     */
    public static void addMailingList(Connection connection, String project,
            String list, boolean update) 
            throws SQLException, UpdateException, AlreadyExists {
        Statement s = connection.createStatement();
        
        // Check to see if the list does not already exist
        ResultSet r = s.executeQuery("SELECT list FROM project_mlists " +
                                     "WHERE project = '" + project + "' " +
                                     "AND list = '" + list + "'");
        
        // If any rows are found, the module is already taken
        if (r.next())
            throw new AlreadyExists(project, list);

        s.executeUpdate("INSERT INTO project_mlists (project,list) " +
                        "VALUES ('" + project + "','" + list + "')");
        }

    /**
     * Remove a mailing list from the database.
     *
     * @@param tigris The Tigris context to operate in
     * @@param project The name of the project the list is for
     * @@param module The name of the list to delete
     *
     * @@exception SQLException if there was a database error
     * @@exception UpdateException if the update program could not be run
     */
    public static void deleteMailingList(Connection connection, String project,
            String list) throws SQLException, UpdateException {
        Statement s = connection.createStatement();
        
        // Delete project from all rows
        String whereQuery = " WHERE project = '" + project + "'" +
                            " AND list = '" + list + '\'';
        s.executeUpdate("DELETE FROM project_mlists" + whereQuery);
        
        // Update the database
        TigrisUpdate.update(connection);
    }

    /**
     * Retrive a list of mailing lists from the database.
     *
     * @@param tigris the Tigris context
     * @@param project the project to list mailing lists from
     * @@return a List of MailingList.Entry objects representing all the modules
     *         in the project, ordered alphabetically by project name
     */
    public static List getMailingLists(Connection connection, String project)
            throws SQLException {
        ArrayList lists = new ArrayList();

        Statement s = connection.createStatement();
        ResultSet r = s.executeQuery("SELECT list FROM project_mlists " +
                                     "WHERE project = '" + project + "' " +
                                     "ORDER BY list");
        while (r.next()) {
            lists.add(new Entry(project, r.getString(1)));
        }

        return lists;
    }

} /* end class MailingList */
@


1.6
log
@
Obtained from:
Submitted by:
Reviewed by:

Moved from org.helm to org.tigris.helm
Moved from org/helm to org/tigris/helm

perl -pi.bak -e, how I love thee

note: this update was done POST-CVS-REPOSITORY surgury.  In order to
get this right, you may need to remove the directories

$CVSROOT/helm/java/org/helm
$CVSROOT/helm/data/htdoc/look/www/org/helm
$CVSROOT/helm/templates/org/helm

before doing the "CVS update" call, since those directories don't
exist anymore and CVS will try to create lockfiles for you in them,
giving you an error.
@
text
@@


1.5
log
@Removed unneeded import.
@
text
@d48 1
a48 1
package org.helm.tool;
d53 2
a54 2
import org.helm.tool.UpdateException;
import org.helm.tool.TigrisUpdate;
@


1.4
log
@standardize formatting to 4 spaces
PR:
Obtained from:
Submitted by:
Reviewed by:
@
text
@a49 2
import javax.servlet.*;

@


1.3
log
@switched from collections2.jar to collections.jar
@
text
@d74 183
a256 94
  /**
   * An array of the names of the options
   */
  private static String[] optList = {
    "archived", "digest", "prefix", "guard_archive", "indexed",
    "kill_opt", "list_subs", "message_moderation", "new_text_file",
    "public", "request_address", "remote_admin", "sub_moderation",
    "trailer", "user_posts_only", "address_restriction", "extra"
  };
  protected List initPrivList() {
    return Arrays.asList(optList);
  }

  private static HashMap optTable;
  static {
    // Initialize the list of privileges. Eventually this should probably
    // be serialized. For now this will do.
    optTable = new HashMap(optList.length);
    optTable.put("archived", "Archived");
    optTable.put("digest", "Digest");
    optTable.put("prefix", "Prefix");
    optTable.put("guard_archive", "Guard archive");
    optTable.put("indexed", "Indexed");
    optTable.put("kill_opt", "Kill");
    optTable.put("list_subs", "List subscribers");
    optTable.put("message_moderation", "Message moderation");
    optTable.put("new_text_file", "New text file");
    optTable.put("public", "Public");
    optTable.put("request_address", "Request address is serviced");
    optTable.put("remote_admin", "Remote admin");
    optTable.put("sub_moderation", "Subscription moderation");
    optTable.put("trailer", "Trailer");
    optTable.put("user_posts_only", "User posts only");
    optTable.put("address_restriction", "Address restriction");
    optTable.put("extra", "A few extras");
  };
  protected Map initPrivTable() {
    return optTable;
  }

  public static class MLEntry {
    private String name;
    private boolean value;
	
    MLEntry(String optName, boolean val) {
	name = optName;
	value = val;
    }

    /**
     * Get the internal name of this option. This generally corresponds
     * to the database column this name is found under
     */
    public String getName() { return name; }
    /**
     * Returns a short description of this option, usually about
     * a sentence in length.
     */
    public String getText() { return (String)optTable.get(name); }
    /**
     * Obtain the default value of this option.
     *
     * @@return true if and only if the option exists and is valid
     */
    public boolean getValue() { return value; }
  } /* end class MLEntry */

  /**
   * Returns a List of MailingList.MLEntry entries for the
   * default values for a mailing list for the boolean options.
   */
  public static List getDefaultValues() {
    return Arrays.asList(getDefaultValuesArray());
  }

  public static MLEntry[] getDefaultValuesArray() {
    MLEntry[] opts = new MLEntry[optList.length];
    for (int i = 0; i < optList.length; i++)
	opts[i] = new MLEntry(optList[i], defaultPriv(optList[i]));
    return opts;
  }

  /**
   * A list of the names of the privileges. They should correspond
   * to the columns of the privilege table, and should map to the keys
   * of the privTable table below.
   */
  private List privList = initPrivList();

  /**
   * The current privileges. The keys are the names of the privs.
   * The values are instances of class Boolean (true for Y)
   */
  private HashMap privValues;
d259 15
a273 15
  /**
   * A map with the (db) names of the privileges as keys and
   * a short description of them as values.
   */
  private Map privTable = initPrivTable();

  /**
   * Does a row for this set of privileges exist in the table?
   */
  protected boolean rowExists;

  /**
   * The table used to find the current privileges in.
   */
  private String tableName;
d275 4
a278 106
  /**
   * Non-boolean list option: list owner (null if none)
   */
  private String owner;

  /**
   * Non-boolean list option: sublist of another list (null if main list)
   */
  private String subList;

  private Connection connection;

  /**
   * A Map containing as keys Strings naming the columns of the
   * database table named in tableName used to identify uniquely
   * the row of the table for this instance, and as values Strings
   * giving the proper value for the mapped key.
   */
  private Map queryMap;

  public static class DoesNotExist extends Exception {
    private DoesNotExist(String project, String list) {
	    super("List " + list + " does not exist in project " + project);
    }
    private DoesNotExist() {
	    super("List does not exist in project");
    }
  } /* end class DoesNotExist */ 

  /**
   * Create a new MailingList object based on the given mailing list. 
   *
   * @@param project the project the mailing list belongs to
   * @@param list the name of the mailing list
   *
   * @@exception DoesNotExist if the mailing list does not exist
   * @@exception SQLException if there is a database error
   */
  public MailingList(Connection connection, String project, String list)
    throws SQLException, DoesNotExist {
    
    queryMap = mlistQueryMap(project,list);
    tableName = "project_mlists";
    this.connection = connection;
    
    StringBuffer cols = new StringBuffer();
    for (Iterator i = privList.iterator(); i.hasNext();) {
	    cols.append((String)i.next());
	    if (i.hasNext())
        cols.append(',');
    }
    
    Statement s = connection.createStatement();
    ResultSet r = s.executeQuery("SELECT " + cols + " FROM " + tableName
                                 + " WHERE " + whereQuery());
    
    rowExists = r.next();
    
    // Fill up the privValues table with either the results from the
    // database, or default values if no row exists
    privValues = new HashMap(privList.size());
    for (ListIterator i = privList.listIterator(); i.hasNext();) {
	    int idx = i.nextIndex();
	    String name = (String)i.next();
	    privValues.put(name, new Boolean(rowExists
                                       ? r.getString(idx+1).equals("Y")
                                       : defaultPriv(name)));
    }
    
    // if the row exists, then we mine it for the non-boolean options
    if (rowExists) {
	    r = s.executeQuery("SELECT owner,sublist FROM "
                                   + "project_mlists WHERE " 
                                   + whereQuery());
	    if (r.next()) {	// This should always be true, btw
        owner = r.getString(1);
        subList = r.getString(2);
	    }
    } else {
	    // Unlike privs, we care that our row exists
	    throw new DoesNotExist(project, list);
    }
  }

  private static Map mlistQueryMap(String project, String list) {
    HashMap queryMap = new HashMap(1);
    queryMap.put("project", project);
    queryMap.put("list", list);
    return queryMap;
  }

  /**
   * Several mailing list options are, by default, on. Indicate this
   * to the privs mechanism
   */
  protected static boolean defaultPriv(String optName) {
    if (optName.equals("archived"))
	    return true;
    if (optName.equals("indexed"))
	    return true;
    if (optName.equals("public"))
	    return true;
    if (optName.equals("remote_admin"))
	    return true;
    if (optName.equals("new_text_file"))
	    return true;
d280 104
a383 2
    return false;
  }
d392 1
a392 1
	return Arrays.asList(getPrivArray());
d396 48
a443 41
	MLEntry[] privs = new MLEntry[privList.size()];
	for (ListIterator i = privList.listIterator(); i.hasNext();) {
	    int idx = i.nextIndex();
	    String opt = (String) i.next();
	    privs[idx] = new MLEntry(opt,
				     Boolean.TRUE.equals(privValues.get(opt)));
	}
	return privs;
    }

  /**
   * Returns a List of Strings corresponding to the names of the
   * privileges
   */
  public List getPrivNames() {
    return Collections.unmodifiableList(privList);
  }

  /**
   * Changes a privilege. This method presumes the privilege is a
   * valid name; if not, an SQL error may occur.
   *
   * @@param privilege the name of the privilege to change
   * @@param value true if and only if the given privilege should exist
   */
  public void setPrivilege(String privilege, boolean value)
    throws SQLException {
    Statement s = connection.createStatement();
    
    // only bother changing if we're making a change
    if (value == getPrivilege(privilege))
	    return;
    
    if (rowExists) {
	    s.executeUpdate("UPDATE " + tableName + " SET " + privilege
                      + " = '" + (value ? 'Y' : 'N') + "' WHERE "
                      + whereQuery());
    } else {
	    StringBuffer insertCols = new StringBuffer();
	    StringBuffer insertVals = new StringBuffer();
	    insertQuery(insertCols, insertVals);
d445 2
a446 2
	    // Note that both strings now end with a comma. We use this fact
	    // below.
d448 7
a454 54
	    s.executeUpdate("INSERT INTO " + tableName + " (" + insertCols
                      + privilege + ") VALUES (" + insertVals
                      + (value ? "'Y'" : "'N'") + ')');
	    rowExists = true;
    }
    
    privValues.put(privilege, new Boolean(value));
  }

  /**
   * Generate the appropriate columns and values for an INSERT statement.
   * Matching comma-seperated lists of colums and values will be written
   * into the StringBuffer objects passed as arguments. Both strings
   * will be comma-terminated, to allow for another column/value to
   * be present after them with ease.
   *
   * <p>The StringBuffer arguments should be empty when this function
   * is called; the function simply appends to them, and does not clear
   * the values first.
   *
   * @@param insertCols an allocated StringBuffer for the columns
   * @@param insertVals an allocated StringBuffer for the values
   */
  protected void insertQuery(StringBuffer insertCols,
                             StringBuffer insertVals) {
    Iterator i = queryMap.entrySet().iterator();
    while (i.hasNext()) {
	    Map.Entry entry = (Map.Entry)i.next();
	    insertCols.append((String)entry.getKey());
	    insertCols.append(',');
	    insertVals.append('\'');
	    insertVals.append((String)entry.getValue());
      insertVals.append("',");
    }
  }

  /**
   * Generate the appropriate WHERE statement for this query, not
   * including the "WHERE" phrase. For example, for the privileges
   * for user <code>akosut</code>, this method would return
   * "username = 'akosut'"
   */
  protected String whereQuery() {
    StringBuffer query = new StringBuffer();
    
    Iterator i = queryMap.entrySet().iterator(); 
    while (i.hasNext()) {
	    Map.Entry entry = (Map.Entry)i.next();
	    query.append((String)entry.getKey());
	    query.append(" = '");
	    query.append((String)entry.getValue());
	    query.append('\'');
	    if (i.hasNext())
        query.append(" AND ");
d456 47
d504 2
a505 2
    return query.toString();
  }
d509 6
a514 78
  /**
   * Return the owner of this mailing list, or null if none specified
   */
  public String getOwner() {
    return owner;
  }

  /**
   * If this list is a sublist of another mailing list, return the main
   * list. Otherwise, return null
   */
  public String getSubList() {
    return subList;
  }

  /**
   * Set the owner of this mailing list. Note that UpdateTigris.update()
   * is not called, and should be invoked by the caller.
   *
   * @@param owner The new owner, or null for none
   *
   * @@exception SQLException if there is a database error
   * @@exception DoesNotExist if the mailing list does not exist
   */
  public void setOwner(String owner) throws SQLException,DoesNotExist {
    setStringOption("owner", owner, this.owner);
    this.owner = owner;
  }

  /**
   * Set the main list of this sublist. Note that UpdateTigris.update()
   * is not called, and should be invoked by the caller.
   *
   * @@param sublist The main list, or null if this list is not a sublist
   *
   * @@exception DoesNotExist if the mailing list does not exist
   * @@exception SQLException if there is a database error
   */
  public void setSubList(String subList) throws SQLException, DoesNotExist {
    setStringOption("sublist", subList, this.subList);
    this.subList = subList;
  }

  /**
   * Change a string option. Note that although the instance variable
   * is passed to this method (so it can see if a change is needed),
   * it <b>is not changed</b>. Methods calling this one should change
   * the member variable after (not before) this function returns.
   *
   * @@param option the name of the option (database column) to change
   * @@param value the new value for the option, possibly null
   * @@param curVal the current value for the option, possibly null
   *
   * @@exception DoesNotExist if the mailing list does not exist
   * @@exception SQLException if there is a database error
   */
  private void setStringOption(String option, String value, String curVal)
    throws SQLException, DoesNotExist {
    // If we're not making a change, don't do anything
    if ((value == null && curVal == null)
        || (value != null && curVal != null && value.equals(curVal))) {
	    return;
    }

    if (!rowExists) {
	    throw new DoesNotExist();
    }

    // Properly quote string or SQL NULL
    if (value != null)
	    value = '\'' + value + '\'';
    else
	    value = "NULL";

    Statement s = connection.createStatement();
    s.executeUpdate("UPDATE project_mlists SET " + option + " = "
                    + value + " WHERE " + whereQuery());
  }
d516 3
a518 2
  /**
     * This exception indicates that the given mailing list already exists.
d520 3
a522 2
  public static class AlreadyExists extends Exception {
    private String project, list;
d525 2
a526 1
     * Create a new "list already exists" exception
d528 4
a531 2
     * @@param project the project the list is in
     * @@param list the list that already exists
d533 3
a535 4
    public AlreadyExists(String project, String list) {
	    super("List " +list + " already exists in project " + project);
	    this.project = project;
	    this.list = list;
d539 7
a545 1
     * Return the project of the list
d547 3
a549 2
    public String getProject() {
	    return project;
d553 11
a563 1
     * The name of hte list that already exists
d565 21
a585 2
    public String getList() {
	    return list;
a586 1
  } /* end class AlreadyExists */
d588 45
a632 11
  /**
   * Returns the value of the given privilege
   *
   * @@param privilege the name of the privilege to query
   * @@return true if and only if the privilege exists and is valid
   */
  public boolean getPrivilege(String privilege) {
    try {
      return ((Boolean)privValues.get(privilege)).booleanValue();
    } catch (NullPointerException e) {
      return false;
a633 1
  }
d635 11
a645 10
  /**
   * Returns a short (sentence-long) description of the abilities
   * granted by the given privilege
   *
   * @@param privilege the name of the privilege to describe
   * @@return a description, or null if the named privilege does not exist
   */
  public String getDescription(String privilege) {
    return (String)privTable.get(privilege);
  }
a647 6
  /**
   * A mailing list entry from the Tigris database
   */
  public static class Entry {
    private String project, list;
    
d649 1
a649 4
     * Create a new list entry with the given project and list name
     * 
     * @@param project the project this list belongs to
     * @@param list the name of the list
d651 22
a672 4
    public Entry(String project, String list) {
	    this.project = project;
	    this.list = list;
    }
d674 1
a674 10
    public String getProject() {
	    return project;
    }

    public String getList() {
	    return list;
    }
  } /* end class Entry */

  /**
d687 17
a703 19
  public static void addMailingList(Connection connection, String project,
                                    String list, boolean update) 
    throws SQLException, UpdateException, AlreadyExists {
    Statement s = connection.createStatement();
	
    // Check to see if the list does not already exist
    ResultSet r = s.executeQuery("SELECT list FROM "
                                 + "project_mlists WHERE project = '"
                                 + project + "' AND list = '" + list
                                 + "'");
	
    // If any rows are found, the module is already taken
    if (r.next())
	    throw new AlreadyExists(project, list);

    s.executeUpdate("INSERT INTO project_mlists "
                    + "(project,list) VALUES ('" + project + "','"
                    + list + "')");
  }
d705 1
a705 1
  /**
d715 12
a726 13
  public static void deleteMailingList(Connection connection, String project,
                                       String list)
    throws SQLException, UpdateException {
    Statement s = connection.createStatement();
	
    // Delete project from all rows
    String whereQuery = " WHERE project = '" + project
	    + "' AND list = '" + list + '\'';
    s.executeUpdate("DELETE FROM project_mlists" + whereQuery);
	
    // Update the database
    TigrisUpdate.update(connection);
  }
d728 1
a728 1
  /**
d736 13
a748 10
  public static List getMailingLists(Connection connection, String project)
    throws SQLException {
    ArrayList lists = new ArrayList();

    Statement s = connection.createStatement();
    ResultSet r = s.executeQuery("SELECT list FROM "
                                 + "project_mlists WHERE project = '"
                                 + project + "' ORDER BY list");
    while (r.next()) {
	    lists.add(new Entry(project, r.getString(1)));
a749 3

    return lists;
  }
@


1.2
log
@Added tigris.org license
PR:
Obtained from:
Submitted by:
Reviewed by:
@
text
@d53 1
@


1.1
log
@initial checking
@
text
@d1 46
a46 1
// Copyright (c) 2000 Collab.Net, Inc. All Rights Reserved.
@

