diff --git a/src/java/org/jivesoftware/sparkimpl/settings/JiveInfo.java b/src/java/org/jivesoftware/sparkimpl/settings/JiveInfo.java index 0be766143..dc075770a 100644 --- a/src/java/org/jivesoftware/sparkimpl/settings/JiveInfo.java +++ b/src/java/org/jivesoftware/sparkimpl/settings/JiveInfo.java @@ -17,7 +17,7 @@ public class JiveInfo { } public static String getVersion() { - return "1.1.9.7"; + return "2.0.0.1"; } public static String getOS() { diff --git a/src/plugins/growl/build.xml b/src/plugins/growl/build.xml new file mode 100644 index 000000000..a92ba317c --- /dev/null +++ b/src/plugins/growl/build.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/plugins/growl/growl.iml b/src/plugins/growl/growl.iml new file mode 100644 index 000000000..fc8cf1dd8 --- /dev/null +++ b/src/plugins/growl/growl.iml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/plugins/growl/src/com/growl/Growl.java b/src/plugins/growl/src/com/growl/Growl.java new file mode 100644 index 000000000..556273a49 --- /dev/null +++ b/src/plugins/growl/src/com/growl/Growl.java @@ -0,0 +1,465 @@ +/** + * Growl.java + * + * Version: + * $Id:$ + * + * Revisions: + * $Log:$ + * + */ + +package com.growl; + +import com.apple.cocoa.foundation.NSDistributedNotificationCenter; +import com.apple.cocoa.foundation.NSArray; +import com.apple.cocoa.foundation.NSDictionary; +import com.apple.cocoa.foundation.NSMutableDictionary; +import com.apple.cocoa.foundation.NSData; +import com.apple.cocoa.application.NSImage; + +/** + * A class that encapsulates the "work" of talking to growl + * + * @author Karl Adam + */ +public class Growl { + + // defines + /** The name of the growl registration notification for DNC. */ + public static final String GROWL_APP_REGISTRATION = "GrowlApplicationRegistrationNotification"; + + // Ticket Defines + /** Ticket key for the application name. */ + public static final String GROWL_APP_NAME = "ApplicationName"; + /** Ticket key for the application icon. */ + public static final String GROWL_APP_ICON = "ApplicationIcon"; + /** Ticket key for the default notifactions. */ + public static final String GROWL_NOTIFICATIONS_DEFAULT = "DefaultNotifications"; + /** Ticket key for all notifactions. */ + public static final String GROWL_NOTIFICATIONS_ALL = "AllNotifications"; + + // Notification Defines + /** The name of the growl notification for DNC. */ + public static final String GROWL_NOTIFICATION = "GrowlNotification"; + /** Notification key for the name. */ + public static final String GROWL_NOTIFICATION_NAME = "NotificationName"; + /** Notification key for the title. */ + public static final String GROWL_NOTIFICATION_TITLE = "NotificationTitle"; + /** Notification key for the description. */ + public static final String GROWL_NOTIFICATION_DESCRIPTION = "NotificationDescription"; + /** Notification key for the icon. */ + public static final String GROWL_NOTIFICATION_ICON = "NotificationIcon"; + /** Notification key for the application icon. */ + public static final String GROWL_NOTIFICATION_APP_ICON = "NotificationAppIcon"; + /** Notification key for the sticky flag. */ + public static final String GROWL_NOTIFICATION_STICKY = "NotificationSticky"; + + // Actual instance data + private boolean registered; // We should only register once + private String appName; // "Application" Name + private NSData appImageData; // "application" Icon + private NSDictionary regDict; // Registration Dictionary + private NSArray allNotes; // All notifications + private NSArray defNotes; // Default Notifications + private NSDistributedNotificationCenter theCenter; + + //************ Constructors **************// + + /** + * Convenience method to contruct a growl instance, defers to Growl(String + * inAppName, NSData inImageData, NSArray inAllNotes, NSArray inDefNotes, + * boolean registerNow) with empty arrays for your notifications. + * + * + * @param inAppName - The Name of your "application" + * @param inImage - The NSImage Icon for your Application + * + */ + public Growl(String inAppName, NSImage inImage) { + + this(inAppName, + inImage.TIFFRepresentation(), + new NSArray(), + new NSArray(), + false); + } + + /** + * Convenience method to contruct a growl instance, defers to Growl(String + * inAppName, NSData inImageData, NSArray inAllNotes, NSArray inDefNotes, + * boolean registerNow) with empty arrays for your notifications. + * + * @param inAppName - The Name of your "Application" + * @param inImageData - The NSData for your NSImage + */ + public Growl(String inAppName, NSData inImageData) { + + this(inAppName, + inImageData, + new NSArray(), + new NSArray(), + false); + } + + /** + * Convenience method to contruct a growl instance, defers to Growl(String + * inAppName, NSData inImageData, NSArray inAllNotes, NSArray inDefNotes, + * boolean registerNow) with empty arrays for your notifications. + * + * @param inAppName - The Name of your "Application" + * @param inImagePath - The path to your icon + * + */ + public Growl(String inAppName, String inImagePath) { + + this(inAppName, + new NSImage(inImagePath, false).TIFFRepresentation(), + new NSArray(), + new NSArray(), + false); + } + + /** + * Convenience method to contruct a growl instance, defers to Growl(String + * inAppName, NSData inImageData, NSArray inAllNotes, NSArray inDefNotes, + * boolean registerNow) with the arrays passed here and empty Data for the icon. + * + * @param inAppName - The Name of your "Application" + * @param inAllNotes - A String Array with the name of all your notifications + * @param inDefNotes - A String Array with the na,es of the Notifications on + * by default + */ + public Growl(String inAppName, String [] inAllNotes, String [] inDefNotes) { + + this(inAppName, + new NSData(), + new NSArray(inAllNotes), + new NSArray(inDefNotes), + false); + } + + /** + * Convenience method to contruct a growl instance, defers to Growl(String + * inAppName, NSData inImageData, NSArray inAllNotes, NSArray inDefNotes, + * boolean registerNow) with empty arrays for your notifications. + * + * @param inAppName - The Name of your "Application" + * @param inImageData - The Data of your "Application"'s icon + * @param inAllNotes - The NSArray of Strings of all your Notifications + * @param inDefNotes - The NSArray of Strings of your default Notifications + * @param registerNow - Since we have all the necessary info we can go ahead + * and register + */ + public Growl(String inAppName, NSData inImageData, NSArray inAllNotes, + NSArray inDefNotes, boolean registerNow) { + appName = inAppName; + appImageData = inImageData; + allNotes = inAllNotes; + defNotes = inDefNotes; + + theCenter = (NSDistributedNotificationCenter)NSDistributedNotificationCenter.defaultCenter(); + + if (registerNow) { + register(); + } + } + + //************ Commonly Used Methods **************// + + /** + * Register all our notifications with Growl, this should only be called + * once. + * @return true. + */ + public boolean register() { + if (!registered) { + + // Construct our dictionary + // Make the arrays of objects then keys + Object [] objects = { appName, allNotes, defNotes, appImageData }; + String [] keys = { GROWL_APP_NAME, + GROWL_NOTIFICATIONS_ALL, + GROWL_NOTIFICATIONS_DEFAULT, + GROWL_APP_ICON}; + + // Make the Dictionary + regDict = new NSDictionary(objects, keys); + + theCenter.postNotification(GROWL_APP_REGISTRATION, // notificationName + (String)null, // anObject + regDict, // userInfoDictionary + true); // deliverImmediately + } + + return true; + } + + /** + * The fun part is actually sending those notifications we worked so hard for + * so here we let growl know about things we think the user would like, and growl + * decides if that is the case. + * + * @param inNotificationName - The name of one of the notifications we told growl + * about. + * @param inIconData - The NSData for the icon for this notification, can be null + * @param inTitle - The Title of our Notification as Growl will show it + * @param inDescription - The Description of our Notification as Growl will + * display it + * @param inExtraInfo - Growl is flexible and allows Display Plugins to do as they + * please with thier own special keys and values, you may use + * them here. These may be ignored by either the user's + * preferences or the current Display Plugin. This can be null + * @param inSticky - Whether the Growl notification should be sticky + * + * @throws Exception When a notification is not known + */ + public void notifyGrowlOf(String inNotificationName, NSData inIconData, + String inTitle, String inDescription, + NSDictionary inExtraInfo, boolean inSticky) throws Exception { + NSMutableDictionary noteDict = new NSMutableDictionary(); + + if (!allNotes.containsObject(inNotificationName)) { + throw new Exception("Undefined Notification attempted"); + } + + noteDict.setObjectForKey(inNotificationName, GROWL_NOTIFICATION_NAME); + noteDict.setObjectForKey(inTitle, GROWL_NOTIFICATION_TITLE); + noteDict.setObjectForKey(inDescription, GROWL_NOTIFICATION_DESCRIPTION); + noteDict.setObjectForKey(appName, GROWL_APP_NAME); + if (inIconData != null) { + noteDict.setObjectForKey(inIconData, GROWL_NOTIFICATION_ICON); + } + + if (inSticky) { + noteDict.setObjectForKey(new Integer(1), GROWL_NOTIFICATION_STICKY); + } + + if (inExtraInfo != null) { + noteDict.addEntriesFromDictionary(inExtraInfo); + } + + theCenter.postNotification(GROWL_NOTIFICATION, + (String)null, + noteDict, + true); + } + + /** + * Convenience method that defers to notifyGrowlOf(String inNotificationName, + * NSData inIconData, String inTitle, String inDescription, + * NSDictionary inExtraInfo, boolean inSticky) + * This is primarily for compatibility with older code + * + * @param inNotificationName - The name of one of the notifications we told growl + * about. + * @param inIconData - The NSData for the icon for this notification, can be null + * @param inTitle - The Title of our Notification as Growl will show it + * @param inDescription - The Description of our Notification as Growl will + * display it + * @param inExtraInfo - Growl is flexible and allows Display Plugins to do as + * they please with their own special keys and values, you + * may use them here. These may be ignored by either the + * user's preferences or the current Display Plugin. This + * can be null. + * + * @throws Exception When a notification is not known + * + */ + public void notifyGrowlOf(String inNotificationName, NSData inIconData, + String inTitle, String inDescription, + NSDictionary inExtraInfo) throws Exception { + + notifyGrowlOf(inNotificationName, inIconData, inTitle, inDescription, + inExtraInfo, false); + } + + /** + * Convenienve method that defers to notifyGrowlOf(String inNotificationName, + * NSData inIconData, String inTitle, String inDescription, + * NSDictionary inExtraInfo) with null passed for icon and extraInfo arguments + * + * @param inNotificationName - The name of one of the notifications we told growl + * about. + * @param inTitle - The Title of our Notification as Growl will show it + * @param inDescription - The Description of our Notification as Growl will + * display it + * + * @throws Exception When a notification is not known + */ + public void notifyGrowlOf(String inNotificationName, String inTitle, + String inDescription) throws Exception { + notifyGrowlOf(inNotificationName, (NSData)null, + inTitle, inDescription, (NSDictionary)null, false); + } + + /** + * Convenience method that defers to notifyGrowlOf(String inNotificationName, + * NSData inIconData, String inTitle, String inDescription, + * NSDictionary inExtraInfo, boolean inSticky) + * with null passed for icon and extraInfo arguments + * + * @param inNotificationName - The name of one of the notifications we told growl + * about. + * @param inTitle - The Title of our Notification as Growl will show it + * @param inDescription - The Description of our Notification as Growl will + * display it + * @param inSticky - Whether our notification should be sticky + * + * @throws Exception When a notification is not known + * + */ + public void notifyGrowlOf(String inNotificationName, String inTitle, + String inDescription, boolean inSticky) throws Exception { + notifyGrowlOf(inNotificationName, (NSData)null, + inTitle, inDescription, (NSDictionary)null, inSticky); + } + + /** + * Defers to notifyGrowlOf(String inNotificationName, NSData inIconData, + * String inTitle, String inDescription, NSDictionary inExtraInfo) with null + * passed for icon and extraInfo arguments + * + * @param inNotificationName - The name of one of the notifications we told growl + * about. + * @param inImage - The notification image. + * @param inTitle - The Title of our Notification as Growl will show it + * @param inDescription - The Description of our Notification as Growl will + * display it + * @param inExtraInfo - Look above for info + * + * @throws Exception When a notification is not known + * + */ + public void notifyGrowlOf(String inNotificationName, NSImage inImage, + String inTitle, String inDescription, + NSDictionary inExtraInfo) throws Exception { + + notifyGrowlOf(inNotificationName, inImage.TIFFRepresentation(), + inTitle, inDescription, inExtraInfo, false); + } + + /** + * Convenienve method that defers to notifyGrowlOf(String inNotificationName, + * NSData inIconData, String inTitle, String inDescription, + * NSDictionary inExtraInfo) with null passed for extraInfo + * + * @param inNotificationName - The name of one of the notifications we told growl + * about. + * @param inImagePath - Path to the image for this notification + * @param inTitle - The Title of our Notification as Growl will show it + * @param inDescription - The Description of our Notification as Growl will + * display it + * + * @throws Exception When a notification is not known + */ + public void notifyGrowlOf(String inNotificationName, String inImagePath, + String inTitle, String inDescription) throws Exception { + + notifyGrowlOf(inNotificationName, + new NSImage(inImagePath, false).TIFFRepresentation(), + inTitle, inDescription, (NSDictionary)null, false); + } + + //************ Accessors **************// + + /** + * Accessor for The currently set "Application" Name + * + * @return String - Application Name + */ + public String applicationName() { + return appName; + } + + /** + * Accessor for the Array of allowed Notifications returned an NSArray + * + * @return the array of allowed notifications. + */ + public NSArray allowedNotifications() { + return allNotes; + } + + /** + * Accessor for the Array of default Notifications returned as an NSArray + * + * @return the array of default notifications. + */ + public NSArray defaultNotifications() { + return defNotes; + } + + //************ Mutators **************// + + /** + * Sets The name of the Application talking to growl + * + * @param inAppName - The Application Name + */ + public void setApplicationName(String inAppName) { + appName = inAppName; + } + + /** + * Set the list of allowed Notifications + * + * @param inAllNotes - The array of allowed Notifications + */ + public void setAllowedNotifications(NSArray inAllNotes) { + allNotes = inAllNotes; + } + + /** + * Set the list of allowed Notifications + * + * @param inAllNotes - The array of allowed Notifications + * + */ + public void setAllowedNotifications(String[] inAllNotes) { + allNotes = new NSArray(inAllNotes); + } + + /** + * Set the list of Default Notfiications + * + * @param inDefNotes - The default Notifications + * + * @throws Exception when an element of the array is not in the + * allowedNotifications + */ + public void setDefaultNotifications(NSArray inDefNotes) throws Exception { + int stop = inDefNotes.count(); + int i = 0; + + for(i = 0; i < stop; i++) { + if (!allNotes.containsObject(inDefNotes.objectAtIndex(i))) { + throw new Exception("Array Element not in Allowed Notifications"); + } + } + + defNotes = inDefNotes; + } + + /** + * Set the list of Default Notfiications + * + * @param inDefNotes - The default Notifications + * + * @throws Exception when an element of the array is not in the + * allowedNotifications + * + */ + public void setDefaultNotifications(String [] inDefNotes) throws Exception { + int stop = inDefNotes.length; + int i = 0; + + for(i = 0; i < stop; i++) { + if (! allNotes.containsObject(inDefNotes[i])) { + throw new Exception("Array Element not in Allowed Notifications"); + } + } + + defNotes = new NSArray(inDefNotes); + } +} diff --git a/src/plugins/growl/src/com/jivesoftware/spark/plugin/growl/GrowlMessageListener.java b/src/plugins/growl/src/com/jivesoftware/spark/plugin/growl/GrowlMessageListener.java new file mode 100644 index 000000000..965013bcf --- /dev/null +++ b/src/plugins/growl/src/com/jivesoftware/spark/plugin/growl/GrowlMessageListener.java @@ -0,0 +1,123 @@ +/** + * $Revision: 22540 $ + * $Date: 2005-10-10 08:44:25 -0700 (Mon, 10 Oct 2005) $ + * + * Copyright (C) 1999-2005 Jive Software. All rights reserved. + * + * This software is the proprietary information of Jive Software. + * Use is subject to license terms. + */ +package com.jivesoftware.spark.plugin.growl; + +import com.apple.cocoa.application.NSImage; +import com.apple.cocoa.foundation.NSData; +import com.growl.Growl; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smackx.packet.VCard; +import org.jivesoftware.spark.ui.MessageListener; +import org.jivesoftware.spark.ui.ChatRoom; +import org.jivesoftware.spark.SparkManager; + +import javax.swing.*; +import java.io.InputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * @author Andrew Wright + */ +public class GrowlMessageListener implements MessageListener { + + private Growl growl; + + public GrowlMessageListener() { + String[] notes = {"Message Received"}; + growl = new Growl("Spark", notes, notes); + growl.register(); + } + + public void messageReceived(final ChatRoom room, final Message message) { + if (!SparkManager.getMainWindow().isFocused()) { + + SwingUtilities.invokeLater(new Runnable() { + + public void run() { + try { + String name = SparkManager.getUserManager().getUserNicknameFromJID(message.getFrom()); + + // Since it looks the method can return null do this in case + if (name == null) { + name = StringUtils.parseName(message.getFrom()); + } + + VCard vCard = null; + + try { + vCard = SparkManager.getVCardManager().getVCard( + StringUtils.parseBareAddress(message.getFrom())); + } + catch (Exception e) { + // vcard can time out so ignore + } + + NSImage image = null; + if (vCard != null) { + byte[] bytes = vCard.getAvatar(); + if (bytes != null) { + try { + NSData data = new NSData(bytes); + image = new NSImage(data); + } + catch (Exception e) { + // just incase there is an error i didn't intend + } + } + } + + if (image == null) { + image = getImage("/images/message-32x32.png"); + } + + growl.notifyGrowlOf("Message Received", image, name, message.getBody(), null); + + } + catch (Exception e) { + Logger.logError(e.getMessage(), e); + } + + } + }); + } + } + + public void messageSent(ChatRoom room, Message message) { + // Ignore + } + + /** + * Creates a {@link com.apple.cocoa.application.NSImage} from a string that points to an image in the class + * + * @param image classpath path of an image + * @return an cocoa image object + */ + private NSImage getImage(String image) { + InputStream in = this.getClass().getResourceAsStream(image); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + byte[] buff = new byte[10 * 1024]; + int len; + try { + while ((len = in.read(buff)) != -1) { + out.write(buff, 0, len); + } + in.close(); + out.close(); + } catch (IOException e) { + Logger.logError(e.getMessage(), e); + } + + NSData data = new NSData(out.toByteArray()); + return new NSImage(data); + } +} diff --git a/src/plugins/growl/src/com/jivesoftware/spark/plugin/growl/GrowlPlugin.java b/src/plugins/growl/src/com/jivesoftware/spark/plugin/growl/GrowlPlugin.java new file mode 100644 index 000000000..009264e20 --- /dev/null +++ b/src/plugins/growl/src/com/jivesoftware/spark/plugin/growl/GrowlPlugin.java @@ -0,0 +1,45 @@ +/** + * $Revision: 22540 $ + * $Date: 2005-10-10 08:44:25 -0700 (Mon, 10 Oct 2005) $ + * + * Copyright (C) 1999-2005 Jive Software. All rights reserved. + * + * This software is the proprietary information of Jive Software. + * Use is subject to license terms. + */ +package com.jivesoftware.spark.plugin.growl; + +import org.jivesoftware.spark.SparkManager; +import org.jivesoftware.spark.plugin.Plugin; + + +/** + * Provides support for Growl Notifications on Mac OS X. Growl can be acquired at + * http://growl.info + * + * + * @author Andrew Wright + */ +public class GrowlPlugin implements Plugin { + + private GrowlRoomListener growlListener; + + + public void initialize() { + growlListener = new GrowlRoomListener(); + SparkManager.getChatManager().addChatRoomListener(growlListener); + } + + public void shutdown() { + SparkManager.getChatManager().removeChatRoomListener(growlListener); + } + + public boolean canShutDown() { + return true; + } + + public void uninstall() { + SparkManager.getChatManager().removeChatRoomListener(growlListener); + } + +} diff --git a/src/plugins/growl/src/com/jivesoftware/spark/plugin/growl/GrowlRoomListener.java b/src/plugins/growl/src/com/jivesoftware/spark/plugin/growl/GrowlRoomListener.java new file mode 100644 index 000000000..2b8820983 --- /dev/null +++ b/src/plugins/growl/src/com/jivesoftware/spark/plugin/growl/GrowlRoomListener.java @@ -0,0 +1,50 @@ +/** + * $Revision: 22540 $ + * $Date: 2005-10-10 08:44:25 -0700 (Mon, 10 Oct 2005) $ + * + * Copyright (C) 1999-2005 Jive Software. All rights reserved. + * + * This software is the proprietary information of Jive Software. + * Use is subject to license terms. + */ +package com.jivesoftware.spark.plugin.growl; + +import org.jivesoftware.spark.ui.ChatRoom; +import org.jivesoftware.spark.ui.ChatRoomListener; + + +/** + * @author Andrew Wright + */ +public class GrowlRoomListener implements ChatRoomListener { + + private GrowlMessageListener growlMessageListener; + + public GrowlRoomListener() { + growlMessageListener = new GrowlMessageListener(); + } + + public void chatRoomOpened(ChatRoom room) { + room.addMessageListener(growlMessageListener); + } + + public void chatRoomLeft(ChatRoom room) { + // Do nothing + } + + public void chatRoomClosed(ChatRoom room) { + // Do nothing + } + + public void chatRoomActivated(ChatRoom room) { + // Do nothing + } + + public void userHasJoined(ChatRoom room, String userid) { + // Do nothing + } + + public void userHasLeft(ChatRoom room, String userid) { + // Do nothing + } +} diff --git a/src/plugins/growl/src/plugin.xml b/src/plugins/growl/src/plugin.xml new file mode 100644 index 000000000..035e49cbc --- /dev/null +++ b/src/plugins/growl/src/plugin.xml @@ -0,0 +1,10 @@ + + Growl Plugin + 1.0 + Andrew Wright + http://www.jivesoftware.com + andrew@jivesoftware.com + Provides Growl notifications on Mac OS X.(http://growl.info) + org.jivesoftware.spark.plugin.growl.GrowlPlugin + 2.0.0.1 + \ No newline at end of file