package pl.radical.open.gg.packet.out; import pl.radical.open.gg.GGException; import pl.radical.open.gg.ILocalStatus; import pl.radical.open.gg.packet.GGOutgoingPackage; import pl.radical.open.gg.packet.OutgoingPacket; import pl.radical.open.gg.packet.dicts.GGHashType; import pl.radical.open.gg.packet.dicts.GGStatusFlags; import pl.radical.open.gg.packet.dicts.GGStatuses; import pl.radical.open.gg.packet.dicts.GGVersion; import pl.radical.open.gg.utils.GGConversion; import pl.radical.open.gg.utils.GGUtils; import java.util.Arrays; import org.apache.commons.collections.primitives.ArrayByteList; import org.apache.commons.collections.primitives.ByteList; /** * Login to the Gadu-Gadu network. * * <pre> * struct gg_login80 { * int uin; « numer Gadu-Gadu » * char language[2]; « język: "pl" » * char hash_type; « rodzaj funkcji skrótu hasła » * char hash[64]; « skrót hasła dopełniony \0 » * int status; « początkowy status połączenia » * int flags; « początkowe flagi połączenia » * int features; « opcje protokołu (0x00000367) » * int local_ip; « lokalny adres połączeń bezpośrednich (nieużywany) » * short local_port; « lokalny port połączeń bezpośrednich (nieużywany) » * int external_ip; « zewnętrzny adres (nieużywany) » * short external_port; « zewnętrzny port (nieużywany) » * char image_size; « maksymalny rozmiar grafiki w KB » * char unknown2; « 0x64 » * int version_len; « długość ciągu z wersją (0x23) » * char version[]; « "Gadu-Gadu Client build 10.0.0.10450" (bez \0) » * int description_size; « rozmiar opisu » * char description[]; « opis (nie musi wystąpić, bez \0) » * }; * * <pre> * * @author <a href="mailto:lukasz.rzanek@radical.com.pl>Łukasz Rżanek</a> */ @OutgoingPacket(type = 0x0031, label = "GG_LOGIN80") public class GGLogin80 implements GGOutgoingPackage { public static final int GG_LOGIN80 = 0x0031; /** * Gadu-Gadu number that will be used during logging */ private int uin = -1; /** * Language of the client, default to "pl" */ static final String LANGUAGE = "pl"; /** * Password that will be used during logging */ private char[] password = null; /** * Login hash type that will be used to authenticate the user */ private final GGHashType hashType = GGHashType.GG_LOGIN_HASH_SHA1; /** * Computed login hash based on seed retreived from Gadu-Gadu server */ private byte[] loginHash = null; /** * Initial status that will be set after logging */ private int status = GGStatuses.GG_STATUS_AVAIL; /** * Starting protocols flags */ private final int flags = GGStatusFlags.FLAG_UNKNOWN.getValue() + GGStatusFlags.FLAG_RECEIVELINKS.getValue(); /** * Protocol options - 0x00000367 */ private static final int FEATURES = 0x00000007; /** * Local IP */ private byte[] localIP = new byte[] { (byte) 0, (byte) 0, (byte) 0, (byte) 0 }; /** * Local port that we are listening on */ private int localPort = 0; /** * ExternalIP */ private byte[] externalIP = new byte[] { (byte) 0, (byte) 0, (byte) 0, (byte) 0 }; /** * External port */ private int externalPort = 0; /** * size of image in kilobytes */ private byte imageSize = (byte) -1; /** * Unknown property */ private static final int UNKNOWN2 = 0x64; /** * Version of the client */ private final int version_len = GGVersion.VERSION_60_1_build_133.getCode(); /** * Version descriptive string */ private static final String VERSION = "Gadu-Gadu Client Build 8.0.0.8731";// "Gadu-Gadu Client build 10.0.0.10450"; /** * The length of the status description */ private int descriptionSize; /** * Description that will be set after successfuly logging */ private String description = null; public GGLogin80(final int uin, final char[] password, final int seed) throws GGException { if (uin < 0) { throw new IllegalArgumentException("uin cannot be less than 0"); } if (password == null) { throw new IllegalArgumentException("password cannot be null"); } this.uin = uin; this.password = Arrays.copyOf(password, password.length); loginHash = GGUtils.getLoginHash(password, seed, hashType); } public void setStatus(final ILocalStatus localStatus) { if (localStatus == null) { throw new IllegalArgumentException("localStatus cannot be null"); } status = GGConversion.getProtocolStatus(localStatus, localStatus.isFriendsOnly(), false); if (localStatus.isDescriptionSet()) { description = localStatus.getDescription(); descriptionSize = description.length(); } } public int getUin() { return uin; } public char[] getPassword() { return password; } public void setLocalIP(final byte[] localIP) { if (localIP == null) { throw new IllegalArgumentException("localIP cannot be null"); } if (localIP.length != 4) { throw new IllegalArgumentException("localIp table has to have 4 entries"); } this.localIP = Arrays.copyOf(localIP, localIP.length); } public byte[] getLocalIP() { return localIP; } public void setLocalPort(final int port) { if (port < 0) { throw new IllegalArgumentException("port cannot be null"); } localPort = port; } public int getLocalPort() { return localPort; } public void setExternalIP(final byte[] externalIP) { if (externalIP == null) { throw new IllegalArgumentException("externalIP cannot be null"); } if (externalIP.length != 4) { throw new IllegalArgumentException("externalIP table has to have 4 entries"); } this.externalIP = Arrays.copyOf(externalIP, externalIP.length); } public void setExternalPort(final int externalPort) { if (externalPort < 0) { throw new IllegalArgumentException("port cannot be null"); } this.externalPort = externalPort; } public void setImageSize(final byte imageSize) { if (imageSize < 0) { throw new IllegalArgumentException("imageSize cannot be less than 0"); } this.imageSize = imageSize; } /** * @see pl.radical.open.gg.packet.GGOutgoingPackage#getPacketType() */ @Override public int getPacketType() { return GG_LOGIN80; } /** * @see pl.radical.open.gg.packet.GGOutgoingPackage#getLength() */ @Override public int getLength() { int length = 4 + 2 + 4 + 4 + 4 + 1 + 4 + 2 + 4 + 2 + 1 + 1; if (description != null) { length += description.length() + 1; } return length; } /** * @see pl.radical.open.gg.packet.GGOutgoingPackage#getContents() */ @Override public byte[] getContents() { final ByteList byteList = new ArrayByteList(); byteList.add((byte) uin); byteList.add((byte) (uin >>> 8)); byteList.add((byte) (uin >>> 16)); byteList.add((byte) (uin >>> 24)); byteList.add(LANGUAGE.getBytes()[0]); byteList.add(LANGUAGE.getBytes()[1]); byteList.add((byte) hashType.getValue()); for (int i = 0; i < 64; i++) { if (i < loginHash.length) { byteList.add(loginHash[i]); } else { byteList.add(Character.UNASSIGNED); } } // status byteList.add((byte) status); byteList.add((byte) (status >>> 8)); byteList.add((byte) (status >>> 16)); byteList.add((byte) (status >>> 24)); // flags byteList.add((byte) flags); byteList.add((byte) (flags >>> 8)); byteList.add((byte) (flags >>> 16)); byteList.add((byte) (flags >>> 24)); // FEATURES (?? byte) byteList.add((byte) FEATURES); byteList.add((byte) (FEATURES >>> 8)); byteList.add((byte) (FEATURES >>> 16)); byteList.add((byte) (FEATURES >>> 24)); // local IP byteList.add(localIP[0]); byteList.add(localIP[1]); byteList.add(localIP[2]); byteList.add(localIP[3]); // local port byteList.add((byte) (localPort & 0xFF)); byteList.add((byte) (localPort >> 8 & 0xFF)); // external IP byteList.add(externalIP[0]); byteList.add(externalIP[1]); byteList.add(externalIP[2]); byteList.add(externalIP[3]); // external port byteList.add((byte) (externalPort & 0xFF)); byteList.add((byte) (externalPort >> 8 & 0xFF)); // image size byteList.add(imageSize); // unknown 2 byteList.add((byte) UNKNOWN2); // ? // VERSION length byteList.add((byte) (version_len & 0xFF)); byteList.add((byte) (version_len >> 8 & 0xFF)); byteList.add((byte) (version_len >> 16 & 0xFF)); byteList.add((byte) (version_len >> 24 & 0xFF)); for (final byte b : VERSION.getBytes()) { byteList.add(b); } // description size byteList.add((byte) (descriptionSize & 0xFF)); byteList.add((byte) (descriptionSize >> 8 & 0xFF)); byteList.add((byte) (descriptionSize >> 16 & 0xFF)); byteList.add((byte) (descriptionSize >> 24 & 0xFF)); if (description != null) { final byte[] descBytes = description.getBytes(); for (final byte b : descBytes) { byteList.add(b); } } return byteList.toArray(); } }