[Commits] [SCM] claws branch, new-rssyl, created. 3.10.0-66-g6f7b8b2

ticho at claws-mail.org ticho at claws-mail.org
Sat Jun 7 20:56:16 CEST 2014


The branch new-rssyl of project "claws" (Claws Mail) has been created
        at  6f7b8b2c476af720b8d68b64e05b716bacd5896c (commit)

- Log -----------------------------------------------------------------
commit 6f7b8b2c476af720b8d68b64e05b716bacd5896c
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Mon Jun 2 00:24:21 2014 +0200

    New RSSyl replacing old one.

diff --git a/configure.ac b/configure.ac
index 281a4ad..f47031f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1055,7 +1055,7 @@ dnl PGP/Mime:		pgpcore libgpgme
 dnl PGP/Inline:		pgpcore libgpgme
 dnl S/Mime:		pgpcore libgpgme
 dnl Python:		Python
-dnl RSSyl:		libxml2 libcurl
+dnl RSSyl:		expat libcurl
 dnl SpamReport:		libcurl
 dnl vCalendar:		libcurl
 
@@ -1064,10 +1064,14 @@ PKG_CHECK_MODULES(CURL, libcurl, HAVE_CURL=yes, HAVE_CURL=no)
 AC_SUBST(CURL_LIBS)
 AC_SUBST(CURL_CFLAGS)
 
-dnl libxml2 ********************************************************************
-PKG_CHECK_MODULES(LIBXML, libxml-2.0, HAVE_LIBXML=yes, HAVE_LIBXML=no)
-AC_SUBST(LIBXML_LIBS)
-AC_SUBST(LIBXML_CFLAGS)
+dnl expat **********************************************************************
+HAVE_EXPAT=0
+AC_CHECK_HEADER(expat.h, [expat_header=yes], [])
+AC_CHECK_LIB(expat, XML_ParserCreate, [expat_lib=yes], [])
+if test x"$expat_header" = xyes -a x"$expat_lib"=xyes; then
+	AC_DEFINE(HAVE_EXPAT, 1, [Define if expat is available])
+	EXPAT_LIBS="-lexpat"
+fi
 
 dnl webkit *********************************************************************
 PKG_CHECK_MODULES(WEBKIT, webkit-1.0 >= 1.1.14, HAVE_WEBKIT=yes, HAVE_WEBKIT=no)
@@ -1721,8 +1725,8 @@ AC_MSG_CHECKING([whether to build rssyl plugin])
 if test x"$enable_rssyl_plugin" != xno; then
 	dependencies_missing=""
 
-	if test x"$HAVE_LIBXML" = xno; then
-		dependencies_missing="libxml2 $dependencies_missing"
+	if test x"$HAVE_EXPAT" = xno; then
+		dependencies_missing="expat $dependencies_missing"
 	fi
 	if test x"$HAVE_CURL" = xno; then
 		dependencies_missing="libcurl $dependencies_missing"
@@ -1923,6 +1927,7 @@ src/plugins/pgpcore/Makefile
 src/plugins/pgpmime/Makefile
 src/plugins/pgpinline/Makefile
 src/plugins/rssyl/Makefile
+src/plugins/rssyl/libfeed/Makefile
 src/plugins/smime/Makefile
 src/plugins/spamassassin/Makefile
 src/plugins/spam_report/Makefile
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 2013668..55c4488 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -128,14 +128,23 @@ src/plugins/pgpinline/pgpinline.c
 src/plugins/pgpinline/plugin.c
 src/plugins/pgpmime/pgpmime.c
 src/plugins/pgpmime/plugin.c
-src/plugins/rssyl/rssyl_prefs.c
-src/plugins/rssyl/rssyl.h
-src/plugins/rssyl/rssyl_gtk.c
+src/plugins/rssyl/old_feeds.c
+src/plugins/rssyl/opml_import.c
 src/plugins/rssyl/plugin.c
-src/plugins/rssyl/feed.h
-src/plugins/rssyl/rssyl_cb_menu.c
+src/plugins/rssyl/rssyl_add_item.c
 src/plugins/rssyl/rssyl.c
-src/plugins/rssyl/feed.c
+src/plugins/rssyl/rssyl_cb_menu.c
+src/plugins/rssyl/rssyl_feed.c
+src/plugins/rssyl/rssyl_feed.h
+src/plugins/rssyl/rssyl_feed_props.c
+src/plugins/rssyl/rssyl_gtk.c
+src/plugins/rssyl/rssyl.h
+src/plugins/rssyl/rssyl_prefs.c
+src/plugins/rssyl/rssyl_subscribe.c
+src/plugins/rssyl/rssyl_subscribe_gtk.c
+src/plugins/rssyl/rssyl_update_comments.c
+src/plugins/rssyl/rssyl_update_feed.c
+src/plugins/rssyl/rssyl_update_format.c
 src/plugins/smime/plugin.c
 src/plugins/smime/smime.c
 src/plugins/spam_report/spam_report_prefs.c
diff --git a/src/plugins/rssyl/Makefile.am b/src/plugins/rssyl/Makefile.am
index 7887963..64417c9 100644
--- a/src/plugins/rssyl/Makefile.am
+++ b/src/plugins/rssyl/Makefile.am
@@ -2,6 +2,8 @@
 # This file is part of Claws Mail package.
 # See COPYING file for license details.
 
+SUBDIRS = libfeed
+
 EXTRA_DIST = claws.def plugin.def version.rc
 
 IFLAGS = \
@@ -62,29 +64,35 @@ rssyl_la_LDFLAGS = \
 	-avoid-version -module \
 	$(GTK_LIBS)
 
-rssyl_la_DEPENDENCIES = $(plugin_deps)
+rssyl_la_DEPENDENCIES = $(plugin_deps) libfeed/libfeed.la
 
 rssyl_la_LIBADD = $(plugin_ldadd) $(cygwin_export_lib) \
-	$(GTK_LIBS) $(LIBXML_LIBS) $(CURL_LIBS)
+	$(GTK_LIBS) $(CURL_LIBS) libfeed/libfeed.la
 
 rssyl_la_CPPFLAGS = \
 	$(IFLAGS) \
 	$(GLIB_CFLAGS) \
 	$(GTK_CFLAGS) \
-	$(LIBXML_CFLAGS) \
 	$(CURL_CFLAGS)
 
 rssyl_la_SOURCES = \
-	date.c date.h \
-	feed.c feed.h \
-	feedprops.c feedprops.h \
-	opml.c opml.h \
-	parsers.c parsers.h \
+	old_feeds.c old_feeds.h \
+	opml_export.c opml_export.h \
+	opml_import.c opml_import.h \
+	parse822.c parse822.h \
 	plugin.c \
 	rssyl.c rssyl.h \
-	rssyl_cb_gtk.c rssyl_cb_gtk.h \
+	rssyl_add_item.c rssyl_add_item.h \
 	rssyl_cb_menu.c rssyl_cb_menu.h \
+	rssyl_deleted.c rssyl_deleted.h \
+	rssyl_feed.c rssyl_feed.h \
+	rssyl_feed_props.c rssyl_feed_props.h \
 	rssyl_gtk.c rssyl_gtk.h \
+	rssyl_parse_feed.c rssyl_parse_feed.h \
 	rssyl_prefs.c rssyl_prefs.h \
-	strreplace.c strreplace.h
-
+	rssyl_update_comments.c rssyl_update_comments.h \
+	rssyl_update_feed.c rssyl_update_feed.h \
+	rssyl_update_format.c rssyl_update_format.h \
+	rssyl_subscribe.c rssyl_subscribe.h \
+	rssyl_subscribe_gtk.c rssyl_subscribe_gtk.h \
+	strutils.c strutils.h
diff --git a/src/plugins/rssyl/feed.c b/src/plugins/rssyl/feed.c
deleted file mode 100644
index 8542bc7..0000000
--- a/src/plugins/rssyl/feed.c
+++ /dev/null
@@ -1,1869 +0,0 @@
-/*
- * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2004 Hiroyuki Yamamoto
- * This file (C) 2005-2008 Andrej Kacian <andrej at kacian.sk> and the Claws Mail team
- *
- * - various feed parsing functions
- * - this file could use some sorting and/or splitting
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#include "claws-features.h"
-#endif
-
-#include <glib.h>
-#include <glib/gi18n.h>
-
-#include <gtk/gtk.h>
-
-#include <curl/curl.h>
-#include <curl/curlver.h>
-#include <libxml/parser.h>
-#include <libxml/xpath.h>
-#include <pthread.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "common/claws.h"
-#include "common/version.h"
-#include "codeconv.h"
-#include "procmsg.h"
-#include "procheader.h"
-#include "alertpanel.h"
-#include "folder.h"
-#include "mainwindow.h"
-#include "statusbar.h"
-#include "log.h"
-#include "prefs_common.h"
-#include "defs.h"
-#include "inc.h"
-#include "common/utils.h"
-#include "main.h"
-
-#include "date.h"
-#include "rssyl.h"
-#include "rssyl_cb_gtk.h"
-#include "feed.h"
-#include "feedprops.h"
-#include "strreplace.h"
-#include "parsers.h"
-#include "rssyl_prefs.h"
-
-static int rssyl_curl_progress_function(void *clientp,
-		double dltotal, double dlnow, double ultotal, double ulnow)
-{
-	if (claws_is_exiting()) {
-		debug_print("RSSyl: curl_progress_function bailing out, app is exiting\n");
-		return 1;
-	}
-
-	return 0;
-}
-
-struct _RSSylThreadCtx {
-	const gchar *url;
-	time_t last_update;
-	gboolean not_modified;
-	gboolean defer_modified_check;
-	gboolean ready;
-	gchar *error;
-	gboolean ssl_verify_peer;
-};
-
-typedef struct _RSSylThreadCtx RSSylThreadCtx;
-
-static void *rssyl_fetch_feed_threaded(void *arg)
-{
-	RSSylThreadCtx *ctx = (RSSylThreadCtx *)arg;
-	CURL *eh = NULL;
-	CURLcode res;
-	time_t last_modified;
-	gchar *time_str = NULL;
-	long response_code;
-
-#ifndef G_OS_WIN32
-	gchar *template = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
-			G_DIR_SEPARATOR_S, RSSYL_TMP_TEMPLATE, NULL);
-	int fd = mkstemp(template);
-#else
-	gchar *template = get_tmp_file();
-	int fd = open(template, (O_CREAT|O_RDWR|O_BINARY), (S_IRUSR|S_IWUSR));
-#endif
-	FILE *f;
-
-#ifdef USE_PTHREAD
-	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
-	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
-#endif
-
-	if (fd == -1) {
-		perror("mkstemp");
-		ctx->ready = TRUE;
-		g_free(template);
-		return NULL;
-	}
-
-	f = fdopen(fd, "w");
-	if (f == NULL) {
-		perror("fdopen");
-		ctx->error = g_strdup(_("Cannot open temporary file"));
-		claws_unlink(template);
-		g_free(template);
-		ctx->ready = TRUE;
-		return NULL;
-	}
-
-	eh = curl_easy_init();
-
-	if (eh == NULL) {
-		g_warning("can't init curl");
-		ctx->error = g_strdup(_("Cannot init libCURL"));
-		fclose(f);
-		claws_unlink(template);
-		g_free(template);
-		ctx->ready = TRUE;
-		return NULL;
-	}
-
-	debug_print("TEMPLATE: %s\n", template);
-
-	curl_easy_setopt(eh, CURLOPT_URL, ctx->url);
-	curl_easy_setopt(eh, CURLOPT_NOPROGRESS, 0);
-	curl_easy_setopt(eh, CURLOPT_PROGRESSFUNCTION, rssyl_curl_progress_function);
-#if LIBCURL_VERSION_NUM < 0x071000
-	curl_easy_setopt(eh, CURLOPT_MUTE, 1);
-#endif
-	curl_easy_setopt(eh, CURLOPT_WRITEFUNCTION, NULL);
-	curl_easy_setopt(eh, CURLOPT_WRITEDATA, f);
-	curl_easy_setopt(eh, CURLOPT_FOLLOWLOCATION, 1);
-	curl_easy_setopt(eh, CURLOPT_MAXREDIRS, 3);
-	curl_easy_setopt(eh, CURLOPT_TIMEOUT, prefs_common_get_prefs()->io_timeout_secs);
-	curl_easy_setopt(eh, CURLOPT_NOSIGNAL, 1);
-	curl_easy_setopt(eh, CURLOPT_ENCODING, "");
-#if LIBCURL_VERSION_NUM >= 0x070a00
-	if(ctx->ssl_verify_peer == FALSE) {
-		curl_easy_setopt(eh, CURLOPT_SSL_VERIFYPEER, 0);
-		curl_easy_setopt(eh, CURLOPT_SSL_VERIFYHOST, 0);
-	}
-#endif
-	curl_easy_setopt(eh, CURLOPT_USERAGENT,
-		"Claws Mail RSSyl plugin "VERSION
-		" (" PLUGINS_URI ")");
-#ifdef RSSYL_DEBUG
-	curl_easy_setopt(eh, CURLOPT_VERBOSE, 1);
-#endif
-	curl_easy_setopt(eh, CURLOPT_COOKIEFILE,
-			rssyl_prefs_get()->cookies_path);
-	
-	if( !ctx->defer_modified_check ) {
-		if( ctx->last_update != -1 ) {
-			time_str = createRFC822Date(&ctx->last_update);
-		}
-		debug_print("RSSyl: last update %ld (%s)\n",
-			(long int)ctx->last_update,
-			(ctx->last_update != -1 ? time_str : "unknown") );
-		g_free(time_str);
-		time_str = NULL;
-		if( ctx->last_update != -1 ) {
-			curl_easy_setopt(eh, CURLOPT_TIMECONDITION,
-				CURL_TIMECOND_IFMODSINCE);
-			curl_easy_setopt(eh, CURLOPT_TIMEVALUE, ctx->last_update);
-		}
-	}
-			
-	res = curl_easy_perform(eh);
-
-	if (res != 0) {
-		if (res == CURLE_OPERATION_TIMEOUTED) {
-			log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_TIMEOUT, ctx->url);
-		} else if (res == CURLE_ABORTED_BY_CALLBACK) {
-			log_print(LOG_PROTOCOL, RSSYL_LOG_EXITING);
-		}
-		ctx->error = g_strdup(curl_easy_strerror(res));
-		ctx->ready = TRUE;
-		curl_easy_cleanup(eh);
-		fclose(f);
-		claws_unlink(template);
-		g_free(template);
-		return NULL;
-	}
-	curl_easy_getinfo(eh, CURLINFO_RESPONSE_CODE, &response_code);
-
-	if( !ctx->defer_modified_check ) {
-		if( ctx->last_update != -1 ) {
-			curl_easy_getinfo(eh, CURLINFO_FILETIME, &last_modified);
-
-			if( last_modified != -1 ) {
-				time_str = createRFC822Date(&last_modified);
-			}
-			debug_print("RSSyl: got status %ld, last mod %ld (%s)\n",
-					response_code, (long int) last_modified, 
-					(last_modified != -1 ? time_str : "unknown") );
-			g_free(time_str);
-			time_str = NULL;
-		} else {
-			debug_print("RSSyl: got status %ld\n", response_code);
-		}
-	}
-
-	curl_easy_cleanup(eh);
-
-	fclose(f);
-
-	if( response_code >= 400 && response_code < 500 ) {
-		debug_print("RSSyl: got %ld\n", response_code);
-		switch(response_code) {
-			case 401: 
-				ctx->error = g_strdup(_("401 (Authorisation required)"));
-				break;
-			case 403:
-				ctx->error = g_strdup(_("403 (Unauthorised)"));
-				break;
-			case 404:
-				ctx->error = g_strdup(_("404 (Not found)"));
-				break;
-			default:
-				ctx->error = g_strdup_printf(_("Error %ld"), response_code);
-				break;
-		}
-		ctx->ready = TRUE;
-		claws_unlink(template);
-		g_free(template);
-		return NULL;
-	}
-
-	if( !ctx->defer_modified_check ) {
-		if( response_code == 304 ) {
-			debug_print("RSSyl: don't rely on server response 304, defer modified "
-					"check\n");
-			claws_unlink(template);
-			g_free(template);
-			ctx->defer_modified_check = TRUE;
-			template = rssyl_fetch_feed_threaded(ctx);
-			return template;
-		}
-	}
-	ctx->ready = TRUE;
-
-	return template;
-}
-
-gchar *rssyl_feed_title_to_dir(const gchar *title)
-{
-#ifndef G_OS_WIN32
-	return rssyl_strreplace(title, "/", "\\");
-#else
-	gchar *patterns[] = { "/", "\\", ":", "*", "?" , "\"", "<", ">", "|" };
-	gchar *sanitized = g_strdup(title);
-	int i;
-
-	for (i = 0; i < sizeof(patterns)/sizeof(patterns[0]); i++) {
-		gchar *tmp = rssyl_strreplace(sanitized, patterns[i], "-");
-		g_free(sanitized);
-		sanitized = tmp;
-	}
-	
-	return sanitized;
-#endif
-}
-
-/* rssyl_fetch_feed()
- *
- * This function utilizes libcurl's easy interface to fetch the feed, pre-parse
- * it for title, create a directory based on the title. It returns a xmlDocPtr
- * for libxml2 to parse further.
- */
-xmlDocPtr rssyl_fetch_feed(const gchar *url, time_t last_update, gboolean ssl_verify_peer, gchar **title, gchar **error) {
-	gchar *xpath, *rootnode, *dir;
-	xmlDocPtr doc;
-	xmlNodePtr node, n, rnode;
-	xmlXPathContextPtr context;
-	xmlXPathObjectPtr result;
-	MainWindow *mainwin = mainwindow_get_mainwindow();
-	RSSylThreadCtx *ctx = g_new0(RSSylThreadCtx, 1);
-	gchar *template = NULL;
-	gboolean defer_modified_check = FALSE;
-#ifdef RSSYL_DEBUG
-	gchar *unixtime_str = NULL, *debugfname = NULL;
-#endif /* RSSYL_DEBUG */
-
-#ifdef USE_PTHREAD
-	pthread_t pt;
-	pthread_attr_t pta;
-#endif
-	gchar *msg = NULL, *tmptitle = NULL;
-	gchar *content;
-	xmlErrorPtr xml_err;
-
-	ctx->url = url;
-	ctx->ready = FALSE;
-	ctx->last_update = last_update;
-	ctx->not_modified = FALSE;
-	ctx->defer_modified_check = FALSE;
-	ctx->ssl_verify_peer = ssl_verify_peer;
-
-	*title = NULL;
-
-	g_return_val_if_fail(url != NULL, NULL);
-
-	debug_print("RSSyl: XML - url is '%s'\n", url);
-
-	msg = g_strdup_printf(_("Fetching '%s'..."), url);
-	STATUSBAR_PUSH(mainwin, msg );
-	g_free(msg);
-
-	GTK_EVENTS_FLUSH();
-
-#ifdef USE_PTHREAD
-	if (pthread_attr_init(&pta) != 0 ||
-	    pthread_attr_setdetachstate(&pta, PTHREAD_CREATE_JOINABLE) != 0 ||
-	    pthread_create(&pt, &pta, rssyl_fetch_feed_threaded,
-				(void *)ctx) != 0 ) {
-		/* Bummer, couldn't create thread. Continue non-threaded */
-		template = rssyl_fetch_feed_threaded(ctx);
-	} else {
-		/* Thread created, let's wait until it finishes */
-		debug_print("RSSyl: waiting for thread to finish\n");
-		while( !ctx->ready ) {
-			claws_do_idle();
-		}
-
-		debug_print("RSSyl: thread finished\n");
-		pthread_join(pt, (void *)&template);
-	}
-#else
-	debug_print("RSSyl: no pthreads, run blocking fetch\n");
-	template = rssyl_fetch_feed_threaded(ctx);
-#endif
-
-	defer_modified_check = ctx->defer_modified_check;
-
-	if (error)
-		*error = ctx->error;
-
-	g_free(ctx);
-	STATUSBAR_POP(mainwin);
-
-	if( template == NULL ) {
-		debug_print("RSSyl: no feed to parse, returning\n");
-		log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_FETCH, url);
-		return NULL;
-	}
-		
-	/* Strip ugly \r\n endlines */
-#ifndef G_OS_WIN32
-	file_strip_crs((gchar *)template);
-#endif
-	debug_print("parsing %s\n", template);
-	doc = xmlParseFile(template);
-	
-	if( doc == NULL ) {
-		claws_unlink(template);
-		g_free(template);
-		xml_err = xmlGetLastError();
-		if (xml_err)
-			debug_print("error %s\n", xml_err->message);
-		
-		g_warning("Couldn't fetch feed '%s', aborting.\n", url);
-		log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_FETCH, url);
-		if (error && !(*error)) {
-			*error = g_strdup(_("Malformed feed"));
-		}
-		return NULL;
-	}
-
-	node = xmlDocGetRootElement(doc);
-	rnode = node;
-
-#ifdef RSSYL_DEBUG
-	/* debug mode - get timestamp, add it to returned xmlDoc, and make a copy
-	 * of the fetched feed file */
-	tmptitle = rssyl_feed_title_to_dir(url);
-	unixtime_str = g_strdup_printf("%ld", time(NULL) );
-	debugfname = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
-			G_DIR_SEPARATOR_S, ".", tmptitle, ".", unixtime_str, NULL);
-
-	debug_print("Storing fetched feed in file '%s' for debug purposes.\n",
-			debugfname);
-	link(template, debugfname);
-
-	debug_print("Adding 'fetched' property to root node: %s\n", unixtime_str);
-	xmlSetProp(rnode, "fetched", unixtime_str);
-	g_free(unixtime_str);
-	g_free(debugfname);
-	g_free(tmptitle);
-#endif	/* RSSYL_DEBUG */
-
-	claws_unlink(template);
-	g_free(template);
-
-	debug_print("RSSyl: XML - root node is '%s'\n", node->name);
-
-	rootnode = g_ascii_strdown(node->name, -1);
-
-	if( !xmlStrcmp(rootnode, "rss") ) {
-		context = xmlXPathNewContext(doc);
-		xpath = g_strconcat("/", node->name, "/channel/title",	NULL);
-		debug_print("RSSyl: XML - '%s'\n", xpath);
-		if( !(result = xmlXPathEvalExpression(xpath, context)) ) {
-			debug_print("RSSyl: XML - no result found for '%s'\n", xpath);
-			xmlXPathFreeContext(context);
-			g_free(rootnode);
-			g_free(xpath);
-			log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_PARSE, url);
-			return NULL;
-		}
-
-		if( xmlXPathNodeSetIsEmpty(result->nodesetval) ) {
-			debug_print("RSSyl: XML - nodeset empty for '%s'\n", xpath);
-			g_free(rootnode);
-			g_free(xpath);
-			xmlXPathFreeObject(result);
-			xmlXPathFreeContext(context);
-			log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_PARSE, url);
-			return NULL;
-		}
-		g_free(xpath);
-
-		xmlXPathFreeContext(context);
-		node = result->nodesetval->nodeTab[0];
-		xmlXPathFreeObject(result);
-		content = xmlNodeGetContent(node);
-		debug_print("RSSyl: XML - title is '%s'\n", content );
-		*title = g_strdup(content);
-		xmlFree(content);
-		debug_print("RSSyl: XML - our title is '%s'\n", *title);
-
-		/* use the feed's pubDate to determine if it's modified */
-		if( defer_modified_check ) {
-		   time_t pub_date;
-
-		   context = xmlXPathNewContext(doc);
-		   node = rnode;
-		   xpath = g_strconcat("/", node->name, "/channel/pubDate", NULL);
-		   debug_print("RSSyl: XML - '%s'\n", xpath);
-		   if( !(result = xmlXPathEvalExpression(xpath, context)) ) {
-			   debug_print("RSSyl: XML - no result found for '%s'\n", xpath);
-			   xmlXPathFreeContext(context);
-			   g_free(rootnode);
-			   g_free(xpath);
-				 log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_PARSE, url);
-			   return NULL;
-		   }
-
-		   if( xmlXPathNodeSetIsEmpty(result->nodesetval) ) {
-			   debug_print("RSSyl: XML - nodeset empty for '%s', using current time\n",
-						 xpath);
-				 pub_date = time(NULL);
-		   } else {
-			   node = result->nodesetval->nodeTab[0];
-			   content = xmlNodeGetContent(node);
-			   pub_date = procheader_date_parse(NULL, content, 0);
-			   debug_print("RSSyl: XML - pubDate is '%s'\n", content);
-				 xmlFree(content);
-			 }
-
-			 xmlXPathFreeObject(result);
-			 xmlXPathFreeContext(context);
-			 g_free(xpath);
-
-		   /* check date validity and perform postponed modified check */
-		   if( pub_date > 0 ) {
-			   gchar *time_str = NULL;
-
-			   time_str = createRFC822Date(&pub_date);
-			   debug_print("RSSyl: XML - item date found: %ld (%s)\n",
-					   (long int) pub_date, time_str ? time_str : "unknown");
-			   if( !time_str || ( pub_date < last_update && last_update > 0) ) {
-				   if( !time_str) {
-					   debug_print("RSSyl: XML - invalid item date\n");
-				   } else {
-					   debug_print("RSSyl: XML - no update needed\n");
-				   }
-				   g_free(time_str);
-				   time_str = NULL;
-				   g_free(rootnode);
-				   return NULL;
-			   }
-			   g_free(time_str);
-			   time_str = NULL;
-		   } else {
-			   debug_print("RSSyl: XML - item date not found\n");
-			   g_free(rootnode);
-			   return NULL;
-		   }
-		}
-
-	} else if( !xmlStrcmp(rootnode, "rdf") ) {
-		node = node->children;
-		/* find "channel" */
-		while( node && xmlStrcmp(node->name, "channel") )
-			node = node->next;
-		/* now find "title" */
-		for( n = node->children; n; n = n->next ) {
-			if( !xmlStrcmp(n->name, "title") ) {
-				content = xmlNodeGetContent(n);
-				*title = g_strdup(content);
-				xmlFree(content);
-				debug_print("RSSyl: XML - RDF our title is '%s'\n", *title);
-			}
-		}
-	} else if( !xmlStrcmp(rootnode, "feed") ) {
-		/* find "title" */
-		for( n = node->children; n; n = n->next ) {
-			if( !xmlStrcmp(n->name, "title") ) {
-				content = xmlNodeGetContent(n);
-				*title = g_strdup(content);
-				xmlFree(content);
-				debug_print("RSSyl: XML - FEED our title is '%s'\n", *title);
-			}
-		}
-	} else {
-		log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_UNKNOWN, url);
-		g_free(rootnode);
-		return NULL;
-	}
-
-	g_return_val_if_fail(*title != NULL, NULL);
-
-	if (*title[0] == '\0') {
-		g_free(*title);
-		*title = g_strdup(url);
-		subst_for_shellsafe_filename(*title);
-	}
-
-	tmptitle = rssyl_feed_title_to_dir(*title);
-	dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
-			G_DIR_SEPARATOR_S, tmptitle, NULL);
-	g_free(tmptitle);
-
-	if( !is_dir_exist(dir) ) {
-		if( make_dir(dir) < 0 ) {
-			g_warning("couldn't create directory %s\n", dir);
-			g_free(rootnode);
-			g_free(dir);
-			return NULL;
-		}
-	}
-
-	g_free(rootnode);
-	g_free(dir);
-
-	return doc;
-}
-
-typedef struct _RSSyl_HTMLSymbol RSSyl_HTMLSymbol;
-struct _RSSyl_HTMLSymbol
-{
-	gchar *const key;
-	gchar *const val;
-};
-
-static RSSyl_HTMLSymbol symbol_list[] = {
-	{ "<", "<" },
-	{ ">", ">" },
-	{ "&", "&" },
-	{ """, "\"" },
-	{ "‘",  "'" },
-	{ "’",  "'" },
-	{ "“",  "\"" },
-	{ "”",  "\"" },
-	{ " ", " " },
-	{ "™", "(TM)" },
-	{ "™", "(TM)" },
-	{ "'", "'" },
-	{ "…", "..." },
-	{ "—", "-" },
-	{ "<cite>", "\"" },
-	{ "</cite>", "\"" },
-	{ "<i>", "" },
-	{ "</i>", "" },
-	{ "<em>", "" },
-	{ "</em>", ""},
-	{ "<b>", "" },
-	{ "</b>", "" },
-	{ "<nobr>", "" },
-	{ "</nobr>", "" },
-	{ "<wbr>", "" },
-	{ NULL, NULL },
-};
-
-static gchar *rssyl_replace_html_symbols(const gchar *text)
-{
-	gchar *tmp = NULL, *wtext = g_strdup(text);
-	gint i;
-
-	for( i = 0; symbol_list[i].key != NULL; i++ ) {
-		if( g_strstr_len(text, strlen(text), symbol_list[i].key) ) {
-			tmp = rssyl_strreplace(wtext, symbol_list[i].key, symbol_list[i].val);
-			wtext = g_strdup(tmp);
-			g_free(tmp);
-		}
-	}
-
-	return wtext;
-}
-
-gchar *rssyl_format_string(const gchar *str, gboolean replace_html, gboolean replace_returns)
-{
-	gchar *res = NULL;
-	gchar *tmp = NULL;
-
-	g_return_val_if_fail(str != NULL, NULL);
-
-	if (replace_html)
-		tmp = rssyl_replace_html_symbols(str);
-	else
-		tmp = g_strdup(str);
-
-	res = rssyl_sanitize_string(tmp, replace_returns);
-	g_free(tmp);
-
-	g_strstrip(res);
-
-	return res;
-}
-
-/* this function splits a string into an array of string, by 
- * returning an array of pointers to positions of the delimiter
- * in the original string and replacing this delimiter with a
- * NULL. It does not duplicate memory, hence you should only
- * free the array and not its elements, and you should not
- * free the original string before you're done with the array.
- * maybe could be part of the core (utils.c).
- */
-static gchar **strplit_no_copy(gchar *str, char delimiter)
-{
-	gchar **array = g_new(gchar *, 1);
-	int i = 0;
-	gchar *cur = str, *next;
-	
-	array[i] = cur;
-	i++;
-	while ((next = strchr(cur, delimiter)) != NULL) {
-		*(next) = '\0';
-		array = g_realloc(array, (sizeof(gchar *)) * (i + 1));
-		array[i] = next + 1;
-		cur = next + 1;
-		i++;
-	}
-	array = g_realloc(array, (sizeof(gchar *)) * (i + 1));
-	array[i] = NULL;
-	return array;
-}
-
-/* rssyl_parse_folder_item_file()
- *
- * Parse the RFC822-formatted feed item given by "path", and returns a
- * pointer to a RSSylFeedItem struct, which contains all required data.
- */
-static RSSylFeedItem *rssyl_parse_folder_item_file(gchar *dir_path, gchar *filename)
-{
-	gchar *contents, **lines, **line, **splid;
-	GError *error = NULL;
-	RSSylFeedItem *fitem;
-	gint i = 0;
-	gboolean parsing_headers, past_html_tag, past_endhtml_tag;
-	gboolean started_author = FALSE, started_subject = FALSE;
-	gboolean started_link = FALSE, started_clink = FALSE, started_plink = FALSE;
-	gchar *full_path = g_strconcat(dir_path, G_DIR_SEPARATOR_S, filename, NULL);
-	debug_print("RSSyl: parsing '%s'\n", full_path);
-
-	g_file_get_contents(full_path, &contents, NULL, &error);
-
-	if( error ) {
-		g_warning("GError: '%s'\n", error->message);
-		g_error_free(error);
-		error = NULL;
-	}
-
-	if( contents ) {
-		lines = strplit_no_copy(contents, '\n');
-	} else {
-		g_warning("Badly formatted file found, ignoring: '%s'\n", full_path);
-		g_free(contents);
-		return NULL;
-	}
-
-	fitem = g_new0(RSSylFeedItem, 1); /* free that */
-	fitem->date = 0;
-	fitem->date_published = 0;
-	fitem->link = NULL;
-	fitem->text = NULL;
-	fitem->id = NULL;
-	fitem->id_is_permalink = FALSE;
-	fitem->realpath = g_strdup(full_path);
-
-	g_free(full_path);
-
-	parsing_headers = TRUE;
-	past_html_tag = FALSE;
-	past_endhtml_tag = FALSE;
-	while(lines[i] ) {
-		if( parsing_headers && lines[i] && !strlen(lines[i]) && fitem->link ) {
-			parsing_headers = FALSE;
-			debug_print("RSSyl: finished parsing headers\n");
-		}
-
-		if( parsing_headers ) {
-			line = g_strsplit(lines[i], ": ", 2);
-			if( line[0] && line[1] && strlen(line[0]) && lines[i][0] != ' ') {
-				started_author = FALSE;
-				started_subject = FALSE;
-				started_link = FALSE;
-				started_clink = FALSE;
-				started_plink = FALSE;
-
-				/* Author */
-				if( !strcmp(line[0], "From") ) {
-					fitem->author = g_strdup(line[1]);
-					debug_print("RSSyl: got author '%s'\n", fitem->author);
-					started_author = TRUE;
-				}
-
-				/* Date */
-				if( !strcmp(line[0], "Date") ) {
-					fitem->date = procheader_date_parse(NULL, line[1], 0);
-					debug_print("RSSyl: got date \n" );
-				}
-
-				/* Title */
-				if( !strcmp(line[0], "Subject") ) {
-					fitem->title = g_strdup(line[1]);
-					debug_print("RSSyl: got title '%s'\n", fitem->title);
-					started_subject = TRUE;
-				}
-
-				/* Link */
-				if( !strcmp(line[0], "X-RSSyl-URL") ) {
-					fitem->link = g_strdup(line[1]);
-					debug_print("RSSyl: got link '%s'\n", fitem->link);
-					started_link = TRUE;
-				}
-
-				/* ID */
-				if( !strcmp(line[0], "Message-ID") ) {
-					splid = g_strsplit_set(line[1], "<>", 3);
-					if( strlen(splid[1]) != 0 ) {
-						fitem->id = g_strdup(splid[1]);
-						debug_print("RSSyl: got id '%s'\n", fitem->id);
-					}
-					g_strfreev(splid);
-				}
-
-				if( !strcmp(line[0], "X-RSSyl-Comments") ) {
-					fitem->comments_link = g_strdup(line[1]);
-					debug_print("RSSyl: got clink '%s'\n", fitem->comments_link);
-					started_clink = TRUE;
-				}
-				if( !strcmp(line[0], "X-RSSyl-Parent") ) {
-					fitem->parent_link = g_strdup(line[1]);
-					debug_print("RSSyl: got plink '%s'\n", fitem->parent_link);
-					started_plink = TRUE;
-				}
-			} else if (lines[i][0] == ' ') {
-				gchar *tmp = NULL;
-				/* continuation line */
-				if (started_author) {
-					tmp = g_strdup_printf("%s %s", fitem->author, lines[i]+1);
-					g_free(fitem->author);
-					fitem->author = tmp;
-					debug_print("RSSyl: updated author to '%s'\n", fitem->author);
-				} else if (started_subject) {
-					tmp = g_strdup_printf("%s %s", fitem->title, lines[i]+1);
-					g_free(fitem->title);
-					fitem->title = tmp;
-					debug_print("RSSyl: updated title to '%s'\n", fitem->title);
-				} else if (started_link) {
-					tmp = g_strdup_printf("%s%s", fitem->link, lines[i]+1);
-					g_free(fitem->link);
-					fitem->link = tmp;
-					debug_print("RSSyl: updated link to '%s'\n", fitem->link);
-				} else if (started_clink) {
-					tmp = g_strdup_printf("%s%s", fitem->comments_link, lines[i]+1);
-					g_free(fitem->comments_link);
-					fitem->comments_link = tmp;
-					debug_print("RSSyl: updated comments_link to '%s'\n", fitem->comments_link);
-				} else if (started_plink) {
-					tmp = g_strdup_printf("%s%s", fitem->parent_link, lines[i]+1);
-					g_free(fitem->parent_link);
-					fitem->parent_link = tmp;
-					debug_print("RSSyl: updated comments_link to '%s'\n", fitem->parent_link);
-				}
-			}
-			g_strfreev(line);
-		} else {
-			if( !strcmp(lines[i], RSSYL_TEXT_START) ) {
-				debug_print("Leading html tag found at line %d\n", i);
-				past_html_tag = TRUE;
-				i++;
-				continue;
-			}
-			while( past_html_tag && !past_endhtml_tag && lines[i] ) {
-				if( !strcmp(lines[i], RSSYL_TEXT_END) ) {
-					debug_print("Trailing html tag found at line %d\n", i);
-					past_endhtml_tag = TRUE;
-					i++;
-					continue;
-				}
-				if( fitem->text != NULL ) {
-					gint e_len, n_len;
-					e_len = strlen(fitem->text);
-					n_len = strlen(lines[i]);
-					fitem->text = g_realloc(fitem->text, e_len + n_len + 2);
-					*(fitem->text+e_len) = '\n';
-					strcpy(fitem->text+e_len+1, lines[i]);
-					*(fitem->text+e_len+n_len+1) = '\0';
-				} else {
-					fitem->text = g_strdup(lines[i]);
-				}
-				i++;
-			}
-
-			if( lines[i] == NULL )
-				return fitem;
-		}
-
-		i++;
-	}
-	g_free(lines);
-	g_free(contents);
-	return fitem;
-}
-
-/* rssyl_free_feeditem()
- * frees an RSSylFeedItem
- */
-void rssyl_free_feeditem(RSSylFeedItem *item)
-{
-	if (!item)
-		return;
-	g_free(item->title);
-	item->title = NULL;
-	g_free(item->text);
-	item->text = NULL;
-	g_free(item->link);
-	item->link = NULL;
-	g_free(item->id);
-	item->id = NULL;
-	g_free(item->comments_link);
-	item->comments_link = NULL;
-	g_free(item->parent_link);
-	item->parent_link = NULL;
-	g_free(item->author);
-	item->author = NULL;
-	g_free(item->realpath);
-	item->realpath = NULL;
-	if( item->media != NULL ) {
-		g_free(item->media->url);
-		g_free(item->media->type);
-		g_free(item->media);
-	}
-	g_free(item);
-}
-
-static void *rssyl_read_existing_thr(void *arg)
-{
-	RSSylParseCtx *ctx = (RSSylParseCtx *)arg;
-	RSSylFolderItem *ritem = ctx->ritem;
-	FolderItem *item = &ritem->item;
-	RSSylFeedItem *fitem = NULL;
-	DIR *dp;
-	struct dirent *d;
-	gint num;
-	gchar *path;
-
-	debug_print("RSSyl: rssyl_read_existing_thr()\n");
-
-	path = folder_item_get_path(item);
-	if( !path ) {
-		debug_print("RSSyl: read_existing - path is NULL, bailing out\n");
-		ctx->ready = TRUE;
-		return NULL;
-	}
-
-	/* create a new GSList, throw away the old one */
-	if( ritem->contents != NULL ) {
-		GSList *cur;
-		for (cur = ritem->contents; cur; cur = cur->next) {
-			RSSylFeedItem *olditem = (RSSylFeedItem *)cur->data;
-			rssyl_free_feeditem(olditem);
-		}
-		g_slist_free(ritem->contents); /* leak fix here */
-		ritem->contents = NULL;
-	}
-	ritem->contents = g_slist_alloc();
-
-	if( change_dir(path) < 0 ) {
-		g_free(path);
-		return NULL;
-	}
-
-	if( (dp = opendir(".")) == NULL ) {
-		FILE_OP_ERROR(item->path, "opendir");
-		g_free(path);
-		return NULL;
-	}
-
-	while( (d = readdir(dp)) != NULL ) {
-		if (claws_is_exiting()) {
-			closedir(dp);
-			g_free(path);
-			debug_print("RSSyl: read_existing is bailing out, app is exiting\n");
-			ctx->ready = TRUE;
-			return NULL;
-		}
-		if( (num = to_number(d->d_name)) > 0 && dirent_is_regular_file(d) ) {
-			debug_print("RSSyl: starting to parse '%s'\n", d->d_name);
-			if( (fitem = rssyl_parse_folder_item_file(path, d->d_name)) != NULL ) {
-				debug_print("Appending '%s'\n", fitem->title);
-				ritem->contents = g_slist_prepend(ritem->contents, fitem);
-			}
-		}
-	}
-	closedir(dp);
-	g_free(path);
-
-	ritem->contents = g_slist_reverse(ritem->contents);
-
-	ctx->ready = TRUE;
-
-	debug_print("RSSyl: rssyl_read_existing_thr() is returning\n");
-	return NULL;
-}
-
-/* rssyl_read_existing()
- *
- * Parse all existing folder items, storing their data in memory. Data is
- * later used for checking for duplicate entries.
- * Of course, actual work is done in a separate thread (if available) in
- * rssyl_read_existing_thr().
- */
-void rssyl_read_existing(RSSylFolderItem *ritem)
-{
-	RSSylParseCtx *ctx = NULL;
-#ifdef USE_PTHREAD
-	pthread_t pt;
-#endif
-
-	g_return_if_fail(ritem != NULL);
-
-	ctx = g_new0(RSSylParseCtx, 1);
-	ctx->ritem = ritem;
-	ctx->ready = FALSE;
-
-#ifdef USE_PTHREAD
-	if( pthread_create(&pt, PTHREAD_CREATE_JOINABLE, rssyl_read_existing_thr,
-				(void *)ctx) != 0 ) {
-		/* Couldn't create thread, continue nonthreaded */
-		rssyl_read_existing_thr(ctx);
-	} else {
-		debug_print("RSSyl: waiting for read_existing thread to finish\n");
-		while( !ctx->ready ) {
-			claws_do_idle();
-		}
-
-		debug_print("RSSyl: read_existing thread finished\n");
-		pthread_join(pt, NULL);
-	}
-#else
-	debug_print("RSSyl: pthreads not available, running read_existing non-threaded\n");
-	rssyl_read_existing_thr(ctx);
-#endif
-
-	g_free(ctx);
-}
-
-/* rssyl_cb_feed_compare()
- *
- * Callback compare function called by glib2's g_slist_find_custom().
- */
-static gint rssyl_cb_feed_compare(const RSSylFeedItem *a,
-		const RSSylFeedItem *b)
-{
-	gboolean date_publ_eq = FALSE, date_eq = FALSE;
-	gboolean link_eq = FALSE, title_eq = FALSE;
-	gboolean no_link = FALSE, no_title = FALSE;
-	gchar *atit = NULL, *btit = NULL;
-
-	if( a == NULL || b == NULL )
-		return 1;
-
-	/* ID should be unique. If it matches, we've found what we came for. */
-	if( (a->id != NULL) && (b->id != NULL) ) {
-		if( strcmp(a->id, b->id) == 0 )
-			return 0;
-
-		/* If both IDs are present, but they do not match, we need
-		 * to look elsewhere. */
-		return 1;
-	}
-
-	/* Ok, we have no ID to aid us. Let's have a look at item timestamps,
-	 * item link and title. */
-	if( (a->link != NULL) && (b->link != NULL) ) {
-		if( strcmp(a->link, b->link) == 0 )
-			link_eq = TRUE;
-	} else
-		no_link = TRUE;
-
-	if( (a->title != NULL) && (b->title != NULL) ) {
-		atit = conv_unmime_header(a->title, CS_UTF_8, FALSE);
-		btit = conv_unmime_header(b->title, CS_UTF_8, FALSE);
-		if( strcmp(atit, btit) == 0 )
-			title_eq = TRUE;
-		g_free(atit);
-		g_free(btit);
-	} else
-		no_title = TRUE;
-
-	/* If there's no 'published' timestamp for the item, we can only judge
-	 * by item link and title - 'modified' timestamp can have changed if the
-	 * item was updated recently. */
-	if( b->date_published <= 0 && b->date <= 0) {
-		if( link_eq && (title_eq || no_title) )
-			return 0;
-	}
-
-	if( ((a->date_published > 0) && (b->date_published > 0) &&
-			(a->date_published == b->date_published)) ) {
-		date_publ_eq = TRUE;
-	}
-
-	if( ((a->date > 0) && (b->date > 0) &&
-			(a->date == b->date)) ) {
-		date_eq = TRUE;
-	}
-
-	/* If 'published' time and item link match, it is reasonable to assume
-	 * it's this item. */
-	if( (link_eq || no_link) && (date_publ_eq || date_eq) )
-		return 0;
-
-	/* Last ditch effort - if everything else is missing, at least titles
-	 * should match. */
-	if( no_link && title_eq )
-		return 0;
-
-	/* We don't know this item. */
-	return 1;
-}
-
-enum {
-	ITEM_UNCHANGED,
-	ITEM_CHANGED_TEXTONLY,
-	ITEM_CHANGED
-};
-
-static gint rssyl_feed_item_changed(RSSylFeedItem *old_item, RSSylFeedItem *new_item)
-{
-	/* if both have title ... */
-	if( old_item->title && new_item->title ) {
-		gchar *old = conv_unmime_header(old_item->title, CS_UTF_8, FALSE);
-		gchar *new = conv_unmime_header(new_item->title, CS_UTF_8, FALSE);
-		if( strcmp(old, new) ) {	/* ... compare "unmimed" titles */
-			g_free(old);
-			g_free(new);
-			debug_print("RSSyl: item titles differ\n");
-			return ITEM_CHANGED;
-		}
-		g_free(old);
-		g_free(new);
-	} else {
-		/* if atleast one has a title, they differ */
-		if( old_item->title || new_item->title ) {
-			debug_print("RSSyl: +/- title\n");
-			return ITEM_CHANGED;
-		}
-	}
-
-	/* if both have author ... */
-	if( old_item->author && new_item->author ) {
-		gchar *old = conv_unmime_header(old_item->author, CS_UTF_8, TRUE);
-		gchar *new = conv_unmime_header(new_item->author, CS_UTF_8, TRUE);
-		if( strcmp(old, new) ) {	/* ... compare "unmimed" authors */
-			g_free(old);
-			g_free(new);
-			debug_print("RSSyl: item authors differ\n");
-			return ITEM_CHANGED;
-		}
-		g_free(old);
-		g_free(new);
-	} else {
-		/* if atleast one has author, they differ */
-		if( old_item->author || new_item->author ) {
-			debug_print("RSSyl: +/- author\n");
-			return ITEM_CHANGED;
-		}
-	}
-
-	/* if both have text ... */
-	if( old_item->text && new_item->text ) {
-		if( strcmp(old_item->text, new_item->text) ) {	/* ... compare texts */
-			debug_print("RSSyl: item texts differ\n");
-			return ITEM_CHANGED_TEXTONLY;
-		}
-	} else {
-		/* if atleast one has some text, they differ */
-		if( old_item->text || new_item->text ) {
-			debug_print("RSSyl: +/- text\n");
-			if ( !old_item->text )
-				debug_print("RSSyl:   old_item has no text\n");
-			else
-				debug_print("RSSyl:   new_item has no text\n");
-			return ITEM_CHANGED_TEXTONLY;
-		}
-	}
-
-	/* they don't seem to differ */
-	return ITEM_UNCHANGED;
-}
-
-/* rssyl_feed_item_exists()
- *
- * Returns 1 if a feed item already exists locally, 2 if there's a changed
- * item with link that already belongs to existing item, 3 if only item's
- * text has changed, 0 if item is new.
- */
-enum {
-	EXISTS_NEW,
-	EXISTS_UNCHANGED,
-	EXISTS_CHANGED,
-	EXISTS_CHANGED_TEXTONLY
-};
-
-static guint rssyl_feed_item_exists(RSSylFolderItem *ritem,
-		RSSylFeedItem *fitem, RSSylFeedItem **oldfitem)
-{
-	gint changed;
-	GSList *item = NULL;
-	RSSylFeedItem *efitem = NULL;
-	g_return_val_if_fail(ritem != NULL, FALSE);
-	g_return_val_if_fail(fitem != NULL, FALSE);
-
-	if( ritem->contents == NULL || g_slist_length(ritem->contents) == 0 )
-		return 0;
-
-	if( (item = g_slist_find_custom(ritem->contents,
-					(gconstpointer)fitem, (GCompareFunc)rssyl_cb_feed_compare)) ) {
-		efitem = (RSSylFeedItem *)item->data;
-		if( (changed = rssyl_feed_item_changed(efitem, fitem)) > EXISTS_NEW ) {
-			*oldfitem = efitem;
-			if (changed == ITEM_CHANGED_TEXTONLY)
-				return EXISTS_CHANGED_TEXTONLY;
-			else
-				return EXISTS_CHANGED;
-		}
-		return EXISTS_UNCHANGED;
-	}
-
-	return EXISTS_NEW;
-}
-
-void rssyl_parse_feed(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent)
-{
-	xmlNodePtr node;
-	gchar *rootnode;
-	MainWindow *mainwin = mainwindow_get_mainwindow();
-	gint count;
-	gchar *msg;
-
-	if (doc == NULL)
-		return;
-
-	rssyl_read_existing(ritem);
-
-	if (claws_is_exiting()) {
-		debug_print("RSSyl: parse_feed bailing out, app is exiting\n");
-		return;
-	}
-
-	node = xmlDocGetRootElement(doc);
-
-	debug_print("RSSyl: XML - root node is '%s'\n", node->name);
-	rootnode = g_ascii_strdown(node->name, -1);
-
-	msg = g_strdup_printf(_("Refreshing feed '%s'..."),
-				ritem->item.name);
-	STATUSBAR_PUSH(mainwin, msg );
-	g_free(msg);
-	GTK_EVENTS_FLUSH();
-
-	folder_item_update_freeze();
-
-	/* we decide what parser to call, depending on what the root node is */
-	if( !strcmp(rootnode, "rss") ) {
-		debug_print("RSSyl: XML - calling rssyl_parse_rss()\n");
-		count = rssyl_parse_rss(doc, ritem, parent);
-	} else if( !strcmp(rootnode, "rdf") ) {
-		debug_print("RSSyl: XML - calling rssyl_parse_rdf()\n");
-		if (ritem->fetch_comments) {
-			log_error(LOG_PROTOCOL, _("RSSyl: Fetching comments is not supported for RDF feeds. "
-				    "Cannot fetch comments of '%s'"), ritem->item.name);
-			ritem->fetch_comments = FALSE;
-		}
-		count = rssyl_parse_rdf(doc, ritem, parent);
-	} else if( !strcmp(rootnode, "feed") ) {
-		debug_print("RSSyl: XML - calling rssyl_parse_atom()\n");
-		count = rssyl_parse_atom(doc, ritem, parent);
-	} else {
-		alertpanel_error(_("This feed format is not supported yet."));
-		count = 0;
-	}
-
-	if (!parent)
-		ritem->last_count = count;
-
-	folder_item_scan(&ritem->item);
-	folder_item_update_thaw();
-
-	STATUSBAR_POP(mainwin);
-
-	g_free(rootnode);
-}
-
-gboolean rssyl_add_feed_item(RSSylFolderItem *ritem, RSSylFeedItem *fitem)
-{
-	MsgFlags *flags;
-	gchar *template, *tmpurl, *tmpid;
-	gchar tmp[10240];
-	gint d = -1, fd, dif = 0;
-	FILE *f;
-	RSSylFeedItem *oldfitem = NULL;
-	gchar *meta_charset = NULL, *url_html = NULL;
-	gboolean err = FALSE;
-
-	g_return_val_if_fail(ritem != NULL, FALSE);
-	g_return_val_if_fail(ritem->item.path != NULL, FALSE);
-	g_return_val_if_fail(fitem != NULL, FALSE);
-
-	if( !fitem->author )
-		fitem->author = g_strdup(_("N/A"));
-
-	/* Skip if the item already exists */
-	dif = rssyl_feed_item_exists(ritem, fitem, &oldfitem);
-	if( dif == 1 ) {
-		debug_print("RSSyl: This item already exists, skipping...\n");
-		return FALSE;
-	}
-	if( dif >= 2 && oldfitem != NULL ) {
-		debug_print("RSSyl: Item changed, removing old one and adding new...\n");
-		ritem->contents = g_slist_remove(ritem->contents, oldfitem);
-		g_remove(oldfitem->realpath);
-		rssyl_free_feeditem(oldfitem);
-		oldfitem = NULL;
-	}
-
-	/* Adjust some fields */
-	if( fitem->date <= 0 )
-		fitem->date = time(NULL);
-
-	debug_print("RSSyl: Adding item '%s' (%d)\n", fitem->title, dif);
-
-	ritem->contents = g_slist_append(ritem->contents, fitem);
-
-	flags = g_new(MsgFlags, 1);
-#ifndef G_OS_WIN32
-	template = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
-			G_DIR_SEPARATOR_S, RSSYL_TMP_TEMPLATE, NULL);
-	fd = mkstemp(template);
-#else
-	template = get_tmp_file();
-	fd = open(template, (O_CREAT|O_RDWR|O_BINARY), (S_IRUSR|S_IWUSR));
-#endif
-
-	f = fdopen(fd, "w");
-	g_return_val_if_fail(f != NULL, FALSE);
-
-	if( fitem->date != 0 ) {
-		gchar *tmpdate = createRFC822Date(&fitem->date);
-		err |= (fprintf(f, "Date: %s\n", tmpdate ) < 0);
-		g_free(tmpdate);
-	}
-
-	if( fitem->author ) {
-		if (g_utf8_validate(fitem->author, -1, NULL)) {
-			conv_encode_header_full(tmp, 10239, fitem->author, 
-				strlen("From: "), TRUE, CS_UTF_8);
-			err |= (fprintf(f, "From: %s\n", tmp) < 0);
-		} else
-			err |= (fprintf(f, "From: %s\n", fitem->author) < 0);
-	} 
-
-	if( fitem->title ) {
-		if (g_utf8_validate(fitem->title, -1, NULL)) {
-			conv_encode_header_full(tmp, 10239, fitem->title, 
-				strlen("Subject: "), FALSE, CS_UTF_8);
-			err |= (fprintf(f, "Subject: %s\n", tmp) < 0);
-		} else
-			err |= (fprintf(f, "Subject: %s\n", fitem->title) < 0);
-	}
-
-	if( (tmpurl = fitem->link) == NULL ) {
-		if( fitem->id != NULL && fitem->id_is_permalink )
-			tmpurl = fitem->id;
-	}
-	if( tmpurl != NULL )
-		err |= (fprintf(f, "X-RSSyl-URL: %s\n", tmpurl) < 0);
-
-	if( (tmpid = fitem->id) == NULL )
-		tmpid = fitem->link;
-	if( tmpid != NULL )
-		err |= (fprintf(f, "Message-ID: <%s>\n", tmpid) < 0);
-
-	if( fitem->comments_link ) {
-		err |= (fprintf(f, "X-RSSyl-Comments: %s\n", fitem->comments_link) < 0);
-	}
-	if( fitem->parent_link) {
-		err |= (fprintf(f, "X-RSSyl-Parent: %s\n", fitem->parent_link) < 0);
-		err |= (fprintf(f, "References: <%s>\n", fitem->parent_link) < 0);
-	}
-
-#ifdef RSSYL_DEBUG
-	if( fitem->debug_fetched != -1 ) {
-		err |= (fprintf(f, "X-RSSyl-Debug-Fetched: %ld\n", fitem->debug_fetched) < 0);
-	}
-#endif	/* RSSYL_DEBUG */
-
-	if (fitem->text && g_utf8_validate(fitem->text, -1, NULL)) {
-		/* if it passes UTF-8 validation, specify it. */
-		err |= (fprintf(f, "Content-Type: text/html; charset=UTF-8\n\n") < 0);
-		meta_charset = g_strdup("<meta http-equiv=\"Content-Type\" "
-			       "content=\"text/html; charset=UTF-8\">");
-	} else {
-		/* make sure Claws Mail displays it as html */
-		err |= (fprintf(f, "Content-Type: text/html\n\n") < 0);
-	}
-
-	if( tmpurl )
-		url_html = g_strdup_printf("<p>URL: <a href=\"%s\">%s</a></p>\n<br>\n",
-				tmpurl, tmpurl);
-
-	err |= (fprintf(f, "<html><head>"
-			"%s\n"
-			"<base href=\"%s\">\n"
-			"</head><body>\n"
-			"%s"
-			RSSYL_TEXT_START"\n"
-			"%s%s"
-			RSSYL_TEXT_END"\n\n",
-
-			meta_charset ? meta_charset:"",
-			fitem->link,
-			url_html?url_html:"",
-			(fitem->text ? fitem->text : ""),
-			(fitem->text ? "\n" : "") ) < 0 );
-
-	g_free(meta_charset);
-	g_free(url_html);	
-	if( fitem->media ) {
-		if( fitem->media->size > 0 ) {
-			tmpid = g_strdup_printf(ngettext("%ld byte", "%ld bytes",
-						fitem->media->size), fitem->media->size);
-		} else {
-			tmpid = g_strdup(_("size unknown"));
-		}
-
-		fprintf(f, "<p><a href=\"%s\">Attached media file</a> [%s] (%s)</p>\n",
-				fitem->media->url, fitem->media->type, tmpid);
-		
-		g_free(tmpid);
-	}
-
-	if( fitem->media )
-		err |= (fprintf(f,
-					"<p><a href=\"%s\">Attached media file</a> [%s] (%ld bytes)</p>\n",
-				fitem->media->url, fitem->media->type, fitem->media->size) < 0);
-
-	err |= (fprintf(f, "</body></html>\n") < 0);
-
-	err |= (fclose(f) == EOF);
-
-	if (!err) {
-		g_return_val_if_fail(template != NULL, FALSE);
-		d = folder_item_add_msg(&ritem->item, template, flags, TRUE);
-	}
-	g_free(template);
-
-	if (ritem->silent_update == 2
-			|| (ritem->silent_update == 1 && dif == EXISTS_CHANGED_TEXTONLY))
-		procmsg_msginfo_unset_flags(
-				folder_item_get_msginfo((FolderItem *)ritem, d), MSG_NEW | MSG_UNREAD, 0);
-	else
-	
-	debug_print("RSSyl: folder_item_add_msg(): %d, err %d\n", d, err);
-
-	return err ? FALSE:TRUE;
-}
-
-MsgInfo *rssyl_parse_feed_item_to_msginfo(gchar *file, MsgFlags flags,
-		gboolean a, gboolean b, FolderItem *item)
-{
-	MsgInfo *msginfo;
-
-	g_return_val_if_fail(item != NULL, NULL);
-
-	msginfo = procheader_parse_file(file, flags, a, b);
-	if (msginfo)
-		msginfo->folder = item;
-
-	return msginfo;
-}
-
-void rssyl_remove_feed_cache(FolderItem *item)
-{
-	gchar *path;
-	DIR *dp;
-	struct dirent *d;
-	gint num = 0;
-
-	g_return_if_fail(item != NULL);
-
-	debug_print("Removing local cache for '%s'\n", item->name);
-
-	path = folder_item_get_path(item);
-	g_return_if_fail(path != NULL);
-	if( change_dir(path) < 0 ) {
-		g_free(path);
-		return;
-	}
-
-	debug_print("Emptying '%s'\n", path);
-
-	if( (dp = opendir(".")) == NULL ) {
-		FILE_OP_ERROR(item->path, "opendir");
-		return;
-	}
-
-	while( (d = readdir(dp)) != NULL ) {
-		g_remove(d->d_name);
-		num++;
-	}
-	closedir(dp);
-
-	debug_print("Removed %d files\n", num);
-
-	g_remove(path);
-	g_free(path);
-}
-
-void rssyl_update_comments(RSSylFolderItem *ritem)
-{
-	FolderItem *item = &ritem->item;
-	RSSylFeedItem *fitem = NULL;
-	DIR *dp;
-	struct dirent *d;
-	gint num;
-	gchar *path;
-
-	g_return_if_fail(ritem != NULL);
-
-	if (ritem->fetch_comments == FALSE)
-		return;
-
-	path = folder_item_get_path(item);
-	g_return_if_fail(path != NULL);
-	if( change_dir(path) < 0 ) {
-		g_free(path);
-		return;
-	}
-
-	if( (dp = opendir(".")) == NULL ) {
-		FILE_OP_ERROR(item->path, "opendir");
-		g_free(path);
-		return;
-	}
-
-	while( (d = readdir(dp)) != NULL ) {
-		if (claws_is_exiting()) {
-			g_free(path);
-			closedir(dp);
-			debug_print("RSSyl: update_comments bailing out, app is exiting\n");
-			return;
-		}
-
-		if( (num = to_number(d->d_name)) > 0 && dirent_is_regular_file(d) ) {
-			debug_print("RSSyl: starting to parse '%s'\n", d->d_name);
-			if( (fitem = rssyl_parse_folder_item_file(path, d->d_name)) != NULL ) {
-				xmlDocPtr doc;
-				gchar *title;
-				if (fitem->comments_link && fitem->id && 
-				    (ritem->fetch_comments_for == -1 ||
-				     time(NULL) - fitem->date <= ritem->fetch_comments_for*86400)) {
-					debug_print("RSSyl: fetching comments '%s'\n", fitem->comments_link);
-					doc = rssyl_fetch_feed(fitem->comments_link, ritem->item.mtime, 
-							ritem->ssl_verify_peer, &title, NULL);
-					rssyl_parse_feed(doc, ritem, fitem->id);
-					xmlFreeDoc(doc);
-					g_free(title);
-				}
-				rssyl_free_feeditem(fitem);
-			}
-		}
-	}
-	closedir(dp);
-	g_free(path);
-
-	debug_print("RSSyl: rssyl_update_comments() is returning\n");
-}
-
-void rssyl_update_feed(RSSylFolderItem *ritem)
-{
-	gchar *title = NULL, *dir = NULL, *error = NULL, *dir2, *tmp;
-	xmlDocPtr doc = NULL;
-
-	g_return_if_fail(ritem != NULL);
-
-	if( !ritem->url )
-		rssyl_get_feed_props(ritem);
-	g_return_if_fail(ritem->url != NULL);
-
-	log_print(LOG_PROTOCOL, RSSYL_LOG_UPDATING, ritem->url);
-
-	doc = rssyl_fetch_feed(ritem->url, ritem->item.mtime, ritem->ssl_verify_peer, &title, &error);
-
-	if (claws_is_exiting()) {
-		debug_print("RSSyl: Claws-Mail is exiting, aborting feed parsing\n");
-		log_print(LOG_PROTOCOL, RSSYL_LOG_EXITING);
-		if (error)
-			g_free(error);
-		if (doc)
-			xmlFreeDoc(doc);
-		g_free(title);
-		g_free(dir);
-		return;
-	}
-
-	if (error) {
-		log_error(LOG_PROTOCOL, _("RSSyl: Cannot update feed %s:\n%s\n"), ritem->url, error);
-	}
-	g_free(error);
-
-	if (doc && title) {
-		tmp = rssyl_feed_title_to_dir(title);
-		dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
-				G_DIR_SEPARATOR_S, tmp, NULL);
-		g_free(tmp);
-		if( strcmp(title, ritem->official_name) ) {
-			tmp = rssyl_feed_title_to_dir((&ritem->item)->name);
-			dir2 = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
-					G_DIR_SEPARATOR_S, tmp,
-					NULL);
-			g_free(tmp);
-			if( g_rename(dir2, dir) == -1 ) {
-				g_warning("couldn't rename directory '%s'\n", dir2);
-				g_free(dir);
-				g_free(dir2);
-				g_free(title);
-				xmlFreeDoc(doc);
-				return;
-			}
-			g_free(dir2);
-
-			rssyl_props_update_name(ritem, title);
-
-			g_free((&ritem->item)->name);
-			(&ritem->item)->name = g_strdup(title);
-			g_free(ritem->official_name);
-			ritem->official_name = g_strdup(title);
-			folder_item_rename(&ritem->item, title);
-			rssyl_store_feed_props(ritem);
-		} 
-
-		rssyl_parse_feed(doc, ritem, NULL);
-
-		if (claws_is_exiting()) {
-			debug_print("RSSyl: Claws-Mail is exiting, aborting feed parsing\n");
-			log_print(LOG_PROTOCOL, RSSYL_LOG_EXITING);
-			if (error)
-				g_free(error);
-			if (doc)
-				xmlFreeDoc(doc);
-			g_free(title);
-			g_free(dir);
-			return;
-		}
-
-		rssyl_expire_items(ritem);
-	}
-
-	if (claws_is_exiting()) {
-		g_free(title);
-		g_free(dir);
-		if (doc)
-			xmlFreeDoc(doc);
-		return;
-	}
-
-	if( ritem->fetch_comments == TRUE)
-		rssyl_update_comments(ritem);
-
-	ritem->item.mtime = time(NULL);
-	debug_print("setting %s mtime to %ld\n", ritem->item.name, (long int)time(NULL));
-
-	if (doc)
-		xmlFreeDoc(doc);
-	g_free(title);
-	g_free(dir);
-
-	log_print(LOG_PROTOCOL, RSSYL_LOG_UPDATED, ritem->url);
-}
-
-void rssyl_start_refresh_timeout(RSSylFolderItem *ritem)
-{
-	RSSylRefreshCtx *ctx;
-	guint source_id;
-	RSSylPrefs *rsprefs = NULL;
-
-	g_return_if_fail(ritem != NULL);
-
-	if( ritem->default_refresh_interval ) {
-		rsprefs = rssyl_prefs_get();
-		ritem->refresh_interval = rsprefs->refresh;
-	}
-
-	/* Do not start refreshing if the interval is set to 0 */
-	if( ritem->refresh_interval == 0 )
-		return;
-
-	ctx = g_new0(RSSylRefreshCtx, 1);
-	ctx->ritem = ritem;
-
-	source_id = g_timeout_add(ritem->refresh_interval * 60 * 1000,
-			(GSourceFunc)rssyl_refresh_timeout_cb, ctx );
-	ritem->refresh_id = source_id;
-	ctx->id = source_id;
-
-	debug_print("RSSyl: start_refresh_timeout - %d min (id %d)\n",
-			ritem->refresh_interval, ctx->id);
-}
-
-static void rssyl_find_feed_by_url_func(FolderItem *item, gpointer data)
-{
-	RSSylFolderItem *ritem;
-	RSSylFindByUrlCtx *ctx = (RSSylFindByUrlCtx *)data;
-
-	/* If we've already found a feed with desired URL, don't do anything */
-	if( ctx->ritem != NULL )
-		return;
-
-	/* Only check rssyl folders */
-	if( !IS_RSSYL_FOLDER_ITEM(item) )
-		return;
-
-	/* Don't bother with the root folder */
-	if( folder_item_parent(item) == NULL )
-		return;
-
-	ritem = (RSSylFolderItem *)item;
-
-	if( ritem->url && ctx->url && !strcmp(ritem->url, ctx->url) )
-		ctx->ritem = ritem;
-}
-
-static RSSylFolderItem *rssyl_find_feed_by_url(gchar *url)
-{
-	RSSylFindByUrlCtx *ctx = NULL;
-	RSSylFolderItem *ritem = NULL;
-
-	g_return_val_if_fail(url != NULL, NULL);
-
-	ctx = g_new0(RSSylFindByUrlCtx, 1);
-	ctx->url = url;
-	ctx->ritem = NULL;
-
-	folder_func_to_all_folders(
-			(FolderItemFunc)rssyl_find_feed_by_url_func, ctx);
-
-	if( ctx->ritem != NULL )
-		ritem = ctx->ritem;
-
-	g_free(ctx);
-
-	return ritem;
-}
-
-FolderItem *rssyl_subscribe_new_feed(FolderItem *parent, const gchar *url, 
-				  gboolean verbose)
-{
-	gchar *title = NULL;
-	xmlDocPtr doc;
-	FolderItem *new_item;
-	RSSylFolderItem *ritem;
-	gchar *myurl = NULL;
-	gchar *error = NULL;
-
-	g_return_val_if_fail(parent != NULL, NULL);
-	g_return_val_if_fail(url != NULL, NULL);
-
-	if (!strncmp(url, "feed://", 7))
-		myurl = g_strdup(url+7);
-	else if (!strncmp(url, "feed:", 5))
-		myurl = g_strdup(url+5);
-	else
-		myurl = g_strdup(url);
-
-	myurl = g_strchomp(myurl);
-
-	if( rssyl_find_feed_by_url(myurl) != NULL ) {
-		if (verbose)
-			alertpanel_error(_("You are already subscribed to this feed."));
-		g_free(myurl);
-		return NULL;
-	}
-	
-	main_window_cursor_wait(mainwindow_get_mainwindow());
-	doc = rssyl_fetch_feed(myurl, -1, rssyl_prefs_get()->ssl_verify_peer, &title, &error);
-	main_window_cursor_normal(mainwindow_get_mainwindow());
-	if( !doc || !title ) {
-		if (verbose) {
-			gchar *tmp;
-			tmp = g_markup_printf_escaped(_("Couldn't fetch URL '%s':\n%s"),
-						myurl, error ? error:_("Unknown error"));
-			alertpanel_error("%s", tmp);
-			g_free(tmp);
-		} else
-			log_error(LOG_PROTOCOL, _("Couldn't fetch URL '%s':\n%s\n"), myurl, error ? error:_("Unknown error"));
-		g_free(myurl);
-		g_free(error);
-		g_free(title);
-		if (doc)
-			xmlFreeDoc(doc);
-		return NULL;
-	}
-
-	g_free(error);
-
-	new_item = folder_create_folder(parent, title);
-	if( !new_item ) {
-		if (verbose) {
-			gchar *tmp;
-			tmp = g_markup_printf_escaped("%s", title);
-			alertpanel_error(_("Can't subscribe feed '%s'."), title);
-			g_free(tmp);
-		}
-		g_free(myurl);
-		xmlFreeDoc(doc);
-		return NULL;
-	}
-
-	ritem = (RSSylFolderItem *)new_item;
-	ritem->url = myurl;
-	
-	ritem->default_refresh_interval = TRUE;
-	ritem->default_expired_num = TRUE;
-
-	rssyl_store_feed_props(ritem);
-
-	folder_write_list();
-
-	rssyl_parse_feed(doc, ritem, NULL);
-	xmlFreeDoc(doc);
-
-	rssyl_expire_items(ritem);
-
-	/* TODO: allow user to enable this when adding the feed */
-	if( ritem->fetch_comments )
-		rssyl_update_comments(ritem);
-
-	/* update official_title */
-	rssyl_store_feed_props(ritem);
-	rssyl_start_refresh_timeout(ritem);
-
-	folder_item_scan(new_item);
-	return new_item;
-}
-
-static gint rssyl_expire_sort_func(RSSylFeedItem *a, RSSylFeedItem *b)
-{
-	if( !a || !b )
-		return 0;
-
-	return (b->date - a->date);
-}
-
-void rssyl_expire_items(RSSylFolderItem *ritem)
-{
-	int num;
-	RSSylFeedItem *fitem;
-	GSList *i;
-
-	g_return_if_fail(ritem != NULL);
-
-	rssyl_read_existing(ritem);
-
-	g_return_if_fail(ritem->contents != NULL);
-
-	num = ritem->expired_num;
-	if( num == -1 ||
-			(num > (g_slist_length(ritem->contents) - ritem->last_count)) )
-		return;
-
-	debug_print("RSSyl: rssyl_expire_items()\n");
-
-	ritem->contents = g_slist_sort(ritem->contents,
-			(GCompareFunc)rssyl_expire_sort_func);
-
-	debug_print("RSSyl: finished sorting\n");
-
-	while( (i = g_slist_nth(ritem->contents, ritem->last_count + num + 1)) ) {
-		fitem = (RSSylFeedItem *)i->data;
-		debug_print("RSSyl: expiring '%s'\n", fitem->realpath);
-		g_remove(fitem->realpath);
-		rssyl_free_feeditem(fitem);
-		fitem = NULL;
-		ritem->contents = g_slist_remove(ritem->contents, i->data);
-	}
-
-	folder_item_scan(&ritem->item);
-
-	debug_print("RSSyl: finished expiring\n");
-}
-
-
-void rssyl_refresh_all_func(FolderItem *item, gpointer data)
-{
-	RSSylFolderItem *ritem = (RSSylFolderItem *)item;
-	/* Only try to refresh our feed folders */
-	if( !IS_RSSYL_FOLDER_ITEM(item) )
-		return;
-
-	/* Don't try to refresh the root folder */
-	if( folder_item_parent(item) == NULL )
-		return;
-	/* Don't try to update normal folders */
-	if (ritem->url == NULL)
-		return;
-	rssyl_update_feed((RSSylFolderItem *)item);
-}
-
-void rssyl_refresh_all_feeds(void)
-{
-	if (prefs_common_get_prefs()->work_offline && 
-	    !inc_offline_should_override(TRUE,
-			ngettext("Claws Mail needs network access in order "
-			    "to update the feed.",
-			    "Claws Mail needs network access in order "
-			    "to update the feeds.", 2))) {
-			return;
-	}
-
-	folder_func_to_all_folders((FolderItemFunc)rssyl_refresh_all_func, NULL);
-}
diff --git a/src/plugins/rssyl/feed.h b/src/plugins/rssyl/feed.h
deleted file mode 100644
index 1d66b7d..0000000
--- a/src/plugins/rssyl/feed.h
+++ /dev/null
@@ -1,94 +0,0 @@
-#ifndef __FEED_H
-#define __FEED_H
-
-#include <libxml/parser.h>
-
-#include "procmsg.h"
-
-#include "rssyl.h"
-
-#define RSSYL_TMP_TEMPLATE	"curltmpXXXXXX"
-
-#define RSSYL_XPATH_ROOT		"/rssyl"
-#define RSSYL_XPATH_TITLE		RSSYL_XPATH_ROOT"/title"
-#define RSSYL_XPATH_LINK		RSSYL_XPATH_ROOT"/link"
-#define RSSYL_XPATH_TEXT		RSSYL_XPATH_ROOT"/text"
-
-#define RSSYL_TEXT_START		"<!-- RSSyl text start -->"
-#define RSSYL_TEXT_END			"<!-- RSSyl text end -->"
-
-#define RSSYL_LOG_ERROR_TIMEOUT		_("Time out connecting to URL %s\n")
-#define RSSYL_LOG_ERROR_FETCH		_("Couldn't fetch URL %s\n")
-#define RSSYL_LOG_ERROR_PARSE		_("Error parsing feed from URL %s\n")
-#define RSSYL_LOG_ERROR_UNKNOWN		_("Unsupported feed type at URL %s\n")
-
-#define RSSYL_LOG_UPDATING		_("RSSyl: Updating feed %s\n")
-#define RSSYL_LOG_UPDATED 		_("RSSyl: Feed update finished: %s\n")
-#define RSSYL_LOG_EXITING			_("RSSyl: Feed update aborted, application is exiting.\n")
-
-struct _RSSylFeedItemMedia {
-	gchar *url;
-	gchar *type;
-	gulong size;
-};
-
-typedef struct _RSSylFeedItemMedia RSSylFeedItemMedia;
-
-struct _RSSylFeedItem {
-	gchar *title;
-	gchar *text;
-	gchar *link;
-	gchar *parent_link;
-	gchar *comments_link;
-	gchar *author;
-	gchar *id;
-	gboolean id_is_permalink;
-
-	RSSylFeedItemMedia *media;
-
-#ifdef RSSYL_DEBUG
-	long int debug_fetched;
-#endif	/* RSSYL_DEBUG */
-
-	gchar *realpath;
-	time_t date;
-	time_t date_published;
-};
-
-typedef struct _RSSylFeedItem RSSylFeedItem;
-
-struct _RSSylFindByUrlCtx {
-	gchar *url;
-	RSSylFolderItem *ritem;
-};
-
-typedef struct _RSSylFindByUrlCtx RSSylFindByUrlCtx;
-
-struct _RSSylParseCtx {
-	RSSylFolderItem *ritem;
-	gboolean ready;
-};
-
-typedef struct _RSSylParseCtx RSSylParseCtx;
-
-xmlDocPtr rssyl_fetch_feed(const gchar *url, time_t last_update, gboolean ssl_verify_peer, gchar **title, gchar **error);
-void rssyl_parse_feed(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent);
-gboolean rssyl_add_feed_item(RSSylFolderItem *ritem, RSSylFeedItem *fitem);
-MsgInfo *rssyl_parse_feed_item_to_msginfo(gchar *file, MsgFlags flags,
-		gboolean a, gboolean b, FolderItem *item);
-void rssyl_remove_feed_cache(FolderItem *item);
-void rssyl_update_feed(RSSylFolderItem *ritem);
-void rssyl_read_existing(RSSylFolderItem *ritem);
-
-void rssyl_start_refresh_timeout(RSSylFolderItem *ritem);
-void rssyl_expire_items(RSSylFolderItem *ritem);
-
-FolderItem *rssyl_subscribe_new_feed(FolderItem *parent, const gchar *url, gboolean verbose);
-void rssyl_free_feeditem(RSSylFeedItem *item);
-gchar *rssyl_format_string(const gchar *str, gboolean replace_html, gboolean replace_returns);
-
-void rssyl_refresh_all_func(FolderItem *item, gpointer data);
-void rssyl_refresh_all_feeds(void);
-gchar *rssyl_feed_title_to_dir(const gchar *title);
-
-#endif /* __FEED_H */
diff --git a/src/plugins/rssyl/feedprops.c b/src/plugins/rssyl/feedprops.c
deleted file mode 100644
index d52bde5..0000000
--- a/src/plugins/rssyl/feedprops.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2004 Hiroyuki Yamamoto
- * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
- *
- * - functions for handling feeds.xml file
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include <glib.h>
-
-#include <libxml/parser.h>
-#include <libxml/xpath.h>
-
-#include "folder.h"
-
-#include "feed.h"
-#include "feedprops.h"
-#include "rssyl.h"
-#include "rssyl_prefs.h"
-
-static gchar *rssyl_get_props_path(void)
-{
-	return g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
-			G_DIR_SEPARATOR_S, RSSYL_PROPS_FILE, NULL);
-}
-
-
-/* rssyl_store_feed_props()
- *
- * Stores feed properties into feeds.xml file in the rcdir. Updates if already
- * stored for this feed.
- */
-void rssyl_store_feed_props(RSSylFolderItem *ritem)
-{
-	gchar *path;
-	xmlDocPtr doc;
-	xmlNodePtr node, rootnode;
-	xmlXPathObjectPtr result;
-	xmlXPathContextPtr context;
-	FolderItem *item = &ritem->item;
-	gboolean found = FALSE, def_ri, def_ex;
-	gint i;
-
-	g_return_if_fail(ritem != NULL);
-	g_return_if_fail(ritem->url != NULL);
-
-	def_ri = ritem->default_refresh_interval;
-	if( def_ri )
-		ritem->refresh_interval = rssyl_prefs_get()->refresh;
-
-	def_ex = ritem->default_expired_num;
-	if( def_ex )
-		ritem->expired_num = rssyl_prefs_get()->expired;
-
-	path = rssyl_get_props_path();
-
-	if( !(doc = xmlParseFile(path)) ) {
-		debug_print("RSSyl: file %s doesn't exist, creating it\n", path);
-		doc = xmlNewDoc("1.0");
-
-		rootnode = xmlNewNode(NULL, "feeds");
-		xmlDocSetRootElement(doc, rootnode);
-	} else {
-		rootnode = xmlDocGetRootElement(doc);
-	}
-
-	context = xmlXPathNewContext(doc);
-	if( !(result = xmlXPathEvalExpression(RSSYL_PROPS_XPATH, context)) ) {
-		debug_print("RSSyl: XML - no result found for %s\n", RSSYL_PROPS_XPATH);
-		xmlXPathFreeContext(context);
-	} else {
-		for( i = 0; i < result->nodesetval->nodeNr; i++ ) {
-			gchar *tmp, *t_prop = NULL;
-			node = result->nodesetval->nodeTab[i];
-			tmp = xmlGetProp(node, RSSYL_PROP_NAME);
-
-			if( !strcmp(tmp, item->name) ) {
-				debug_print("RSSyl: XML - updating node for '%s'\n", item->name);
-
-				xmlSetProp(node, RSSYL_PROP_NAME, item->name);
-				xmlSetProp(node, RSSYL_PROP_OFFICIAL_NAME, 
-						ritem->official_name?ritem->official_name:item->name);
-				xmlSetProp(node, RSSYL_PROP_URL, ritem->url);
-
-				xmlSetProp(node, RSSYL_PROP_DEF_REFRESH, (def_ri ? "1" : "0") );
-				if( !def_ri ) {
-					t_prop = g_strdup_printf("%d", ritem->refresh_interval);
-					xmlSetProp(node, RSSYL_PROP_REFRESH,
-							t_prop );
-					g_free(t_prop);
-				}
-
-				xmlSetProp(node, RSSYL_PROP_DEF_EXPIRED, (def_ex ? "1" : "0") );
-				if( !def_ex ) {
-					t_prop = g_strdup_printf("%d", ritem->expired_num);
-					xmlSetProp(node, RSSYL_PROP_EXPIRED,
-							t_prop );
-					g_free(t_prop);
-				}
-				xmlSetProp(node, RSSYL_PROP_FETCH_COMMENTS,
-						(ritem->fetch_comments ? "1" : "0"));
-				t_prop = g_strdup_printf("%d", ritem->fetch_comments_for);
-				xmlSetProp(node, RSSYL_PROP_FETCH_COMMENTS_FOR, t_prop);
-				g_free(t_prop);
-
-				t_prop = g_strdup_printf("%d", ritem->silent_update);
-				xmlSetProp(node, RSSYL_PROP_SILENT_UPDATE, t_prop);
-				g_free(t_prop);
-
-				t_prop = g_strdup_printf("%d", ritem->ssl_verify_peer);
-				xmlSetProp(node, RSSYL_PROP_SSL_VERIFY_PEER, t_prop);
-				g_free(t_prop);
-
-				found = TRUE;
-			}
-			xmlFree(tmp);
-		}
-	}
-
-	xmlXPathFreeContext(context);
-	xmlXPathFreeObject(result);
-
-	/* node for our feed doesn't exist, let's make one */
-	if( !found ) {
-		debug_print("RSSyl: XML - creating node for '%s', storing URL '%s'\n",
-				item->name, ritem->url);
-		node = xmlNewTextChild(rootnode, NULL, "feed", NULL);
-		xmlSetProp(node, RSSYL_PROP_NAME, item->name);
-		xmlSetProp(node, RSSYL_PROP_OFFICIAL_NAME, 
-				ritem->official_name?ritem->official_name:item->name);
-		xmlSetProp(node, RSSYL_PROP_URL, ritem->url);
-		xmlSetProp(node, RSSYL_PROP_DEF_REFRESH, (def_ri ? "1" : "0") );
-		if( !def_ri )
-			xmlSetProp(node, RSSYL_PROP_REFRESH,
-					g_strdup_printf("%d", ritem->refresh_interval) );
-		xmlSetProp(node, RSSYL_PROP_DEF_EXPIRED, (def_ex ? "1" : "0") );
-		if( !def_ex )
-			xmlSetProp(node, RSSYL_PROP_EXPIRED,
-					g_strdup_printf("%d", ritem->expired_num) );
-	}
-
-	xmlSaveFormatFile(path, doc, 1);
-	xmlFreeDoc(doc);
-	g_free(path);
-}
-
-/* rssyl_get_feed_props()
- *
- * Retrieves props for feed from feeds.xml file in the rcdir.
- */
-void rssyl_get_feed_props(RSSylFolderItem *ritem)
-{
-	gchar *path, *tmp = NULL;
-	xmlDocPtr doc;
-	xmlNodePtr node;
-	xmlXPathObjectPtr result;
-	xmlXPathContextPtr context;
-	FolderItem *item = &ritem->item;
-	gint i, tmpi;
-	gboolean force_update = FALSE;
-	RSSylPrefs *rsprefs = NULL;
-
-	g_return_if_fail(ritem != NULL);
-
-	if( ritem->url ) {
-		g_free(ritem->url);
-		ritem->url = NULL;
-	}
-
-	ritem->default_refresh_interval = TRUE;
-	ritem->refresh_interval = rssyl_prefs_get()->refresh;
-	ritem->expired_num = rssyl_prefs_get()->expired;
-
-	path = rssyl_get_props_path();
-
-	doc = xmlParseFile(path);
-	g_return_if_fail(doc != NULL);
-
-	context = xmlXPathNewContext(doc);
-	if( !(result = xmlXPathEvalExpression(RSSYL_PROPS_XPATH, context)) ) {
-		debug_print("RSSyl: XML - no result found for %s\n", RSSYL_PROPS_XPATH);
-		xmlXPathFreeContext(context);
-	} else {
-		for( i = 0; i < result->nodesetval->nodeNr; i++ ) {
-			gchar *property = NULL;
-			node = result->nodesetval->nodeTab[i];
-			property = xmlGetProp(node, RSSYL_PROP_NAME);
-			if( !strcmp(property, item->name) ) {
-				/* official name */
-				tmp = xmlGetProp(node, RSSYL_PROP_OFFICIAL_NAME);
-				ritem->official_name = (tmp ? g_strdup(tmp) : g_strdup(item->name));
-				if (tmp == NULL)
-					force_update = TRUE;
-				xmlFree(tmp);
-				tmp = NULL;
-
-				/* URL */
-				tmp = xmlGetProp(node, RSSYL_PROP_URL);
-				ritem->url = (tmp ? g_strdup(tmp) : NULL);
-				xmlFree(tmp);
-				tmp = NULL;
-
-				tmp = xmlGetProp(node, RSSYL_PROP_DEF_REFRESH);
-				tmpi = 0;
-				if( tmp )
-					tmpi = atoi(tmp);
-				ritem->default_refresh_interval = (tmpi ? TRUE : FALSE );
-				xmlFree(tmp);
-				tmp = NULL;
-
-				/* refresh_interval */
-				tmp = xmlGetProp(node, RSSYL_PROP_REFRESH);
-				if( ritem->default_refresh_interval )
-					ritem->refresh_interval = rssyl_prefs_get()->refresh;
-				else {
-					tmpi = -1;
-					if( tmp )
-						tmpi = atoi(tmp);
-
-					ritem->refresh_interval =
-						(tmpi != -1 ? tmpi : rssyl_prefs_get()->refresh);
-				}
-				
-				xmlFree(tmp);
-				tmp = NULL;
-
-				/* expired_num */
-				tmp = xmlGetProp(node, RSSYL_PROP_DEF_EXPIRED);
-				tmpi = 0;
-				if( tmp ) {
-					tmpi = atoi(tmp);
-					ritem->default_expired_num = tmpi;
-				}
-				xmlFree(tmp);
-				tmp = NULL;
-
-				/* fetch_comments */
-				tmp = xmlGetProp(node, RSSYL_PROP_FETCH_COMMENTS);
-				tmpi = 0;
-				if( tmp ) {
-					tmpi = atoi(tmp);
-					ritem->fetch_comments = tmpi;
-				}
-				xmlFree(tmp);
-				tmp = NULL;
-
-				/* fetch_comments_for */
-				tmp = xmlGetProp(node, RSSYL_PROP_FETCH_COMMENTS_FOR);
-				tmpi = 0;
-				if( tmp ) {
-					tmpi = atoi(tmp);
-					ritem->fetch_comments_for = tmpi;
-				}
-				xmlFree(tmp);
-				tmp = NULL;
-
-				/* silent_update */
-				tmp = xmlGetProp(node, RSSYL_PROP_SILENT_UPDATE);
-				tmpi = 0;
-				if( tmp ) {
-					tmpi = atoi(tmp);
-					ritem->silent_update = tmpi;
-				}
-				xmlFree(tmp);
-				tmp = NULL;
-
-				/* ssl_verify_peer */
-				tmp = xmlGetProp(node, RSSYL_PROP_SSL_VERIFY_PEER);
-				tmpi = 0;
-				if( tmp ) {
-					tmpi = atoi(tmp);
-					ritem->ssl_verify_peer = tmpi;
-				}
-				xmlFree(tmp);
-				tmp = NULL;
-
-				tmp = xmlGetProp(node, RSSYL_PROP_EXPIRED);
-
-				if( ritem->default_expired_num )
-					ritem->expired_num = rssyl_prefs_get()->expired;
-				else {
-					tmpi = -2;
-					if( tmp )
-						tmpi = atoi(tmp);
-
-					ritem->expired_num = (tmpi != -2 ? tmpi : rssyl_prefs_get()->expired);
-				}
-
-				xmlFree(tmp);
-				tmp = NULL;
-
-				debug_print("RSSyl: XML - props for '%s' loaded\n", item->name);
-
-				/* Start automatic refresh timer, if necessary */
-				if( ritem->refresh_id == 0 ) {
-					/* Check if user wants the default for this feed */
-					if( ritem->default_refresh_interval ) {
-						rsprefs = rssyl_prefs_get();
-						ritem->refresh_interval = rsprefs->refresh;
-					}
-
-					/* Start the timer, if determined interval is >0 */
-					if( ritem->refresh_interval >= 0 )
-						rssyl_start_refresh_timeout(ritem);
-				}
-			}
-			xmlFree(property);
-		}
-	}
-
-	xmlXPathFreeObject(result);
-	xmlXPathFreeContext(context);
-	xmlFreeDoc(doc);
-	g_free(path);
-	if (force_update)
-		rssyl_store_feed_props(ritem);
-}
-
-void rssyl_remove_feed_props(RSSylFolderItem *ritem)
-{
-	gchar *path;
-	xmlDocPtr doc;
-	xmlNodePtr node;
-	xmlXPathObjectPtr result;
-	xmlXPathContextPtr context;
-	FolderItem *item = &ritem->item;
-	gint i;
-
-	g_return_if_fail(ritem != NULL);
-
-	path = rssyl_get_props_path();
-
-	doc = xmlParseFile(path);
-	g_return_if_fail(doc != NULL);
-
-	context = xmlXPathNewContext(doc);
-	if( !(result = xmlXPathEvalExpression(RSSYL_PROPS_XPATH, context)) ) {
-		debug_print("RSSyl: XML - no result found for %s\n", RSSYL_PROPS_XPATH);
-		xmlXPathFreeContext(context);
-	} else {
-		for( i = 0; i < result->nodesetval->nodeNr; i++ ) {
-			gchar *tmp;
-			node = result->nodesetval->nodeTab[i];
-			tmp = xmlGetProp(node, RSSYL_PROP_NAME);
-			if( !strcmp(tmp, item->name) ) {
-				debug_print("RSSyl: XML - found node for '%s', removing\n", item->name);
-				xmlUnlinkNode(node);
-			}
-			xmlFree(tmp);
-		}
-	}
-
-	xmlXPathFreeObject(result);
-	xmlXPathFreeContext(context);
-
-	xmlSaveFormatFile(path, doc, 1);
-
-	xmlFreeDoc(doc);
-	g_free(path);
-}
-
-void rssyl_props_update_name(RSSylFolderItem *ritem, gchar *new_name)
-{
-	gchar *path;
-	xmlDocPtr doc;
-	xmlNodePtr node, rootnode;
-	xmlXPathObjectPtr result;
-	xmlXPathContextPtr context;
-	FolderItem *item = &ritem->item;
-	gboolean found = FALSE;
-	gint i;
-
-	g_return_if_fail(ritem != NULL);
-	g_return_if_fail(ritem->url != NULL);
-
-	path = rssyl_get_props_path();
-
-	if( !(doc = xmlParseFile(path)) ) {
-		debug_print("RSSyl: file %s doesn't exist, creating it\n", path);
-		doc = xmlNewDoc("1.0");
-
-		rootnode = xmlNewNode(NULL, "feeds");
-		xmlDocSetRootElement(doc, rootnode);
-	} else {
-		rootnode = xmlDocGetRootElement(doc);
-	}
-
-	context = xmlXPathNewContext(doc);
-	if( !(result = xmlXPathEvalExpression(RSSYL_PROPS_XPATH, context)) ) {
-		debug_print("RSSyl: XML - no result found for %s\n", RSSYL_PROPS_XPATH);
-		xmlXPathFreeContext(context);
-	} else {
-		for( i = 0; i < result->nodesetval->nodeNr; i++ ) {
-			gchar *tmp;
-			node = result->nodesetval->nodeTab[i];
-			tmp = xmlGetProp(node, RSSYL_PROP_NAME);
-			if( !strcmp(tmp, item->name) ) {
-				debug_print("RSSyl: XML - updating node for '%s'\n", item->name);
-				xmlSetProp(node, "name", new_name);
-				found = TRUE;
-			}
-			xmlFree(tmp);
-		}
-	}
-
-	xmlXPathFreeContext(context);
-	xmlXPathFreeObject(result);
-
-	if( !found )
-		debug_print("couldn't find feed\n");
-
-	xmlSaveFormatFile(path, doc, 1);
-	xmlFreeDoc(doc);
-	g_free(path);
-}
diff --git a/src/plugins/rssyl/feedprops.h b/src/plugins/rssyl/feedprops.h
deleted file mode 100644
index f4a3b27..0000000
--- a/src/plugins/rssyl/feedprops.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __FEEDPROPS_H
-#define __FEEDPROPS_H
-
-#include "rssyl.h"
-
-#define RSSYL_PROPS_FILE	"feeds.xml"
-#define RSSYL_PROPS_XPATH	"/feeds/feed"
-
-#define RSSYL_PROP_URL					"url"
-#define RSSYL_PROP_NAME					"name"
-#define RSSYL_PROP_OFFICIAL_NAME			"official_name"
-#define RSSYL_PROP_DEF_REFRESH	"default_refresh_interval"
-#define RSSYL_PROP_REFRESH			"refresh_interval"
-#define RSSYL_PROP_DEF_EXPIRED	"default_expired_num"
-#define RSSYL_PROP_EXPIRED			"expired_num"
-#define RSSYL_PROP_FETCH_COMMENTS		"fetch_comments"
-#define RSSYL_PROP_FETCH_COMMENTS_FOR		"fetch_comments_for"
-#define RSSYL_PROP_SILENT_UPDATE "silent_update"
-#define RSSYL_PROP_SSL_VERIFY_PEER "ssl_verify_peer"
-
-void rssyl_store_feed_props(RSSylFolderItem *ritem);
-void rssyl_get_feed_props(RSSylFolderItem *ritem);
-void rssyl_remove_feed_props(RSSylFolderItem *ritem);
-void rssyl_props_update_name(RSSylFolderItem *ritem, gchar *new_name);
-
-#endif /* __FEEDPROPS_H */
diff --git a/src/plugins/rssyl/libfeed/Makefile.am b/src/plugins/rssyl/libfeed/Makefile.am
new file mode 100644
index 0000000..227b25e
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/Makefile.am
@@ -0,0 +1,22 @@
+noinst_LTLIBRARIES = libfeed.la
+
+INCLUDES = \
+	-I$(top_srcdir)/src \
+	-I.
+
+libfeed_la_CPPFLAGS = \
+	-Wall \
+	$(CLAWS_MAIL_CFLAGS) \
+	$(GLIB_CFLAGS) \
+	$(GTK_CFLAGS)
+
+libfeed_la_SOURCES = \
+	date.c date.h \
+	feed.c feed.h \
+	feeditem.c feeditem.h \
+	feeditemenclosure.c feeditemenclosure.h \
+	parser.c parser.h \
+	parser_atom10.c parser_atom10.h \
+	parser_opml.c parser_opml.h \
+	parser_rdf.c parser_rdf.h \
+	parser_rss20.c parser_rss20.h
diff --git a/src/plugins/rssyl/date.c b/src/plugins/rssyl/libfeed/date.c
similarity index 76%
rename from src/plugins/rssyl/date.c
rename to src/plugins/rssyl/libfeed/date.c
index 4145f52..2b8ffff 100644
--- a/src/plugins/rssyl/date.c
+++ b/src/plugins/rssyl/libfeed/date.c
@@ -33,15 +33,7 @@
 #endif
 
 /* this is needed for strptime() */
-#if !defined (__FreeBSD__)
-#define _XOPEN_SOURCE 600 /* glibc2 needs this */
-#else
-#define _XOPEN_SOURCE
-#endif
-
-#ifdef USE_PTHREAD
-#include <pthread.h>
-#endif
+#define _XOPEN_SOURCE /* glibc2 needs this */
 
 #include <time.h>
 #include <glib.h>
@@ -50,46 +42,17 @@
 #include <ctype.h>
 #include <stdlib.h>
 
-#include "procheader.h"
-
 /* converts a ISO 8601 time string to a time_t value */
 time_t parseISO8601Date(gchar *date) {
 	struct tm	tm;
 	time_t		t, t2, offset = 0;
 	gboolean	success = FALSE;
-#ifdef G_OS_WIN32
-	gchar *tmp = g_strdup(date);
-	gint result, year, month, day, hour, minute, second;
-#else
 	gchar *pos;
-#endif	
+	
 	g_assert(date != NULL);
 	
 	memset(&tm, 0, sizeof(struct tm));
 	
-#ifdef G_OS_WIN32
-	g_strstrip(tmp);
-	result = sscanf((const char *)date, "%d-%d-%dT%d:%d:%d", 
-			&year, &month, &day, &hour, &minute, &second);
-	if (result < 6)
-		second = 0;
-	if (result < 5)
-		minute = 0;
-	if (result < 4)
-		hour = 0;
-	if (result >= 3) {
-		tm.tm_sec = second;
-		tm.tm_min = minute;
-		tm.tm_hour = hour;
-		tm.tm_mday = day;
-		tm.tm_mon = month - 1;
-		tm.tm_year = year - 1900;
-		tm.tm_wday = 0;
-		tm.tm_yday = 0;
-		tm.tm_isdst = -1;
-		success = TRUE;
-	}
-#else
 	/* we expect at least something like "2003-08-07T15:28:19" and
 	   don't require the second fractions and the timezone info
 
@@ -97,7 +60,7 @@ time_t parseISO8601Date(gchar *date) {
 	 */
 	 
 	/* full specified variant */
-	if(NULL != (pos = strptime((const char *)date, "%t%Y-%m-%dT%H:%M%t", &tm))) {
+	if(NULL != (pos = strptime((const char *)date, "%Y-%m-%dT%H:%M:%SZ", &tm))) {
 		/* Parse seconds */
 		if (*pos == ':')
 			pos++;
@@ -127,13 +90,12 @@ time_t parseISO8601Date(gchar *date) {
 	} else if(NULL != strptime((const char *)date, "%t%Y-%m-%d", &tm))
 		success = TRUE;
 	/* there were others combinations too... */
-#endif
+
 	if(TRUE == success) {
 		if((time_t)(-1) != (t = mktime(&tm))) {
-			struct tm buft;
 			/* Correct for the local timezone*/
 			t = t - offset;
-			t2 = mktime(gmtime_r(&t, &buft));
+			t2 = mktime(gmtime(&t));
 			t = t - (t2 - t);
 			
 			return t;
@@ -152,16 +114,34 @@ gchar *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"
 
 gchar *createRFC822Date(const time_t *time) {
 	struct tm *tm;
-	struct tm buft;
-#ifdef G_OS_WIN32
-	if (*time < 0) {
-		time_t t = 1;
-		tm = gmtime_r(&t, &buft);
-	} else 
-#endif
-	{
-		tm = gmtime_r(time, &buft); /* No need to free because it is statically allocated */
-	}
+
+	tm = gmtime(time); /* No need to free because it is statically allocated */
 	return g_strdup_printf("%s, %2d %s %4d %02d:%02d:%02d GMT", dayofweek[tm->tm_wday], tm->tm_mday,
 					   months[tm->tm_mon], 1900 + tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec);
 }
+
+time_t parseRFC822Date(gchar *date)
+{
+	struct tm t;
+	memset(&t, 0, sizeof(struct tm));
+	const char *c = setlocale(LC_TIME, NULL);
+
+	/* Adjust the LC_TIME locale to standard C in order for strptime()
+	 * to work reliably. */
+	if (c != NULL)
+		setlocale(LC_TIME, "C");
+
+	if (!strptime(date, "%a, %d %b %Y %H:%M:%S %Z", &t) &&
+		!strptime(date, "%a, %d %b %Y %H:%M %Z", &t)) {
+		g_warning("Invalid RFC822 date!\n");
+		if (c != NULL)
+			setlocale(LC_TIME, c);
+		return 0;
+	}
+
+	/* Restore the original LC_TIME locale. */
+	if (c != NULL)
+		setlocale(LC_TIME, c);
+
+	return mktime(&t);
+}
diff --git a/src/plugins/rssyl/date.h b/src/plugins/rssyl/libfeed/date.h
similarity index 82%
rename from src/plugins/rssyl/date.h
rename to src/plugins/rssyl/libfeed/date.h
index 27c1353..c8ea1a6 100644
--- a/src/plugins/rssyl/date.h
+++ b/src/plugins/rssyl/libfeed/date.h
@@ -6,5 +6,6 @@
 
 time_t parseISO8601Date(gchar *date);
 gchar *createRFC822Date(const time_t *time);
+time_t parseRFC822Date(gchar *date);
 
 #endif /* __DATE_H */
diff --git a/src/plugins/rssyl/libfeed/feed.c b/src/plugins/rssyl/libfeed/feed.c
new file mode 100644
index 0000000..7719278
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/feed.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#define __USE_GNU
+
+#include <stdlib.h>
+#include <glib.h>
+#include <curl/curl.h>
+#include <expat.h>
+
+#include "feed.h"
+#include "parser.h"
+
+/* feed_new()
+ * Initializes new Feed struct, setting its url and a default timeout. */
+Feed *feed_new(gchar *url)
+{
+	Feed *feed = NULL;
+
+	g_return_val_if_fail(url != NULL, NULL);
+
+	feed = malloc( sizeof(Feed) );
+	g_return_val_if_fail(feed != NULL, NULL);
+
+	feed->timeout = FEED_DEFAULT_TIMEOUT;
+	feed->url = g_strdup(url);
+	feed->title = NULL;
+	feed->description = NULL;
+	feed->language = NULL;
+	feed->author = NULL;
+	feed->generator = NULL;
+	feed->items = NULL;
+
+	feed->fetcherr = NULL;
+	feed->cookies_path = NULL;
+
+	return feed;
+}
+
+static void _free_items(gpointer item, gpointer nada)
+{
+	feed_item_free(item);
+}
+
+void feed_free(Feed *feed)
+{
+	if( feed == NULL )
+		return;	/* Return silently, without printing a glib error. */
+
+	g_free(feed->url);
+	g_free(feed->title);
+	g_free(feed->description);
+	g_free(feed->language);
+	g_free(feed->author);
+	g_free(feed->generator);
+	g_free(feed->fetcherr);
+	g_free(feed->cookies_path);
+
+	if( feed->items != NULL ) {
+		g_slist_foreach(feed->items, _free_items, NULL);
+		g_slist_free(feed->items);
+	}
+
+	g_free(feed);
+	feed = NULL;
+}
+
+void feed_free_items(Feed *feed)
+{
+	if( feed == NULL )
+		return;
+
+	if( feed->items != NULL ) {
+		g_slist_foreach(feed->items, _free_items, NULL);
+		g_slist_free(feed->items);
+		feed->items = NULL;
+	}
+}
+
+/* Timeout */
+void feed_set_timeout(Feed *feed, guint timeout)
+{
+	g_return_if_fail(feed != NULL);
+	feed->timeout = timeout;
+}
+
+guint feed_get_timeout(Feed *feed)
+{
+	g_return_val_if_fail(feed != NULL, 0);
+	return feed->timeout;
+}
+
+/* URL */
+void feed_set_url(Feed *feed, gchar *url)
+{
+	g_return_if_fail(feed != NULL);
+	g_return_if_fail(url != NULL);
+
+	if( feed->url != NULL ) {
+		g_free(feed->url);
+		feed->url = NULL;
+	}
+
+	feed->url = g_strdup(url);
+}
+
+gchar *feed_get_url(Feed *feed)
+{
+	g_return_val_if_fail(feed != NULL, NULL);
+	return feed->url;
+}
+
+/* Title */
+gchar *feed_get_title(Feed *feed)
+{
+	g_return_val_if_fail(feed != NULL, NULL);
+	return feed->title;
+}
+
+void feed_set_title(Feed *feed, gchar *new_title)
+{
+	g_return_if_fail(feed != NULL);
+	g_return_if_fail(new_title != NULL);
+
+	if (feed->title != NULL) {
+		g_free(feed->title);
+		feed->title = NULL;
+	}
+
+	feed->title = g_strdup(new_title);
+}
+
+/* Description */
+gchar *feed_get_description(Feed *feed)
+{
+	g_return_val_if_fail(feed != NULL, NULL);
+	return feed->description;
+}
+
+/* Language */
+gchar *feed_get_language(Feed *feed)
+{
+	g_return_val_if_fail(feed != NULL, NULL);
+	return feed->language;
+}
+
+/* Author */
+gchar *feed_get_author(Feed *feed)
+{
+	g_return_val_if_fail(feed != NULL, NULL);
+	return feed->author;
+}
+
+/* Generator */
+gchar *feed_get_generator(Feed *feed)
+{
+	g_return_val_if_fail(feed != NULL, NULL);
+	return feed->generator;
+}
+
+/* Fetch error (if not NULL, supplied by libcurl) */
+gchar *feed_get_fetcherror(Feed *feed)
+{
+	g_return_val_if_fail(feed != NULL, NULL);
+	return feed->fetcherr;
+}
+
+/* Returns number of items currently in the feed. */
+gint feed_n_items(Feed *feed)
+{
+	g_return_val_if_fail(feed != NULL, -1);
+
+	if( feed->items == NULL )	/* No items here. */
+		return 0;
+
+	return g_slist_length(feed->items);
+}
+
+/* Returns nth item from feed. */
+FeedItem *feed_nth_item(Feed *feed, guint n)
+{
+	g_return_val_if_fail(feed != NULL, NULL);
+
+	return g_slist_nth_data(feed->items, n);
+}
+
+/* feed_update()
+ * Takes initialized feed with url set, fetches the feed from this url,
+ * updates rest of Feed struct members and returns HTTP response code
+ * we got from url's server. */
+guint feed_update(Feed *feed, time_t last_update)
+{
+	CURL *eh = NULL;
+	CURLcode res;
+	FeedParserCtx *feed_ctx = NULL;
+	glong response_code = 0;
+
+	g_return_val_if_fail(feed != NULL, FEED_ERR_NOFEED);
+	g_return_val_if_fail(feed->url != NULL, FEED_ERR_NOURL);
+
+	/* Init curl before anything else. */
+	eh = curl_easy_init();
+
+	g_return_val_if_fail(eh != NULL, FEED_ERR_INIT);
+
+	/* Curl initialized, create parser context now. */
+	feed_ctx = malloc( sizeof(FeedParserCtx) );
+
+	feed_ctx->parser = XML_ParserCreate(NULL);
+	feed_ctx->depth = 0;
+	feed_ctx->str = NULL;
+	feed_ctx->feed = feed;
+	feed_ctx->location = 0;
+	feed_ctx->curitem = NULL;
+	feed_ctx->id_is_permalink = TRUE;
+
+	feed_ctx->name = NULL;
+	feed_ctx->mail = NULL;
+
+	/* Set initial expat handlers, which will take care of choosing
+	 * correct parser later. */
+	feed_parser_set_expat_handlers(feed_ctx);
+
+	curl_easy_setopt(eh, CURLOPT_URL, feed->url);
+	curl_easy_setopt(eh, CURLOPT_NOPROGRESS, 1);
+#ifdef CURLOPT_MUTE
+	curl_easy_setopt(eh, CURLOPT_MUTE, 1);
+#endif
+	curl_easy_setopt(eh, CURLOPT_WRITEFUNCTION, feed_writefunc);
+	curl_easy_setopt(eh, CURLOPT_WRITEDATA, feed_ctx);
+	curl_easy_setopt(eh, CURLOPT_FOLLOWLOCATION, 1);
+	curl_easy_setopt(eh, CURLOPT_MAXREDIRS, 3);
+	curl_easy_setopt(eh, CURLOPT_TIMEOUT, feed->timeout);
+	curl_easy_setopt(eh, CURLOPT_NOSIGNAL, 1);
+	curl_easy_setopt(eh, CURLOPT_ENCODING, "");
+	curl_easy_setopt(eh, CURLOPT_USERAGENT, "libfeed 0.1");
+
+	/* Use HTTP's If-Modified-Since feature, if application provided
+	 * the timestamp of last update. */
+	if( last_update != -1 ) {
+		curl_easy_setopt(eh, CURLOPT_TIMECONDITION,
+				CURL_TIMECOND_IFMODSINCE);
+		curl_easy_setopt(eh, CURLOPT_TIMEVALUE, last_update);
+	}
+
+#if LIBCURL_VERSION_NUM >= 0x070a00
+	if (feed->ssl_verify_peer == FALSE) {
+		curl_easy_setopt(eh, CURLOPT_SSL_VERIFYPEER, 0);
+		curl_easy_setopt(eh, CURLOPT_SSL_VERIFYHOST, 0);
+	}
+#endif
+
+	if(feed->cookies_path != NULL)
+		curl_easy_setopt(eh, CURLOPT_COOKIEFILE, feed->cookies_path);
+
+	res = curl_easy_perform(eh);
+	XML_Parse(feed_ctx->parser, "", 0, TRUE);
+
+	if( res != CURLE_OK ) {
+		feed->fetcherr = g_strdup(curl_easy_strerror(res));
+		response_code = FEED_ERR_FETCH;
+	} else
+		curl_easy_getinfo(eh, CURLINFO_RESPONSE_CODE, &response_code);
+
+	curl_easy_cleanup(eh);
+
+	/* Cleanup, we should be done. */
+	XML_ParserFree(feed_ctx->parser);
+	g_free(feed_ctx->name);
+	g_free(feed_ctx->mail);
+	g_free(feed_ctx);
+
+	return response_code;
+}
+
+void feed_foreach_item(Feed *feed, GFunc func, gpointer data)
+{
+	g_return_if_fail(feed != NULL);
+	g_return_if_fail(feed->items != NULL);
+
+	g_slist_foreach(feed->items, func, data);
+}
+
+gboolean feed_prepend_item(Feed *feed, FeedItem *item)
+{
+	g_return_val_if_fail(feed != NULL, FALSE);
+	g_return_val_if_fail(item != NULL, FALSE);
+
+	feed->items = g_slist_prepend(feed->items, item);
+	return TRUE;
+}
+
+gboolean feed_append_item(Feed *feed, FeedItem *item)
+{
+	g_return_val_if_fail(feed != NULL, FALSE);
+	g_return_val_if_fail(item != NULL, FALSE);
+
+	feed->items = g_slist_append(feed->items, item);
+	return TRUE;
+}
+
+gboolean feed_insert_item(Feed *feed, FeedItem *item, gint pos)
+{
+	g_return_val_if_fail(feed != NULL, FALSE);
+	g_return_val_if_fail(item != NULL, FALSE);
+	g_return_val_if_fail(pos < 0, FALSE);
+
+	feed->items = g_slist_insert(feed->items, item, pos);
+	return TRUE;
+}
+
+gchar *feed_get_cookies_path(Feed *feed)
+{
+	g_return_val_if_fail(feed != NULL, NULL);
+	return feed->cookies_path;
+}
+
+void feed_set_cookies_path(Feed *feed, gchar *path)
+{
+	g_return_if_fail(feed != NULL);
+
+	if( feed->cookies_path != NULL ) {
+		g_free(feed->cookies_path);
+		feed->cookies_path = NULL;
+	}
+
+	feed->cookies_path = (path != NULL ? g_strdup(path) : NULL);
+}
+
+gboolean feed_get_ssl_verify_peer(Feed *feed)
+{
+	g_return_val_if_fail(feed != NULL, FALSE);
+	return feed->ssl_verify_peer;
+}
+
+void feed_set_ssl_verify_peer(Feed *feed, gboolean ssl_verify_peer)
+{
+	g_return_if_fail(feed != NULL);
+	feed->ssl_verify_peer = ssl_verify_peer;
+}
diff --git a/src/plugins/rssyl/libfeed/feed.h b/src/plugins/rssyl/libfeed/feed.h
new file mode 100644
index 0000000..dc8847d
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/feed.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __FEED_H
+#define __FEED_H
+
+#include <glib.h>
+#include <expat.h>
+
+#define FEED_DEFAULT_TIMEOUT	20	/* In seconds */
+
+/* ---------------- Structures */
+
+typedef struct _Feed Feed;
+typedef struct _FeedItem FeedItem;
+typedef struct _FeedParserCtx FeedParserCtx;
+	
+struct _Feed {
+	gchar *url;
+	gchar *title;
+	gchar *description;
+	gchar *language;
+	gchar *author;
+	gchar *generator;
+	time_t date;
+
+	guint timeout;
+	gchar *fetcherr;
+	gchar *cookies_path;
+	gboolean ssl_verify_peer;
+
+	GSList *items;
+};
+
+struct _FeedParserCtx {
+	XML_Parser parser;
+	guint depth;
+	guint location;
+	GString *str;
+	gchar *name;
+	gchar *mail;
+	gboolean id_is_permalink;
+
+	Feed *feed;
+	FeedItem *curitem;
+};
+
+typedef enum {
+	FEED_ERR_NOFEED,
+	FEED_ERR_NOURL,
+	FEED_ERR_INIT,
+	FEED_ERR_FETCH
+} FeedErrCodes;
+
+/* ---------------- Prototypes */
+
+Feed *feed_new(gchar *url);
+void feed_free(Feed *feed);
+
+void feed_free_items(Feed *feed);
+
+void feed_set_timeout(Feed *feed, guint timeout);
+guint feed_get_timeout(Feed *feed);
+
+void feed_set_url(Feed *feed, gchar *url);
+gchar *feed_get_url(Feed *feed);
+
+gchar *feed_get_title(Feed *feed);
+void feed_set_title(Feed *feed, gchar *new_title);
+
+gchar *feed_get_description(Feed *feed);
+gchar *feed_get_language(Feed *feed);
+gchar *feed_get_author(Feed *feed);
+gchar *feed_get_generator(Feed *feed);
+gchar *feed_get_fetcherror(Feed *feed);
+
+gchar *feed_get_cookies_path(Feed *feed);
+void feed_set_cookies_path(Feed *feed, gchar *path);
+
+gboolean feed_get_ssl_verify_peer(Feed *feed);
+void feed_set_ssl_verify_peer(Feed *feed, gboolean ssl_verify_peer);
+
+gint feed_n_items(Feed *feed);
+FeedItem *feed_nth_item(Feed *feed, guint n);
+
+void feed_foreach_item(Feed *feed, GFunc func, gpointer data);
+
+gboolean feed_prepend_item(Feed *feed, FeedItem *item);
+gboolean feed_append_item(Feed *feed, FeedItem *item);
+gboolean feed_insert_item(Feed *feed, FeedItem *item, gint pos);
+
+guint feed_update(Feed *feed, time_t last_update);
+
+#define FILL(n)		g_free(n); n = g_strdup(text);
+
+#include "feeditem.h"
+
+#endif /* __FEED_H */
diff --git a/src/plugins/rssyl/libfeed/feeditem.c b/src/plugins/rssyl/libfeed/feeditem.c
new file mode 100644
index 0000000..d04831b
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/feeditem.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#define __USE_GNU
+
+#include <stdlib.h>
+#include <glib.h>
+#include <curl/curl.h>
+#include <expat.h>
+
+#include "feed.h"
+#include "feeditem.h"
+#include "feeditemenclosure.h"
+#include "parser.h"
+
+/* feed_item_new()
+ * Initializes a new empty FeedItem struct, setting its parent feed,
+ * if supplied. */
+FeedItem *feed_item_new(Feed *feed)
+{
+	FeedItem *item = NULL;
+
+	item = malloc( sizeof(FeedItem) );
+	item->url = NULL;
+	item->title = NULL;
+	item->title_format = 0;
+	item->summary = NULL;
+	item->text = NULL;
+	item->author = NULL;
+	item->id = NULL;
+	item->comments_url = NULL;
+	item->parent_id = NULL;
+	item->enclosure = NULL;
+
+	item->sourcetitle = NULL;
+	item->sourceid = NULL;
+	item->sourcedate = -1;
+
+	item->id_is_permalink = FALSE;
+	item->xhtml_content = FALSE;
+
+	item->date_published = -1;
+	item->date_modified = -1;
+	
+	if( feed != NULL )
+		item->feed = feed;
+
+	item->data = NULL;
+
+	return item;
+}
+
+void feed_item_free(FeedItem *item)
+{
+	if( item == NULL )
+		return;
+
+	g_free(item->url);
+	g_free(item->title);
+	g_free(item->summary);
+	g_free(item->text);
+	g_free(item->author);
+	g_free(item->id);
+	g_free(item->data);
+	g_free(item->comments_url);
+	g_free(item->parent_id);
+	g_free(item->enclosure);
+
+	g_free(item->sourcetitle);
+	g_free(item->sourceid);
+
+	g_free(item);
+	item = NULL;
+}
+
+Feed *feed_item_get_feed(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, NULL);
+	return item->feed;
+}
+
+/* URL */
+gchar *feed_item_get_url(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, NULL);
+	return item->url;
+}
+
+void feed_item_set_url(FeedItem *item, const gchar *url)
+{
+	g_return_if_fail(item != NULL);
+	g_return_if_fail(url != NULL);
+
+	g_free(item->url);
+	item->url = g_strdup(url);
+}
+
+/* Title */
+gchar *feed_item_get_title(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, NULL);
+	return item->title;
+}
+
+void feed_item_set_title(FeedItem *item, const gchar *title)
+{
+	g_return_if_fail(item != NULL);
+	g_return_if_fail(title != NULL);
+
+	g_free(item->title);
+	item->title = g_strdup(title);
+}
+
+/* Title format */
+gint feed_item_get_title_format(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, -1);
+	return item->title_format;
+}
+
+void feed_item_set_title_format(FeedItem *item, gint format)
+{
+	g_return_if_fail(item != NULL);
+	g_return_if_fail(format >= 0 && format <= FEED_ITEM_TITLE_UNKNOWN);
+
+	item->title_format = format;
+}
+
+/* Summary */
+gchar *feed_item_get_summary(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, NULL);
+	return item->summary;
+}
+
+void feed_item_set_summary(FeedItem *item, const gchar *summary)
+{
+	g_return_if_fail(item != NULL);
+	g_return_if_fail(summary != NULL);
+
+	g_free(item->summary);
+	item->summary = g_strdup(summary);
+}
+
+/* Text */
+gchar *feed_item_get_text(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, NULL);
+	return item->text;
+}
+
+void feed_item_set_text(FeedItem *item, const gchar *text)
+{
+	g_return_if_fail(item != NULL);
+	g_return_if_fail(text != NULL);
+
+	g_free(item->text);
+	item->text = g_strdup(text);
+}
+
+/* Author */
+gchar *feed_item_get_author(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, NULL);
+	return item->author;
+}
+
+void feed_item_set_author(FeedItem *item, const gchar *author)
+{
+	g_return_if_fail(item != NULL);
+	g_return_if_fail(author != NULL);
+
+	g_free(item->author);
+	item->author = g_strdup(author);
+}
+
+/* ID */
+gchar *feed_item_get_id(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, NULL);
+	return item->id;
+}
+
+void feed_item_set_id(FeedItem *item, const gchar *id)
+{
+	g_return_if_fail(item != NULL);
+	g_return_if_fail(id != NULL);
+
+	g_free(item->id);
+	item->id = g_strdup(id);
+}
+
+/* Comments URL */
+gchar *feed_item_get_comments_url(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, NULL);
+	return item->comments_url;
+}
+
+void feed_item_set_comments_url(FeedItem *item, const gchar *url)
+{
+	g_return_if_fail(item != NULL);
+	g_return_if_fail(url != NULL);
+
+	g_free(item->comments_url);
+	item->comments_url = g_strdup(url);
+}
+
+/* Comments URL */
+gchar *feed_item_get_parent_id(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, NULL);
+	return item->parent_id;
+}
+
+void feed_item_set_parent_id(FeedItem *item, const gchar *id)
+{
+	g_return_if_fail(item != NULL);
+	g_return_if_fail(id != NULL);
+
+	g_free(item->parent_id);
+	item->parent_id = g_strdup(id);
+}
+
+/* Media enclosure */
+FeedItemEnclosure *feed_item_get_enclosure(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, NULL);
+	return item->enclosure;
+}
+
+void feed_item_set_enclosure(FeedItem *item, FeedItemEnclosure *enclosure)
+{
+	g_return_if_fail(item != NULL);
+	g_return_if_fail(enclosure != NULL);
+	g_return_if_fail(enclosure->url != NULL);
+	g_return_if_fail(enclosure->type != NULL);
+
+	feed_item_enclosure_free(item->enclosure);
+	item->enclosure = enclosure;
+}
+
+/* Source title (Atom only) */
+gchar *feed_item_get_sourcetitle(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, NULL);
+	return item->sourcetitle;
+}
+
+void feed_item_set_sourcetitle(FeedItem *item, const gchar *sourcetitle)
+{
+	g_return_if_fail(item != NULL);
+	g_return_if_fail(sourcetitle != NULL);
+
+	g_free(item->sourcetitle);
+	item->sourcetitle = g_strdup(sourcetitle);
+}
+
+/* Source ID (Atom only) */
+gchar *feed_item_get_sourceid(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, NULL);
+	return item->sourceid;
+}
+
+void feed_item_set_sourceid(FeedItem *item, const gchar *sourceid)
+{
+	g_return_if_fail(item != NULL);
+	g_return_if_fail(sourceid != NULL);
+
+	g_free(item->sourceid);
+	item->sourceid = g_strdup(sourceid);
+}
+
+/* Source date (Atom only) */
+time_t feed_item_get_sourcedate(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, -1);
+	return item->sourcedate;
+}
+
+void feed_item_set_sourcedate(FeedItem *item, time_t date)
+{
+	g_return_if_fail(item != NULL);
+	item->sourcedate = date;
+}
+
+/* Date published */
+time_t feed_item_get_date_published(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, -1);
+	return item->date_published;
+}
+
+void feed_item_set_date_published(FeedItem *item, time_t date)
+{
+	g_return_if_fail(item != NULL);
+	item->date_published = date;
+}
+
+/* Date modified */
+time_t feed_item_get_date_modified(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, -1);
+	return item->date_modified;
+}
+
+void feed_item_set_date_modified(FeedItem *item, time_t date)
+{
+	g_return_if_fail(item != NULL);
+	item->date_modified = date;
+}
+
+FeedItem *feed_item_copy(FeedItem *item)
+{
+	FeedItem *nitem;
+
+	g_return_val_if_fail(item != NULL, NULL);
+
+	nitem = feed_item_new(NULL);
+
+	nitem->url = g_strdup(item->url);
+	nitem->title = g_strdup(item->title);
+	nitem->summary = g_strdup(item->summary);
+	nitem->text = g_strdup(item->text);
+	nitem->author = g_strdup(item->author);
+	nitem->id = g_strdup(item->id);
+	nitem->comments_url = g_strdup(item->comments_url);
+	nitem->parent_id = g_strdup(item->parent_id);
+
+	nitem->enclosure = g_memdup(item->enclosure, sizeof(FeedItemEnclosure));
+
+	nitem->date_published = item->date_published;
+	nitem->date_modified = item->date_modified;
+
+	nitem->id_is_permalink = item->id_is_permalink;
+	nitem->xhtml_content = item->xhtml_content;
+
+	nitem->data = g_memdup(item->data, sizeof(item->data));
+
+	return nitem;
+}
+
+gboolean feed_item_id_is_permalink(FeedItem *item)
+{
+	g_return_val_if_fail(item != NULL, FALSE);
+
+	return item->id_is_permalink;
+}
+
+void feed_item_set_id_permalink(FeedItem *item, gboolean permalink)
+{
+	g_return_if_fail(item != NULL);
+
+	item->id_is_permalink = permalink;
+}
diff --git a/src/plugins/rssyl/libfeed/feeditem.h b/src/plugins/rssyl/libfeed/feeditem.h
new file mode 100644
index 0000000..9125af4
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/feeditem.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __FEEDITEM_H
+#define __FEEDITEM_H
+
+#include "feed.h"
+#include "feeditemenclosure.h"
+
+struct _FeedItem {
+	gchar *url;
+	gchar *title;
+	gint title_format;
+	gchar *summary;
+	gchar *text;
+	gchar *author;
+	gchar *id;
+	gchar *comments_url;
+	gchar *parent_id;
+
+	gchar *sourceid;
+	gchar *sourcetitle;
+	time_t sourcedate;
+
+	gboolean id_is_permalink;
+	gboolean xhtml_content;
+
+	FeedItemEnclosure *enclosure;
+
+	time_t date_published;
+	time_t date_modified;
+
+	Feed *feed;		/* feed we belong to */
+
+	gpointer data;		/* application-specific data */
+};
+
+#define FEED_ITEM_TITLE_TEXT 0
+#define FEED_ITEM_TITLE_HTML 1
+#define FEED_ITEM_TITLE_XHTML 2
+#define FEED_ITEM_TITLE_UNKNOWN 3
+
+FeedItem *feed_item_new(Feed *feed);
+void feed_item_free(FeedItem *item);
+
+Feed *feed_item_get_feed(FeedItem *item);
+
+gchar *feed_item_get_url(FeedItem *item);
+void feed_item_set_url(FeedItem *item, const gchar *url);
+
+gchar *feed_item_get_title(FeedItem *item);
+void feed_item_set_title(FeedItem *item, const gchar *title);
+
+gint feed_item_get_title_format(FeedItem *item);
+void feed_item_set_title_format(FeedItem *item, gint format);
+
+gchar *feed_item_get_summary(FeedItem *item);
+void feed_item_set_summary(FeedItem *item, const gchar *summary);
+
+gchar *feed_item_get_text(FeedItem *item);
+void feed_item_set_text(FeedItem *item, const gchar *text);
+
+gchar *feed_item_get_author(FeedItem *item);
+void feed_item_set_author(FeedItem *item, const gchar *author);
+
+gchar *feed_item_get_id(FeedItem *item);
+void feed_item_set_id(FeedItem *item, const gchar *id);
+
+gchar *feed_item_get_comments_url(FeedItem *item);
+void feed_item_set_comments_url(FeedItem *item, const gchar *url);
+
+gchar *feed_item_get_parent_id(FeedItem *item);
+void feed_item_set_parent_id(FeedItem *item, const gchar *id);
+
+FeedItemEnclosure *feed_item_get_enclosure(FeedItem *item);
+void feed_item_set_enclosure(FeedItem *item, FeedItemEnclosure *enclosure);
+
+gchar *feed_item_get_sourcetitle(FeedItem *item);
+void feed_item_set_sourcetitle(FeedItem *item, const gchar *sourcetitle);
+
+gchar *feed_item_get_sourceid(FeedItem *item);
+void feed_item_set_sourceid(FeedItem *item, const gchar *sourceid);
+
+time_t feed_item_get_sourcedate(FeedItem *item);
+void feed_item_set_sourcedate(FeedItem *item, time_t date);
+
+time_t feed_item_get_date_published(FeedItem *item);
+void feed_item_set_date_published(FeedItem *item, time_t date);
+
+time_t feed_item_get_date_modified(FeedItem *item);
+void feed_item_set_date_modified(FeedItem *item, time_t date);
+
+FeedItem *feed_item_copy(FeedItem *item);
+
+gboolean feed_item_id_is_permalink(FeedItem *item);
+void feed_item_set_id_permalink(FeedItem *item, gboolean permalink);
+
+#endif /* __FEEDITEM_H */
diff --git a/src/plugins/rssyl/libfeed/feeditemenclosure.c b/src/plugins/rssyl/libfeed/feeditemenclosure.c
new file mode 100644
index 0000000..183cfb5
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/feeditemenclosure.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#define __USE_GNU
+
+#include <stdlib.h>
+#include <glib.h>
+
+#include "feeditemenclosure.h"
+
+FeedItemEnclosure *feed_item_enclosure_new(gchar *url, gchar *type, gulong size)
+{
+	FeedItemEnclosure *enclosure = NULL;
+
+	g_return_val_if_fail(url != NULL, NULL);
+	g_return_val_if_fail(type != NULL, NULL);
+	g_return_val_if_fail(size > 0, NULL);
+
+	enclosure = malloc( sizeof(FeedItemEnclosure) );
+	enclosure->url = g_strdup(url);
+	enclosure->type = g_strdup(type);
+	enclosure->size = size;
+
+	return enclosure;
+}
+
+void feed_item_enclosure_free(FeedItemEnclosure *enclosure)
+{
+	if( enclosure == NULL )
+		return;
+
+	g_free(enclosure->url);
+	g_free(enclosure->type);
+
+	g_free(enclosure);
+	enclosure = NULL;
+}
+
+/* URL */
+gchar *feed_item_enclosure_get_url(FeedItemEnclosure *enclosure)
+{
+	g_return_val_if_fail(enclosure != NULL, NULL);
+	return enclosure->url;
+}
+
+void feed_item_enclosure_set_url(FeedItemEnclosure *enclosure, gchar *url)
+{
+	g_return_if_fail(enclosure != NULL);
+	g_return_if_fail(url != NULL);
+
+	g_free(enclosure->url);
+	enclosure->url = g_strdup(url);
+}
+
+/* Type */
+gchar *feed_item_enclosure_get_type(FeedItemEnclosure *enclosure)
+{
+	g_return_val_if_fail(enclosure != NULL, NULL);
+	return enclosure->type;
+}
+
+void feed_item_enclosure_set_type(FeedItemEnclosure *enclosure, gchar *type)
+{
+	g_return_if_fail(enclosure != NULL);
+	g_return_if_fail(type != NULL);
+
+	g_free(enclosure->type);
+	enclosure->type = g_strdup(type);
+}
+
+/* Size */
+gulong feed_item_enclosure_get_size(FeedItemEnclosure *enclosure)
+{
+	g_return_val_if_fail(enclosure != NULL, -1);
+	return enclosure->size;
+}
+
+void feed_item_enclosure_set_size(FeedItemEnclosure *enclosure, gulong size)
+{
+	g_return_if_fail(enclosure != NULL);
+	g_return_if_fail(size > 0);
+
+	enclosure->size = size;
+}
diff --git a/src/plugins/rssyl/libfeed/feeditemenclosure.h b/src/plugins/rssyl/libfeed/feeditemenclosure.h
new file mode 100644
index 0000000..ba4d127
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/feeditemenclosure.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __FEEDITEMENCLOSURE_H
+#define __FEEDITEMENCLOSURE_H
+
+struct _FeedItemEnclosure {
+	gchar *url;
+	gchar *type;
+	gulong size;
+};
+
+typedef struct _FeedItemEnclosure FeedItemEnclosure;
+
+FeedItemEnclosure *feed_item_enclosure_new(gchar *url, gchar *type, gulong size);
+void feed_item_enclosure_free(FeedItemEnclosure *enclosure);
+
+gchar *feed_item_enclosure_get_url(FeedItemEnclosure *enclosure);
+void feed_item_enclosure_set_url(FeedItemEnclosure *enclosure, gchar *url);
+
+gchar *feed_item_enclosure_get_type(FeedItemEnclosure *enclosure);
+void feed_item_enclosure_set_type(FeedItemEnclosure *enclosure, gchar *type);
+
+gulong feed_item_enclosure_get_size(FeedItemEnclosure *enclosure);
+void feed_item_enclosure_set_size(FeedItemEnclosure *enclosure, gulong size);
+
+#endif /* __FEEDITEMENCLOSURE_H */
diff --git a/src/plugins/rssyl/libfeed/parser.c b/src/plugins/rssyl/libfeed/parser.c
new file mode 100644
index 0000000..1ebc412
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+#include <curl/curl.h>
+#include <expat.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <codeconv.h>
+
+#include "feed.h"
+
+#include "parser.h"
+
+static void _handler_set(XML_Parser parser, guint type)
+{
+	if( parser == NULL )
+		return;
+
+	switch(type) {
+		case FEED_TYPE_RSS_20:
+			XML_SetElementHandler(parser,
+					feed_parser_rss20_start,
+					feed_parser_rss20_end);
+			break;
+
+		case FEED_TYPE_RDF:
+			XML_SetElementHandler(parser,
+					feed_parser_rdf_start,
+					feed_parser_rdf_end);
+			break;
+
+		case FEED_TYPE_ATOM_10:
+			XML_SetElementHandler(parser,
+					feed_parser_atom10_start,
+					feed_parser_atom10_end);
+			break;
+	}
+}
+
+static void _elparse_start_chooser(void *data,
+		const gchar *el, const gchar **attr)
+{
+	FeedParserCtx *ctx = (FeedParserCtx *)data;
+	guint feedtype = FEED_TYPE_NONE;
+	gchar *version;
+
+	if( ctx->depth == 0 ) {
+
+		/* RSS 2.0 detected */
+		if( !strcmp(el, "rss") ) {
+			feedtype = FEED_TYPE_RSS_20;
+		} else if( !strcmp(el, "rdf:RDF") ) {
+			feedtype = FEED_TYPE_RDF;
+		} else if( !strcmp(el, "feed") ) {
+
+			/* ATOM feed detected, let's check version */
+			version = feed_parser_get_attribute_value(attr, "xmlns");
+			if( !strcmp(version, "http://www.w3.org/2005/Atom") ||
+					!strcmp(version, "https://www.w3.org/2005/Atom") )
+				feedtype = FEED_TYPE_ATOM_10;
+			else
+				feedtype = FEED_TYPE_ATOM_03;
+		}
+	}
+
+	_handler_set(ctx->parser, feedtype);
+
+	ctx->depth++;
+}
+
+static void _elparse_end_dummy(void *data, const gchar *el)
+{
+	FeedParserCtx *ctx = (FeedParserCtx *)data;
+
+	if( ctx->str != NULL ) {
+		g_string_free(ctx->str, TRUE);
+		ctx->str = NULL;
+	}
+
+	ctx->depth--;
+}
+
+void libfeed_expat_chparse(void *data, const gchar *s, gint len)
+{
+	FeedParserCtx *ctx = (FeedParserCtx *)data;
+	gchar *buf = NULL;
+	gint i, xblank = 1;
+
+	buf = malloc(len+1);
+	strncpy(buf, s, len);
+	buf[len] = '\0';
+
+	/* check if the string is blank, ... */
+	for( i = 0; i < strlen(buf); i++ )
+		if( !isspace(buf[i]) )
+			xblank = 0;
+
+	/* ...because we do not want the blanks if we're just starting new GString */
+	if( xblank > 0 && ctx->str == NULL ) {
+		g_free(buf);
+		return;
+	}
+
+	if( ctx->str == NULL ) {
+		ctx->str = g_string_sized_new(len + 1);
+	}
+
+	g_string_append(ctx->str, buf);
+	g_free(buf);
+}
+
+
+void feed_parser_set_expat_handlers(FeedParserCtx *ctx)
+{
+	XML_SetUserData(ctx->parser, (void *)ctx);
+
+	XML_SetElementHandler(ctx->parser,
+			_elparse_start_chooser,
+			_elparse_end_dummy);
+
+	XML_SetCharacterDataHandler(ctx->parser,
+		libfeed_expat_chparse);
+
+	XML_SetUnknownEncodingHandler(ctx->parser, feed_parser_unknown_encoding_handler,
+			NULL);
+}
+
+size_t feed_writefunc(void *ptr, size_t size, size_t nmemb, void *data)
+{
+	gint len = size * nmemb;
+	FeedParserCtx *ctx = (FeedParserCtx *)data;
+	gint status, err;
+
+	status = XML_Parse(ctx->parser, ptr, len, FALSE);
+
+	if( status == XML_STATUS_ERROR ) {
+		err = XML_GetErrorCode(ctx->parser);
+		printf("\nExpat: --- %s\n\n", XML_ErrorString(err));
+	}
+
+	return len;
+}
+
+gchar *feed_parser_get_attribute_value(const gchar **attr, const gchar *name)
+{
+	guint i;
+
+	if( attr == NULL && name == NULL )
+		return NULL;
+
+	for( i = 0; attr[i] != NULL && attr[i+1] != NULL; i += 2 ) {
+		if( !strcmp( attr[i], name) )
+			return (gchar *)attr[i+1];
+	}
+
+	/* We haven't found anything. */
+	return NULL;
+}
+
+#define CHARSIZEUTF32	4
+
+enum {
+	LEP_ICONV_OK,
+	LEP_ICONV_FAILED,
+	LEP_ICONV_ILSEQ,
+	LEP_ICONV_INVAL,
+	LEP_ICONV_UNKNOWN
+};
+
+static gint giconv_utf32_char(GIConv cd, const gchar *inbuf, size_t insize,
+		guint32 *p_value)
+{
+#ifdef HAVE_ICONV
+	size_t outsize;
+	guchar outbuf[CHARSIZEUTF32];
+	gchar *outbufp;
+	gint r, errno;
+
+	outsize = sizeof(outbuf);
+	outbufp = (gchar *)outbuf;
+#ifdef HAVE_ICONV_PROTO_CONST
+	r = g_iconv(cd, (const gchar **)&inbuf, &insize,
+			&outbufp, &outsize);
+#else
+	r = g_iconv(cd, (gchar **)&inbuf, &insize,
+			&outbufp, &outsize);
+#endif
+	if( r == -1 ) {
+		g_iconv(cd, 0, 0, 0, 0);
+		switch(errno) {
+		case EILSEQ:
+			return LEP_ICONV_ILSEQ;
+		case EINVAL:
+			return LEP_ICONV_INVAL;
+		default:
+			return LEP_ICONV_UNKNOWN;
+		}
+	} else {
+		guint32 value;
+		guint i;
+
+		if( (insize > 0) || (outsize > 0) )
+			return LEP_ICONV_FAILED;
+
+		value = 0;
+		for( i = 0; i < sizeof(outbuf); i++ ) {
+			value = (value << 8) + outbuf[i];
+		}
+		*p_value = value;
+		return LEP_ICONV_OK;
+	}
+#else
+	return LEP_ICONV_FAILED;
+#endif
+}
+
+static gint feed_parser_setup_unknown_encoding(const gchar *charset,
+		XML_Encoding *info)
+{
+	GIConv cd;
+	gint flag, r;
+	gchar buf[4];
+	guint i, j, k;
+	guint32 value;
+
+	cd = g_iconv_open("UTF-32BE", charset);
+	if( cd == (GIConv) -1 )
+		return -1;
+
+	flag = 0;
+	for( i = 0; i < 256; i++ ) {
+		/* first char */
+		buf[0] = i;
+		info->map[i] = 0;
+		r = giconv_utf32_char(cd, buf, 1, &value);
+		if( r == LEP_ICONV_OK) {
+			info->map[i] = value;
+		} else if( r != LEP_ICONV_INVAL ) {
+		} else {
+			for( j = 0; j < 256; j++ ) {
+				/* second char */
+				buf[1] = j;
+				r = giconv_utf32_char(cd, buf, 2, &value);
+				if( r == LEP_ICONV_OK ) {
+					flag = 1;
+					info->map[i] = -2;
+				} else if( r != LEP_ICONV_INVAL ) {
+				} else {
+					for( k = 0; k < 256; k++ ) {
+						/* third char */
+						buf[2] = k;
+						r = giconv_utf32_char(cd, buf, 3, &value);
+						if( r == LEP_ICONV_OK) {
+							info->map[i] = -3;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	g_iconv_close(cd);
+
+	return flag;
+}
+
+struct FeedParserUnknownEncoding {
+	gchar *charset;
+	GIConv cd;
+};
+
+static gint feed_parser_unknown_encoding_convert(void *data, const gchar *s)
+{
+	gint r;
+	struct FeedParserUnknownEncoding *enc_data;
+	size_t insize;
+	guint32 value;
+
+	enc_data = data;
+	insize = 4;
+
+	if( s == NULL )
+		return -1;
+
+	r = giconv_utf32_char(enc_data->cd, s, insize, &value);
+	if( r != LEP_ICONV_OK )
+		return -1;
+
+	return 0;
+}
+
+static void feed_parser_unknown_encoding_data_free(void *data)
+{
+	struct FeedParserUnknownEncoding *enc_data;
+
+	enc_data = data;
+	free(enc_data->charset);
+	g_iconv_close(enc_data->cd);
+	free(enc_data);
+}
+
+int feed_parser_unknown_encoding_handler(void *encdata, const XML_Char *name,
+		XML_Encoding *info)
+{
+	GIConv cd;
+	struct FeedParserUnknownEncoding *data;
+	int result;
+
+	result = feed_parser_setup_unknown_encoding(name, info);
+	if( result == 0 ) {
+		info->data = NULL;
+		info->convert = NULL;
+		info->release = NULL;
+		return XML_STATUS_OK;
+	}
+
+	cd = g_iconv_open("UTF-32BE", name);
+	if( cd == (GIConv)-1 )
+		return XML_STATUS_ERROR;
+
+	data = malloc( sizeof(*data) );
+	if( data == NULL ) {
+		g_iconv_close(cd);
+		return XML_STATUS_ERROR;
+	}
+
+	data->charset = strdup(name);
+	if( data->charset == NULL ) {
+		free(data);
+		g_iconv_close(cd);
+		return XML_STATUS_ERROR;
+	}
+
+	data->cd = cd;
+	info->data = data;
+	info->convert = feed_parser_unknown_encoding_convert;
+	info->release = feed_parser_unknown_encoding_data_free;
+
+	return XML_STATUS_OK;
+}
diff --git a/src/plugins/rssyl/libfeed/parser.h b/src/plugins/rssyl/libfeed/parser.h
new file mode 100644
index 0000000..f8cbb9a
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PARSER_H
+
+#include "feed.h"
+#include "parser_rss20.h"
+#include "parser_rdf.h"
+#include "parser_atom10.h"
+
+void libfeed_expat_chparse(void *data, const gchar *s, gint len);
+void feed_parser_set_expat_handlers(FeedParserCtx *ctx);
+size_t feed_writefunc(void *ptr, size_t size, size_t nmemb, void *stream);
+gchar *feed_parser_get_attribute_value(const gchar **attr, const gchar *name);
+
+int feed_parser_unknown_encoding_handler(void *encdata, const XML_Char *name,
+		XML_Encoding *info);
+
+
+enum {
+	FEED_TYPE_NONE,
+	FEED_TYPE_RDF,
+	FEED_TYPE_RSS_20,
+	FEED_TYPE_ATOM_03,
+	FEED_TYPE_ATOM_10,
+	FEED_TYPE_OPML
+} FeedTypes;
+
+#endif /* __PARSER_H */
diff --git a/src/plugins/rssyl/libfeed/parser_atom10.c b/src/plugins/rssyl/libfeed/parser_atom10.c
new file mode 100644
index 0000000..59fba1c
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser_atom10.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#define __USE_GNU
+
+#include <glib.h>
+#include <expat.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "feed.h"
+#include "feeditem.h"
+#include "date.h"
+#include "parser.h"
+#include "parser_atom10.h"
+
+void feed_parser_atom10_start(void *data, const gchar *el, const gchar **attr)
+{
+	FeedParserCtx *ctx = (FeedParserCtx *)data;
+	gchar *a = NULL;
+
+	if( ctx->depth == 1 ) {
+
+		if( !strcmp(el, "entry") ) {
+			/* Start of new feed item found.
+			 * Create a new FeedItem, freeing the one we already have, if any. */
+			if( ctx->curitem != NULL )
+				feed_item_free(ctx->curitem);
+			ctx->curitem = feed_item_new(ctx->feed);
+			ctx->location = FEED_LOC_ATOM10_ENTRY;
+		} else if( !strcmp(el, "author") ) {
+			/* Start of author info for the feed found.
+			 * Set correct location. */
+			ctx->location = FEED_LOC_ATOM10_AUTHOR;
+		} else ctx->location = FEED_LOC_ATOM10_NONE;
+
+	} else if( ctx->depth == 2 ) {
+
+		if( !strcmp(el, "author") ) {
+			/* Start of author info for current feed item.
+			 * Set correct location. */
+			ctx->location = FEED_LOC_ATOM10_AUTHOR;
+		} else if( !strcmp(el, "link") ) {
+			/* Capture item URL, from the "url" XML attribute. */
+			if (ctx->curitem && ctx->location == FEED_LOC_ATOM10_ENTRY)
+  		  ctx->curitem->url = g_strdup(feed_parser_get_attribute_value(attr, "href"));
+		} else if( !strcmp(el, "source") ) {
+			ctx->location = FEED_LOC_ATOM10_SOURCE;
+		} else ctx->location = FEED_LOC_ATOM10_ENTRY;
+
+		if( !strcmp(el, "title") ) {
+			a = feed_parser_get_attribute_value(attr, "type");
+			if( !a || !strcmp(a, "text") )
+				ctx->curitem->title_format = FEED_ITEM_TITLE_TEXT;
+			else if( !strcmp(a, "html") )
+				ctx->curitem->title_format = FEED_ITEM_TITLE_HTML;
+			else if( !strcmp(a, "xhtml") )
+				ctx->curitem->title_format = FEED_ITEM_TITLE_XHTML;
+			else
+				ctx->curitem->title_format = FEED_ITEM_TITLE_UNKNOWN;
+		} else if (!strcmp(el, "content") ) {
+			a = feed_parser_get_attribute_value(attr, "type");
+			if (a && !strcmp(a, "xhtml")) {
+				ctx->curitem->xhtml_content = TRUE;
+				ctx->location = FEED_LOC_ATOM10_CONTENT;
+			}
+		}
+	}
+
+	ctx->depth++;
+}
+
+void feed_parser_atom10_end(void *data, const gchar *el)
+{
+	FeedParserCtx *ctx = (FeedParserCtx *)data;
+	Feed *feed = ctx->feed;
+	gchar *text = NULL;
+
+	if( ctx->str != NULL )
+		text = ctx->str->str;
+
+	ctx->depth--;
+
+	switch( ctx->depth ) {
+
+		case 0:
+
+			if( !strcmp(el, "feed") ) {
+				/* We have finished parsing the feed, reverse the list
+				 * so it's not upside down. */
+				feed->items = g_slist_reverse(ctx->feed->items);
+			}
+
+			break;
+
+		case 1:
+
+			/* decide if we just received </entry>, so we can
+			 * add a complete item to feed */
+			if( !strcmp(el, "entry") ) {
+
+				/* append the complete feed item */
+				if( ctx->curitem->id && ctx->curitem->title
+						&& ctx->curitem->date_modified ) {
+					feed->items = 
+						g_slist_prepend(feed->items, (gpointer)ctx->curitem);
+				}
+				
+				/* since it's in the linked list, lose this pointer */
+				ctx->curitem = NULL;
+
+			} else if( !strcmp(el, "title") ) {	/* so it wasn't end of item */
+				FILL(feed->title)
+			} else if( !strcmp(el, "summary" ) ) {
+				FILL(feed->description)
+			} else if( !strcmp(el, "updated" ) ) {
+				feed->date = parseISO8601Date(text);
+			}
+			/* FIXME: add more later */
+
+			break;
+
+		case 2:
+
+			if( ctx->curitem == NULL )
+				break;
+
+			switch(ctx->location) {
+
+				/* We're in feed/entry */
+				case FEED_LOC_ATOM10_ENTRY:
+					if( !strcmp(el, "title") ) {
+						FILL(ctx->curitem->title)
+					} else if( !strcmp(el, "summary") ) {
+						FILL(ctx->curitem->summary)
+					} else if( !strcmp(el, "content") ) {
+						if (!ctx->curitem->xhtml_content)
+							FILL(ctx->curitem->text);
+					} else if( !strcmp(el, "id") ) {
+						FILL(ctx->curitem->id);
+						feed_item_set_id_permalink(ctx->curitem, TRUE);
+					} else if( !strcmp(el, "published") ) {
+						ctx->curitem->date_published = parseISO8601Date(text);
+					} else if( !strcmp(el, "updated") ) {
+						ctx->curitem->date_modified = parseISO8601Date(text);
+					}
+
+					break;
+
+				/* We're in feed/author or about to leave feed/entry/author */
+				case FEED_LOC_ATOM10_AUTHOR:
+					if( !strcmp(el, "author" ) ) {
+						/* We just finished parsing <author> */
+						ctx->curitem->author = g_strdup_printf("%s%s%s%s%s",
+								ctx->name ? ctx->name : "",
+								ctx->name && ctx->mail ? " <" : ctx->mail ? "<" : "",
+								ctx->mail ? ctx->mail : "",
+								ctx->mail ? ">" : "",
+								!ctx->name && !ctx->mail ? "N/A" : "");
+						ctx->location = FEED_LOC_ATOM10_ENTRY;
+					} else if( !strcmp(el, "name") ) {
+						FILL(feed->author);
+					}
+
+					break;
+			}
+
+			break;
+
+		case 3:
+
+			if( ctx->curitem == NULL )
+				break;
+
+			switch(ctx->location) {
+
+				/* We're in feed/entry/author */
+				case FEED_LOC_ATOM10_AUTHOR:
+					if( !strcmp(el, "name") ) {
+						FILL(ctx->name);
+					} else if( !strcmp(el, "email") ) {
+						FILL(ctx->mail);
+					}
+
+					break;
+
+				/* We're in feed/entry/source */
+				case FEED_LOC_ATOM10_SOURCE:
+					if( !strcmp(el, "title" ) ) {
+						FILL(ctx->curitem->sourcetitle);
+					} else if( !strcmp(el, "id" ) ) {
+						FILL(ctx->curitem->sourceid);
+					} else if( !strcmp(el, "updated" ) ) {
+						ctx->curitem->sourcedate = parseISO8601Date(text);
+					}
+
+					break;
+
+				case FEED_LOC_ATOM10_CONTENT:
+					if (!strcmp(el, "div") && ctx->curitem->xhtml_content)
+						FILL(ctx->curitem->text);
+					break;
+
+				}
+
+
+			break;
+	}
+
+	if( ctx->str != NULL ) {
+		g_string_free(ctx->str, TRUE);
+		ctx->str = NULL;
+	}
+	ctx->str = NULL;
+}
diff --git a/src/plugins/rssyl/libfeed/parser_atom10.h b/src/plugins/rssyl/libfeed/parser_atom10.h
new file mode 100644
index 0000000..85e95b4
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser_atom10.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PARSER_ATOM03_H
+#define __PARSER_ATOM03_H
+
+void feed_parser_atom10_start(void *data, const char *el, const char **attr);
+void feed_parser_atom10_end(void *data, const char *el);
+
+enum {
+	FEED_LOC_ATOM10_NONE,
+	FEED_LOC_ATOM10_ENTRY,
+	FEED_LOC_ATOM10_AUTHOR,
+	FEED_LOC_ATOM10_SOURCE,
+	FEED_LOC_ATOM10_CONTENT
+} FeedAtom10Locations;
+
+#endif /* __PARSER_ATOM03_H */
diff --git a/src/plugins/rssyl/libfeed/parser_opml.c b/src/plugins/rssyl/libfeed/parser_opml.c
new file mode 100644
index 0000000..09e34aa
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser_opml.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+#include <curl/curl.h>
+#include <expat.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <codeconv.h>
+
+#include "feed.h"
+
+#include "parser.h"
+#include "parser_opml.h"
+
+static void _opml_parser_start(void *data, const gchar *el, const gchar **attr)
+{
+	OPMLProcessCtx *ctx = (OPMLProcessCtx *)data;
+	gchar *title = NULL, *type = NULL, *url = NULL, *tmp = NULL;
+
+	if( ctx->body_reached ) {
+		if( ctx->depth >= 2 && !strcmp(el, "outline") ) {
+			title = feed_parser_get_attribute_value(attr, "title");
+			type = feed_parser_get_attribute_value(attr, "type");
+			if( type != NULL && strcmp(type, "folder") ) {
+				url = feed_parser_get_attribute_value(attr, "xmlUrl");
+
+				if( url != NULL ) {
+					if( !strncmp(url, "feed://", 7) )
+						tmp = g_strdup(url+7);
+					else if( !strncmp(url, "feed:", 5) )
+						tmp = g_strdup(url+5);
+				
+					if( tmp != NULL ) {
+						g_free(url);
+						url = tmp;
+					}
+				}
+			}
+
+			if( ctx->user_function != NULL ) {
+				ctx->user_function(title, url, ctx->depth, ctx->user_data);
+			}
+		}
+	}
+
+	if( ctx->depth == 1 ) {
+		if( !strcmp(el, "body") ) {
+			ctx->body_reached = TRUE;
+		}
+	}
+
+	ctx->depth++;
+}
+
+static void _opml_parser_end(void *data, const gchar *el)
+{
+	OPMLProcessCtx *ctx = (OPMLProcessCtx *)data;
+
+	ctx->depth--;
+}
+
+void opml_process(gchar *path, OPMLProcessFunc function, gpointer data)
+{
+	OPMLProcessCtx *ctx = NULL;
+	gchar *contents = NULL;
+	GError *error = NULL;
+	gint status, err;
+
+	/* Initialize our context */
+	ctx = malloc( sizeof(OPMLProcessCtx) );
+	ctx->parser = XML_ParserCreate(NULL);
+	ctx->depth = 0;
+	ctx->str = NULL;
+	ctx->user_function = function;
+	ctx->body_reached = FALSE;
+	ctx->user_data = data;
+
+	/* Set expat parser handlers */
+	XML_SetUserData(ctx->parser, (void *)ctx);
+	XML_SetElementHandler(ctx->parser,
+			_opml_parser_start,
+			_opml_parser_end);
+	XML_SetCharacterDataHandler(ctx->parser, libfeed_expat_chparse);
+	XML_SetUnknownEncodingHandler(ctx->parser,
+			feed_parser_unknown_encoding_handler, NULL);
+
+	g_file_get_contents(path, &contents, NULL, &error);
+
+	if( error || !contents )
+		return;
+
+/*
+	lines = g_strsplit(contents, '\n', 0);
+
+	while( lines[i] ) {
+		status = XML_Parse(ctx->parser, lines[i], strlen(lines[i]), FALSE);
+		if( status == XML_STATUS_ERROR ) {
+			err = XML_GetErrorCode(ctx->parser);
+			sprintf(stderr, "\nExpat: --- %s\n\n", XML_ErrorString(err));
+		}
+	}
+*/
+
+	status = XML_Parse(ctx->parser, contents, strlen(contents), FALSE);
+	err = XML_GetErrorCode(ctx->parser);
+	fprintf(stderr, "\nExpat: --- %s (%s)\n\n", XML_ErrorString(err),
+			(status == XML_STATUS_OK ? "OK" : "NOT OK"));
+
+	XML_Parse(ctx->parser, "", 0, TRUE);
+
+	XML_ParserFree(ctx->parser);
+	g_free(ctx);
+}
diff --git a/src/plugins/rssyl/libfeed/parser_opml.h b/src/plugins/rssyl/libfeed/parser_opml.h
new file mode 100644
index 0000000..518b072
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser_opml.h
@@ -0,0 +1,23 @@
+#ifndef __PARSER_OPML
+#define __PARSER_OPML
+
+#include <expat.h>
+
+typedef void (*OPMLProcessFunc) (gchar *title, gchar *url, gint depth,
+		gpointer data);
+
+struct _OPMLProcessCtx {
+	XML_Parser parser;
+	guint depth;
+	guint prevdepth;
+	GString *str;
+	OPMLProcessFunc user_function;
+	gboolean body_reached;
+	gpointer user_data;
+};
+
+typedef struct _OPMLProcessCtx OPMLProcessCtx;
+
+void opml_process(gchar *path, OPMLProcessFunc function, gpointer data);
+
+#endif /* __PARSER_OPML */
diff --git a/src/plugins/rssyl/libfeed/parser_rdf.c b/src/plugins/rssyl/libfeed/parser_rdf.c
new file mode 100644
index 0000000..dc424c5
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser_rdf.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#define __USE_GNU
+
+#include <glib.h>
+#include <expat.h>
+#include <string.h>
+
+#include "feed.h"
+#include "date.h"
+#include "parser_rdf.h"
+
+void feed_parser_rdf_start(void *data, const gchar *el, const gchar **attr)
+{
+	FeedParserCtx *ctx = (FeedParserCtx *)data;
+
+	if( ctx->depth == 1 ) {
+		if( !strcmp(el, "channel") ) {
+			ctx->location = FEED_LOC_RDF_CHANNEL;
+		} else if( !strcmp(el, "item") ) {
+
+			if( ctx->curitem != NULL )
+				feed_item_free(ctx->curitem);
+
+			ctx->curitem = feed_item_new(ctx->feed);
+			ctx->location = FEED_LOC_RDF_ITEM;
+
+		} else ctx->location = 0;
+	}
+
+	ctx->depth++;
+
+}
+
+void feed_parser_rdf_end(void *data, const gchar *el)
+{
+	FeedParserCtx *ctx = (FeedParserCtx *)data;
+	Feed *feed = ctx->feed;
+	gchar *text = NULL;
+
+	if( ctx->str != NULL )
+		text = ctx->str->str;
+
+	ctx->depth--;
+	
+	switch( ctx->depth ) {
+
+		case 0:
+
+			if( !strcmp(el, "rdf") ) {
+				/* we finished parsing the feed */
+				ctx->feed->items = g_slist_reverse(ctx->feed->items);
+			}
+
+			break;
+
+		case 1:
+
+			/* <item></item> block just ended, so ... */
+			if( !strcmp(el, "item") ) {
+
+				/* add the complete feed item to our feed struct */
+				ctx->feed->items = 
+					g_slist_prepend(ctx->feed->items, (gpointer)ctx->curitem);
+				
+				/* since it's in the linked list, lose this pointer */
+				ctx->curitem = NULL;
+			}
+
+			break;
+
+		case 2:
+
+			switch(ctx->location) {
+
+				/* We're inside introductory <channel></channel> */
+				case FEED_LOC_RDF_CHANNEL:
+					if( !strcmp(el, "title") ) {
+						FILL(feed->title)
+					} else if( !strcmp(el, "description" ) ) {
+						FILL(feed->description)
+					} else if( !strcmp(el, "dc:language") ) {
+						FILL(feed->language)
+					} else if( !strcmp(el, "dc:creator") ) {
+						FILL(feed->author)
+					} else if( !strcmp(el, "dc:date") ) {
+						feed->date = parseISO8601Date(text);
+					} else if( !strcmp(el, "pubDate") ) {
+						feed->date = parseRFC822Date(text);
+					}
+
+					break;
+
+				/* We're inside an <item></item> */
+				case FEED_LOC_RDF_ITEM:
+					if( ctx->curitem == NULL ) {
+						break;
+					}
+
+					/* decide which field did we just get */
+					if( !strcmp(el, "title") ) {
+						FILL(ctx->curitem->title)
+					} else if( !strcmp(el, "dc:creator") ) {
+						FILL(ctx->curitem->author)
+					} else if( !strcmp(el, "description") ) {
+						FILL(ctx->curitem->summary)
+					} else if( !strcmp(el, "content:encoded") ) {
+						FILL(ctx->curitem->text)
+					} else if( !strcmp(el, "link") ) {
+						FILL(ctx->curitem->url)
+					} else if( !strcmp(el, "dc:date") ) {
+						ctx->curitem->date_modified = parseISO8601Date(text);
+					} else if( !strcmp(el, "pubDate") ) {
+						ctx->curitem->date_modified = parseRFC822Date(text);
+					}
+
+					break;
+			}
+
+			break;
+
+	}
+
+	if( ctx->str != NULL ) {
+		g_string_free(ctx->str, TRUE);
+		ctx->str = NULL;
+	}
+}
diff --git a/src/plugins/rssyl/libfeed/parser_rdf.h b/src/plugins/rssyl/libfeed/parser_rdf.h
new file mode 100644
index 0000000..1c3809f
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser_rdf.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PARSER_RDF_H
+#define __PARSER_RDF_H
+
+void feed_parser_rdf_start(void *data, const char *el, const char **attr);
+void feed_parser_rdf_end(void *data, const char *el);
+
+enum {
+	FEED_LOC_RDF_NONE,
+	FEED_LOC_RDF_CHANNEL,
+	FEED_LOC_RDF_ITEM
+} FeedRdfLocations;
+
+#endif /* __PARSER_RDF_H */
diff --git a/src/plugins/rssyl/libfeed/parser_rss20.c b/src/plugins/rssyl/libfeed/parser_rss20.c
new file mode 100644
index 0000000..3882750
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser_rss20.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#define __USE_GNU
+
+#include <glib.h>
+#include <expat.h>
+#include <string.h>
+
+#include "feed.h"
+#include "feeditem.h"
+#include "feeditemenclosure.h"
+#include "date.h"
+#include "parser.h"
+
+void feed_parser_rss20_start(void *data, const gchar *el, const gchar **attr)
+{
+	FeedParserCtx *ctx = (FeedParserCtx *)data;
+	FeedItemEnclosure *enclosure = NULL;
+	gchar *url, *type, *size_s;
+	gulong size = -1;
+
+	/* ------------------- */
+	if( ctx->depth == 2 ) {
+		if( !strcmp(el, "item") ) {		/* Start of new item */
+
+			if( ctx->curitem != NULL )
+				feed_item_free(ctx->curitem);
+
+			ctx->curitem = feed_item_new(ctx->feed);
+
+		} else ctx->location = 0;
+	/* ------------------- */
+	} else if( ctx->depth == 3 ) {
+		if( !strcmp(el, "enclosure") ) {	/* Media enclosure */
+
+			url = feed_parser_get_attribute_value(attr, "url");
+			type = feed_parser_get_attribute_value(attr, "type");
+			size_s = feed_parser_get_attribute_value(attr, "length");
+			if( size_s != NULL )
+				size = (gulong)atol(size_s);
+
+			if( url != NULL && type != NULL && size > 0 ) {
+				if( (enclosure = feed_item_enclosure_new(url, type, size)) )
+					feed_item_set_enclosure(ctx->curitem, enclosure);
+			}
+
+		} else if( !strcmp(el, "guid") ) { /* Unique ID */
+			type = feed_parser_get_attribute_value(attr, "isPermaLink");
+			if( type != NULL && !strcmp(type, "false") )
+				feed_item_set_id_permalink(ctx->curitem, TRUE);
+		}
+	} else ctx->location = 0;
+
+	ctx->depth++;
+
+}
+
+void feed_parser_rss20_end(void *data, const gchar *el)
+{
+	FeedParserCtx *ctx = (FeedParserCtx *)data;
+	Feed *feed = ctx->feed;
+	gchar *text = NULL;
+
+	if( ctx->str != NULL )
+		text = ctx->str->str;
+	else
+		text = "";
+
+	ctx->depth--;
+
+	switch( ctx->depth ) {
+
+	/* ------------------- */
+		case 0:
+
+			if( !strcmp(el, "rss") ) {
+				/* we finished parsing the feed */
+				ctx->feed->items = g_slist_reverse(ctx->feed->items);
+			}
+
+			break;
+
+	/* ------------------- */
+		case 1:
+
+			break;	/* nothing to do at this depth */
+
+	/* ------------------- */
+		case 2:
+
+			/* decide if we just received </item>, so we can
+			 * add a complete item to feed */
+			if( !strcmp(el, "item") ) {
+
+				/* append the complete feed item, if it is valid
+				 * "All elements of an item are optional, however at least one
+				 * of title or description must be present." */
+				if( ctx->curitem->title != NULL || ctx->curitem->summary != NULL ) {
+					ctx->feed->items = 
+						g_slist_prepend(ctx->feed->items, (gpointer)ctx->curitem);
+				}
+				
+				/* since it's in the linked list, lose this pointer */
+				ctx->curitem = NULL;
+
+			} else if( !strcmp(el, "title") ) {	/* so it wasn't end of item */
+				FILL(feed->title)
+			} else if( !strcmp(el, "description" ) ) {
+				FILL(feed->description)
+			} else if( !strcmp(el, "dc:language") ) {
+				FILL(feed->language)
+			} else if( !strcmp(el, "author") ) {
+				FILL(feed->author)
+			} else if( !strcmp(el, "admin:generatorAgent") ) {
+				FILL(feed->generator)
+			} else if( !strcmp(el, "dc:date") ) {
+				feed->date = parseISO8601Date(text);
+			} else if( !strcmp(el, "pubDate") ) {
+				feed->date = parseRFC822Date(text);
+			}
+
+			break;
+
+	/* ------------------- */
+		case 3:
+
+			if( ctx->curitem == NULL ) {
+				break;
+			}
+
+			/* decide which field did we just get */
+			if( !strcmp(el, "title") ) {
+				FILL(ctx->curitem->title)
+			} else if( !strcmp(el, "author") ) {
+				FILL(ctx->curitem->author)
+			} else if( !strcmp(el, "description") ) { 
+				FILL(ctx->curitem->summary)
+			} else if( !strcmp(el, "content:encoded") ) {
+				FILL(ctx->curitem->text)
+			} else if( !strcmp(el, "link") ) {
+				FILL(ctx->curitem->url)
+			} else if( !strcmp(el, "guid") ) {
+				FILL(ctx->curitem->id)
+			} else if( !strcmp(el, "wfw:commentRSS") || !strcmp(el, "wfw:commentRss") ) {
+				FILL(ctx->curitem->comments_url)
+			} else if( !strcmp(el, "dc:date") ) {
+				ctx->curitem->date_modified = parseISO8601Date(text);
+			} else if( !strcmp(el, "pubDate") ) {
+				ctx->curitem->date_modified = parseRFC822Date(text);
+			} else if( !strcmp(el, "dc:creator")) {
+				FILL(ctx->curitem->author)
+			}
+
+			break;
+
+	}
+
+	if( ctx->str != NULL ) {
+		g_string_free(ctx->str, TRUE);
+		ctx->str = NULL;
+	}
+}
diff --git a/src/plugins/rssyl/libfeed/parser_rss20.h b/src/plugins/rssyl/libfeed/parser_rss20.h
new file mode 100644
index 0000000..27cc40c
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser_rss20.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PARSER_RSS20_H
+#define __PARSER_RSS20_H
+
+void feed_parser_rss20_start(void *data, const char *el, const char **attr);
+void feed_parser_rss20_end(void *data, const char *el);
+
+#endif /* __PARSER_RSS20_H */
diff --git a/src/plugins/rssyl/old_feeds.c b/src/plugins/rssyl/old_feeds.c
new file mode 100644
index 0000000..45e6cf6
--- /dev/null
+++ b/src/plugins/rssyl/old_feeds.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2012 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Expat parser for old feeds.xml */
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <expat.h>
+
+#include <alertpanel.h>
+#include <common/utils.h>
+
+#include "libfeed/parser.h"
+#include "old_feeds.h"
+#include "rssyl.h"
+
+struct _oldrssyl_ctx {
+	GSList *oldfeeds;
+};
+
+static void _elparse_start_oldrssyl(void *data, const gchar *el,
+		const gchar **attr)
+{
+	struct _oldrssyl_ctx *ctx = data;
+	OldRFeed *of;
+	gchar *tmp;
+
+#define GETVAL_STR(name) (g_strdup(feed_parser_get_attribute_value(attr, name)))
+#define GETVAL_INT(name) \
+	((tmp = feed_parser_get_attribute_value(attr, name)) == NULL ? 0 : \
+		(gint)atoi(tmp))
+
+	if (!strcmp(el, "feed")) {
+		of = g_new0(OldRFeed, 1);
+
+		of->name = GETVAL_STR("name");
+		of->official_name = GETVAL_STR("official_name");
+		of->url = GETVAL_STR("url");
+		of->default_refresh_interval = GETVAL_INT("default_refresh_interval");
+		of->refresh_interval = GETVAL_INT("refresh_interval");
+		of->expired_num = GETVAL_INT("expired_num");
+		of->fetch_comments = GETVAL_INT("fetch_comments");
+		of->fetch_comments_for = GETVAL_INT("fetch_comments_for");
+		of->silent_update = GETVAL_INT("silent_update");
+
+		debug_print("RSSyl: old feeds.xml: Adding '%s' (%s).\n", of->name,
+				of->url);
+
+		ctx->oldfeeds = g_slist_prepend(ctx->oldfeeds, of);
+	}
+
+	return;
+}
+
+static void _elparse_end_oldrssyl(void *data, const gchar *el)
+{
+	return;
+}
+
+GSList *rssyl_old_feed_metadata_parse(gchar *filepath)
+{
+	XML_Parser parser;
+	GSList *oldfeeds = NULL;
+	gchar *contents = NULL;
+	gsize length;
+	GError *error;
+	struct _oldrssyl_ctx *ctx;
+
+	debug_print("RSSyl: Starting to parse old feeds.xml\n");
+
+	/* Read contents of the file into memory */
+	if (!g_file_get_contents(filepath, &contents, &length, &error)) {
+		alertpanel_error(_("Couldn't read contents of old feeds.xml file:\n%s"),
+				error->message);
+		debug_print("RSSyl: Couldn't read contents of feeds.xml\n");
+		g_error_free(error);
+		return NULL;
+	}
+
+	/* Set up expat parser */
+	parser = XML_ParserCreate(NULL);
+
+	ctx = g_new0(struct _oldrssyl_ctx, 1);
+	ctx->oldfeeds = NULL;
+	XML_SetUserData(parser, ctx);
+	XML_SetElementHandler(parser,
+			_elparse_start_oldrssyl,
+			_elparse_end_oldrssyl);
+
+	/* Parse the XML, our output ending up in oldfeeds */
+	XML_Parse(parser, contents, length, 1);
+
+	/* And clean up */
+	XML_ParserFree(parser);
+	g_free(contents);
+	oldfeeds = ctx->oldfeeds;
+	g_free(ctx);
+
+	debug_print("RSSyl: old feeds.xml: added %d items in total\n",
+			g_slist_length(oldfeeds));
+
+	return oldfeeds;
+}
+
+static void _free_old_feed_entry(gpointer d, gpointer user_data)
+{
+	OldRFeed *of = (OldRFeed *)d;
+
+	if (of == NULL)
+		return;
+
+	g_free(of->name);
+	g_free(of->official_name);
+	g_free(of->url);
+	g_free(of);
+}
+
+void rssyl_old_feed_metadata_free(GSList *oldfeeds)
+{
+	if (oldfeeds != NULL) {
+		debug_print("RSSyl: releasing parsed contents of old feeds.xml\n");
+		g_slist_foreach(oldfeeds, _free_old_feed_entry, NULL);
+		g_slist_free(oldfeeds);
+		oldfeeds = NULL;
+	}
+}
+
+static gint _old_feed_find_by_url(gconstpointer a, gconstpointer b)
+{
+	OldRFeed *of = (OldRFeed *)a;
+	gchar *name = (gchar *)b;
+
+	if (of == NULL || of->name == NULL || of->url == NULL || name == NULL)
+		return 1;
+
+	return strcmp(of->name, name);
+}
+
+OldRFeed *rssyl_old_feed_get_by_name(GSList *oldfeeds, gchar *name)
+{
+	GSList *needle;
+
+	g_return_val_if_fail(oldfeeds != NULL, NULL);
+	g_return_val_if_fail(name != NULL, NULL);
+
+	if ((needle = g_slist_find_custom(oldfeeds, name, _old_feed_find_by_url))
+			!= NULL)
+		return (OldRFeed *)needle->data;
+	
+	return NULL;
+}
diff --git a/src/plugins/rssyl/old_feeds.h b/src/plugins/rssyl/old_feeds.h
new file mode 100644
index 0000000..b52cd86
--- /dev/null
+++ b/src/plugins/rssyl/old_feeds.h
@@ -0,0 +1,22 @@
+#ifndef __RSSYL_OLD_FEEDS
+#define __RSSYL_OLD_FEEDS
+
+struct _OldRFeed {
+	gchar *name;
+	gchar *official_name;
+	gchar *url;
+	gint default_refresh_interval;
+	gint refresh_interval;
+	gint expired_num;
+	gint fetch_comments;
+	gint fetch_comments_for;
+	gint silent_update;
+};
+
+typedef struct _OldRFeed OldRFeed;
+
+GSList *rssyl_old_feed_metadata_parse(gchar *filepath);
+void rssyl_old_feed_metadata_free(GSList *oldfeeds);
+OldRFeed *rssyl_old_feed_get_by_name(GSList *oldfeeds, gchar *name);
+
+#endif /* __RSSYL_OLD_FEEDS */
diff --git a/src/plugins/rssyl/opml.c b/src/plugins/rssyl/opml_export.c
similarity index 50%
rename from src/plugins/rssyl/opml.c
rename to src/plugins/rssyl/opml_export.c
index c71cf8b..7ec9369 100644
--- a/src/plugins/rssyl/opml.c
+++ b/src/plugins/rssyl/opml_export.c
@@ -23,42 +23,35 @@
 #  include "config.h"
 #endif
 
-#include <errno.h>
+/* Global includes */
 #include <glib.h>
+#include <glib/gi18n.h>
+#include <errno.h>
 
-#include <libxml/parser.h>
-#include <libxml/xpath.h>
-
-#include "log.h"
-#include "folder.h"
-#include "folderview.h"
+/* Claws Mail includes */
+#include <log.h>
+#include <folder.h>
+#include <common/utils.h>
 
-#include "date.h"
-#include "feed.h"
+/* Local includes */
+#include "libfeed/date.h"
 #include "rssyl.h"
-#include "strreplace.h"
+#include "opml_import.h"
+#include "strutils.h"
 
 #define RSSYL_OPML_FILE	"rssyl-feedlist.opml"
 
-static gint _folder_depth(FolderItem *item)
-{
-	gint i;
-
-	for( i = 0; item != NULL; item = folder_item_parent(item), i++ ) {}
-	return i;
-}
-
-struct _RSSylOpmlExportCtx {
+struct _RSSylOpmlCtx {
 	FILE *f;
 	gint depth;
 };
 
-typedef struct _RSSylOpmlExportCtx RSSylOpmlExportCtx;
+typedef struct _RSSylOpmlCtx RSSylOpmlCtx;
 
 static void rssyl_opml_export_func(FolderItem *item, gpointer data)
 {
-	RSSylOpmlExportCtx *ctx = (RSSylOpmlExportCtx *)data;
-	RSSylFolderItem *ritem = (RSSylFolderItem *)item;
+	RSSylOpmlCtx *ctx = (RSSylOpmlCtx *)data;
+	RFolderItem *ritem = (RFolderItem *)item;
 	gboolean isfolder = FALSE, err = FALSE;
 	gboolean haschildren = FALSE;
 	gchar *indent = NULL, *xmlurl = NULL;
@@ -72,10 +65,10 @@ static void rssyl_opml_export_func(FolderItem *item, gpointer data)
 		return;
 
 	/* Check for depth and adjust indentation */
-	depth = _folder_depth(item);
+	depth = rssyl_folder_depth(item);
 	if( depth < ctx->depth ) {
 		for( ctx->depth--; depth <= ctx->depth; ctx->depth-- ) {
-			indent = g_strnfill(ctx->depth, '\t');
+			indent = g_strnfill(ctx->depth + 1, '\t');
 			err |= (fprintf(ctx->f, "%s</outline>\n", indent) < 0);
 			g_free(indent);
 		}
@@ -93,13 +86,13 @@ static void rssyl_opml_export_func(FolderItem *item, gpointer data)
 	if( g_node_n_children(item->node) )
 		haschildren = TRUE;
 
-	indent = g_strnfill(ctx->depth, '\t');
+	indent = g_strnfill(ctx->depth + 1, '\t');
 
 	tmpname = rssyl_strreplace(item->name, "&", "&");
-	if (ritem->official_name != NULL)
-		tmpoffn = rssyl_strreplace(item->name, "&", "&");
-	else
-		tmpoffn = g_strdup(tmpname);
+	 if( ritem->official_title != NULL )
+		 tmpoffn = rssyl_strreplace(ritem->official_title, "&", "&");
+	 else
+		 tmpoffn = g_strdup(tmpname);
 
 	err |= (fprintf(ctx->f,
 				"%s<outline title=\"%s\" text=\"%s\" description=\"%s\" type=\"%s\" %s%s>\n",
@@ -114,7 +107,7 @@ static void rssyl_opml_export_func(FolderItem *item, gpointer data)
 	
 	if( err ) {
 		log_warning(LOG_PROTOCOL,
-				"Error while writing '%s' to feed export list.\n",
+				_("RSSyl: Error while writing '%s' to feed export list.\n"),
 				item->name);
 		debug_print("Error while writing '%s' to feed_export list.\n",
 				item->name);
@@ -124,9 +117,9 @@ static void rssyl_opml_export_func(FolderItem *item, gpointer data)
 void rssyl_opml_export(void)
 {
 	FILE *f;
-	gchar *opmlfile, *tmpdate, *indent;
+	gchar *opmlfile, *tmp;
 	time_t tt = time(NULL);
-	RSSylOpmlExportCtx *ctx = NULL;
+	RSSylOpmlCtx *ctx = NULL;
 	gboolean err = FALSE;
 
 	opmlfile = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
@@ -137,14 +130,14 @@ void rssyl_opml_export(void)
 	
 	if( (f = g_fopen(opmlfile, "w")) == NULL ) {
 		log_warning(LOG_PROTOCOL,
-				"Couldn't open file '%s' for feed list exporting: %s\n",
+				_("RSSyl: Couldn't open file '%s' for feed list exporting: %s\n"),
 				opmlfile, g_strerror(errno));
-		debug_print("Couldn't open feed list export file, returning.\n");
+		debug_print("RSSyl: Couldn't open feed list export file, returning.\n");
 		g_free(opmlfile);
 		return;
 	}
 
-	tmpdate = createRFC822Date(&tt);
+	tmp = createRFC822Date(&tt);
 
 	/* Write OPML header */
 	err |= (fprintf(f,
@@ -155,20 +148,22 @@ void rssyl_opml_export(void)
 				"\t\t<dateCreated>%s</dateCreated>\n"
 				"\t</head>\n"
 				"\t<body>\n",
-				tmpdate) < 0);
-	g_free(tmpdate);
+				tmp) < 0);
+	g_free(tmp);
 
-	ctx = g_new0(RSSylOpmlExportCtx, 1);
+	ctx = g_new0(RSSylOpmlCtx, 1);
 	ctx->f = f;
 	ctx->depth = 1;
 
 	folder_func_to_all_folders(
 			(FolderItemFunc)rssyl_opml_export_func, ctx);
 
-	for( ctx->depth--; ctx->depth >= 2; ctx->depth-- ) {
-		indent = g_strnfill(ctx->depth, '\t');
-		err |= (fprintf(ctx->f, "%s</outline>\n", indent) < 0);
-		g_free(indent);
+	/* Print close all open <outline> tags if needed. */
+	while( ctx->depth > 2 ) {
+		ctx->depth--;
+		tmp = g_strnfill(ctx->depth, '\t');
+		err |= (fprintf(f, "%s</outline>\n", tmp) < 0);
+		g_free(tmp);
 	}
 
 	err |= (fprintf(f,
@@ -176,84 +171,13 @@ void rssyl_opml_export(void)
 				"</opml>\n") < 0);
 
 	if( err ) {
-		log_warning(LOG_PROTOCOL, "Error during writing feed export file.\n");
-		debug_print("Error during writing feed export file.");
+		log_warning(LOG_PROTOCOL, _("RSSyl: Error during writing feed export file.\n"));
+		debug_print("RSSyl: Error during writing feed export file.\n");
 	}
 
-	debug_print("Feed export finished.\n");
+	debug_print("RSSyl: Feed export finished.\n");
 
 	fclose(f);
 	g_free(opmlfile);
 	g_free(ctx);
 }
-
-static void rssyl_opml_import_node(xmlNodePtr node,
-		FolderItem *parent, gint depth)
-{
-	xmlNodePtr curn;
-	gchar *url = NULL, *title = NULL, *nodename = NULL;
-	FolderItem *item = NULL;
-
-	if( node == NULL )
-		return;
-
-	for( curn = node; curn; curn = curn->next ) {
-		nodename = g_ascii_strdown((gchar *)curn->name, -1);
-		if( curn->type == XML_ELEMENT_NODE &&
-				!strcmp(nodename, "outline") ) {
-
-			url = (gchar *)xmlGetProp(curn, (xmlChar *)"xmlUrl");
-			title = (gchar *)xmlGetProp(curn, (xmlChar *)"title");
-			if (!title)
-				title = (gchar *)xmlGetProp(curn, (xmlChar *)"text");
-			
-			debug_print("Adding '%s' (%s)\n", title, (url ? url : "folder") );
-			if( url != NULL )
-				item = rssyl_subscribe_new_feed(parent, url, FALSE);
-			else if (title != NULL)
-				item = folder_create_folder(parent, title);
-			else
-				item = NULL;
-			if (item)
-				rssyl_opml_import_node(curn->children, item, depth + 1);
-		}
-		g_free(nodename);
-	}
-}
-
-void rssyl_opml_import(const gchar *opmlfile, FolderItem *parent)
-{
-	xmlDocPtr doc;
-	xmlNodePtr node;
-	xmlXPathContextPtr context;
-	xmlXPathObjectPtr result;
-	gchar *rootnode = NULL;
-
-	doc = xmlParseFile(opmlfile);
-	if( doc == NULL )
-		return;
-
-	node = xmlDocGetRootElement(doc);
-	rootnode = g_ascii_strdown((gchar *)node->name, -1);
-	if( !strcmp(rootnode, "opml") ) {
-		gchar *xpath = "/opml/body";
-		context = xmlXPathNewContext(doc);
-		if( !(result = xmlXPathEval((xmlChar *)xpath, context)) ) {
-			g_free(rootnode);
-			xmlFreeDoc(doc);
-			return;
-		}
-
-		node = result->nodesetval->nodeTab[0];
-
-		debug_print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
-		rssyl_opml_import_node(node->children, parent, 2);
-		debug_print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
-
-		xmlXPathFreeNodeSetList(result);
-		xmlXPathFreeContext(context);
-		xmlFreeDoc(doc);
-	}
-
-	g_free(rootnode);
-}
diff --git a/src/plugins/rssyl/opml.h b/src/plugins/rssyl/opml_export.h
similarity index 64%
rename from src/plugins/rssyl/opml.h
rename to src/plugins/rssyl/opml_export.h
index 9a8aef2..6e89149 100644
--- a/src/plugins/rssyl/opml.h
+++ b/src/plugins/rssyl/opml_export.h
@@ -4,6 +4,5 @@
 #include "rssyl.h"
 
 void rssyl_opml_export(void);
-void rssyl_opml_import(const gchar *opmlfile, FolderItem *parent);
 
 #endif /* __RSSYL_OPML */
diff --git a/src/plugins/rssyl/opml_import.c b/src/plugins/rssyl/opml_import.c
new file mode 100644
index 0000000..2a34f5d
--- /dev/null
+++ b/src/plugins/rssyl/opml_import.c
@@ -0,0 +1,110 @@
+/*
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
+ *
+ * - OPML import handling
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <glib/gi18n.h>
+
+/* Claws Mail includes */
+#include <folder.h>
+#include <alertpanel.h>
+#include <common/utils.h>
+
+/* Local includes */
+#include "rssyl_feed.h"
+#include "opml_import.h"
+
+gint rssyl_folder_depth(FolderItem *item)
+{
+	gint i;
+
+	for( i = -1; item != NULL; item = folder_item_parent(item), i++ ) {}
+	return i;
+}
+
+/* This gets called from the libfeed's OPML parser as a user function for
+ * each <outline ...> from the .opml file.
+ * It creates a folder or subscribes a feed, while keeping track of the
+ * location inside folder hierarchy (using depth and linked list of parent
+ * folders up to the root). */
+void rssyl_opml_import_func(gchar *title, gchar *url, gint depth, gpointer data)
+{
+	OPMLImportCtx *ctx = (OPMLImportCtx *)data;
+	gchar *tmp = NULL;
+	FolderItem *new_item;
+	gboolean nulltitle = FALSE;
+	gint i = 1;
+
+	debug_print("depth %d, ctx->depth %d\n", depth, ctx->depth);
+	while (depth < ctx->depth) {
+		/* We've gone up at least one level, need to find correct parent */
+		ctx->current = g_slist_delete_link(ctx->current, ctx->current);
+		ctx->depth--;
+	}
+
+	debug_print("OPML_IMPORT: %s %s (%s)\n",
+			(url != NULL ? "feed": "folder"), title, url);
+
+	if( title == NULL ) {
+		debug_print("NULL title received, substituting a placeholder title\n");
+		title = g_strdup(_("Untitled"));
+		nulltitle = TRUE;
+	}
+
+	/* If URL is not given, then it's a folder */
+	if( url == NULL ) {
+		/* Find an unused name for new folder */
+		tmp = g_strdup(title);
+		while (folder_find_child_item_by_name((FolderItem *)ctx->current->data, tmp)) {
+			debug_print("RSSyl: Folder '%s' already exists, trying another name\n",
+					title);
+			g_free(tmp);
+			tmp = g_strdup_printf("%s__%d", title, ++i);
+		}
+
+		/* Create the folder */
+		new_item = folder_create_folder((FolderItem *)ctx->current->data, tmp);
+		if (!new_item) {
+			alertpanel_error(_("Can't create the folder '%s'."), tmp);
+			g_free(tmp);
+		}
+
+		if (nulltitle) {
+			g_free(title);
+			title = NULL;
+		}
+
+		ctx->current = g_slist_prepend(ctx->current, new_item);
+		ctx->depth++;
+	} else {
+		/* We have URL, try to add new feed... */
+		new_item = rssyl_feed_subscribe_new((FolderItem *)ctx->current->data,
+				url, TRUE);
+		/* ...and rename it if needed */
+		if (new_item != NULL && strcmp(title, new_item->name))
+			folder_item_rename(new_item, title);
+	}
+}
diff --git a/src/plugins/rssyl/opml_import.h b/src/plugins/rssyl/opml_import.h
new file mode 100644
index 0000000..91b71aa
--- /dev/null
+++ b/src/plugins/rssyl/opml_import.h
@@ -0,0 +1,15 @@
+#ifndef __OPML_IMPORT
+#define __OPML_IMPORT
+
+struct _OPMLImportCtx {
+	GSList *current;
+	gint depth;
+	gint failures;
+};
+
+typedef struct _OPMLImportCtx OPMLImportCtx;
+
+gint rssyl_folder_depth(FolderItem *item);
+void rssyl_opml_import_func(gchar *title, gchar *url, gint depth, gpointer data);
+
+#endif /* __OPML_IMPORT */
diff --git a/src/plugins/rssyl/parse822.c b/src/plugins/rssyl/parse822.c
new file mode 100644
index 0000000..846fb6d
--- /dev/null
+++ b/src/plugins/rssyl/parse822.c
@@ -0,0 +1,352 @@
+/*
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+/* Global includes */
+#include <sys/stat.h>
+#include <glib.h>
+#include <pthread.h>
+
+/* Claws Mail includes */
+#include <common/claws.h>
+#include <procheader.h>
+#include <common/utils.h>
+#include <main.h>
+
+/* Local includes */
+#include "libfeed/feed.h"
+#include "libfeed/feeditem.h"
+#include "libfeed/date.h"
+#include "parse822.h"
+#include "rssyl_feed.h"
+#include "rssyl_parse_feed.h"
+#include "strutils.h"
+
+/* rssyl_parse_folder_item_file()
+ *
+ * Parse a RFC822-formatted feed item given by "path", and returns a
+ * pointer to a newly-allocated FeedItem struct, which contains all required data.
+ *
+ */
+FeedItem *rssyl_parse_folder_item_file(gchar *path)
+{
+	gchar *contents, **lines, **line, **splid;
+	GError *error = NULL;
+	FeedItem *item;
+	RFeedCtx *ctx;
+	gint i = 0;
+	gboolean parsing_headers = TRUE, past_html_tag = FALSE, past_endhtml_tag = FALSE;
+	gboolean started_author = FALSE, started_subject = FALSE;
+	gboolean started_link = FALSE, started_clink = FALSE, got_original_title = FALSE;
+
+	debug_print("RSSyl: parsing '%s'\n", path);
+
+	g_file_get_contents(path, &contents, NULL, &error);
+
+	if( error )
+		g_warning("GError: '%s'\n", error->message);
+
+	if( contents != NULL ) {
+		lines = strsplit_no_copy(contents, '\n');
+	} else {
+		g_warning("Badly formatted file found, ignoring: '%s'\n", path);
+		return NULL;
+	}
+
+	ctx = g_new0(RFeedCtx, 1);
+	ctx->path = g_strdup(path); /* store filesystem path to source file */
+	ctx->last_seen = 0;
+
+	item = feed_item_new(NULL);
+	item->data = ctx;
+
+	while( lines[i] ) {
+		if( parsing_headers && lines[i] && !strlen(lines[i]) ) {
+			parsing_headers = FALSE;
+			debug_print("RSSyl: finished parsing headers\n");
+		}
+
+		if( parsing_headers ) {
+			line = g_strsplit(lines[i], ": ", 2);
+			if( line[0] && line[1] && strlen(line[0]) && lines[i][0] != ' ') {
+				started_author = FALSE;
+				started_subject = FALSE;
+				started_link = FALSE;
+				started_clink = FALSE;
+
+				/* Author */
+				if( !strcmp(line[0], "From") ) {
+					feed_item_set_author(item, line[1]);
+					debug_print("RSSyl: got author '%s'\n", feed_item_get_author(item));
+					started_author = TRUE;
+				}
+
+				/* Date */
+				if( !strcmp(line[0], "Date") ) {
+					feed_item_set_date_modified(item,
+							procheader_date_parse(NULL, line[1], 0));
+					debug_print("RSSyl: got date \n" );
+				}
+
+				/* Title */
+				if( !strcmp(line[0], "Subject") && !got_original_title ) {
+					feed_item_set_title(item,line[1]);
+					debug_print("RSSyl: got title '%s'\n", feed_item_get_title(item));
+					started_subject = TRUE;
+				}
+
+				/* Original (including HTML) title - Atom feeds */
+				if( !strcmp(line[0], "X-RSSyl-OrigTitle") ) {
+					feed_item_set_title(item, line[1]);
+					debug_print("RSSyl: got original title '%s'\n",
+							feed_item_get_title(item));
+					got_original_title = TRUE;
+				}
+
+				/* URL */
+				if( !strcmp(line[0], "X-RSSyl-URL") ) {
+					feed_item_set_url(item, line[1]);
+					debug_print("RSSyl: got link '%s'\n", feed_item_get_url(item));
+					started_link = TRUE;
+				}
+
+				/* Last-Seen timestamp */
+				if( !strcmp(line[0], "X-RSSyl-Last-Seen") ) {
+					ctx->last_seen = atol(line[1]);
+					debug_print("RSSyl: got last_seen timestamp %ld\n", ctx->last_seen);
+				}
+
+				/* ID */
+				if( !strcmp(line[0], "Message-ID") ) {
+					splid = g_strsplit_set(line[1], "<>", 3);
+					if( strlen(splid[1]) != 0 )
+						feed_item_set_id(item, splid[1]);
+					g_strfreev(splid);
+				}
+
+				/* Feed comments */
+				if( !strcmp(line[0], "X-RSSyl-Comments") ) {
+					feed_item_set_comments_url(item, line[1]);
+					debug_print("RSSyl: got clink '%s'\n", feed_item_get_comments_url(item));
+					started_clink = TRUE;
+				}
+
+				/* References */
+				if( !strcmp(line[0], "References") ) {
+					splid = g_strsplit_set(line[1], "<>", 3);
+					if( strlen(splid[1]) != 0 )
+						feed_item_set_parent_id(item, line[1]);
+					g_strfreev(splid);
+				}
+
+			} else if (lines[i][0] == ' ') {
+				gchar *tmp = NULL;
+				/* continuation line */
+				if (started_author) {
+					tmp = g_strdup_printf("%s %s", feed_item_get_author(item), lines[i]+1);
+					feed_item_set_author(item, tmp);
+					debug_print("RSSyl: updated author to '%s'\n", tmp);
+					g_free(tmp);
+				} else if (started_subject) {
+					tmp = g_strdup_printf("%s %s", feed_item_get_title(item), lines[i]+1);
+					feed_item_set_title(item, tmp);
+					debug_print("RSSyl: updated title to '%s'\n", tmp);
+					g_free(tmp);
+				} else if (started_link) {
+					tmp = g_strdup_printf("%s%s", feed_item_get_url(item), lines[i]+1);
+					feed_item_set_url(item, tmp);
+					debug_print("RSSyl: updated link to '%s'\n", tmp);
+					g_free(tmp);
+				} else if (started_clink) {
+					tmp = g_strdup_printf("%s%s", feed_item_get_comments_url(item), lines[i]+1);
+					feed_item_set_comments_url(item, tmp);
+					debug_print("RSSyl: updated comments_link to '%s'\n", tmp);
+				}
+			}
+			g_strfreev(line);
+		} else {
+			if( !strcmp(lines[i], RSSYL_TEXT_START) ) {
+				debug_print("RSSyl: Leading html tag found at line %d\n", i);
+				past_html_tag = TRUE;
+				i++;
+				continue;
+			}
+			while( past_html_tag && !past_endhtml_tag && lines[i] ) {
+				if( !strcmp(lines[i], RSSYL_TEXT_END) ) {
+					debug_print("RSSyl: Trailing html tag found at line %d\n", i);
+					past_endhtml_tag = TRUE;
+					i++;
+					continue;
+				}
+				if( feed_item_get_text(item) != NULL ) {
+					gint e_len, n_len;
+					e_len = strlen(item->text);
+					n_len = strlen(lines[i]);
+					item->text = g_realloc(item->text, e_len + n_len + 2);
+					*(item->text+e_len) = '\n';
+					strcpy(item->text+e_len+1, lines[i]);
+					*(item->text+e_len+n_len+1) = '\0';
+				} else {
+					item->text = g_strdup(lines[i]);
+				}
+				i++;
+			}
+
+			if( lines[i] == NULL )
+				return item;
+		}
+
+		i++;
+	}
+	g_free(lines);
+	g_free(contents);
+	return item;
+}
+
+static void rssyl_flush_folder_func(gpointer data, gpointer user_data)
+{
+	FeedItem *item = (FeedItem *)data;
+	RFeedCtx *ctx = (RFeedCtx *)item->data;
+
+	if( ctx != NULL && ctx->path != NULL)
+		g_free(ctx->path);
+	feed_item_free(item);
+}
+
+static void rssyl_folder_read_existing_real(RFolderItem *ritem)
+{
+	gchar *path = NULL, *fname = NULL;
+	DIR *dp;
+	struct dirent *d;
+	struct stat st;
+	gint num;
+	FeedItem *item = NULL;
+	RFeedCtx *ctx;
+
+	g_return_if_fail(ritem != NULL);
+
+	path = folder_item_get_path(&ritem->item);
+	g_return_if_fail(path != NULL);
+
+	debug_print("RSSyl: reading existing items from '%s'\n", path);
+
+	/* Flush contents if any, so we can add new */
+	if( g_slist_length(ritem->items) > 0 ) {
+		g_slist_foreach(ritem->items, (GFunc)rssyl_flush_folder_func, NULL);
+		g_slist_free(ritem->items);
+	}
+	ritem->items = NULL;
+	ritem->last_update = 0;
+
+	if( (dp = opendir(path)) == NULL ) {
+		FILE_OP_ERROR(path, "opendir");
+		g_free(path);
+		return;
+	}
+
+	while( (d = readdir(dp)) != NULL ) {
+		if( claws_is_exiting() ) {
+			closedir(dp);
+			g_free(path);
+			return;
+		}
+
+		if( d->d_name[0] != '.' && (num = to_number(d->d_name)) > 0 ) {
+			fname = g_strdup_printf("%s%c%s", path, G_DIR_SEPARATOR, d->d_name);
+			if( g_stat(fname, &st) < 0 ) {
+				debug_print("RSSyl: couldn't stat() file '%s', ignoring it\n", fname);
+				g_free(fname);
+				continue;
+			}
+
+			if( !S_ISREG(st.st_mode)) {
+				debug_print("RSSyl: not a regular file: '%s', ignoring it\n", fname);
+				g_free(fname);
+				continue;
+			}
+
+			debug_print("RSSyl: starting to parse '%s'\n", d->d_name);
+			if( (item = rssyl_parse_folder_item_file(fname)) != NULL ) {
+				/* Find latest timestamp */
+				ctx = (RFeedCtx *)item->data;
+				if( ritem->last_update < ctx->last_seen )
+					ritem->last_update = ctx->last_seen;
+				debug_print("RSSyl: Appending '%s'\n", feed_item_get_title(item));
+				ritem->items = g_slist_prepend(ritem->items, item);
+			}
+			g_free(fname);
+		}
+	}
+
+	closedir(dp);
+	g_free(path);
+
+	ritem->items = g_slist_reverse(ritem->items);
+}
+
+#ifdef USE_PTHREAD
+static void *rssyl_read_existing_thr(void *arg)
+{
+	RParseCtx *ctx = (RParseCtx *)arg;
+
+	rssyl_folder_read_existing_real(ctx->ritem);
+	ctx->ready = TRUE;
+	return NULL;
+}
+#endif
+
+void rssyl_folder_read_existing(RFolderItem *ritem)
+{
+#ifdef USE_PTHREAD
+	RParseCtx *ctx;
+	pthread_t pt;
+#endif
+
+	g_return_if_fail(ritem != NULL);
+
+
+#ifdef USE_PTHREAD
+	ctx = g_new0(RParseCtx, 1);
+	ctx->ritem = ritem;
+	ctx->ready = FALSE;
+
+	if( pthread_create(&pt, PTHREAD_CREATE_JOINABLE, rssyl_read_existing_thr,
+				(void *)ctx) != 0 ) {
+		/* Couldn't create thread, let's continue non-threaded. */
+		rssyl_folder_read_existing_real(ritem);
+	} else {
+		/* Thread started, wait until it is done. */
+		debug_print("RSSyl: waiting for thread to finish\n");
+		while( !ctx->ready ) {
+			claws_do_idle();
+		}
+
+		debug_print("RSSyl: thread finished\n");
+		pthread_join(pt, NULL);
+	}
+
+	g_free(ctx);
+#else
+	rssyl_folder_read_existing_real(ritem);
+#endif
+}
diff --git a/src/plugins/rssyl/parse822.h b/src/plugins/rssyl/parse822.h
new file mode 100644
index 0000000..94318fc
--- /dev/null
+++ b/src/plugins/rssyl/parse822.h
@@ -0,0 +1,19 @@
+#ifndef __RSSYL_PARSE822_H
+#define __RSSYL_PARSE822_H
+
+#include <glib.h>
+
+#include "libfeed/feeditem.h"
+#include "rssyl.h"
+
+struct _RFeedCtx {
+	gchar *path;
+	time_t last_seen;
+};
+
+typedef struct _RFeedCtx RFeedCtx;
+
+FeedItem *rssyl_parse_folder_item_file(gchar *path);
+void rssyl_folder_read_existing(RFolderItem *ritem);
+
+#endif /* __RSSYL_PARSE822_H */
diff --git a/src/plugins/rssyl/parsers.c b/src/plugins/rssyl/parsers.c
deleted file mode 100644
index bc491ae..0000000
--- a/src/plugins/rssyl/parsers.c
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2004 Hiroyuki Yamamoto
- * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
- *
- * - various feed parsing functions
- * - this file could use some sorting and/or splitting
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include <glib.h>
-#include <libxml/parser.h>
-#include <libxml/xpath.h>
-#include <libxml/HTMLtree.h>
-
-#include "date.h"
-#include "feed.h"
-#include "strreplace.h"
-#include "utils.h"
-#include "procheader.h"
-
-gint rssyl_parse_rdf(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent)
-{
-	xmlNodePtr rnode, node, n;
-	RSSylFeedItem *fitem = NULL;
-	gint count = 0;
-	gchar *content = NULL;
-	g_return_val_if_fail(doc != NULL, 0);
-	g_return_val_if_fail(ritem != NULL, 0);
-#ifdef RSSYL_DEBUG
-	gchar *fetched = NULL;
-#endif	/* RSSYL_DEBUG */
-
-	if( ritem->contents == NULL )
-		rssyl_read_existing(ritem);
-
-	rnode = xmlDocGetRootElement(doc);
-
-	for( node = rnode->children; node; node = node->next ) {
-		if( !xmlStrcmp(node->name, "item") ) {
-			/* We've found an "item" tag, let's poke through its contents */
-			fitem = g_new0(RSSylFeedItem, 1);
-			fitem->date = 0;
-#ifdef RSSYL_DEBUG
-			fetched = xmlGetProp(rnode, "fetched");
-			fitem->debug_fetched = atoll(fetched);
-			xmlFree(fetched);
-#endif	/* RSSYL_DEBUG */
-
-			for( n = node->children; n; n = n->next ) {
-				/* Title */
-				if( !xmlStrcmp(n->name, "title") ) {
-					content = xmlNodeGetContent(n);
-					fitem->title = rssyl_format_string(content, TRUE, TRUE);
-					xmlFree(content);
-					debug_print("RSSyl: XML - RDF title is '%s'\n", fitem->title);
-				}
-
-				/* Text */
-				if( !xmlStrcmp(n->name, "description") ) {
-					content = xmlNodeGetContent(n);
-					fitem->text = rssyl_format_string(content, FALSE, FALSE);
-					xmlFree(content);
-					debug_print("RSSyl: XML - got RDF text\n");
-				}
-
-				/* URL */
-				if( !xmlStrcmp(n->name, "link") ) {
-					content = xmlNodeGetContent(n);
-					fitem->link = rssyl_format_string(content, FALSE, TRUE);
-					xmlFree(content);
-					debug_print("RSSyl: XML - RDF link is '%s'\n", fitem->link);
-				}
-
-				/* Date - rfc822 format */
-				if( !xmlStrcmp(n->name, "pubDate") ) {
-					content = xmlNodeGetContent(n);
-					fitem->date = procheader_date_parse(NULL, content, 0);
-					xmlFree(content);
-					if( fitem->date > 0 ) {
-						debug_print("RSSyl: XML - RDF pubDate found\n" );
-					} else
-						fitem->date = 0;
-				}
-				/* Date - ISO8701 format */
-				if( !xmlStrcmp(n->name, "date") &&
-						(n->ns && n->ns->prefix && (!xmlStrcmp(n->ns->prefix, "ns")
-						 || !xmlStrcmp(n->ns->prefix, "dc"))) ) {
-					content = xmlNodeGetContent(n);
-					fitem->date = parseISO8601Date(content);
-					xmlFree(content);
-					debug_print("RSSyl: XML - RDF date found\n" );
-				}
-
-				/* Author */
-				if( !xmlStrcmp(n->name, "creator") ) {
-					content = xmlNodeGetContent(n);
-					fitem->author = rssyl_format_string(content, TRUE, TRUE);
-					xmlFree(content);
-					debug_print("RSSyl: XML - RDF author is '%s'\n", fitem->author);
-				}
-			}
-		}
-
-		if( fitem && fitem->link && fitem->title ) {
-			if (rssyl_add_feed_item(ritem, fitem) == FALSE) {
-				rssyl_free_feeditem(fitem);
-				fitem = NULL;
-			}
-			fitem = NULL;
-			count++;
-		}
-	}
-
-	return count;
-}
-
-
-/* rssyl_parse_rss()
- *
- * This is where we parse the fetched rss document and create a
- * RSSylFolderItem from it. Returns number of parsed items
- */
-gint rssyl_parse_rss(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent)
-{
-	xmlXPathContextPtr context;
-	xmlXPathObjectPtr result;
-	xmlNodePtr node, n, rnode;
-	gint i, count = 0;
-	RSSylFeedItem *fitem = NULL;
-	gchar *xpath;
-	gboolean got_encoded, got_author;
-	gchar *rootnode = NULL;
-	RSSylFeedItemMedia *media;
-	gchar *media_url, *media_type;
-	gulong media_size = 0;
-#ifdef RSSYL_DEBUG
-	gchar *fetched = NULL;
-#endif	/* RSSYL_DEBUG */
-
-	g_return_val_if_fail(doc != NULL, 0);
-	g_return_val_if_fail(ritem != NULL, 0);
-
-	if( ritem->contents == NULL )
-		rssyl_read_existing(ritem);
-
-	rnode = xmlDocGetRootElement(doc);
-
-	rootnode = g_ascii_strdown(rnode->name, -1);
-	xpath = g_strconcat("/", rootnode,
-				"/channel/item",	NULL);
-	g_free(rootnode);
-	context = xmlXPathNewContext(doc);
-	if( !(result = xmlXPathEvalExpression(xpath, context)) ){
-		debug_print("RSSyl: XML - no result found for '%s'\n", xpath);
-		xmlXPathFreeContext(context);
-		g_free(xpath);
-		return 0;
-	}
-
-	g_free(xpath);
-
-	for( i = 0; i < result->nodesetval->nodeNr; i++ ) {
-		node = result->nodesetval->nodeTab[i];
-		
-		if ((n = node->children) == NULL)
-			continue;
-
-		fitem = g_new0(RSSylFeedItem, 1);
-		fitem->media = NULL;
-		fitem->date = 0;
-#ifdef RSSYL_DEBUG
-		fetched = xmlGetProp(rnode, "fetched");
-		fitem->debug_fetched = atoll(fetched);
-		xmlFree(fetched);
-#endif	/* RSSYL_DEBUG */
-		fitem->text = NULL;
-		
-		if (parent)
-			fitem->parent_link = g_strdup(parent);
-
-		got_encoded = FALSE;
-		got_author = FALSE;
-		do {
-			gchar *content = NULL;
-
-			/* Title */
-			if( !xmlStrcmp(n->name, "title") ) {
-				content = xmlNodeGetContent(n);
-				fitem->title = rssyl_format_string(content, TRUE, TRUE);
-				xmlFree(content);
-				debug_print("RSSyl: XML - item title: '%s'\n", fitem->title);
-			}
-
-			/* Text */
-			if( !xmlStrcmp(n->name, "description") ) {
-				if( (fitem->text == NULL) && (got_encoded == FALSE) ) {
-					content = xmlNodeGetContent(n);
-					debug_print("RSSyl: XML - item text (description) caught\n");
-					fitem->text = rssyl_format_string(content, FALSE, FALSE);
-					xmlFree(content);
-				}
-			}
-			if( !xmlStrcmp(n->name, "encoded") &&
-					(n->ns && n->ns->prefix && !xmlStrcmp(n->ns->prefix, "content")) ) {
-				debug_print("RSSyl: XML - item text (content) caught\n");
-
-				if (fitem->text != NULL)
-					g_free(fitem->text); /* free "description" */
-					
-				content = xmlNodeGetContent(n);
-				fitem->text = rssyl_format_string(content, FALSE, FALSE);
-				xmlFree(content);
-				got_encoded = TRUE;
-			}
-
-			/* URL link to the original post */
-			if( !xmlStrcmp(n->name, "link") &&
-					(!n->ns || !n->ns->prefix || !strlen(n->ns->prefix)) ) {
-				content = xmlNodeGetContent(n);
-				fitem->link = rssyl_format_string(content, FALSE, TRUE);
-				xmlFree(content);
-				debug_print("RSSyl: XML - item link: '%s'\n", fitem->link);
-			}
-
-			/* GUID - sometimes used as link */
-			if( !xmlStrcmp(n->name, "guid") ) {
-				gchar *tmp = xmlGetProp(n, "isPermaLink");
-				content = xmlNodeGetContent(n);
-				fitem->id_is_permalink = FALSE;
-				if( !tmp || xmlStrcmp(tmp, "false") )	/* permalink? */
-					fitem->id_is_permalink = TRUE;
-				fitem->id = rssyl_format_string(content, FALSE, TRUE);
-				xmlFree(content);
-				debug_print("RSSyl: XML - item guid: '%s'\n", fitem->id);
-				xmlFree(tmp);
-			}
-
-			/* Date - rfc822 format */
-			if( !xmlStrcmp(n->name, "pubDate") ) {
-				content = xmlNodeGetContent(n);
-				fitem->date = procheader_date_parse(NULL, content, 0);
-				xmlFree(content);
-				if( fitem->date > 0 ) {
-					debug_print("RSSyl: XML - item date found: %d\n", (gint)fitem->date);
-				} else
-					fitem->date = 0;
-			}
-			/* Date - ISO8701 format */
-			if( !xmlStrcmp(n->name, "date") && !xmlStrcmp(n->ns->prefix, "dc") ) {
-				content = xmlNodeGetContent(n);
-				fitem->date = parseISO8601Date(content);
-				xmlFree(content);
-				debug_print("RSSyl: XML - item date found\n" );
-			}
-
-			/* Author */
-			if( !xmlStrcmp(n->name, "author") ) {
-				content = xmlNodeGetContent(n);
-				fitem->author = rssyl_format_string(content, TRUE, TRUE);
-				xmlFree(content);
-				debug_print("RSSyl: XML - item author: '%s'\n", fitem->author);
-				got_author = TRUE;
-			}
-
-			if( !xmlStrcmp(n->name, "creator")
-					&& !xmlStrcmp(n->ns->prefix, "dc") && !got_author) {
-				content = xmlNodeGetContent(n);
-				fitem->author = rssyl_format_string(content, TRUE, TRUE);
-				xmlFree(content);
-				debug_print("RSSyl: XML - item author (creator): '%s'\n", fitem->author);
-			}
-
-			/* Media enclosure */
-			if( !xmlStrcmp(n->name, "enclosure") ) {
-				gchar *tmp = xmlGetProp(n, "length");
-				media_url = xmlGetProp(n, "url");
-				media_type = xmlGetProp(n, "type");
-				media_size = (tmp ? atoi(tmp) : 0);
-				xmlFree(tmp);
-
-				if( media_url != NULL &&
-						media_type != NULL &&
-						media_size != 0 ) {
-					debug_print("RSSyl: XML - enclosure: '%s' [%s] (%ld)\n",
-							media_url, media_type, media_size);
-					media = g_new(RSSylFeedItemMedia, 1);
-					media->url = media_url;
-					media->type = media_type;
-					media->size = media_size;
-					fitem->media = media;
-				} else {
-					debug_print("RSSyl: XML - enclosure found, but some data is missing\n");
-					g_free(media_url);
-					g_free(media_type);
-				}
-			}
-
-			/* Comments */
-			if( !xmlStrcmp(n->name, "commentRSS") || !xmlStrcmp(n->name, "commentRss") ) {
-				content = xmlNodeGetContent(n);
-				fitem->comments_link = rssyl_format_string(content, FALSE, TRUE);
-				xmlFree(content);
-				debug_print("RSSyl: XML - comments_link: '%s'\n", fitem->comments_link);
-			}
-		} while( (n = n->next) != NULL);
-
-		if( (fitem->link || fitem->id) && fitem->title ) {
-			if (rssyl_add_feed_item(ritem, fitem) == FALSE) {
-				rssyl_free_feeditem(fitem);
-				fitem = NULL;
-			}
-			count++;
-		}
-	}
-
-	xmlXPathFreeObject(result);
-	xmlXPathFreeContext(context);
-
-	return count;
-}
-
-/* rssyl_parse_atom()
- *
- * This is where we parse the fetched atom document and create a
- * RSSylFolderItem from it. Returns number of parsed items
- */
-gint rssyl_parse_atom(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent)
-{
-	xmlNodePtr node, n, h;
-	xmlBufferPtr buf = NULL;
-	gint count = 0;
-	RSSylFeedItem *fitem = NULL;
-	RSSylFeedItemMedia *media = NULL;
-	gchar *link_type, *link_href, *link_rel, *tmp, *content = NULL;
-	gulong link_size;
-
-	g_return_val_if_fail(doc != NULL, 0);
-	g_return_val_if_fail(ritem != NULL, 0);
-
-	if( ritem->contents == NULL )
-		rssyl_read_existing(ritem);
-
-	node = xmlDocGetRootElement(doc);
-
-	if (node == NULL)
-		return 0;
-
-	node = node->children;
-
-	for (; node; node = node->next) {
-		gboolean got_content = FALSE;
-		if (xmlStrcmp(node->name, "entry")) {
-			continue;
-		}
-	
-		n = node->children;
-		fitem = g_new0(RSSylFeedItem, 1);
-		fitem->date = 0;
-		fitem->date_published = 0;
-		fitem->text = NULL;
-		
-		if (parent)
-			fitem->parent_link = g_strdup(parent);
-
-		do {
-			/* Title */
-			if( !xmlStrcmp(n->name, "title") ) {
-				content = xmlNodeGetContent(n);
-				fitem->title = rssyl_format_string(content, TRUE, TRUE);
-				xmlFree(content);
-				debug_print("RSSyl: XML - Atom item title: '%s'\n", fitem->title);
-			}
-
-			/* ID */
-			if( !xmlStrcmp(n->name, "id") ) {
-				content = xmlNodeGetContent(n);
-				fitem->id = g_strdup_printf("%s%s", (parent?"comment-":""), content);
-				xmlFree(content);
-				debug_print("RSSyl: XML - Atom id: '%s'\n", fitem->id);
-			}
-
-			/* Text */
-			if( !xmlStrcmp(n->name, "summary") && !got_content ) {
-				content = xmlNodeGetContent(n);
-				debug_print("RSSyl: XML - Atom item text (summary) caught\n");
-				fitem->text = rssyl_format_string(content, FALSE, FALSE);
-				xmlFree(content);
-			}
-
-			if( !xmlStrcmp(n->name, "content") ) {
-				gchar *tmp = xmlGetProp(n, "type");
-				debug_print("RSSyl: XML - Atom item text (content) caught\n");
-				if (fitem->text)
-					g_free(fitem->text);
-				if( !xmlStrcmp(tmp, "xhtml")) {
-					for( h = n->children; h; h = h->next ) {
-						if( !xmlStrcmp(h->name, "div") ) {
-							buf = xmlBufferCreate();
-							htmlNodeDump(buf, doc, h);
-							content = g_strdup((gchar *)xmlBufferContent(buf));
-							xmlBufferFree(buf);
-						}
-					}
-				} else
-					content = xmlNodeGetContent(n);
-				xmlFree(tmp);
-				fitem->text = rssyl_format_string(content, FALSE, FALSE);
-				xmlFree(content);
-				got_content = TRUE;
-			}
-
-			/* link */
-			if( !xmlStrcmp(n->name, "link") ) {
-				link_type = xmlGetProp(n, "type");
-				link_rel = xmlGetProp(n, "rel");
-				link_href = xmlGetProp(n, "href");
-				tmp = xmlGetProp(n, "length");
-				link_size = (tmp ? atoi(tmp) : 0);
-				g_free(tmp);
-
-				if( !link_rel || (link_rel && !xmlStrcmp(link_rel, "alternate")) ) {
-					fitem->link = link_href;
-					debug_print("RSSyl: XML - Atom item link: '%s'\n", fitem->link);
-					xmlFree(link_type);
-					xmlFree(link_rel);
-				} else if( link_rel && !xmlStrcmp(link_rel, "enclosure") ) {
-					debug_print("RSSyl: XML - Atom item enclosure: '%s' (%ld) [%s]\n",
-							link_href, link_size, link_type);
-					media = g_new(RSSylFeedItemMedia, 1);
-					media->url = link_href;
-					media->type = link_type;
-					media->size = link_size;
-					fitem->media = media;
-					xmlFree(link_rel);
-				} else {
-					xmlFree(link_type);
-					xmlFree(link_rel);
-					xmlFree(link_href);
-				}
-			}
-
-			/* Date published - ISO8701 format */
-			if( !xmlStrcmp(n->name, "published") ) {
-				content = xmlNodeGetContent(n);
-				fitem->date_published = parseISO8601Date(content);
-				xmlFree(content);
-				debug_print("RSSyl: XML - Atom item 'issued' date found\n" );
-			}
-
-			/* Date modified - ISO8701 format */
-			if( !xmlStrcmp(n->name, "updated") ) {
-				content = xmlNodeGetContent(n);
-				fitem->date = parseISO8601Date(content);
-				xmlFree(content);
-				debug_print("RSSyl: XML - Atom item 'updated' date found\n" );
-			}
-
-			/* Author */
-			if( !xmlStrcmp(n->name, "author") ) {
-				xmlNodePtr subnode;
-				gchar *name = NULL, *mail = NULL;
-				gchar *tmp;
-				for (subnode = n->children; subnode; subnode = subnode->next) {
-					content = xmlNodeGetContent(subnode);
-					if (!xmlStrcmp(subnode->name, "name") && !name)
-						name = g_strdup(content);
-					if (!xmlStrcmp(subnode->name, "email") && !mail)
-						mail = g_strdup(content);
-					xmlFree(content);
-				}
-				tmp = g_strdup_printf("%s%s%s%s%s",
-							name ? name:"",
-							name && mail ? " <":(mail?"<":""),
-							mail ? mail:"",
-							mail ? ">":"",
-							!name && !mail ? "N/A":"");
-				fitem->author = rssyl_format_string(tmp, TRUE, TRUE);
-				g_free(tmp);
-				g_free(name);
-				g_free(mail);
-				debug_print("RSSyl: XML - Atom item author: '%s'\n", fitem->author);
-			}
-
-			/* Comments */
-			if( !xmlStrcmp(n->name, "commentRSS") || !xmlStrcmp(n->name, "commentRss")) {
-				content = xmlNodeGetContent(n);
-				fitem->comments_link = rssyl_format_string(content, FALSE, TRUE);
-				xmlFree(content);
-				debug_print("RSSyl: XML - comments_link: '%s'\n", fitem->comments_link);
-			}
-		} while( (n = n->next) != NULL);
-
-		if( fitem->id && fitem->title && fitem->date ) {
-
-			/* If no link is available, and we can safely guess ID
-			 * might be a (perma)link, mark it so. */
-			if (!fitem->link && fitem->id	/* no url, but we have id */
-					&& (!strncmp(fitem->id, "http:", 5) /* id looks like an url */
-						|| !strncmp(fitem->id, "https:", 6))) {
-				if (!ritem->url || strcmp(ritem->url, fitem->id)) {
-					/* id is different from feed url (good chance it is a permalink) */
-					debug_print("RSSyl: Marking ID as permalink\n");
-					fitem->id_is_permalink = TRUE;
-				}
-			}
-
-			if (rssyl_add_feed_item(ritem, fitem) == FALSE) {
-				rssyl_free_feeditem(fitem);
-				fitem = NULL;
-			}
-			count++;
-		} else
-			debug_print("RSSyl: Incomplete Atom entry, need at least 'id', 'title' and 'updated' tags\n");
-	}
-
-	return count;
-}
diff --git a/src/plugins/rssyl/parsers.h b/src/plugins/rssyl/parsers.h
deleted file mode 100644
index 48321e6..0000000
--- a/src/plugins/rssyl/parsers.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __PARSERS_H
-#define __PARSERS_H
-
-#include <glib.h>
-#include <libxml/parser.h>
-
-#include "feed.h"
-
-gint rssyl_parse_rss(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent);
-gint rssyl_parse_rdf(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent);
-gint rssyl_parse_atom(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent);
-
-#endif /* __PARSERS_H */
diff --git a/src/plugins/rssyl/plugin.c b/src/plugins/rssyl/plugin.c
index 9cf3cdc..7ade914 100644
--- a/src/plugins/rssyl/plugin.c
+++ b/src/plugins/rssyl/plugin.c
@@ -1,5 +1,5 @@
 /*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
  * Copyright (C) 1999-2004 Hiroyuki Yamamoto
  * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
  *
@@ -22,23 +22,25 @@
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
-#include "claws-features.h"
+#  include "claws-features.h"
 #endif
 
-#include <glib.h>
+/* Global includes */
 #include <glib/gi18n.h>
-
-#include "common/version.h"
-#include "claws.h"
 #include <curl/curl.h>
 
+/* Claws Mail includes */
+#include <common/claws.h>
+#include <common/version.h>
+#include <plugin.h>
+
+/* Local includes */
 #include "rssyl.h"
-#include "plugin.h"
 
 gint plugin_init(gchar **error)
 {
-	if( !check_plugin_version(MAKE_NUMERIC_VERSION(3,7,8,31),
-				VERSION_NUMERIC, PLUGIN_NAME, error) )
+	if( !check_plugin_version(MAKE_NUMERIC_VERSION(3, 7, 8, 31),
+				VERSION_NUMERIC, "RSSyl", error) )
 		return -1;
 
 	curl_global_init(CURL_GLOBAL_DEFAULT);
@@ -55,7 +57,7 @@ gboolean plugin_done(void)
 
 const gchar *plugin_name(void)
 {
-	return PLUGIN_NAME;
+	return "RSSyl";
 }
 
 const gchar *plugin_desc(void)
diff --git a/src/plugins/rssyl/rssyl.c b/src/plugins/rssyl/rssyl.c
index 670dd86..2c5a634 100644
--- a/src/plugins/rssyl/rssyl.c
+++ b/src/plugins/rssyl/rssyl.c
@@ -1,5 +1,5 @@
 /*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
  * Copyright (C) 1999-2004 Hiroyuki Yamamoto
  * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
  *
@@ -22,52 +22,73 @@
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
-#include "claws-features.h"
 #endif
 
+/* Global includes */
 #include <glib.h>
 #include <glib/gi18n.h>
-
-#ifdef G_OS_WIN32
-#  include <w32lib.h>
-#endif
-
-#include <glib.h>
 #include <curl/curl.h>
 
-#include "folder.h"
-#include "localfolder.h"
-
-#include "procheader.h"
-#include "common/utils.h"
-#include "toolbar.h"
-#include "prefs_toolbar.h"
-
-#include "main.h"
-
-#include "feed.h"
-#include "feedprops.h"
-#include "opml.h"
+/* Claws Mail includes */
+#include <folder.h>
+#include <procmsg.h>
+#include <localfolder.h>
+#include <common/utils.h>
+#include <main.h>
+#include <mh.h>
+#include <xml.h>
+#include <toolbar.h>
+#include <prefs_toolbar.h>
+
+/* Local includes */
+#include "libfeed/feeditem.h"
 #include "rssyl.h"
+#include "rssyl_deleted.h"
 #include "rssyl_gtk.h"
+#include "rssyl_feed.h"
 #include "rssyl_prefs.h"
-#include "strreplace.h"
+#include "rssyl_update_feed.h"
+#include "rssyl_update_format.h"
+#include "opml_import.h"
+#include "opml_export.h"
+#include "strutils.h"
+
+FolderClass rssyl_class;
 
 static gint rssyl_create_tree(Folder *folder);
+static gint rssyl_scan_tree(Folder *folder);
 
 static gboolean existing_tree_found = FALSE;
 
 static void rssyl_init_read_func(FolderItem *item, gpointer data)
 {
+	RFolderItem *ritem = (RFolderItem *)item;
+	RPrefs *rsprefs = NULL;
+
 	if( !IS_RSSYL_FOLDER_ITEM(item) )
 		return;
 
 	existing_tree_found = TRUE;
 
-	if( folder_item_parent(item) == NULL )
+	/* Don't do anything if we're on root of our folder tree or on
+	 * a regular folder (no feed) */
+	if( folder_item_parent(item) == NULL || ritem->url == NULL )
 		return;
 
-	rssyl_get_feed_props((RSSylFolderItem *)item);
+	ritem->refresh_id = 0;
+
+	/* Start automatic refresh timer, if necessary */
+	if( ritem->default_refresh_interval ) {
+		rsprefs = rssyl_prefs_get();
+		if( !rsprefs->refresh_enabled )
+			return;
+
+		ritem->refresh_interval = rsprefs->refresh;
+	}
+
+	/* Start the timer, if determined interval is >0 */
+	if( ritem->refresh_interval > 0 )
+		rssyl_feed_start_refresh_timeout(ritem);
 }
 
 static void rssyl_make_rc_dir(void)
@@ -80,7 +101,7 @@ static void rssyl_make_rc_dir(void)
 			g_warning("couldn't create directory %s\n", rssyl_dir);
 		}
 
-		debug_print("created directorty %s\n", rssyl_dir);
+		debug_print("RSSyl: created directory %s\n", rssyl_dir);
 	}
 
 	g_free(rssyl_dir);
@@ -89,7 +110,6 @@ static void rssyl_make_rc_dir(void)
 static void rssyl_create_default_mailbox(void)
 {
 	Folder *root = NULL;
-	FolderItem *item;
 
 	rssyl_make_rc_dir();
 
@@ -98,20 +118,21 @@ static void rssyl_create_default_mailbox(void)
 	g_return_if_fail(root != NULL);
 	folder_add(root);
 
-	item = FOLDER_ITEM(root->node->data);
+	rssyl_scan_tree(root);
 
-	rssyl_subscribe_new_feed(item, RSSYL_DEFAULT_FEED, TRUE);
+	/* FIXME: subscribe default feed */
+//	rssyl_subscribe_new_feed(item, RSSYL_DEFAULT_FEED, TRUE);
 }
 
-static gboolean rssyl_refresh_all_feeds_deferred(gpointer data)
+static gboolean rssyl_update_all_feeds_deferred(gpointer data)
 {
-	rssyl_refresh_all_feeds();
+	rssyl_update_all_feeds();
 	return FALSE;
 }
 
-static void rssyl_toolbar_cb_refresh_all(gpointer parent, const gchar *item_name, gpointer data)
+static void rssyl_toolbar_cb_refresh_all_feeds(gpointer parent, const gchar *item_name, gpointer data)
 {
-	rssyl_refresh_all_feeds();
+	rssyl_update_all_feeds();
 }
 
 void rssyl_init(void)
@@ -119,34 +140,37 @@ void rssyl_init(void)
 	folder_register_class(rssyl_folder_get_class());
 
 	rssyl_gtk_init();
-
 	rssyl_make_rc_dir();
 
 	rssyl_prefs_init();
 
 	folder_func_to_all_folders((FolderItemFunc)rssyl_init_read_func, NULL);
 
-	if( existing_tree_found == FALSE )
+	if( !existing_tree_found )
 		rssyl_create_default_mailbox();
+	else
+		rssyl_update_format();
 
-	prefs_toolbar_register_plugin_item(TOOLBAR_MAIN, "RSSyl",
-			_("Refresh all feeds"), rssyl_toolbar_cb_refresh_all, NULL);
-
-	rssyl_opml_export();
+	prefs_toolbar_register_plugin_item(TOOLBAR_MAIN, "RSSyl", _("Refresh all feeds"), rssyl_toolbar_cb_refresh_all_feeds, NULL);
 
 	if( rssyl_prefs_get()->refresh_on_startup &&
 			claws_is_starting() )
-		g_timeout_add(2000, rssyl_refresh_all_feeds_deferred, NULL);
+		g_timeout_add(2000, rssyl_update_all_feeds_deferred, NULL);
 }
 
 void rssyl_done(void)
 {
-	prefs_toolbar_unregister_plugin_item(TOOLBAR_MAIN, "RSSyl",
-			_("Refresh all feeds"));
+	rssyl_opml_export();
+
+	prefs_toolbar_unregister_plugin_item(TOOLBAR_MAIN, "RSSyl", _("Refresh all feeds"));
+
 	rssyl_prefs_done();
 	rssyl_gtk_done();
-	if (!claws_is_exiting())
+
+	if( !claws_is_exiting() )
 		folder_unregister_class(rssyl_folder_get_class());
+
+	debug_print("RSSyl is done\n");
 }
 
 static gchar *rssyl_get_new_msg_filename(FolderItem *dest)
@@ -188,17 +212,15 @@ static void rssyl_get_last_num(Folder *folder, FolderItem *item)
 	debug_print("rssyl_get_last_num(): Scanning %s ...\n", item->path);
 	path = folder_item_get_path(item);
 	g_return_if_fail(path != NULL);
-	if( change_dir(path) < 0 ) {
-		g_free(path);
-		return;
-	}
-	g_free(path);
 
-	if( (dp = opendir(".")) == NULL ) {
+	if( (dp = opendir(path)) == NULL ) {
 		FILE_OP_ERROR(item->path, "opendir");
+		g_free(path);
 		return;
 	}
 
+	g_free(path);
+
 	while( (d = readdir(dp)) != NULL ) {
 		if( (num = to_number(d->d_name)) > 0 && dirent_is_regular_file(d) ) {
 			if( max < num )
@@ -211,36 +233,127 @@ static void rssyl_get_last_num(Folder *folder, FolderItem *item)
 	item->last_num = max;
 }
 
-struct _RSSylFolder {
-	LocalFolder folder;
-};
-
-typedef struct _RSSylFolder RSSylFolder;
-
-FolderClass rssyl_class;
-
 static Folder *rssyl_new_folder(const gchar *name, const gchar *path)
 {
-	RSSylFolder *folder;
+	Folder *folder;
 
-	debug_print("RSSyl: new_folder\n");
+	debug_print("RSSyl: new_folder: %s (%s)\n", name, path);
 
 	rssyl_make_rc_dir();
 
-	folder = g_new0(RSSylFolder, 1);
+	folder = g_new0(Folder, 1);
 	FOLDER(folder)->klass = &rssyl_class;
 	folder_init(FOLDER(folder), name);
 
 	return FOLDER(folder);
 }
 
-static void rssyl_destroy_folder(Folder *_folder)
+static void rssyl_destroy_folder(Folder *folder)
 {
-	RSSylFolder *folder = (RSSylFolder *)_folder;
-
 	folder_local_folder_destroy(LOCAL_FOLDER(folder));
 }
 
+static void rssyl_item_set_xml(Folder *folder, FolderItem *item, XMLTag *tag)
+{
+	GList *cur;
+	RFolderItem *ritem = (RFolderItem *)item;
+
+	folder_item_set_xml(folder, item, tag);
+
+	for( cur = tag->attr; cur != NULL; cur = g_list_next(cur)) {
+		XMLAttr *attr = (XMLAttr *) cur->data;
+
+		if( !attr || !attr->name || !attr->value)
+			continue;
+
+		/* (str) URL */
+		if( !strcmp(attr->name, "uri")) {
+			g_free(ritem->url);
+			ritem->url = g_strdup(attr->value);
+		}
+		/* (str) Official title */
+		if( !strcmp(attr->name, "official_title")) {
+			g_free(ritem->official_title);
+			ritem->official_title = g_strdup(attr->value);
+		}
+		/* (bool) Keep old items */
+		if( !strcmp(attr->name, "keep_old"))
+			ritem->keep_old = (atoi(attr->value) == 0 ? FALSE : TRUE );
+		/* (bool) Use default refresh_interval */
+		if( !strcmp(attr->name, "default_refresh_interval"))
+			ritem->default_refresh_interval = (atoi(attr->value) == 0 ? FALSE : TRUE );
+		/* (int) Refresh interval */
+		if( !strcmp(attr->name, "refresh_interval"))
+			ritem->refresh_interval = atoi(attr->value);
+		/* (bool) Fetch comments */
+		if( !strcmp(attr->name, "fetch_comments"))
+			ritem->fetch_comments = (atoi(attr->value) == 0 ? FALSE : TRUE );
+		/* (int) Max age of posts to fetch comments for */
+		if( !strcmp(attr->name, "fetch_comments_max_age"))
+			ritem->fetch_comments_max_age = atoi(attr->value);
+		/* (bool) Write heading */
+		if( !strcmp(attr->name, "write_heading"))
+			ritem->write_heading = (atoi(attr->value) == 0 ? FALSE : TRUE );
+		/* (int) Silent update */
+		if( !strcmp(attr->name, "silent_update"))
+			ritem->silent_update = atoi(attr->value);
+		/* (bool) Ignore title rename */
+		if( !strcmp(attr->name, "ignore_title_rename"))
+			ritem->ignore_title_rename = (atoi(attr->value) == 0 ? FALSE : TRUE );
+		/* (bool) Verify SSL peer  */
+		if( !strcmp(attr->name, "ssl_verify_peer"))
+			ritem->ssl_verify_peer = (atoi(attr->value) == 0 ? FALSE : TRUE );
+	}
+}
+
+static XMLTag *rssyl_item_get_xml(Folder *folder, FolderItem *item)
+{
+	XMLTag *tag;
+	RFolderItem *ri = (RFolderItem *)item;
+	gchar *tmp = NULL;
+
+	tag = folder_item_get_xml(folder, item);
+
+	/* (str) URL */
+	if( ri->url != NULL )
+		xml_tag_add_attr(tag, xml_attr_new("uri", ri->url));
+	/* (str) Official title */
+	if( ri->official_title != NULL )
+		xml_tag_add_attr(tag, xml_attr_new("official_title", ri->official_title));
+	/* (bool) Keep old items */
+	xml_tag_add_attr(tag, xml_attr_new("keep_old",
+				(ri->keep_old ? "1" : "0")) );
+	/* (bool) Use default refresh interval */
+	xml_tag_add_attr(tag, xml_attr_new("default_refresh_interval",
+				(ri->default_refresh_interval ? "1" : "0")) );
+	/* (int) Refresh interval */
+	tmp = g_strdup_printf("%d", ri->refresh_interval);
+	xml_tag_add_attr(tag, xml_attr_new("refresh_interval", tmp));
+	g_free(tmp);
+	/* (bool) Fetch comments */
+	xml_tag_add_attr(tag, xml_attr_new("fetch_comments",
+				(ri->fetch_comments ? "1" : "0")) );
+	/* (int) Max age of posts to fetch comments for */
+	tmp = g_strdup_printf("%d", ri->fetch_comments_max_age);
+	xml_tag_add_attr(tag, xml_attr_new("fetch_comments_max_age", tmp));
+	g_free(tmp);
+	/* (bool) Write heading */
+	xml_tag_add_attr(tag, xml_attr_new("write_heading",
+				(ri->write_heading ? "1" : "0")) );
+	/* (int) Silent update */
+	tmp = g_strdup_printf("%d", ri->silent_update);
+	xml_tag_add_attr(tag, xml_attr_new("silent_update", tmp));
+	g_free(tmp);
+	/* (bool) Ignore title rename */
+	xml_tag_add_attr(tag, xml_attr_new("ignore_title_rename",
+				(ri->ignore_title_rename ? "1" : "0")) );
+	/* (bool) Verify SSL peer */
+	xml_tag_add_attr(tag, xml_attr_new("ssl_verify_peer",
+				(ri->ssl_verify_peer ? "1" : "0")) );
+
+	return tag;
+}
+
 static gint rssyl_scan_tree(Folder *folder)
 {
 	g_return_val_if_fail(folder != NULL, -1);
@@ -261,6 +374,8 @@ static gint rssyl_create_tree(Folder *folder)
 	FolderItem *rootitem;
 	GNode *rootnode;
 
+	g_return_val_if_fail(folder != NULL, -1);
+
 	rssyl_make_rc_dir();
 
 	if( !folder->node ) {
@@ -269,9 +384,6 @@ static gint rssyl_create_tree(Folder *folder)
 		rootnode = g_node_new(rootitem);
 		folder->node = rootnode;
 		rootitem->node = rootnode;
-	} else {
-		rootitem = FOLDER_ITEM(folder->node->data);
-		rootnode = folder->node;
 	}
 
 	debug_print("RSSyl: created new rssyl tree\n");
@@ -280,125 +392,201 @@ static gint rssyl_create_tree(Folder *folder)
 
 static FolderItem *rssyl_item_new(Folder *folder)
 {
-	RSSylFolderItem *ritem;
-
-	debug_print("RSSyl: item_new\n");
-
-	ritem = g_new0(RSSylFolderItem, 1);
+	RFolderItem *ritem = g_new0(RFolderItem, 1);
 
 	ritem->url = NULL;
+	ritem->official_title = NULL;
+	ritem->source_id = NULL;
+	ritem->items = NULL;
+	ritem->keep_old = FALSE;
 	ritem->default_refresh_interval = TRUE;
-	ritem->default_expired_num = TRUE;
+	ritem->refresh_interval = atoi(PREF_DEFAULT_REFRESH);
 	ritem->fetch_comments = FALSE;
-	ritem->fetch_comments_for = -1;
+	ritem->fetch_comments_max_age = -1;
+	ritem->write_heading = TRUE;
+	ritem->fetching_comments = FALSE;
 	ritem->silent_update = 0;
-	ritem->refresh_interval = rssyl_prefs_get()->refresh;
-	ritem->refresh_id = 0;
-	ritem->expired_num = rssyl_prefs_get()->expired;
-	ritem->last_count = 0;
-	ritem->ssl_verify_peer = rssyl_prefs_get()->ssl_verify_peer;
-
-	ritem->contents = NULL;
-	ritem->feedprop = NULL;
+	ritem->last_update = 0;
+	ritem->ignore_title_rename = FALSE;
 
 	return (FolderItem *)ritem;
 }
 
 static void rssyl_item_destroy(Folder *folder, FolderItem *item)
 {
-	RSSylFolderItem *ritem = (RSSylFolderItem *)item;
+	RFolderItem *ritem = (RFolderItem *)item;
 
 	g_return_if_fail(ritem != NULL);
 
-	/* Silently remove feed refresh timeouts */
-	if( ritem->refresh_id != 0 )
-		g_source_remove(ritem->refresh_id);
-
 	g_free(ritem->url);
-	g_free(ritem->official_name);
-	g_slist_free(ritem->contents);
+	g_free(ritem->official_title);
+	g_slist_free(ritem->items);
 
-	g_free(item);
+	/* Remove a scheduled refresh, if any */
+	if( ritem->refresh_id != 0)
+		g_source_remove(ritem->refresh_id);
+
+	g_free(ritem);
 }
 
 static FolderItem *rssyl_create_folder(Folder *folder,
 								FolderItem *parent, const gchar *name)
 {
-	gchar *path = NULL, *tmp;
+	gchar *path = NULL, *basepath = NULL, *itempath = NULL;
 	FolderItem *newitem = NULL;
 
 	g_return_val_if_fail(folder != NULL, NULL);
 	g_return_val_if_fail(parent != NULL, NULL);
 	g_return_val_if_fail(name != NULL, NULL);
-	tmp = rssyl_feed_title_to_dir((gchar *)name);
-	path = g_strconcat((parent->path != NULL) ? parent->path : "", ".",
-				tmp, NULL);
-	g_free(tmp);
-	newitem = folder_item_new(folder, name, path);
-	folder_item_append(parent, newitem);
+
+	path = folder_item_get_path(parent);
+	if( !is_dir_exist(path) ) {
+		if( (make_dir_hier(path) != 0) ) {
+			debug_print("RSSyl: Couldn't create directory (rec) '%s'\n", path);
+			return NULL;
+		}
+	}
+
+	basepath = g_strdelimit(g_strdup(name), G_DIR_SEPARATOR_S, '_');
+	path = g_strconcat(path, G_DIR_SEPARATOR_S, basepath, NULL);
+
+	if( make_dir(path) < 0 ) {
+		debug_print("RSSyl: Couldn't create directory '%s'\n", path);
+		g_free(path);
+		g_free(basepath);
+		return NULL;
+	}
 	g_free(path);
 
+	itempath = g_strconcat((parent->path ? parent->path : ""),
+			G_DIR_SEPARATOR_S, basepath, NULL);
+	newitem = folder_item_new(folder, name, itempath);
+	g_free(itempath);
+	g_free(basepath);
+
+	folder_item_append(parent, newitem);
+
 	return newitem;
 }
 
+FolderItem *rssyl_get_root_folderitem(FolderItem *item)
+{
+	FolderItem *i;
+
+	for( i = item; folder_item_parent(i) != NULL; i = folder_item_parent(i) ) { }
+	return i;
+}
+
 static gchar *rssyl_item_get_path(Folder *folder, FolderItem *item)
 {
-	gchar *result, *tmp;
-	tmp = rssyl_feed_title_to_dir(item->name);
-	result = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
-			G_DIR_SEPARATOR_S, tmp, NULL);
-	g_free(tmp);
-	return result;
+	gchar *path, *name;
+
+	g_return_val_if_fail(folder != NULL, NULL);
+	g_return_val_if_fail(item != NULL, NULL);
+
+	debug_print("RSSyl: item_get_path\n");
+
+	name = folder_item_get_name(rssyl_get_root_folderitem(item));
+	path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
+			G_DIR_SEPARATOR_S, name, G_DIR_SEPARATOR_S, item->path, NULL);
+	g_free(name);
+
+	return path;
+}
+
+static gboolean rssyl_rename_folder_func(GNode *node, gpointer data)
+{
+	FolderItem *item = node->data;
+	gchar **paths = data;
+	const gchar *oldpath = paths[0];
+	const gchar *newpath = paths[1];
+	gchar *base;
+	gchar *new_itempath;
+	gint oldpathlen;
+
+	oldpathlen = strlen(oldpath);
+	if (strncmp(oldpath, item->path, oldpathlen) != 0) {
+		g_warning("path doesn't match: %s, %s\n", oldpath, item->path);
+		return TRUE;
+	}
+
+	base = item->path + oldpathlen;
+	while (*base == G_DIR_SEPARATOR) base++;
+	if (*base == '\0')
+		new_itempath = g_strdup(newpath);
+	else
+		new_itempath = g_strconcat(newpath, G_DIR_SEPARATOR_S, base,
+				NULL);
+	g_free(item->path);
+	item->path = new_itempath;
+
+	return FALSE;
 }
 
 static gint rssyl_rename_folder(Folder *folder, FolderItem *item,
 				const gchar *name)
 {
-	gchar *oldname = NULL, *oldpath = NULL, *newpath = NULL;
-	RSSylFolderItem *ritem = NULL;
+	gchar *oldpath;
+	gchar *dirname;
+	gchar *newpath, *utf8newpath;
+	gchar *basenewpath;
+	gchar *paths[2];
+
 	g_return_val_if_fail(folder != NULL, -1);
 	g_return_val_if_fail(item != NULL, -1);
 	g_return_val_if_fail(item->path != NULL, -1);
 	g_return_val_if_fail(name != NULL, -1);
 
-	debug_print("RSSyl: renaming folder '%s' to '%s'\n", item->path, name);
+	debug_print("RSSyl: rssyl_rename_folder '%s' -> '%s'\n",
+			item->name, name);
 
-	oldpath = rssyl_item_get_path(folder, item);
-	
-	/* now get the new path using the new name */
-	oldname = item->name;
-	item->name = g_strdup(name);
-	newpath = rssyl_item_get_path(folder, item);
-	
-	/* put back the old name in case the rename fails */
-	g_free(item->name);
-	item->name = oldname;
-	
-	if (g_rename(oldpath, newpath) < 0) {
+	if (!strcmp(item->name, name))
+			return 0;
+
+	oldpath = folder_item_get_path(item);
+	if( !is_dir_exist(oldpath) )
+		make_dir_hier(oldpath);
+
+	dirname = g_path_get_dirname(oldpath);
+	basenewpath = g_strdelimit(g_strdup(name), G_DIR_SEPARATOR_S, '_');
+	newpath = g_strconcat(dirname, G_DIR_SEPARATOR_S, basenewpath, NULL);
+	g_free(basenewpath);
+
+	if( g_rename(oldpath, newpath) < 0 ) {
 		FILE_OP_ERROR(oldpath, "rename");
 		g_free(oldpath);
 		g_free(newpath);
 		return -1;
 	}
-	
-	g_free(item->path);
-	item->path = g_strdup_printf(".%s", name);
-	
-	ritem = (RSSylFolderItem *)item;
-	
-	if (ritem->url)
-		rssyl_props_update_name(ritem, (gchar *)name);
-	
+
+	g_free(oldpath);
+	g_free(newpath);
+
+	if( strchr(item->path, G_DIR_SEPARATOR) != NULL ) {
+		dirname = g_path_get_dirname(item->path);
+		utf8newpath = g_strconcat(dirname, G_DIR_SEPARATOR_S, name, NULL);
+		g_free(dirname);
+	} else
+		utf8newpath = g_strdup(name);
+
 	g_free(item->name);
 	item->name = g_strdup(name);
-	
-	folder_write_list();
+
+	paths[0] = g_strdup(item->path);
+	paths[1] = utf8newpath;
+	g_node_traverse(item->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+			rssyl_rename_folder_func, paths);
+
+	g_free(paths[0]);
+	g_free(paths[1]);
 
 	return 0;
 }
 
 static gint rssyl_remove_folder(Folder *folder, FolderItem *item)
 {
+	gchar *path = NULL;
+
 	g_return_val_if_fail(folder != NULL, -1);
 	g_return_val_if_fail(item != NULL, -1);
 	g_return_val_if_fail(item->path != NULL, -1);
@@ -406,6 +594,14 @@ static gint rssyl_remove_folder(Folder *folder, FolderItem *item)
 
 	debug_print("RSSyl: removing folder item %s\n", item->path);
 
+	path = folder_item_get_path(item);
+	if( remove_dir_recursive(path) < 0 ) {
+		g_warning("can't remove directory '%s'\n", path);
+		g_free(path);
+		return -1;
+	}
+
+	g_free(path);
 	folder_item_remove(item);
 
 	return 0;
@@ -418,40 +614,35 @@ static gint rssyl_get_num_list(Folder *folder, FolderItem *item,
 	DIR *dp;
 	struct dirent *d;
 	gint num, nummsgs = 0;
-	RSSylFolderItem *ritem = (RSSylFolderItem *)item;
 
 	g_return_val_if_fail(item != NULL, -1);
 
-	debug_print("RSSyl: scanning '%s'...\n", item->path);
-
-	rssyl_get_feed_props(ritem);
-
-	if (ritem->url == NULL)
-		return -1;
+	debug_print("RSSyl: get_num_list: scanning '%s'\n", item->path);
 
 	*old_uids_valid = TRUE;
-
+	
 	path = folder_item_get_path(item);
 	g_return_val_if_fail(path != NULL, -1);
-	if( change_dir(path) < 0 ) {
-		g_free(path);
-		return -1;
-	}
-	g_free(path);
 
-	if( (dp = opendir(".")) == NULL ) {
+	if( (dp = opendir(path)) == NULL ) {
 		FILE_OP_ERROR(item->path, "opendir");
+		g_free(path);
 		return -1;
 	}
 
+	g_free(path);
+
 	while( (d = readdir(dp)) != NULL ) {
 		if( (num = to_number(d->d_name)) > 0 ) {
 			*list = g_slist_prepend(*list, GINT_TO_POINTER(num));
 			nummsgs++;
 		}
 	}
+
 	closedir(dp);
 
+	debug_print("Rssyl: get_num_list: returning %d\n", nummsgs);
+
 	return nummsgs;
 }
 
@@ -462,15 +653,22 @@ static gboolean rssyl_scan_required(Folder *folder, FolderItem *item)
 
 static gchar *rssyl_fetch_msg(Folder *folder, FolderItem *item, gint num)
 {
-	gchar *snum = g_strdup_printf("%d", num);
-	gchar *tmp = rssyl_feed_title_to_dir(item->name);
-	gchar *file = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
-			G_DIR_SEPARATOR_S, tmp,
-			G_DIR_SEPARATOR_S, snum, NULL);
-	g_free(tmp);
-	debug_print("RSSyl: fetch_msg: '%s'\n", file);
+	gchar *path;
+	gchar *file;
+
+	g_return_val_if_fail(item != NULL, NULL);
+	g_return_val_if_fail(num > 0, NULL);
+
+	path = folder_item_get_path(item);
+	file = g_strconcat(path, G_DIR_SEPARATOR_S, itos(num), NULL);
+	g_free(path);
+
+	debug_print("RSSyl: fetch_msg '%s'\n", file);
 
-	g_free(snum);
+	if( !is_file_exist(file)) {
+		g_free(file);
+		return NULL;
+	}
 
 	return file;
 }
@@ -481,25 +679,24 @@ static MsgInfo *rssyl_get_msginfo(Folder *folder, FolderItem *item, gint num)
 	gchar *file;
 	MsgFlags flags;
 
-	debug_print("RSSyl: get_msginfo: %d\n", num);
-
 	g_return_val_if_fail(folder != NULL, NULL);
 	g_return_val_if_fail(item != NULL, NULL);
 	g_return_val_if_fail(num > 0, NULL);
 
+	debug_print("RSSyl: get_msginfo: %d\n", num);
+
 	file = rssyl_fetch_msg(folder, item, num);
 	g_return_val_if_fail(file != NULL, NULL);
 
-	flags.perm_flags = MSG_NEW | MSG_UNREAD;
+	flags.perm_flags = 0;
 	flags.tmp_flags = 0;
 
-	msginfo = rssyl_parse_feed_item_to_msginfo(file, flags, TRUE, TRUE, item);
+	msginfo = rssyl_feed_parse_item_to_msginfo(file, flags, TRUE, TRUE, item);
+	g_free(file);
 
 	if( msginfo )
 		msginfo->msgnum = num;
 
-	g_free(file);
-
 	return msginfo;
 }
 
@@ -523,30 +720,31 @@ static gint rssyl_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
 
 		destfile = rssyl_get_new_msg_filename(dest);
 		g_return_val_if_fail(destfile != NULL, -1);
+		debug_print("RSSyl: add_msgs: new filename is '%s'\n", destfile);
 
-#ifdef G_OS_UNIX
-		if( link(fileinfo->file, destfile) < 0 )
-#endif
+		if( link(fileinfo->file, destfile) < 0 ) {
 			if( copy_file(fileinfo->file, destfile, TRUE) < 0 ) {
 				g_warning("can't copy message %s to %s\n", fileinfo->file, destfile);
 				g_free(destfile);
 				return -1;
 			}
+		}
 
 		if( relation != NULL )
-			g_hash_table_insert(relation, fileinfo,
-					GINT_TO_POINTER(dest->last_num + 1) );
+			g_hash_table_insert(relation, fileinfo->msginfo != NULL ?
+					(gpointer) fileinfo->msginfo : (gpointer) fileinfo,
+					GINT_TO_POINTER(dest->last_num + 1));
 		g_free(destfile);
 		dest->last_num++;
 	}
 
+
 	return dest->last_num;
 }
 
 static gint rssyl_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
 		MsgFlags *flags)
 {
-	gint ret;
 	GSList file_list;
 	MsgFileInfo fileinfo;
 
@@ -558,28 +756,9 @@ static gint rssyl_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
 	file_list.data = &fileinfo;
 	file_list.next = NULL;
 
-	ret = rssyl_add_msgs(folder, dest, &file_list, NULL);
-	return ret;
+	return rssyl_add_msgs(folder, dest, &file_list, NULL);
 }
 
-static gint rssyl_dummy_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *info)
-{
-	if (info->folder == NULL || info->folder->folder != dest->folder) {
-		return -1;
-	}
-	if (info->folder && info->folder->name && dest->name
-	&&  !strcmp(info->folder->name, dest->name)) {
-		/* this is a folder move */
-		gchar *file = procmsg_get_message_file(info);
-		gchar *tmp = g_strdup_printf("%s.tmp", file);
-		copy_file(file, tmp, TRUE);
-		g_free(file);
-		g_free(tmp);
-		return info->msgnum;
-	} else {
-		return -1;
-	}
-}
 static gint rssyl_remove_msg(Folder *folder, FolderItem *item, gint num)
 {
 	gboolean need_scan = FALSE;
@@ -595,13 +774,16 @@ static gint rssyl_remove_msg(Folder *folder, FolderItem *item, gint num)
 	/* are we doing a folder move ? */
 	tmp = g_strdup_printf("%s.tmp", file);
 	if (is_file_exist(tmp)) {
-		claws_unlink(tmp);
+		g_unlink(tmp);
 		g_free(tmp);
 		g_free(file);
 		return 0;
 	}
 	g_free(tmp);
-	if( claws_unlink(file) < 0 ) {
+
+	rssyl_deleted_add((RFolderItem *)item, file);
+
+	if( g_unlink(file) < 0 ) {
 		FILE_OP_ERROR(file, "unlink");
 		g_free(file);
 		return -1;
@@ -618,11 +800,29 @@ static gboolean rssyl_subscribe_uri(Folder *folder, const gchar *uri)
 {
 	if (folder->klass != rssyl_folder_get_class())
 		return FALSE;
-	
-	if( rssyl_subscribe_new_feed(
-				FOLDER_ITEM(folder->node->data), uri, FALSE) != NULL )
-		return TRUE;
-	return FALSE;
+	return (rssyl_feed_subscribe_new(FOLDER_ITEM(folder->node->data), uri, FALSE) ?
+			TRUE : FALSE);
+}
+
+static void rssyl_copy_private_data(Folder *folder, FolderItem *oldi,
+		FolderItem *newi)
+{
+	RFolderItem *olditem = (RFolderItem *)oldi,
+									*newitem = (RFolderItem *)newi;
+
+	g_return_if_fail(folder != NULL);
+	g_return_if_fail(olditem != NULL);
+	g_return_if_fail(newitem != NULL);
+
+	if( olditem->url != NULL ) {
+		g_free(newitem->url);
+		newitem->url = g_strdup(olditem->url);
+	}
+
+	if( olditem->official_title != NULL ) {
+		g_free(newitem->official_title);
+		newitem->official_title = g_strdup(olditem->official_title);
+	}
 }
 
 /************************************************************************/
@@ -651,11 +851,14 @@ FolderClass *rssyl_folder_get_class()
 		rssyl_class.remove_folder = rssyl_remove_folder;
 		rssyl_class.get_num_list = rssyl_get_num_list;
 		rssyl_class.scan_required = rssyl_scan_required;
+		rssyl_class.item_set_xml = rssyl_item_set_xml;
+		rssyl_class.item_get_xml = rssyl_item_get_xml;
 
 		/* Message functions */
 		rssyl_class.get_msginfo = rssyl_get_msginfo;
 		rssyl_class.fetch_msg = rssyl_fetch_msg;
-		rssyl_class.copy_msg = rssyl_dummy_copy_msg;
+		rssyl_class.copy_msg = mh_get_class()->copy_msg;
+		rssyl_class.copy_msgs = mh_get_class()->copy_msgs;
 		rssyl_class.add_msg = rssyl_add_msg;
 		rssyl_class.add_msgs = rssyl_add_msgs;
 		rssyl_class.remove_msg = rssyl_remove_msg;
@@ -663,7 +866,8 @@ FolderClass *rssyl_folder_get_class()
 //		rssyl_class.change_flags = rssyl_change_flags;
 		rssyl_class.change_flags = NULL;
 		rssyl_class.subscribe = rssyl_subscribe_uri;
-		debug_print("RSSyl: registered folderclass\n");
+		rssyl_class.copy_private_data = rssyl_copy_private_data;
+		rssyl_class.search_msgs = folder_item_search_msgs_local;
 	}
 
 	return &rssyl_class;
diff --git a/src/plugins/rssyl/rssyl.h b/src/plugins/rssyl/rssyl.h
index 917adbe..7b1b169 100644
--- a/src/plugins/rssyl/rssyl.h
+++ b/src/plugins/rssyl/rssyl.h
@@ -5,10 +5,13 @@
 
 #include <folder.h>
 
-#define PLUGIN_NAME		(_("RSSyl"))
+#include "libfeed/feed.h"
 
 /* Name of directory in rcdir where RSSyl will store its data. */
-#define RSSYL_DIR "RSSyl"
+#define RSSYL_DIR		"RSSyl"
+
+/* Folder name for a new feed, before it is parsed for the first time. */
+#define RSSYL_NEW_FOLDER_NAME		"NewFeed"
 
 /* Default RSSyl mailbox name */
 #define RSSYL_DEFAULT_MAILBOX	_("My Feeds")
@@ -16,43 +19,80 @@
 /* Default feed to be added when creating mailbox for the first time */
 #define RSSYL_DEFAULT_FEED	"http://planet.claws-mail.org/rss20.xml"
 
-struct _RSSylFolderItem {
-	FolderItem item;
-	GSList *contents;
-	gint last_count;
+/* File where info about user-deleted feed items is stored */
+#define RSSYL_DELETED_FILE ".deleted"
 
+struct _RFolderItem {
+	FolderItem item;
 	gchar *url;
-	gchar *official_name;
+	gchar *official_title;
+	gchar *source_id;
+
+	gboolean keep_old;
 
 	gboolean default_refresh_interval;
 	gint refresh_interval;
 
-	gboolean default_expired_num;
-	gint expired_num;
-
-	guint refresh_id;	
 	gboolean fetch_comments;
-	gint fetch_comments_for;
+	gint fetch_comments_max_age;
+
 	gint silent_update;
+	gboolean write_heading;
+	gboolean ignore_title_rename;
 	gboolean ssl_verify_peer;
 
-	struct _RSSylFeedProp *feedprop;
+	guint refresh_id;
+	gboolean fetching_comments;
+	time_t last_update;
+
+	struct _RFeedProp *feedprop;
+
+	GSList *items;
+	GSList *deleted_items;
 };
 
-typedef struct _RSSylFolderItem RSSylFolderItem;
+typedef struct _RFolderItem RFolderItem;
 
-struct _RSSylRefreshCtx {
-	RSSylFolderItem *ritem;
+struct _RRefreshCtx {
+	RFolderItem *ritem;
 	guint id;
 };
 
-typedef struct _RSSylRefreshCtx RSSylRefreshCtx;
+typedef struct _RRefreshCtx RRefreshCtx;
+
+struct _RFetchCtx {
+	Feed *feed;
+	guint response_code;
+	gchar *error;
+	gboolean success;
+	gboolean ready;
+};
+
+typedef struct _RFetchCtx RFetchCtx;
+
+struct _RParseCtx {
+	RFolderItem *ritem;
+	gboolean ready;
+};
+
+typedef struct _RParseCtx RParseCtx;
+
+struct _RDeletedItem {
+	gchar *id;
+	gchar *title;
+	time_t date_published;
+	time_t date_modified;
+};
+
+typedef struct _RDeletedItem RDeletedItem;
 
 void rssyl_init(void);
 void rssyl_done(void);
 
 FolderClass *rssyl_folder_get_class(void);
 
+FolderItem *rssyl_get_root_folderitem(FolderItem *item);
+
 #define IS_RSSYL_FOLDER_ITEM(item) \
 	(item->folder->klass == rssyl_folder_get_class())
 
diff --git a/src/plugins/rssyl/rssyl_add_item.c b/src/plugins/rssyl/rssyl_add_item.c
new file mode 100644
index 0000000..b058660
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_add_item.c
@@ -0,0 +1,540 @@
+/*
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
+ *
+ * - DESCRIPTION HERE
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <string.h>
+
+/* Claws Mail includes */
+#include <codeconv.h>
+#include <procmsg.h>
+#include <common/utils.h>
+
+/* Local includes */
+#include "libfeed/date.h"
+#include "libfeed/feeditem.h"
+#include "parse822.h"
+#include "rssyl.h"
+#include "rssyl_deleted.h"
+#include "rssyl_feed.h"
+#include "rssyl_parse_feed.h"
+#include "strutils.h"
+
+/* rssyl_cb_feed_compare()
+ *
+ * GCompareFunc function called by glib2's g_slist_find_custom().
+ */
+
+static gint rssyl_cb_feed_compare(const FeedItem *a, const FeedItem *b)
+{
+	gboolean date_eq = FALSE, url_eq = FALSE, title_eq = FALSE;
+	gboolean no_url = FALSE, no_date = FALSE, no_title = FALSE;
+	gchar *atit = NULL, *btit = NULL;
+
+	g_return_val_if_fail(a != NULL && b != NULL, 1);
+
+	/* ID should be unique. If it matches, we've found what we came for. */
+	if( (a->id != NULL) && (b->id != NULL) ) {
+			if( !strcmp(a->id, b->id) ) {
+				return 0;
+			}
+
+			/* If both IDs are present, but they do not match, these are not the
+			 * droids we're looking for. */
+			return 1;
+	}
+
+	/* Ok, we have no ID to aid us. Let's have a look at item timestamps
+	 * and item title & url. */
+	if( (a->url != NULL) && (b->url != NULL) ) {
+		if( !strcmp(a->url, b->url) )
+			url_eq = TRUE;
+	} else
+		no_url = TRUE;
+
+	if( (a->title != NULL) && (b->title != NULL) ) {
+		atit = conv_unmime_header(a->title, CS_UTF_8, FALSE);
+		btit = conv_unmime_header(b->title, CS_UTF_8, FALSE);
+		if( !strcmp(atit, btit) )
+			title_eq = TRUE;
+		g_free(atit);
+		g_free(btit);
+	} else
+		no_title = TRUE;
+
+	/* If there's no 'published' timestamp for the item, we can only judge
+	 * by item url - 'modified' timestamp can have changed if the item was
+	 * updated recently. */
+	if( b->date_published <= 0 ) {
+		if( b->date_modified > 0 ) {
+			/* If the item has 'modified' timestamp, we can only rely on url
+			 * and title at this point. */
+			if( (url_eq || no_url) && title_eq
+				&& (a->date_modified >= b->date_modified) )
+				return 0;
+			else
+				return 1;
+		} else {
+			/* No timestamp of any kind, we'll just assume if both title and url
+			 * match, we found the right item. Items in such feeds rarely change,
+			 * and if they do, there's no way we can really */
+			if( (url_eq || no_url) && title_eq )
+				return 0;
+			else
+				return 1;
+		}
+	}
+
+	/* Check if 'published' or at least 'modified' timestamps match */
+	if( ((a->date_published > 0) && (b->date_published > 0) &&
+			(a->date_published == b->date_published))
+			|| ((a->date_modified > 0) && (b->date_modified > 0) &&
+			(a->date_modified == b->date_modified))) {
+		date_eq = TRUE;
+	} else
+		no_date = TRUE;
+
+	/* If 'published' time and item url match, it is reasonable to assume
+	 * we found our item. */
+	if( (no_url || url_eq) && date_eq )
+		return 0;
+
+	/* There is no timestamp and the url matches (or there is none),
+	 * we need to compare titles, ... */
+	if( (no_url || url_eq) && no_date ) {
+		if( title_eq )
+			return 0;
+		else
+			return 1;
+
+		/* ... and as a last resort, if there is no title, item texts. */
+		if( no_title && a->text && b->text ) {
+			if( !strcmp(a->text, b->text) )
+				return 0;
+			else
+				return 1;
+		}
+	}
+
+	/* We don't know this item. */
+	return 1;
+}
+
+enum {
+	ITEM_UNCHANGED,
+	ITEM_CHANGED_TEXTONLY,
+	ITEM_CHANGED
+};
+
+static gint rssyl_feed_item_changed(FeedItem *new_item, FeedItem *old_item )
+{
+	debug_print("RSSyl: comparing '%s' and '%s'\n",
+			new_item->title, old_item->title);
+
+	/* if both have title ... */
+	if( old_item->title && new_item->title ) {
+		gchar *old = conv_unmime_header(old_item->title, CS_UTF_8, FALSE);
+		gchar *new = conv_unmime_header(new_item->title, CS_UTF_8, FALSE);
+		if( strcmp(old, new) != 0 ) { /* ... compare "unmimed" titles */
+			debug_print("RSSyl:\t\titem titles differ:\nOLD: '%s'\nNEW: '%s'\n",
+					old, new);
+			g_free(old);
+			g_free(new);
+			return ITEM_CHANGED;
+		}
+		g_free(old);
+		g_free(new);
+	} else {
+		/* if atleast one has a title, they differ */
+		if( old_item->title || new_item->title ) {
+			debug_print("RSSyl:\t\t+/- title\n");
+			return ITEM_CHANGED;
+		}
+	}
+
+	if( old_item->author && new_item->author ) {
+		gchar *old = conv_unmime_header(old_item->author, CS_UTF_8, TRUE);
+		gchar *new = conv_unmime_header(new_item->author, CS_UTF_8, TRUE);
+		if( strcmp(old, new) ) {  /* ... compare "unmimed" authors */
+			g_free(old);
+			g_free(new);
+			debug_print("RSSyl:\t\titem authors differ\n");
+			return ITEM_CHANGED;
+		}
+		g_free(old);
+		g_free(new);
+	} else {
+		/* if atleast one has author, they differ */
+		if( old_item->author || new_item->author ) {
+			debug_print("RSSyl:\t\t+/- author\n");
+			return ITEM_CHANGED;
+		}
+	}
+
+	/* if both have text ... */
+	if( old_item->text && new_item->text ) {
+		if( strcmp(old_item->text, new_item->text) ) { /* ... compare them */
+			debug_print("RSSyl:\t\titem texts differ\n");
+			debug_print("\nOLD: '%s'\n", old_item->text);
+			debug_print("\nNEW: '%s'\n", new_item->text);
+
+			return ITEM_CHANGED_TEXTONLY;
+		}
+	} else {
+		/* if at least one has some text, they differ */
+		if( old_item->text || new_item->text ) {
+			debug_print("RSSyl:\t\t+/- text\n");
+			return ITEM_CHANGED_TEXTONLY;
+		}
+	}
+
+	/* they don't seem to differ */
+	return ITEM_UNCHANGED;
+}
+
+enum {
+	EXISTS_NEW,
+	EXISTS_UNCHANGED,
+	EXISTS_CHANGED,
+	EXISTS_CHANGED_TEXTONLY
+};
+
+/* rssyl_feed_item_exists()
+ *
+ * Returns 1 if a feed item already exists locally, 2 if there's a changed
+ * item with link that already belongs to existing item, 3 if only item's
+ * text has changed, 0 if item is new.
+ */
+
+static guint rssyl_feed_item_exists(RFolderItem *ritem, FeedItem *fitem,
+		FeedItem **oldfitem)
+{
+	GSList *item = NULL;
+	FeedItem *efitem = NULL;
+	gint changed;
+
+	g_return_val_if_fail(ritem != NULL, FALSE);
+	g_return_val_if_fail(fitem != NULL, FALSE);
+
+	if( ritem->items == NULL || g_slist_length(ritem->items) == 0 )
+		return EXISTS_NEW;
+
+	if( (item = g_slist_find_custom(ritem->items,
+					(gconstpointer)fitem, (GCompareFunc)rssyl_cb_feed_compare)) ) {
+		efitem = (FeedItem *)item->data;
+		if( (changed = rssyl_feed_item_changed(fitem, efitem)) > ITEM_UNCHANGED ) {
+			*oldfitem = efitem;
+			if (changed == ITEM_CHANGED_TEXTONLY)
+				return EXISTS_CHANGED_TEXTONLY;
+			else
+				return EXISTS_CHANGED;
+		}
+
+		return EXISTS_UNCHANGED;
+	}
+
+	return EXISTS_NEW;
+}
+
+/* =============================================================== */
+
+void rssyl_add_item(RFolderItem *ritem, FeedItem *feed_item)
+{
+	FeedItem *old_item = NULL;
+	MsgFlags *flags;
+	MsgPermFlags oldperm_flags = 0;
+	MsgInfo *msginfo;
+	FILE *f;
+	gint fd, d, dif;
+	time_t tmpd;
+	gchar *meta_charset = NULL;
+	gchar *baseurl = NULL;
+	gchar *template = NULL;
+	gchar *tmp = NULL, *tmpurl = NULL, *tmpid = NULL;
+	gchar *dirname = NULL;
+	gchar *text = NULL;
+	gchar *heading = NULL;
+	gchar hdr[1024];
+	FeedItemEnclosure *enc = NULL;
+	RFeedCtx *ctx;
+
+	g_return_if_fail(ritem != NULL);
+
+	/* If item title is empty, try to fill it from source title (Atom only). */
+	debug_print(",%s,\n", (feed_item->title ? feed_item->title : "<null>"));
+	debug_print(",%s,\n", (feed_item->sourcetitle ? feed_item->sourcetitle : "<null>"));
+	tmp = feed_item_get_sourcetitle(feed_item);
+	if( feed_item_get_title(feed_item) == NULL ||
+			strlen(feed_item->title) == 0 ) {
+		if( tmp != NULL && strlen(tmp) > 0 )
+			feed_item_set_title(feed_item, tmp);
+		else
+			feed_item_set_title(feed_item, C_("Empty RSS feed title placeholder", "(empty)"));
+	}
+
+	debug_print(",%s,\n", (feed_item->title ? feed_item->title : "<null>"));
+	debug_print(",%s,\n", (feed_item->sourcetitle ? feed_item->sourcetitle : "<null>"));
+	if (feed_item_get_id(feed_item) == NULL) {
+		debug_print("RSSyl: item ID empty, using its URL as ID.\n");
+		feed_item_set_id(feed_item, feed_item_get_url(feed_item));
+	}
+
+	/* If neither item date is set, use date from source (Atom only). */
+	if( feed_item_get_date_modified(feed_item) == -1 &&
+			feed_item_get_date_published(feed_item) == -1 )
+		feed_item_set_date_published(feed_item,
+				feed_item_get_sourcedate(feed_item));
+
+	/* Fix up subject, url and ID (rssyl_format_string()) so that
+	 * comparing doesn't break. */
+	debug_print("RSSyl: fixing up subject '%s'\n", feed_item_get_title(feed_item));
+	feed_item_set_title(feed_item, rssyl_format_string(feed_item_get_title(feed_item), TRUE, TRUE));
+	debug_print("RSSyl: fixing up URL\n");
+	feed_item_set_url(feed_item, rssyl_format_string(feed_item_get_url(feed_item),
+				TRUE, TRUE));
+	if( feed_item_get_id(feed_item) != NULL ) {
+		debug_print("RSSyl: fixing up ID\n");
+		feed_item_set_id(feed_item, rssyl_format_string(feed_item_get_id(feed_item),
+					TRUE, TRUE));
+	}
+
+	/* If there's a summary, but no text, use summary as text. */
+	if( feed_item_get_text(feed_item) == NULL &&
+			(tmp = feed_item_get_summary(feed_item)) != NULL ) {
+		feed_item_set_text(feed_item, tmp);
+		g_free(feed_item->summary);	/* We do not need summary in rssyl now. */
+		feed_item->summary = NULL;
+	}
+
+	/* Do not add if the item already exists, update if it does exist, but
+	 * has changed. */
+	dif = rssyl_feed_item_exists(ritem, feed_item, &old_item);
+	debug_print("RSSyl: rssyl_feed_item_exists returned %d\n", dif);
+
+	if( dif == EXISTS_UNCHANGED ) {
+		debug_print("RSSyl: This item already exists, skipping...\n");
+		return;
+	}
+
+	/* Item is already in the list, but has changed */
+	if( dif >= EXISTS_CHANGED && old_item != NULL ) {
+		debug_print("RSSyl: Item changed, removing old one and adding new.\n");
+
+		/* Store permflags of the old item. */
+		ctx = (RFeedCtx *)old_item->data;
+		msginfo = folder_item_get_msginfo((FolderItem *)ritem,
+				atoi(g_path_get_basename(ctx->path)));
+		oldperm_flags = msginfo->flags.perm_flags;
+
+		ritem->items = g_slist_remove(ritem->items, old_item);
+		g_remove(ctx->path);
+
+		g_free(ctx->path);
+		feed_item_free(old_item);
+		old_item = NULL;
+	}
+
+	/* Check against list of deleted items. */
+	if (rssyl_deleted_check(ritem->deleted_items, feed_item)) {
+		debug_print("RSSyl: Item '%s' found among deleted items, NOT adding it.\n",
+				feed_item_get_title(feed_item));
+		return;
+	}
+
+	/* Add a new item, formatting its title along the way */
+	debug_print("RSSyl: Adding item '%s'\n", feed_item_get_title(feed_item));
+	ritem->items = g_slist_prepend(ritem->items, feed_item_copy(feed_item));
+
+	dirname = folder_item_get_path(&ritem->item);
+	template = g_strconcat(dirname, G_DIR_SEPARATOR_S,
+			RSSYL_TMP_TEMPLATE, NULL);
+	fd = mkstemp(template);
+
+	f = fdopen(fd, "w");
+	if(f == NULL) {
+		g_warning("Couldn't open file '%s', not adding msg!\n", template);
+		g_free(template);
+		return;
+	}
+
+	/* From */
+	if( (tmp = feed_item_get_author(feed_item)) != NULL ) {
+		if( g_utf8_validate(tmp, -1, NULL)) {
+			conv_encode_header_full(hdr, 1023, tmp, strlen("From: "),
+					TRUE, CS_UTF_8);
+			fprintf(f, "From: %s\n", hdr);
+		} else
+			fprintf(f, "From: %s\n", tmp);
+	}
+
+	/* Date */
+	if( (tmpd = feed_item_get_date_modified(feed_item)) != -1 ) {
+		tmp = createRFC822Date(&tmpd);
+		debug_print("RSSyl: using date_modified: '%s'\n", tmp);
+	} else if( (tmpd = feed_item_get_date_published(feed_item)) != -1 ) {
+		tmp = createRFC822Date(&tmpd);
+		debug_print("RSSyl: using date_published: '%s'\n", tmp);
+	} else {
+		tmpd = time(NULL);
+		tmp = createRFC822Date(&tmpd);
+	}
+
+	if( tmp != NULL ) {
+		fprintf(f, "Date: %s\n", tmp);
+		g_free(tmp);
+	}
+
+	if( (tmp = feed_item_get_title(feed_item)) != NULL ) {
+
+		/* (Atom only) Strip HTML markup from title for the Subject line. */
+		if( feed_item_get_title_format(feed_item) == FEED_ITEM_TITLE_HTML
+				|| feed_item_get_title_format(feed_item) == FEED_ITEM_TITLE_XHTML) {
+			debug_print("RSSyl: item title is HTML/XHTML, stripping tags for Subject line\n");
+			tmp = g_strdup(tmp);
+			strip_html(tmp);
+		}
+
+		if( g_utf8_validate(tmp, -1, NULL) ) {
+			conv_encode_header_full(hdr, 1023, tmp, strlen("Subject: "),
+					FALSE, CS_UTF_8);
+			debug_print("RSSyl: Subject: %s\n", hdr);
+			fprintf(f, "Subject: %s\n", hdr);
+		} else
+			fprintf(f, "Subject: %s\n", tmp);
+
+		if( feed_item_get_title_format(feed_item) == FEED_ITEM_TITLE_HTML
+				|| feed_item_get_title_format(feed_item) == FEED_ITEM_TITLE_XHTML) {
+			g_free(tmp);
+			fprintf(f, "X-RSSyl-OrigTitle: %s\n", feed_item_get_title(feed_item));
+		}
+	} else {
+		debug_print("RSSyl: No feed title, it seems\n");
+		fprintf(f, "Subject: (empty)\n");
+	}
+
+	/* X-RSSyl-URL */
+	if( (tmpurl = feed_item_get_url(feed_item)) == NULL ) {
+		if( feed_item_get_id(feed_item) != NULL &&
+				feed_item_id_is_permalink(feed_item) ) {
+			tmpurl = feed_item_get_id(feed_item);
+		}
+	}
+
+	if( tmpurl != NULL )
+		fprintf(f, "X-RSSyl-URL: %s\n", tmpurl);
+
+	if( ritem->last_update > 0) {
+		fprintf(f, "X-RSSyl-Last-Seen: %ld\n", ritem->last_update);
+	}
+
+	/* Message-ID */
+	if( (tmpid = feed_item_get_id(feed_item)) == NULL )
+		tmpid = feed_item_get_url(feed_item);
+	if( tmpid != NULL )
+		fprintf(f, "Message-ID: <%s>\n", tmpid);
+
+	/* X-RSSyl-Comments */
+	if( (text = feed_item_get_comments_url(feed_item)) != NULL )
+		fprintf(f, "X-RSSyl-Comments: %s\n", text);
+
+	/* References */
+	if( (text = feed_item_get_parent_id(feed_item)) != NULL )
+		fprintf(f, "References: <%s>\n", text);
+
+	/* Content-Type */
+	text = feed_item_get_text(feed_item);
+	if( text && g_utf8_validate(text, -1, NULL) ) {
+		fprintf(f, "Content-Type: text/html; charset=UTF-8\n\n");
+		meta_charset = g_strdup("<meta http-equiv=\"Content-Type\" "
+				"content=\"text/html; charset=UTF-8\">");
+	} else {
+		fprintf(f, "Content-Type: text/html\n\n");
+	}
+
+	/* construct base href */
+	if( feed_item_get_url(feed_item) != NULL )
+		baseurl = g_strdup_printf("<base href=\"%s\">\n",
+			feed_item_get_url(feed_item) );
+
+	if( ritem->write_heading )
+		heading = g_strdup_printf("<h2>%s</h2>\n<br><br>\n",
+				feed_item_get_title(feed_item));
+
+	/* Message body */
+	fprintf(f, "<html><head>"
+			"%s\n"
+			"%s"
+			"</head>\n<body>\n"
+			"%s\n"
+			"URL: <a href=\"%s\">%s</a>\n\n<br><br>\n"
+			RSSYL_TEXT_START"\n"
+			"%s%s"
+			RSSYL_TEXT_END"\n\n",
+			(meta_charset ? meta_charset : ""),
+			(baseurl ? baseurl : ""),
+			(heading ? heading : ""),
+			(tmpurl ? tmpurl : ""),
+			(tmpurl ? tmpurl : "n/a"),
+			(text ? text : ""), (text ? "\n" : "") );
+
+	g_free(meta_charset);
+	g_free(baseurl);
+	g_free(heading);
+
+	if( (enc = feed_item_get_enclosure(feed_item)) != NULL )
+		fprintf(f, "<p><a href=\"%s\">Attached media file</a> [%s] (%ld bytes)</p>\n",
+				feed_item_enclosure_get_url(enc),
+				feed_item_enclosure_get_type(enc),
+				feed_item_enclosure_get_size(enc) );
+
+	fprintf(f, "</body></html>\n");
+	fclose(f);
+
+	g_return_if_fail(template != NULL);
+
+	flags = g_new(MsgFlags, 1);
+	flags->perm_flags = MSG_NEW | MSG_UNREAD;
+	flags->tmp_flags = 0;
+
+	d = folder_item_add_msg(&ritem->item, template, flags, TRUE);
+	g_free(template);
+
+	ctx = g_new0(RFeedCtx, 1);
+	ctx->path = (gpointer)g_strdup_printf("%s%c%d", dirname,
+			G_DIR_SEPARATOR, d);
+	ctx->last_seen = ritem->last_update;
+	((FeedItem *)ritem->items->data)->data = (gpointer)ctx;
+
+	/* Unset unread+new if the changed item wasn't set unread and user
+	 * doesn't want to see it unread because of the change. */
+	if (!(oldperm_flags & MSG_UNREAD) && (ritem->silent_update == 2
+			|| (ritem->silent_update == 1 && dif == EXISTS_CHANGED_TEXTONLY)))
+		procmsg_msginfo_unset_flags(
+				folder_item_get_msginfo((FolderItem *)ritem, d), MSG_NEW | MSG_UNREAD, 0);
+
+	debug_print("RSSyl: folder_item_add_msg(): %d\n", d);
+}
diff --git a/src/plugins/rssyl/rssyl_add_item.h b/src/plugins/rssyl/rssyl_add_item.h
new file mode 100644
index 0000000..5e5e4e3
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_add_item.h
@@ -0,0 +1,6 @@
+#ifndef __RSSYL_ADD_ITEM_H
+#define __RSSYL_ADD_ITEM_H
+
+void rssyl_add_item(RFolderItem *ritem, FeedItem *feed_item);
+
+#endif /* __RSSYL_ADD_ITEM_H */
diff --git a/src/plugins/rssyl/rssyl_cb_gtk.c b/src/plugins/rssyl/rssyl_cb_gtk.c
deleted file mode 100644
index 0e49bb9..0000000
--- a/src/plugins/rssyl/rssyl_cb_gtk.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2004 Hiroyuki Yamamoto
- * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
- *
- * - callback handler functions for GTK signals and timeouts
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include <gtk/gtk.h>
-#include <gdk/gdkkeysyms.h>
-
-#include "folderview.h"
-#include "alertpanel.h"
-#include "gtk/inputdialog.h"
-
-#include "date.h"
-#include "feed.h"
-#include "rssyl.h"
-#include "rssyl_gtk.h"
-#include "rssyl_cb_gtk.h"
-#include "prefs_common.h"
-
-gboolean rssyl_props_cancel_cb(GtkWidget *widget, gpointer data)
-{
-	RSSylFolderItem *ritem = (RSSylFolderItem *)data;
-
-	debug_print("RSSyl: Cancel pressed\n");
-	gtk_widget_destroy(ritem->feedprop->window);
-	return FALSE;
-}
-
-gboolean rssyl_props_ok_cb(GtkWidget *widget, gpointer data)
-{
-	RSSylFolderItem *ritem = (RSSylFolderItem *)data;
-
-	debug_print("RSSyl: OK pressed\n");
-	rssyl_gtk_prop_store(ritem);
-
-	gtk_widget_destroy(ritem->feedprop->window);
-
-	return FALSE;
-}
-
-gboolean rssyl_refresh_timeout_cb(gpointer data)
-{
-	RSSylRefreshCtx *ctx = (RSSylRefreshCtx *)data;
-	time_t tt = time(NULL);
-	gchar *tmpdate;
-
-	g_return_val_if_fail(ctx != NULL, FALSE);
-
-	if( prefs_common_get_prefs()->work_offline)
-		return TRUE;
-
-	if( ctx->ritem == NULL || ctx->ritem->url == NULL ) {
-		debug_print("RSSyl: refresh_timeout_cb - ritem or url NULL\n");
-		g_free(ctx);
-		return FALSE;
-	}
-
-	if( ctx->id != ctx->ritem->refresh_id ) {
-		tmpdate = createRFC822Date(&tt);
-		debug_print(" %s: timeout id changed, stopping: %d != %d\n",
-				tmpdate, ctx->id, ctx->ritem->refresh_id);
-		g_free(tmpdate);
-		g_free(ctx);
-		return FALSE;
-	}
-
-	tmpdate = createRFC822Date(&tt);
-	debug_print(" %s: refresh %s (%d)\n", tmpdate, ctx->ritem->url,
-			ctx->ritem->refresh_id);
-	g_free(tmpdate);
-	rssyl_update_feed(ctx->ritem);
-
-	return TRUE;
-}
-
-gboolean rssyl_default_refresh_interval_toggled_cb(GtkToggleButton *default_ri,
-		gpointer data)
-{
-	gboolean active = gtk_toggle_button_get_active(default_ri);
-	GtkWidget *refresh_interval = (GtkWidget *)data;
-
-	debug_print("default is %s\n", ( active ? "ON" : "OFF" ) );
-
-	gtk_widget_set_sensitive(refresh_interval, !active);
-
-	return FALSE;
-}
-
-gboolean rssyl_default_expired_num_toggled_cb(GtkToggleButton *default_ex,
-		gpointer data)
-{
-	gboolean active = gtk_toggle_button_get_active(default_ex);
-	GtkWidget *expired_num = (GtkWidget *)data;
-
-	debug_print("default is %s\n", ( active ? "ON" : "OFF" ) );
-
-	gtk_widget_set_sensitive(expired_num, !active);
-
-	return FALSE;
-}
-
-gboolean rssyl_fetch_comments_toggled_cb(GtkToggleButton *fetch_comments,
-		gpointer data)
-{
-	gboolean active = gtk_toggle_button_get_active(fetch_comments);
-	GtkWidget *num_comments = (GtkWidget *)data;
-
-	debug_print("fetch comments is %s\n", (active ? "ON" : "OFF") );
-
-	gtk_widget_set_sensitive(num_comments, active);
-
-	return FALSE;
-}
-
-gboolean rssyl_props_key_press_cb(GtkWidget *widget, GdkEventKey *event,
-		gpointer data)
-{
-	if (event) {
-		switch (event->keyval) {
-			case GDK_Escape:
-				rssyl_props_cancel_cb(widget, data);
-				return TRUE;
-			case GDK_Return:
-			case GDK_KP_Enter:
-				rssyl_props_ok_cb(widget, data);
-				return TRUE;
-			default:
-				break;
-		}
-	}
-
-	return FALSE;
-}
diff --git a/src/plugins/rssyl/rssyl_cb_gtk.h b/src/plugins/rssyl/rssyl_cb_gtk.h
deleted file mode 100644
index a49d3a3..0000000
--- a/src/plugins/rssyl/rssyl_cb_gtk.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __RSSYL_GTK_CB
-#define __RSSYL_GTK_CB
-
-#include <glib.h>
-#include <gtk/gtk.h>
-
-gboolean rssyl_props_cancel_cb(GtkWidget *widget, gpointer data);
-gboolean rssyl_props_ok_cb(GtkWidget *widget, gpointer data);
-gboolean rssyl_refresh_timeout_cb(gpointer data);
-gboolean rssyl_default_refresh_interval_toggled_cb(GtkToggleButton *default_ri,
-		gpointer data);
-gboolean rssyl_default_expired_num_toggled_cb(GtkToggleButton *default_ex,
-		gpointer data);
-gboolean rssyl_fetch_comments_toggled_cb(GtkToggleButton *fetch_comments,
-		gpointer data);
-gboolean rssyl_props_key_press_cb(GtkWidget *widget, GdkEventKey *event,
-		gpointer data);
-
-#endif /* __RSSYL_GTK_CB */
diff --git a/src/plugins/rssyl/rssyl_cb_menu.c b/src/plugins/rssyl/rssyl_cb_menu.c
index f3047de..d0c2ef9 100644
--- a/src/plugins/rssyl/rssyl_cb_menu.c
+++ b/src/plugins/rssyl/rssyl_cb_menu.c
@@ -1,5 +1,5 @@
 /*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
  * Copyright (C) 1999-2004 Hiroyuki Yamamoto
  * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
  *
@@ -22,34 +22,38 @@
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
-#include "claws-features.h"
 #endif
 
+/* Global includes */
 #include <glib.h>
 #include <glib/gi18n.h>
-
 #include <gtk/gtk.h>
 
-#include "folderview.h"
-#include "alertpanel.h"
-#include "gtk/inputdialog.h"
-#include "prefs_common.h"
-#include "filesel.h"
-#include "inc.h"
-#include "folder_item_prefs.h"
-
-#include "feed.h"
-#include "feedprops.h"
-#include "opml.h"
-#include "rssyl.h"
+/* Claws Mail includes */
+#include <folderview.h>
+#include <alertpanel.h>
+#include <gtk/inputdialog.h>
+#include <prefs_common.h>
+#include <folder_item_prefs.h>
+#include <filesel.h>
+#include <inc.h>
+
+/* Local includes */
+#include "libfeed/parser_opml.h"
 #include "rssyl_gtk.h"
-
-void rssyl_new_feed_cb(GtkAction *action, gpointer data)
+#include "rssyl_feed.h"
+#include "rssyl_feed_props.h"
+#include "rssyl_update_feed.h"
+#include "rssyl_subscribe.h"
+#include "opml_import.h"
+
+void rssyl_new_feed_cb(GtkAction *action,
+		gpointer data)
 {
-	FolderView *folderview = (FolderView *)data;
+	FolderView *folderview = (FolderView*)data;
 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
 	FolderItem *item;
-	gchar *new_feed;
+	gchar *url;
 
 	debug_print("RSSyl: new_feed_cb\n");
 
@@ -59,26 +63,26 @@ void rssyl_new_feed_cb(GtkAction *action, gpointer data)
 	g_return_if_fail(item != NULL);
 	g_return_if_fail(item->folder != NULL);
 
-	new_feed = input_dialog(_("Subscribe feed"),
-					 _("Input the URL of the news feed you wish to subscribe:"),
-					 "");
-	g_return_if_fail(new_feed != NULL);
+	url = input_dialog(_("Subscribe feed"),
+			_("Input the URL of the news feed you wish to subscribe:"),
+			"");
+	if( url == NULL )	/* User cancelled */
+		return;
 
-	rssyl_subscribe_new_feed(item, new_feed, TRUE);
+	rssyl_subscribe(item, url, TRUE);
 
-	g_free(new_feed);
+	g_free(url);
 }
 
-void rssyl_new_folder_cb(GtkAction *action, gpointer data)
+void rssyl_new_folder_cb(GtkAction *action,
+		gpointer data)
 {
-	FolderView *folderview = (FolderView *)data;
+	FolderView *folderview = (FolderView*)data;
 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
 	FolderItem *item;
 	FolderItem *new_item;
-	gchar *new_folder;
-	gchar *name;
-	gchar *p;
-	RSSylFolderItem *ritem = NULL;
+	gchar *new_folder, *p, *tmp;
+	gint i = 1;
 
 	if (!folderview->selected) return;
 
@@ -90,132 +94,44 @@ void rssyl_new_folder_cb(GtkAction *action, gpointer data)
 				  _("Input the name of new folder:"),
 				  _("NewFolder"));
 	if (!new_folder) return;
-	AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
 
 	p = strchr(new_folder, G_DIR_SEPARATOR);
 	if (p) {
-		alertpanel_error(_("'%c' can't be included in folder name."),
+		alertpanel_error(_("'%c' can't be used in folder name."),
 				 G_DIR_SEPARATOR);
+		g_free(new_folder);
 		return;
 	}
 
-	name = trim_string(new_folder, 32);
-	AUTORELEASE_STR(name, {g_free(name); return;});
-
-	/* find whether the directory already exists */
-	if (folder_find_child_item_by_name(item, new_folder)) {
-		alertpanel_error(_("The folder '%s' already exists."), name);
-		return;
+	/* Find an unused name for new folder */
+	/* TODO: Perhaps stop after X attempts? */
+	tmp = g_strdup(new_folder);
+	while (folder_find_child_item_by_name(item, tmp)) {
+		debug_print("RSSyl: Folder '%s' already exists, trying another name\n",
+				new_folder);
+		g_free(tmp);
+		tmp = g_strdup_printf("%s__%d", new_folder, ++i);
 	}
 
+	g_free(new_folder);
+	new_folder = tmp;
+
 	new_item = folder_create_folder(item, new_folder);
 	if (!new_item) {
-		alertpanel_error(_("Can't create the folder '%s'."), name);
-		return;
-	}
-
-	ritem = (RSSylFolderItem *)new_item;
-	ritem->url = NULL;
-
-	folder_write_list();
-}
-
-void rssyl_remove_rss_cb(GtkAction *action, gpointer data)
-{
-	FolderView *folderview = (FolderView *)data;
-	FolderItem *item;
-	gchar *name, *message;
-	AlertValue aval;
-
-	debug_print("RSSyl: remove_rss_cb\n");
-
-	item = folderview_get_selected_item(folderview);
-	g_return_if_fail(item != NULL);
-	g_return_if_fail(item->folder != NULL);
-	g_return_if_fail( !folder_item_parent(item) );
-
-	name = trim_string(item->folder->name, 32);
-	message = g_strdup_printf(_("Really remove the folder tree '%s'?\n"), name);
-	aval = alertpanel_full(_("Remove folder tree"), message,
-			 GTK_STOCK_CANCEL, _("_Remove"), NULL, FALSE, NULL,
-			  ALERT_WARNING, G_ALERTDEFAULT);
-	g_free(message);
-	g_free(name);
-
-	if (aval != G_ALERTALTERNATE)
-		return;
-
-	folderview_unselect(folderview);
-	summary_clear_all(folderview->summaryview);
-
-	folder_destroy(item->folder);
-}
-
-void rssyl_remove_feed_cb(GtkAction *action, gpointer data)
-{
-	FolderView *folderview = (FolderView *)data;
-	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
-	FolderItem *item;
-	gint response;
-	GtkWidget *dialog, *rmcache_widget = NULL;
-	gboolean rmcache = FALSE;
-	debug_print("RSSyl: remove_feed_cb\n");
-
-	item = folderview_get_selected_item(folderview);
-	g_return_if_fail(item != NULL);
-	g_return_if_fail(item->path != NULL);
-	g_return_if_fail(item->folder != NULL);
-
-	dialog = rssyl_feed_removal_dialog(item->name, &rmcache_widget);
-
-	g_return_if_fail(dialog != NULL);
-
-	gtk_widget_show_all(dialog);
-
-	response = gtk_dialog_run(GTK_DIALOG(dialog));
-
-	if( response != GTK_RESPONSE_YES ) {
-		debug_print("'No' clicked, returning\n");
-		gtk_widget_destroy(dialog);
+		alertpanel_error(_("Can't create the folder '%s'."), new_folder);
+		g_free(new_folder);
 		return;
 	}
 
-	g_return_if_fail(rmcache_widget != NULL);
-
-	rmcache = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(rmcache_widget) );
-
-	gtk_widget_destroy(dialog);
-
-	if( folderview->opened == folderview->selected ||
-			gtk_cmctree_is_ancestor(ctree,
-					folderview->selected,
-					folderview->opened) ) {
-		summary_clear_all(folderview->summaryview);
-		folderview->opened = NULL;
-	}
-
-	rssyl_remove_feed_props((RSSylFolderItem *)item);
-
-	if( rmcache == TRUE )
-		rssyl_remove_feed_cache(item);
-
-	if( item->folder->klass->remove_folder(item->folder, item) < 0 ) {
-		gchar *tmp;
-		tmp = g_markup_printf_escaped(_("Can't remove feed '%s'."), item->name);
-		alertpanel_error("%s", tmp);
-		g_free(tmp);
-		if( folderview->opened == folderview->selected )
-			summary_show(folderview->summaryview,
-					folderview->summaryview->folder_item);
-		return;
-	}
+	g_free(new_folder);
 
 	folder_write_list();
 }
 
-void rssyl_remove_folder_cb(GtkAction *action, gpointer data)
+void rssyl_remove_folder_cb(GtkAction *action,
+			     gpointer data)
 {
-	FolderView *folderview = (FolderView *)data;
+	FolderView *folderview = (FolderView*)data;
 	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
 	FolderItem *item;
 	gchar *message, *name;
@@ -263,45 +179,82 @@ void rssyl_remove_folder_cb(GtkAction *action, gpointer data)
 
 }
 
-void rssyl_refresh_cb(GtkAction *action, gpointer data)
+void rssyl_rename_cb(GtkAction *action,
+			     gpointer *data)
 {
-	FolderView *folderview = (FolderView *)data;
 	FolderItem *item;
-	RSSylFolderItem *ritem;
-
+	gchar *new_folder;
+	gchar *name;
+	gchar *message;
+	FolderView *folderview = (FolderView*)data;
 	item = folderview_get_selected_item(folderview);
 	g_return_if_fail(item != NULL);
+	g_return_if_fail(item->path != NULL);
 	g_return_if_fail(item->folder != NULL);
 
-	ritem = (RSSylFolderItem *)item;
+	name = trim_string(item->name, 32);
+	message = g_strdup_printf(_("Input new name for '%s':"), name);
+	new_folder = input_dialog(_("Rename folder"), message, name);
+	g_free(message);
+	g_free(name);
+	if (!new_folder) return;
+	AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
+
+	if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
+		alertpanel_error(_("'%c' can't be included in folder name."),
+				 G_DIR_SEPARATOR);
+		return;
+	}
 
-	if (prefs_common_get_prefs()->work_offline && 
-	   !inc_offline_should_override(TRUE,
-			ngettext(
-			   "Claws Mail needs network access in order "
-			   "to update the feed.",
-			   "Claws Mail needs network access in order "
-			   "to update the feeds.", 1))) {
-			return;
+	if (folder_find_child_item_by_name(folder_item_parent(item), new_folder)) {
+		name = trim_string(new_folder, 32);
+		alertpanel_error(_("The folder '%s' already exists."), name);
+		g_free(name);
+		return;
 	}
 
-	main_window_cursor_wait(mainwindow_get_mainwindow());
-	rssyl_update_feed(ritem);
-	main_window_cursor_normal(mainwindow_get_mainwindow());
+	if (folder_item_rename(item, new_folder) < 0) {
+		alertpanel_error(_("The folder could not be renamed.\n"
+				   "The new folder name is not allowed."));
+		return;
+	}
+
+	folder_item_prefs_save_config(item);
+	folder_write_list();
 }
 
-void rssyl_refresh_all_cb(GtkAction *action, gpointer data)
+void rssyl_refresh_feed_cb(GtkAction *action,
+		gpointer data)
 {
-	main_window_cursor_wait(mainwindow_get_mainwindow());
-	rssyl_refresh_all_feeds();
-	main_window_cursor_normal(mainwindow_get_mainwindow());
+	FolderView *folderview = (FolderView*)data;
+	FolderItem *item = NULL;
+	RFolderItem *ritem = NULL;
+
+	item = folderview_get_selected_item(folderview);
+	g_return_if_fail(item != NULL);
+	g_return_if_fail(item->folder != NULL);
+
+	ritem = (RFolderItem *)item;
+
+	/* Offline check */
+	if( prefs_common.work_offline &&
+			!inc_offline_should_override(TRUE,
+					ngettext("Claws-Mail needs network access in order "
+					"to update the feed.",
+					"Claws-Mail needs network access in order "
+					"to update feeds.", 1))) {
+		return;
+	}
+
+	/* Update feed, displaying errors if any. */
+	rssyl_update_feed(ritem, TRUE);
 }
 
 void rssyl_prop_cb(GtkAction *action, gpointer data)
 {
-	FolderView *folderview = (FolderView *)data;
+	FolderView *folderview = (FolderView*)data;
 	FolderItem *item;
-	RSSylFolderItem *ritem;
+	RFolderItem *ritem;
 
 	item = folderview_get_selected_item(folderview);
 	g_return_if_fail(item != NULL);
@@ -309,74 +262,103 @@ void rssyl_prop_cb(GtkAction *action, gpointer data)
 
 	debug_print("RSSyl: rssyl_prop_cb() for '%s'\n", item->name);
 
-	ritem = (RSSylFolderItem *)item;
-	rssyl_get_feed_props(ritem);
+	ritem = (RFolderItem *)item;
+
 	rssyl_gtk_prop(ritem);
 }
 
-void rssyl_rename_cb(GtkAction *action, gpointer data)
+void rssyl_update_all_cb( GtkAction *action, gpointer data)
 {
-	FolderView *folderview = (FolderView *)data;
 	FolderItem *item;
-	gchar *new_folder;
-	gchar *name;
-	gchar *message;
+	FolderView *folderview = (FolderView*)data;
 
 	item = folderview_get_selected_item(folderview);
 	g_return_if_fail(item != NULL);
-	g_return_if_fail(item->path != NULL);
 	g_return_if_fail(item->folder != NULL);
 
-	name = trim_string(item->name, 32);
-	message = g_strdup_printf(_("Input new name for '%s':"), name);
-	new_folder = input_dialog(_("Rename folder"), message, item->name);
-	g_free(message);
-	g_free(name);
-	if (!new_folder) return;
-	AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
+	debug_print("RSSyl: rssyl_update_all_cb(): clicked on '%s'\n", item->name);
 
-	if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
-		alertpanel_error(_("'%c' can't be included in folder name."),
-				 G_DIR_SEPARATOR);
+	if( item->folder->klass != rssyl_folder_get_class() ) {
+		debug_print("RSSyl: this is not a RSSyl folder, returning\n");
 		return;
 	}
 
-	if (folder_find_child_item_by_name(folder_item_parent(item), new_folder)) {
-		name = trim_string(new_folder, 32);
-		alertpanel_error(_("The folder '%s' already exists."), name);
-		g_free(name);
+	rssyl_update_recursively(item);
+}
+
+void rssyl_remove_mailbox_cb(GtkAction *action, gpointer data)
+{
+	FolderView *folderview = (FolderView *)data;
+	FolderItem *item = NULL;
+	gchar *n, *message;
+	AlertValue avalue;
+
+	item = folderview_get_selected_item(folderview);
+
+	g_return_if_fail(item != NULL);
+	g_return_if_fail(item->folder != NULL);
+
+	if( folder_item_parent(item) )
 		return;
-	}
 
-	if (folder_item_rename(item, new_folder) < 0) {
-		alertpanel_error(_("The folder could not be renamed.\n"
-				   "The new folder name is not allowed."));
+	n = trim_string(item->folder->name, 32);
+	message = g_strdup_printf(_("Really remove the feed tree `%s' ?\n"), n);
+	avalue = alertpanel_full(_("Remove feed tree"), message,
+				 GTK_STOCK_CANCEL, _("_Remove"), NULL, FALSE,
+				 NULL, ALERT_WARNING, G_ALERTDEFAULT);
+	g_free(message);
+	g_free(n);
+
+	if( avalue != G_ALERTALTERNATE )
+		return;
+
+	folderview_unselect(folderview);
+	summary_clear_all(folderview->summaryview);
+
+	n = folder_item_get_path(item);
+	if( remove_dir_recursive(n) < 0 ) {
+		g_warning("can't remove directory '%s'\n", n);
+		g_free(n);
 		return;
 	}
 
-	folder_item_prefs_save_config_recursive(item);
-	folder_write_list();
+	g_free(n);
+	folder_destroy(item->folder);
 }
 
 void rssyl_import_feed_list_cb(GtkAction *action, gpointer data)
 {
 	FolderView *folderview = (FolderView *)data;
-	debug_print("RSSyl: rssyl_import_feed_cb\n");
+	GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
+	FolderItem *item = NULL;
+	gchar *path = NULL;
+	OPMLImportCtx *ctx = NULL;
 
-	FolderItem *item;
-	gchar *opmlfile = NULL;
+	debug_print("RSSyl: import_feed_list_cb\n");
 
-	item = folderview_get_selected_item(folderview);
+	/* Ask user for a file to import */
+	path = filesel_select_file_open_with_filter(
+			_("Select an OPML file"), NULL, "*.opml");
+	if (!is_file_exist(path)) {
+		g_free(path);
+		return;
+	}
+
+	/* Find the destination folder for the import */
+	g_return_if_fail(folderview->selected != NULL);
+	item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
 	g_return_if_fail(item != NULL);
 	g_return_if_fail(item->folder != NULL);
 
-	opmlfile = filesel_select_file_open_with_filter(
-			_("Select a .opml file"), NULL, "*.opml");
-	
-	if (!is_file_exist(opmlfile)) {
-		g_free(opmlfile);
-		return;
-	}
+	ctx = malloc( sizeof(OPMLImportCtx) );
+	ctx->failures = 0;
+	ctx->depth = rssyl_folder_depth(item);
+	ctx->current = NULL;
+	ctx->current = g_slist_append(ctx->current, item);
+
+	/* Start the whole shebang - call libfeed's OPML parser with correct
+	 * user function */
+	opml_process(path, rssyl_opml_import_func, (gpointer)ctx);
 
-	rssyl_opml_import(opmlfile, item);
+	g_free(ctx);
 }
diff --git a/src/plugins/rssyl/rssyl_cb_menu.h b/src/plugins/rssyl/rssyl_cb_menu.h
index 098f43c..258f9a5 100644
--- a/src/plugins/rssyl/rssyl_cb_menu.h
+++ b/src/plugins/rssyl/rssyl_cb_menu.h
@@ -7,14 +7,13 @@
 #include "folderview.h"
 
 void rssyl_new_feed_cb(GtkAction *action, gpointer data);
-void rssyl_remove_feed_cb(GtkAction *action, gpointer data);
-void rssyl_remove_rss_cb(GtkAction *action, gpointer data);
-void rssyl_refresh_cb(GtkAction *action, gpointer data);
-void rssyl_prop_cb(GtkAction *action, gpointer data);
-void rssyl_import_feed_list_cb(GtkAction *action, gpointer data);
-void rssyl_refresh_all_cb(GtkAction *action, gpointer data);
 void rssyl_rename_cb(GtkAction *action, gpointer data);
 void rssyl_new_folder_cb(GtkAction *action, gpointer data);
 void rssyl_remove_folder_cb(GtkAction *action, gpointer data);
+void rssyl_refresh_feed_cb(GtkAction *action, gpointer data);
+void rssyl_prop_cb(GtkAction *action, gpointer data);
+void rssyl_update_all_cb(GtkAction *action, gpointer data);
+void rssyl_remove_mailbox_cb(GtkAction *action, gpointer data);
+void rssyl_import_feed_list_cb(GtkAction *action, gpointer data);
 
 #endif /* __RSSYL_MENU_FEED */
diff --git a/src/plugins/rssyl/rssyl_deleted.c b/src/plugins/rssyl/rssyl_deleted.c
new file mode 100644
index 0000000..2d39adb
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_deleted.c
@@ -0,0 +1,354 @@
+/*
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
+ *
+ * - handling of info about user-deleted feed items
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <string.h>
+
+/* Claws Mail includes */
+#include <codeconv.h>
+#include <common/utils.h>
+
+/* Local includes */
+#include "rssyl.h"
+#include "parse822.h"
+#include "strutils.h"
+
+static RDeletedItem *_new_deleted_item()
+{
+	RDeletedItem *ditem = g_new0(RDeletedItem, 1);
+
+	ditem->id = NULL;
+	ditem->title = NULL;
+	ditem->date_published = -1;
+	ditem->date_modified = -1;
+
+	return ditem;
+}
+
+static void _free_deleted_item(gpointer d, gpointer user_data)
+{
+	RDeletedItem *ditem = (RDeletedItem *)d;
+
+	if (ditem == NULL)
+		return;
+
+	g_free(ditem->id);
+	g_free(ditem->title);
+	g_free(ditem);
+}
+
+void rssyl_deleted_free(GSList *deleted_items)
+{
+	if (deleted_items != NULL) {
+		debug_print("RSSyl: releasing list of deleted items\n");
+		g_slist_foreach(deleted_items, _free_deleted_item, NULL);
+		g_slist_free(deleted_items);
+		deleted_items = NULL;
+	}
+}
+
+static gchar * _deleted_file_path(RFolderItem *ritem)
+{
+	gchar *itempath, *deleted_file;
+
+	itempath = folder_item_get_path(&ritem->item);
+	deleted_file = g_strconcat(itempath, G_DIR_SEPARATOR_S, RSSYL_DELETED_FILE, NULL);
+	g_free(itempath);
+
+	return deleted_file;
+}
+
+/***************************************************************/
+GSList *rssyl_deleted_update(RFolderItem *ritem)
+{
+	gchar *deleted_file, *contents, **lines, **line;
+	GError *error = NULL;
+	guint i = 0;
+	RDeletedItem *ditem = NULL;
+	GSList *deleted_items = NULL;
+
+	g_return_val_if_fail(ritem != NULL, NULL);
+
+	deleted_file = _deleted_file_path(ritem);
+
+	debug_print("RSSyl: getting list of deleted items from '%s'\n", deleted_file);
+
+	if (!g_file_test(deleted_file, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+		debug_print("RSSyl: '%s' doesn't exist, ignoring\n", deleted_file);
+		return NULL;
+	}
+
+	g_file_get_contents(deleted_file, &contents, NULL, &error);
+
+	if (error)
+		g_warning("GError: '%s'\n", error->message);
+
+	if (contents != NULL) {
+		lines = strsplit_no_copy(contents, '\n');
+	} else {
+		g_warning("Couldn't read '%s', ignoring\n", deleted_file);
+		g_free(deleted_file);
+		return NULL;
+	}
+
+	g_free(deleted_file);
+
+	while (lines[i]) {
+		line = g_strsplit(lines[i], ": ", 2);
+		if (line[0] && line[1] && strlen(line[0]) && strlen(line[1])) {
+			if (!strcmp(line[0], "ID")) {
+				ditem = _new_deleted_item();
+				ditem->id = g_strdup(line[1]);
+			} else if (ditem != NULL && !strcmp(line[0], "TITLE")) {
+				ditem->title = g_strdup(line[1]);
+			} else if (ditem != NULL && !strcmp(line[0], "DPUB")) {
+				ditem->date_published = atoi(line[1]);
+			} else if (ditem != NULL && !strcmp(line[0], "DMOD")) {
+				ditem->date_modified = atoi(line[1]);
+				deleted_items = g_slist_prepend(deleted_items, ditem);
+				ditem = NULL;
+			}
+		}
+
+		g_strfreev(line);
+		i++;
+	}
+
+	g_free(lines);
+	g_free(contents);
+
+	debug_print("RSSyl: got %d deleted items\n", g_slist_length(deleted_items));
+	return deleted_items;
+}
+
+static void _store_one_deleted_item(gpointer data, gpointer user_data)
+{
+	RDeletedItem *ditem = (RDeletedItem *)data;
+	FILE *f = (FILE *)user_data;
+	gboolean err = FALSE;
+
+	if (ditem == NULL || ditem->id == NULL)
+		return;
+
+	err |= (fprintf(f,
+			"ID: %s\n"
+			"TITLE: %s\n"
+			"DPUB: %ld\n"
+			"DMOD: %ld\n",
+			ditem->id, ditem->title,
+			ditem->date_published, ditem->date_modified) < 0);
+
+	if (err)
+		debug_print("RSSyl: Error during writing deletion file.\n");
+}
+
+static void rssyl_deleted_store_internal(GSList *deleted_items, const gchar *deleted_file)
+{
+	FILE *f;
+
+	if (g_file_test(deleted_file, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
+		g_remove(deleted_file);
+
+	if (g_slist_length(deleted_items) == 0)
+		return;
+
+	if ((f = g_fopen(deleted_file, "w")) == NULL) {
+		debug_print("RSSyl: Couldn't open '%s', ignoring.\n", deleted_file);
+		return;
+	}
+
+	g_slist_foreach(deleted_items, (GFunc)_store_one_deleted_item,
+			(gpointer)f);
+	
+	fclose(f);
+	debug_print("RSSyl: written and closed deletion file\n");
+}
+
+void rssyl_deleted_store(RFolderItem *ritem)
+{
+	gchar *path;
+
+	g_return_if_fail(ritem != NULL);
+
+	path = _deleted_file_path(ritem);
+	rssyl_deleted_store_internal(ritem->deleted_items, path);
+}
+
+
+/* Creates a FeedItem from a message file and uses the data to add a item
+ * to the list of deleted stuff. */
+void rssyl_deleted_add(RFolderItem *ritem, gchar *path)
+{
+	FeedItem *fitem = NULL;
+	RDeletedItem *ditem = NULL;
+	GSList *deleted_items = rssyl_deleted_update(ritem);
+	gchar *deleted_file = NULL;
+
+	if (!(fitem = rssyl_parse_folder_item_file(path)))
+		return;
+
+	ditem = _new_deleted_item();
+	ditem->id = g_strdup(feed_item_get_id(fitem));
+	ditem->title = conv_unmime_header(feed_item_get_title(fitem),
+			CS_UTF_8, FALSE);
+	ditem->date_published = feed_item_get_date_published(fitem);
+	ditem->date_modified = feed_item_get_date_modified(fitem);
+
+	deleted_items = g_slist_prepend(deleted_items, ditem);
+
+	deleted_file = _deleted_file_path(ritem);
+	rssyl_deleted_store_internal(deleted_items, deleted_file);
+	g_free(deleted_file);
+
+	rssyl_deleted_free(deleted_items);
+}
+
+static gint _rssyl_deleted_check_func(gconstpointer a, gconstpointer b)
+{
+	RDeletedItem *ditem = (RDeletedItem *)a;
+	FeedItem *fitem = (FeedItem *)b;
+
+	g_return_val_if_fail(ditem != NULL, -10);
+	g_return_val_if_fail(fitem != NULL, -20);
+
+	/* Following must match:
+	 * ID, ... */
+	if (!ditem->id || !feed_item_get_id(fitem) ||
+			strcmp(ditem->id, feed_item_get_id(fitem)))
+		return -1;
+
+	/* title, ... */
+	if (!ditem->title || !feed_item_get_title(fitem) ||
+			strcmp(ditem->title, feed_item_get_title(fitem)))
+		return -2;
+
+	/* time of publishing, ... */
+	if (ditem->date_published != -1 &&
+			ditem->date_published != feed_item_get_date_published(fitem))
+		return -3;
+
+	/* and the time of last modification must be greater
+	 * (this means that the item was updated since deletion, and possibly
+	 * contains new data, so we add it again) */
+	if (ditem->date_modified != -1 &&
+			ditem->date_modified < feed_item_get_date_modified(fitem))
+		return -4;
+
+	return 0;
+}
+
+/* Returns TRUE if fitem is found among the deleted stuff. */
+gboolean rssyl_deleted_check(GSList *deleted_items, FeedItem *fitem)
+{
+	if (g_slist_find_custom(deleted_items, (gconstpointer)fitem,
+				_rssyl_deleted_check_func) != NULL)
+		return TRUE;
+
+	return FALSE;
+}
+
+/******** Expiring ********/
+struct _RDelExpireCtx {
+	RDeletedItem *ditem;
+	gboolean delete;
+};
+
+typedef struct _RDelExpireCtx RDelExpireCtx;
+
+static void _rssyl_deleted_expire_func_f(gpointer data, gpointer user_data)
+{
+	FeedItem *fitem = (FeedItem *)data;
+	RDelExpireCtx *ctx = (RDelExpireCtx *)user_data;
+
+	/* Following must match:
+	 * ID, ... */
+	if (!ctx->ditem->id || !feed_item_get_id(fitem) ||
+			strcmp(ctx->ditem->id, feed_item_get_id(fitem)))
+		return;
+
+	/* title, ... */
+	if (!ctx->ditem->title || !feed_item_get_title(fitem) ||
+			strcmp(ctx->ditem->title, feed_item_get_title(fitem)))
+		return;
+
+	/* time of publishing, ... */
+	if (ctx->ditem->date_published != feed_item_get_date_published(fitem))
+		return;
+
+	/* and the time of last modification must be greater
+	 * (this means that the item was updated since deletion, and possibly
+	 * contains new data, so we add it again) */
+	if (ctx->ditem->date_modified != feed_item_get_date_modified(fitem))
+		return;
+
+	ctx->delete = FALSE;
+}
+
+/* Checks each item in deleted items list against feed and removes it if
+ * it is not found there anymore. */
+void rssyl_deleted_expire(RFolderItem *ritem, Feed *feed)
+{
+	GSList *d = NULL, *d2;
+	RDelExpireCtx *ctx = NULL;
+	RDeletedItem *ditem;
+
+	g_return_if_fail(ritem != NULL);
+	g_return_if_fail(feed != NULL);
+
+	ritem->deleted_items = rssyl_deleted_update(ritem);
+
+	/* Iterate over all items in the list */
+	d = ritem->deleted_items;
+	while (d) {
+		ditem = (RDeletedItem *)d->data;
+		ctx = g_new0(RDelExpireCtx, 1);
+		ctx->ditem = ditem;
+		ctx->delete = TRUE;
+
+		/* Adjust ctx->delete accordingly */
+		feed_foreach_item(feed, _rssyl_deleted_expire_func_f, (gpointer)ctx);
+
+		/* Remove the item if necessary */
+		if (ctx->delete) {
+			debug_print("RSSyl: (DELETED) removing '%s' from list\n", ditem->title);
+			d2 = d->next;
+			ritem->deleted_items = g_slist_remove_link(ritem->deleted_items, d);
+			d = d2;
+			continue;
+		} else {
+			d = d->next;
+		}
+
+		g_free(ctx);
+	}
+
+	/* Write the new list to disk */
+	rssyl_deleted_store(ritem);
+
+	/* And clean up after myself */
+	rssyl_deleted_free(ritem->deleted_items);
+}
diff --git a/src/plugins/rssyl/rssyl_deleted.h b/src/plugins/rssyl/rssyl_deleted.h
new file mode 100644
index 0000000..d3c198d
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_deleted.h
@@ -0,0 +1,14 @@
+#ifndef __RSSYL_DELETED_H
+#define __RSSYL_DELETED_H
+
+#include <glib.h>
+
+#include "rssyl.h"
+
+GSList *rssyl_deleted_update(RFolderItem *ritem);
+void *rssyl_deleted_free(GSList *deleted_items);
+void rssyl_deleted_add(RFolderItem *ritem, gchar *path);
+gboolean rssyl_deleted_check(GSList *deleted_items, FeedItem *fitem);
+void rssyl_deleted_expire(RFolderItem *ritem, Feed *feed);
+
+#endif /* __RSSYL_DELETED_H */
diff --git a/src/plugins/rssyl/rssyl_feed.c b/src/plugins/rssyl/rssyl_feed.c
new file mode 100644
index 0000000..46edc01
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_feed.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <glib/gi18n.h>
+
+/* Claws Mail includes */
+#include <folder.h>
+#include <alertpanel.h>
+#include <procheader.h>
+#include <prefs_common.h>
+#include <mainwindow.h>
+
+/* Local includes */
+#include "libfeed/feeditem.h"
+#include "libfeed/date.h"
+#include "rssyl.h"
+#include "rssyl_feed.h"
+#include "rssyl_prefs.h"
+#include "rssyl_update_feed.h"
+#include "strutils.h"
+
+FolderItem *rssyl_feed_subscribe_new(FolderItem *parent, const gchar *url,
+		gboolean verbose)
+{
+	gchar *myurl = NULL, *tmpname = NULL;
+	FolderItem *new_item = NULL;
+	RFolderItem *ritem = NULL;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail(parent != NULL, FALSE);
+	g_return_val_if_fail(url != NULL, FALSE);
+
+	log_print(LOG_PROTOCOL, RSSYL_LOG_SUBSCRIBING, url);
+
+	if( !strncmp(url, "feed://", 7) )
+		myurl = g_strdup(url+7);
+	else if( !strncmp(url, "feed:", 5) )
+		myurl = g_strdup(url+5);
+	else
+		myurl = g_strdup(url);
+
+	myurl = g_strchomp(myurl);
+
+	gtk_cmclist_freeze(GTK_CMCLIST(mainwindow_get_mainwindow()->folderview->ctree));
+	folder_item_update_freeze();
+
+	/* Create a feed folder with generic name. */
+	tmpname = g_strdup_printf("%s.%ld", RSSYL_NEW_FOLDER_NAME, (long int)time(NULL));
+	new_item = folder_create_folder(parent, tmpname);
+	g_free(tmpname);
+	if( !new_item ) {
+		if( verbose )
+			alertpanel_error(_("Couldn't create folder for new feed '%s'."),
+						myurl);
+		g_free(myurl);
+		return NULL;
+	}
+
+	/* Set it up as a RSSyl folder */
+	ritem = (RFolderItem *)new_item;
+	ritem->url = g_strdup(myurl);
+
+	/* Try to update it, delete if failed.
+	 * (it is renamed in rssyl_update_feed(). */
+	if( (success = rssyl_update_feed(ritem, verbose)) == FALSE )
+		new_item->folder->klass->remove_folder(new_item->folder, new_item);
+	else {
+		folder_item_scan(new_item);
+		folder_write_list();
+	}
+
+	folder_item_update_thaw();
+	gtk_cmclist_thaw(GTK_CMCLIST(mainwindow_get_mainwindow()->folderview->ctree));
+
+	if( success )
+		log_print(LOG_PROTOCOL, RSSYL_LOG_SUBSCRIBED, ritem->official_title,
+				ritem->url);
+	else {
+		debug_print("RSSyl: Failed to add feed '%s'\n", myurl);
+		g_free(myurl);
+		return NULL;
+	}
+
+	return new_item;
+}
+
+MsgInfo *rssyl_feed_parse_item_to_msginfo(gchar *file, MsgFlags flags,
+		gboolean a, gboolean b, FolderItem *item)
+{
+	MsgInfo *msginfo;
+
+	g_return_val_if_fail(item != NULL, NULL);
+
+	msginfo = procheader_parse_file(file, flags, a, b);
+	if (msginfo)
+		msginfo->folder = item;
+
+	return msginfo;
+}
+
+gboolean rssyl_refresh_timeout_cb(gpointer data)
+{
+	RRefreshCtx *ctx = (RRefreshCtx *)data;
+	time_t tt = time(NULL);
+	gchar *tmpdate = NULL;
+
+	g_return_val_if_fail(ctx != NULL, FALSE);
+
+	if( prefs_common.work_offline)
+		return TRUE;
+
+	if( ctx->ritem == NULL || ctx->ritem->url == NULL ) {
+		debug_print("RSSyl: refresh_timeout_cb - ritem or url NULL\n");
+		g_free(ctx);
+		return FALSE;
+	}
+
+	if( ctx->id != ctx->ritem->refresh_id ) {
+		tmpdate = createRFC822Date(&tt);
+		debug_print("RSSyl: %s: timeout id changed, stopping: %d != %d\n",
+				tmpdate, ctx->id, ctx->ritem->refresh_id);
+		g_free(tmpdate);
+		g_free(ctx);
+		return FALSE;
+	}
+
+	tmpdate = createRFC822Date(&tt);
+	debug_print(" %s: refresh %s (%d)\n", tmpdate, ctx->ritem->url,
+			ctx->ritem->refresh_id);
+	g_free(tmpdate);
+	rssyl_update_feed(ctx->ritem, FALSE);
+
+	return TRUE;
+}
+
+void rssyl_feed_start_refresh_timeout(RFolderItem *ritem)
+{
+	RRefreshCtx *ctx;
+	guint source_id;
+	RPrefs *rsprefs = NULL;
+
+	g_return_if_fail(ritem != NULL);
+
+	if( ritem->default_refresh_interval ) {
+		rsprefs = rssyl_prefs_get();
+		if( !rsprefs->refresh_enabled )
+			return;
+		ritem->refresh_interval = rsprefs->refresh;
+	}
+
+	ctx = g_new0(RRefreshCtx, 1);
+	ctx->ritem = ritem;
+
+	source_id = g_timeout_add(ritem->refresh_interval * 60 * 1000,
+			(GSourceFunc)rssyl_refresh_timeout_cb, ctx );
+	ritem->refresh_id = source_id;
+	ctx->id = source_id;
+
+	debug_print("RSSyl: start_refresh_timeout - %d min (id %d)\n",
+			ritem->refresh_interval, ctx->id);
+}
diff --git a/src/plugins/rssyl/rssyl_feed.h b/src/plugins/rssyl/rssyl_feed.h
new file mode 100644
index 0000000..e34fc10
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_feed.h
@@ -0,0 +1,27 @@
+#ifndef __RSSYL_FEED_H
+#define __RSSYL_FEED_H
+
+#include <glib.h>
+
+#include <folder.h>
+
+#include "rssyl.h"
+
+#define RSSYL_LOG_SUBSCRIBING  _("RSSyl: Subscribing new feed: %s\n")
+#define RSSYL_LOG_SUBSCRIBED   _("RSSyl: New feed subscribed: '%s' (%s)\n")
+#define RSSYL_LOG_UPDATING     _("RSSyl: Updating feed: %s\n")
+#define RSSYL_LOG_UPDATED      _("RSSyl: Feed update finished: %s\n")
+#define RSSYL_LOG_ERROR_FETCH  _("RSSyl: Error fetching feed at '%s': %s\n")
+#define RSSYL_LOG_ERROR_NOFEED _("RSSyl: No valid feed found at '%s'\n")
+#define RSSYL_LOG_ERROR_PROC   _("RSSyl: Couldn't process feed at '%s'\n")
+#define RSSYL_LOG_ABORTED_EXITING _("RSSyl: Application is exiting, couldn't finish updating feed at '%s'\n")
+
+FolderItem *rssyl_feed_subscribe_new(FolderItem *parent, const gchar *url,
+				gboolean verbose);
+
+MsgInfo *rssyl_feed_parse_item_to_msginfo(gchar *file, MsgFlags flags,
+		gboolean a, gboolean b, FolderItem *item);
+
+void rssyl_feed_start_refresh_timeout(RFolderItem *ritem);
+
+#endif /* __RSSYL_FEED_H */
diff --git a/src/plugins/rssyl/rssyl_feed_props.c b/src/plugins/rssyl/rssyl_feed_props.c
new file mode 100644
index 0000000..f6a2d89
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_feed_props.c
@@ -0,0 +1,566 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
+ *
+ * - Plugin preferences
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+
+/* Claws Mail includes */
+#include <mainwindow.h>
+
+/* Local includes */
+#include "rssyl.h"
+#include "rssyl_feed.h"
+#include "rssyl_feed_props.h"
+#include "rssyl_prefs.h"
+#include "rssyl_update_feed.h"
+
+static void rssyl_gtk_prop_store(RFolderItem *ritem)
+{
+	gchar *url;
+	gint x, old_ri, old_fetch_comments;
+	gboolean use_default_ri = FALSE, keep_old = FALSE;
+	FolderItem *item;
+
+	g_return_if_fail(ritem != NULL);
+	g_return_if_fail(ritem->feedprop != NULL);
+
+	url = (gchar *)gtk_entry_get_text(GTK_ENTRY(ritem->feedprop->url));
+
+	if( strlen(url) ) {
+		if( ritem->url ) {
+			g_free(ritem->url);
+		}
+		ritem->url = g_strdup(url);
+	}
+
+	use_default_ri = gtk_toggle_button_get_active(
+			GTK_TOGGLE_BUTTON(ritem->feedprop->default_refresh_interval));
+	ritem->default_refresh_interval = use_default_ri;
+	debug_print("store: default refresh interval is %s\n",
+			( use_default_ri ? "ON" : "OFF" ) );
+
+	/* Use default if checkbutton is set */
+	if( use_default_ri )
+		x = rssyl_prefs_get()->refresh;
+	else
+		x = gtk_spin_button_get_value_as_int(
+				GTK_SPIN_BUTTON(ritem->feedprop->refresh_interval) );
+
+	old_ri = ritem->refresh_interval;
+	ritem->refresh_interval = x;
+
+	/* Set timer for next automatic refresh, if needed. */
+	if( x > 0 ) {
+		if( old_ri != x || ritem->refresh_id == 0 ) {
+			debug_print("RSSyl: GTK - refresh interval changed to %d , updating "
+					"timeout\n", ritem->refresh_interval);
+			rssyl_feed_start_refresh_timeout(ritem);
+		}
+	} else
+		ritem->refresh_id = 0;
+
+	old_fetch_comments = ritem->fetch_comments;
+	ritem->fetch_comments = gtk_toggle_button_get_active(
+			GTK_TOGGLE_BUTTON(ritem->feedprop->fetch_comments));
+
+	if (!old_fetch_comments && ritem->fetch_comments) {
+		/* reset the RFolderItem's mtime to be sure we get all 
+		 * available comments */
+		 ritem->item.mtime = 0;
+	}
+	
+	ritem->fetch_comments_max_age = gtk_spin_button_get_value_as_int(
+			GTK_SPIN_BUTTON(ritem->feedprop->fetch_comments_max_age));
+
+	keep_old = gtk_toggle_button_get_active(
+			GTK_TOGGLE_BUTTON(ritem->feedprop->keep_old));
+	ritem->keep_old = keep_old;
+
+	ritem->silent_update =
+		gtk_combo_box_get_active(GTK_COMBO_BOX(ritem->feedprop->silent_update));
+
+	ritem->write_heading = gtk_toggle_button_get_active(
+			GTK_TOGGLE_BUTTON(ritem->feedprop->write_heading));
+
+	ritem->ignore_title_rename = gtk_toggle_button_get_active(
+			GTK_TOGGLE_BUTTON(ritem->feedprop->ignore_title_rename));
+
+	ritem->ssl_verify_peer = gtk_toggle_button_get_active(
+			GTK_TOGGLE_BUTTON(ritem->feedprop->ssl_verify_peer));
+
+	/* Store updated properties */
+	item = &ritem->item;
+	item->folder->klass->item_get_xml(item->folder, item);
+}
+
+static gboolean
+rssyl_feedprop_togglebutton_toggled_cb(GtkToggleButton *tb,
+		gpointer data)
+{
+	gboolean active = gtk_toggle_button_get_active(tb);
+	RFeedProp *feedprop = (RFeedProp *)data;
+	GtkWidget *sb = NULL;
+
+	if( (GtkWidget *)tb == feedprop->default_refresh_interval ) {
+		active = !active;
+		sb = feedprop->refresh_interval;
+	} else if( (GtkWidget *)tb == feedprop->fetch_comments ) {
+		sb = feedprop->fetch_comments_max_age;
+	}
+
+	g_return_val_if_fail(sb != NULL, FALSE);
+
+	gtk_widget_set_sensitive(sb, active);
+
+	return FALSE;
+}
+
+
+static gboolean
+rssyl_props_cancel_cb(GtkWidget *widget, gpointer data)
+{
+	RFolderItem *ritem = (RFolderItem *)data;
+
+	debug_print("RSSyl: Cancel pressed\n");
+
+	gtk_widget_destroy(ritem->feedprop->window);
+
+	return FALSE;
+}
+
+static gboolean
+rssyl_props_ok_cb(GtkWidget *widget, gpointer data)
+{
+	RFolderItem *ritem = (RFolderItem *)data;
+
+	debug_print("RSSyl: OK pressed\n");
+	rssyl_gtk_prop_store(ritem);
+
+	gtk_widget_destroy(ritem->feedprop->window);
+
+	return FALSE;
+}
+
+static gboolean
+rssyl_props_trim_cb(GtkWidget *widget, gpointer data)
+{
+	RFolderItem *ritem = (RFolderItem *)data;
+	gboolean k = ritem->keep_old;
+
+	if( k )
+		ritem->keep_old = FALSE;
+
+	rssyl_update_feed(ritem, FALSE);
+
+	if( k )
+		ritem->keep_old = TRUE;
+
+	return FALSE;
+}
+
+static gboolean
+rssyl_props_key_press_cb(GtkWidget *widget, GdkEventKey *event,
+		gpointer data)
+{
+	if (event) {
+		switch (event->keyval) {
+			case GDK_Escape:
+				rssyl_props_cancel_cb(widget, data);
+				return TRUE;
+			case GDK_Return:
+			case GDK_KP_Enter:
+				rssyl_props_ok_cb(widget, data);
+				return TRUE;
+			default:
+				break;
+		}
+	}
+
+	return FALSE;
+}
+
+
+void rssyl_gtk_prop(RFolderItem *ritem)
+{
+	MainWindow *mainwin = mainwindow_get_mainwindow();
+	RFeedProp *feedprop;
+	GtkWidget *vbox, *urllabel, *urlframe, *urlalign, *table, *label,
+						*hsep, *sep, *bbox, *cancel_button, *cancel_align,
+						*cancel_hbox, *cancel_image, *cancel_label, *ok_button, *ok_align,
+						*ok_hbox, *ok_image, *ok_label, *trim_button, *silent_update_label;
+	GtkObject *adj;
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+	GtkTooltips *tooltips;
+#endif
+	gint refresh;
+	gint row = 0;
+
+	g_return_if_fail(ritem != NULL);
+
+	feedprop = g_new0(RFeedProp, 1);
+
+	/**** Create required widgets ****/
+
+	/* Window */
+	feedprop->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+	tooltips = gtk_tooltips_new();
+	gtk_tooltips_enable(tooltips);
+#endif
+
+	/* URL entry */
+	feedprop->url = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(feedprop->url), ritem->url);
+
+	/* "Use default refresh interval" checkbutton */
+	feedprop->default_refresh_interval = gtk_check_button_new_with_mnemonic(
+			_("Use default refresh interval"));
+	gtk_toggle_button_set_active(
+			GTK_TOGGLE_BUTTON(feedprop->default_refresh_interval),
+			ritem->default_refresh_interval);
+
+	if( ritem->refresh_interval >= 0 && !ritem->default_refresh_interval )
+		refresh = ritem->refresh_interval;
+	else
+		refresh = rssyl_prefs_get()->refresh;
+
+	/* "Keep old items" checkbutton */
+	feedprop->keep_old = gtk_check_button_new_with_mnemonic(
+			_("Keep old items"));
+	gtk_toggle_button_set_active(
+			GTK_TOGGLE_BUTTON(feedprop->keep_old),
+			ritem->keep_old);
+
+	/* "Trim" button */
+	trim_button = gtk_button_new_with_mnemonic(_("_Trim"));
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+	gtk_tooltips_set_tip(tooltips, trim_button,
+			_("Update feed, deleting items which are no longer in the source feed"), NULL);
+#else
+	gtk_widget_set_tooltip_text(trim_button,
+			_("Update feed, deleting items which are no longer in the source feed"));
+#endif
+
+	feedprop->fetch_comments = gtk_check_button_new_with_mnemonic(
+			_("Fetch comments if possible"));
+	gtk_toggle_button_set_active(
+			GTK_TOGGLE_BUTTON(feedprop->fetch_comments),
+			ritem->fetch_comments);
+
+	/* Fetch comments max age spinbutton */
+	adj = gtk_adjustment_new(ritem->fetch_comments_max_age,
+			-1, 100000, 1, 10, 0);
+	feedprop->fetch_comments_max_age = gtk_spin_button_new(GTK_ADJUSTMENT(adj),
+			1, 0);
+
+	/* Refresh interval spinbutton */
+	adj = gtk_adjustment_new(refresh,
+			0, 100000, 10, 100, 0);
+	feedprop->refresh_interval = gtk_spin_button_new(GTK_ADJUSTMENT(adj),
+			1, 0);
+
+	/* Silent update - combobox */
+	feedprop->silent_update = gtk_combo_box_new_text();
+	gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
+			_("Always mark as new"));
+	gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
+			_("If only its text changed"));
+	gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
+			_("Never mark as new"));
+	gtk_combo_box_set_active(GTK_COMBO_BOX(feedprop->silent_update),
+			ritem->silent_update);
+
+	feedprop->write_heading = gtk_check_button_new_with_mnemonic(
+			_("Add item title to top of message"));
+	gtk_toggle_button_set_active(
+			GTK_TOGGLE_BUTTON(feedprop->write_heading),
+			ritem->write_heading);
+
+	/* Ignore title rename - checkbox */
+	feedprop->ignore_title_rename = gtk_check_button_new_with_mnemonic(
+			_("Ignore title rename"));
+	gtk_toggle_button_set_active(
+			GTK_TOGGLE_BUTTON(feedprop->ignore_title_rename),
+			ritem->ignore_title_rename);
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+	gtk_tooltips_set_tip(tooltips, feedprop->ignore_title_rename,
+			_("Enable this to keep current folder name, even if feed author changes title of the feed."), NULL);
+#else
+	gtk_widget_set_tooltip_text(feedprop->ignore_title_rename,
+			_("Enable this to keep current folder name, even if feed author changes title of the feed."));
+#endif
+
+	/* Verify SSL peer certificate */
+	feedprop->ssl_verify_peer = gtk_check_button_new_with_label(
+			_("Verify SSL certificate validity"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(feedprop->ssl_verify_peer),
+			ritem->ssl_verify_peer);
+
+	/* === Now pack all the widgets */
+	vbox = gtk_vbox_new(FALSE, 0);
+	gtk_container_add(GTK_CONTAINER(feedprop->window), vbox);
+
+	/* URL frame */
+	urlframe = gtk_frame_new(NULL);
+	gtk_container_set_border_width(GTK_CONTAINER(urlframe), 5);
+	gtk_frame_set_label_align(GTK_FRAME(urlframe), 0.05, 0.5);
+	gtk_frame_set_shadow_type(GTK_FRAME(urlframe), GTK_SHADOW_ETCHED_OUT);
+	gtk_box_pack_start(GTK_BOX(vbox), urlframe, FALSE, FALSE, 0);
+
+	/* Label for URL frame */
+	urllabel = gtk_label_new(_("<b>Source URL:</b>"));
+	gtk_label_set_use_markup(GTK_LABEL(urllabel), TRUE);
+	gtk_misc_set_padding(GTK_MISC(urllabel), 5, 0);
+	gtk_frame_set_label_widget(GTK_FRAME(urlframe), urllabel);
+
+	/* URL entry (+ alignment in frame) */
+	urlalign = gtk_alignment_new(0, 0.5, 1, 1);
+	gtk_alignment_set_padding(GTK_ALIGNMENT(urlalign), 5, 5, 5, 5);
+	gtk_container_add(GTK_CONTAINER(urlframe), urlalign);
+
+	gtk_entry_set_activates_default(GTK_ENTRY(feedprop->url), TRUE);
+	gtk_container_add(GTK_CONTAINER(urlalign), feedprop->url);
+
+	/* Table for remaining properties */
+	table = gtk_table_new(11, 2, FALSE);
+	gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
+
+	/* Fetch comments - checkbutton */
+	gtk_table_attach(GTK_TABLE(table), feedprop->fetch_comments,
+			0, 2, row, row+1,
+			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			(GtkAttachOptions) (0), 10, 0);
+	g_signal_connect(G_OBJECT(feedprop->fetch_comments), "toggled",
+			G_CALLBACK(rssyl_feedprop_togglebutton_toggled_cb),
+			(gpointer)feedprop);
+
+	row++;
+	/* Fetch comments max age - label */
+	label = gtk_label_new(_("<b>Fetch comments on posts aged less than:</b>\n"
+				"<small>(In days; set to -1 to fetch all comments)</small>"));
+	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+	gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1,
+			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			(GtkAttachOptions) (0), 10, 5);
+
+	/* Fetch comments max age - spinbutton */
+	gtk_widget_set_sensitive(feedprop->fetch_comments_max_age,
+			ritem->fetch_comments);
+	gtk_table_attach(GTK_TABLE(table), feedprop->fetch_comments_max_age,
+			1, 2, row, row+1,
+			(GtkAttachOptions) (0),
+			(GtkAttachOptions) (0), 10, 5);
+
+	row++;
+	/* Separator below comments max age */
+	hsep = gtk_hseparator_new();
+	gtk_widget_set_size_request(hsep, -1, 10);
+	gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
+			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			(GtkAttachOptions) (0), 10, 5);
+
+	row++;
+	/* Keep old items - checkbutton */
+	gtk_table_attach(GTK_TABLE(table), feedprop->keep_old,
+			0, 1, row, row+1,
+			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			(GtkAttachOptions) (0), 10, 0);
+
+	/* 'Trim' - button */
+	gtk_table_attach(GTK_TABLE(table), trim_button,
+			1, 2, row, row+1,
+			(GtkAttachOptions) (0),
+			(GtkAttachOptions) (0), 10, 0);
+	g_signal_connect(G_OBJECT(trim_button), "clicked",
+			G_CALLBACK(rssyl_props_trim_cb), ritem);
+
+	row++;
+	hsep = gtk_hseparator_new();
+	gtk_widget_set_size_request(hsep, -1, 10);
+	gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
+			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			(GtkAttachOptions) (0), 10, 5);
+
+	row++;
+	/* Use default refresh interval - checkbutton */
+	gtk_table_attach(GTK_TABLE(table), feedprop->default_refresh_interval,
+			0, 2, row, row+1,
+			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			(GtkAttachOptions) (0), 10, 0);
+	g_signal_connect(G_OBJECT(feedprop->default_refresh_interval), "toggled",
+			G_CALLBACK(rssyl_feedprop_togglebutton_toggled_cb),
+			(gpointer)feedprop);
+
+	row++;
+	/* Refresh interval - label */
+	label = gtk_label_new(_("<b>Refresh interval in minutes:</b>\n"
+			"<small>(Set to 0 to disable automatic refreshing for this feed)"
+			"</small>"));
+	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+	gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1,
+			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			(GtkAttachOptions) (0), 10, 5);
+
+	/* Refresh interval - spinbutton */
+	gtk_widget_set_sensitive(feedprop->refresh_interval,
+			!ritem->default_refresh_interval);
+	gtk_table_attach(GTK_TABLE(table), feedprop->refresh_interval, 1, 2, row, row+1,
+			(GtkAttachOptions) (0),
+			(GtkAttachOptions) (0), 10, 5);
+
+	row++;
+	hsep = gtk_hseparator_new();
+	gtk_widget_set_size_request(hsep, -1, 10);
+	gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
+			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			(GtkAttachOptions) (0), 10, 5);
+
+	row++;
+	/* Silent update - label */
+	silent_update_label =
+		gtk_label_new(_("<b>If an item changes, do not mark it as new:</b>"));
+	gtk_label_set_use_markup(GTK_LABEL(silent_update_label), TRUE);
+	gtk_misc_set_alignment(GTK_MISC(silent_update_label), 0, 0.5);
+	gtk_table_attach(GTK_TABLE(table), silent_update_label, 0, 1, row, row+1,
+			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			(GtkAttachOptions) (0), 10, 5);
+
+	gtk_table_attach(GTK_TABLE(table), feedprop->silent_update, 1, 2, row, row+1,
+			(GtkAttachOptions) (0),
+			(GtkAttachOptions) (0), 10, 5);
+
+	row++;
+	hsep = gtk_hseparator_new();
+	gtk_widget_set_size_request(hsep, -1, 10);
+	gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
+			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			(GtkAttachOptions) (0), 10, 5);
+
+	row++;
+
+	/* Write heading - checkbox */
+	gtk_table_attach(GTK_TABLE(table), feedprop->write_heading,
+			0, 2, row, row+1,
+			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			(GtkAttachOptions) (0), 10, 0);
+
+
+	row++;
+
+	/* Ignore title rename - checkbutton */
+	gtk_table_attach(GTK_TABLE(table), feedprop->ignore_title_rename,
+			0, 1, row, row+1,
+			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			(GtkAttachOptions) (0), 10, 0);
+
+	row++;
+
+	/* Verify SSL peer certificate - checkbutton */
+	gtk_table_attach(GTK_TABLE(table), feedprop->ssl_verify_peer,
+			0, 1, row, row+1,
+			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			(GtkAttachOptions) (0), 10, 0);
+
+	row++;
+
+	/* Separator above the button box */
+	sep = gtk_hseparator_new();
+	gtk_widget_set_size_request(sep, -1, 10);
+	gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
+
+	/* Buttonbox */
+	bbox = gtk_hbutton_box_new();
+	gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
+	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+	gtk_box_set_spacing(GTK_BOX(bbox), 5);
+	gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
+
+	/* Cancel button */
+	cancel_button = gtk_button_new();
+	gtk_container_add(GTK_CONTAINER(bbox), cancel_button);
+
+	cancel_align = gtk_alignment_new(0.5, 0.5, 0, 0);
+	gtk_container_add(GTK_CONTAINER(cancel_button), cancel_align);
+
+	cancel_hbox = gtk_hbox_new(FALSE, 2);
+	gtk_container_add(GTK_CONTAINER(cancel_align), cancel_hbox);
+
+	cancel_image = gtk_image_new_from_stock(GTK_STOCK_CANCEL,
+			GTK_ICON_SIZE_BUTTON);
+	gtk_box_pack_start(GTK_BOX(cancel_hbox), cancel_image, FALSE, FALSE, 0);
+
+	cancel_label = gtk_label_new_with_mnemonic(_("_Cancel"));
+	gtk_box_pack_end(GTK_BOX(cancel_hbox), cancel_label, FALSE, FALSE, 0);
+
+	g_signal_connect(G_OBJECT(cancel_button), "clicked",
+			G_CALLBACK(rssyl_props_cancel_cb), ritem);
+
+	/* OK button */
+	ok_button = gtk_button_new();
+	gtk_container_add(GTK_CONTAINER(bbox), ok_button);
+	GTK_WIDGET_SET_FLAGS(ok_button, GTK_CAN_DEFAULT );
+
+	ok_align = gtk_alignment_new(0.5, 0.5, 0, 0);
+	gtk_container_add(GTK_CONTAINER(ok_button), ok_align);
+
+	ok_hbox = gtk_hbox_new(FALSE, 2);
+	gtk_container_add(GTK_CONTAINER(ok_align), ok_hbox);
+
+	ok_image = gtk_image_new_from_stock(GTK_STOCK_OK,
+			GTK_ICON_SIZE_BUTTON);
+	gtk_box_pack_start(GTK_BOX(ok_hbox), ok_image, FALSE, FALSE, 0);
+
+	ok_label = gtk_label_new_with_mnemonic(_("_OK"));
+	gtk_box_pack_end(GTK_BOX(ok_hbox), ok_label, FALSE, FALSE, 0);
+
+	g_signal_connect(G_OBJECT(ok_button), "clicked",
+			G_CALLBACK(rssyl_props_ok_cb), ritem);
+
+	/* Set some misc. stuff */
+	gtk_window_set_title(GTK_WINDOW(feedprop->window),
+			g_strdup(_("Set feed properties")) );
+	gtk_window_set_modal(GTK_WINDOW(feedprop->window), TRUE);
+	gtk_window_set_transient_for(GTK_WINDOW(feedprop->window),
+			GTK_WINDOW(mainwin->window) );
+
+	/* Attach callbacks to handle Enter and Escape keys */
+	g_signal_connect(G_OBJECT(feedprop->window), "key_press_event",
+			G_CALLBACK(rssyl_props_key_press_cb), ritem);
+
+	/* ...and voila! */
+	gtk_widget_show_all(feedprop->window);
+	gtk_widget_grab_default(ok_button);
+
+	/* Unselect the text in URL entry */
+	gtk_editable_select_region(GTK_EDITABLE(feedprop->url), 0, 0);
+
+	ritem->feedprop = feedprop;
+}
diff --git a/src/plugins/rssyl/rssyl_feed_props.h b/src/plugins/rssyl/rssyl_feed_props.h
new file mode 100644
index 0000000..5aa4539
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_feed_props.h
@@ -0,0 +1,24 @@
+#ifndef __RSSYL_FEED_PROPS
+#define __RSSYL_FEED_PROPS
+
+#include "rssyl.h"
+
+void rssyl_gtk_prop(RFolderItem *ritem);
+
+struct _RFeedProp {
+	GtkWidget *window;
+	GtkWidget *url;
+	GtkWidget *default_refresh_interval;
+	GtkWidget *refresh_interval;
+	GtkWidget *keep_old;
+	GtkWidget *fetch_comments;
+	GtkWidget *fetch_comments_max_age;
+	GtkWidget *silent_update;
+	GtkWidget *write_heading;
+	GtkWidget *ignore_title_rename;
+	GtkWidget *ssl_verify_peer;
+};
+
+typedef struct _RFeedProp RFeedProp;
+
+#endif /* __RSSYL_FEED_PROPS */
diff --git a/src/plugins/rssyl/rssyl_gtk.c b/src/plugins/rssyl/rssyl_gtk.c
index 24c2abe..dc6e72a 100644
--- a/src/plugins/rssyl/rssyl_gtk.c
+++ b/src/plugins/rssyl/rssyl_gtk.c
@@ -1,5 +1,5 @@
 /*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
  * Copyright (C) 1999-2004 Hiroyuki Yamamoto
  * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
  *
@@ -22,101 +22,85 @@
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
-#include "claws-features.h"
 #endif
 
-#include <glib.h>
-#include <glib/gi18n.h>
-
+/* Global includes */
 #include <gtk/gtk.h>
+#include <glib/gi18n.h>
 
-#include "gtk/menu.h"
-#include "mainwindow.h"
-#include "inputdialog.h"
-#include "folderview.h"
-#include "alertpanel.h"
-#include "summaryview.h"
-
-#include "main.h"
-#include "gtkutils.h"
+/* Claws Mail includes */
+#include <gtk/menu.h>
+#include <mainwindow.h>
+#include <inputdialog.h>
+#include <folderview.h>
+#include <alertpanel.h>
+#include <main.h>
+#include <summaryview.h>
 
-#include "feed.h"
-#include "feedprops.h"
+/* Local includes */
 #include "rssyl.h"
-#include "rssyl_cb_gtk.h"
-#include "rssyl_cb_menu.h"
-#include "rssyl_gtk.h"
 #include "rssyl_prefs.h"
+#include "rssyl_gtk.h"
+#include "rssyl_cb_menu.h"
 
 static char *rssyl_popup_menu_labels[] =
 {
 	N_("_Refresh feed"),
-	N_("Refresh _all feeds"),
+	N_("Feed pr_operties"),
+	N_("Rena_me..."),
+	N_("R_efresh recursively"),
 	N_("Subscribe _new feed..."),
-	N_("_Unsubscribe feed..."),
-	N_("Feed pr_operties..."),
+	N_("Create new _folder..."),
 	N_("Import feed list..."),
-	N_("Rena_me..."),
-	N_("_Create new folder..."),
 	N_("_Delete folder..."),
-	N_("Remove folder _tree..."),
+	N_("Remove tree"),
 	NULL
 };
 
 static GtkActionEntry rssyl_popup_entries[] = 
 {
-	{"FolderViewPopup/RefreshFeed",		NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_refresh_cb) },
-	{"FolderViewPopup/RefreshAllFeeds",	NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_refresh_all_cb) },
-
-	{"FolderViewPopup/NewFeed",		NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_new_feed_cb) },
-	{"FolderViewPopup/RemoveFeed",		NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_remove_feed_cb) },
-	{"FolderViewPopup/FeedProperties",	NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_prop_cb) },
-	{"FolderViewPopup/ImportFeedlist",	NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_import_feed_list_cb) },
-
-	{"FolderViewPopup/RenameFolder",	NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_rename_cb) },
-
-	{"FolderViewPopup/NewFolder",		NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_new_folder_cb) },
-	{"FolderViewPopup/RemoveFolder",	NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_remove_folder_cb) },
-
-	{"FolderViewPopup/RemoveMailbox",	NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_remove_rss_cb) },
-
+	{"FolderViewPopup/RefreshFeed", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_refresh_feed_cb) },
+	{"FolderViewPopup/FeedProperties", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_prop_cb) },
+	{"FolderViewPopup/RenameFolder", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_rename_cb) },
+	{"FolderViewPopup/RefreshAllFeeds", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_update_all_cb) },
+	{"FolderViewPopup/NewFeed", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_new_feed_cb) },
+	{"FolderViewPopup/NewFolder", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_new_folder_cb) },
+	{"FolderViewPopup/ImportFeedList", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_import_feed_list_cb) },
+	{"FolderViewPopup/RemoveFolder", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_remove_folder_cb) },
+	{"FolderViewPopup/RemoveMailbox", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_remove_mailbox_cb) }
 };
 
 static void rssyl_add_menuitems(GtkUIManager *ui_manager, FolderItem *item)
 {
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RefreshFeed", "FolderViewPopup/RefreshFeed", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RefreshAllFeeds", "FolderViewPopup/RefreshAllFeeds", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "NewFeed", "FolderViewPopup/NewFeed", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RemoveFeed", "FolderViewPopup/RemoveFeed", GTK_UI_MANAGER_MENUITEM)
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "FeedProperties", "FolderViewPopup/FeedProperties", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "ImportFeedlist", "FolderViewPopup/ImportFeedlist", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS2", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RenameFolder", "FolderViewPopup/RenameFolder", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS3", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RefreshAllFeeds", "FolderViewPopup/RefreshAllFeeds", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS2", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "NewFeed", "FolderViewPopup/NewFeed", GTK_UI_MANAGER_MENUITEM)
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "NewFolder", "FolderViewPopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "ImportFeedList", "FolderViewPopup/ImportFeedList", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS3", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RemoveFolder", "FolderViewPopup/RemoveFolder", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS4", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS4", "FolderView/Popup/---", GTK_UI_MANAGER_SEPARATOR)
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RemoveMailbox", "FolderViewPopup/RemoveMailbox", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS5", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS5", "FolderView/Popup/---", GTK_UI_MANAGER_SEPARATOR)
 }
 
 static void rssyl_set_sensitivity(GtkUIManager *ui_manager, FolderItem *item)
 {
 #define SET_SENS(name, sens) \
 	cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens)
-
-	RSSylFolderItem *ritem = (RSSylFolderItem *)item;
-	SET_SENS("FolderViewPopup/RefreshFeed", folder_item_parent(item) != NULL && ritem->url);
-	SET_SENS("FolderViewPopup/RefreshAllFeeds", folder_item_parent(item) == NULL );
-	SET_SENS("FolderViewPopup/NewFeed", TRUE);
-	SET_SENS("FolderViewPopup/ImportFeedlist", TRUE );
-	SET_SENS("FolderViewPopup/RemoveFeed", folder_item_parent(item) != NULL && ritem->url );
+	RFolderItem *ritem = (RFolderItem *)item;
+	SET_SENS("FolderViewPopup/RefreshFeed", folder_item_parent(item) != NULL && ritem->url );
 	SET_SENS("FolderViewPopup/FeedProperties", folder_item_parent(item) != NULL && ritem->url );
 	SET_SENS("FolderViewPopup/RenameFolder", folder_item_parent(item) != NULL );
+	SET_SENS("FolderViewPopup/RefreshAllFeeds", TRUE );
+	SET_SENS("FolderViewPopup/NewFeed", TRUE);
 	SET_SENS("FolderViewPopup/NewFolder", TRUE );
-	SET_SENS("FolderViewPopup/RemoveFolder", folder_item_parent(item) != NULL && !ritem->url );
-	SET_SENS("FolderViewPopup/RemoveMailbox", folder_item_parent(item) == NULL );
+	SET_SENS("FolderViewPopup/RemoveFolder", folder_item_parent(item) != NULL);
+	SET_SENS("FolderViewPopup/RemoveMailbox", folder_item_parent(item) == NULL);
 
 #undef SET_SENS
 }
@@ -133,20 +117,10 @@ static FolderViewPopup rssyl_popup =
 	rssyl_set_sensitivity
 };
 
-static void rssyl_fill_popup_menu_labels(void)
-{
-	gint i;
-
-	for( i = 0; rssyl_popup_menu_labels[i] != NULL; i++ ) {
-		(rssyl_popup_entries[i]).label = _(rssyl_popup_menu_labels[i]);
-	}
-}
-
 static void rssyl_add_mailbox(GtkAction *action, gpointer callback_data)
 {
 	MainWindow *mainwin = (MainWindow *) callback_data;
-	gchar *path;
-	gchar *base = NULL;
+	gchar *path = NULL, *tmp = NULL;
 	Folder *folder;
 
 	path = input_dialog(_("Add RSS folder tree"),
@@ -160,10 +134,10 @@ static void rssyl_add_mailbox(GtkAction *action, gpointer callback_data)
 		return;
 	}
 
-	base = g_path_get_basename(path);
-	folder = folder_new(folder_get_class_from_string("rssyl"),
-			base, path);
-	g_free(base);
+	tmp = g_path_get_basename(path);
+	folder = folder_new(folder_get_class_from_string("rssyl"), tmp, path);
+	g_free(tmp);
+	g_free(path);
 
 	if( folder->klass->create_tree(folder) < 0 ) {
 		alertpanel_error(_("Creation of folder tree failed.\n"
@@ -179,24 +153,30 @@ static void rssyl_add_mailbox(GtkAction *action, gpointer callback_data)
 	folderview_set(mainwin->folderview);
 }
 
+
 static GtkActionEntry mainwindow_add_mailbox[] = {{
 	"File/AddMailbox/RSSyl",
-	NULL, N_("RSSyl..."), NULL, NULL, G_CALLBACK(rssyl_add_mailbox)
+	NULL, "RSSyl...", NULL, NULL, G_CALLBACK(rssyl_add_mailbox)
 }};
 
+static void rssyl_fill_popup_menu_labels(void) {
+	gint i;
+
+	for (i = 0; rssyl_popup_menu_labels[i] != NULL; i++) { 
+		(rssyl_popup_entries[i].label = _(rssyl_popup_menu_labels[i]));
+	}
+}
+
 static guint main_menu_id = 0;
 
 void rssyl_gtk_init(void)
 {
 	MainWindow *mainwin = mainwindow_get_mainwindow();
-
 	gtk_action_group_add_actions(mainwin->action_group, mainwindow_add_mailbox,
 			1, (gpointer)mainwin);
 	MENUITEM_ADDUI_ID_MANAGER(mainwin->ui_manager, "/Menu/File/AddMailbox", "RSSyl", 
 			  "File/AddMailbox/RSSyl", GTK_UI_MANAGER_MENUITEM,
-			  main_menu_id)
-
-
+			  main_menu_id);
 	rssyl_fill_popup_menu_labels();
 	folderview_register_popup(&rssyl_popup);
 }
@@ -222,482 +202,5 @@ void rssyl_gtk_done(void)
 
 	MENUITEM_REMUI_MANAGER(mainwin->ui_manager,mainwin->action_group, "File/AddMailbox/RSSyl", main_menu_id);
 	main_menu_id = 0;
-}
-
-/***********************************************/
-
-static RSSylFeedProp *rssyl_gtk_prop_real(RSSylFolderItem *ritem)
-{
-	MainWindow *mainwin = mainwindow_get_mainwindow();
-	RSSylFeedProp *feedprop;
-	GtkWidget *vbox, *urllabel, *urlframe, *urlalign, *table, *refresh_label,
-						*expired_label, *hsep, *sep, *bbox, *cancel_button, *cancel_align,
-						*cancel_hbox, *cancel_image, *cancel_label, *ok_button, *ok_align,
-						*ok_hbox, *ok_image, *ok_label, *silent_update_label;
-
-	GtkObject *refresh_adj, *expired_adj, *fetch_comments_for_adj;
-	gint refresh;
-	gint row = 0;
-
-	g_return_val_if_fail(ritem != NULL, NULL);
-
-	feedprop = g_new0(RSSylFeedProp, 1);
-
-	/* Create required widgets */
-
-	/* Window */
-	feedprop->window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "rssyl_gtk");
-
-	/* URL entry */
-	feedprop->url = gtk_entry_new();
-	gtk_entry_set_text(GTK_ENTRY(feedprop->url), ritem->url);
-
-	/* "Use default refresh interval" checkbutton */
-	feedprop->default_refresh_interval = gtk_check_button_new_with_mnemonic(
-			_("Use default refresh interval"));
-	gtk_toggle_button_set_active(
-			GTK_TOGGLE_BUTTON(feedprop->default_refresh_interval),
-			ritem->default_refresh_interval);
-
-	if( ritem->refresh_interval >= 0 && !ritem->default_refresh_interval )
-		refresh = ritem->refresh_interval;
-	else
-		refresh = rssyl_prefs_get()->refresh;
-
-	/* "Keep default number of expired items" checkbutton */
-	feedprop->default_expired_num = gtk_check_button_new_with_mnemonic(
-			_("Keep default number of expired entries"));
-	gtk_toggle_button_set_active(
-			GTK_TOGGLE_BUTTON(feedprop->default_expired_num),
-			ritem->default_expired_num);
-
-	feedprop->fetch_comments = gtk_check_button_new_with_mnemonic(
-			_("Fetch comments if possible"));
-	gtk_toggle_button_set_active(
-			GTK_TOGGLE_BUTTON(feedprop->fetch_comments),
-			ritem->fetch_comments);
-
-	/* Refresh interval spinbutton */
-	fetch_comments_for_adj = gtk_adjustment_new(ritem->fetch_comments_for,
-			-1, 100000, 1, 10, 0);
-	feedprop->fetch_comments_for = gtk_spin_button_new(GTK_ADJUSTMENT(fetch_comments_for_adj),
-			1, 0);
-
-	/* Refresh interval spinbutton */
-	refresh_adj = gtk_adjustment_new(refresh,
-			0, 100000, 1, 10, 0);
-	feedprop->refresh_interval = gtk_spin_button_new(GTK_ADJUSTMENT(refresh_adj),
-			1, 0);
-
-	/* Expired num spinbutton */
-	expired_adj = gtk_adjustment_new(ritem->expired_num, -1, 100000, 1, 10, 0);
-	feedprop->expired_num = gtk_spin_button_new(GTK_ADJUSTMENT(expired_adj),
-			1, 0);
-
-	vbox = gtk_vbox_new(FALSE, 0);
-	gtk_container_add(GTK_CONTAINER(feedprop->window), vbox);
-
-	/* URL frame */
-	urlframe = gtk_frame_new(NULL);
-	gtk_container_set_border_width(GTK_CONTAINER(urlframe), 5);
-	gtk_frame_set_label_align(GTK_FRAME(urlframe), 0.05, 0.5);
-	gtk_frame_set_shadow_type(GTK_FRAME(urlframe), GTK_SHADOW_ETCHED_OUT);
-	gtk_box_pack_start(GTK_BOX(vbox), urlframe, FALSE, FALSE, 0);
-
-	/* Label for URL frame */
-	urllabel = gtk_label_new(_("<b>Source URL:</b>"));
-	gtk_label_set_use_markup(GTK_LABEL(urllabel), TRUE);
-	gtk_misc_set_padding(GTK_MISC(urllabel), 5, 0);
-	gtk_frame_set_label_widget(GTK_FRAME(urlframe), urllabel);
-
-	/* URL entry (+ alignment in frame) */
-	urlalign = gtk_alignment_new(0, 0.5, 1, 1);
-	gtk_alignment_set_padding(GTK_ALIGNMENT(urlalign), 5, 5, 5, 5);
-	gtk_container_add(GTK_CONTAINER(urlframe), urlalign);
-
-	gtk_entry_set_activates_default(GTK_ENTRY(feedprop->url), TRUE);
-	gtk_container_add(GTK_CONTAINER(urlalign), feedprop->url);
-
-	/* Table for remaining properties */
-	table = gtk_table_new(8, 2, FALSE);
-	gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
-
-	/* Fetch comments - checkbutton */
-	gtk_table_attach(GTK_TABLE(table), feedprop->fetch_comments,
-			0, 2, row, row+1,
-			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-			(GtkAttachOptions) (0), 10, 0);
-	g_signal_connect(G_OBJECT(feedprop->fetch_comments), "toggled",
-			G_CALLBACK(rssyl_fetch_comments_toggled_cb),
-			(gpointer)feedprop->fetch_comments_for);
-	row++;
-
-	/* Fetch comments for - label */
-	refresh_label = gtk_label_new(_("<b>Fetch comments on posts aged less than:</b>\n"
-			"<small>(In days; set to -1 to fetch all comments)"
-			"</small>"));
-	gtk_label_set_use_markup(GTK_LABEL(refresh_label), TRUE);
-	gtk_misc_set_alignment(GTK_MISC(refresh_label), 0, 0.5);
-	gtk_table_attach(GTK_TABLE(table), refresh_label, 0, 1, row, row+1,
-			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-			(GtkAttachOptions) (0), 10, 5);
-
-	/* Fetch comments for - spinbutton */
-	gtk_widget_set_sensitive(feedprop->fetch_comments_for,
-			ritem->fetch_comments);
-	gtk_table_attach(GTK_TABLE(table), feedprop->fetch_comments_for, 1, 2, row, row+1,
-			(GtkAttachOptions) (0),
-			(GtkAttachOptions) (0), 10, 5);
-
-	row++;
-	hsep = gtk_hseparator_new();
-	gtk_widget_set_size_request(hsep, -1, 10);
-	gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
-			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-			(GtkAttachOptions) (0), 10, 5);
-
-	row++;
-	/* Use default refresh interval - checkbutton */
-	gtk_table_attach(GTK_TABLE(table), feedprop->default_refresh_interval,
-			0, 2, row, row+1,
-			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-			(GtkAttachOptions) (0), 10, 0);
-	g_signal_connect(G_OBJECT(feedprop->default_refresh_interval), "toggled",
-			G_CALLBACK(rssyl_default_refresh_interval_toggled_cb),
-			(gpointer)feedprop->refresh_interval);
-	row++;
-	/* Refresh interval - label */
-	refresh_label = gtk_label_new(_("<b>Refresh interval in minutes:</b>\n"
-			"<small>(Set to 0 to disable automatic refreshing for this feed)"
-			"</small>"));
-	gtk_label_set_use_markup(GTK_LABEL(refresh_label), TRUE);
-	gtk_misc_set_alignment(GTK_MISC(refresh_label), 0, 0.5);
-	gtk_table_attach(GTK_TABLE(table), refresh_label, 0, 1, row, row+1,
-			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-			(GtkAttachOptions) (0), 10, 5);
-
-	/* Refresh interval - spinbutton */
-	gtk_widget_set_sensitive(feedprop->refresh_interval,
-			!ritem->default_refresh_interval);
-	gtk_table_attach(GTK_TABLE(table), feedprop->refresh_interval, 1, 2, row, row+1,
-			(GtkAttachOptions) (0),
-			(GtkAttachOptions) (0), 10, 5);
-	row++;
-	hsep = gtk_hseparator_new();
-	gtk_widget_set_size_request(hsep, -1, 10);
-	gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
-			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-			(GtkAttachOptions) (0), 10, 5);
-
-	row++;
-	/* Use default number for expired - checkbutton */
-	gtk_table_attach(GTK_TABLE(table), feedprop->default_expired_num,	0, 2, row, row+1,
-			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-			(GtkAttachOptions) (0), 10, 0);
-	g_signal_connect(G_OBJECT(feedprop->default_expired_num), "toggled",
-			G_CALLBACK(rssyl_default_expired_num_toggled_cb),
-			(gpointer)feedprop->expired_num);
-
-	row++;
-	/* Expired items - label */
-	expired_label = gtk_label_new(_("<b>Number of expired entries to keep:"
-			"</b>\n<small>(Set to -1 if you want to keep expired entries)"
-			"</small>"));
-	gtk_label_set_use_markup(GTK_LABEL(expired_label), TRUE);
-	gtk_misc_set_alignment(GTK_MISC(expired_label), 0, 0.5);
-	gtk_table_attach(GTK_TABLE(table), expired_label, 0, 1, row, row+1,
-			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-			(GtkAttachOptions) (0), 10, 5);
-
-	/* Expired items - spinbutton */
-	gtk_widget_set_sensitive(feedprop->expired_num,
-			!ritem->default_expired_num);
-	gtk_table_attach(GTK_TABLE(table), feedprop->expired_num, 1, 2, row, row+1,
-			(GtkAttachOptions) (0),
-			(GtkAttachOptions) (0), 10, 5);
-
-	row++;
-	hsep = gtk_hseparator_new();
-	gtk_widget_set_size_request(hsep, -1, 10);
-	gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
-			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-			(GtkAttachOptions) (0), 10, 5);
-
-	row++;
-	/* Silent update - label */
-	silent_update_label =
-		gtk_label_new(_("<b>If an item changes, do not mark it as unread:</b>"));
-	gtk_label_set_use_markup(GTK_LABEL(silent_update_label), TRUE);
-	gtk_misc_set_alignment(GTK_MISC(silent_update_label), 0, 0.5);
-	gtk_table_attach(GTK_TABLE(table), silent_update_label, 0, 1, row, row+1,
-			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-			(GtkAttachOptions) (0), 10, 5);
-
-	/* Silent update - combobox */
-	feedprop->silent_update = gtk_combo_box_new_text();
-	gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
-			_("Always mark as unread"));
-	gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
-			_("If only its text has changed"));
-	gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
-			_("Never mark as unread"));
-	gtk_table_attach(GTK_TABLE(table), feedprop->silent_update, 1, 2, row, row+1,
-			(GtkAttachOptions) (0),
-			(GtkAttachOptions) (0), 10, 5);
-	gtk_combo_box_set_active(GTK_COMBO_BOX(feedprop->silent_update),
-			ritem->silent_update);
-
-	row++;
-	hsep = gtk_hseparator_new();
-	gtk_widget_set_size_request(hsep, -1, 10);
-	gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
-			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-			(GtkAttachOptions) (0), 10, 5);
-
-	row++;
-	feedprop->ssl_verify_peer_checkbtn = gtk_check_button_new_with_label(
-		_("Verify SSL certificate validity"));
-	gtk_widget_show(feedprop->ssl_verify_peer_checkbtn);
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(feedprop->ssl_verify_peer_checkbtn), 
-			ritem->ssl_verify_peer);
-	gtk_table_attach(GTK_TABLE(table), feedprop->ssl_verify_peer_checkbtn, 0, 1, row, row+1,
-			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-			(GtkAttachOptions) (0), 10, 5);
-
-
-	/* Separator above the button box */
-	sep = gtk_hseparator_new();
-	gtk_widget_set_size_request(sep, -1, 10);
-	gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
-
-	/* Buttonbox */
-	bbox = gtk_hbutton_box_new();
-	gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
-	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
-	gtk_box_set_spacing(GTK_BOX(bbox), 5);
-	gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
-
-	/* Cancel button */
-	cancel_button = gtk_button_new();
-	gtk_container_add(GTK_CONTAINER(bbox), cancel_button);
-
-	cancel_align = gtk_alignment_new(0.5, 0.5, 0, 0);
-	gtk_container_add(GTK_CONTAINER(cancel_button), cancel_align);
-
-	cancel_hbox = gtk_hbox_new(FALSE, 2);
-	gtk_container_add(GTK_CONTAINER(cancel_align), cancel_hbox);
-
-	cancel_image = gtk_image_new_from_stock(GTK_STOCK_CANCEL,
-			GTK_ICON_SIZE_BUTTON);
-	gtk_box_pack_start(GTK_BOX(cancel_hbox), cancel_image, FALSE, FALSE, 0);
-
-	cancel_label = gtk_label_new_with_mnemonic(_("_Cancel"));
-	gtk_box_pack_end(GTK_BOX(cancel_hbox), cancel_label, FALSE, FALSE, 0);
-
-	g_signal_connect(G_OBJECT(cancel_button), "clicked",
-			G_CALLBACK(rssyl_props_cancel_cb), ritem);
-
-	/* OK button */
-	ok_button = gtk_button_new();
-	gtk_container_add(GTK_CONTAINER(bbox), ok_button);
-	gtkut_widget_set_can_default(ok_button, TRUE);
-
-	ok_align = gtk_alignment_new(0.5, 0.5, 0, 0);
-	gtk_container_add(GTK_CONTAINER(ok_button), ok_align);
-
-	ok_hbox = gtk_hbox_new(FALSE, 2);
-	gtk_container_add(GTK_CONTAINER(ok_align), ok_hbox);
-
-	ok_image = gtk_image_new_from_stock(GTK_STOCK_OK,
-			GTK_ICON_SIZE_BUTTON);
-	gtk_box_pack_start(GTK_BOX(ok_hbox), ok_image, FALSE, FALSE, 0);
-
-	ok_label = gtk_label_new_with_mnemonic(_("_OK"));
-	gtk_box_pack_end(GTK_BOX(ok_hbox), ok_label, FALSE, FALSE, 0);
-
-	g_signal_connect(G_OBJECT(ok_button), "clicked",
-			G_CALLBACK(rssyl_props_ok_cb), ritem);
-
-	/* Set some misc. stuff */
-	gtk_window_set_title(GTK_WINDOW(feedprop->window),
-			g_strdup(_("Set feed properties")) );
-	gtk_window_set_modal(GTK_WINDOW(feedprop->window), TRUE);
-	gtk_window_set_transient_for(GTK_WINDOW(feedprop->window),
-			GTK_WINDOW(mainwin->window) );
-
-	/* Attach callbacks to handle Enter and Escape keys */
-	g_signal_connect(G_OBJECT(feedprop->window), "key_press_event",
-			G_CALLBACK(rssyl_props_key_press_cb), ritem);
-
-	/* ...and voila! */
-	gtk_widget_show_all(feedprop->window);
-	gtk_widget_grab_default(ok_button);
-
-	/* Unselect the text in URL entry */
-	gtk_editable_select_region(GTK_EDITABLE(feedprop->url), 0, 0);
-
-	ritem->feedprop = feedprop;
-
-	return feedprop;
-}
-
-void rssyl_gtk_prop(RSSylFolderItem *ritem)
-{
-	g_return_if_fail(ritem != NULL);
-
-	rssyl_gtk_prop_real(ritem);
-}
-
-void rssyl_gtk_prop_store(RSSylFolderItem *ritem)
-{
-	gchar *url;
-	gint x, old_ri, old_ex, old_fetch_comments;
-	gboolean use_default_ri = FALSE, use_default_ex = FALSE;
-
-	g_return_if_fail(ritem != NULL);
-	g_return_if_fail(ritem->feedprop != NULL);
-
-	url = (gchar *)gtk_entry_get_text(GTK_ENTRY(ritem->feedprop->url));
-
-	if( strlen(url) ) {
-		if( ritem->url ) {
-			g_free(ritem->url);
-		}
-		ritem->url = g_strdup(url);
-	}
-
-	use_default_ri = gtk_toggle_button_get_active(
-			GTK_TOGGLE_BUTTON(ritem->feedprop->default_refresh_interval));
-	ritem->default_refresh_interval = use_default_ri;
-	debug_print("store: default is %s\n", ( use_default_ri ? "ON" : "OFF" ) );
-
-	/* Use default if checkbutton is set */
-	if( use_default_ri )
-		x = rssyl_prefs_get()->refresh;
-	else
-		x = gtk_spin_button_get_value_as_int(
-				GTK_SPIN_BUTTON(ritem->feedprop->refresh_interval) );
-
-	old_ri = ritem->refresh_interval;
-	ritem->refresh_interval = x;
-
-	/* Update refresh interval setting if it has changed and has a sane value */
-	if( old_ri != x && x >= 0 ) {
-		debug_print("RSSyl: GTK - refresh interval changed to %d , updating "
-				"timeout\n", ritem->refresh_interval);
-		/* Value of 0 means we do not want to update automatically */
-		if( x > 0 )
-			rssyl_start_refresh_timeout(ritem);
-	}
-
-	old_fetch_comments = ritem->fetch_comments;
-	ritem->fetch_comments = gtk_toggle_button_get_active(
-			GTK_TOGGLE_BUTTON(ritem->feedprop->fetch_comments));
-
-	ritem->fetch_comments_for = gtk_spin_button_get_value_as_int(
-				GTK_SPIN_BUTTON(ritem->feedprop->fetch_comments_for));
-
-	if (!old_fetch_comments && ritem->fetch_comments) {
-		/* reset the RSSylFolderItem's mtime to be sure we get all 
-		 * available comments */
-		 ritem->item.mtime = 0;
-	}
-	
-	use_default_ex = gtk_toggle_button_get_active(
-			GTK_TOGGLE_BUTTON(ritem->feedprop->default_expired_num));
-	ritem->default_expired_num = use_default_ex;
-	debug_print("store: default is %s\n", ( use_default_ex ? "ON" : "OFF" ) );
-
-	/* Use default if checkbutton is set */
-	if( use_default_ex )
-		x = rssyl_prefs_get()->expired;
-	else
-		x = gtk_spin_button_get_value_as_int(
-				GTK_SPIN_BUTTON(ritem->feedprop->expired_num) );
-
-	old_ex = ritem->expired_num;
-	ritem->expired_num = x;
-
-	ritem->silent_update =
-		gtk_combo_box_get_active(GTK_COMBO_BOX(ritem->feedprop->silent_update));
-	if( ritem->silent_update < 0 )
-		ritem->silent_update = 0;
-
-	ritem->ssl_verify_peer = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
-					 (ritem->feedprop->ssl_verify_peer_checkbtn));;
-
-	rssyl_store_feed_props(ritem);
-
-	debug_print("last_count %d, x %d, old_ex %d\n", ritem->last_count, x, old_ex);
-
-	/* update if new setting is lower, or if it was changed from -1 */
-	if( ritem->last_count != 0 && x != -1 && (old_ex > x || old_ex == -1) ) {
-		debug_print("RSSyl: GTK - expired_num has changed to %d, expiring\n",
-				ritem->expired_num);
-		rssyl_expire_items(ritem);
-	}
-}
-
-GtkWidget *rssyl_feed_removal_dialog(gchar *name, GtkWidget **rmcache_widget)
-{
-	gchar *message;
-	GtkWidget *dialog, *vbox, *hbox, *image, *vbox2, *label, *cb, *aa,
-						*bno, *byes;
-	MainWindow *mainwin = mainwindow_get_mainwindow();
-
-	g_return_val_if_fail(name != NULL, NULL);
-
-	dialog = gtk_dialog_new();
-	gtk_window_set_title(GTK_WINDOW(dialog), _("Unsubscribe feed"));
-	gtk_window_set_type_hint(GTK_WINDOW(dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
-
-	vbox = GTK_DIALOG(dialog)->vbox;
-
-	hbox = gtk_hbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
-
-	/* Question icon */
-	image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION,
-			GTK_ICON_SIZE_DIALOG);
-	gtk_misc_set_alignment(GTK_MISC(image), 0.5, 0.30);
-	gtk_misc_set_padding(GTK_MISC(image), 12, 0);
-	gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
-
-	vbox2 = gtk_vbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(hbox), vbox2, TRUE, TRUE, 0);
-
-	/* Dialog text label */
-	label = gtk_label_new("");
-	gtk_misc_set_alignment(GTK_MISC(label), 0.1, 0);
-	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
-	gtk_misc_set_padding(GTK_MISC(label), 0, 12);
-	message = g_markup_printf_escaped("<span size='x-large'><b>%s</b></span>"
-			"\n\n%s '%s' ?", _("Unsubscribe feed"),
-			_("Do you really want to remove feed"), name);
-	gtk_label_set_markup(GTK_LABEL(label), message);
-	g_free(message);
-	gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, FALSE, 0);
-
-	/* Remove cache checkbutton */
-	cb = gtk_check_button_new_with_mnemonic(_("Remove cached entries"));
-	gtk_button_set_focus_on_click(GTK_BUTTON(cb), FALSE);
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb), TRUE);
-	gtk_box_pack_start(GTK_BOX(vbox2), cb, FALSE, FALSE, 0);
-	*rmcache_widget = cb;
-
-	aa = GTK_DIALOG(dialog)->action_area;
-	gtk_button_box_set_layout(GTK_BUTTON_BOX(aa), GTK_BUTTONBOX_END);
-
-	bno = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
-	gtk_dialog_add_action_widget(GTK_DIALOG(dialog), bno, GTK_RESPONSE_NO);
-	gtkut_widget_set_can_default(bno, TRUE);
-	
-	byes = gtk_button_new_with_mnemonic(_("_Unsubscribe"));
-	gtk_dialog_add_action_widget(GTK_DIALOG(dialog), byes, GTK_RESPONSE_YES);
-
-	gtk_widget_grab_default(bno);
-	gtk_window_set_transient_for(GTK_WINDOW(dialog),
-			GTK_WINDOW(mainwin->window) );
 
-	return dialog;
 }
diff --git a/src/plugins/rssyl/rssyl_gtk.h b/src/plugins/rssyl/rssyl_gtk.h
index a670a6b..6a97fc8 100644
--- a/src/plugins/rssyl/rssyl_gtk.h
+++ b/src/plugins/rssyl/rssyl_gtk.h
@@ -7,27 +7,11 @@
 
 #include "rssyl.h"
 
-struct _RSSylFeedProp {
-	GtkWidget *window;
-	GtkWidget *url;
-	GtkWidget *default_refresh_interval;
-	GtkWidget *refresh_interval;
-	GtkWidget *default_expired_num;
-	GtkWidget *expired_num;
-	GtkWidget *fetch_comments;
-	GtkWidget *fetch_comments_for;
-	GtkWidget *silent_update;
-	GtkWidget *ssl_verify_peer_checkbtn;
-};
-
-typedef struct _RSSylFeedProp RSSylFeedProp;
-
 void rssyl_gtk_init(void);
 void rssyl_gtk_done(void);
 
-void rssyl_gtk_prop(RSSylFolderItem *ritem);
-void rssyl_gtk_prop_store(RSSylFolderItem *ritem);
-
 GtkWidget *rssyl_feed_removal_dialog(gchar *name, GtkWidget **rmcache_widget);
 
+void rssyl_gtk_prop(RFolderItem *ritem);
+
 #endif /* __RSSYL_GTK */
diff --git a/src/plugins/rssyl/rssyl_parse_feed.c b/src/plugins/rssyl/rssyl_parse_feed.c
new file mode 100644
index 0000000..88dc406
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_parse_feed.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <glib/gi18n.h>
+
+/* Claws Mail includes */
+#include <log.h>
+#include <codeconv.h>
+#include <main.h>
+#include <procmsg.h>
+
+/* Local includes */
+#include "libfeed/feed.h"
+#include "libfeed/feeditem.h"
+#include "libfeed/date.h"
+#include "parse822.h"
+#include "rssyl.h"
+#include "rssyl_add_item.h"
+#include "rssyl_deleted.h"
+#include "rssyl_feed.h"
+#include "rssyl_parse_feed.h"
+#include "rssyl_prefs.h"
+#include "strutils.h"
+
+static void rssyl_foreach_parse_func(gpointer data, gpointer user_data)
+{
+	FeedItem *feed_item = (FeedItem *)data;
+	RFolderItem *ritem = (RFolderItem *)user_data;
+
+	rssyl_add_item(ritem, feed_item);
+}
+
+struct _RSSylExpireItemsCtx {
+	gboolean exists;
+	FeedItem *item;
+};
+
+typedef struct _RSSylExpireItemsCtx RSSylExpireItemsCtx;
+
+static void expire_items_func(gpointer data, gpointer user_data)
+{
+	RSSylExpireItemsCtx *ctx = (RSSylExpireItemsCtx *)user_data;
+	FeedItem *item = (FeedItem *)data;
+	gchar *id = NULL, *id2 = NULL;
+
+	if( (id = feed_item_get_id(item)) == NULL )
+		id = feed_item_get_url(item);
+
+	if( id == NULL )
+		return;
+
+	if( (id2 = feed_item_get_id(ctx->item)) == NULL )
+		id2 = feed_item_get_url(ctx->item);
+
+	if( id2 == NULL )
+		return;
+
+	/* Simply check ID, as we should have up-to-date items right now. */
+	if( !strcmp(id, id2) )
+		ctx->exists = TRUE;
+}
+
+static void rssyl_expire_items(RFolderItem *ritem, Feed *feed)
+{
+	FeedItem *item = NULL;
+	GSList *i = NULL;
+	RSSylExpireItemsCtx *ctx = NULL;
+	RFeedCtx *fctx;
+
+	debug_print("RSSyl: rssyl_expire_items()\n");
+
+	g_return_if_fail(ritem != NULL);
+	g_return_if_fail(ritem->items != NULL);
+	g_return_if_fail(feed != NULL);
+
+	ctx = malloc( sizeof(RSSylExpireItemsCtx) );
+
+	/* Check each locally stored item, if it is still in the upstream
+	 * feed - xnay it if not. */
+	for( i = ritem->items; i != NULL; i = i->next ) {
+		item = (FeedItem *)i->data;
+
+		/* Do not expire comments, they expire with their parents */
+		if (feed_item_get_parent_id(item) != NULL)
+			continue;
+
+		ctx->exists = FALSE;
+		ctx->item = item;
+		feed_foreach_item(feed, expire_items_func, ctx);
+
+		if( !ctx->exists ) {
+			fctx = (RFeedCtx *)item->data;
+			/* TODO: expire item's comments (items with our parent_id) */
+			g_remove(fctx->path);
+		}
+	}
+
+	g_free(ctx);
+}
+
+/* -------------------------------------------------------------------------
+ * rssyl_parse_feed() */
+
+gboolean rssyl_parse_feed(RFolderItem *ritem, Feed *feed)
+{
+	gchar *tmp = NULL, *tmp2 = NULL;
+	gint i = 1;
+
+	g_return_val_if_fail(ritem != NULL, FALSE);
+	g_return_val_if_fail(feed != NULL, FALSE);
+	g_return_val_if_fail(feed->title != NULL, FALSE);
+
+	debug_print("RSSyl: parse_feed\n");
+
+	/* Set the last_update timestamp here, so it is the same for all items */
+	ritem->last_update = time(NULL);
+
+	/* If the upstream feed changed its title, change name of our folder
+	 * accordingly even if user has renamed it before. This makes sure that
+	 * user will be aware of the upstream title change. */
+	if( !ritem->ignore_title_rename &&
+			(ritem->official_title == NULL ||
+			strcmp(feed->title, ritem->official_title)) ) {
+		g_free(ritem->official_title);
+		ritem->official_title = g_strdup(feed->title);
+
+		tmp = rssyl_format_string(feed->title, TRUE, TRUE);
+
+		tmp2 = g_strdup(tmp);
+		while (folder_item_rename(&ritem->item, tmp2) != 0 && i < 20) {
+			g_free(tmp2);
+			tmp2 = g_strdup_printf("%s__%d", tmp, ++i);
+			debug_print("RSSyl: couldn't rename, trying '%s'\n", tmp2);
+		}
+		/* TODO: handle case when i reaches 20 */
+	
+		g_free(tmp);
+		g_free(tmp2);
+
+		/* FIXME: update name in properties */
+		/* FIXME: store feed properties */
+	}
+
+	folder_item_update_freeze();
+
+	/* Read contents of folder, so we can check for duplicates/updates */
+	rssyl_folder_read_existing(ritem);
+
+	if( claws_is_exiting() ) {
+		debug_print("RSSyl: Claws-Mail is exiting, bailing out\n");
+		log_print(LOG_PROTOCOL, RSSYL_LOG_ABORTED_EXITING, ritem->url);
+		folder_item_update_thaw();
+		return TRUE;
+	}
+
+	/* Populate the ->deleted_items list so that we can check it when
+	 * adding each item. */
+	ritem->deleted_items = rssyl_deleted_update(ritem);
+
+	/* Parse each item in the feed, adding or updating existing items if
+	 * necessary */
+	if( feed_n_items(feed) > 0 )
+		feed_foreach_item(feed, rssyl_foreach_parse_func, (gpointer)ritem);
+
+	if( !ritem->keep_old && !ritem->fetching_comments ) {
+		rssyl_folder_read_existing(ritem);
+		rssyl_expire_items(ritem, feed);
+	}
+
+	rssyl_deleted_free(ritem->deleted_items);
+
+	folder_item_scan(&ritem->item);
+	folder_item_update_thaw();
+
+	if( !ritem->fetching_comments )
+		log_print(LOG_PROTOCOL, RSSYL_LOG_UPDATED, ritem->url);
+
+	return TRUE;
+}
diff --git a/src/plugins/rssyl/rssyl_parse_feed.h b/src/plugins/rssyl/rssyl_parse_feed.h
new file mode 100644
index 0000000..5e4a3f3
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_parse_feed.h
@@ -0,0 +1,16 @@
+#ifndef __RSSYL_PARSE_FEED
+#define __RSSYL_PARSE_FEED
+
+#include <glib.h>
+
+#include "rssyl.h"
+#include "libfeed/feed.h"
+
+#define RSSYL_TMP_TEMPLATE	"rssylXXXXXX"
+
+#define RSSYL_TEXT_START    "<!-- RSSyl text start -->"
+#define RSSYL_TEXT_END      "<!-- RSSyl text end -->"
+
+gboolean rssyl_parse_feed(RFolderItem *ritem, Feed *feed);
+
+#endif /* __RSSYL_PARSE_FEED */
diff --git a/src/plugins/rssyl/rssyl_prefs.c b/src/plugins/rssyl/rssyl_prefs.c
index 97b2b83..6b8b050 100644
--- a/src/plugins/rssyl/rssyl_prefs.c
+++ b/src/plugins/rssyl/rssyl_prefs.c
@@ -22,39 +22,43 @@
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
-#include "claws-features.h"
 #endif
 
+/* Global includes */
 #include <glib.h>
 #include <glib/gi18n.h>
 
-#include "common/defs.h"
-#include "common/utils.h"
-#include "gtk/gtkutils.h"
-#include "prefs_gtk.h"
+/* Claws Mail includes */
+#include <common/defs.h>
+#include <prefs_gtk.h>
+#include <mainwindow.h>
 
+/* Local includes */
+#include "rssyl.h"
 #include "rssyl_prefs.h"
+#include "rssyl_feed.h"
 
-static RSSylPrefsPage rssyl_prefs_page;
-RSSylPrefs rssyl_prefs;
+static RPrefsPage rssyl_gtk_prefs_page;
+RPrefs rssyl_prefs;
 
 static void destroy_rssyl_prefs_page(PrefsPage *page);
 static void create_rssyl_prefs_page(PrefsPage *page,
 		GtkWindow *window, gpointer data);
 static void save_rssyl_prefs(PrefsPage *page);
-
-static PrefParam param[] = {
-	{ "refresh_interval", RSSYL_PREF_DEFAULT_REFRESH, &rssyl_prefs.refresh, P_INT,
-		NULL, NULL, NULL },
-	{ "expired_keep", RSSYL_PREF_DEFAULT_EXPIRED, &rssyl_prefs.expired, P_INT,
-		NULL, NULL, NULL },
-	{ "refresh_on_startup", "FALSE", &rssyl_prefs.refresh_on_startup, P_BOOL,
-		NULL, NULL, NULL },
-	{ "cookies_path", "", &rssyl_prefs.cookies_path, P_STRING,
-		NULL, NULL, NULL },
-	{ "ssl_verify_peer", "TRUE", &rssyl_prefs.ssl_verify_peer, P_BOOL,
-		NULL, NULL, NULL },
-	{ 0, 0, 0, 0, 0, 0, 0 }
+static void rssyl_apply_prefs(void);
+
+	static PrefParam param[] = {
+		{ "refresh_interval", PREF_DEFAULT_REFRESH, &rssyl_prefs.refresh, P_INT,
+			NULL, NULL, NULL },
+		{ "refresh_on_startup", "FALSE", &rssyl_prefs.refresh_on_startup, P_BOOL,
+			NULL, NULL, NULL },
+		{ "refresh_enabled", "TRUE", &rssyl_prefs.refresh_enabled, P_BOOL,
+			NULL, NULL, NULL },
+		{ "cookies_path", "", &rssyl_prefs.cookies_path, P_STRING,
+			NULL, NULL, NULL },
+		{ "ssl_verify_peer", "TRUE", &rssyl_prefs.ssl_verify_peer, P_BOOL,
+			NULL, NULL, NULL },
+		{ 0, 0, 0, 0, 0, 0, 0 }
 };
 
 void rssyl_prefs_init(void)
@@ -71,98 +75,119 @@ void rssyl_prefs_init(void)
 	prefs_read_config(param, PREFS_BLOCK_NAME, rcpath, NULL);
 	g_free(rcpath);
 
-	rssyl_prefs_page.page.path = path;
-	rssyl_prefs_page.page.create_widget = create_rssyl_prefs_page;
-	rssyl_prefs_page.page.destroy_widget = destroy_rssyl_prefs_page;
-	rssyl_prefs_page.page.save_page = save_rssyl_prefs;
-	rssyl_prefs_page.page.weight = 30.0;
+	rssyl_gtk_prefs_page.page.path = path;
+	rssyl_gtk_prefs_page.page.create_widget = create_rssyl_prefs_page;
+	rssyl_gtk_prefs_page.page.destroy_widget = destroy_rssyl_prefs_page;
+	rssyl_gtk_prefs_page.page.save_page = save_rssyl_prefs;
+	rssyl_gtk_prefs_page.page.weight = 30.0;
 
-	prefs_gtk_register_page((PrefsPage *) &rssyl_prefs_page);
+	prefs_gtk_register_page((PrefsPage *) &rssyl_gtk_prefs_page);
 }
 
 void rssyl_prefs_done(void)
 {
-	prefs_gtk_unregister_page((PrefsPage *) &rssyl_prefs_page);
+	prefs_gtk_unregister_page((PrefsPage *) &rssyl_gtk_prefs_page);
+}
+
+/* Toggle the refresh timeout spinbutton sensitivity after the
+ * checkbutton was toggled. */
+static gboolean
+rssyl_refresh_enabled_toggled_cb(GtkToggleButton *tb, gpointer data)
+{
+	gtk_widget_set_sensitive(GTK_WIDGET(data),
+			gtk_toggle_button_get_active(tb));
+	return FALSE;
 }
 
 static void create_rssyl_prefs_page(PrefsPage *page,
 		GtkWindow *window, gpointer data)
 {
-	RSSylPrefsPage *prefs_page = (RSSylPrefsPage *) page;
+	int row = 0;
+	RPrefsPage *prefs_page = (RPrefsPage *) page;
 	GtkWidget *table;
-	GtkWidget *refresh;
-	GtkWidget *expired;
+	GtkWidget *refresh, *refresh_enabled;
+	GtkWidget *label;
 	GtkWidget *refresh_on_startup;
+	GtkObject *refresh_adj;
 	GtkWidget *cookies_path;
-	GtkWidget *ssl_verify_peer_checkbtn;
-	GtkWidget *label;
-	GtkObject *refresh_adj, *expired_adj;
+	GtkWidget *ssl_verify_peer;
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+	GtkTooltips *tooltips;
+
+	tooltips = gtk_tooltips_new();
+	gtk_tooltips_enable(tooltips);
+#endif
 
-	table = gtk_table_new(RSSYL_NUM_PREFS, 2, FALSE);
-	gtk_container_set_border_width(GTK_CONTAINER(table), 6);
+	table = gtk_table_new(3, 2, FALSE);
+	gtk_container_set_border_width(GTK_CONTAINER(table), 5);
 	gtk_table_set_row_spacings(GTK_TABLE(table), VSPACING_NARROW);
 	gtk_table_set_col_spacings(GTK_TABLE(table), 8);
 
-	label = gtk_label_new(_("Default refresh interval in minutes"));
-	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1,
-			GTK_FILL, 0, 0, 0);
+	/* Refresh interval */
+	refresh_enabled = gtk_check_button_new_with_label(
+			_("Default refresh interval in minutes"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(refresh_enabled),
+			rssyl_prefs.refresh_enabled);
+	gtk_table_attach(GTK_TABLE(table), refresh_enabled, 0, 1, row, row+1,
+			GTK_FILL | GTK_EXPAND, 0, 0, 0);
 
 	refresh_adj = gtk_adjustment_new(rssyl_prefs.refresh,
-			0, 100000, 1, 10, 0);
+			1, 100000, 1, 10, 0);
 	refresh = gtk_spin_button_new(GTK_ADJUSTMENT(refresh_adj), 1, 0);
-	gtk_table_attach(GTK_TABLE(table), refresh, 1, 2, 0, 1,
+	gtk_widget_set_sensitive(GTK_WIDGET(refresh), rssyl_prefs.refresh_enabled);
+	gtk_table_attach(GTK_TABLE(table), refresh, 1, 2, row, row+1,
 			GTK_FILL, 0, 0, 0);
-	CLAWS_SET_TIP(refresh,
-			_("Set to 0 to disable automatic refreshing"));
 
-	label = gtk_label_new(_("Default number of expired items to keep"));
-	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2,
-			GTK_FILL, 0, 0, 0);
-
-	expired_adj = gtk_adjustment_new(rssyl_prefs.expired,
-			-1, 100000, 1, 10, 0);
-	expired = gtk_spin_button_new(GTK_ADJUSTMENT(expired_adj), 1, 0);
-	gtk_table_attach(GTK_TABLE(table), expired, 1, 2, 1, 2,
-			GTK_FILL, 0, 0, 0);
-	CLAWS_SET_TIP(expired,
-			_("Set to -1 to keep expired items"));
+	g_signal_connect(G_OBJECT(refresh_enabled), "toggled",
+			G_CALLBACK(rssyl_refresh_enabled_toggled_cb), refresh);
 
+	row++;
+	/* Whether to refresh all feeds on CM startup */
 	refresh_on_startup = gtk_check_button_new_with_label(
 			_("Refresh all feeds on application start"));
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(refresh_on_startup),
 			rssyl_prefs.refresh_on_startup);
-	gtk_table_attach(GTK_TABLE(table), refresh_on_startup, 0, 2, 3, 4,
+	gtk_table_attach(GTK_TABLE(table), refresh_on_startup, 0, 2, row, row+1,
 			GTK_FILL | GTK_EXPAND, 0, 0, 0);
 
+	row++;
+	/* Path to cookies file for libcurl to use */
 	label = gtk_label_new(_("Path to cookies file"));
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5,
-			GTK_FILL, 0, 0, 0);
+	gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1,
+			GTK_FILL | GTK_EXPAND, 0, 0, 0);
 	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
 
-	cookies_path = gtk_entry_new ();
+	cookies_path = gtk_entry_new();
 	gtk_entry_set_text(GTK_ENTRY(cookies_path), rssyl_prefs.cookies_path);
-	gtk_table_attach(GTK_TABLE(table), cookies_path, 1, 2, 4, 5,
-			GTK_FILL | GTK_EXPAND, 0, 0, 0);
-	CLAWS_SET_TIP(cookies_path,
+	gtk_table_attach(GTK_TABLE(table), cookies_path, 1, 2, row, row+1,
+			GTK_FILL, 0, 0, 0);
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+	gtk_tooltips_set_tip(tooltips, cookies_path,
+			_("Path to Netscape-style cookies.txt file containing your cookies"), NULL);
+#else
+	gtk_widget_set_tooltip_text(cookies_path,
 			_("Path to Netscape-style cookies.txt file containing your cookies"));
+#endif
 
-	ssl_verify_peer_checkbtn = gtk_check_button_new_with_label(
-			_("Verify SSL certificate validity for new feeds"));
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ssl_verify_peer_checkbtn),
+	row++;
+
+	/* Whether to verify SSL peer certificate */
+	ssl_verify_peer = gtk_check_button_new_with_label(
+			_("Verify SSL certificates validity for new feeds"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ssl_verify_peer),
 			rssyl_prefs.ssl_verify_peer);
-	gtk_table_attach(GTK_TABLE(table), ssl_verify_peer_checkbtn, 0, 2, 5, 6,
+	gtk_table_attach(GTK_TABLE(table), ssl_verify_peer, 0, 2, row, row+1,
 			GTK_FILL | GTK_EXPAND, 0, 0, 0);
 
 	gtk_widget_show_all(table);
 
+	/* Store pointers to relevant widgets */
 	prefs_page->page.widget = table;
+	prefs_page->refresh_enabled = refresh_enabled;
 	prefs_page->refresh = refresh;
-	prefs_page->expired = expired;
 	prefs_page->refresh_on_startup = refresh_on_startup;
 	prefs_page->cookies_path = cookies_path;
-	prefs_page->ssl_verify_peer_checkbtn = ssl_verify_peer_checkbtn;
+	prefs_page->ssl_verify_peer = ssl_verify_peer;
 }
 
 static void destroy_rssyl_prefs_page(PrefsPage *page)
@@ -172,23 +197,25 @@ static void destroy_rssyl_prefs_page(PrefsPage *page)
 
 static void save_rssyl_prefs(PrefsPage *page)
 {
-	RSSylPrefsPage *prefs_page = (RSSylPrefsPage *)page;
+	RPrefsPage *prefs_page = (RPrefsPage *)page;
 	PrefFile *pref_file;
 	gchar *rc_file_path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
 			COMMON_RC, NULL);
 
+	/* Grab values from GTK widgets */
+	rssyl_prefs.refresh_enabled = gtk_toggle_button_get_active(
+			GTK_TOGGLE_BUTTON(prefs_page->refresh_enabled));
 	rssyl_prefs.refresh = gtk_spin_button_get_value_as_int(
 			GTK_SPIN_BUTTON(prefs_page->refresh));
-	rssyl_prefs.expired = gtk_spin_button_get_value_as_int(
-			GTK_SPIN_BUTTON(prefs_page->expired));
 	rssyl_prefs.refresh_on_startup = gtk_toggle_button_get_active(
 			GTK_TOGGLE_BUTTON(prefs_page->refresh_on_startup));
 	g_free(rssyl_prefs.cookies_path);
 	rssyl_prefs.cookies_path = g_strdup(gtk_entry_get_text(
-			GTK_ENTRY(prefs_page->cookies_path)));
+				GTK_ENTRY(prefs_page->cookies_path)));
 	rssyl_prefs.ssl_verify_peer = gtk_toggle_button_get_active(
-			GTK_TOGGLE_BUTTON(prefs_page->ssl_verify_peer_checkbtn));
+			GTK_TOGGLE_BUTTON(prefs_page->ssl_verify_peer));
 
+	/* Store prefs in rc file */
 	pref_file = prefs_write_open(rc_file_path);
 	g_free(rc_file_path);
 
@@ -201,14 +228,56 @@ static void save_rssyl_prefs(PrefsPage *page)
 		return;
 	}
 
-        if (fprintf(pref_file->fp, "\n") < 0) {
-		FILE_OP_ERROR(rc_file_path, "fprintf");
-		prefs_file_close_revert(pref_file);
-	} else
-	        prefs_file_close(pref_file);
+	fprintf(pref_file->fp, "\n");
+	prefs_file_close(pref_file);
+
+	rssyl_apply_prefs();
 }
 
-RSSylPrefs *rssyl_prefs_get(void)
+RPrefs *rssyl_prefs_get(void)
 {
 	return &rssyl_prefs;
 }
+
+static void rssyl_start_default_refresh_timeouts_func(FolderItem *item,
+		gpointer data)
+{
+	RFolderItem *ritem = (RFolderItem *)item;
+	guint prefs_interval = GPOINTER_TO_UINT(data);
+
+	if( !IS_RSSYL_FOLDER_ITEM(item) )
+		return;
+
+	if( folder_item_parent(item) == NULL || ritem->url == NULL )
+		return;
+
+	/* Feeds which use default refresh interval */
+	if( ritem->default_refresh_interval ) {
+		/* Start a new timer if the default value has changed
+		 * (ritem->refresh_interval should contain previous default
+		 * value in this case). */
+		if( ritem->refresh_interval != prefs_interval ) {
+			ritem->refresh_interval = prefs_interval;
+			rssyl_feed_start_refresh_timeout(ritem);
+		}
+	}
+}
+
+static void rssyl_start_default_refresh_timeouts(void)
+{
+	RPrefs *rsprefs = rssyl_prefs_get();
+
+	folder_func_to_all_folders(
+			(FolderItemFunc)rssyl_start_default_refresh_timeouts_func,
+			GUINT_TO_POINTER(rsprefs->refresh));
+}
+
+/* rssyl_apply_prefs():
+ * Do what's needed to start using newly set preferences */
+static void rssyl_apply_prefs(void)
+{
+	/* Update refresh timeouts for feeds which use default interval. */
+	rssyl_start_default_refresh_timeouts();
+
+	/* Nothing else here, so far... */
+}
diff --git a/src/plugins/rssyl/rssyl_prefs.h b/src/plugins/rssyl/rssyl_prefs.h
index 15248ce..51325f6 100644
--- a/src/plugins/rssyl/rssyl_prefs.h
+++ b/src/plugins/rssyl/rssyl_prefs.h
@@ -3,34 +3,31 @@
 
 #define PREFS_BLOCK_NAME	"rssyl"
 
-#define RSSYL_NUM_PREFS		4
+#define PREF_DEFAULT_REFRESH	"180"
 
-#define RSSYL_PREF_DEFAULT_REFRESH	"180"
-#define RSSYL_PREF_DEFAULT_EXPIRED	"-1"
+typedef struct _RPrefs RPrefs;
 
-typedef struct _RSSylPrefs RSSylPrefs;
-
-struct _RSSylPrefs {
+struct _RPrefs {
+	gboolean refresh_enabled;
 	gint refresh;
-	gint expired;
 	gboolean refresh_on_startup;
 	gchar *cookies_path;
 	gboolean ssl_verify_peer;
 };
 
-typedef struct _RSSylPrefsPage RSSylPrefsPage;
+typedef struct _RPrefsPage RPrefsPage;
 
-struct _RSSylPrefsPage {
+struct _RPrefsPage {
 	PrefsPage page;
+	GtkWidget *refresh_enabled;
 	GtkWidget *refresh;
-	GtkWidget *expired;
 	GtkWidget *refresh_on_startup;
 	GtkWidget *cookies_path;
-	GtkWidget *ssl_verify_peer_checkbtn;
+	GtkWidget *ssl_verify_peer;
 };
 
 void rssyl_prefs_init(void);
 void rssyl_prefs_done(void);
-RSSylPrefs *rssyl_prefs_get(void);
+RPrefs *rssyl_prefs_get(void);
 
 #endif /* __RSSYL_PREFS */
diff --git a/src/plugins/rssyl/rssyl_subscribe.c b/src/plugins/rssyl/rssyl_subscribe.c
new file mode 100644
index 0000000..3bdbc73
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_subscribe.c
@@ -0,0 +1,151 @@
+/*
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
+ *
+ * - DESCRIPTION HERE
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+/* Global includes */
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+/* Claws Mail includes */
+#include <alertpanel.h>
+#include <folder.h>
+#include <log.h>
+#include <common/utils.h>
+
+/* Local includes */
+#include "libfeed/feed.h"
+#include "libfeed/feeditem.h"
+#include "rssyl.h"
+#include "rssyl_add_item.h"
+#include "rssyl_feed.h"
+#include "rssyl_update_feed.h"
+#include "rssyl_subscribe_gtk.h"
+#include "strutils.h"
+
+static void rssyl_subscribe_foreach_func(gpointer data, gpointer user_data)
+{
+	RFolderItem *ritem = (RFolderItem *)user_data;
+	FeedItem *feed_item = (FeedItem *)data;
+
+	g_return_if_fail(ritem != NULL);
+	g_return_if_fail(feed_item != NULL);
+
+	rssyl_add_item(ritem, feed_item);
+}
+
+gboolean rssyl_subscribe(FolderItem *parent, const gchar *url,
+		gboolean verbose)
+{
+	gchar *myurl = NULL, *tmpname = NULL, *tmpname2 = NULL;
+	RFetchCtx *ctx;
+	FolderItem *new_item;
+	RFolderItem *ritem;
+	gint i = 1;
+	RSubCtx *sctx;
+
+	g_return_val_if_fail(parent != NULL, FALSE);
+	g_return_val_if_fail(url != NULL, FALSE);
+
+	log_print(LOG_PROTOCOL, RSSYL_LOG_SUBSCRIBING, url);
+
+	myurl = my_normalize_url(url);
+
+	/* Fetch the feed. */
+	ctx = rssyl_prep_fetchctx_from_url(myurl);
+	g_free(myurl);
+	g_return_val_if_fail(ctx != NULL, FALSE);
+
+	rssyl_fetch_feed(ctx, verbose);
+
+	debug_print("RSSyl: fetch success == %s\n",
+			ctx->success ? "TRUE" : "FALSE");
+
+	if (!ctx->success) {
+		/* User notification was already handled inside rssyl_fetch_feed(),
+		 * let's just return quietly. */
+		feed_free(ctx->feed);
+		g_free(ctx->error);
+		g_free(ctx);
+		return FALSE;
+	}
+
+	if (verbose) {
+		sctx = g_new0(RSubCtx, 1);
+		sctx->feed = ctx->feed;
+
+		debug_print("RSSyl: Calling subscribe dialog routine...\n");
+		rssyl_subscribe_dialog(sctx);
+
+		if (sctx->feed == NULL) {
+			debug_print("RSSyl: User cancelled subscribe.\n");
+			g_free(sctx);
+			return FALSE;
+		}
+	}
+
+	/* OK, feed is succesfully fetched and correct, let's add it to CM. */
+
+	/* Create a folder for it. */
+	tmpname = rssyl_format_string(ctx->feed->title, TRUE, TRUE);
+	tmpname2 = g_strdup(tmpname);
+	while (folder_find_child_item_by_name(parent, tmpname2) != 0 && i < 20) {
+		debug_print("RSSyl: Folder '%s' already exists, trying another name\n",
+				tmpname2);
+		g_free(tmpname2);
+		tmpname2 = g_strdup_printf("%s__%d", tmpname, ++i);
+	}
+	/* TODO: handle cases where i reaches 20 */
+
+	folder_item_update_freeze();
+
+	new_item = folder_create_folder(parent, tmpname2);
+	g_free(tmpname);
+	g_free(tmpname2);
+
+	if (!new_item) {
+		if (verbose)
+			alertpanel_error(_("Couldn't create folder for new feed '%s'."),
+					myurl);
+		feed_free(ctx->feed);
+		g_free(ctx->error);
+		g_free(ctx); 
+		g_free(myurl);
+		return FALSE;
+	}
+
+	debug_print("RSSyl: Adding '%s'\n", ctx->feed->url);
+
+	ritem = (RFolderItem *)new_item;
+	ritem->url = g_strdup(ctx->feed->url);
+
+	if (feed_n_items(ctx->feed) > 0)
+		feed_foreach_item(ctx->feed, rssyl_subscribe_foreach_func, (gpointer)ritem);
+
+	folder_item_scan(new_item);
+	folder_write_list();
+	folder_item_update_thaw();
+
+	return TRUE;
+}
diff --git a/src/plugins/rssyl/rssyl_subscribe.h b/src/plugins/rssyl/rssyl_subscribe.h
new file mode 100644
index 0000000..52b80f9
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_subscribe.h
@@ -0,0 +1,6 @@
+#ifndef __RSSYL_SUBSCRIBE_H
+#define __RSSYL_SUBSCRIBE_H
+
+gboolean rssyl_subscribe(FolderItem *parent, const gchar *url, gboolean verbose);
+
+#endif /* __RSSYL_SUBSCRIBE_H */
diff --git a/src/plugins/rssyl/rssyl_subscribe_gtk.c b/src/plugins/rssyl/rssyl_subscribe_gtk.c
new file mode 100644
index 0000000..3f63440
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_subscribe_gtk.c
@@ -0,0 +1,109 @@
+/*
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
+ *
+ * - Dialog which appears when manually subscribing a new feed.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+/* Global includes */
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+/* Claws Mail includes */
+#include <mainwindow.h>
+
+/* Local includes */
+#include "libfeed/feed.h"
+#include "rssyl_subscribe_gtk.h"
+
+void rssyl_subscribe_dialog(RSubCtx *ctx) {
+	GtkWidget *win, *vbox, *titleframe, *titlelabel;
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+	GtkTooltips *tooltips;
+#endif
+	gint ret;
+	gchar *newtitle;
+
+	g_return_if_fail(ctx != NULL);
+	g_return_if_fail(ctx->feed != NULL);
+
+	/* Create window */
+	win = gtk_dialog_new_with_buttons(_("Subscribe new feed?"),
+			GTK_WINDOW(mainwindow_get_mainwindow()->window),
+			GTK_DIALOG_DESTROY_WITH_PARENT,
+			GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+			GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+			NULL);
+	gtk_dialog_set_default_response(GTK_DIALOG(win), GTK_RESPONSE_ACCEPT);
+
+	vbox = gtk_dialog_get_content_area(GTK_DIALOG(win));
+
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+	tooltips = gtk_tooltips_new();
+	gtk_tooltips_enable(tooltips);
+#endif
+
+	/* Feed title */
+	titleframe = gtk_frame_new(NULL);
+	gtk_container_set_border_width(GTK_CONTAINER(titleframe), 5);
+	gtk_frame_set_label_align(GTK_FRAME(titleframe), 0.05, 0.5);
+	gtk_frame_set_shadow_type(GTK_FRAME(titleframe), GTK_SHADOW_ETCHED_OUT);
+	gtk_box_pack_start(GTK_BOX(vbox), titleframe, FALSE, FALSE, 0);
+
+	titlelabel = gtk_label_new(_("<b>Feed folder:</b>"));
+	gtk_label_set_use_markup(GTK_LABEL(titlelabel), TRUE);
+	gtk_misc_set_padding(GTK_MISC(titlelabel), 5, 0);
+	gtk_frame_set_label_widget(GTK_FRAME(titleframe), titlelabel);
+
+	ctx->title = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(ctx->title), feed_get_title(ctx->feed));
+	gtk_entry_set_activates_default(GTK_ENTRY(ctx->title), TRUE);
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+	gtk_tooltips_set_tip(tooltips, ctx->title,
+			_("Instead of using official title, you can enter a different folder "
+				"name for the feed."), NULL);
+#else
+	gtk_widget_set_tooltip_text(ctx->title,
+			_("Instead of using official title, you can enter a different folder "
+				"name for the feed."));
+#endif
+	gtk_container_add(GTK_CONTAINER(titleframe), ctx->title);
+
+	gtk_widget_show_all(vbox);
+
+	ret = gtk_dialog_run(GTK_DIALOG(win));
+
+	if (ret == GTK_RESPONSE_ACCEPT) {
+		/* Modify ctx->feed based on user changes in dialog */
+		newtitle = (gchar *)gtk_entry_get_text(GTK_ENTRY(ctx->title));
+		if (strcmp(feed_get_title(ctx->feed), newtitle)) {
+			debug_print("RSSyl: Using feed title '%s'\n", newtitle);
+			feed_set_title(ctx->feed, newtitle);
+		}
+	} else {
+		/* Destroy the feed to signal outside that user cancelled subscribing */
+		feed_free(ctx->feed);
+		ctx->feed = NULL;
+	}
+
+	gtk_widget_destroy(win);
+}
diff --git a/src/plugins/rssyl/rssyl_subscribe_gtk.h b/src/plugins/rssyl/rssyl_subscribe_gtk.h
new file mode 100644
index 0000000..2d40b13
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_subscribe_gtk.h
@@ -0,0 +1,15 @@
+#ifndef __RSSYL_SUBSCRIBE_GTK_H
+#define __RSSYL_SUBSCRIBE_GTK_H
+
+#include "libfeed/feed.h"
+
+struct _RSubCtx {
+	Feed *feed;
+	GtkWidget *title;
+};
+
+typedef struct _RSubCtx RSubCtx;
+
+void rssyl_subscribe_dialog(RSubCtx *ctx);
+
+#endif /* __RSSYL_SUBSCRIBE_GTK_H */
diff --git a/src/plugins/rssyl/rssyl_update_comments.c b/src/plugins/rssyl/rssyl_update_comments.c
new file mode 100644
index 0000000..c54142d
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_update_comments.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <pthread.h>
+
+/* Claws Mail includes */
+#include <log.h>
+#include <mainwindow.h>
+#include <statusbar.h>
+#include <main.h>
+
+/* Local includes */
+#include "libfeed/feed.h"
+#include "rssyl.h"
+#include "rssyl_feed.h"
+#include "rssyl_parse_feed.h"
+#include "rssyl_update_feed.h"
+#include "parse822.h"
+
+static void rssyl_update_reference_func(gpointer data, gpointer user_data)
+{
+	FeedItem *item = (FeedItem *)data;
+	gchar *parent_id = (gchar *)user_data;
+
+	g_return_if_fail(item != NULL);
+	g_return_if_fail(user_data != NULL);
+
+	feed_item_set_parent_id(item, parent_id);
+}
+
+void rssyl_update_comments(RFolderItem *ritem)
+{
+	FolderItem *item = &ritem->item;
+	FeedItem *fi = NULL;
+	RFetchCtx *ctx = NULL;
+	DIR *dp;
+	struct dirent *d;
+	gint num;
+	gchar *path, *msg, *fname;
+	MainWindow *mainwin = mainwindow_get_mainwindow();
+
+	g_return_if_fail(ritem != NULL);
+
+	if( ritem->fetch_comments == FALSE )
+		return;
+
+	path = folder_item_get_path(item);
+	g_return_if_fail(path != NULL);
+
+	debug_print("RSSyl: starting to parse comments, path is '%s'\n", path);
+
+	if( (dp = opendir(path)) == NULL ) {
+		FILE_OP_ERROR(item->path, "opendir");
+		g_free(path);
+		return;
+	}
+
+	ritem->fetching_comments = TRUE;
+
+	while( (d = readdir(dp)) != NULL ) {
+		if (claws_is_exiting()) {
+			closedir(dp);
+			g_free(path);
+			debug_print("RSSyl: bailing out, app is exiting\n");
+		}
+
+		if( (num = to_number(d->d_name)) > 0 && d->d_type == DT_REG ) {
+			debug_print("RSSyl: starting to parse '%s'\n", d->d_name);
+
+			fname = g_strdup_printf("%s%c%s", path, G_DIR_SEPARATOR, d->d_name);
+			if( (fi = rssyl_parse_folder_item_file(fname)) != NULL ) {
+				if( feed_item_get_comments_url(fi) && feed_item_get_id(fi) &&
+						(ritem->fetch_comments_max_age == -1 ||
+						 time(NULL) - feed_item_get_date_modified(fi) <= ritem->fetch_comments_max_age*86400)) {
+					msg = g_strdup_printf(_("Updating comments for '%s'..."),
+							feed_item_get_title(fi));
+					debug_print("RSSyl: updating comments for '%s' (%s)\n",
+							feed_item_get_title(fi), feed_item_get_comments_url(fi));
+					STATUSBAR_PUSH(mainwin, msg);
+
+					ctx = rssyl_prep_fetchctx_from_url(feed_item_get_comments_url(fi));
+					g_return_if_fail(ctx != NULL);
+					feed_set_ssl_verify_peer(ctx->feed, ritem->ssl_verify_peer);
+
+					rssyl_fetch_feed(ctx, FALSE);
+					
+					if( ctx->success && feed_n_items(ctx->feed) > 0 ) {
+						g_free(ctx->feed->title);
+						ctx->feed->title = g_strdup(ritem->official_title);
+
+						feed_foreach_item(ctx->feed, rssyl_update_reference_func,
+								feed_item_get_id(fi));
+
+						if( !rssyl_parse_feed(ritem, ctx->feed) ) {
+							debug_print("RSSyl: Error processing comments feed\n");
+							log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_PROC, ctx->feed->url);
+						}
+					}
+				}
+
+				STATUSBAR_POP(mainwin);
+
+				feed_item_free(fi);
+			}
+
+			g_free(fname);
+		}
+	}
+
+	closedir(dp);
+	g_free(path);
+
+	ritem->fetching_comments = FALSE;
+
+	debug_print("RSSyl: rssyl_update_comments() is done\n");
+}
diff --git a/src/plugins/rssyl/rssyl_update_comments.h b/src/plugins/rssyl/rssyl_update_comments.h
new file mode 100644
index 0000000..3ce56e4
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_update_comments.h
@@ -0,0 +1,12 @@
+
+
+#ifndef __RSSYL_UPDATE_COMMENTS
+#define __RSSYL_UPDATE_COMMENTS
+
+#include <glib.h>
+
+#include "rssyl.h"
+
+void rssyl_update_comments(RFolderItem *ritem);
+
+#endif /* __RSSYL_UPDATE_COMMENTS */
diff --git a/src/plugins/rssyl/rssyl_update_feed.c b/src/plugins/rssyl/rssyl_update_feed.c
new file mode 100644
index 0000000..8a97f90
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_update_feed.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <pthread.h>
+
+/* Claws Mail includes */
+#include <common/claws.h>
+#include <mainwindow.h>
+#include <statusbar.h>
+#include <alertpanel.h>
+#include <log.h>
+#include <prefs_common.h>
+#include <inc.h>
+#include <main.h>
+
+/* Local includes */
+#include "libfeed/feed.h"
+#include "rssyl.h"
+#include "rssyl_deleted.h"
+#include "rssyl_feed.h"
+#include "rssyl_parse_feed.h"
+#include "rssyl_prefs.h"
+#include "rssyl_update_comments.h"
+
+/* rssyl_fetch_feed_thr() */
+
+static void *rssyl_fetch_feed_thr(void *arg)
+{
+	RFetchCtx *ctx = (RFetchCtx *)arg;
+
+	/* Fetch and parse the feed. */
+	ctx->response_code = feed_update(ctx->feed, -1);
+
+	/* Signal main thread that we're done here. */
+	ctx->ready = TRUE;
+
+	return NULL;
+}
+
+/* rssyl_fetch_feed() */
+RFetchCtx *rssyl_fetch_feed(RFetchCtx *ctx, gboolean verbose)
+{
+#ifdef USE_PTHREAD
+	pthread_t pt;
+#endif
+
+	g_return_if_fail(ctx != NULL);
+
+#ifdef USE_PTHREAD
+	if( pthread_create(&pt, PTHREAD_CREATE_JOINABLE, rssyl_fetch_feed_thr,
+				(void *)ctx) != 0 ) {
+		/* Bummer, couldn't create thread. Continue non-threaded. */
+		rssyl_fetch_feed_thr(ctx);
+	} else {
+		/* Thread created, let's wait until it finishes. */
+		debug_print("RSSyl: waiting for thread to finish (timeout: %ds)\n",
+				feed_get_timeout(ctx->feed));
+		while( !ctx->ready ) {
+			claws_do_idle();
+		}
+
+		debug_print("RSSyl: thread finished\n");
+		pthread_join(pt, NULL);
+	}
+#else
+	debug_print("RSSyl: no pthreads available, running non-threaded fetch\n");
+	rssyl_fetch_feed_thr(ctx);
+#endif
+
+	if( ctx->response_code == FEED_ERR_INIT ) {
+		debug_print("RSSyl: libfeed reports init error from libcurl\n");
+		ctx->error = g_strdup("Internal error");
+	} else if( ctx->response_code == FEED_ERR_FETCH ) {
+		debug_print("RSSyl: libfeed reports some other error from libcurl\n");
+		ctx->error = g_strdup(ctx->feed->fetcherr);
+	} else if( ctx->response_code >= 400 && ctx->response_code < 500 ) {
+		switch( ctx->response_code ) {
+			case 401:
+				ctx->error = g_strdup(_("401 (Authorisation required)"));
+				break;
+			case 403:
+				ctx->error = g_strdup(_("403 (Unauthorised)"));
+				break;
+			case 404:
+				ctx->error = g_strdup(_("404 (Not found)"));
+				break;
+			default:
+				ctx->error = g_strdup_printf(_("Error %d"), ctx->response_code);
+				break;
+		}
+	}
+
+	/* Here we handle "imperfect" conditions. If verbose is TRUE, we also
+	 * display error dialogs for user. We always log the error. */
+	if( ctx->error != NULL ) {
+		/* libcurl wasn't happy */
+		debug_print("RSSyl: Error: %s\n", ctx->error);
+		if( verbose )
+			alertpanel_error(C_("First parameter is URL, second is error text",
+						"Error fetching feed at\n<b>%s</b>:\n\n%s"),
+					feed_get_url(ctx->feed), ctx->error);
+
+		log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_FETCH, ctx->feed->url, ctx->error);
+
+		ctx->success = FALSE;
+	} else {
+		if( ctx->feed == NULL || feed_get_title(ctx->feed) == NULL ) {
+			/* libcurl was happy, but libfeed wasn't */
+			debug_print("RSSyl: Error reading feed\n");
+			if( verbose )
+				alertpanel_error(_("No valid feed found at\n<b>%s</b>"),
+							feed_get_url(ctx->feed));
+			log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_NOFEED, ctx->feed->url);
+			ctx->success = FALSE;
+		}
+	}
+}
+
+RFetchCtx *rssyl_prep_fetchctx_from_item(RFolderItem *ritem)
+{
+	RFetchCtx *ctx = NULL;
+
+	g_return_val_if_fail(ritem != NULL, NULL);
+
+	ctx = g_new0(RFetchCtx, 1);
+	ctx->feed = feed_new(ritem->url);
+	ctx->error = NULL;
+	ctx->success = TRUE;
+	ctx->ready = FALSE;
+
+	feed_set_timeout(ctx->feed, prefs_common.io_timeout_secs);
+	feed_set_cookies_path(ctx->feed, rssyl_prefs_get()->cookies_path);
+	feed_set_ssl_verify_peer(ctx->feed, ritem->ssl_verify_peer);
+
+	return ctx;
+}
+
+RFetchCtx *rssyl_prep_fetchctx_from_url(gchar *url)
+{
+	RFetchCtx *ctx = NULL;
+
+	g_return_val_if_fail(url != NULL, NULL);
+
+	ctx = g_new0(RFetchCtx, 1);
+	ctx->feed = feed_new(url);
+	ctx->error = NULL;
+	ctx->success = TRUE;
+	ctx->ready = FALSE;
+
+	feed_set_timeout(ctx->feed, prefs_common.io_timeout_secs);
+	feed_set_cookies_path(ctx->feed, rssyl_prefs_get()->cookies_path);
+	feed_set_ssl_verify_peer(ctx->feed, rssyl_prefs_get()->ssl_verify_peer);
+
+	return ctx;
+}
+
+/* rssyl_update_feed() */
+
+gboolean rssyl_update_feed(RFolderItem *ritem, gboolean verbose)
+{
+	RFetchCtx *ctx = NULL;
+	MainWindow *mainwin = mainwindow_get_mainwindow();
+	gchar *msg = NULL;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail(ritem != NULL, FALSE);
+	g_return_val_if_fail(ritem->url != NULL, FALSE);
+
+	debug_print("RSSyl: starting to update '%s' (%s)\n",
+			ritem->item.name, ritem->url);
+
+	log_print(LOG_PROTOCOL, RSSYL_LOG_UPDATING, ritem->url);
+
+	msg = g_strdup_printf(_("Updating feed '%s'..."), ritem->item.name);
+	STATUSBAR_PUSH(mainwin, msg);
+	g_free(msg);
+
+	GTK_EVENTS_FLUSH();
+
+	/* Prepare context for fetching the feed file */
+	ctx = rssyl_prep_fetchctx_from_item(ritem);
+	g_return_val_if_fail(ctx != NULL, FALSE);
+
+	/* Fetch the feed file */
+	rssyl_fetch_feed(ctx, verbose);
+
+	debug_print("RSSyl: fetch done; success == %s\n",
+			ctx->success ? "TRUE" : "FALSE");
+
+	debug_print("RSSyl: STARTING TO PARSE FEED\n");
+  if( ctx->success && !(ctx->success = rssyl_parse_feed(ritem, ctx->feed)) ) {
+		/* both libcurl and libfeed were happy, but we weren't */
+		debug_print("RSSyl: Error processing feed\n");
+		if( verbose )
+			alertpanel_error(_("Couldn't process feed at\n<b>%s</b>\n\nPlease contact developers, this should not happen."),
+					feed_get_url(ctx->feed));
+
+		log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_PROC, ctx->feed->url);
+	}
+	
+	debug_print("RSSyl: FEED PARSED\n");
+
+	STATUSBAR_POP(mainwin);
+
+	if( claws_is_exiting() ) {
+		feed_free(ctx->feed);
+		g_free(ctx->error);
+		g_free(ctx);
+		return success;
+	}
+
+	if( ritem->fetch_comments )
+		rssyl_update_comments(ritem);
+
+	/* Prune our deleted items list of items which are no longer in
+	 * upstream feed. */
+	rssyl_deleted_expire(ritem, ctx->feed);
+
+	/* Clean up. */
+	success = ctx->success;
+	feed_free(ctx->feed);
+	g_free(ctx->error);
+	g_free(ctx);
+
+	return success;
+}
+
+static gboolean rssyl_update_recursively_func(GNode *node, gpointer data)
+{
+	FolderItem *item;
+	RFolderItem *ritem;
+
+	g_return_val_if_fail(node->data != NULL, FALSE);
+
+	item = FOLDER_ITEM(node->data);
+	ritem = (RFolderItem *)item;
+
+	if( ritem->url != NULL ) {
+		debug_print("RSSyl: Updating feed '%s'\n", item->name);
+		rssyl_update_feed(ritem, FALSE);
+	} else
+		debug_print("RSSyl: Updating in folder '%s'\n", item->name);
+
+	return FALSE;
+}
+
+void rssyl_update_recursively(FolderItem *item)
+{
+	g_return_if_fail(item != NULL);
+	g_return_if_fail(item->folder != NULL);
+
+	if( item->folder->klass != rssyl_folder_get_class() )
+		return;
+
+	debug_print("Recursively updating '%s'\n", item->name);
+
+	g_node_traverse(item->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+			rssyl_update_recursively_func, NULL);
+}
+
+void rssyl_update_all_func(FolderItem *item, gpointer data)
+{
+	/* Only try to refresh our feed folders */
+	if( !IS_RSSYL_FOLDER_ITEM(item) )
+		return;
+
+	if( folder_item_parent(item) == NULL )
+		rssyl_update_recursively(item);
+}
+
+void rssyl_update_all_feeds(void)
+{
+	if (prefs_common.work_offline &&
+			!inc_offline_should_override(TRUE,
+				_("Claws Mail needs network access in order to update your feeds.")) ) {
+		return;
+	}
+
+	folder_func_to_all_folders((FolderItemFunc)rssyl_update_all_func, NULL);
+}
diff --git a/src/plugins/rssyl/rssyl_update_feed.h b/src/plugins/rssyl/rssyl_update_feed.h
new file mode 100644
index 0000000..f72d04a
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_update_feed.h
@@ -0,0 +1,19 @@
+#ifndef __RSSYL_UPDATE_FEED
+#define __RSSYL_UPDATE_FEED
+
+#include <glib.h>
+
+#include "rssyl.h"
+
+void rssyl_fetch_feed(RFetchCtx *ctx, gboolean verbose);
+
+RFetchCtx *rssyl_prep_fetchctx_from_url(gchar *url);
+RFetchCtx *rssyl_prep_fetchctx_from_item(RFolderItem *ritem);
+
+gboolean rssyl_update_feed(RFolderItem *ritem, gboolean verbose);
+
+void rssyl_update_recursively(FolderItem *item);
+
+void rssyl_update_all_feeds(void);
+
+#endif /* __RSSYL_UPDATE_FEED */
diff --git a/src/plugins/rssyl/rssyl_update_format.c b/src/plugins/rssyl/rssyl_update_format.c
new file mode 100644
index 0000000..8284450
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_update_format.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+/* Global includes */
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+/* Claws Mail includes */
+#include <alertpanel.h>
+#include <log.h>
+#include <mainwindow.h>
+
+/* Local includes */
+#include "old_feeds.h"
+#include "rssyl.h"
+#include "rssyl_feed.h"
+#include "strutils.h"
+
+struct _RUpdateFormatCtx {
+	FolderItem *o_prev;
+	FolderItem *o_parent;
+	FolderItem *n_prev;
+	FolderItem *n_parent;
+	Folder *n_first;
+	GSList *oldfeeds;
+	GSList *oldroots;
+	gboolean reached_first_new;
+};
+
+typedef struct _RUpdateFormatCtx RUpdateFormatCtx;
+
+extern FolderClass rssyl_class;
+
+static void rssyl_update_format_move_contents(FolderItem *olditem,
+		FolderItem *newitem);
+static gchar *_old_rssyl_item_get_path(Folder *folder, FolderItem *item);
+static void _delete_old_roots_func(gpointer data, gpointer user_data);
+
+static void rssyl_update_format_func(FolderItem *item, gpointer data)
+{
+	RFolderItem *ritem;
+	RUpdateFormatCtx *ctx = (RUpdateFormatCtx *)data;
+	Folder *f = NULL;
+	FolderItem *new_item = NULL;
+	gchar *name;
+	OldRFeed *of;
+
+	if( !IS_RSSYL_FOLDER_ITEM(item) )
+		return;
+
+	/* Do not do anything once we reached first new folder
+	 * (which we created earlier in this process) */
+	if( ctx->reached_first_new )
+		return;
+
+	if( item->folder == ctx->n_first ) {
+		ctx->reached_first_new = TRUE;
+		debug_print("RSSyl: (FORMAT) reached first new folder\n");
+		return;
+	}
+
+	debug_print("RSSyl: (FORMAT) item '%s'\n", item->name);
+
+	if( folder_item_parent(item) == NULL ) {
+		/* Root rssyl folder */
+		ctx->oldroots = g_slist_prepend(ctx->oldroots, item);
+
+		/* Create its counterpart */
+		name = rssyl_strreplace(folder_item_get_name(item), " (RSSyl)", "");
+		debug_print("RSSyl: (FORMAT) adding new root folder '%s'\n", name);
+		f = folder_new(rssyl_folder_get_class(), name, NULL);
+		g_free(name);
+		g_return_if_fail(f != NULL);
+		folder_add(f);
+
+		folder_write_list();
+
+		new_item = FOLDER_ITEM(f->node->data);
+
+		/* If user has more than one old rssyl foldertrees, keep the n_first
+		 * pointer at the beginning of first one. */
+		if (ctx->n_first == NULL)
+			ctx->n_first = f;
+
+		ctx->n_parent = new_item;
+	} else {
+		/* Non-root folder */
+
+		if (folder_item_parent(item) == ctx->o_prev) {
+			/* We went one step deeper in folder hierarchy, adjust pointers
+			 * to parents */
+			ctx->o_parent = ctx->o_prev;
+			ctx->n_parent = ctx->n_prev;
+		} else if (folder_item_parent(item) != ctx->o_parent) {
+			/* We are not in same folder anymore, which can only mean we have
+			 * moved up in the hierarchy. Find a correct parent */
+			while (folder_item_parent(item) != ctx->o_parent) {
+				ctx->o_parent = folder_item_parent(ctx->o_parent);
+				ctx->n_parent = folder_item_parent(ctx->n_parent);
+				if (ctx->o_parent == NULL) {
+					/* This shouldn't happen, unless we are magically moved to a
+					 * completely different folder structure */
+					debug_print("RSSyl: MISHAP WHILE UPGRADING STORAGE FORMAT: couldn't find folder parent\n");
+					alertpanel_error(_("Internal problem while upgrading storage format. This should not happen. Please report this, with debug output attached.\n"));
+					return;
+				}
+			}
+		} else {
+			/* We have remained in the same subfolder, nothing to do here */
+		}
+
+		debug_print("RSSyl: (FORMAT) adding folder '%s'\n", item->name);
+		new_item = folder_create_folder(ctx->n_parent, item->name);
+
+		if (new_item == NULL) {
+			debug_print("RSSyl: (FORMAT) couldn't add folder '%s', skipping it\n",
+					item->name);
+			return;
+		}
+
+		of = rssyl_old_feed_get_by_name(ctx->oldfeeds, item->name);
+		if (of != NULL && of->url != NULL) {
+			/* Folder with an actual subscribed feed */
+			debug_print("RSSyl: (FORMAT) making '%s' a feed with URL '%s'\n",
+					item->name, of->url);
+
+			ritem = (RFolderItem *)new_item;
+			ritem->url = g_strdup(of->url);
+
+			rssyl_feed_start_refresh_timeout(ritem);
+
+			/* TODO: copy feed preferences from old structure */
+			ritem->official_title = g_strdup(of->official_name);
+			ritem->default_refresh_interval =
+				(of->default_refresh_interval != 0 ? TRUE : FALSE);
+			ritem->refresh_interval = of->refresh_interval;
+			ritem->keep_old = (of->expired_num > -1 ? TRUE : FALSE);
+			ritem->fetch_comments =
+				(of->fetch_comments != 0 ? TRUE : FALSE);
+			ritem->fetch_comments_max_age = of->fetch_comments_for;
+			ritem->silent_update = of->silent_update;
+		}
+
+		rssyl_update_format_move_contents(item, new_item);
+
+		/* Store folderlist with the new folder */
+		folder_item_scan(new_item);
+		folder_write_list();
+	}
+
+	ctx->o_prev = item;
+	ctx->n_prev = new_item;
+}
+
+
+void rssyl_update_format()
+{
+	RUpdateFormatCtx *ctx = NULL;
+	GSList *oldfeeds;
+	gchar *old_feeds_xml = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+			RSSYL_DIR, G_DIR_SEPARATOR_S, "feeds.xml", NULL);
+
+	if (!g_file_test(old_feeds_xml,
+				G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+		g_free(old_feeds_xml);
+		return;
+	}
+
+	debug_print("RSSyl: Old format found, updating.\n");
+
+	oldfeeds = rssyl_old_feed_metadata_parse(old_feeds_xml);
+
+	/* We find all rssyl root folders and perform magic on each */
+	ctx = g_new0(RUpdateFormatCtx, 1);
+	ctx->o_prev = NULL;
+	ctx->o_parent = NULL;
+	ctx->n_prev = NULL;
+	ctx->n_parent = NULL;
+	ctx->n_first = NULL;
+	ctx->oldfeeds = oldfeeds;
+	ctx->oldroots = NULL;
+	ctx->reached_first_new = FALSE;
+
+	folder_item_update_freeze();
+
+	/* Go through all RSSyl folders, making new copies */
+	folder_func_to_all_folders((FolderItemFunc)rssyl_update_format_func, ctx);
+
+	g_slist_foreach(ctx->oldroots, _delete_old_roots_func, NULL);
+	g_slist_free(ctx->oldroots);
+
+	folder_item_update_thaw();
+
+	g_free(ctx);
+
+	g_remove(old_feeds_xml);
+	g_free(old_feeds_xml);
+}
+
+static void _delete_old_roots_func(gpointer data, gpointer user_data)
+{
+	FolderItem *item = (FolderItem *)data;
+
+	folder_destroy(item->folder);
+}
+
+/* Copy each item in a feed to the new directory */
+static void rssyl_update_format_move_contents(FolderItem *olditem,
+		FolderItem *newitem)
+{
+	gchar *oldpath, *newpath, *fname, *fpath, *nfpath;
+	GDir *d = NULL;
+	GError *error = NULL;
+
+	oldpath = _old_rssyl_item_get_path(NULL, olditem);
+	newpath = folder_item_get_path(newitem);
+
+	if ((d = g_dir_open(oldpath, 0, &error)) == NULL) {
+		debug_print("RSSyl: (FORMAT) couldn't open dir '%s': %s\n", oldpath,
+				error->message);
+		g_error_free(error);
+		return;
+	}
+
+	debug_print("RSSyl: (FORMAT) moving contents of '%s' to '%s'\n",
+			oldpath, newpath);
+
+	while ((fname = (gchar *)g_dir_read_name(d)) != NULL) {
+		fpath = g_strconcat(oldpath, G_DIR_SEPARATOR_S, fname, NULL);
+		if (to_number(fname) > 0 && g_file_test(fpath, G_FILE_TEST_IS_REGULAR)) {
+			nfpath = g_strconcat(newpath, G_DIR_SEPARATOR_S, fname, NULL);
+			move_file(fpath, nfpath, FALSE);
+			g_free(nfpath);
+		}
+		g_remove(fpath);
+		g_free(fpath);
+	}
+
+	g_dir_close(d);
+	g_rmdir(oldpath);
+
+	g_free(oldpath);
+	g_free(newpath);
+}
+
+static gchar *_old_rssyl_item_get_path(Folder *folder, FolderItem *item)
+{
+	gchar *result, *tmp;
+
+	if (folder_item_parent(item) == NULL)
+		return g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR, NULL);
+
+	tmp = rssyl_strreplace(item->name, "/", "\\");
+	result = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
+			G_DIR_SEPARATOR_S, tmp, NULL);
+	g_free(tmp);
+	return result;
+}
diff --git a/src/plugins/rssyl/rssyl_update_format.h b/src/plugins/rssyl/rssyl_update_format.h
new file mode 100644
index 0000000..7e3a858
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_update_format.h
@@ -0,0 +1,6 @@
+#ifndef __RSSYL_UPDATE_FORMAT
+#define __RSSYL_UPDATE_FORMAT
+
+void rssyl_update_format();
+
+#endif /* __RSSYL_UPDATE_FORMAT */
diff --git a/src/plugins/rssyl/strreplace.c b/src/plugins/rssyl/strreplace.c
deleted file mode 100644
index 7d4322c..0000000
--- a/src/plugins/rssyl/strreplace.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2005 Andrej Kacian <andrej at kacian.sk>
- *
- * - a strreplace function (something like sed's s/foo/bar/g)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include <glib.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-#include "common/utils.h"
-
-gchar *rssyl_strreplace(const gchar *source, gchar *pattern,
-			gchar *replacement)
-{
-	gchar *new, *w_new;
-	const gchar *c;
-	guint count = 0, final_length;
-	size_t len_pattern, len_replacement;
-
-/*
-	debug_print("RSSyl: ======= strreplace: '%s': '%s'->'%s'\n", source, pattern,
-			replacement);
-*/
-
-	if( source == NULL || pattern == NULL ) {
-		debug_print("RSSyl: source or pattern is NULL!!!\n");
-		return NULL;
-	}
-
-	if( !g_utf8_validate(source, -1, NULL) ) {
-		debug_print("RSSyl: source is not an UTF-8 encoded text\n");
-		return NULL;
-	}
-
-	if( !g_utf8_validate(pattern, -1, NULL) ) {
-		debug_print("RSSyl: pattern is not an UTF-8 encoded text\n");
-		return NULL;
-	}
-
-	len_pattern = strlen(pattern);
-	len_replacement = strlen(replacement);
-
-	c = source;
-	while( ( c = g_strstr_len(c, strlen(c), pattern) ) ) {
-		count++;
-		c += len_pattern;
-	}
-
-/*
-	debug_print("RSSyl: ==== count = %d\n", count);
-*/
-
-	final_length = strlen(source)
-		- ( count * len_pattern )
-		+ ( count * len_replacement );
-
-	new = malloc(final_length + 1);
-	w_new = new;
-	memset(new, '\0', final_length + 1);
-
-	c = source;
-
-	while( *c != '\0' ) {
-		if( !memcmp(c, pattern, len_pattern) ) {
-			gboolean break_after_rep = FALSE;
-			int i;
-			if (*(c + len_pattern) == '\0')
-				break_after_rep = TRUE;
-			for (i = 0; i < len_replacement; i++) {
-				*w_new = replacement[i];
-				w_new++;
-			}
-			if (break_after_rep)
-				break;
-			c = c + len_pattern;
-		} else {
-			*w_new = *c;
-			w_new++;
-			c++;
-		}
-	}
-	return new;
-}
-
-gchar *rssyl_sanitize_string(const gchar *str, gboolean strip_nl)
-{
-	gchar *new = NULL;
-	const gchar *c = str;
-	gchar *new_ptr;
-	if( str == NULL )
-		return NULL;
-
-	new_ptr = new = malloc(strlen(str) + 1);
-	if (new == NULL)
-		return NULL;
-	memset(new, '\0', strlen(str) + 1);
-
-	while( *c != '\0' ) {
-		if( !g_ascii_isspace(*c) || *c == ' ' || (!strip_nl && *c == '\n') ) {
-			*new_ptr = *c;
-			new_ptr++;
-		}
-		c++;
-	}
-
-	return new;
-}
diff --git a/src/plugins/rssyl/strreplace.h b/src/plugins/rssyl/strreplace.h
deleted file mode 100644
index 37c29dc..0000000
--- a/src/plugins/rssyl/strreplace.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __STRREPLACE_H
-#define __STRREPLACE_H
-
-gchar *rssyl_strreplace(const gchar *source, gchar *pattern,
-			gchar *replacement);
-gchar *rssyl_sanitize_string(const gchar *str, gboolean strip_nl);
-
-#endif /* __STRREPLACE_H */
diff --git a/src/plugins/rssyl/strutils.c b/src/plugins/rssyl/strutils.c
new file mode 100644
index 0000000..3d9f1c5
--- /dev/null
+++ b/src/plugins/rssyl/strutils.c
@@ -0,0 +1,289 @@
+/*
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2005 Andrej Kacian <andrej at kacian.sk>
+ *
+ * - a strreplace function (something like sed's s/foo/bar/g)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+/* Claws Mail includes */
+#include <common/utils.h>
+
+/* Local includes */
+/* (shouldn't be any) */
+
+gchar *rssyl_strreplace(gchar *source, gchar *pattern,
+		gchar *replacement)
+{
+	gchar *new, *w_new = NULL, *c;
+	guint count = 0, final_length;
+	size_t len_pattern, len_replacement;
+
+	/*
+	debug_print("RSSyl: ======= strreplace: '%s': '%s'->'%s'\n", source, pattern,
+			replacement);
+	*/
+
+	if( source == NULL || pattern == NULL ) {
+		debug_print("RSSyl: source or pattern is NULL!!!\n");
+		return source;
+	}
+
+	if( !g_utf8_validate(source, -1, NULL) ) {
+		debug_print("RSSyl: source is not an UTF-8 encoded text\n");
+		return source;
+	}
+
+	if( !g_utf8_validate(pattern, -1, NULL) ) {
+		debug_print("RSSyl: pattern is not an UTF-8 encoded text\n");
+		return source;
+	}
+
+	len_pattern = strlen(pattern);
+	len_replacement = strlen(replacement);
+
+	c = source;
+	while( ( c = g_strstr_len(c, strlen(c), pattern) ) ) {
+		count++;
+		c += len_pattern;
+	}
+
+	/*
+	debug_print("RSSyl: ==== count = %d\n", count);
+	*/
+
+	final_length = strlen(source)
+		- ( count * len_pattern )
+		+ ( count * len_replacement );
+
+	new = malloc(final_length + 1);
+	w_new = new;
+	memset(new, '\0', final_length + 1);
+
+	c = source;
+
+	while( *c != '\0' ) {
+		if( !memcmp(c, pattern, len_pattern) ) {
+			gboolean break_after_rep = FALSE;
+			int i;
+			if (*(c + len_pattern) == '\0')
+				break_after_rep = TRUE;
+			for (i = 0; i < len_replacement; i++) {
+				*w_new = replacement[i];
+				w_new++;
+			}
+			if (break_after_rep)
+				break;
+			c = c + len_pattern;
+		} else {
+			*w_new = *c;
+			w_new++;
+			c++;
+		}
+	}
+	return new;
+}
+
+typedef struct _RSSyl_HTMLSymbol RSSyl_HTMLSymbol;
+struct _RSSyl_HTMLSymbol
+{
+	gchar *const key;
+	gchar *const val;
+};
+
+static RSSyl_HTMLSymbol symbol_list[] = {
+	{ "<", "<" },
+	{ ">", ">" },
+	{ "&", "&" },
+	{ """, "\"" },
+	{ "‘",  "'" },
+	{ "’",  "'" },
+	{ "“",  "\"" },
+	{ "”",  "\"" },
+	{ " ", " " },
+	{ "™", "(TM)" },
+	{ "™", "(TM)" },
+	{ "'", "'" },
+	{ "…", "..." },
+	{ "…", "..." },
+	{ "—", "-" },
+	{ NULL, NULL }
+};
+
+static RSSyl_HTMLSymbol tag_list[] = {
+	{ "<cite>", "\"" },
+	{ "</cite>", "\"" },
+	{ "<i>", "" },
+	{ "</i>", "" },
+	{ "<em>", "" },
+	{ "</em>", "" },
+	{ "<b>", "" },
+	{ "</b>", "" },
+	{ "<nobr>", "" },
+	{ "</nobr>", "" },
+	{ "<wbr>", "" },
+	{ NULL, NULL }
+};
+
+gchar *rssyl_replace_html_stuff(gchar *text,
+		gboolean symbols, gboolean tags)
+{
+	gchar *tmp = NULL, *wtext = NULL;
+	gint i;
+
+	g_return_val_if_fail(text != NULL, NULL);
+
+	wtext = g_strdup(text);
+
+	/* Ugly, needlessly traverses the string again and again. Probably
+	 * could use a rewrite. */
+	if( symbols ) {
+		for( i = 0; symbol_list[i].key != NULL; i++ ) {
+			if( g_strstr_len(text, strlen(text), symbol_list[i].key) ) {
+				tmp = rssyl_strreplace(wtext, symbol_list[i].key, symbol_list[i].val);
+				wtext = g_strdup(tmp);
+				g_free(tmp);
+			}
+		}
+	}
+
+	if( tags ) {
+		for( i = 0; tag_list[i].key != NULL; i++ ) {
+			if( g_strstr_len(text, strlen(text), symbol_list[i].key) ) {
+				tmp = rssyl_strreplace(wtext, tag_list[i].key, tag_list[i].val);
+				wtext = g_strdup(tmp);
+				g_free(tmp);
+			}
+		}
+	}
+
+	return wtext;
+}
+
+static gchar *rssyl_sanitize_string(gchar *str, gboolean strip_nl)
+{
+	gchar *new = NULL, *c = str, *n = NULL;
+
+	if( str == NULL )
+		return NULL;
+
+	n = new = malloc(strlen(str) + 1);
+	memset(new, '\0', strlen(str) + 1);
+
+	while( *c != '\0' ) {
+		if( !isspace(*c) || *c == ' ' || (!strip_nl && *c == '\n') ) {
+			*n = *c;
+			n++;
+		}
+		c++;
+	}
+
+	return new;
+}
+
+/* rssyl_format_string()
+ * - return value needs to be freed
+ */
+gchar *rssyl_format_string(gchar *str, gboolean replace_html,
+		gboolean strip_nl)
+{
+	gchar *res = NULL, *tmp = NULL;
+
+	g_return_val_if_fail(str != NULL, NULL);
+
+	if (replace_html)
+		tmp = rssyl_replace_html_stuff(str, TRUE, TRUE);
+	else
+		tmp = g_strdup(str);
+
+	res = rssyl_sanitize_string(tmp, strip_nl);
+	g_free(tmp);
+
+	g_strstrip(res);
+
+	return res;
+}
+
+/* this functions splits a string into an array of string, by 
+ * returning an array of pointers to positions of the delimiter
+ * in the original string and replacing this delimiter with a
+ * NULL. It does not duplicate memory, hence you should only
+ * free the array and not its elements, and you should not
+ * free the original string before you're done with the array.
+ * maybe could be part of the core (utils.c).
+ */
+gchar **strsplit_no_copy(gchar *str, char delimiter)
+{
+	gchar **array = g_new(gchar *, 1);
+	int i = 0;
+	gchar *cur = str, *next;
+	
+	array[i] = cur;
+	i++;
+	while ((next = strchr(cur, delimiter)) != NULL) {
+		*(next) = '\0';
+		array = g_realloc(array, (sizeof(gchar *)) * (i + 1));
+		array[i] = next + 1;
+		cur = next + 1;
+		i++;
+	}
+	array = g_realloc(array, (sizeof(gchar *)) * (i + 1));
+	array[i] = NULL;
+	return array;
+}
+
+/* This is a very dumb function - it just strips <, > and everything between
+ * them. */
+void strip_html(gchar *str)
+{
+	gchar *p = str;
+	gboolean intag = FALSE;
+
+	while (*p) {
+		if (*p == '<')
+			intag = TRUE;
+		else if (*p == '>')
+			intag = FALSE;
+
+		if (*p == '<' || *p == '>' || intag)
+			memmove(p, p + 1, strlen(p));
+		else
+			p++;
+	}
+}
+
+gchar *my_normalize_url(const gchar *url)
+{
+	gchar *myurl = NULL;
+
+	if (!strncmp(url, "feed://", 7))
+		myurl = g_strdup(url+7);
+	else if (!strncmp(url, "feed:", 5))
+		myurl = g_strdup(url+5);
+	else
+		myurl = g_strdup(url);
+
+	return myurl;
+}
diff --git a/src/plugins/rssyl/strutils.h b/src/plugins/rssyl/strutils.h
new file mode 100644
index 0000000..2976e6f
--- /dev/null
+++ b/src/plugins/rssyl/strutils.h
@@ -0,0 +1,19 @@
+#ifndef __STRUTILS_H
+#define __STRUTILS_H
+
+gchar *rssyl_strreplace(gchar *source, gchar *pattern,
+		gchar *replacement);
+
+gchar *rssyl_replace_html_stuff(gchar *text,
+		gboolean symbols, gboolean tags);
+
+gchar *rssyl_format_string(gchar *str, gboolean replace_html,
+		gboolean strip_nl);
+
+gchar **strsplit_no_copy(gchar *str, char delimiter);
+
+void strip_html(gchar *str);
+
+gchar *my_normalize_url(const gchar *url);
+
+#endif /* __STRUTILS_H */

-----------------------------------------------------------------------


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list