/*******************************************************************************
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 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/Icq.java
Version: ###VERSION### Date: ###DATE###
Author: Manuel Linsmayer, Andreas Rossbacher
*******************************************************************************/
// #sijapp cond.if protocols_ICQ is "true" #
package protocol.icq;
import java.io.*;
import java.util.*;
import jimm.chat.message.*;
import jimm.comm.*;
import jimm.forms.*;
import jimm.search.UserInfo;
import protocol.icq.action.*;
import protocol.icq.packet.*;
import jimm.search.Search;
import jimm.util.JLocale;
import jimm.*;
import protocol.*;
import protocol.icq.plugin.*;
import protocol.ui.InfoFactory;
import protocol.ui.StatusInfo;
import protocol.ui.StatusView;
import protocol.ui.XStatusInfo;
public class Icq extends Protocol {
private IcqNetWorking connection = null;
// #sijapp cond.if modules_XSTATUSES is "true" #
public static final IcqXStatus xstatus = new IcqXStatus();
// #sijapp cond.end #
public static final byte PSTATUS_ALL = 0x01;
public static final byte PSTATUS_NONE = 0x02;
public static final byte PSTATUS_VISIBLE_ONLY = 0x03;
public static final byte PSTATUS_NOT_INVISIBLE = 0x04;
public static final byte PSTATUS_CL_ONLY = 0x05;
// #sijapp cond.if modules_SERVERLISTS is "true" #
private Vector<PrivacyItem> ignoreList = new Vector<PrivacyItem>();
private Vector<PrivacyItem> invisibleList = new Vector<PrivacyItem>();
private Vector<PrivacyItem> visibleList = new Vector<PrivacyItem>();
// #sijapp cond.end #
public Icq() {
}
public String getUserIdName() {
return "UIN";
}
@Override
public boolean isEmpty() {
return super.isEmpty() || ((0 == Util.strToIntDef(getUserId(), 0)) && (getUserId().indexOf('@') <= 0));
}
public final void setRealUin(String uin) {
if (!StringUtils.isEmpty(uin)) {
setUserId(uin);
}
}
public void requestSimpleAction(IcqAction act) {
if (null != connection) {
connection.requestAction(act);
}
}
private void requestSimpleAction(Packet pkt) {
requestSimpleAction(new OtherAction(pkt));
}
/**
* Construct plain message object and request new SendMessageAction
* Add the new message to the chat history
*/
protected void sendSomeMessage(PlainMessage msg) {
msg.setMessageId(Util.uniqueValue());
// Get UIN
byte[] uinRaw = StringUtils.stringToByteArray(msg.getRcvrUin());
String text = StringUtils.restoreCrLf(msg.getText());
OutStream buffer = new OutStream();
if (true) {
byte[] textRaw = StringUtils.stringToUcs2beByteArray(text);
buffer.writeDWordBE(msg.getMessageId()); // CLI_SENDMSG.TIME
buffer.writeDWordBE(0x00000000); // CLI_SENDMSG.ID
buffer.writeWordBE(0x0001); // CLI_SENDMSG.FORMAT
buffer.writeByte(uinRaw.length); // CLI_SENDMSG.UIN
buffer.writeByteArray(uinRaw);
buffer.writeWordBE(0x0002); // CLI_SENDMSG.SUB_MSG_TYPE1
buffer.writeWordBE(5 + 4 + 4 + textRaw.length);
buffer.writeTLVByte(0x0501, 0x01); // SUB_MSG_TYPE1.CAPABILITIES
buffer.writeWordBE(0x0101); // SUB_MSG_TYPE1.MESSAGE
buffer.writeWordBE(4 + textRaw.length);
buffer.writeDWordBE(0x00020000); // MESSAGE.ENCODING
buffer.writeByteArray(textRaw); // MESSAGE.MESSAGE
} else {
byte[] textRaw = StringUtils.stringToByteArrayUtf8(text);
OutStream tlv1127 = new OutStream();
// Put 0x1b00
tlv1127.writeWordLE(0x001B); // length
// Put ICQ protocol version in LE
tlv1127.writeWordLE(0x0008);
// Put capablilty (16 zero bytes)
tlv1127.writeDWordBE(0x00000000);
tlv1127.writeDWordBE(0x00000000);
tlv1127.writeDWordBE(0x00000000);
tlv1127.writeDWordBE(0x00000000);
// Put some unknown stuff
tlv1127.writeWordLE(0x0000);
tlv1127.writeByte(0x03);
// Set the DC_TYPE to "normal" if we send a file transfer request
tlv1127.writeDWordBE(0x00000000);
// Put cookie, unkown 0x0e00 and cookie again
final int SEQ1 = 0xffff;
tlv1127.writeWordLE(SEQ1);
tlv1127.writeWordLE(0x000E); // length
tlv1127.writeWordLE(SEQ1);
// Put 12 unknown zero bytes
tlv1127.writeDWordLE(0x00000000);
tlv1127.writeDWordLE(0x00000000);
tlv1127.writeDWordLE(0x00000000);
tlv1127.writeWordLE(0x0001); // Put message type
tlv1127.writeWordLE(0); // Put contact statu
// Put priority
tlv1127.writeWordLE(0x0001);
// Put message
tlv1127.writeWordLE(textRaw.length + 1);
tlv1127.writeByteArray(textRaw);
tlv1127.writeByte(0x00);
// Put foreground, background color and guidlength
tlv1127.writeDWordBE(0x00000000);
tlv1127.writeDWordBE(0x00FFFFFF);
byte[] utf8 = "{0946134E-4C7F-11D1-8222-444553540000}".getBytes();
tlv1127.writeDWordLE(utf8.length);
tlv1127.writeByteArray(utf8);
OutStream tlv5 = new OutStream();
tlv5.writeWordBE(0x0000);
tlv5.writeDWordBE(msg.getMessageId());
tlv5.writeDWordBE(0x00000000);
tlv5.writeByteArray(GUID.CAP_AIM_SERVERRELAY.toByteArray());
tlv5.writeTLVWord(0x000a, 0x0001);
tlv5.writeTLV(0x000f, null);
// Set TLV 0x2711
tlv5.writeTLV(0x2711, tlv1127.toByteArray());
buffer.writeDWordBE(msg.getMessageId()); // CLI_SENDMSG.TIME
buffer.writeDWordBE(0x00000000); // CLI_SENDMSG.ID
buffer.writeWordBE(0x0002); // CLI_SENDMSG.FORMAT
buffer.writeByte(uinRaw.length); // CLI_SENDMSG.UIN
buffer.writeByteArray(uinRaw);
buffer.writeTLV(0x0005, tlv5.toByteArray());
}
// flag of delivery to server
buffer.writeTLV(0x0003, null);
// store message if recipient offline
buffer.writeTLV(0x0006, null);
// Send packet
byte[] buf = buffer.toByteArray();
connection.addMessage(msg);
requestSimpleAction(new SnacPacket(SnacPacket.CLI_ICBM_FAMILY,
SnacPacket.CLI_SENDMSG_COMMAND, buf));
}
protected void s_addGroup(Group group) {
IcqAction act = new UpdateContactListAction(group,
UpdateContactListAction.ACTION_ADD);
requestSimpleAction(act);
}
// Adds a IcqContact to the server saved contact list
protected void s_addContact(Contact contact) {
// Request contact item adding
IcqAction act = new UpdateContactListAction(this, contact, UpdateContactListAction.ACTION_ADD);
requestSimpleAction(act);
}
/** Connects to the ICQ network */
protected void startConnection() {
connection = new IcqNetWorking();
connection.initNet(this);
connection.start();
}
/** Disconnects from the ICQ network */
protected void closeConnection() {
IcqNetWorking icqState = connection;
connection = null;
if (null != icqState) {
icqState.disconnect();
}
}
// Checks whether the comm. subsystem is in STATE_CONNECTED
public boolean isConnected() {
return (null != connection) && connection.isIcqConnected();
}
// Dels a IcqContact to the server saved contact list
protected void s_removeContact(Contact cItem) {
requestSimpleAction(new UpdateContactListAction(this, cItem,
UpdateContactListAction.ACTION_DEL));
}
/** ********************************************************************* */
@Override
public void doAction(Contact contact, int action) {
switch (action) {
case IcqContact.USER_MENU_REMOVE_ME:
// Remove me from other users contact list
sendRemoveMePacket(contact.getUserId());
Jimm.getJimm().getCL().activate();
break;
// #sijapp cond.if modules_SERVERLISTS is "true" #
case Contact.USER_MENU_PS_VISIBLE:
case Contact.USER_MENU_PS_INVISIBLE:
case Contact.USER_MENU_PS_IGNORE:
int list = IGNORE_LIST;
switch (action) {
case Contact.USER_MENU_PS_VISIBLE:
list = VISIBLE_LIST;
break;
case Contact.USER_MENU_PS_INVISIBLE:
list = INVISIBLE_LIST;
break;
case Contact.USER_MENU_PS_IGNORE:
list = IGNORE_LIST;
break;
}
changeServerList(list, (IcqContact) contact);
Jimm.getJimm().getCL().activate();
break;
// #sijapp cond.end #
}
}
/** ********************************************************************* */
// #sijapp cond.if modules_XSTATUSES is "true" #
public void requestXStatusMessage(Contact c) {
StringBuilder str = new StringBuilder();
str.append("<N><QUERY>");
str.append(Util.xmlEscape("<Q><PluginID>srvMng</PluginID></Q>"));
str.append("</QUERY><NOTIFY>");
str.append(Util.xmlEscape("<srv><id>cAwaySrv</id><req><id>AwayStat</id><trans>1</trans><senderId>"
+ getUserId()
+ "</senderId></req></srv>"));
str.append("</NOTIFY></N>");
XtrazMessagePlugin plugin = new XtrazMessagePlugin((IcqContact)c, str.toString());
requestSimpleAction(plugin.getPacket());
((IcqContact)c).setXStatusMessage("");
updateStatusView(c);
}
// #sijapp cond.end #
/** *********************************************************************** */
public boolean isMeVisible(Contact to) {
// #sijapp cond.if modules_SERVERLISTS is "true" #
switch (getPrivateStatus()) {
case PrivateStatusForm.PSTATUS_NONE:
return false;
case PrivateStatusForm.PSTATUS_NOT_INVISIBLE:
return !to.inInvisibleList();
case PrivateStatusForm.PSTATUS_VISIBLE_ONLY:
return to.inVisibleList();
case PrivateStatusForm.PSTATUS_CL_ONLY:
return !to.isTemp();
}
// #sijapp cond.else #
long status = getProfile().statusIndex;
if ((StatusInfo.STATUS_INVISIBLE == status)
|| (StatusInfo.STATUS_INVIS_ALL == status)) {
return false;
}
// #sijapp cond.end #
return true;
}
public UserInfo getUserInfo(Contact c) {
UserInfo data = new UserInfo(this);
RequestInfoAction getInfoAction = new RequestInfoAction(data, (IcqContact) c);
requestSimpleAction(getInfoAction);
return data;
}
/** *********************************************************************** */
protected void s_updateOnlineStatus() {
byte bCode = getPrivateStatusByStatus();
// #sijapp cond.if modules_SERVERLISTS isnot "true" #
if (-1 == bCode) {
bCode = Icq.PSTATUS_NOT_INVISIBLE;
sendPrivateStatus(bCode);
}
// #sijapp cond.end #
sendCaps();
// #sijapp cond.if modules_XSTATUSES is "true" #
sendNewXStatus();
// #sijapp cond.end #
sendStatus();
// #sijapp cond.if modules_SERVERLISTS isnot "true" #
if (Icq.PSTATUS_NOT_INVISIBLE != bCode) {
sendPrivateStatus(bCode);
}
// #sijapp cond.else #
if (-1 != bCode) {
setPrivateStatus((Icq.PSTATUS_NONE == bCode)
? (byte)PrivateStatusForm.PSTATUS_NONE
: (byte)PrivateStatusForm.PSTATUS_VISIBLE_ONLY);
}
// #sijapp cond.end #
}
// #sijapp cond.if modules_XSTATUSES is "true" #
protected void s_updateXStatus() {
sendCaps();
sendNewXStatus();
}
// #sijapp cond.end #
protected void s_setPrivateStatus() {
sendPrivateStatus(getIcqPrivateStatus());
}
private byte getPrivateStatusByStatus() {
switch (getProfile().statusIndex) {
case StatusInfo.STATUS_INVIS_ALL: return Icq.PSTATUS_NONE;
case StatusInfo.STATUS_INVISIBLE: return Icq.PSTATUS_VISIBLE_ONLY;
}
return -1;
}
public byte getIcqPrivateStatus() {
byte p = getPrivateStatusByStatus();
if (-1 != p) return p;
// #sijapp cond.if modules_SERVERLISTS is "true" #
switch (getPrivateStatus()) {
case PrivateStatusForm.PSTATUS_ALL: return Icq.PSTATUS_ALL;
case PrivateStatusForm.PSTATUS_VISIBLE_ONLY: return Icq.PSTATUS_VISIBLE_ONLY;
case PrivateStatusForm.PSTATUS_NOT_INVISIBLE: return Icq.PSTATUS_NOT_INVISIBLE;
case PrivateStatusForm.PSTATUS_CL_ONLY: return Icq.PSTATUS_CL_ONLY;
case PrivateStatusForm.PSTATUS_NONE: return Icq.PSTATUS_NONE;
}
// #sijapp cond.end #
return Icq.PSTATUS_NOT_INVISIBLE;
}
public int privateStatusId = 0;
private int ssiListLastChangeTime = -1;
private int ssiNumberOfItems = 0;
/* Returns the id number #1 which identifies (together with id number #2)
the saved contact list version */
public int getSsiListLastChangeTime() {
return ssiListLastChangeTime;
}
/* Returns the id number #2 which identifies (together with id number #1)
the saved contact list version */
public int getSsiNumberOfItems() {
return ssiNumberOfItems;
}
public void setContactListInfo(int timestamp, int numberOfItems) {
ssiListLastChangeTime = timestamp;
ssiNumberOfItems = numberOfItems;
}
public Group createGroup(String name) {
Group g = new Group(name);
g.setMode(Group.MODE_FULL_ACCESS);
g.setGroupId(createRandomId());
return g;
}
protected Contact createContact(String uin, String name) {
name = (null == name) ? uin : name;
try {
IcqContact c = new IcqContact(uin);
c.init(-1, Group.NOT_IN_GROUP, name, false);
return c;
} catch (Exception e) {
// Message from non-icq contact
return null;
}
}
private boolean isExistId(final int id) {
if (id == privateStatusId) {
return true;
}
if (null != roster) {
for (int i = roster.groups.size() - 1; i >= 0; --i) {
Group group = (Group)roster.groups.elementAt(i);
if (group.getId() == id) {
return true;
}
}
for (int i = roster.contacts.size() - 1; i >= 0; --i) {
IcqContact item = (IcqContact)roster.contacts.elementAt(i);
if ((item.getContactId() == id)) {
return true;
}
}
}
// #sijapp cond.if modules_SERVERLISTS is "true" #
if (isExistId(invisibleList, id) || isExistId(visibleList, id)
|| isExistId(ignoreList, id)) {
return true;
}
// #sijapp cond.end #
return false;
}
// #sijapp cond.if modules_SERVERLISTS is "true" #
private boolean isExistId(Vector list, int id) {
for (int i = list.size() - 1; 0 <= i; --i) {
if (((PrivacyItem)list.elementAt(i)).id == id) {
return true;
}
}
return false;
}
// #sijapp cond.end #
// Create a random id which is not used yet
public int createRandomId() {
int id;
do {
// Max value is probably 0x7FFF, lowest value is unknown.
// We use range 0x1000-0x7FFF.
// From miranda source
id = Util.nextRandInt() % 0x6FFF + 0x1000;
} while (isExistId(id));
return id;
}
protected void loadProtocolData(byte[] data) throws Exception {
ByteArrayInputStream bais = new ByteArrayInputStream(data);
DataInputStream dis = new DataInputStream(bais);
ssiListLastChangeTime = dis.readInt();
ssiNumberOfItems = dis.readUnsignedShort();
}
protected byte[] saveProtocolData() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(getSsiListLastChangeTime());
dos.writeShort((short)getSsiNumberOfItems());
return baos.toByteArray();
}
protected Contact loadContact(DataInputStream dis) throws Exception {
int contactId = dis.readInt();
int groupId = dis.readInt();
byte flags = dis.readByte();
String uin = dis.readUTF();
String name = dis.readUTF();
// #sijapp cond.if modules_SERVERLISTS is "true" #
int visibleId = dis.readInt();
int invisibleId = dis.readInt();
int ignoreId = dis.readInt();
// #sijapp cond.end #
IcqContact contact = (IcqContact) createContact(uin, name);
contact.setContactId(contactId);
contact.setGroupId(groupId);
contact.setBooleanValues(flags);
contact.setName(name);
// #sijapp cond.if modules_SERVERLISTS is "true" #
setVisibleId(contact, visibleId);
setInvisibleId(contact, invisibleId);
setIgnoreId(contact, ignoreId);
// #sijapp cond.end #
contact.setOfflineStatus();
return contact;
}
protected void saveContact(DataOutputStream out, Contact contact) throws Exception {
IcqContact icqContact = ((IcqContact)contact);
out.writeByte(0);
out.writeInt(icqContact.getContactId());
out.writeInt(icqContact.getGroupId());
out.writeByte(icqContact.getBooleanValues());
out.writeUTF(icqContact.getUserId());
out.writeUTF(icqContact.getName());
// #sijapp cond.if modules_SERVERLISTS is "true" #
out.writeInt(getVisibleId(icqContact));
out.writeInt(getInvisibleId(icqContact));
out.writeInt(getIgnoreId(icqContact));
// #sijapp cond.end #
}
public void getAvatar(UserInfo userInfo) {
new jimmui.view.timers.GetVersion(userInfo).get();
}
protected void s_searchUsers(Search cont) {
String userId = cont.getSearchParam(Search.UIN);
if (null != userId) {
UserInfo userInfo = new UserInfo(this);
userInfo.uin = userId;
cont.addResult(userInfo);
cont.finished();
} else {
requestSimpleAction(new SearchAction(cont));
}
}
protected void s_removeGroup(Group group) {
requestSimpleAction(new UpdateContactListAction(group, UpdateContactListAction.ACTION_DEL));
}
protected void s_renameGroup(Group group, String name) {
group.setName(name);
IcqAction act = new UpdateContactListAction(group, UpdateContactListAction.ACTION_RENAME);
requestSimpleAction(act);
}
/* Sets new contact name */
protected void s_renameContact(Contact contact, String name) {
contact.setName(name);
/* Try to save ContactList to server */
requestSimpleAction(new UpdateContactListAction(this, contact,
UpdateContactListAction.ACTION_RENAME));
}
protected void s_moveContact(Contact contact, Group to) {
requestSimpleAction(new UpdateContactListAction(contact, getGroup(contact), to));
}
public void saveUserInfo(UserInfo userInfo) {
requestSimpleAction(makeSaveInfoPacket(userInfo));
}
private ToIcqSrvPacket makeSaveInfoPacket(UserInfo userInfo) {
OutStream stream = new OutStream();
/* 0x0C3A */
stream.writeWordLE(ToIcqSrvPacket.CLI_SET_FULLINFO);
stream.writeProfileAsciizTLV(NICK_TLV_ID, userInfo.nick);
stream.writeProfileAsciizTLV(FIRSTNAME_TLV_ID, userInfo.firstName);
stream.writeProfileAsciizTLV(LASTNAME_TLV_ID, userInfo.lastName);
stream.writeProfileAsciizTLV(CITY_TLV_ID, userInfo.homeCity);
stream.writeProfileAsciizTLV(STATE_TLV_ID, userInfo.homeState);
stream.writeProfileAsciizTLV(HOME_PAGE_TLD, userInfo.homePage);
stream.writeProfileAsciizTLV(WORK_COMPANY_TLV, userInfo.workCompany);
stream.writeProfileAsciizTLV(WORK_DEPARTMENT_TLV, userInfo.workDepartment);
stream.writeProfileAsciizTLV(WORK_POSITION_TLV, userInfo.workPosition);
/* Birsday */
if (userInfo.birthDay != null) {
String[] bDate = Util.explode(userInfo.birthDay, '.');
try {
if (bDate.length == 3) {
int year = Integer.parseInt(bDate[2]);
int month = Integer.parseInt(bDate[1]);
int day = Integer.parseInt(bDate[0]);
stream.writeWordLE(BDAY_TLV_ID);
stream.writeWordLE(6);
stream.writeWordLE(year);
stream.writeWordLE(month);
stream.writeWordLE(day);
}
} catch (Exception ignored) {
}
}
/* Gender */
stream.writeWordLE(GENDER_TLV_ID);
stream.writeWordLE(1);
stream.writeByte(userInfo.gender);
/* Email */
stream.writeTlvECombo(EMAIL_TLV_ID, userInfo.email, 0);
return new ToIcqSrvPacket(0, getUserId(),
ToIcqSrvPacket.CLI_META_SUBCMD, new byte[0], stream.toByteArray());
}
//TLVs
private static final int NICK_TLV_ID = 0x0154;
private static final int FIRSTNAME_TLV_ID = 0x0140;
private static final int LASTNAME_TLV_ID = 0x014A;
private static final int EMAIL_TLV_ID = 0x015E;
private static final int BDAY_TLV_ID = 0x023A;
private static final int GENDER_TLV_ID = 0x017C;
private static final int HOME_PAGE_TLD = 0x0213;
private static final int CITY_TLV_ID = 0x0190;
private static final int STATE_TLV_ID = 0x019A;
private static final int WORK_COMPANY_TLV = 0x01AE;
private static final int WORK_DEPARTMENT_TLV = 0x01B8;
private static final int WORK_POSITION_TLV = 0x01C2;
protected void s_sendTypingNotify(Contact to, boolean isTyping) {
sendBeginTyping(to, isTyping);
}
/** ************************************************************************* */
public SnacPacket getStatusPacket() {
long status = 0x10000000 | IcqStatusInfo.getNativeStatus(getProfile().statusIndex);
// Send a CLI_SETSTATUS packet
byte[] data = new byte[4 + 4 + 4 + 0x25];//CLI_SETSTATUS_DATA;
Util.putDWordBE(data, 0, 0x00060004);
Util.putDWordBE(data, 4, status);
Util.putDWordBE(data, 8, 0x000C0025);
Util.putDWordBE(data, 23, 0xE36C96A9);
Util.putWordBE (data, 21, 0x0009);
Util.putDWordBE(data, 35, 0xFFFFFFFE);
Util.putDWordBE(data, 39, 0x00100000);
Util.putDWordBE(data, 43, 0xFFFFFFFE);
return new SnacPacket(SnacPacket.SERVICE_FAMILY, SnacPacket.CLI_SETSTATUS_COMMAND, data);
}
public SnacPacket getCapsPacket() {
Vector<GUID> guids = new Vector<GUID>();
guids.addElement(GUID.CAP_AIM_ISICQ);
guids.addElement(GUID.CAP_AIM_SERVERRELAY);
// #sijapp cond.if modules_XSTATUSES is "true" #
guids.addElement(GUID.CAP_XTRAZ);
// #sijapp cond.end #
guids.addElement(GUID.CAP_JIMM);
guids.addElement(GUID.CAP_UTF8);
// #sijapp cond.if modules_XSTATUSES is "true" #
GUID x = Icq.xstatus.getIcqGuid(getProfile().xstatusIndex);
if (null != x) {
guids.addElement(x);
}
// #sijapp cond.end #
if (Options.getInt(Options.OPTION_TYPING_MODE) > 0) {
guids.addElement(GUID.CAP_MTN);
}
// Send a CLI_SETUSERINFO packet
// Set version information to this packet in our capability
byte extStatus = IcqStatusInfo.getExtStatus(getProfile().statusIndex);
int extStatusCount = (0 == extStatus ? 0 : 1);
int guidsCount = guids.size() + extStatusCount;
byte[] packet = new byte[guidsCount * 16 + 4];
packet[0] = 0x00;
packet[1] = 0x05;
packet[2] = (byte)((guidsCount * 16) / 0x0100);
packet[3] = (byte)((guidsCount * 16) % 0x0100);
if (0 != extStatus) {
System.arraycopy(GUID.CAP_QIP_STATUS.toByteArray(), 0, packet, 4, 16);
Util.putByte(packet, 4 + 15, extStatus); // status
}
for (int i = extStatusCount; i < guidsCount; ++i) {
System.arraycopy(((GUID)guids.elementAt(i - extStatusCount)).toByteArray(), 0, packet, i * 16 + 4, 16);
}
return new SnacPacket(SnacPacket.LOCATION_FAMILY, SnacPacket.CLI_SETUSERINFO_COMMAND, packet);
}
public SnacPacket getPrivateStatusPacket(byte status) {
int id = privateStatusId;
int cmd = SnacPacket.CLI_ROSTERUPDATE_COMMAND;
if (id == 0) {
id = createRandomId();
cmd = SnacPacket.CLI_ROSTERADD_COMMAND;
privateStatusId = id;
}
OutStream stream = new OutStream();
stream.writeWordBE(0); // name (null)
stream.writeWordBE(0); // GroupID
stream.writeWordBE(id); // EntryID
stream.writeWordBE(4); // EntryType
stream.writeWordBE(5); // Length in bytes of following TLV
stream.writeTLVByte(0xCA, status);
return new SnacPacket(SnacPacket.SSI_FAMILY, cmd, stream.toByteArray());
}
private void sendCaps() {
requestSimpleAction(getCapsPacket());
}
private void sendStatus() {
long status = 0x10000000 | IcqStatusInfo.getNativeStatus(getProfile().statusIndex);
OutStream data = new OutStream();
data.writeTLVDWord(0x0006, status);
SnacPacket p = new SnacPacket(SnacPacket.SERVICE_FAMILY, SnacPacket.CLI_SETSTATUS_COMMAND, data.toByteArray());
requestSimpleAction(p);
}
private void sendPrivateStatus(byte status) {
requestSimpleAction(getPrivateStatusPacket(status));
}
private static final byte[] MTN_PACKET_BEGIN = {
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x01
};
private void sendBeginTyping(Contact contact, boolean isTyping) {
OutStream stream = new OutStream();
stream.writeByteArray(MTN_PACKET_BEGIN);
stream.writeShortLenAndUtf8String(contact.getUserId());
stream.writeWordBE(isTyping ? 0x0002 : 0x0000);
SnacPacket snacPkt = new SnacPacket(0x0004, 0x0014, stream.toByteArray());
requestSimpleAction(snacPkt);
}
// #sijapp cond.if modules_XSTATUSES is "true" #
private void addMoodToStatus(OutStream out, int xStatus, String msg) {
int moodIndex = Icq.xstatus.getIcqMood(xStatus);
String mood = (moodIndex < 0) ? "" : ("0icqmood" + moodIndex);
msg = (msg.length() < 250) ? msg : (msg.substring(0, 250 - 3) + "...");
/* xStatus */
byte[] moodArr = StringUtils.stringToByteArrayUtf8(mood);
byte[] xMsgArr = StringUtils.stringToByteArrayUtf8(msg);
int xMsgLen = (0 == xMsgArr.length) ? 0 : (2 + xMsgArr.length + 2);
int tlvLen = (2 + 1 + 1 + xMsgLen)
+ (2 + 1 + 1 + moodArr.length);
// TLV (0x1D)
out.writeWordBE(0x1D);
out.writeWordBE(tlvLen);
// subTLV 0x000E (mood)
out.writeWordBE(0x000E);
out.writeWordBE(moodArr.length);
out.writeByteArray(moodArr);
// subTLV 0x0002 (text)
out.writeWordBE(0x0002);
out.writeByte(0x04);
out.writeByte(xMsgLen);
if (0 < xMsgLen) {
out.writeWordBE(xMsgArr.length);
out.writeByteArray(xMsgArr);
out.writeWordBE(0x0000);
}
}
public SnacPacket getNewXStatusPacket(int xStatus, String msg) {
OutStream mood = new OutStream();
addMoodToStatus(mood, xStatus, msg.trim());
return new SnacPacket(SnacPacket.SERVICE_FAMILY,
SnacPacket.CLI_SETSTATUS_COMMAND, mood.toByteArray());
}
private void sendNewXStatus() {
int index = getProfile().xstatusIndex;
String title = getProfile().xstatusTitle;
String desc = getProfile().xstatusDescription;
title = StringUtils.notNull(title);
desc = StringUtils.notNull(desc);
String text = (title + " " + desc).trim();
requestSimpleAction(getNewXStatusPacket(index, text));
}
// #sijapp cond.end#
void sendRemoveMePacket(String uin) {
byte[] uinRaw = StringUtils.stringToByteArray(uin);
byte[] buf = new byte[1 + uinRaw.length];
// Assemble the packet
Util.putByte(buf, 0, uinRaw.length);
System.arraycopy(uinRaw, 0, buf, 1, uinRaw.length);
SnacPacket pkt = new SnacPacket(SnacPacket.SSI_FAMILY,
SnacPacket.CLI_REMOVEME_COMMAND, 0x00000003, buf);
requestSimpleAction(pkt);
}
/** ************************************************************************* */
// #sijapp cond.if modules_SERVERLISTS is "true" #
private static final int VISIBLE_LIST = 0x0002;
private static final int INVISIBLE_LIST = 0x0003;
private static final int IGNORE_LIST = 0x000E;
private static final int ADD_INTO_LIST = 0;
private static final int REMOVE_FROM_LIST = 1;
private void changeServerList(int list, IcqContact item) {
int id = 0;
switch (list) {
case VISIBLE_LIST:
id = getVisibleId(item);
break;
case INVISIBLE_LIST:
id = getInvisibleId(item);
break;
case IGNORE_LIST:
id = getIgnoreId(item);
break;
}
int subaction;
if (id == 0) {
id = createRandomId();
subaction = ADD_INTO_LIST;
} else {
subaction = REMOVE_FROM_LIST;
}
OutStream stream = new OutStream();
stream.writeLenAndUtf8String(item.getUserId());
stream.writeWordBE(0);
stream.writeWordBE(id);
stream.writeWordBE(list);
stream.writeWordLE(0);
SnacPacket packet = null;
switch (subaction) {
case ADD_INTO_LIST:
packet = new SnacPacket(SnacPacket.SSI_FAMILY, SnacPacket.CLI_ROSTERADD_COMMAND, stream.toByteArray());
break;
case REMOVE_FROM_LIST:
packet = new SnacPacket(SnacPacket.SSI_FAMILY, SnacPacket.CLI_ROSTERDELETE_COMMAND, stream.toByteArray());
id = 0;
break;
}
requestSimpleAction(packet);
switch (list) {
case VISIBLE_LIST:
setVisibleId(item, id);
break;
case INVISIBLE_LIST:
setInvisibleId(item, id);
break;
case IGNORE_LIST:
setIgnoreId(item, id);
break;
}
ui_updateContact(item);
}
public void setPrivacyLists(Vector<PrivacyItem> ignore, Vector<PrivacyItem> invisible, Vector<PrivacyItem> visible) {
ignoreList = ignore;
invisibleList = invisible;
visibleList = visible;
}
private void setIgnoreId(IcqContact c, int id) {
setPrivacy(ignoreList, c, Contact.SL_IGNORE, id);
}
private void setVisibleId(IcqContact c, int id) {
setPrivacy(visibleList, c, Contact.SL_VISIBLE, id);
}
private void setInvisibleId(IcqContact c, int id) {
setPrivacy(invisibleList, c, Contact.SL_INVISIBLE, id);
}
private void setPrivacy(Vector<PrivacyItem> list, Contact c, byte l, int id) {
PrivacyItem item = getListItem(list, c);
if (0 == id) {
invisibleList.removeElement(item);
} else if (null == item) {
item = new PrivacyItem(c.getUserId(), id);
list.addElement(item);
} else {
item.id = id;
}
c.setBooleanValue(l, id != 0);
}
private PrivacyItem getListItem(Vector list, Contact c) {
String uin = c.getUserId();
PrivacyItem item;
for (int i = list.size() - 1; 0 <= i; --i) {
item = (PrivacyItem)list.elementAt(i);
if (uin.equals(item.userId)) {
item.userId = uin;
return item;
}
}
return null;
}
public int getIgnoreId(Contact c) {
PrivacyItem item = getListItem(ignoreList, c);
return (null == item) ? 0 : item.id;
}
public int getVisibleId(Contact c) {
PrivacyItem item = getListItem(visibleList, c);
return (null == item) ? 0 : item.id;
}
public int getInvisibleId(Contact c) {
PrivacyItem item = getListItem(invisibleList, c);
return (null == item) ? 0 : item.id;
}
// #sijapp cond.end #
/** ************************************************************************* */
private void sendAuthResult(String userId, boolean confirm) {
OutStream stream = new OutStream();
stream.writeShortLenAndUtf8String(userId);
stream.writeByte(confirm ? 0x01 : 0x00);
stream.writeLenAndUtf8String("" /* reason */);
// Send a CLI_AUTHORIZE packet
requestSimpleAction(new SnacPacket(SnacPacket.SSI_FAMILY,
SnacPacket.CLI_AUTHORIZE_COMMAND, 0x0000001A,
stream.toByteArray()));
}
protected void requestAuth(String userId) {
final String reason = "";
OutStream stream = new OutStream();
stream.writeShortLenAndUtf8String(userId);
stream.writeLenAndUtf8String(reason);
stream.writeWordBE(0x0000);
// Send a CLI_REQUAUTH packet
requestSimpleAction(new SnacPacket(SnacPacket.SSI_FAMILY,
SnacPacket.CLI_REQAUTH_COMMAND, 0x00000018,
stream.toByteArray()));
}
@Override
public void grandAuth(String userId) {
sendAuthResult(userId, true);
}
@Override
public void denyAuth(String userId) {
sendAuthResult(userId, false);
}
public void showUserInfo(Contact contact) {
final UserInfo data;
if (isConnected()) {
data = getUserInfo(contact);
data.createProfileView(contact.getName());
data.setProfileViewToWait();
} else {
data = new UserInfo(this);
data.nick = contact.getName();
data.uin = contact.getUserId();
data.createProfileView(contact.getName());
data.updateProfileView();
}
data.showProfile();
}
public void showStatus(Contact contact) {
StatusView statusView = Jimm.getJimm().getStatusView();
_updateStatusView(statusView, contact);
statusView.showIt();
// #sijapp cond.if modules_XSTATUSES is "true" #
if ((XStatusInfo.XSTATUS_NONE != contact.getXStatusIndex())
&& (null == contact.getXStatusText())
&& isMeVisible(contact)) {
requestXStatusMessage(contact);
}
// #sijapp cond.end #
}
public void updateStatusView(Contact contact) {
StatusView statusView = Jimm.getJimm().getStatusView();
if (contact == statusView.getContact()) {
_updateStatusView(statusView, contact);
}
}
private void _updateStatusView(StatusView statusView, Contact contact) {
statusView.init(this, contact);
statusView.initUI();
statusView.addContactStatus();
if (contact.isOnline()) {
if (((IcqContact)contact).happyFlag) {
statusView.addPlain(InfoFactory.happyIcon,
JLocale.getString("status_happy_flag"));
}
String statusText = contact.getStatusText();
if (!StringUtils.isEmpty(statusText)) {
statusView.addStatusText(statusText);
}
// #sijapp cond.if modules_XSTATUSES is "true" #
if (XStatusInfo.XSTATUS_NONE != contact.getXStatusIndex()) {
statusView.addXStatus();
String xText = contact.getXStatusText();
if (!StringUtils.isEmpty(xText)) {
statusView.addStatusText(xText);
}
}
// #sijapp cond.end #
}
// #sijapp cond.if modules_CLIENTS is "true" #
statusView.addClient();
// #sijapp cond.end #
statusView.addTime();
statusView.update();
}
}
// #sijapp cond.end #