Package net.bnubot.core.digitaltext

Source Code of net.bnubot.core.digitaltext.DTConnection

/**
* This file is distributed under the GPL
* $Id: DTConnection.java 1897 2014-02-12 05:20:57Z scotta $
*/

package net.bnubot.core.digitaltext;

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;

import net.bnubot.core.Connection;
import net.bnubot.core.Profile;
import net.bnubot.core.bncs.ProductIDs;
import net.bnubot.logging.Out;
import net.bnubot.settings.ConnectionSettings;
import net.bnubot.util.BNetInputStream;
import net.bnubot.util.BNetUser;
import net.bnubot.util.ByteArray;
import net.bnubot.util.MirrorSelector;
import net.bnubot.util.StatString;
import net.bnubot.util.crypto.HexDump;
import net.bnubot.util.task.Task;

/**
* @author scotta
*/
public class DTConnection extends Connection {
  private static final String DT_TYPE = "DigitalText";
  private BNetInputStream dtInputStream = null;
  private DataOutputStream dtOutputStream = null;

  public DTConnection(ConnectionSettings cs, Profile p) {
    super(cs, p);
  }

  @Override
  public String getServerType() {
    return DT_TYPE;
  }

  /**
   * Initialize the connection, send game id
   * @throws Exception
   */
  @Override
  protected void initializeConnection(Task connect) throws Exception {
    // Set up DT
    connect.updateProgress("Connecting to DigitalText");
    int port = getPort();
    InetAddress address = MirrorSelector.getClosestMirror(getServer(), port);
    dispatchRecieveInfo("Connecting to " + address + ":" + port + ".");
    socket = new Socket(address, port);
    socket.setKeepAlive(true);
    dtInputStream = new BNetInputStream(socket.getInputStream());
    dtOutputStream = new DataOutputStream(socket.getOutputStream());

    // Connected
    connect.updateProgress("Connected");
  }

  /**
   * Do the login work up to SID_ENTERCHAT
   * @throws Exception
   */
  @Override
  protected boolean sendLoginPackets(Task connect) throws Exception {
    DTPacket p = new DTPacket(this, DTPacketId.PKT_LOGON);
    p.writeNTString(cs.username);
    p.writeNTString(cs.password);
    p.sendPacket(dtOutputStream);

    while(isConnected() && !socket.isClosed() && !disposed) {
      if(dtInputStream.available() <= 0) {
        sleep(200);
      } else {
        DTPacketReader pr = new DTPacketReader(dtInputStream);
        BNetInputStream is = pr.getData();

        switch(pr.packetId) {
        case PKT_LOGON: {
          /* (BYTE)   Status
           *
           * Status codes:
           * 0x00 - (C) Passed
           * 0x01 - (A) Failed
           * 0x02 - (C) Account created
           * 0x03 - (A) Account online.
           * Other: Unknown (failure).
           */
          int status = is.readByte();
          switch(status) {
          case 0x00:
            dispatchRecieveInfo("Login accepted.");
            break;
          case 0x01:
            dispatchRecieveError("Login failed");
            disconnect(ConnectionState.LONG_PAUSE_BEFORE_CONNECT);
            break;
          case 0x02:
            dispatchRecieveInfo("Login created.");
            break;
          case 0x03:
            dispatchRecieveError("That account is already logged in.");
            disconnect(ConnectionState.LONG_PAUSE_BEFORE_CONNECT);
            break;
          default:
            dispatchRecieveError("Unknown PKT_LOGON status 0x" + Integer.toHexString(status));
            disconnect(ConnectionState.LONG_PAUSE_BEFORE_CONNECT);
            break;
          }

          if(!isConnected())
            break;

          // We are officially logged in!
          sendJoinChannel("x86");

          myUser = new BNetUser(this, cs.username, cs.myRealm);
          dispatchTitleChanged();
          return true;
        }

        default:
          Out.debugAlways(getClass(), "Unexpected packet " + pr.packetId.name() + "\n" + HexDump.hexDump(pr.data));
          break;
        }
      }
    }

    return false;
  }

