from mailu import db, models

import socket
import urllib


SUPPORTED_AUTH_METHODS = ["none", "plain"]


STATUSES = {
    "authentication": ("Authentication credentials invalid", {
        "imap": "AUTHENTICATIONFAILED",
        "smtp": "535 5.7.8",
        "pop3": ""
    }),
}


def handle_authentication(headers):
    """ Handle an HTTP nginx authentication request
    See: http://nginx.org/en/docs/mail/ngx_mail_auth_http_module.html#protocol
    """
    method = headers["Auth-Method"]
    protocol = headers["Auth-Protocol"]
    # Incoming mail, no authentication
    if method == "none" and protocol == "smtp":
        server, port = get_server(headers["Auth-Protocol"], False)
        return {
            "Auth-Status": "OK",
            "Auth-Server": server,
            "Auth-Port": port
        }
    # Authenticated user
    elif method == "plain":
        server, port = get_server(headers["Auth-Protocol"], True)
        user_email = urllib.parse.unquote(headers["Auth-User"])
        password = urllib.parse.unquote(headers["Auth-Pass"])
        ip = urllib.parse.unquote(headers["Client-Ip"])
        user = models.User.query.get(user_email)
        for token in user.tokens:
            if (token.check_password(password) and
                (not token.ip or token.ip == ip)):
                    return {
                        "Auth-Status": "OK",
                        "Auth-Server": server,
                        "Auth-Port": port
                    }
        if user and user.check_password(password):
            return {
                "Auth-Status": "OK",
                "Auth-Server": server,
                "Auth-Port": port
            }
        else:
            status, code = get_status(protocol, "authentication")
            return {
                "Auth-Status": status,
                "Auth-Error-Code": code,
                "Auth-Wait": 0
            }
    # Unexpected
    else:
        return {}


def get_status(protocol, status):
    """ Return the proper error code depending on the protocol
    """
    status, codes = STATUSES[status]
    return status, codes[protocol]


def get_server(protocol, authenticated=False):
    if protocol == "imap":
        hostname, port = "imap", 143
    elif protocol == "pop3":
        hostname, port = "imap", 110
    elif protocol == "smtp":
        hostname = "smtp"
        port = 10025 if authenticated else 25
    address = socket.gethostbyname(hostname)
    return address, port

@@ -1154,16 +1154,37 @@
 _email)%0A
+        if user:%0A    
         
@@ -1221,16 +1221,20 @@
         
+    
 if (toke
@@ -1280,16 +1280,20 @@
         
+    
 (not tok
@@ -1331,32 +1331,36 @@
                 
+  
+  
 return %7B%0A       
@@ -1344,32 +1344,36 @@
        return %7B%0A
+    
                 
@@ -1393,32 +1393,36 @@
 -Status%22: %22OK%22,%0A
+    
                 
@@ -1468,32 +1468,36 @@
                 
+    
 %22Auth-Port%22: por
@@ -1510,34 +1510,42 @@
                 
-%7D%0A
+    %7D%0A    
         if user 
@@ -1543,17 +1543,8 @@
  if 
-user and 
 user
@@ -1574,32 +1574,36 @@
 d):%0A            
+    
 return %7B%0A       
@@ -1587,32 +1587,36 @@
        return %7B%0A
+    
                 
@@ -1644,32 +1644,36 @@
                 
+  
+  
 %22Auth-Server%22: s
@@ -1687,32 +1687,36 @@
                 
+    
 %22Auth-Port%22: por
@@ -1709,32 +1709,36 @@
 uth-Port%22: port%0A
+    
             %7D%0A  

Fix a bug when trying to authenticate with a non existing user