/* * Copyright 2011 Ronald Kurniawan. * * This file is part of CodeTraq. * * CodeTraq is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * CodeTraq 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 CodeTraq. If not, see <http://www.gnu.org/licenses/>. */ package net.mobid.codetraq.talkers; import java.util.logging.Level; import net.mobid.codetraq.ConnectionType; import net.mobid.codetraq.ITalker; import net.mobid.codetraq.utils.LogService; import org.jivesoftware.smack.Chat; import org.jivesoftware.smack.ChatManager; import org.jivesoftware.smack.ConnectionConfiguration; import org.jivesoftware.smack.MessageListener; import org.jivesoftware.smack.Roster; import org.jivesoftware.smack.SASLAuthentication; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Presence; /** * This class implements the CodeTraq connector to XMPP-based instant messaging * service. Currently, this class works perfectly well for GoogleTalk and Jabber.org * clients. * * @author Ronald Kurniawan * @version 0.1 */ public class XMPPTalker implements ITalker { private XMPPConnection _conn = null; private String _username = null; private String _password = null; private ConnectionType _cType = null; private Roster _roster = null; private boolean _connected = false; /** * Creates a new XMPPTalker. You should provide the password as * an encrypted <code>String</code> inside the configuration file. See * <code>PasswordProcessor.java</code> for more information on how we encrypt * or decrypt text. <b>DO NOT</b> store plaintext passwords in your configuration * file. * @param username - GoogleTalk / Jabber.org username * @param password - GoogleTalk / Jabber.org password * @param connection */ public XMPPTalker(String username, String password, ConnectionType connection) { _username = username; _password = password; _cType = connection; ConnectionConfiguration config = new ConnectionConfiguration(_cType.getServer(), _cType.getPort(), _cType.getResource()); config.setCompressionEnabled(true); config.setReconnectionAllowed(true); config.setRosterLoadedAtLogin(true); _conn = new XMPPConnection(config); connect(); // if we don't have a default group "client" we need to create one if (_roster != null && _roster.getGroup("client") == null) { _roster.createGroup("client"); } } /** * Checks whether our service is online and ready to send messages. * @return <code>true</code> if online, <code>false</code> otherwise */ public boolean isConnected() { return _connected; } /** * Sets our online status. * @param value - <code>true</code> if online, <code>false</code> otherwise */ public void setConnected(boolean value) { _connected = value; } /** * Logs into our XMPP-based service provider. This method has been tested against * GoogleTalk and Jabber.org. */ public final void connect() { if (_conn != null && !_conn.isConnected()) { try { System.out.printf("Connecting to %s on port %d...%n", _cType.getServer(), _cType.getPort()); _conn.connect(); SASLAuthentication.supportSASLMechanism("PLAIN", 0); Thread.sleep(2000); System.out.printf("Logging in...%n"); _conn.login(_username, _password, _cType.getResource()); _roster = _conn.getRoster(); _roster.setSubscriptionMode(Roster.SubscriptionMode.accept_all); while (_roster == null) { try { Thread.sleep(1000); } catch (InterruptedException ex) { } } System.out.printf("There are %d contacts on the list%n", _roster.getEntryCount()); setConnected(true); } catch (XMPPException ex) { System.out.printf("%s%n", ex.getMessage()); // UnknownHostException 504; LogService.getLogger(XMPPTalker.class.getName()).log(Level.SEVERE, null, ex); LogService.writeLog(Level.SEVERE, ex); System.out.printf("ERROR %d: %s%n", ex.getXMPPError().getCode(), ex.getXMPPError().getMessage()); setConnected(false); } catch (InterruptedException ex) { } } } public boolean talk(String to, String message) { if (!isConnected()) { connect(); } try { if (recipientOnline(to)) { ChatManager cm = _conn.getChatManager(); Chat newMessage = cm.createChat(to, new MessageListener() { public void processMessage(Chat chat, Message message) { } }); newMessage.sendMessage(message); return true; } } catch (XMPPException ex) { LogService.getLogger(XMPPTalker.class.getName()).log(Level.SEVERE, null, ex); LogService.writeLog(Level.SEVERE, ex); } return false; } public void disconnect() { if (_conn != null && _conn.isConnected()) { _conn.disconnect(); setConnected(false); } } public boolean isInContactList(String recipientAddress) { if (!isConnected()) { connect(); } return _roster.contains(recipientAddress); } public void addToContactList(String recipientAddress) { try { if (!isConnected()) { connect(); } String[] groups = new String[]{"client"}; _roster.createEntry(recipientAddress, recipientAddress, groups); } catch (XMPPException ex) { LogService.getLogger(XMPPTalker.class.getName()).log(Level.SEVERE, null, ex); LogService.writeLog(Level.SEVERE, ex); } } public boolean recipientOnline(String recipientAddress) { // Presence object can be null if recipient is offline or if // server's identity is not present in recipient's contact list if (!isConnected()) { connect(); } String[] groups = new String[] { "client" }; // if recipient is not in our roster, we need to add it first if (!_roster.contains(recipientAddress)) { try { _roster.createEntry(recipientAddress, recipientAddress, groups); } catch (XMPPException ex) { LogService.getLogger(XMPPTalker.class.getName()).log(Level.SEVERE, null, ex); LogService.writeLog(Level.SEVERE, ex); } } Presence p = _roster.getPresence(recipientAddress); if (p == null || !p.isAvailable()) { return false; } return true; } }