package org.limewire.xmpp.client.impl;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smackx.ChatStateManager;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.limewire.concurrent.ListeningExecutorService;
import org.limewire.concurrent.ListeningFuture;
import org.limewire.friend.api.Friend;
import org.limewire.friend.api.FriendConnection;
import org.limewire.friend.api.FriendConnectionConfiguration;
import org.limewire.friend.api.FriendConnectionEvent;
import org.limewire.friend.api.FriendException;
import org.limewire.friend.api.FriendPresence;
import org.limewire.friend.api.FriendPresenceEvent;
import org.limewire.friend.api.FriendRequestEvent;
import org.limewire.friend.api.RosterEvent;
import org.limewire.friend.api.feature.AddressFeature;
import org.limewire.friend.api.feature.AuthTokenFeature;
import org.limewire.friend.api.feature.ConnectBackRequestFeature;
import org.limewire.friend.api.feature.FeatureEvent;
import org.limewire.friend.api.feature.FeatureRegistry;
import org.limewire.friend.api.feature.FileOfferFeature;
import org.limewire.friend.api.feature.LibraryChangedNotifierFeature;
import org.limewire.friend.impl.feature.LimewireFeatureInitializer;
import org.limewire.friend.impl.feature.NoSaveFeature;
import org.limewire.friend.impl.util.PresenceUtils;
import org.limewire.listener.AsynchronousEventBroadcaster;
import org.limewire.listener.AsynchronousEventMulticaster;
import org.limewire.listener.EventBroadcaster;
import org.limewire.listener.EventListenerList;
import org.limewire.listener.EventMulticaster;
import org.limewire.listener.EventRebroadcaster;
import org.limewire.listener.ListenerSupport;
import org.limewire.listener.EventListener;
import org.limewire.logging.Log;
import org.limewire.logging.LogFactory;
import org.limewire.net.address.AddressFactory;
import org.limewire.xmpp.client.impl.features.NoSaveFeatureInitializer;
import org.limewire.xmpp.client.impl.messages.address.AddressIQListener;
import org.limewire.xmpp.client.impl.messages.address.AddressIQListenerFactory;
import org.limewire.xmpp.client.impl.messages.address.AddressIQProvider;
import org.limewire.xmpp.client.impl.messages.authtoken.AuthTokenIQListener;
import org.limewire.xmpp.client.impl.messages.authtoken.AuthTokenIQListenerFactory;
import org.limewire.xmpp.client.impl.messages.authtoken.AuthTokenIQProvider;
import org.limewire.xmpp.client.impl.messages.connectrequest.ConnectBackRequestIQ;
import org.limewire.xmpp.client.impl.messages.connectrequest.ConnectBackRequestIQListener;
import org.limewire.xmpp.client.impl.messages.connectrequest.ConnectBackRequestIQListenerFactory;
import org.limewire.xmpp.client.impl.messages.connectrequest.ConnectBackRequestIQProvider;
import org.limewire.xmpp.client.impl.messages.discoinfo.DiscoInfoListener;
import org.limewire.xmpp.client.impl.messages.filetransfer.FileTransferIQ;
import org.limewire.xmpp.client.impl.messages.filetransfer.FileTransferIQListener;
import org.limewire.xmpp.client.impl.messages.filetransfer.FileTransferIQListenerFactory;
import org.limewire.xmpp.client.impl.messages.library.LibraryChangedIQ;
import org.limewire.xmpp.client.impl.messages.library.LibraryChangedIQListener;
import org.limewire.xmpp.client.impl.messages.library.LibraryChangedIQListenerFactory;
import org.limewire.xmpp.client.impl.messages.nosave.NoSaveIQ;
import org.limewire.xmpp.activity.XmppActivityEvent;
import org.limewire.xmpp.api.client.JabberSettings;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/**
* Implements a {@link FriendConnection} using XMPP.
* <p>
* It wraps a {@link XMPPConnection} and keeps track of all the listeners
* created around that connection and the list of users that is online.
*/
public class XMPPFriendConnectionImpl implements FriendConnection {
private static final Log LOG = LogFactory.getLog(XMPPFriendConnectionImpl.class);
private final FriendConnectionConfiguration configuration;
private final EventBroadcaster<FriendRequestEvent> friendRequestBroadcaster;
private final AsynchronousEventMulticaster<FriendConnectionEvent> connectionMulticaster;
private final AddressFactory addressFactory;
private final EventMulticaster<FeatureEvent> featureSupport;
private final ListeningExecutorService executorService;
private final List<ConnectionConfigurationFactory> connectionConfigurationFactories;
private final AddressIQListenerFactory addressIQListenerFactory;
private final AuthTokenIQListenerFactory authTokenIQListenerFactory;
private final LibraryChangedIQListenerFactory libraryChangedIQListenerFactory;
private volatile AddressIQListener addressIQListener;
private volatile AuthTokenIQListener authTokenIQListener;
private volatile LibraryChangedIQListener libraryChangedIQListener;
private volatile ConnectBackRequestIQListener connectRequestIQListener;
private volatile FileTransferIQListener fileTransferIQListener;
private final EventListenerList<RosterEvent> rosterListeners;
private final Map<String, XMPPFriendImpl> friends;
private final SmackConnectionListener smackConnectionListener;
private final AtomicBoolean loggedIn = new AtomicBoolean(false);
private final AtomicBoolean loggingIn = new AtomicBoolean(false);
private volatile org.jivesoftware.smack.XMPPConnection connection;
private volatile DiscoInfoListener discoInfoListener;
private final ConnectBackRequestIQListenerFactory connectBackRequestIQListenerFactory;
private final FileTransferIQListenerFactory fileTransferIQListenerFactory;
private final ListenerSupport<FriendPresenceEvent> friendPresenceSupport;
private final FeatureRegistry featureRegistry;
private final IdleStatusMonitorFactory idleStatusMonitorFactory;
private IdleStatusMonitor idleStatusMonitor;
private volatile NoSaveFeatureInitializer noSaveFeatureInitializer;
private final JabberSettings jabberSettings;
private final ListenerSupport<XmppActivityEvent> xmppActivitySupport;
private EventListener<XmppActivityEvent> xmppActivityListener;
@Inject
public XMPPFriendConnectionImpl(@Assisted FriendConnectionConfiguration configuration,
@Assisted ListeningExecutorService executorService,
AsynchronousEventBroadcaster<RosterEvent> rosterBroadcaster,
EventBroadcaster<FriendRequestEvent> friendRequestBroadcaster,
AsynchronousEventMulticaster<FriendConnectionEvent> connectionMulticaster,
AddressFactory addressFactory,
EventMulticaster<FeatureEvent> featureSupport,
List<ConnectionConfigurationFactory> connectionConfigurationFactories,
AddressIQListenerFactory addressIQListenerFactory,
AuthTokenIQListenerFactory authTokenIQListenerFactory,
ConnectBackRequestIQListenerFactory connectBackRequestIQListenerFactory,
LibraryChangedIQListenerFactory libraryChangedIQListenerFactory,
FileTransferIQListenerFactory fileTransferIQListenerFactory,
ListenerSupport<FriendPresenceEvent> friendPresenceSupport,
FeatureRegistry featureRegistry,
IdleStatusMonitorFactory idleStatusMonitorFactory,
JabberSettings jabberSettings,
ListenerSupport<XmppActivityEvent> xmppActivitySupport) {
this.configuration = configuration;
this.friendRequestBroadcaster = friendRequestBroadcaster;
this.connectionMulticaster = connectionMulticaster;
this.addressFactory = addressFactory;
this.featureSupport = featureSupport;
this.executorService = executorService;
this.connectionConfigurationFactories = connectionConfigurationFactories;
this.addressIQListenerFactory = addressIQListenerFactory;
this.authTokenIQListenerFactory = authTokenIQListenerFactory;
this.libraryChangedIQListenerFactory = libraryChangedIQListenerFactory;
this.connectBackRequestIQListenerFactory = connectBackRequestIQListenerFactory;
this.fileTransferIQListenerFactory = fileTransferIQListenerFactory;
this.friendPresenceSupport = friendPresenceSupport;
this.featureRegistry = featureRegistry;
this.idleStatusMonitorFactory = idleStatusMonitorFactory;
this.jabberSettings = jabberSettings;
this.xmppActivitySupport = xmppActivitySupport;
rosterListeners = new EventListenerList<RosterEvent>();
// FIXME: this is only used by tests
if(configuration.getRosterListener() != null) {
rosterListeners.addListener(configuration.getRosterListener());
}
rosterListeners.addListener(new EventRebroadcaster<RosterEvent>(rosterBroadcaster));
friends = new TreeMap<String, XMPPFriendImpl>(String.CASE_INSENSITIVE_ORDER);
smackConnectionListener = new SmackConnectionListener();
}
@Override
public String toString() {
return org.limewire.util.StringUtils.toString(this, configuration, connection);
}
@Override
public boolean supportsMode() {
return true;
}
public ListeningFuture<Void> setMode(final FriendPresence.Mode mode) {
return executorService.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
setModeImpl(mode);
return null;
}
});
}
void setModeImpl(FriendPresence.Mode mode) throws FriendException {
synchronized (this) {
try {
checkLoggedIn();
connection.sendPacket(getPresenceForMode(mode));
} catch (org.jivesoftware.smack.XMPPException e) {
throw new FriendException(e);
}
}
}
private Packet getPresenceForMode(FriendPresence.Mode mode) {
org.jivesoftware.smack.packet.Presence presence = new org.jivesoftware.smack.packet.Presence(
org.jivesoftware.smack.packet.Presence.Type.available);
presence.setMode(org.jivesoftware.smack.packet.Presence.Mode.valueOf(mode.name()));
return presence;
}
public FriendConnectionConfiguration getConfiguration() {
return configuration;
}
@Override
public ListeningFuture<Void> login() {
return executorService.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
loginImpl();
return null;
}
});
}
void loginImpl() throws FriendException {
synchronized (this) {
try {
loggingIn.set(true);
connectionMulticaster.broadcast(new FriendConnectionEvent(this, FriendConnectionEvent.Type.CONNECTING));
org.jivesoftware.smack.XMPPConnection.addConnectionCreationListener(smackConnectionListener);
org.jivesoftware.smack.XMPPConnection.DEBUG_ENABLED = configuration.isDebugEnabled();
connect();
LOG.infof("connected.");
LOG.infof("logging in {0} with resource: {1} ...", configuration.getUserInputLocalID(), configuration.getResource());
connection.login(configuration.getUserInputLocalID(), configuration.getPassword(), configuration.getResource());
LOG.infof("logged in.");
loggedIn.set(true);
loggingIn.set(false);
connectionMulticaster.broadcast(new FriendConnectionEvent(this, FriendConnectionEvent.Type.CONNECTED));
} catch (org.jivesoftware.smack.XMPPException e) {
handleLoginError(e);
throw new FriendException(e);
} catch (RuntimeException e) {
handleLoginError(e);
throw e;
}
}
}
/**
* Unwind upon login error - broadcast login failed, remove conn creation
* listener from smack, set conn to null, disconnect if need be, etc
*
* @param e Exception which occurred during login
*/
private synchronized void handleLoginError(Exception e) {
loggingIn.set(false);
connectionMulticaster.broadcast(new FriendConnectionEvent(this, FriendConnectionEvent.Type.CONNECT_FAILED, e));
if (connection != null && connection.isConnected()) {
connection.disconnect();
}
org.jivesoftware.smack.XMPPConnection.removeConnectionCreationListener(smackConnectionListener);
connection = null;
}
private void connect() throws org.jivesoftware.smack.XMPPException {
for(ConnectionConfigurationFactory factory : connectionConfigurationFactories) {
try {
connectUsingFactory(factory);
return;
} catch (FriendException e) {
LOG.debug(e.getMessage(), e);
}
}
}
private void connectUsingFactory(ConnectionConfigurationFactory factory) throws FriendException {
ConnectionConfigurationFactory.RequestContext requestContext = new ConnectionConfigurationFactory.RequestContext();
while(factory.hasMore(configuration, requestContext)) {
ConnectionConfiguration connectionConfig = factory.getConnectionConfiguration(configuration, requestContext);
connection = new XMPPConnection(connectionConfig);
connection.addRosterListener(new RosterListenerImpl());
LOG.infof("connecting to {0} at {1}:{2} ...", connectionConfig.getServiceName(), connectionConfig.getHost(), connectionConfig.getPort());
try {
connection.connect();
return;
} catch (org.jivesoftware.smack.XMPPException e) {
LOG.debug(e.getMessage(), e);
requestContext.incrementRequests();
}
}
throw new FriendException("couldn't connect using " + factory);
}
@Override
public boolean isLoggingIn() {
return loggingIn.get();
}
@Override
public ListeningFuture<Void> logout() {
return executorService.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
logoutImpl(null);
return null;
}
});
}
/**
*
* @param error null if connection is closed by user
*/
void logoutImpl(Exception error) {
synchronized (this) {
if(isLoggedIn()) {
loggedIn.set(false);
LOG.infof("disconnecting from {0} at {1}:{2} ...", connection.getServiceName(), connection.getHost(), connection.getPort());
connection.disconnect();
synchronized (friends) {
friends.clear();
}
XMPPConnection.removeConnectionCreationListener(smackConnectionListener);
connection = null;
LOG.info("disconnected.");
connectionMulticaster.broadcast(new FriendConnectionEvent(XMPPFriendConnectionImpl.this, FriendConnectionEvent.Type.DISCONNECTED, error));
ChatStateManager.remove(connection);
if(discoInfoListener != null) {
discoInfoListener.cleanup();
}
if (noSaveFeatureInitializer != null) {
noSaveFeatureInitializer.cleanup();
}
if (idleStatusMonitor != null) {
idleStatusMonitor.stop();
}
if (xmppActivityListener != null) {
xmppActivitySupport.removeListener(xmppActivityListener);
}
featureRegistry.deregisterInitializer(NoSaveFeature.ID);
}
}
}
public boolean isLoggedIn() {
return loggedIn.get();
}
private void checkLoggedIn() throws FriendException {
synchronized (this) {
if(!isLoggedIn()) {
throw new FriendException("not connected");
}
}
}
private class RosterListenerImpl implements org.jivesoftware.smack.RosterListener {
public void entriesAdded(Collection<String> addedIds) {
try {
synchronized (XMPPFriendConnectionImpl.this) {
checkLoggedIn();
synchronized (friends) {
Roster roster = connection.getRoster();
if(roster != null) {
Map<String, XMPPFriendImpl> newFriends = new HashMap<String, XMPPFriendImpl>();
for(String id : addedIds) {
RosterEntry rosterEntry = roster.getEntry(id);
XMPPFriendImpl friend = new XMPPFriendImpl(id, rosterEntry, configuration, connection, featureRegistry);
LOG.debugf("user {0} added", friend);
newFriends.put(id, friend);
}
friends.putAll(newFriends);
rosterListeners.broadcast(new RosterEvent(new ArrayList<Friend>(newFriends.values()), RosterEvent.Type.FRIENDS_ADDED));
}
}
}
} catch (org.jivesoftware.smack.XMPPException e) {
LOG.debugf(e, "error getting roster");
} catch (FriendException e) {
LOG.debugf(e, "error getting roster");
}
}
public void entriesUpdated(Collection<String> updatedIds) {
try {
synchronized (XMPPFriendConnectionImpl.this) {
checkLoggedIn();
synchronized (friends) {
Roster roster = connection.getRoster();
if(roster != null) {
List<Friend> updatedFriends = new ArrayList<Friend>();
for(String id : updatedIds) {
RosterEntry rosterEntry = roster.getEntry(id);
XMPPFriendImpl friend = friends.get(id);
if(friend == null) {
// should never happen ?
friend = new XMPPFriendImpl(id, rosterEntry, configuration, connection, featureRegistry);
friends.put(id, friend);
} else {
friend.setRosterEntry(rosterEntry);
}
updatedFriends.add(friend);
LOG.debugf("user {0} updated", friend);
}
rosterListeners.broadcast(new RosterEvent(updatedFriends, RosterEvent.Type.FRIENDS_UPDATED));
}
}
}
} catch (org.jivesoftware.smack.XMPPException e) {
LOG.debugf(e, "error getting roster");
} catch (FriendException e) {
LOG.debugf(e, "error getting roster");
}
}
public void entriesDeleted(Collection<String> removedIds) {
synchronized (friends) {
List<Friend> deletedFriends = new ArrayList<Friend>();
for(String id : removedIds) {
XMPPFriendImpl friend = friends.remove(id);
if(friend != null) {
deletedFriends.add(friend);
LOG.debugf("user {0} removed", friend);
}
}
rosterListeners.broadcast(new RosterEvent(deletedFriends, RosterEvent.Type.FRIENDS_DELETED));
}
}
@Override
public void presenceChanged(final org.jivesoftware.smack.packet.Presence presence) {
String localJID;
try {
localJID = getLocalJid();
} catch (FriendException e) {
localJID = null;
}
if(!presence.getFrom().equals(localJID)) {
XMPPFriendImpl friend = getFriend(presence);
if(friend != null) {
LOG.debugf("presence from {0} changed to {1}", presence.getFrom(), presence.getType());
// synchronize to avoid updates or presences from being lost
// better to replace that with a lock object private to this
// connection class
synchronized (friend) {
if (presence.getType().equals(org.jivesoftware.smack.packet.Presence.Type.available)) {
if(!friend.getPresences().containsKey(presence.getFrom())) {
addNewPresence(friend, presence);
} else {
updatePresence(friend, presence);
}
} else if (presence.getType().equals(org.jivesoftware.smack.packet.Presence.Type.unavailable)) {
PresenceImpl p = (PresenceImpl)friend.getPresence(presence.getFrom());
if(p != null) {
p.update(presence);
friend.removePresense(p);
}
}
}
} else {
LOG.debugf("no friend for presence {0}", presence.getFrom());
}
}
}
private XMPPFriendImpl getFriend(org.jivesoftware.smack.packet.Presence presence) {
XMPPFriendImpl friend;
synchronized (friends) {
friend = friends.get(PresenceUtils.parseBareAddress(presence.getFrom()));
}
return friend;
}
private void addNewPresence(final XMPPFriendImpl friend, final org.jivesoftware.smack.packet.Presence presence) {
final PresenceImpl presenceImpl = new PresenceImpl(presence, friend, featureSupport);
presenceImpl.addTransport(AddressFeature.class, addressIQListener);
presenceImpl.addTransport(AuthTokenFeature.class, authTokenIQListener);
presenceImpl.addTransport(ConnectBackRequestFeature.class, connectRequestIQListener);
presenceImpl.addTransport(LibraryChangedNotifierFeature.class, libraryChangedIQListener);
presenceImpl.addTransport(FileOfferFeature.class, fileTransferIQListener);
friend.addPresense(presenceImpl);
}
private void updatePresence(XMPPFriendImpl friend, org.jivesoftware.smack.packet.Presence presence) {
PresenceImpl currentPresence = (PresenceImpl)friend.getPresences().get(presence.getFrom());
currentPresence.update(presence);
friend.updatePresence(currentPresence);
}
}
@Override
public boolean supportsAddRemoveFriend() {
return true;
}
@Override
public ListeningFuture<Void> addNewFriend(final String id, final String name) {
return executorService.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
addFriendImpl(id, name);
return null;
}
});
}
void addFriendImpl(String id, String name) throws FriendException {
synchronized (this) {
try {
checkLoggedIn();
Roster roster = connection.getRoster();
if(roster != null) {
// TODO smack enhancement
// TODO to support notifications when
// TODO the Roster is created
roster.createEntry(id, name, null);
}
} catch (org.jivesoftware.smack.XMPPException e) {
throw new FriendException(e);
}
}
}
@Override
public ListeningFuture<Void> removeFriend(final String id) {
return executorService.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
removeFriendImpl(id);
return null;
}
});
}
private void removeFriendImpl(String id) throws FriendException {
synchronized (this) {
try {
checkLoggedIn();
Roster roster = connection.getRoster();
if(roster != null) {
// TODO smack enhancement
// TODO to support notifications when
// TODO the Roster is created
RosterEntry entry = roster.getEntry(id);
if(entry!= null) {
roster.removeEntry(entry);
}
}
} catch (org.jivesoftware.smack.XMPPException e) {
throw new FriendException(e);
}
}
}
@Override
public XMPPFriendImpl getFriend(String id) {
id = PresenceUtils.parseBareAddress(id);
synchronized (friends) {
return friends.get(id);
}
}
@Override
public Collection<Friend> getFriends() {
synchronized (friends) {
return new ArrayList<Friend>(friends.values());
}
}
public void sendPacket(Packet packet) throws FriendException {
synchronized (this) {
try {
checkLoggedIn();
connection.sendPacket(packet);
} catch (org.jivesoftware.smack.XMPPException e) {
throw new FriendException(e);
}
}
}
public String getLocalJid() throws FriendException {
synchronized (this) {
checkLoggedIn();
return connection.getUser();
}
}
/**
* Sets the connection mode to idle (extended away) after receiving activity
* events triggered by periods of inactivity.
*/
private class XmppActivityEventListener implements EventListener<XmppActivityEvent> {
@Override
public void handleEvent(XmppActivityEvent event) {
switch (event.getSource()) {
case Idle:
try {
setModeImpl(FriendPresence.Mode.xa);
} catch (FriendException e) {
LOG.debugf(e, "couldn't set mode based on {0}", event);
}
break;
case Active:
try {
setModeImpl(jabberSettings.isDoNotDisturbSet() ?
FriendPresence.Mode.dnd : FriendPresence.Mode.available);
} catch (FriendException e) {
LOG.debugf(e, "couldn't set mode based on {0}", event);
}
}
}
}
private class SmackConnectionListener implements ConnectionListener, ConnectionCreationListener {
@Override
public void connectionCreated(XMPPConnection connection) {
if(XMPPFriendConnectionImpl.this.connection != connection) {
return;
}
if(LOG.isDebugEnabled()) {
LOG.debug("connection created for "+ connection.toString());
}
connection.addConnectionListener(this);
synchronized (ProviderManager.getInstance()) {
if(ProviderManager.getInstance().getIQProvider("address", "jabber:iq:lw-address") == null) {
ProviderManager.getInstance().addIQProvider("address", "jabber:iq:lw-address", new AddressIQProvider(addressFactory));
}
if(ProviderManager.getInstance().getIQProvider("file-transfer", "jabber:iq:lw-file-transfer") == null) {
ProviderManager.getInstance().addIQProvider("file-transfer", "jabber:iq:lw-file-transfer", FileTransferIQ.getIQProvider());
}
if(ProviderManager.getInstance().getIQProvider("auth-token", "jabber:iq:lw-auth-token") == null) {
ProviderManager.getInstance().addIQProvider("auth-token", "jabber:iq:lw-auth-token", new AuthTokenIQProvider());
}
if(ProviderManager.getInstance().getIQProvider("library-changed", "jabber:iq:lw-lib-change") == null) {
ProviderManager.getInstance().addIQProvider("library-changed", "jabber:iq:lw-lib-change", LibraryChangedIQ.getIQProvider());
}
if (ProviderManager.getInstance().getIQProvider(ConnectBackRequestIQ.ELEMENT_NAME, ConnectBackRequestIQ.NAME_SPACE) == null) {
ProviderManager.getInstance().addIQProvider(ConnectBackRequestIQ.ELEMENT_NAME, ConnectBackRequestIQ.NAME_SPACE, new ConnectBackRequestIQProvider());
}
if (ProviderManager.getInstance().getIQProvider(NoSaveIQ.ELEMENT_NAME, NoSaveIQ.NAME_SPACE) == null) {
ProviderManager.getInstance().addIQProvider(NoSaveIQ.ELEMENT_NAME, NoSaveIQ.NAME_SPACE, NoSaveIQ.getIQProvider());
}
}
ChatStateManager.getInstance(connection);
discoInfoListener = new DiscoInfoListener(XMPPFriendConnectionImpl.this, connection, featureRegistry);
discoInfoListener.addListeners(connectionMulticaster, friendPresenceSupport);
addressIQListener = addressIQListenerFactory.create(XMPPFriendConnectionImpl.this, addressFactory);
connection.addPacketListener(addressIQListener, addressIQListener.getPacketFilter());
fileTransferIQListener = fileTransferIQListenerFactory.create(XMPPFriendConnectionImpl.this);
connection.addPacketListener(fileTransferIQListener, fileTransferIQListener.getPacketFilter());
authTokenIQListener = authTokenIQListenerFactory.create(XMPPFriendConnectionImpl.this);
connection.addPacketListener(authTokenIQListener, authTokenIQListener.getPacketFilter());
libraryChangedIQListener = libraryChangedIQListenerFactory.create(XMPPFriendConnectionImpl.this);
connection.addPacketListener(libraryChangedIQListener, libraryChangedIQListener.getPacketFilter());
connectRequestIQListener = connectBackRequestIQListenerFactory.create(XMPPFriendConnectionImpl.this);
connection.addPacketListener(connectRequestIQListener, connectRequestIQListener.getPacketFilter());
new LimewireFeatureInitializer().register(featureRegistry);
noSaveFeatureInitializer = new NoSaveFeatureInitializer(connection, XMPPFriendConnectionImpl.this,
rosterListeners, friendPresenceSupport);
noSaveFeatureInitializer.register(featureRegistry);
SubscriptionListener sub = new SubscriptionListener(connection,
friendRequestBroadcaster);
connection.addPacketListener(sub, sub);
for(URI feature : featureRegistry.getPublicFeatureUris()) {
ServiceDiscoveryManager.getInstanceFor(connection).addFeature(feature.toASCIIString());
}
if (xmppActivityListener == null) {
xmppActivityListener = new XmppActivityEventListener();
}
xmppActivitySupport.addListener(xmppActivityListener);
if (idleStatusMonitor == null) {
idleStatusMonitor = idleStatusMonitorFactory.create();
}
idleStatusMonitor.start();
}
@Override
public void connectionClosed() {
LOG.debug("smack connection closed");
}
@Override
public void connectionClosedOnError(Exception e) {
LOG.debug("smack connection closed with error", e);
logoutImpl(e);
}
@Override
public void reconnectingIn(int seconds) {
}
@Override
public void reconnectionFailed(Exception e) {
}
@Override
public void reconnectionSuccessful() {
}
}
}