com.turt2live.xmail.engine.connection.PHPConnection2A.java Source code

Java tutorial

Introduction

Here is the source code for com.turt2live.xmail.engine.connection.PHPConnection2A.java

Source

/*******************************************************************************
 * Copyright (C) 2014 Travis Ralston (turt2live)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/

package com.turt2live.xmail.engine.connection;

import com.turt2live.xmail.XMail;
import com.turt2live.xmail.XMailConfig;
import com.turt2live.xmail.engine.MinecraftAuthentication;
import com.turt2live.xmail.engine.PasswordPolicy;
import com.turt2live.xmail.engine.PasswordPolicy.Method;
import com.turt2live.xmail.engine.ServerResponse;
import com.turt2live.xmail.engine.request.Request.RequestType;
import com.turt2live.xmail.mail.Mail;
import com.turt2live.xmail.mail.attachment.*;
import com.turt2live.xmail.mail.attachment.Attachment.AttachmentType;
import com.turt2live.xmail.utils.Variable;
import org.json.simple.JSONValue;
import org.json.simple.parser.ContainerFactory;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;
import java.util.Map.Entry;

/**
 * Represents a PHP (Protocol 2A) connection
 *
 * @author turt2live
 */
public class PHPConnection2A extends ServerConnection {

    /**
     * The HTTP status code to represent a successful login
     */
    public static final int LOGGED_IN_CODE = 418;

    /**
     * The protocol version for this connection class
     */
    public static final String PROTOCOL_VERSION = "2A";

    /**
     * The HTTP status code to indicate a username is taken
     */
    public static final int USERNAME_TAKEN_CODE = 402;

    private String username = "NotSet", password = "NotSet", secret = "NotSet", server = "NotSet";

    /**
     * Creates a new PHP Server connection (protocol 2A)
     *
     * @param server the server to connect to
     * @param mcAuth the minecraft authentication container
     */
    public PHPConnection2A(String server, MinecraftAuthentication mcAuth) {
        super(mcAuth);
        this.server = server;
    }

    @Override
    public Attachment attemptGetAttachment(Map<String, Object> json) {
        if (json == null) {
            return null;
        }
        if (json.containsKey("type") && json.containsKey("content")) {
            String type = null, content = null;
            Object o = json.get("type");
            if (o instanceof String) {
                type = (String) o;
            }
            o = json.get("content");
            if (o instanceof String) {
                content = (String) o;
            }
            if (type != null && content != null) {
                AttachmentType atype = AttachmentType.fromName(type);
                switch (atype) {
                case MESSAGE:
                    return new MessageAttachment(content);
                case MONEY:
                    try {
                        double value = Double.parseDouble(content);
                        return new MoneyAttachment(value);
                    } catch (NumberFormatException e) {
                        return new UnknownAttachment(content);
                    }
                case COD:
                    try {
                        double value = Double.parseDouble(content);
                        return new CODAttachment(value);
                    } catch (NumberFormatException e) {
                        return new UnknownAttachment(content);
                    }
                case ITEM:
                    ItemAttachment ia = ItemAttachment.deserializeFromJson(content);
                    return ia == null ? new UnknownAttachment(content) : ia;
                case MAIL:
                    MailMessageAttachment ma = MailMessageAttachment.deserializeFromJson(content);
                    return ma == null ? new UnknownAttachment(content) : ma;
                default:
                    return new UnknownAttachment(content);
                }
            }
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    @Override
    public ServerResponse attemptRequest(RequestType mode, Variable... data) {
        List<String> lines = new ArrayList<String>();
        int errorCode = 200;

        if (XMailConfig.isDebugMode()) {
            XMail.getInstance().getLogger().info("[DEBUG] Mode: " + mode.name());
        }

        boolean cannotLogOut = false;
        try {
            URL url = new URL(server + ServerConnection.toQuery(data));
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            connection.setRequestMethod("GET");

            String userpass = username + ":" + password;
            String basicAuth = "Basic " + new String(Base64Coder.encode(userpass.getBytes()));
            connection.setRequestProperty("Authorization", basicAuth);

            // TODO: Resolve when pushing live
            //connection.setRequestProperty("XMAIL-DEBUG", XMailConfig.isDebugMode() ? "true" : "false");
            connection.setRequestProperty("XMAIL-DEBUG", "false");
            connection.setRequestProperty("XMAIL-PROTOCOL-VERSION", PROTOCOL_VERSION);
            connection.setRequestProperty("XMAIL-SERVER-KEY", secret);

            connection.setRequestProperty("XMAIL-MODE", mode.name());

            if (false || super.mcAuth != null) {
                connection.setRequestProperty("XMAIL-AUTH-PORT", String.valueOf(super.mcAuth.port));
                connection.setRequestProperty("XMAIL-AUTH-VERSION", super.mcAuth.version);
            }

            if (mode == RequestType.REQUEST_AUTH) {
                connection.setRequestProperty("XMAIL-REQUEST-AUTH", "request");
            }

            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));

            String line;
            while ((line = reader.readLine()) != null) {
                lines.add(line);

                JSONParser parser = new JSONParser();
                ContainerFactory containerFactory = new ContainerFactory() {
                    @Override
                    public List<Object> creatArrayContainer() {
                        return new LinkedList<Object>();
                    }

                    @Override
                    public Map<String, Object> createObjectContainer() {
                        return new LinkedHashMap<String, Object>();
                    }

                };

                Map<String, Object> map = new HashMap<String, Object>();

                try {
                    Map<?, ?> json = (Map<?, ?>) parser.parse(line, containerFactory);
                    Iterator<?> iter = json.entrySet().iterator();

                    // Type check
                    while (iter.hasNext()) {
                        Entry<?, ?> entry = (Entry<?, ?>) iter.next();
                        if (!(entry.getKey() instanceof String)) {
                            throw new IllegalArgumentException("Not in <String, Object> format");
                        }
                    }

                    map = (Map<String, Object>) json;
                } catch (ParseException e) {
                    e.printStackTrace();
                    return null;
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                    return null;
                }
                checkResponseForAuth(map);
                if (XMailConfig.isDebugMode()) {
                    XMail.getInstance().getLogger().info("[DEBUG] " + line);
                }
            }
            errorCode = connection.getResponseCode();
            if (mode == RequestType.LOGOUT && errorCode == 405) {
                cannotLogOut = true;
            }

            reader.close();

        } catch (IOException e) {
            if (e.getMessage().contains("402")) {
                errorCode = 402; // Username taken
            } else if (e.getMessage().contains("418")) {
                errorCode = 418; // Logged in already
            } else {
                e.printStackTrace();
                errorCode = -1;
            }
        }

        return new ServerResponse(lines, errorCode, errorCode == LOGGED_IN_CODE || cannotLogOut,
                errorCode == USERNAME_TAKEN_CODE);
    }