  /**
   * This method is the main loop after recieving SID_ENTERCHAT
   * @throws Exception
   */
  @Override
  protected void connectedLoop() throws Exception {
    while(isConnected() && !socket.isClosed() && !disposed) {
      long timeNow = System.currentTimeMillis();

      //Send null packets every 30 seconds
      if(true) {
        long timeSinceNullPacket = timeNow - lastNullPacket;
        //Wait 30 seconds
        timeSinceNullPacket /= 1000;
        if(timeSinceNullPacket > 30) {
          lastNullPacket = timeNow;
          DTPacket p = new DTPacket(this, DTPacketId.PKT_NULL);
          p.sendPacket(dtOutputStream);
        }
      }

      //Send anti-idles every 5 minutes
      if((channelName != null) && cs.enableAntiIdle) {
        synchronized(profile) {
          long timeSinceAntiIdle = timeNow - profile.lastAntiIdle;

          //Wait 5 minutes
          timeSinceAntiIdle /= 1000;
          timeSinceAntiIdle /= 60;
          if(timeSinceAntiIdle >= cs.antiIdleTimer) {
            profile.lastAntiIdle = timeNow;
            sendChatInternal(getAntiIdle());
          }
        }
      }

      if(dtInputStream.available() <= 0) {
        sleep(200);
      } else {
        DTPacketReader pr = new DTPacketReader(dtInputStream);
        BNetInputStream is = pr.getData();

        switch(pr.packetId) {
        case PKT_ENTERCHANNEL: {
          /* (CString)   Channel
           * (UInt32)  Flags
           * (CString)  MOTD
           *
           * Flags:
           * 0x01 : Registered
           * 0x02 : Silent
           * 0x04 : Admin
           */

          String channel = is.readNTString();
          int flags = is.readDWord();
          String motd = is.readNTString();

          dispatchJoinedChannel(channel, flags);
          dispatchRecieveInfo(motd);
          break;
        }

        case PKT_CHANNELUSERS: {
          /* (Byte)    User Count
           * (void)    User Data
           *
           * For each user...
           *   (CString)  Username
           *   (UInt32)  Flags
           *
           * User Flags:
           * 0x01 : Operator
           * 0x02 : Ignored
           * 0x04 : Admin
           * 0x08 : NetOp
           */
          int numUsers = is.readByte();
          for(int i = 0; i < numUsers; i++) {
            String username = is.readNTString();
            int flags = is.readDWord();

            dispatchChannelUser(findCreateBNUser(username, flags));
          }
          break;
        }

        case PKT_USERUPDATE: {
          /* (CString)  Username
           * (UInt32)  Flags
           */
          String username = is.readNTString();
          int flags = is.readDWord();

          dispatchChannelUser(findCreateBNUser(username, flags));
          break;
        }

        case PKT_CHANNELJOIN: {
          /* (CString)  Username
           * (UInt32)  Flags
           */
          String username = is.readNTString();
          int flags = is.readDWord();

          dispatchChannelJoin(findCreateBNUser(username, flags));
          break;
        }

        case PKT_CHANNELLEAVE: {
          /* (CString)  Username
           */
          String username = is.readNTString();

          dispatchChannelLeave(findCreateBNUser(username, null));
          break;
        }

        case PKT_CHANNELCHAT: {
          /* (Byte)    Chat Type
           * (CString)  From
           * (CString)  Message
           *
           * Chat Type values:
           * 0x00 : Normal
           * 0x01 : Self Talking
           * 0x02 : Whisper To
           * 0x03 : Whisper From
           * 0x04 : Emote
           * 0x05 : Self Emote
           */
          int chatType = is.readByte();
          String username = is.readNTString();
          ByteArray text = new ByteArray(is.readNTBytes());

          // Get a BNetUser object for the user
          BNetUser user = null;
          if(myUser.equals(username))
            user = myUser;
          else
            user = getCreateBNetUser(username, myUser);

          switch(chatType) {
          case 0x00: // Normal
          case 0x01: // Self talking
            dispatchRecieveChat(user, text);
            break;
          case 0x02: // Whisper to
            dispatchWhisperSent(user, text.toString());
            break;
          case 0x03: // Whisper from
            dispatchWhisperRecieved(user, text.toString());
            break;
          case 0x04: // Emote
          case 0x05: // Self Emote
            dispatchRecieveEmote(user, text.toString());
            break;
          default:
            Out.debugAlways(getClass(), "Unexpected chat type 0x" + Integer.toHexString(chatType) + " from " + username + ": " + text);
            break;
          }

          break;
        }

        case PKT_UNKNOWN_0x22: {
          int unknown = is.readDWord();
          String text = is.readNTString();
          switch(unknown) {
          case 0x00:
            dispatchRecieveInfo(text);
            break;
          case 0x01:
            dispatchRecieveError(text);
            break;
          default:
            Out.debugAlways(getClass(), "0x" + Integer.toHexString(unknown) + ": " + text);
            break;
          }
          break;
        }

        default:
          Out.debugAlways(getClass(), "Unexpected packet " + pr.packetId.name() + "\n" + HexDump.hexDump(pr.data));
          break;
        }
      }
    }
  }

