MsnConnection.java :  » Mobile » jimm-fork-van » protocol » msn » Java Open Source

Java Open Source » Mobile » jimm fork van 
jimm fork van » protocol » msn » MsnConnection.java
/* JIMMY - Instant Mobile Messenger
   Copyright (C) 2006  JIMMY Project
 
 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 2
 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, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 **********************************************************************
 File: jimmy/MsnConnection.java
 Version: alpha  Date: 2006/04/11
 Author(s): Zoran Mesec
 */
// #sijapp cond.if protocols_MSN is "true" #
package protocol.msn;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.*;
import jimm.JimmException;
import jimm.SplashCanvas;
import jimm.chat.message.PlainMessage;
import jimm.chat.message.SystemNotice;
import jimm.comm.MD5;
import jimm.comm.StringConvertor;
import jimm.comm.Util;
import jimm.ui.Progress;
import protocol.*;
/**
 * This class is used to connect with a remote server using SocketConnection class.
 * @author Zoran Mesec
 */
public class MsnConnection implements  Runnable {
    final public static String CMD_CVR = "CVR";
    final public static String CMD_VER = "VER";
    final public static String CMD_USR = "USR";
    final public static String CMD_CHG = "CHG";
    final public static String CMD_XFR = "XFR";
    final public static String CMD_FLN = "FLN";
    
    final public static String CMD_ILN = "ILN";
    final public static String CMD_NLN = "NLN";
    final public static String CMD_ADG = "ADG";
    final public static String CMD_CHL = "CHL";
    final public static String CMD_RNG = "RNG";
    final public static String CMD_OUT = "OUT";
    final public static String CMD_LST = "LST";
    final public static String CMD_LSG = "LSG";
    final public static String CMD_MSG = "MSG";
    
    private String username;
    private String password;
    private boolean connected_;
    private boolean stop;
    private Thread thread_;
    
    private MSNTransaction tr;
    private MsnContact movingUser = null;
    private boolean busy = false;
    private final Hashtable contacts_ = new Hashtable();
    private final Hashtable commands = new Hashtable();
    
    private byte status_;
    public static final byte DISCONNECTED = 0; //disconnected, ok
    public static final byte CONNECTED = 1; //connected, ok
    public static final byte CONNECTING = 2; //connecting, busy
    public static final byte WRONG_PASSWORD = -1; //wrong password, error
    public static final byte NO_CONNECTION = -2; //connection cannot be established, error
    
    private ServerHandler sh;
    
    /**
     * A Vector of all ChatSession classes. Each ChatSession represents a conversation with a contact.
     */
    protected final Vector chatSessions_ = new Vector();  //list of active chat sessions
    /**
     * A Vector of all ServerHandler classes that are required for Chatsessions. MSN
     * Protocol has different IP number for every conversation between two users,
     * therefore a ServerHandler for each conversation is required.
     */
    //protected final Vector sessionHandlers_ = new Vector();  //list of IPs of alive chat sessions
    /**
     * This Hashtable maps Chatsessions and their Transaction IDs. With every message
     * the transaction ID of Chatsession increases.
     */
    private final Hashtable groupID = new Hashtable();
    
    // definitions of constants
    //const of protocol MSNP10
    final String NsURL = "messenger.hotmail.com";
    final String ProductKey = "YMM8C_H7KCQ2S_KL";
    final String ProductIDhash = "Q1P7W2E4J9R8U3S5";
    final String ProductID = "msmsgs@msnmsgr.com";
    //final String NSredirectURL = "207.46.114.22";
    
    final String ProductIDMSNP12 = "PROD0090YUAUV{2B"; //ilya
    
