Commit fe9661f3 authored by Daniel Henninger's avatar Daniel Henninger Committed by dhenninger

[JM-761] [JM-769] Base code put together, not entirely functional yet. Start...

[JM-761] [JM-769] Base code put together, not entirely functional yet.  Start of OSCAR and Yahoo protocol pieces.  Do not use yet.

git-svn-id: http://svn.igniterealtime.org/svn/repos/wildfire/trunk@4344 b35dd754-fafc-0310-a699-88a17e54d16e
parent b36238e5
......@@ -6,10 +6,22 @@
<!-- Plugin meta-data -->
<name>IM Gateway</name>
<description>Provides gateway connectivity to the public AIM and ICQ networks</description>
<author></author>
<version>.1</version>
<description>Provides gateway connectivity to the other public instant messaging networks</description>
<author>Daniel Henninger</author>
<version>0.0.1</version>
<date>07/02/2006</date>
<minServerVersion>3.0.0</minServerVersion>
<databaseKey>gateway</databaseKey>
<databaseVersion>0</databaseVersion>
<licenseType>gpl</licenseType>
<!-- Admin console meta-data -->
<adminconsole>
<tab id="tab-server">
<sidebar id="sidebar-server-settings">
<item id="gateway-service" name="IM Gateway" url="gateway-service.jsp"
description="Click to manage the service that provides access to other IM networks" />
</sidebar>
</tab>
</adminconsole>
</plugin>
CREATE TABLE gatewayRegistration (
gwID VARCHAR(50) NOT NULL,
username VARCHAR(64) NOT NULL,
legacyAcct VARCHAR(255) NOT NULL,
legacyPwd VARCHAR(255) NOT NULL,
CONSTRAINT gatewayRegistration_pk PRIMARY KEY (gwID, username)
);
INSERT INTO jiveVersion (name, version) VALUES ('gateway', 0);
CREATE TABLE gatewayRegistration (
gwID VARCHAR(50) NOT NULL,
username VARCHAR(64) NOT NULL,
legacyAcct VARCHAR(255) NOT NULL,
legacyPwd VARCHAR(255) NOT NULL,
CONSTRAINT gatewayRegistration_pk PRIMARY KEY (gwID, username)
);
INSERT INTO jiveVersion (name, version) VALUES ('gateway', 0);
CREATE TABLE gatewayRegistration (
gwID VARCHAR(50) NOT NULL,
username VARCHAR(64) NOT NULL,
legacyAcct VARCHAR(255) NOT NULL,
legacyPwd VARCHAR(255) NOT NULL,
primary key (gwID, username)
);
INSERT INTO jiveVersion (name, version) VALUES ('gateway', 0);
CREATE TABLE gatewayRegistration (
gwID VARCHAR2(50) NOT NULL,
username VARCHAR2(64) NOT NULL,
legacyAcct VARCHAR2(255) NOT NULL,
legacyPwd VARCHAR2(255) NOT NULL,
CONSTRAINT gatewayRegistration_pk PRIMARY KEY (gwID, username)
);
INSERT INTO jiveVersion (name, version) VALUES ('gateway', 0);
CREATE TABLE gatewayRegistration (
gwID VARCHAR(50) NOT NULL,
username VARCHAR(64) NOT NULL,
legacyAcct VARCHAR(255) NOT NULL,
legacyPwd VARCHAR(255) NOT NULL,
CONSTRAINT gatewayRegistration_pk PRIMARY KEY (gwID, username)
);
INSERT INTO jiveVersion (name, version) VALUES ('gateway', 0);
CREATE TABLE gatewayRegistration (
gwID NVARCHAR(50) NOT NULL,
username NVARCHAR(64) NOT NULL,
legacyAcct NVARCHAR(255) NOT NULL,
legacyPwd NVARCHAR(255) NOT NULL,
CONSTRAINT gatewayRegistration_pk PRIMARY KEY (gwID, username)
);
INSERT INTO jiveVersion (name, version) VALUES ('gateway', 0);
CREATE TABLE gatewayRegistration (
gwID NVARCHAR(50) NOT NULL,
username NVARCHAR(64) NOT NULL,
legacyAcct NVARCHAR(255) NOT NULL,
legacyPwd NVARCHAR(255) NOT NULL,
CONSTRAINT gatewayRegistration_pk PRIMARY KEY (gwID, username)
);
INSERT INTO jiveVersion (name, version) VALUES ('gateway', 0);
invaliduser=Unknown user
\ No newline at end of file
externalgateway.startup=Started external gateway {0}.
externalgateway.filenotfound=Configuration file {0} not found: {1}
externalgateway.invalidconfig=Invalid configuratino file: {0}
externalgateway.missingconfig=Unable to locate config.properties in classpath. \
Either specify on the command line the config properties or include it in the proper jar file.
externalgateway.invalidcommandline=Invalid command line option. {0}
externalgateway.usingdefaultgateway=Using default gateway "{0}" with secret passphrase "{1}".
externalgateway.addcomponentfailed=Unable to add component. Please ensure that the domain ({0}) is correct and matches the secret phrase ({1}) on the server. Error from server: {2}
persistencemanager.unabletoflush=Unable to flush roster.
persistencemanager.loadrosterfailed=Unable to load roster.
persistencemanager.registrarFinalize=PersistenceManager destroyed.
persistencemanager.nokey=Unable to locate secret key.
persistencemanager.gennewkey=Generating new key.
register.unabletologout=Unable to log out of session: {0}.
basegateway.unknownhost=Unable to determine host for this gateway.
basegateway.domainname=Setting gateway domain to: {0}.
basegateway.dataformnotused=DataForm not used, reverting to IQ level elements.
basegateway.notfound={0} not found.
basegateway.unregister=Unregister {0}.
basegateway.register=Registering user: {0}.
basegateway.unabletofind=Unable to find JID: {0}.
basegateway.unauthorizedrequest=Unauthorized request ({0}) by {1}.
basegateway.unabletolocatesession=Unable to locate GatewaySession for: {0}.
basegateway.subscribed=Subscribed to legacy user.
basegateway.unabletosendpresence=Unable to send presense packet.
basegateway.maintenancestart=Starting maintenance.
basegateway.maintenancestop=Finished maintenance.
basegateway.registerfirst=Please register first.
basegateway.statusexception=Unable to get status from {1} to send to {0}. Error message: {2}
basegateway.gatewaypresence=Gateway presence requested and served.
jabberendpoint.sendpacketenqueue=Enqueue packet from {0}.
STATUS_AVAILABLE = "Available";
STATUS_BRB = "Be right back";
STATUS_BUSY = "Busy";
STATUS_NOTATHOME = "Not at home";
STATUS_NOTATDESK = "Not at desk";
STATUS_NOTINOFFICE = "Not in office";
STATUS_ONPHONE = "On the phone";
STATUS_ONVACATION = "On vacation";
STATUS_OUTTOLUNCH = "Out to lunch";
STATUS_STEPPEDOUT = "Stepped out";
STATUS_INVISIBLE = "Invisible";
STATUS_CUSTOM = "<custom>";
STATUS_IDLE = "Zzz";
STATUS_OFFLINE = "Offline";
STATUS_TYPING = "Typing";
\ No newline at end of file
package org.jivesoftware.wildfire.gateway;
/**
* AbstractGatewaySession provides an abstract implementation of
* <code>GatewaySession</code> that implements the some of the core responsibilties
* of a GatewaySession. This includes: handling registration and endpoint
* management.
*
* @author Noah Campbell
* @version 1.0
*/
public abstract class AbstractGatewaySession implements GatewaySession, Endpoint {
/**
* Construct an a gateway session.
*
* @param info the <code>SubscriptionInfo</code> for this session.
* @param gateway the <code>Gateway</code> that constructed this session.
*/
protected AbstractGatewaySession(SubscriptionInfo info, Gateway gateway) {
this.gateway = gateway;
this.subscription = info;
}
/**
* The gateway.
*/
protected transient Gateway gateway;
/**
* Has the client registered with the gateway?
*/
public boolean clientRegistered;
/**
* Has the server attempted to register with the client?
*/
public boolean serverRegistered;
/**
* The subscriptionInfo.
* @see org.jivesoftware.wildfire.gateway.SubscriptionInfo
*/
private final SubscriptionInfo subscription;
/**
* The jabber endpoint.
* @see org.jivesoftware.wildfire.gateway.Endpoint
*/
private Endpoint jabberEndpoint;
/**
* Set the Jabber <code>Endpoint</code>.
*
* @see org.jivesoftware.wildfire.gateway.GatewaySession#setJabberEndpoint(org.jivesoftware.wildfire.gateway.Endpoint)
*/
public void setJabberEndpoint(Endpoint jabberEndpoint) {
this.jabberEndpoint = jabberEndpoint;
}
/**
* Return the jabber <code>Endpoint</code>.
*
* @return endpoint The jabber endpoint.
* @see org.jivesoftware.wildfire.gateway.Endpoint
*/
public Endpoint getJabberEndpoint() {
return jabberEndpoint;
}
/**
* Return the legacy <code>Endpoint</code>.
*
* @return endpoint The legacy endpoint.
* @see org.jivesoftware.wildfire.gateway.Endpoint
*/
public Endpoint getLegacyEndpoint() {
return this;
}
/**
* Return the <code>SubscriptionInfo</code>
*
* @return subscriptionInfo the <code>SubscriptionInfo</code> associated
* this session.
* @see org.jivesoftware.wildfire.gateway.SubscriptionInfo
*/
public SubscriptionInfo getSubscriptionInfo() {
return this.subscription;
}
/**
* Return the gateway associated with this session.
*
* @return gateway The gateway.
* @see org.jivesoftware.wildfire.gateway.Gateway
*/
public Gateway getGateway() {
return this.gateway;
}
/**
* @see org.jivesoftware.wildfire.gateway.Endpoint#getValve()
*/
public EndpointValve getValve() {
return this.jabberEndpoint.getValve();
}
}
package org.jivesoftware.wildfire.gateway;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.collections.BidiMap;
import org.apache.commons.collections.bidimap.DualHashBidiMap;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.jivesoftware.wildfire.gateway.roster.AbstractForeignContact;
import org.jivesoftware.wildfire.gateway.roster.ForeignContact;
import org.jivesoftware.wildfire.gateway.roster.NormalizedJID;
import org.jivesoftware.wildfire.gateway.roster.PersistenceManager;
import org.jivesoftware.wildfire.gateway.roster.Roster;
import org.jivesoftware.wildfire.gateway.roster.Status;
import org.jivesoftware.wildfire.gateway.util.BackgroundThreadFactory;
import org.xmpp.component.Component;
import org.xmpp.component.ComponentException;
import org.xmpp.component.ComponentManager;
import org.xmpp.component.ComponentManagerFactory;
import org.xmpp.forms.DataForm;
import org.xmpp.forms.FormField;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence;
import org.xmpp.packet.PacketError.Condition;
import org.xmpp.packet.Presence.Show;
/**
* Handle a good share of the tasks for a gateway. Dealing with lookups for ids,
* dealing with registration, dealing with presence information.
*
* @author ncampbell
* @version 1.0
*/
public abstract class BaseGateway implements Gateway, Component, Runnable {
/**
* @see org.jivesoftware.wildfire.gateway.Gateway#getName()
*/
public abstract String getName();
/**
* @see org.jivesoftware.wildfire.gateway.Gateway#setName()
*/
public abstract void setName(String newname);
/**
* @see org.jivesoftware.wildfire.gateway.Gateway#getDescription()
*/
public abstract String getDescription();
/**
* @see org.jivesoftware.wildfire.gateway.Gateway#getDomain()
*/
public final String getDomain() {
String domainName = this.componentManager.getServerName();
logger.log(Level.FINE, "basegateway.domainname", domainName);
return domainName;
}
/**
* @return version the version of the gateway
*/
public abstract String getVersion();
/**
* @return gatewayType the type of gateway. THis should always be "gateway"
*/
public String getType() {
return "gateway";
}
/** The logger. @see java.util.logging.Logger */
private static final Logger logger = Logger.getLogger("BaseGateway","gateway_i18n");
/**
* Jabber endpoint.
*/
protected JabberEndpoint jabberEndpoint;
/**
* Component Manager to handle communication to the XMPP server.
*/
public final ComponentManager componentManager = ComponentManagerFactory.getComponentManager();
/**
* JID of component.
*/
public JID jid;
/**
* Handles registration for this gateway.
*/
public final PersistenceManager rosterManager = PersistenceManager.Factory.get(this);
/** The threadPool. @see java.util.concurrent.ScheduledExecutorService */
protected static final ScheduledExecutorService threadPool = Executors.newSingleThreadScheduledExecutor(new BackgroundThreadFactory());
/**
* Handle Foreign Contacts and JID Mapping
*/
private final BidiMap foreignContacts = new DualHashBidiMap();
/**
* helper method for getting the ns from a packet.
*
* @param packet
* @return namespace The namespaceUri.
*/
private String getNS(IQ packet) {
Element childElement = (packet).getChildElement();
String namespace = null;
if (childElement != null) {
namespace = childElement.getNamespaceURI();
}
return namespace;
}
/**
* Process an IQ packet.
*
* @param iq the IQ packet sent from the client.
* @return packetList A list of Packets to be sent to the client.
* @see java.util.List
* @see org.xmpp.packet.IQ
*/
private List<Packet> processPacket(IQ iq) {
String namespace = getNS(iq);
List<Packet> response = new ArrayList<Packet>();
if("http://jabber.org/protocol/disco#info".equals(namespace)) {
response.add(handleServiceDiscovery(iq));
} else if("jabber:iq:agents".equals(namespace)) {
response.add(handleLegacyServiceDiscovery(iq));
} else if("http://jabber.org/protocol/disco#items".equals(namespace)) {
response.add(handleDiscoveryItems(iq));
} else if("jabber:iq:register".equals(namespace)) {
response.addAll(handleRegisterInBand(iq));
} else if("jabber:iq:version".equals(namespace)) {
response.add(handleVersion(iq));
} else if("jabber:iq:browse".equals(namespace)) {
response.add(handleBrowse(iq));
}
return response;
}
/**
* Proces a browse request.
*
* @param iq The client IQ packet.
* @return iq The response IQ packet.
*/
private IQ handleBrowse(IQ iq) {
IQ reply = IQ.createResultIQ(iq);
Element responseElement = DocumentHelper.createElement(QName.get(
"query", "jabber:iq:browse"));
try {
for(ForeignContact fc : PersistenceManager.Factory.get(this).getRegistrar().getGatewaySession(iq.getFrom()).getContacts()) {
Element item = DocumentHelper.createElement("item");
item.addAttribute("category", "user");
item.addAttribute("jid", fc + "@" + this.getName() + "." + this.getDomain());
item.addAttribute("type", "client");
responseElement.add(item);
}
reply.setChildElement(responseElement);
} catch (Exception e) {
logger.log(Level.WARNING, "basegateway.notfound", iq.getFrom().toBareJID());
}
return reply;
}
/**
* Process a version request.
*
* @param iq The client IQ packet.
* @return iq The response to the client.
*/
private IQ handleVersion(IQ iq) {
IQ reply = IQ.createResultIQ(iq);
Element responseElement = DocumentHelper.createElement(QName.get(
"query", "jabber:iq:version"));
responseElement.addElement("name").addText(this.getName());
responseElement.addElement("version").addText(this.getVersion());
responseElement.addElement("os").addText(System.getProperty("os.name"));
reply.setChildElement(responseElement);
return reply;
}
/**
* Handle a register command...this may be the request or the response for
* the registration process.
*
* @param iq The client iq packet.
* @return response The <code>Collection</code> of <code>Packet</code> that
* make up the response.
*/
private Collection<Packet> handleRegisterInBand(final IQ iq) {
Element remove = iq.getChildElement().element("remove");
Collection<Packet> response = new ArrayList<Packet>();
if(remove != null) {
response.addAll(unregister(iq));
} else {
response.addAll(register(iq));
}
return response;
}
/**
* Handle a unregister request.
*
* @param iq The IQ packet sent from the client.
* @return response The packets that make up the response.
*/
private Collection<Packet> unregister(IQ iq) {
IQ reply = IQ.createResultIQ(iq);
PersistenceManager.Factory.get(this).remove(iq.getFrom());
Collection<Packet> results = new ArrayList<Packet>();
results.add(reply);
Presence unsubscribed, unsubscribe, unavailable;
unavailable = new Presence(Presence.Type.unavailable);
unavailable.setTo(reply.getTo());
unavailable.setFrom(reply.getFrom());
unsubscribed = new Presence(Presence.Type.unsubscribed);
unsubscribed.setTo(reply.getTo());
unsubscribed.setFrom(reply.getFrom());
unsubscribe = new Presence(Presence.Type.unsubscribe);
unsubscribe.setTo(reply.getTo());
unsubscribe.setFrom(reply.getFrom());
results.add(unsubscribe);
results.add(unsubscribed);
results.add(unavailable);
logger.log(Level.INFO, "basegateway.unregister", iq.getFrom());
return results;
}
/**
* Handle a register request.
*
* @param iq The client's IQ packet.
* @return response A <code>Collection</code> of <code>Packet</code>s that make up the response.
*/
private Collection<Packet> register(IQ iq) {
Collection<Packet> response = new ArrayList<Packet>();
IQ reply = IQ.createResultIQ(iq);
Element responseElement = DocumentHelper.createElement(QName.get(
"query", "jabber:iq:register"));
if(iq.getType().equals(IQ.Type.set)) {
String username = null;
String password = null;
try {
DataForm form = new DataForm(iq.getChildElement().element("x"));
List<FormField> fields = form.getFields();
for(FormField field : fields) {
String var = field.getVariable();
if(var.equalsIgnoreCase("username")) {
username = field.getValues().get(0);
} else if (var.equalsIgnoreCase("password")) {
/**
* The password is stored in Whack and DOM4J as a String
* so the password is sent in the clear and stored in
* JVM until termination.
*/
password = field.getValues().get(0);
}
}
} catch (Exception e) {
// unable to use dataform
logger.log(Level.FINER, "basegateway.dataformnotused", e);
}
if(username == null || password == null) {
// try non DataForm.
Element usernameElement = iq.getChildElement().element("username");
Element passwordElement = iq.getChildElement().element("password");
if(usernameElement != null) {
username = usernameElement.getTextTrim();
}
if(passwordElement != null) {
password = passwordElement.getTextTrim();
}
}
// make sure that something was collected, otherwise return an error.
if(username == null || password == null) {
IQ result = IQ.createResultIQ(iq);
result.setError(Condition.bad_request);
response.add(result);
} else {
logger.log(Level.INFO, "basegateway.register", username.trim());
SubscriptionInfo info = new SubscriptionInfo(username.trim(), password);
PersistenceManager.Factory.get(this).getRegistrar().add(iq.getFrom(), info);
reply.setChildElement(responseElement);
response.add( reply );
Presence subscribe = new Presence(Presence.Type.subscribe);
subscribe.setTo(iq.getFrom());
subscribe.setFrom(iq.getTo());
response.add(subscribe);
}
} else if(iq.getType().equals(IQ.Type.get)) {
DataForm form = new DataForm(DataForm.Type.form);
form.addInstruction("Please enter your AIM Screenname and Password");
FormField usernameField = form.addField();
usernameField.setLabel("Username");
usernameField.setVariable("username");
usernameField.setType(FormField.Type.text_single);
FormField passwordField = form.addField();
passwordField.setLabel("Password");
passwordField.setVariable("password");
passwordField.setType(FormField.Type.text_private);
/**
* Add standard elements to request.
*/
responseElement.addElement("instruction").addText("Please enter your AIM screenname and password");
responseElement.addElement("username");
responseElement.addElement("password");
/**
* Add data form (for those that can support it.
*/
responseElement.add(form.getElement());
reply.setChildElement(responseElement);
response.add( reply );
}
return response;
}
/**
* Returns the contacts for the user that made the request.
*
* @param iq The client request.
* @return response The IQ packet response.
*/
private IQ handleDiscoveryItems(IQ iq) {
IQ reply = IQ.createResultIQ(iq);
Element responseElement = DocumentHelper.createElement(QName.get(
"query", "http://jabber.org/protocol/disco#info"));
Roster roster = this.rosterManager.getContactManager().getRoster(iq.getFrom());
for( ForeignContact entry : roster.getAll()) {
Element item = responseElement.addElement("item");
item.addAttribute("jid", entry.getJid().toBareJID());
item.addAttribute("name", entry.getName());
responseElement.add(item);
}
reply.setChildElement(responseElement);
System.out.println(reply);
return reply;
}
/**
* TODO: handle a legacy service discovery request.
*
* @param iq
* @return response
*/
private IQ handleLegacyServiceDiscovery(IQ iq) {
return IQ.createResultIQ(iq);
// TODO: Implement Legacy Service Discovery.
}
/**
* Handle service discovery.
*
* @param iq The client IQ packet.
* @return respones The IQ response.
*/
private IQ handleServiceDiscovery(IQ iq) {
IQ reply = IQ.createResultIQ(iq);
Element responseElement = DocumentHelper.createElement(QName.get(
"query", "http://jabber.org/protocol/disco#info"));
responseElement.addElement("identity").addAttribute("category", "gateway")
.addAttribute("type", this.getType())
.addAttribute("name", this.getDescription());
responseElement.addElement("feature").addAttribute("var", "jabber:iq:time");
responseElement.addElement("feature").addAttribute("var", "jabber:iq:version");
responseElement.addElement("feature").addAttribute("var", "jabber:iq:register");
reply.setChildElement(responseElement);
return reply;
}
/**
* Dispatch the appropriate message type.
*
* @param packet The packet to process.
*/
public void processPacket(Packet packet) {
try {
List<Packet> response = new ArrayList<Packet>();
if(packet instanceof IQ) {
response.addAll( processPacket((IQ)packet) );
} else if (packet instanceof Presence) {
response.addAll( processPacket((Presence)packet) );
} else if (packet instanceof Message) {
processPacket((Message)packet);
} else {
System.out.println("UNHANDLED: " + packet.toString());
}
// process
if(response.size() > 0) {
for(Packet p : response) {
componentManager.sendPacket(this, p);
}
} else {
//System.out.println("Request[" + packet.toString() + "] with no response");
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* Process a message from the client.
*
* @param message Client <code>Message</code>
* @throws Exception
* @see org.xmpp.packet.Message
*/
private void processPacket(Message message) throws Exception {
logger.finer(message.toString());
GatewaySession session = PersistenceManager.Factory.get(this).getRegistrar().getGatewaySession(message.getFrom());
session.getLegacyEndpoint().sendPacket(message);
return;
}
/**
* Proces a presense packet.
*
* @param presence The presence packet from the client.
* @return list A <code>List</code> of <code>Presence</code> packets.
* @throws Exception
*/
private List<Presence> processPacket(Presence presence) throws Exception {
List<Presence> p = new ArrayList<Presence>();
JID from = presence.getFrom();
logger.finest(presence.toString());
/*
* Unknown entity is trying to access the gateway.
*/
if(!rosterManager.getRegistrar().isRegistered(NormalizedJID.wrap(from))) {
logger.log(Level.INFO, "basegateway.unabletofind", from);
// silently ignore a delete request
if(!Presence.Type.unavailable.equals(presence.getType())) {
logger.log(Level.INFO, "basegateway.unauthorizedrequest", new Object[] { presence.getType(), from.toString() });
Presence result = new Presence();
result = new Presence();
result.setError(Condition.not_authorized);
result.setStatus(bundle.getString("basegateway.registerfirst"));
p.add(result);
}
return p;
}
/*
* Get the underlying session for this JID and handle accordingly.
*/
GatewaySession sessionInfo = rosterManager.getRegistrar().getGatewaySession(from);
if(sessionInfo == null) {
logger.log(Level.WARNING, "basegateway.unabletolocatesession" , from);
return p;
}
if(Presence.Type.subscribe.equals(presence.getType())) {
if(presence.getTo().equals(this.jid)) {
sessionInfo.getSubscriptionInfo().serverRegistered = true;
} else {
Presence subscribe = new Presence(Presence.Type.subscribe);
subscribe.setTo(presence.getFrom());
subscribe.setFrom(presence.getTo());
p.add(subscribe);
}
Presence reply = new Presence(Presence.Type.subscribed);
reply.setTo(presence.getFrom());
reply.setFrom(presence.getTo());
p.add(reply);
} else if (Presence.Type.subscribed.equals(presence.getType())) {
if(presence.getTo().equals(this.jid)) { // subscribed to server
sessionInfo.getSubscriptionInfo().clientRegistered = true;
} else { // subscribe to legacy user
logger.log(Level.FINE,"basegateway.subscribed");
}
} else if (Presence.Type.unavailable.equals(presence.getType())){
/**
* If an unavailable presence stanza is received then logout the
* current user and send back and unavailable stanza.
*/
if(sessionInfo.isConnected()) {
sessionInfo.logout();
}
Presence reply = new Presence(Presence.Type.unavailable);
reply.setTo(presence.getFrom());
reply.setFrom(presence.getTo());
p.add(reply);
} else if (presence.getTo().getNode() == null) { // this is a request to the gateway only.
Presence result = new Presence();
result.setTo(presence.getFrom());
result.setFrom(this.jid);
p.add(result);
logger.log(Level.FINE, "basegateway.gatewaypresence");
} else {
GatewaySession session = rosterManager.getRegistrar().getGatewaySession(presence.getFrom());
try {
ForeignContact fc = session.getContact(presence.getTo());
Status status = fc.getStatus();
Presence p2 = new Presence();
p2.setFrom(presence.getTo());
p2.setTo(presence.getFrom());
if(status.isOnline()) {
p2.setStatus(status.getValue());
} else {
p2.setType(Presence.Type.unavailable);
}
p.add(p2);
} catch (Exception e) {
logger.log(Level.WARNING, "basegateway.statusexception",
new Object[]{presence.getTo(), presence.getFrom(), e.getLocalizedMessage()});
}
}
return p;
}
/** The resource bundle for this gateway. */
ResourceBundle bundle = PropertyResourceBundle.getBundle("gateway_i18n");
/** The jabberEndpointValve. */
private EndpointValve jabberEndpointValve;
/**
* Return the JID of this component.
*
* @return jid The JID for this gateway.
* @see Gateway#getJID()
*/
public JID getJID() {
return this.jid;
}
/**
* Handle initialization.
*
* @param jid The JID for this component
* @param componentManager The <code>ComponentManager</code> associated with this component
* @throws ComponentException
*
* @see org.xmpp.component.Component#initialize(JID, ComponentManager)
*/
public void initialize(JID jid, ComponentManager componentManager) throws ComponentException {
this.jid = jid;
this.jabberEndpointValve = new EndpointValve(false);
this.jabberEndpoint = new JabberEndpoint(componentManager, this, jabberEndpointValve);
}
/**
* Reverse lookup. This will always succeed. A new JID will be created for a
* foreign contact.
*
* @param foreignContact The foreign contact name.
* @return jid The JID associated with this contact.
*/
public JID whois(String foreignContact) {
JID jid = new JID(foreignContact + "@" + this.getName() + "." + this.getDomain());
foreignContacts.put(foreignContact, jid);
return jid;
}
/**
* Lookup a foreign contact
*
* @param jid The JID to lookup.
* @return contact A String for the foreign contact or null if non is regestered.
*/
public String whois(JID jid) {
return (String)foreignContacts.get(jid);
}
/**
* Start this component
*/
public void start() {
threadPool.scheduleAtFixedRate(this, 0, 3, TimeUnit.SECONDS);
}
/**
* Shutdown this component
*/
public void shutdown() {
}
/**
* Do maintenance, essentially send out a presense ping. Will also attempt to
* subscribed the contact to the JID.
*/
public void run() {
logger.log(Level.FINEST, "basegateway.maintenancestart");
for(SubscriptionInfo si : rosterManager.getRegistrar().getAllGatewaySessions()) {
if(!si.clientRegistered) {
Presence p = new Presence();
p.setType(Presence.Type.subscribe);
p.setTo(si.jid);
p.setFrom(this.jid);
try {
componentManager.sendPacket(this, p);
} catch (ComponentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// for(ForeignContact fc : rosterManager.getContactManager().getRoster(si.jid).getAll()) {
// Presence p = new Presence();
// p.setFrom(fc.getJid());
// p.setTo(si.jid);
// p.setStatus(fc.status.getValue());
// try {
// componentManager.sendPacket(this, p);
// } catch (Exception e) {
// logger.log(Level.WARNING, "basegateway.unabletosendpresence", e);
// }
// }
}
// for(ForeignContact contact : rosterManager.getContactManager().getAllForeignContacts()) {
// if(!contact.isConnected())
// continue;
// Presence p = new Presence();
// p.setFrom(contact.getJid());
// try {
// componentManager.sendPacket(this, p);
// } catch (Exception e) {
// logger.log(Level.WARNING, "basegateway.unabletosendpresence", e);
// }
// }
logger.log(Level.FINEST, "basegateway.maintenancestop");
}
/**
* Returns a <code>SessionFactory</code>. The session factory utilizes the
* abstract method <code>getSessionInstance</code> to get a new instance and
* set the jabber endpoint associated with this <code>SessionFactory</code>
*
* @see org.jivesoftware.wildfire.gateway.Gateway#getSessionFactory()
* @see #getSessionInstance(SubscriptionInfo)
*/
public SessionFactory getSessionFactory() {
return new SessionFactory() {
public GatewaySession newInstance(SubscriptionInfo info) {
GatewaySession session = getSessionInstance(info);
session.setJabberEndpoint(jabberEndpoint);
return session;
}
};
}
/**
* @see org.jivesoftware.wildfire.gateway.Endpoint#getValve()
*/
public EndpointValve getValve() {
return this.jabberEndpoint.getValve();
}
/**
* Return a <code>GatewaySession</code> given the <code>SubscriptionInfo</code>
*
* @param info The subscription information to use to create the gateway.
* @return session A new gateway session.
* @see #getSessionFactory()
* @see Gateway#getSessionFactory()
*/
protected abstract GatewaySession getSessionInstance(SubscriptionInfo info);
}
package org.jivesoftware.wildfire.gateway;
import org.xmpp.component.ComponentException;
import org.xmpp.packet.Packet;
/**
* An endpoint represents a server or gateway and can forward the message to the
* underlying implementation, providing translation if necessary.
*
* @author Noah Campbell
* @version 1.0
*/
public interface Endpoint {
/**
* Send a packet to the underlying messaging services
*
* @param packet
* @throws ComponentException
*/
public void sendPacket(Packet packet) throws ComponentException;
/**
* Return the <code>EndpointValve</code>. This provides the ability of the
* caller to open or close the valve to control the follow of packets to the
* destination.
*
* @return valve The <code>EndpointValve</code> associated with this <code>Endpoint</code>
*/
public EndpointValve getValve();
}
/**
*
*/
package org.jivesoftware.wildfire.gateway;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author Noah Campbell
* @version 1.0
*/
public class EndpointValve {
/** The valve handle. */
private final AtomicBoolean open;
/**
* Construct a new <code>EndpointValve</code>. The valve is closed by
* default.
*/
public EndpointValve() {
this(false);
}
/**
* Construct a new <code>EndpointValve</code>.
*
* @param open The valve is open or closed.
*/
public EndpointValve(boolean open) {
this.open = new AtomicBoolean(open);
}
/**
* @return open If the valve is open or not.
*/
public boolean isOpen() {
return this.open.get();
}
/**
* Open the valve and let any pending message get processed.
*/
public void open() {
this.open.set(true);
}
/**
* Close the valve and queue any new messeages destine for the endpoint.
*/
public void close() {
this.open.set(false);
}
}
/**
*
*/
package org.jivesoftware.wildfire.gateway;
import org.xmpp.packet.JID;
/**
* A gateway to an external or legacy messaging system.
*
* @author ncampbell
* @version 1.0
*/
public interface Gateway extends Endpoint {
/**
* Return the name, or node, of the gateway. This should comply with JID
* Node naming coventions
* @return Name The gateway name (JID Node)
*/
public String getName();
/**
* Sets the name, or node, of the gateway. This should comply with JID
* Node naming coventions
*/
public void setName(String newname);
/**
* A textual description of the gateway
* @return description
*/
public String getDescription();
/**
* The domain name
* @return domain
*/
public String getDomain();
/**
* Lookup a contact name for the JID
* @param jid The jabber id
* @return contact The legacy name
*/
public String whois(JID jid);
/**
* Lookup a JID for a legacy contact name
* @param contact The name of legacy contact
* @return JID
*/
public JID whois(String contact);
/**
* The JID of the gateway
* @return JID
*/
public JID getJID();
/**
* Return the session gateway for this gateway
* @return SessionFactory
*/
public SessionFactory getSessionFactory();
}
......@@ -10,24 +10,96 @@
package org.jivesoftware.wildfire.gateway;
import org.jivesoftware.util.Log;
import org.jivesoftware.wildfire.container.Plugin;
import org.jivesoftware.wildfire.container.PluginManager;
import org.jivesoftware.wildfire.gateway.util.GatewayInstance;
import org.xmpp.component.ComponentManager;
import org.xmpp.component.ComponentManagerFactory;
import java.io.File;
import java.util.Hashtable;
/**
* IM Gateway plugin.
*
* @author
* @author Daniel Henninger
*/
public class GatewayPlugin implements Plugin {
/**
* Represents all configured gateway handlers.
*/
private Hashtable<String,GatewayInstance> gateways;
/**
* Represents the base component manager.
*/
private ComponentManager componentManager;
/**
* Configures and starts the plugin.
*/
public void initializePlugin(PluginManager manager, File pluginDirectory) {
gateways = new Hashtable<String,GatewayInstance>();
componentManager = ComponentManagerFactory.getComponentManager();
/* Set up AIM gateway. */
gateways.put("aim", new GatewayInstance("aim", "org.jivesoftware.wildfire.gateway.protocols.oscar.OSCARGateway", componentManager));
maybeStartService("aim");
/* Set up ICQ gateway. */
gateways.put("icq", new GatewayInstance("icq", "org.jivesoftware.wildfire.gateway.protocols.oscar.OSCARGateway", componentManager));
maybeStartService("icq");
/* Set up Yahoo gateway. */
gateways.put("yahoo", new GatewayInstance("yahoo", "org.jivesoftware.wildfire.gateway.protocols.yahoo.YahooGateway", componentManager));
maybeStartService("yahoo");
}
public void destroyPlugin() {
/**
* Starts a gateway service, identified by subdomain. The gateway
* service will only start if it is enabled.
*/
private void maybeStartService(String serviceName) {
GatewayInstance gwInstance = gateways.get(serviceName);
gwInstance.startInstance();
Log.debug("Starting gateway service: "+serviceName);
}
/**
* Enables a gateway service, identified by subdomain.
*/
public void enableService(String serviceName) {
GatewayInstance gwInstance = gateways.get(serviceName);
gwInstance.enable();
Log.debug("Enabling gateway service: "+serviceName);
}
/**
* Disables a gateway service, identified by subdomain.
*/
public void disableService(String serviceName) {
GatewayInstance gwInstance = gateways.get(serviceName);
gwInstance.disable();
Log.debug("Disabling gateway service: "+serviceName);
}
/**
* Returns the state of a gateway service, identified by subdomain.
*/
public Boolean serviceEnabled(String serviceName) {
GatewayInstance gwInstance = gateways.get(serviceName);
return gwInstance.isEnabled();
}
/**
* Shuts down the plugin.
*/
public void destroyPlugin() {
for (GatewayInstance gwInstance : gateways.values()) {
gwInstance.stopInstance();
}
}
}
package org.jivesoftware.wildfire.gateway;
import java.util.List;
import org.jivesoftware.wildfire.gateway.roster.ForeignContact;
import org.jivesoftware.wildfire.gateway.roster.UnknownForeignContactException;
import org.xmpp.packet.JID;
/**
* GatewaySession provides an interface that legacy gateways need to implement.
*
* @author Noah Campbell
* @version 1.0
*/
public interface GatewaySession {
/**
* Logout from the underlying gateway session.
* @throws Exception
*/
public void logout() throws Exception;
/**
* Login to the underlying gateway session.
* @throws Exception
*/
public void login() throws Exception;
/**
* Momento of this session, so it can be restablished later without the
* need for prompting the user for their credentials.
*
* @return SubscriptionInfo the subscription information for this session.
*/
public SubscriptionInfo getSubscriptionInfo();
/**
* Is the session connected?
*
* @return boolean
*/
public boolean isConnected();
/**
* Returns all sessions associated with this session/login.
*
* @return contacts A list of <code>String</code>s.
* @see java.util.List
*/
public List<ForeignContact> getContacts();
/**
* Return the endpoint for the legacy system.
*
* @see org.jivesoftware.wildfire.gateway.Endpoint
* @return Endpoint legacy endpoint.
*/
public Endpoint getLegacyEndpoint();
/**
* Get the Jabber endpoint.
*
* @see org.jivesoftware.wildfire.gateway.Endpoint
* @return Endpoint the jabber endpoint.
*/
public Endpoint getJabberEndpoint();
/**
* JID associated with this session.
*
* @return jid The jid for this session.
* @see org.xmpp.packet.JID
*/
public JID getJID();
/**
* Status for a particular contact.
*
* @param id The id of the contact of interest.
* @return status The status for the particular JID.
*/
public String getStatus(JID id);
/**
* Add a contact to this session. This method will typically update the
* roster on the legacy system.
*
* @param jid
* @throws Exception If add fails.
* @see org.xmpp.packet.JID
*/
public void addContact(JID jid) throws Exception;
/**
* Remove a contact from this session. This will typically update the
* roster on the legacy system.
*
* @param jid
* @throws Exception If remove fails.
* @see org.xmpp.packet.JID
*/
public void removeContact(JID jid) throws Exception;
/**
* Sets the XMPP Server endpoint.
*
* @param jabberEndpoint
* @see org.jivesoftware.wildfire.gateway.Endpoint
*/
public void setJabberEndpoint(Endpoint jabberEndpoint);
/**
* Get the gateway that is associated with this session. Every session
* has an orinating gateway from which is was created.
*
* @return gateway The underlying gateway for this sessin.
* @see org.jivesoftware.wildfire.gateway.Gateway
*/
public Gateway getGateway();
/**
* The session will return a foreign contact identified by the JID. If it
* does not exist then an exception will be thrown. The Session is responsible
* for contacting the gateway to perform any name resolution (if it cannot
* perform it from the JID).
*
* @param to The JID of the contact to locate.
* @return foreignContact The ForeignContact object that represents this JID.
* @throws UnknownForeignContactException
*/
public ForeignContact getContact(JID to) throws UnknownForeignContactException;
}
package org.jivesoftware.wildfire.gateway;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xmpp.component.Component;
import org.xmpp.component.ComponentException;
import org.xmpp.component.ComponentManager;
import org.xmpp.packet.Packet;
/**
* The <code>JabberEndpoint</code> implements the <code>Endpoint</code> for an
* XMPP server.
*
* @author Noah Campbell
* @version 1.0
*/
public class JabberEndpoint implements Endpoint {
/**
* The componentManager
*
* @see ComponentManager
*/
private final ComponentManager componentManager;
/**
* The component
*
* @see Component
*/
private final Component component;
/**
* The value.
* @see EndpointValve
*/
private final EndpointValve valve;
/**
* Construct a new <code>JabberEndpoint</code>.
* @param componentManager The componentManager.
* @param component The component.
*/
public JabberEndpoint(ComponentManager componentManager, Component component) {
this(componentManager, component, new EndpointValve());
}
/**
* Construct a new <code>JabberEndpoint</code>.
* @param componentManager
* @param component
* @param valve
*/
public JabberEndpoint(ComponentManager componentManager, Component component, EndpointValve valve) {
this.componentManager = componentManager;
this.component = component;
this.valve= valve;
}
//
//
// /**
// * @param jid
// * @param string
// * @throws Exception
// */
// public void sendMessage(JID jid, String string) throws Exception {
// Message message = new Message();
// message.setBody(string);
// message.setTo(jid);
// this.componentManager.sendPacket(this.component, message);
// }
/**
* @see org.jivesoftware.wildfire.gateway.Endpoint#sendPacket(Packet)
*/
public void sendPacket(Packet packet) throws ComponentException {
if(valve.isOpen()) {
/**
* Push all pending packets to the XMPP Server.
*/
while(!queue.isEmpty()) {
this.componentManager.sendPacket(this.component, queue.poll());
}
this.componentManager.sendPacket(this.component, packet);
} else {
queue.add(packet);
logger.log(Level.FINE, "jabberendpoint.sendpacketenqueue", packet.getFrom());
}
}
/** The backlog queue. */
private final ConcurrentLinkedQueue<Packet> queue = new ConcurrentLinkedQueue<Packet>();
/** The logger. */
final static private Logger logger = Logger.getLogger("JabberEndpoint", "gateway_i18n");
/**
* @see org.jivesoftware.wildfire.gateway.Endpoint#getValve()
*/
public EndpointValve getValve() {
return this.valve;
}
}
package org.jivesoftware.wildfire.gateway;
/**
* {@code SessionFactory} is used to generate a new {@code GatewaySession}.
*
* @author Noah Campbell
* @version 1.0
*/
public interface SessionFactory {
/**
* Return a new instance of a {@code GatewaySession}.
*
* @param info The subscription information for the session.
* @return gatewaySession The gateway session.
*/
public GatewaySession newInstance(SubscriptionInfo info);
}
package org.jivesoftware.wildfire.gateway;
import java.io.Serializable;
import org.xmpp.packet.JID;
/**
* <code>SubscriptionInfo</code> contains all the information that pertains to
* a legacy gateway that must be persisted across sessions. For example,
* username and password are stored so the user does not have to enter the
* information repeatedly.
*
* @author Noah Campbell
* @version 1.0
*/
public class SubscriptionInfo implements Serializable {
/**
* Construct a new <code>SubscriptionInfo</code>
* @param username The username
* @param password The password
*/
public SubscriptionInfo(String username, String password) {
this.username = username;
this.password = password;
}
/**
* Has the session been registered on the client?
*/
public boolean clientRegistered;
/**
* Has the server registered with the client?
*/
public boolean serverRegistered;
/**
* The username.
*/
public String username;
/**
* The password.
*/
public String password;
/**
* The jid.
*
* @see org.xmpp.packet.JID
*/
public transient JID jid;
}
/**
* $Revision$
* $Date$
*
* Copyright (C) 2006 Jive Software. 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.
*
* Heavily inspired by joscardemo of the Joust Project: http://joust.kano.net/
*/
package org.jivesoftware.wildfire.gateway.protocols.oscar;
import org.jivesoftware.util.Log;
import net.kano.joscar.*;
import net.kano.joscar.flap.*;
import net.kano.joscar.flapcmd.*;
import net.kano.joscar.net.*;
import net.kano.joscar.snac.*;
import net.kano.joscar.snaccmd.*;
import net.kano.joscar.snaccmd.conn.*;
import net.kano.joscar.snaccmd.icbm.*;
import net.kano.joscar.snaccmd.loc.*;
import net.kano.joscar.snaccmd.ssi.*;
import net.kano.joscar.ssiitem.*;
import java.net.InetAddress;
public class BOSConnection extends BasicFlapConnection {
protected SsiItemObjectFactory itemFactory = new DefaultSsiItemObjFactory();
public BOSConnection(OSCARGatewaySession mainSession, ByteBlock cookie) {
super(mainSession, cookie); // HAnd off to BasicFlapConnection
}
public BOSConnection(String host, int port, OSCARGatewaySession mainSession, ByteBlock cookie) {
super(host, port, mainSession, cookie); // HAnd off to BasicFlapConnection
}
public BOSConnection(InetAddress ip, int port, OSCARGatewaySession mainSession, ByteBlock cookie) {
super(ip, port, mainSession, cookie); // HAnd off to BasicFlapConnection
}
protected void handleStateChange(ClientConnEvent e) {
Log.debug("main connection state changed from "
+ e.getOldState() + " to " + e.getNewState() + ": "
+ e.getReason());
}
protected void handleFlapPacket(FlapPacketEvent e) {
super.handleFlapPacket(e);
}
protected void handleSnacPacket(SnacPacketEvent e) {
super.handleSnacPacket(e);
SnacCommand cmd = e.getSnacCommand();
if (cmd instanceof ServerReadyCmd) {
request(new ParamInfoRequest());
request(new LocRightsRequest());
request(new SsiRightsRequest());
request(new SsiDataRequest());
}
}
protected void handleSnacResponse(SnacResponseEvent e) {
super.handleSnacResponse(e);
SnacCommand cmd = e.getSnacCommand();
if (cmd instanceof LocRightsCmd) {
request(new SetInfoCmd(new InfoData("oscargateway",
null, new CapabilityBlock[] {
CapabilityBlock.BLOCK_ICQCOMPATIBLE,
}, null)));
request(new MyInfoRequest());
} else if (cmd instanceof ParamInfoCmd) {
ParamInfoCmd pic = (ParamInfoCmd) cmd;
ParamInfo info = pic.getParamInfo();
request(new SetParamInfoCmd(new ParamInfo(0,
info.getFlags() | ParamInfo.FLAG_TYPING_NOTIFICATION, 8000,
info.getMaxSenderWarning(), info.getMaxReceiverWarning(),
0)));
} else if (cmd instanceof YourInfoCmd) {
YourInfoCmd yic = (YourInfoCmd) cmd;
FullUserInfo info = yic.getUserInfo();
Log.debug("got my user info: " + info);
} else if (cmd instanceof UserInfoCmd) {
UserInfoCmd uic = (UserInfoCmd) cmd;
String sn = uic.getUserInfo().getScreenname();
Log.debug("user info for " + sn + ": "
+ uic.getInfoData());
} else if (cmd instanceof ServiceRedirect) {
ServiceRedirect sr = (ServiceRedirect) cmd;
Log.debug("connecting to " + sr.getRedirectHost()
+ " for 0x" + Integer.toHexString(sr.getSnacFamily()));
session.connectToService(sr.getSnacFamily(), sr.getRedirectHost(),
sr.getCookie());
} else if (cmd instanceof SsiDataCmd) {
SsiDataCmd sdc = (SsiDataCmd) cmd;
SsiItem[] items = sdc.getItems();
for (int i = 0; i < items.length; i++) {
SsiItemObj obj = itemFactory.getItemObj(items[i]);
if (obj instanceof BuddyItem) {
session.gotBuddy((BuddyItem)obj);
}
else if (obj instanceof GroupItem) {
session.gotGroup((GroupItem)obj);
}
Log.debug("- " + (obj == null ? (Object) items[i]
: (Object) obj));
}
if (sdc.getLastModDate() != 0) {
Log.debug("done with SSI");
request(new ActivateSsiCmd());
clientReady();
}
}
}
}
/**
* $Revision$
* $Date$
*
* Copyright (C) 2006 Jive Software. 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.
*
* Heavily inspired by joscardemo of the Joust Project: http://joust.kano.net/
*/
package org.jivesoftware.wildfire.gateway.protocols.oscar;
import org.jivesoftware.util.Log;
import net.kano.joscar.flap.*;
import net.kano.joscar.flapcmd.*;
import net.kano.joscar.net.*;
import net.kano.joscar.snac.*;
import net.kano.joscar.snaccmd.*;
import java.net.InetAddress;
public abstract class BaseFlapConnection extends ClientFlapConn {
protected ClientSnacProcessor sp;
OSCARGatewaySession session;
public BaseFlapConnection(OSCARGatewaySession mainSession) {
initBaseFlapConnection();
session = mainSession;
}
public BaseFlapConnection(String host, int port, OSCARGatewaySession mainSession) {
super(host, port); // Hand off to ClientFlapConn
initBaseFlapConnection();
session = mainSession;
}
public BaseFlapConnection(InetAddress ip, int port, OSCARGatewaySession mainSession) {
super(ip, port); // Hand off to ClientFlapConn
initBaseFlapConnection();
session = mainSession;
}
private void initBaseFlapConnection() {
FlapProcessor fp = getFlapProcessor();
sp = new ClientSnacProcessor(fp);
fp.setFlapCmdFactory(new DefaultFlapCmdFactory());
sp.addPreprocessor(new FamilyVersionPreprocessor());
sp.getCmdFactoryMgr().setDefaultFactoryList(new DefaultClientFactoryList());
addConnListener(new ClientConnListener() {
public void stateChanged(ClientConnEvent e) {
handleStateChange(e);
}
});
getFlapProcessor().addPacketListener(new FlapPacketListener() {
public void handleFlapPacket(FlapPacketEvent e) {
BaseFlapConnection.this.handleFlapPacket(e);
}
});
getFlapProcessor().addExceptionHandler(new FlapExceptionHandler() {
public void handleException(FlapExceptionEvent event) {
Log.error(event.getType() + " FLAP ERROR: "
+ event.getException().getMessage());
// How do do this right?
//Log.error(event.getException().printStackTrace());
}
});
sp.addPacketListener(new SnacPacketListener() {
public void handleSnacPacket(SnacPacketEvent e) {
BaseFlapConnection.this.handleSnacPacket(e);
}
});
}
protected SnacRequestListener genericReqListener = new SnacRequestAdapter() {
public void handleResponse(SnacResponseEvent e) {
handleSnacResponse(e);
}
};
public SnacRequestListener getGenericReqListener() {
return genericReqListener;
}
public ClientSnacProcessor getSnacProcessor() {
return sp;
}
public OSCARGatewaySession getMainSession() { return session; }
void sendRequest(SnacRequest req) {
if (!req.hasListeners()) req.addListener(genericReqListener);
sp.sendSnac(req);
}
SnacRequest request(SnacCommand cmd) {
return request(cmd, null);
}
SnacRequest request(SnacCommand cmd, SnacRequestListener listener) {
SnacRequest req = new SnacRequest(cmd, listener);
sendRequest(req);
return req;
}
protected abstract void handleStateChange(ClientConnEvent e);
protected abstract void handleFlapPacket(FlapPacketEvent e);
protected abstract void handleSnacPacket(SnacPacketEvent e);
protected abstract void handleSnacResponse(SnacResponseEvent e);
}
/**
* $Revision$
* $Date$
*
* Copyright (C) 2006 Jive Software. 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.
*
* Heavily inspired by joscardemo of the Joust Project: http://joust.kano.net/
*/
package org.jivesoftware.wildfire.gateway.protocols.oscar;
import org.jivesoftware.util.Log;
import net.kano.joscar.*;
import net.kano.joscar.flap.*;
import net.kano.joscar.flapcmd.*;
import net.kano.joscar.ratelim.*;
import net.kano.joscar.rv.*;
import net.kano.joscar.rvcmd.*;
import net.kano.joscar.rvcmd.addins.*;
import net.kano.joscar.rvcmd.chatinvite.*;
import net.kano.joscar.rvcmd.directim.*;
import net.kano.joscar.rvcmd.getfile.*;
import net.kano.joscar.rvcmd.icon.*;
import net.kano.joscar.rvcmd.sendbl.*;
import net.kano.joscar.rvcmd.sendfile.*;
import net.kano.joscar.snac.*;
import net.kano.joscar.snaccmd.*;
import net.kano.joscar.snaccmd.buddy.*;
import net.kano.joscar.snaccmd.conn.*;
import net.kano.joscar.snaccmd.icbm.*;
import net.kano.joscar.snaccmd.rooms.*;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.xmpp.packet.Message;
public abstract class BasicFlapConnection extends BaseFlapConnection {
protected final ByteBlock cookie;
protected boolean sentClientReady = false;
protected int[] snacFamilies = null;
protected SnacFamilyInfo[] snacFamilyInfos;
protected RateLimitingQueueMgr rateMgr = new RateLimitingQueueMgr();
protected RvProcessor rvProcessor = new RvProcessor(sp);
protected RvProcessorListener rvListener = new RvProcessorListener() {
public void handleNewSession(NewRvSessionEvent event) {
Log.debug("new RV session: " + event.getSession());
event.getSession().addListener(rvSessionListener);
}
};
protected RvSessionListener rvSessionListener = new RvSessionListener() {
public void handleRv(RecvRvEvent event) {
RvCommand cmd = event.getRvCommand();
RvSession session = event.getRvSession();
SnacCommand snaccmd = event.getSnacCommand();
if (!(snaccmd instanceof RecvRvIcbm)) return;
RecvRvIcbm icbm = (RecvRvIcbm) snaccmd;
Log.debug("got rendezvous on session <" + session + ">");
Log.debug("- command: " + cmd);
}
public void handleSnacResponse(RvSnacResponseEvent event) {
Log.debug("got SNAC response for <"
+ event.getRvSession() + ">: "
+ event.getSnacCommand());
}
};
{ // init
sp.setSnacQueueManager(rateMgr);
rvProcessor.registerRvCmdFactory(new DefaultRvCommandFactory());
rvProcessor.addListener(rvListener);
}
public BasicFlapConnection(OSCARGatewaySession mainSession, ByteBlock cookie) {
super(mainSession);
this.cookie = cookie;
}
public BasicFlapConnection(String host, int port, OSCARGatewaySession mainSession, ByteBlock cookie) {
super(host, port, mainSession);
this.cookie = cookie;
}
public BasicFlapConnection(InetAddress ip, int port, OSCARGatewaySession mainSession,
ByteBlock cookie) {
super(ip, port, mainSession);
this.cookie = cookie;
}
protected DateFormat dateFormat
= DateFormat.getDateTimeInstance(DateFormat.SHORT,
DateFormat.SHORT);
protected void handleFlapPacket(FlapPacketEvent e) {
FlapCommand cmd = e.getFlapCommand();
if (cmd instanceof LoginFlapCmd) {
getFlapProcessor().sendFlap(new LoginFlapCmd(cookie));
} else {
Log.debug("got FLAP command on channel 0x"
+ Integer.toHexString(e.getFlapPacket().getChannel())
+ ": " + cmd);
}
}
protected void handleSnacPacket(SnacPacketEvent e) {
SnacPacket packet = e.getSnacPacket();
Log.debug("got snac packet type "
+ Integer.toHexString(packet.getFamily()) + "/"
+ Integer.toHexString(packet.getCommand()) + ": "
+ e.getSnacCommand());
SnacCommand cmd = e.getSnacCommand();
if (cmd instanceof ServerReadyCmd) {
ServerReadyCmd src = (ServerReadyCmd) cmd;
setSnacFamilies(src.getSnacFamilies());
SnacFamilyInfo[] familyInfos = SnacFamilyInfoFactory
.getDefaultFamilyInfos(src.getSnacFamilies());
setSnacFamilyInfos(familyInfos);
session.registerSnacFamilies(this);
request(new ClientVersionsCmd(familyInfos));
request(new RateInfoRequest());
} else if (cmd instanceof RecvImIcbm) {
RecvImIcbm icbm = (RecvImIcbm) cmd;
String sn = icbm.getSenderInfo().getScreenname();
InstantMessage message = icbm.getMessage();
String msg = null;
msg = OscarTools.stripHtml(message.getMessage());
Message jmessage = new Message();
jmessage.setTo(session.getSessionJID());
jmessage.setBody(msg);
jmessage.setType(Message.Type.chat);
jmessage.setFrom(this.session.getGateway().whois(sn));
try {
session.getJabberEndpoint().sendPacket(jmessage);
}
catch (Exception ex) {
Log.error("Unable to send packet.");
}
//sendRequest(new SnacRequest(new SendImIcbm(sn, msg), null));
String str = dateFormat.format(new Date()) + " IM from "
+ sn + ": " + msg;
Log.debug(str);
} else if (cmd instanceof WarningNotification) {
WarningNotification wn = (WarningNotification) cmd;
MiniUserInfo warner = wn.getWarner();
if (warner == null) {
Log.debug("*** You were warned anonymously to "
+ wn.getNewLevel() + "%");
} else {
Log.debug("*** " + warner.getScreenname()
+ " warned you up to " + wn.getNewLevel() + "%");
}
} else if (cmd instanceof BuddyStatusCmd) {
BuddyStatusCmd bsc = (BuddyStatusCmd) cmd;
FullUserInfo info = bsc.getUserInfo();
String sn = info.getScreenname();
ExtraInfoBlock[] extraInfos = info.getExtraInfoBlocks();
if (extraInfos != null) {
for (int i = 0; i < extraInfos.length; i++) {
ExtraInfoBlock extraInfo = extraInfos[i];
ExtraInfoData data = extraInfo.getExtraData();
if (extraInfo.getType() == ExtraInfoBlock.TYPE_AVAILMSG) {
ByteBlock msgBlock = data.getData();
int len = BinaryTools.getUShort(msgBlock, 0);
byte[] msgBytes = msgBlock.subBlock(2, len).toByteArray();
String msg;
try {
msg = new String(msgBytes, "UTF-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
return;
}
if (msg.length() > 0) {
Log.debug(info.getScreenname()
+ " availability: " + msg);
}
}
}
}
if (info.getCapabilityBlocks() != null) {
List known = Arrays.asList(new CapabilityBlock[] {
CapabilityBlock.BLOCK_ICQCOMPATIBLE,
});
List caps = new ArrayList(Arrays.asList(
info.getCapabilityBlocks()));
caps.removeAll(known);
if (!caps.isEmpty()) {
Log.debug(sn + " has " + caps.size()
+ " unknown caps:");
for (Iterator it = caps.iterator(); it.hasNext();) {
Log.debug("- " + it.next());
}
}
/*
caps = new ArrayList(known);
caps.removeAll(Arrays.asList(info.getCapabilityBlocks()));
if (!caps.isEmpty()) {
Log.debug(sn + " is missing " + caps.size()
+ " caps:");
for (Iterator it = caps.iterator(); it.hasNext();) {
Log.debug("- " + it.next());
}
}
*/
}
} else if (cmd instanceof BuddyOfflineCmd) {
BuddyOfflineCmd boc = (BuddyOfflineCmd) cmd;
} else if (cmd instanceof RateChange) {
RateChange rc = (RateChange) cmd;
Log.debug("rate change: current avg is "
+ rc.getRateInfo().getCurrentAvg());
}
}
protected void handleSnacResponse(SnacResponseEvent e) {
SnacPacket packet = e.getSnacPacket();
Log.debug("got snac response type "
+ Integer.toHexString(packet.getFamily()) + "/"
+ Integer.toHexString(packet.getCommand()) + ": "
+ e.getSnacCommand());
SnacCommand cmd = e.getSnacCommand();
if (cmd instanceof RateInfoCmd) {
RateInfoCmd ric = (RateInfoCmd) cmd;
RateClassInfo[] rateClasses = ric.getRateClassInfos();
int[] classes = new int[rateClasses.length];
for (int i = 0; i < rateClasses.length; i++) {
classes[i] = rateClasses[i].getRateClass();
// Log.debug("- " + rateClasses[i] + ": " + Arrays.asList(rateClasses[i].getCommands()));
}
request(new RateAck(classes));
}
}
public int[] getSnacFamilies() { return snacFamilies; }
protected void setSnacFamilies(int[] families) {
this.snacFamilies = (int[]) families.clone();
Arrays.sort(snacFamilies);
}
protected void setSnacFamilyInfos(SnacFamilyInfo[] infos) {
snacFamilyInfos = infos;
}
protected boolean supportsFamily(int family) {
return Arrays.binarySearch(snacFamilies, family) >= 0;
}
protected void clientReady() {
if (!sentClientReady) {
sentClientReady = true;
request(new ClientReadyCmd(snacFamilyInfos));
}
}
protected SnacRequest dispatchRequest(SnacCommand cmd) {
return dispatchRequest(cmd, null);
}
protected SnacRequest dispatchRequest(SnacCommand cmd,
SnacRequestListener listener) {
SnacRequest req = new SnacRequest(cmd, listener);
dispatchRequest(req);
return req;
}
protected void dispatchRequest(SnacRequest req) {
session.handleRequest(req);
}
protected SnacRequest request(SnacCommand cmd,
SnacRequestListener listener) {
SnacRequest req = new SnacRequest(cmd, listener);
handleReq(req);
return req;
}
private void handleReq(SnacRequest request) {
int family = request.getCommand().getFamily();
if (snacFamilies == null || supportsFamily(family)) {
// this connection supports this snac, so we'll send it here
sendRequest(request);
} else {
session.handleRequest(request);
}
}
}
/**
* $Revision$
* $Date$
*
* Copyright (C) 2006 Jive Software. 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.
*
* Heavily inspired by joscardemo of the Joust Project: http://joust.kano.net/
*/
package org.jivesoftware.wildfire.gateway.protocols.oscar;
import org.jivesoftware.util.Log;
import net.kano.joscar.*;
import net.kano.joscar.tlv.*;
import net.kano.joscar.flap.*;
import net.kano.joscar.flapcmd.*;
import net.kano.joscar.net.*;
import net.kano.joscar.snac.*;
import net.kano.joscar.snaccmd.auth.*;
import net.kano.joscar.snaccmd.chat.*;
import java.net.InetAddress;
public class LoginConnection extends BaseFlapConnection {
protected boolean loggedin = false;
public LoginConnection(OSCARGatewaySession mainSession) {
super(mainSession); // Hand off to BaseFlapConnection
}
public LoginConnection(String host, int port, OSCARGatewaySession mainSession) {
super(host, port, mainSession); // Hand off to BaseFlapConnection
}
public LoginConnection(InetAddress ip, int port, OSCARGatewaySession mainSession) {
super(ip, port, mainSession); // Hand off to BaseFlapConnection
}
protected void handleStateChange(ClientConnEvent e) {
Log.debug("state changed to: " + e.getNewState() + " (" + e.getReason() + ")");
if (e.getNewState() == ClientFlapConn.STATE_CONNECTED) {
Log.debug("connected, sending flap version and key request");
getFlapProcessor().sendFlap(new LoginFlapCmd());
request(new KeyRequest(session.getLegacyName()));
}
else if (e.getNewState() == ClientFlapConn.STATE_FAILED) {
Log.info("connection failed: " + e.getReason());
}
else if (e.getNewState() == ClientFlapConn.STATE_NOT_CONNECTED) {
if (!loggedin) {
Log.info("connection lost: " + e.getReason());
}
}
}
protected void handleFlapPacket(FlapPacketEvent e) { }
protected void handleSnacPacket(SnacPacketEvent e) { }
protected void handleSnacResponse(SnacResponseEvent e) {
SnacCommand cmd = e.getSnacCommand();
Log.debug("snac response: "
+ Integer.toHexString(cmd.getFamily()) + "/"
+ Integer.toHexString(cmd.getCommand()) + ": " + cmd);
if (cmd instanceof KeyResponse) {
KeyResponse kr = (KeyResponse) cmd;
ByteBlock authkey = kr.getKey();
ClientVersionInfo version = new ClientVersionInfo(
"AOL Instant Messenger, version 5.2.3292/WIN32",
5, 1, 0, 3292, 238);
request(new AuthRequest(
session.getLegacyName(), session.getLegacyPassword(),
version, authkey));
} else if (cmd instanceof AuthResponse) {
AuthResponse ar = (AuthResponse) cmd;
int error = ar.getErrorCode();
if (error != -1) {
Log.error("connection error! code: " + error);
if (ar.getErrorUrl() != null) {
Log.error("Error URL: " + ar.getErrorUrl());
}
} else {
loggedin = true;
session.startBosConn(ar.getServer(), ar.getPort(),
ar.getCookie());
Log.info("connecting to " + ar.getServer() + ":"
+ ar.getPort());
}
disconnect();
}
}
}
/**
* $Revision$
* $Date$
*
* Copyright (C) 2006 Jive Software. 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 org.jivesoftware.wildfire.gateway.protocols.oscar;
import org.jivesoftware.util.Log;
import org.jivesoftware.wildfire.gateway.Gateway;
import org.jivesoftware.wildfire.gateway.roster.AbstractForeignContact;
import org.jivesoftware.wildfire.gateway.roster.Status;
import net.kano.joscar.snaccmd.ssi.*;
import net.kano.joscar.ssiitem.*;
/**
* @author Daniel Henninger
* @version 1.0
*/
public class OSCARForeignContact extends AbstractForeignContact {
private BuddyItem ssiItem;
private String oscarStatus = "offline";
public OSCARForeignContact(BuddyItem ssiItem, Gateway gateway) {
super(ssiItem.getScreenname(), new Status(), gateway);
this.ssiItem = ssiItem;
}
public Status getStatus() {
getStatusMessage(ssiItem, this.status);
return super.status;
}
public void setStatus(String oscarStatus) {
this.oscarStatus = oscarStatus;
}
private Status getStatusMessage(BuddyItem issiItem, Status status) {
status.setOnline(true);
// We need to check other statuses here, keep track of them somehow.
return status;
}
public String getName() {
return ssiItem.getScreenname();
}
public SsiItem getSSIItem() {
return ssiItem.toSsiItem();
}
}
/**
* $Revision$
* $Date$
*
* Copyright (C) 2006 Jive Software. 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 org.jivesoftware.wildfire.gateway.protocols.oscar;
import java.util.logging.Logger;
import org.jivesoftware.util.Log;
import org.jivesoftware.wildfire.gateway.BaseGateway;
import org.jivesoftware.wildfire.gateway.GatewaySession;
import org.jivesoftware.wildfire.gateway.SubscriptionInfo;
import org.xmpp.component.ComponentException;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
/**
* @author Daniel Henninger
* @version 1.0
*/
public class OSCARGateway extends BaseGateway {
/* Gateway Name String */
private static String NameString = "oscar";
@Override
public String getName() {
return NameString;
}
@Override
public void setName(String newname) {
NameString = newname;
}
@Override
public String getDescription() {
return "OSCAR (AIM/ICQ) Gateway";
}
/*@SuppressWarnings("unused"); */
public void sendPacket(@SuppressWarnings("unused") Packet packet) throws ComponentException {
// Do nothing
}
public void sendMessage(JID jid, String string) throws Exception {
Message m = new Message();
m.setTo(jid);
m.setBody(string);
this.sendPacket(m);
}
@Override
public String getType() {
return "oscar";
}
@Override
public String getVersion() {
return "v1.0";
}
@Override
protected GatewaySession getSessionInstance(SubscriptionInfo info) {
Log.debug("Getting session instance");
return new OSCARGatewaySession(info, this);
}
}
package org.jivesoftware.wildfire.gateway.protocols.oscar;
import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.HashSet;
import org.jivesoftware.util.Log;
import org.jivesoftware.wildfire.gateway.AbstractGatewaySession;
import org.jivesoftware.wildfire.gateway.Endpoint;
import org.jivesoftware.wildfire.gateway.EndpointValve;
import org.jivesoftware.wildfire.gateway.Gateway;
import org.jivesoftware.wildfire.gateway.JabberEndpoint;
import org.jivesoftware.wildfire.gateway.SubscriptionInfo;
import org.jivesoftware.wildfire.gateway.roster.AbstractForeignContact;
import org.jivesoftware.wildfire.gateway.roster.ForeignContact;
import org.jivesoftware.wildfire.gateway.roster.NormalizedJID;
import org.jivesoftware.wildfire.gateway.roster.PersistenceManager;
import org.jivesoftware.wildfire.gateway.roster.UnknownForeignContactException;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence;
import net.kano.joscar.flap.*;
import net.kano.joscar.flapcmd.*;
import net.kano.joscar.snac.*;
import net.kano.joscar.snaccmd.*;
import net.kano.joscar.snaccmd.auth.*;
import net.kano.joscar.snaccmd.conn.*;
import net.kano.joscar.snaccmd.icbm.*;
import net.kano.joscar.snaccmd.ssi.*;
import net.kano.joscar.ssiitem.*;
import net.kano.joscar.ByteBlock;
/**
* Manages the session to the underlying legacy system.
*
* @author Daniel Henninger
* @version 1.0
*/
public class OSCARGatewaySession extends AbstractGatewaySession implements Endpoint {
/**
* OSCAR Session Pieces
*/
private LoginConnection loginConn = null;
private BOSConnection bosConn = null;
private Set services = new HashSet();
private Boolean connected = false;
/**
* The Screenname, Password, and JID associated with this session.
*/
private JID jid;
private String legacyname = null;
private String legacypass = null;
/**
* Misc tracking variables.
*/
private ArrayList<ForeignContact> contacts = new ArrayList<ForeignContact>();
private ArrayList<GroupItem> groups = new ArrayList<GroupItem>();
private Integer highestBuddyId = -1;
private Integer highestGroupId = -1;
/**
* Initialize a new session object for OSCAR
*
* @param info The subscription information to use during login.
* @param gateway The gateway that created this session.
*/
public OSCARGatewaySession(SubscriptionInfo info, Gateway gateway) {
super(info, gateway);
this.jid = info.jid;
this.legacyname = info.username;
this.legacypass = info.password;
}
public synchronized void login() throws Exception {
Log.debug("Login called");
if (!isConnected()) {
Log.debug("Connecting...");
loginConn = new LoginConnection("login.oscar.aol.com", 5190, this);
loginConn.connect();
getJabberEndpoint().getValve().open(); // allow any buffered messages to pass through
connected = true;
} else {
Log.warn(this.jid + " is already logged in");
}
}
public boolean isConnected() {
Log.debug("isConnected called");
return connected;
}
public synchronized void logout() throws Exception {
Log.debug("logout called");
Log.info("[" + this.jid + "]" + getSubscriptionInfo().username + " logged out.");
bosConn.disconnect();
connected = false;
}
@Override
public String toString() { return "[" + this.getSubscriptionInfo().username + " CR:" + clientRegistered + " SR:" + serverRegistered + "]"; }
public String getId() {
Log.debug("getId called");
return this.jid.toBareJID();
}
public String getLegacyName() {
Log.debug("getLegacyName called");
return this.legacyname;
}
public String getLegacyPassword() {
Log.debug("getLegacyPassword called");
return this.legacypass;
}
@SuppressWarnings("unchecked")
public List<ForeignContact> getContacts() {
Log.debug("getContacts called");
return contacts;
}
public JID getSessionJID() {
Log.debug("getSessionJID called");
return this.jid;
}
public JID getJID() {
Log.debug("getJID called");
return this.jid;
}
public String getStatus(JID to) {
Log.debug("getStatus called");
for (ForeignContact c : contacts) {
if (c.getName() == to.getNode()) {
return c.getStatus().getValue();
}
}
return null;
}
public void addContact(JID jid) throws Exception {
Log.debug("addContact called");
Integer newBuddyId = highestBuddyId + 1;
Integer groupId = -1;
for (GroupItem g : groups) {
if (g.getGroupName() == "Transport Buddies") {
groupId = g.getId();
}
}
if (groupId == -1) {
Integer newGroupId = highestGroupId + 1;
request(new CreateItemsCmd(new SsiItem[] {
new GroupItem("Transport Buddies", newGroupId).toSsiItem() }));
highestGroupId = newGroupId;
groupId = newGroupId;
}
request(new CreateItemsCmd(new SsiItem[] {
new BuddyItem(jid.getNode(), newBuddyId, groupId).toSsiItem() }));
}
public void removeContact(JID jid) throws Exception {
Log.debug("removeContact called");
for (ForeignContact c : contacts) {
if (c.getName() == jid.getNode()) {
OSCARForeignContact oc = (OSCARForeignContact)c;
request(new DeleteItemsCmd(new SsiItem[] { oc.getSSIItem() }));
contacts.remove(contacts.indexOf(c));
}
}
}
public void sendPacket(Packet packet) {
Log.debug("sendPacket called:"+packet.toString());
if (packet instanceof Message) {
Message m = (Message)packet;
request(new SendImIcbm(packet.getTo().getNode(), m.getBody()));
}
}
public ForeignContact getContact(JID to) throws UnknownForeignContactException {
Log.debug("getContact called");
for (ForeignContact c : contacts) {
if (c.getName() == to.getNode()) {
return c;
}
}
return null;
}
void startBosConn(String server, int port, ByteBlock cookie) {
bosConn = new BOSConnection(server, port, this, cookie);
bosConn.connect();
}
void registerSnacFamilies(BasicFlapConnection conn) {
snacMgr.register(conn);
}
protected SnacManager snacMgr = new SnacManager(new PendingSnacListener() {
public void dequeueSnacs(SnacRequest[] pending) {
Log.debug("dequeuing " + pending.length + " snacs");
for (int i = 0; i < pending.length; i++) {
handleRequest(pending[i]);
}
}
});
synchronized void handleRequest(SnacRequest request) {
int family = request.getCommand().getFamily();
if (snacMgr.isPending(family)) {
snacMgr.addRequest(request);
return;
}
BasicFlapConnection conn = snacMgr.getConn(family);
if (conn != null) {
conn.sendRequest(request);
} else {
// it's time to request a service
if (!(request.getCommand() instanceof ServiceRequest)) {
Log.debug("requesting " + Integer.toHexString(family)
+ " service.");
snacMgr.setPending(family, true);
snacMgr.addRequest(request);
request(new ServiceRequest(family));
} else {
Log.error("eep! can't find a service redirector server.");
}
}
}
SnacRequest request(SnacCommand cmd) {
return request(cmd, null);
}
private SnacRequest request(SnacCommand cmd, SnacRequestListener listener) {
SnacRequest req = new SnacRequest(cmd, listener);
handleRequest(req);
return req;
}
void connectToService(int snacFamily, String host, ByteBlock cookie) {
ServiceConnection conn = new ServiceConnection(host, 5190, this,
cookie, snacFamily);
conn.connect();
}
void serviceFailed(ServiceConnection conn) {
}
void serviceConnected(ServiceConnection conn) {
services.add(conn);
}
void serviceReady(ServiceConnection conn) {
snacMgr.dequeueSnacs(conn);
}
void serviceDied(ServiceConnection conn) {
services.remove(conn);
snacMgr.unregister(conn);
}
void gotBuddy(BuddyItem buddy) {
contacts.add(new OSCARForeignContact(buddy, this.gateway));
if (buddy.getId() > highestBuddyId) {
highestBuddyId = buddy.getId();
}
}
void gotGroup(GroupItem group) {
groups.add(group);
if (group.getId() > highestGroupId) {
highestGroupId = group.getId();
}
}
}
/**
* $Revision$
* $Date$
*
* Copyright (C) 2006 Jive Software. 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.
*
* Heavily inspired by joscardemo of the Joust Project: http://joust.kano.net/
*/
package org.jivesoftware.wildfire.gateway.protocols.oscar;
import org.jivesoftware.util.Log;
import net.kano.joscar.snac.SnacRequest;
public interface PendingSnacListener {
void dequeueSnacs(SnacRequest[] pending);
}
/**
* $Revision$
* $Date$
*
* Copyright (C) 2006 Jive Software. 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.
*
* Heavily inspired by joscardemo of the Joust Project: http://joust.kano.net/
*/
package org.jivesoftware.wildfire.gateway.protocols.oscar;
import org.jivesoftware.util.Log;
import net.kano.joscar.snac.SnacRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PendingSnacMgr {
protected Map snacs = new HashMap();
public boolean isPending(int familyCode) {
Integer family = new Integer(familyCode);
return snacs.containsKey(family);
}
public void add(SnacRequest request) {
Integer family = new Integer(request.getCommand().getFamily());
List pending = (List) snacs.get(family);
pending.add(request);
}
public SnacRequest[] getPending(int familyCode) {
Integer family = new Integer(familyCode);
List pending = (List) snacs.get(family);
return (SnacRequest[]) pending.toArray(new SnacRequest[0]);
}
public void setPending(int familyCode, boolean pending) {
Integer family = new Integer(familyCode);
if (pending) snacs.put(family, new ArrayList());
else snacs.remove(family);
}
}
/**
* $Revision$
* $Date$
*
* Copyright (C) 2006 Jive Software. 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.
*
* Heavily inspired by joscardemo of the Joust Project: http://joust.kano.net/
*/
package org.jivesoftware.wildfire.gateway.protocols.oscar;
import org.jivesoftware.util.Log;
import net.kano.joscar.*;
import net.kano.joscar.flap.*;
import net.kano.joscar.flapcmd.*;
import net.kano.joscar.net.*;
import net.kano.joscar.snac.*;
import net.kano.joscar.snaccmd.*;
import net.kano.joscar.snaccmd.conn.*;
import net.kano.joscar.snaccmd.icon.*;
import net.kano.joscar.snaccmd.search.*;
import java.awt.Image;
import java.awt.Toolkit;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class ServiceConnection extends BasicFlapConnection {
protected int serviceFamily;
public ServiceConnection(OSCARGatewaySession mainSession, ByteBlock cookie, int serviceFamily) {
super(mainSession, cookie);
this.serviceFamily = serviceFamily;
}
public ServiceConnection(String host, int port, OSCARGatewaySession mainSession, ByteBlock cookie, int serviceFamily) {
super(host, port, mainSession, cookie);
this.serviceFamily = serviceFamily;
}
public ServiceConnection(InetAddress ip, int port, OSCARGatewaySession mainSession, ByteBlock cookie, int serviceFamily) {
super(ip, port, mainSession, cookie);
this.serviceFamily = serviceFamily;
}
protected void clientReady() {
session.serviceReady(this);
super.clientReady();
}
protected void handleStateChange(ClientConnEvent e) {
Log.debug("0x" + Integer.toHexString(serviceFamily)
+ " service connection state changed to " + e.getNewState()
+ ": " + e.getReason());
if (e.getNewState() == ClientFlapConn.STATE_FAILED) {
session.serviceFailed(this);
} else if (e.getNewState() == ClientFlapConn.STATE_CONNECTED) {
session.serviceConnected(this);
} else if (e.getNewState() == ClientFlapConn.STATE_NOT_CONNECTED) {
session.serviceDied(this);
}
}
protected void handleFlapPacket(FlapPacketEvent e) {
super.handleFlapPacket(e);
}
protected void handleSnacPacket(SnacPacketEvent e) {
super.handleSnacPacket(e);
}
protected void handleSnacResponse(SnacResponseEvent e) {
super.handleSnacResponse(e);
SnacCommand cmd = e.getSnacCommand();
if (cmd instanceof RateInfoCmd) {
// this is all we need.
clientReady();
} else if (cmd instanceof InterestListCmd) {
InterestListCmd ilc = (InterestListCmd) cmd;
InterestInfo[] infos = ilc.getInterests();
if (infos != null) {
Map children = new HashMap();
for (int i = 0; i < infos.length; i++) {
if (infos[i].getType() == InterestInfo.TYPE_CHILD) {
int parentCode = infos[i].getParentId();
Integer parent = new Integer(parentCode);
List interests = (List) children.get(parent);
if (interests == null) {
interests = new LinkedList();
children.put(parent, interests);
}
interests.add(infos[i]);
}
}
for (int i = 0; i < infos.length; i++) {
if (infos[i].getType() == InterestInfo.TYPE_PARENT) {
Integer id = new Integer(infos[i].getParentId());
List interests = (List) children.get(id);
Log.debug("- " + infos[i].getName());
if (interests != null) {
for (Iterator it = interests.iterator();
it.hasNext();) {
InterestInfo info = (InterestInfo) it.next();
Log.debug(" - " + info.getName());
}
}
}
}
List toplevels = (List) children.get(new Integer(0));
if (toplevels != null) {
for (Iterator it = toplevels.iterator(); it.hasNext();) {
Log.debug(" "
+ ((InterestInfo) it.next()).getName());
}
}
}
} else if (cmd instanceof SearchResultsCmd) {
SearchResultsCmd src = (SearchResultsCmd) cmd;
DirInfo[] results = src.getResults();
for (int i = 0; i < results.length; i++) {
Log.debug("result " + (i + 1) + ": " + results[i]);
}
} else if (cmd instanceof IconDataCmd) {
IconDataCmd idc = (IconDataCmd) cmd;
String sn = idc.getScreenname();
byte[] data = idc.getIconData().toByteArray();
Image icon = Toolkit.getDefaultToolkit().createImage(data);
// session.getUserInfo(sn).setIcon(icon);
}
}
}
/**
* $Revision$
* $Date$
*
* Copyright (C) 2006 Jive Software. 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.
*
* Heavily inspired by joscardemo of the Joust Project: http://joust.kano.net/
*/
package org.jivesoftware.wildfire.gateway.protocols.oscar;
import org.jivesoftware.util.Log;
import net.kano.joscar.snac.SnacRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class SnacManager {
protected Map conns = new HashMap();
protected PendingSnacMgr pendingSnacs = new PendingSnacMgr();
protected List listeners = new ArrayList();
protected Map supportedFamilies = new IdentityHashMap();
public SnacManager() { }
public SnacManager(PendingSnacListener listener) {
addListener(listener);
}
public void register(BasicFlapConnection conn) {
int[] families = conn.getSnacFamilies();
supportedFamilies.put(conn, families);
for (int i = 0; i < families.length; i++) {
int familyCode = families[i];
Integer family = new Integer(familyCode);
List handlers = (List) conns.get(family);
if (handlers == null) {
handlers = new LinkedList();
conns.put(family, handlers);
}
if (!handlers.contains(conn)) handlers.add(conn);
}
}
public void dequeueSnacs(BasicFlapConnection conn) {
int[] infos = (int[]) supportedFamilies.get(conn);
if (infos != null) {
for (int i = 0; i < infos.length; i++) {
int familyCode = infos[i];
if (pendingSnacs.isPending(familyCode)) {
dequeueSnacs(familyCode);
}
}
}
}
protected void dequeueSnacs(int familyCode) {
SnacRequest[] pending = pendingSnacs.getPending(familyCode);
pendingSnacs.setPending(familyCode, false);
for (Iterator it = listeners.iterator(); it.hasNext();) {
PendingSnacListener listener = (PendingSnacListener) it.next();
listener.dequeueSnacs(pending);
}
}
public void unregister(BasicFlapConnection conn) {
for (Iterator it = conns.values().iterator(); it.hasNext();) {
List handlers = (List) it.next();
handlers.remove(conn);
}
}
public BasicFlapConnection getConn(int familyCode) {
Integer family = new Integer(familyCode);
List handlers = (List) conns.get(family);
if (handlers == null || handlers.size() == 0) return null;
return (BasicFlapConnection) handlers.get(0);
}
public boolean isPending(int familyCode) {
return pendingSnacs.isPending(familyCode);
}
public void addRequest(SnacRequest request) {
pendingSnacs.add(request);
}
public void addListener(PendingSnacListener l) {
if (!listeners.contains(l)) listeners.add(l);
}
public void removeListener(PendingSnacListener l) {
listeners.remove(l);
}
public void setPending(int family, boolean pending) {
pendingSnacs.setPending(family, pending);
}
}
/**
*
*/
package org.jivesoftware.wildfire.gateway.protocols.yahoo;
import java.util.logging.Logger;
import ymsg.network.event.SessionChatEvent;
import ymsg.network.event.SessionConferenceEvent;
import ymsg.network.event.SessionErrorEvent;
import ymsg.network.event.SessionEvent;
import ymsg.network.event.SessionExceptionEvent;
import ymsg.network.event.SessionFileTransferEvent;
import ymsg.network.event.SessionFriendEvent;
import ymsg.network.event.SessionListener;
import ymsg.network.event.SessionNewMailEvent;
import ymsg.network.event.SessionNotifyEvent;
/**
* NoopSessionListener provides a mechanism to quickly create a SessionListener
* for the ymsg9 library.
*
* @author Noah Campbell
* @version 1.0
*/
public class NoopSessionListener implements SessionListener {
/** The logger. @see java.util.logging.Logger */
private static final Logger logger = Logger.getLogger("NoopSessionListener");
/**
* @see ymsg.network.event.SessionListener#fileTransferReceived(ymsg.network.event.SessionFileTransferEvent)
*/
/**
* @see ymsg.network.event.SessionListener#fileTransferReceived(ymsg.network.event.SessionFileTransferEvent)
*/
/**
* @see ymsg.network.event.SessionListener#fileTransferReceived(ymsg.network.event.SessionFileTransferEvent)
*/
public void fileTransferReceived(SessionFileTransferEvent arg0) {
logger.info(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#connectionClosed(ymsg.network.event.SessionEvent)
*/
public void connectionClosed(SessionEvent arg0) {
logger.info(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#listReceived(ymsg.network.event.SessionEvent)
*/
public void listReceived(SessionEvent arg0) {
logger.info(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#messageReceived(ymsg.network.event.SessionEvent)
*/
public void messageReceived(SessionEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#buzzReceived(ymsg.network.event.SessionEvent)
*/
public void buzzReceived(SessionEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#offlineMessageReceived(ymsg.network.event.SessionEvent)
*/
public void offlineMessageReceived(SessionEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#errorPacketReceived(ymsg.network.event.SessionErrorEvent)
*/
public void errorPacketReceived(SessionErrorEvent arg0) {
logger.severe(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#inputExceptionThrown(ymsg.network.event.SessionExceptionEvent)
*/
public void inputExceptionThrown(SessionExceptionEvent arg0) {
arg0.getException().printStackTrace();
logger.severe(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#newMailReceived(ymsg.network.event.SessionNewMailEvent)
*/
public void newMailReceived(SessionNewMailEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#notifyReceived(ymsg.network.event.SessionNotifyEvent)
*/
public void notifyReceived(SessionNotifyEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#contactRequestReceived(ymsg.network.event.SessionEvent)
*/
public void contactRequestReceived(SessionEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#contactRejectionReceived(ymsg.network.event.SessionEvent)
*/
public void contactRejectionReceived(SessionEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#conferenceInviteReceived(ymsg.network.event.SessionConferenceEvent)
*/
public void conferenceInviteReceived(SessionConferenceEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#conferenceInviteDeclinedReceived(ymsg.network.event.SessionConferenceEvent)
*/
public void conferenceInviteDeclinedReceived(SessionConferenceEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#conferenceLogonReceived(ymsg.network.event.SessionConferenceEvent)
*/
public void conferenceLogonReceived(SessionConferenceEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#conferenceLogoffReceived(ymsg.network.event.SessionConferenceEvent)
*/
/**
* @see ymsg.network.event.SessionListener#conferenceLogoffReceived(ymsg.network.event.SessionConferenceEvent)
*/
public void conferenceLogoffReceived(SessionConferenceEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#conferenceMessageReceived(ymsg.network.event.SessionConferenceEvent)
*/
public void conferenceMessageReceived(SessionConferenceEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#friendsUpdateReceived(ymsg.network.event.SessionFriendEvent)
*/
public void friendsUpdateReceived(SessionFriendEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#friendAddedReceived(ymsg.network.event.SessionFriendEvent)
*/
public void friendAddedReceived(SessionFriendEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#friendRemovedReceived(ymsg.network.event.SessionFriendEvent)
*/
public void friendRemovedReceived(SessionFriendEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#chatLogonReceived(ymsg.network.event.SessionChatEvent)
*/
public void chatLogonReceived(SessionChatEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#chatLogoffReceived(ymsg.network.event.SessionChatEvent)
*/
public void chatLogoffReceived(SessionChatEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#chatMessageReceived(ymsg.network.event.SessionChatEvent)
*/
public void chatMessageReceived(SessionChatEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#chatUserUpdateReceived(ymsg.network.event.SessionChatEvent)
*/
public void chatUserUpdateReceived(SessionChatEvent arg0) {
logger.finest(arg0.toString());
}
/**
* @see ymsg.network.event.SessionListener#chatConnectionClosed(ymsg.network.event.SessionEvent)
*/
public void chatConnectionClosed(SessionEvent arg0) {
logger.finest(arg0.toString());
}
}
/**
*
*/
package org.jivesoftware.wildfire.gateway.protocols.yahoo;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.wildfire.gateway.Gateway;
import org.jivesoftware.wildfire.gateway.roster.AbstractForeignContact;
import org.jivesoftware.wildfire.gateway.roster.Status;
import ymsg.network.StatusConstants;
import ymsg.network.YahooUser;
/**
* @author Noah Campbell
* @version 1.0
*/
public class YahooForeignContact extends AbstractForeignContact {
/** The serialVersionUID. */
private static final long serialVersionUID = 1L;
/** The yahoo user. */
final private YahooUser user;
/**
* Construct a new <code>YahooForeignContact</code>.
* @param user A YahooUser
* @param gateway
* @see YahooUser
*/
public YahooForeignContact(YahooUser user, Gateway gateway) {
super(user.getId(), new Status(), gateway);
this.user = user;
}
/**
* @see org.jivesoftware.wildfire.gateway.roster.ForeignContact#getStatus()
*/
public Status getStatus() {
getStatusMessage(user, this.status);
return super.status;
}
/**
* @param user2
* @return
*/
private Status getStatusMessage(YahooUser user2, Status status) {
long id = user2.getStatus();
status.setOnline(true);
if( StatusConstants.STATUS_AVAILABLE == id) { status.updateValue( resource.getString("STATUS_AVAILABLE" ));
} else if( StatusConstants.STATUS_BRB == id) { status.updateValue( resource.getString("STATUS_BRB " ));
} else if( StatusConstants.STATUS_BUSY == id) { status.updateValue( resource.getString("STATUS_BUSY" ));
} else if( StatusConstants.STATUS_NOTATHOME == id) { status.updateValue( resource.getString("STATUS_NOTATHOME" ));
} else if( StatusConstants.STATUS_NOTATDESK == id) { status.updateValue( resource.getString("STATUS_NOTATDESK" ));
} else if( StatusConstants.STATUS_NOTINOFFICE == id) { status.updateValue( resource.getString("STATUS_NOTINOFFICE" ));
} else if( StatusConstants.STATUS_ONPHONE == id) { status.updateValue( resource.getString("STATUS_ONPHONE" ));
} else if( StatusConstants.STATUS_ONVACATION == id) { status.updateValue( resource.getString("STATUS_ONVACATION" ));
} else if( StatusConstants.STATUS_OUTTOLUNCH == id) { status.updateValue( resource.getString("STATUS_OUTTOLUNCH" ));
} else if( StatusConstants.STATUS_STEPPEDOUT == id) { status.updateValue( resource.getString("STATUS_STEPPEDOUT" ));
} else if( StatusConstants.STATUS_INVISIBLE == id) { status.updateValue( resource.getString("STATUS_INVISIBLE" ));
} else if( StatusConstants.STATUS_BAD == id) { status.updateValue( resource.getString("STATUS_BAD" )); // Bad login?
} else if( StatusConstants.STATUS_LOCKED == id) { status.updateValue( resource.getString("STATUS_LOCKED" )); // You've been naughty
} else if( StatusConstants.STATUS_CUSTOM == id) { status.updateValue( user.getCustomStatusMessage() );
} else if( StatusConstants.STATUS_IDLE == id) { status.updateValue( resource.getString("STATUS_IDLE" ));
} else if( StatusConstants.STATUS_OFFLINE == id) { status.setOnline(false);
} else if( StatusConstants.STATUS_TYPING == id) { status.updateValue( resource.getString("STATUS_TYPING" ));
} else {
logger.log(Level.WARNING, "yahooforeigncontact.unabletolocatestatus");
status.updateValue( "????" );
}
return status;
}
/** The logger. */
final static private Logger logger = Logger.getLogger("yahooforeigncontact",
"gateway_i18n");
/** The resource. */
private static ResourceBundle resource = PropertyResourceBundle.getBundle("yahoostatus");
/**
* @see org.jivesoftware.wildfire.gateway.roster.ForeignContact#getName()
*/
public String getName() {
return user.getId();
}
}
package org.jivesoftware.wildfire.gateway.protocols.yahoo;
import java.util.logging.Logger;
import org.jivesoftware.wildfire.gateway.BaseGateway;
import org.jivesoftware.wildfire.gateway.GatewaySession;
import org.jivesoftware.wildfire.gateway.SubscriptionInfo;
import org.xmpp.component.ComponentException;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
/**
* @author Noah Campbell
* @version 1.0
*/
public class YahooGateway extends BaseGateway {
/** The YAHOO. */
private static String YAHOO = "yahoo";
/**
* @see org.jivesoftware.wildfire.gateway.BaseGateway#getName()
*/
@Override
public String getName() {
return YAHOO;
}
/**
* @see org.jivesoftware.wildfire.gateway.BaseGateway#setName()
*/
@Override
public void setName(String newname) {
YAHOO = newname;
}
/**
* @see org.jivesoftware.wildfire.gateway.BaseGateway#getDescription()
*/
@Override
public String getDescription() {
return "Yahoo! Gateway (ymsg9)";
}
/** The logger. @see java.util.logging.Logger */
static public final Logger logger = Logger.getLogger("YahooGateway");
/**
* @see org.jivesoftware.wildfire.gateway.Endpoint#sendPacket(Packet)
*/
@SuppressWarnings("unused")
public void sendPacket(@SuppressWarnings("unused") Packet packet) throws ComponentException {
// do nothing.
}
/**
* @param jid
* @param string
* @throws Exception
*/
public void sendMessage(JID jid, String string) throws Exception {
Message m = new Message();
m.setTo(jid);
m.setBody(string);
this.sendPacket(m);
}
/**
* @see org.jivesoftware.wildfire.gateway.BaseGateway#getType()
*/
@Override
public String getType() {
return "yahoo";
}
/**
* @see org.jivesoftware.wildfire.gateway.BaseGateway#getVersion()
*/
@Override
public String getVersion() {
return "v1.0";
}
/**
* @see org.jivesoftware.wildfire.gateway.BaseGateway#getSessionInstance(org.jivesoftware.wildfire.gateway.SubscriptionInfo)
*/
@Override
protected GatewaySession getSessionInstance(SubscriptionInfo info) {
return new YahooGatewaySession(info, this);
}
}
package org.jivesoftware.wildfire.gateway.protocols.yahoo;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.wildfire.gateway.AbstractGatewaySession;
import org.jivesoftware.wildfire.gateway.Endpoint;
import org.jivesoftware.wildfire.gateway.EndpointValve;
import org.jivesoftware.wildfire.gateway.Gateway;
import org.jivesoftware.wildfire.gateway.JabberEndpoint;
import org.jivesoftware.wildfire.gateway.SubscriptionInfo;
import org.jivesoftware.wildfire.gateway.roster.AbstractForeignContact;
import org.jivesoftware.wildfire.gateway.roster.ForeignContact;
import org.jivesoftware.wildfire.gateway.roster.NormalizedJID;
import org.jivesoftware.wildfire.gateway.roster.PersistenceManager;
import org.jivesoftware.wildfire.gateway.roster.UnknownForeignContactException;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence;
import ymsg.network.LoginRefusedException;
import ymsg.network.Session;
import ymsg.network.YahooGroup;
import ymsg.network.YahooUser;
/**
* NOT THREAD SAFE
*
* Manages the session to the underlying legacy system.
*
* @author Noah Campbell
* @version 1.0
*/
public class YahooGatewaySession extends AbstractGatewaySession implements Endpoint {
/** The serialVersionUID. */
private static final long serialVersionUID = 1L;
/** The logger. */
private static Logger logger = Logger.getLogger("YahooGatewaySession", "gateway_i18n");
/**
* Yahoo Session
*/
public final Session session;
/**
* The JID associated with this session.
*
* @see org.xmpp.packet.JID
*/
private final JID jid; // JID associated with this session
/**
* Initialize a new session object for Yahoo!
*
* @param info The subscription information to use during login.
* @param gateway The gateway that created this session.
*/
public YahooGatewaySession(SubscriptionInfo info, Gateway gateway) {
super(info, gateway);
this.jid = info.jid;
session = new Session();
session.addSessionListener(new YahooSessionListener(this));
}
/** The attemptingLogin. */
private boolean attemptingLogin = false;
/** The loginFailed. */
private boolean loginFailed = false;
/** The loginFailedCount. */
private int loginFailedCount = 0;
/**
* Manage presense information.
*/
// public void updatePresence() {
// if(isConnected()) {
//
// for(YahooGroup group : session.getGroups()) {
// Vector members = group.getMembers();
// for(Object member : members) {
// YahooUser user = (YahooUser)member;
// logger.info("Adding foreign contact: " + user.getId());
// String foreignId = user.getId();
// NormalizedJID whois = NormalizedJID.wrap(gateway.whois(foreignId));
// AbstractForeignContact fc = PersistenceManager.Factory.get(gateway)
// .getContactManager().getRoster(this.jid)
// .getForeignContact(foreignId, gateway);
//
// if(fc == null || fc.status == null) {
// logger.warning("Unable to find Foreign Contact for: " + whois);
// continue;
// }
// if(user == null) {
// logger.warning("Invalid Yahoo user");
// continue;
// }
// if(fc.status.getValue() != null && !fc.status.getValue().equalsIgnoreCase(user.getCustomStatusMessage())) {
// logger.log(Level.FINE, "yahoogatewaysession.status", new Object[] {fc.status});
// try {
// Presence p = new Presence();
// if(!fc.status.isSubscribed()) {
// p.setType(Presence.Type.subscribe);
// fc.status.setSubscribed(true);
// }
// p.setFrom(user.getId() + "@" + gateway.getName() + "." + gateway.getDomain());
// p.setTo(this.jid);
// gateway.sendPacket(p);
//
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
//
// }
// }
// }
// }
/**
* Login to the Yahoo! Messenger serverice
* @throws Exception
*/
public synchronized void login() throws Exception {
if(!isConnected() && !loginFailed && !attemptingLogin) {
attemptingLogin = true;
new Thread() {
@Override
public void run() {
try {
session.login(getSubscriptionInfo().username,
new String(getSubscriptionInfo().password));
/**
* Password is stored in the JVM as a string in JVM
* util termination.
*/
logger.log(Level.INFO, "yahoogatewaysession.login", new Object[]{jid, getSubscriptionInfo().username});
getJabberEndpoint().getValve().open(); // allow any buffered messages to pass through
// updatePresence();
} catch (LoginRefusedException lre) {
session.reset();
if( loginFailedCount++ > 3) {
loginFailed = true;
}
logger.warning("Login failed for " + getSubscriptionInfo().username);
} catch (IOException ioe) {
ioe.printStackTrace();
}
attemptingLogin = false;
}
}.run(); // intentionally not forked.
} else {
logger.warning(this.jid + " is already logged in");
}
}
/**
* Is the connection connected?
* @return connected is the session connected?
*/
public boolean isConnected() {
return session.getSessionStatus() == Session.MESSAGING;
}
/**
* Logout from Yahoo!
* @throws Exception
*/
public synchronized void logout() throws Exception {
logger.info("[" + this.jid + "]" + getSubscriptionInfo().username + " logged out.");
session.logout();
session.reset();
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() { return "[" + this.getSubscriptionInfo().username + " CR:" + clientRegistered + " SR:" + serverRegistered + "]"; }
/**
* Return the id of this session as a <code>String</code>.
* @return ID the jid for this session.
* @see org.xmpp.packet.JID
*/
public String getId() {
return this.jid.toBareJID();
}
/**
* Returns all the contacts associated with this Session.
* @return contacts A list of <code>String</code>s.
*/
@SuppressWarnings("unchecked")
public List<ForeignContact> getContacts() {
Map users = session.getUsers();
ArrayList<ForeignContact> contacts = new ArrayList<ForeignContact>(users.size());
for(YahooUser user : (Collection<YahooUser>)session.getUsers().values()) {
contacts.add(new YahooForeignContact(user, this.gateway));
}
return contacts;
}
/**
* Return the <code>JID</code> for this session.
* @return JID The jid for this session.
* @see org.xmpp.packet.JID
*/
public JID getSessionJID() {
return this.jid;
}
/**
* Returns the <code>JID> for this session.
* @return JID The jid for this session.
* @see org.xmpp.packet.JID
* @deprecated
*/
public JID getJID() {
return this.jid;
}
/**
* Return the status for the JID. This will be translated into a legacy request.
* @param to JID of user we're looking for
* @return String status of JID
*/
public String getStatus(JID to) {
Map table = this.session.getUsers();
if(isConnected() && table != null && to.getNode() != null && table.containsKey(to.getNode())) {
YahooUser user = this.session.getUser(to.getNode());
return user.getCustomStatusMessage();
} else {
return null;
}
}
/**
* Add a contact to this session. This will update the legacy roster and
* will be persisted across sessions.
* @param jid The JID of the friend.
* @throws Exception
*/
public void addContact(JID jid) throws Exception {
String node = jid.getNode();
session.addFriend(node, "jabber");
}
/**
* Remove a contact from this session. This will update the legacy roster
* and will be persisted across session.
* @param jid The friend to be removed.
* @throws Exception
*/
public void removeContact(JID jid) throws Exception {
String node = jid.getNode();
session.removeFriend(node, "jabber");
}
/**
* Sends a packet to the legacy system. It'll translate the XMPP request
* into a custom request.
* @param packet incoming packet from XMPP Server (typically from client)
*/
public void sendPacket(Packet packet) {
logger.log(Level.FINE, packet.toString());
if(packet instanceof Message) {
Message m = (Message)packet;
try {
session.sendMessage(packet.getTo().getNode(), m.getBody());
} catch (IOException ioe) {
logger.warning(ioe.getLocalizedMessage());
}
}
}
/**
* @see org.jivesoftware.wildfire.gateway.GatewaySession#getContact(org.xmpp.packet.JID)
*/
public ForeignContact getContact(JID to) throws UnknownForeignContactException {
String node = to.getNode();
if(node == null || node.length() == 0) throw new UnknownForeignContactException("invalidnode", node.toString());
YahooUser user = session.getUser(node);
if(user == null) throw new UnknownForeignContactException("invaliduser");
return new YahooForeignContact(session.getUser(to.getNode()), this.gateway);
}
}
package org.jivesoftware.wildfire.gateway.protocols.yahoo;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xmpp.component.ComponentException;
import org.xmpp.packet.Message;
import org.xmpp.packet.Presence;
import ymsg.network.event.SessionChatEvent;
import ymsg.network.event.SessionEvent;
import ymsg.network.event.SessionFriendEvent;
import ymsg.network.event.SessionNewMailEvent;
/**
* <code>YahooSessionListener</code> is a call back mechanism for <code>ymsg9</code>
* api.
*
* @author Noah Campbell
* @version 1.0
*/
public class YahooSessionListener extends NoopSessionListener {
/**
* Gateway session associated with this listener.
*/
private YahooGatewaySession gatewaySession;
/** The logger. */
private static final Logger logger = Logger.getLogger("YahooSessionListener");
/**
* Creates a YahooSessionListener that will translate events from the Yahoo!
* connection into XMPP formated packets.
*
* @param gateway The yahoo gateway.
*/
public YahooSessionListener(YahooGatewaySession gateway) {
this.gatewaySession = gateway;
}
/**
* @see org.jivesoftware.wildfire.gateway.protocols.yahoo.NoopSessionListener#newMailReceived(ymsg.network.event.SessionNewMailEvent)
*/
@Override
public void newMailReceived(SessionNewMailEvent snme) {
try {
Message message = new Message();
message.setTo(gatewaySession.getSessionJID());
message.setFrom(this.gatewaySession.getGateway().getJID());
message.setBody("New Mail Received (" + snme.getMailCount() + ")");
message.setType(Message.Type.headline);
gatewaySession.getJabberEndpoint().sendPacket(message);
} catch (Exception e) {
logger.severe("Unable to send message: " + e.getLocalizedMessage());
}
}
/** (non-Javadoc)
* @see org.jivesoftware.wildfire.gateway.protocols.yahoo.NoopSessionListener#messageReceived(ymsg.network.event.SessionEvent)
*/
@Override
public void messageReceived(SessionEvent sessionEvent) {
logger.finest(sessionEvent.toString());
try {
Message message = new Message();
message.setTo(gatewaySession.getSessionJID());
message.setBody(sessionEvent.getMessage());
message.setType(Message.Type.chat);
message.setFrom(this.gatewaySession.getGateway().whois(sessionEvent.getFrom()));
gatewaySession.getJabberEndpoint().sendPacket(message);
logger.fine(message.getElement().asXML());
} catch (Exception e) {
logger.severe("unable to send message: "+ e.getLocalizedMessage());
}
}
/**
* @see org.jivesoftware.wildfire.gateway.protocols.yahoo.NoopSessionListener#friendsUpdateReceived(ymsg.network.event.SessionFriendEvent)
*/
@Override
public void friendsUpdateReceived(SessionFriendEvent event) {
try {
updateStatus(event);
} catch (Exception e) {
logger.log(Level.SEVERE, "yahoosessionlistener.friendupdateerror", e.getLocalizedMessage());
}
}
/**
* Update a friends status.
*
* @param event
* @throws ComponentException
*/
private void updateStatus(SessionFriendEvent event) throws ComponentException {
Presence p = new Presence();
p.setStatus(event.getFriend().getCustomStatusMessage());
p.setFrom(gatewaySession.getGateway().whois(event.getFriend().getId()));
p.setTo(gatewaySession.getSessionJID());
gatewaySession.getJabberEndpoint().sendPacket(p);
}
/**
* @see org.jivesoftware.wildfire.gateway.protocols.yahoo.NoopSessionListener#chatMessageReceived(ymsg.network.event.SessionChatEvent)
*/
@Override
public void chatMessageReceived(SessionChatEvent sessionEvent) {
logger.finer(sessionEvent.toString());
try {
Message message = new Message();
message.setTo(gatewaySession.getSessionJID());
message.setBody(sessionEvent.getMessage());
message.setFrom(this.gatewaySession.getGateway().whois(sessionEvent.getFrom()));
gatewaySession.getJabberEndpoint().sendPacket(message);
} catch (Exception e) {
logger.severe("unable to send message: "+ e.getLocalizedMessage());
}
}
/**
* @see org.jivesoftware.wildfire.gateway.protocols.yahoo.NoopSessionListener#connectionClosed(ymsg.network.event.SessionEvent)
*/
@Override
public void connectionClosed(SessionEvent arg0) {
gatewaySession.getJabberEndpoint().getValve().close();
}
/**
* @see org.jivesoftware.wildfire.gateway.protocols.yahoo.NoopSessionListener#friendAddedReceived(ymsg.network.event.SessionFriendEvent)
*/
@Override
public void friendAddedReceived(SessionFriendEvent arg0) {
// TODO Auto-generated method stub
super.friendAddedReceived(arg0);
}
/**
* @see org.jivesoftware.wildfire.gateway.protocols.yahoo.NoopSessionListener#friendRemovedReceived(ymsg.network.event.SessionFriendEvent)
*/
@Override
public void friendRemovedReceived(SessionFriendEvent arg0) {
// TODO Auto-generated method stub
super.friendRemovedReceived(arg0);
}
}
/**
*
*/
package org.jivesoftware.wildfire.gateway.roster;
import java.io.IOException;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Set;
import org.jivesoftware.wildfire.gateway.Gateway;
import org.jivesoftware.wildfire.gateway.GatewaySession;
import org.xmpp.packet.JID;
/**
* All maintanence information pretaining to a gateway user.
*
* @author Noah Campbell
* @version 1.0
*/
public abstract class AbstractForeignContact implements Serializable, ForeignContact {
/**
* The serialVersionUID
*/
private static final long serialVersionUID = 1L;
/**
* The id for this contact. This maps directly to the legacy userid.
*/
public final String id;
/**
* The status of this contact.
*
* @see Status
*/
public final Status status;
/**
* The jid associated with this foreign contact.
*
* @see JID
*/
private transient JID jid;
/**
* The gatewayDomain.
*/
private final String gatewayDomain;
/**
* The gatewayName.
*/
private final String gatewayName;
/**
* The associatedSessions that are currently active for this <code>ForeignContact</code>.
*
* @see java.util.Set
*/
private transient Set<GatewaySession> associatedSessions = new HashSet<GatewaySession>();
/**
* The format for a JID
*
* @see java.text.MessageFormat
*/
private static final MessageFormat mf = new MessageFormat("{0}@{1}.{2}");
/**
* Create a ForeignContact relating to the gateway it originated from.
*
* @param id the foreign contact id.
* @param status the current status of the contact.
* @param gateway the gateway the foreign contact is associated with.
*/
public AbstractForeignContact(String id, Status status, Gateway gateway) {
this.id = id;
this.status = status;
this.gatewayDomain = gateway.getDomain();
this.gatewayName = gateway.getName();
}
/**
* @see org.jivesoftware.wildfire.gateway.roster.ForeignContact#getJid()
*/
public JID getJid() {
if(jid == null) {
jid = new JID(mf.format(new Object[]{id, gatewayName, gatewayDomain}));
}
return jid;
}
/**
* @param in
* @throws IOException
* @throws ClassNotFoundException
*/
@SuppressWarnings("unused")
private void readObject(@SuppressWarnings("unused") java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
associatedSessions = new HashSet<GatewaySession>();
getJid();
}
/**
* @see org.jivesoftware.wildfire.gateway.roster.ForeignContact#addSession(org.jivesoftware.wildfire.gateway.GatewaySession)
*/
public void addSession(GatewaySession session) {
associatedSessions.add(session);
}
/**
* @see org.jivesoftware.wildfire.gateway.roster.ForeignContact#removeSession(org.jivesoftware.wildfire.gateway.GatewaySession)
*/
public void removeSession(GatewaySession session) {
associatedSessions.remove(session);
}
/**
* @see org.jivesoftware.wildfire.gateway.roster.ForeignContact#isConnected()
*/
public boolean isConnected() {
boolean connected = true;
for(GatewaySession session : associatedSessions) {
if(!session.isConnected()) {
connected = false;
break;
}
}
return connected;
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if(obj instanceof AbstractForeignContact) {
AbstractForeignContact fc = (AbstractForeignContact)obj;
return fc.id.equalsIgnoreCase(this.id);
} else {
return super.equals(obj);
}
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return this.getJid().toBareJID().hashCode();
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Foreign Contact: " + this.getJid() + "[Gateway: " + this.gatewayName + ", Connected: " + isConnected() + "]";
}
}
package org.jivesoftware.wildfire.gateway.roster;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.xmpp.packet.JID;
/**
*
* Manage contacts for a paticular JID.
*
* @author Noah Campbell
*
*/
public class ContactManager implements Serializable {
/**
* Construct a new <code>ContactManager</code>
*/
ContactManager() { }
/**
* The serialVersionUID
*/
private static final long serialVersionUID = 1L;
/**
* The fcs
*
* @see java.util.Set
*/
private final Set<AbstractForeignContact> fcs = new HashSet<AbstractForeignContact>();
/**
* Maintain a mapping of JIDs to their contact list.
*/
private final Map<NormalizedJID, Roster> contactLists =
new HashMap<NormalizedJID, Roster>();
/**
* Return a roster for a JID.
*
* @param name The <code>JID</code> to lookup.
* @return roster The roster for the <code>JID</code>.
*/
public synchronized Roster getRoster(JID name) {
Roster r = contactLists.get(NormalizedJID.wrap(name));
if(r == null) {
r = new Roster();
contactLists.put(NormalizedJID.wrap(name), r);
}
return r;
}
/**
* @return foreignContacts A {@code java.util.Set} of {@code ForeignContact}s.
*/
public Set<AbstractForeignContact> getAllForeignContacts() {
return this.fcs;
}
/**
* Remove the <code>JID</code> from the contact list.
*
* @param jid
*/
void remove(NormalizedJID jid) {
contactLists.remove(jid);
}
}
/**
*
*/
package org.jivesoftware.wildfire.gateway.roster;
import org.jivesoftware.wildfire.gateway.GatewaySession;
import org.xmpp.packet.JID;
/**
* @author Noah Campbell
* @version 1.0
*/
public interface ForeignContact {
/**
* Get the JID, constructing it if necessary.
*
* @return jid returns the jid.
*/
public JID getJid();
/**
* Add a session to the associated sessions for this foreign contact.
*
* @param session
*/
public void addSession(GatewaySession session);
/**
* Remove a <code>GatewaySession</code> from the foreign contact.
*
* @param session
*/
public void removeSession(GatewaySession session);
/**
* Returns true if at least one associated session is connected.
*
* @return connected
*/
public boolean isConnected();
/**
* Return the translated status for the contact.
*
* @return Status
*/
public Status getStatus();
/**
* Return the name of the contact.
*
* @return name The name of the contact.
*/
public String getName();
}
package org.jivesoftware.wildfire.gateway.roster;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.xmpp.packet.JID;
/**
* @author Noah Campbell
*
*/
/**
* Ignore the resource portion of the JID.
*
* @author Noah Campbell
*
*/
public final class NormalizedJID implements Serializable {
/**
* The JID.
*
* @see JID
*/
public final String JID;
/**
* The toStringValue. Stored to increase efficiency.
*
* @see NormalizedJID
*/
private final String toStringValue;
/**
* The serialVersionUID.
*/
private static final long serialVersionUID = 1L;
/**
* Construct a new <code>NormalizedJID</code>
* @param jid
*/
private NormalizedJID(JID jid) {
JID = jid.toBareJID();
toStringValue = JID + " (normalized)";
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if(obj instanceof NormalizedJID) {
NormalizedJID jid = (NormalizedJID)obj;
return JID.equalsIgnoreCase(jid.JID);
} else if(obj instanceof JID) {
JID jid = new JID( ((JID)obj).toBareJID() );
return JID.equalsIgnoreCase(jid.toBareJID());
} else if( obj instanceof String) {
JID jid = new JID((String)obj);
jid = new JID(jid.toBareJID());
return JID.equalsIgnoreCase(jid.toBareJID());
} else {
return super.equals(obj);
}
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return JID.hashCode();
}
/**
* Wrap a <code>JID</code> and return a <code>NormalizedJID</code>. If the
* <code>JID</code> has already been wrapped, then the cached version is returned.
*
* @param jid
* @return normalizedJID
*/
public static NormalizedJID wrap(JID jid) {
if(cache.containsKey(jid)) {
return cache.get(jid);
} else {
NormalizedJID nJID = new NormalizedJID(jid);
cache.put(jid, nJID);
return nJID;
}
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return toStringValue;
}
/**
* The cache of <code>NormailzedJID</code>s.
*
* @see java.util.Map
*/
private transient static final Map<JID, NormalizedJID> cache = new ConcurrentHashMap<JID, NormalizedJID>();
}
package org.jivesoftware.wildfire.gateway.roster;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.jivesoftware.wildfire.gateway.Gateway;
import org.jivesoftware.wildfire.gateway.util.BackgroundThreadFactory;
import org.jivesoftware.wildfire.gateway.util.GatewayLevel;
import org.xmpp.packet.JID;
/**
* Responsible for managing:
*
* - ForeignContact (legacy system identity)
* - Registered users JID and credentials for the gateway
*
* @author Noah Campbell
*
*/
public class PersistenceManager implements Serializable {
/**
* The contactManager.
*
* @see ContactManager
*/
private ContactManager contactManager = null;
/**
* The registrar.
*
* @see Registrar
*/
private Registrar registrar = null;
/**
* The gateway.
*
* @see Gateway
*/
@SuppressWarnings("unused")
private Gateway gateway;
/**
* Factory for accessing the various RosterManagers.
*
* @author Noah Campbell
*/
public final static class Factory {
/**
* The <code>PersistanceManager</code> associated with a particular
* <code>Gateway</code>
*
* @see Factory
*/
private final static Map<Gateway, PersistenceManager> instances =
new HashMap<Gateway, PersistenceManager>();
/**
* Given a <code>Gateway</code> return a <code>PersistenceManager</code>
* @param gateway
* @return persistenceManager returns a <code>PersistenceManager</code>
* @see PersistenceManager
*/
public static synchronized PersistenceManager get(Gateway gateway) {
PersistenceManager rm = instances.get(gateway);
if(rm == null) {
rm = new PersistenceManager(gateway);
instances.put(gateway, rm);
}
return rm;
}
}
/** The db file. */
private final File db;
/**
* Construct a new <code>PersistanceManager</code>.
*
* @param gateway
*/
private PersistenceManager(Gateway gateway) {
this.gateway = gateway;
db = new File("/tmp/." + this.gateway.getName().toLowerCase() + ".dat");
load(gateway);
timer.scheduleAtFixedRate(archiver, 5, 5, TimeUnit.SECONDS);
}
/**
* Unregister a JID.
* @param jid
*/
public void remove(JID jid) {
String bareJID = jid.toBareJID();
try {
NormalizedJID njid = NormalizedJID.wrap(jid);
contactManager.remove(njid);
registrar.remove(jid);
} catch (Exception e) {
logger.severe("Unable to remove " + bareJID + ": " + e.getLocalizedMessage());
}
}
/**
* Load the roster manager (we simply read a binary file from the file system).
* @param gateway
*/
private void load(Gateway gateway) {
ContactManager contactManager = null;
Registrar registrar = null;
try {
/**
* The key is stored in the registry so the key is as secure as the
* registry is secure.
*/
byte[] rawKey = Preferences.systemNodeForPackage(this.getClass()).getByteArray(".key", null);
if(rawKey == null) {
logger.log(GatewayLevel.SECURITY, "persistencemanager.nokey");
return;
}
SecretKeySpec key = new SecretKeySpec(rawKey, "AES");
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.DECRYPT_MODE, key);
CipherInputStream cis = new CipherInputStream(new FileInputStream(db), c);
ObjectInputStream is = new ObjectInputStream(cis);
contactManager = (ContactManager)is.readObject() ;
registrar = (Registrar) is.readObject() ;
is.close();
} catch (Exception e) {
if(db.exists()) {
db.delete();
}
logger.log(Level.WARNING, "persistencemanager.loadrosterfailed",e);
} finally {
this.contactManager = (contactManager != null) ? contactManager : new ContactManager();
this.registrar = (registrar != null) ? registrar : new Registrar();
this.registrar.setGateway(gateway); // re-vitialize the registrar.
}
}
/**
* A timer for executing tasks related to PersistanceManager.
*
* @see java.util.concurrent.ScheduledExecutorService
*/
private final ScheduledExecutorService timer = Executors.newScheduledThreadPool(1, new BackgroundThreadFactory());
/**
* The serialVersionUID.
*
* @see PersistenceManager
*/
private static final long serialVersionUID = 1L;
/**
* The logger.
*
* @see PersistenceManager
*/
private static final Logger logger = Logger.getLogger("PersistenceManager", "gateway_i18n");
/**
* Responsible for flushing the in-memory database.
*/
private final Runnable archiver = new Runnable() {
public void run() {
try {
store();
} catch (Exception e) {
logger.log(Level.WARNING, "persistencemanager.unabletoflush", e);
e.printStackTrace();
}
}
};
/**
* Write the contact manager and registrar to the file system.
*
* @throws Exception
*/
public synchronized void store() throws Exception {
Preferences prefs = Preferences.systemNodeForPackage(this.getClass());
byte[] rawKey = prefs.getByteArray(".key", null);
if(rawKey == null) {
logger.log(GatewayLevel.SECURITY, "persistencemanager.gennewkey");
KeyGenerator kg = KeyGenerator.getInstance("AES");
SecretKey key = kg.generateKey();
rawKey = key.getEncoded();
prefs.putByteArray(".key", rawKey);
}
SecretKeySpec key = new SecretKeySpec(rawKey, "AES");
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.ENCRYPT_MODE, key);
CipherOutputStream os = new CipherOutputStream(new FileOutputStream(db), c);
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(contactManager);
oos.writeObject(registrar);
oos.flush();
oos.close();
}
/**
* @return Returns the contactManager.
*/
public ContactManager getContactManager() {
return contactManager;
}
/**
* @return Returns the registrar.
*/
public Registrar getRegistrar() {
return registrar;
}
/**
* @see java.lang.Object#finalize()
*/
@Override
protected void finalize() throws Throwable {
super.finalize();
this.timer.shutdownNow();
logger.log(Level.FINER, "persistencemanager.registrarFinalize");
}
}
package org.jivesoftware.wildfire.gateway.roster;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import org.jivesoftware.wildfire.gateway.Gateway;
import org.jivesoftware.wildfire.gateway.GatewaySession;
import org.jivesoftware.wildfire.gateway.SubscriptionInfo;
import org.xmpp.packet.JID;
/**
*
* This class is responsible for managing all the registrations between the
* legacy system and the XMPP Server.
*
* @author Noah Campbell
* @version 1.0
*/
public class Registrar implements Serializable {
/**
* The serialVersionUID.
*
* @see Registrar
*/
private static final long serialVersionUID = 1L;
/**
* Construct a new <code>Registrar</code>.
*/
Registrar() {
createSessionCache();
}
/**
* Initializes a new session cache
*/
private void createSessionCache() {
sessions = new HashMap<JID, GatewaySession>();
}
/**
* GatewaySessions are maintained in the registration
*/
private final Map<NormalizedJID, SubscriptionInfo> registrar = new HashMap<NormalizedJID, SubscriptionInfo>();
/**
* The <code>GatewaySessions</code> mapped by <code>JID</code>
*
* @see java.util.Map
*/
private transient Map<JID, GatewaySession> sessions;
/**
* Determine if the JID is registered (based on the bare JID)
* @param id
* @return true/false
*/
public boolean isRegistered(NormalizedJID id) {
return registrar.containsKey(id);
}
/**
* Add a JID to the registrar.
* @param id
* @param info
*/
public void add(JID id, SubscriptionInfo info) {
registrar.put(NormalizedJID.wrap(id), info);
//timer.scheduleAtFixedRate(info, 10, 10, TimeUnit.SECONDS);
}
/**
* Get the Session for a JID.
*
* @param jid the <code>JID</code>
* @return session the gateway session
* @throws Exception
*/
public GatewaySession getGatewaySession(JID jid) throws Exception {
SubscriptionInfo info = registrar.get(NormalizedJID.wrap(jid));
if(info == null) {
throw new IllegalStateException("Please register before attempting to get a session");
}
if(!sessions.containsKey(jid)) {
info.jid = jid;
GatewaySession session = this.gateway.getSessionFactory().newInstance(info);
session.login();
logger.info("Creating session for: " + jid);
sessions.put(jid, session);
}
return sessions.get(jid);
}
/**
* @return collection of subscriptionInfos
*/
public Collection<SubscriptionInfo> getAllGatewaySessions() {
return registrar.values();
}
/**
* @param gateway
*/
void setGateway(Gateway gateway) {
this.gateway = gateway;
}
/**
* The gateway.
*
* @see Gateway
*/
private transient Gateway gateway;
/**
* The logger.
*
* @see Registrar
*/
private static final Logger logger = Logger.getLogger("Registrar");
/**
* Removes the NormalizedJID from the registrar.
* @param jid
*/
void remove(JID jid) {
NormalizedJID wrapped = NormalizedJID.wrap(jid);
registrar.remove(wrapped);
GatewaySession session = sessions.get(jid);
if(session.isConnected()) {
try {
session.logout();
} catch (Exception e) {
// silently ignore
}
}
}
/**
* @param ois
* @throws IOException
* @throws ClassNotFoundException
*/
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
this.createSessionCache();
}
}
package org.jivesoftware.wildfire.gateway.roster;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.jivesoftware.wildfire.gateway.Gateway;
/**
* Roster maintains the list of <code>ForeignContact</code>s that are related
* to a particular <code>JID</code>
*
* @author Noah Campbell
* @version 1.0
*
* @see AbstractForeignContact
* @see org.xmpp.packet.JID
* @deprecated
*/
public class Roster implements Serializable {
/**
* The serialVersionUID.
*/
private static final long serialVersionUID = 1L;
/**
* The foreignContacts.
*
* @see java.util.Map
* @see AbstractForeignContact
*/
private Map<String, AbstractForeignContact> foreignContacts = new HashMap<String, AbstractForeignContact>();
/**
* Return the foreign contact based on the legacy id. A ForeignContact will always
* be returned. If the foreignId does not exist in the Roster, than a new one will be
* created.
*
* @param foreignId The legacy contact id.
* @param gateway The gateway that this foreign contact came from.
* @return ForeignContact
*/
public ForeignContact getForeignContact(String foreignId, Gateway gateway) {
AbstractForeignContact fc = this.foreignContacts.get(foreignId);
if(fc == null) {
// fc = new ForeignContact(foreignId, new Status(), gateway);
this.foreignContacts.put(foreignId, fc);
}
return fc;
}
/**
* @return allForeignContacts a <code>Collection</code> of <code>ForeignContact</code>s.
*/
public Collection<AbstractForeignContact> getAll() {
return Collections.unmodifiableCollection(this.foreignContacts.values());
}
}
/**
*
*/
package org.jivesoftware.wildfire.gateway.roster;
import java.io.Serializable;
/**
* @author Noah Campbell
* @version 1.0
*/
/**
* Status object.
*
* @author Noah Campbell
* @version 1.0
*/
public final class Status implements Serializable {
/** The serialVersionUID. */
private static final long serialVersionUID = 1L;
/** The subscribed. */
private boolean subscribed = false;
/** The online. */
private boolean online = false;
/** The value. */
private String value;
/**
* @return status a string representation of the status's state.
*/
public String getValue() { return value; }
/**
* @param value the new value of the status
*/
public void updateValue(String value) { this.value = value; }
/**
* @return Returns the subscribed.
*/
public boolean isSubscribed() {
return subscribed;
}
/**
* @param subscribed The subscribed to set.
*/
public void setSubscribed(boolean subscribed) {
this.subscribed = subscribed;
}
/**
* @return Returns the online.
*/
public boolean isOnline() {
return this.online;
}
/**
* @param online The online to set.
*/
public void setOnline(boolean online) {
this.online = online;
}
}
/**
*
*/
package org.jivesoftware.wildfire.gateway.roster;
import java.text.MessageFormat;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
/**
* @author Noah Campbell
* @version 1.0
*/
public class UnknownForeignContactException extends Exception {
/** The args. */
private final Object[] args;
/** The serialVersionUID. */
private static final long serialVersionUID = 1L;
/**
* Construct a new <code>UnknownForeignContactException</code>.
*
*/
public UnknownForeignContactException() {
super();
args = new Object[0];
}
/**
* Construct a new <code>UnknownForeignContactException</code>.
*
* @param message The message key.
* @param args Any arguments that are required for the message.
*/
public UnknownForeignContactException(String message, Object...args) {
super(message);
this.args = args;
}
/**
* Construct a new <code>UnknownForeignContactException</code>.
*
* @param message The message key.
* @param cause The cause of the exception, if this is a wrapped exception.
* @param args Any arguments that are required for the message.
*/
public UnknownForeignContactException(String message, Throwable cause, Object...args) {
super(message, cause);
this.args = args;
}
/**
* Construct a new <code>UnknownForeignContactException</code>.
*
* @param cause
*/
public UnknownForeignContactException(Throwable cause) {
super(cause);
args = new Object[0];
}
/**
* @see java.lang.Throwable#getLocalizedMessage()
*/
@Override
public String getLocalizedMessage() {
return MessageFormat.format(resource.getString(this.getMessage()), args);
}
/** The resource. */
private static ResourceBundle resource = PropertyResourceBundle.getBundle("exceptions");
}
/**
*
*/
package org.jivesoftware.wildfire.gateway.util;
import java.util.concurrent.ThreadFactory;
/**
* Generates threads that are of low priority and daemon.
*
* @author Noah Campbell
* @version 1.0
*/
public class BackgroundThreadFactory implements ThreadFactory {
/** The background thread group. */
private static ThreadGroup group = new ThreadGroup("background");
/**
* @see java.util.concurrent.ThreadFactory#newThread(java.lang.Runnable)
*/
public Thread newThread(Runnable r) {
Thread thread = new Thread(group, r);
thread.setDaemon(true);
thread.setPriority(Thread.MIN_PRIORITY);
return thread;
}
}
/**
* $Revision$
* $Date$
*
* Copyright (C) 2006 Jive Software. 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 org.jivesoftware.wildfire.gateway.util;
import org.jivesoftware.util.Log;
import org.xmpp.component.ComponentManager;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.wildfire.gateway.BaseGateway;
import org.jivesoftware.util.PropertyEventDispatcher;
/**
* Gateway Instance
*
* Represents all information that needs to be tracked about a gateway instance.
*
* @author Daniel Henninger
*/
public class GatewayInstance {
private ComponentManager componentManager;
private String serviceName = null;
private String nameOfClass = null;
private BaseGateway gateway = null;
private Boolean enabled = false;
private Boolean running = false;
public GatewayInstance(String subdomain, String classname, ComponentManager componentManager) {
this.serviceName = subdomain;
this.nameOfClass = classname;
this.componentManager = componentManager;
enabled = JiveGlobals.getBooleanProperty("plugin.gateway."+serviceName+"Enabled", false);
}
public String getName() {
return serviceName;
}
public Boolean isEnabled() {
return enabled;
}
public Boolean isRunning() {
return running;
}
public void enable() {
enabled = true;
JiveGlobals.setProperty("plugin.gateway."+serviceName+"Enabled", "true");
if (!running) {
startInstance();
}
}
public void disable() {
enabled = false;
JiveGlobals.setProperty("plugin.gateway."+serviceName+"Enabled", "false");
if (running) {
stopInstance();
}
}
public void startInstance() {
if (!enabled || running) {
return;
}
BaseGateway gateway = null;
Log.debug("Loading class "+nameOfClass);
try {
gateway = (BaseGateway)Class.forName(nameOfClass).newInstance();
}
catch (ClassNotFoundException e) {
Log.error("Unable to find class: "+nameOfClass);
}
catch (InstantiationException e) {
Log.error("Unable to instantiate class: "+nameOfClass);
}
catch (IllegalAccessException e) {
Log.error("Unable to access class: "+nameOfClass);
}
gateway.setName(serviceName);
//componentManager = ComponentManagerFactory.getComponentManager();
try {
componentManager.addComponent(serviceName, gateway);
//PropertyEventDispatcher.addListener(gateway);
running = true;
Log.debug("Started class "+nameOfClass);
}
catch (Exception e) {
componentManager.getLog().error(e);
}
}
public void stopInstance() {
if (!running) {
return;
}
//PropertyEventDispatcher.removeListener(gateway);
try {
componentManager.removeComponent(serviceName);
//componentManager = null;
}
catch (Exception e) {
componentManager.getLog().error(e);
}
gateway = null;
running = false;
}
}
/**
*
*/
package org.jivesoftware.wildfire.gateway.util;
import java.util.logging.Level;
/**
* Custom log levels.
*
* @author Noah Campbell
* @version 1.0
* @see java.util.logging.Level
*/
public class GatewayLevel extends Level {
/** SECURITY log level. */
public static final Level SECURITY = new GatewayLevel("SECURITY", 501);
/**
* Construct a new <code>GatewayLevel</code>.
*
* @param name
* @param value
*/
protected GatewayLevel(String name, int value) {
super(name, value, "gateway_i18n");
}
/** The serialVersionUID. */
private static final long serialVersionUID = 1L;
}
<%@ page import="java.util.*,
org.jivesoftware.wildfire.XMPPServer,
org.jivesoftware.util.*,
org.jivesoftware.wildfire.gateway.GatewayPlugin"
errorPage="error.jsp"
%>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>
<% // Get parameters
boolean save = request.getParameter("save") != null;
boolean success = request.getParameter("success") != null;
boolean aimEnabled = ParamUtils.getBooleanParameter(request, "aimEnabled");
boolean icqEnabled = ParamUtils.getBooleanParameter(request, "icqEnabled");
boolean yahooEnabled = ParamUtils.getBooleanParameter(request, "yahooEnabled");
String serverName = XMPPServer.getInstance().getServerInfo().getName();
GatewayPlugin plugin = (GatewayPlugin)XMPPServer.getInstance().getPluginManager().getPlugin("gateway");
// Handle a save
if (save) {
//plugin.setPresencePublic(presencePublic);
if (aimEnabled) {
plugin.enableService("aim");
}
else {
plugin.disableService("aim");
}
if (icqEnabled) {
plugin.enableService("icq");
}
else {
plugin.disableService("icq");
}
if (yahooEnabled) {
plugin.enableService("yahoo");
}
else {
plugin.disableService("yahoo");
}
response.sendRedirect("gateway-service.jsp?success=true");
return;
}
aimEnabled = plugin.serviceEnabled("aim");
icqEnabled = plugin.serviceEnabled("icq");
yahooEnabled = plugin.serviceEnabled("yahoo");
%>
<html>
<head>
<title>IM Gateway Settings</title>
<meta name="pageID" content="gateway-service"/>
</head>
<body>
<p>
Use the form below to enable or disable any of the available gateways. By
default, all of the gateways are turned off. Gateways will answer as the
JID provided in each corresponding section.
</p>
<% if (success) { %>
<div class="jive-success">
<table cellpadding="0" cellspacing="0" border="0">
<tbody>
<tr><td class="jive-icon"><img src="images/success-16x16.gif" width="16" height="16" border="0"></td>
<td class="jive-icon-label">
Gateway services successfully updated.
</td></tr>
</tbody>
</table>
</div><br>
<% } %>
<form action="gateway-service.jsp?save" method="post">
<fieldset>
<legend>AIM Gateway</legend>
<div>
<p>
This gateway provides a mechanism for users to access the AIM network.
Users will be able to register with the JID specified below, specifying
their AIM screen name and password.<br />
<br />
JID: aim.<%= serverName %>
</p>
<table cellpadding="3" cellspacing="0" border="0" width="100%">
<tbody>
<tr>
<td width="1%">
<input type="radio" name="aimEnabled" value="true" id="rb01"
<%= ((aimEnabled) ? "checked" : "") %>>
</td>
<td width="99%">
<label for="rb01"><b>Enabled</b> - AIM gateway is available.</label>
</td>
</tr>
<tr>
<td width="1%">
<input type="radio" name="aimEnabled" value="false" id="rb02"
<%= ((!aimEnabled) ? "checked" : "") %>>
</td>
<td width="99%">
<label for="rb01"><b>Disabled</b> - AIM gateway is not available.</label>
</td>
</tr>
</tbody>
</table>
</div>
</fieldset>
<br><br>
<fieldset>
<legend>ICQ Gateway</legend>
<div>
<p>
This gateway provides a mechanism for users to access the ICQ network.
Users will be able to register with the JID specified below, specifying
their ICQ UIN (user identification number) and password.<br />
<br />
JID: icq.<%= serverName %>
</p>
<table cellpadding="3" cellspacing="0" border="0" width="100%">
<tbody>
<tr>
<td width="1%">
<input type="radio" name="icqEnabled" value="true" id="rb03"
<%= ((icqEnabled) ? "checked" : "") %>>
</td>
<td width="99%">
<label for="rb01"><b>Enabled</b> - ICQ gateway is available.</label>
</td>
</tr>
<tr>
<td width="1%">
<input type="radio" name="icqEnabled" value="false" id="rb04"
<%= ((!icqEnabled) ? "checked" : "") %>>
</td>
<td width="99%">
<label for="rb01"><b>Disabled</b> - ICQ gateway is not available.</label>
</td>
</tr>
</tbody>
</table>
</div>
</fieldset>
<br><br>
<fieldset>
<legend>Yahoo Gateway</legend>
<div>
<p>
This gateway provides a mechanism for users to access the YIM network.
Users will be able to register with the JID specified below, specifying
their YIM username and password.<br />
<br />
JID: yahoo.<%= serverName %>
</p>
<table cellpadding="3" cellspacing="0" border="0" width="100%">
<tbody>
<tr>
<td width="1%">
<input type="radio" name="yahooEnabled" value="true" id="rb03"
<%= ((yahooEnabled) ? "checked" : "") %>>
</td>
<td width="99%">
<label for="rb01"><b>Enabled</b> - Yahoo gateway is available.</label>
</td>
</tr>
<tr>
<td width="1%">
<input type="radio" name="yahooEnabled" value="false" id="rb04"
<%= ((!yahooEnabled) ? "checked" : "") %>>
</td>
<td width="99%">
<label for="rb01"><b>Disabled</b> - Yahoo gateway is not available.</label>
</td>
</tr>
</tbody>
</table>
</div>
</fieldset>
<br><br>
<input type="submit" value="Save Settings">
</form>
</body>
</html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment