/*
* Hamsam - Instant Messaging API
* Copyright (C) 2003 Raghu K
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package hamsam.protocol.msn;
import hamsam.api.Buddy;
import hamsam.api.Conference;
import hamsam.api.IMListener;
import hamsam.api.Message;
import hamsam.api.SmileyComponent;
import hamsam.exception.IllegalArgumentException;
import hamsam.exception.IllegalStateException;
import hamsam.exception.UnsupportedOperationException;
import hamsam.net.ProxyInfo;
import hamsam.protocol.Protocol;
/**
* Implementation of MSN messenger protocol. This class implements the
* {@link hamsam.protocol.Protocol Protocol} interface so as to provide
* instant messaging and presence services via Hamsam API.
* <p>
* Users of the API should never use this class directly. They must use
* the {@link hamsam.protocol.ProtocolManager ProtocolManager} and
* {@link hamsam.protocol.Protocol Protocol} classes to access the MSN
* services indirectly.
*
* @author Raghu K
*/
public class MsnProtocol implements Protocol
{
/**
* All smileys supported by MSN.
*/
private SmileyComponent[] smileys;
/**
* Processes all events received from MSN server.
*/
private EventProcessor eventProcessor;
/**
* Listener for this protocol.
*/
private IMListener listener;
/**
* The dispatch or notification server currently used by this
* session.
*/
private MsnServer server;
/**
* Passport of the user currently logged in.
*/
private String username;
/**
* Password of the user currently logged in.
*/
private String password;
/**
* Information about the proxy server to be used for all connections.
*/
private ProxyInfo proxyInfo;
/**
* Default Constructor.
*/
public MsnProtocol()
{
eventProcessor = new EventProcessor(this);
smileys = Util.loadSmileys();
}
/**
* Log in to the MSN server. If we are already logged in, this method will first
* disconnect from MSN and then try to login.
*
* @param username the user id to log in.
* @param password the password for authentication.
* @param info the proxy information explaining how to connect.
*
* @throws IllegalStateException if no listener is set using the
* {@link #setListener(IMListener) setListener} method.
*/
public synchronized void connect(String username, String password, ProxyInfo info) throws IllegalStateException
{
if(listener == null)
throw new IllegalStateException("IMListener not set for this protocol");
if(this.server instanceof NotificationServer)
disconnect();
this.username = username;
this.password = password;
this.proxyInfo = info;
listener.connecting(this);
try
{
this.server = new DispatchServer(this, eventProcessor, info);
}
catch(Exception e)
{
eventProcessor.connectFailed("Cannot connect: " + e.toString());
}
}
/**
* Change the status message for the user logged in for this protocol.
* If <code>status</code> is <code>null</code>, the status is changed
* to invisible.
* <p>
* MSN protocol supports only a limited range of status messages. If you
* pass a status message which is not supported by MSN protocol, this
* method throws an IllegalArgumentException. In order to get a complete list
* of supported status messages, use the getSupportedStatusMessages() method.
*
* @param status the new status message.
* @throws IllegalArgumentException when the status message is invalid.
* @throws IllegalStateException if the protocol is not connected.
* @see #getSupportedStatusMessages() getSupportedStatusMessages()
*/
public void changeStatus(String status) throws IllegalArgumentException, IllegalStateException
{
String code = Util.getStatusCode(status);
if(code == null)
throw new IllegalArgumentException("Invalid status message - " + status);
if(server instanceof NotificationServer)
{
NotificationServer ns = (NotificationServer) server;
ns.changeStatus(code);
}
else
throw new IllegalStateException("Not yet connected to MSN");
}
/**
* Disconnect from MSN messaging service. This is equivalent to
* logging out from the service.
*
* @throws IllegalStateException if the protocol is not connected.
*/
public void disconnect() throws IllegalStateException
{
if(!(server instanceof NotificationServer))
throw new IllegalStateException("Not yet connected to MSN");
server.shutdown();
eventProcessor.disconnected();
}
/**
* Returns the name of this protocol.
*
* @return the string "MSN".
*/
public String getProtocolName()
{
return "MSN";
}
/**
* Determines whether this protocol will notify you if a user attempts to
* add you to his / her buddy list. This method always returns true.
*
* @return <code>true</code>.
*/
public boolean isBuddyAddRequestSupported()
{
return true;
}
/**
* Determines whether this protocol supports arranging buddies in
* different groups. This method always returns true.
*
* @return <code>true</code>.
*/
public boolean isBuddyGroupSupported()
{
return true;
}
/**
* Determines whether this protocol supports ignoring
* buddies. This method always returns true.
*
* @return <code>true</code>.
*/
public boolean isIgnoreSupported()
{
return true;
}
/**
* Determines whether this protocol supports sending and
* receiving offline messages. This method always returns false;
*
* @return <code>false</code>.
*/
public boolean isOfflineMessageSupported()
{
return false;
}
/**
* Determines whether this protocol supports typing notifications.
* This method always returns false.
*
* @return <code>false</code>.
*/
public boolean isTypingNotifySupported()
{
return false;
}
/**
* Determines whether this protocol supports conferences.
* This method always returns true.
*
* @return <code>true</code>.
* @see hamsam.api.Conference Conference
*/
public boolean isConferenceSupported()
{
return true;
}
/**
* Determines whether this protocol supports e-mail alerts.
* This method always returns true.
*
* @return <code>true</code>.
*/
public boolean isMailNotifySupported()
{
return true;
}
/**
* Determines whether this protocol supports setting the status of the
* user to invisible. This method always returns true.
*
* @return <code>true</code>.
*/
public boolean isInvisibleSupported()
{
return true;
}
/**
* Sets the listener for this protocol. This listener will be notified for
* any instant message events that originates from MSN protocol.
*
* @param listener the listener for this protocol, pass <code>null</code>
* to unregister the current listener.
*/
public void setListener(IMListener listener)
{
this.listener = listener;
eventProcessor.setListener(listener);
}
/**
* Start a new conference by inviting some buddies. MSN protocol does not support
* any invitation messages, hence <code>message</code> is always ignored.
*
* @param conf the conference which is to be started.
* @param message the invitation message to be sent. This parameter is always ignored.
* @throws IllegalStateException if the protocol is not connected to MSN yet.
*/
public void startConference(Conference conf, String message) throws IllegalStateException
{
NotificationServer ns = checkValidNotificationServer();
ns.startSBSession(conf);
}
/**
* Disconnect the current user from a conference.
*
* @param conf the conference from which the user has to disconnect.
* @throws IllegalStateException if the protocol is not connected to MSN yet.
*/
public void quitConference(Conference conf) throws IllegalStateException
{
NotificationServer ns = checkValidNotificationServer();
ns.quitSBSession(conf);
}
/**
* Send a conference message.
*
* @param conf the conference to which the message is to be sent.
* @param message the instant message to be sent.
* @throws IllegalStateException if the protocol is not connected to MSN yet.
*/
public void sendConferenceMessage(Conference conf, Message message) throws IllegalStateException
{
NotificationServer ns = checkValidNotificationServer();
ns.sendConferenceMessage(conf, message);
}
/**
* Add a buddy to your buddy list. The result of this operation
* will be notified to the registered <code>IMListener</code>.
*
* @param buddy the buddy to be added.
*
* @see IMListener#buddyAddRequest(Buddy,Buddy,String) IMListener.buddyAddRequest
* @see IMListener#buddyAdded(Buddy) IMListener.buddyAdded
* @see IMListener#buddyAddFailed(Buddy,String) IMListener.buddyAddFailed
*
* @throws IllegalStateException if the protocol is not connected to MSN yet.
* @throws IllegalArgumentException if the group of the buddy is not specified, or
* the specified group does not exist.
*/
public void addToBuddyList(Buddy buddy) throws IllegalStateException, IllegalArgumentException
{
NotificationServer ns = checkValidNotificationServer();
ns.addBuddyToForwardList(buddy);
}
/**
* Delete a buddy from your buddy list. The result of this operation
* will be notified to the registered <code>IMListener</code>.
*
* @param buddy the buddy to be deleted.
*
* @see IMListener#buddyDeleted(Buddy) IMListener.buddyDeleted
* @see IMListener#buddyDeleteFailed(Buddy,String) IMListener.buddyDeleteFailed
*
* @throws IllegalArgumentException if the group of the buddy is not specified.
* @throws IllegalStateException if the protocol is not connected to MSN yet.
*/
public void deleteFromBuddyList(Buddy buddy) throws IllegalArgumentException, IllegalStateException
{
NotificationServer ns = checkValidNotificationServer();
ns.removeBuddyFromForwardList(buddy);
}
/**
* Prevent a buddy from sending you messages. The result of this
* operation will be notified to the registered <code>IMListener</code>.
*
* @param buddy the buddy to be ignored.
*
* @see IMListener#buddyIgnored(Buddy) IMListener.buddyIgnored
* @see IMListener#buddyIgnoreFailed(Buddy,String) IMListener.buddyIgnoreFailed
*
* @throws IllegalStateException if the protocol is not connected to MSN yet.
*/
public void ignoreBuddy(Buddy buddy) throws IllegalStateException
{
NotificationServer ns = checkValidNotificationServer();
ns.addBuddyToBlockedList(buddy);
}
/**
* Undo a previous ignore operation for a buddy. The result of this
* operation will be notified to the registered <code>IMListener</code>.
*
* @param buddy the buddy to be ignored.
*
* @see IMListener#buddyUnignored(Buddy) IMListener.buddyUnignored
* @see IMListener#buddyUnignoreFailed(Buddy,String) IMListener.buddyUnignoreFailed
*
* @throws IllegalStateException if the protocol is not connected to MSN yet.
*/
public void unignoreBuddy(Buddy buddy) throws IllegalStateException
{
NotificationServer ns = checkValidNotificationServer();
ns.removeBuddyFromBlockedList(buddy);
}
/**
* Send an instant message to a buddy.
*
* @param buddy the buddy to whom the message should be sent.
* @param message the message to be sent.
*/
public void sendInstantMessage(Buddy buddy, Message message) throws IllegalStateException
{
NotificationServer ns = checkValidNotificationServer();
SwitchboardServer server = ns.getExistingSBSession(buddy);
if(server == null)
server = startSBSession(buddy);
server.sendMessage(message);
}
/**
* Notify this buddy that you have started typing.
*
* @param buddy the buddy to whom the typing notification is to be sent.
*
* @throws UnsupportedOperationException if this protocol does not support
* typing notifications.
*/
public void typingStarted(Buddy buddy) throws UnsupportedOperationException
{
throw new UnsupportedOperationException("Typing notifications are not supported.");
}
/**
* Notify this buddy that you have stopped typing.
*
* @param buddy the buddy to whom the typing notification is to be sent.
*
* @throws UnsupportedOperationException if this protocol does not support
* typing notifications.
*/
public void typingStopped(Buddy buddy) throws UnsupportedOperationException
{
throw new UnsupportedOperationException("Typing notifications are not supported.");
}
/**
* Returns an array of all SmileyComponents supported by this protocol.
*
* @return an array of all SmileyComponents supported by this protocol.
*/
public SmileyComponent[] getSupportedSmileys()
{
return smileys;
}
/**
* Returns an array of status messages supported by MSN protocol.
*
* @return array of status messages supported by MSN protocol
*/
public String[] getSupportedStatusMessages()
{
return Util.getSupportedStatusMessages();
}
/**
* Returns the passport of the current user.
*
* @return passport of the current user
*/
String getUsername()
{
return username;
}
/**
* Returns the password of the current user.
*
* @return password of the current user
*/
String getPassword()
{
return password;
}
/**
* Invoked by dispatch server for connecting to notification server.
*
* @param connect the host name and port number to connect to, separated
* by colon.
*/
void switchServer(String connect)
{
int index = connect.indexOf(':');
if(index != -1)
{
try
{
String host = connect.substring(0, index);
int port = Integer.parseInt(connect.substring(index + 1));
this.server = new NotificationServer(this, eventProcessor, host, port, proxyInfo);
}
catch(NumberFormatException e)
{
eventProcessor.connectFailed("Invalid server name and port: " + connect);
}
catch(Exception e)
{
eventProcessor.connectFailed("I/O Error: " + e.toString());
}
}
else
eventProcessor.connectFailed("Invalid server name and port: " + connect);
}
/**
* Returns the proxy information object.
*
* @return the <code>ProxyInfo</code> to be used for all connections.
*/
ProxyInfo getProxyInfo()
{
return proxyInfo;
}
/**
* Invoked when an SB session terminates abnormally.
*
* @param server the SB server that terminated.
*/
void switchBoardTerminated(SwitchboardServer server)
{
try
{
NotificationServer ns = checkValidNotificationServer();
ns.switchBoardTerminated(server);
}
catch(IllegalStateException e)
{
// This will never be thrown
}
}
/**
* Returns the notification server object to which this protocol is
* currently connected. If it is not connected yet, this method throws
* an exception.
*
* @return the notification server we are currently connected to.
* @throws IllegalStateException if the protocol is not connected to MSN yet.
*/
private NotificationServer checkValidNotificationServer() throws IllegalStateException
{
if(!(server instanceof NotificationServer))
throw new IllegalStateException("Not logged in yet - MSN");
return (NotificationServer) server;
}
private SwitchboardServer startSBSession(Buddy buddy) throws IllegalStateException
{
try
{
NotificationServer ns = checkValidNotificationServer();
Buddy host = new Buddy(this, username);
Buddy[] participants = new Buddy[2];
participants[0] = host;
participants[1] = buddy;
Conference conf = new Conference(this, host, participants);
ns.startSBSession(conf);
// Wait till we get an SB session for this
return ns.waitForSBSession(conf);
}
catch(UnsupportedOperationException e)
{
// We will not get this
}
catch(IllegalArgumentException e)
{
// We will not get this
}
// We will never reach here
return null;
}
/**
* Checks whether this protocol supports buddy aliases.
*
* @return <code>true</code>
*/
public boolean isBuddyNameAliasSupported()
{
return true;
}
/**
* Changes the alias of a buddy.
*
* @param buddy the buddy whose alias needs to be changed.
* @param alias the new alias of this buddy.
* @see #isBuddyNameAliasSupported() isBuddyNameAliasSupported()
*/
public void changeBuddyAlias(Buddy buddy, String alias)
{
// TODO Auto-generated method stub
}
}