New RSSyl replacing old one.
authorAndrej Kacian <ticho@claws-mail.org>
Sun, 1 Jun 2014 22:24:21 +0000 (00:24 +0200)
committerAndrej Kacian <andrej@kacian.sk>
Tue, 17 Jun 2014 12:24:01 +0000 (14:24 +0200)
71 files changed:
configure.ac
po/POTFILES.in
src/plugins/rssyl/Makefile.am
src/plugins/rssyl/feed.c [deleted file]
src/plugins/rssyl/feed.h [deleted file]
src/plugins/rssyl/feedprops.c [deleted file]
src/plugins/rssyl/feedprops.h [deleted file]
src/plugins/rssyl/libfeed/Makefile.am [new file with mode: 0644]
src/plugins/rssyl/libfeed/date.c [moved from src/plugins/rssyl/date.c with 76% similarity]
src/plugins/rssyl/libfeed/date.h [moved from src/plugins/rssyl/date.h with 82% similarity]
src/plugins/rssyl/libfeed/feed.c [new file with mode: 0644]
src/plugins/rssyl/libfeed/feed.h [new file with mode: 0644]
src/plugins/rssyl/libfeed/feeditem.c [new file with mode: 0644]
src/plugins/rssyl/libfeed/feeditem.h [new file with mode: 0644]
src/plugins/rssyl/libfeed/feeditemenclosure.c [new file with mode: 0644]
src/plugins/rssyl/libfeed/feeditemenclosure.h [new file with mode: 0644]
src/plugins/rssyl/libfeed/parser.c [new file with mode: 0644]
src/plugins/rssyl/libfeed/parser.h [new file with mode: 0644]
src/plugins/rssyl/libfeed/parser_atom10.c [new file with mode: 0644]
src/plugins/rssyl/libfeed/parser_atom10.h [new file with mode: 0644]
src/plugins/rssyl/libfeed/parser_opml.c [new file with mode: 0644]
src/plugins/rssyl/libfeed/parser_opml.h [new file with mode: 0644]
src/plugins/rssyl/libfeed/parser_rdf.c [new file with mode: 0644]
src/plugins/rssyl/libfeed/parser_rdf.h [new file with mode: 0644]
src/plugins/rssyl/libfeed/parser_rss20.c [new file with mode: 0644]
src/plugins/rssyl/libfeed/parser_rss20.h [new file with mode: 0644]
src/plugins/rssyl/old_feeds.c [new file with mode: 0644]
src/plugins/rssyl/old_feeds.h [new file with mode: 0644]
src/plugins/rssyl/opml_export.c [moved from src/plugins/rssyl/opml.c with 50% similarity]
src/plugins/rssyl/opml_export.h [moved from src/plugins/rssyl/opml.h with 64% similarity]
src/plugins/rssyl/opml_import.c [new file with mode: 0644]
src/plugins/rssyl/opml_import.h [new file with mode: 0644]
src/plugins/rssyl/parse822.c [new file with mode: 0644]
src/plugins/rssyl/parse822.h [new file with mode: 0644]
src/plugins/rssyl/parsers.c [deleted file]
src/plugins/rssyl/parsers.h [deleted file]
src/plugins/rssyl/plugin.c
src/plugins/rssyl/rssyl.c
src/plugins/rssyl/rssyl.h
src/plugins/rssyl/rssyl_add_item.c [new file with mode: 0644]
src/plugins/rssyl/rssyl_add_item.h [new file with mode: 0644]
src/plugins/rssyl/rssyl_cb_gtk.c [deleted file]
src/plugins/rssyl/rssyl_cb_gtk.h [deleted file]
src/plugins/rssyl/rssyl_cb_menu.c
src/plugins/rssyl/rssyl_cb_menu.h
src/plugins/rssyl/rssyl_deleted.c [new file with mode: 0644]
src/plugins/rssyl/rssyl_deleted.h [new file with mode: 0644]
src/plugins/rssyl/rssyl_feed.c [new file with mode: 0644]
src/plugins/rssyl/rssyl_feed.h [new file with mode: 0644]
src/plugins/rssyl/rssyl_feed_props.c [new file with mode: 0644]
src/plugins/rssyl/rssyl_feed_props.h [new file with mode: 0644]
src/plugins/rssyl/rssyl_gtk.c
src/plugins/rssyl/rssyl_gtk.h
src/plugins/rssyl/rssyl_parse_feed.c [new file with mode: 0644]
src/plugins/rssyl/rssyl_parse_feed.h [new file with mode: 0644]
src/plugins/rssyl/rssyl_prefs.c
src/plugins/rssyl/rssyl_prefs.h
src/plugins/rssyl/rssyl_subscribe.c [new file with mode: 0644]
src/plugins/rssyl/rssyl_subscribe.h [new file with mode: 0644]
src/plugins/rssyl/rssyl_subscribe_gtk.c [new file with mode: 0644]
src/plugins/rssyl/rssyl_subscribe_gtk.h [new file with mode: 0644]
src/plugins/rssyl/rssyl_update_comments.c [new file with mode: 0644]
src/plugins/rssyl/rssyl_update_comments.h [new file with mode: 0644]
src/plugins/rssyl/rssyl_update_feed.c [new file with mode: 0644]
src/plugins/rssyl/rssyl_update_feed.h [new file with mode: 0644]
src/plugins/rssyl/rssyl_update_format.c [new file with mode: 0644]
src/plugins/rssyl/rssyl_update_format.h [new file with mode: 0644]
src/plugins/rssyl/strreplace.c [deleted file]
src/plugins/rssyl/strreplace.h [deleted file]
src/plugins/rssyl/strutils.c [new file with mode: 0644]
src/plugins/rssyl/strutils.h [new file with mode: 0644]

