com.devoteam.srit.xmlloader.imap.MsgImap.java Source code

Java tutorial

Introduction

Here is the source code for com.devoteam.srit.xmlloader.imap.MsgImap.java

Source

/* 
 * Copyright 2012 Devoteam http://www.devoteam.com
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * 
 * This file is part of Multi-Protocol Test Suite (MTS).
 * 
 * Multi-Protocol Test Suite (MTS) 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.
 * 
 * Multi-Protocol Test Suite (MTS) 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 Multi-Protocol Test Suite (MTS).
 * If not, see <http://www.gnu.org/licenses/>.
 * 
 */

package com.devoteam.srit.xmlloader.imap;

import java.util.Vector;

import org.dom4j.Element;

import com.devoteam.srit.xmlloader.core.Parameter;
import com.devoteam.srit.xmlloader.core.Runner;
import com.devoteam.srit.xmlloader.core.coding.text.MsgParser;
import com.devoteam.srit.xmlloader.core.log.GlobalLogger;
import com.devoteam.srit.xmlloader.core.log.TextEvent;
import com.devoteam.srit.xmlloader.core.protocol.Channel;
import com.devoteam.srit.xmlloader.core.protocol.MessageId;
import com.devoteam.srit.xmlloader.core.protocol.StackFactory;
import com.devoteam.srit.xmlloader.core.protocol.Msg;
import com.devoteam.srit.xmlloader.core.protocol.Stack;
import com.devoteam.srit.xmlloader.core.utils.Utils;
import com.devoteam.srit.xmlloader.tcp.ChannelTcp;
import com.devoteam.srit.xmlloader.tcp.bio.ChannelTcpBIO;
import com.devoteam.srit.xmlloader.tcp.nio.ChannelTcpNIO;
import com.devoteam.srit.xmlloader.tls.ChannelTls;

public class MsgImap extends Msg {

    private String dataRaw = "";//just the message to read/write on socket
    private String dataComplete = "";//concatenation of all messages of provisionnal request/response
    private String tag = "";
    private String command = "";
    private Vector<String> arguments = null;
    private String result = "";
    private String text = null;
    private Boolean isRequest = null;

    private Vector<String> messages = null;

    /** Creates a new instance */
    public MsgImap(Stack stack) {
        super(stack);
    }

    /** Creates a new instance */
    public MsgImap(Stack stack, Vector<String> someData) throws Exception {
        super(stack);
        for (int i = 0; i < someData.size(); i++) {
            dataRaw += someData.get(i);
        }
        dataRaw = dataRaw.replace("\r\n", "\n");
        dataRaw = dataRaw.replace("\n", "\r\n");

        if (!dataRaw.endsWith("\r\n"))
            dataRaw += "\r\n";

        dataComplete = dataRaw;
        messages = someData;

        checkLiteral();

        GlobalLogger.instance().getApplicationLogger().debug(TextEvent.Topic.PROTOCOL, "Msg Imap is: ", toString());
    }

    /** 
     * Return true if the message is a request else return false
     */
    @Override
    public boolean isRequest() {
        if (isRequest == null) {
            if (isSend()) {
                if (((ChannelImap) this.getChannel()).isServer())
                    isRequest = false;
                else
                    isRequest = true;
            } else {
                if (getChannel().getTransport().equalsIgnoreCase(StackFactory.PROTOCOL_TCP)) {
                    if (getChannel() instanceof ChannelTcp
                            && ((ChannelTcp) getChannel()).getListenpointTcp() != null)
                        isRequest = true;
                    else if (getChannel() instanceof ChannelTcpBIO
                            && ((ChannelTcpBIO) getChannel()).getListenpointTcp() != null)
                        isRequest = true;
                    else if (getChannel() instanceof ChannelTcpNIO
                            && ((ChannelTcpNIO) getChannel()).getListenpointTcp() != null)
                        isRequest = true;
                    else
                        isRequest = false;
                } else {
                    if (((ChannelTls) this.getChannel()).getListenpointTLS() != null)
                        isRequest = true;
                    else
                        isRequest = false;
                }
            }
        }
        return isRequest;
    }

