ConnectAction.java :  » Chat » jimm-0.5.1 » jimm » comm » Java Open Source

Java Open Source » Chat » jimm 0.5.1 
jimm 0.5.1 » jimm » comm » ConnectAction.java
/*******************************************************************************
 Jimm - Mobile Messaging - J2ME ICQ clone
 Copyright (C) 2003-05  Jimm 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: src/jimm/comm/ConnectAction.java
 Version: 0.5.1  Date: 2006/10/31
 Author(s): Manuel Linsmayer, Andreas Rossbacher
 *******************************************************************************/

package jimm.comm;

import java.util.*;
import java.io.*;

import jimm.ContactListContactItem;
import jimm.ContactListGroupItem;
import jimm.ContactListItem;
import jimm.ContactList;
import jimm.Jimm;
import jimm.JimmException;
import jimm.Options;
import jimm.RunnableImpl;
import jimm.comm.Icq.HTTPConnection;

public class ConnectAction extends Action
{
    // Action states
    public static final int STATE_ERROR = -1;
    public static final int STATE_INIT_DONE = 0;
  public static final int STATE_AUTHKEY_REQUESTED = 1;
    public static final int STATE_CLI_IDENT_SENT = 2;
    public static final int STATE_CLI_DISCONNECT_SENT = 3;
    public static final int STATE_CLI_COOKIE_SENT = 4;
    public static final int STATE_CLI_CHECKROSTER_SENT = 5;
    public static final int STATE_CLI_REQOFFLINEMSGS_SENT = 6;
    public static final int STATE_CLI_ACKOFFLINEMSGS_SENT = 7;