    private static final long MSNP11_MAGIC_NUM = 0x0E79A9C1;
    final int serverPort = 1863;
    final int NexusPort = 443;
    final String               DALOGIN                      = "DALogin=";
    final String               DASTATUS                     = "da-status=";
    final String               TICKET                       = "from-PP=";
    final String               SUCCESS                      = "success";
    final String               KEY_PASSPORT_URLS            = "PassportURLs";
    final String               KEY_LOCATION                 = "Location";
    final String               KEY_AUTHENTICATION_INFO      = "Authentication-Info";
    static final String        PASSPORT_LIST_SERVER_ADDRESS = "https://nexus.passport.com/rdr/pprdr.asp";
    
    
    private Msn msn;
    /**
     * The constructor method.
     * @param URL URL of the server. No protocolis specified here! Example: messenger.hotmail.com.
     * @param PORT PORT of the server(inputs as a String). Example: "1863".
     */
    public MsnConnection(Msn msn) {
        this.msn = msn;
        
        this.connected_ = false;
        this.busy = false;
        this.commands.put(CMD_ADG,"1");
        this.commands.put(CMD_LSG,"2");
        this.commands.put(CMD_LST,"3");
        this.commands.put(CMD_CHL,"4");
        this.commands.put(CMD_FLN,"5");
        this.commands.put(CMD_ILN,"6");
        this.commands.put(CMD_NLN,"7");
        this.commands.put(CMD_RNG,"8");
        this.commands.put(CMD_USR,"9");
        this.commands.put(CMD_VER,"10");
        this.commands.put(CMD_XFR,"11");
        this.commands.put(CMD_OUT,"12");
        this.commands.put(CMD_CHG,"13");
        this.commands.put(CMD_CVR,"14");
        
    }
    /**
     *
     * @see method login(String, String)
     */
    public boolean login() {
        this.status_ = CONNECTING;
        this.thread_ = new Thread(this);
        this.thread_.start();
        return true;
    }
    private void setProgress(int progress) {
        msn.setConnectingProgress(progress);
    }
    public static final String productKey = "CFHUR$52U_{VIX5T";
    public static final String productId = "PROD0101{0RM?UBW";
    private boolean login___() {
        setProgress(10);
        {   // remove all chats
            Vector contacts = msn.getContactItems();
            for (int i = 0; i < contacts.size(); ++i) {
                ((Contact)contacts.elementAt(i)).deleteChat();
            }
        }

        msn.setContactList(new Vector(), new Vector());
        this.username = msn.getUserId();
        this.password = msn.getPassword();
        try {
            this.tr = new MSNTransaction();
            this.tr.newTransaction();
            this.sh= new ServerHandler(this.NsURL, this.serverPort);
            this.sh.connect();
            
            this.tr.setType(CMD_VER);
            this.tr.addArgument("MSNP11");
            this.tr.addArgument("CVR0");
            //String message = "VER 1 MSNP8 CVR0\r\n";
            this.sh.sendRequest(this.tr.toString());
            //System.out.print(this.tr.toString());
            this.sh.getReply();
            setProgress(10);
            //message = "CVR 2 0x0409 win 4.10 i386 MSNMSGR 5.0.0544 MSMSGS avgustin.ocepek@yahoo.com.au\r\n"; //MSNP10
            //message = "CVR 2 0x040c winnt 5.1 i386 MSNMSGR 7.0.0813 msmsgs idanilov@ua.fm\r\n"; \\MSNP11
            //message = "CVR 2 0x0409 winnt 5.1 i386 MSNMSGR 7.5.0324 msmsgs idanilov@ua.fm\r\n"; \\MSNP12
            //message = "CVR 2 0x0409 winnt 5.1 i386 MSG80BETA 8.0.0566 msmsgs alice@hotmail.com\r\n"; \\MSNP13
            this.tr.newTransaction();
            this.tr.setType(CMD_CVR);
            this.tr.addArgument("0x040c winnt 5.1 i386 MSNMSGR 7.0.0813 msmsgs"); //MSNP11
            this.tr.addArgument(username);
            this.sh.sendRequest(this.tr.toString());
            this.sh.getReply();
            setProgress(20);
            
            //message="USR 3 TWN I avgustin.ocepek@yahoo.com.au\r\n";
            this.tr.newTransaction();
            this.tr.setType(CMD_USR);
            this.tr.addArgument("TWN I");
            this.tr.addArgument(this.username);
            
            this.sh.sendRequest(this.tr.toString());
            String data = this.sh.getReply();
            setProgress(30);

            String NSredirectURL = data.substring(data.indexOf("NS")+3, data.indexOf(" ", 10));
            this.sh.disconnect();
            setProgress(35);
            
            
            this.sh = new ServerHandler(NSredirectURL);
            try {
                this.sh.connect();
            } catch (Exception e) {
                return false;
            }
            setProgress(40);
            
            this.tr.newTransaction();
            this.tr.setType(CMD_VER);
            this.tr.addArgument("MSNP11");    //  only in v2 :)
            this.tr.addArgument("CVR0");
            this.sh.sendRequest(this.tr.toString());
            this.sh.getReply();
            //parseReply(this.sh.getReply());
            setProgress(45);
            
            this.tr.newTransaction();
            this.tr.setType(CMD_CVR);
            this.tr.addArgument("0x0409 win 5.1 i386 MSNMSGR 7.0.0813 msmsgs");
            this.tr.addArgument(this.username);
            this.sh.sendRequest(this.tr.toString());
            this.sh.getReply();
            //parseReply(this.sh.getReply());
            setProgress(50);
            
            this.tr.newTransaction();
            this.tr.setType(CMD_USR);
            this.tr.addArgument("TWN I");
            this.tr.addArgument(this.username);
            this.sh.sendRequest(this.tr.toString());
            //jimm.modules.DebugLog.println(this.tr.toString());
            String USRreply = this.sh.getReply();
            String challenge = USRreply.substring(12);
            setProgress(60);
            
            //this is where the password stuff fun starts
            
            // We have to establish a connection MSN Passport network
            // for authentification with user password.

            //its required for S40 handsets which has a bug with header length and due this unable to use Passport 1.4
            PassportLoginNet pn = new PassportLoginNet();
            String ticket = pn.requestAuthorizationTicket(this.username, this.password, challenge);
            
            if (null == ticket) {
                this.status_ = WRONG_PASSWORD;
                msn.setPassword(null);
                throw new JimmException(111, 0);
            }
            setProgress(70);
            
            this.tr.newTransaction();
            this.tr.setType(CMD_USR);
            this.tr.addArgument("TWN S");
            this.tr.addArgument(ticket);
            this.sh.sendRequest(this.tr.toString());
            this.sh.getReply();    //gets the SBS or anything else that is not important
            setProgress(80);
            
            this.tr.newTransaction();
            this.tr.setType("SYN");
            this.tr.addArgument("2007-08-14T06:03:32.863-07:00 2006-08-16T06:03:33.177-07:00");
            this.sh.sendRequest(this.tr.toString());
            this.sh.getReply();//SBS
            setProgress(90);

            parseMainReply(this.sh.getReply());//MSG
            
            String[] syn  = Util.explode(this.sh.getReply(), ' ');// SYN
            int groupNum = Util.strToIntDef(syn[syn.length - 2], 0);
            int contactNum = Util.strToIntDef(syn[syn.length - 1], 0);
            while ((0 < contactNum) && (0 < groupNum)) {
                String reply = this.sh.getReply();
                if (null == reply) {
                    continue;
                }
                parseMainReply(reply);
                if (reply.startsWith("LST")) {
                    contactNum--;
                } else if (reply.startsWith("LSG")) {
                    groupNum--;
                }
            }

            this.sh.sendRequest(getStatusPacket());
            setProgress(95);
            
            this.status_ = CONNECTED;
            this.stop = false;
        } catch (Exception e) {
            this.status_ = NO_CONNECTION;
            // #sijapp cond.if modules_DEBUGLOG is "true" #
            jimm.modules.DebugLog.panic("msn", e);
            // #sijapp cond.end #
            return false;
        }
        msn.setContactList(msn.getGroupItems(), msn.getContactItems());
        msn.safeSave();
        setProgress(100);
        return true;
    }
/*    
BSY - Busy 
IDL - Idle 
BRB - Be Right Back 
AWY - Away 
LUN - Out to Lunch 
PHN - On the Phone 
FLN - Offline 
HDN - Hidden
 */
    private String getStatus() {
        return CMD_NLN;
    }
    private String getStatusPacket() {
        this.tr.newTransaction();
        this.tr.setType(CMD_CHG);
        this.tr.addArgument(getStatus());
        //this.tr.addArgument("HDN"); //log in as anavailable(for testing)
        this.tr.addArgument("" + 0x01);
        return this.tr.toString();
    }
    