    /** 
     * Get the type of the message
     * Used for message filtering with "type" attribute and for statistic counters 
     */
    @Override
    public String getType() {
        if (command.equalsIgnoreCase(""))
        // cmd
        {
            if (isRequest())//to not try to get command on a response
            {
                String[] msgSplit = Utils.splitNoRegex(messages.firstElement().trim(), " ");
                if (msgSplit[0].matches("\\p{Alnum}{1,4}")) {
                    tag = msgSplit[0];
                    command = msgSplit[1];
                }
            }
            // refer to the transaction request in case of response to get command
            else {
                setTypeFromPreviousRequest();
            }
        }
        return command.toUpperCase();
    }

    /** 
     * Get the result of the message (null if request)
     * Used for message filtering with "result" attribute and for statistic counters 
     */
    @Override
    public String getResult() throws Exception {
        //response
        if (!isRequest()) //to not try to get result on a request
        {
            if (result.equalsIgnoreCase("")) {
                String[] msgSplit = Utils.splitNoRegex(messages.lastElement().trim(), " ");
                if (msgSplit[0].matches("\\p{Alnum}{1,4}")) {
                    tag = msgSplit[0];
                    result = msgSplit[1];
                    if ((msgSplit.length > 2) && msgSplit[2].startsWith("[") && msgSplit[2].endsWith("]"))//resultCode is present
                        result += " " + msgSplit[2];
                }
            }
        }
        return result.toUpperCase();
    }

    /** Return the transport of the messages */
    @Override
    public String getTransport() {
        return getChannel().getTransport();
    }

    private void setTypeFromPreviousRequest() {
        try {
            MsgImap msg;
            //vrifier si server ou client pour savoir quelle liste de transaction utiliser
            if (isSend()) {
                if (((ChannelImap) this.getChannel()).isServer())
                    msg = (MsgImap) this.stack.getInTransaction(getTransactionId()).getBeginMsg();
                else
                    msg = (MsgImap) this.stack.getOutTransaction(getTransactionId()).getBeginMsg();
            } else {
                if (getChannel().getTransport().equalsIgnoreCase(StackFactory.PROTOCOL_TCP)) {
                    if (getChannel() instanceof ChannelTcp
                            && ((ChannelTcp) getChannel()).getListenpointTcp() != null)
                        msg = (MsgImap) this.stack.getInTransaction(getTransactionId()).getBeginMsg();
                    else if (getChannel() instanceof ChannelTcpBIO
                            && ((ChannelTcpBIO) getChannel()).getListenpointTcp() != null)
                        msg = (MsgImap) this.stack.getInTransaction(getTransactionId()).getBeginMsg();
                    else if (getChannel() instanceof ChannelTcpNIO
                            && ((ChannelTcpNIO) getChannel()).getListenpointTcp() != null)
                        msg = (MsgImap) this.stack.getInTransaction(getTransactionId()).getBeginMsg();
                    else
                        msg = (MsgImap) this.stack.getOutTransaction(getTransactionId()).getBeginMsg();
                } else {
                    if (((ChannelTls) this.getChannel()).getListenpointTLS() != null)
                        msg = (MsgImap) this.stack.getInTransaction(getTransactionId()).getBeginMsg();
                    else
                        msg = (MsgImap) this.stack.getOutTransaction(getTransactionId()).getBeginMsg();
                }
            }
            command = msg.getType();
        } catch (Exception e) {
            // System.out.println("exception catched while searching type in previous request");
        }
    }

    public String getTag() {
        if (tag.equalsIgnoreCase("")) {
            //dernire ligne(si requete, c'est aussi la premire, si reponse, c'est la dernire)
            String[] msgSplit = Utils.splitNoRegex(messages.lastElement().trim(), " ");

            if (msgSplit[0].matches("\\p{Alnum}{1,4}") || msgSplit[0].equals("+")) {
                tag = msgSplit[0];
            }
        }
        return tag;
    }

    public Vector<String> getArguments() {
        if (isRequest()) {
            arguments = new Vector<String>();
            MsgParser.split(arguments,
                    dataComplete.substring(dataComplete.indexOf(getType()) + getType().length() + 1), " ", true,
                    "()", "\0\0");
        }
        return arguments;
    }

    @Override
    public MessageId getMessageId() throws Exception {
        return null;
    }

