/* * Created on Sep 20, 2005 * *Copyright Reliable Response, 2005 */ package net.reliableresponse.notification.providers; import java.util.Enumeration; import java.util.Hashtable; import java.util.List; import java.util.Vector; import java.util.regex.Pattern; import net.reliableresponse.notification.Notification; import net.reliableresponse.notification.NotificationException; import net.reliableresponse.notification.actions.SendNotification; import net.reliableresponse.notification.broker.BrokerFactory; import net.reliableresponse.notification.broker.impl.clustered.ClusteredServiceManager; import net.reliableresponse.notification.device.Device; import net.reliableresponse.notification.device.SameTimeDevice; import net.reliableresponse.notification.sender.NotificationSender; import net.reliableresponse.notification.usermgmt.UnknownUser; import net.reliableresponse.notification.usermgmt.User; import com.echomine.common.SendMessageFailedException; import com.lotus.sametime.awareness.AwarenessService; import com.lotus.sametime.awareness.AwarenessServiceEvent; import com.lotus.sametime.awareness.AwarenessServiceListener; import com.lotus.sametime.community.CommunityService; import com.lotus.sametime.community.LoginEvent; import com.lotus.sametime.community.LoginListener; import com.lotus.sametime.core.comparch.DuplicateObjectException; import com.lotus.sametime.core.comparch.STSession; import com.lotus.sametime.core.constants.EncLevel; import com.lotus.sametime.core.constants.ImTypes; import com.lotus.sametime.core.types.STObject; import com.lotus.sametime.core.types.STUser; import com.lotus.sametime.core.types.STUserStatus; import com.lotus.sametime.directory.Directory; import com.lotus.sametime.directory.DirectoryEvent; import com.lotus.sametime.directory.DirectoryListener; import com.lotus.sametime.directory.DirectoryService; import com.lotus.sametime.directory.DirectoryServiceListener; import com.lotus.sametime.im.Im; import com.lotus.sametime.im.ImEvent; import com.lotus.sametime.im.ImListener; import com.lotus.sametime.im.ImServiceListener; import com.lotus.sametime.im.InstantMessagingService; /** * This is the SameTime IM interface. SameTime is an instant messaging server * that is part of the Lotus Notes/Domino suite. We use the IBM library for * accessing it. * * @author David Rudder * * Copyright 2004 - David Rudder */ public class SameTimeNotificationProvider extends AbstractNotificationProvider implements ImListener, ImServiceListener, DirectoryServiceListener, LoginListener, AwarenessServiceListener { private static STSession session; String serverName; static InstantMessagingService imService; DirectoryService dir; AwarenessService awarenessService; Im im; Vector imOpened; // We need to keep track of the open IM windows // If we don't, we end up with a memory leak static Directory[] directories; public SameTimeNotificationProvider(String serverName) { init (serverName); } public SameTimeNotificationProvider() { } public void init (Hashtable params) { String serverName = (String)params.get("serverName"); init (serverName); } public void init (String serverName) { this.serverName = serverName; imOpened = new Vector(); if (!ClusteredServiceManager.getInstance().willRun("SameTime")) { return; } getSession (); } private STSession getSession () { if (session == null){ String accountName = BrokerFactory.getConfigurationBroker().getStringValue("sametime.account", ""); String password = BrokerFactory.getConfigurationBroker().getStringValue("sametime.password", ""); BrokerFactory.getLoggingBroker().logDebug( "Creating SameTime Context for " + accountName); try { session = new STSession ("Reliable Response " + this+" at "+System.currentTimeMillis()); session.loadSemanticComponents(); session.start(); dir = (DirectoryService)session.getCompApi(DirectoryService.COMP_NAME); imService = (InstantMessagingService)session.getCompApi(InstantMessagingService.COMP_NAME); imService.registerImType(ImTypes.IM_TYPE_CHAT); imService.addImServiceListener(this); // Set up the awareness service so we can find out about network issues awarenessService = (AwarenessService)session.getCompApi(AwarenessService.COMP_NAME); awarenessService.addAwarenessServiceListener(this); BrokerFactory.getLoggingBroker().logDebug( "Logging into SameTime at "+serverName); CommunityService comm = (CommunityService)session.getCompApi(CommunityService.COMP_NAME); comm.addLoginListener(this); comm.loginByPassword(serverName, accountName, password); comm.setKeepAliveRate(30000); } catch (DuplicateObjectException e) { BrokerFactory.getLoggingBroker().logError(e); } } return session; } public static NotificationProvider getInstance (Hashtable params) { String serverName = (String)params.get("serverName"); SameTimeNotificationProvider provider = new SameTimeNotificationProvider(serverName); return provider; } /* * (non-Javadoc) * * @see net.reliableresponse.notification.providers.NotificationProvider#cancelPage(net.reliableresponse.notification.Notification) */ public boolean cancelPage(Notification page) { return false; } public String[] getResponses(Notification page) { return new String[0]; } /* * (non-Javadoc) * * @see net.reliableresponse.notification.providers.NotificationProvider#sendPage(net.reliableresponse.notification.usermgmt.User, * net.reliableresponse.notification.device.Device, java.lang.String, * java.lang.String, java.lang.String, java.util.Vector) */ public Hashtable sendNotification(Notification notification, Device device) throws NotificationException { if (!ClusteredServiceManager.getInstance().willRun("SameTime")) { ClusteredServiceManager.getInstance().sendNotificationToDevice (notification, "SameTime", notification.getDisplayText(), device.getUuid()); return new Hashtable(); } String summary = notification.getSubject(); String messageText = notification.getDisplayText(); String message = summary+"\n"+messageText; if (notification.isPersistent()) { message += "\n\n"; String[] responses = notification.getSender() .getAvailableResponses(notification); if (responses.length > 0) { message += "You may respond with:\n"; for (int r = 0; r < responses.length; r++) { message += "\t \"" + responses[r] + " " + notification.getID() + "\"\n"; } } } Hashtable params = new Hashtable(); params.put ("serverName", serverName); if (device instanceof SameTimeDevice) { try { sendMessage(notification, device, message); if (notification != null) setStatusOfSend(notification, "pending"); BrokerFactory.getLoggingBroker().logDebug("Sent SameTime message to "+notification.getRecipient()); return params; } catch (SendMessageFailedException e) { BrokerFactory.getLoggingBroker().logDebug( "SameTime message failed: " + e.getMessage()); throw new NotificationException(NotificationException.FAILED, e.getMessage()); } } else { BrokerFactory.getLoggingBroker().logDebug("Could not send to "+device+" because it is not a SameTime device"); if (notification != null) setStatusOfSend(notification, "failed"); throw new NotificationException(NotificationException.INTERNAL_ERROR, "Supplied device does not support SameTime"); } } /** * @param device * @param message * @throws SendMessageFailedException */ private void sendMessage(Notification notification, Device device, String message) throws SendMessageFailedException { SameTimeDevice sametimeDevice = (SameTimeDevice) device; sendMessage (notification, sametimeDevice.getAccount(), message); } private void sendMessage(Notification notification, String account, String message) throws SendMessageFailedException { // Check to make sure we're logged in BrokerFactory.getLoggingBroker().logDebug("Is ST available? "+awarenessService.isServiceAvailable()); if (!awarenessService.isServiceAvailable()) { if (session != null) { session.unloadSession(); } session = null; getSession(); } BrokerFactory.getLoggingBroker().logDebug("Is ST logged in? "+((CommunityService)session.getCompApi(CommunityService.COMP_NAME)).isLoggedIn()); if (!((CommunityService)session.getCompApi(CommunityService.COMP_NAME)).isLoggedIn()) { if (session != null) { session.unloadSession(); } session = null; getSession(); } if (SameTimeNotificationProvider.directories == null) { SameTimeNotificationProvider.directories = new Directory[0]; } BrokerFactory.getLoggingBroker().logDebug("Querying "+directories.length+" directories"); for (int i = 0; i < SameTimeNotificationProvider.directories.length; i++) { SameTimeNotificationProvider.directories[i].addDirectoryListener(new MessageSendingDirectoryListener (imService, this, notification, message, account, SameTimeNotificationProvider.directories[i])); SameTimeNotificationProvider.directories[i].queryEntries(account); } } public void serviceAvailable(AwarenessServiceEvent arg0) { BrokerFactory.getLoggingBroker().logDebug("SameTime Service available: "+arg0); } public void serviceUnavailable(AwarenessServiceEvent arg0) { BrokerFactory.getLoggingBroker().logDebug("SameTime Service unavailable: "+arg0); } public void dataReceived(ImEvent arg0) { } public void imClosed(ImEvent arg0) { } public void imOpened(ImEvent arg0) { } public void openImFailed(ImEvent arg0) { } public void imReceived(ImEvent event) { Im im = event.getIm(); boolean imExist = false; Im currentIm = null; for (int i = 0; i < imOpened.size(); i++) { currentIm = (Im) imOpened.elementAt(i); if (currentIm.equals(im)) { imExist = true; im = currentIm; break; } } if (!imExist) { imOpened.addElement(im); im.addImListener(this); } } public void textReceived(ImEvent event) { String text = event.getText(); String from = event.getIm().getPartner().getName(); textReceived(text, from); } public void textReceived(String text, String from) { BrokerFactory.getLoggingBroker().logDebug("Got SameTime IM: "+text+" from "+from); if (text == null) { return; } User user = null; User[] usersWithSameTime = BrokerFactory.getUserMgmtBroker().getUsersWithDeviceType ("net.reliableresponse.notification.device.SameTimeDevice"); BrokerFactory.getLoggingBroker().logDebug("Got "+usersWithSameTime.length+" users with SameTime"); for (int i = 0; i < usersWithSameTime.length; i++) { BrokerFactory.getLoggingBroker().logDebug("user w/ sametime ["+i+"]="+usersWithSameTime[i]); Device[] devices = usersWithSameTime[i].getDevices(); for (int d = 0; d < devices.length; d++) { if (devices[d] instanceof SameTimeDevice) { if (((SameTimeDevice)devices[d]).getAccount().equals(from)) { user = usersWithSameTime[i]; } } } } // We don't know who this is if (user == null) { BrokerFactory.getLoggingBroker().logInfo("Got SameTime message from unknown source, "+from+ " - "+text); user = new UnknownUser(); } else { String responseToAction = getResponseToAction(user, text); if (responseToAction != null) { try { sendMessage(null, from, responseToAction); } catch (SendMessageFailedException e) { BrokerFactory.getLoggingBroker().logError(e); } return; } } List<Notification> pendingNotifications = BrokerFactory.getNotificationBroker().getNotificationsSince(8640000L); Vector responses = new Vector(); for (Notification pendingNotification: pendingNotifications) { NotificationSender sender = pendingNotification.getSender(); String[] respArray = sender.getAvailableResponses(pendingNotification); for (int r = 0; r < respArray.length; r++) { if (!responses.contains(respArray[r])) { responses.addElement(respArray[r]); } } } for (int i = 0; i < responses.size(); i++) { String response = (String)responses.elementAt(i); Pattern pattern = Pattern.compile("\\b(?i)"+response+"\\b"); if (pattern.matcher(text).find()) { for (Notification pendingNotification: pendingNotifications) { if (text.indexOf(pendingNotification.getID()) >= 0) { NotificationSender sender = pendingNotification.getSender(); if (sender != null) { BrokerFactory.getLoggingBroker().logDebug("Responding to "+ pendingNotification+" with \""+response+"\"via SameTime message from "+from); sender.handleResponse(pendingNotification, user, response, "Notification confirmed by Sametime message: "+text); try { sendMessage(null, from, "Responded to notification "+pendingNotification.getID()+" with "+response); } catch (SendMessageFailedException e) { BrokerFactory.getLoggingBroker().logError(e); } } } } } } } public void loggedIn(LoginEvent arg0) { BrokerFactory.getLoggingBroker().logDebug("Logged into SameTime"); dir.addDirectoryServiceListener(this); dir.queryAllDirectories(); } public void loggedOut(LoginEvent evt) { // if we're logged out, force a new session BrokerFactory.getLoggingBroker().logInfo("SameTime logged out."); try { if (session != null) { session.stop(); session.unloadSession(); } BrokerFactory.getLoggingBroker().logInfo("SameTime logging in again in 120 seconds."); Thread.sleep(120000); session = null; getSession(); } catch (InterruptedException e) { BrokerFactory.getLoggingBroker().logError(e); } } public void allDirectoriesQueried(DirectoryEvent arg0) { SameTimeNotificationProvider.directories = arg0.getDirectories(); BrokerFactory.getLoggingBroker().logDebug("All directories queried, we have "+SameTimeNotificationProvider.directories+" directories"); for (int i = 0; i < SameTimeNotificationProvider.directories.length; i++) { SameTimeNotificationProvider.directories[i].open(); } } public void allDirectoriesQueryFailed(DirectoryEvent arg0) { BrokerFactory.getLoggingBroker().logError("Could not query SameTime directories"); // TODO: This should be logged as a failure, but we don't have the notification object } public void serviceAvailable(DirectoryEvent arg0) { } public void serviceUnavailable(DirectoryEvent arg0) { // TODO: This should be logged as a failure, but we don't have the notification object } public Hashtable getParameters(Notification notification, Device device) { Hashtable params = new Hashtable(); params.put ("serverName", serverName); params.put ("recipient", ""); return params; } public boolean isConfirmed(Notification page) { return false; } public boolean isPassed(Notification page) { return false; } public String getName() { return "SameTime IM"; } } class MessageSendingDirectoryListener implements DirectoryListener, ImListener { String text; String recipient; Directory directory; InstantMessagingService imService; SameTimeNotificationProvider parent; Notification notification; public MessageSendingDirectoryListener (InstantMessagingService imService, SameTimeNotificationProvider parent, Notification notification, String text, String recipient, Directory directory) { this.text = text; this.notification = notification; this.recipient = recipient; this.directory = directory; this.imService = imService; this.parent = parent; } public void directoryOpened(DirectoryEvent arg0) { } public void directoryOpenFailed(DirectoryEvent arg0) { notification.addMessage("Failed to open SameTime directory", null); if (notification != null) parent.setStatusOfSend(notification, "failed"); } public void entriesQueried(DirectoryEvent event) { STObject[] objects = event.getEntries(); for (int i = 0; i < objects.length; i++) { BrokerFactory.getLoggingBroker().logDebug("objects["+i+"]="+objects[i]); if (objects[i] instanceof STUser) { STUser user = (STUser)objects[i]; BrokerFactory.getLoggingBroker().logDebug("user="+user.getName()); if (user.getName().equals (recipient)) { Im im = imService.createIm(user, EncLevel.ENC_LEVEL_NONE, ImTypes.IM_TYPE_CHAT); im.addImListener(this); im.addImListener(parent); im.open(); return; } } } if (!event.isAtEnd()) { directory.queryEntries(false); } else { directory.removeDirectoryListener(this); notification.addMessage("Could not find account in SameTime directory", null); if (notification != null) parent.setStatusOfSend(notification, "failed"); } } public void entriesQueryFailed(DirectoryEvent arg0) { directory.removeDirectoryListener(this); notification.addMessage("Could not query SameTime directory", null); if (notification != null) parent.setStatusOfSend(notification, "failed"); } public void dataReceived(ImEvent arg0) { } public void imClosed(ImEvent arg0) { } public void imOpened(ImEvent arg0) { BrokerFactory.getLoggingBroker().logDebug("Im Opened"); STUserStatus status = arg0.getIm().getAcceptingSideStatus(); BrokerFactory.getLoggingBroker().logDebug(recipient+"'s SameTime status = "+status); if ((status != null) && ((status.isStatus(STUserStatus.ST_USER_STATUS_DND)) || (status.isStatus(STUserStatus.ST_USER_STATUS_OFFLINE)))) { notification.addMessage(recipient+" is not accepting SameTime messages", null); if (notification != null) parent.setStatusOfSend(notification, "failed"); } else { arg0.getIm().sendText(false, text); directory.removeDirectoryListener(this); if (notification != null) parent.setStatusOfSend(notification, "succeeded"); } } public void openImFailed(ImEvent arg0) { BrokerFactory.getLoggingBroker().logDebug("Im Open Failed"); if (notification != null) { notification.addMessage("Sending IM to "+recipient+" via SameTime failed. "+recipient+" is probably not logged in.", null); if (notification != null) parent.setStatusOfSend(notification, "failed"); } } public void textReceived(ImEvent arg0) { BrokerFactory.getLoggingBroker().logDebug("Text Received"); } }