+ aLevel=NONE;
+ } else if(aLevel>ALL) {
+ aLevel=ALL;
+ }
+
+ level=aLevel;
+
+ if(level>NONE) {
+ log(INFO,"Log level changed to",level,levels[level]);
+ }
+ }
+
+ public static void setLogger(PrintWriter pw)
+ {
+ if(logger!=null) {
+ try {
+ logger.flush();
+ logger.close();
+ } catch(Exception ex) {
+ logger=pw;
+ log(ERROR,"Exception while closing logger",ex);
+ }
+ }
+ logger=pw;
+ }
+
+ public static void log(String msg)
+ {
+ log(INFO,msg);
+ }
+
+ public static void log(int aLevel,String msg)
+ {
+ write(aLevel,msg,null);
+ }
+
+ public static void log(int aLevel,String msg,int arg1)
+ {
+ Object o[] = {new Integer(arg1)};
+ write(aLevel,msg,o);
+ }
+
+ public static void log(int aLevel,String msg,int arg1,Object arg2)
+ {
+ Object o[] = {new Integer(arg1),arg2};
+ write(aLevel,msg,o);
+ }
+
+ public static void log(int aLevel,String msg,double arg1)
+ {
+ Object o[] = {new Double(arg1)};
+ write(aLevel,msg,o);
+ }
+
+ public static void log(int aLevel,String msg,double arg1,Object arg2)
+ {
+ Object o[] = {new Double(arg1),arg2};
+ write(aLevel,msg,o);
+ }
+
+ public static void log(int aLevel,String msg,Object arg1)
+ {
+ Object o[] = {arg1};
+ write(aLevel,msg,o);
+ }
+
+ public static void log(int aLevel,String msg,Object arg1,Object arg2)
+ {
+ Object o[] = {arg1,arg2};
+ write(aLevel,msg,o);
+ }
+
+ public static void log(int aLevel,String msg,Object arg1,Object arg2,Object arg3)
+ {
+ Object o[] = {arg1,arg2,arg3};
+ write(aLevel,msg,o);
+ }
+
+ public static void log(int aLevel,String msg,Throwable t)
+ {
+ CharArrayWriter buffer = new CharArrayWriter();
+ PrintWriter printWriter = new PrintWriter(buffer);
+ t.printStackTrace(printWriter);
+ Object o[] = {buffer.toString()};
+ buffer.close();
+ write(aLevel,msg,o);
+ }
+
+ private static void write(int aLevel,String aMsg,Object args[])
+ {
+ // Can't be above ALL
+ if(aLevel>ALL) {
+ aLevel=ALL;
+ }
+
+ // Ignore if below or equal to NONE
+ if(aLevellevel) {
+ return;
+ }
+
+ logger.print("Logger:");
+ logger.print(levels[aLevel]);
+ logger.print(aMsg);
+ if(args!=null) {
+ for(int a=0;a
+ logger.print(":");
+ logger.print(args[a]);
+ }
+ }
+ logger.println();
+ logger.flush();
+ }
+
+}
--- /dev/null
+package uk.org.retep.util;
+
+import uk.org.retep.util.StandaloneApp;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+
+/**
+ * This is a template for your own Tools. Copy not extend this class. Please
+ * refer to Implementation for details.
+ *
+ * All you need to to is implement the init() method.
+ *
+ * $Id: Main.java,v 1.1 2001/03/05 09:15:36 peter Exp $
+ */
+
+public class Main extends StandaloneApp
+{
+ public Main(String[] args)
+ throws Exception
+ {
+ super(args);
+ }
+
+ public JComponent init()
+ throws Exception
+ {
+ // Create your tool here, then do things like load files based on the
+ // command line arguments. Then return that tool.
+
+ // NB: This just allows us to compile. You're implementation must return
+ // the Tool itself.
+ return new JLabel("Replace with your own tool!");
+ }
+
+ public static void main(String[] args)
+ throws Exception
+ {
+ Main main = new Main(args);
+ main.pack();
+ main.setVisible(true);
+ }
+}
--- /dev/null
+package uk.org.retep.util;
+
+import uk.org.retep.tools.Tool;
+import uk.org.retep.util.Globals;
+import uk.org.retep.util.ExceptionDialog;
+
+import java.awt.*;
+import javax.swing.*;
+import java.awt.event.*;
+
+/**
+ * This provides the basic services needed for enabling some of the tools to
+ * run in a Stand-alone fassion.
+ *
+ * Note: Because it's designed for standalone use, if this window is closed,
+ * the JVM is terminated. Do not use for normal application use.
+ *
+ * $Id: StandaloneApp.java,v 1.1 2001/03/05 09:15:36 peter Exp $
+ *
+ * @author
+ * @version 1.0
+ */
+
+public abstract class StandaloneApp extends JFrame
+{
+ public StandaloneApp(String[] aArgs)
+ throws Exception
+ {
+ super(); // Initialise JFrame
+
+ // Allow dialogs to work with us
+ ExceptionDialog.setFrame(this);
+
+ // Add a window listener
+ this.addWindowListener(new java.awt.event.WindowAdapter()
+ {
+ public void windowClosing(WindowEvent e)
+ {
+ System.exit(0);
+ }
+ });
+
+ // Parse the command line arguments
+ Globals.getInstance().parseArguments(aArgs);
+
+ // Now initialise this tool (init is overidden)
+ JComponent tool = init();
+
+ // Now add to this frame
+ this.getContentPane().add(tool, BorderLayout.CENTER);
+
+ // Finally call the Tool interface
+ if(tool instanceof Tool) {
+ Tool t = (Tool) tool;
+
+ // Notify the tool we are a standalone
+ t.setStandaloneMode(true);
+
+ // Fetch the title
+ setTitle(t.getTitle());
+
+ // and a MenuBar (if needed)
+ JMenuBar mb = t.getMenuBar();
+ if(mb!=null) {
+ setJMenuBar(t.getMenuBar());
+ }
+ } else {
+ // Ok, set a default title string
+ setTitle("RetepTools Standalone");
+ }
+
+ }
+
+ /**
+ * You must overide this method with your initialiser.
+ */
+ public abstract JComponent init() throws Exception;
+
+}
\ No newline at end of file
--- /dev/null
+package uk.org.retep.util.hba;
+
+import uk.org.retep.tools.Tool;
+import uk.org.retep.util.models.HBATableModel;
+
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.table.*;
+import javax.swing.*;
+
+/**
+ * pg_hba.conf editor (& repairer)
+ *
+ * @author
+ * @version 1.0
+ */
+
+public class Editor extends JPanel implements Tool
+{
+ BorderLayout borderLayout1 = new BorderLayout();
+ HBATableModel model = new HBATableModel();
+ JPanel jPanel1 = new JPanel();
+ GridBagLayout gridBagLayout1 = new GridBagLayout();
+ JLabel jLabel1 = new JLabel();
+ JComboBox typeEntry = new JComboBox();
+ JLabel jLabel2 = new JLabel();
+ JLabel jLabel3 = new JLabel();
+ JLabel jLabel4 = new JLabel();
+ JTextField ipEntry = new JTextField();
+ JTextField maskEntry = new JTextField();
+ JComboBox authEntry = new JComboBox();
+ JTextField argEntry = new JTextField();
+ JLabel jLabel5 = new JLabel();
+ JPanel jPanel2 = new JPanel();
+ FlowLayout flowLayout1 = new FlowLayout();
+ JButton jButton1 = new JButton();
+ JButton jButton2 = new JButton();
+ JScrollPane jScrollPane1 = new JScrollPane();
+ JButton jButton3 = new JButton();
+ JTable jTable1 = new JTable();
+
+ public Editor()
+ {
+ try
+ {
+ jbInit();
+ }
+ catch(Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ void jbInit() throws Exception
+ {
+ this.setLayout(borderLayout1);
+ jTable1.setPreferredSize(new Dimension(600, 300));
+ jTable1.setModel(model);
+ this.setPreferredSize(new Dimension(600, 300));
+ this.add(jScrollPane1, BorderLayout.CENTER);
+ jScrollPane1.getViewport().add(jTable1, null);
+ jPanel1.setLayout(gridBagLayout1);
+ jLabel1.setText("Type");
+ jLabel2.setText("IP Address");
+ jLabel3.setText("Mask");
+ jLabel4.setText("Authentication");
+ ipEntry.setText("jTextField1");
+ maskEntry.setText("jTextField2");
+ argEntry.setText("jTextField3");
+ jLabel5.setText("Argument");
+ jPanel2.setLayout(flowLayout1);
+ jButton1.setText("New entry");
+ jButton2.setText("Validate");
+ jButton3.setText("Devele");
+ this.add(jPanel1, BorderLayout.SOUTH);
+ jPanel1.add(jLabel1, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+ ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+ jPanel1.add(typeEntry, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0
+ ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+ jPanel1.add(jLabel2, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0
+ ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+ jPanel1.add(jLabel3, new GridBagConstraints(3, 1, 1, 1, 0.0, 0.0
+ ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+ jPanel1.add(jLabel4, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
+ ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+ jPanel1.add(ipEntry, new GridBagConstraints(2, 1, 1, 1, 0.0, 0.0
+ ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+ jPanel1.add(maskEntry, new GridBagConstraints(4, 1, 1, 1, 0.0, 0.0
+ ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+ jPanel1.add(authEntry, new GridBagConstraints(2, 2, 1, 1, 0.0, 0.0
+ ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+ jPanel1.add(argEntry, new GridBagConstraints(4, 2, 1, 1, 0.0, 0.0
+ ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+ jPanel1.add(jLabel5, new GridBagConstraints(3, 2, 1, 1, 0.0, 0.0
+ ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+ jPanel1.add(jPanel2, new GridBagConstraints(0, 3, 5, 1, 0.0, 0.0
+ ,GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+ jPanel2.add(jButton3, null);
+ jPanel2.add(jButton1, null);
+ jPanel2.add(jButton2, null);
+ }
+
+ public void openFile(String aFilename)
+ throws IOException
+ {
+ FileInputStream fis = new FileInputStream(aFilename);
+ BufferedReader br = new BufferedReader(new InputStreamReader(fis));
+ ArrayList list = model.getArray();
+
+ String s = br.readLine();
+ while(s!=null) {
+ if(s.startsWith("#")) {
+ // ignore comments
+ } else {
+ Record rec = Record.parseLine(s);
+ if(rec!=null) {
+ rec.validate();
+ list.add(rec);
+ }
+ }
+ s=br.readLine();
+ }
+
+ model.fireTableDataChanged();
+ }
+
+ public JMenuBar getMenuBar()
+ {
+ return null;
+ }
+
+ public String getTitle()
+ {
+ return "pg_hba.conf Editor/Repair tool";
+ }
+
+ public void setStandaloneMode(boolean aMode)
+ {
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package uk.org.retep.util.hba;
+
+import uk.org.retep.util.ExceptionDialog;
+import uk.org.retep.util.Globals;
+import uk.org.retep.util.Logger;
+import uk.org.retep.util.StandaloneApp;
+
+import java.io.IOException;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+
+/**
+ * Standalone entry point for the Properties editor
+ *
+ * $Id: Main.java,v 1.1 2001/03/05 09:15:37 peter Exp $
+ */
+
+public class Main extends StandaloneApp
+{
+ public Main(String[] args)
+ throws Exception
+ {
+ super(args);
+ }
+
+ public JComponent init()
+ throws Exception
+ {
+ Globals globals = Globals.getInstance();
+
+ Editor editor = new Editor();
+
+ if(globals.getArgumentCount()>0) {
+ editor.openFile(globals.getArgument(0));
+ }
+
+ return editor;
+ }
+
+ public static void main(String[] args)
+ throws Exception
+ {
+ Main main = new Main(args);
+ main.pack();
+ main.setVisible(true);
+ }
+}
--- /dev/null
+package uk.org.retep.util.hba;
+
+import uk.org.retep.util.Logger;
+import uk.org.retep.util.misc.IPAddress;
+import uk.org.retep.util.misc.WStringTokenizer;
+
+/**
+ * Used to store the entries of a pg_hba.conf file
+ * @author
+ * @version 1.0
+ */
+
+public class Record
+{
+ int type;
+ String dbname;
+ IPAddress ip;
+ IPAddress mask;
+ int authType;
+ String authArg;
+
+ public static final int TYPE_LOCAL = 0;
+ public static final int TYPE_HOST = 1;
+ public static final int TYPE_HOSTSSL = 2;
+
+ public static final String types[] = {
+ "local","host","hostssl"
+ };
+
+ public static final int AUTH_TRUST = 0;
+ public static final int AUTH_PASSWORD = 1;
+ public static final int AUTH_CRYPT = 2;
+ public static final int AUTH_IDENT = 3;
+ public static final int AUTH_KRB4 = 4;
+ public static final int AUTH_KRB5 = 5;
+ public static final int AUTH_REJECT = 6;
+
+ public static final String auths[] = {
+ "trust","password","crypt",
+ "ident",
+ "krb4","krb5",
+ "reject"
+ };
+
+ private static final String spc = " ";
+
+ public Record()
+ {
+ }
+
+ public int getType()
+ {
+ return type;
+ }
+
+ public void setType(int aType)
+ {
+ type=aType;
+ }
+
+ public String getDatabase()
+ {
+ return dbname;
+ }
+
+ public void setDatabase(String aDB)
+ {
+ dbname=aDB;
+ }
+
+ public int getAuthType()
+ {
+ return authType;
+ }
+
+ public void setAuthType(int aType)
+ {
+ authType=aType;
+ }
+
+ public String getAuthArgs()
+ {
+ return authArg;
+ }
+
+ public void setAuthArgs(String aArg)
+ {
+ authArg=aArg;
+ }
+
+ public IPAddress getIP()
+ {
+ return ip;
+ }
+
+ public void setIP(String aArg)
+ {
+ setIP(new IPAddress(aArg));
+ }
+
+ public void setIP(IPAddress aArg)
+ {
+ ip=aArg;
+ }
+
+ public IPAddress getMask()
+ {
+ return mask;
+ }
+
+ public void setMask(String aArg)
+ {
+ setMask(new IPAddress(aArg));
+ }
+
+ public void setMask(IPAddress aArg)
+ {
+ mask=aArg;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ write(buf);
+ return buf.toString();
+ }
+
+ public void write(StringBuffer buf)
+ {
+ buf.append(types[type]).append(spc);
+
+ if(type==TYPE_HOST || type==TYPE_HOSTSSL) {
+ buf.append(getIP()).append(spc);
+ buf.append(getMask()).append(spc);
+ }
+
+ buf.append(auths[authType]);
+
+ // Now the authArg
+ switch(type)
+ {
+ // These have no authArgs
+ case AUTH_TRUST:
+ case AUTH_REJECT:
+ case AUTH_KRB4:
+ case AUTH_KRB5:
+ break;
+
+ // These must have an arg
+ case AUTH_IDENT:
+ buf.append(spc).append(getAuthArgs());
+ break;
+
+ // These may have an optional arg
+ case AUTH_PASSWORD:
+ case AUTH_CRYPT:
+ if(!(authArg==null || authArg.equals("")))
+ buf.append(spc).append(getAuthArgs());
+ break;
+ }
+ }
+
+ private static WStringTokenizer tok;
+
+ public static Record parseLine(String s)
+ {
+ Record res = new Record();
+ int type;
+
+ if(s==null || s.equals("") || s.startsWith("#"))
+ return null;
+
+ if(tok==null)
+ tok=new WStringTokenizer();
+
+ tok.setString(s);
+
+ type=WStringTokenizer.matchToken(types,tok.nextToken());
+ res.setType(type);
+
+ res.setDatabase(tok.nextToken());
+
+ if(type==TYPE_HOST || type==TYPE_HOSTSSL) {
+ res.setIP(new IPAddress(tok.nextToken()));
+ res.setMask(new IPAddress(tok.nextToken()));
+ }
+
+ res.setAuthType(WStringTokenizer.matchToken(auths,tok.nextToken()));
+ res.setAuthArgs(tok.nextToken());
+
+ return res;
+ }
+
+ public static final int VALID = 0;
+ public static final int INVALID_TYPE = 1;
+ public static final int INVALID_IPREQUIRED = 2;
+
+ /**
+ * Validates the record
+ */
+ public int validate()
+ {
+ switch(type)
+ {
+ case TYPE_HOST:
+ case TYPE_HOSTSSL:
+ if(ip==null || ip.isInvalid()) {
+ Logger.log(Logger.INFO,"pg_hba.conf: IP missing or invalid - repairing");
+ setMask("127.0.0.1");
+ }
+
+ if(mask==null || mask.isInvalid() || !ip.validateMask(mask)) {
+ Logger.log(Logger.INFO,"pg_hba.conf: IP address without mask - repairing");
+ setMask(ip.getMask());
+ }
+
+ break;
+
+ case TYPE_LOCAL:
+ break;
+
+ default:
+ return INVALID_TYPE;
+ }
+
+ return VALID;
+ }
+
+ /*
+# host all 192.168.54.1 255.255.255.255 reject
+# host all 0.0.0.0 0.0.0.0 krb5
+# host all 192.168.0.0 255.255.0.0 ident omicron
+#
+
+local all trust
+host all 127.0.0.1 255.255.255.255 trust
+*/
+}
\ No newline at end of file
--- /dev/null
+package uk.org.retep.util.misc;
+
+import java.util.StringTokenizer;
+
+/**
+ * Represent an IP address
+ * @author
+ * @version 1.0
+ */
+
+public class IPAddress
+{
+ protected long address;
+ protected long b[] = new long[4];
+ protected boolean invalid=true;
+
+ public IPAddress()
+ {
+ }
+
+ public IPAddress(String s)
+ {
+ setAddress(s);
+ }
+
+ public synchronized void setAddress(String s)
+ {
+ if(s==null || s.equals("")) {
+ invalid=true;
+ return;
+ }
+
+ address=0;
+ StringTokenizer tok = new StringTokenizer(s,".");
+ int i=0;
+ while(i<4 && tok.hasMoreElements()) {
+ b[i++] = Long.parseLong(tok.nextToken());
+ }
+ while(i<4) {
+ b[i++]=0;
+ }
+
+ invalid=false;
+ refresh();
+ }
+
+ public void refresh()
+ {
+ if(invalid)
+ return;
+ address = (b[0]<<24) | (b[1]<<16) | (b[2]<<8) | (b[3]);
+ }
+
+ public boolean isInvalid()
+ {
+ refresh();
+ return invalid;
+ }
+
+ public String toString()
+ {
+ refresh();
+ if(invalid)
+ return "*INVALID*";
+
+ return Long.toString(b[0])+"."+Long.toString(b[1])+"."+Long.toString(b[2])+"."+Long.toString(b[3]);
+ }
+
+ public boolean equals(Object o)
+ {
+ if(o instanceof IPAddress) {
+ IPAddress ip = (IPAddress) o;
+
+ refresh();
+ ip.refresh();
+
+ if(ip.invalid == invalid)
+ return false;
+
+ return address==ip.address;
+ }
+ return false;
+ }
+
+ private static int gethoststart(long b)
+ {
+ if((b & 0x80)==0x00) return 1; // class A
+ if((b & 0xc0)==0x80) return 2; // class B
+ if((b & 0xe0)==0xc0) return 3; // class C
+ return 4; // class D
+ }
+
+ public boolean validateMask(IPAddress mask)
+ {
+ // If were a network check the host mask
+ int i=gethoststart(b[0]);
+System.out.println("Host start "+i);
+ while(i<4 && b[i]==0) {
+ if(mask.b[i++]>0)
+ return false;
+ }
+
+ for(i=0;i<4;i++) {
+ if((b[i]&mask.b[i])!=b[i])
+ return false;
+ }
+
+ return true;
+ }
+
+ public IPAddress getMask()
+ {
+ IPAddress mask = new IPAddress();
+ int i=3;
+ while(i>-1 && b[i]==0) {
+ mask.b[i--]=0;
+ }
+ while(i>-1) {
+ mask.b[i--]=255;
+ }
+ mask.invalid=false;
+ mask.refresh();
+ return mask;
+ }
+}
\ No newline at end of file
--- /dev/null
+package uk.org.retep.util.misc;
+
+import java.io.*;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.TreeMap;
+
+/**
+ * Misc Properties utilities..
+ * @author
+ * @version 1.0
+ */
+
+public class PropertiesIO
+{
+
+ public PropertiesIO()
+ {
+ }
+
+ /**
+ * Builds a TreeMap based on the given Properties object. This is useful
+ * because the keys will be in sorted order.
+ */
+ public static TreeMap getTreeMap(Properties p)
+ {
+ TreeMap map = new TreeMap();
+ Iterator e = p.keySet().iterator();
+ while(e.hasNext()) {
+ Object k = e.next();
+ map.put(k,p.get(k));
+ }
+ return map;
+ }
+
+ /**
+ * Writes a Properties file to the writer. This is similar to Properties.save
+ * except you can pick the key/value separator
+ */
+ public static synchronized void save(Properties p,OutputStream out,char sep,String header)
+ throws IOException
+ {
+ save(p,p.keySet().iterator(),out,sep,header);
+ }
+
+ /**
+ * Writes a Properties file to the writer. This is similar to Properties.save
+ * except you can pick the key/value separator and the keys are written
+ * in a sorted manner
+ */
+ public static synchronized void saveSorted(Properties p,OutputStream out,char sep,String header)
+ throws IOException
+ {
+ save(p,getTreeMap(p).keySet().iterator(),out,sep,header);
+ }
+
+ /**
+ * This is the same as save, only the keys in the enumeration are written.
+ */
+ public static synchronized void save(Properties p,Iterator e, OutputStream out,char sep,String header)
+ throws IOException
+ {
+ BufferedWriter w = new BufferedWriter(new OutputStreamWriter(out, "8859_1"));
+
+ if (header != null) {
+ w.write('#');
+ w.write(header);
+ w.newLine();
+ }
+
+ w.write('#');
+ w.write(new Date().toString());
+ w.newLine();
+
+ while(e.hasNext()) {
+ String key = (String)e.next();
+ w.write(encode(key,true));
+ w.write(sep);
+ w.write(encode((String)p.get(key),false));
+ w.newLine();
+ }
+ w.flush();
+ }
+
+ private static final String specialSaveChars = "=: \t\r\n\f#!";
+
+ /**
+ * Encodes a string in a way similar to the JDK's Properties method
+ */
+ public static String encode(String s, boolean escapeSpace)
+ {
+ int l=s.length();
+ StringBuffer buf = new StringBuffer(l<<1);
+
+ for(int i=0;i
+ char c = s.charAt(i);
+ switch(c)
+ {
+ case ' ':
+ if(i==0 || escapeSpace) {
+ buf.append('\\');
+ }
+ buf.append(' ');
+ break;
+
+ case '\\':
+ buf.append('\\').append('\\');
+ break;
+
+ case '\t':
+ buf.append('\\').append('t');
+ break;
+
+ case '\n':
+ buf.append('\\').append('n');
+ break;
+
+ case '\r':
+ buf.append('\\').append('r');
+ break;
+
+ case '\f':
+ buf.append('\\').append('f');
+ break;
+
+ default:
+ if((c<0x20)||(c>0x7e)) {
+ buf.append('\\').append('u');
+ buf.append(toHex((c >> 12) & 0xF));
+ buf.append(toHex((c >> 8) & 0xF));
+ buf.append(toHex((c >> 4) & 0xF));
+ buf.append(toHex( c & 0xF));
+ } else {
+ if (specialSaveChars.indexOf(c) != -1)
+ buf.append('\\');
+ buf.append(c);
+ }
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Convert a nibble to a hex character
+ * @param nibble the nibble to convert.
+ */
+ public static char toHex(int n) {
+ return hd[(n & 0xF)];
+ }
+
+ /** A table of hex digits */
+ private static final char[] hd = {
+ '0','1','2','3','4','5','6','7',
+ '8','9','A','B','C','D','E','F'
+ };
+}
\ No newline at end of file
--- /dev/null
+package uk.org.retep.util.misc;
+
+/**
+ * Similar to StringTokenizer but handles white spaces and multiple delimiters
+ * between tokens. It also handles quotes
+ *
+ * @author
+ * @version 1.0
+ */
+
+public class WStringTokenizer
+{
+ String string;
+ int pos,len;
+
+ /**
+ * Constructor
+ */
+ public WStringTokenizer()
+ {
+ }
+
+ /**
+ * Constructor: set the initial string
+ * @param aString String to tokenise
+ */
+ public WStringTokenizer(String aString)
+ {
+ setString(aString);
+ }
+
+ /**
+ * @param aString String to tokenise
+ */
+ public void setString(String aString)
+ {
+ string=aString;
+ pos=0;
+ len=string.length();
+ }
+
+ /**
+ * @return true if more tokens may be possible
+ */
+ public boolean hasMoreTokens()
+ {
+ return !(string==null || pos==len);
+ }
+
+ /**
+ * @return next token, null if complete.
+ */
+ public String nextToken()
+ {
+ char c;
+ boolean q=false;
+
+ if(!hasMoreTokens())
+ return null;
+
+ // find start of token
+ while(pos
+ c = string.charAt(pos);
+ if(c=='\'' || c=='\"')
+ q=!q;
+ if(q || c==' '||c=='\t')
+ pos++;
+ else
+ break;
+ }
+
+ // find last char of token
+ int p=pos;
+ while(pos
+ c = string.charAt(pos);
+ if(c=='\'' || c=='\"')
+ q=!q;
+ if(!q && (c==' '||c=='\t') )
+ break;
+ else
+ pos++;
+ }
+
+ return string.substring(p,pos);
+ }
+
+ /**
+ * Compare a string against an array of strings and return the index
+ * @param t array to compare against (all lowercase)
+ * @param s string to test
+ * @return index in t of s, -1 if not present
+ */
+ public static int matchToken(String[] t,String s)
+ {
+ s=s.toLowerCase();
+ for(int i=0;i
+ if(t[i].equals(s))
+ return i;
+ return -1;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package uk.org.retep.util.models;
+
+import uk.org.retep.util.hba.Record;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import javax.swing.table.*;
+
+/**
+ * A TableModel to display the contents of a pg_hba.conf file
+ * @author
+ * @version 1.0
+ */
+
+public class HBATableModel extends AbstractTableModel
+{
+ ArrayList list = new ArrayList();
+
+ private static final String cols[] = {
+ "Type","Database","IP Address","IP Mask","Authentication","Arguments"
+ };
+
+
+ public HBATableModel()
+ {
+ }
+
+ public ArrayList getArray()
+ {
+ return list;
+ }
+
+ public int getColumnCount()
+ {
+ return cols.length;
+ }
+
+ public Object getValueAt(int aRow, int aCol)
+ {
+ Record rec = (Record) list.get(aRow);
+ int t;
+
+ switch(aCol)
+ {
+ case 0:
+ t = rec.getType();
+ return t<0 ? "ERR" : Record.types[t] ;
+
+ case 1:
+ return rec.getDatabase();
+
+ case 2:
+ return rec.getIP();
+
+ case 3:
+ return rec.getMask();
+
+ case 4:
+ t=rec.getAuthType();
+ return t<0 ? "ERR" : Record.auths[t] ;
+
+ case 5:
+ return rec.getAuthArgs();
+
+ default:
+ return "";
+ }
+ }
+
+ public int getRowCount()
+ {
+ return list.size();
+ }
+
+ public boolean isCellEditable(int rowIndex, int columnIndex)
+ {
+ /**@todo: Override this javax.swing.table.AbstractTableModel method*/
+ return super.isCellEditable( rowIndex, columnIndex);
+ }
+
+ public String getColumnName(int aColumn)
+ {
+ return cols[aColumn];
+ }
+
+ public void setValueAt(Object aValue, int rowIndex, int columnIndex)
+ {
+ /**@todo: Override this javax.swing.table.AbstractTableModel method*/
+ super.setValueAt( aValue, rowIndex, columnIndex);
+ }
+}
\ No newline at end of file
--- /dev/null
+package uk.org.retep.util.models;
+
+import uk.org.retep.util.Logger;
+import uk.org.retep.util.misc.PropertiesIO;
+
+import java.io.*;
+import java.util.*;
+import javax.swing.table.*;
+
+import java.text.*;
+
+/**
+ * A TableModel that shows a view of a PropertyFile object
+ *
+ * $Id: PropertiesTableModel.java,v 1.1 2001/03/05 09:15:37 peter Exp $
+ *
+ * @author
+ * @version 1.0
+ */
+public class PropertiesTableModel extends AbstractTableModel
+{
+ // The properties
+ protected TreeMap properties;
+ protected Properties origProperties;
+ protected Object keys[];
+
+ public PropertiesTableModel()
+ {
+ this(new Properties());
+ }
+
+ public PropertiesTableModel(Properties aProperties)
+ {
+ setProperties(aProperties);
+ }
+
+ public synchronized int getKeyRow(Object k)
+ {
+ for(int i=0;i
+ if(keys[i].equals(k)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Best not use this one to update, use the put method in this class!
+ */
+ public Properties getProperties()
+ {
+ return origProperties;
+ }
+
+ public synchronized void put(Object k,Object v)
+ {
+ properties.put(k,v);
+ origProperties.put(k,v);
+ refresh();
+ }
+
+ public Object get(Object k)
+ {
+ return origProperties.get(k);
+ }
+
+ public synchronized void remove(Object k)
+ {
+ properties.remove(k);
+ origProperties.remove(k);
+ refresh();
+ }
+
+ public boolean contains(Object o)
+ {
+ return origProperties.contains(o);
+ }
+
+ public boolean containsKey(Object o)
+ {
+ return origProperties.containsKey(o);
+ }
+
+ public boolean containsValue(Object o)
+ {
+ return origProperties.containsValue(o);
+ }
+
+ public void setProperties(Properties aProperties)
+ {
+ origProperties=aProperties;
+ properties = PropertiesIO.getTreeMap(aProperties);
+ refresh();
+ }
+
+ public void refresh()
+ {
+ keys = properties.keySet().toArray();
+ fireTableDataChanged();
+ }
+
+ private static final String cols[] = {
+ "Property","Value"
+ };
+
+ public int getColumnCount()
+ {
+ return cols.length;
+ }
+
+ public Object getValueAt(int aRow, int aColumn)
+ {
+ if(aRow<0 || aRow>=keys.length || aColumn<0 || aColumn>=cols.length)
+ return null;
+
+ Object key = keys[aRow];
+
+ switch(aColumn)
+ {
+ case 0:
+ return key;
+
+ case 1:
+ return properties.get(key);
+
+ default:
+ return null;
+ }
+ }
+
+ public int getRowCount()
+ {
+ return keys.length;
+ }
+
+ public String getColumnName(int aColumn)
+ {
+ return cols[aColumn];
+ }
+
+ public void setValueAt(Object aValue, int aRow, int aColumn)
+ {
+ if(aRow<0 || aRow>=keys.length || aColumn<0 || aColumn>=cols.length)
+ return;
+
+ switch(aColumn)
+ {
+ // Rename the key (only if not already present). If already present
+ // the refresh() will replace with the old one anyhow...
+ case 0:
+ if(!properties.containsKey(aValue)) {
+ Object oldValue = get(keys[aRow]);
+ remove(keys[aRow]);
+ put(aValue,oldValue);
+ }
+ refresh();
+ break;
+
+ // Update the value...
+ case 1:
+ put(keys[aRow],aValue);
+ //refresh();
+ break;
+
+ default:
+ // Should never be called
+ Logger.log(Logger.ERROR,"PropertiesTableModel: Column range",aColumn);
+ }
+ }
+
+ public boolean isCellEditable(int aRow, int aColumn)
+ {
+ return true;
+ }
+
+}
--- /dev/null
+package uk.org.retep.util.proped;
+
+import uk.org.retep.util.ExceptionDialog;
+import uk.org.retep.util.Globals;
+import uk.org.retep.util.Logger;
+import uk.org.retep.util.StandaloneApp;
+
+import java.io.IOException;
+import java.util.Iterator;
+import javax.swing.JComponent;
+
+/**
+ * Standalone entry point for the Properties editor
+ *
+ * $Id: Main.java,v 1.1 2001/03/05 09:15:38 peter Exp $
+ */
+
+public class Main extends StandaloneApp
+{
+ public Main(String[] args)
+ throws Exception
+ {
+ super(args);
+ }
+
+ public JComponent init()
+ throws Exception
+ {
+ Globals globals = Globals.getInstance();
+
+ PropertyEditor panel = new PropertyEditor();
+
+ // Only handle 1 open at a time in standalone mode
+ if(globals.getArgumentCount()>0) {
+ try {
+ panel.openFile(globals.getArgument(0));
+ } catch(IOException ioe) {
+ ExceptionDialog.displayException(ioe,"while loading "+globals.getArgument(0));
+ throw (Exception) ioe.fillInStackTrace();
+ }
+ }
+
+ return panel;
+ }
+
+ public static void main(String[] args)
+ throws Exception
+ {
+ Main main = new Main(args);
+ main.pack();
+ main.setVisible(true);
+ }
+}
\ No newline at end of file
--- /dev/null
+package uk.org.retep.util.proped;
+
+import uk.org.retep.util.ExceptionDialog;
+import uk.org.retep.util.misc.PropertiesIO;
+import uk.org.retep.util.models.PropertiesTableModel;
+
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import java.awt.event.*;
+
+/**
+ * A property file editor
+ *
+ * $Id: PropertyEditor.java,v 1.1 2001/03/05 09:15:38 peter Exp $
+ *
+ * @author
+ * @version 1.0
+ */
+
+public class PropertyEditor
+extends JPanel
+implements uk.org.retep.tools.Tool
+{
+ BorderLayout borderLayout1 = new BorderLayout();
+
+ // The filename, null if not set
+ String filename;
+ File file;
+
+ JScrollPane jScrollPane1 = new JScrollPane();
+ JTable contentTable = new JTable();
+
+ PropertiesTableModel model = new PropertiesTableModel();
+
+ boolean standaloneMode;
+
+ private static final String TITLE_PREFIX = "Retep PropertyEditor";
+ JPopupMenu popupMenu = new JPopupMenu();
+ JMenuItem newPopupItem = new JMenuItem();
+ JMenuItem dupPopupItem = new JMenuItem();
+ JMenuItem delPopupItem = new JMenuItem();
+ JMenuBar menuBar = new JMenuBar();
+ JMenu jMenu1 = new JMenu();
+ JMenuItem jMenuItem4 = new JMenuItem();
+ JMenuItem jMenuItem5 = new JMenuItem();
+ JMenuItem jMenuItem6 = new JMenuItem();
+ JMenuItem jMenuItem7 = new JMenuItem();
+ JMenuItem jMenuItem8 = new JMenuItem();
+ JMenuItem closeMenuItem = new JMenuItem();
+
+ public PropertyEditor()
+ {
+ try
+ {
+ jbInit();
+ }
+ catch(Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+ /**
+ * @return the default menubar
+ */
+ public JMenuBar getMenuBar()
+ {
+ return menuBar;
+ }
+
+ /**
+ * @return the File menu
+ */
+ public JMenu getMenu()
+ {
+ return jMenu1;
+ }
+
+ /**
+ * @return the recomended title string for the parent JFrame/JInternalFrame
+ */
+ public String getTitle()
+ {
+ if(filename==null) {
+ return TITLE_PREFIX;
+ }
+ return TITLE_PREFIX+": "+filename;
+ }
+
+ /**
+ * Sets menus up to Standalone mode
+ */
+ public void setStandaloneMode(boolean aMode)
+ {
+ standaloneMode=aMode;
+ if(aMode) {
+ closeMenuItem.setText("Exit");
+ } else {
+ closeMenuItem.setText("Close");
+ }
+ }
+
+ public boolean isStandalone()
+ {
+ return standaloneMode;
+ }
+
+ public void openFile(String aFile)
+ throws IOException
+ {
+ openFile(new File(aFile));
+ }
+
+ public void openFile(File aFile)
+ throws IOException
+ {
+ FileInputStream fis = new FileInputStream(aFile);
+ Properties p = new Properties();
+ p.load(fis);
+ fis.close();
+ model.setProperties(p);
+
+ file=aFile;
+ filename = aFile.getAbsolutePath();
+ }
+
+ public void saveFile(File aFile)
+ throws IOException
+ {
+ FileOutputStream fis = new FileOutputStream(aFile);
+ PropertiesIO.save(model.getProperties(),fis,'=',"Written by "+TITLE_PREFIX);
+ fis.close();
+
+ filename = aFile.getAbsolutePath();
+ file = aFile;
+ }
+
+ void jbInit() throws Exception
+ {
+ this.setLayout(borderLayout1);
+ contentTable.setToolTipText("");
+ contentTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
+ contentTable.setModel(model);
+ contentTable.addMouseListener(new java.awt.event.MouseAdapter()
+ {
+ public void mouseClicked(MouseEvent e)
+ {
+ contentTable_mouseClicked(e);
+ }
+ public void mouseReleased(MouseEvent e)
+ {
+ contentTable_mouseReleased(e);
+ }
+ });
+ newPopupItem.setText("New");
+ newPopupItem.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ newPopupItem_actionPerformed(e);
+ }
+ });
+ dupPopupItem.setText("Duplicate");
+ dupPopupItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(67, java.awt.event.KeyEvent.CTRL_MASK, false));
+ dupPopupItem.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ dupPopupItem_actionPerformed(e);
+ }
+ });
+ delPopupItem.setText("Delete");
+ delPopupItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(68, java.awt.event.KeyEvent.CTRL_MASK, false));
+ delPopupItem.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ delPopupItem_actionPerformed(e);
+ }
+ });
+ jMenu1.setText("File");
+ jMenuItem4.setText("Open");
+ jMenuItem4.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ jMenuItem4_actionPerformed(e);
+ }
+ });
+ jMenuItem5.setText("Save");
+ jMenuItem5.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ jMenuItem5_actionPerformed(e);
+ }
+ });
+ jMenuItem6.setText("Save As");
+ jMenuItem6.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ jMenuItem6_actionPerformed(e);
+ }
+ });
+ jMenuItem7.setText("Revert");
+ jMenuItem7.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ jMenuItem7_actionPerformed(e);
+ }
+ });
+ jMenuItem8.setText("Print");
+ closeMenuItem.setText("Close");
+ closeMenuItem.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ closeMenuItem_actionPerformed(e);
+ }
+ });
+ jMenu2.setText("Edit");
+ jMenuItem1.setText("New");
+ jMenuItem1.setAccelerator(javax.swing.KeyStroke.getKeyStroke(78, java.awt.event.KeyEvent.CTRL_MASK, false));
+ jMenuItem1.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ newPopupItem_actionPerformed(e);
+ }
+ });
+ jMenuItem2.setText("Duplicate");
+ jMenuItem3.setText("Delete");
+ this.add(jScrollPane1, BorderLayout.CENTER);
+ jScrollPane1.getViewport().add(contentTable, null);
+ popupMenu.add(newPopupItem);
+ popupMenu.add(dupPopupItem);
+ popupMenu.add(delPopupItem);
+ menuBar.add(jMenu1);
+ menuBar.add(jMenu2);
+ jMenu1.add(jMenuItem4);
+ jMenu1.add(jMenuItem5);
+ jMenu1.add(jMenuItem6);
+ jMenu1.add(jMenuItem7);
+ jMenu1.addSeparator();
+ jMenu1.add(jMenuItem8);
+ jMenu1.addSeparator();
+ jMenu1.add(closeMenuItem);
+ jMenu2.add(jMenuItem1);
+ jMenu2.add(jMenuItem2);
+ jMenu2.add(jMenuItem3);
+ }
+
+ Point popupPoint = new Point();
+ JMenu jMenu2 = new JMenu();
+ JMenuItem jMenuItem1 = new JMenuItem();
+ JMenuItem jMenuItem2 = new JMenuItem();
+ JMenuItem jMenuItem3 = new JMenuItem();
+ void contentTable_mouseClicked(MouseEvent e)
+ {
+ if(e.isPopupTrigger()) {
+ popupPoint.setLocation(e.getX(),e.getY());
+ popupMenu.show(contentTable,e.getX(),e.getY());
+ }
+ }
+
+ void contentTable_mouseReleased(MouseEvent e)
+ {
+ contentTable_mouseClicked(e);
+ }
+
+ void jMenuItem4_actionPerformed(ActionEvent e)
+ {
+ JFileChooser fc = new JFileChooser();
+ if(fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
+ try {
+ openFile(fc.getSelectedFile());
+ } catch(IOException ioe) {
+ ExceptionDialog.displayException(ioe);
+ }
+ }
+ }
+
+ void closeMenuItem_actionPerformed(ActionEvent e)
+ {
+ if(standaloneMode) {
+ System.exit(0);
+ } else {
+ filename="";
+ file=null;
+ model.setProperties(new Properties());
+ }
+ }
+
+ void newPopupItem_actionPerformed(ActionEvent e)
+ {
+ int y = contentTable.rowAtPoint(popupPoint);
+
+ // create a new unique key based on the current one
+ String key=(String) model.getValueAt(y,0);
+
+ if(key==null) {
+ key="new-key";
+ }
+
+ int uid=1;
+ while(model.containsKey(key+uid)) {
+ uid++;
+ }
+
+ key=key+uid;
+ model.put(key,"");
+ contentTable.clearSelection();
+ }
+
+ void dupPopupItem_actionPerformed(ActionEvent e)
+ {
+ int y = contentTable.rowAtPoint(popupPoint);
+
+ // create a new unique key based on the current one
+ String key=(String) model.getValueAt(y,0);
+ Object val=model.get(key);
+
+ int uid=1;
+ while(model.containsKey(key+uid)) {
+ uid++;
+ }
+
+ key=key+uid;
+ model.put(key,val);
+ contentTable.clearSelection();
+ }
+
+ void delPopupItem_actionPerformed(ActionEvent e)
+ {
+ int y = contentTable.rowAtPoint(popupPoint);
+ model.remove(model.getValueAt(y,0));
+ }
+
+ void jMenuItem6_actionPerformed(ActionEvent e)
+ {
+ JFileChooser fc = new JFileChooser();
+ if(fc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
+ try {
+ saveFile(fc.getSelectedFile());
+ } catch(IOException ioe) {
+ ExceptionDialog.displayException(ioe);
+ }
+ }
+ }
+
+ void jMenuItem5_actionPerformed(ActionEvent e)
+ {
+ if(filename==null) {
+ jMenuItem6_actionPerformed(e);
+ } else {
+ try {
+ saveFile(file);
+ } catch(IOException ioe) {
+ ExceptionDialog.displayException(ioe);
+ }
+ }
+ }
+
+ void jMenuItem7_actionPerformed(ActionEvent e)
+ {
+ // add check here
+ if(file!=null) {
+ try {
+ openFile(file);
+ } catch(IOException ioe) {
+ ExceptionDialog.displayException(ioe);
+ }
+ } else {
+ jMenuItem4_actionPerformed(e);
+ }
+ }
+}
\ No newline at end of file