aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/ChatWindowManager.java18
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatRoomProviderWrapper.java5
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatManager.java2
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomList.java9
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/ChatRoomJabberImpl.java12
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java8
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/JabberActivator.java38
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetMultiUserChatJabberImpl.java131
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java31
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/ServerStoredContactListJabberImpl.java3
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/UriHandlerJabberImpl.java689
-rwxr-xr-xsrc/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf2
12 files changed, 845 insertions, 103 deletions
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWindowManager.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWindowManager.java
index 48b5329..c53d890 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWindowManager.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWindowManager.java
@@ -39,8 +39,20 @@ public class ChatWindowManager
* @param setSelected specifies whether we should bring the chat to front
* after creating it.
*/
- public void openChat(ChatPanel chatPanel, boolean setSelected)
+ public void openChat(final ChatPanel chatPanel, final boolean setSelected)
{
+ if(!SwingUtilities.isEventDispatchThread())
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ openChat(chatPanel, setSelected);
+ }
+ });
+ return;
+ }
+
synchronized (syncChat)
{
ChatWindow chatWindow = chatPanel.getChatWindow();
@@ -154,7 +166,7 @@ public class ChatWindowManager
ChatRoomWrapper chatRoomWrapper
= (ChatRoomWrapper) descriptor;
- if(chatRoomWrapper.getChatRoom().equals(chatRoom)
+ if(chatRoomWrapper.getChatRoomID().equals(chatRoom.getIdentifier())
&& getChat(chatSession).isShown())
{
return true;
@@ -409,8 +421,8 @@ public class ChatWindowManager
}
else
return createChat(chatRoomWrapper);
+ }
}
- }
/**
* Returns the chat panel corresponding to the given chat room.
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatRoomProviderWrapper.java b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatRoomProviderWrapper.java
index 8c9250d..cb59a13 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatRoomProviderWrapper.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatRoomProviderWrapper.java
@@ -152,10 +152,11 @@ public class ChatRoomProviderWrapper
*/
public ChatRoomWrapper findChatRoomWrapperForChatRoom(ChatRoom chatRoom)
{
+ // compare ids, cause saved chatrooms don't have ChatRoom object
+ // but Id's are the same
for (ChatRoomWrapper chatRoomWrapper : chatRoomsOrderedCopy)
{
- if (chatRoomWrapper.getChatRoom() != null
- && chatRoomWrapper.getChatRoom().equals(chatRoom))
+ if (chatRoomWrapper.getChatRoomID().equals(chatRoom.getIdentifier()))
{
return chatRoomWrapper;
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatManager.java b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatManager.java
index 2d9a50e..f211957 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatManager.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatManager.java
@@ -691,7 +691,7 @@ public class ConferenceChatManager
GuiActivator.getUIService().getMainFrame(),
GuiActivator.getResources().getI18NString("service.gui.WARNING"),
GuiActivator.getResources().getI18NString(
- "service.gui.CHAT_ROOM_LEAVE_NOT_CONNECTED="))
+ "service.gui.CHAT_ROOM_LEAVE_NOT_CONNECTED"))
.showDialog();
return;
diff --git a/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomList.java b/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomList.java
index 9269ac1..d4cfb7d 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomList.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomList.java
@@ -246,7 +246,16 @@ public class ChatRoomList
= provider.findChatRoomWrapperForChatRoom(chatRoom);
if (chatRoomWrapper != null)
+ {
+ // stored chatrooms has no chatroom, but their
+ // id is the same as the chatroom we are searching wrapper for
+ if(chatRoomWrapper.getChatRoom() == null)
+ {
+ chatRoomWrapper.setChatRoom(chatRoom);
+ }
+
return chatRoomWrapper;
+ }
}
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ChatRoomJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ChatRoomJabberImpl.java
index f5cecd9..b47b38a 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/ChatRoomJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/ChatRoomJabberImpl.java
@@ -20,6 +20,7 @@ import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.util.*;
import org.jivesoftware.smackx.*;
import org.jivesoftware.smackx.muc.*;
+import org.jivesoftware.smackx.packet.DiscoverInfo;
/**
* Implements chat rooms for jabber. The class encapsulates instances of the
@@ -1724,10 +1725,15 @@ public class ChatRoomJabberImpl
String roomName = multiUserChat.getRoom();
try
{
- RoomInfo info = MultiUserChat.getRoomInfo(
- provider.getConnection(), roomName);
+ // Do not use getRoomInfo, as it has bug and
+ // throws NPE
+ DiscoverInfo info =
+ ServiceDiscoveryManager.getInstanceFor(provider.getConnection()).
+ discoverInfo(roomName);
+
if (info != null)
- persistent = info.isPersistent();
+ persistent = info.containsFeature("muc_persistent");
+
} catch (Exception ex)
{
logger.warn("could not get persistent state for room :" +
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java b/src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java
index 955d4a3..153978d 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java
@@ -257,14 +257,6 @@ public class InfoRetreiver
+ this + " : " + exc.getMessage()
, exc);
}
-
-
- Iterator i = result.iterator();
- while (i.hasNext())
- {
- Object object = i.next();
- logger.info("--------------- " + object.getClass() + " " + object);
- }
}
retreivedDetails.put(contactAddress, result);
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/JabberActivator.java b/src/net/java/sip/communicator/impl/protocol/jabber/JabberActivator.java
index 3b1f100..a66bfb7 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/JabberActivator.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/JabberActivator.java
@@ -10,6 +10,7 @@ import java.util.*;
import org.osgi.framework.*;
import net.java.sip.communicator.service.configuration.*;
+import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.media.*;
@@ -48,6 +49,10 @@ public class JabberActivator
*/
private static ProtocolProviderFactoryJabberImpl jabberProviderFactory = null;
+ private UriHandlerJabberImpl uriHandlerImpl = null;
+
+ private static UIService uiService = null;
+
/**
* Called when this bundle is started so the Framework can perform the
* bundle-specific activities necessary to start this bundle.
@@ -67,6 +72,13 @@ public class JabberActivator
jabberProviderFactory = new ProtocolProviderFactoryJabberImpl();
+ /*
+ * Install the UriHandler prior to registering the factory service in
+ * order to allow it to detect when the stored accounts are loaded
+ * (because they may be asynchronously loaded).
+ */
+ uriHandlerImpl = new UriHandlerJabberImpl(jabberProviderFactory);
+
//reg the jabber account man.
jabberPpFactoryServReg = context.registerService(
ProtocolProviderFactory.class.getName(),
@@ -153,5 +165,31 @@ public class JabberActivator
{
jabberProviderFactory.stop();
jabberPpFactoryServReg.unregister();
+
+ if (uriHandlerImpl != null)
+ {
+ uriHandlerImpl.dispose();
+ uriHandlerImpl = null;
+ }
+ }
+
+ /**
+ * Returns a reference to the UIService implementation currently registered
+ * in the bundle context or null if no such implementation was found.
+ *
+ * @return a reference to a UIService implementation currently registered
+ * in the bundle context or null if no such implementation was found.
+ */
+ public static UIService getUIService()
+ {
+ if(uiService == null)
+ {
+ ServiceReference uiServiceReference
+ = bundleContext.getServiceReference(
+ UIService.class.getName());
+ uiService = (UIService)bundleContext
+ .getService(uiServiceReference);
+ }
+ return uiService;
}
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetMultiUserChatJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetMultiUserChatJabberImpl.java
index 0286875..6af4b1d 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetMultiUserChatJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetMultiUserChatJabberImpl.java
@@ -13,7 +13,6 @@ import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
import org.jivesoftware.smack.*;
-import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.*;
import org.jivesoftware.smackx.muc.*;
@@ -114,7 +113,7 @@ public class OperationSetMultiUserChatJabberImpl
invitationListeners.remove(listener);
}
}
-
+
/**
* Adds a listener that will be notified of changes in our status in a chat
* room such as us being kicked, banned or dropped.
@@ -236,7 +235,7 @@ public class OperationSetMultiUserChatJabberImpl
private ChatRoom createLocalChatRoomInstance(MultiUserChat muc)
{
synchronized(chatRoomCache)
- {
+ {
ChatRoomJabberImpl chatRoom
= new ChatRoomJabberImpl(muc, jabberProvider);
cacheChatRoom(chatRoom);
@@ -246,7 +245,7 @@ public class OperationSetMultiUserChatJabberImpl
// ChatRoomInvitationRejectionListener.
muc.addInvitationRejectionListener(
new SmackInvitationRejectionListener(chatRoom));
-
+
return chatRoom;
}
}
@@ -264,7 +263,7 @@ public class OperationSetMultiUserChatJabberImpl
* @throws OperationNotSupportedException if the server does not support
* multi user chat
*/
- public ChatRoom findRoom(String roomName)
+ public synchronized ChatRoom findRoom(String roomName)
throws OperationFailedException, OperationNotSupportedException
{
//make sure we are connected and multichat is supported.
@@ -279,59 +278,23 @@ public class OperationSetMultiUserChatJabberImpl
try
{
- RoomInfo infos = MultiUserChat.getRoomInfo(
- getXmppConnection(), canonicalRoomName);
- if (infos.getRoom().equals(canonicalRoomName))
- {
- MultiUserChat muc =
+ // throws Exception if room does not exist
+ // do not use MultiUserChat.getRoomInfo as there is a bug which
+ // throws NPE
+ ServiceDiscoveryManager.getInstanceFor(getXmppConnection()).
+ discoverInfo(canonicalRoomName);
+
+ MultiUserChat muc =
new MultiUserChat(getXmppConnection(), canonicalRoomName);
- room = new ChatRoomJabberImpl(muc, jabberProvider);
- chatRoomCache.put(canonicalRoomName, room);
- return room;
- }
- }
- catch (XMPPException xe)
- {
- return null;
- }
- catch (NullPointerException ne)
- {
- // caused by some bug in smack, we will try another method
- }
+ room = new ChatRoomJabberImpl(muc, jabberProvider);
+ chatRoomCache.put(canonicalRoomName, room);
- try
- {
- // getHostedRooms will let us if the room doesnt exists
- // by raising an XMPPException with
- // XMPPError.Condition.item_not_found as error condition.
- // if we get anything else, we can conclude so we create
- // the MultiUserChat instance and the failure point will be
- // join method
- Collection<HostedRoom> co =
- MultiUserChat.getHostedRooms(
- getXmppConnection(), canonicalRoomName);
- }
- catch (XMPPException xe)
+ return room;
+ } catch (XMPPException e)
{
- if (xe.getXMPPError().getCondition().equals(
- XMPPError.Condition.item_not_found.toString()))
- {
- return null;
- }
- else
- {
- MultiUserChat muc =
- new MultiUserChat(
- getXmppConnection(), canonicalRoomName);
-
- room = new ChatRoomJabberImpl(muc,
- jabberProvider);
-
- chatRoomCache.put(canonicalRoomName, room);
- return room;
- }
+ // room not found
+ return null;
}
- return null;
}
/**
@@ -342,7 +305,7 @@ public class OperationSetMultiUserChatJabberImpl
* a given connection.
*/
public List<ChatRoom> getCurrentlyJoinedChatRooms()
- {
+ {
synchronized(chatRoomCache)
{
List joinedRooms
@@ -415,9 +378,9 @@ public class OperationSetMultiUserChatJabberImpl
OperationNotSupportedException
{
assertSupportedAndConnected();
-
+
List list = new LinkedList();
-
+
//first retrieve all conference service names available on this server
Iterator<String> serviceNames = null;
try
@@ -484,7 +447,7 @@ public class OperationSetMultiUserChatJabberImpl
if(contact.getProtocolProvider()
.getOperationSet(OperationSetMultiUserChat.class) != null)
return true;
-
+
return false;
}
@@ -650,11 +613,11 @@ public class OperationSetMultiUserChatJabberImpl
return (List) joinedRoomsIter;
}
-
+
/**
* Delivers a <tt>LocalUserChatRoomPresenceChangeEvent</tt> to all
* registered <tt>LocalUserChatRoomPresenceListener</tt>s.
- *
+ *
* @param chatRoom the <tt>ChatRoom</tt> which has been joined, left, etc.
* @param eventType the type of this event; one of LOCAL_USER_JOINED,
* LOCAL_USER_LEFT, etc.
@@ -668,7 +631,7 @@ public class OperationSetMultiUserChatJabberImpl
chatRoom,
eventType,
reason);
-
+
Iterator listeners = null;
synchronized (presenceListeners)
{
@@ -679,7 +642,7 @@ public class OperationSetMultiUserChatJabberImpl
{
LocalUserChatRoomPresenceListener listener
= (LocalUserChatRoomPresenceListener) listeners.next();
-
+
listener.localUserPresenceChanged(evt);
}
}
@@ -687,11 +650,11 @@ public class OperationSetMultiUserChatJabberImpl
/**
* Delivers a <tt>ChatRoomInvitationReceivedEvent</tt> to all
* registered <tt>ChatRoomInvitationListener</tt>s.
- *
+ *
* @param targetChatRoom the room that invitation refers to
* @param inviter the inviter that sent the invitation
* @param reason the reason why the inviter sent the invitation
- * @param password the password to use when joining the room
+ * @param password the password to use when joining the room
*/
public void fireInvitationEvent(
ChatRoom targetChatRoom,
@@ -704,11 +667,11 @@ public class OperationSetMultiUserChatJabberImpl
inviter,
reason,
password);
-
+
ChatRoomInvitationReceivedEvent evt
= new ChatRoomInvitationReceivedEvent(this, invitation,
new Date(System.currentTimeMillis()));
-
+
Iterator listeners = null;
synchronized (invitationListeners)
{
@@ -723,11 +686,11 @@ public class OperationSetMultiUserChatJabberImpl
listener.invitationReceived(evt);
}
}
-
+
/**
* Delivers a <tt>ChatRoomInvitationRejectedEvent</tt> to all
* registered <tt>ChatRoomInvitationRejectionListener</tt>s.
- *
+ *
* @param sourceChatRoom the room that invitation refers to
* @param invitee the name of the invitee that rejected the invitation
* @param reason the reason of the rejection
@@ -740,18 +703,18 @@ public class OperationSetMultiUserChatJabberImpl
= new ChatRoomInvitationRejectedEvent(
this, sourceChatRoom, invitee, reason,
new Date(System.currentTimeMillis()));
-
+
Iterator listeners = null;
synchronized (invitationRejectionListeners)
{
listeners = new ArrayList(invitationRejectionListeners).iterator();
}
-
+
while (listeners.hasNext())
{
ChatRoomInvitationRejectionListener listener
= (ChatRoomInvitationRejectionListener) listeners.next();
-
+
listener.invitationRejected(evt);
}
}
@@ -765,11 +728,11 @@ public class OperationSetMultiUserChatJabberImpl
{
/**
* Called when the an invitation to join a MUC room is received.<p>
- *
+ *
* If the room is password-protected, the invitee will receive a
* password to use to join the room. If the room is members-only, the
* the invitee may be added to the member list.
- *
+ *
* @param conn the XMPPConnection that received the invitation.
* @param room the room that invitation refers to.
* @param inviter the inviter that sent the invitation.
@@ -808,7 +771,7 @@ public class OperationSetMultiUserChatJabberImpl
}
}
}
-
+
/**
* A listener that is fired anytime an invitee declines or rejects an
* invitation.
@@ -817,39 +780,39 @@ public class OperationSetMultiUserChatJabberImpl
implements InvitationRejectionListener
{
private ChatRoom chatRoom;
-
+
/**
* Creates an instance of <tt>SmackInvitationRejectionListener</tt> and
* passes to it the chat room for which it will listen for rejection
* events.
- *
+ *
* @param chatRoom
*/
public SmackInvitationRejectionListener(ChatRoom chatRoom)
{
this.chatRoom = chatRoom;
}
-
+
/**
* Called when the invitee declines the invitation.
- *
+ *
* @param invitee the invitee that declined the invitation.
* (e.g. hecate@shakespeare.lit).
* @param reason the reason why the invitee declined the invitation.
*/
public void invitationDeclined(String invitee, String reason)
- {
+ {
fireInvitationRejectedEvent(chatRoom, invitee, reason);
}
}
-
+
/**
* Our listener that will tell us when we're registered to jabber and the
* smack MultiUserChat is ready to accept us as a listener.
*/
private class RegistrationStateListener
implements RegistrationStateChangeListener
- {
+ {
/**
* The method is called by a ProtocolProvider implementation whenver
* a change in the registration state of the corresponding provider had
@@ -862,14 +825,14 @@ public class OperationSetMultiUserChatJabberImpl
if (evt.getNewState() == RegistrationState.REGISTERED)
{
logger.debug("adding an Invitation listener to the smack muc");
-
+
MultiUserChat.addInvitationListener(
jabberProvider.getConnection(),
new SmackInvitationListener());
}
}
}
-
+
/**
* Updates corresponding chat room members when a contact has been modified
* in our contact list.
@@ -924,7 +887,7 @@ public class OperationSetMultiUserChatJabberImpl
/**
* Finds all chat room members, which name corresponds to the name of the
* given contact and updates their contact references.
- *
+ *
* @param contact the contact we're looking correspondences for.
*/
private void updateChatRoomMembers(Contact contact)
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
index 3e24ffd..fcffd6a 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
@@ -358,7 +358,36 @@ public class ProtocolProviderServiceJabberImpl
if(accountResource == null || accountResource.equals(""))
accountResource = "sip-comm";
- connection.login(userID, password, accountResource);
+ SASLAuthentication.supportSASLMechanism("PLAIN", 0);
+
+ try
+ {
+ connection.login(userID, password, accountResource);
+ } catch (XMPPException e1)
+ {
+ // after updating to new smack lib
+ // login mechanisum changed
+ // this is a way to avoid the problem
+ try
+ {
+ // server disconnect us after such un error
+ // cleanup
+ try
+ {
+ connection.disconnect();
+ } catch (Exception e)
+ {}
+ // and connect again
+ connection.connect();
+ // logging in to google need and service name
+ connection.login(userID + "@" + serviceName,
+ password, accountResource);
+ } catch (XMPPException e2)
+ {
+ // if it happens once again throw the original exception
+ throw e1;
+ }
+ }
if(connection.isAuthenticated())
{
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ServerStoredContactListJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ServerStoredContactListJabberImpl.java
index e03214a..356ab0b 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/ServerStoredContactListJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/ServerStoredContactListJabberImpl.java
@@ -543,7 +543,8 @@ public class ServerStoredContactListJabberImpl
while (iter.hasNext())
{
ContactJabberImpl item = (ContactJabberImpl) iter.next();
- roster.removeEntry(item.getSourceEntry());
+ if(item.isPersistent())
+ roster.removeEntry(item.getSourceEntry());
}
}
catch (XMPPException ex)
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/UriHandlerJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/UriHandlerJabberImpl.java
new file mode 100644
index 0000000..67ab291
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/UriHandlerJabberImpl.java
@@ -0,0 +1,689 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.jabber;
+
+import java.util.*;
+import java.util.regex.*;
+
+import org.osgi.framework.*;
+
+import net.java.sip.communicator.service.argdelegation.*;
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.util.*;
+
+
+/**
+ * The jabber implementation of the URI handler. This class handles xmpp URIs by
+ * trying to establish a chat with them or add you to a chatroom.
+ *
+ * @author Emil Ivov
+ * @author Damian Minkov
+ */
+public class UriHandlerJabberImpl
+ implements UriHandler, ServiceListener, AccountManagerListener
+{
+ private static final Logger logger =
+ Logger.getLogger(UriHandlerJabberImpl.class);
+
+ /**
+ * The protocol provider factory that created us.
+ */
+ private final ProtocolProviderFactory protoFactory;
+
+ /**
+ * A reference to the OSGi registration we create with this handler.
+ */
+ private ServiceRegistration ourServiceRegistration = null;
+
+ /**
+ * The object that we are using to synchronize our service registration.
+ */
+ private final Object registrationLock = new Object();
+
+ /**
+ * The <code>AccountManager</code> which loads the stored accounts of
+ * {@link #protoFactory} and to be monitored when the mentioned loading is
+ * complete so that any pending {@link #uris} can be handled
+ */
+ private AccountManager accountManager;
+
+ /**
+ * The indicator (and its synchronization lock) which determines whether the
+ * stored accounts of {@link #protoFactory} have already been loaded.
+ * <p>
+ * Before the loading of the stored accounts (even if there're none) of the
+ * <code>protoFactory</code> is complete, no handling of URIs is to be
+ * performed because there's neither information which account to handle the
+ * URI in case there're stored accounts available nor ground for warning the
+ * user a registered account is necessary to handle URIs at all in case
+ * there're no stored accounts.
+ * </p>
+ */
+ private final boolean[] storedAccountsAreLoaded = new boolean[1];
+
+ /**
+ * The list of URIs which have received requests for handling before the
+ * stored accounts of the {@link #protoFactory} have been loaded. They will
+ * be handled as soon as the mentioned loading completes.
+ */
+ private List<String> uris;
+
+ /**
+ * Marks network fails in order to avoid endless loops.
+ */
+ private boolean networkFailReceived = false;
+
+ /**
+ * Creates an instance of this uri handler, so that it would start handling
+ * URIs by passing them to the providers registered by <tt>protoFactory</tt>
+ * .
+ *
+ * @param parentProvider the provider that created us.
+ *
+ * @throws NullPointerException if <tt>protoFactory</tt> is <tt>null</tt>.
+ */
+ public UriHandlerJabberImpl(ProtocolProviderFactory protoFactory)
+ throws NullPointerException
+ {
+ if (protoFactory == null)
+ {
+ throw new NullPointerException(
+ "The ProtocolProviderFactory that a UriHandler is created with "
+ + " cannot be null.");
+ }
+
+ this.protoFactory = protoFactory;
+
+ hookStoredAccounts();
+
+ this.protoFactory.getBundleContext().addServiceListener(this);
+ /*
+ * Registering the UriHandler isn't strictly necessary if the
+ * requirement to register the protoFactory after creating this instance
+ * is met.
+ */
+ registerHandlerService();
+ }
+
+ /**
+ * Disposes of this <code>UriHandler</code> by, for example, removing the
+ * listeners it has added in its constructor (in order to prevent memory
+ * leaks, for one).
+ */
+ public void dispose()
+ {
+ protoFactory.getBundleContext().removeServiceListener(this);
+ unregisterHandlerService();
+
+ unhookStoredAccounts();
+ }
+
+ /**
+ * Sets up (if not set up already) listening for the loading of the stored
+ * accounts of {@link #protoFactory} in order to make it possible to
+ * discover when the prerequisites for handling URIs are met.
+ */
+ private void hookStoredAccounts()
+ {
+ if (accountManager == null)
+ {
+ BundleContext bundleContext = protoFactory.getBundleContext();
+
+ accountManager =
+ (AccountManager) bundleContext.getService(bundleContext
+ .getServiceReference(AccountManager.class.getName()));
+ accountManager.addListener(this);
+ }
+ }
+
+ /**
+ * Reverts (if not reverted already) the setup performed by a previous chat
+ * to {@link #hookStoredAccounts()}.
+ */
+ private void unhookStoredAccounts()
+ {
+ if (accountManager != null)
+ {
+ accountManager.removeListener(this);
+ accountManager = null;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.java.sip.communicator.service.protocol.event.AccountManagerListener
+ * #handleAccountManagerEvent
+ * (net.java.sip.communicator.service.protocol.event.AccountManagerEvent)
+ */
+ public void handleAccountManagerEvent(AccountManagerEvent event)
+ {
+
+ /*
+ * When the loading of the stored accounts of protoFactory is complete,
+ * the prerequisites for handling URIs have been met so it's time to
+ * load any handling requests which have come before the loading and
+ * were thus delayed in uris.
+ */
+ if ((AccountManagerEvent.STORED_ACCOUNTS_LOADED == event.getType())
+ && (protoFactory == event.getFactory()))
+ {
+ List<String> uris = null;
+
+ synchronized (storedAccountsAreLoaded)
+ {
+ storedAccountsAreLoaded[0] = true;
+
+ if (this.uris != null)
+ {
+ uris = this.uris;
+ this.uris = null;
+ }
+ }
+
+ unhookStoredAccounts();
+
+ if (uris != null)
+ {
+ for (Iterator<String> uriIter = uris.iterator(); uriIter
+ .hasNext();)
+ {
+ handleUri(uriIter.next());
+ }
+ }
+ }
+ }
+
+ /**
+ * Registers this UriHandler with the bundle context so that it could start
+ * handling URIs
+ */
+ public void registerHandlerService()
+ {
+ synchronized (registrationLock)
+ {
+ if (ourServiceRegistration != null)
+ {
+ // ... we are already registered (this is probably
+ // happening during startup)
+ return;
+ }
+
+ Hashtable<String, String> registrationProperties =
+ new Hashtable<String, String>();
+
+ registrationProperties.put(UriHandler.PROTOCOL_PROPERTY,
+ getProtocol());
+
+ ourServiceRegistration =
+ JabberActivator.bundleContext.registerService(UriHandler.class
+ .getName(), this, registrationProperties);
+ }
+
+ }
+
+ /**
+ * Unregisters this UriHandler from the bundle context.
+ */
+ public void unregisterHandlerService()
+ {
+ synchronized (registrationLock)
+ {
+ if (ourServiceRegistration != null)
+ {
+ ourServiceRegistration.unregister();
+ ourServiceRegistration = null;
+ }
+ }
+ }
+
+ /**
+ * Returns the protocol that this handler is responsible for or "xmpp" in
+ * other words.
+ *
+ * @return the "xmpp" string to indicate that this handler is responsible for
+ * handling "xmpp" uris.
+ */
+ public String getProtocol()
+ {
+ return "xmpp";
+ }
+
+ /**
+ * Parses the specified URI and creates a chat with the currently active
+ * im operation set.
+ *
+ * @param uri the xmpp URI that we have to handle.
+ */
+ public void handleUri(String uri)
+ {
+ /*
+ * TODO If the requirement to register the factory service after
+ * creating this instance is broken, we'll end up not handling the URIs.
+ */
+ synchronized (storedAccountsAreLoaded)
+ {
+ if (!storedAccountsAreLoaded[0])
+ {
+ if (uris == null)
+ {
+ uris = new LinkedList<String>();
+ }
+ uris.add(uri);
+ return;
+ }
+ }
+
+ ProtocolProviderService provider;
+ try
+ {
+ provider = selectHandlingProvider(uri);
+ }
+ catch (OperationFailedException exc)
+ {
+ // The operation has been canceled by the user. Bail out.
+ logger.trace("User canceled handling of uri " + uri);
+ return;
+ }
+
+ // if provider is null then we need to tell the user to create an
+ // account
+ if (provider == null)
+ {
+ showErrorMessage(
+ "You need to configure at least one XMPP account \n"
+ + "to be able to call " + uri, null);
+ return;
+ }
+
+ if(!uri.contains("?"))
+ {
+ OperationSetPersistentPresence presenceOpSet =
+ (OperationSetPersistentPresence) provider
+ .getOperationSet(OperationSetPersistentPresence.class);
+
+ String contactId = uri.replaceFirst(getProtocol() + ":", "");
+
+ //todo check url!!
+ //Set the email pattern string
+ Pattern p = Pattern.compile(".+@.+\\.[a-z]+");
+ if(!p.matcher(contactId).matches())
+ {
+ showErrorMessage(
+ "Wrong contact id : " + uri, null);
+ return;
+ }
+
+ Contact contact = presenceOpSet.findContactByID(contactId);
+ if(contact == null)
+ {
+ Object result =
+ JabberActivator.getUIService().getPopupDialog().
+ showConfirmPopupDialog(
+ "Do you want to add the contact : " + contactId + " ?",
+ "Add contact",
+ PopupDialog.YES_NO_OPTION);
+
+ if(result.equals(PopupDialog.YES_OPTION))
+ {
+ ExportedWindow ex = JabberActivator.getUIService().
+ getExportedWindow(ExportedWindow.ADD_CONTACT_WINDOW,
+ new String[]{contactId});
+ ex.setVisible(true);
+ }
+
+ return;
+ }
+
+ JabberActivator.getUIService().
+ getChat(contact).setChatVisible(true);
+ }
+ else
+ {
+ String croom = uri.replaceFirst(getProtocol() + ":", "");
+ int ix = croom.indexOf("?");
+ String param = croom.substring(ix + 1, croom.length());
+ croom = croom.substring(0, ix);
+
+ if(param.equalsIgnoreCase("join"))
+ {
+ OperationSetMultiUserChat mchatOpSet =
+ (OperationSetMultiUserChat) provider
+ .getOperationSet(OperationSetMultiUserChat.class);
+
+ try
+ {
+ ChatRoom room = mchatOpSet.findRoom(croom);
+
+ if(room != null)
+ {
+ room.join();
+ }
+ }
+ catch (OperationFailedException exc)
+ {
+ // if we are not online we get this error
+ // will wait for it and then will try to handle once again
+ if(exc.getErrorCode() == OperationFailedException.NETWORK_FAILURE
+ && !networkFailReceived)
+ {
+ networkFailReceived = true;
+ OperationSetPresence presenceOpSet =
+ (OperationSetPresence) provider
+ .getOperationSet(OperationSetPresence.class);
+ presenceOpSet.addProviderPresenceStatusListener(
+ new ProviderStatusListener(uri, presenceOpSet));
+ }
+ else
+ showErrorMessage("Error joining to " + croom, exc);
+ }
+ catch (OperationNotSupportedException exc)
+ {
+ showErrorMessage("Join to " + croom + ", not supported!", exc);
+ }
+ }
+ else
+ showErrorMessage(
+ "Unknown param : " + param, null);
+ }
+ }
+
+ /**
+ * Informs the user that they need to be registered before chatting and
+ * asks them whether they would like us to do it for them.
+ *
+ * @param uri the uri that the user would like us to chat with after registering.
+ * @param provider the provider that we may have to reregister.
+ */
+ private void promptForRegistration(String uri,
+ ProtocolProviderService provider)
+ {
+ int answer =
+ JabberActivator
+ .getUIService()
+ .getPopupDialog()
+ .showConfirmPopupDialog(
+ "You need to be online in order to chat and your "
+ + "account is currently offline. Do want to connect now?",
+ "Account is currently offline", PopupDialog.YES_NO_OPTION);
+
+ if (answer == PopupDialog.YES_OPTION)
+ {
+ new ProtocolRegistrationThread(uri, provider).start();
+ }
+ }
+
+ /**
+ * The point of implementing a service listener here is so that we would
+ * only register our own uri handling service and thus only handle URIs
+ * while the factory is available as an OSGi service. We remove ourselves
+ * when our factory unregisters its service reference.
+ *
+ * @param event the OSGi <tt>ServiceEvent</tt>
+ */
+ public void serviceChanged(ServiceEvent event)
+ {
+ Object sourceService =
+ JabberActivator.bundleContext.
+ getService(event.getServiceReference());
+
+ // ignore anything but our protocol factory.
+ if (sourceService != protoFactory)
+ {
+ return;
+ }
+
+ switch (event.getType())
+ {
+ case ServiceEvent.REGISTERED:
+ // our factory has just been registered as a service ...
+ registerHandlerService();
+ break;
+ case ServiceEvent.UNREGISTERING:
+ // our factory just died - seppuku.
+ unregisterHandlerService();
+ break;
+ default:
+ // we don't care.
+ break;
+ }
+ }
+
+ /**
+ * Uses the <tt>UIService</tt> to show an error <tt>message</tt> and log and
+ * <tt>exception</tt>.
+ *
+ * @param message the message that we'd like to show to the user.
+ * @param exc the exception that we'd like to log
+ */
+ private void showErrorMessage(String message, Exception exc)
+ {
+ JabberActivator.getUIService().getPopupDialog().showMessagePopupDialog(
+ message, "Failed to create chat!", PopupDialog.ERROR_MESSAGE);
+ logger.error(message, exc);
+ }
+
+ /**
+ * We use this class when launching a provider registration by ourselves in
+ * order to track for provider registration states and retry uri handling,
+ * once the provider is registered.
+ *
+ */
+ private class ProtocolRegistrationThread
+ extends Thread
+ implements RegistrationStateChangeListener
+ {
+
+ private ProtocolProviderService handlerProvider = null;
+
+ /**
+ * The URI that we'd need to chat.
+ */
+ private String uri = null;
+
+ /**
+ * Configures this thread register our parent provider and re-attempt
+ * connection to the specified <tt>uri</tt>.
+ *
+ * @param uri the uri that we need to handle.
+ * @param handlerProvider the provider that we are going to make
+ * register and that we are going to use to handle the
+ * <tt>uri</tt>.
+ */
+ public ProtocolRegistrationThread(String uri,
+ ProtocolProviderService handlerProvider)
+ {
+ super("UriHandlerProviderRegistrationThread:uri=" + uri);
+ this.uri = uri;
+ this.handlerProvider = handlerProvider;
+ }
+
+ /**
+ * Starts the registration process, ads this class as a registration
+ * listener and then tries to rehandle the uri this thread was initiaded
+ * with.
+ */
+ @Override
+ public void run()
+ {
+ handlerProvider.addRegistrationStateChangeListener(this);
+
+ try
+ {
+ handlerProvider.register(JabberActivator.getUIService()
+ .getDefaultSecurityAuthority(handlerProvider));
+ }
+ catch (OperationFailedException exc)
+ {
+ logger.error("Failed to manually register provider.");
+ logger.warn(exc.getMessage(), exc);
+ }
+ }
+
+ /**
+ * If the parent provider passes into the registration state, the method
+ * re-handles the URI that this thread was initiated with. The method
+ * would only rehandle the uri if the event shows successful
+ * registration. It would ignore intermediate states such as
+ * REGISTERING. Disconnection and failure events would simply cause this
+ * listener to remove itself from the list of registration listeners.
+ *
+ * @param evt the <tt>RegistrationStateChangeEvent</tt> that this thread
+ * was initiated with.
+ */
+ public void registrationStateChanged(RegistrationStateChangeEvent evt)
+ {
+ if (evt.getNewState() == RegistrationState.REGISTERED)
+ {
+ Thread uriRehandleThread = new Thread()
+ {
+ public void run()
+ {
+ handleUri(uri);
+ }
+ };
+
+ uriRehandleThread.setName("UriRehandleThread:uri=" + uri);
+ uriRehandleThread.start();
+ }
+
+ // we're only interested in a single event so we stop listening
+ // (unless this was a REGISTERING notification)
+ if (evt.getNewState() == RegistrationState.REGISTERING)
+ return;
+
+ handlerProvider.removeRegistrationStateChangeListener(this);
+ }
+ }
+
+ /**
+ * Returns the default provider that we are supposed to handle URIs through
+ * or null if there aren't any. Depending on the implementation this method
+ * may require user intervention so make sure you don't rely on a quick
+ * outcome when chatting it.
+ *
+ * @param uri the uri that we'd like to handle with the provider that we are
+ * about to select.
+ *
+ * @return the provider that we should handle URIs through.
+ *
+ * @throws OperationFailedException with code <tt>OPERATION_CANCELED</tt> if
+ * the users.
+ */
+ public ProtocolProviderService selectHandlingProvider(String uri)
+ throws OperationFailedException
+ {
+ ArrayList<AccountID> registeredAccounts =
+ protoFactory.getRegisteredAccounts();
+
+ // if we don't have any providers - return null.
+ if (registeredAccounts.size() == 0)
+ {
+ return null;
+ }
+
+ // if we only have one provider - select it
+ if (registeredAccounts.size() == 1)
+ {
+ ServiceReference providerReference =
+ protoFactory.getProviderForAccount(registeredAccounts.get(0));
+
+ ProtocolProviderService provider =
+ (ProtocolProviderService) JabberActivator.bundleContext
+ .getService(providerReference);
+
+ return provider;
+ }
+
+ // otherwise - ask the user.
+ ArrayList<ProviderComboBoxEntry> providers =
+ new ArrayList<ProviderComboBoxEntry>();
+ for (AccountID accountID : registeredAccounts)
+ {
+ ServiceReference providerReference =
+ protoFactory.getProviderForAccount(accountID);
+
+ ProtocolProviderService provider =
+ (ProtocolProviderService) JabberActivator.bundleContext
+ .getService(providerReference);
+
+ providers.add(new ProviderComboBoxEntry(provider));
+ }
+
+ Object result =
+ JabberActivator.getUIService().getPopupDialog().showInputPopupDialog(
+ "Please select the account that you would like \n"
+ + "to use to chat with " + uri, "Account Selection",
+ PopupDialog.OK_CANCEL_OPTION, providers.toArray(),
+ providers.get(0));
+
+ if (result == null)
+ {
+ throw new OperationFailedException("Operation cancelled",
+ OperationFailedException.OPERATION_CANCELED);
+ }
+
+ return ((ProviderComboBoxEntry) result).provider;
+ }
+
+ /**
+ * A class that we use to wrap providers before showing them to the user
+ * through a selection popup dialog from the UIService.
+ */
+ private static class ProviderComboBoxEntry
+ {
+ public final ProtocolProviderService provider;
+
+ public ProviderComboBoxEntry(ProtocolProviderService provider)
+ {
+ this.provider = provider;
+ }
+
+ /**
+ * Returns a human readable <tt>String</tt> representing the provider
+ * encapsulated by this class.
+ *
+ * @return a human readable string representing the provider.
+ */
+ @Override
+ public String toString()
+ {
+ return provider.getAccountID().getAccountAddress();
+ }
+ }
+
+ /**
+ * Waiting for the provider to bcome online and then handle the uri.
+ */
+ private class ProviderStatusListener
+ implements ProviderPresenceStatusListener
+ {
+ private String uri;
+ private OperationSetPresence parentOpSet;
+
+ public ProviderStatusListener(String uri, OperationSetPresence parentOpSet)
+ {
+ this.uri = uri;
+ this.parentOpSet = parentOpSet;
+ }
+
+ public void providerStatusChanged(ProviderPresenceStatusChangeEvent evt)
+ {
+ if(evt.getNewStatus().isOnline())
+ {
+ parentOpSet.removeProviderPresenceStatusListener(this);
+ handleUri(uri);
+ }
+ }
+
+ public void providerStatusMessageChanged(java.beans.PropertyChangeEvent evt)
+ {
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf
index 21872f6..6aa6e2d 100755
--- a/src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf
@@ -27,6 +27,8 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.jabberconstants,
net.java.sip.communicator.service.protocol.event,
net.java.sip.communicator.service.protocol.whiteboardobjects,
+ net.java.sip.communicator.service.argdelegation,
+ net.java.sip.communicator.service.gui,
net.java.sip.communicator.service.media,
net.java.sip.communicator.service.media.event,
org.xmlpull.v1,