blob: f022a04850f00bf00d9ee37624fc9dde8f1cc84a [file] [log] [blame]
/****************************************************************************
* Copyright (c) 2006, 2007 Remy Suen, Composent Inc., and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Remy Suen <remy.suen@gmail.com> - initial API and implementation
*****************************************************************************/
package org.eclipse.ecf.internal.provider.msn;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.ecf.core.ContainerConnectException;
import org.eclipse.ecf.core.IContainer;
import org.eclipse.ecf.core.IContainerListener;
import org.eclipse.ecf.core.events.ContainerConnectedEvent;
import org.eclipse.ecf.core.events.ContainerConnectingEvent;
import org.eclipse.ecf.core.events.ContainerDisconnectedEvent;
import org.eclipse.ecf.core.events.ContainerDisconnectingEvent;
import org.eclipse.ecf.core.events.ContainerDisposeEvent;
import org.eclipse.ecf.core.events.IContainerEvent;
import org.eclipse.ecf.core.identity.ID;
import org.eclipse.ecf.core.identity.IDCreateException;
import org.eclipse.ecf.core.identity.IDFactory;
import org.eclipse.ecf.core.identity.Namespace;
import org.eclipse.ecf.core.security.IConnectContext;
import org.eclipse.ecf.core.security.ObjectCallback;
import org.eclipse.ecf.core.security.UnsupportedCallbackException;
import org.eclipse.ecf.core.user.IUser;
import org.eclipse.ecf.core.util.ECFException;
import org.eclipse.ecf.presence.IAccountManager;
import org.eclipse.ecf.presence.IIMMessageListener;
import org.eclipse.ecf.presence.IPresence;
import org.eclipse.ecf.presence.IPresenceContainerAdapter;
import org.eclipse.ecf.presence.IPresenceListener;
import org.eclipse.ecf.presence.IPresenceSender;
import org.eclipse.ecf.presence.chatroom.IChatRoomManager;
import org.eclipse.ecf.presence.history.IHistory;
import org.eclipse.ecf.presence.history.IHistoryManager;
import org.eclipse.ecf.presence.im.ChatMessage;
import org.eclipse.ecf.presence.im.ChatMessageEvent;
import org.eclipse.ecf.presence.im.IChat;
import org.eclipse.ecf.presence.im.IChatManager;
import org.eclipse.ecf.presence.im.IChatMessageSender;
import org.eclipse.ecf.presence.im.ITypingMessageSender;
import org.eclipse.ecf.presence.im.TypingMessage;
import org.eclipse.ecf.presence.im.TypingMessageEvent;
import org.eclipse.ecf.presence.im.IChatMessage.Type;
import org.eclipse.ecf.presence.roster.IRoster;
import org.eclipse.ecf.presence.roster.IRosterEntry;
import org.eclipse.ecf.presence.roster.IRosterGroup;
import org.eclipse.ecf.presence.roster.IRosterItem;
import org.eclipse.ecf.presence.roster.IRosterListener;
import org.eclipse.ecf.presence.roster.IRosterManager;
import org.eclipse.ecf.presence.roster.IRosterSubscriptionListener;
import org.eclipse.ecf.presence.roster.IRosterSubscriptionSender;
import org.eclipse.ecf.presence.search.ICriteria;
import org.eclipse.ecf.presence.search.ISearch;
import org.eclipse.ecf.presence.search.IRestriction;
import org.eclipse.ecf.presence.search.IUserSearchListener;
import org.eclipse.ecf.presence.search.IUserSearchManager;
import org.eclipse.ecf.presence.search.UserSearchException;
import org.eclipse.ecf.presence.search.message.IMessageSearchManager;
import org.eclipse.ecf.presence.service.IPresenceService;
import org.eclipse.ecf.protocol.msn.ChatSession;
import org.eclipse.ecf.protocol.msn.Contact;
import org.eclipse.ecf.protocol.msn.Group;
import org.eclipse.ecf.protocol.msn.MsnClient;
import org.eclipse.ecf.protocol.msn.Status;
import org.eclipse.ecf.protocol.msn.events.IChatSessionListener;
import org.eclipse.ecf.protocol.msn.events.IContactListListener;
import org.eclipse.ecf.protocol.msn.events.IContactListener;
import org.eclipse.ecf.protocol.msn.events.ISessionListener;
final class MSNContainer implements IContainer, IChatManager,
IChatMessageSender, IPresenceService, IPresenceSender, IRoster,
IRosterManager, IRosterSubscriptionSender, ITypingMessageSender {
private static final long serialVersionUID = 1676711994010767942L;
private final Map chatSessions;
private final List containerListeners;
private final List updateListeners;
private final List messageListeners;
private final List presenceListeners;
private final List subscriptionListeners;
private final List entries;
private final IUser user;
private final Namespace namespace;
private final ID guid;
private MsnClient client;
private MSNID connectID;
protected IHistoryManager historyManager = new IHistoryManager() {
public IHistory getHistory(ID partnerID, Map options) {
// TODO Auto-generated method stub
return null;
}
public boolean isActive() {
// TODO Auto-generated method stub
return false;
}
public void setActive(boolean active) {
// TODO Auto-generated method stub
}
public Object getAdapter(Class adapter) {
// TODO Auto-generated method stub
return null;
}
};
MSNContainer() throws IDCreateException {
guid = IDFactory.getDefault().createGUID();
namespace = IDFactory.getDefault().getNamespaceByName(
Activator.NAMESPACE_ID);
user = new Account();
chatSessions = new Hashtable();
containerListeners = new ArrayList();
updateListeners = new ArrayList();
messageListeners = new ArrayList();
presenceListeners = new ArrayList();
subscriptionListeners = new ArrayList();
entries = new ArrayList();
}
public void connect(ID targetID, IConnectContext connectContext)
throws ContainerConnectException {
if (!(targetID instanceof MSNID)) {
throw new ContainerConnectException(
Messages.MSNContainer_TargetIDNotMSNID);
}
client = new MsnClient();
ObjectCallback[] cb = { new ObjectCallback() };
try {
connectContext.getCallbackHandler().handle(cb);
client.addSessionListener(new ISessionListener() {
public void sessionConnected(ChatSession session) {
try {
Contact contact = session.getParticipants()[0];
final ID toID = namespace
.createInstance(new Object[] { contact
.getEmail() });
chatSessions.put(toID, session);
session.addChatSessionListener(new ChatSessionListener(
toID));
} catch (IDCreateException e) {
// ignored since this should not be possible
}
}
});
client.getContactList().addContactListListener(
new IContactListListener() {
public void contactAdded(Contact contact) {
final MSNRosterEntry entry = new MSNRosterEntry(
MSNContainer.this, contact, namespace);
for (int i = 0; i < entries.size(); i++) {
Object e = entries.get(i);
if (e instanceof MSNRosterGroup) {
MSNRosterGroup group = (MSNRosterGroup) e;
if (group.getGroup().contains(contact)) {
MSNRosterEntry check = group
.getEntryFor(contact);
if (check == null) {
check = entry;
contact
.addContactListener(new IContactListener() {
public void nameChanged(
String name) {
firePresence(
entry
.getID(),
entry
.getPresence());
fireRosterUpdate(entry);
}
public void personalMessageChanged(
String personalMessage) {
entry
.updatePersonalMessage();
firePresence(
entry
.getID(),
entry
.getPresence());
fireRosterUpdate(entry);
}
public void statusChanged(
Status status) {
firePresence(
entry
.getID(),
entry
.getPresence());
fireRosterUpdate(entry);
}
});
group.add(check);
fireRosterEntryAdded(check);
}
fireRosterUpdate(group);
return;
}
} else {
MSNRosterEntry check = (MSNRosterEntry) e;
if (entry.getContact().equals(
check.getContact())) {
fireRosterEntryAdded(check);
fireRosterUpdate(check.getParent());
return;
}
}
}
contact.addContactListener(new IContactListener() {
public void nameChanged(String name) {
firePresence(entry.getID(), entry
.getPresence());
fireRosterUpdate(entry);
}
public void personalMessageChanged(
String personalMessage) {
entry.updatePersonalMessage();
firePresence(entry.getID(), entry
.getPresence());
fireRosterUpdate(entry);
}
public void statusChanged(Status status) {
firePresence(entry.getID(), entry
.getPresence());
fireRosterUpdate(entry);
}
});
entries.add(entry);
entry.setParent(MSNContainer.this);
fireRosterEntryAdded(entry);
fireRosterUpdate(MSNContainer.this);
}
public void contactRemoved(Contact contact) {
MSNRosterEntry entry = findEntry(entries, contact
.getEmail());
if (entry != null) {
fireHandleUnsubscribed(entry.getUser().getID());
fireRosterEntryRemoved(entry);
fireRosterUpdate(entry.getParent());
if (entry.getContact().getGroups().isEmpty()) {
entry.setParent(MSNContainer.this);
fireRosterUpdate(MSNContainer.this);
}
}
}
public void contactAddedUser(String email) {
try {
fireHandleSubscriptionRequest(namespace
.createInstance(new Object[] { email }));
} catch (IDCreateException e) {
// ignored
}
}
public void contactRemovedUser(String email) {
// nothing to do
}
public void groupAdded(Group group) {
entries.add(new MSNRosterGroup(MSNContainer.this,
group));
}
});
fireContainerEvent(new ContainerConnectingEvent(guid, targetID));
client.connect(targetID.getName(), (String) cb[0].getObject());
connectID = (MSNID) targetID;
fireContainerEvent(new ContainerConnectedEvent(guid, connectID));
Activator.getDefault().registerService(this);
} catch (UnsupportedCallbackException e) {
throw new ContainerConnectException(e);
} catch (IOException e) {
throw new ContainerConnectException(e);
}
}
private MSNRosterEntry findEntry(Collection entries, String email) {
for (Iterator it = entries.iterator(); it.hasNext();) {
Object o = it.next();
if (o instanceof IRosterGroup) {
MSNRosterEntry entry = findEntry(((IRosterGroup) o)
.getEntries(), email);
if (entry != null) {
return entry;
}
} else {
MSNRosterEntry entry = (MSNRosterEntry) o;
if (entry.getUser().getID().getName().equals(email)) {
return entry;
}
}
}
return null;
}
public void disconnect() {
if (client != null) {
fireContainerEvent(new ContainerDisconnectingEvent(guid, connectID));
client.disconnect();
fireContainerEvent(new ContainerDisconnectedEvent(guid, connectID));
for (Iterator it = chatSessions.values().iterator(); it.hasNext();) {
((ChatSession) it.next()).close();
}
chatSessions.clear();
connectID = null;
client = null;
Activator.getDefault().unregisterService(this);
}
}
public void dispose() {
disconnect();
fireContainerEvent(new ContainerDisposeEvent(guid));
}
private void fireContainerEvent(IContainerEvent event) {
synchronized (containerListeners) {
for (int i = 0; i < containerListeners.size(); i++) {
((IContainerListener) containerListeners.get(i))
.handleEvent(event);
}
}
}
private void fireMessageEvent(ID fromID, String message) {
synchronized (messageListeners) {
for (int i = 0; i < messageListeners.size(); i++) {
((IIMMessageListener) messageListeners.get(i))
.handleMessageEvent(new ChatMessageEvent(fromID,
new ChatMessage(fromID, message)));
}
}
}
private void fireTypingMessageEvent(ID fromID) {
synchronized (messageListeners) {
for (int i = 0; i < messageListeners.size(); i++) {
((IIMMessageListener) messageListeners.get(i))
.handleMessageEvent(new TypingMessageEvent(fromID,
new TypingMessage(fromID, true, null)));
}
}
}
private void fireRosterUpdate(IRosterItem item) {
synchronized (updateListeners) {
for (int i = 0; i < updateListeners.size(); i++) {
((IRosterListener) updateListeners.get(i)).handleRosterUpdate(
this, item);
}
}
}
private void fireRosterEntryAdded(IRosterEntry entry) {
synchronized (updateListeners) {
for (int i = 0; i < updateListeners.size(); i++) {
((IRosterListener) updateListeners.get(i))
.handleRosterEntryAdd(entry);
}
}
}
private void fireRosterEntryRemoved(IRosterEntry entry) {
synchronized (updateListeners) {
for (int i = 0; i < updateListeners.size(); i++) {
((IRosterListener) updateListeners.get(i))
.handleRosterEntryRemove(entry);
}
}
}
private void firePresence(ID id, IPresence presence) {
synchronized (presenceListeners) {
for (int i = 0; i < presenceListeners.size(); i++) {
((IPresenceListener) presenceListeners.get(i)).handlePresence(
id, presence);
}
}
}
private void fireHandleSubscriptionRequest(ID fromID) {
synchronized (subscriptionListeners) {
for (int i = 0; i < subscriptionListeners.size(); i++) {
((IRosterSubscriptionListener) subscriptionListeners.get(i))
.handleSubscribeRequest(fromID);
}
}
}
private void fireHandleUnsubscribed(ID fromID) {
synchronized (subscriptionListeners) {
for (int i = 0; i < subscriptionListeners.size(); i++) {
((IRosterSubscriptionListener) subscriptionListeners.get(i))
.handleUnsubscribed(fromID);
}
}
}
public Object getAdapter(Class serviceType) {
if (serviceType != null && serviceType.isInstance(this)) {
return this;
} else {
return null;
}
}
public Namespace getConnectNamespace() {
return IDFactory.getDefault()
.getNamespaceByName(Activator.NAMESPACE_ID);
}
public ID getConnectedID() {
return connectID;
}
public ID getID() {
return guid;
}
public IAccountManager getAccountManager() {
return null;
}
public IChatRoomManager getChatRoomManager() {
return null;
}
public IPresenceSender getPresenceSender() {
return this;
}
public void addListener(IContainerListener listener) {
if (listener != null) {
synchronized (containerListeners) {
if (!containerListeners.contains(listener)) {
containerListeners.add(listener);
}
}
}
}
public void removeListener(IContainerListener listener) {
if (listener != null) {
synchronized (containerListeners) {
containerListeners.remove(listener);
}
}
}
private class ChatSessionListener implements IChatSessionListener {
private ID toID;
private ChatSessionListener(ID toID) {
this.toID = toID;
}
public void contactIsTyping(Contact contact) {
fireTypingMessageEvent(toID);
}
public void contactJoined(Contact contact) {
}
public void contactLeft(Contact contact) {
chatSessions.remove(toID);
}
public void messageReceived(Contact contact, String message) {
fireMessageEvent(toID, message);
}
public void sessionTimedOut() {
chatSessions.remove(toID);
}
}
public void sendPresenceUpdate(ID toID, IPresence presence)
throws ECFException {
if (presence == null || client == null) {
throw new ECFException();
}
IPresence.Mode mode = presence.getMode();
try {
client.setPersonalMessage(presence.getStatus());
if (presence.getType() == IPresence.Type.UNAVAILABLE) {
disconnect();
} else if (mode == IPresence.Mode.AVAILABLE
|| mode == IPresence.Mode.CHAT) {
client.setStatus(Status.ONLINE);
} else if (mode == IPresence.Mode.AWAY
|| mode == IPresence.Mode.EXTENDED_AWAY) {
client.setStatus(Status.AWAY);
} else if (mode == IPresence.Mode.DND) {
client.setStatus(Status.BUSY);
} else {
client.setStatus(Status.APPEAR_OFFLINE);
}
} catch (IOException e) {
throw new ECFException(e);
}
}
public IRosterManager getRosterManager() {
return this;
}
public void addRosterListener(IRosterListener listener) {
synchronized (updateListeners) {
if (!updateListeners.contains(listener)) {
updateListeners.add(listener);
}
}
}
public IRoster getRoster() {
return this;
}
public IRosterSubscriptionSender getRosterSubscriptionSender() {
return this;
}
public void addRosterSubscriptionListener(
IRosterSubscriptionListener listener) {
if (listener != null) {
synchronized (subscriptionListeners) {
if (!subscriptionListeners.contains(listener)) {
subscriptionListeners.add(listener);
}
}
}
}
public void removeRosterSubscriptionListener(
IRosterSubscriptionListener listener) {
if (listener != null) {
synchronized (subscriptionListeners) {
subscriptionListeners.remove(listener);
}
}
}
public void removeRosterListener(IRosterListener listener) {
if (listener != null) {
synchronized (updateListeners) {
updateListeners.remove(listener);
}
}
}
public Collection getItems() {
return Collections.unmodifiableCollection(entries);
}
public IUser getUser() {
return connectID == null ? null : user;
}
public void addPresenceListener(IPresenceListener listener) {
if (listener != null) {
synchronized (presenceListeners) {
if (!presenceListeners.contains(listener)) {
presenceListeners.add(listener);
}
}
}
}
public void removePresenceListener(IPresenceListener listener) {
if (listener != null) {
synchronized (presenceListeners) {
presenceListeners.remove(listener);
}
}
}
public IChatManager getChatManager() {
return this;
}
public IChatMessageSender getChatMessageSender() {
return this;
}
public ITypingMessageSender getTypingMessageSender() {
return this;
}
public void sendChatMessage(ID toID, ID threadID, Type type,
String subject, String body, Map properties) throws ECFException {
sendChatMessage(toID, body);
}
public void sendChatMessage(ID toID, String body) throws ECFException {
try {
ChatSession cs = (ChatSession) chatSessions.get(toID);
if (cs == null) {
cs = client.createChatSession(toID.getName());
cs.addChatSessionListener(new ChatSessionListener(toID));
chatSessions.put(toID, cs);
}
cs.sendMessage(body);
} catch (IOException e) {
throw new ECFException(e);
}
}
public void sendTypingMessage(ID toID, boolean isTyping, String body)
throws ECFException {
try {
if (isTyping) {
ChatSession cs = (ChatSession) chatSessions.get(toID);
if (cs == null) {
cs = client.createChatSession(toID.getName());
cs.addChatSessionListener(new ChatSessionListener(toID));
chatSessions.put(toID, cs);
}
cs.sendTypingNotification();
}
} catch (IOException e) {
throw new ECFException(e);
}
}
public void addMessageListener(IIMMessageListener listener) {
if (listener != null) {
synchronized (messageListeners) {
if (!messageListeners.contains(listener)) {
messageListeners.add(listener);
}
}
}
}
public void removeMessageListener(IIMMessageListener listener) {
if (listener != null) {
synchronized (messageListeners) {
messageListeners.remove(listener);
}
}
}
private class Account implements IUser {
private static final long serialVersionUID = 7497082891662391996L;
public Object getAdapter(Class adapter) {
return null;
}
public ID getID() {
return connectID;
}
public Map getProperties() {
return null;
}
public String getName() {
return client.getUserEmail();
}
public String getNickname() {
return client.getDisplayName();
}
}
public void sendRosterAdd(String user, String name, String[] groups)
throws ECFException {
try {
client.getContactList().addContact(user, name);
} catch (IOException e) {
throw new ECFException(e);
}
}
public void sendRosterRemove(ID userID) throws ECFException {
MSNRosterEntry entry = findEntry(entries, userID.getName());
if (entry != null) {
try {
client.getContactList().removeContact(entry.getContact());
} catch (IOException e) {
throw new ECFException(e);
}
}
}
public String getName() {
IUser user = getUser();
return user == null ? null : user.getName();
}
public IRosterItem getParent() {
return null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ecf.presence.im.IChatManager#getHistoryManager()
*/
public IHistoryManager getHistoryManager() {
// TODO Auto-generated method stub
return historyManager;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ecf.presence.roster.IRoster#getPresenceContainerAdapter()
*/
public IPresenceContainerAdapter getPresenceContainerAdapter() {
return this;
}
/* (non-Javadoc)
* @see org.eclipse.ecf.presence.im.IChatManager#createChat(org.eclipse.ecf.core.identity.ID)
*/
public IChat createChat(ID targetUser, IIMMessageListener messageListener) throws ECFException {
// TODO Auto-generated method stub
return null;
}
/**
* TODO Implement a User Search Manager for MSN
* for while it just returns a manger
* to inform that user search is not allow
* for this provider see {@link IUserSearchManager#isEnabled()}
*/
public IUserSearchManager getUserSearchManager() {
return new IUserSearchManager(){
public ICriteria createCriteria() {
// TODO Auto-generated method stub
return null;
}
public IRestriction createRestriction() {
// TODO Auto-generated method stub
return null;
}
public String[] getUserPropertiesFields()
throws ContainerConnectException {
// TODO Auto-generated method stub
return null;
}
public boolean isEnabled() {
// TODO Auto-generated method stub
return false;
}
public ISearch search(ICriteria criteria)
throws UserSearchException {
// TODO Auto-generated method stub
return null;
}
public void search(ICriteria criteria, IUserSearchListener listener) {
// TODO Auto-generated method stub
}
};
}
public IMessageSearchManager getMessageSearchManager() {
// TODO Auto-generated method stub
return null;
}
}