Index: /home/maurer/stuff/workspace/james-trunk/src/java/org/apache/james/remotemanager/RemoteManagerHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk/src/java/org/apache/james/remotemanager/RemoteManagerHandler.java	(revision 413584)
+++ /home/maurer/stuff/workspace/james-trunk/src/java/org/apache/james/remotemanager/RemoteManagerHandler.java	(working copy)
@@ -34,6 +34,8 @@
 
 import java.io.IOException;
 import java.net.Socket;
+import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Locale;
 import java.util.Date;
@@ -38,6 +40,11 @@
 import java.util.Locale;
 import java.util.Date;
 
+import org.apache.oro.text.regex.MalformedPatternException;
+import org.apache.oro.text.regex.Pattern;
+import org.apache.oro.text.regex.Perl5Compiler;
+import org.apache.oro.text.regex.Perl5Matcher;
+
 
 /**
  * Provides a really rude network interface to administer James.
@@ -155,6 +162,16 @@
      * The current UsersRepository being managed/viewed/modified
      */
     private UsersRepository users;
+    
+
+    private boolean retrieveByKey = false;  
+    private final String KEY_KEY = "key";
+    private final String SUBJECT_KEY = "subject";
+    private final String SENDER_KEY = "sender";
+    private final String RCPTTO_KEY = "rcptto";
+    private final String HEADER_KEY = "header"; 
+    private final String REMOTE_IP_KEY = "remoteip";
+    private final String ALLOWED_KEYWORDS [] = new String[] {KEY_KEY,SUBJECT_KEY,SENDER_KEY,RCPTTO_KEY,HEADER_KEY,REMOTE_IP_KEY};
 
     /**
      * Set the configuration data for the handler.
@@ -537,25 +554,25 @@
      */
     private boolean doHELP(String argument) {
         out.println("Currently implemented commands:");
-        out.println("help                                           display this help");
-        out.println("listusers                                      display existing accounts");
-        out.println("countusers                                     display the number of existing accounts");
-        out.println("adduser [username] [password]                  add a new user");
-        out.println("verify [username]                              verify if specified user exist");
-        out.println("deluser [username]                             delete existing user");
-        out.println("setpassword [username] [password]              sets a user's password");
-        out.println("setalias [user] [alias]                        locally forwards all email for 'user' to 'alias'");
-        out.println("showalias [username]                           shows a user's current email alias");
-        out.println("unsetalias [user]                              unsets an alias for 'user'");
-        out.println("setforwarding [username] [emailaddress]        forwards a user's email to another email address");
-        out.println("showforwarding [username]                      shows a user's current email forwarding");
-        out.println("unsetforwarding [username]                     removes a forward");
-        out.println("user [repositoryname]                          change to another user repository");
-        out.println("listspool [spoolrepositoryname]                list all mails which reside in the spool and have an error state");
-        out.println("flushspool [spoolrepositoryname] ([key])       try to resend the mail assing to the given key. If no key is given all mails get resend");
-        out.println("deletespool [spoolrepositoryname] ([key])      delete the mail assign to the given key. If no key is given all mails get deleted");
-        out.println("shutdown                                       kills the current JVM (convenient when James is run as a daemon)");
-        out.println("quit                                           close connection");
+        out.println("help                                                   display this help");
+        out.println("listusers                                              display existing accounts");
+        out.println("countusers                                             display the number of existing accounts");
+        out.println("adduser [username] [password]                          add a new user");
+        out.println("verify [username]                                      verify if specified user exist");
+        out.println("deluser [username]                                     delete existing user");
+        out.println("setpassword [username] [password]                      sets a user's password");
+        out.println("setalias [user] [alias]                                locally forwards all email for 'user' to 'alias'");
+        out.println("showalias [username]                                   shows a user's current email alias");
+        out.println("unsetalias [user]                                      unsets an alias for 'user'");
+        out.println("setforwarding [username] [emailaddress]                forwards a user's email to another email address");
+        out.println("showforwarding [username]                              shows a user's current email forwarding");
+        out.println("unsetforwarding [username]                             removes a forward");
+        out.println("user [repositoryname]                                  change to another user repository");
+        out.println("listspool [spoolrepositoryname] ([keyValue=pattern])   list all mails which reside in the spool and have an error state");
+        out.println("flushspool [spoolrepositoryname] ([keyValue=pattern])  try to resend the mail assing to the given key. If no key is given all mails get resend");
+        out.println("deletespool [spoolrepositoryname] ([keyValue=pattern]) delete the mail assign to the given key. If no key is given all mails get deleted");
+        out.println("shutdown                                               kills the current JVM (convenient when James is run as a daemon)");
+        out.println("quit                                                   close connection");
         out.flush();
         return true;
         
@@ -874,16 +891,27 @@
      */
     private boolean doLISTSPOOL(String argument) {
         int count = 0;
+        String[] args = null;
+        String url = null;
+
+        if (argument != null)
+            args = argument.split(" ");
 
         // check if the command was called correct
-        if ((argument == null) || (argument.trim().equals(""))) {
-            writeLoggedFlushedResponse("Usage: LISTSPOOL [spoolrepositoryname]");
+        if ((argument == null) || (argument.trim().equals(""))
+                || (args.length < 1) || (args.length > 2)) {
+            writeLoggedFlushedResponse("Usage: LISTSPOOL [spoolrepositoryname] ([keyValue=pattern])");
             return true;
         }
 
-        String url = argument;
+        if (args == null) {
+            url = argument;
+        } else {
+            url = args[0];
+        }
 
         SpoolRepository spoolRepository;
+
         try {
             spoolRepository = getSpoolRepository(url);
 
@@ -890,18 +918,46 @@
             // get an iterator of all keys
             Iterator spoolR = spoolRepository.list();
 
-            while (spoolR.hasNext()) {
+            // get sure this value get reseted
+            retrieveByKey = false;
+
+            while (spoolR.hasNext() && retrieveByKey == false) {
+                boolean matchMail = false;
                 String key = spoolR.next().toString();
 
-                out.println("Messages in spool:");
                 Mail m = spoolRepository.retrieve(key);
 
+                if (args != null && args.length == 2) {
+                    try {
+                        matchMail = matchRegex(m, getRegexPattern(args[1]));
+                    } catch (MalformedPatternException e) {
+                        // write an error message and return true!
+                        out.println("Malformed pattern: " + e.getMessage());
+                        out.flush();
+
+                        return true;
+
+                    } catch (Exception e) {
+                        // Display exception and return true
+                        out.println(e.getMessage());
+                        out.flush();
+
+                        return true;
+                    }
+                } else {
+                    // match the mail!
+                    matchMail = true;
+                }
+
                 // Only show email if its in error state.
-                if (m.getState().equals(Mail.ERROR)) {
+                if (m.getState().equals(Mail.ERROR) && matchMail) {
                     out.print("key: " + key + " sender: " + m.getSender()
                             + " recipient:");
                     for (int i = 0; i < m.getRecipients().size(); i++) {
-                        out.print(" " + m.getRecipients());
+                        String recip = m.getRecipients().toArray()[i]
+                                .toString();
+
+                        out.print(" " + recip);
                     }
                     out.println();
 
@@ -910,7 +966,12 @@
             }
             out.println("Number of spooled mails: " + count);
             out.flush();
-        } catch (Exception e) {
+        } catch (ServiceException e) {
+            out.println("Error opening the spoolrepository " + e.getMessage());
+            out.flush();
+            getLogger().error(
+                    "Error opening the spoolrepository " + e.getMessage());
+        } catch (MessagingException e) {
             out.println("Error opening the spoolrepository " + e.getMessage());
             out.flush();
             getLogger().error(
@@ -916,6 +977,7 @@
             getLogger().error(
                     "Error opening the spoolrepository " + e.getMessage());
         }
+
         return true;
     }
 
@@ -920,10 +982,119 @@
     }
 
     /**
-     * Handler method called upon receipt of a LISTSPOOL command.
-     * Returns whether further commands should be read off the wire.
-     *
-     * @param argument the argument passed in with the command
+     * Check if given keyValue and regex match on the given mail
+     * 
+     * @param mail
+     *            The mail object
+     * @param regexPattern
+     *            The Hashmap which contains the pattern and keyValue
+     * @return true or false
+     * @throws MalformedPatternException
+     *             if the pattern is not valid
+     */
+    private boolean matchRegex(Mail mail, HashMap regexPattern)
+            throws MalformedPatternException {
+        Pattern pattern = null;
+
+        if (!regexPattern.isEmpty()) {
+
+            String keyValue = regexPattern.keySet().iterator().next()
+                    .toString();
+            String regex = regexPattern.get(keyValue).toString();
+            String key = mail.getName();
+
+            // Check if the keyword was not key
+            if (!regex.equals(key)) {
+
+                Perl5Compiler compiler = new Perl5Compiler();
+                pattern = compiler.compile(regex, Perl5Compiler.READ_ONLY_MASK);
+                Perl5Matcher matcher = new Perl5Matcher();
+
+                if (keyValue.equals(SENDER_KEY)) {
+                    return matcher
+                            .matches(mail.getSender().toString(), pattern);
+                } else if (keyValue.equals(RCPTTO_KEY)) {
+                    Iterator r = mail.getRecipients().iterator();
+
+                    while (r.hasNext()) {
+                        return matcher.matches(r.next().toString(), pattern);
+                    }
+                } else if (keyValue.equals(REMOTE_IP_KEY)) {
+                    return matcher.matches(mail.getRemoteAddr(), pattern);
+                } else if (keyValue.equals(HEADER_KEY)) {
+                    try {
+                        // search all headers
+                        for (Enumeration e = mail.getMessage().getAllHeaderLines(); e.hasMoreElements();) {
+                            return matcher.matches(e.nextElement().toString(), pattern);
+                        }
+                    } catch (MessagingException e) {
+                        //this should never happen.. Anyway if we can't get the headers we cant match
+                        return false;
+                    }
+                }
+
+            } else {
+                // keyword was key
+                retrieveByKey = true;
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Extract the regex and the keyValue from the rawCommand
+     * 
+     * @param rawString
+     *            The rawCommand
+     * @return Hashmap which contains the keyValue as key and the regex as value
+     * @throws Exception
+     *             if the pattern could not extracted
+     */
+    private HashMap getRegexPattern(String rawString) throws Exception {
+        HashMap h = new HashMap();
+        boolean validKeyValue = false;
+
+        if (rawString.contains("=\"") && rawString.endsWith("\"")) {
+            String keyWord = null;
+            String regex = null;
+
+            for (int i = 0; ALLOWED_KEYWORDS.length > i; i++) {
+                if (rawString.startsWith(ALLOWED_KEYWORDS[i])) {
+                    keyWord = ALLOWED_KEYWORDS[i];
+
+                    // remove =""
+                    regex = rawString.substring(
+                            (ALLOWED_KEYWORDS[i].length() + 2), (rawString
+                                    .length() - 1));
+                    validKeyValue = true;
+                    break;
+                }
+            }
+            
+            if (validKeyValue == false) {
+                StringBuffer sb = new StringBuffer();
+                for (int i = 0; i < ALLOWED_KEYWORDS.length; i++) {
+                    sb.append(ALLOWED_KEYWORDS[i] + " ");
+                }
+                throw new Exception("Unknown keyword used. Allowed keywords: "
+                        + sb.toString());
+            } else if (keyWord != null && regex != null) {
+                h.put(keyWord, regex);
+            }
+        } else {
+            throw new Exception("Pattern could not be extracted");
+        }
+        return h;
+    }
+
+    /**
+     * Handler method called upon receipt of a LISTSPOOL command. Returns
+     * whether further commands should be read off the wire.
+     * 
+     * @param argument
+     *            the argument passed in with the command
      */
     private boolean doFLUSHSPOOL(String argument) {
         int count = 0;
@@ -928,6 +1099,9 @@
     private boolean doFLUSHSPOOL(String argument) {
         int count = 0;
         String[] args = null;
+        String url = null;
+        boolean retrieveByKey = false;
+        SpoolRepository spoolRepository;
 
         if (argument != null)
             args = argument.split(" ");
@@ -935,28 +1109,56 @@
         // check if the command was called correct
         if ((argument == null || argument.trim().equals(""))
                 || (args.length < 1 || args.length > 2)) {
-            writeLoggedFlushedResponse("Usage: FLUSHSPOOL [spoolrepositoryname] ([key])");
+            writeLoggedFlushedResponse("Usage: FLUSHSPOOL [spoolrepositoryname] ([keyValue=pattern])");
             return true;
         }
 
-        SpoolRepository spoolRepository;
-        String url = args[0];
+        if (args == null) {
+            url = argument;
+        } else {
+            url = args[0];
+        }
+
         try {
+            // get the spoolRepository
+            spoolRepository = getSpoolRepository(url);
+
+            // get an iterator of all keys
+            Iterator spoolR = spoolRepository.list();
 
-            spoolRepository = getSpoolRepository(url);
+            // get sure this value get reseted
+            retrieveByKey = false;
+
+            while (spoolR.hasNext() && retrieveByKey == false) {
+                boolean matchMail = false;
+                String key = spoolR.next().toString();
 
-            // check if an key was given as argument
-            if (args.length == 2) {
-                String key = args[1];
-                if (resendErrorMail(spoolRepository, key))
-                    count++;
+                Mail m = spoolRepository.retrieve(key);
+
+                if (args != null && args.length == 2) {
+                    try {
+                        matchMail = matchRegex(m, getRegexPattern(args[1]));
 
-            } else {
-                // get an iterator of all keys
-                Iterator spoolR = spoolRepository.list();
+                    } catch (MalformedPatternException e) {
+                        // write an error message and return true!
+                        out.println("Malformed pattern: " + e.getMessage());
+                        out.flush();
+
+                        return true;
 
-                while (spoolR.hasNext()) {
-                    String key = spoolR.next().toString();
+                    } catch (Exception e) {
+                        // Display exception
+                        out.println(e.getMessage());
+                        out.flush();
+
+                        return true;
+                    }
+                } else {
+                    // match the mail!
+                    matchMail = true;
+                }
+                // the mail should be flushed
+                if (matchMail) {
                     if (resendErrorMail(spoolRepository, key))
                         count++;
                 }
@@ -961,17 +1163,21 @@
                         count++;
                 }
             }
+
             out.println("Number of flushed mails: " + count);
             out.flush();
-
-        } catch (Exception e) {
-            out
-                    .println("Error accessing the spoolrepository "
-                            + e.getMessage());
+        } catch (ServiceException e) {
+            out.println("Error opening the spoolrepository " + e.getMessage());
+            out.flush();
+            getLogger().error(
+                    "Error opening the spoolrepository " + e.getMessage());
+        } catch (MessagingException e) {
+            out.println("Error opening the spoolrepository " + e.getMessage());
             out.flush();
             getLogger().error(
-                    "Error accessing the spoolrepository " + e.getMessage());
+                    "Error opening the spoolrepository " + e.getMessage());
         }
+
         return true;
     }
 
@@ -976,12 +1182,15 @@
     }
 
     /**
-     * Resent the mail that belongs to the given key and spoolRepository 
+     * Resent the mail that belongs to the given key and spoolRepository
      * 
-     * @param spoolRepository The spoolRepository
-     * @param key The message key
+     * @param spoolRepository
+     *            The spoolRepository
+     * @param key
+     *            The message key
      * @return true orf false
-     * @throws MessagingException Get thrown if there happen an error on modify the mail
+     * @throws MessagingException
+     *             Get thrown if there happen an error on modify the mail
      */
     private boolean resendErrorMail(SpoolRepository spoolRepository, String key)
             throws MessagingException {
@@ -987,11 +1196,12 @@
             throws MessagingException {
         if (spoolRepository.lock(key)) {
 
-            // get the mail and set the error_message to "0" that will force the spoolmanager to try to deliver it now!
+            // get the mail and set the error_message to "0" that will force the
+            // spoolmanager to try to deliver it now!
             Mail m = spoolRepository.retrieve(key);
 
             if (m.getState().equals(Mail.ERROR)) {
-               
+
                 // this will force Remotedelivery to try deliver the mail now!
                 m.setLastUpdated(new Date(0));
 
@@ -1028,6 +1238,7 @@
     private boolean doDELETESPOOL(String argument) {
         int count = 0;
         String[] args = null;
+        String url = null;
 
         if (argument != null)
             args = argument.split(" ");
@@ -1035,25 +1246,53 @@
         // check if the command was called correct
         if ((argument == null || argument.trim().equals(""))
                 || (args.length < 1 || args.length > 2)) {
-            writeLoggedFlushedResponse("Usage: DELETESPOOL [spoolrepositoryname] ([key])");
+            writeLoggedFlushedResponse("Usage: DELETESPOOL [spoolrepositoryname] ([keyValue=pattern])");
             return true;
         }
 
-        SpoolRepository spoolRepository;
-        String url = args[0];
+        if (args == null) {
+            url = argument;
+        } else {
+            url = args[0];
+        }
+
         try {
-            spoolRepository = getSpoolRepository(url);
+            SpoolRepository spoolRepository = getSpoolRepository(url);
+            Iterator spoolR = spoolRepository.list();
 
-            if (args.length == 2) {
-                String key = args[1];
-                if (removeMail(spoolRepository, key))
-                    count++;
-            } else {
-                Iterator spoolR = spoolRepository.list();
+            // get sure this value get reseted
+            retrieveByKey = false;
+
+            while (spoolR.hasNext() && retrieveByKey == false) {
+                boolean matchMail = false;
+                String key = spoolR.next().toString();
+                Mail m = spoolRepository.retrieve(key);
+
+                if (args != null && args.length == 2) {
+                    try {
+                        matchMail = matchRegex(m, getRegexPattern(args[1]));
+
+                    } catch (MalformedPatternException e) {
+                        // write an error message and return true!
+                        out.println("Malformed pattern: " + e.getMessage());
+                        out.flush();
+
+                        return true;
+
+                    } catch (Exception e) {
+                        // Display exception
+                        out.println(e.getMessage());
+                        out.flush();
 
-                while (spoolR.hasNext()) {
-                    String key = spoolR.next().toString();
+                        return true;
+                    }
+                } else {
+                    // match the mail!
+                    matchMail = true;
+                }
 
+                // the mail should be removed
+                if (matchMail) {
                     if (removeMail(spoolRepository, key))
                         count++;
                 }
@@ -1058,15 +1297,22 @@
                         count++;
                 }
             }
+
             out.println("Number of deleted mails: " + count);
             out.flush();
 
-        } catch (Exception e) {
+        } catch (ServiceException e) {
             out.println("Error opening the spoolrepository " + e.getMessage());
             out.flush();
             getLogger().error(
-                    "Error opeing the spoolrepository " + e.getMessage());
+                    "Error opening the spoolrepository " + e.getMessage());
+        } catch (MessagingException e) {
+            out.println("Error opening the spoolrepository " + e.getMessage());
+            out.flush();
+            getLogger().error(
+                    "Error opening the spoolrepository " + e.getMessage());
         }
+
         return true;
     }
 
@@ -1071,11 +1317,15 @@
     }
 
     /**
-     * Remove the mail that belongs to the given key and spoolRepository 
-     * @param spoolRepository The spoolRepository
-     * @param key The message key
+     * Remove the mail that belongs to the given key and spoolRepository
+     * 
+     * @param spoolRepository
+     *            The spoolRepository
+     * @param key
+     *            The message key
      * @return true or false
-     * @throws MessagingException Get thrown if there happen an error on modify the mail
+     * @throws MessagingException
+     *             Get thrown if there happen an error on modify the mail
      */
     private boolean removeMail(SpoolRepository spoolRepository, String key)
             throws MessagingException {
@@ -1097,9 +1347,11 @@
     /**
      * Retrieve a spoolRepository by the given url
      * 
-     * @param url The spoolRepository url
+     * @param url
+     *            The spoolRepository url
      * @return The spoolRepository
-     * @throws ServiceException Get thrown if the spoolRepository can not retrieved
+     * @throws ServiceException
+     *             Get thrown if the spoolRepository can not retrieved
      */
     private SpoolRepository getSpoolRepository(String url)
             throws ServiceException {