    /**
     * method disconnects the SocketConnection of this class.
     */
    public void logout() {
        this.status_ = DISCONNECTED;
        this.sh.sendRequest(this.tr.getLogoutString());
        
        this.stop = true;
        //this.thread_.interrupt();
    }
    /**
     * Parses a reply from the server according to first three letters.
     * @param reply raw data from the server, presented as a string
     */
    public void parseReply(String reply) {
        if (reply == null) {
            return;
        }
        reply = reply.trim();
        if (reply.length() < 3) {
            return;
        }
        String cmd = (String)commands.get(reply.substring(0, 3));
        if (null == cmd) {
            return;
        }
        
        switch (Integer.parseInt(cmd)) {
            case 1: //ADG
                groupAdded(reply);
                break;
                
            case 2: //LSG
                parseGroups(reply);
                break;
            case 3: //LST
                parseContacts(reply);
                break;
            case 4: //CHL
                parseChallenge(reply);
                break;
            case 5: //FLN
                userGoesOffline(reply);
                break;
            case 6: //ILN
                parsePresence(reply);
                break;
            case 7: //NLN
                changePresence(reply);
                break;
            case 8: //RNG
                SBhandle(reply);
                break;
            case 11: //XFR
                startSession(reply);
                break;
            case 12: //OUT
                this.connected_ = false;
                this.status_ = DISCONNECTED;
                this.logout();
                break;
            default:
                //unknown command
                break;
        }
    }
    