  /**
   * Find or create a BNetUser
   * @param username The user's name
   * @param flags Flags to mangle and set
   * @return BNetUser describing the person
   */
  private BNetUser findCreateBNUser(String username, Integer userFlags) {
    // Create the BNetUser
    BNetUser user = getCreateBNetUser(username, myUser);

    // Flags
    if(userFlags != null) {
      int flags = userFlags.intValue();
      // Make flags look like bnet flags
      int bnflags = 0x10// No UDP
      if((flags & 0x10) != 0// Voiced -> Speaker
        bnflags |= 0x04;
      if((flags & 0x08) != 0// NetOp -> Blizzard Rep
        bnflags |= 0x01;
      if((flags & 0x04) != 0// Admin -> B.net Rep
        bnflags |= 0x08;
      if((flags & 0x02) != 0// Ignored -> Squelched
        bnflags |= 0x20;
      if((flags & 0x01) != 0// Operator
        bnflags |= 0x02;
      user.setFlags(bnflags);
    }

    // StatString
    if(user.getStatString() == null)
      user.setStatString(new StatString("TAHC"));

    return user;
  }

  @Override
  public boolean isOp() {
    return (myUser.getFlags() & 0x02) == 0x02;
  }

  /**
   * Send SID_JOINCHANNEL
   */
  @Override
  public void sendJoinChannel(String channel) throws Exception {
    DTPacket p = new DTPacket(this, DTPacketId.PKT_ENTERCHANNEL);
    p.writeNTString(channel);
    p.sendPacket(dtOutputStream);
  }

  /**
   * Send SID_JOINCHANNEL with create channel flag
   */
  @Override
  public void sendJoinChannel2(String channel) throws Exception {
    sendJoinChannel(channel);
  }

  /**
   * Send SID_CHATCOMMAND
   */
  @Override
  public void sendChatCommand(ByteArray text) {
    super.sendChatCommand(text);

    //Write the packet
    try {
      DTPacket p = new DTPacket(this, DTPacketId.PKT_CHANNELCHAT);
      p.writeNTString(text);
      p.sendPacket(dtOutputStream);
    } catch(IOException e) {
      Out.exception(e);
      disconnect(ConnectionState.ALLOW_CONNECT);
      return;
    }
  }

  @Override
  public String toString() {
    if(myUser == null)
      return toShortString();

    String out = myUser.getShortLogonName();
    if(channelName != null)
      out += " - [ #" + channelName + " ]";
    return out;
  }

  @Override
  public ProductIDs getProductID() {
    return ProductIDs.CHAT;
  }
}
TOP

Related Classes of net.bnubot.core.digitaltext.DTConnection

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.