support for CAPTCHAs
[mir.git] / source / mircoders / localizer / basic / MirBasicPostingSessionHandler.java
index dcd50d7..7483a78 100755 (executable)
  */
 package mircoders.localizer.basic;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-
 import mir.config.MirPropertiesConfiguration;
 import mir.log.LoggerWrapper;
-import mir.session.Request;
-import mir.session.Response;
-import mir.session.Session;
-import mir.session.SessionExc;
-import mir.session.SessionFailure;
-import mir.session.SessionHandler;
-import mir.session.UploadedFile;
-import mir.session.ValidationError;
+import mir.session.*;
 import mir.storage.Database;
-import mir.util.ExceptionFunctions;
-import mir.util.FileFunctions;
+import mir.util.ExceptionRoutines;
+import mir.util.FileRoutines;
+import mir.util.IORoutines;
 import mircoders.global.MirGlobal;
 import mircoders.media.UnsupportedMediaTypeExc;
+import mircoders.localizer.MirOpenPostingLocalizer;
+
+import java.io.*;
+import java.util.*;
 
 /**
  * Extensible handler for open postings.
@@ -67,7 +52,7 @@ public abstract class MirBasicPostingSessionHandler implements SessionHandler {
   protected MirPropertiesConfiguration configuration = MirPropertiesConfiguration.instance();
 
   /** Previously uploaded files */
-  protected List attachments;
+  protected final List attachments = new ArrayList();
   /** counter to generate unique field names for uploaded files */
   protected int uploadedFileIndex = 0;
 
@@ -79,7 +64,6 @@ public abstract class MirBasicPostingSessionHandler implements SessionHandler {
   private boolean persistentUploadedFiles;
 
   public MirBasicPostingSessionHandler(boolean aPersistentUploadedFiles) {
-    attachments = new ArrayList();
     persistentUploadedFiles = aPersistentUploadedFiles;
   }
 
@@ -130,7 +114,9 @@ public abstract class MirBasicPostingSessionHandler implements SessionHandler {
           processAttachmentError(aRequest, aSession, attachment, t);
         }
         catch (Throwable u) {
+          logger.error("Error while processing attachment error", u);
         }
+        logger.error("Error while processing attachment", t);
       }
     }
   }