    private boolean hasHeader(String msg, String header, int headerSize) {
        int index = msg.indexOf(header);
        return (-1 < index) && (index < headerSize);
    }
    private void processMessage(String msg, String userId, String nick, ChatSession activeCS) {
        int marker = msg.indexOf("\r\n\r\n");
        if (-1 == marker) marker = msg.length();
        if (hasHeader(msg, "TypingUser:", marker)) {
            // #sijapp cond.if modules_SOUND is "true" #
            msn.beginTyping(activeCS.c.getUin(), true);
            // #sijapp cond.end #
            return;
        }
        if (hasHeader(msg, "Content-Type: text/x-mms-emoticon", marker)) {
            return;
        }

        String message = null;
        if (hasHeader(msg, "Content-Type: text/x-msnmsgr-datacast", marker)) {
            message = "/wakeup";

        } else if (hasHeader(msg, "Content-Type: text/plain", marker)) {
            if (marker + 4 < msg.length()) {
                message = msg.substring(marker + 4);
            }
        } else {
            if (marker + 4 < msg.length()) {
                message = "Unknown message\n" + msg.substring(marker + 4);
            }
        }

        if (!StringConvertor.isEmpty(message)) {
            PlainMessage m = new PlainMessage(activeCS.c.getUin(), msn, jimm.comm.Util.createCurrentDate(false), message, false);
            if (!StringConvertor.isEmpty(nick)) {
                m.setName(nick);
            }
            
            msn.addMessage(m);
            return;
        }
    }
    private String readBody(ServerHandler sh, String line) {
        int lenght = Integer.parseInt(line.substring(line.lastIndexOf(' ') + 1));
        byte[] bytes = sh.getReplyBytes(lenght);
        String body = StringConvertor.utf8beByteArrayToString(bytes, 0, bytes.length);
        return body;
    }
    private void parseMessage(String line, ChatSession cs) {
        // there can be a lot of different structures of MSG incoming string
        // therefore a complex structure of this function
        String[] tokens = Utils.tokenize(line);
        String body = readBody(cs.sh, line);
        processMessage(body, tokens[1], Utils.urlDecode(tokens[2]), cs);
    }
    private void parseADC(String line) {
        //ADC 0 RL N=odar_5ra@hotmail.com F=Kalypso\r\n
        
        //line = ADC 0 RL N=odar_5ra@hotmail.com F=Kalypso
        String[] atoms = Utils.tokenize(line);
        //atoms[0] = ADC
        //atoms[1] = cid
        //atoms[2] = FL, AL, RL, BL
        //atoms[3] = N=username
        //atoms[4] = F=full name
        
        if (atoms[2].compareTo("RL")==0) {
            String userID = getVal(atoms, "N=");
            String name = getVal(atoms, "F=");
            Contact c = msn.createContact(userID, name);
            
            this.addContact(c);
            msn.addLocalContact(c);
        }
    }
    private void userJoin(String data, ChatSession cs) {
        //JOE zoran.mesec@siol.net nick
        String[] params = Utils.tokenize(data);
        String msg = params[2] + " has joined the conversation window.";
        msn.addMessage(new SystemNotice(msn, SystemNotice.SYS_NOTICE_MESSAGE, cs.c.getUin(), msg));
    }
    private void userBYE(String data, ChatSession cs) {
        //BYE zoran.mesec@siol.net
        String userId = data.substring(3);
        String msg = userId + " has closed the conversation window.";
        msn.addMessage(new SystemNotice(msn, SystemNotice.SYS_NOTICE_MESSAGE, cs.c.getUin(), msg));
    }
    private void groupAdded(String data) {
        //ADG 15 New%20Group b145b37f-7e09-47e7-880e-9daa5346eaab
    }
    private String getVal(String[] data, String key) {
        for (int i = 0; i < data.length; ++i) {
            if (data[i].startsWith(key)) {
                return data[i].substring(key.length());
            }
        }
        return null;
    }
    private void parseContacts(String data) {
        /**
         * TODO: rewrite this with the new string tokenizer in Utils
         */
        //Normal form:
        //LST N=matevz.jekovec@guest.arnes.si F=Matevz C=d954638f-1963-4e45-b157-2029eae8714f 3 406c6d87-043d-4f20-b569-0450b49ca65d
        //Someone got a reply like this once(repeatedly):
        //LST N=p
        
        String[] packet = Utils.tokenize(data.trim());
        String username = getVal(packet, "N=");
        String screenname = Utils.urlDecode(getVal(packet, "F="));
        if (null == screenname) {
            screenname = username;
        }
        if (null == username) {
            return;
        }        
        String contactHash = getVal(packet, "C=");
        if (null == contactHash) {
            return;
        }
        MsnContact person = (MsnContact)msn.createContact(username, screenname);
        person.setUserHash(contactHash);
        
        String groupGuid = packet[packet.length - 1];
        String listStr;
        if ((groupGuid.length() < 10)) {
            //user does not belong to a group
            listStr = packet[packet.length - 1];
        } else {
            listStr = packet[packet.length - 2];
            //person.setGroupHash(groupGuid);
            person.setGroup((Group)groupID.get(groupGuid));
        }
        short list = Short.parseShort(listStr);
        person.setLists(list);
        this.contacts_.put(person.getUin(), person);
        
        //the forward list is 1, the allow list is 2, the block list is 4,
        //the reverse list is 8 and the pending list 16.
        
        switch (list) {
            case 1: //user in my FL list, but i'm not in his/her FL list
                break;
            case 2:
            case 3:
            case 9: //user in my FL list only, i'm in his FL and AL. Means he can't see my presence, so add user to AL list
                this.tr.newTransaction();
                this.tr.setType("ADC");
                this.tr.addArgument("AL N=" + person.getUin());
                this.sh.sendRequest(this.tr.toString());
                break;
            case 11: //user in my FL and AL. Means he can see my presence
            case 17:
                break;
            default:
                break;
        }
        msn.addLocalContact(person);
    }
    
