/*
 * Copyright (c) 2014 Wael Chatila / Icegreen Technologies. All Rights Reserved.
 * This software is released under the Apache license 2.0
 * This file has been modified by the copyright holder.
 * Original file can be found at http://james.apache.org
 */
package com.icegreen.greenmail.imap;

import com.icegreen.greenmail.server.ProtocolHandler;
import com.icegreen.greenmail.user.UserManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.Socket;

/**
 * The handler class for IMAP connections.
 *
 * @author Federico Barbieri <scoobie@systemy.it>
 * @author Peter M. Goldstein <farsight@alum.mit.edu>
 */
public class ImapHandler implements ImapConstants, ProtocolHandler {
    protected final Logger log = LoggerFactory.getLogger(getClass());
    private ImapRequestHandler requestHandler = new ImapRequestHandler();
    private ImapSession session;

    /**
     * The TCP/IP socket over which the IMAP interaction
     * is occurring
     */
    private Socket socket;

    private ImapResponse response;

    UserManager userManager;
    private ImapHostManager imapHost;

    public ImapHandler(UserManager userManager, ImapHostManager imapHost, Socket socket) {
        this.userManager = userManager;
        this.imapHost = imapHost;
        this.socket = socket;
    }

    public void forceConnectionClose(final String message) {
        response.byeResponse(message);
        close();
    }

    @Override
    public void run() {
        try {
            // Closed automatically when socket is closed via #close()
            InputStream ins = new BufferedInputStream(socket.getInputStream(), 512);
            OutputStream outs = new BufferedOutputStream(socket.getOutputStream(), 1024);

            response = new ImapResponse(outs);

            // Write welcome message
            String responseBuffer = VERSION +" Server GreenMail ready";
            response.okResponse(null, responseBuffer);

            session = new ImapSessionImpl(imapHost,
                    userManager,
                    this,
                    socket.getInetAddress().getHostAddress());

            while (requestHandler.handleRequest(ins, outs, session)) {
                // Loop ...
            }

        } catch (Exception e) {
            // Ignore if closed is invoked
            if (null != socket && !socket.isClosed()) {
                log.error("Can not handle IMAP connection", e);
                throw new IllegalStateException("Can not handle IMAP connection", e);
            }
        } finally {
           close();
        }
    }

    /**
     * Resets the handler data to a basic state.
     */
    @Override
    public void close() {
        // Close and clear streams, sockets etc.
        if (socket != null) {
            try {
                // Terminates thread blocking on socket read
                // and automatically closed depending streams
                socket.close();
            } catch (IOException e) {
                log.warn("Can not close socket", e);
            } finally {
                socket = null;
            }
        }

        // Clear user data
        session = null;
        response = null;
    }
}


@@ -922,16 +922,65 @@
 ession;%0D
+%0A    private Object closeMonitor = new Object();%0D
 %0A%0D%0A    /
@@ -2849,24 +2849,153 @@
 %0D%0A        //
+ Use monitor to avoid race between external close and handler thread run()%0D%0A        synchronized (closeMonitor) %7B%0D%0A            //
  Close and c
@@ -3026,24 +3026,28 @@
 c.%0D%0A        
+    
 if (socket !
@@ -3061,39 +3061,47 @@
  %7B%0D%0A            
+  
+  
 try %7B%0D%0A
+    
                 
@@ -3162,16 +3162,20 @@
         
+    
 // and a
@@ -3225,24 +3225,28 @@
             
+  
+  
 socket.close
@@ -3242,32 +3242,36 @@
 ocket.close();%0D%0A
+    
             %7D ca
@@ -3305,24 +3305,28 @@
             
+ 
+   
 log.warn(%22Ca
@@ -3355,32 +3355,36 @@
 );%0D%0A            
+   
+ 
 %7D finally %7B%0D%0A   
@@ -3372,32 +3372,36 @@
    %7D finally %7B%0D%0A
+    
                 
@@ -3428,27 +3428,34 @@
         
-%7D%0D%0A
+    %7D%0D%0A   
         
 %7D%0D%0A%0D%0A   
@@ -3438,37 +3438,42 @@
   %7D%0D%0A           
+ 
 %7D%0D%0A%0D%0A
+    
         // Clear
@@ -3484,32 +3484,36 @@
 r data%0D%0A        
+    
 session = null;%0D
@@ -3513,32 +3513,36 @@
  null;%0D%0A        
+   
+ 
 response = null;
@@ -3539,24 +3539,35 @@
 se = null;%0D%0A
+        %7D%0D%0A
     %7D%0D%0A%7D%0D%0A%0D%0A

Fix thread synchronization issues (issue #43)