@@ -176,17 +162,6 @@ public abstract class MirBasicPostingSessionHandler implements SessionHandler {
    * when an older session gets re-initiated after a session timeout.
    */
   protected void initializeSession(Request aRequest, Session aSession) throws SessionExc, SessionFailure {
-    if (MirGlobal.abuse().getOpenPostingPassword()) {
-      String password = (String) aSession.getAttribute("password");
-      if (password==null) {
-        password = generateOnetimePassword();
-        aSession.setAttribute("password", password);
-      }
-    }
-    else {
-      aSession.deleteAttribute("password");
-    }
-
     aSession.setAttribute("referer", aRequest.getHeader("Referer"));
   }
 
@@ -205,6 +180,8 @@ public abstract class MirBasicPostingSessionHandler implements SessionHandler {
       nrMediaItems = Math.min(configuration.getInt("ServletModule.OpenIndy.MaxMediaUploadItems"), Integer.parseInt(aRequest.getParameter("nrmediaitems")));
     }
     catch (Throwable t) {
+      logger.warn("Error while retrieving configuration setting " +
+              "ServletModule.OpenIndy.MaxMediaUploadItems", t);
     }
 
     aSession.setAttribute("nrmediaitems", new Integer(nrMediaItems));
@@ -216,13 +193,16 @@ public abstract class MirBasicPostingSessionHandler implements SessionHandler {
 
     aResponse.setResponseValue("nrmediaitems", new Integer(nrMediaItems));
     aResponse.setResponseValue("mediaitems", mediaItems);
-    aResponse.setResponseValue("password", aSession.getAttribute("password"));
+
+    if (MirGlobal.abuse().getRequireCaptcha()) {
+      aResponse.setResponseValue("password", Boolean.TRUE);
+    }
     aResponse.setResponseValue("referer", aSession.getAttribute("referer"));
     aResponse.setResponseValue("errors", null);
 
     if (configuration.getBoolean("Localizer.OpenSession.AllowFTPUploads", false)) {
       aResponse.setResponseValue("ftpfiles",
-          FileFunctions.getDirectoryContentsAsList(configuration.getFile("Localizer.OpenSession.FTPDirectory"),
+          FileRoutines.getDirectoryContentsAsList(configuration.getFile("Localizer.OpenSession.FTPDirectory"),
               new FilenameFilter() {
                 public boolean accept(File aDir, String aName) {
                   return !(new File(aDir, aName).isDirectory());
@@ -308,7 +288,18 @@ public abstract class MirBasicPostingSessionHandler implements SessionHandler {
     if (configuration.getBoolean("Localizer.OpenSession.AllowFTPUploads", false)) {
       File FTPDirectory = configuration.getFile("Localizer.OpenSession.FTPDirectory");
 
-      List ftpUploads = aRequest.getPrefixedParameterNames("ftpupload");
+      List ftpUploads = new ArrayList(aRequest.getPrefixedParameterNames("ftpupload"));
+      Collections.sort(ftpUploads, new Comparator() {
+        public int compare(Object o1, Object o2) {
+          if (o1 instanceof String && o2 instanceof String) {
+            return ((String) o1).compareTo((String) o2);
+          }
+          else {
+            return 0;
+          }
+        }
+      });
+
       i = ftpUploads.iterator();
       while (i.hasNext()) {
         final String fieldName = (String) i.next();
@@ -323,7 +314,16 @@ public abstract class MirBasicPostingSessionHandler implements SessionHandler {
               preprocessNewAttachment(aRequest, aSession, new UploadedFile() {
                 public void writeToFile(File aFile) throws SessionFailure {
                   try {
-                    FileFunctions.move(sourceFile, aFile);
+                    FileRoutines.move(sourceFile, aFile);
+                  }
+                  catch (IOException e) {
+                    throw new SessionFailure(e);
+                  }
+                }
+
+                public void writeToStream(OutputStream aStream) throws SessionFailure {
+                  try {
+                    IORoutines.copyStream(getInputStream(), aStream);
                   }
                   catch (IOException e) {
                     throw new SessionFailure(e);
@@ -372,7 +372,7 @@ public abstract class MirBasicPostingSessionHandler implements SessionHandler {
   }
 
   protected void makeErrorResponse(Request aRequest, Session aSession, Response aResponse, Throwable anError) throws SessionExc, SessionFailure {
-    Throwable rootCause = ExceptionFunctions.traceCauseException(anError);
+    Throwable rootCause = ExceptionRoutines.traceCauseException(anError);
 
     if (rootCause instanceof DuplicatePostingExc)
       aResponse.setResponseGenerator(dupeResponseGenerator);
@@ -410,10 +410,12 @@ public abstract class MirBasicPostingSessionHandler implements SessionHandler {
    * store data, etc
    */
   protected boolean shouldProcessRequest(Request aRequest, Session aSession, List aValidationErrors) throws SessionExc, SessionFailure {
-    if (aRequest.getParameter("post")==null)
+    if (aRequest.getParameter("post")==null) {
       return false;
-               validate(aValidationErrors, aRequest, aSession);
-               return (aValidationErrors == null || aValidationErrors.size() == 0);
+    }
+    validate(aValidationErrors, aRequest, aSession);
+    
+    return (aValidationErrors == null || aValidationErrors.size() == 0);
   }
 
   /**
@@ -424,43 +426,23 @@ public abstract class MirBasicPostingSessionHandler implements SessionHandler {
    * <code>aResults</code> is empty.
    */
   protected void validate(List aResults, Request aRequest, Session aSession) throws SessionExc, SessionFailure {
-    String password = (String) aSession.getAttribute("password");
+    if (MirGlobal.abuse().getRequireCaptcha()) {
+      String submittedPassword = aRequest.getParameter("password");
+      MirOpenPostingLocalizer.Captcha captcha = (MirOpenPostingLocalizer.Captcha) aSession.getAttribute("captcha");
 
-    if (password!=null) {
-      String submittedPassword= aRequest.getParameter("password").trim();
-
-      if (!password.equals(submittedPassword)) {
-        aResults.add(new ValidationError("password", "passwordmismatch"));
+      if (captcha == null || !captcha.validateAnswer(submittedPassword)) {
+        aResults.add(new ValidationError("password", "validationerror.passwordmismatch"));
       }
     }
   }
 
 
-  /**
-   * Method to generate a one-time password
-   *
-   * @return a password, to be used once
-   */
-  protected String generateOnetimePassword() {
-    Random r = new Random();
-    int random = r.nextInt();
-
-    long l = System.currentTimeMillis();
-
-    l = (l*l*l*l)/random;
-    if (l<0)
-      l = l * -1;
-
-    String returnString = ""+l;
-
-    return returnString.substring(5);
-  }
 
   /**
    * Method to filter the attributes and their values of a request
    * based on the fields of a database object.
    */
-  protected static final Map getIntersectingValues(Request aRequest, Database aStorage) throws SessionFailure {
+  protected static Map getIntersectingValues(Request aRequest, Database aStorage) throws SessionFailure {
     Map result = new HashMap();
 
     Iterator i = aStorage.getFieldNames().iterator();
@@ -506,6 +488,15 @@ public abstract class MirBasicPostingSessionHandler implements SessionHandler {
       uploadedFile.writeToFile(aFile);
     }
 
+    public void writeToStream(OutputStream aStream) throws SessionExc, SessionFailure {
+      try {
+        IORoutines.copyStream(uploadedFile.getInputStream(), aStream);
+      }
+      catch (IOException e) {
+        throw new SessionFailure(e);
+      }
+    }
+
     public InputStream getInputStream() throws SessionExc, SessionFailure {
       return uploadedFile.getInputStream();
     }