    private void userGoesOffline(String data) {
        //FLN matevz.jekovec@guest.arnes.si
        String uID = data.substring(4, data.length()-2);
        MsnContact c = null;
        c = (MsnContact)this.contacts_.get(uID);
        if (c==null) {
            return;
        }
        /*for (int i=0; i<this.contacts_.size();i++)
        {
            c = (Contact)this.contacts_.elementAt(i);
            if (uID.compareTo(c.getUserId())==0)
            {
                 break;
            }
        }*/
        c.setOfflineStatus();
        msn.ui_changeContactStatus(c);
    }
    private byte status2StatusIndex(String presence) {
        if (presence.compareTo("BSY")==0) {
            return Status.I_STATUS_AWAY;
        } else if ((presence.compareTo("IDL")==0) || (presence.compareTo("NLN")==0)) {
            return Status.I_STATUS_ONLINE;
        } else if (presence.compareTo("AWY")==0) {
            return Status.I_STATUS_AWAY;
        }
        return Status.I_STATUS_ONLINE;
    }
    private void changePresence(String data) {
        if (data.length()<20 || data.substring(0,3).compareTo("NLN")!=0) {
            return;
        }
        String presence = data.substring(4, 7);
        String uID = data.substring(8, data.indexOf(" ", 10));

        MsnContact con = (MsnContact)this.contacts_.get(uID);
        if (null != con) {
            con.setStatus(status2StatusIndex(presence));
            msn.ui_changeContactStatus(con);
        }
    }
    private void startSession(String line) {
        if (waitingChats.isEmpty()) return;
        ChatSession cs = (ChatSession) waitingChats.elementAt(0);
        waitingChats.removeElementAt(0);

        //MSN in: XFR 13 SB 64.4.35.58:1863 CKI 1298692120.186224106.56203170
        String[] params = Utils.tokenize(line);
        ServerHandler switchHandler = new ServerHandler(params[3]);
        switchHandler.connect();
        switchHandler.sendRequest("USR 1 " + this.username + " " + params[5] + "\r\n");
        switchHandler.getReply();
        switchHandler.sendRequest("CAL 2 " + cs.c.getUin()+"\r\n");
        switchHandler.getReply();// CAL
        switchHandler.getReply();// JOI
        cs.sh = switchHandler;
        this.chatSessions_.addElement(cs);
        sendMsg(cs.msg);
        cs.msg = null;
    }
    private void parseGroups(String data) {
        //MSN in: LSG %201 6624a16d-1269-4339-bcdc-0e3a5b28f85e
        String[] params = Utils.tokenize(data);
        MsnGroup g = (MsnGroup) msn.createGroup(Utils.urlDecode(params[1]));
        g.setGuid(params[2]);
        msn.getGroupItems().addElement(g);
        this.groupID.put(params[2], g);
    }
    