    /** Get the messages Identifier of this messages */
    private void addVector(Parameter var, Vector vect) throws Exception {
        for (int i = 0; i < vect.size(); i++) {
            var.add(vect.get(i).toString());
        }
    }

    public boolean isIncompleteMessage() {
        boolean res = false;
        //always check the last message present in the vector
        String[] msgSplit = Utils.splitNoRegex(messages.lastElement(), " ");
        if (msgSplit[msgSplit.length - 1].matches("\\{\\d*\\}\r\n"))
            res = true;
        return res;
    }

    public void addNewMessage(String message) {
        messages.add(message);
        dataComplete += message;
        dataRaw = message;

        checkLiteral();
    }

    public String getDataRaw() {
        return dataRaw;
    }

    public String getDataComplete() {
        return dataComplete;
    }

    private void checkLiteral() {
        String[] msgSplit;
        String tmp;
        String firstTag = " {";
        String secondTag = "}\r\n";

        //modification of data to integrate literal in request or response
        //get literal
        int index = dataComplete.indexOf(firstTag);
        int index2 = dataComplete.indexOf(secondTag);
        int nbChar = 0;
        if ((index != -1) && (index2 != -1)) {
            nbChar = Integer.parseInt(dataComplete.substring(index + 2, index2));
            if ((index2 + secondTag.length() + nbChar) <= dataComplete.length())//check that nb indicate is not > to length or data
            {
                tmp = dataComplete.substring(index2 + secondTag.length(), index2 + secondTag.length() + nbChar);
                //replace {xx} by \0literal\0 and remove literal from dataComplete
                dataComplete = dataComplete.replace(tmp, "").replace(
                        firstTag + dataComplete.substring(index + 2, index2) + secondTag, "\r\n\0" + tmp + "\0");
            }
        }

        //vector parsing to integrate modification to it
        for (int i = 0; i < messages.size(); i++) {
            tmp = messages.elementAt(i);
            msgSplit = Utils.splitNoRegex(tmp, " ");

            if (msgSplit[msgSplit.length - 1].matches("\\{\\d*\\}\r\n")) {
                index = tmp.indexOf(firstTag);
                index2 = tmp.indexOf(secondTag);
                nbChar = Integer.parseInt(tmp.substring(index + 2, index2));
                if ((i + 1) < messages.size()) {
                    tmp = tmp.replace(firstTag + tmp.substring(index + 2, index2) + secondTag,
                            "\r\n\0" + messages.elementAt(i + 1) + "\0");
                    messages.remove(i);
                    messages.insertElementAt(tmp, i);
                    messages.remove(i + 1);
                    break;
                }
            }
        }
    }

    //-------------------------------------------------
    // methods for the encoding / decoding of the message
    //-------------------------------------------------

    /** 
     * encode the message to binary data 
     */
    @Override
    public byte[] encode() throws Exception {
        return this.dataRaw.getBytes();
    }

    /** 
     * decode the message from binary data 
     */
    public void decode(byte[] data) throws Exception {
        String text = new String(data);
        text = text.replace("\r\n", "\n");
        dataRaw = text.replace("\n", "\r\n");

        if (!dataRaw.endsWith("\r\n"))
            dataRaw += "\r\n";

        dataComplete = dataRaw;
        messages = new Vector<String>();

        String[] msgSplit = Utils.splitNoRegex(dataRaw, "\r\n");
        for (int i = 0; i < (msgSplit.length - 1); i++)//msgSplit.length - 1 because the last will be empty with a \r\n
        {
            messages.add(msgSplit[i] + "\r\n");
        }

        checkLiteral();

        //no need to do another processing because this messages is
        //ready to be sent and no operation to get data on it will be done
        GlobalLogger.instance().getApplicationLogger().debug(TextEvent.Topic.PROTOCOL, "Msg Imap is: ", toString());
    }

    //---------------------------------------------------------------------
    // methods for the XML display / parsing of the message
    //---------------------------------------------------------------------

    /** Returns a short description of the message. Used for logging as INFO level */
    /** This methods HAS TO be quick to execute for performance reason */
    @Override
    public String toShortString() throws Exception {
        String ret = super.toShortString();
        ret += "\n";
        if (messages != null)
            ret += new String(messages.lastElement().getBytes(), 0, Math.min(messages.lastElement().length(), 100),
                    "UTF8");
        else
            ret += new String(dataRaw.getBytes(), 0, Math.min(dataRaw.length(), 100), "UTF8");
        ret = ret.replace("\0", "");
        return ret;
    }

