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