    // CLI_SETUSERINFO packet data
    public static final byte[] CLI_SETUSERINFO_DATA =
  {
    (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x60,   // 5 capabilities follow

    (byte) 0x09, (byte) 0x46, (byte) 0x13, (byte) 0x49, // CAP_AIM_SERVERRELAY
    (byte) 0x4C, (byte) 0x7F, (byte) 0x11, (byte) 0xD1, 
    (byte) 0x82, (byte) 0x22, (byte) 0x44, (byte) 0x45, 
    (byte) 0x53, (byte) 0x54, (byte) 0x00, (byte) 0x00,
    
    (byte) 0x09, (byte) 0x46, (byte) 0x13, (byte) 0x44,   // CAP_AIM_ISICQ
    (byte) 0x4C, (byte) 0x7F, (byte) 0x11, (byte) 0xD1, 
    (byte) 0x82, (byte) 0x22, (byte) 0x44, (byte) 0x45, 
    (byte) 0x53, (byte) 0x54, (byte) 0x00, (byte) 0x00,    
    
    (byte) 0x09, (byte) 0x46, (byte) 0x00, (byte) 0x00,   //CAP_UNKNOWN
    (byte) 0x4C, (byte) 0x7F, (byte) 0x11, (byte) 0xD1, 
    (byte) 0x82, (byte) 0x22, (byte) 0x44, (byte) 0x45, 
    (byte) 0x53, (byte) 0x54, (byte) 0x00, (byte) 0x00,
    
    (byte) 0x09, (byte) 0x46, (byte) 0x13, (byte) 0x4E,   //CAP_UTF8
    (byte) 0x4C, (byte) 0x7F, (byte) 0x11, (byte) 0xD1, 
    (byte) 0x82, (byte) 0x22, (byte) 0x44, (byte) 0x45, 
    (byte) 0x53, (byte) 0x54, (byte) 0x00, (byte) 0x00,
    
    /* Jimm */ 'J', 'i', 'm', 'm',             //Jimm version
    (byte) 0x20, (byte) 0x00, (byte) 0x00, (byte) 0x00,  //Place for string & raw version
    (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, //Place for string & raw version
    (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, //Last byte - target
    
    (byte) 0x56, (byte) 0x3f, (byte) 0xc8, (byte) 0x09,      // CAP_MTN
    (byte) 0x0b, (byte) 0x6f, (byte) 0x41, (byte) 0xbd,
    (byte) 0x9f, (byte) 0x79, (byte) 0x42, (byte) 0x26,
    (byte) 0x09, (byte) 0xdf, (byte) 0xa2, (byte) 0xf3
  };

    // CLI_SETICBM packet data
    public static final byte[] CLI_SETICBM_DATA =
    { 0, 0, 0, 0, 0, 0x0B, 0x1F,  0x40, 3, (byte)0xE7, 3, (byte)0xE7, 0, 0, 0, 0};

    // CLI_SETSTATUS packet data
    public static final byte[] CLI_SETSTATUS_DATA =
    { (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x04, 
    (byte) 0x11, (byte) 0x00, (byte) 0x00, (byte) 0x00, // Online status
      (byte) 0x00, (byte) 0x0C, (byte) 0x00, (byte) 0x25, // TLV(C)
      (byte) 0xC0, (byte) 0xA8, (byte) 0x00, (byte) 0x01, // 192.168.0.1, cannot get own IP address
      (byte) 0x00, (byte) 0x00, (byte) 0xAB, (byte) 0xCD, // Port 43981
      (byte) 0x00, // Firewall
      (byte) 0x00, (byte) 0x08, // Support protocol version 8
      (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
      (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x50, 
      (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03, // 3                                                                                                                                                                 // follow
      (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFE, // Timestamp 1
      (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, // Timestamp 2
      (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFE, // Timestamp 3
      (byte) 0x00, (byte) 0x00};

    // CLI_READY packet data
    public static final byte[] CLI_READY_DATA =
    {
        (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x04, 
      (byte)0x01, (byte)0x10, (byte)0x08, (byte)0xe4, 
      (byte)0x00, (byte)0x13, (byte)0x00, (byte)0x04,
      (byte)0x01,(byte)0x10, (byte)0x08, (byte)0xe4,
      (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x01,
      (byte)0x01, (byte)0x10, (byte)0x08, (byte)0xe4,
      (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x01,
      (byte)0x01, (byte)0x10, (byte)0x08, (byte)0xe4,
      (byte)0x00, (byte)0x15, (byte)0x00, (byte)0x01, 
      (byte)0x01, (byte)0x10, (byte)0x08, (byte)0xe4,
      (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x01,
      (byte)0x01, (byte)0x10, (byte)0x08, (byte)0xe4,
      (byte)0x00, (byte)0x06, (byte)0x00, (byte)0x01,
      (byte)0x01, (byte)0x10, (byte)0x08, (byte)0xe4,
      (byte)0x00, (byte)0x09, (byte)0x00, (byte)0x01,
      (byte)0x01, (byte)0x10, (byte)0x08, (byte)0xe4,
      (byte)0x00, (byte)0x0a, (byte)0x00, (byte)0x01,
      (byte)0x01, (byte)0x10, (byte)0x08, (byte)0xe4,
      (byte)0x00, (byte)0x0b, (byte)0x00, (byte)0x01,
      (byte)0x01, (byte)0x10, (byte)0x08, (byte)0xe4
    };
//    {(byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x03,
//   (byte) 0x01, (byte) 0x10, (byte) 0x04,  (byte) 0x7B,
//   (byte) 0x00, (byte) 0x13, (byte) 0x00, (byte) 0x02,
//   (byte) 0x01, (byte) 0x10, (byte) 0x04, (byte) 0x7B,
//     (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x01, 
//   (byte) 0x01, (byte) 0x01, (byte) 0x04, (byte) 0x7B,
//     (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x01, 
//   (byte) 0x01, (byte) 0x10, (byte) 0x04, (byte) 0x7B,
//     (byte) 0x00, (byte) 0x15, (byte) 0x00, (byte) 0x01,
//   (byte) 0x01, (byte) 0x10, (byte) 0x04, (byte) 0x7B,
//     (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x01, 
//   (byte) 0x01, (byte) 0x10, (byte) 0x04, (byte) 0x7B,
//     (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x01, 
//   (byte) 0x01, (byte) 0x10, (byte) 0x04, (byte) 0x7B,
//     (byte) 0x00, (byte) 0x09, (byte) 0x00, (byte) 0x01, 
//   (byte) 0x01, (byte) 0x10, (byte) 0x04, (byte) 0x7B,
//     (byte) 0x00, (byte) 0x0A, (byte) 0x00, (byte) 0x01, 
//   (byte) 0x01, (byte) 0x10, (byte) 0x04, (byte) 0x7B,
//     (byte) 0x00, (byte) 0x0B, (byte) 0x00, (byte) 0x01, 
//   (byte) 0x01, (byte) 0x10, (byte) 0x04, (byte) 0x7B};

    // Timeout
    // #sijapp cond.if modules_PROXY is "true" #
    public static final int TIME_OUT = 20 * 1000;
    // #sijapp cond.end #
    public int TIMEOUT = 20 * 1000; // milliseconds

    /** *********************************************************************** */

    // UIN
    private String uin;

    // Password
    private String password;

    // Server host
    private String srvHost;

    // Server port
    private String srvPort;

    // Action state
    private int state;

    // Last activity
    private Date lastActivity = new Date();
    private boolean active;

    // Temporary variables
  private String server;
    private byte[] cookie;
    private boolean srvReplyRosterRcvd;

    // Constructor
    public ConnectAction(String uin, String password, String srvHost, String srvPort)
    {
      super(true, false);
        this.uin = new String(uin);
        this.password = new String(password);
        this.srvHost = new String(srvHost);
        this.srvPort = new String(srvPort);
    }

    // Returns the UID
    public String getUin()
    {
        return (new String(this.uin));
    }

    // Returns the password
    public String getPassword()
    {
        return (new String(this.password));
    }

    // Returns the server host
    public String getSrvHost()
    {
        return (new String(this.srvHost));
    }

    // Returns the server port
    public String getSrvPort()
    {
        return (new String(this.srvPort));
    }

    // Init action
    protected void init() throws JimmException
    {
        // #sijapp cond.if modules_PROXY is "true" #
        int retry = 1;
        try
        {
            retry = Integer.parseInt(Options.getString(Options.OPTION_AUTORETRY_COUNT));
            retry = (retry > 0) ? retry : 1;
        } catch (NumberFormatException e)
        {
            retry = 1;
        }

        this.TIMEOUT = ConnectAction.TIME_OUT * retry;
        // #sijapp cond.end#
 
        // Check parameters
        if ((this.uin.length() == 0) || (this.password.length() == 0))
        {
            this.state = ConnectAction.STATE_ERROR;
            throw (new JimmException(117, 0));
        }

        // Open connection
        // #sijapp cond.if modules_PROXY is "true" #

        for (int i = 0; i < retry; i++)
        {
            // #sijapp cond.end#

            try
            {
              Icq.c.connect(this.srvHost + ":" + this.srvPort);
                // #sijapp cond.if modules_PROXY is "true" #
                break;
                // #sijapp cond.end #
            } catch (JimmException e)
            {
                // #sijapp cond.if modules_PROXY is "true" #
                if (i >= (retry - 1) || ((this.lastActivity.getTime() + this.TIMEOUT) < System.currentTimeMillis()))
                {
                    // #sijapp cond.end #

                    this.state = ConnectAction.STATE_ERROR;
                    throw (e);
                }
                // #sijapp cond.if modules_PROXY is "true" #
                else
                    if ((this.lastActivity.getTime() + this.TIMEOUT) > System.currentTimeMillis())
                    {
                      Icq.c.close();
                        try
                        {
                            // Wait the given time
                            Thread.sleep(2000);
                        } catch (InterruptedException er)
                        {
                            // Do nothing
                        }
                    }
            }
        }
        // #sijapp cond.end #

        // Set STATE_INIT
        this.state = ConnectAction.STATE_INIT_DONE;

        // Update activity timestamp
        this.lastActivity = new Date();

    }

    // Forwards received packet, returns true if packet has been consumed
    protected boolean forward(Packet packet) throws JimmException
    {
        // #sijapp cond.if modules_PROXY is "true" #

        int retry = 1;
        try
        {
            retry = Integer.parseInt(Options.getString(Options.OPTION_AUTORETRY_COUNT));
            retry = (retry > 0) ? retry : 1;
        } catch (NumberFormatException e)
        {
            retry = 1;
        }
        // #sijapp cond.end #

        // Set activity flag
        this.active = true;

        // Catch JimmExceptions
        try
        {

            // Flag indicates whether packet has been consumed or not
            boolean consumed = false;

            // Watch out for STATE_INIT_DONE
            if (this.state == ConnectAction.STATE_INIT_DONE)
            {
                // Watch out for SRV_CLI_HELLO packet
                if (packet instanceof ConnectPacket)
                {
                    ConnectPacket connectPacket = (ConnectPacket) packet;
                    if (connectPacket.getType() == ConnectPacket.SRV_CLI_HELLO)
                    {
            if (Options.getBoolean(Options.OPTION_MD5_LOGIN)) {
              Icq.c.sendPacket(new ConnectPacket());
              byte[] buf = new byte[4 + this.uin.length()];
              Util.putWord(buf, 0, 0x0001);
              Util.putWord(buf, 2, this.uin.length());
              byte[] uinRaw = Util.stringToByteArray(this.uin);
              System.arraycopy(uinRaw, 0, buf, 4, uinRaw.length);
              Icq.c.sendPacket(new SnacPacket(0x0017, 0x0006, 0, new byte[0], buf));
            } else {
              // Send a CLI_IDENT packet as reply
              ConnectPacket reply = new ConnectPacket(this.uin, this.password);
              Icq.c.sendPacket(reply);
            }

                        // Move to next state
                        this.state = !Options.getBoolean(Options.OPTION_MD5_LOGIN) ? ConnectAction.STATE_CLI_IDENT_SENT :
              STATE_AUTHKEY_REQUESTED;

                        // Packet has been consumed
                        consumed = true;

                    }
                }

            }
      else if (state == STATE_AUTHKEY_REQUESTED) {
        if (packet instanceof SnacPacket) {
          SnacPacket snacPacket = (SnacPacket)packet;
          if ((snacPacket.getFamily() == 0x0017) && (snacPacket.getCommand() == 0x0007)) {
            byte[] rbuf = snacPacket.getData();
            int len = Util.getWord(rbuf, 0);
            byte[] authkey = new byte[len];
            System.arraycopy(rbuf, 2, authkey, 0, len);
            rbuf = null;
            byte[] buf = new byte[2 + 2 + this.uin.length() + 2 + 2 + 16];
            int marker = 0;
            Util.putWord(buf, marker, 0x0001);
            marker += 2;
            Util.putWord(buf, marker, this.uin.length());
            marker += 2;
            byte[] uinRaw = Util.stringToByteArray(this.uin);
            System.arraycopy(uinRaw, 0, buf, marker, uinRaw.length);
            marker += uinRaw.length;
            Util.putWord(buf, marker, 0x0025);
            marker += 2;
            Util.putWord(buf, marker, 0x0010);
            marker += 2;
            byte[] md5buf = new byte[authkey.length + this.password.length() + Util.AIM_MD5_STRING.length];
            int md5marker = 0;
            System.arraycopy(authkey, 0, md5buf, md5marker, authkey.length);
            md5marker += authkey.length;
            byte[] passwordRaw = Util.stringToByteArray(this.password);
            System.arraycopy(passwordRaw, 0, md5buf, md5marker, passwordRaw.length);
            md5marker += passwordRaw.length;
            System.arraycopy(Util.AIM_MD5_STRING, 0, md5buf, md5marker, Util.AIM_MD5_STRING.length);
            byte[] hash = Util.calculateMD5(md5buf);
            System.arraycopy(hash, 0, buf, marker, 16);
            Icq.c.sendPacket(new SnacPacket(0x0017, 0x0002, 0, new byte[0], buf));
            state = STATE_CLI_IDENT_SENT;
          } else {
            throw new JimmException(100,0);
          }
        }
        consumed = true;
      }
            // Watch out for STATE_CLI_IDENT_SENT
            else if (this.state == ConnectAction.STATE_CLI_IDENT_SENT)
      {
        int errcode = -1;
        if (Options.getBoolean(Options.OPTION_MD5_LOGIN)) {
          if (packet instanceof SnacPacket) {
            SnacPacket snacPacket = (SnacPacket)packet;
            if ((snacPacket.getFamily() == 0x0017) && (snacPacket.getCommand() == 0x0003)) {
              byte[] buf = snacPacket.getData();
              int marker = 0;
              while (marker < buf.length) {
                byte[] tlvData = Util.getTlv(buf, marker);
                int tlvType = Util.getWord(buf, marker);
                marker += 4 + tlvData.length;
                switch (tlvType) {
                  case 0x0008:
                    errcode = Util.getWord(tlvData, 0);
                    break;
                  case 0x0005:
                    this.server = Util.byteArrayToString(tlvData);
                    break;
                  case 0x0006:
                    this.cookie = tlvData;
                    break;
                }
              }
            }
          } else if (packet instanceof DisconnectPacket) {
            consumed = true;
          }
        } else {
          // watch out for channel 4 packet
          if (packet instanceof DisconnectPacket) {
            DisconnectPacket disconnectPacket = (DisconnectPacket) packet;
            // Watch out for SRV_COOKIE packet
            if (disconnectPacket.getType() == DisconnectPacket.TYPE_SRV_COOKIE) {
              // Save cookie
              this.cookie = disconnectPacket.getCookie();
              this.server = disconnectPacket.getServer();
            }
            // Watch out for SRV_GOODBYE packet
            else if (disconnectPacket.getType() == DisconnectPacket.TYPE_SRV_GOODBYE)
              errcode = disconnectPacket.getError();
            consumed = true;
          }
        }

        if (errcode != -1) {
          int toThrow = 100;
          switch (errcode) {
            // Multiple logins
            case 0x0001:
              toThrow = 110;
              break;
            // Bad password
            case 0x0004: case 0x0005:
              toThrow = 111;
              break;
            // Non-existant UIN
            case 0x0007: case 0x0008:
              toThrow = 112;
              break;
            // Too many clients from same IP
            case 0x0015: case 0x0016:
              toThrow = 113;
              break;
            // Rate exceeded
            case 0x0018: case 0x001d:
              toThrow = 114;
              break;
          }
          throw new JimmException(toThrow, errcode);
        }

        if (consumed & (this.server != null) & (this.cookie != null)) {
          // Close connection (only if not HTTP Connection)
          if (!(Icq.c instanceof HTTPConnection))
            Icq.c.close();
          // #sijapp cond.if target is "DEFAULT" | target is "MIDP2"#
          if (Options.getBoolean(Options.OPTION_SHADOW_CON)) try
          {
            // Wait the given time before starting the
            // new connection
            Thread.sleep(2000);
          } catch (InterruptedException e) {}
          // #sijapp cond.end#
          // Open connection
          // #sijapp cond.if modules_PROXY is "true" #
          for (int i = 0; i < retry; i++)
          {
            try
            {
              // #sijapp cond.end #
              Icq.c.connect(server);
              // #sijapp cond.if modules_PROXY is "true" #
              break;

            } catch (JimmException e)
            {
              if (i >= (retry - 1) || ((this.lastActivity.getTime() + this.TIMEOUT) < System.currentTimeMillis()))
              {
                this.active = false;
                this.state = ConnectAction.STATE_ERROR;
                throw (e);
              }
              else if ((this.lastActivity.getTime() + this.TIMEOUT) > System.currentTimeMillis())
              {
                Icq.c.close();
                try
                {
                  // Wait the given time
                  Thread.sleep(2000);
                } catch (InterruptedException er)
                {
                  // Do nothing
                }
              }
            }
          }
          // #sijapp cond.end #
          // Move to next state
          this.state = ConnectAction.STATE_CLI_DISCONNECT_SENT;
        }

      }
      // Watch out for STATE_CLI_DISCONNECT_SENT
      else if (this.state == ConnectAction.STATE_CLI_DISCONNECT_SENT)
      {

        // Watch out for SRV_HELLO packet
        if (packet instanceof ConnectPacket)
        {
          ConnectPacket connectPacket = (ConnectPacket) packet;
          if (connectPacket.getType() == ConnectPacket.SRV_CLI_HELLO)
          {

            // Send a CLI_COOKIE packet as reply
            ConnectPacket reply = new ConnectPacket(this.cookie);
            Icq.c.sendPacket(reply);

            // Send a CLI_SETUSERINFO packet
            // Set version information to this packet in our capability
            byte[] tmp = ConnectAction.CLI_SETUSERINFO_DATA;
            byte[] ver = Util.stringToByteArray("0.5.1");
            if (ver.length <=10)
              System.arraycopy(ver,0,tmp,tmp.length-11-16,ver.length);
            
            // If typing notify is on, we send full caps..with typing
            byte[] tmp_packet;
            
            //#sijapp cond.if target isnot "DEFAULT"#
            if (Options.getInt(Options.OPTION_TYPING_MODE) > 0)
            {
                tmp_packet = tmp;
            }
            // If typing notify option is disabled,
            // We must remove typing capability
            else
            {
            //#sijapp cond.end#
              
                tmp_packet = new byte[tmp.length-16];
                System.arraycopy(tmp,0,tmp_packet,0,tmp.length-16);
                
                // Length correction
                tmp_packet[3] = (byte)0x40;
                        //#sijapp cond.if target isnot "DEFAULT"#
            }
            //#sijapp cond.end#
              Icq.c.sendPacket(new SnacPacket(0x0002, 0x0004, 0, new byte[0], tmp_packet));

            // Send a CLI_SETICBM packet
            SnacPacket reply1;
            
            //#sijapp cond.if target isnot "DEFAULT"#
            if (Options.getInt(Options.OPTION_TYPING_MODE) > 0)
            {
              reply1 = new SnacPacket(SnacPacket.CLI_SETICBM_FAMILY, SnacPacket.CLI_SETICBM_COMMAND, 0x00000000, new byte[0], ConnectAction.CLI_SETICBM_DATA);
            }
            else
            {
              //#sijapp cond.end#
              tmp_packet = ConnectAction.CLI_SETICBM_DATA;
              tmp_packet[5] = 0x03;
              reply1 = new SnacPacket(SnacPacket.CLI_SETICBM_FAMILY, SnacPacket.CLI_SETICBM_COMMAND, 0x00000000, new byte[0], tmp_packet);
              //#sijapp cond.if target isnot "DEFAULT"#
            }
            //#sijapp cond.end#
            Icq.c.sendPacket(reply1);

            // Send a CLI_SETSTATUS packet
            Util.putDWord(ConnectAction.CLI_SETSTATUS_DATA, 4, (0x10<<24)|Util.translateStatusSend((int)Options.getLong(Options.OPTION_ONLINE_STATUS)));
            SnacPacket reply2 = new SnacPacket(SnacPacket.CLI_SETSTATUS_FAMILY, SnacPacket.CLI_SETSTATUS_COMMAND, 0x00000000, new byte[0], ConnectAction.CLI_SETSTATUS_DATA);
            Icq.c.sendPacket(reply2);

            // Move to next state
            this.state = ConnectAction.STATE_CLI_COOKIE_SENT;

            // Packet has been consumed
            consumed = true;

          }
        }

      }
      // Watch out for STATE_CLI_COOKIE_SENT
      else if (this.state == ConnectAction.STATE_CLI_COOKIE_SENT)
      {

        // Send a CLI_REQROSTER or
        // CLI_CHECKROSTER packet
        long versionId1 = ContactList.getSsiListLastChangeTime();
        int versionId2 = ContactList.getSsiNumberOfItems();
        if (((versionId1 == -1) && (versionId2 == -1)) || (ContactList.getSize() == 0))
        {
          SnacPacket reply2 = new SnacPacket(SnacPacket.CLI_REQROSTER_FAMILY, SnacPacket.CLI_REQROSTER_COMMAND, 0x00000000, new byte[0], new byte[0]);
          Icq.c.sendPacket(reply2);
        }
        else
        {
          byte[] data = new byte[6];
          Util.putDWord(data, 0, versionId1);
          Util.putWord(data, 4, versionId2);
          SnacPacket reply2 = new SnacPacket(SnacPacket.CLI_CHECKROSTER_FAMILY, SnacPacket.CLI_CHECKROSTER_COMMAND, 0x00000000, new byte[0], data);
          Icq.c.sendPacket(reply2);
        }

        // Move to next state
        this.state = ConnectAction.STATE_CLI_CHECKROSTER_SENT;

      }
      // Watch out for STATE_CLI_CHECKROSTER_SENT
      else if (this.state == ConnectAction.STATE_CLI_CHECKROSTER_SENT)
      {

        // Watch out for SNAC packet
        if (packet instanceof SnacPacket)
        {
          SnacPacket snacPacket = (SnacPacket) packet;

          // Watch out for
          // SRV_REPLYROSTEROK
          if ((snacPacket.getFamily() == SnacPacket.SRV_REPLYROSTEROK_FAMILY) && (snacPacket.getCommand() == SnacPacket.SRV_REPLYROSTEROK_COMMAND))
          {
            this.srvReplyRosterRcvd = true;

            // Packet has been consumed
            consumed = true;

          }
          // watch out for SRV_REPLYROSTER
          // packet
          else if ((snacPacket.getFamily() == SnacPacket.SRV_REPLYROSTER_FAMILY) && (snacPacket.getCommand() == SnacPacket.SRV_REPLYROSTER_COMMAND))
          {
            if (snacPacket.getFlags() != 1) this.srvReplyRosterRcvd = true;

            // System.out.println("Flag:
            // "+snacPacket.getFlags());

            // Initialize vector for
            // items
            Vector items = new Vector();

            // Get data
            byte[] buf = snacPacket.getData();
            int marker = 0;

            // Check length
            if (buf.length < 3) { throw (new JimmException(115, 0)); }

            // Skip
            // SRV_REPLYROSTER.UNKNOWN
            marker += 1;

            // Iterate through all
            // items
            int count = Util.getWord(buf, marker);
            marker += 2;
        
            
            // System.out.println("elemente in serverlist: "+count);
            for (int i = 0; i < count; i++)
            {

              // Check length
              if (buf.length < marker + 2) { throw (new JimmException(115, 1)); }

              // Get name length
              int nameLen = Util.getWord(buf, marker);
              marker += 2;

              // Check length
              if (buf.length < marker + nameLen + 2 + 2 + 2 + 2) { throw (new JimmException(115, 2)); }

              // Get name
              String name = Util.byteArrayToString(buf, marker, nameLen, Util.isDataUTF8(buf, marker, nameLen));
              marker += nameLen;

              // Get group, id and type
              int group = Util.getWord(buf, marker);
              int id = Util.getWord(buf, marker + 2);
              int type = Util.getWord(buf, marker + 4);
              marker += 6;

              // Get length of the following TLVs
              int len = Util.getWord(buf, marker);
              marker += 2;

              // Check length
              if (buf.length < marker + len) { throw (new JimmException(115, 3)); }

              // Normal contact
              if (type == 0x0000)
              {
                // ByteArrayOutputStream serverData = new ByteArrayOutputStream();
                
                // Get nick
                String nick = new String(name);
                
                boolean noAuth = false;
                while (len > 0)
                {
                  byte[] tlvData = Util.getTlv(buf, marker);
                  if (tlvData == null) { throw (new JimmException(115, 4)); }
                  int tlvType = Util.getWord(buf, marker);
                  if (tlvType == 0x0131)
                  {
                    nick = Util.byteArrayToString(tlvData, true);
                  }
                  else if (tlvType == 0x0066)
                  {
                    noAuth = true;
                  }
                  
                  //else if (tlvType == 0x006D) /* Server-side additional data */
                  //{
                  //  Util.writeWord(serverData, tlvType, true);
                  //  Util.writeWord(serverData, tlvData.length, true);
                  //  Util.writeByteArray(serverData, tlvData);
                  //  
                  //  Util.showBytes(serverData.toByteArray());
                  //}
                  
                  len -= 4;
                  len -= tlvData.length;
                  marker += 4 + tlvData.length;
                }
                if (len != 0) { throw (new JimmException(115, 5)); }

                // Add this contact item to the vector
                try
                {
                  ContactListContactItem item = new ContactListContactItem(id, group, name, nick, noAuth, true);
                  // if (serverData.size() != 0) item.ssData = serverData.toByteArray();
                  items.addElement(item);
                }
                catch (Exception e)
                {
                  // Contact with wrong uin was received  
                }

              }
              // Group of contacts
              else if (type == 0x0001)
              {
                //System.out.println("g "+i+": "+name);
                // Skip TLVs
                marker += len;

                // Add this group item to the vector
                if (group != 0x0000)
                {
                  items.addElement(new ContactListGroupItem(group, name));
                }

              }
              // My visibility settings
              else if (type == 0x0004)
              {
                while (len > 0)
                {
                  byte[] tlvData = Util.getTlv(buf, marker);
                  if (tlvData == null) { throw (new JimmException(115, 110)); }
                  int tlvType = Util.getWord(buf, marker);

                  if (tlvType == 0x00CA)
                  {
                    Options.setInt(Options.OPTION_VISIBILITY_ID, (int)id);
                  }

                  len -= 4;
                  len -= tlvData.length;
                  marker += 4 + tlvData.length;
                }
                if (len != 0) { throw (new JimmException(115, 111)); }
              }
              // All other item types
              else
              {
                //System.out.println("x "+i+": ");
                // Skip TLVs
                marker += len;

              }

            }

            // Check length
            if (buf.length != marker + 4) { throw (new JimmException(115, 6)); }

            // Get timestamp
            int timestamp = (int)Util.getDWord(buf, marker);

            // Update contact list
            ContactListItem[] itemsAsArray = new ContactListItem[items.size()];
            items.copyInto(itemsAsArray);
            ContactList.update(snacPacket.getFlags(), timestamp, count, itemsAsArray);

            // Packet has been consumed
            consumed = true;

          }

          // Check if all required packets have been received
          if (this.srvReplyRosterRcvd)
          {

            // Send a CLI_ROSTERACK packet
            SnacPacket reply1 = new SnacPacket(SnacPacket.CLI_ROSTERACK_FAMILY, SnacPacket.CLI_ROSTERACK_COMMAND, 0x00000000, new byte[0], new byte[0]);
            Icq.c.sendPacket(reply1);

            int onlineStatusOpt = (int)Options.getLong(Options.OPTION_ONLINE_STATUS);
            int onlineStatus = Util.translateStatusSend(onlineStatusOpt);
            int visibilityItemId = Options.getInt(Options.OPTION_VISIBILITY_ID);
            byte[] buf = new byte[15];
            byte bCode = 0;
            if(visibilityItemId != 0)
            {
              // Build packet for privacy setting changing
              int marker = 0;

              if(onlineStatus == Util.SET_STATUS_INVISIBLE)
                bCode = (onlineStatusOpt == ContactList.STATUS_INVIS_ALL)?(byte)2:(byte)3;
              else
                bCode = (byte)4;

              Util.putWord(buf, marker,    0); marker += 2; // name (null)
              Util.putWord(buf, marker,    0); marker += 2; // GroupID
              Util.putWord(buf, marker,  visibilityItemId); marker += 2; // EntryID
              Util.putWord(buf, marker,    4); marker += 2; // EntryType
              Util.putWord(buf, marker,    5); marker += 2; // Length in bytes of following TLV
              Util.putWord(buf, marker, 0xCA); marker += 2; // TLV Type
              Util.putWord(buf, marker,    1); marker += 2; // TLV Length
              Util.putByte(buf, marker,bCode);              // TLV Value

              // Change privacy setting according to new status
              if(onlineStatus == Util.SET_STATUS_INVISIBLE)
              {
                SnacPacket reply2pre = new SnacPacket(SnacPacket.CLI_ROSTERUPDATE_FAMILY,
                               SnacPacket.CLI_ROSTERUPDATE_COMMAND,
                               SnacPacket.CLI_ROSTERUPDATE_COMMAND,
                               new byte[0],
                               buf);
                Icq.c.sendPacket(reply2pre);
              }
            }

            // Send to server sequence of unuthoruzed contacts to see their statuses 
            String[] noauth = ContactList.getUnauthAndTempContacts();
            if (noauth.length > 0) Icq.addLocalContacts(noauth);

            // Change privacy setting according to new status
            if(visibilityItemId != 0 && onlineStatus != Util.SET_STATUS_INVISIBLE)
            {
              SnacPacket reply2post = new SnacPacket(SnacPacket.CLI_ROSTERUPDATE_FAMILY,
                            SnacPacket.CLI_ROSTERUPDATE_COMMAND,
                            SnacPacket.CLI_ROSTERUPDATE_COMMAND,
                            new byte[0],
                            buf);
              Icq.c.sendPacket(reply2post);
            }

            // Send a CLI_READY packet
            SnacPacket reply2 = new SnacPacket(SnacPacket.CLI_READY_FAMILY, SnacPacket.CLI_READY_COMMAND, 0x00000000, new byte[0], ConnectAction.CLI_READY_DATA);
            Icq.c.sendPacket(reply2);

            // Send a CLI_TOICQSRV/CLI_REQOFFLINEMSGS packet
            ToIcqSrvPacket reply3 = new ToIcqSrvPacket(0x00000000, this.uin, ToIcqSrvPacket.CLI_REQOFFLINEMSGS_SUBCMD, new byte[0], new byte[0]);
            Icq.c.sendPacket(reply3);

            // Move to next state
            this.state = ConnectAction.STATE_CLI_REQOFFLINEMSGS_SENT;

          }

        }

      }
      // Watch out for STATE_CLI_REQOFFLINEMSGS_SENT
      else if (this.state == ConnectAction.STATE_CLI_REQOFFLINEMSGS_SENT)
      {

        if (packet instanceof FromIcqSrvPacket)
        {
          FromIcqSrvPacket fromIcqSrvPacket = (FromIcqSrvPacket) packet;

          // Watch out for SRV_OFFLINEMSG
          if (fromIcqSrvPacket.getSubcommand() == FromIcqSrvPacket.SRV_OFFLINEMSG_SUBCMD)
          {

            // Get raw data
            byte[] buf = fromIcqSrvPacket.getData();

            // Check length
            if (buf.length < 14) return false;
              

            // Extract UIN
            long uinRaw = Util.getDWord(buf, 0, false);

            String uin = String.valueOf(uinRaw);
            
            // Extract date of dispatch
            long date = Util.createLongTime
                    (
                      Util.getWord(buf, 4, false),
                      Util.getByte(buf, 6),
                      Util.getByte(buf, 7),
                      Util.getByte(buf, 8),
                      Util.getByte(buf, 9),
                      0
                     );
            
            //System.out.println("Offline mess:");
            //System.out.println("hour="+(int)Util.getByte(buf, 8));
            //System.out.println("min="+(int)Util.getByte(buf, 9));
            //System.out.println();

            // Get type
            int type = Util.getWord(buf, 10, false);

            // Get text length
            int textLen = Util.getWord(buf, 12, false);

            // Check length
            if (buf.length != 14 + textLen) { throw (new JimmException(116, 1)); }

            // Get text
            String text = Util.removeCr(Util.byteArrayToString(buf, 14, textLen, Util.isDataUTF8(buf, 14, textLen)));

            // Normal message
            if (type == 0x0001)
            {
               // Forward message to contact list
              System.out.println("bef");
              PlainMessage message = new PlainMessage(uin, this.uin, Util.gmtTimeToLocalTime(date), text, true);
              System.out.println("aft");
              RunnableImpl.addMessageSerially(message);
            }
            // URL message
            else if (type == 0x0004)
            {

              // Search for delimiter
              int delim = text.indexOf(0xFE);

              // Split message, if delimiter could be found
              String urlText;
              String url;
              if (delim != -1)
              {
                urlText = text.substring(0, delim);
                url = text.substring(delim + 1);
              }
              else
              {
                urlText = text;
                url = "";
              }

              // Forward message message to contact list
              UrlMessage message = new UrlMessage(uin, this.uin, Util.gmtTimeToLocalTime(date), url, urlText);
              RunnableImpl.addMessageSerially(message);
            }

            // Packet has been consumed
            consumed = true;

          }
          // Watch out for SRV_DONEOFFLINEMSGS
          else if (fromIcqSrvPacket.getSubcommand() == FromIcqSrvPacket.SRV_DONEOFFLINEMSGS_SUBCMD)
          {

            // Send a CLI_TOICQSRV/CLI_ACKOFFLINEMSGS packet
            ToIcqSrvPacket reply = new ToIcqSrvPacket(0x00000000, this.uin, ToIcqSrvPacket.CLI_ACKOFFLINEMSGS_SUBCMD, new byte[0], new byte[0]);
            Icq.c.sendPacket(reply);

            // Move to next state
            this.state = ConnectAction.STATE_CLI_ACKOFFLINEMSGS_SENT;

            // Move to STATE_CONNECTED
            Icq.setConnected();

            // Packet has been consumed
            consumed = true;

          }

        }

      }

            // Update activity timestamp and reset activity flag
            this.lastActivity = new Date();
            this.active = false;

            // Return consumption flag
            return (consumed);

        }
        // Catch JimmExceptions
        catch (JimmException e)
        {

            // Update activity timestamp and reset activity flag
            this.lastActivity = new Date();
            this.active = false;

            // Set error state if exception is critical
            if (e.isCritical()) this.state = ConnectAction.STATE_ERROR;

            // Forward exception
            throw (e);

        }

    }

    // Returns true if the action is completed
    public boolean isCompleted()
    {
        return (this.state == ConnectAction.STATE_CLI_ACKOFFLINEMSGS_SENT);
    }

    // Returns true if an error has occured
    public boolean isError()
    {
      if ((this.state != ConnectAction.STATE_ERROR) && !this.active && (this.lastActivity.getTime() + this.TIMEOUT < System.currentTimeMillis()))
        {
            JimmException.handleException(new JimmException(118, 0));
            this.state = ConnectAction.STATE_ERROR;
        }
        return (this.state == ConnectAction.STATE_ERROR);
    }

    // Returns a number between 0 and 100 (inclusive) which indicates the current progress
    public int getProgress()
    {
        switch (this.state)
        {
        case ConnectAction.STATE_INIT_DONE:
            return 12;
    case STATE_AUTHKEY_REQUESTED:
      return 25;
        case ConnectAction.STATE_CLI_IDENT_SENT:
            return 37;
        case ConnectAction.STATE_CLI_DISCONNECT_SENT:
            return 50;
        case ConnectAction.STATE_CLI_COOKIE_SENT:
            return 62;
        case ConnectAction.STATE_CLI_CHECKROSTER_SENT:
            return 75;
        case ConnectAction.STATE_CLI_REQOFFLINEMSGS_SENT:
            return 87;
        case ConnectAction.STATE_CLI_ACKOFFLINEMSGS_SENT:
            return 100;
        default:
            return (0);
        }
    }
    
    public void onEvent(int eventType)
    {
      switch (eventType)
      {
      case ON_COMPLETE:
        ContactList.activate();
        break;
      }
    }

}
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.