    /** 
     * Convert the message to XML document 
     */
    @Override
    public String toXml() throws Exception {
        String xml = dataComplete.replace("\0", "");
        return xml;
    }

    /** 
     * Parse the message from XML element 
     */
    @Override
    public void parseFromXml(Boolean request, Element root, Runner runner) throws Exception {
        String text = root.getText().trim();
        decode(text.getBytes());
    }

    /** Get the message as text */
    public String getMessageText() throws Exception {
        if (text == null) {
            //uniquement pour les reponse continue et les reponse done => derniere ligne
            String[] msgSplit = Utils.splitNoRegex(messages.lastElement().trim(), " ");
            if (msgSplit[0].equalsIgnoreCase("+")) {
                if (msgSplit.length > 1) {
                    text = dataRaw.substring(dataRaw.indexOf(msgSplit[1])).trim();
                }
            } else {
                if (msgSplit.length > 2) {
                    text = dataRaw.substring(dataRaw.indexOf(msgSplit[2])).trim();
                }
            }
        }
        return text;
    }

    /** Set the message from text */
    /*
    public void setMessageText(String text) throws Exception
    {
    }
    */

    //------------------------------------------------------
    // method for the "setFromMessage" <parameter> operation
    //------------------------------------------------------

    /** 
     * Get a parameter from the message 
     */
    @Override
    public Parameter getParameter(String path) throws Exception {
        Parameter var = super.getParameter(path);
        if (null != var) {
            return var;
        }

        var = new Parameter();
        path = path.trim();
        String[] params = Utils.splitPath(path);

        if (params[0].equalsIgnoreCase("request")) {
            if (params[1].equalsIgnoreCase("tag")) {
                var.add(this.getTag());
            } else if (params[1].equalsIgnoreCase("command")) {
                var.add(this.getType());
            } else if (params[1].equalsIgnoreCase("arguments")) {
                this.addVector(var, this.getArguments());
            } else {
                Parameter.throwBadPathKeywordException(path);
            }
        } else if (params[0].equalsIgnoreCase("response")) {
            if (params[1].equalsIgnoreCase("done")) {
                if (params[2].equalsIgnoreCase("tag")) {
                    var.add(this.getTag());
                } else if (params[2].equalsIgnoreCase("command")) {
                    var.add(this.getType());
                } else if (params[2].equalsIgnoreCase("result")) {
                    var.add(this.getResult());
                } else if (params[2].equalsIgnoreCase("text")) {
                    var.add(this.getMessageText());
                } else {
                    Parameter.throwBadPathKeywordException(path);
                }
            } else if (params[1].equalsIgnoreCase("continue")) {
                if (params[2].equalsIgnoreCase("tag")) {
                    var.add(this.getTag());
                } else if (params[2].equalsIgnoreCase("text")) {
                    var.add(this.getMessageText());
                } else {
                    Parameter.throwBadPathKeywordException(path);
                }
            } else if (params[1].equalsIgnoreCase("data")) {
                //search for param[2] passed in argument
                for (int i = 0; i < messages.size(); i++) {
                    if (messages.elementAt(i).contains(params[2])) {
                        var.add(messages.elementAt(i).trim());
                    }
                }
            } else {
                Parameter.throwBadPathKeywordException(path);
            }
        } else if (params[0].equalsIgnoreCase("data")) {
            var.add(dataComplete.replace("\0", ""));
        } else {
            Parameter.throwBadPathKeywordException(path);
        }

        return var;
    }

    public boolean isSTARTTLS_request() {
        for (String s : this.messages) {
            if (!s.startsWith("*") && s.toLowerCase().contains("STARTTLS".toLowerCase()))
                return true;
        }
        return false;
    }

    public boolean isSTARTTLS_answer() {
        for (String s : this.messages) {
            if (!s.startsWith("*") && s.toLowerCase().contains("OK Begin TLS negotiation now".toLowerCase()))
                return true;
        }
        return false;
    }
}