/*
* Copyright 2006-2010 Daniel Henninger. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package net.sf.kraken.protocols.oscar;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Locale;
import net.kano.joscar.BinaryTools;
import net.kano.joscar.ByteBlock;
import net.kano.joscar.DefensiveTools;
import net.kano.joscar.flap.FlapCommand;
import net.kano.joscar.snaccmd.auth.ClientVersionInfo;
import net.kano.joscar.tlv.Tlv;
import org.apache.log4j.Logger;
/**
* Representation of an ICQ auth request.
*
* @author Daniel Henninger
* Heavily inspired by AuthRequest.java from the joscar project.
*/
public class LoginICQFlapCmd extends FlapCommand {
static Logger Log = Logger.getLogger(LoginICQFlapCmd.class);
/**
* The FLAP channel on which this command resides.
*/
public static final int CHANNEL_LOGIN = 0x0001;
/**
* I guess this is the FLAP protocol version joscar implements; this is
* what should be sent in a FLAP version command. <code>1</code> is the only
* publically known FLAP protocol version.
*/
public static final long VERSION_DEFAULT = 0x00000001;
/**
* The type of the TLV that contains the cookie block.
*/
private static final int TYPE_COOKIE = 0x0006;
/**
* The version of the FLAP protocol in use.
*/
private final long version;
/**
* The connection cookie.
*/
private final ByteBlock cookie;
/** A TLV type containing the user's uin. */
private static final int TYPE_UIN = 0x0001;
/** A TLV type containing the user's two-letter country code. */
private static final int TYPE_COUNTRY = 0x000e;
/** A TLV type containing the user's two-letter language code. */
private static final int TYPE_LANG = 0x000f;
/** A TLV type containing the user's password, xored. */
private static final int TYPE_XORPASS = 0x0002;
/** The user's UIN (user identification number). */
private final String uin;
/** The user's client version information. */
private final ClientVersionInfo clVersion;
/** The user's locale. */
private final Locale locale;
/** The user's password, encrypted. */
private final ByteBlock encryptedPass;
/**
* Creates a <code>LoginCookieCmd</code> with the {@linkplain
* #VERSION_DEFAULT default FLAP version} and no login cookie.
* @param uin UIN of the username logging in
* @param pass Password of the user logging in
* @param clVersion version for the ICQ client
* @param locale Locale for the connection.
*/
public LoginICQFlapCmd(String uin, String pass, ClientVersionInfo clVersion, Locale locale) {
this(VERSION_DEFAULT, null, uin, pass, clVersion, locale);
}
/**
* Creates a <code>LoginCookieCmd</code> with the given FLAP version and
* no login cookie. This constructor is useful for server developers because
* no login cookie is ever sent by the server; also, no login cookie is sent
* by the client or the server upon initial connection to the login ("auth")
* server.
*
* @param version the FLAP protocol version in use on the FLAP connection on
* which this command will be sent
* @param uin UIN of the username logging in
* @param pass Password of the user logging in
* @param clVersion version for the ICQ client
* @param locale Locale for the connection.
*/
public LoginICQFlapCmd(long version, String uin, String pass, ClientVersionInfo clVersion, Locale locale) {
this(version, null, uin, pass, clVersion, locale);
}
/**
* Creates a <code>LoginCookieCmd</code> with the {@linkplain
* #VERSION_DEFAULT default FLAP version} and the given login cookie.
*
* @param cookie the login cookie for the connection on which this command
* will be sent
* @param uin UIN of the username logging in
* @param pass Password of the user logging in
* @param clVersion version for the ICQ client
* @param locale Locale for the connection.
*/
public LoginICQFlapCmd(ByteBlock cookie, String uin, String pass, ClientVersionInfo clVersion, Locale locale) {
this(VERSION_DEFAULT, cookie, uin, pass, clVersion, locale);
}
/**
* Creates a new <code>LoginCookieCmd</code> with the given FLAP protocol
* version and with the given cookie.
*
* @param version the FLAP protocol version in use
* @param cookie a login "cookie" provided by another OSCAR connection
* @param uin UIN of the username logging in
* @param pass Password of the user logging in
* @param clVersion version for the ICQ client
* @param locale Locale for the connection.
*/
public LoginICQFlapCmd(long version, ByteBlock cookie, String uin, String pass, ClientVersionInfo clVersion, Locale locale) {
super(CHANNEL_LOGIN);
DefensiveTools.checkRange(version, "version", 0);
this.version = version;
this.cookie = cookie;
this.uin = uin;
this.clVersion = clVersion;
this.locale = locale;
this.encryptedPass = ByteBlock.wrap(encryptICQPassword(pass));
Log.debug("Non-encrypted password is "+pass+", Encrypted password is "+encryptedPass);
}
/**
* Encrypts the given password with ICQ's xor key.
* This code is borrowed from JOscarLib (http://sourceforge.net/projects/ooimlib/)
*
* @param pass the user's password
* @return the user's password, encrypted
*/
private byte[] encryptICQPassword(String pass) {
//char charPass[] = new char[pass.length()];
byte encPass[] = new byte[pass.length()];
byte bytePassword[] = pass.getBytes();
final byte[] xorValues = {
(byte) 0xF3, (byte) 0x26, (byte) 0x81, (byte) 0xC4,
(byte) 0x39, (byte) 0x86, (byte) 0xDB, (byte) 0x92
};
for (int i = 0, j; i < bytePassword.length; i++) {
j = i % xorValues.length;
//charPass[i] = (char) ( (byte) (bytePassword[i]) ^ (byte) (xorValues[j]));
encPass[i] = (byte)((bytePassword[i]) ^ (xorValues[j]));
}
return encPass;
}
/**
* Returns the UIN whose login is being attempted.
*
* @return the user's UIN
*/
public final String getUIN() { return uin; }
/**
* Returns the user's client information block.
*
* @return the user's client version information
*/
public final ClientVersionInfo getVersionInfo() { return clVersion; }
/**
* Returns the user's locale.
*
* @return the user's locale
*/
public final Locale getLocale() { return locale; }
/**
* The raw encrypted password sent in this authorization request.
*
* @return the user's password, encrypted
*/
public final ByteBlock getEncryptedPass() { return encryptedPass; }
/**
* Returns the FLAP protocol version declared in this command.
*
* @return the FLAP version of the FLAP connection on which this packet was
* received
*/
public final long getVersion() { return version; }
/**
* Returns the login cookie associated with this command.
*
* @return this command's login cookie
*/
public final ByteBlock getCookie() { return cookie; }
@Override
public void writeData(OutputStream out) throws IOException {
BinaryTools.writeUInt(out, version);
if (cookie != null) new Tlv(TYPE_COOKIE, cookie).write(out);
if (uin != null) {
Tlv.getStringInstance(TYPE_UIN, uin).write(out);
}
if (encryptedPass != null) {
new Tlv(TYPE_XORPASS, encryptedPass).write(out);
}
// write the version TLV's
if (clVersion != null) clVersion.write(out);
if (locale != null) {
String language = locale.getLanguage();
if (!language.equals("")) {
Tlv.getStringInstance(TYPE_LANG, language).write(out);
}
String country = locale.getCountry();
if (!country.equals("")) {
Tlv.getStringInstance(TYPE_COUNTRY, country).write(out);
}
}
}
@Override
public String toString() {
return "LoginICQFlapCmd: "
+ "version=" + version
+ ", cookie=" + cookie + ", uin='" + uin + "'" +
", version='" + version + "'" + ", locale=" + locale;
}
}