    private void parsePresence(String data) {
        //data = ILN 11 NLN idanilov@ua.fm Ilya%20Danilov 1342177280
        String[] atoms = Utils.tokenize(data);
        //atoms[0] = ILN or NLN
        //atoms[1] = cid number
        //atoms[2] = status
        //atoms[3] = contact name (email)
        //atoms[4] = url decoded screen name
        //atoms[5] = contact capabilities (see: http://www.hypothetic.org/docs/msn/notification/presence.php)
        String presence = atoms[2];
        MsnContact con;
        con = (MsnContact)this.contacts_.get(atoms[3]);
        if (con!=null) {
            con.setStatus(status2StatusIndex(presence));
            msn.ui_changeContactStatus(con);
        }
    }
    
    private void parseChallenge(String line) {
        //data = CHL 0 25270234921473318824
        String[] atoms = Utils.tokenize(line);
        //atoms[0] = CHL
        //atoms[1] = ?
        //atoms[2] = challenge
        String challenge = atoms[2];
        
        
        // first step for v11
        //StringBuffer challenge =new StringBuffer(data.substring(6,data.length()-2));
        //challenge.append(this.ProductKey);
        //String challenge = data.substring(6,26);
        
        
        // v11 challenge
        //String hash = new String(md5.toHex(md5.fingerprint(challenge.toString().getBytes())));
        //challenge.concat("YMM8C_H7KCQ2S_KL");
        //challenge = "15570131571988941333";
        
        challenge+=this.ProductIDhash;

        MD5 md5 = new MD5();
        md5.calculate(challenge.getBytes());
        String hash = md5.getDigestHex();

        this.tr.newTransaction();
        this.tr.setType("QRY");
        this.tr.addArgument(this.ProductID);
        this.tr.addArgument("32\r\n"+hash);
        this.sh.sendRequest(this.tr.toStringNN());
    }
    private void SBhandle(String data)  //Switchboard handle
    {
        //RNG 1083693517 207.46.26.110:1863 CKI 18321026.739392 zoran.mesec@siol.net Zoran%20Mesec
        //ANS 1 name_123@hotmail.com 18321026.739392 11752013\r\n
        String[] params = Utils.tokenize(data);
        String authNr = params[1];
        String sbIP = params[2];
        String authKey = params[4];
        String uID = params[5];
        MSNTransaction answer = new MSNTransaction();
        answer.newTransaction();    //set id to 1
        answer.setType("ANS");
        answer.addArgument(this.username);
        answer.addArgument(authKey);
        answer.addArgument(authNr);
        
        MsnContact c = (MsnContact)this.contacts_.get(uID);
        
        if (null == c) {
            return;
        }
        ServerHandler sbHandler = new ServerHandler(sbIP);
        sbHandler.connect();
        sbHandler.sendRequest(answer.toString());
        
        ChatSession cs = new ChatSession(c);
        cs.id = 3;
        cs.sh = sbHandler;
        this.chatSessions_.addElement(cs);
    }
    