index 8b7c47a..612b555 100644 (file)
@@ -1056,7 +1056,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
 
@@ -1065,10 +1065,15 @@ 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=no
+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
+       HAVE_EXPAT=yes
+       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)
@@ -1722,8 +1727,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"
@@ -1924,6 +1929,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
index 3ebe982..31cd537 100644 (file)
@@ -164,14 +164,23 @@ src/plugins/python/claws-mail-python.metainfo.xml.in
 src/plugins/python/composewindowtype.c
 src/plugins/python/python_plugin.c
 src/plugins/rssyl/claws-mail-rssyl.metainfo.xml.in
-src/plugins/rssyl/feed.c
-src/plugins/rssyl/feed.h
+src/plugins/rssyl/old_feeds.c
+src/plugins/rssyl/opml_import.c
 src/plugins/rssyl/plugin.c
+src/plugins/rssyl/rssyl_add_item.c
 src/plugins/rssyl/rssyl.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/claws-mail-smime.metainfo.xml.in
 src/plugins/smime/plugin.c
 src/plugins/smime/smime.c
index 9eaf574..949efd3 100644 (file)
@@ -2,6 +2,8 @@
 # This file is part of Claws Mail package.
 # See COPYING file for license details.
 
+SUBDIRS = libfeed
+
 appdata_in_files = claws-mail-rssyl.metainfo.xml.in
 appdatadir=$(datadir)/appdata
 appdata_DATA = $(appdata_in_files:.xml.in=.xml)
@@ -68,29 +70,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 (file)
index 8542bc7..0000000
+++ /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@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[] = {
-       { "&lt;", "<" },
-       { "&gt;", ">" },
-       { "&amp;", "&" },
-       { "&quot;", "\"" },
-       { "&lsquo;",  "'" },
-       { "&rsquo;",  "'" },
-       { "&ldquo;",  "\"" },
-       { "&rdquo;",  "\"" },
-       { "&nbsp;", " " },
-       { "&trade;", "(TM)" },
-       { "&#153;", "(TM)" },
-       { "&#39;", "'" },
-       { "&hellip;", "..." },
-       { "&mdash;", "-" },
-       { "<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 (file)
index 1d66b7d..0000000
+++ /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 (file)
index d52bde5..0000000
+++ /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@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 (file)
index f4a3b27..0000000
+++ /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 (file)
index 0000000..227b25e
--- /dev/null
@@ -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
similarity index 76%
rename from src/plugins/rssyl/date.c
rename to src/plugins/rssyl/libfeed/date.c
index 4145f52..2b8ffff 100644 (file)
 #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>
 #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);
+}
similarity index 82%
rename from src/plugins/rssyl/date.h
rename to src/plugins/rssyl/libfeed/date.h
index 27c1353..c8ea1a6 100644 (file)
@@ -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 (file)
index 0000000..7719278
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej@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 (file)
index 0000000..dc8847d
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej@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 (file)
index 0000000..d04831b
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej@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 (file)
index 0000000..9125af4
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej@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 (file)
index 0000000..183cfb5
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej@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 (file)
index 0000000..ba4d127
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej@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 (file)
index 0000000..1ebc412
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej@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 (file)
index 0000000..f8cbb9a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej@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 (file)
index 0000000..59fba1c
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej@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 (file)
index 0000000..85e95b4
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej@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 (file)
index 0000000..09e34aa
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej@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 (file)
index 0000000..518b072
--- /dev/null
@@ -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 (file)
index 0000000..dc424c5
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej@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 (file)
index 0000000..1c3809f
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej@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 (file)
index 0000000..3882750
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej@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 (file)
index 0000000..27cc40c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej@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 (file)
index 0000000..45e6cf6
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2012 Andrej Kacian <andrej@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 (file)
index 0000000..b52cd86
--- /dev/null
@@ -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 */
similarity index 50%
rename from src/plugins/rssyl/opml.c
rename to src/plugins/rssyl/opml_export.c
index c71cf8b..7ec9369 100644 (file)
 #  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, "&", "&amp;");
-       if (ritem->official_name != NULL)
-               tmpoffn = rssyl_strreplace(item->name, "&", "&amp;");
-       else
-               tmpoffn = g_strdup(tmpname);
+        if( ritem->official_title != NULL )
+                tmpoffn = rssyl_strreplace(ritem->official_title, "&", "&amp;");
+        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);
-}
similarity index 64%
rename from src/plugins/rssyl/opml.h
rename to src/plugins/rssyl/opml_export.h
index 9a8aef2..6e89149 100644 (file)
@@ -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 (file)
index 0000000..2a34f5d
--- /dev/null
@@ -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@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 (file)
index 0000000..91b71aa
--- /dev/null
@@ -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 (file)
index 0000000..846fb6d
--- /dev/null
@@ -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@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 (file)
index 0000000..94318fc
--- /dev/null
@@ -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 (file)
index bc491ae..0000000
+++ /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@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 (file)
index 48321e6..0000000
+++ /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 */
index 9cf3cdc..7ade914 100644 (file)
@@ -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@kacian.sk>
  *
 
 #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)
index 670dd86..2c5a634 100644 (file)
@@ -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@kacian.sk>
  *
 
 #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);
+