package com.commafeed.backend.feeds;

import java.io.ByteArrayInputStream;
import java.util.Calendar;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.SystemUtils;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;
import org.xml.sax.InputSource;

import com.commafeed.backend.model.Feed;
import com.commafeed.backend.model.FeedEntry;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.SyndFeedInput;

public class FeedParser {

	@SuppressWarnings("unchecked")
	public Feed parse(String feedUrl, byte[] xml) throws FeedException {
		Feed feed = new Feed();
		feed.setLastUpdated(Calendar.getInstance().getTime());

		try {
			SyndFeed rss = new SyndFeedInput().build(new InputSource(
					new ByteArrayInputStream(xml)));
			feed.setUrl(feedUrl);
			feed.setTitle(rss.getTitle());
			feed.setLink(rss.getLink());
			List<SyndEntry> items = rss.getEntries();
			for (SyndEntry item : items) {
				FeedEntry entry = new FeedEntry();
				entry.setGuid(item.getUri());
				entry.setTitle(handleContent(item.getTitle()));
				entry.setContent(getContent(item));
				entry.setUrl(item.getLink());
				entry.setUpdated(item.getUpdatedDate() != null ? item
						.getUpdatedDate() : item.getPublishedDate());

				feed.getEntries().add(entry);
			}
		} catch (Exception e) {
			throw new FeedException(String.format(
					"Could not parse feed from %s : %s", feedUrl,
					e.getMessage()), e);
		}
		return feed;
	}

	@SuppressWarnings("unchecked")
	private String getContent(SyndEntry item) {
		String content = null;
		if (item.getContents().isEmpty()) {
			content = item.getDescription() == null ? null : item
					.getDescription().getValue();
		} else {
			content = StringUtils.join(Collections2.transform(
					item.getContents(), new Function<SyndContent, String>() {
						public String apply(SyndContent content) {
							return content.getValue();
						}
					}), SystemUtils.LINE_SEPARATOR);
		}
		content = handleContent(content);
		return content;
	}

	private String handleContent(String content) {
		if (StringUtils.isNotBlank(content)) {
			Whitelist whitelist = Whitelist.relaxed();
			whitelist.addEnforcedAttribute("a", "target", "_blank");

			// TODO evaluate potential security issues
			whitelist.addTags("iframe");
			whitelist.addAttributes("iframe", "src", "height", "width",
					"allowfullscreen", "frameborder");

			content = Jsoup.clean(content, whitelist);
		}
		return content;
	}
}

@@ -240,16 +240,110 @@
 Jsoup;%0D%0A
+import org.jsoup.nodes.Document.OutputSettings;%0D%0Aimport org.jsoup.nodes.Entities.EscapeMode;%0D%0A
 import o
@@ -366,24 +366,24 @@
 Whitelist;%0D%0A
-
 import org.x
@@ -1061,102 +1061,388 @@
 %0A%09%09%09
-SyndFeed rss = new SyndFeedInput().build(new InputSource(%0D%0A%09%09%09%09%09new ByteArrayInputStream(xml))
+InputSource source = new InputSource(new ByteArrayInputStream(xml));%0D%0A%09%09%09if (new String(xml).split(SystemUtils.LINE_SEPARATOR)%5B0%5D%0D%0A%09%09%09%09%09.toUpperCase().contains(%22ISO-8859-1%22)) %7B%0D%0A%09%09%09%09// they probably use word, we need to handle curly quotes and%0D%0A%09%09%09%09// other word special characters%0D%0A%09%09%09%09source.setEncoding(%22windows-1252%22);%0D%0A%09%09%09%7D%0D%0A%09%09%09SyndFeed rss = new SyndFeedInput().build(source
 );%0D%0A
@@ -1765,16 +1765,30 @@
 Content(
+handleContent(
 getConte
@@ -1796,16 +1796,17 @@
 t(item))
+)
 ;%0D%0A%09%09%09%09e
@@ -2677,45 +2677,8 @@
 %09%7D%0D%0A
-%09%09content = handleContent(content);%0D%0A
 %09%09re
@@ -3119,16 +3119,20 @@
 content,
+ %22%22,
  whiteli
@@ -3133,16 +3133,76 @@
 hitelist
+,%0D%0A%09%09%09%09%09new OutputSettings().escapeMode(EscapeMode.extended)
 );%0D%0A%09%09%7D%0D

fix encoding issues with idiots using word for writing content