    private String getField( String strKey, String strField ) {
        
        try  {
            int       nIniPos        = strField.indexOf( strKey );
            int       nEndPos        = 0;
            
            
            if ( nIniPos < 0 )
                return "";
            
            nIniPos+=strKey.length();
            nEndPos = strField.indexOf( ',', nIniPos );
            
            if ( nEndPos < 0 )
                return "";
            
            return strField.substring( nIniPos, nEndPos );
        } catch( Exception e )  {
            return "";
        }
    }
    /**
     * yy
     * @deprecated This method does nothing.
     */
    public void disconnect() {
        
    }
    public void connect() {
        
    }

    private Vector waitingChats = new Vector();
    /**
     * This method start a Chatsession(a conversation) with a person. The person is given as a function parameter.
     * @param c contact we wish to converse.
     * @return an instance of the newly created ChatSession.
     */
    private ChatSession startChatSession(MsnContact c, PlainMessage msg) {
        ChatSession cs = new ChatSession(c);
        cs.id = 3;
        cs.msg = msg;
        this.busy = true;
        this.tr.newTransaction();
        this.tr.setType("XFR");
        this.tr.addArgument("SB");
        this.sh.sendRequest(this.tr.toString());
        waitingChats.addElement(cs);
        return cs;
    }
    private Vector outgoingMessages = new Vector();
    /**
     * Send a message.
     * @param msg Message in String
     * @param session Active Chat Session to send the message to
     */
    public void sendMessage(PlainMessage message) {
        outgoingMessages.addElement(message);
    }
    private ChatSession getSession(MsnContact c) {
        ChatSession session = null;
        ServerHandler sh = null;
        for (int i = 0; i < this.chatSessions_.size(); ++i) {
            session = (ChatSession)chatSessions_.elementAt(i);
            if (session.c == c) {
                sh = session.sh;
                if ((null == sh) || !sh.isConnected()) {
                    chatSessions_.removeElementAt(i);
                    return null;
                }
                break;
            }
        }
        return (null == sh) ? null : session;
    }
    public void leaveConversation(MsnContact c) {
        ChatSession session = getSession(c);
        if (null == session) {
            return;
        }
        session.outgoingPackets.addElement("BYE " + session.id + "\r\n");
        session.id++;
    }
    private void sendMsg(PlainMessage message) {
        MsnContact c = (MsnContact) message.getRcvr();
        if (null == c) return;
        String msg = message.getText();
        ChatSession session = getSession(c);
        if (null == session) {
            startChatSession(c, message);
            return;
        }
        ServerHandler sh = session.sh;

        //// Typing notify
        //String payload = "MIME-Version: 1.0\r\nContent-Type: text/x-msmsgscontrol\r\nTypingUser: "+this.username+"\r\n\r\n\r\n";
        //byte[] body = StringConvertor.stringToByteArrayUtf8(payload);
        //sh.sendRequest("MSG " + session.id + " U " + body.length + "\r\n", body);
        //session.id++;
        
        String payload = "MIME-Version: 1.0\r\nContent-Type: text/plain; charset=UTF-8\r\nX-MMS-IM-Format: FN=MS%20Sans%20Serif; EF=; CO=0; CS=0; PF=0\r\n\r\n";
        byte[] body = StringConvertor.stringToByteArrayUtf8(payload + msg);
        sh.sendRequest("MSG " + session.id + " U " + body.length + "\r\n", body);
        session.id++;
    }
    
