diff --git a/build.xml b/build.xml
index d93b26e86..8a6e99813 100644
--- a/build.xml
+++ b/build.xml
@@ -8,6 +8,9 @@
+
+
+
@@ -120,6 +123,9 @@
+
+
+
@@ -293,6 +299,13 @@
+
+
+
+
+
+
+
@@ -335,6 +348,7 @@
infostring="SIP Communicator"
bundleid="org.sip-communicator"
stubfile="${macosx.stubfile}"
+ extraclasspath="/System/Library/Java"
workingdirectory="$APP_PACKAGE/Contents/Resources/Java">
@@ -353,14 +367,18 @@
+
+
-
+
+
+
@@ -650,7 +668,8 @@
bundle-contactlist,meta-contactlist,meta-contactlist-slick,
bundle-plugin-icqaccregwizz,bundle-plugin-jabberaccregwizz,
bundle-plugin-msnaccregwizz,bundle-plugin-sipaccregwizz,
- bundle-version,bundle-version-impl,bundle-shutdown"/>
+ bundle-version,bundle-version-impl,bundle-shutdown,
+ bundle-growlnotification"/>
@@ -1116,4 +1135,14 @@ javax.swing.event, javax.swing.border"/>
prefix="net/java/sip/communicator/impl/shutdown"/>
+
+
+
+
+
+
+
+
diff --git a/lib/growl.jar b/lib/growl.jar
new file mode 100644
index 000000000..f2ebec2f4
Binary files /dev/null and b/lib/growl.jar differ
diff --git a/resources/install/macosx/felix.client.run.properties b/resources/install/macosx/felix.client.run.properties
new file mode 100644
index 000000000..7713350f7
--- /dev/null
+++ b/resources/install/macosx/felix.client.run.properties
@@ -0,0 +1,98 @@
+#
+# Framework config properties.
+#
+org.osgi.framework.system.packages= org.osgi.framework; \
+ javax.swing; \
+ javax.swing.event; \
+ javax.swing.table; \
+ javax.swing.text; \
+ javax.swing.text.html; \
+ javax.accessibility; \
+ javax.swing.plaf; \
+ javax.swing.plaf.metal; \
+ javax.swing.plaf.basic; \
+ javax.imageio; \
+ javax.swing.tree; \
+ javax.swing.undo; \
+ javax.swing.event; \
+ javax.swing.border; \
+ javax.swing.filechooser; \
+ org.w3c.dom; \
+ org.xml.sax; \
+ javax.xml.parsers;\
+ org.apache.xml.serializer; \
+ javax.xml.transform; \
+ javax.xml.transform.dom; \
+ javax.xml.transform.stream; \
+ sun.security.action; \
+ javax.net.ssl; \
+ javax.naming; \
+ javax.naming.directory; \
+ javax.sound;\
+ javax.sound.sampled; \
+ edu.stanford.ejalbert; \
+ edu.stanford.ejalbert.exception; \
+ edu.stanford.ejalbert.exceptionhandler; \
+ com.growl;
+
+felix.auto.start.1= reference:file:lib/bundle/org.apache.felix.servicebinder-0.8.0-SNAPSHOT.jar
+#reference:file:lib/bundle/org.apache.felix.bundlerepository-0.8.0-SNAPSHOT.jar
+#\
+# file:lib/bundle/shell.jar \
+# \
+# file:lib/bundle/servicebinder.jar \
+# file:lib/bundle/tablelayout.jar
+
+felix.auto.start.2= \
+ reference:file:sc-bundles/util.jar
+
+felix.auto.start.3= \
+ reference:file:sc-bundles/configuration.jar \
+ reference:file:sc-bundles/version.jar \
+ reference:file:sc-bundles/version-impl.jar \
+ reference:file:sc-bundles/fileaccess.jar \
+ reference:file:sc-bundles/protocol.jar \
+ reference:file:sc-bundles/contactlist.jar \
+ reference:file:sc-bundles/media.jar \
+ reference:file:sc-bundles/protocol-icq.jar \
+ reference:file:sc-bundles/protocol-sip.jar \
+ reference:file:sc-bundles/protocol-jabber.jar \
+ reference:file:sc-bundles/protocol-msn.jar \
+ reference:file:sc-bundles/netaddr.jar \
+ reference:file:sc-bundles/meta-cl.jar
+
+felix.auto.start.4= \
+ reference:file:sc-bundles/history.jar \
+ reference:file:sc-bundles/msghistory.jar \
+ reference:file:sc-bundles/callhistory.jar
+
+
+ felix.auto.start.66= \
+ reference:file:sc-bundles/swing-ui.jar \
+ reference:file:sc-bundles/growlnotification.jar
+
+ felix.auto.start.67= \
+ reference:file:sc-bundles/icqaccregwizz.jar \
+ reference:file:sc-bundles/sipaccregwizz.jar \
+ reference:file:sc-bundles/jabberaccregwizz.jar \
+ reference:file:sc-bundles/msnaccregwizz.jar \
+ reference:file:sc-bundles/shutdown.jar
+
+# Uncomment the following lines if you want to run the architect viewer
+# bundle.
+#oscar.auto.start.100= \
+# file:lib/bundle/architectureviewer1.1.jar
+
+#Specify the directory where oscar should deploy its bundles
+felix.cache.profiledir=sip-communicator.bin
+
+
+felix.startlevel.framework=100
+felix.startlevel.bundle=100
+#
+# Bundle config properties.
+#
+#org.osgi.service.http.port=8080
+#osgi.shell.telnet=on
+#oscar.repository.url=file:/home/rickhall/projects/noscar/repository.xml
+oscar.embedded.execution=false
diff --git a/src/net/java/sip/communicator/impl/growlnotification/GrowlNotificationActivator.java b/src/net/java/sip/communicator/impl/growlnotification/GrowlNotificationActivator.java
new file mode 100644
index 000000000..3fbfb6b77
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/growlnotification/GrowlNotificationActivator.java
@@ -0,0 +1,44 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.growlnotification;
+
+import org.osgi.framework.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * Activates the GrowlNotificationService
+ *
+ * @author Romain Kuntz
+ */
+public class GrowlNotificationActivator
+ implements BundleActivator
+{
+ private static Logger logger =
+ Logger.getLogger(GrowlNotificationActivator.class);
+
+ private GrowlNotificationServiceImpl growlNotificationService = null;
+
+ /**
+ * Initialize and start Growl Notifications Service
+ *
+ * @param bundleContext BundleContext
+ * @throws Exception
+ */
+ public void start(BundleContext bundleContext) throws Exception
+ {
+ /* Create and start the Growl Notification service. */
+ growlNotificationService = new GrowlNotificationServiceImpl();
+ growlNotificationService.start(bundleContext);
+
+ logger.info("Growl Notification Plugin ...[Started]");
+ }
+
+ public void stop(BundleContext bundleContext) throws Exception
+ {
+ logger.info("Growl Notification Service ...[Stopped]");
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/growlnotification/GrowlNotificationServiceImpl.java b/src/net/java/sip/communicator/impl/growlnotification/GrowlNotificationServiceImpl.java
new file mode 100644
index 000000000..0bc0b5b80
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/growlnotification/GrowlNotificationServiceImpl.java
@@ -0,0 +1,344 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.growlnotification;
+
+import java.util.*;
+
+import org.osgi.framework.*;
+import com.growl.*;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import java.lang.reflect.*;
+
+
+/**
+ * The Growl Notification Service displays on-screen information such as
+ * messages or call received, etc.
+ *
+ * @author Romain Kuntz
+ */
+public class GrowlNotificationServiceImpl
+ implements MessageListener,
+ ServiceListener
+{
+ /**
+ * The logger for this class.
+ */
+ private static Logger logger =
+ Logger.getLogger(GrowlNotificationServiceImpl.class);
+
+ /**
+ * The BundleContext that we got from the OSGI bus.
+ */
+ private BundleContext bundleContext = null;
+
+ /**
+ * The Growl notifier
+ */
+ private Growl notifier;
+
+ /**
+ * The noifyGrowlOf method of the growl class. We use reflection to access
+ * it in order to avoid compilation errors on non mac platforms.
+ */
+ private Method notifyMethod = null;
+
+ /* All Growl Notifications and the default ones */
+ private String [] allNotif =
+ new String[] { "SIP Communicator Started",
+ "Protocol events",
+ "Message Received",
+ "Message Sent"};
+
+ private String [] defaultNotif =
+ new String[] { "SIP Communicator Started",
+ "Message Received" };
+
+ /**
+ * starts the service. Creates a Growl notifier, and check the current
+ * registerd protocol providers which supports BasicIM and adds message
+ * listener to them.
+ *
+ * @param bc a currently valid bundle context
+ * @throws java.lang.Exception if we fail initializing the growl notifier.
+ */
+ public void start(BundleContext bc)
+ throws Exception
+ {
+ logger.debug("Starting the Growl Notification implementation.");
+ this.bundleContext = bc;
+
+ /* Register to Growl */
+ try
+ {
+ Constructor constructor = Growl.class.getConstructor(new Class[]
+ {String.class, String.class, String.class});
+ notifier = (Growl)constructor.newInstance(
+ new Object[]{"SIP Communicator", allNotif, defaultNotif});
+ notifier.register();
+
+ //init the notifyGrowlOf method
+ notifyMethod = Growl.class.getMethod(
+ "notifyGrowlOf"
+ , new Class[]{String.class, String.class, String.class});
+
+ notifyGrowlOf("SIP Communicator Started"
+ , "Welcome to SIP Communicator"
+ , "http://www.sip-communicator.org");
+ }
+ catch (Exception ex)
+ {
+ logger.error("Could not send the message to Growl", ex);
+ throw ex;
+ }
+
+ /* Start listening for newly register or removed protocol providers */
+ bc.addServiceListener(this);
+
+ ServiceReference[] protocolProviderRefs = null;
+ try
+ {
+ protocolProviderRefs = bc.getServiceReferences(
+ ProtocolProviderService.class.getName(),
+ null);
+ }
+ catch (InvalidSyntaxException ex)
+ {
+ // this shouldn't happen since we're providing no parameter string
+ // but let's log just in case.
+ logger.error("Error while retrieving service refs", ex);
+ return;
+ }
+
+ // in case we found any
+ if (protocolProviderRefs != null)
+ {
+ logger.debug("Found "
+ + protocolProviderRefs.length
+ + " already installed providers.");
+ for (int i = 0; i < protocolProviderRefs.length; i++)
+ {
+ ProtocolProviderService provider = (ProtocolProviderService) bc
+ .getService(protocolProviderRefs[i]);
+
+ this.handleProviderAdded(provider);
+ }
+ }
+ }
+
+ /**
+ * stops the service.
+ *
+ * @param bc BundleContext
+ */
+ public void stop(BundleContext bc)
+ {
+ // start listening for newly register or removed protocol providers
+ bc.removeServiceListener(this);
+
+ ServiceReference[] protocolProviderRefs = null;
+ try
+ {
+ protocolProviderRefs = bc.getServiceReferences(
+ ProtocolProviderService.class.getName(),
+ null);
+ }
+ catch (InvalidSyntaxException ex)
+ {
+ // this shouldn't happen since we're providing no parameter string
+ // but let's log just in case.
+ logger.error(
+ "Error while retrieving service refs", ex);
+ return;
+ }
+
+ // in case we found any
+ if (protocolProviderRefs != null)
+ {
+ for (int i = 0; i < protocolProviderRefs.length; i++)
+ {
+ ProtocolProviderService provider = (ProtocolProviderService) bc
+ .getService(protocolProviderRefs[i]);
+
+ this.handleProviderRemoved(provider);
+ }
+ }
+ }
+
+ // ////////////////////////////////////////////////////////////////////////
+ // MessageListener implementation methods
+
+ /**
+ * Passes the newly received message to growl.
+ * @param evt MessageReceivedEvent the vent containing the new message.
+ */
+ public void messageReceived(MessageReceivedEvent evt)
+ {
+ try
+ {
+ notifyGrowlOf("Message Received"
+ , evt.getSourceContact().getDisplayName()
+ , evt.getSourceMessage().getContent());
+ }
+ catch (Exception ex)
+ {
+ logger.error("Could not notify the received message to Growl", ex);
+ }
+ }
+
+ /**
+ * Notify growl that a message has been sent.
+ * @param evt the event containing the message that has just been sent.
+ */
+ public void messageDelivered(MessageDeliveredEvent evt)
+ {
+ try
+ {
+ notifyGrowlOf("Message Sent"
+ , "Me"
+ , evt.getSourceMessage().getContent());
+ }
+ catch (Exception ex)
+ {
+ logger.error("Could not pass the sent message to Growl", ex);
+ }
+ }
+
+ /**
+ * Currently unused
+ * @param evt ignored
+ */
+ public void messageDeliveryFailed(MessageDeliveryFailedEvent evt)
+ {
+ }
+ // //////////////////////////////////////////////////////////////////////////
+
+ /**
+ * When new protocol provider is registered we check
+ * does it supports BasicIM and if so add a listener to it
+ *
+ * @param serviceEvent ServiceEvent
+ */
+ public void serviceChanged(ServiceEvent serviceEvent)
+ {
+ Object sService
+ = bundleContext.getService(serviceEvent.getServiceReference());
+
+ logger.trace("Received a service event for: "
+ + sService.getClass().getName());
+
+ // we don't care if the source service is not a protocol provider
+ if (! (sService instanceof ProtocolProviderService))
+ {
+ return;
+ }
+
+ logger.debug("Service is a protocol provider.");
+ if (serviceEvent.getType() == ServiceEvent.REGISTERED)
+ {
+ logger.debug("Handling registration of a new Protocol Provider.");
+
+ this.handleProviderAdded((ProtocolProviderService)sService);
+ }
+ else if (serviceEvent.getType() == ServiceEvent.UNREGISTERING)
+ {
+ this.handleProviderRemoved( (ProtocolProviderService) sService);
+ }
+
+ }
+
+ /**
+ * Used to attach the Growl Notification Service to existing or
+ * just registered protocol provider. Checks if the provider has
+ * implementation of OperationSetBasicInstantMessaging
+ *
+ * @param provider ProtocolProviderService
+ */
+ private void handleProviderAdded(ProtocolProviderService provider)
+ {
+ logger.debug("Adding protocol provider " + provider.getProtocolName());
+
+ // check whether the provider has a basic im operation set
+ OperationSetBasicInstantMessaging opSetIm
+ = (OperationSetBasicInstantMessaging) provider
+ .getSupportedOperationSets().get(
+ OperationSetBasicInstantMessaging.class.getName());
+
+ if (opSetIm != null)
+ {
+ opSetIm.addMessageListener(this);
+ try
+ {
+ notifyGrowlOf("Protocol events"
+ , "New Protocol Registered"
+ , provider.getProtocolName() + " registered");
+ }
+ catch (Exception ex)
+ {
+ logger.error("Could not notify the message to Growl", ex);
+ }
+ }
+ else
+ {
+ logger.trace("Service did not have a im op. set.");
+ }
+ }
+
+ /**
+ * Removes the specified provider from the list of currently known providers
+ * and ignores all the messages exchanged by it
+ *
+ * @param provider the ProtocolProviderService that has been unregistered.
+ */
+ private void handleProviderRemoved(ProtocolProviderService provider)
+ {
+ OperationSetBasicInstantMessaging opSetIm
+ = (OperationSetBasicInstantMessaging) provider
+ .getSupportedOperationSets().get(
+ OperationSetBasicInstantMessaging.class.getName());
+
+ if (opSetIm != null)
+ {
+ opSetIm.removeMessageListener(this);
+ try
+ {
+ notifyGrowlOf("Protocol events"
+ , "Protocol deregistered"
+ , provider.getProtocolName()
+ + " deregistered");
+ }
+ catch (Exception ex)
+ {
+ logger.error("Could not notify the message to Growl", ex);
+ }
+ }
+ }
+
+ /**
+ * Convenience method that defers to notifier.notifyGrowlOf() using
+ * reflection without referencing it directly. The purpose of this method
+ * is to allow the class to compile on non-mac systems.
+ *
+ * @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
+ {
+ notifyMethod.invoke(
+ notifier, new Object[]{inNotificationName, inTitle, inDescription});
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/growlnotification/growlnotification.manifest.mf b/src/net/java/sip/communicator/impl/growlnotification/growlnotification.manifest.mf
new file mode 100644
index 000000000..400db0861
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/growlnotification/growlnotification.manifest.mf
@@ -0,0 +1,9 @@
+Bundle-Activator: net.java.sip.communicator.impl.growlnotification.GrowlNotificationActivator
+Bundle-Name: Growl Notification Service Provider
+Bundle-Description: A bundle that implements the Growl notification package.
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+Import-Package: org.osgi.framework,
+ net.java.sip.communicator.util,
+ net.java.sip.communicator.service.protocol,
+ net.java.sip.communicator.service.protocol.event