    @Override
    public List<Variable> convertMail(Mail mail) {
        if (mail == null) {
            return null;
        }
        List<Variable> vars = new ArrayList<Variable>();
        Map<String, Object> map = new HashMap<String, Object>();

        map.put("to", mail.getTo());
        map.put("from", mail.getFrom());
        map.put("date", mail.getTimestamp());
        map.put("sent-from", mail.getServerSender());
        map.put("unread", !mail.isRead());
        List<String> tags = mail.getTags();

        // Convert attachments
        List<String> attachments = new ArrayList<String>();
        List<Attachment> lAtt = mail.getAttachments();
        for (Attachment a : lAtt) {
            attachments.add(a.toJson());
        }

        map.put("tags", tags);
        map.put("attachments", attachments);

        try {
            vars.add(new Variable("mail", URLEncoder.encode(JSONValue.toJSONString(map), "UTF-8")));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return vars;
    }

    @Override
    public String getConnectionIP() {
        return this.server;
    }

    @Override
    public String getVersion() {
        return PROTOCOL_VERSION;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void init() {
        ServerResponse response = attemptRequest(RequestType.REQUEST_AUTH); // Start a request for auth
        if (response.getErrorCode() == 403) {
            throw new IllegalAccessError("xMail server denied authentication request");
        } else if (response.getErrorCode() < 0) {
            throw new IllegalAccessError("xMail server cannot be reached");
        }
        List<String> lines = attemptRequest(RequestType.INFORMATION).getLines();
        for (String line : lines) {
            JSONParser parser = new JSONParser();
            ContainerFactory containerFactory = new ContainerFactory() {
                @Override
                public List<Object> creatArrayContainer() {
                    return new LinkedList<Object>();
                }

                @Override
                public Map<String, Object> createObjectContainer() {
                    return new LinkedHashMap<String, Object>();
                }

            };

            Map<String, Object> map = new HashMap<String, Object>();

            try {
                Map<?, ?> json = (Map<?, ?>) parser.parse(line, containerFactory);
                Iterator<?> iter = json.entrySet().iterator();

                // Type check
                while (iter.hasNext()) {
                    Entry<?, ?> entry = (Entry<?, ?>) iter.next();
                    if (!(entry.getKey() instanceof String)) {
                        throw new IllegalArgumentException("Not in <String, Object> format");
                    }
                }

                map = (Map<String, Object>) json;
            } catch (ParseException e) {
                e.printStackTrace();
                return;
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
                return;
            }
            if (map.containsKey("password-policy")) {
                // It will be a <String, Object>
                Map<String, Object> pw = (Map<String, Object>) map.get("password-policy");
                String method = (String) pw.get("method");
                // It will be a <String, Object>
                Map<String, Object> saltOpts = (Map<String, Object>) pw.get("salt");
                String salt = (String) saltOpts.get("salt");
                String format = (String) saltOpts.get("format");
                super.generatePasswordPolicy(PasswordPolicy.Method.getMethod(method), salt, format);
            }
            if (map.containsKey("time")) {
                Object time = map.get("time");
                if (time instanceof Double) {
                    long t = ((Double) time).longValue();
                    super.connectionTime.reportedTime = t;
                    super.connectionTime.requestedTime = System.currentTimeMillis() / 1000;
                }
            }
        }
        if (super.getPasswordPolicy() != null) {
            String testHash = super.getPasswordPolicy().hashPassword("test-xmail-password");
            if (testHash == null) {
                super.generatePasswordPolicy(Method.SHA1, "", "P"); // Default
            }
        } else {
            super.generatePasswordPolicy(Method.SHA1, "", "P"); // Default
        }
    }

    private void checkResponseForAuth(Map<String, Object> response) {
        if (response.containsKey("SERVER_ACCESS_UPDATE")) {
            @SuppressWarnings("unchecked")
            // It will be a <String, Object>
            Map<String, Object> map = (Map<String, Object>) response.get("SERVER_ACCESS_UPDATE");
            this.username = (String) map.get("username");
            this.password = (String) map.get("password");
            this.secret = (String) map.get("secret");
        }
    }

}