private BNetPacketReader obtainPacket() throws IOException {
   byte magic;
   do {
     magic = BNInputStream.readByte();
   } while (magic != (byte) 0xFF);
   try {
     return new BNetPacketReader(BNInputStream);
   } catch (SocketTimeoutException e) {
     throw new IOException("Unexpected socket timeout while reading packet", e);
   }
 }
  private void BNetChat() throws Exception {
    while (!socket.isClosed()) {
      BNetPacketReader pr;
      try {
        pr = obtainPacket();
      } catch (SocketTimeoutException e) {
        continue;
      } catch (SocketException e) {
        if (socket == null) break;
        if (socket.isClosed()) break;
        throw e;
      }

      BNetInputStream is = pr.getData();
      switch (pr.packetId) {
        case SID_CHATEVENT:
          {
            BNetChatEventId eid = BNetChatEventId.values()[is.readDWord()];
            int flags = is.readDWord();
            int ping = is.readDWord();
            is.skip(12);
            String username = is.readNTString();
            ByteArray data = null;
            StatString statstr = null;

            System.out.println(username + ":");

            switch (eid) {
              case EID_SHOWUSER:
              case EID_USERFLAGS:
              case EID_JOIN:
              case EID_LEAVE:
              case EID_TALK:
              case EID_EMOTE:
              case EID_WHISPERSENT:
              case EID_WHISPER:
                {
                  System.out.println(is.readNTString());
                  break;
                }
            }
          }
      }
    }
  }
  public void BNetLogin() throws Exception {
    while (!socket.isClosed()) {
      BNetPacketReader pr;
      try {
        pr = obtainPacket();
      } catch (SocketTimeoutException e) {
        continue;
      } catch (SocketException e) {
        if (socket == null) break;
        if (socket.isClosed()) break;
        throw e;
      }

      BNetInputStream is = pr.getData();
      switch (pr.packetId) {
        case SID_OPTIONALWORK:
        case SID_EXTRAWORK:
        case SID_REQUIREDWORK:
          break;
        case SID_NULL:
          {
            BNetProtocolPacket p = new BNetProtocolPacket(BNetProtocolPacketId.SID_NULL);
            p.sendPacket(BNetOutputStream);
            break;
          }

        case SID_PING:
          {
            System.out.println("PONG!");
            BNetProtocolPacket p = new BNetProtocolPacket(BNetProtocolPacketId.SID_PING);
            p.writeDWord(is.readDWord());
            p.sendPacket(BNetOutputStream);
            break;
          }

        case SID_AUTH_INFO:
          {
            if (pr.packetId == BNetProtocolPacketId.SID_AUTH_INFO) {
              nlsRevision = is.readDWord();
              serverToken = is.readDWord();
              is.skip(4); // int udpValue = is.readDWord();
            }
            assert (is.available() == 0);

            BNetProtocolPacket p = new BNetProtocolPacket(BNetProtocolPacketId.SID_AUTH_CHECK);
            p.writeDWord(clientToken); // Client Token
            p.writeDWord(0x1015019c); // EXE Version
            p.writeDWord(0x1b375294); // EXE Hash
            p.writeDWord(1); // Number of CD-Keys
            p.writeDWord(0); // Spawn CD-Key
            p.writeDWord(0x00000000);
            p.writeDWord(0x00000000);
            p.writeDWord(0x00000000);
            p.writeDWord(0x00000000);
            p.writeDWord(0x00000000);
            p.writeDWord(0x00000000);
            p.writeDWord(0x00000000);
            p.writeDWord(0x00000000);
            p.writeDWord(0x00000000);
            p.writeNTString("war3.exe 03/18/11 20:03:55 471040");
            p.writeNTString("Chat");
            p.sendPacket(BNetOutputStream);
            break;
          }

        case SID_AUTH_CHECK:
          {
            int result = is.readDWord();
            String extraInfo = is.readNTString();
            assert (is.available() == 0);

            if (pr.packetId == BNetProtocolPacketId.SID_AUTH_CHECK) {
              if (result != 0) {
                switch (result) {
                  case 0x211:
                    System.out.println("BANNED!" + extraInfo);
                    break;
                  default:
                    System.out.println("Unknown Error" + Integer.toHexString(result));
                    break;
                    // todo: disconnect socket
                }
                System.out.println("Disconnect!" + extraInfo);
                break;
              }
              System.out.println("Passed Check Revision");
            } else {
              if (result != 2) {
                // todo: disconnect socket
                System.out.println("Failed Version Check!");
                break;
              }
              System.out.println("Passed Check Revision");
            }
            sendAuth();
            break;
          }

        case SID_LOGONRESPONSE2:
          {
            int result = is.readDWord();
            switch (result) {
              case 0x00: // Success
                System.out.println("Login successful; entering chat.");
                sendEnterChat();
                sendJoinChannelFirst();
                break;
              case 0x01:
                // todo: disconnect socket
                System.out.println("Account does not Exist");
                break;
              case 0x02:
                // todo: disconnect socket
                System.out.println("Incorrect password.");
                break;
              case 0x06: // Account is closed
                // todo: disconnect socket
                System.out.println("Your account is locked.");
                break;
              default:
                // todo: disconnect socket
                System.out.println("Unknown ERROR.");
                break;
            }
            break;
          }

        case SID_ENTERCHAT:
          {
            String uniqueUserName = is.readNTString();

            BNetChat();
          }
      }
    }
  }