diff --git a/lib/felix.client.run.properties.rss b/lib/felix.client.run.properties.rss new file mode 100644 index 000000000..3827cd884 --- /dev/null +++ b/lib/felix.client.run.properties.rss @@ -0,0 +1,114 @@ +# +# 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.serialize; \ + javax.xml.transform; \ + javax.xml.transform.dom; \ + javax.xml.transform.stream; \ + sun.security.action; \ + sun.misc; \ + javax.net; \ + javax.net.ssl; \ + javax.naming; \ + javax.naming.directory; \ + javax.sound;\ + javax.sound.sampled; \ + org.jdesktop.jdic.tray; \ + org.jdesktop.jdic.desktop; \ + com.apple.eio; \ + org.xml.sax.helpers; + +felix.auto.start.10= 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.20= \ + reference:file:sc-bundles/util.jar + + +felix.auto.start.40= \ + reference:file:sc-bundles/configuration.jar \ + reference:file:sc-bundles/version.jar \ + reference:file:sc-bundles/version-impl.jar \ + reference:file:sc-bundles/splashscreen.jar \ + +felix.auto.start.50= \ + reference:file:sc-bundles/fileaccess.jar \ + reference:file:sc-bundles/browserlauncher.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/smacklib.jar \ + reference:file:sc-bundles/protocol-jabber.jar \ + reference:file:sc-bundles/protocol-msn.jar \ + reference:file:sc-bundles/protocol-yahoo.jar \ + reference:file:sc-bundles/protocol-gibberish.jar \ + reference:file:sc-bundles/netaddr.jar \ + reference:file:sc-bundles/protocol-zeroconf.jar \ + reference:file:sc-bundles/meta-cl.jar + +felix.auto.start.60= \ + reference:file:sc-bundles/history.jar \ + reference:file:sc-bundles/msghistory.jar \ + reference:file:sc-bundles/callhistory.jar \ + reference:file:sc-bundles/audionotifier.jar + + + felix.auto.start.66= \ + reference:file:sc-bundles/swing-ui.jar \ + reference:file:sc-bundles/systray.jar + + felix.auto.start.67= \ + reference:file:sc-bundles/pluginmanager.jar \ + reference:file:sc-bundles/icqaccregwizz.jar \ + reference:file:sc-bundles/aimaccregwizz.jar \ + reference:file:sc-bundles/jabberaccregwizz.jar \ + reference:file:sc-bundles/msnaccregwizz.jar \ + reference:file:sc-bundles/yahooaccregwizz.jar \ + reference:file:sc-bundles/gibberishaccregwizz.jar \ + reference:file:sc-bundles/extendedcallhistorysearch.jar \ + reference:file:sc-bundles/zeroconfaccregwizz.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.cache.profiledir=${user.home}/.sip-communicator/profiledir + +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/lib/installer-exclude/aclibico-2.1.jar b/lib/installer-exclude/aclibico-2.1.jar new file mode 100644 index 000000000..5f6b57673 Binary files /dev/null and b/lib/installer-exclude/aclibico-2.1.jar differ diff --git a/src/net/java/sip/communicator/impl/protocol/rss/ContactRssImpl.java b/src/net/java/sip/communicator/impl/protocol/rss/ContactRssImpl.java index a9a771a46..7b67289ce 100644 --- a/src/net/java/sip/communicator/impl/protocol/rss/ContactRssImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/rss/ContactRssImpl.java @@ -12,10 +12,17 @@ import net.java.sip.communicator.util.*; import java.net.*; +import com.ctreber.aclib.image.ico.*; +import java.io.*; +import java.awt.*; +import javax.imageio.*; +import java.awt.image.*; + /** * An implementation of a rss Contact. * * @author Jean-Albert Vescovo + * @author Mihai Balan */ public class ContactRssImpl implements Contact @@ -30,6 +37,11 @@ public class ContactRssImpl private static SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy.MM.dd-HH:mm:ss"); + /** + * The path within the bundle for the default RSS 64x64 icon. + */ + private String defaultIconPath = "resources/images/rss/rss64x64.png"; + /** * The source flow for this contact. */ @@ -200,14 +212,124 @@ private void convertStringToDate(String lastDate) } /** - * Returns a byte array containing an image (most often a photo or an - * avatar) that the contact uses as a representation. + * Returns a byte array containing an image to represent the feed. This is + * acquired either via the favicon.ico file on the server where the + * feed resides, either a default standard RSS icon is returned. * - * @return byte[] an image representing the contact. + * @return byte[] the binary representation of the best available image in + * the icon, or null in case the image is invalid or inexistent. */ public byte[] getImage() { - return null; + Image selectedIcon; + + //we use these to get the best possible icon in case our favicon is a + //multi-page icon. + int maxWidth = 0; + int maxColors = 0; + int crtDescriptor = -1; + + //used for ICO to PNG translation. Uses PNG as it's the "safest" choice. + ByteArrayOutputStream output = new ByteArrayOutputStream(); + byte[] result = null; + + URL feedLocation = getRssURL(); + + //TODO: Fix aclico log4j-related errors + + try + { + URL location = new URL(feedLocation.getProtocol() + "://" + + feedLocation.getHost() + "/favicon.ico"); + ICOFile favicon = new ICOFile(location); + + logger.trace("Icon has " + favicon.getImageCount() + " pages"); + + for (int i = 0; i < favicon.getDescriptors().size(); i++) + { + BitmapDescriptor bmpDesc = favicon.getDescriptor(i); + if ((maxWidth < bmpDesc.getWidth())) + { + maxWidth = bmpDesc.getWidth(); + maxColors = bmpDesc.getColorCount(); + crtDescriptor = i; + } + + if ((maxColors < bmpDesc.getColorCount())) + { + maxWidth = bmpDesc.getWidth(); + maxColors = bmpDesc.getColorCount(); + crtDescriptor = i; + } + } + + //if icons is either invalid or contains no data, return the default + // RSS icon. + if (crtDescriptor == -1) + { + return getDefaultRssIcon(); + } + + selectedIcon = favicon.getDescriptor(crtDescriptor).getImageRGB(); + + //decode ICO as a PNG and return the result + ImageIO.write((BufferedImage)selectedIcon, "PNG", output); + result = output.toByteArray(); + + logger.trace("Result has " + result.length + " bytes"); + logger.trace("Icon is " + maxWidth + " px X " + maxWidth + " px @ " + + maxColors + " colors"); + + output.close(); + return result; + } + catch (MalformedURLException murlex) + { + //this shouldn't happen. Ever. + logger.error("Malformed URL " + murlex, + murlex); + } + catch (IOException ioex) + { + logger.error("I/O Error on favicon retrieval. " + ioex, + ioex); + } + return getDefaultRssIcon(); + } + + /** + * Returns the default icon in case the feed has no favicon on the server. + * Uses the defaultIconPath to locate the default icon to be + * displayed. + * + * @return binary representation of the default icon + */ + private byte[] getDefaultRssIcon() + { + logger.trace("Loading default icon at " + defaultIconPath); + + InputStream is = ContactRssImpl.class.getClassLoader() + .getResourceAsStream(defaultIconPath); + + byte[] result = null; + + //if something happened and the resource isn't at the specified location + //(messed jar-s, wrong filename, etc.) just return now + if (is == null) + return result; + try + { + logger.trace("Icon is "+is.available() + " bytes long"); + result = new byte[is.available()]; + is.read(result); + } + catch (IOException ioex) + { + logger.error("Error loading default icon at" + defaultIconPath, + ioex); + } + return result; + } /** @@ -234,7 +356,7 @@ public void setPresenceStatus(PresenceStatus rssPresenceStatus) /** * Returns a reference to the protocol provider that created the contact. * - * @return a refererence to an instance of the ProtocolProviderService + * @return a reference to an instance of the ProtocolProviderService */ public ProtocolProviderService getProtocolProvider() { diff --git a/src/net/java/sip/communicator/impl/protocol/rss/OperationSetBasicInstantMessagingRssImpl.java b/src/net/java/sip/communicator/impl/protocol/rss/OperationSetBasicInstantMessagingRssImpl.java index 33be96bcb..2ffa56882 100644 --- a/src/net/java/sip/communicator/impl/protocol/rss/OperationSetBasicInstantMessagingRssImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/rss/OperationSetBasicInstantMessagingRssImpl.java @@ -16,6 +16,7 @@ * Instant messaging functionalites for the Rss protocol. * * @author Jean-Albert Vescovo + * @author Mihai Balan */ public class OperationSetBasicInstantMessagingRssImpl implements OperationSetBasicInstantMessaging, @@ -97,8 +98,10 @@ public void addMessageListener(MessageListener listener) public Message createMessage(byte[] content, String contentType, String contentEncoding, String subject) { - return new MessageRssImpl(new String(content), contentType - , contentEncoding, subject); + return new MessageRssImpl(new String(content), + contentType, + contentEncoding, + subject); } /** @@ -110,9 +113,10 @@ public Message createMessage(byte[] content, String contentType, */ public Message createMessage(String messageText) { - - return new MessageRssImpl(messageText, DEFAULT_MIME_TYPE - , DEFAULT_MIME_ENCODING, null); + return new MessageRssImpl(messageText, + "text/html", + DEFAULT_MIME_ENCODING, + null); } /** @@ -356,9 +360,9 @@ public boolean isOfflineMessagingSupported() { return false; } - + /** - * Determines wheter the protocol supports the supplied content type + * Determines whether the protocol supports the supplied content type * * @param contentType the type we want to check * @return true if the protocol supports it and @@ -368,6 +372,8 @@ public boolean isContentTypeSupported(String contentType) { if(contentType.equals(DEFAULT_MIME_TYPE)) return true; + else if(contentType.equals("text/html")) + return true; else return false; } diff --git a/src/net/java/sip/communicator/impl/protocol/rss/RssFeedReader.java b/src/net/java/sip/communicator/impl/protocol/rss/RssFeedReader.java index ac9cab819..a684c1f62 100644 --- a/src/net/java/sip/communicator/impl/protocol/rss/RssFeedReader.java +++ b/src/net/java/sip/communicator/impl/protocol/rss/RssFeedReader.java @@ -18,6 +18,7 @@ * The class used for using the Informa Library into the RSS protocol * * @author Jean-Albert Vescovo + * @author Mihai Balan */ public class RssFeedReader { @@ -65,7 +66,7 @@ public RssFeedReader(URL contactRssURL) { this.rssURL = contactRssURL; - /** @todo should retrieve this from a resource file.*/ + /* TODO should retrieve this from a resource file.*/ this.title = "No feed avalaible !"; } @@ -103,7 +104,8 @@ public void retrieveFlow() //chronological order items = (SyndEntry[]) (this.feed.getEntries() .toArray(new SyndEntry[0])); - sortItems(); + //sort items + Arrays.sort(items, syndEntryComparator); //if we don't understand the date format we don't want to handle //this feed @@ -145,10 +147,13 @@ public void retrieveFlow() */ public synchronized String feedToString(Date latestRetrievedItemDate) { + String newsAbstract = null; StringBuffer printedFeed = new StringBuffer(); + /* TODO move this in a resources file.*/ if (items.length == 0) - return "No items currently available for this feed !"; + return "No items currently available for this feed !
"; + //go through the items list in reverse order so that we could stop //as soon as we reach items that we've already shown to the user. @@ -157,37 +162,32 @@ public synchronized String feedToString(Date latestRetrievedItemDate) if (items[i].getPublishedDate() .compareTo(latestRetrievedItemDate) > 0) { - printedFeed.insert( - 0 - , "\nAt " + items[i].getPublishedDate() - + " - " + items[i].getTitle() - + "\nLink: " + items[i].getLink() + "\n\n"); + // Get the abstract of the news. + newsAbstract = items[i].getDescription().getValue(); + // Forge the news to be displayed. + printedFeed.insert(0, "At " + + items[i].getPublishedDate() + + "
"+ items[i].getTitle() + "" + + " Link
"); } else { if (i == items.length - 1) { printedFeed - .append("\n\nNo new articles in your feed since" - + " last update."); + .append("No new articles in your feed since" + + " last update.
"); + } break; } } - printedFeed.append ("\n\nSend anything to refresh this feed..."); + printedFeed + .append ("Send anything to refresh this feed...
\n"); return printedFeed.toString(); } - /** - * Sorts the items retrieved from the rss contact/feed associated with this - * reader. The method uses a bubble sort algorithm. - */ - private void sortItems() - { - Arrays.sort(items, syndEntryComparator); - } - /** * Returns a Date that can be used to know the most recent item in a * retrieved feed. diff --git a/src/net/java/sip/communicator/impl/protocol/rss/rss.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/rss/rss.provider.manifest.mf index 09b8d2ab0..f8d7ddd1e 100644 --- a/src/net/java/sip/communicator/impl/protocol/rss/rss.provider.manifest.mf +++ b/src/net/java/sip/communicator/impl/protocol/rss/rss.provider.manifest.mf @@ -12,5 +12,7 @@ Import-Package: org.osgi.framework, net.java.sip.communicator.service.configuration.event, net.java.sip.communicator.util, net.java.sip.communicator.service.protocol, - net.java.sip.communicator.service.protocol.event + net.java.sip.communicator.service.protocol.event, + org.apache.log4j, + javax.imageio