| /******************************************************************************* |
| * Copyright (c) 2005, 2007 Remy Suen |
| * 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.protocol.msn; |
| |
| import java.io.IOException; |
| import java.net.URLEncoder; |
| import java.util.Iterator; |
| import org.eclipse.ecf.protocol.msn.events.ISessionListener; |
| import org.eclipse.ecf.protocol.msn.internal.encode.ResponseCommand; |
| import org.eclipse.ecf.protocol.msn.internal.encode.StringUtils; |
| |
| /** |
| * <p> |
| * The MsnClient class allows a developer to easily create a client that will |
| * authenticate the user and establish a connection with the MSN servers. |
| * </p> |
| * |
| * <p> |
| * <b>Note:</b> This class/interface is part of an interim API that is still |
| * under development and expected to change significantly before reaching |
| * stability. It is being made available at this early stage to solicit feedback |
| * from pioneering adopters on the understanding that any code that uses this |
| * API will almost certainly be broken (repeatedly) as the API evolves. |
| * </p> |
| */ |
| public final class MsnClient { |
| |
| /** |
| * The default hostname that will be used to connect to the MSN servers - |
| * messenger.hotmail.com |
| */ |
| private static final String HOSTNAME = "messenger.hotmail.com"; //$NON-NLS-1$ |
| |
| /** |
| * The default port that will be used to connect to the MSN servers - 1863 |
| */ |
| private static final int PORT = 1863; |
| |
| /** |
| * The NotificationSession that will be connect to the notification server |
| * to handle most non-messaging related incoming and outgoing requests. |
| */ |
| private NotificationSession notification; |
| |
| /** |
| * The list of contacts that are on this user's list. |
| */ |
| private final ContactList list; |
| |
| /** |
| * The user's email address. |
| */ |
| private String username; |
| |
| /** |
| * The name the user displays to other contacts. |
| */ |
| private String displayName; |
| |
| /** |
| * The hostname to use to connect to the dispatch server. |
| */ |
| private final String hostname; |
| |
| /** |
| * The user's personal message. |
| */ |
| private String personalMessage = ""; //$NON-NLS-1$ |
| |
| /** |
| * The media that the user is currently playing. |
| */ |
| private final String currentMedia = "";//$NON-NLS-1$ |
| |
| /** |
| * The port to use to connect to the dispatch server. |
| */ |
| private final int port; |
| |
| /** |
| * The current status of the user. |
| */ |
| private Status status; |
| |
| /** |
| * Instantiate a new MsnClient that defaults to setting the user as being |
| * online and available when signing in. |
| * |
| */ |
| public MsnClient() { |
| this(Status.ONLINE); |
| } |
| |
| /** |
| * Instantiate a new MsnClient that set the user to the specified status |
| * when signing in. |
| * |
| * @param initialStatus |
| * the status that a user would like to sign on to the servers |
| * as, refer to {@link Status#ONLINE} and other static variables |
| * for the available options. |
| */ |
| public MsnClient(Status initialStatus) { |
| status = initialStatus; |
| hostname = HOSTNAME; |
| port = PORT; |
| list = new ContactList(this); |
| notification = new NotificationSession(this); |
| } |
| |
| /** |
| * Connects the client to the MSN servers. |
| * |
| * @param userEmail |
| * the user's email address that is associated with an MSN |
| * account |
| * @param password |
| * the email's corresponding password |
| * @throws IOException |
| * If an I/O error occurred while connecting to the dispatch or |
| * notification servers. |
| */ |
| public void connect(String userEmail, String password) throws IOException { |
| this.username = userEmail; |
| final DispatchSession dispatch = new DispatchSession(hostname, port); |
| // get the address of the notification server by first authenticating |
| // ourselves |
| final String address = dispatch.authenticate(userEmail); |
| // close the session |
| dispatch.close(); |
| // connect the notification session to the received address |
| notification.openSocket(address); |
| try { |
| // keep looping until we've connected successfully |
| while (!notification.login(userEmail, password)) { |
| notification.reset(); |
| } |
| } catch (final RuntimeException e) { |
| if (!notification.isClosed()) { |
| throw e; |
| } |
| } catch (final IOException e) { |
| if (!notification.isClosed()) { |
| throw e; |
| } |
| } |
| } |
| |
| /** |
| * Disconnects the user from the MSN servers. Please note that any |
| * {@link ChatSession}s that may have been created since the client was |
| * instantiated are not disconnected automatically in this method. |
| */ |
| public void disconnect() { |
| if (notification != null) { |
| try { |
| notification.write("OUT"); //$NON-NLS-1$ |
| } catch (final Exception e) { |
| // ignored since we're disconnecting anyway |
| } |
| notification.close(); |
| } |
| notification = null; |
| } |
| |
| /** |
| * Changes the user's status to the provided status flag. |
| * |
| * @param status |
| * the status that the user wishes to change to |
| * @throws IOException if some problem setting status (e.g. disconnected). |
| */ |
| public void setStatus(Status status) throws IOException { |
| if (this.status != status) { |
| if (status == Status.OFFLINE) { |
| disconnect(); |
| } else { |
| notification.write("CHG", status.getLiteral() + " 268435488"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| this.status = status; |
| } |
| } |
| |
| /** |
| * Returns the status that the user is currently in. |
| * |
| * @return the user's current status |
| */ |
| public Status getStatus() { |
| return status; |
| } |
| |
| void add(String email, String userName) throws IOException { |
| notification.write("ADC", "FL N=" + email + " F=" + userName); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| |
| void remove(Contact contact) throws IOException { |
| final String guid = contact.getGuid(); |
| for (final Iterator it = contact.getGroups().iterator(); it.hasNext();) { |
| notification.write("REM", "FL " + guid + " " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| + list.getGuid((Group) it.next())); |
| } |
| notification.write("REM", "FL " + guid); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| void remove(String guid) throws IOException { |
| notification.write("RMG", "FL " + guid); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| /** |
| * Returns the contact list that is associated with this client. |
| * |
| * @return this client's contact list |
| */ |
| public ContactList getContactList() { |
| return list; |
| } |
| |
| /** |
| * Creates a {@link ChatSession} to connect to the specified contact. |
| * |
| * @param email |
| * the contact to connect to |
| * @return the created ChatSession |
| * @throws IOException |
| * If an I/O error occurred |
| */ |
| public ChatSession createChatSession(String email) throws IOException { |
| final ResponseCommand cmd = notification.getChatSession(); |
| final ChatSession cs = new ChatSession(cmd.getParam(2), this, username, cmd.getParam(4)); |
| // reset the ResponseCommand so that the next XFR request won't conflict |
| cmd.process(null); |
| cs.invite(email); |
| return cs; |
| } |
| |
| void internalSetDisplayName(String newName) { |
| displayName = newName; |
| } |
| |
| /** |
| * Sets the display name of this user. |
| * |
| * @param newName |
| * the new name of this user |
| * @throws IOException |
| */ |
| public void setDisplayName(String newName) throws IOException { |
| notification.write("PRP", "MFN " + URLEncoder.encode(newName)); //$NON-NLS-1$ //$NON-NLS-2$ |
| displayName = newName; |
| } |
| |
| /** |
| * Returns the displayed name of this user. |
| * |
| * @return the name that this user is using |
| */ |
| public String getDisplayName() { |
| return displayName; |
| } |
| |
| /** |
| * Returns the user's account's email address. |
| * |
| * @return the email address the user is using for MSN login |
| */ |
| public String getUserEmail() { |
| return username; |
| } |
| |
| private void sendStatusData() throws IOException { |
| final String message = "<Data><PSM>" + personalMessage //$NON-NLS-1$ |
| + "</PSM><CurrentMedia>" + currentMedia //$NON-NLS-1$ |
| + "</CurrentMedia></Data>"; //$NON-NLS-1$ |
| notification.write("UUX", message.length() + "\r\n" //$NON-NLS-1$ //$NON-NLS-2$ |
| + message, false); |
| } |
| |
| /** |
| * Sets the user's personal message to the specified string. |
| * |
| * @param personalMessage |
| * the new message to use as the user's personal message |
| * @throws IOException |
| * If an I/O error occurred while sending the data to the |
| * notification server |
| */ |
| public void setPersonalMessage(String personalMessage) throws IOException { |
| if (personalMessage == null) { |
| personalMessage = ""; //$NON-NLS-1$ |
| } else { |
| personalMessage = StringUtils.xmlEncode(personalMessage); |
| } |
| if (!this.personalMessage.equals(personalMessage)) { |
| this.personalMessage = personalMessage; |
| sendStatusData(); |
| } |
| } |
| |
| /** |
| * Retrieves the user's current personal message. |
| * |
| * @return the personal message that the user is currently using |
| */ |
| public String getPersonalMessage() { |
| return StringUtils.xmlDecode(personalMessage); |
| } |
| |
| /** |
| * Add an ISessionListener to this client. |
| * |
| * @param listener |
| * the listener to be added |
| */ |
| public void addSessionListener(ISessionListener listener) { |
| notification.addSessionListener(listener); |
| } |
| |
| /** |
| * Removes an ISessionListener from this client. |
| * |
| * @param listener |
| * the listener to be removed |
| */ |
| public void removeSessionListener(ISessionListener listener) { |
| notification.removeSessionListener(listener); |
| } |
| } |