/* * Jabber.java * * Created on 12 Июль 2008 г., 19:05 * * To change this template, choose Tools | Template Manager * and open the template in the editor. */ // #sijapp cond.if protocols_JABBER is "true" # package protocol.xmpp; import java.util.Hashtable; import java.util.Vector; import jimm.*; import jimm.chat.message.PlainMessage; import jimm.comm.*; import jimm.forms.ManageContactListForm; import jimm.search.*; import jimmui.view.UIBuilder; import jimmui.view.base.SomeContentList; import jimmui.view.form.Form; import jimmui.view.form.FormListener; import jimmui.view.menu.MenuModel; import jimm.util.JLocale; import protocol.*; import protocol.ui.InfoFactory; import protocol.ui.StatusInfo; import protocol.ui.StatusView; import protocol.ui.XStatusInfo; /** * * @author Vladimir Krukov */ public final class Xmpp extends Protocol implements FormListener { private XmppConnection connection; private Vector<String> rejoinList = new Vector<String>(); private String resource; private ServiceDiscovery disco = null; // #sijapp cond.if modules_XSTATUSES is "true" # public static final XmppXStatus xStatus = new XmppXStatus(); // #sijapp cond.end# private static final String[] bots = {"juick@juick.com", "psto@psto.net"}; public Xmpp() { } public void addRejoin(String jid) { if (!rejoinList.contains(jid)) { rejoinList.addElement(jid); } } public void removeRejoin(String jid) { rejoinList.removeElement(jid); } public void rejoin() { for (int i = 0; i < rejoinList.size(); ++i) { String jid = (String) rejoinList.elementAt(i); XmppServiceContact conf = (XmppServiceContact) getItemByUID(jid); if ((null != conf) && !conf.isOnline()) { join(conf); } } } @Override public boolean isEmpty() { return super.isEmpty() || (getUserId().indexOf('@') <= 0); } @Override public boolean isConnected() { return (null != connection) && connection.isConnected(); } @Override public final boolean isBlogBot(String jid) { for (String bot : bots) { if (bot.equals(jid)) return true; } return false; } @Override protected void startConnection() { connection = new XmppConnection(); connection.setJabber(this); connection.start(); } XmppConnection getConnection() { return connection; } public boolean hasS2S() { switch (getProfile().protocolType) { case Profile.PROTOCOL_FACEBOOK: case Profile.PROTOCOL_ODNOKLASSNIKI: return false; } return true; } @Override public boolean hasVCardEditor() { switch (getProfile().protocolType) { case Profile.PROTOCOL_FACEBOOK: case Profile.PROTOCOL_LJ: case Profile.PROTOCOL_ODNOKLASSNIKI: return false; } return true; } @Override protected final void userCloseConnection() { rejoinList.removeAllElements(); } @Override protected final void closeConnection() { XmppConnection c = connection; connection = null; if (null != c) { c.disconnect(); } } private int getNextGroupId() { while (true) { int id = Util.nextRandInt() % 0x1000; if (null != roster) { for (int i = roster.groups.size() - 1; i >= 0; --i) { Group group = (Group) roster.groups.elementAt(i); if (group.getId() == id) { id = -1; break; } } } if (0 <= id) { return id; } } } public static final String GENERAL_GROUP = "group_general"; public static final String GATE_GROUP = "group_transports"; public static final String CONFERENCE_GROUP = "group_conferences"; @Override public final Group createGroup(String name) { Group group = new Group(name); group.setGroupId(getNextGroupId()); int mode = Group.MODE_FULL_ACCESS; if (JLocale.getString(Xmpp.CONFERENCE_GROUP).equals(name)) { mode &= ~Group.MODE_EDITABLE; mode |= Group.MODE_TOP; } else if (JLocale.getString(Xmpp.GATE_GROUP).equals(name)) { mode &= ~Group.MODE_EDITABLE; mode |= Group.MODE_BOTTOM; } group.setMode(mode); return group; } /** * Create or get group. * * WARNING! This method adds new group to list of group. */ public final Group getOrCreateGroup(String groupName) { if (StringUtils.isEmpty(groupName)) { return null; } Group group = getGroup(groupName); if (null == group) { group = createGroup(groupName); addGroup(group); } return group; } protected final Contact createContact(String jid, String name) { name = (null == name) ? jid : name; jid = Jid.realJidToJimmJid(jid); boolean isGate = (-1 == jid.indexOf('@')); boolean isConference = Jid.isConference(jid); if (isGate || isConference) { XmppServiceContact c = new XmppServiceContact(jid, name); if (c.isConference()) { c.setMyName(getDefaultName()); } else if (isConference /* private */) { XmppServiceContact conf = (XmppServiceContact) getItemByUID(Jid.getBareJid(jid)); if (null != conf) { c.setPrivateContactStatus(conf); c.setMyName(conf.getMyName()); } } return c; } return new XmppContact(jid, name); } private String getDefaultName() { // FIXME: NullPointer String nick = getProfile().nick; if (StringUtils.isEmpty(nick)) { return Jid.getNick(getUserId()); } return nick; } @Override protected void sendSomeMessage(PlainMessage msg) { getConnection().sendMessage(msg); } @Override protected final void s_searchUsers(Search cont) { // FIXME UserInfo userInfo = new UserInfo(this); userInfo.uin = cont.getSearchParam(Search.UIN); if (null != userInfo.uin) { cont.addResult(userInfo); } cont.finished(); } public final static int PRIORITY = 50; @Override protected void s_updateOnlineStatus() { connection.setStatus(getProfile().statusIndex, "", PRIORITY); for (int i = 0; i < rejoinList.size(); ++i) { String jid = (String) rejoinList.elementAt(i); XmppServiceContact c = (XmppServiceContact) getItemByUID(jid); if (null != c) { connection.sendPresence(c); } } } void setConfContactStatus(XmppServiceContact conf, String resource, byte status, String statusText, int role) { conf.__setStatus(resource, role, status, statusText); } void setContactStatus(XmppContact c, String resource, byte status, String text, int priority) { c.__setStatus(resource, priority, status, text); } @Override protected final void s_addedContact(Contact contact) { connection.updateContact((XmppContact) contact); } @Override protected final void s_addGroup(Group group) { } @Override protected final void s_removeGroup(Group group) { } @Override protected final void s_removedContact(Contact contact) { if (!contact.isTemp()) { boolean unregister = Jid.isGate(contact.getUserId()) && !Jid.getDomain(getUserId()).equals(contact.getUserId()); if (unregister) { getConnection().unregister(contact.getUserId()); } connection.removeContact(contact.getUserId()); if (unregister) { getConnection().removeGateContacts(contact.getUserId()); } } if (contact.isOnline() && !contact.isSingleUserContact()) { getConnection().sendPresenceUnavailable(contact.getUserId()); } } @Override protected final void s_renameGroup(Group group, String name) { group.setName(name); connection.updateContacts(roster.contacts); } @Override protected final void s_moveContact(Contact contact, Group to) { contact.setGroup(to); connection.updateContact((XmppContact) contact); } @Override protected final void s_renameContact(Contact contact, String name) { contact.setName(name); connection.updateContact((XmppContact) contact); } @Override public void grandAuth(String uin) { connection.sendSubscribed(uin); } @Override public void denyAuth(String uin) { connection.sendUnsubscribed(uin); } @Override public void autoDenyAuth(String uin) { denyAuth(uin); } @Override public void requestAuth(String uin) { connection.requestSubscribe(uin); } private String getYandexDomain(String domain) { boolean nonPdd = "ya.ru".equals(domain) || "narod.ru".equals(domain) || domain.startsWith("yandex."); return nonPdd ? "xmpp.yandex.ru" : "domain-xmpp.ya.ru"; } String getDefaultServer(String domain) { switch (getProfile().protocolType) { case Profile.PROTOCOL_GTALK: return "talk.google.com"; case Profile.PROTOCOL_FACEBOOK: return "chat.facebook.com"; case Profile.PROTOCOL_LJ: return "livejournal.com"; case Profile.PROTOCOL_YANDEX: return getYandexDomain(domain); case Profile.PROTOCOL_QIP: return "webim.qip.ru"; case Profile.PROTOCOL_ODNOKLASSNIKI: return "xmpp.odnoklassniki.ru"; } return (String) defaultDomains.get(domain); } private static final Hashtable<String, String> defaultDomains = new Hashtable<String, String>(); static { defaultDomains.put("livejournal.com", "livejournal.com"); defaultDomains.put("chat.facebook.com", "chat.facebook.com"); defaultDomains.put("qip.ru", "webim.qip.ru"); defaultDomains.put("gmail.com", "talk.google.com"); defaultDomains.put("ya.ru", "xmpp.yandex.ru"); defaultDomains.put("xmpp.ru", "xmpp.ru"); defaultDomains.put("jabber.ru", "jabber.ru"); } @Override protected String processUin(String uin) { resource = Jid.getResource(uin, "Jimm"); return Jid.getBareJid(uin); } public String getResource() { return resource; } @Override protected void s_setPrivateStatus() { } void removeMe(String uin) { connection.sendUnsubscribed(uin); } public ServiceDiscovery getServiceDiscovery() { if (null == disco) { disco = new ServiceDiscovery(); } disco.setProtocol(this); return disco; } @Override public String getUserIdName() { return "JID"; } // #sijapp cond.if modules_FILES is "true"# @Override public void sendFile(FileTransfer transfer, String filename, String description) { getConnection().setIBB(new IBBFileTransfer(filename, description, transfer)); } // #sijapp cond.end# // #sijapp cond.if modules_XSTATUSES is "true" # @Override protected void s_updateXStatus() { connection.setXStatus(); } // #sijapp cond.end # @Override public void saveUserInfo(UserInfo userInfo) { if (isConnected()) { getConnection().saveVCard(userInfo); } } @Override protected void s_sendTypingNotify(Contact to, boolean isTyping) { if (to instanceof XmppServiceContact) { return; } if (Profile.PROTOCOL_LJ == getProfile().protocolType) { return; } XmppContact c = (XmppContact) to; XmppContact.SubContact s = c.getCurrentSubContact(); if (null != s) { connection.sendTypingNotify(to.getUserId() + "/" + s.resource, isTyping); } } public boolean isContactOverGate(String jid) { if (Jid.isGate(jid)) { return false; } Vector all = getContactItems(); for (int i = all.size() - 1; 0 <= i; --i) { XmppContact c = (XmppContact) all.elementAt(i); if (Jid.isGate(c.getUserId())) { if (jid.endsWith(c.getUserId())) { return true; } } } return false; } public void leave(XmppServiceContact conf) { if (conf.isOnline()) { getConnection().sendPresenceUnavailable(conf.getUserId() + "/" + conf.getMyName()); conf.nickOffline(this, conf.getMyName(), 0, null); // Remove private contacts Vector all = getContactItems(); String conferenceJid = conf.getUserId() + '/'; for (int i = all.size() - 1; 0 <= i; --i) { XmppContact c = (XmppContact) all.elementAt(i); if (c.getUserId().startsWith(conferenceJid) && !c.hasUnreadMessage()) { removeContact(c); } } } } public void join(XmppServiceContact c) { String jid = c.getUserId(); if (!c.isOnline()) { setContactStatus(c, c.getMyName(), StatusInfo.STATUS_ONLINE, "", 0); c.doJoining(); } connection.sendPresence(c); String password = c.getPassword(); if (Jid.isIrcConference(jid) && !StringUtils.isEmpty(password)) { String nickserv = jid.substring(jid.indexOf('%') + 1) + "/NickServ"; connection.sendMessage(nickserv, "/quote NickServ IDENTIFY " + password); connection.sendMessage(nickserv, "IDENTIFY " + password); } } @Override public void doAction(Contact c, int cmd) { XmppContact contact = (XmppContact) c; switch (cmd) { case XmppServiceContact.GATE_CONNECT: getConnection().sendPresence((XmppServiceContact) contact); Jimm.getJimm().getCL().activate(); break; case XmppServiceContact.GATE_DISCONNECT: getConnection().sendPresenceUnavailable(c.getUserId()); Jimm.getJimm().getCL().activate(); break; case XmppServiceContact.GATE_REGISTER: getConnection().register(c.getUserId()); break; case XmppServiceContact.GATE_UNREGISTER: getConnection().unregister(c.getUserId()); getConnection().removeGateContacts(c.getUserId()); Jimm.getJimm().getCL().activate(); break; case XmppServiceContact.GATE_ADD: ManageContactListForm m = new ManageContactListForm(this); m.setXmppGate(c.getUserId()); m.showContactAdd(); break; case XmppServiceContact.USER_MENU_USERS_LIST: if (contact.isOnline() || !isConnected()) { new SomeContentList(new ConferenceParticipants(this, (XmppServiceContact) c), c.getName()).show(); } else { ServiceDiscovery sd = getServiceDiscovery(); sd.setServer(contact.getUserId()); sd.showIt(); } break; case XmppServiceContact.CONFERENCE_CONNECT: join((XmppServiceContact) c); Jimm.getJimm().getChatUpdater().activate(getChatModel(c)); break; case XmppServiceContact.CONFERENCE_OPTIONS: showOptionsForm((XmppServiceContact) c); break; case XmppServiceContact.CONFERENCE_OWNER_OPTIONS: connection.requestOwnerForm(c.getUserId()); break; case XmppServiceContact.CONFERENCE_DISCONNECT: leave((XmppServiceContact) c); Jimm.getJimm().getCL().activate(); break; case XmppServiceContact.CONFERENCE_ADD: addContact(c); Jimm.getJimm().getCL().activate(); break; case XmppContact.USER_MENU_CONNECTIONS: showListOfSubcontacts(contact); break; case XmppContact.USER_MENU_ADHOC: AdHoc adhoc = new AdHoc(this, contact); adhoc.show(); break; case XmppContact.USER_MENU_REMOVE_ME: removeMe(c.getUserId()); Jimm.getJimm().getCL().activate(); break; } } private void showListOfSubcontacts(XmppContact c) { MenuModel sublist = new MenuModel(); int selected = 0; StatusInfo statusInfo = InfoFactory.factory.getStatusInfo(this); for (int i = 0; i < c.subContacts.size(); ++i) { XmppContact.SubContact contact = (XmppContact.SubContact) c.subContacts.elementAt(i); sublist.addRawItem(contact.resource, statusInfo.getIcon(contact.status), i); if (contact.resource.equals(c.currentResource)) { selected = i; } } sublist.setDefaultItemCode(selected); sublist.setActionListener(c); UIBuilder.createMenu(sublist).show(); } @Override public void showUserInfo(Contact contact) { if (!contact.isSingleUserContact()) { doAction(contact, XmppContact.USER_MENU_USERS_LIST); return; } String realJid = contact.getUserId(); if (Jid.isConference(realJid) && (-1 != realJid.indexOf('/'))) { XmppServiceContact conference = (XmppServiceContact) getItemByUID(Jid.getBareJid(realJid)); String r = conference.getRealJid(Jid.getResource(realJid, "")); if (!StringUtils.isEmpty(r)) { realJid = r; } } UserInfo data; if (isConnected()) { data = getConnection().getUserInfo(contact); data.uin = realJid; data.createProfileView(contact.getName()); data.setProfileViewToWait(); } else { data = new UserInfo(this, contact.getUserId()); data.uin = realJid; data.nick = contact.getName(); data.createProfileView(contact.getName()); data.updateProfileView(); } data.showProfile(); } public void updateStatusView(StatusView statusView, Contact contact) { if (statusView.getContact() != contact) { return; } String statusMessage = contact.getStatusText(); // #sijapp cond.if modules_XSTATUSES is "true" # String xstatusMessage = ""; if (XStatusInfo.XSTATUS_NONE != contact.getXStatusIndex()) { xstatusMessage = contact.getXStatusText(); String s = StringUtils.notNull(statusMessage); if (!StringUtils.isEmpty(xstatusMessage) && s.startsWith(xstatusMessage)) { xstatusMessage = statusMessage; statusMessage = null; } } // #sijapp cond.end # statusView.initUI(); statusView.addContactStatus(); statusView.addStatusText(statusMessage); // #sijapp cond.if modules_XSTATUSES is "true" # if (XStatusInfo.XSTATUS_NONE != contact.getXStatusIndex()) { statusView.addXStatus(); statusView.addStatusText(xstatusMessage); } // #sijapp cond.end # // #sijapp cond.if modules_CLIENTS is "true" # if (contact.isSingleUserContact()) { statusView.addClient(); } // #sijapp cond.end # statusView.addTime(); statusView.update(); } @Override public void showStatus(Contact contact) { StatusView statusView = Jimm.getJimm().getStatusView(); try { if (contact.isOnline() && contact.isSingleUserContact()) { String jid = contact.getUserId(); if (!(contact instanceof XmppServiceContact)) { jid += '/' + ((XmppContact) contact).getCurrentSubContact().resource; } getConnection().requestClientVersion(jid); } } catch (Exception ignored) { } statusView.init(this, contact); updateStatusView(statusView, contact); statusView.showIt(); } @Override public String getUniqueUserId(Contact c) { String jid = c.getUserId(); if (isContactOverGate(jid)) { return Jid.getNick(jid).replace('%', '@'); } return jid.replace('%', '@'); } // ----------------------------------------------------------------------- private static Form enterData = null; private static XmppServiceContact enterConf = null; private static final int NICK = 0; private static final int PASSWORD = 1; private static final int AUTOJOIN = 2; void showOptionsForm(XmppServiceContact c) { enterConf = c; enterData = UIBuilder.createForm("conference", "ok", "cancel", this); enterData.addTextField(NICK, "nick", c.getMyName(), 32); enterData.addTextField(PASSWORD, "password", c.getPassword(), 32); if (!c.isTemp()) { enterData.addCheckBox(AUTOJOIN, "autojoin", c.isAutoJoin()); } enterData.show(); if (!Jid.isIrcConference(c.getUserId())) { getConnection().requestConferenceInfo(c.getUserId()); } } void setConferenceInfo(String jid, String description) { if ((null != enterData) && enterConf.getUserId().equals(jid)) { enterData.addString("description", description); } } @Override public void formAction(Form form, boolean apply) { if (enterData == form) { if (apply) { if (enterConf.isConference()) { String oldNick = enterConf.getMyName(); enterConf.setMyName(enterData.getTextFieldValue(NICK)); enterConf.setAutoJoin(!enterConf.isTemp() && enterData.getCheckBoxValue(AUTOJOIN)); enterConf.setPassword(enterData.getTextFieldValue(PASSWORD)); boolean needUpdate = !enterConf.isTemp(); if (needUpdate) { getConnection().saveConferences(); } if (enterConf.isOnline() && !oldNick.equals(enterConf.getMyName())) { join(enterConf); } } Jimm.getJimm().getCL().activate(); } else { enterData.back(); } enterData = null; enterConf = null; } } } // #sijapp cond.end #