    private void processSession(ChatSession csTemp) {
        if (!csTemp.sh.isConnected()) {
            return;
        }
        try {
            while (!csTemp.outgoingPackets.isEmpty()) {
                csTemp.sh.sendRequest((String)csTemp.outgoingPackets.elementAt(0));
                csTemp.outgoingPackets.removeElementAt(0);
            }
            while (csTemp.sh.available()) {
                String reply = csTemp.sh.getReply();
                if (null == reply) return;

                if (reply.startsWith(CMD_MSG)) {
                    parseMessage(reply, csTemp);

                } else if (reply.startsWith("BYE")) {
                    userBYE(reply, csTemp);

                } else if (reply.startsWith("JOI")) {
                    userJoin(reply, csTemp);
                }
            }
        } catch (Exception e) {
            csTemp.sh.disconnect();
            // #sijapp cond.if modules_DEBUGLOG is "true" #
            jimm.modules.DebugLog.panic("chat", e);
            // #sijapp cond.end #
        }
    }
    /**
     * This method is called when Thread starts. It is a infinite loop that checks all
     * ServerHandlers whether any message has arrived from servers(that you are
     * currently connected to).
     */
    public void run() {
        if (!login___()) {
            return;
        }

        connected_ = true;
        while(!stop) {
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
            }

            try {
                while (!outgoingMessages.isEmpty()) {
                    PlainMessage m = (PlainMessage)outgoingMessages.elementAt(0);
                    outgoingMessages.removeElementAt(0);
                    sendMsg(m);
                }
            } catch (Exception e) {
                // #sijapp cond.if modules_DEBUGLOG is "true" #
                jimm.modules.DebugLog.panic("err", e);
                // #sijapp cond.end #
            }

            // main
            if ((this.status_ == CONNECTED) && sh.available()) {
                parseMainReply(sh.getReply());
                continue;
            }
            
            // chats
            String reply = null;
            for (int i = 0; i < this.chatSessions_.size(); ++i) {
                if (this.status_ != CONNECTED) break;
                ChatSession csTemp = (ChatSession)this.chatSessions_.elementAt(i);
                processSession(csTemp);
                if (!csTemp.sh.isConnected()) {
                    chatSessions_.removeElementAt(i);
                    --i;
                    continue;
                }
            }
        }
        this.connected_ = false;
        for (int i = 0; i < this.chatSessions_.size(); ++i) {
            ChatSession csTemp = (ChatSession)chatSessions_.elementAt(i);
            csTemp.sh.disconnect();
        }
        chatSessions_.removeAllElements();
        sh.disconnect();
    }
    private void parseMainReply(String reply) {
        if (reply.startsWith(CMD_MSG)) {
            String body = readBody(sh, reply);
        } else if (reply.startsWith("UBX")) {
            String body = readBody(sh, reply);
        } else {
            parseReply(reply);
        }
    }
    /**
     * Removes a contact from all lists.
     * @param Contact c the contact to be removed
     * @return true for success or false if the Contact is not on local list of Contacts
     */
    public boolean removeContact(Contact c) {
        MsnContact con=(MsnContact)this.contacts_.get(c.getUin());
        
        if (con!=null) {
            short list = con.getLists();
            this.tr.newTransaction();
            this.tr.setType("REM");
            this.tr.addArgument("FL " + con.getUserHash());
            this.sh.sendRequest(this.tr.toString());
            switch (list) {
                case 11: //user also in my AL list, so don't forget to remove him from this list also
                    this.tr.newTransaction();
                    this.tr.setType("REM");
                    this.tr.addArgument("AL "+c.getUin());
                    this.sh.sendRequest(this.tr.toString());
                case 1:
                case 3: //???
                    this.tr.newTransaction();
                    this.tr.setType("REM");
                    this.tr.addArgument("FL " + con.getUserHash());
                    this.sh.sendRequest(this.tr.toString());
                    break;
            }
            
            this.contacts_.remove(c.getUin());
            return true;
        }
        return false;
    }
    /**
     * This method adds a contact to the local list and then sends a message to the
     * MSN server in order to add a contact to the main list on the server.
     * @param Contact c The contact to be removed.
     */
    public void addContact(Contact c) {
        //ADC 16 FL N=passport@hotmail.com F=Display%20Name\r\n
        //ADC 16 AL N=passport@hotmail.com F=Display%20Name\r\n
        this.contacts_.put(c.getUin(), c);
        
        this.tr.newTransaction();
        this.tr.setType("ADC");
        this.tr.addArgument("FL N=" + c.getUin() + " " + "F=" + Utils.urlDecode(c.getName()));
        this.sh.sendRequest(this.tr.toString());
        
    }
    public void addGroup(String groupName) {
        //ADG 15 New%20Group
        this.tr.newTransaction();
        this.tr.setType("ADG");
        this.tr.addArgument(groupName.replace(' ', '_'));
        this.sh.sendRequest(this.tr.toString());
    }
    
    boolean isConnected() {
        return connected_;
    }
}
// #sijapp cond.end #
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.