[Commits] [SCM] claws branch, master, updated. 3.10.1-71-g72af590
ticho at claws-mail.org
ticho at claws-mail.org
Tue Jun 17 14:34:40 CEST 2014
The branch master of project "claws" (Claws Mail) has been updated
via 72af590ae944e16136d1dcbb2ea3e4f7c7fd44aa (commit)
via 332a84cc65e594093a0509791bc7a595edd850d5 (commit)
via 9e5668deae60da62525316de59d1f735062f1f79 (commit)
via 7b80f1f639341f9711d9b28b45de2939f1b55728 (commit)
from 822857b4d2c40faae26dc5444c5a5ecca1134c8e (commit)
Summary of changes:
configure.ac | 20 +-
po/POTFILES.in | 13 +-
src/plugins/rssyl/Makefile.am | 30 +-
src/plugins/rssyl/feed.c | 1869 -------------------------
src/plugins/rssyl/feed.h | 94 --
src/plugins/rssyl/feedprops.c | 433 ------
src/plugins/rssyl/feedprops.h | 26 -
src/plugins/rssyl/libfeed/Makefile.am | 22 +
src/plugins/rssyl/{ => libfeed}/date.c | 86 +-
src/plugins/rssyl/{ => libfeed}/date.h | 1 +
src/plugins/rssyl/libfeed/feed.c | 356 +++++
src/plugins/rssyl/libfeed/feed.h | 114 ++
src/plugins/rssyl/libfeed/feeditem.c | 372 +++++
src/plugins/rssyl/libfeed/feeditem.h | 114 ++
src/plugins/rssyl/libfeed/feeditemenclosure.c | 100 ++
src/plugins/rssyl/libfeed/feeditemenclosure.h | 43 +
src/plugins/rssyl/libfeed/parser.c | 359 +++++
src/plugins/rssyl/libfeed/parser.h | 45 +
src/plugins/rssyl/libfeed/parser_atom10.c | 230 +++
src/plugins/rssyl/libfeed/parser_atom10.h | 34 +
src/plugins/rssyl/libfeed/parser_opml.c | 131 ++
src/plugins/rssyl/libfeed/parser_opml.h | 23 +
src/plugins/rssyl/libfeed/parser_rdf.c | 144 ++
src/plugins/rssyl/libfeed/parser_rdf.h | 32 +
src/plugins/rssyl/libfeed/parser_rss20.c | 178 +++
src/plugins/rssyl/libfeed/parser_rss20.h | 26 +
src/plugins/rssyl/old_feeds.c | 168 +++
src/plugins/rssyl/old_feeds.h | 23 +
src/plugins/rssyl/{opml.c => opml_export.c} | 156 +--
src/plugins/rssyl/{opml.h => opml_export.h} | 1 -
src/plugins/rssyl/opml_import.c | 110 ++
src/plugins/rssyl/opml_import.h | 15 +
src/plugins/rssyl/parse822.c | 352 +++++
src/plugins/rssyl/parse822.h | 19 +
src/plugins/rssyl/parsers.c | 535 -------
src/plugins/rssyl/parsers.h | 13 -
src/plugins/rssyl/plugin.c | 22 +-
src/plugins/rssyl/rssyl.c | 584 +++++---
src/plugins/rssyl/rssyl.h | 74 +-
src/plugins/rssyl/rssyl_add_item.c | 540 +++++++
src/plugins/rssyl/rssyl_add_item.h | 6 +
src/plugins/rssyl/rssyl_cb_gtk.c | 154 --
src/plugins/rssyl/rssyl_cb_gtk.h | 19 -
src/plugins/rssyl/rssyl_cb_menu.c | 382 +++--
src/plugins/rssyl/rssyl_cb_menu.h | 11 +-
src/plugins/rssyl/rssyl_deleted.c | 354 +++++
src/plugins/rssyl/rssyl_deleted.h | 14 +
src/plugins/rssyl/rssyl_feed.c | 183 +++
src/plugins/rssyl/rssyl_feed.h | 27 +
src/plugins/rssyl/rssyl_feed_props.c | 566 ++++++++
src/plugins/rssyl/rssyl_feed_props.h | 24 +
src/plugins/rssyl/rssyl_gtk.c | 613 +-------
src/plugins/rssyl/rssyl_gtk.h | 20 +-
src/plugins/rssyl/rssyl_parse_feed.c | 201 +++
src/plugins/rssyl/rssyl_parse_feed.h | 16 +
src/plugins/rssyl/rssyl_prefs.c | 227 +--
src/plugins/rssyl/rssyl_prefs.h | 21 +-
src/plugins/rssyl/rssyl_subscribe.c | 151 ++
src/plugins/rssyl/rssyl_subscribe.h | 6 +
src/plugins/rssyl/rssyl_subscribe_gtk.c | 109 ++
src/plugins/rssyl/rssyl_subscribe_gtk.h | 15 +
src/plugins/rssyl/rssyl_update_comments.c | 139 ++
src/plugins/rssyl/rssyl_update_comments.h | 12 +
src/plugins/rssyl/rssyl_update_feed.c | 303 ++++
src/plugins/rssyl/rssyl_update_feed.h | 19 +
src/plugins/rssyl/rssyl_update_format.c | 286 ++++
src/plugins/rssyl/rssyl_update_format.h | 6 +
src/plugins/rssyl/strreplace.c | 127 --
src/plugins/rssyl/strreplace.h | 8 -
src/plugins/rssyl/strutils.c | 289 ++++
src/plugins/rssyl/strutils.h | 19 +
71 files changed, 7279 insertions(+), 4555 deletions(-)
delete mode 100644 src/plugins/rssyl/feed.c
delete mode 100644 src/plugins/rssyl/feed.h
delete mode 100644 src/plugins/rssyl/feedprops.c
delete mode 100644 src/plugins/rssyl/feedprops.h
create mode 100644 src/plugins/rssyl/libfeed/Makefile.am
rename src/plugins/rssyl/{ => libfeed}/date.c (76%)
rename src/plugins/rssyl/{ => libfeed}/date.h (82%)
create mode 100644 src/plugins/rssyl/libfeed/feed.c
create mode 100644 src/plugins/rssyl/libfeed/feed.h
create mode 100644 src/plugins/rssyl/libfeed/feeditem.c
create mode 100644 src/plugins/rssyl/libfeed/feeditem.h
create mode 100644 src/plugins/rssyl/libfeed/feeditemenclosure.c
create mode 100644 src/plugins/rssyl/libfeed/feeditemenclosure.h
create mode 100644 src/plugins/rssyl/libfeed/parser.c
create mode 100644 src/plugins/rssyl/libfeed/parser.h
create mode 100644 src/plugins/rssyl/libfeed/parser_atom10.c
create mode 100644 src/plugins/rssyl/libfeed/parser_atom10.h
create mode 100644 src/plugins/rssyl/libfeed/parser_opml.c
create mode 100644 src/plugins/rssyl/libfeed/parser_opml.h
create mode 100644 src/plugins/rssyl/libfeed/parser_rdf.c
create mode 100644 src/plugins/rssyl/libfeed/parser_rdf.h
create mode 100644 src/plugins/rssyl/libfeed/parser_rss20.c
create mode 100644 src/plugins/rssyl/libfeed/parser_rss20.h
create mode 100644 src/plugins/rssyl/old_feeds.c
create mode 100644 src/plugins/rssyl/old_feeds.h
rename src/plugins/rssyl/{opml.c => opml_export.c} (50%)
rename src/plugins/rssyl/{opml.h => opml_export.h} (64%)
create mode 100644 src/plugins/rssyl/opml_import.c
create mode 100644 src/plugins/rssyl/opml_import.h
create mode 100644 src/plugins/rssyl/parse822.c
create mode 100644 src/plugins/rssyl/parse822.h
delete mode 100644 src/plugins/rssyl/parsers.c
delete mode 100644 src/plugins/rssyl/parsers.h
create mode 100644 src/plugins/rssyl/rssyl_add_item.c
create mode 100644 src/plugins/rssyl/rssyl_add_item.h
delete mode 100644 src/plugins/rssyl/rssyl_cb_gtk.c
delete mode 100644 src/plugins/rssyl/rssyl_cb_gtk.h
create mode 100644 src/plugins/rssyl/rssyl_deleted.c
create mode 100644 src/plugins/rssyl/rssyl_deleted.h
create mode 100644 src/plugins/rssyl/rssyl_feed.c
create mode 100644 src/plugins/rssyl/rssyl_feed.h
create mode 100644 src/plugins/rssyl/rssyl_feed_props.c
create mode 100644 src/plugins/rssyl/rssyl_feed_props.h
create mode 100644 src/plugins/rssyl/rssyl_parse_feed.c
create mode 100644 src/plugins/rssyl/rssyl_parse_feed.h
create mode 100644 src/plugins/rssyl/rssyl_subscribe.c
create mode 100644 src/plugins/rssyl/rssyl_subscribe.h
create mode 100644 src/plugins/rssyl/rssyl_subscribe_gtk.c
create mode 100644 src/plugins/rssyl/rssyl_subscribe_gtk.h
create mode 100644 src/plugins/rssyl/rssyl_update_comments.c
create mode 100644 src/plugins/rssyl/rssyl_update_comments.h
create mode 100644 src/plugins/rssyl/rssyl_update_feed.c
create mode 100644 src/plugins/rssyl/rssyl_update_feed.h
create mode 100644 src/plugins/rssyl/rssyl_update_format.c
create mode 100644 src/plugins/rssyl/rssyl_update_format.h
delete mode 100644 src/plugins/rssyl/strreplace.c
delete mode 100644 src/plugins/rssyl/strreplace.h
create mode 100644 src/plugins/rssyl/strutils.c
create mode 100644 src/plugins/rssyl/strutils.h
- Log -----------------------------------------------------------------
commit 72af590ae944e16136d1dcbb2ea3e4f7c7fd44aa
Author: Andrej Kacian <andrej at kacian.sk>
Date: Sat Jun 14 17:32:39 2014 +0200
Get rid of deprecated use of GtkComboBox text functions in favour of GtkComboBoxText.
diff --git a/src/plugins/rssyl/rssyl_feed_props.c b/src/plugins/rssyl/rssyl_feed_props.c
index f6a2d89..f1eba40 100644
--- a/src/plugins/rssyl/rssyl_feed_props.c
+++ b/src/plugins/rssyl/rssyl_feed_props.c
@@ -286,12 +286,12 @@ void rssyl_gtk_prop(RFolderItem *ritem)
1, 0);
/* Silent update - combobox */
- feedprop->silent_update = gtk_combo_box_new_text();
- gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
+ feedprop->silent_update = gtk_combo_box_text_new();
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->silent_update),
_("Always mark as new"));
- gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->silent_update),
_("If only its text changed"));
- gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->silent_update),
_("Never mark as new"));
gtk_combo_box_set_active(GTK_COMBO_BOX(feedprop->silent_update),
ritem->silent_update);
commit 332a84cc65e594093a0509791bc7a595edd850d5
Author: Colin Leroy <colin at colino.net>
Date: Thu Jun 12 16:35:20 2014 +0200
Don't forget the ssl_verify_peer pref when migrating
diff --git a/src/plugins/rssyl/old_feeds.c b/src/plugins/rssyl/old_feeds.c
index 45e6cf6..9bbb6cf 100644
--- a/src/plugins/rssyl/old_feeds.c
+++ b/src/plugins/rssyl/old_feeds.c
@@ -58,6 +58,7 @@ static void _elparse_start_oldrssyl(void *data, const gchar *el,
of->fetch_comments = GETVAL_INT("fetch_comments");
of->fetch_comments_for = GETVAL_INT("fetch_comments_for");
of->silent_update = GETVAL_INT("silent_update");
+ of->ssl_verify_peer = GETVAL_INT("ssl_verify_peer");
debug_print("RSSyl: old feeds.xml: Adding '%s' (%s).\n", of->name,
of->url);
diff --git a/src/plugins/rssyl/old_feeds.h b/src/plugins/rssyl/old_feeds.h
index b52cd86..b4349eb 100644
--- a/src/plugins/rssyl/old_feeds.h
+++ b/src/plugins/rssyl/old_feeds.h
@@ -11,6 +11,7 @@ struct _OldRFeed {
gint fetch_comments;
gint fetch_comments_for;
gint silent_update;
+ gint ssl_verify_peer;
};
typedef struct _OldRFeed OldRFeed;
diff --git a/src/plugins/rssyl/rssyl_update_format.c b/src/plugins/rssyl/rssyl_update_format.c
index 571eada..2b577dd 100644
--- a/src/plugins/rssyl/rssyl_update_format.c
+++ b/src/plugins/rssyl/rssyl_update_format.c
@@ -159,6 +159,7 @@ static void rssyl_update_format_func(FolderItem *item, gpointer data)
(of->fetch_comments != 0 ? TRUE : FALSE);
ritem->fetch_comments_max_age = of->fetch_comments_for;
ritem->silent_update = of->silent_update;
+ ritem->ssl_verify_peer = of->ssl_verify_peer;
}
rssyl_update_format_move_contents(item, new_item);
commit 9e5668deae60da62525316de59d1f735062f1f79
Author: Colin Leroy <colin at colino.net>
Date: Wed Jun 11 17:05:02 2014 +0200
Migrate the old feeds' caches if possible.
diff --git a/src/plugins/rssyl/rssyl_update_format.c b/src/plugins/rssyl/rssyl_update_format.c
index 8284450..571eada 100644
--- a/src/plugins/rssyl/rssyl_update_format.c
+++ b/src/plugins/rssyl/rssyl_update_format.c
@@ -163,6 +163,12 @@ static void rssyl_update_format_func(FolderItem *item, gpointer data)
rssyl_update_format_move_contents(item, new_item);
+ /* destroy the new folder's cache so we'll re-read the migrated one */
+ if (new_item->cache) {
+ msgcache_destroy(new_item->cache);
+ new_item->cache = NULL;
+ }
+
/* Store folderlist with the new folder */
folder_item_scan(new_item);
folder_write_list();
@@ -246,8 +252,9 @@ static void rssyl_update_format_move_contents(FolderItem *olditem,
oldpath, newpath);
while ((fname = (gchar *)g_dir_read_name(d)) != NULL) {
+ gboolean migrate_file = to_number(fname) > 0 || strstr(fname, ".claws_") == fname;
fpath = g_strconcat(oldpath, G_DIR_SEPARATOR_S, fname, NULL);
- if (to_number(fname) > 0 && g_file_test(fpath, G_FILE_TEST_IS_REGULAR)) {
+ if (migrate_file && g_file_test(fpath, G_FILE_TEST_IS_REGULAR)) {
nfpath = g_strconcat(newpath, G_DIR_SEPARATOR_S, fname, NULL);
move_file(fpath, nfpath, FALSE);
g_free(nfpath);
commit 7b80f1f639341f9711d9b28b45de2939f1b55728
Author: Andrej Kacian <ticho at claws-mail.org>
Date: Mon Jun 2 00:24:21 2014 +0200
New RSSyl replacing old one.
diff --git a/configure.ac b/configure.ac
index 8b7c47a..612b555 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 3ebe982..31cd537 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -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
diff --git a/src/plugins/rssyl/Makefile.am b/src/plugins/rssyl/Makefile.am
index 9eaf574..949efd3 100644
--- a/src/plugins/rssyl/Makefile.am
+++ b/src/plugins/rssyl/Makefile.am
@@ -2,6 +2,8 @@
# This file is part of Claws Mail package.
# See COPYING file for license details.
+SUBDIRS = libfeed
+
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
index 8542bc7..0000000
--- a/src/plugins/rssyl/feed.c
+++ /dev/null
@@ -1,1869 +0,0 @@
-/*
- * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2004 Hiroyuki Yamamoto
- * This file (C) 2005-2008 Andrej Kacian <andrej at kacian.sk> and the Claws Mail team
- *
- * - various feed parsing functions
- * - this file could use some sorting and/or splitting
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#include "claws-features.h"
-#endif
-
-#include <glib.h>
-#include <glib/gi18n.h>
-
-#include <gtk/gtk.h>
-
-#include <curl/curl.h>
-#include <curl/curlver.h>
-#include <libxml/parser.h>
-#include <libxml/xpath.h>
-#include <pthread.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "common/claws.h"
-#include "common/version.h"
-#include "codeconv.h"
-#include "procmsg.h"
-#include "procheader.h"
-#include "alertpanel.h"
-#include "folder.h"
-#include "mainwindow.h"
-#include "statusbar.h"
-#include "log.h"
-#include "prefs_common.h"
-#include "defs.h"
-#include "inc.h"
-#include "common/utils.h"
-#include "main.h"
-
-#include "date.h"
-#include "rssyl.h"
-#include "rssyl_cb_gtk.h"
-#include "feed.h"
-#include "feedprops.h"
-#include "strreplace.h"
-#include "parsers.h"
-#include "rssyl_prefs.h"
-
-static int rssyl_curl_progress_function(void *clientp,
- double dltotal, double dlnow, double ultotal, double ulnow)
-{
- if (claws_is_exiting()) {
- debug_print("RSSyl: curl_progress_function bailing out, app is exiting\n");
- return 1;
- }
-
- return 0;
-}
-
-struct _RSSylThreadCtx {
- const gchar *url;
- time_t last_update;
- gboolean not_modified;
- gboolean defer_modified_check;
- gboolean ready;
- gchar *error;
- gboolean ssl_verify_peer;
-};
-
-typedef struct _RSSylThreadCtx RSSylThreadCtx;
-
-static void *rssyl_fetch_feed_threaded(void *arg)
-{
- RSSylThreadCtx *ctx = (RSSylThreadCtx *)arg;
- CURL *eh = NULL;
- CURLcode res;
- time_t last_modified;
- gchar *time_str = NULL;
- long response_code;
-
-#ifndef G_OS_WIN32
- gchar *template = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
- G_DIR_SEPARATOR_S, RSSYL_TMP_TEMPLATE, NULL);
- int fd = mkstemp(template);
-#else
- gchar *template = get_tmp_file();
- int fd = open(template, (O_CREAT|O_RDWR|O_BINARY), (S_IRUSR|S_IWUSR));
-#endif
- FILE *f;
-
-#ifdef USE_PTHREAD
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
- pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
-#endif
-
- if (fd == -1) {
- perror("mkstemp");
- ctx->ready = TRUE;
- g_free(template);
- return NULL;
- }
-
- f = fdopen(fd, "w");
- if (f == NULL) {
- perror("fdopen");
- ctx->error = g_strdup(_("Cannot open temporary file"));
- claws_unlink(template);
- g_free(template);
- ctx->ready = TRUE;
- return NULL;
- }
-
- eh = curl_easy_init();
-
- if (eh == NULL) {
- g_warning("can't init curl");
- ctx->error = g_strdup(_("Cannot init libCURL"));
- fclose(f);
- claws_unlink(template);
- g_free(template);
- ctx->ready = TRUE;
- return NULL;
- }
-
- debug_print("TEMPLATE: %s\n", template);
-
- curl_easy_setopt(eh, CURLOPT_URL, ctx->url);
- curl_easy_setopt(eh, CURLOPT_NOPROGRESS, 0);
- curl_easy_setopt(eh, CURLOPT_PROGRESSFUNCTION, rssyl_curl_progress_function);
-#if LIBCURL_VERSION_NUM < 0x071000
- curl_easy_setopt(eh, CURLOPT_MUTE, 1);
-#endif
- curl_easy_setopt(eh, CURLOPT_WRITEFUNCTION, NULL);
- curl_easy_setopt(eh, CURLOPT_WRITEDATA, f);
- curl_easy_setopt(eh, CURLOPT_FOLLOWLOCATION, 1);
- curl_easy_setopt(eh, CURLOPT_MAXREDIRS, 3);
- curl_easy_setopt(eh, CURLOPT_TIMEOUT, prefs_common_get_prefs()->io_timeout_secs);
- curl_easy_setopt(eh, CURLOPT_NOSIGNAL, 1);
- curl_easy_setopt(eh, CURLOPT_ENCODING, "");
-#if LIBCURL_VERSION_NUM >= 0x070a00
- if(ctx->ssl_verify_peer == FALSE) {
- curl_easy_setopt(eh, CURLOPT_SSL_VERIFYPEER, 0);
- curl_easy_setopt(eh, CURLOPT_SSL_VERIFYHOST, 0);
- }
-#endif
- curl_easy_setopt(eh, CURLOPT_USERAGENT,
- "Claws Mail RSSyl plugin "VERSION
- " (" PLUGINS_URI ")");
-#ifdef RSSYL_DEBUG
- curl_easy_setopt(eh, CURLOPT_VERBOSE, 1);
-#endif
- curl_easy_setopt(eh, CURLOPT_COOKIEFILE,
- rssyl_prefs_get()->cookies_path);
-
- if( !ctx->defer_modified_check ) {
- if( ctx->last_update != -1 ) {
- time_str = createRFC822Date(&ctx->last_update);
- }
- debug_print("RSSyl: last update %ld (%s)\n",
- (long int)ctx->last_update,
- (ctx->last_update != -1 ? time_str : "unknown") );
- g_free(time_str);
- time_str = NULL;
- if( ctx->last_update != -1 ) {
- curl_easy_setopt(eh, CURLOPT_TIMECONDITION,
- CURL_TIMECOND_IFMODSINCE);
- curl_easy_setopt(eh, CURLOPT_TIMEVALUE, ctx->last_update);
- }
- }
-
- res = curl_easy_perform(eh);
-
- if (res != 0) {
- if (res == CURLE_OPERATION_TIMEOUTED) {
- log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_TIMEOUT, ctx->url);
- } else if (res == CURLE_ABORTED_BY_CALLBACK) {
- log_print(LOG_PROTOCOL, RSSYL_LOG_EXITING);
- }
- ctx->error = g_strdup(curl_easy_strerror(res));
- ctx->ready = TRUE;
- curl_easy_cleanup(eh);
- fclose(f);
- claws_unlink(template);
- g_free(template);
- return NULL;
- }
- curl_easy_getinfo(eh, CURLINFO_RESPONSE_CODE, &response_code);
-
- if( !ctx->defer_modified_check ) {
- if( ctx->last_update != -1 ) {
- curl_easy_getinfo(eh, CURLINFO_FILETIME, &last_modified);
-
- if( last_modified != -1 ) {
- time_str = createRFC822Date(&last_modified);
- }
- debug_print("RSSyl: got status %ld, last mod %ld (%s)\n",
- response_code, (long int) last_modified,
- (last_modified != -1 ? time_str : "unknown") );
- g_free(time_str);
- time_str = NULL;
- } else {
- debug_print("RSSyl: got status %ld\n", response_code);
- }
- }
-
- curl_easy_cleanup(eh);
-
- fclose(f);
-
- if( response_code >= 400 && response_code < 500 ) {
- debug_print("RSSyl: got %ld\n", response_code);
- switch(response_code) {
- case 401:
- ctx->error = g_strdup(_("401 (Authorisation required)"));
- break;
- case 403:
- ctx->error = g_strdup(_("403 (Unauthorised)"));
- break;
- case 404:
- ctx->error = g_strdup(_("404 (Not found)"));
- break;
- default:
- ctx->error = g_strdup_printf(_("Error %ld"), response_code);
- break;
- }
- ctx->ready = TRUE;
- claws_unlink(template);
- g_free(template);
- return NULL;
- }
-
- if( !ctx->defer_modified_check ) {
- if( response_code == 304 ) {
- debug_print("RSSyl: don't rely on server response 304, defer modified "
- "check\n");
- claws_unlink(template);
- g_free(template);
- ctx->defer_modified_check = TRUE;
- template = rssyl_fetch_feed_threaded(ctx);
- return template;
- }
- }
- ctx->ready = TRUE;
-
- return template;
-}
-
-gchar *rssyl_feed_title_to_dir(const gchar *title)
-{
-#ifndef G_OS_WIN32
- return rssyl_strreplace(title, "/", "\\");
-#else
- gchar *patterns[] = { "/", "\\", ":", "*", "?" , "\"", "<", ">", "|" };
- gchar *sanitized = g_strdup(title);
- int i;
-
- for (i = 0; i < sizeof(patterns)/sizeof(patterns[0]); i++) {
- gchar *tmp = rssyl_strreplace(sanitized, patterns[i], "-");
- g_free(sanitized);
- sanitized = tmp;
- }
-
- return sanitized;
-#endif
-}
-
-/* rssyl_fetch_feed()
- *
- * This function utilizes libcurl's easy interface to fetch the feed, pre-parse
- * it for title, create a directory based on the title. It returns a xmlDocPtr
- * for libxml2 to parse further.
- */
-xmlDocPtr rssyl_fetch_feed(const gchar *url, time_t last_update, gboolean ssl_verify_peer, gchar **title, gchar **error) {
- gchar *xpath, *rootnode, *dir;
- xmlDocPtr doc;
- xmlNodePtr node, n, rnode;
- xmlXPathContextPtr context;
- xmlXPathObjectPtr result;
- MainWindow *mainwin = mainwindow_get_mainwindow();
- RSSylThreadCtx *ctx = g_new0(RSSylThreadCtx, 1);
- gchar *template = NULL;
- gboolean defer_modified_check = FALSE;
-#ifdef RSSYL_DEBUG
- gchar *unixtime_str = NULL, *debugfname = NULL;
-#endif /* RSSYL_DEBUG */
-
-#ifdef USE_PTHREAD
- pthread_t pt;
- pthread_attr_t pta;
-#endif
- gchar *msg = NULL, *tmptitle = NULL;
- gchar *content;
- xmlErrorPtr xml_err;
-
- ctx->url = url;
- ctx->ready = FALSE;
- ctx->last_update = last_update;
- ctx->not_modified = FALSE;
- ctx->defer_modified_check = FALSE;
- ctx->ssl_verify_peer = ssl_verify_peer;
-
- *title = NULL;
-
- g_return_val_if_fail(url != NULL, NULL);
-
- debug_print("RSSyl: XML - url is '%s'\n", url);
-
- msg = g_strdup_printf(_("Fetching '%s'..."), url);
- STATUSBAR_PUSH(mainwin, msg );
- g_free(msg);
-
- GTK_EVENTS_FLUSH();
-
-#ifdef USE_PTHREAD
- if (pthread_attr_init(&pta) != 0 ||
- pthread_attr_setdetachstate(&pta, PTHREAD_CREATE_JOINABLE) != 0 ||
- pthread_create(&pt, &pta, rssyl_fetch_feed_threaded,
- (void *)ctx) != 0 ) {
- /* Bummer, couldn't create thread. Continue non-threaded */
- template = rssyl_fetch_feed_threaded(ctx);
- } else {
- /* Thread created, let's wait until it finishes */
- debug_print("RSSyl: waiting for thread to finish\n");
- while( !ctx->ready ) {
- claws_do_idle();
- }
-
- debug_print("RSSyl: thread finished\n");
- pthread_join(pt, (void *)&template);
- }
-#else
- debug_print("RSSyl: no pthreads, run blocking fetch\n");
- template = rssyl_fetch_feed_threaded(ctx);
-#endif
-
- defer_modified_check = ctx->defer_modified_check;
-
- if (error)
- *error = ctx->error;
-
- g_free(ctx);
- STATUSBAR_POP(mainwin);
-
- if( template == NULL ) {
- debug_print("RSSyl: no feed to parse, returning\n");
- log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_FETCH, url);
- return NULL;
- }
-
- /* Strip ugly \r\n endlines */
-#ifndef G_OS_WIN32
- file_strip_crs((gchar *)template);
-#endif
- debug_print("parsing %s\n", template);
- doc = xmlParseFile(template);
-
- if( doc == NULL ) {
- claws_unlink(template);
- g_free(template);
- xml_err = xmlGetLastError();
- if (xml_err)
- debug_print("error %s\n", xml_err->message);
-
- g_warning("Couldn't fetch feed '%s', aborting.\n", url);
- log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_FETCH, url);
- if (error && !(*error)) {
- *error = g_strdup(_("Malformed feed"));
- }
- return NULL;
- }
-
- node = xmlDocGetRootElement(doc);
- rnode = node;
-
-#ifdef RSSYL_DEBUG
- /* debug mode - get timestamp, add it to returned xmlDoc, and make a copy
- * of the fetched feed file */
- tmptitle = rssyl_feed_title_to_dir(url);
- unixtime_str = g_strdup_printf("%ld", time(NULL) );
- debugfname = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
- G_DIR_SEPARATOR_S, ".", tmptitle, ".", unixtime_str, NULL);
-
- debug_print("Storing fetched feed in file '%s' for debug purposes.\n",
- debugfname);
- link(template, debugfname);
-
- debug_print("Adding 'fetched' property to root node: %s\n", unixtime_str);
- xmlSetProp(rnode, "fetched", unixtime_str);
- g_free(unixtime_str);
- g_free(debugfname);
- g_free(tmptitle);
-#endif /* RSSYL_DEBUG */
-
- claws_unlink(template);
- g_free(template);
-
- debug_print("RSSyl: XML - root node is '%s'\n", node->name);
-
- rootnode = g_ascii_strdown(node->name, -1);
-
- if( !xmlStrcmp(rootnode, "rss") ) {
- context = xmlXPathNewContext(doc);
- xpath = g_strconcat("/", node->name, "/channel/title", NULL);
- debug_print("RSSyl: XML - '%s'\n", xpath);
- if( !(result = xmlXPathEvalExpression(xpath, context)) ) {
- debug_print("RSSyl: XML - no result found for '%s'\n", xpath);
- xmlXPathFreeContext(context);
- g_free(rootnode);
- g_free(xpath);
- log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_PARSE, url);
- return NULL;
- }
-
- if( xmlXPathNodeSetIsEmpty(result->nodesetval) ) {
- debug_print("RSSyl: XML - nodeset empty for '%s'\n", xpath);
- g_free(rootnode);
- g_free(xpath);
- xmlXPathFreeObject(result);
- xmlXPathFreeContext(context);
- log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_PARSE, url);
- return NULL;
- }
- g_free(xpath);
-
- xmlXPathFreeContext(context);
- node = result->nodesetval->nodeTab[0];
- xmlXPathFreeObject(result);
- content = xmlNodeGetContent(node);
- debug_print("RSSyl: XML - title is '%s'\n", content );
- *title = g_strdup(content);
- xmlFree(content);
- debug_print("RSSyl: XML - our title is '%s'\n", *title);
-
- /* use the feed's pubDate to determine if it's modified */
- if( defer_modified_check ) {
- time_t pub_date;
-
- context = xmlXPathNewContext(doc);
- node = rnode;
- xpath = g_strconcat("/", node->name, "/channel/pubDate", NULL);
- debug_print("RSSyl: XML - '%s'\n", xpath);
- if( !(result = xmlXPathEvalExpression(xpath, context)) ) {
- debug_print("RSSyl: XML - no result found for '%s'\n", xpath);
- xmlXPathFreeContext(context);
- g_free(rootnode);
- g_free(xpath);
- log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_PARSE, url);
- return NULL;
- }
-
- if( xmlXPathNodeSetIsEmpty(result->nodesetval) ) {
- debug_print("RSSyl: XML - nodeset empty for '%s', using current time\n",
- xpath);
- pub_date = time(NULL);
- } else {
- node = result->nodesetval->nodeTab[0];
- content = xmlNodeGetContent(node);
- pub_date = procheader_date_parse(NULL, content, 0);
- debug_print("RSSyl: XML - pubDate is '%s'\n", content);
- xmlFree(content);
- }
-
- xmlXPathFreeObject(result);
- xmlXPathFreeContext(context);
- g_free(xpath);
-
- /* check date validity and perform postponed modified check */
- if( pub_date > 0 ) {
- gchar *time_str = NULL;
-
- time_str = createRFC822Date(&pub_date);
- debug_print("RSSyl: XML - item date found: %ld (%s)\n",
- (long int) pub_date, time_str ? time_str : "unknown");
- if( !time_str || ( pub_date < last_update && last_update > 0) ) {
- if( !time_str) {
- debug_print("RSSyl: XML - invalid item date\n");
- } else {
- debug_print("RSSyl: XML - no update needed\n");
- }
- g_free(time_str);
- time_str = NULL;
- g_free(rootnode);
- return NULL;
- }
- g_free(time_str);
- time_str = NULL;
- } else {
- debug_print("RSSyl: XML - item date not found\n");
- g_free(rootnode);
- return NULL;
- }
- }
-
- } else if( !xmlStrcmp(rootnode, "rdf") ) {
- node = node->children;
- /* find "channel" */
- while( node && xmlStrcmp(node->name, "channel") )
- node = node->next;
- /* now find "title" */
- for( n = node->children; n; n = n->next ) {
- if( !xmlStrcmp(n->name, "title") ) {
- content = xmlNodeGetContent(n);
- *title = g_strdup(content);
- xmlFree(content);
- debug_print("RSSyl: XML - RDF our title is '%s'\n", *title);
- }
- }
- } else if( !xmlStrcmp(rootnode, "feed") ) {
- /* find "title" */
- for( n = node->children; n; n = n->next ) {
- if( !xmlStrcmp(n->name, "title") ) {
- content = xmlNodeGetContent(n);
- *title = g_strdup(content);
- xmlFree(content);
- debug_print("RSSyl: XML - FEED our title is '%s'\n", *title);
- }
- }
- } else {
- log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_UNKNOWN, url);
- g_free(rootnode);
- return NULL;
- }
-
- g_return_val_if_fail(*title != NULL, NULL);
-
- if (*title[0] == '\0') {
- g_free(*title);
- *title = g_strdup(url);
- subst_for_shellsafe_filename(*title);
- }
-
- tmptitle = rssyl_feed_title_to_dir(*title);
- dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
- G_DIR_SEPARATOR_S, tmptitle, NULL);
- g_free(tmptitle);
-
- if( !is_dir_exist(dir) ) {
- if( make_dir(dir) < 0 ) {
- g_warning("couldn't create directory %s\n", dir);
- g_free(rootnode);
- g_free(dir);
- return NULL;
- }
- }
-
- g_free(rootnode);
- g_free(dir);
-
- return doc;
-}
-
-typedef struct _RSSyl_HTMLSymbol RSSyl_HTMLSymbol;
-struct _RSSyl_HTMLSymbol
-{
- gchar *const key;
- gchar *const val;
-};
-
-static RSSyl_HTMLSymbol symbol_list[] = {
- { "<", "<" },
- { ">", ">" },
- { "&", "&" },
- { """, "\"" },
- { "‘", "'" },
- { "’", "'" },
- { "“", "\"" },
- { "”", "\"" },
- { " ", " " },
- { "™", "(TM)" },
- { "", "(TM)" },
- { "'", "'" },
- { "…", "..." },
- { "—", "-" },
- { "<cite>", "\"" },
- { "</cite>", "\"" },
- { "<i>", "" },
- { "</i>", "" },
- { "<em>", "" },
- { "</em>", ""},
- { "<b>", "" },
- { "</b>", "" },
- { "<nobr>", "" },
- { "</nobr>", "" },
- { "<wbr>", "" },
- { NULL, NULL },
-};
-
-static gchar *rssyl_replace_html_symbols(const gchar *text)
-{
- gchar *tmp = NULL, *wtext = g_strdup(text);
- gint i;
-
- for( i = 0; symbol_list[i].key != NULL; i++ ) {
- if( g_strstr_len(text, strlen(text), symbol_list[i].key) ) {
- tmp = rssyl_strreplace(wtext, symbol_list[i].key, symbol_list[i].val);
- wtext = g_strdup(tmp);
- g_free(tmp);
- }
- }
-
- return wtext;
-}
-
-gchar *rssyl_format_string(const gchar *str, gboolean replace_html, gboolean replace_returns)
-{
- gchar *res = NULL;
- gchar *tmp = NULL;
-
- g_return_val_if_fail(str != NULL, NULL);
-
- if (replace_html)
- tmp = rssyl_replace_html_symbols(str);
- else
- tmp = g_strdup(str);
-
- res = rssyl_sanitize_string(tmp, replace_returns);
- g_free(tmp);
-
- g_strstrip(res);
-
- return res;
-}
-
-/* this function splits a string into an array of string, by
- * returning an array of pointers to positions of the delimiter
- * in the original string and replacing this delimiter with a
- * NULL. It does not duplicate memory, hence you should only
- * free the array and not its elements, and you should not
- * free the original string before you're done with the array.
- * maybe could be part of the core (utils.c).
- */
-static gchar **strplit_no_copy(gchar *str, char delimiter)
-{
- gchar **array = g_new(gchar *, 1);
- int i = 0;
- gchar *cur = str, *next;
-
- array[i] = cur;
- i++;
- while ((next = strchr(cur, delimiter)) != NULL) {
- *(next) = '\0';
- array = g_realloc(array, (sizeof(gchar *)) * (i + 1));
- array[i] = next + 1;
- cur = next + 1;
- i++;
- }
- array = g_realloc(array, (sizeof(gchar *)) * (i + 1));
- array[i] = NULL;
- return array;
-}
-
-/* rssyl_parse_folder_item_file()
- *
- * Parse the RFC822-formatted feed item given by "path", and returns a
- * pointer to a RSSylFeedItem struct, which contains all required data.
- */
-static RSSylFeedItem *rssyl_parse_folder_item_file(gchar *dir_path, gchar *filename)
-{
- gchar *contents, **lines, **line, **splid;
- GError *error = NULL;
- RSSylFeedItem *fitem;
- gint i = 0;
- gboolean parsing_headers, past_html_tag, past_endhtml_tag;
- gboolean started_author = FALSE, started_subject = FALSE;
- gboolean started_link = FALSE, started_clink = FALSE, started_plink = FALSE;
- gchar *full_path = g_strconcat(dir_path, G_DIR_SEPARATOR_S, filename, NULL);
- debug_print("RSSyl: parsing '%s'\n", full_path);
-
- g_file_get_contents(full_path, &contents, NULL, &error);
-
- if( error ) {
- g_warning("GError: '%s'\n", error->message);
- g_error_free(error);
- error = NULL;
- }
-
- if( contents ) {
- lines = strplit_no_copy(contents, '\n');
- } else {
- g_warning("Badly formatted file found, ignoring: '%s'\n", full_path);
- g_free(contents);
- return NULL;
- }
-
- fitem = g_new0(RSSylFeedItem, 1); /* free that */
- fitem->date = 0;
- fitem->date_published = 0;
- fitem->link = NULL;
- fitem->text = NULL;
- fitem->id = NULL;
- fitem->id_is_permalink = FALSE;
- fitem->realpath = g_strdup(full_path);
-
- g_free(full_path);
-
- parsing_headers = TRUE;
- past_html_tag = FALSE;
- past_endhtml_tag = FALSE;
- while(lines[i] ) {
- if( parsing_headers && lines[i] && !strlen(lines[i]) && fitem->link ) {
- parsing_headers = FALSE;
- debug_print("RSSyl: finished parsing headers\n");
- }
-
- if( parsing_headers ) {
- line = g_strsplit(lines[i], ": ", 2);
- if( line[0] && line[1] && strlen(line[0]) && lines[i][0] != ' ') {
- started_author = FALSE;
- started_subject = FALSE;
- started_link = FALSE;
- started_clink = FALSE;
- started_plink = FALSE;
-
- /* Author */
- if( !strcmp(line[0], "From") ) {
- fitem->author = g_strdup(line[1]);
- debug_print("RSSyl: got author '%s'\n", fitem->author);
- started_author = TRUE;
- }
-
- /* Date */
- if( !strcmp(line[0], "Date") ) {
- fitem->date = procheader_date_parse(NULL, line[1], 0);
- debug_print("RSSyl: got date \n" );
- }
-
- /* Title */
- if( !strcmp(line[0], "Subject") ) {
- fitem->title = g_strdup(line[1]);
- debug_print("RSSyl: got title '%s'\n", fitem->title);
- started_subject = TRUE;
- }
-
- /* Link */
- if( !strcmp(line[0], "X-RSSyl-URL") ) {
- fitem->link = g_strdup(line[1]);
- debug_print("RSSyl: got link '%s'\n", fitem->link);
- started_link = TRUE;
- }
-
- /* ID */
- if( !strcmp(line[0], "Message-ID") ) {
- splid = g_strsplit_set(line[1], "<>", 3);
- if( strlen(splid[1]) != 0 ) {
- fitem->id = g_strdup(splid[1]);
- debug_print("RSSyl: got id '%s'\n", fitem->id);
- }
- g_strfreev(splid);
- }
-
- if( !strcmp(line[0], "X-RSSyl-Comments") ) {
- fitem->comments_link = g_strdup(line[1]);
- debug_print("RSSyl: got clink '%s'\n", fitem->comments_link);
- started_clink = TRUE;
- }
- if( !strcmp(line[0], "X-RSSyl-Parent") ) {
- fitem->parent_link = g_strdup(line[1]);
- debug_print("RSSyl: got plink '%s'\n", fitem->parent_link);
- started_plink = TRUE;
- }
- } else if (lines[i][0] == ' ') {
- gchar *tmp = NULL;
- /* continuation line */
- if (started_author) {
- tmp = g_strdup_printf("%s %s", fitem->author, lines[i]+1);
- g_free(fitem->author);
- fitem->author = tmp;
- debug_print("RSSyl: updated author to '%s'\n", fitem->author);
- } else if (started_subject) {
- tmp = g_strdup_printf("%s %s", fitem->title, lines[i]+1);
- g_free(fitem->title);
- fitem->title = tmp;
- debug_print("RSSyl: updated title to '%s'\n", fitem->title);
- } else if (started_link) {
- tmp = g_strdup_printf("%s%s", fitem->link, lines[i]+1);
- g_free(fitem->link);
- fitem->link = tmp;
- debug_print("RSSyl: updated link to '%s'\n", fitem->link);
- } else if (started_clink) {
- tmp = g_strdup_printf("%s%s", fitem->comments_link, lines[i]+1);
- g_free(fitem->comments_link);
- fitem->comments_link = tmp;
- debug_print("RSSyl: updated comments_link to '%s'\n", fitem->comments_link);
- } else if (started_plink) {
- tmp = g_strdup_printf("%s%s", fitem->parent_link, lines[i]+1);
- g_free(fitem->parent_link);
- fitem->parent_link = tmp;
- debug_print("RSSyl: updated comments_link to '%s'\n", fitem->parent_link);
- }
- }
- g_strfreev(line);
- } else {
- if( !strcmp(lines[i], RSSYL_TEXT_START) ) {
- debug_print("Leading html tag found at line %d\n", i);
- past_html_tag = TRUE;
- i++;
- continue;
- }
- while( past_html_tag && !past_endhtml_tag && lines[i] ) {
- if( !strcmp(lines[i], RSSYL_TEXT_END) ) {
- debug_print("Trailing html tag found at line %d\n", i);
- past_endhtml_tag = TRUE;
- i++;
- continue;
- }
- if( fitem->text != NULL ) {
- gint e_len, n_len;
- e_len = strlen(fitem->text);
- n_len = strlen(lines[i]);
- fitem->text = g_realloc(fitem->text, e_len + n_len + 2);
- *(fitem->text+e_len) = '\n';
- strcpy(fitem->text+e_len+1, lines[i]);
- *(fitem->text+e_len+n_len+1) = '\0';
- } else {
- fitem->text = g_strdup(lines[i]);
- }
- i++;
- }
-
- if( lines[i] == NULL )
- return fitem;
- }
-
- i++;
- }
- g_free(lines);
- g_free(contents);
- return fitem;
-}
-
-/* rssyl_free_feeditem()
- * frees an RSSylFeedItem
- */
-void rssyl_free_feeditem(RSSylFeedItem *item)
-{
- if (!item)
- return;
- g_free(item->title);
- item->title = NULL;
- g_free(item->text);
- item->text = NULL;
- g_free(item->link);
- item->link = NULL;
- g_free(item->id);
- item->id = NULL;
- g_free(item->comments_link);
- item->comments_link = NULL;
- g_free(item->parent_link);
- item->parent_link = NULL;
- g_free(item->author);
- item->author = NULL;
- g_free(item->realpath);
- item->realpath = NULL;
- if( item->media != NULL ) {
- g_free(item->media->url);
- g_free(item->media->type);
- g_free(item->media);
- }
- g_free(item);
-}
-
-static void *rssyl_read_existing_thr(void *arg)
-{
- RSSylParseCtx *ctx = (RSSylParseCtx *)arg;
- RSSylFolderItem *ritem = ctx->ritem;
- FolderItem *item = &ritem->item;
- RSSylFeedItem *fitem = NULL;
- DIR *dp;
- struct dirent *d;
- gint num;
- gchar *path;
-
- debug_print("RSSyl: rssyl_read_existing_thr()\n");
-
- path = folder_item_get_path(item);
- if( !path ) {
- debug_print("RSSyl: read_existing - path is NULL, bailing out\n");
- ctx->ready = TRUE;
- return NULL;
- }
-
- /* create a new GSList, throw away the old one */
- if( ritem->contents != NULL ) {
- GSList *cur;
- for (cur = ritem->contents; cur; cur = cur->next) {
- RSSylFeedItem *olditem = (RSSylFeedItem *)cur->data;
- rssyl_free_feeditem(olditem);
- }
- g_slist_free(ritem->contents); /* leak fix here */
- ritem->contents = NULL;
- }
- ritem->contents = g_slist_alloc();
-
- if( change_dir(path) < 0 ) {
- g_free(path);
- return NULL;
- }
-
- if( (dp = opendir(".")) == NULL ) {
- FILE_OP_ERROR(item->path, "opendir");
- g_free(path);
- return NULL;
- }
-
- while( (d = readdir(dp)) != NULL ) {
- if (claws_is_exiting()) {
- closedir(dp);
- g_free(path);
- debug_print("RSSyl: read_existing is bailing out, app is exiting\n");
- ctx->ready = TRUE;
- return NULL;
- }
- if( (num = to_number(d->d_name)) > 0 && dirent_is_regular_file(d) ) {
- debug_print("RSSyl: starting to parse '%s'\n", d->d_name);
- if( (fitem = rssyl_parse_folder_item_file(path, d->d_name)) != NULL ) {
- debug_print("Appending '%s'\n", fitem->title);
- ritem->contents = g_slist_prepend(ritem->contents, fitem);
- }
- }
- }
- closedir(dp);
- g_free(path);
-
- ritem->contents = g_slist_reverse(ritem->contents);
-
- ctx->ready = TRUE;
-
- debug_print("RSSyl: rssyl_read_existing_thr() is returning\n");
- return NULL;
-}
-
-/* rssyl_read_existing()
- *
- * Parse all existing folder items, storing their data in memory. Data is
- * later used for checking for duplicate entries.
- * Of course, actual work is done in a separate thread (if available) in
- * rssyl_read_existing_thr().
- */
-void rssyl_read_existing(RSSylFolderItem *ritem)
-{
- RSSylParseCtx *ctx = NULL;
-#ifdef USE_PTHREAD
- pthread_t pt;
-#endif
-
- g_return_if_fail(ritem != NULL);
-
- ctx = g_new0(RSSylParseCtx, 1);
- ctx->ritem = ritem;
- ctx->ready = FALSE;
-
-#ifdef USE_PTHREAD
- if( pthread_create(&pt, PTHREAD_CREATE_JOINABLE, rssyl_read_existing_thr,
- (void *)ctx) != 0 ) {
- /* Couldn't create thread, continue nonthreaded */
- rssyl_read_existing_thr(ctx);
- } else {
- debug_print("RSSyl: waiting for read_existing thread to finish\n");
- while( !ctx->ready ) {
- claws_do_idle();
- }
-
- debug_print("RSSyl: read_existing thread finished\n");
- pthread_join(pt, NULL);
- }
-#else
- debug_print("RSSyl: pthreads not available, running read_existing non-threaded\n");
- rssyl_read_existing_thr(ctx);
-#endif
-
- g_free(ctx);
-}
-
-/* rssyl_cb_feed_compare()
- *
- * Callback compare function called by glib2's g_slist_find_custom().
- */
-static gint rssyl_cb_feed_compare(const RSSylFeedItem *a,
- const RSSylFeedItem *b)
-{
- gboolean date_publ_eq = FALSE, date_eq = FALSE;
- gboolean link_eq = FALSE, title_eq = FALSE;
- gboolean no_link = FALSE, no_title = FALSE;
- gchar *atit = NULL, *btit = NULL;
-
- if( a == NULL || b == NULL )
- return 1;
-
- /* ID should be unique. If it matches, we've found what we came for. */
- if( (a->id != NULL) && (b->id != NULL) ) {
- if( strcmp(a->id, b->id) == 0 )
- return 0;
-
- /* If both IDs are present, but they do not match, we need
- * to look elsewhere. */
- return 1;
- }
-
- /* Ok, we have no ID to aid us. Let's have a look at item timestamps,
- * item link and title. */
- if( (a->link != NULL) && (b->link != NULL) ) {
- if( strcmp(a->link, b->link) == 0 )
- link_eq = TRUE;
- } else
- no_link = TRUE;
-
- if( (a->title != NULL) && (b->title != NULL) ) {
- atit = conv_unmime_header(a->title, CS_UTF_8, FALSE);
- btit = conv_unmime_header(b->title, CS_UTF_8, FALSE);
- if( strcmp(atit, btit) == 0 )
- title_eq = TRUE;
- g_free(atit);
- g_free(btit);
- } else
- no_title = TRUE;
-
- /* If there's no 'published' timestamp for the item, we can only judge
- * by item link and title - 'modified' timestamp can have changed if the
- * item was updated recently. */
- if( b->date_published <= 0 && b->date <= 0) {
- if( link_eq && (title_eq || no_title) )
- return 0;
- }
-
- if( ((a->date_published > 0) && (b->date_published > 0) &&
- (a->date_published == b->date_published)) ) {
- date_publ_eq = TRUE;
- }
-
- if( ((a->date > 0) && (b->date > 0) &&
- (a->date == b->date)) ) {
- date_eq = TRUE;
- }
-
- /* If 'published' time and item link match, it is reasonable to assume
- * it's this item. */
- if( (link_eq || no_link) && (date_publ_eq || date_eq) )
- return 0;
-
- /* Last ditch effort - if everything else is missing, at least titles
- * should match. */
- if( no_link && title_eq )
- return 0;
-
- /* We don't know this item. */
- return 1;
-}
-
-enum {
- ITEM_UNCHANGED,
- ITEM_CHANGED_TEXTONLY,
- ITEM_CHANGED
-};
-
-static gint rssyl_feed_item_changed(RSSylFeedItem *old_item, RSSylFeedItem *new_item)
-{
- /* if both have title ... */
- if( old_item->title && new_item->title ) {
- gchar *old = conv_unmime_header(old_item->title, CS_UTF_8, FALSE);
- gchar *new = conv_unmime_header(new_item->title, CS_UTF_8, FALSE);
- if( strcmp(old, new) ) { /* ... compare "unmimed" titles */
- g_free(old);
- g_free(new);
- debug_print("RSSyl: item titles differ\n");
- return ITEM_CHANGED;
- }
- g_free(old);
- g_free(new);
- } else {
- /* if atleast one has a title, they differ */
- if( old_item->title || new_item->title ) {
- debug_print("RSSyl: +/- title\n");
- return ITEM_CHANGED;
- }
- }
-
- /* if both have author ... */
- if( old_item->author && new_item->author ) {
- gchar *old = conv_unmime_header(old_item->author, CS_UTF_8, TRUE);
- gchar *new = conv_unmime_header(new_item->author, CS_UTF_8, TRUE);
- if( strcmp(old, new) ) { /* ... compare "unmimed" authors */
- g_free(old);
- g_free(new);
- debug_print("RSSyl: item authors differ\n");
- return ITEM_CHANGED;
- }
- g_free(old);
- g_free(new);
- } else {
- /* if atleast one has author, they differ */
- if( old_item->author || new_item->author ) {
- debug_print("RSSyl: +/- author\n");
- return ITEM_CHANGED;
- }
- }
-
- /* if both have text ... */
- if( old_item->text && new_item->text ) {
- if( strcmp(old_item->text, new_item->text) ) { /* ... compare texts */
- debug_print("RSSyl: item texts differ\n");
- return ITEM_CHANGED_TEXTONLY;
- }
- } else {
- /* if atleast one has some text, they differ */
- if( old_item->text || new_item->text ) {
- debug_print("RSSyl: +/- text\n");
- if ( !old_item->text )
- debug_print("RSSyl: old_item has no text\n");
- else
- debug_print("RSSyl: new_item has no text\n");
- return ITEM_CHANGED_TEXTONLY;
- }
- }
-
- /* they don't seem to differ */
- return ITEM_UNCHANGED;
-}
-
-/* rssyl_feed_item_exists()
- *
- * Returns 1 if a feed item already exists locally, 2 if there's a changed
- * item with link that already belongs to existing item, 3 if only item's
- * text has changed, 0 if item is new.
- */
-enum {
- EXISTS_NEW,
- EXISTS_UNCHANGED,
- EXISTS_CHANGED,
- EXISTS_CHANGED_TEXTONLY
-};
-
-static guint rssyl_feed_item_exists(RSSylFolderItem *ritem,
- RSSylFeedItem *fitem, RSSylFeedItem **oldfitem)
-{
- gint changed;
- GSList *item = NULL;
- RSSylFeedItem *efitem = NULL;
- g_return_val_if_fail(ritem != NULL, FALSE);
- g_return_val_if_fail(fitem != NULL, FALSE);
-
- if( ritem->contents == NULL || g_slist_length(ritem->contents) == 0 )
- return 0;
-
- if( (item = g_slist_find_custom(ritem->contents,
- (gconstpointer)fitem, (GCompareFunc)rssyl_cb_feed_compare)) ) {
- efitem = (RSSylFeedItem *)item->data;
- if( (changed = rssyl_feed_item_changed(efitem, fitem)) > EXISTS_NEW ) {
- *oldfitem = efitem;
- if (changed == ITEM_CHANGED_TEXTONLY)
- return EXISTS_CHANGED_TEXTONLY;
- else
- return EXISTS_CHANGED;
- }
- return EXISTS_UNCHANGED;
- }
-
- return EXISTS_NEW;
-}
-
-void rssyl_parse_feed(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent)
-{
- xmlNodePtr node;
- gchar *rootnode;
- MainWindow *mainwin = mainwindow_get_mainwindow();
- gint count;
- gchar *msg;
-
- if (doc == NULL)
- return;
-
- rssyl_read_existing(ritem);
-
- if (claws_is_exiting()) {
- debug_print("RSSyl: parse_feed bailing out, app is exiting\n");
- return;
- }
-
- node = xmlDocGetRootElement(doc);
-
- debug_print("RSSyl: XML - root node is '%s'\n", node->name);
- rootnode = g_ascii_strdown(node->name, -1);
-
- msg = g_strdup_printf(_("Refreshing feed '%s'..."),
- ritem->item.name);
- STATUSBAR_PUSH(mainwin, msg );
- g_free(msg);
- GTK_EVENTS_FLUSH();
-
- folder_item_update_freeze();
-
- /* we decide what parser to call, depending on what the root node is */
- if( !strcmp(rootnode, "rss") ) {
- debug_print("RSSyl: XML - calling rssyl_parse_rss()\n");
- count = rssyl_parse_rss(doc, ritem, parent);
- } else if( !strcmp(rootnode, "rdf") ) {
- debug_print("RSSyl: XML - calling rssyl_parse_rdf()\n");
- if (ritem->fetch_comments) {
- log_error(LOG_PROTOCOL, _("RSSyl: Fetching comments is not supported for RDF feeds. "
- "Cannot fetch comments of '%s'"), ritem->item.name);
- ritem->fetch_comments = FALSE;
- }
- count = rssyl_parse_rdf(doc, ritem, parent);
- } else if( !strcmp(rootnode, "feed") ) {
- debug_print("RSSyl: XML - calling rssyl_parse_atom()\n");
- count = rssyl_parse_atom(doc, ritem, parent);
- } else {
- alertpanel_error(_("This feed format is not supported yet."));
- count = 0;
- }
-
- if (!parent)
- ritem->last_count = count;
-
- folder_item_scan(&ritem->item);
- folder_item_update_thaw();
-
- STATUSBAR_POP(mainwin);
-
- g_free(rootnode);
-}
-
-gboolean rssyl_add_feed_item(RSSylFolderItem *ritem, RSSylFeedItem *fitem)
-{
- MsgFlags *flags;
- gchar *template, *tmpurl, *tmpid;
- gchar tmp[10240];
- gint d = -1, fd, dif = 0;
- FILE *f;
- RSSylFeedItem *oldfitem = NULL;
- gchar *meta_charset = NULL, *url_html = NULL;
- gboolean err = FALSE;
-
- g_return_val_if_fail(ritem != NULL, FALSE);
- g_return_val_if_fail(ritem->item.path != NULL, FALSE);
- g_return_val_if_fail(fitem != NULL, FALSE);
-
- if( !fitem->author )
- fitem->author = g_strdup(_("N/A"));
-
- /* Skip if the item already exists */
- dif = rssyl_feed_item_exists(ritem, fitem, &oldfitem);
- if( dif == 1 ) {
- debug_print("RSSyl: This item already exists, skipping...\n");
- return FALSE;
- }
- if( dif >= 2 && oldfitem != NULL ) {
- debug_print("RSSyl: Item changed, removing old one and adding new...\n");
- ritem->contents = g_slist_remove(ritem->contents, oldfitem);
- g_remove(oldfitem->realpath);
- rssyl_free_feeditem(oldfitem);
- oldfitem = NULL;
- }
-
- /* Adjust some fields */
- if( fitem->date <= 0 )
- fitem->date = time(NULL);
-
- debug_print("RSSyl: Adding item '%s' (%d)\n", fitem->title, dif);
-
- ritem->contents = g_slist_append(ritem->contents, fitem);
-
- flags = g_new(MsgFlags, 1);
-#ifndef G_OS_WIN32
- template = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
- G_DIR_SEPARATOR_S, RSSYL_TMP_TEMPLATE, NULL);
- fd = mkstemp(template);
-#else
- template = get_tmp_file();
- fd = open(template, (O_CREAT|O_RDWR|O_BINARY), (S_IRUSR|S_IWUSR));
-#endif
-
- f = fdopen(fd, "w");
- g_return_val_if_fail(f != NULL, FALSE);
-
- if( fitem->date != 0 ) {
- gchar *tmpdate = createRFC822Date(&fitem->date);
- err |= (fprintf(f, "Date: %s\n", tmpdate ) < 0);
- g_free(tmpdate);
- }
-
- if( fitem->author ) {
- if (g_utf8_validate(fitem->author, -1, NULL)) {
- conv_encode_header_full(tmp, 10239, fitem->author,
- strlen("From: "), TRUE, CS_UTF_8);
- err |= (fprintf(f, "From: %s\n", tmp) < 0);
- } else
- err |= (fprintf(f, "From: %s\n", fitem->author) < 0);
- }
-
- if( fitem->title ) {
- if (g_utf8_validate(fitem->title, -1, NULL)) {
- conv_encode_header_full(tmp, 10239, fitem->title,
- strlen("Subject: "), FALSE, CS_UTF_8);
- err |= (fprintf(f, "Subject: %s\n", tmp) < 0);
- } else
- err |= (fprintf(f, "Subject: %s\n", fitem->title) < 0);
- }
-
- if( (tmpurl = fitem->link) == NULL ) {
- if( fitem->id != NULL && fitem->id_is_permalink )
- tmpurl = fitem->id;
- }
- if( tmpurl != NULL )
- err |= (fprintf(f, "X-RSSyl-URL: %s\n", tmpurl) < 0);
-
- if( (tmpid = fitem->id) == NULL )
- tmpid = fitem->link;
- if( tmpid != NULL )
- err |= (fprintf(f, "Message-ID: <%s>\n", tmpid) < 0);
-
- if( fitem->comments_link ) {
- err |= (fprintf(f, "X-RSSyl-Comments: %s\n", fitem->comments_link) < 0);
- }
- if( fitem->parent_link) {
- err |= (fprintf(f, "X-RSSyl-Parent: %s\n", fitem->parent_link) < 0);
- err |= (fprintf(f, "References: <%s>\n", fitem->parent_link) < 0);
- }
-
-#ifdef RSSYL_DEBUG
- if( fitem->debug_fetched != -1 ) {
- err |= (fprintf(f, "X-RSSyl-Debug-Fetched: %ld\n", fitem->debug_fetched) < 0);
- }
-#endif /* RSSYL_DEBUG */
-
- if (fitem->text && g_utf8_validate(fitem->text, -1, NULL)) {
- /* if it passes UTF-8 validation, specify it. */
- err |= (fprintf(f, "Content-Type: text/html; charset=UTF-8\n\n") < 0);
- meta_charset = g_strdup("<meta http-equiv=\"Content-Type\" "
- "content=\"text/html; charset=UTF-8\">");
- } else {
- /* make sure Claws Mail displays it as html */
- err |= (fprintf(f, "Content-Type: text/html\n\n") < 0);
- }
-
- if( tmpurl )
- url_html = g_strdup_printf("<p>URL: <a href=\"%s\">%s</a></p>\n<br>\n",
- tmpurl, tmpurl);
-
- err |= (fprintf(f, "<html><head>"
- "%s\n"
- "<base href=\"%s\">\n"
- "</head><body>\n"
- "%s"
- RSSYL_TEXT_START"\n"
- "%s%s"
- RSSYL_TEXT_END"\n\n",
-
- meta_charset ? meta_charset:"",
- fitem->link,
- url_html?url_html:"",
- (fitem->text ? fitem->text : ""),
- (fitem->text ? "\n" : "") ) < 0 );
-
- g_free(meta_charset);
- g_free(url_html);
- if( fitem->media ) {
- if( fitem->media->size > 0 ) {
- tmpid = g_strdup_printf(ngettext("%ld byte", "%ld bytes",
- fitem->media->size), fitem->media->size);
- } else {
- tmpid = g_strdup(_("size unknown"));
- }
-
- fprintf(f, "<p><a href=\"%s\">Attached media file</a> [%s] (%s)</p>\n",
- fitem->media->url, fitem->media->type, tmpid);
-
- g_free(tmpid);
- }
-
- if( fitem->media )
- err |= (fprintf(f,
- "<p><a href=\"%s\">Attached media file</a> [%s] (%ld bytes)</p>\n",
- fitem->media->url, fitem->media->type, fitem->media->size) < 0);
-
- err |= (fprintf(f, "</body></html>\n") < 0);
-
- err |= (fclose(f) == EOF);
-
- if (!err) {
- g_return_val_if_fail(template != NULL, FALSE);
- d = folder_item_add_msg(&ritem->item, template, flags, TRUE);
- }
- g_free(template);
-
- if (ritem->silent_update == 2
- || (ritem->silent_update == 1 && dif == EXISTS_CHANGED_TEXTONLY))
- procmsg_msginfo_unset_flags(
- folder_item_get_msginfo((FolderItem *)ritem, d), MSG_NEW | MSG_UNREAD, 0);
- else
-
- debug_print("RSSyl: folder_item_add_msg(): %d, err %d\n", d, err);
-
- return err ? FALSE:TRUE;
-}
-
-MsgInfo *rssyl_parse_feed_item_to_msginfo(gchar *file, MsgFlags flags,
- gboolean a, gboolean b, FolderItem *item)
-{
- MsgInfo *msginfo;
-
- g_return_val_if_fail(item != NULL, NULL);
-
- msginfo = procheader_parse_file(file, flags, a, b);
- if (msginfo)
- msginfo->folder = item;
-
- return msginfo;
-}
-
-void rssyl_remove_feed_cache(FolderItem *item)
-{
- gchar *path;
- DIR *dp;
- struct dirent *d;
- gint num = 0;
-
- g_return_if_fail(item != NULL);
-
- debug_print("Removing local cache for '%s'\n", item->name);
-
- path = folder_item_get_path(item);
- g_return_if_fail(path != NULL);
- if( change_dir(path) < 0 ) {
- g_free(path);
- return;
- }
-
- debug_print("Emptying '%s'\n", path);
-
- if( (dp = opendir(".")) == NULL ) {
- FILE_OP_ERROR(item->path, "opendir");
- return;
- }
-
- while( (d = readdir(dp)) != NULL ) {
- g_remove(d->d_name);
- num++;
- }
- closedir(dp);
-
- debug_print("Removed %d files\n", num);
-
- g_remove(path);
- g_free(path);
-}
-
-void rssyl_update_comments(RSSylFolderItem *ritem)
-{
- FolderItem *item = &ritem->item;
- RSSylFeedItem *fitem = NULL;
- DIR *dp;
- struct dirent *d;
- gint num;
- gchar *path;
-
- g_return_if_fail(ritem != NULL);
-
- if (ritem->fetch_comments == FALSE)
- return;
-
- path = folder_item_get_path(item);
- g_return_if_fail(path != NULL);
- if( change_dir(path) < 0 ) {
- g_free(path);
- return;
- }
-
- if( (dp = opendir(".")) == NULL ) {
- FILE_OP_ERROR(item->path, "opendir");
- g_free(path);
- return;
- }
-
- while( (d = readdir(dp)) != NULL ) {
- if (claws_is_exiting()) {
- g_free(path);
- closedir(dp);
- debug_print("RSSyl: update_comments bailing out, app is exiting\n");
- return;
- }
-
- if( (num = to_number(d->d_name)) > 0 && dirent_is_regular_file(d) ) {
- debug_print("RSSyl: starting to parse '%s'\n", d->d_name);
- if( (fitem = rssyl_parse_folder_item_file(path, d->d_name)) != NULL ) {
- xmlDocPtr doc;
- gchar *title;
- if (fitem->comments_link && fitem->id &&
- (ritem->fetch_comments_for == -1 ||
- time(NULL) - fitem->date <= ritem->fetch_comments_for*86400)) {
- debug_print("RSSyl: fetching comments '%s'\n", fitem->comments_link);
- doc = rssyl_fetch_feed(fitem->comments_link, ritem->item.mtime,
- ritem->ssl_verify_peer, &title, NULL);
- rssyl_parse_feed(doc, ritem, fitem->id);
- xmlFreeDoc(doc);
- g_free(title);
- }
- rssyl_free_feeditem(fitem);
- }
- }
- }
- closedir(dp);
- g_free(path);
-
- debug_print("RSSyl: rssyl_update_comments() is returning\n");
-}
-
-void rssyl_update_feed(RSSylFolderItem *ritem)
-{
- gchar *title = NULL, *dir = NULL, *error = NULL, *dir2, *tmp;
- xmlDocPtr doc = NULL;
-
- g_return_if_fail(ritem != NULL);
-
- if( !ritem->url )
- rssyl_get_feed_props(ritem);
- g_return_if_fail(ritem->url != NULL);
-
- log_print(LOG_PROTOCOL, RSSYL_LOG_UPDATING, ritem->url);
-
- doc = rssyl_fetch_feed(ritem->url, ritem->item.mtime, ritem->ssl_verify_peer, &title, &error);
-
- if (claws_is_exiting()) {
- debug_print("RSSyl: Claws-Mail is exiting, aborting feed parsing\n");
- log_print(LOG_PROTOCOL, RSSYL_LOG_EXITING);
- if (error)
- g_free(error);
- if (doc)
- xmlFreeDoc(doc);
- g_free(title);
- g_free(dir);
- return;
- }
-
- if (error) {
- log_error(LOG_PROTOCOL, _("RSSyl: Cannot update feed %s:\n%s\n"), ritem->url, error);
- }
- g_free(error);
-
- if (doc && title) {
- tmp = rssyl_feed_title_to_dir(title);
- dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
- G_DIR_SEPARATOR_S, tmp, NULL);
- g_free(tmp);
- if( strcmp(title, ritem->official_name) ) {
- tmp = rssyl_feed_title_to_dir((&ritem->item)->name);
- dir2 = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
- G_DIR_SEPARATOR_S, tmp,
- NULL);
- g_free(tmp);
- if( g_rename(dir2, dir) == -1 ) {
- g_warning("couldn't rename directory '%s'\n", dir2);
- g_free(dir);
- g_free(dir2);
- g_free(title);
- xmlFreeDoc(doc);
- return;
- }
- g_free(dir2);
-
- rssyl_props_update_name(ritem, title);
-
- g_free((&ritem->item)->name);
- (&ritem->item)->name = g_strdup(title);
- g_free(ritem->official_name);
- ritem->official_name = g_strdup(title);
- folder_item_rename(&ritem->item, title);
- rssyl_store_feed_props(ritem);
- }
-
- rssyl_parse_feed(doc, ritem, NULL);
-
- if (claws_is_exiting()) {
- debug_print("RSSyl: Claws-Mail is exiting, aborting feed parsing\n");
- log_print(LOG_PROTOCOL, RSSYL_LOG_EXITING);
- if (error)
- g_free(error);
- if (doc)
- xmlFreeDoc(doc);
- g_free(title);
- g_free(dir);
- return;
- }
-
- rssyl_expire_items(ritem);
- }
-
- if (claws_is_exiting()) {
- g_free(title);
- g_free(dir);
- if (doc)
- xmlFreeDoc(doc);
- return;
- }
-
- if( ritem->fetch_comments == TRUE)
- rssyl_update_comments(ritem);
-
- ritem->item.mtime = time(NULL);
- debug_print("setting %s mtime to %ld\n", ritem->item.name, (long int)time(NULL));
-
- if (doc)
- xmlFreeDoc(doc);
- g_free(title);
- g_free(dir);
-
- log_print(LOG_PROTOCOL, RSSYL_LOG_UPDATED, ritem->url);
-}
-
-void rssyl_start_refresh_timeout(RSSylFolderItem *ritem)
-{
- RSSylRefreshCtx *ctx;
- guint source_id;
- RSSylPrefs *rsprefs = NULL;
-
- g_return_if_fail(ritem != NULL);
-
- if( ritem->default_refresh_interval ) {
- rsprefs = rssyl_prefs_get();
- ritem->refresh_interval = rsprefs->refresh;
- }
-
- /* Do not start refreshing if the interval is set to 0 */
- if( ritem->refresh_interval == 0 )
- return;
-
- ctx = g_new0(RSSylRefreshCtx, 1);
- ctx->ritem = ritem;
-
- source_id = g_timeout_add(ritem->refresh_interval * 60 * 1000,
- (GSourceFunc)rssyl_refresh_timeout_cb, ctx );
- ritem->refresh_id = source_id;
- ctx->id = source_id;
-
- debug_print("RSSyl: start_refresh_timeout - %d min (id %d)\n",
- ritem->refresh_interval, ctx->id);
-}
-
-static void rssyl_find_feed_by_url_func(FolderItem *item, gpointer data)
-{
- RSSylFolderItem *ritem;
- RSSylFindByUrlCtx *ctx = (RSSylFindByUrlCtx *)data;
-
- /* If we've already found a feed with desired URL, don't do anything */
- if( ctx->ritem != NULL )
- return;
-
- /* Only check rssyl folders */
- if( !IS_RSSYL_FOLDER_ITEM(item) )
- return;
-
- /* Don't bother with the root folder */
- if( folder_item_parent(item) == NULL )
- return;
-
- ritem = (RSSylFolderItem *)item;
-
- if( ritem->url && ctx->url && !strcmp(ritem->url, ctx->url) )
- ctx->ritem = ritem;
-}
-
-static RSSylFolderItem *rssyl_find_feed_by_url(gchar *url)
-{
- RSSylFindByUrlCtx *ctx = NULL;
- RSSylFolderItem *ritem = NULL;
-
- g_return_val_if_fail(url != NULL, NULL);
-
- ctx = g_new0(RSSylFindByUrlCtx, 1);
- ctx->url = url;
- ctx->ritem = NULL;
-
- folder_func_to_all_folders(
- (FolderItemFunc)rssyl_find_feed_by_url_func, ctx);
-
- if( ctx->ritem != NULL )
- ritem = ctx->ritem;
-
- g_free(ctx);
-
- return ritem;
-}
-
-FolderItem *rssyl_subscribe_new_feed(FolderItem *parent, const gchar *url,
- gboolean verbose)
-{
- gchar *title = NULL;
- xmlDocPtr doc;
- FolderItem *new_item;
- RSSylFolderItem *ritem;
- gchar *myurl = NULL;
- gchar *error = NULL;
-
- g_return_val_if_fail(parent != NULL, NULL);
- g_return_val_if_fail(url != NULL, NULL);
-
- if (!strncmp(url, "feed://", 7))
- myurl = g_strdup(url+7);
- else if (!strncmp(url, "feed:", 5))
- myurl = g_strdup(url+5);
- else
- myurl = g_strdup(url);
-
- myurl = g_strchomp(myurl);
-
- if( rssyl_find_feed_by_url(myurl) != NULL ) {
- if (verbose)
- alertpanel_error(_("You are already subscribed to this feed."));
- g_free(myurl);
- return NULL;
- }
-
- main_window_cursor_wait(mainwindow_get_mainwindow());
- doc = rssyl_fetch_feed(myurl, -1, rssyl_prefs_get()->ssl_verify_peer, &title, &error);
- main_window_cursor_normal(mainwindow_get_mainwindow());
- if( !doc || !title ) {
- if (verbose) {
- gchar *tmp;
- tmp = g_markup_printf_escaped(_("Couldn't fetch URL '%s':\n%s"),
- myurl, error ? error:_("Unknown error"));
- alertpanel_error("%s", tmp);
- g_free(tmp);
- } else
- log_error(LOG_PROTOCOL, _("Couldn't fetch URL '%s':\n%s\n"), myurl, error ? error:_("Unknown error"));
- g_free(myurl);
- g_free(error);
- g_free(title);
- if (doc)
- xmlFreeDoc(doc);
- return NULL;
- }
-
- g_free(error);
-
- new_item = folder_create_folder(parent, title);
- if( !new_item ) {
- if (verbose) {
- gchar *tmp;
- tmp = g_markup_printf_escaped("%s", title);
- alertpanel_error(_("Can't subscribe feed '%s'."), title);
- g_free(tmp);
- }
- g_free(myurl);
- xmlFreeDoc(doc);
- return NULL;
- }
-
- ritem = (RSSylFolderItem *)new_item;
- ritem->url = myurl;
-
- ritem->default_refresh_interval = TRUE;
- ritem->default_expired_num = TRUE;
-
- rssyl_store_feed_props(ritem);
-
- folder_write_list();
-
- rssyl_parse_feed(doc, ritem, NULL);
- xmlFreeDoc(doc);
-
- rssyl_expire_items(ritem);
-
- /* TODO: allow user to enable this when adding the feed */
- if( ritem->fetch_comments )
- rssyl_update_comments(ritem);
-
- /* update official_title */
- rssyl_store_feed_props(ritem);
- rssyl_start_refresh_timeout(ritem);
-
- folder_item_scan(new_item);
- return new_item;
-}
-
-static gint rssyl_expire_sort_func(RSSylFeedItem *a, RSSylFeedItem *b)
-{
- if( !a || !b )
- return 0;
-
- return (b->date - a->date);
-}
-
-void rssyl_expire_items(RSSylFolderItem *ritem)
-{
- int num;
- RSSylFeedItem *fitem;
- GSList *i;
-
- g_return_if_fail(ritem != NULL);
-
- rssyl_read_existing(ritem);
-
- g_return_if_fail(ritem->contents != NULL);
-
- num = ritem->expired_num;
- if( num == -1 ||
- (num > (g_slist_length(ritem->contents) - ritem->last_count)) )
- return;
-
- debug_print("RSSyl: rssyl_expire_items()\n");
-
- ritem->contents = g_slist_sort(ritem->contents,
- (GCompareFunc)rssyl_expire_sort_func);
-
- debug_print("RSSyl: finished sorting\n");
-
- while( (i = g_slist_nth(ritem->contents, ritem->last_count + num + 1)) ) {
- fitem = (RSSylFeedItem *)i->data;
- debug_print("RSSyl: expiring '%s'\n", fitem->realpath);
- g_remove(fitem->realpath);
- rssyl_free_feeditem(fitem);
- fitem = NULL;
- ritem->contents = g_slist_remove(ritem->contents, i->data);
- }
-
- folder_item_scan(&ritem->item);
-
- debug_print("RSSyl: finished expiring\n");
-}
-
-
-void rssyl_refresh_all_func(FolderItem *item, gpointer data)
-{
- RSSylFolderItem *ritem = (RSSylFolderItem *)item;
- /* Only try to refresh our feed folders */
- if( !IS_RSSYL_FOLDER_ITEM(item) )
- return;
-
- /* Don't try to refresh the root folder */
- if( folder_item_parent(item) == NULL )
- return;
- /* Don't try to update normal folders */
- if (ritem->url == NULL)
- return;
- rssyl_update_feed((RSSylFolderItem *)item);
-}
-
-void rssyl_refresh_all_feeds(void)
-{
- if (prefs_common_get_prefs()->work_offline &&
- !inc_offline_should_override(TRUE,
- ngettext("Claws Mail needs network access in order "
- "to update the feed.",
- "Claws Mail needs network access in order "
- "to update the feeds.", 2))) {
- return;
- }
-
- folder_func_to_all_folders((FolderItemFunc)rssyl_refresh_all_func, NULL);
-}
diff --git a/src/plugins/rssyl/feed.h b/src/plugins/rssyl/feed.h
deleted file mode 100644
index 1d66b7d..0000000
--- a/src/plugins/rssyl/feed.h
+++ /dev/null
@@ -1,94 +0,0 @@
-#ifndef __FEED_H
-#define __FEED_H
-
-#include <libxml/parser.h>
-
-#include "procmsg.h"
-
-#include "rssyl.h"
-
-#define RSSYL_TMP_TEMPLATE "curltmpXXXXXX"
-
-#define RSSYL_XPATH_ROOT "/rssyl"
-#define RSSYL_XPATH_TITLE RSSYL_XPATH_ROOT"/title"
-#define RSSYL_XPATH_LINK RSSYL_XPATH_ROOT"/link"
-#define RSSYL_XPATH_TEXT RSSYL_XPATH_ROOT"/text"
-
-#define RSSYL_TEXT_START "<!-- RSSyl text start -->"
-#define RSSYL_TEXT_END "<!-- RSSyl text end -->"
-
-#define RSSYL_LOG_ERROR_TIMEOUT _("Time out connecting to URL %s\n")
-#define RSSYL_LOG_ERROR_FETCH _("Couldn't fetch URL %s\n")
-#define RSSYL_LOG_ERROR_PARSE _("Error parsing feed from URL %s\n")
-#define RSSYL_LOG_ERROR_UNKNOWN _("Unsupported feed type at URL %s\n")
-
-#define RSSYL_LOG_UPDATING _("RSSyl: Updating feed %s\n")
-#define RSSYL_LOG_UPDATED _("RSSyl: Feed update finished: %s\n")
-#define RSSYL_LOG_EXITING _("RSSyl: Feed update aborted, application is exiting.\n")
-
-struct _RSSylFeedItemMedia {
- gchar *url;
- gchar *type;
- gulong size;
-};
-
-typedef struct _RSSylFeedItemMedia RSSylFeedItemMedia;
-
-struct _RSSylFeedItem {
- gchar *title;
- gchar *text;
- gchar *link;
- gchar *parent_link;
- gchar *comments_link;
- gchar *author;
- gchar *id;
- gboolean id_is_permalink;
-
- RSSylFeedItemMedia *media;
-
-#ifdef RSSYL_DEBUG
- long int debug_fetched;
-#endif /* RSSYL_DEBUG */
-
- gchar *realpath;
- time_t date;
- time_t date_published;
-};
-
-typedef struct _RSSylFeedItem RSSylFeedItem;
-
-struct _RSSylFindByUrlCtx {
- gchar *url;
- RSSylFolderItem *ritem;
-};
-
-typedef struct _RSSylFindByUrlCtx RSSylFindByUrlCtx;
-
-struct _RSSylParseCtx {
- RSSylFolderItem *ritem;
- gboolean ready;
-};
-
-typedef struct _RSSylParseCtx RSSylParseCtx;
-
-xmlDocPtr rssyl_fetch_feed(const gchar *url, time_t last_update, gboolean ssl_verify_peer, gchar **title, gchar **error);
-void rssyl_parse_feed(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent);
-gboolean rssyl_add_feed_item(RSSylFolderItem *ritem, RSSylFeedItem *fitem);
-MsgInfo *rssyl_parse_feed_item_to_msginfo(gchar *file, MsgFlags flags,
- gboolean a, gboolean b, FolderItem *item);
-void rssyl_remove_feed_cache(FolderItem *item);
-void rssyl_update_feed(RSSylFolderItem *ritem);
-void rssyl_read_existing(RSSylFolderItem *ritem);
-
-void rssyl_start_refresh_timeout(RSSylFolderItem *ritem);
-void rssyl_expire_items(RSSylFolderItem *ritem);
-
-FolderItem *rssyl_subscribe_new_feed(FolderItem *parent, const gchar *url, gboolean verbose);
-void rssyl_free_feeditem(RSSylFeedItem *item);
-gchar *rssyl_format_string(const gchar *str, gboolean replace_html, gboolean replace_returns);
-
-void rssyl_refresh_all_func(FolderItem *item, gpointer data);
-void rssyl_refresh_all_feeds(void);
-gchar *rssyl_feed_title_to_dir(const gchar *title);
-
-#endif /* __FEED_H */
diff --git a/src/plugins/rssyl/feedprops.c b/src/plugins/rssyl/feedprops.c
deleted file mode 100644
index d52bde5..0000000
--- a/src/plugins/rssyl/feedprops.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2004 Hiroyuki Yamamoto
- * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
- *
- * - functions for handling feeds.xml file
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <glib.h>
-
-#include <libxml/parser.h>
-#include <libxml/xpath.h>
-
-#include "folder.h"
-
-#include "feed.h"
-#include "feedprops.h"
-#include "rssyl.h"
-#include "rssyl_prefs.h"
-
-static gchar *rssyl_get_props_path(void)
-{
- return g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
- G_DIR_SEPARATOR_S, RSSYL_PROPS_FILE, NULL);
-}
-
-
-/* rssyl_store_feed_props()
- *
- * Stores feed properties into feeds.xml file in the rcdir. Updates if already
- * stored for this feed.
- */
-void rssyl_store_feed_props(RSSylFolderItem *ritem)
-{
- gchar *path;
- xmlDocPtr doc;
- xmlNodePtr node, rootnode;
- xmlXPathObjectPtr result;
- xmlXPathContextPtr context;
- FolderItem *item = &ritem->item;
- gboolean found = FALSE, def_ri, def_ex;
- gint i;
-
- g_return_if_fail(ritem != NULL);
- g_return_if_fail(ritem->url != NULL);
-
- def_ri = ritem->default_refresh_interval;
- if( def_ri )
- ritem->refresh_interval = rssyl_prefs_get()->refresh;
-
- def_ex = ritem->default_expired_num;
- if( def_ex )
- ritem->expired_num = rssyl_prefs_get()->expired;
-
- path = rssyl_get_props_path();
-
- if( !(doc = xmlParseFile(path)) ) {
- debug_print("RSSyl: file %s doesn't exist, creating it\n", path);
- doc = xmlNewDoc("1.0");
-
- rootnode = xmlNewNode(NULL, "feeds");
- xmlDocSetRootElement(doc, rootnode);
- } else {
- rootnode = xmlDocGetRootElement(doc);
- }
-
- context = xmlXPathNewContext(doc);
- if( !(result = xmlXPathEvalExpression(RSSYL_PROPS_XPATH, context)) ) {
- debug_print("RSSyl: XML - no result found for %s\n", RSSYL_PROPS_XPATH);
- xmlXPathFreeContext(context);
- } else {
- for( i = 0; i < result->nodesetval->nodeNr; i++ ) {
- gchar *tmp, *t_prop = NULL;
- node = result->nodesetval->nodeTab[i];
- tmp = xmlGetProp(node, RSSYL_PROP_NAME);
-
- if( !strcmp(tmp, item->name) ) {
- debug_print("RSSyl: XML - updating node for '%s'\n", item->name);
-
- xmlSetProp(node, RSSYL_PROP_NAME, item->name);
- xmlSetProp(node, RSSYL_PROP_OFFICIAL_NAME,
- ritem->official_name?ritem->official_name:item->name);
- xmlSetProp(node, RSSYL_PROP_URL, ritem->url);
-
- xmlSetProp(node, RSSYL_PROP_DEF_REFRESH, (def_ri ? "1" : "0") );
- if( !def_ri ) {
- t_prop = g_strdup_printf("%d", ritem->refresh_interval);
- xmlSetProp(node, RSSYL_PROP_REFRESH,
- t_prop );
- g_free(t_prop);
- }
-
- xmlSetProp(node, RSSYL_PROP_DEF_EXPIRED, (def_ex ? "1" : "0") );
- if( !def_ex ) {
- t_prop = g_strdup_printf("%d", ritem->expired_num);
- xmlSetProp(node, RSSYL_PROP_EXPIRED,
- t_prop );
- g_free(t_prop);
- }
- xmlSetProp(node, RSSYL_PROP_FETCH_COMMENTS,
- (ritem->fetch_comments ? "1" : "0"));
- t_prop = g_strdup_printf("%d", ritem->fetch_comments_for);
- xmlSetProp(node, RSSYL_PROP_FETCH_COMMENTS_FOR, t_prop);
- g_free(t_prop);
-
- t_prop = g_strdup_printf("%d", ritem->silent_update);
- xmlSetProp(node, RSSYL_PROP_SILENT_UPDATE, t_prop);
- g_free(t_prop);
-
- t_prop = g_strdup_printf("%d", ritem->ssl_verify_peer);
- xmlSetProp(node, RSSYL_PROP_SSL_VERIFY_PEER, t_prop);
- g_free(t_prop);
-
- found = TRUE;
- }
- xmlFree(tmp);
- }
- }
-
- xmlXPathFreeContext(context);
- xmlXPathFreeObject(result);
-
- /* node for our feed doesn't exist, let's make one */
- if( !found ) {
- debug_print("RSSyl: XML - creating node for '%s', storing URL '%s'\n",
- item->name, ritem->url);
- node = xmlNewTextChild(rootnode, NULL, "feed", NULL);
- xmlSetProp(node, RSSYL_PROP_NAME, item->name);
- xmlSetProp(node, RSSYL_PROP_OFFICIAL_NAME,
- ritem->official_name?ritem->official_name:item->name);
- xmlSetProp(node, RSSYL_PROP_URL, ritem->url);
- xmlSetProp(node, RSSYL_PROP_DEF_REFRESH, (def_ri ? "1" : "0") );
- if( !def_ri )
- xmlSetProp(node, RSSYL_PROP_REFRESH,
- g_strdup_printf("%d", ritem->refresh_interval) );
- xmlSetProp(node, RSSYL_PROP_DEF_EXPIRED, (def_ex ? "1" : "0") );
- if( !def_ex )
- xmlSetProp(node, RSSYL_PROP_EXPIRED,
- g_strdup_printf("%d", ritem->expired_num) );
- }
-
- xmlSaveFormatFile(path, doc, 1);
- xmlFreeDoc(doc);
- g_free(path);
-}
-
-/* rssyl_get_feed_props()
- *
- * Retrieves props for feed from feeds.xml file in the rcdir.
- */
-void rssyl_get_feed_props(RSSylFolderItem *ritem)
-{
- gchar *path, *tmp = NULL;
- xmlDocPtr doc;
- xmlNodePtr node;
- xmlXPathObjectPtr result;
- xmlXPathContextPtr context;
- FolderItem *item = &ritem->item;
- gint i, tmpi;
- gboolean force_update = FALSE;
- RSSylPrefs *rsprefs = NULL;
-
- g_return_if_fail(ritem != NULL);
-
- if( ritem->url ) {
- g_free(ritem->url);
- ritem->url = NULL;
- }
-
- ritem->default_refresh_interval = TRUE;
- ritem->refresh_interval = rssyl_prefs_get()->refresh;
- ritem->expired_num = rssyl_prefs_get()->expired;
-
- path = rssyl_get_props_path();
-
- doc = xmlParseFile(path);
- g_return_if_fail(doc != NULL);
-
- context = xmlXPathNewContext(doc);
- if( !(result = xmlXPathEvalExpression(RSSYL_PROPS_XPATH, context)) ) {
- debug_print("RSSyl: XML - no result found for %s\n", RSSYL_PROPS_XPATH);
- xmlXPathFreeContext(context);
- } else {
- for( i = 0; i < result->nodesetval->nodeNr; i++ ) {
- gchar *property = NULL;
- node = result->nodesetval->nodeTab[i];
- property = xmlGetProp(node, RSSYL_PROP_NAME);
- if( !strcmp(property, item->name) ) {
- /* official name */
- tmp = xmlGetProp(node, RSSYL_PROP_OFFICIAL_NAME);
- ritem->official_name = (tmp ? g_strdup(tmp) : g_strdup(item->name));
- if (tmp == NULL)
- force_update = TRUE;
- xmlFree(tmp);
- tmp = NULL;
-
- /* URL */
- tmp = xmlGetProp(node, RSSYL_PROP_URL);
- ritem->url = (tmp ? g_strdup(tmp) : NULL);
- xmlFree(tmp);
- tmp = NULL;
-
- tmp = xmlGetProp(node, RSSYL_PROP_DEF_REFRESH);
- tmpi = 0;
- if( tmp )
- tmpi = atoi(tmp);
- ritem->default_refresh_interval = (tmpi ? TRUE : FALSE );
- xmlFree(tmp);
- tmp = NULL;
-
- /* refresh_interval */
- tmp = xmlGetProp(node, RSSYL_PROP_REFRESH);
- if( ritem->default_refresh_interval )
- ritem->refresh_interval = rssyl_prefs_get()->refresh;
- else {
- tmpi = -1;
- if( tmp )
- tmpi = atoi(tmp);
-
- ritem->refresh_interval =
- (tmpi != -1 ? tmpi : rssyl_prefs_get()->refresh);
- }
-
- xmlFree(tmp);
- tmp = NULL;
-
- /* expired_num */
- tmp = xmlGetProp(node, RSSYL_PROP_DEF_EXPIRED);
- tmpi = 0;
- if( tmp ) {
- tmpi = atoi(tmp);
- ritem->default_expired_num = tmpi;
- }
- xmlFree(tmp);
- tmp = NULL;
-
- /* fetch_comments */
- tmp = xmlGetProp(node, RSSYL_PROP_FETCH_COMMENTS);
- tmpi = 0;
- if( tmp ) {
- tmpi = atoi(tmp);
- ritem->fetch_comments = tmpi;
- }
- xmlFree(tmp);
- tmp = NULL;
-
- /* fetch_comments_for */
- tmp = xmlGetProp(node, RSSYL_PROP_FETCH_COMMENTS_FOR);
- tmpi = 0;
- if( tmp ) {
- tmpi = atoi(tmp);
- ritem->fetch_comments_for = tmpi;
- }
- xmlFree(tmp);
- tmp = NULL;
-
- /* silent_update */
- tmp = xmlGetProp(node, RSSYL_PROP_SILENT_UPDATE);
- tmpi = 0;
- if( tmp ) {
- tmpi = atoi(tmp);
- ritem->silent_update = tmpi;
- }
- xmlFree(tmp);
- tmp = NULL;
-
- /* ssl_verify_peer */
- tmp = xmlGetProp(node, RSSYL_PROP_SSL_VERIFY_PEER);
- tmpi = 0;
- if( tmp ) {
- tmpi = atoi(tmp);
- ritem->ssl_verify_peer = tmpi;
- }
- xmlFree(tmp);
- tmp = NULL;
-
- tmp = xmlGetProp(node, RSSYL_PROP_EXPIRED);
-
- if( ritem->default_expired_num )
- ritem->expired_num = rssyl_prefs_get()->expired;
- else {
- tmpi = -2;
- if( tmp )
- tmpi = atoi(tmp);
-
- ritem->expired_num = (tmpi != -2 ? tmpi : rssyl_prefs_get()->expired);
- }
-
- xmlFree(tmp);
- tmp = NULL;
-
- debug_print("RSSyl: XML - props for '%s' loaded\n", item->name);
-
- /* Start automatic refresh timer, if necessary */
- if( ritem->refresh_id == 0 ) {
- /* Check if user wants the default for this feed */
- if( ritem->default_refresh_interval ) {
- rsprefs = rssyl_prefs_get();
- ritem->refresh_interval = rsprefs->refresh;
- }
-
- /* Start the timer, if determined interval is >0 */
- if( ritem->refresh_interval >= 0 )
- rssyl_start_refresh_timeout(ritem);
- }
- }
- xmlFree(property);
- }
- }
-
- xmlXPathFreeObject(result);
- xmlXPathFreeContext(context);
- xmlFreeDoc(doc);
- g_free(path);
- if (force_update)
- rssyl_store_feed_props(ritem);
-}
-
-void rssyl_remove_feed_props(RSSylFolderItem *ritem)
-{
- gchar *path;
- xmlDocPtr doc;
- xmlNodePtr node;
- xmlXPathObjectPtr result;
- xmlXPathContextPtr context;
- FolderItem *item = &ritem->item;
- gint i;
-
- g_return_if_fail(ritem != NULL);
-
- path = rssyl_get_props_path();
-
- doc = xmlParseFile(path);
- g_return_if_fail(doc != NULL);
-
- context = xmlXPathNewContext(doc);
- if( !(result = xmlXPathEvalExpression(RSSYL_PROPS_XPATH, context)) ) {
- debug_print("RSSyl: XML - no result found for %s\n", RSSYL_PROPS_XPATH);
- xmlXPathFreeContext(context);
- } else {
- for( i = 0; i < result->nodesetval->nodeNr; i++ ) {
- gchar *tmp;
- node = result->nodesetval->nodeTab[i];
- tmp = xmlGetProp(node, RSSYL_PROP_NAME);
- if( !strcmp(tmp, item->name) ) {
- debug_print("RSSyl: XML - found node for '%s', removing\n", item->name);
- xmlUnlinkNode(node);
- }
- xmlFree(tmp);
- }
- }
-
- xmlXPathFreeObject(result);
- xmlXPathFreeContext(context);
-
- xmlSaveFormatFile(path, doc, 1);
-
- xmlFreeDoc(doc);
- g_free(path);
-}
-
-void rssyl_props_update_name(RSSylFolderItem *ritem, gchar *new_name)
-{
- gchar *path;
- xmlDocPtr doc;
- xmlNodePtr node, rootnode;
- xmlXPathObjectPtr result;
- xmlXPathContextPtr context;
- FolderItem *item = &ritem->item;
- gboolean found = FALSE;
- gint i;
-
- g_return_if_fail(ritem != NULL);
- g_return_if_fail(ritem->url != NULL);
-
- path = rssyl_get_props_path();
-
- if( !(doc = xmlParseFile(path)) ) {
- debug_print("RSSyl: file %s doesn't exist, creating it\n", path);
- doc = xmlNewDoc("1.0");
-
- rootnode = xmlNewNode(NULL, "feeds");
- xmlDocSetRootElement(doc, rootnode);
- } else {
- rootnode = xmlDocGetRootElement(doc);
- }
-
- context = xmlXPathNewContext(doc);
- if( !(result = xmlXPathEvalExpression(RSSYL_PROPS_XPATH, context)) ) {
- debug_print("RSSyl: XML - no result found for %s\n", RSSYL_PROPS_XPATH);
- xmlXPathFreeContext(context);
- } else {
- for( i = 0; i < result->nodesetval->nodeNr; i++ ) {
- gchar *tmp;
- node = result->nodesetval->nodeTab[i];
- tmp = xmlGetProp(node, RSSYL_PROP_NAME);
- if( !strcmp(tmp, item->name) ) {
- debug_print("RSSyl: XML - updating node for '%s'\n", item->name);
- xmlSetProp(node, "name", new_name);
- found = TRUE;
- }
- xmlFree(tmp);
- }
- }
-
- xmlXPathFreeContext(context);
- xmlXPathFreeObject(result);
-
- if( !found )
- debug_print("couldn't find feed\n");
-
- xmlSaveFormatFile(path, doc, 1);
- xmlFreeDoc(doc);
- g_free(path);
-}
diff --git a/src/plugins/rssyl/feedprops.h b/src/plugins/rssyl/feedprops.h
deleted file mode 100644
index f4a3b27..0000000
--- a/src/plugins/rssyl/feedprops.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __FEEDPROPS_H
-#define __FEEDPROPS_H
-
-#include "rssyl.h"
-
-#define RSSYL_PROPS_FILE "feeds.xml"
-#define RSSYL_PROPS_XPATH "/feeds/feed"
-
-#define RSSYL_PROP_URL "url"
-#define RSSYL_PROP_NAME "name"
-#define RSSYL_PROP_OFFICIAL_NAME "official_name"
-#define RSSYL_PROP_DEF_REFRESH "default_refresh_interval"
-#define RSSYL_PROP_REFRESH "refresh_interval"
-#define RSSYL_PROP_DEF_EXPIRED "default_expired_num"
-#define RSSYL_PROP_EXPIRED "expired_num"
-#define RSSYL_PROP_FETCH_COMMENTS "fetch_comments"
-#define RSSYL_PROP_FETCH_COMMENTS_FOR "fetch_comments_for"
-#define RSSYL_PROP_SILENT_UPDATE "silent_update"
-#define RSSYL_PROP_SSL_VERIFY_PEER "ssl_verify_peer"
-
-void rssyl_store_feed_props(RSSylFolderItem *ritem);
-void rssyl_get_feed_props(RSSylFolderItem *ritem);
-void rssyl_remove_feed_props(RSSylFolderItem *ritem);
-void rssyl_props_update_name(RSSylFolderItem *ritem, gchar *new_name);
-
-#endif /* __FEEDPROPS_H */
diff --git a/src/plugins/rssyl/libfeed/Makefile.am b/src/plugins/rssyl/libfeed/Makefile.am
new file mode 100644
index 0000000..227b25e
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/Makefile.am
@@ -0,0 +1,22 @@
+noinst_LTLIBRARIES = libfeed.la
+
+INCLUDES = \
+ -I$(top_srcdir)/src \
+ -I.
+
+libfeed_la_CPPFLAGS = \
+ -Wall \
+ $(CLAWS_MAIL_CFLAGS) \
+ $(GLIB_CFLAGS) \
+ $(GTK_CFLAGS)
+
+libfeed_la_SOURCES = \
+ date.c date.h \
+ feed.c feed.h \
+ feeditem.c feeditem.h \
+ feeditemenclosure.c feeditemenclosure.h \
+ parser.c parser.h \
+ parser_atom10.c parser_atom10.h \
+ parser_opml.c parser_opml.h \
+ parser_rdf.c parser_rdf.h \
+ parser_rss20.c parser_rss20.h
diff --git a/src/plugins/rssyl/date.c b/src/plugins/rssyl/libfeed/date.c
similarity index 76%
rename from src/plugins/rssyl/date.c
rename to src/plugins/rssyl/libfeed/date.c
index 4145f52..2b8ffff 100644
--- a/src/plugins/rssyl/date.c
+++ b/src/plugins/rssyl/libfeed/date.c
@@ -33,15 +33,7 @@
#endif
/* this is needed for strptime() */
-#if !defined (__FreeBSD__)
-#define _XOPEN_SOURCE 600 /* glibc2 needs this */
-#else
-#define _XOPEN_SOURCE
-#endif
-
-#ifdef USE_PTHREAD
-#include <pthread.h>
-#endif
+#define _XOPEN_SOURCE /* glibc2 needs this */
#include <time.h>
#include <glib.h>
@@ -50,46 +42,17 @@
#include <ctype.h>
#include <stdlib.h>
-#include "procheader.h"
-
/* converts a ISO 8601 time string to a time_t value */
time_t parseISO8601Date(gchar *date) {
struct tm tm;
time_t t, t2, offset = 0;
gboolean success = FALSE;
-#ifdef G_OS_WIN32
- gchar *tmp = g_strdup(date);
- gint result, year, month, day, hour, minute, second;
-#else
gchar *pos;
-#endif
+
g_assert(date != NULL);
memset(&tm, 0, sizeof(struct tm));
-#ifdef G_OS_WIN32
- g_strstrip(tmp);
- result = sscanf((const char *)date, "%d-%d-%dT%d:%d:%d",
- &year, &month, &day, &hour, &minute, &second);
- if (result < 6)
- second = 0;
- if (result < 5)
- minute = 0;
- if (result < 4)
- hour = 0;
- if (result >= 3) {
- tm.tm_sec = second;
- tm.tm_min = minute;
- tm.tm_hour = hour;
- tm.tm_mday = day;
- tm.tm_mon = month - 1;
- tm.tm_year = year - 1900;
- tm.tm_wday = 0;
- tm.tm_yday = 0;
- tm.tm_isdst = -1;
- success = TRUE;
- }
-#else
/* we expect at least something like "2003-08-07T15:28:19" and
don't require the second fractions and the timezone info
@@ -97,7 +60,7 @@ time_t parseISO8601Date(gchar *date) {
*/
/* full specified variant */
- if(NULL != (pos = strptime((const char *)date, "%t%Y-%m-%dT%H:%M%t", &tm))) {
+ if(NULL != (pos = strptime((const char *)date, "%Y-%m-%dT%H:%M:%SZ", &tm))) {
/* Parse seconds */
if (*pos == ':')
pos++;
@@ -127,13 +90,12 @@ time_t parseISO8601Date(gchar *date) {
} else if(NULL != strptime((const char *)date, "%t%Y-%m-%d", &tm))
success = TRUE;
/* there were others combinations too... */
-#endif
+
if(TRUE == success) {
if((time_t)(-1) != (t = mktime(&tm))) {
- struct tm buft;
/* Correct for the local timezone*/
t = t - offset;
- t2 = mktime(gmtime_r(&t, &buft));
+ t2 = mktime(gmtime(&t));
t = t - (t2 - t);
return t;
@@ -152,16 +114,34 @@ gchar *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"
gchar *createRFC822Date(const time_t *time) {
struct tm *tm;
- struct tm buft;
-#ifdef G_OS_WIN32
- if (*time < 0) {
- time_t t = 1;
- tm = gmtime_r(&t, &buft);
- } else
-#endif
- {
- tm = gmtime_r(time, &buft); /* No need to free because it is statically allocated */
- }
+
+ tm = gmtime(time); /* No need to free because it is statically allocated */
return g_strdup_printf("%s, %2d %s %4d %02d:%02d:%02d GMT", dayofweek[tm->tm_wday], tm->tm_mday,
months[tm->tm_mon], 1900 + tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec);
}
+
+time_t parseRFC822Date(gchar *date)
+{
+ struct tm t;
+ memset(&t, 0, sizeof(struct tm));
+ const char *c = setlocale(LC_TIME, NULL);
+
+ /* Adjust the LC_TIME locale to standard C in order for strptime()
+ * to work reliably. */
+ if (c != NULL)
+ setlocale(LC_TIME, "C");
+
+ if (!strptime(date, "%a, %d %b %Y %H:%M:%S %Z", &t) &&
+ !strptime(date, "%a, %d %b %Y %H:%M %Z", &t)) {
+ g_warning("Invalid RFC822 date!\n");
+ if (c != NULL)
+ setlocale(LC_TIME, c);
+ return 0;
+ }
+
+ /* Restore the original LC_TIME locale. */
+ if (c != NULL)
+ setlocale(LC_TIME, c);
+
+ return mktime(&t);
+}
diff --git a/src/plugins/rssyl/date.h b/src/plugins/rssyl/libfeed/date.h
similarity index 82%
rename from src/plugins/rssyl/date.h
rename to src/plugins/rssyl/libfeed/date.h
index 27c1353..c8ea1a6 100644
--- a/src/plugins/rssyl/date.h
+++ b/src/plugins/rssyl/libfeed/date.h
@@ -6,5 +6,6 @@
time_t parseISO8601Date(gchar *date);
gchar *createRFC822Date(const time_t *time);
+time_t parseRFC822Date(gchar *date);
#endif /* __DATE_H */
diff --git a/src/plugins/rssyl/libfeed/feed.c b/src/plugins/rssyl/libfeed/feed.c
new file mode 100644
index 0000000..7719278
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/feed.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#define __USE_GNU
+
+#include <stdlib.h>
+#include <glib.h>
+#include <curl/curl.h>
+#include <expat.h>
+
+#include "feed.h"
+#include "parser.h"
+
+/* feed_new()
+ * Initializes new Feed struct, setting its url and a default timeout. */
+Feed *feed_new(gchar *url)
+{
+ Feed *feed = NULL;
+
+ g_return_val_if_fail(url != NULL, NULL);
+
+ feed = malloc( sizeof(Feed) );
+ g_return_val_if_fail(feed != NULL, NULL);
+
+ feed->timeout = FEED_DEFAULT_TIMEOUT;
+ feed->url = g_strdup(url);
+ feed->title = NULL;
+ feed->description = NULL;
+ feed->language = NULL;
+ feed->author = NULL;
+ feed->generator = NULL;
+ feed->items = NULL;
+
+ feed->fetcherr = NULL;
+ feed->cookies_path = NULL;
+
+ return feed;
+}
+
+static void _free_items(gpointer item, gpointer nada)
+{
+ feed_item_free(item);
+}
+
+void feed_free(Feed *feed)
+{
+ if( feed == NULL )
+ return; /* Return silently, without printing a glib error. */
+
+ g_free(feed->url);
+ g_free(feed->title);
+ g_free(feed->description);
+ g_free(feed->language);
+ g_free(feed->author);
+ g_free(feed->generator);
+ g_free(feed->fetcherr);
+ g_free(feed->cookies_path);
+
+ if( feed->items != NULL ) {
+ g_slist_foreach(feed->items, _free_items, NULL);
+ g_slist_free(feed->items);
+ }
+
+ g_free(feed);
+ feed = NULL;
+}
+
+void feed_free_items(Feed *feed)
+{
+ if( feed == NULL )
+ return;
+
+ if( feed->items != NULL ) {
+ g_slist_foreach(feed->items, _free_items, NULL);
+ g_slist_free(feed->items);
+ feed->items = NULL;
+ }
+}
+
+/* Timeout */
+void feed_set_timeout(Feed *feed, guint timeout)
+{
+ g_return_if_fail(feed != NULL);
+ feed->timeout = timeout;
+}
+
+guint feed_get_timeout(Feed *feed)
+{
+ g_return_val_if_fail(feed != NULL, 0);
+ return feed->timeout;
+}
+
+/* URL */
+void feed_set_url(Feed *feed, gchar *url)
+{
+ g_return_if_fail(feed != NULL);
+ g_return_if_fail(url != NULL);
+
+ if( feed->url != NULL ) {
+ g_free(feed->url);
+ feed->url = NULL;
+ }
+
+ feed->url = g_strdup(url);
+}
+
+gchar *feed_get_url(Feed *feed)
+{
+ g_return_val_if_fail(feed != NULL, NULL);
+ return feed->url;
+}
+
+/* Title */
+gchar *feed_get_title(Feed *feed)
+{
+ g_return_val_if_fail(feed != NULL, NULL);
+ return feed->title;
+}
+
+void feed_set_title(Feed *feed, gchar *new_title)
+{
+ g_return_if_fail(feed != NULL);
+ g_return_if_fail(new_title != NULL);
+
+ if (feed->title != NULL) {
+ g_free(feed->title);
+ feed->title = NULL;
+ }
+
+ feed->title = g_strdup(new_title);
+}
+
+/* Description */
+gchar *feed_get_description(Feed *feed)
+{
+ g_return_val_if_fail(feed != NULL, NULL);
+ return feed->description;
+}
+
+/* Language */
+gchar *feed_get_language(Feed *feed)
+{
+ g_return_val_if_fail(feed != NULL, NULL);
+ return feed->language;
+}
+
+/* Author */
+gchar *feed_get_author(Feed *feed)
+{
+ g_return_val_if_fail(feed != NULL, NULL);
+ return feed->author;
+}
+
+/* Generator */
+gchar *feed_get_generator(Feed *feed)
+{
+ g_return_val_if_fail(feed != NULL, NULL);
+ return feed->generator;
+}
+
+/* Fetch error (if not NULL, supplied by libcurl) */
+gchar *feed_get_fetcherror(Feed *feed)
+{
+ g_return_val_if_fail(feed != NULL, NULL);
+ return feed->fetcherr;
+}
+
+/* Returns number of items currently in the feed. */
+gint feed_n_items(Feed *feed)
+{
+ g_return_val_if_fail(feed != NULL, -1);
+
+ if( feed->items == NULL ) /* No items here. */
+ return 0;
+
+ return g_slist_length(feed->items);
+}
+
+/* Returns nth item from feed. */
+FeedItem *feed_nth_item(Feed *feed, guint n)
+{
+ g_return_val_if_fail(feed != NULL, NULL);
+
+ return g_slist_nth_data(feed->items, n);
+}
+
+/* feed_update()
+ * Takes initialized feed with url set, fetches the feed from this url,
+ * updates rest of Feed struct members and returns HTTP response code
+ * we got from url's server. */
+guint feed_update(Feed *feed, time_t last_update)
+{
+ CURL *eh = NULL;
+ CURLcode res;
+ FeedParserCtx *feed_ctx = NULL;
+ glong response_code = 0;
+
+ g_return_val_if_fail(feed != NULL, FEED_ERR_NOFEED);
+ g_return_val_if_fail(feed->url != NULL, FEED_ERR_NOURL);
+
+ /* Init curl before anything else. */
+ eh = curl_easy_init();
+
+ g_return_val_if_fail(eh != NULL, FEED_ERR_INIT);
+
+ /* Curl initialized, create parser context now. */
+ feed_ctx = malloc( sizeof(FeedParserCtx) );
+
+ feed_ctx->parser = XML_ParserCreate(NULL);
+ feed_ctx->depth = 0;
+ feed_ctx->str = NULL;
+ feed_ctx->feed = feed;
+ feed_ctx->location = 0;
+ feed_ctx->curitem = NULL;
+ feed_ctx->id_is_permalink = TRUE;
+
+ feed_ctx->name = NULL;
+ feed_ctx->mail = NULL;
+
+ /* Set initial expat handlers, which will take care of choosing
+ * correct parser later. */
+ feed_parser_set_expat_handlers(feed_ctx);
+
+ curl_easy_setopt(eh, CURLOPT_URL, feed->url);
+ curl_easy_setopt(eh, CURLOPT_NOPROGRESS, 1);
+#ifdef CURLOPT_MUTE
+ curl_easy_setopt(eh, CURLOPT_MUTE, 1);
+#endif
+ curl_easy_setopt(eh, CURLOPT_WRITEFUNCTION, feed_writefunc);
+ curl_easy_setopt(eh, CURLOPT_WRITEDATA, feed_ctx);
+ curl_easy_setopt(eh, CURLOPT_FOLLOWLOCATION, 1);
+ curl_easy_setopt(eh, CURLOPT_MAXREDIRS, 3);
+ curl_easy_setopt(eh, CURLOPT_TIMEOUT, feed->timeout);
+ curl_easy_setopt(eh, CURLOPT_NOSIGNAL, 1);
+ curl_easy_setopt(eh, CURLOPT_ENCODING, "");
+ curl_easy_setopt(eh, CURLOPT_USERAGENT, "libfeed 0.1");
+
+ /* Use HTTP's If-Modified-Since feature, if application provided
+ * the timestamp of last update. */
+ if( last_update != -1 ) {
+ curl_easy_setopt(eh, CURLOPT_TIMECONDITION,
+ CURL_TIMECOND_IFMODSINCE);
+ curl_easy_setopt(eh, CURLOPT_TIMEVALUE, last_update);
+ }
+
+#if LIBCURL_VERSION_NUM >= 0x070a00
+ if (feed->ssl_verify_peer == FALSE) {
+ curl_easy_setopt(eh, CURLOPT_SSL_VERIFYPEER, 0);
+ curl_easy_setopt(eh, CURLOPT_SSL_VERIFYHOST, 0);
+ }
+#endif
+
+ if(feed->cookies_path != NULL)
+ curl_easy_setopt(eh, CURLOPT_COOKIEFILE, feed->cookies_path);
+
+ res = curl_easy_perform(eh);
+ XML_Parse(feed_ctx->parser, "", 0, TRUE);
+
+ if( res != CURLE_OK ) {
+ feed->fetcherr = g_strdup(curl_easy_strerror(res));
+ response_code = FEED_ERR_FETCH;
+ } else
+ curl_easy_getinfo(eh, CURLINFO_RESPONSE_CODE, &response_code);
+
+ curl_easy_cleanup(eh);
+
+ /* Cleanup, we should be done. */
+ XML_ParserFree(feed_ctx->parser);
+ g_free(feed_ctx->name);
+ g_free(feed_ctx->mail);
+ g_free(feed_ctx);
+
+ return response_code;
+}
+
+void feed_foreach_item(Feed *feed, GFunc func, gpointer data)
+{
+ g_return_if_fail(feed != NULL);
+ g_return_if_fail(feed->items != NULL);
+
+ g_slist_foreach(feed->items, func, data);
+}
+
+gboolean feed_prepend_item(Feed *feed, FeedItem *item)
+{
+ g_return_val_if_fail(feed != NULL, FALSE);
+ g_return_val_if_fail(item != NULL, FALSE);
+
+ feed->items = g_slist_prepend(feed->items, item);
+ return TRUE;
+}
+
+gboolean feed_append_item(Feed *feed, FeedItem *item)
+{
+ g_return_val_if_fail(feed != NULL, FALSE);
+ g_return_val_if_fail(item != NULL, FALSE);
+
+ feed->items = g_slist_append(feed->items, item);
+ return TRUE;
+}
+
+gboolean feed_insert_item(Feed *feed, FeedItem *item, gint pos)
+{
+ g_return_val_if_fail(feed != NULL, FALSE);
+ g_return_val_if_fail(item != NULL, FALSE);
+ g_return_val_if_fail(pos < 0, FALSE);
+
+ feed->items = g_slist_insert(feed->items, item, pos);
+ return TRUE;
+}
+
+gchar *feed_get_cookies_path(Feed *feed)
+{
+ g_return_val_if_fail(feed != NULL, NULL);
+ return feed->cookies_path;
+}
+
+void feed_set_cookies_path(Feed *feed, gchar *path)
+{
+ g_return_if_fail(feed != NULL);
+
+ if( feed->cookies_path != NULL ) {
+ g_free(feed->cookies_path);
+ feed->cookies_path = NULL;
+ }
+
+ feed->cookies_path = (path != NULL ? g_strdup(path) : NULL);
+}
+
+gboolean feed_get_ssl_verify_peer(Feed *feed)
+{
+ g_return_val_if_fail(feed != NULL, FALSE);
+ return feed->ssl_verify_peer;
+}
+
+void feed_set_ssl_verify_peer(Feed *feed, gboolean ssl_verify_peer)
+{
+ g_return_if_fail(feed != NULL);
+ feed->ssl_verify_peer = ssl_verify_peer;
+}
diff --git a/src/plugins/rssyl/libfeed/feed.h b/src/plugins/rssyl/libfeed/feed.h
new file mode 100644
index 0000000..dc8847d
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/feed.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __FEED_H
+#define __FEED_H
+
+#include <glib.h>
+#include <expat.h>
+
+#define FEED_DEFAULT_TIMEOUT 20 /* In seconds */
+
+/* ---------------- Structures */
+
+typedef struct _Feed Feed;
+typedef struct _FeedItem FeedItem;
+typedef struct _FeedParserCtx FeedParserCtx;
+
+struct _Feed {
+ gchar *url;
+ gchar *title;
+ gchar *description;
+ gchar *language;
+ gchar *author;
+ gchar *generator;
+ time_t date;
+
+ guint timeout;
+ gchar *fetcherr;
+ gchar *cookies_path;
+ gboolean ssl_verify_peer;
+
+ GSList *items;
+};
+
+struct _FeedParserCtx {
+ XML_Parser parser;
+ guint depth;
+ guint location;
+ GString *str;
+ gchar *name;
+ gchar *mail;
+ gboolean id_is_permalink;
+
+ Feed *feed;
+ FeedItem *curitem;
+};
+
+typedef enum {
+ FEED_ERR_NOFEED,
+ FEED_ERR_NOURL,
+ FEED_ERR_INIT,
+ FEED_ERR_FETCH
+} FeedErrCodes;
+
+/* ---------------- Prototypes */
+
+Feed *feed_new(gchar *url);
+void feed_free(Feed *feed);
+
+void feed_free_items(Feed *feed);
+
+void feed_set_timeout(Feed *feed, guint timeout);
+guint feed_get_timeout(Feed *feed);
+
+void feed_set_url(Feed *feed, gchar *url);
+gchar *feed_get_url(Feed *feed);
+
+gchar *feed_get_title(Feed *feed);
+void feed_set_title(Feed *feed, gchar *new_title);
+
+gchar *feed_get_description(Feed *feed);
+gchar *feed_get_language(Feed *feed);
+gchar *feed_get_author(Feed *feed);
+gchar *feed_get_generator(Feed *feed);
+gchar *feed_get_fetcherror(Feed *feed);
+
+gchar *feed_get_cookies_path(Feed *feed);
+void feed_set_cookies_path(Feed *feed, gchar *path);
+
+gboolean feed_get_ssl_verify_peer(Feed *feed);
+void feed_set_ssl_verify_peer(Feed *feed, gboolean ssl_verify_peer);
+
+gint feed_n_items(Feed *feed);
+FeedItem *feed_nth_item(Feed *feed, guint n);
+
+void feed_foreach_item(Feed *feed, GFunc func, gpointer data);
+
+gboolean feed_prepend_item(Feed *feed, FeedItem *item);
+gboolean feed_append_item(Feed *feed, FeedItem *item);
+gboolean feed_insert_item(Feed *feed, FeedItem *item, gint pos);
+
+guint feed_update(Feed *feed, time_t last_update);
+
+#define FILL(n) g_free(n); n = g_strdup(text);
+
+#include "feeditem.h"
+
+#endif /* __FEED_H */
diff --git a/src/plugins/rssyl/libfeed/feeditem.c b/src/plugins/rssyl/libfeed/feeditem.c
new file mode 100644
index 0000000..d04831b
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/feeditem.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#define __USE_GNU
+
+#include <stdlib.h>
+#include <glib.h>
+#include <curl/curl.h>
+#include <expat.h>
+
+#include "feed.h"
+#include "feeditem.h"
+#include "feeditemenclosure.h"
+#include "parser.h"
+
+/* feed_item_new()
+ * Initializes a new empty FeedItem struct, setting its parent feed,
+ * if supplied. */
+FeedItem *feed_item_new(Feed *feed)
+{
+ FeedItem *item = NULL;
+
+ item = malloc( sizeof(FeedItem) );
+ item->url = NULL;
+ item->title = NULL;
+ item->title_format = 0;
+ item->summary = NULL;
+ item->text = NULL;
+ item->author = NULL;
+ item->id = NULL;
+ item->comments_url = NULL;
+ item->parent_id = NULL;
+ item->enclosure = NULL;
+
+ item->sourcetitle = NULL;
+ item->sourceid = NULL;
+ item->sourcedate = -1;
+
+ item->id_is_permalink = FALSE;
+ item->xhtml_content = FALSE;
+
+ item->date_published = -1;
+ item->date_modified = -1;
+
+ if( feed != NULL )
+ item->feed = feed;
+
+ item->data = NULL;
+
+ return item;
+}
+
+void feed_item_free(FeedItem *item)
+{
+ if( item == NULL )
+ return;
+
+ g_free(item->url);
+ g_free(item->title);
+ g_free(item->summary);
+ g_free(item->text);
+ g_free(item->author);
+ g_free(item->id);
+ g_free(item->data);
+ g_free(item->comments_url);
+ g_free(item->parent_id);
+ g_free(item->enclosure);
+
+ g_free(item->sourcetitle);
+ g_free(item->sourceid);
+
+ g_free(item);
+ item = NULL;
+}
+
+Feed *feed_item_get_feed(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, NULL);
+ return item->feed;
+}
+
+/* URL */
+gchar *feed_item_get_url(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, NULL);
+ return item->url;
+}
+
+void feed_item_set_url(FeedItem *item, const gchar *url)
+{
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(url != NULL);
+
+ g_free(item->url);
+ item->url = g_strdup(url);
+}
+
+/* Title */
+gchar *feed_item_get_title(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, NULL);
+ return item->title;
+}
+
+void feed_item_set_title(FeedItem *item, const gchar *title)
+{
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(title != NULL);
+
+ g_free(item->title);
+ item->title = g_strdup(title);
+}
+
+/* Title format */
+gint feed_item_get_title_format(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, -1);
+ return item->title_format;
+}
+
+void feed_item_set_title_format(FeedItem *item, gint format)
+{
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(format >= 0 && format <= FEED_ITEM_TITLE_UNKNOWN);
+
+ item->title_format = format;
+}
+
+/* Summary */
+gchar *feed_item_get_summary(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, NULL);
+ return item->summary;
+}
+
+void feed_item_set_summary(FeedItem *item, const gchar *summary)
+{
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(summary != NULL);
+
+ g_free(item->summary);
+ item->summary = g_strdup(summary);
+}
+
+/* Text */
+gchar *feed_item_get_text(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, NULL);
+ return item->text;
+}
+
+void feed_item_set_text(FeedItem *item, const gchar *text)
+{
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(text != NULL);
+
+ g_free(item->text);
+ item->text = g_strdup(text);
+}
+
+/* Author */
+gchar *feed_item_get_author(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, NULL);
+ return item->author;
+}
+
+void feed_item_set_author(FeedItem *item, const gchar *author)
+{
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(author != NULL);
+
+ g_free(item->author);
+ item->author = g_strdup(author);
+}
+
+/* ID */
+gchar *feed_item_get_id(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, NULL);
+ return item->id;
+}
+
+void feed_item_set_id(FeedItem *item, const gchar *id)
+{
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(id != NULL);
+
+ g_free(item->id);
+ item->id = g_strdup(id);
+}
+
+/* Comments URL */
+gchar *feed_item_get_comments_url(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, NULL);
+ return item->comments_url;
+}
+
+void feed_item_set_comments_url(FeedItem *item, const gchar *url)
+{
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(url != NULL);
+
+ g_free(item->comments_url);
+ item->comments_url = g_strdup(url);
+}
+
+/* Comments URL */
+gchar *feed_item_get_parent_id(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, NULL);
+ return item->parent_id;
+}
+
+void feed_item_set_parent_id(FeedItem *item, const gchar *id)
+{
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(id != NULL);
+
+ g_free(item->parent_id);
+ item->parent_id = g_strdup(id);
+}
+
+/* Media enclosure */
+FeedItemEnclosure *feed_item_get_enclosure(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, NULL);
+ return item->enclosure;
+}
+
+void feed_item_set_enclosure(FeedItem *item, FeedItemEnclosure *enclosure)
+{
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(enclosure != NULL);
+ g_return_if_fail(enclosure->url != NULL);
+ g_return_if_fail(enclosure->type != NULL);
+
+ feed_item_enclosure_free(item->enclosure);
+ item->enclosure = enclosure;
+}
+
+/* Source title (Atom only) */
+gchar *feed_item_get_sourcetitle(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, NULL);
+ return item->sourcetitle;
+}
+
+void feed_item_set_sourcetitle(FeedItem *item, const gchar *sourcetitle)
+{
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(sourcetitle != NULL);
+
+ g_free(item->sourcetitle);
+ item->sourcetitle = g_strdup(sourcetitle);
+}
+
+/* Source ID (Atom only) */
+gchar *feed_item_get_sourceid(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, NULL);
+ return item->sourceid;
+}
+
+void feed_item_set_sourceid(FeedItem *item, const gchar *sourceid)
+{
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(sourceid != NULL);
+
+ g_free(item->sourceid);
+ item->sourceid = g_strdup(sourceid);
+}
+
+/* Source date (Atom only) */
+time_t feed_item_get_sourcedate(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, -1);
+ return item->sourcedate;
+}
+
+void feed_item_set_sourcedate(FeedItem *item, time_t date)
+{
+ g_return_if_fail(item != NULL);
+ item->sourcedate = date;
+}
+
+/* Date published */
+time_t feed_item_get_date_published(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, -1);
+ return item->date_published;
+}
+
+void feed_item_set_date_published(FeedItem *item, time_t date)
+{
+ g_return_if_fail(item != NULL);
+ item->date_published = date;
+}
+
+/* Date modified */
+time_t feed_item_get_date_modified(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, -1);
+ return item->date_modified;
+}
+
+void feed_item_set_date_modified(FeedItem *item, time_t date)
+{
+ g_return_if_fail(item != NULL);
+ item->date_modified = date;
+}
+
+FeedItem *feed_item_copy(FeedItem *item)
+{
+ FeedItem *nitem;
+
+ g_return_val_if_fail(item != NULL, NULL);
+
+ nitem = feed_item_new(NULL);
+
+ nitem->url = g_strdup(item->url);
+ nitem->title = g_strdup(item->title);
+ nitem->summary = g_strdup(item->summary);
+ nitem->text = g_strdup(item->text);
+ nitem->author = g_strdup(item->author);
+ nitem->id = g_strdup(item->id);
+ nitem->comments_url = g_strdup(item->comments_url);
+ nitem->parent_id = g_strdup(item->parent_id);
+
+ nitem->enclosure = g_memdup(item->enclosure, sizeof(FeedItemEnclosure));
+
+ nitem->date_published = item->date_published;
+ nitem->date_modified = item->date_modified;
+
+ nitem->id_is_permalink = item->id_is_permalink;
+ nitem->xhtml_content = item->xhtml_content;
+
+ nitem->data = g_memdup(item->data, sizeof(item->data));
+
+ return nitem;
+}
+
+gboolean feed_item_id_is_permalink(FeedItem *item)
+{
+ g_return_val_if_fail(item != NULL, FALSE);
+
+ return item->id_is_permalink;
+}
+
+void feed_item_set_id_permalink(FeedItem *item, gboolean permalink)
+{
+ g_return_if_fail(item != NULL);
+
+ item->id_is_permalink = permalink;
+}
diff --git a/src/plugins/rssyl/libfeed/feeditem.h b/src/plugins/rssyl/libfeed/feeditem.h
new file mode 100644
index 0000000..9125af4
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/feeditem.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __FEEDITEM_H
+#define __FEEDITEM_H
+
+#include "feed.h"
+#include "feeditemenclosure.h"
+
+struct _FeedItem {
+ gchar *url;
+ gchar *title;
+ gint title_format;
+ gchar *summary;
+ gchar *text;
+ gchar *author;
+ gchar *id;
+ gchar *comments_url;
+ gchar *parent_id;
+
+ gchar *sourceid;
+ gchar *sourcetitle;
+ time_t sourcedate;
+
+ gboolean id_is_permalink;
+ gboolean xhtml_content;
+
+ FeedItemEnclosure *enclosure;
+
+ time_t date_published;
+ time_t date_modified;
+
+ Feed *feed; /* feed we belong to */
+
+ gpointer data; /* application-specific data */
+};
+
+#define FEED_ITEM_TITLE_TEXT 0
+#define FEED_ITEM_TITLE_HTML 1
+#define FEED_ITEM_TITLE_XHTML 2
+#define FEED_ITEM_TITLE_UNKNOWN 3
+
+FeedItem *feed_item_new(Feed *feed);
+void feed_item_free(FeedItem *item);
+
+Feed *feed_item_get_feed(FeedItem *item);
+
+gchar *feed_item_get_url(FeedItem *item);
+void feed_item_set_url(FeedItem *item, const gchar *url);
+
+gchar *feed_item_get_title(FeedItem *item);
+void feed_item_set_title(FeedItem *item, const gchar *title);
+
+gint feed_item_get_title_format(FeedItem *item);
+void feed_item_set_title_format(FeedItem *item, gint format);
+
+gchar *feed_item_get_summary(FeedItem *item);
+void feed_item_set_summary(FeedItem *item, const gchar *summary);
+
+gchar *feed_item_get_text(FeedItem *item);
+void feed_item_set_text(FeedItem *item, const gchar *text);
+
+gchar *feed_item_get_author(FeedItem *item);
+void feed_item_set_author(FeedItem *item, const gchar *author);
+
+gchar *feed_item_get_id(FeedItem *item);
+void feed_item_set_id(FeedItem *item, const gchar *id);
+
+gchar *feed_item_get_comments_url(FeedItem *item);
+void feed_item_set_comments_url(FeedItem *item, const gchar *url);
+
+gchar *feed_item_get_parent_id(FeedItem *item);
+void feed_item_set_parent_id(FeedItem *item, const gchar *id);
+
+FeedItemEnclosure *feed_item_get_enclosure(FeedItem *item);
+void feed_item_set_enclosure(FeedItem *item, FeedItemEnclosure *enclosure);
+
+gchar *feed_item_get_sourcetitle(FeedItem *item);
+void feed_item_set_sourcetitle(FeedItem *item, const gchar *sourcetitle);
+
+gchar *feed_item_get_sourceid(FeedItem *item);
+void feed_item_set_sourceid(FeedItem *item, const gchar *sourceid);
+
+time_t feed_item_get_sourcedate(FeedItem *item);
+void feed_item_set_sourcedate(FeedItem *item, time_t date);
+
+time_t feed_item_get_date_published(FeedItem *item);
+void feed_item_set_date_published(FeedItem *item, time_t date);
+
+time_t feed_item_get_date_modified(FeedItem *item);
+void feed_item_set_date_modified(FeedItem *item, time_t date);
+
+FeedItem *feed_item_copy(FeedItem *item);
+
+gboolean feed_item_id_is_permalink(FeedItem *item);
+void feed_item_set_id_permalink(FeedItem *item, gboolean permalink);
+
+#endif /* __FEEDITEM_H */
diff --git a/src/plugins/rssyl/libfeed/feeditemenclosure.c b/src/plugins/rssyl/libfeed/feeditemenclosure.c
new file mode 100644
index 0000000..183cfb5
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/feeditemenclosure.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#define __USE_GNU
+
+#include <stdlib.h>
+#include <glib.h>
+
+#include "feeditemenclosure.h"
+
+FeedItemEnclosure *feed_item_enclosure_new(gchar *url, gchar *type, gulong size)
+{
+ FeedItemEnclosure *enclosure = NULL;
+
+ g_return_val_if_fail(url != NULL, NULL);
+ g_return_val_if_fail(type != NULL, NULL);
+ g_return_val_if_fail(size > 0, NULL);
+
+ enclosure = malloc( sizeof(FeedItemEnclosure) );
+ enclosure->url = g_strdup(url);
+ enclosure->type = g_strdup(type);
+ enclosure->size = size;
+
+ return enclosure;
+}
+
+void feed_item_enclosure_free(FeedItemEnclosure *enclosure)
+{
+ if( enclosure == NULL )
+ return;
+
+ g_free(enclosure->url);
+ g_free(enclosure->type);
+
+ g_free(enclosure);
+ enclosure = NULL;
+}
+
+/* URL */
+gchar *feed_item_enclosure_get_url(FeedItemEnclosure *enclosure)
+{
+ g_return_val_if_fail(enclosure != NULL, NULL);
+ return enclosure->url;
+}
+
+void feed_item_enclosure_set_url(FeedItemEnclosure *enclosure, gchar *url)
+{
+ g_return_if_fail(enclosure != NULL);
+ g_return_if_fail(url != NULL);
+
+ g_free(enclosure->url);
+ enclosure->url = g_strdup(url);
+}
+
+/* Type */
+gchar *feed_item_enclosure_get_type(FeedItemEnclosure *enclosure)
+{
+ g_return_val_if_fail(enclosure != NULL, NULL);
+ return enclosure->type;
+}
+
+void feed_item_enclosure_set_type(FeedItemEnclosure *enclosure, gchar *type)
+{
+ g_return_if_fail(enclosure != NULL);
+ g_return_if_fail(type != NULL);
+
+ g_free(enclosure->type);
+ enclosure->type = g_strdup(type);
+}
+
+/* Size */
+gulong feed_item_enclosure_get_size(FeedItemEnclosure *enclosure)
+{
+ g_return_val_if_fail(enclosure != NULL, -1);
+ return enclosure->size;
+}
+
+void feed_item_enclosure_set_size(FeedItemEnclosure *enclosure, gulong size)
+{
+ g_return_if_fail(enclosure != NULL);
+ g_return_if_fail(size > 0);
+
+ enclosure->size = size;
+}
diff --git a/src/plugins/rssyl/libfeed/feeditemenclosure.h b/src/plugins/rssyl/libfeed/feeditemenclosure.h
new file mode 100644
index 0000000..ba4d127
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/feeditemenclosure.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __FEEDITEMENCLOSURE_H
+#define __FEEDITEMENCLOSURE_H
+
+struct _FeedItemEnclosure {
+ gchar *url;
+ gchar *type;
+ gulong size;
+};
+
+typedef struct _FeedItemEnclosure FeedItemEnclosure;
+
+FeedItemEnclosure *feed_item_enclosure_new(gchar *url, gchar *type, gulong size);
+void feed_item_enclosure_free(FeedItemEnclosure *enclosure);
+
+gchar *feed_item_enclosure_get_url(FeedItemEnclosure *enclosure);
+void feed_item_enclosure_set_url(FeedItemEnclosure *enclosure, gchar *url);
+
+gchar *feed_item_enclosure_get_type(FeedItemEnclosure *enclosure);
+void feed_item_enclosure_set_type(FeedItemEnclosure *enclosure, gchar *type);
+
+gulong feed_item_enclosure_get_size(FeedItemEnclosure *enclosure);
+void feed_item_enclosure_set_size(FeedItemEnclosure *enclosure, gulong size);
+
+#endif /* __FEEDITEMENCLOSURE_H */
diff --git a/src/plugins/rssyl/libfeed/parser.c b/src/plugins/rssyl/libfeed/parser.c
new file mode 100644
index 0000000..1ebc412
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+#include <curl/curl.h>
+#include <expat.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <codeconv.h>
+
+#include "feed.h"
+
+#include "parser.h"
+
+static void _handler_set(XML_Parser parser, guint type)
+{
+ if( parser == NULL )
+ return;
+
+ switch(type) {
+ case FEED_TYPE_RSS_20:
+ XML_SetElementHandler(parser,
+ feed_parser_rss20_start,
+ feed_parser_rss20_end);
+ break;
+
+ case FEED_TYPE_RDF:
+ XML_SetElementHandler(parser,
+ feed_parser_rdf_start,
+ feed_parser_rdf_end);
+ break;
+
+ case FEED_TYPE_ATOM_10:
+ XML_SetElementHandler(parser,
+ feed_parser_atom10_start,
+ feed_parser_atom10_end);
+ break;
+ }
+}
+
+static void _elparse_start_chooser(void *data,
+ const gchar *el, const gchar **attr)
+{
+ FeedParserCtx *ctx = (FeedParserCtx *)data;
+ guint feedtype = FEED_TYPE_NONE;
+ gchar *version;
+
+ if( ctx->depth == 0 ) {
+
+ /* RSS 2.0 detected */
+ if( !strcmp(el, "rss") ) {
+ feedtype = FEED_TYPE_RSS_20;
+ } else if( !strcmp(el, "rdf:RDF") ) {
+ feedtype = FEED_TYPE_RDF;
+ } else if( !strcmp(el, "feed") ) {
+
+ /* ATOM feed detected, let's check version */
+ version = feed_parser_get_attribute_value(attr, "xmlns");
+ if( !strcmp(version, "http://www.w3.org/2005/Atom") ||
+ !strcmp(version, "https://www.w3.org/2005/Atom") )
+ feedtype = FEED_TYPE_ATOM_10;
+ else
+ feedtype = FEED_TYPE_ATOM_03;
+ }
+ }
+
+ _handler_set(ctx->parser, feedtype);
+
+ ctx->depth++;
+}
+
+static void _elparse_end_dummy(void *data, const gchar *el)
+{
+ FeedParserCtx *ctx = (FeedParserCtx *)data;
+
+ if( ctx->str != NULL ) {
+ g_string_free(ctx->str, TRUE);
+ ctx->str = NULL;
+ }
+
+ ctx->depth--;
+}
+
+void libfeed_expat_chparse(void *data, const gchar *s, gint len)
+{
+ FeedParserCtx *ctx = (FeedParserCtx *)data;
+ gchar *buf = NULL;
+ gint i, xblank = 1;
+
+ buf = malloc(len+1);
+ strncpy(buf, s, len);
+ buf[len] = '\0';
+
+ /* check if the string is blank, ... */
+ for( i = 0; i < strlen(buf); i++ )
+ if( !isspace(buf[i]) )
+ xblank = 0;
+
+ /* ...because we do not want the blanks if we're just starting new GString */
+ if( xblank > 0 && ctx->str == NULL ) {
+ g_free(buf);
+ return;
+ }
+
+ if( ctx->str == NULL ) {
+ ctx->str = g_string_sized_new(len + 1);
+ }
+
+ g_string_append(ctx->str, buf);
+ g_free(buf);
+}
+
+
+void feed_parser_set_expat_handlers(FeedParserCtx *ctx)
+{
+ XML_SetUserData(ctx->parser, (void *)ctx);
+
+ XML_SetElementHandler(ctx->parser,
+ _elparse_start_chooser,
+ _elparse_end_dummy);
+
+ XML_SetCharacterDataHandler(ctx->parser,
+ libfeed_expat_chparse);
+
+ XML_SetUnknownEncodingHandler(ctx->parser, feed_parser_unknown_encoding_handler,
+ NULL);
+}
+
+size_t feed_writefunc(void *ptr, size_t size, size_t nmemb, void *data)
+{
+ gint len = size * nmemb;
+ FeedParserCtx *ctx = (FeedParserCtx *)data;
+ gint status, err;
+
+ status = XML_Parse(ctx->parser, ptr, len, FALSE);
+
+ if( status == XML_STATUS_ERROR ) {
+ err = XML_GetErrorCode(ctx->parser);
+ printf("\nExpat: --- %s\n\n", XML_ErrorString(err));
+ }
+
+ return len;
+}
+
+gchar *feed_parser_get_attribute_value(const gchar **attr, const gchar *name)
+{
+ guint i;
+
+ if( attr == NULL && name == NULL )
+ return NULL;
+
+ for( i = 0; attr[i] != NULL && attr[i+1] != NULL; i += 2 ) {
+ if( !strcmp( attr[i], name) )
+ return (gchar *)attr[i+1];
+ }
+
+ /* We haven't found anything. */
+ return NULL;
+}
+
+#define CHARSIZEUTF32 4
+
+enum {
+ LEP_ICONV_OK,
+ LEP_ICONV_FAILED,
+ LEP_ICONV_ILSEQ,
+ LEP_ICONV_INVAL,
+ LEP_ICONV_UNKNOWN
+};
+
+static gint giconv_utf32_char(GIConv cd, const gchar *inbuf, size_t insize,
+ guint32 *p_value)
+{
+#ifdef HAVE_ICONV
+ size_t outsize;
+ guchar outbuf[CHARSIZEUTF32];
+ gchar *outbufp;
+ gint r, errno;
+
+ outsize = sizeof(outbuf);
+ outbufp = (gchar *)outbuf;
+#ifdef HAVE_ICONV_PROTO_CONST
+ r = g_iconv(cd, (const gchar **)&inbuf, &insize,
+ &outbufp, &outsize);
+#else
+ r = g_iconv(cd, (gchar **)&inbuf, &insize,
+ &outbufp, &outsize);
+#endif
+ if( r == -1 ) {
+ g_iconv(cd, 0, 0, 0, 0);
+ switch(errno) {
+ case EILSEQ:
+ return LEP_ICONV_ILSEQ;
+ case EINVAL:
+ return LEP_ICONV_INVAL;
+ default:
+ return LEP_ICONV_UNKNOWN;
+ }
+ } else {
+ guint32 value;
+ guint i;
+
+ if( (insize > 0) || (outsize > 0) )
+ return LEP_ICONV_FAILED;
+
+ value = 0;
+ for( i = 0; i < sizeof(outbuf); i++ ) {
+ value = (value << 8) + outbuf[i];
+ }
+ *p_value = value;
+ return LEP_ICONV_OK;
+ }
+#else
+ return LEP_ICONV_FAILED;
+#endif
+}
+
+static gint feed_parser_setup_unknown_encoding(const gchar *charset,
+ XML_Encoding *info)
+{
+ GIConv cd;
+ gint flag, r;
+ gchar buf[4];
+ guint i, j, k;
+ guint32 value;
+
+ cd = g_iconv_open("UTF-32BE", charset);
+ if( cd == (GIConv) -1 )
+ return -1;
+
+ flag = 0;
+ for( i = 0; i < 256; i++ ) {
+ /* first char */
+ buf[0] = i;
+ info->map[i] = 0;
+ r = giconv_utf32_char(cd, buf, 1, &value);
+ if( r == LEP_ICONV_OK) {
+ info->map[i] = value;
+ } else if( r != LEP_ICONV_INVAL ) {
+ } else {
+ for( j = 0; j < 256; j++ ) {
+ /* second char */
+ buf[1] = j;
+ r = giconv_utf32_char(cd, buf, 2, &value);
+ if( r == LEP_ICONV_OK ) {
+ flag = 1;
+ info->map[i] = -2;
+ } else if( r != LEP_ICONV_INVAL ) {
+ } else {
+ for( k = 0; k < 256; k++ ) {
+ /* third char */
+ buf[2] = k;
+ r = giconv_utf32_char(cd, buf, 3, &value);
+ if( r == LEP_ICONV_OK) {
+ info->map[i] = -3;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ g_iconv_close(cd);
+
+ return flag;
+}
+
+struct FeedParserUnknownEncoding {
+ gchar *charset;
+ GIConv cd;
+};
+
+static gint feed_parser_unknown_encoding_convert(void *data, const gchar *s)
+{
+ gint r;
+ struct FeedParserUnknownEncoding *enc_data;
+ size_t insize;
+ guint32 value;
+
+ enc_data = data;
+ insize = 4;
+
+ if( s == NULL )
+ return -1;
+
+ r = giconv_utf32_char(enc_data->cd, s, insize, &value);
+ if( r != LEP_ICONV_OK )
+ return -1;
+
+ return 0;
+}
+
+static void feed_parser_unknown_encoding_data_free(void *data)
+{
+ struct FeedParserUnknownEncoding *enc_data;
+
+ enc_data = data;
+ free(enc_data->charset);
+ g_iconv_close(enc_data->cd);
+ free(enc_data);
+}
+
+int feed_parser_unknown_encoding_handler(void *encdata, const XML_Char *name,
+ XML_Encoding *info)
+{
+ GIConv cd;
+ struct FeedParserUnknownEncoding *data;
+ int result;
+
+ result = feed_parser_setup_unknown_encoding(name, info);
+ if( result == 0 ) {
+ info->data = NULL;
+ info->convert = NULL;
+ info->release = NULL;
+ return XML_STATUS_OK;
+ }
+
+ cd = g_iconv_open("UTF-32BE", name);
+ if( cd == (GIConv)-1 )
+ return XML_STATUS_ERROR;
+
+ data = malloc( sizeof(*data) );
+ if( data == NULL ) {
+ g_iconv_close(cd);
+ return XML_STATUS_ERROR;
+ }
+
+ data->charset = strdup(name);
+ if( data->charset == NULL ) {
+ free(data);
+ g_iconv_close(cd);
+ return XML_STATUS_ERROR;
+ }
+
+ data->cd = cd;
+ info->data = data;
+ info->convert = feed_parser_unknown_encoding_convert;
+ info->release = feed_parser_unknown_encoding_data_free;
+
+ return XML_STATUS_OK;
+}
diff --git a/src/plugins/rssyl/libfeed/parser.h b/src/plugins/rssyl/libfeed/parser.h
new file mode 100644
index 0000000..f8cbb9a
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PARSER_H
+
+#include "feed.h"
+#include "parser_rss20.h"
+#include "parser_rdf.h"
+#include "parser_atom10.h"
+
+void libfeed_expat_chparse(void *data, const gchar *s, gint len);
+void feed_parser_set_expat_handlers(FeedParserCtx *ctx);
+size_t feed_writefunc(void *ptr, size_t size, size_t nmemb, void *stream);
+gchar *feed_parser_get_attribute_value(const gchar **attr, const gchar *name);
+
+int feed_parser_unknown_encoding_handler(void *encdata, const XML_Char *name,
+ XML_Encoding *info);
+
+
+enum {
+ FEED_TYPE_NONE,
+ FEED_TYPE_RDF,
+ FEED_TYPE_RSS_20,
+ FEED_TYPE_ATOM_03,
+ FEED_TYPE_ATOM_10,
+ FEED_TYPE_OPML
+} FeedTypes;
+
+#endif /* __PARSER_H */
diff --git a/src/plugins/rssyl/libfeed/parser_atom10.c b/src/plugins/rssyl/libfeed/parser_atom10.c
new file mode 100644
index 0000000..59fba1c
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser_atom10.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#define __USE_GNU
+
+#include <glib.h>
+#include <expat.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "feed.h"
+#include "feeditem.h"
+#include "date.h"
+#include "parser.h"
+#include "parser_atom10.h"
+
+void feed_parser_atom10_start(void *data, const gchar *el, const gchar **attr)
+{
+ FeedParserCtx *ctx = (FeedParserCtx *)data;
+ gchar *a = NULL;
+
+ if( ctx->depth == 1 ) {
+
+ if( !strcmp(el, "entry") ) {
+ /* Start of new feed item found.
+ * Create a new FeedItem, freeing the one we already have, if any. */
+ if( ctx->curitem != NULL )
+ feed_item_free(ctx->curitem);
+ ctx->curitem = feed_item_new(ctx->feed);
+ ctx->location = FEED_LOC_ATOM10_ENTRY;
+ } else if( !strcmp(el, "author") ) {
+ /* Start of author info for the feed found.
+ * Set correct location. */
+ ctx->location = FEED_LOC_ATOM10_AUTHOR;
+ } else ctx->location = FEED_LOC_ATOM10_NONE;
+
+ } else if( ctx->depth == 2 ) {
+
+ if( !strcmp(el, "author") ) {
+ /* Start of author info for current feed item.
+ * Set correct location. */
+ ctx->location = FEED_LOC_ATOM10_AUTHOR;
+ } else if( !strcmp(el, "link") ) {
+ /* Capture item URL, from the "url" XML attribute. */
+ if (ctx->curitem && ctx->location == FEED_LOC_ATOM10_ENTRY)
+ ctx->curitem->url = g_strdup(feed_parser_get_attribute_value(attr, "href"));
+ } else if( !strcmp(el, "source") ) {
+ ctx->location = FEED_LOC_ATOM10_SOURCE;
+ } else ctx->location = FEED_LOC_ATOM10_ENTRY;
+
+ if( !strcmp(el, "title") ) {
+ a = feed_parser_get_attribute_value(attr, "type");
+ if( !a || !strcmp(a, "text") )
+ ctx->curitem->title_format = FEED_ITEM_TITLE_TEXT;
+ else if( !strcmp(a, "html") )
+ ctx->curitem->title_format = FEED_ITEM_TITLE_HTML;
+ else if( !strcmp(a, "xhtml") )
+ ctx->curitem->title_format = FEED_ITEM_TITLE_XHTML;
+ else
+ ctx->curitem->title_format = FEED_ITEM_TITLE_UNKNOWN;
+ } else if (!strcmp(el, "content") ) {
+ a = feed_parser_get_attribute_value(attr, "type");
+ if (a && !strcmp(a, "xhtml")) {
+ ctx->curitem->xhtml_content = TRUE;
+ ctx->location = FEED_LOC_ATOM10_CONTENT;
+ }
+ }
+ }
+
+ ctx->depth++;
+}
+
+void feed_parser_atom10_end(void *data, const gchar *el)
+{
+ FeedParserCtx *ctx = (FeedParserCtx *)data;
+ Feed *feed = ctx->feed;
+ gchar *text = NULL;
+
+ if( ctx->str != NULL )
+ text = ctx->str->str;
+
+ ctx->depth--;
+
+ switch( ctx->depth ) {
+
+ case 0:
+
+ if( !strcmp(el, "feed") ) {
+ /* We have finished parsing the feed, reverse the list
+ * so it's not upside down. */
+ feed->items = g_slist_reverse(ctx->feed->items);
+ }
+
+ break;
+
+ case 1:
+
+ /* decide if we just received </entry>, so we can
+ * add a complete item to feed */
+ if( !strcmp(el, "entry") ) {
+
+ /* append the complete feed item */
+ if( ctx->curitem->id && ctx->curitem->title
+ && ctx->curitem->date_modified ) {
+ feed->items =
+ g_slist_prepend(feed->items, (gpointer)ctx->curitem);
+ }
+
+ /* since it's in the linked list, lose this pointer */
+ ctx->curitem = NULL;
+
+ } else if( !strcmp(el, "title") ) { /* so it wasn't end of item */
+ FILL(feed->title)
+ } else if( !strcmp(el, "summary" ) ) {
+ FILL(feed->description)
+ } else if( !strcmp(el, "updated" ) ) {
+ feed->date = parseISO8601Date(text);
+ }
+ /* FIXME: add more later */
+
+ break;
+
+ case 2:
+
+ if( ctx->curitem == NULL )
+ break;
+
+ switch(ctx->location) {
+
+ /* We're in feed/entry */
+ case FEED_LOC_ATOM10_ENTRY:
+ if( !strcmp(el, "title") ) {
+ FILL(ctx->curitem->title)
+ } else if( !strcmp(el, "summary") ) {
+ FILL(ctx->curitem->summary)
+ } else if( !strcmp(el, "content") ) {
+ if (!ctx->curitem->xhtml_content)
+ FILL(ctx->curitem->text);
+ } else if( !strcmp(el, "id") ) {
+ FILL(ctx->curitem->id);
+ feed_item_set_id_permalink(ctx->curitem, TRUE);
+ } else if( !strcmp(el, "published") ) {
+ ctx->curitem->date_published = parseISO8601Date(text);
+ } else if( !strcmp(el, "updated") ) {
+ ctx->curitem->date_modified = parseISO8601Date(text);
+ }
+
+ break;
+
+ /* We're in feed/author or about to leave feed/entry/author */
+ case FEED_LOC_ATOM10_AUTHOR:
+ if( !strcmp(el, "author" ) ) {
+ /* We just finished parsing <author> */
+ ctx->curitem->author = g_strdup_printf("%s%s%s%s%s",
+ ctx->name ? ctx->name : "",
+ ctx->name && ctx->mail ? " <" : ctx->mail ? "<" : "",
+ ctx->mail ? ctx->mail : "",
+ ctx->mail ? ">" : "",
+ !ctx->name && !ctx->mail ? "N/A" : "");
+ ctx->location = FEED_LOC_ATOM10_ENTRY;
+ } else if( !strcmp(el, "name") ) {
+ FILL(feed->author);
+ }
+
+ break;
+ }
+
+ break;
+
+ case 3:
+
+ if( ctx->curitem == NULL )
+ break;
+
+ switch(ctx->location) {
+
+ /* We're in feed/entry/author */
+ case FEED_LOC_ATOM10_AUTHOR:
+ if( !strcmp(el, "name") ) {
+ FILL(ctx->name);
+ } else if( !strcmp(el, "email") ) {
+ FILL(ctx->mail);
+ }
+
+ break;
+
+ /* We're in feed/entry/source */
+ case FEED_LOC_ATOM10_SOURCE:
+ if( !strcmp(el, "title" ) ) {
+ FILL(ctx->curitem->sourcetitle);
+ } else if( !strcmp(el, "id" ) ) {
+ FILL(ctx->curitem->sourceid);
+ } else if( !strcmp(el, "updated" ) ) {
+ ctx->curitem->sourcedate = parseISO8601Date(text);
+ }
+
+ break;
+
+ case FEED_LOC_ATOM10_CONTENT:
+ if (!strcmp(el, "div") && ctx->curitem->xhtml_content)
+ FILL(ctx->curitem->text);
+ break;
+
+ }
+
+
+ break;
+ }
+
+ if( ctx->str != NULL ) {
+ g_string_free(ctx->str, TRUE);
+ ctx->str = NULL;
+ }
+ ctx->str = NULL;
+}
diff --git a/src/plugins/rssyl/libfeed/parser_atom10.h b/src/plugins/rssyl/libfeed/parser_atom10.h
new file mode 100644
index 0000000..85e95b4
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser_atom10.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PARSER_ATOM03_H
+#define __PARSER_ATOM03_H
+
+void feed_parser_atom10_start(void *data, const char *el, const char **attr);
+void feed_parser_atom10_end(void *data, const char *el);
+
+enum {
+ FEED_LOC_ATOM10_NONE,
+ FEED_LOC_ATOM10_ENTRY,
+ FEED_LOC_ATOM10_AUTHOR,
+ FEED_LOC_ATOM10_SOURCE,
+ FEED_LOC_ATOM10_CONTENT
+} FeedAtom10Locations;
+
+#endif /* __PARSER_ATOM03_H */
diff --git a/src/plugins/rssyl/libfeed/parser_opml.c b/src/plugins/rssyl/libfeed/parser_opml.c
new file mode 100644
index 0000000..09e34aa
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser_opml.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+#include <curl/curl.h>
+#include <expat.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <codeconv.h>
+
+#include "feed.h"
+
+#include "parser.h"
+#include "parser_opml.h"
+
+static void _opml_parser_start(void *data, const gchar *el, const gchar **attr)
+{
+ OPMLProcessCtx *ctx = (OPMLProcessCtx *)data;
+ gchar *title = NULL, *type = NULL, *url = NULL, *tmp = NULL;
+
+ if( ctx->body_reached ) {
+ if( ctx->depth >= 2 && !strcmp(el, "outline") ) {
+ title = feed_parser_get_attribute_value(attr, "title");
+ type = feed_parser_get_attribute_value(attr, "type");
+ if( type != NULL && strcmp(type, "folder") ) {
+ url = feed_parser_get_attribute_value(attr, "xmlUrl");
+
+ if( url != NULL ) {
+ if( !strncmp(url, "feed://", 7) )
+ tmp = g_strdup(url+7);
+ else if( !strncmp(url, "feed:", 5) )
+ tmp = g_strdup(url+5);
+
+ if( tmp != NULL ) {
+ g_free(url);
+ url = tmp;
+ }
+ }
+ }
+
+ if( ctx->user_function != NULL ) {
+ ctx->user_function(title, url, ctx->depth, ctx->user_data);
+ }
+ }
+ }
+
+ if( ctx->depth == 1 ) {
+ if( !strcmp(el, "body") ) {
+ ctx->body_reached = TRUE;
+ }
+ }
+
+ ctx->depth++;
+}
+
+static void _opml_parser_end(void *data, const gchar *el)
+{
+ OPMLProcessCtx *ctx = (OPMLProcessCtx *)data;
+
+ ctx->depth--;
+}
+
+void opml_process(gchar *path, OPMLProcessFunc function, gpointer data)
+{
+ OPMLProcessCtx *ctx = NULL;
+ gchar *contents = NULL;
+ GError *error = NULL;
+ gint status, err;
+
+ /* Initialize our context */
+ ctx = malloc( sizeof(OPMLProcessCtx) );
+ ctx->parser = XML_ParserCreate(NULL);
+ ctx->depth = 0;
+ ctx->str = NULL;
+ ctx->user_function = function;
+ ctx->body_reached = FALSE;
+ ctx->user_data = data;
+
+ /* Set expat parser handlers */
+ XML_SetUserData(ctx->parser, (void *)ctx);
+ XML_SetElementHandler(ctx->parser,
+ _opml_parser_start,
+ _opml_parser_end);
+ XML_SetCharacterDataHandler(ctx->parser, libfeed_expat_chparse);
+ XML_SetUnknownEncodingHandler(ctx->parser,
+ feed_parser_unknown_encoding_handler, NULL);
+
+ g_file_get_contents(path, &contents, NULL, &error);
+
+ if( error || !contents )
+ return;
+
+/*
+ lines = g_strsplit(contents, '\n', 0);
+
+ while( lines[i] ) {
+ status = XML_Parse(ctx->parser, lines[i], strlen(lines[i]), FALSE);
+ if( status == XML_STATUS_ERROR ) {
+ err = XML_GetErrorCode(ctx->parser);
+ sprintf(stderr, "\nExpat: --- %s\n\n", XML_ErrorString(err));
+ }
+ }
+*/
+
+ status = XML_Parse(ctx->parser, contents, strlen(contents), FALSE);
+ err = XML_GetErrorCode(ctx->parser);
+ fprintf(stderr, "\nExpat: --- %s (%s)\n\n", XML_ErrorString(err),
+ (status == XML_STATUS_OK ? "OK" : "NOT OK"));
+
+ XML_Parse(ctx->parser, "", 0, TRUE);
+
+ XML_ParserFree(ctx->parser);
+ g_free(ctx);
+}
diff --git a/src/plugins/rssyl/libfeed/parser_opml.h b/src/plugins/rssyl/libfeed/parser_opml.h
new file mode 100644
index 0000000..518b072
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser_opml.h
@@ -0,0 +1,23 @@
+#ifndef __PARSER_OPML
+#define __PARSER_OPML
+
+#include <expat.h>
+
+typedef void (*OPMLProcessFunc) (gchar *title, gchar *url, gint depth,
+ gpointer data);
+
+struct _OPMLProcessCtx {
+ XML_Parser parser;
+ guint depth;
+ guint prevdepth;
+ GString *str;
+ OPMLProcessFunc user_function;
+ gboolean body_reached;
+ gpointer user_data;
+};
+
+typedef struct _OPMLProcessCtx OPMLProcessCtx;
+
+void opml_process(gchar *path, OPMLProcessFunc function, gpointer data);
+
+#endif /* __PARSER_OPML */
diff --git a/src/plugins/rssyl/libfeed/parser_rdf.c b/src/plugins/rssyl/libfeed/parser_rdf.c
new file mode 100644
index 0000000..dc424c5
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser_rdf.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#define __USE_GNU
+
+#include <glib.h>
+#include <expat.h>
+#include <string.h>
+
+#include "feed.h"
+#include "date.h"
+#include "parser_rdf.h"
+
+void feed_parser_rdf_start(void *data, const gchar *el, const gchar **attr)
+{
+ FeedParserCtx *ctx = (FeedParserCtx *)data;
+
+ if( ctx->depth == 1 ) {
+ if( !strcmp(el, "channel") ) {
+ ctx->location = FEED_LOC_RDF_CHANNEL;
+ } else if( !strcmp(el, "item") ) {
+
+ if( ctx->curitem != NULL )
+ feed_item_free(ctx->curitem);
+
+ ctx->curitem = feed_item_new(ctx->feed);
+ ctx->location = FEED_LOC_RDF_ITEM;
+
+ } else ctx->location = 0;
+ }
+
+ ctx->depth++;
+
+}
+
+void feed_parser_rdf_end(void *data, const gchar *el)
+{
+ FeedParserCtx *ctx = (FeedParserCtx *)data;
+ Feed *feed = ctx->feed;
+ gchar *text = NULL;
+
+ if( ctx->str != NULL )
+ text = ctx->str->str;
+
+ ctx->depth--;
+
+ switch( ctx->depth ) {
+
+ case 0:
+
+ if( !strcmp(el, "rdf") ) {
+ /* we finished parsing the feed */
+ ctx->feed->items = g_slist_reverse(ctx->feed->items);
+ }
+
+ break;
+
+ case 1:
+
+ /* <item></item> block just ended, so ... */
+ if( !strcmp(el, "item") ) {
+
+ /* add the complete feed item to our feed struct */
+ ctx->feed->items =
+ g_slist_prepend(ctx->feed->items, (gpointer)ctx->curitem);
+
+ /* since it's in the linked list, lose this pointer */
+ ctx->curitem = NULL;
+ }
+
+ break;
+
+ case 2:
+
+ switch(ctx->location) {
+
+ /* We're inside introductory <channel></channel> */
+ case FEED_LOC_RDF_CHANNEL:
+ if( !strcmp(el, "title") ) {
+ FILL(feed->title)
+ } else if( !strcmp(el, "description" ) ) {
+ FILL(feed->description)
+ } else if( !strcmp(el, "dc:language") ) {
+ FILL(feed->language)
+ } else if( !strcmp(el, "dc:creator") ) {
+ FILL(feed->author)
+ } else if( !strcmp(el, "dc:date") ) {
+ feed->date = parseISO8601Date(text);
+ } else if( !strcmp(el, "pubDate") ) {
+ feed->date = parseRFC822Date(text);
+ }
+
+ break;
+
+ /* We're inside an <item></item> */
+ case FEED_LOC_RDF_ITEM:
+ if( ctx->curitem == NULL ) {
+ break;
+ }
+
+ /* decide which field did we just get */
+ if( !strcmp(el, "title") ) {
+ FILL(ctx->curitem->title)
+ } else if( !strcmp(el, "dc:creator") ) {
+ FILL(ctx->curitem->author)
+ } else if( !strcmp(el, "description") ) {
+ FILL(ctx->curitem->summary)
+ } else if( !strcmp(el, "content:encoded") ) {
+ FILL(ctx->curitem->text)
+ } else if( !strcmp(el, "link") ) {
+ FILL(ctx->curitem->url)
+ } else if( !strcmp(el, "dc:date") ) {
+ ctx->curitem->date_modified = parseISO8601Date(text);
+ } else if( !strcmp(el, "pubDate") ) {
+ ctx->curitem->date_modified = parseRFC822Date(text);
+ }
+
+ break;
+ }
+
+ break;
+
+ }
+
+ if( ctx->str != NULL ) {
+ g_string_free(ctx->str, TRUE);
+ ctx->str = NULL;
+ }
+}
diff --git a/src/plugins/rssyl/libfeed/parser_rdf.h b/src/plugins/rssyl/libfeed/parser_rdf.h
new file mode 100644
index 0000000..1c3809f
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser_rdf.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PARSER_RDF_H
+#define __PARSER_RDF_H
+
+void feed_parser_rdf_start(void *data, const char *el, const char **attr);
+void feed_parser_rdf_end(void *data, const char *el);
+
+enum {
+ FEED_LOC_RDF_NONE,
+ FEED_LOC_RDF_CHANNEL,
+ FEED_LOC_RDF_ITEM
+} FeedRdfLocations;
+
+#endif /* __PARSER_RDF_H */
diff --git a/src/plugins/rssyl/libfeed/parser_rss20.c b/src/plugins/rssyl/libfeed/parser_rss20.c
new file mode 100644
index 0000000..3882750
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser_rss20.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#define __USE_GNU
+
+#include <glib.h>
+#include <expat.h>
+#include <string.h>
+
+#include "feed.h"
+#include "feeditem.h"
+#include "feeditemenclosure.h"
+#include "date.h"
+#include "parser.h"
+
+void feed_parser_rss20_start(void *data, const gchar *el, const gchar **attr)
+{
+ FeedParserCtx *ctx = (FeedParserCtx *)data;
+ FeedItemEnclosure *enclosure = NULL;
+ gchar *url, *type, *size_s;
+ gulong size = -1;
+
+ /* ------------------- */
+ if( ctx->depth == 2 ) {
+ if( !strcmp(el, "item") ) { /* Start of new item */
+
+ if( ctx->curitem != NULL )
+ feed_item_free(ctx->curitem);
+
+ ctx->curitem = feed_item_new(ctx->feed);
+
+ } else ctx->location = 0;
+ /* ------------------- */
+ } else if( ctx->depth == 3 ) {
+ if( !strcmp(el, "enclosure") ) { /* Media enclosure */
+
+ url = feed_parser_get_attribute_value(attr, "url");
+ type = feed_parser_get_attribute_value(attr, "type");
+ size_s = feed_parser_get_attribute_value(attr, "length");
+ if( size_s != NULL )
+ size = (gulong)atol(size_s);
+
+ if( url != NULL && type != NULL && size > 0 ) {
+ if( (enclosure = feed_item_enclosure_new(url, type, size)) )
+ feed_item_set_enclosure(ctx->curitem, enclosure);
+ }
+
+ } else if( !strcmp(el, "guid") ) { /* Unique ID */
+ type = feed_parser_get_attribute_value(attr, "isPermaLink");
+ if( type != NULL && !strcmp(type, "false") )
+ feed_item_set_id_permalink(ctx->curitem, TRUE);
+ }
+ } else ctx->location = 0;
+
+ ctx->depth++;
+
+}
+
+void feed_parser_rss20_end(void *data, const gchar *el)
+{
+ FeedParserCtx *ctx = (FeedParserCtx *)data;
+ Feed *feed = ctx->feed;
+ gchar *text = NULL;
+
+ if( ctx->str != NULL )
+ text = ctx->str->str;
+ else
+ text = "";
+
+ ctx->depth--;
+
+ switch( ctx->depth ) {
+
+ /* ------------------- */
+ case 0:
+
+ if( !strcmp(el, "rss") ) {
+ /* we finished parsing the feed */
+ ctx->feed->items = g_slist_reverse(ctx->feed->items);
+ }
+
+ break;
+
+ /* ------------------- */
+ case 1:
+
+ break; /* nothing to do at this depth */
+
+ /* ------------------- */
+ case 2:
+
+ /* decide if we just received </item>, so we can
+ * add a complete item to feed */
+ if( !strcmp(el, "item") ) {
+
+ /* append the complete feed item, if it is valid
+ * "All elements of an item are optional, however at least one
+ * of title or description must be present." */
+ if( ctx->curitem->title != NULL || ctx->curitem->summary != NULL ) {
+ ctx->feed->items =
+ g_slist_prepend(ctx->feed->items, (gpointer)ctx->curitem);
+ }
+
+ /* since it's in the linked list, lose this pointer */
+ ctx->curitem = NULL;
+
+ } else if( !strcmp(el, "title") ) { /* so it wasn't end of item */
+ FILL(feed->title)
+ } else if( !strcmp(el, "description" ) ) {
+ FILL(feed->description)
+ } else if( !strcmp(el, "dc:language") ) {
+ FILL(feed->language)
+ } else if( !strcmp(el, "author") ) {
+ FILL(feed->author)
+ } else if( !strcmp(el, "admin:generatorAgent") ) {
+ FILL(feed->generator)
+ } else if( !strcmp(el, "dc:date") ) {
+ feed->date = parseISO8601Date(text);
+ } else if( !strcmp(el, "pubDate") ) {
+ feed->date = parseRFC822Date(text);
+ }
+
+ break;
+
+ /* ------------------- */
+ case 3:
+
+ if( ctx->curitem == NULL ) {
+ break;
+ }
+
+ /* decide which field did we just get */
+ if( !strcmp(el, "title") ) {
+ FILL(ctx->curitem->title)
+ } else if( !strcmp(el, "author") ) {
+ FILL(ctx->curitem->author)
+ } else if( !strcmp(el, "description") ) {
+ FILL(ctx->curitem->summary)
+ } else if( !strcmp(el, "content:encoded") ) {
+ FILL(ctx->curitem->text)
+ } else if( !strcmp(el, "link") ) {
+ FILL(ctx->curitem->url)
+ } else if( !strcmp(el, "guid") ) {
+ FILL(ctx->curitem->id)
+ } else if( !strcmp(el, "wfw:commentRSS") || !strcmp(el, "wfw:commentRss") ) {
+ FILL(ctx->curitem->comments_url)
+ } else if( !strcmp(el, "dc:date") ) {
+ ctx->curitem->date_modified = parseISO8601Date(text);
+ } else if( !strcmp(el, "pubDate") ) {
+ ctx->curitem->date_modified = parseRFC822Date(text);
+ } else if( !strcmp(el, "dc:creator")) {
+ FILL(ctx->curitem->author)
+ }
+
+ break;
+
+ }
+
+ if( ctx->str != NULL ) {
+ g_string_free(ctx->str, TRUE);
+ ctx->str = NULL;
+ }
+}
diff --git a/src/plugins/rssyl/libfeed/parser_rss20.h b/src/plugins/rssyl/libfeed/parser_rss20.h
new file mode 100644
index 0000000..27cc40c
--- /dev/null
+++ b/src/plugins/rssyl/libfeed/parser_rss20.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PARSER_RSS20_H
+#define __PARSER_RSS20_H
+
+void feed_parser_rss20_start(void *data, const char *el, const char **attr);
+void feed_parser_rss20_end(void *data, const char *el);
+
+#endif /* __PARSER_RSS20_H */
diff --git a/src/plugins/rssyl/old_feeds.c b/src/plugins/rssyl/old_feeds.c
new file mode 100644
index 0000000..45e6cf6
--- /dev/null
+++ b/src/plugins/rssyl/old_feeds.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2012 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Expat parser for old feeds.xml */
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <expat.h>
+
+#include <alertpanel.h>
+#include <common/utils.h>
+
+#include "libfeed/parser.h"
+#include "old_feeds.h"
+#include "rssyl.h"
+
+struct _oldrssyl_ctx {
+ GSList *oldfeeds;
+};
+
+static void _elparse_start_oldrssyl(void *data, const gchar *el,
+ const gchar **attr)
+{
+ struct _oldrssyl_ctx *ctx = data;
+ OldRFeed *of;
+ gchar *tmp;
+
+#define GETVAL_STR(name) (g_strdup(feed_parser_get_attribute_value(attr, name)))
+#define GETVAL_INT(name) \
+ ((tmp = feed_parser_get_attribute_value(attr, name)) == NULL ? 0 : \
+ (gint)atoi(tmp))
+
+ if (!strcmp(el, "feed")) {
+ of = g_new0(OldRFeed, 1);
+
+ of->name = GETVAL_STR("name");
+ of->official_name = GETVAL_STR("official_name");
+ of->url = GETVAL_STR("url");
+ of->default_refresh_interval = GETVAL_INT("default_refresh_interval");
+ of->refresh_interval = GETVAL_INT("refresh_interval");
+ of->expired_num = GETVAL_INT("expired_num");
+ of->fetch_comments = GETVAL_INT("fetch_comments");
+ of->fetch_comments_for = GETVAL_INT("fetch_comments_for");
+ of->silent_update = GETVAL_INT("silent_update");
+
+ debug_print("RSSyl: old feeds.xml: Adding '%s' (%s).\n", of->name,
+ of->url);
+
+ ctx->oldfeeds = g_slist_prepend(ctx->oldfeeds, of);
+ }
+
+ return;
+}
+
+static void _elparse_end_oldrssyl(void *data, const gchar *el)
+{
+ return;
+}
+
+GSList *rssyl_old_feed_metadata_parse(gchar *filepath)
+{
+ XML_Parser parser;
+ GSList *oldfeeds = NULL;
+ gchar *contents = NULL;
+ gsize length;
+ GError *error;
+ struct _oldrssyl_ctx *ctx;
+
+ debug_print("RSSyl: Starting to parse old feeds.xml\n");
+
+ /* Read contents of the file into memory */
+ if (!g_file_get_contents(filepath, &contents, &length, &error)) {
+ alertpanel_error(_("Couldn't read contents of old feeds.xml file:\n%s"),
+ error->message);
+ debug_print("RSSyl: Couldn't read contents of feeds.xml\n");
+ g_error_free(error);
+ return NULL;
+ }
+
+ /* Set up expat parser */
+ parser = XML_ParserCreate(NULL);
+
+ ctx = g_new0(struct _oldrssyl_ctx, 1);
+ ctx->oldfeeds = NULL;
+ XML_SetUserData(parser, ctx);
+ XML_SetElementHandler(parser,
+ _elparse_start_oldrssyl,
+ _elparse_end_oldrssyl);
+
+ /* Parse the XML, our output ending up in oldfeeds */
+ XML_Parse(parser, contents, length, 1);
+
+ /* And clean up */
+ XML_ParserFree(parser);
+ g_free(contents);
+ oldfeeds = ctx->oldfeeds;
+ g_free(ctx);
+
+ debug_print("RSSyl: old feeds.xml: added %d items in total\n",
+ g_slist_length(oldfeeds));
+
+ return oldfeeds;
+}
+
+static void _free_old_feed_entry(gpointer d, gpointer user_data)
+{
+ OldRFeed *of = (OldRFeed *)d;
+
+ if (of == NULL)
+ return;
+
+ g_free(of->name);
+ g_free(of->official_name);
+ g_free(of->url);
+ g_free(of);
+}
+
+void rssyl_old_feed_metadata_free(GSList *oldfeeds)
+{
+ if (oldfeeds != NULL) {
+ debug_print("RSSyl: releasing parsed contents of old feeds.xml\n");
+ g_slist_foreach(oldfeeds, _free_old_feed_entry, NULL);
+ g_slist_free(oldfeeds);
+ oldfeeds = NULL;
+ }
+}
+
+static gint _old_feed_find_by_url(gconstpointer a, gconstpointer b)
+{
+ OldRFeed *of = (OldRFeed *)a;
+ gchar *name = (gchar *)b;
+
+ if (of == NULL || of->name == NULL || of->url == NULL || name == NULL)
+ return 1;
+
+ return strcmp(of->name, name);
+}
+
+OldRFeed *rssyl_old_feed_get_by_name(GSList *oldfeeds, gchar *name)
+{
+ GSList *needle;
+
+ g_return_val_if_fail(oldfeeds != NULL, NULL);
+ g_return_val_if_fail(name != NULL, NULL);
+
+ if ((needle = g_slist_find_custom(oldfeeds, name, _old_feed_find_by_url))
+ != NULL)
+ return (OldRFeed *)needle->data;
+
+ return NULL;
+}
diff --git a/src/plugins/rssyl/old_feeds.h b/src/plugins/rssyl/old_feeds.h
new file mode 100644
index 0000000..b52cd86
--- /dev/null
+++ b/src/plugins/rssyl/old_feeds.h
@@ -0,0 +1,22 @@
+#ifndef __RSSYL_OLD_FEEDS
+#define __RSSYL_OLD_FEEDS
+
+struct _OldRFeed {
+ gchar *name;
+ gchar *official_name;
+ gchar *url;
+ gint default_refresh_interval;
+ gint refresh_interval;
+ gint expired_num;
+ gint fetch_comments;
+ gint fetch_comments_for;
+ gint silent_update;
+};
+
+typedef struct _OldRFeed OldRFeed;
+
+GSList *rssyl_old_feed_metadata_parse(gchar *filepath);
+void rssyl_old_feed_metadata_free(GSList *oldfeeds);
+OldRFeed *rssyl_old_feed_get_by_name(GSList *oldfeeds, gchar *name);
+
+#endif /* __RSSYL_OLD_FEEDS */
diff --git a/src/plugins/rssyl/opml.c b/src/plugins/rssyl/opml_export.c
similarity index 50%
rename from src/plugins/rssyl/opml.c
rename to src/plugins/rssyl/opml_export.c
index c71cf8b..7ec9369 100644
--- a/src/plugins/rssyl/opml.c
+++ b/src/plugins/rssyl/opml_export.c
@@ -23,42 +23,35 @@
# include "config.h"
#endif
-#include <errno.h>
+/* Global includes */
#include <glib.h>
+#include <glib/gi18n.h>
+#include <errno.h>
-#include <libxml/parser.h>
-#include <libxml/xpath.h>
-
-#include "log.h"
-#include "folder.h"
-#include "folderview.h"
+/* Claws Mail includes */
+#include <log.h>
+#include <folder.h>
+#include <common/utils.h>
-#include "date.h"
-#include "feed.h"
+/* Local includes */
+#include "libfeed/date.h"
#include "rssyl.h"
-#include "strreplace.h"
+#include "opml_import.h"
+#include "strutils.h"
#define RSSYL_OPML_FILE "rssyl-feedlist.opml"
-static gint _folder_depth(FolderItem *item)
-{
- gint i;
-
- for( i = 0; item != NULL; item = folder_item_parent(item), i++ ) {}
- return i;
-}
-
-struct _RSSylOpmlExportCtx {
+struct _RSSylOpmlCtx {
FILE *f;
gint depth;
};
-typedef struct _RSSylOpmlExportCtx RSSylOpmlExportCtx;
+typedef struct _RSSylOpmlCtx RSSylOpmlCtx;
static void rssyl_opml_export_func(FolderItem *item, gpointer data)
{
- RSSylOpmlExportCtx *ctx = (RSSylOpmlExportCtx *)data;
- RSSylFolderItem *ritem = (RSSylFolderItem *)item;
+ RSSylOpmlCtx *ctx = (RSSylOpmlCtx *)data;
+ RFolderItem *ritem = (RFolderItem *)item;
gboolean isfolder = FALSE, err = FALSE;
gboolean haschildren = FALSE;
gchar *indent = NULL, *xmlurl = NULL;
@@ -72,10 +65,10 @@ static void rssyl_opml_export_func(FolderItem *item, gpointer data)
return;
/* Check for depth and adjust indentation */
- depth = _folder_depth(item);
+ depth = rssyl_folder_depth(item);
if( depth < ctx->depth ) {
for( ctx->depth--; depth <= ctx->depth; ctx->depth-- ) {
- indent = g_strnfill(ctx->depth, '\t');
+ indent = g_strnfill(ctx->depth + 1, '\t');
err |= (fprintf(ctx->f, "%s</outline>\n", indent) < 0);
g_free(indent);
}
@@ -93,13 +86,13 @@ static void rssyl_opml_export_func(FolderItem *item, gpointer data)
if( g_node_n_children(item->node) )
haschildren = TRUE;
- indent = g_strnfill(ctx->depth, '\t');
+ indent = g_strnfill(ctx->depth + 1, '\t');
tmpname = rssyl_strreplace(item->name, "&", "&");
- if (ritem->official_name != NULL)
- tmpoffn = rssyl_strreplace(item->name, "&", "&");
- else
- tmpoffn = g_strdup(tmpname);
+ if( ritem->official_title != NULL )
+ tmpoffn = rssyl_strreplace(ritem->official_title, "&", "&");
+ else
+ tmpoffn = g_strdup(tmpname);
err |= (fprintf(ctx->f,
"%s<outline title=\"%s\" text=\"%s\" description=\"%s\" type=\"%s\" %s%s>\n",
@@ -114,7 +107,7 @@ static void rssyl_opml_export_func(FolderItem *item, gpointer data)
if( err ) {
log_warning(LOG_PROTOCOL,
- "Error while writing '%s' to feed export list.\n",
+ _("RSSyl: Error while writing '%s' to feed export list.\n"),
item->name);
debug_print("Error while writing '%s' to feed_export list.\n",
item->name);
@@ -124,9 +117,9 @@ static void rssyl_opml_export_func(FolderItem *item, gpointer data)
void rssyl_opml_export(void)
{
FILE *f;
- gchar *opmlfile, *tmpdate, *indent;
+ gchar *opmlfile, *tmp;
time_t tt = time(NULL);
- RSSylOpmlExportCtx *ctx = NULL;
+ RSSylOpmlCtx *ctx = NULL;
gboolean err = FALSE;
opmlfile = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
@@ -137,14 +130,14 @@ void rssyl_opml_export(void)
if( (f = g_fopen(opmlfile, "w")) == NULL ) {
log_warning(LOG_PROTOCOL,
- "Couldn't open file '%s' for feed list exporting: %s\n",
+ _("RSSyl: Couldn't open file '%s' for feed list exporting: %s\n"),
opmlfile, g_strerror(errno));
- debug_print("Couldn't open feed list export file, returning.\n");
+ debug_print("RSSyl: Couldn't open feed list export file, returning.\n");
g_free(opmlfile);
return;
}
- tmpdate = createRFC822Date(&tt);
+ tmp = createRFC822Date(&tt);
/* Write OPML header */
err |= (fprintf(f,
@@ -155,20 +148,22 @@ void rssyl_opml_export(void)
"\t\t<dateCreated>%s</dateCreated>\n"
"\t</head>\n"
"\t<body>\n",
- tmpdate) < 0);
- g_free(tmpdate);
+ tmp) < 0);
+ g_free(tmp);
- ctx = g_new0(RSSylOpmlExportCtx, 1);
+ ctx = g_new0(RSSylOpmlCtx, 1);
ctx->f = f;
ctx->depth = 1;
folder_func_to_all_folders(
(FolderItemFunc)rssyl_opml_export_func, ctx);
- for( ctx->depth--; ctx->depth >= 2; ctx->depth-- ) {
- indent = g_strnfill(ctx->depth, '\t');
- err |= (fprintf(ctx->f, "%s</outline>\n", indent) < 0);
- g_free(indent);
+ /* Print close all open <outline> tags if needed. */
+ while( ctx->depth > 2 ) {
+ ctx->depth--;
+ tmp = g_strnfill(ctx->depth, '\t');
+ err |= (fprintf(f, "%s</outline>\n", tmp) < 0);
+ g_free(tmp);
}
err |= (fprintf(f,
@@ -176,84 +171,13 @@ void rssyl_opml_export(void)
"</opml>\n") < 0);
if( err ) {
- log_warning(LOG_PROTOCOL, "Error during writing feed export file.\n");
- debug_print("Error during writing feed export file.");
+ log_warning(LOG_PROTOCOL, _("RSSyl: Error during writing feed export file.\n"));
+ debug_print("RSSyl: Error during writing feed export file.\n");
}
- debug_print("Feed export finished.\n");
+ debug_print("RSSyl: Feed export finished.\n");
fclose(f);
g_free(opmlfile);
g_free(ctx);
}
-
-static void rssyl_opml_import_node(xmlNodePtr node,
- FolderItem *parent, gint depth)
-{
- xmlNodePtr curn;
- gchar *url = NULL, *title = NULL, *nodename = NULL;
- FolderItem *item = NULL;
-
- if( node == NULL )
- return;
-
- for( curn = node; curn; curn = curn->next ) {
- nodename = g_ascii_strdown((gchar *)curn->name, -1);
- if( curn->type == XML_ELEMENT_NODE &&
- !strcmp(nodename, "outline") ) {
-
- url = (gchar *)xmlGetProp(curn, (xmlChar *)"xmlUrl");
- title = (gchar *)xmlGetProp(curn, (xmlChar *)"title");
- if (!title)
- title = (gchar *)xmlGetProp(curn, (xmlChar *)"text");
-
- debug_print("Adding '%s' (%s)\n", title, (url ? url : "folder") );
- if( url != NULL )
- item = rssyl_subscribe_new_feed(parent, url, FALSE);
- else if (title != NULL)
- item = folder_create_folder(parent, title);
- else
- item = NULL;
- if (item)
- rssyl_opml_import_node(curn->children, item, depth + 1);
- }
- g_free(nodename);
- }
-}
-
-void rssyl_opml_import(const gchar *opmlfile, FolderItem *parent)
-{
- xmlDocPtr doc;
- xmlNodePtr node;
- xmlXPathContextPtr context;
- xmlXPathObjectPtr result;
- gchar *rootnode = NULL;
-
- doc = xmlParseFile(opmlfile);
- if( doc == NULL )
- return;
-
- node = xmlDocGetRootElement(doc);
- rootnode = g_ascii_strdown((gchar *)node->name, -1);
- if( !strcmp(rootnode, "opml") ) {
- gchar *xpath = "/opml/body";
- context = xmlXPathNewContext(doc);
- if( !(result = xmlXPathEval((xmlChar *)xpath, context)) ) {
- g_free(rootnode);
- xmlFreeDoc(doc);
- return;
- }
-
- node = result->nodesetval->nodeTab[0];
-
- debug_print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
- rssyl_opml_import_node(node->children, parent, 2);
- debug_print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
-
- xmlXPathFreeNodeSetList(result);
- xmlXPathFreeContext(context);
- xmlFreeDoc(doc);
- }
-
- g_free(rootnode);
-}
diff --git a/src/plugins/rssyl/opml.h b/src/plugins/rssyl/opml_export.h
similarity index 64%
rename from src/plugins/rssyl/opml.h
rename to src/plugins/rssyl/opml_export.h
index 9a8aef2..6e89149 100644
--- a/src/plugins/rssyl/opml.h
+++ b/src/plugins/rssyl/opml_export.h
@@ -4,6 +4,5 @@
#include "rssyl.h"
void rssyl_opml_export(void);
-void rssyl_opml_import(const gchar *opmlfile, FolderItem *parent);
#endif /* __RSSYL_OPML */
diff --git a/src/plugins/rssyl/opml_import.c b/src/plugins/rssyl/opml_import.c
new file mode 100644
index 0000000..2a34f5d
--- /dev/null
+++ b/src/plugins/rssyl/opml_import.c
@@ -0,0 +1,110 @@
+/*
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
+ *
+ * - OPML import handling
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <glib/gi18n.h>
+
+/* Claws Mail includes */
+#include <folder.h>
+#include <alertpanel.h>
+#include <common/utils.h>
+
+/* Local includes */
+#include "rssyl_feed.h"
+#include "opml_import.h"
+
+gint rssyl_folder_depth(FolderItem *item)
+{
+ gint i;
+
+ for( i = -1; item != NULL; item = folder_item_parent(item), i++ ) {}
+ return i;
+}
+
+/* This gets called from the libfeed's OPML parser as a user function for
+ * each <outline ...> from the .opml file.
+ * It creates a folder or subscribes a feed, while keeping track of the
+ * location inside folder hierarchy (using depth and linked list of parent
+ * folders up to the root). */
+void rssyl_opml_import_func(gchar *title, gchar *url, gint depth, gpointer data)
+{
+ OPMLImportCtx *ctx = (OPMLImportCtx *)data;
+ gchar *tmp = NULL;
+ FolderItem *new_item;
+ gboolean nulltitle = FALSE;
+ gint i = 1;
+
+ debug_print("depth %d, ctx->depth %d\n", depth, ctx->depth);
+ while (depth < ctx->depth) {
+ /* We've gone up at least one level, need to find correct parent */
+ ctx->current = g_slist_delete_link(ctx->current, ctx->current);
+ ctx->depth--;
+ }
+
+ debug_print("OPML_IMPORT: %s %s (%s)\n",
+ (url != NULL ? "feed": "folder"), title, url);
+
+ if( title == NULL ) {
+ debug_print("NULL title received, substituting a placeholder title\n");
+ title = g_strdup(_("Untitled"));
+ nulltitle = TRUE;
+ }
+
+ /* If URL is not given, then it's a folder */
+ if( url == NULL ) {
+ /* Find an unused name for new folder */
+ tmp = g_strdup(title);
+ while (folder_find_child_item_by_name((FolderItem *)ctx->current->data, tmp)) {
+ debug_print("RSSyl: Folder '%s' already exists, trying another name\n",
+ title);
+ g_free(tmp);
+ tmp = g_strdup_printf("%s__%d", title, ++i);
+ }
+
+ /* Create the folder */
+ new_item = folder_create_folder((FolderItem *)ctx->current->data, tmp);
+ if (!new_item) {
+ alertpanel_error(_("Can't create the folder '%s'."), tmp);
+ g_free(tmp);
+ }
+
+ if (nulltitle) {
+ g_free(title);
+ title = NULL;
+ }
+
+ ctx->current = g_slist_prepend(ctx->current, new_item);
+ ctx->depth++;
+ } else {
+ /* We have URL, try to add new feed... */
+ new_item = rssyl_feed_subscribe_new((FolderItem *)ctx->current->data,
+ url, TRUE);
+ /* ...and rename it if needed */
+ if (new_item != NULL && strcmp(title, new_item->name))
+ folder_item_rename(new_item, title);
+ }
+}
diff --git a/src/plugins/rssyl/opml_import.h b/src/plugins/rssyl/opml_import.h
new file mode 100644
index 0000000..91b71aa
--- /dev/null
+++ b/src/plugins/rssyl/opml_import.h
@@ -0,0 +1,15 @@
+#ifndef __OPML_IMPORT
+#define __OPML_IMPORT
+
+struct _OPMLImportCtx {
+ GSList *current;
+ gint depth;
+ gint failures;
+};
+
+typedef struct _OPMLImportCtx OPMLImportCtx;
+
+gint rssyl_folder_depth(FolderItem *item);
+void rssyl_opml_import_func(gchar *title, gchar *url, gint depth, gpointer data);
+
+#endif /* __OPML_IMPORT */
diff --git a/src/plugins/rssyl/parse822.c b/src/plugins/rssyl/parse822.c
new file mode 100644
index 0000000..846fb6d
--- /dev/null
+++ b/src/plugins/rssyl/parse822.c
@@ -0,0 +1,352 @@
+/*
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Global includes */
+#include <sys/stat.h>
+#include <glib.h>
+#include <pthread.h>
+
+/* Claws Mail includes */
+#include <common/claws.h>
+#include <procheader.h>
+#include <common/utils.h>
+#include <main.h>
+
+/* Local includes */
+#include "libfeed/feed.h"
+#include "libfeed/feeditem.h"
+#include "libfeed/date.h"
+#include "parse822.h"
+#include "rssyl_feed.h"
+#include "rssyl_parse_feed.h"
+#include "strutils.h"
+
+/* rssyl_parse_folder_item_file()
+ *
+ * Parse a RFC822-formatted feed item given by "path", and returns a
+ * pointer to a newly-allocated FeedItem struct, which contains all required data.
+ *
+ */
+FeedItem *rssyl_parse_folder_item_file(gchar *path)
+{
+ gchar *contents, **lines, **line, **splid;
+ GError *error = NULL;
+ FeedItem *item;
+ RFeedCtx *ctx;
+ gint i = 0;
+ gboolean parsing_headers = TRUE, past_html_tag = FALSE, past_endhtml_tag = FALSE;
+ gboolean started_author = FALSE, started_subject = FALSE;
+ gboolean started_link = FALSE, started_clink = FALSE, got_original_title = FALSE;
+
+ debug_print("RSSyl: parsing '%s'\n", path);
+
+ g_file_get_contents(path, &contents, NULL, &error);
+
+ if( error )
+ g_warning("GError: '%s'\n", error->message);
+
+ if( contents != NULL ) {
+ lines = strsplit_no_copy(contents, '\n');
+ } else {
+ g_warning("Badly formatted file found, ignoring: '%s'\n", path);
+ return NULL;
+ }
+
+ ctx = g_new0(RFeedCtx, 1);
+ ctx->path = g_strdup(path); /* store filesystem path to source file */
+ ctx->last_seen = 0;
+
+ item = feed_item_new(NULL);
+ item->data = ctx;
+
+ while( lines[i] ) {
+ if( parsing_headers && lines[i] && !strlen(lines[i]) ) {
+ parsing_headers = FALSE;
+ debug_print("RSSyl: finished parsing headers\n");
+ }
+
+ if( parsing_headers ) {
+ line = g_strsplit(lines[i], ": ", 2);
+ if( line[0] && line[1] && strlen(line[0]) && lines[i][0] != ' ') {
+ started_author = FALSE;
+ started_subject = FALSE;
+ started_link = FALSE;
+ started_clink = FALSE;
+
+ /* Author */
+ if( !strcmp(line[0], "From") ) {
+ feed_item_set_author(item, line[1]);
+ debug_print("RSSyl: got author '%s'\n", feed_item_get_author(item));
+ started_author = TRUE;
+ }
+
+ /* Date */
+ if( !strcmp(line[0], "Date") ) {
+ feed_item_set_date_modified(item,
+ procheader_date_parse(NULL, line[1], 0));
+ debug_print("RSSyl: got date \n" );
+ }
+
+ /* Title */
+ if( !strcmp(line[0], "Subject") && !got_original_title ) {
+ feed_item_set_title(item,line[1]);
+ debug_print("RSSyl: got title '%s'\n", feed_item_get_title(item));
+ started_subject = TRUE;
+ }
+
+ /* Original (including HTML) title - Atom feeds */
+ if( !strcmp(line[0], "X-RSSyl-OrigTitle") ) {
+ feed_item_set_title(item, line[1]);
+ debug_print("RSSyl: got original title '%s'\n",
+ feed_item_get_title(item));
+ got_original_title = TRUE;
+ }
+
+ /* URL */
+ if( !strcmp(line[0], "X-RSSyl-URL") ) {
+ feed_item_set_url(item, line[1]);
+ debug_print("RSSyl: got link '%s'\n", feed_item_get_url(item));
+ started_link = TRUE;
+ }
+
+ /* Last-Seen timestamp */
+ if( !strcmp(line[0], "X-RSSyl-Last-Seen") ) {
+ ctx->last_seen = atol(line[1]);
+ debug_print("RSSyl: got last_seen timestamp %ld\n", ctx->last_seen);
+ }
+
+ /* ID */
+ if( !strcmp(line[0], "Message-ID") ) {
+ splid = g_strsplit_set(line[1], "<>", 3);
+ if( strlen(splid[1]) != 0 )
+ feed_item_set_id(item, splid[1]);
+ g_strfreev(splid);
+ }
+
+ /* Feed comments */
+ if( !strcmp(line[0], "X-RSSyl-Comments") ) {
+ feed_item_set_comments_url(item, line[1]);
+ debug_print("RSSyl: got clink '%s'\n", feed_item_get_comments_url(item));
+ started_clink = TRUE;
+ }
+
+ /* References */
+ if( !strcmp(line[0], "References") ) {
+ splid = g_strsplit_set(line[1], "<>", 3);
+ if( strlen(splid[1]) != 0 )
+ feed_item_set_parent_id(item, line[1]);
+ g_strfreev(splid);
+ }
+
+ } else if (lines[i][0] == ' ') {
+ gchar *tmp = NULL;
+ /* continuation line */
+ if (started_author) {
+ tmp = g_strdup_printf("%s %s", feed_item_get_author(item), lines[i]+1);
+ feed_item_set_author(item, tmp);
+ debug_print("RSSyl: updated author to '%s'\n", tmp);
+ g_free(tmp);
+ } else if (started_subject) {
+ tmp = g_strdup_printf("%s %s", feed_item_get_title(item), lines[i]+1);
+ feed_item_set_title(item, tmp);
+ debug_print("RSSyl: updated title to '%s'\n", tmp);
+ g_free(tmp);
+ } else if (started_link) {
+ tmp = g_strdup_printf("%s%s", feed_item_get_url(item), lines[i]+1);
+ feed_item_set_url(item, tmp);
+ debug_print("RSSyl: updated link to '%s'\n", tmp);
+ g_free(tmp);
+ } else if (started_clink) {
+ tmp = g_strdup_printf("%s%s", feed_item_get_comments_url(item), lines[i]+1);
+ feed_item_set_comments_url(item, tmp);
+ debug_print("RSSyl: updated comments_link to '%s'\n", tmp);
+ }
+ }
+ g_strfreev(line);
+ } else {
+ if( !strcmp(lines[i], RSSYL_TEXT_START) ) {
+ debug_print("RSSyl: Leading html tag found at line %d\n", i);
+ past_html_tag = TRUE;
+ i++;
+ continue;
+ }
+ while( past_html_tag && !past_endhtml_tag && lines[i] ) {
+ if( !strcmp(lines[i], RSSYL_TEXT_END) ) {
+ debug_print("RSSyl: Trailing html tag found at line %d\n", i);
+ past_endhtml_tag = TRUE;
+ i++;
+ continue;
+ }
+ if( feed_item_get_text(item) != NULL ) {
+ gint e_len, n_len;
+ e_len = strlen(item->text);
+ n_len = strlen(lines[i]);
+ item->text = g_realloc(item->text, e_len + n_len + 2);
+ *(item->text+e_len) = '\n';
+ strcpy(item->text+e_len+1, lines[i]);
+ *(item->text+e_len+n_len+1) = '\0';
+ } else {
+ item->text = g_strdup(lines[i]);
+ }
+ i++;
+ }
+
+ if( lines[i] == NULL )
+ return item;
+ }
+
+ i++;
+ }
+ g_free(lines);
+ g_free(contents);
+ return item;
+}
+
+static void rssyl_flush_folder_func(gpointer data, gpointer user_data)
+{
+ FeedItem *item = (FeedItem *)data;
+ RFeedCtx *ctx = (RFeedCtx *)item->data;
+
+ if( ctx != NULL && ctx->path != NULL)
+ g_free(ctx->path);
+ feed_item_free(item);
+}
+
+static void rssyl_folder_read_existing_real(RFolderItem *ritem)
+{
+ gchar *path = NULL, *fname = NULL;
+ DIR *dp;
+ struct dirent *d;
+ struct stat st;
+ gint num;
+ FeedItem *item = NULL;
+ RFeedCtx *ctx;
+
+ g_return_if_fail(ritem != NULL);
+
+ path = folder_item_get_path(&ritem->item);
+ g_return_if_fail(path != NULL);
+
+ debug_print("RSSyl: reading existing items from '%s'\n", path);
+
+ /* Flush contents if any, so we can add new */
+ if( g_slist_length(ritem->items) > 0 ) {
+ g_slist_foreach(ritem->items, (GFunc)rssyl_flush_folder_func, NULL);
+ g_slist_free(ritem->items);
+ }
+ ritem->items = NULL;
+ ritem->last_update = 0;
+
+ if( (dp = opendir(path)) == NULL ) {
+ FILE_OP_ERROR(path, "opendir");
+ g_free(path);
+ return;
+ }
+
+ while( (d = readdir(dp)) != NULL ) {
+ if( claws_is_exiting() ) {
+ closedir(dp);
+ g_free(path);
+ return;
+ }
+
+ if( d->d_name[0] != '.' && (num = to_number(d->d_name)) > 0 ) {
+ fname = g_strdup_printf("%s%c%s", path, G_DIR_SEPARATOR, d->d_name);
+ if( g_stat(fname, &st) < 0 ) {
+ debug_print("RSSyl: couldn't stat() file '%s', ignoring it\n", fname);
+ g_free(fname);
+ continue;
+ }
+
+ if( !S_ISREG(st.st_mode)) {
+ debug_print("RSSyl: not a regular file: '%s', ignoring it\n", fname);
+ g_free(fname);
+ continue;
+ }
+
+ debug_print("RSSyl: starting to parse '%s'\n", d->d_name);
+ if( (item = rssyl_parse_folder_item_file(fname)) != NULL ) {
+ /* Find latest timestamp */
+ ctx = (RFeedCtx *)item->data;
+ if( ritem->last_update < ctx->last_seen )
+ ritem->last_update = ctx->last_seen;
+ debug_print("RSSyl: Appending '%s'\n", feed_item_get_title(item));
+ ritem->items = g_slist_prepend(ritem->items, item);
+ }
+ g_free(fname);
+ }
+ }
+
+ closedir(dp);
+ g_free(path);
+
+ ritem->items = g_slist_reverse(ritem->items);
+}
+
+#ifdef USE_PTHREAD
+static void *rssyl_read_existing_thr(void *arg)
+{
+ RParseCtx *ctx = (RParseCtx *)arg;
+
+ rssyl_folder_read_existing_real(ctx->ritem);
+ ctx->ready = TRUE;
+ return NULL;
+}
+#endif
+
+void rssyl_folder_read_existing(RFolderItem *ritem)
+{
+#ifdef USE_PTHREAD
+ RParseCtx *ctx;
+ pthread_t pt;
+#endif
+
+ g_return_if_fail(ritem != NULL);
+
+
+#ifdef USE_PTHREAD
+ ctx = g_new0(RParseCtx, 1);
+ ctx->ritem = ritem;
+ ctx->ready = FALSE;
+
+ if( pthread_create(&pt, PTHREAD_CREATE_JOINABLE, rssyl_read_existing_thr,
+ (void *)ctx) != 0 ) {
+ /* Couldn't create thread, let's continue non-threaded. */
+ rssyl_folder_read_existing_real(ritem);
+ } else {
+ /* Thread started, wait until it is done. */
+ debug_print("RSSyl: waiting for thread to finish\n");
+ while( !ctx->ready ) {
+ claws_do_idle();
+ }
+
+ debug_print("RSSyl: thread finished\n");
+ pthread_join(pt, NULL);
+ }
+
+ g_free(ctx);
+#else
+ rssyl_folder_read_existing_real(ritem);
+#endif
+}
diff --git a/src/plugins/rssyl/parse822.h b/src/plugins/rssyl/parse822.h
new file mode 100644
index 0000000..94318fc
--- /dev/null
+++ b/src/plugins/rssyl/parse822.h
@@ -0,0 +1,19 @@
+#ifndef __RSSYL_PARSE822_H
+#define __RSSYL_PARSE822_H
+
+#include <glib.h>
+
+#include "libfeed/feeditem.h"
+#include "rssyl.h"
+
+struct _RFeedCtx {
+ gchar *path;
+ time_t last_seen;
+};
+
+typedef struct _RFeedCtx RFeedCtx;
+
+FeedItem *rssyl_parse_folder_item_file(gchar *path);
+void rssyl_folder_read_existing(RFolderItem *ritem);
+
+#endif /* __RSSYL_PARSE822_H */
diff --git a/src/plugins/rssyl/parsers.c b/src/plugins/rssyl/parsers.c
deleted file mode 100644
index bc491ae..0000000
--- a/src/plugins/rssyl/parsers.c
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2004 Hiroyuki Yamamoto
- * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
- *
- * - various feed parsing functions
- * - this file could use some sorting and/or splitting
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <glib.h>
-#include <libxml/parser.h>
-#include <libxml/xpath.h>
-#include <libxml/HTMLtree.h>
-
-#include "date.h"
-#include "feed.h"
-#include "strreplace.h"
-#include "utils.h"
-#include "procheader.h"
-
-gint rssyl_parse_rdf(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent)
-{
- xmlNodePtr rnode, node, n;
- RSSylFeedItem *fitem = NULL;
- gint count = 0;
- gchar *content = NULL;
- g_return_val_if_fail(doc != NULL, 0);
- g_return_val_if_fail(ritem != NULL, 0);
-#ifdef RSSYL_DEBUG
- gchar *fetched = NULL;
-#endif /* RSSYL_DEBUG */
-
- if( ritem->contents == NULL )
- rssyl_read_existing(ritem);
-
- rnode = xmlDocGetRootElement(doc);
-
- for( node = rnode->children; node; node = node->next ) {
- if( !xmlStrcmp(node->name, "item") ) {
- /* We've found an "item" tag, let's poke through its contents */
- fitem = g_new0(RSSylFeedItem, 1);
- fitem->date = 0;
-#ifdef RSSYL_DEBUG
- fetched = xmlGetProp(rnode, "fetched");
- fitem->debug_fetched = atoll(fetched);
- xmlFree(fetched);
-#endif /* RSSYL_DEBUG */
-
- for( n = node->children; n; n = n->next ) {
- /* Title */
- if( !xmlStrcmp(n->name, "title") ) {
- content = xmlNodeGetContent(n);
- fitem->title = rssyl_format_string(content, TRUE, TRUE);
- xmlFree(content);
- debug_print("RSSyl: XML - RDF title is '%s'\n", fitem->title);
- }
-
- /* Text */
- if( !xmlStrcmp(n->name, "description") ) {
- content = xmlNodeGetContent(n);
- fitem->text = rssyl_format_string(content, FALSE, FALSE);
- xmlFree(content);
- debug_print("RSSyl: XML - got RDF text\n");
- }
-
- /* URL */
- if( !xmlStrcmp(n->name, "link") ) {
- content = xmlNodeGetContent(n);
- fitem->link = rssyl_format_string(content, FALSE, TRUE);
- xmlFree(content);
- debug_print("RSSyl: XML - RDF link is '%s'\n", fitem->link);
- }
-
- /* Date - rfc822 format */
- if( !xmlStrcmp(n->name, "pubDate") ) {
- content = xmlNodeGetContent(n);
- fitem->date = procheader_date_parse(NULL, content, 0);
- xmlFree(content);
- if( fitem->date > 0 ) {
- debug_print("RSSyl: XML - RDF pubDate found\n" );
- } else
- fitem->date = 0;
- }
- /* Date - ISO8701 format */
- if( !xmlStrcmp(n->name, "date") &&
- (n->ns && n->ns->prefix && (!xmlStrcmp(n->ns->prefix, "ns")
- || !xmlStrcmp(n->ns->prefix, "dc"))) ) {
- content = xmlNodeGetContent(n);
- fitem->date = parseISO8601Date(content);
- xmlFree(content);
- debug_print("RSSyl: XML - RDF date found\n" );
- }
-
- /* Author */
- if( !xmlStrcmp(n->name, "creator") ) {
- content = xmlNodeGetContent(n);
- fitem->author = rssyl_format_string(content, TRUE, TRUE);
- xmlFree(content);
- debug_print("RSSyl: XML - RDF author is '%s'\n", fitem->author);
- }
- }
- }
-
- if( fitem && fitem->link && fitem->title ) {
- if (rssyl_add_feed_item(ritem, fitem) == FALSE) {
- rssyl_free_feeditem(fitem);
- fitem = NULL;
- }
- fitem = NULL;
- count++;
- }
- }
-
- return count;
-}
-
-
-/* rssyl_parse_rss()
- *
- * This is where we parse the fetched rss document and create a
- * RSSylFolderItem from it. Returns number of parsed items
- */
-gint rssyl_parse_rss(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent)
-{
- xmlXPathContextPtr context;
- xmlXPathObjectPtr result;
- xmlNodePtr node, n, rnode;
- gint i, count = 0;
- RSSylFeedItem *fitem = NULL;
- gchar *xpath;
- gboolean got_encoded, got_author;
- gchar *rootnode = NULL;
- RSSylFeedItemMedia *media;
- gchar *media_url, *media_type;
- gulong media_size = 0;
-#ifdef RSSYL_DEBUG
- gchar *fetched = NULL;
-#endif /* RSSYL_DEBUG */
-
- g_return_val_if_fail(doc != NULL, 0);
- g_return_val_if_fail(ritem != NULL, 0);
-
- if( ritem->contents == NULL )
- rssyl_read_existing(ritem);
-
- rnode = xmlDocGetRootElement(doc);
-
- rootnode = g_ascii_strdown(rnode->name, -1);
- xpath = g_strconcat("/", rootnode,
- "/channel/item", NULL);
- g_free(rootnode);
- context = xmlXPathNewContext(doc);
- if( !(result = xmlXPathEvalExpression(xpath, context)) ){
- debug_print("RSSyl: XML - no result found for '%s'\n", xpath);
- xmlXPathFreeContext(context);
- g_free(xpath);
- return 0;
- }
-
- g_free(xpath);
-
- for( i = 0; i < result->nodesetval->nodeNr; i++ ) {
- node = result->nodesetval->nodeTab[i];
-
- if ((n = node->children) == NULL)
- continue;
-
- fitem = g_new0(RSSylFeedItem, 1);
- fitem->media = NULL;
- fitem->date = 0;
-#ifdef RSSYL_DEBUG
- fetched = xmlGetProp(rnode, "fetched");
- fitem->debug_fetched = atoll(fetched);
- xmlFree(fetched);
-#endif /* RSSYL_DEBUG */
- fitem->text = NULL;
-
- if (parent)
- fitem->parent_link = g_strdup(parent);
-
- got_encoded = FALSE;
- got_author = FALSE;
- do {
- gchar *content = NULL;
-
- /* Title */
- if( !xmlStrcmp(n->name, "title") ) {
- content = xmlNodeGetContent(n);
- fitem->title = rssyl_format_string(content, TRUE, TRUE);
- xmlFree(content);
- debug_print("RSSyl: XML - item title: '%s'\n", fitem->title);
- }
-
- /* Text */
- if( !xmlStrcmp(n->name, "description") ) {
- if( (fitem->text == NULL) && (got_encoded == FALSE) ) {
- content = xmlNodeGetContent(n);
- debug_print("RSSyl: XML - item text (description) caught\n");
- fitem->text = rssyl_format_string(content, FALSE, FALSE);
- xmlFree(content);
- }
- }
- if( !xmlStrcmp(n->name, "encoded") &&
- (n->ns && n->ns->prefix && !xmlStrcmp(n->ns->prefix, "content")) ) {
- debug_print("RSSyl: XML - item text (content) caught\n");
-
- if (fitem->text != NULL)
- g_free(fitem->text); /* free "description" */
-
- content = xmlNodeGetContent(n);
- fitem->text = rssyl_format_string(content, FALSE, FALSE);
- xmlFree(content);
- got_encoded = TRUE;
- }
-
- /* URL link to the original post */
- if( !xmlStrcmp(n->name, "link") &&
- (!n->ns || !n->ns->prefix || !strlen(n->ns->prefix)) ) {
- content = xmlNodeGetContent(n);
- fitem->link = rssyl_format_string(content, FALSE, TRUE);
- xmlFree(content);
- debug_print("RSSyl: XML - item link: '%s'\n", fitem->link);
- }
-
- /* GUID - sometimes used as link */
- if( !xmlStrcmp(n->name, "guid") ) {
- gchar *tmp = xmlGetProp(n, "isPermaLink");
- content = xmlNodeGetContent(n);
- fitem->id_is_permalink = FALSE;
- if( !tmp || xmlStrcmp(tmp, "false") ) /* permalink? */
- fitem->id_is_permalink = TRUE;
- fitem->id = rssyl_format_string(content, FALSE, TRUE);
- xmlFree(content);
- debug_print("RSSyl: XML - item guid: '%s'\n", fitem->id);
- xmlFree(tmp);
- }
-
- /* Date - rfc822 format */
- if( !xmlStrcmp(n->name, "pubDate") ) {
- content = xmlNodeGetContent(n);
- fitem->date = procheader_date_parse(NULL, content, 0);
- xmlFree(content);
- if( fitem->date > 0 ) {
- debug_print("RSSyl: XML - item date found: %d\n", (gint)fitem->date);
- } else
- fitem->date = 0;
- }
- /* Date - ISO8701 format */
- if( !xmlStrcmp(n->name, "date") && !xmlStrcmp(n->ns->prefix, "dc") ) {
- content = xmlNodeGetContent(n);
- fitem->date = parseISO8601Date(content);
- xmlFree(content);
- debug_print("RSSyl: XML - item date found\n" );
- }
-
- /* Author */
- if( !xmlStrcmp(n->name, "author") ) {
- content = xmlNodeGetContent(n);
- fitem->author = rssyl_format_string(content, TRUE, TRUE);
- xmlFree(content);
- debug_print("RSSyl: XML - item author: '%s'\n", fitem->author);
- got_author = TRUE;
- }
-
- if( !xmlStrcmp(n->name, "creator")
- && !xmlStrcmp(n->ns->prefix, "dc") && !got_author) {
- content = xmlNodeGetContent(n);
- fitem->author = rssyl_format_string(content, TRUE, TRUE);
- xmlFree(content);
- debug_print("RSSyl: XML - item author (creator): '%s'\n", fitem->author);
- }
-
- /* Media enclosure */
- if( !xmlStrcmp(n->name, "enclosure") ) {
- gchar *tmp = xmlGetProp(n, "length");
- media_url = xmlGetProp(n, "url");
- media_type = xmlGetProp(n, "type");
- media_size = (tmp ? atoi(tmp) : 0);
- xmlFree(tmp);
-
- if( media_url != NULL &&
- media_type != NULL &&
- media_size != 0 ) {
- debug_print("RSSyl: XML - enclosure: '%s' [%s] (%ld)\n",
- media_url, media_type, media_size);
- media = g_new(RSSylFeedItemMedia, 1);
- media->url = media_url;
- media->type = media_type;
- media->size = media_size;
- fitem->media = media;
- } else {
- debug_print("RSSyl: XML - enclosure found, but some data is missing\n");
- g_free(media_url);
- g_free(media_type);
- }
- }
-
- /* Comments */
- if( !xmlStrcmp(n->name, "commentRSS") || !xmlStrcmp(n->name, "commentRss") ) {
- content = xmlNodeGetContent(n);
- fitem->comments_link = rssyl_format_string(content, FALSE, TRUE);
- xmlFree(content);
- debug_print("RSSyl: XML - comments_link: '%s'\n", fitem->comments_link);
- }
- } while( (n = n->next) != NULL);
-
- if( (fitem->link || fitem->id) && fitem->title ) {
- if (rssyl_add_feed_item(ritem, fitem) == FALSE) {
- rssyl_free_feeditem(fitem);
- fitem = NULL;
- }
- count++;
- }
- }
-
- xmlXPathFreeObject(result);
- xmlXPathFreeContext(context);
-
- return count;
-}
-
-/* rssyl_parse_atom()
- *
- * This is where we parse the fetched atom document and create a
- * RSSylFolderItem from it. Returns number of parsed items
- */
-gint rssyl_parse_atom(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent)
-{
- xmlNodePtr node, n, h;
- xmlBufferPtr buf = NULL;
- gint count = 0;
- RSSylFeedItem *fitem = NULL;
- RSSylFeedItemMedia *media = NULL;
- gchar *link_type, *link_href, *link_rel, *tmp, *content = NULL;
- gulong link_size;
-
- g_return_val_if_fail(doc != NULL, 0);
- g_return_val_if_fail(ritem != NULL, 0);
-
- if( ritem->contents == NULL )
- rssyl_read_existing(ritem);
-
- node = xmlDocGetRootElement(doc);
-
- if (node == NULL)
- return 0;
-
- node = node->children;
-
- for (; node; node = node->next) {
- gboolean got_content = FALSE;
- if (xmlStrcmp(node->name, "entry")) {
- continue;
- }
-
- n = node->children;
- fitem = g_new0(RSSylFeedItem, 1);
- fitem->date = 0;
- fitem->date_published = 0;
- fitem->text = NULL;
-
- if (parent)
- fitem->parent_link = g_strdup(parent);
-
- do {
- /* Title */
- if( !xmlStrcmp(n->name, "title") ) {
- content = xmlNodeGetContent(n);
- fitem->title = rssyl_format_string(content, TRUE, TRUE);
- xmlFree(content);
- debug_print("RSSyl: XML - Atom item title: '%s'\n", fitem->title);
- }
-
- /* ID */
- if( !xmlStrcmp(n->name, "id") ) {
- content = xmlNodeGetContent(n);
- fitem->id = g_strdup_printf("%s%s", (parent?"comment-":""), content);
- xmlFree(content);
- debug_print("RSSyl: XML - Atom id: '%s'\n", fitem->id);
- }
-
- /* Text */
- if( !xmlStrcmp(n->name, "summary") && !got_content ) {
- content = xmlNodeGetContent(n);
- debug_print("RSSyl: XML - Atom item text (summary) caught\n");
- fitem->text = rssyl_format_string(content, FALSE, FALSE);
- xmlFree(content);
- }
-
- if( !xmlStrcmp(n->name, "content") ) {
- gchar *tmp = xmlGetProp(n, "type");
- debug_print("RSSyl: XML - Atom item text (content) caught\n");
- if (fitem->text)
- g_free(fitem->text);
- if( !xmlStrcmp(tmp, "xhtml")) {
- for( h = n->children; h; h = h->next ) {
- if( !xmlStrcmp(h->name, "div") ) {
- buf = xmlBufferCreate();
- htmlNodeDump(buf, doc, h);
- content = g_strdup((gchar *)xmlBufferContent(buf));
- xmlBufferFree(buf);
- }
- }
- } else
- content = xmlNodeGetContent(n);
- xmlFree(tmp);
- fitem->text = rssyl_format_string(content, FALSE, FALSE);
- xmlFree(content);
- got_content = TRUE;
- }
-
- /* link */
- if( !xmlStrcmp(n->name, "link") ) {
- link_type = xmlGetProp(n, "type");
- link_rel = xmlGetProp(n, "rel");
- link_href = xmlGetProp(n, "href");
- tmp = xmlGetProp(n, "length");
- link_size = (tmp ? atoi(tmp) : 0);
- g_free(tmp);
-
- if( !link_rel || (link_rel && !xmlStrcmp(link_rel, "alternate")) ) {
- fitem->link = link_href;
- debug_print("RSSyl: XML - Atom item link: '%s'\n", fitem->link);
- xmlFree(link_type);
- xmlFree(link_rel);
- } else if( link_rel && !xmlStrcmp(link_rel, "enclosure") ) {
- debug_print("RSSyl: XML - Atom item enclosure: '%s' (%ld) [%s]\n",
- link_href, link_size, link_type);
- media = g_new(RSSylFeedItemMedia, 1);
- media->url = link_href;
- media->type = link_type;
- media->size = link_size;
- fitem->media = media;
- xmlFree(link_rel);
- } else {
- xmlFree(link_type);
- xmlFree(link_rel);
- xmlFree(link_href);
- }
- }
-
- /* Date published - ISO8701 format */
- if( !xmlStrcmp(n->name, "published") ) {
- content = xmlNodeGetContent(n);
- fitem->date_published = parseISO8601Date(content);
- xmlFree(content);
- debug_print("RSSyl: XML - Atom item 'issued' date found\n" );
- }
-
- /* Date modified - ISO8701 format */
- if( !xmlStrcmp(n->name, "updated") ) {
- content = xmlNodeGetContent(n);
- fitem->date = parseISO8601Date(content);
- xmlFree(content);
- debug_print("RSSyl: XML - Atom item 'updated' date found\n" );
- }
-
- /* Author */
- if( !xmlStrcmp(n->name, "author") ) {
- xmlNodePtr subnode;
- gchar *name = NULL, *mail = NULL;
- gchar *tmp;
- for (subnode = n->children; subnode; subnode = subnode->next) {
- content = xmlNodeGetContent(subnode);
- if (!xmlStrcmp(subnode->name, "name") && !name)
- name = g_strdup(content);
- if (!xmlStrcmp(subnode->name, "email") && !mail)
- mail = g_strdup(content);
- xmlFree(content);
- }
- tmp = g_strdup_printf("%s%s%s%s%s",
- name ? name:"",
- name && mail ? " <":(mail?"<":""),
- mail ? mail:"",
- mail ? ">":"",
- !name && !mail ? "N/A":"");
- fitem->author = rssyl_format_string(tmp, TRUE, TRUE);
- g_free(tmp);
- g_free(name);
- g_free(mail);
- debug_print("RSSyl: XML - Atom item author: '%s'\n", fitem->author);
- }
-
- /* Comments */
- if( !xmlStrcmp(n->name, "commentRSS") || !xmlStrcmp(n->name, "commentRss")) {
- content = xmlNodeGetContent(n);
- fitem->comments_link = rssyl_format_string(content, FALSE, TRUE);
- xmlFree(content);
- debug_print("RSSyl: XML - comments_link: '%s'\n", fitem->comments_link);
- }
- } while( (n = n->next) != NULL);
-
- if( fitem->id && fitem->title && fitem->date ) {
-
- /* If no link is available, and we can safely guess ID
- * might be a (perma)link, mark it so. */
- if (!fitem->link && fitem->id /* no url, but we have id */
- && (!strncmp(fitem->id, "http:", 5) /* id looks like an url */
- || !strncmp(fitem->id, "https:", 6))) {
- if (!ritem->url || strcmp(ritem->url, fitem->id)) {
- /* id is different from feed url (good chance it is a permalink) */
- debug_print("RSSyl: Marking ID as permalink\n");
- fitem->id_is_permalink = TRUE;
- }
- }
-
- if (rssyl_add_feed_item(ritem, fitem) == FALSE) {
- rssyl_free_feeditem(fitem);
- fitem = NULL;
- }
- count++;
- } else
- debug_print("RSSyl: Incomplete Atom entry, need at least 'id', 'title' and 'updated' tags\n");
- }
-
- return count;
-}
diff --git a/src/plugins/rssyl/parsers.h b/src/plugins/rssyl/parsers.h
deleted file mode 100644
index 48321e6..0000000
--- a/src/plugins/rssyl/parsers.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __PARSERS_H
-#define __PARSERS_H
-
-#include <glib.h>
-#include <libxml/parser.h>
-
-#include "feed.h"
-
-gint rssyl_parse_rss(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent);
-gint rssyl_parse_rdf(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent);
-gint rssyl_parse_atom(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent);
-
-#endif /* __PARSERS_H */
diff --git a/src/plugins/rssyl/plugin.c b/src/plugins/rssyl/plugin.c
index 9cf3cdc..7ade914 100644
--- a/src/plugins/rssyl/plugin.c
+++ b/src/plugins/rssyl/plugin.c
@@ -1,5 +1,5 @@
/*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 1999-2004 Hiroyuki Yamamoto
* This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
*
@@ -22,23 +22,25 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
-#include "claws-features.h"
+# include "claws-features.h"
#endif
-#include <glib.h>
+/* Global includes */
#include <glib/gi18n.h>
-
-#include "common/version.h"
-#include "claws.h"
#include <curl/curl.h>
+/* Claws Mail includes */
+#include <common/claws.h>
+#include <common/version.h>
+#include <plugin.h>
+
+/* Local includes */
#include "rssyl.h"
-#include "plugin.h"
gint plugin_init(gchar **error)
{
- if( !check_plugin_version(MAKE_NUMERIC_VERSION(3,7,8,31),
- VERSION_NUMERIC, PLUGIN_NAME, error) )
+ if( !check_plugin_version(MAKE_NUMERIC_VERSION(3, 7, 8, 31),
+ VERSION_NUMERIC, "RSSyl", error) )
return -1;
curl_global_init(CURL_GLOBAL_DEFAULT);
@@ -55,7 +57,7 @@ gboolean plugin_done(void)
const gchar *plugin_name(void)
{
- return PLUGIN_NAME;
+ return "RSSyl";
}
const gchar *plugin_desc(void)
diff --git a/src/plugins/rssyl/rssyl.c b/src/plugins/rssyl/rssyl.c
index 670dd86..2c5a634 100644
--- a/src/plugins/rssyl/rssyl.c
+++ b/src/plugins/rssyl/rssyl.c
@@ -1,5 +1,5 @@
/*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 1999-2004 Hiroyuki Yamamoto
* This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
*
@@ -22,52 +22,73 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
-#include "claws-features.h"
#endif
+/* Global includes */
#include <glib.h>
#include <glib/gi18n.h>
-
-#ifdef G_OS_WIN32
-# include <w32lib.h>
-#endif
-
-#include <glib.h>
#include <curl/curl.h>
-#include "folder.h"
-#include "localfolder.h"
-
-#include "procheader.h"
-#include "common/utils.h"
-#include "toolbar.h"
-#include "prefs_toolbar.h"
-
-#include "main.h"
-
-#include "feed.h"
-#include "feedprops.h"
-#include "opml.h"
+/* Claws Mail includes */
+#include <folder.h>
+#include <procmsg.h>
+#include <localfolder.h>
+#include <common/utils.h>
+#include <main.h>
+#include <mh.h>
+#include <xml.h>
+#include <toolbar.h>
+#include <prefs_toolbar.h>
+
+/* Local includes */
+#include "libfeed/feeditem.h"
#include "rssyl.h"
+#include "rssyl_deleted.h"
#include "rssyl_gtk.h"
+#include "rssyl_feed.h"
#include "rssyl_prefs.h"
-#include "strreplace.h"
+#include "rssyl_update_feed.h"
+#include "rssyl_update_format.h"
+#include "opml_import.h"
+#include "opml_export.h"
+#include "strutils.h"
+
+FolderClass rssyl_class;
static gint rssyl_create_tree(Folder *folder);
+static gint rssyl_scan_tree(Folder *folder);
static gboolean existing_tree_found = FALSE;
static void rssyl_init_read_func(FolderItem *item, gpointer data)
{
+ RFolderItem *ritem = (RFolderItem *)item;
+ RPrefs *rsprefs = NULL;
+
if( !IS_RSSYL_FOLDER_ITEM(item) )
return;
existing_tree_found = TRUE;
- if( folder_item_parent(item) == NULL )
+ /* Don't do anything if we're on root of our folder tree or on
+ * a regular folder (no feed) */
+ if( folder_item_parent(item) == NULL || ritem->url == NULL )
return;
- rssyl_get_feed_props((RSSylFolderItem *)item);
+ ritem->refresh_id = 0;
+
+ /* Start automatic refresh timer, if necessary */
+ if( ritem->default_refresh_interval ) {
+ rsprefs = rssyl_prefs_get();
+ if( !rsprefs->refresh_enabled )
+ return;
+
+ ritem->refresh_interval = rsprefs->refresh;
+ }
+
+ /* Start the timer, if determined interval is >0 */
+ if( ritem->refresh_interval > 0 )
+ rssyl_feed_start_refresh_timeout(ritem);
}
static void rssyl_make_rc_dir(void)
@@ -80,7 +101,7 @@ static void rssyl_make_rc_dir(void)
g_warning("couldn't create directory %s\n", rssyl_dir);
}
- debug_print("created directorty %s\n", rssyl_dir);
+ debug_print("RSSyl: created directory %s\n", rssyl_dir);
}
g_free(rssyl_dir);
@@ -89,7 +110,6 @@ static void rssyl_make_rc_dir(void)
static void rssyl_create_default_mailbox(void)
{
Folder *root = NULL;
- FolderItem *item;
rssyl_make_rc_dir();
@@ -98,20 +118,21 @@ static void rssyl_create_default_mailbox(void)
g_return_if_fail(root != NULL);
folder_add(root);
- item = FOLDER_ITEM(root->node->data);
+ rssyl_scan_tree(root);
- rssyl_subscribe_new_feed(item, RSSYL_DEFAULT_FEED, TRUE);
+ /* FIXME: subscribe default feed */
+// rssyl_subscribe_new_feed(item, RSSYL_DEFAULT_FEED, TRUE);
}
-static gboolean rssyl_refresh_all_feeds_deferred(gpointer data)
+static gboolean rssyl_update_all_feeds_deferred(gpointer data)
{
- rssyl_refresh_all_feeds();
+ rssyl_update_all_feeds();
return FALSE;
}
-static void rssyl_toolbar_cb_refresh_all(gpointer parent, const gchar *item_name, gpointer data)
+static void rssyl_toolbar_cb_refresh_all_feeds(gpointer parent, const gchar *item_name, gpointer data)
{
- rssyl_refresh_all_feeds();
+ rssyl_update_all_feeds();
}
void rssyl_init(void)
@@ -119,34 +140,37 @@ void rssyl_init(void)
folder_register_class(rssyl_folder_get_class());
rssyl_gtk_init();
-
rssyl_make_rc_dir();
rssyl_prefs_init();
folder_func_to_all_folders((FolderItemFunc)rssyl_init_read_func, NULL);
- if( existing_tree_found == FALSE )
+ if( !existing_tree_found )
rssyl_create_default_mailbox();
+ else
+ rssyl_update_format();
- prefs_toolbar_register_plugin_item(TOOLBAR_MAIN, "RSSyl",
- _("Refresh all feeds"), rssyl_toolbar_cb_refresh_all, NULL);
-
- rssyl_opml_export();
+ prefs_toolbar_register_plugin_item(TOOLBAR_MAIN, "RSSyl", _("Refresh all feeds"), rssyl_toolbar_cb_refresh_all_feeds, NULL);
if( rssyl_prefs_get()->refresh_on_startup &&
claws_is_starting() )
- g_timeout_add(2000, rssyl_refresh_all_feeds_deferred, NULL);
+ g_timeout_add(2000, rssyl_update_all_feeds_deferred, NULL);
}
void rssyl_done(void)
{
- prefs_toolbar_unregister_plugin_item(TOOLBAR_MAIN, "RSSyl",
- _("Refresh all feeds"));
+ rssyl_opml_export();
+
+ prefs_toolbar_unregister_plugin_item(TOOLBAR_MAIN, "RSSyl", _("Refresh all feeds"));
+
rssyl_prefs_done();
rssyl_gtk_done();
- if (!claws_is_exiting())
+
+ if( !claws_is_exiting() )
folder_unregister_class(rssyl_folder_get_class());
+
+ debug_print("RSSyl is done\n");
}
static gchar *rssyl_get_new_msg_filename(FolderItem *dest)
@@ -188,17 +212,15 @@ static void rssyl_get_last_num(Folder *folder, FolderItem *item)
debug_print("rssyl_get_last_num(): Scanning %s ...\n", item->path);
path = folder_item_get_path(item);
g_return_if_fail(path != NULL);
- if( change_dir(path) < 0 ) {
- g_free(path);
- return;
- }
- g_free(path);
- if( (dp = opendir(".")) == NULL ) {
+ if( (dp = opendir(path)) == NULL ) {
FILE_OP_ERROR(item->path, "opendir");
+ g_free(path);
return;
}
+ g_free(path);
+
while( (d = readdir(dp)) != NULL ) {
if( (num = to_number(d->d_name)) > 0 && dirent_is_regular_file(d) ) {
if( max < num )
@@ -211,36 +233,127 @@ static void rssyl_get_last_num(Folder *folder, FolderItem *item)
item->last_num = max;
}
-struct _RSSylFolder {
- LocalFolder folder;
-};
-
-typedef struct _RSSylFolder RSSylFolder;
-
-FolderClass rssyl_class;
-
static Folder *rssyl_new_folder(const gchar *name, const gchar *path)
{
- RSSylFolder *folder;
+ Folder *folder;
- debug_print("RSSyl: new_folder\n");
+ debug_print("RSSyl: new_folder: %s (%s)\n", name, path);
rssyl_make_rc_dir();
- folder = g_new0(RSSylFolder, 1);
+ folder = g_new0(Folder, 1);
FOLDER(folder)->klass = &rssyl_class;
folder_init(FOLDER(folder), name);
return FOLDER(folder);
}
-static void rssyl_destroy_folder(Folder *_folder)
+static void rssyl_destroy_folder(Folder *folder)
{
- RSSylFolder *folder = (RSSylFolder *)_folder;
-
folder_local_folder_destroy(LOCAL_FOLDER(folder));
}
+static void rssyl_item_set_xml(Folder *folder, FolderItem *item, XMLTag *tag)
+{
+ GList *cur;
+ RFolderItem *ritem = (RFolderItem *)item;
+
+ folder_item_set_xml(folder, item, tag);
+
+ for( cur = tag->attr; cur != NULL; cur = g_list_next(cur)) {
+ XMLAttr *attr = (XMLAttr *) cur->data;
+
+ if( !attr || !attr->name || !attr->value)
+ continue;
+
+ /* (str) URL */
+ if( !strcmp(attr->name, "uri")) {
+ g_free(ritem->url);
+ ritem->url = g_strdup(attr->value);
+ }
+ /* (str) Official title */
+ if( !strcmp(attr->name, "official_title")) {
+ g_free(ritem->official_title);
+ ritem->official_title = g_strdup(attr->value);
+ }
+ /* (bool) Keep old items */
+ if( !strcmp(attr->name, "keep_old"))
+ ritem->keep_old = (atoi(attr->value) == 0 ? FALSE : TRUE );
+ /* (bool) Use default refresh_interval */
+ if( !strcmp(attr->name, "default_refresh_interval"))
+ ritem->default_refresh_interval = (atoi(attr->value) == 0 ? FALSE : TRUE );
+ /* (int) Refresh interval */
+ if( !strcmp(attr->name, "refresh_interval"))
+ ritem->refresh_interval = atoi(attr->value);
+ /* (bool) Fetch comments */
+ if( !strcmp(attr->name, "fetch_comments"))
+ ritem->fetch_comments = (atoi(attr->value) == 0 ? FALSE : TRUE );
+ /* (int) Max age of posts to fetch comments for */
+ if( !strcmp(attr->name, "fetch_comments_max_age"))
+ ritem->fetch_comments_max_age = atoi(attr->value);
+ /* (bool) Write heading */
+ if( !strcmp(attr->name, "write_heading"))
+ ritem->write_heading = (atoi(attr->value) == 0 ? FALSE : TRUE );
+ /* (int) Silent update */
+ if( !strcmp(attr->name, "silent_update"))
+ ritem->silent_update = atoi(attr->value);
+ /* (bool) Ignore title rename */
+ if( !strcmp(attr->name, "ignore_title_rename"))
+ ritem->ignore_title_rename = (atoi(attr->value) == 0 ? FALSE : TRUE );
+ /* (bool) Verify SSL peer */
+ if( !strcmp(attr->name, "ssl_verify_peer"))
+ ritem->ssl_verify_peer = (atoi(attr->value) == 0 ? FALSE : TRUE );
+ }
+}
+
+static XMLTag *rssyl_item_get_xml(Folder *folder, FolderItem *item)
+{
+ XMLTag *tag;
+ RFolderItem *ri = (RFolderItem *)item;
+ gchar *tmp = NULL;
+
+ tag = folder_item_get_xml(folder, item);
+
+ /* (str) URL */
+ if( ri->url != NULL )
+ xml_tag_add_attr(tag, xml_attr_new("uri", ri->url));
+ /* (str) Official title */
+ if( ri->official_title != NULL )
+ xml_tag_add_attr(tag, xml_attr_new("official_title", ri->official_title));
+ /* (bool) Keep old items */
+ xml_tag_add_attr(tag, xml_attr_new("keep_old",
+ (ri->keep_old ? "1" : "0")) );
+ /* (bool) Use default refresh interval */
+ xml_tag_add_attr(tag, xml_attr_new("default_refresh_interval",
+ (ri->default_refresh_interval ? "1" : "0")) );
+ /* (int) Refresh interval */
+ tmp = g_strdup_printf("%d", ri->refresh_interval);
+ xml_tag_add_attr(tag, xml_attr_new("refresh_interval", tmp));
+ g_free(tmp);
+ /* (bool) Fetch comments */
+ xml_tag_add_attr(tag, xml_attr_new("fetch_comments",
+ (ri->fetch_comments ? "1" : "0")) );
+ /* (int) Max age of posts to fetch comments for */
+ tmp = g_strdup_printf("%d", ri->fetch_comments_max_age);
+ xml_tag_add_attr(tag, xml_attr_new("fetch_comments_max_age", tmp));
+ g_free(tmp);
+ /* (bool) Write heading */
+ xml_tag_add_attr(tag, xml_attr_new("write_heading",
+ (ri->write_heading ? "1" : "0")) );
+ /* (int) Silent update */
+ tmp = g_strdup_printf("%d", ri->silent_update);
+ xml_tag_add_attr(tag, xml_attr_new("silent_update", tmp));
+ g_free(tmp);
+ /* (bool) Ignore title rename */
+ xml_tag_add_attr(tag, xml_attr_new("ignore_title_rename",
+ (ri->ignore_title_rename ? "1" : "0")) );
+ /* (bool) Verify SSL peer */
+ xml_tag_add_attr(tag, xml_attr_new("ssl_verify_peer",
+ (ri->ssl_verify_peer ? "1" : "0")) );
+
+ return tag;
+}
+
static gint rssyl_scan_tree(Folder *folder)
{
g_return_val_if_fail(folder != NULL, -1);
@@ -261,6 +374,8 @@ static gint rssyl_create_tree(Folder *folder)
FolderItem *rootitem;
GNode *rootnode;
+ g_return_val_if_fail(folder != NULL, -1);
+
rssyl_make_rc_dir();
if( !folder->node ) {
@@ -269,9 +384,6 @@ static gint rssyl_create_tree(Folder *folder)
rootnode = g_node_new(rootitem);
folder->node = rootnode;
rootitem->node = rootnode;
- } else {
- rootitem = FOLDER_ITEM(folder->node->data);
- rootnode = folder->node;
}
debug_print("RSSyl: created new rssyl tree\n");
@@ -280,125 +392,201 @@ static gint rssyl_create_tree(Folder *folder)
static FolderItem *rssyl_item_new(Folder *folder)
{
- RSSylFolderItem *ritem;
-
- debug_print("RSSyl: item_new\n");
-
- ritem = g_new0(RSSylFolderItem, 1);
+ RFolderItem *ritem = g_new0(RFolderItem, 1);
ritem->url = NULL;
+ ritem->official_title = NULL;
+ ritem->source_id = NULL;
+ ritem->items = NULL;
+ ritem->keep_old = FALSE;
ritem->default_refresh_interval = TRUE;
- ritem->default_expired_num = TRUE;
+ ritem->refresh_interval = atoi(PREF_DEFAULT_REFRESH);
ritem->fetch_comments = FALSE;
- ritem->fetch_comments_for = -1;
+ ritem->fetch_comments_max_age = -1;
+ ritem->write_heading = TRUE;
+ ritem->fetching_comments = FALSE;
ritem->silent_update = 0;
- ritem->refresh_interval = rssyl_prefs_get()->refresh;
- ritem->refresh_id = 0;
- ritem->expired_num = rssyl_prefs_get()->expired;
- ritem->last_count = 0;
- ritem->ssl_verify_peer = rssyl_prefs_get()->ssl_verify_peer;
-
- ritem->contents = NULL;
- ritem->feedprop = NULL;
+ ritem->last_update = 0;
+ ritem->ignore_title_rename = FALSE;
return (FolderItem *)ritem;
}
static void rssyl_item_destroy(Folder *folder, FolderItem *item)
{
- RSSylFolderItem *ritem = (RSSylFolderItem *)item;
+ RFolderItem *ritem = (RFolderItem *)item;
g_return_if_fail(ritem != NULL);
- /* Silently remove feed refresh timeouts */
- if( ritem->refresh_id != 0 )
- g_source_remove(ritem->refresh_id);
-
g_free(ritem->url);
- g_free(ritem->official_name);
- g_slist_free(ritem->contents);
+ g_free(ritem->official_title);
+ g_slist_free(ritem->items);
- g_free(item);
+ /* Remove a scheduled refresh, if any */
+ if( ritem->refresh_id != 0)
+ g_source_remove(ritem->refresh_id);
+
+ g_free(ritem);
}
static FolderItem *rssyl_create_folder(Folder *folder,
FolderItem *parent, const gchar *name)
{
- gchar *path = NULL, *tmp;
+ gchar *path = NULL, *basepath = NULL, *itempath = NULL;
FolderItem *newitem = NULL;
g_return_val_if_fail(folder != NULL, NULL);
g_return_val_if_fail(parent != NULL, NULL);
g_return_val_if_fail(name != NULL, NULL);
- tmp = rssyl_feed_title_to_dir((gchar *)name);
- path = g_strconcat((parent->path != NULL) ? parent->path : "", ".",
- tmp, NULL);
- g_free(tmp);
- newitem = folder_item_new(folder, name, path);
- folder_item_append(parent, newitem);
+
+ path = folder_item_get_path(parent);
+ if( !is_dir_exist(path) ) {
+ if( (make_dir_hier(path) != 0) ) {
+ debug_print("RSSyl: Couldn't create directory (rec) '%s'\n", path);
+ return NULL;
+ }
+ }
+
+ basepath = g_strdelimit(g_strdup(name), G_DIR_SEPARATOR_S, '_');
+ path = g_strconcat(path, G_DIR_SEPARATOR_S, basepath, NULL);
+
+ if( make_dir(path) < 0 ) {
+ debug_print("RSSyl: Couldn't create directory '%s'\n", path);
+ g_free(path);
+ g_free(basepath);
+ return NULL;
+ }
g_free(path);
+ itempath = g_strconcat((parent->path ? parent->path : ""),
+ G_DIR_SEPARATOR_S, basepath, NULL);
+ newitem = folder_item_new(folder, name, itempath);
+ g_free(itempath);
+ g_free(basepath);
+
+ folder_item_append(parent, newitem);
+
return newitem;
}
+FolderItem *rssyl_get_root_folderitem(FolderItem *item)
+{
+ FolderItem *i;
+
+ for( i = item; folder_item_parent(i) != NULL; i = folder_item_parent(i) ) { }
+ return i;
+}
+
static gchar *rssyl_item_get_path(Folder *folder, FolderItem *item)
{
- gchar *result, *tmp;
- tmp = rssyl_feed_title_to_dir(item->name);
- result = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
- G_DIR_SEPARATOR_S, tmp, NULL);
- g_free(tmp);
- return result;
+ gchar *path, *name;
+
+ g_return_val_if_fail(folder != NULL, NULL);
+ g_return_val_if_fail(item != NULL, NULL);
+
+ debug_print("RSSyl: item_get_path\n");
+
+ name = folder_item_get_name(rssyl_get_root_folderitem(item));
+ path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
+ G_DIR_SEPARATOR_S, name, G_DIR_SEPARATOR_S, item->path, NULL);
+ g_free(name);
+
+ return path;
+}
+
+static gboolean rssyl_rename_folder_func(GNode *node, gpointer data)
+{
+ FolderItem *item = node->data;
+ gchar **paths = data;
+ const gchar *oldpath = paths[0];
+ const gchar *newpath = paths[1];
+ gchar *base;
+ gchar *new_itempath;
+ gint oldpathlen;
+
+ oldpathlen = strlen(oldpath);
+ if (strncmp(oldpath, item->path, oldpathlen) != 0) {
+ g_warning("path doesn't match: %s, %s\n", oldpath, item->path);
+ return TRUE;
+ }
+
+ base = item->path + oldpathlen;
+ while (*base == G_DIR_SEPARATOR) base++;
+ if (*base == '\0')
+ new_itempath = g_strdup(newpath);
+ else
+ new_itempath = g_strconcat(newpath, G_DIR_SEPARATOR_S, base,
+ NULL);
+ g_free(item->path);
+ item->path = new_itempath;
+
+ return FALSE;
}
static gint rssyl_rename_folder(Folder *folder, FolderItem *item,
const gchar *name)
{
- gchar *oldname = NULL, *oldpath = NULL, *newpath = NULL;
- RSSylFolderItem *ritem = NULL;
+ gchar *oldpath;
+ gchar *dirname;
+ gchar *newpath, *utf8newpath;
+ gchar *basenewpath;
+ gchar *paths[2];
+
g_return_val_if_fail(folder != NULL, -1);
g_return_val_if_fail(item != NULL, -1);
g_return_val_if_fail(item->path != NULL, -1);
g_return_val_if_fail(name != NULL, -1);
- debug_print("RSSyl: renaming folder '%s' to '%s'\n", item->path, name);
+ debug_print("RSSyl: rssyl_rename_folder '%s' -> '%s'\n",
+ item->name, name);
- oldpath = rssyl_item_get_path(folder, item);
-
- /* now get the new path using the new name */
- oldname = item->name;
- item->name = g_strdup(name);
- newpath = rssyl_item_get_path(folder, item);
-
- /* put back the old name in case the rename fails */
- g_free(item->name);
- item->name = oldname;
-
- if (g_rename(oldpath, newpath) < 0) {
+ if (!strcmp(item->name, name))
+ return 0;
+
+ oldpath = folder_item_get_path(item);
+ if( !is_dir_exist(oldpath) )
+ make_dir_hier(oldpath);
+
+ dirname = g_path_get_dirname(oldpath);
+ basenewpath = g_strdelimit(g_strdup(name), G_DIR_SEPARATOR_S, '_');
+ newpath = g_strconcat(dirname, G_DIR_SEPARATOR_S, basenewpath, NULL);
+ g_free(basenewpath);
+
+ if( g_rename(oldpath, newpath) < 0 ) {
FILE_OP_ERROR(oldpath, "rename");
g_free(oldpath);
g_free(newpath);
return -1;
}
-
- g_free(item->path);
- item->path = g_strdup_printf(".%s", name);
-
- ritem = (RSSylFolderItem *)item;
-
- if (ritem->url)
- rssyl_props_update_name(ritem, (gchar *)name);
-
+
+ g_free(oldpath);
+ g_free(newpath);
+
+ if( strchr(item->path, G_DIR_SEPARATOR) != NULL ) {
+ dirname = g_path_get_dirname(item->path);
+ utf8newpath = g_strconcat(dirname, G_DIR_SEPARATOR_S, name, NULL);
+ g_free(dirname);
+ } else
+ utf8newpath = g_strdup(name);
+
g_free(item->name);
item->name = g_strdup(name);
-
- folder_write_list();
+
+ paths[0] = g_strdup(item->path);
+ paths[1] = utf8newpath;
+ g_node_traverse(item->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+ rssyl_rename_folder_func, paths);
+
+ g_free(paths[0]);
+ g_free(paths[1]);
return 0;
}
static gint rssyl_remove_folder(Folder *folder, FolderItem *item)
{
+ gchar *path = NULL;
+
g_return_val_if_fail(folder != NULL, -1);
g_return_val_if_fail(item != NULL, -1);
g_return_val_if_fail(item->path != NULL, -1);
@@ -406,6 +594,14 @@ static gint rssyl_remove_folder(Folder *folder, FolderItem *item)
debug_print("RSSyl: removing folder item %s\n", item->path);
+ path = folder_item_get_path(item);
+ if( remove_dir_recursive(path) < 0 ) {
+ g_warning("can't remove directory '%s'\n", path);
+ g_free(path);
+ return -1;
+ }
+
+ g_free(path);
folder_item_remove(item);
return 0;
@@ -418,40 +614,35 @@ static gint rssyl_get_num_list(Folder *folder, FolderItem *item,
DIR *dp;
struct dirent *d;
gint num, nummsgs = 0;
- RSSylFolderItem *ritem = (RSSylFolderItem *)item;
g_return_val_if_fail(item != NULL, -1);
- debug_print("RSSyl: scanning '%s'...\n", item->path);
-
- rssyl_get_feed_props(ritem);
-
- if (ritem->url == NULL)
- return -1;
+ debug_print("RSSyl: get_num_list: scanning '%s'\n", item->path);
*old_uids_valid = TRUE;
-
+
path = folder_item_get_path(item);
g_return_val_if_fail(path != NULL, -1);
- if( change_dir(path) < 0 ) {
- g_free(path);
- return -1;
- }
- g_free(path);
- if( (dp = opendir(".")) == NULL ) {
+ if( (dp = opendir(path)) == NULL ) {
FILE_OP_ERROR(item->path, "opendir");
+ g_free(path);
return -1;
}
+ g_free(path);
+
while( (d = readdir(dp)) != NULL ) {
if( (num = to_number(d->d_name)) > 0 ) {
*list = g_slist_prepend(*list, GINT_TO_POINTER(num));
nummsgs++;
}
}
+
closedir(dp);
+ debug_print("Rssyl: get_num_list: returning %d\n", nummsgs);
+
return nummsgs;
}
@@ -462,15 +653,22 @@ static gboolean rssyl_scan_required(Folder *folder, FolderItem *item)
static gchar *rssyl_fetch_msg(Folder *folder, FolderItem *item, gint num)
{
- gchar *snum = g_strdup_printf("%d", num);
- gchar *tmp = rssyl_feed_title_to_dir(item->name);
- gchar *file = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
- G_DIR_SEPARATOR_S, tmp,
- G_DIR_SEPARATOR_S, snum, NULL);
- g_free(tmp);
- debug_print("RSSyl: fetch_msg: '%s'\n", file);
+ gchar *path;
+ gchar *file;
+
+ g_return_val_if_fail(item != NULL, NULL);
+ g_return_val_if_fail(num > 0, NULL);
+
+ path = folder_item_get_path(item);
+ file = g_strconcat(path, G_DIR_SEPARATOR_S, itos(num), NULL);
+ g_free(path);
+
+ debug_print("RSSyl: fetch_msg '%s'\n", file);
- g_free(snum);
+ if( !is_file_exist(file)) {
+ g_free(file);
+ return NULL;
+ }
return file;
}
@@ -481,25 +679,24 @@ static MsgInfo *rssyl_get_msginfo(Folder *folder, FolderItem *item, gint num)
gchar *file;
MsgFlags flags;
- debug_print("RSSyl: get_msginfo: %d\n", num);
-
g_return_val_if_fail(folder != NULL, NULL);
g_return_val_if_fail(item != NULL, NULL);
g_return_val_if_fail(num > 0, NULL);
+ debug_print("RSSyl: get_msginfo: %d\n", num);
+
file = rssyl_fetch_msg(folder, item, num);
g_return_val_if_fail(file != NULL, NULL);
- flags.perm_flags = MSG_NEW | MSG_UNREAD;
+ flags.perm_flags = 0;
flags.tmp_flags = 0;
- msginfo = rssyl_parse_feed_item_to_msginfo(file, flags, TRUE, TRUE, item);
+ msginfo = rssyl_feed_parse_item_to_msginfo(file, flags, TRUE, TRUE, item);
+ g_free(file);
if( msginfo )
msginfo->msgnum = num;
- g_free(file);
-
return msginfo;
}
@@ -523,30 +720,31 @@ static gint rssyl_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
destfile = rssyl_get_new_msg_filename(dest);
g_return_val_if_fail(destfile != NULL, -1);
+ debug_print("RSSyl: add_msgs: new filename is '%s'\n", destfile);
-#ifdef G_OS_UNIX
- if( link(fileinfo->file, destfile) < 0 )
-#endif
+ if( link(fileinfo->file, destfile) < 0 ) {
if( copy_file(fileinfo->file, destfile, TRUE) < 0 ) {
g_warning("can't copy message %s to %s\n", fileinfo->file, destfile);
g_free(destfile);
return -1;
}
+ }
if( relation != NULL )
- g_hash_table_insert(relation, fileinfo,
- GINT_TO_POINTER(dest->last_num + 1) );
+ g_hash_table_insert(relation, fileinfo->msginfo != NULL ?
+ (gpointer) fileinfo->msginfo : (gpointer) fileinfo,
+ GINT_TO_POINTER(dest->last_num + 1));
g_free(destfile);
dest->last_num++;
}
+
return dest->last_num;
}
static gint rssyl_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
MsgFlags *flags)
{
- gint ret;
GSList file_list;
MsgFileInfo fileinfo;
@@ -558,28 +756,9 @@ static gint rssyl_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
file_list.data = &fileinfo;
file_list.next = NULL;
- ret = rssyl_add_msgs(folder, dest, &file_list, NULL);
- return ret;
+ return rssyl_add_msgs(folder, dest, &file_list, NULL);
}
-static gint rssyl_dummy_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *info)
-{
- if (info->folder == NULL || info->folder->folder != dest->folder) {
- return -1;
- }
- if (info->folder && info->folder->name && dest->name
- && !strcmp(info->folder->name, dest->name)) {
- /* this is a folder move */
- gchar *file = procmsg_get_message_file(info);
- gchar *tmp = g_strdup_printf("%s.tmp", file);
- copy_file(file, tmp, TRUE);
- g_free(file);
- g_free(tmp);
- return info->msgnum;
- } else {
- return -1;
- }
-}
static gint rssyl_remove_msg(Folder *folder, FolderItem *item, gint num)
{
gboolean need_scan = FALSE;
@@ -595,13 +774,16 @@ static gint rssyl_remove_msg(Folder *folder, FolderItem *item, gint num)
/* are we doing a folder move ? */
tmp = g_strdup_printf("%s.tmp", file);
if (is_file_exist(tmp)) {
- claws_unlink(tmp);
+ g_unlink(tmp);
g_free(tmp);
g_free(file);
return 0;
}
g_free(tmp);
- if( claws_unlink(file) < 0 ) {
+
+ rssyl_deleted_add((RFolderItem *)item, file);
+
+ if( g_unlink(file) < 0 ) {
FILE_OP_ERROR(file, "unlink");
g_free(file);
return -1;
@@ -618,11 +800,29 @@ static gboolean rssyl_subscribe_uri(Folder *folder, const gchar *uri)
{
if (folder->klass != rssyl_folder_get_class())
return FALSE;
-
- if( rssyl_subscribe_new_feed(
- FOLDER_ITEM(folder->node->data), uri, FALSE) != NULL )
- return TRUE;
- return FALSE;
+ return (rssyl_feed_subscribe_new(FOLDER_ITEM(folder->node->data), uri, FALSE) ?
+ TRUE : FALSE);
+}
+
+static void rssyl_copy_private_data(Folder *folder, FolderItem *oldi,
+ FolderItem *newi)
+{
+ RFolderItem *olditem = (RFolderItem *)oldi,
+ *newitem = (RFolderItem *)newi;
+
+ g_return_if_fail(folder != NULL);
+ g_return_if_fail(olditem != NULL);
+ g_return_if_fail(newitem != NULL);
+
+ if( olditem->url != NULL ) {
+ g_free(newitem->url);
+ newitem->url = g_strdup(olditem->url);
+ }
+
+ if( olditem->official_title != NULL ) {
+ g_free(newitem->official_title);
+ newitem->official_title = g_strdup(olditem->official_title);
+ }
}
/************************************************************************/
@@ -651,11 +851,14 @@ FolderClass *rssyl_folder_get_class()
rssyl_class.remove_folder = rssyl_remove_folder;
rssyl_class.get_num_list = rssyl_get_num_list;
rssyl_class.scan_required = rssyl_scan_required;
+ rssyl_class.item_set_xml = rssyl_item_set_xml;
+ rssyl_class.item_get_xml = rssyl_item_get_xml;
/* Message functions */
rssyl_class.get_msginfo = rssyl_get_msginfo;
rssyl_class.fetch_msg = rssyl_fetch_msg;
- rssyl_class.copy_msg = rssyl_dummy_copy_msg;
+ rssyl_class.copy_msg = mh_get_class()->copy_msg;
+ rssyl_class.copy_msgs = mh_get_class()->copy_msgs;
rssyl_class.add_msg = rssyl_add_msg;
rssyl_class.add_msgs = rssyl_add_msgs;
rssyl_class.remove_msg = rssyl_remove_msg;
@@ -663,7 +866,8 @@ FolderClass *rssyl_folder_get_class()
// rssyl_class.change_flags = rssyl_change_flags;
rssyl_class.change_flags = NULL;
rssyl_class.subscribe = rssyl_subscribe_uri;
- debug_print("RSSyl: registered folderclass\n");
+ rssyl_class.copy_private_data = rssyl_copy_private_data;
+ rssyl_class.search_msgs = folder_item_search_msgs_local;
}
return &rssyl_class;
diff --git a/src/plugins/rssyl/rssyl.h b/src/plugins/rssyl/rssyl.h
index 917adbe..7b1b169 100644
--- a/src/plugins/rssyl/rssyl.h
+++ b/src/plugins/rssyl/rssyl.h
@@ -5,10 +5,13 @@
#include <folder.h>
-#define PLUGIN_NAME (_("RSSyl"))
+#include "libfeed/feed.h"
/* Name of directory in rcdir where RSSyl will store its data. */
-#define RSSYL_DIR "RSSyl"
+#define RSSYL_DIR "RSSyl"
+
+/* Folder name for a new feed, before it is parsed for the first time. */
+#define RSSYL_NEW_FOLDER_NAME "NewFeed"
/* Default RSSyl mailbox name */
#define RSSYL_DEFAULT_MAILBOX _("My Feeds")
@@ -16,43 +19,80 @@
/* Default feed to be added when creating mailbox for the first time */
#define RSSYL_DEFAULT_FEED "http://planet.claws-mail.org/rss20.xml"
-struct _RSSylFolderItem {
- FolderItem item;
- GSList *contents;
- gint last_count;
+/* File where info about user-deleted feed items is stored */
+#define RSSYL_DELETED_FILE ".deleted"
+struct _RFolderItem {
+ FolderItem item;
gchar *url;
- gchar *official_name;
+ gchar *official_title;
+ gchar *source_id;
+
+ gboolean keep_old;
gboolean default_refresh_interval;
gint refresh_interval;
- gboolean default_expired_num;
- gint expired_num;
-
- guint refresh_id;
gboolean fetch_comments;
- gint fetch_comments_for;
+ gint fetch_comments_max_age;
+
gint silent_update;
+ gboolean write_heading;
+ gboolean ignore_title_rename;
gboolean ssl_verify_peer;
- struct _RSSylFeedProp *feedprop;
+ guint refresh_id;
+ gboolean fetching_comments;
+ time_t last_update;
+
+ struct _RFeedProp *feedprop;
+
+ GSList *items;
+ GSList *deleted_items;
};
-typedef struct _RSSylFolderItem RSSylFolderItem;
+typedef struct _RFolderItem RFolderItem;
-struct _RSSylRefreshCtx {
- RSSylFolderItem *ritem;
+struct _RRefreshCtx {
+ RFolderItem *ritem;
guint id;
};
-typedef struct _RSSylRefreshCtx RSSylRefreshCtx;
+typedef struct _RRefreshCtx RRefreshCtx;
+
+struct _RFetchCtx {
+ Feed *feed;
+ guint response_code;
+ gchar *error;
+ gboolean success;
+ gboolean ready;
+};
+
+typedef struct _RFetchCtx RFetchCtx;
+
+struct _RParseCtx {
+ RFolderItem *ritem;
+ gboolean ready;
+};
+
+typedef struct _RParseCtx RParseCtx;
+
+struct _RDeletedItem {
+ gchar *id;
+ gchar *title;
+ time_t date_published;
+ time_t date_modified;
+};
+
+typedef struct _RDeletedItem RDeletedItem;
void rssyl_init(void);
void rssyl_done(void);
FolderClass *rssyl_folder_get_class(void);
+FolderItem *rssyl_get_root_folderitem(FolderItem *item);
+
#define IS_RSSYL_FOLDER_ITEM(item) \
(item->folder->klass == rssyl_folder_get_class())
diff --git a/src/plugins/rssyl/rssyl_add_item.c b/src/plugins/rssyl/rssyl_add_item.c
new file mode 100644
index 0000000..b058660
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_add_item.c
@@ -0,0 +1,540 @@
+/*
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
+ *
+ * - DESCRIPTION HERE
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <string.h>
+
+/* Claws Mail includes */
+#include <codeconv.h>
+#include <procmsg.h>
+#include <common/utils.h>
+
+/* Local includes */
+#include "libfeed/date.h"
+#include "libfeed/feeditem.h"
+#include "parse822.h"
+#include "rssyl.h"
+#include "rssyl_deleted.h"
+#include "rssyl_feed.h"
+#include "rssyl_parse_feed.h"
+#include "strutils.h"
+
+/* rssyl_cb_feed_compare()
+ *
+ * GCompareFunc function called by glib2's g_slist_find_custom().
+ */
+
+static gint rssyl_cb_feed_compare(const FeedItem *a, const FeedItem *b)
+{
+ gboolean date_eq = FALSE, url_eq = FALSE, title_eq = FALSE;
+ gboolean no_url = FALSE, no_date = FALSE, no_title = FALSE;
+ gchar *atit = NULL, *btit = NULL;
+
+ g_return_val_if_fail(a != NULL && b != NULL, 1);
+
+ /* ID should be unique. If it matches, we've found what we came for. */
+ if( (a->id != NULL) && (b->id != NULL) ) {
+ if( !strcmp(a->id, b->id) ) {
+ return 0;
+ }
+
+ /* If both IDs are present, but they do not match, these are not the
+ * droids we're looking for. */
+ return 1;
+ }
+
+ /* Ok, we have no ID to aid us. Let's have a look at item timestamps
+ * and item title & url. */
+ if( (a->url != NULL) && (b->url != NULL) ) {
+ if( !strcmp(a->url, b->url) )
+ url_eq = TRUE;
+ } else
+ no_url = TRUE;
+
+ if( (a->title != NULL) && (b->title != NULL) ) {
+ atit = conv_unmime_header(a->title, CS_UTF_8, FALSE);
+ btit = conv_unmime_header(b->title, CS_UTF_8, FALSE);
+ if( !strcmp(atit, btit) )
+ title_eq = TRUE;
+ g_free(atit);
+ g_free(btit);
+ } else
+ no_title = TRUE;
+
+ /* If there's no 'published' timestamp for the item, we can only judge
+ * by item url - 'modified' timestamp can have changed if the item was
+ * updated recently. */
+ if( b->date_published <= 0 ) {
+ if( b->date_modified > 0 ) {
+ /* If the item has 'modified' timestamp, we can only rely on url
+ * and title at this point. */
+ if( (url_eq || no_url) && title_eq
+ && (a->date_modified >= b->date_modified) )
+ return 0;
+ else
+ return 1;
+ } else {
+ /* No timestamp of any kind, we'll just assume if both title and url
+ * match, we found the right item. Items in such feeds rarely change,
+ * and if they do, there's no way we can really */
+ if( (url_eq || no_url) && title_eq )
+ return 0;
+ else
+ return 1;
+ }
+ }
+
+ /* Check if 'published' or at least 'modified' timestamps match */
+ if( ((a->date_published > 0) && (b->date_published > 0) &&
+ (a->date_published == b->date_published))
+ || ((a->date_modified > 0) && (b->date_modified > 0) &&
+ (a->date_modified == b->date_modified))) {
+ date_eq = TRUE;
+ } else
+ no_date = TRUE;
+
+ /* If 'published' time and item url match, it is reasonable to assume
+ * we found our item. */
+ if( (no_url || url_eq) && date_eq )
+ return 0;
+
+ /* There is no timestamp and the url matches (or there is none),
+ * we need to compare titles, ... */
+ if( (no_url || url_eq) && no_date ) {
+ if( title_eq )
+ return 0;
+ else
+ return 1;
+
+ /* ... and as a last resort, if there is no title, item texts. */
+ if( no_title && a->text && b->text ) {
+ if( !strcmp(a->text, b->text) )
+ return 0;
+ else
+ return 1;
+ }
+ }
+
+ /* We don't know this item. */
+ return 1;
+}
+
+enum {
+ ITEM_UNCHANGED,
+ ITEM_CHANGED_TEXTONLY,
+ ITEM_CHANGED
+};
+
+static gint rssyl_feed_item_changed(FeedItem *new_item, FeedItem *old_item )
+{
+ debug_print("RSSyl: comparing '%s' and '%s'\n",
+ new_item->title, old_item->title);
+
+ /* if both have title ... */
+ if( old_item->title && new_item->title ) {
+ gchar *old = conv_unmime_header(old_item->title, CS_UTF_8, FALSE);
+ gchar *new = conv_unmime_header(new_item->title, CS_UTF_8, FALSE);
+ if( strcmp(old, new) != 0 ) { /* ... compare "unmimed" titles */
+ debug_print("RSSyl:\t\titem titles differ:\nOLD: '%s'\nNEW: '%s'\n",
+ old, new);
+ g_free(old);
+ g_free(new);
+ return ITEM_CHANGED;
+ }
+ g_free(old);
+ g_free(new);
+ } else {
+ /* if atleast one has a title, they differ */
+ if( old_item->title || new_item->title ) {
+ debug_print("RSSyl:\t\t+/- title\n");
+ return ITEM_CHANGED;
+ }
+ }
+
+ if( old_item->author && new_item->author ) {
+ gchar *old = conv_unmime_header(old_item->author, CS_UTF_8, TRUE);
+ gchar *new = conv_unmime_header(new_item->author, CS_UTF_8, TRUE);
+ if( strcmp(old, new) ) { /* ... compare "unmimed" authors */
+ g_free(old);
+ g_free(new);
+ debug_print("RSSyl:\t\titem authors differ\n");
+ return ITEM_CHANGED;
+ }
+ g_free(old);
+ g_free(new);
+ } else {
+ /* if atleast one has author, they differ */
+ if( old_item->author || new_item->author ) {
+ debug_print("RSSyl:\t\t+/- author\n");
+ return ITEM_CHANGED;
+ }
+ }
+
+ /* if both have text ... */
+ if( old_item->text && new_item->text ) {
+ if( strcmp(old_item->text, new_item->text) ) { /* ... compare them */
+ debug_print("RSSyl:\t\titem texts differ\n");
+ debug_print("\nOLD: '%s'\n", old_item->text);
+ debug_print("\nNEW: '%s'\n", new_item->text);
+
+ return ITEM_CHANGED_TEXTONLY;
+ }
+ } else {
+ /* if at least one has some text, they differ */
+ if( old_item->text || new_item->text ) {
+ debug_print("RSSyl:\t\t+/- text\n");
+ return ITEM_CHANGED_TEXTONLY;
+ }
+ }
+
+ /* they don't seem to differ */
+ return ITEM_UNCHANGED;
+}
+
+enum {
+ EXISTS_NEW,
+ EXISTS_UNCHANGED,
+ EXISTS_CHANGED,
+ EXISTS_CHANGED_TEXTONLY
+};
+
+/* rssyl_feed_item_exists()
+ *
+ * Returns 1 if a feed item already exists locally, 2 if there's a changed
+ * item with link that already belongs to existing item, 3 if only item's
+ * text has changed, 0 if item is new.
+ */
+
+static guint rssyl_feed_item_exists(RFolderItem *ritem, FeedItem *fitem,
+ FeedItem **oldfitem)
+{
+ GSList *item = NULL;
+ FeedItem *efitem = NULL;
+ gint changed;
+
+ g_return_val_if_fail(ritem != NULL, FALSE);
+ g_return_val_if_fail(fitem != NULL, FALSE);
+
+ if( ritem->items == NULL || g_slist_length(ritem->items) == 0 )
+ return EXISTS_NEW;
+
+ if( (item = g_slist_find_custom(ritem->items,
+ (gconstpointer)fitem, (GCompareFunc)rssyl_cb_feed_compare)) ) {
+ efitem = (FeedItem *)item->data;
+ if( (changed = rssyl_feed_item_changed(fitem, efitem)) > ITEM_UNCHANGED ) {
+ *oldfitem = efitem;
+ if (changed == ITEM_CHANGED_TEXTONLY)
+ return EXISTS_CHANGED_TEXTONLY;
+ else
+ return EXISTS_CHANGED;
+ }
+
+ return EXISTS_UNCHANGED;
+ }
+
+ return EXISTS_NEW;
+}
+
+/* =============================================================== */
+
+void rssyl_add_item(RFolderItem *ritem, FeedItem *feed_item)
+{
+ FeedItem *old_item = NULL;
+ MsgFlags *flags;
+ MsgPermFlags oldperm_flags = 0;
+ MsgInfo *msginfo;
+ FILE *f;
+ gint fd, d, dif;
+ time_t tmpd;
+ gchar *meta_charset = NULL;
+ gchar *baseurl = NULL;
+ gchar *template = NULL;
+ gchar *tmp = NULL, *tmpurl = NULL, *tmpid = NULL;
+ gchar *dirname = NULL;
+ gchar *text = NULL;
+ gchar *heading = NULL;
+ gchar hdr[1024];
+ FeedItemEnclosure *enc = NULL;
+ RFeedCtx *ctx;
+
+ g_return_if_fail(ritem != NULL);
+
+ /* If item title is empty, try to fill it from source title (Atom only). */
+ debug_print(",%s,\n", (feed_item->title ? feed_item->title : "<null>"));
+ debug_print(",%s,\n", (feed_item->sourcetitle ? feed_item->sourcetitle : "<null>"));
+ tmp = feed_item_get_sourcetitle(feed_item);
+ if( feed_item_get_title(feed_item) == NULL ||
+ strlen(feed_item->title) == 0 ) {
+ if( tmp != NULL && strlen(tmp) > 0 )
+ feed_item_set_title(feed_item, tmp);
+ else
+ feed_item_set_title(feed_item, C_("Empty RSS feed title placeholder", "(empty)"));
+ }
+
+ debug_print(",%s,\n", (feed_item->title ? feed_item->title : "<null>"));
+ debug_print(",%s,\n", (feed_item->sourcetitle ? feed_item->sourcetitle : "<null>"));
+ if (feed_item_get_id(feed_item) == NULL) {
+ debug_print("RSSyl: item ID empty, using its URL as ID.\n");
+ feed_item_set_id(feed_item, feed_item_get_url(feed_item));
+ }
+
+ /* If neither item date is set, use date from source (Atom only). */
+ if( feed_item_get_date_modified(feed_item) == -1 &&
+ feed_item_get_date_published(feed_item) == -1 )
+ feed_item_set_date_published(feed_item,
+ feed_item_get_sourcedate(feed_item));
+
+ /* Fix up subject, url and ID (rssyl_format_string()) so that
+ * comparing doesn't break. */
+ debug_print("RSSyl: fixing up subject '%s'\n", feed_item_get_title(feed_item));
+ feed_item_set_title(feed_item, rssyl_format_string(feed_item_get_title(feed_item), TRUE, TRUE));
+ debug_print("RSSyl: fixing up URL\n");
+ feed_item_set_url(feed_item, rssyl_format_string(feed_item_get_url(feed_item),
+ TRUE, TRUE));
+ if( feed_item_get_id(feed_item) != NULL ) {
+ debug_print("RSSyl: fixing up ID\n");
+ feed_item_set_id(feed_item, rssyl_format_string(feed_item_get_id(feed_item),
+ TRUE, TRUE));
+ }
+
+ /* If there's a summary, but no text, use summary as text. */
+ if( feed_item_get_text(feed_item) == NULL &&
+ (tmp = feed_item_get_summary(feed_item)) != NULL ) {
+ feed_item_set_text(feed_item, tmp);
+ g_free(feed_item->summary); /* We do not need summary in rssyl now. */
+ feed_item->summary = NULL;
+ }
+
+ /* Do not add if the item already exists, update if it does exist, but
+ * has changed. */
+ dif = rssyl_feed_item_exists(ritem, feed_item, &old_item);
+ debug_print("RSSyl: rssyl_feed_item_exists returned %d\n", dif);
+
+ if( dif == EXISTS_UNCHANGED ) {
+ debug_print("RSSyl: This item already exists, skipping...\n");
+ return;
+ }
+
+ /* Item is already in the list, but has changed */
+ if( dif >= EXISTS_CHANGED && old_item != NULL ) {
+ debug_print("RSSyl: Item changed, removing old one and adding new.\n");
+
+ /* Store permflags of the old item. */
+ ctx = (RFeedCtx *)old_item->data;
+ msginfo = folder_item_get_msginfo((FolderItem *)ritem,
+ atoi(g_path_get_basename(ctx->path)));
+ oldperm_flags = msginfo->flags.perm_flags;
+
+ ritem->items = g_slist_remove(ritem->items, old_item);
+ g_remove(ctx->path);
+
+ g_free(ctx->path);
+ feed_item_free(old_item);
+ old_item = NULL;
+ }
+
+ /* Check against list of deleted items. */
+ if (rssyl_deleted_check(ritem->deleted_items, feed_item)) {
+ debug_print("RSSyl: Item '%s' found among deleted items, NOT adding it.\n",
+ feed_item_get_title(feed_item));
+ return;
+ }
+
+ /* Add a new item, formatting its title along the way */
+ debug_print("RSSyl: Adding item '%s'\n", feed_item_get_title(feed_item));
+ ritem->items = g_slist_prepend(ritem->items, feed_item_copy(feed_item));
+
+ dirname = folder_item_get_path(&ritem->item);
+ template = g_strconcat(dirname, G_DIR_SEPARATOR_S,
+ RSSYL_TMP_TEMPLATE, NULL);
+ fd = mkstemp(template);
+
+ f = fdopen(fd, "w");
+ if(f == NULL) {
+ g_warning("Couldn't open file '%s', not adding msg!\n", template);
+ g_free(template);
+ return;
+ }
+
+ /* From */
+ if( (tmp = feed_item_get_author(feed_item)) != NULL ) {
+ if( g_utf8_validate(tmp, -1, NULL)) {
+ conv_encode_header_full(hdr, 1023, tmp, strlen("From: "),
+ TRUE, CS_UTF_8);
+ fprintf(f, "From: %s\n", hdr);
+ } else
+ fprintf(f, "From: %s\n", tmp);
+ }
+
+ /* Date */
+ if( (tmpd = feed_item_get_date_modified(feed_item)) != -1 ) {
+ tmp = createRFC822Date(&tmpd);
+ debug_print("RSSyl: using date_modified: '%s'\n", tmp);
+ } else if( (tmpd = feed_item_get_date_published(feed_item)) != -1 ) {
+ tmp = createRFC822Date(&tmpd);
+ debug_print("RSSyl: using date_published: '%s'\n", tmp);
+ } else {
+ tmpd = time(NULL);
+ tmp = createRFC822Date(&tmpd);
+ }
+
+ if( tmp != NULL ) {
+ fprintf(f, "Date: %s\n", tmp);
+ g_free(tmp);
+ }
+
+ if( (tmp = feed_item_get_title(feed_item)) != NULL ) {
+
+ /* (Atom only) Strip HTML markup from title for the Subject line. */
+ if( feed_item_get_title_format(feed_item) == FEED_ITEM_TITLE_HTML
+ || feed_item_get_title_format(feed_item) == FEED_ITEM_TITLE_XHTML) {
+ debug_print("RSSyl: item title is HTML/XHTML, stripping tags for Subject line\n");
+ tmp = g_strdup(tmp);
+ strip_html(tmp);
+ }
+
+ if( g_utf8_validate(tmp, -1, NULL) ) {
+ conv_encode_header_full(hdr, 1023, tmp, strlen("Subject: "),
+ FALSE, CS_UTF_8);
+ debug_print("RSSyl: Subject: %s\n", hdr);
+ fprintf(f, "Subject: %s\n", hdr);
+ } else
+ fprintf(f, "Subject: %s\n", tmp);
+
+ if( feed_item_get_title_format(feed_item) == FEED_ITEM_TITLE_HTML
+ || feed_item_get_title_format(feed_item) == FEED_ITEM_TITLE_XHTML) {
+ g_free(tmp);
+ fprintf(f, "X-RSSyl-OrigTitle: %s\n", feed_item_get_title(feed_item));
+ }
+ } else {
+ debug_print("RSSyl: No feed title, it seems\n");
+ fprintf(f, "Subject: (empty)\n");
+ }
+
+ /* X-RSSyl-URL */
+ if( (tmpurl = feed_item_get_url(feed_item)) == NULL ) {
+ if( feed_item_get_id(feed_item) != NULL &&
+ feed_item_id_is_permalink(feed_item) ) {
+ tmpurl = feed_item_get_id(feed_item);
+ }
+ }
+
+ if( tmpurl != NULL )
+ fprintf(f, "X-RSSyl-URL: %s\n", tmpurl);
+
+ if( ritem->last_update > 0) {
+ fprintf(f, "X-RSSyl-Last-Seen: %ld\n", ritem->last_update);
+ }
+
+ /* Message-ID */
+ if( (tmpid = feed_item_get_id(feed_item)) == NULL )
+ tmpid = feed_item_get_url(feed_item);
+ if( tmpid != NULL )
+ fprintf(f, "Message-ID: <%s>\n", tmpid);
+
+ /* X-RSSyl-Comments */
+ if( (text = feed_item_get_comments_url(feed_item)) != NULL )
+ fprintf(f, "X-RSSyl-Comments: %s\n", text);
+
+ /* References */
+ if( (text = feed_item_get_parent_id(feed_item)) != NULL )
+ fprintf(f, "References: <%s>\n", text);
+
+ /* Content-Type */
+ text = feed_item_get_text(feed_item);
+ if( text && g_utf8_validate(text, -1, NULL) ) {
+ fprintf(f, "Content-Type: text/html; charset=UTF-8\n\n");
+ meta_charset = g_strdup("<meta http-equiv=\"Content-Type\" "
+ "content=\"text/html; charset=UTF-8\">");
+ } else {
+ fprintf(f, "Content-Type: text/html\n\n");
+ }
+
+ /* construct base href */
+ if( feed_item_get_url(feed_item) != NULL )
+ baseurl = g_strdup_printf("<base href=\"%s\">\n",
+ feed_item_get_url(feed_item) );
+
+ if( ritem->write_heading )
+ heading = g_strdup_printf("<h2>%s</h2>\n<br><br>\n",
+ feed_item_get_title(feed_item));
+
+ /* Message body */
+ fprintf(f, "<html><head>"
+ "%s\n"
+ "%s"
+ "</head>\n<body>\n"
+ "%s\n"
+ "URL: <a href=\"%s\">%s</a>\n\n<br><br>\n"
+ RSSYL_TEXT_START"\n"
+ "%s%s"
+ RSSYL_TEXT_END"\n\n",
+ (meta_charset ? meta_charset : ""),
+ (baseurl ? baseurl : ""),
+ (heading ? heading : ""),
+ (tmpurl ? tmpurl : ""),
+ (tmpurl ? tmpurl : "n/a"),
+ (text ? text : ""), (text ? "\n" : "") );
+
+ g_free(meta_charset);
+ g_free(baseurl);
+ g_free(heading);
+
+ if( (enc = feed_item_get_enclosure(feed_item)) != NULL )
+ fprintf(f, "<p><a href=\"%s\">Attached media file</a> [%s] (%ld bytes)</p>\n",
+ feed_item_enclosure_get_url(enc),
+ feed_item_enclosure_get_type(enc),
+ feed_item_enclosure_get_size(enc) );
+
+ fprintf(f, "</body></html>\n");
+ fclose(f);
+
+ g_return_if_fail(template != NULL);
+
+ flags = g_new(MsgFlags, 1);
+ flags->perm_flags = MSG_NEW | MSG_UNREAD;
+ flags->tmp_flags = 0;
+
+ d = folder_item_add_msg(&ritem->item, template, flags, TRUE);
+ g_free(template);
+
+ ctx = g_new0(RFeedCtx, 1);
+ ctx->path = (gpointer)g_strdup_printf("%s%c%d", dirname,
+ G_DIR_SEPARATOR, d);
+ ctx->last_seen = ritem->last_update;
+ ((FeedItem *)ritem->items->data)->data = (gpointer)ctx;
+
+ /* Unset unread+new if the changed item wasn't set unread and user
+ * doesn't want to see it unread because of the change. */
+ if (!(oldperm_flags & MSG_UNREAD) && (ritem->silent_update == 2
+ || (ritem->silent_update == 1 && dif == EXISTS_CHANGED_TEXTONLY)))
+ procmsg_msginfo_unset_flags(
+ folder_item_get_msginfo((FolderItem *)ritem, d), MSG_NEW | MSG_UNREAD, 0);
+
+ debug_print("RSSyl: folder_item_add_msg(): %d\n", d);
+}
diff --git a/src/plugins/rssyl/rssyl_add_item.h b/src/plugins/rssyl/rssyl_add_item.h
new file mode 100644
index 0000000..5e5e4e3
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_add_item.h
@@ -0,0 +1,6 @@
+#ifndef __RSSYL_ADD_ITEM_H
+#define __RSSYL_ADD_ITEM_H
+
+void rssyl_add_item(RFolderItem *ritem, FeedItem *feed_item);
+
+#endif /* __RSSYL_ADD_ITEM_H */
diff --git a/src/plugins/rssyl/rssyl_cb_gtk.c b/src/plugins/rssyl/rssyl_cb_gtk.c
deleted file mode 100644
index 0e49bb9..0000000
--- a/src/plugins/rssyl/rssyl_cb_gtk.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2004 Hiroyuki Yamamoto
- * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
- *
- * - callback handler functions for GTK signals and timeouts
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <gtk/gtk.h>
-#include <gdk/gdkkeysyms.h>
-
-#include "folderview.h"
-#include "alertpanel.h"
-#include "gtk/inputdialog.h"
-
-#include "date.h"
-#include "feed.h"
-#include "rssyl.h"
-#include "rssyl_gtk.h"
-#include "rssyl_cb_gtk.h"
-#include "prefs_common.h"
-
-gboolean rssyl_props_cancel_cb(GtkWidget *widget, gpointer data)
-{
- RSSylFolderItem *ritem = (RSSylFolderItem *)data;
-
- debug_print("RSSyl: Cancel pressed\n");
- gtk_widget_destroy(ritem->feedprop->window);
- return FALSE;
-}
-
-gboolean rssyl_props_ok_cb(GtkWidget *widget, gpointer data)
-{
- RSSylFolderItem *ritem = (RSSylFolderItem *)data;
-
- debug_print("RSSyl: OK pressed\n");
- rssyl_gtk_prop_store(ritem);
-
- gtk_widget_destroy(ritem->feedprop->window);
-
- return FALSE;
-}
-
-gboolean rssyl_refresh_timeout_cb(gpointer data)
-{
- RSSylRefreshCtx *ctx = (RSSylRefreshCtx *)data;
- time_t tt = time(NULL);
- gchar *tmpdate;
-
- g_return_val_if_fail(ctx != NULL, FALSE);
-
- if( prefs_common_get_prefs()->work_offline)
- return TRUE;
-
- if( ctx->ritem == NULL || ctx->ritem->url == NULL ) {
- debug_print("RSSyl: refresh_timeout_cb - ritem or url NULL\n");
- g_free(ctx);
- return FALSE;
- }
-
- if( ctx->id != ctx->ritem->refresh_id ) {
- tmpdate = createRFC822Date(&tt);
- debug_print(" %s: timeout id changed, stopping: %d != %d\n",
- tmpdate, ctx->id, ctx->ritem->refresh_id);
- g_free(tmpdate);
- g_free(ctx);
- return FALSE;
- }
-
- tmpdate = createRFC822Date(&tt);
- debug_print(" %s: refresh %s (%d)\n", tmpdate, ctx->ritem->url,
- ctx->ritem->refresh_id);
- g_free(tmpdate);
- rssyl_update_feed(ctx->ritem);
-
- return TRUE;
-}
-
-gboolean rssyl_default_refresh_interval_toggled_cb(GtkToggleButton *default_ri,
- gpointer data)
-{
- gboolean active = gtk_toggle_button_get_active(default_ri);
- GtkWidget *refresh_interval = (GtkWidget *)data;
-
- debug_print("default is %s\n", ( active ? "ON" : "OFF" ) );
-
- gtk_widget_set_sensitive(refresh_interval, !active);
-
- return FALSE;
-}
-
-gboolean rssyl_default_expired_num_toggled_cb(GtkToggleButton *default_ex,
- gpointer data)
-{
- gboolean active = gtk_toggle_button_get_active(default_ex);
- GtkWidget *expired_num = (GtkWidget *)data;
-
- debug_print("default is %s\n", ( active ? "ON" : "OFF" ) );
-
- gtk_widget_set_sensitive(expired_num, !active);
-
- return FALSE;
-}
-
-gboolean rssyl_fetch_comments_toggled_cb(GtkToggleButton *fetch_comments,
- gpointer data)
-{
- gboolean active = gtk_toggle_button_get_active(fetch_comments);
- GtkWidget *num_comments = (GtkWidget *)data;
-
- debug_print("fetch comments is %s\n", (active ? "ON" : "OFF") );
-
- gtk_widget_set_sensitive(num_comments, active);
-
- return FALSE;
-}
-
-gboolean rssyl_props_key_press_cb(GtkWidget *widget, GdkEventKey *event,
- gpointer data)
-{
- if (event) {
- switch (event->keyval) {
- case GDK_Escape:
- rssyl_props_cancel_cb(widget, data);
- return TRUE;
- case GDK_Return:
- case GDK_KP_Enter:
- rssyl_props_ok_cb(widget, data);
- return TRUE;
- default:
- break;
- }
- }
-
- return FALSE;
-}
diff --git a/src/plugins/rssyl/rssyl_cb_gtk.h b/src/plugins/rssyl/rssyl_cb_gtk.h
deleted file mode 100644
index a49d3a3..0000000
--- a/src/plugins/rssyl/rssyl_cb_gtk.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __RSSYL_GTK_CB
-#define __RSSYL_GTK_CB
-
-#include <glib.h>
-#include <gtk/gtk.h>
-
-gboolean rssyl_props_cancel_cb(GtkWidget *widget, gpointer data);
-gboolean rssyl_props_ok_cb(GtkWidget *widget, gpointer data);
-gboolean rssyl_refresh_timeout_cb(gpointer data);
-gboolean rssyl_default_refresh_interval_toggled_cb(GtkToggleButton *default_ri,
- gpointer data);
-gboolean rssyl_default_expired_num_toggled_cb(GtkToggleButton *default_ex,
- gpointer data);
-gboolean rssyl_fetch_comments_toggled_cb(GtkToggleButton *fetch_comments,
- gpointer data);
-gboolean rssyl_props_key_press_cb(GtkWidget *widget, GdkEventKey *event,
- gpointer data);
-
-#endif /* __RSSYL_GTK_CB */
diff --git a/src/plugins/rssyl/rssyl_cb_menu.c b/src/plugins/rssyl/rssyl_cb_menu.c
index f3047de..d0c2ef9 100644
--- a/src/plugins/rssyl/rssyl_cb_menu.c
+++ b/src/plugins/rssyl/rssyl_cb_menu.c
@@ -1,5 +1,5 @@
/*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 1999-2004 Hiroyuki Yamamoto
* This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
*
@@ -22,34 +22,38 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
-#include "claws-features.h"
#endif
+/* Global includes */
#include <glib.h>
#include <glib/gi18n.h>
-
#include <gtk/gtk.h>
-#include "folderview.h"
-#include "alertpanel.h"
-#include "gtk/inputdialog.h"
-#include "prefs_common.h"
-#include "filesel.h"
-#include "inc.h"
-#include "folder_item_prefs.h"
-
-#include "feed.h"
-#include "feedprops.h"
-#include "opml.h"
-#include "rssyl.h"
+/* Claws Mail includes */
+#include <folderview.h>
+#include <alertpanel.h>
+#include <gtk/inputdialog.h>
+#include <prefs_common.h>
+#include <folder_item_prefs.h>
+#include <filesel.h>
+#include <inc.h>
+
+/* Local includes */
+#include "libfeed/parser_opml.h"
#include "rssyl_gtk.h"
-
-void rssyl_new_feed_cb(GtkAction *action, gpointer data)
+#include "rssyl_feed.h"
+#include "rssyl_feed_props.h"
+#include "rssyl_update_feed.h"
+#include "rssyl_subscribe.h"
+#include "opml_import.h"
+
+void rssyl_new_feed_cb(GtkAction *action,
+ gpointer data)
{
- FolderView *folderview = (FolderView *)data;
+ FolderView *folderview = (FolderView*)data;
GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
FolderItem *item;
- gchar *new_feed;
+ gchar *url;
debug_print("RSSyl: new_feed_cb\n");
@@ -59,26 +63,26 @@ void rssyl_new_feed_cb(GtkAction *action, gpointer data)
g_return_if_fail(item != NULL);
g_return_if_fail(item->folder != NULL);
- new_feed = input_dialog(_("Subscribe feed"),
- _("Input the URL of the news feed you wish to subscribe:"),
- "");
- g_return_if_fail(new_feed != NULL);
+ url = input_dialog(_("Subscribe feed"),
+ _("Input the URL of the news feed you wish to subscribe:"),
+ "");
+ if( url == NULL ) /* User cancelled */
+ return;
- rssyl_subscribe_new_feed(item, new_feed, TRUE);
+ rssyl_subscribe(item, url, TRUE);
- g_free(new_feed);
+ g_free(url);
}
-void rssyl_new_folder_cb(GtkAction *action, gpointer data)
+void rssyl_new_folder_cb(GtkAction *action,
+ gpointer data)
{
- FolderView *folderview = (FolderView *)data;
+ FolderView *folderview = (FolderView*)data;
GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
FolderItem *item;
FolderItem *new_item;
- gchar *new_folder;
- gchar *name;
- gchar *p;
- RSSylFolderItem *ritem = NULL;
+ gchar *new_folder, *p, *tmp;
+ gint i = 1;
if (!folderview->selected) return;
@@ -90,132 +94,44 @@ void rssyl_new_folder_cb(GtkAction *action, gpointer data)
_("Input the name of new folder:"),
_("NewFolder"));
if (!new_folder) return;
- AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
p = strchr(new_folder, G_DIR_SEPARATOR);
if (p) {
- alertpanel_error(_("'%c' can't be included in folder name."),
+ alertpanel_error(_("'%c' can't be used in folder name."),
G_DIR_SEPARATOR);
+ g_free(new_folder);
return;
}
- name = trim_string(new_folder, 32);
- AUTORELEASE_STR(name, {g_free(name); return;});
-
- /* find whether the directory already exists */
- if (folder_find_child_item_by_name(item, new_folder)) {
- alertpanel_error(_("The folder '%s' already exists."), name);
- return;
+ /* Find an unused name for new folder */
+ /* TODO: Perhaps stop after X attempts? */
+ tmp = g_strdup(new_folder);
+ while (folder_find_child_item_by_name(item, tmp)) {
+ debug_print("RSSyl: Folder '%s' already exists, trying another name\n",
+ new_folder);
+ g_free(tmp);
+ tmp = g_strdup_printf("%s__%d", new_folder, ++i);
}
+ g_free(new_folder);
+ new_folder = tmp;
+
new_item = folder_create_folder(item, new_folder);
if (!new_item) {
- alertpanel_error(_("Can't create the folder '%s'."), name);
- return;
- }
-
- ritem = (RSSylFolderItem *)new_item;
- ritem->url = NULL;
-
- folder_write_list();
-}
-
-void rssyl_remove_rss_cb(GtkAction *action, gpointer data)
-{
- FolderView *folderview = (FolderView *)data;
- FolderItem *item;
- gchar *name, *message;
- AlertValue aval;
-
- debug_print("RSSyl: remove_rss_cb\n");
-
- item = folderview_get_selected_item(folderview);
- g_return_if_fail(item != NULL);
- g_return_if_fail(item->folder != NULL);
- g_return_if_fail( !folder_item_parent(item) );
-
- name = trim_string(item->folder->name, 32);
- message = g_strdup_printf(_("Really remove the folder tree '%s'?\n"), name);
- aval = alertpanel_full(_("Remove folder tree"), message,
- GTK_STOCK_CANCEL, _("_Remove"), NULL, FALSE, NULL,
- ALERT_WARNING, G_ALERTDEFAULT);
- g_free(message);
- g_free(name);
-
- if (aval != G_ALERTALTERNATE)
- return;
-
- folderview_unselect(folderview);
- summary_clear_all(folderview->summaryview);
-
- folder_destroy(item->folder);
-}
-
-void rssyl_remove_feed_cb(GtkAction *action, gpointer data)
-{
- FolderView *folderview = (FolderView *)data;
- GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
- FolderItem *item;
- gint response;
- GtkWidget *dialog, *rmcache_widget = NULL;
- gboolean rmcache = FALSE;
- debug_print("RSSyl: remove_feed_cb\n");
-
- item = folderview_get_selected_item(folderview);
- g_return_if_fail(item != NULL);
- g_return_if_fail(item->path != NULL);
- g_return_if_fail(item->folder != NULL);
-
- dialog = rssyl_feed_removal_dialog(item->name, &rmcache_widget);
-
- g_return_if_fail(dialog != NULL);
-
- gtk_widget_show_all(dialog);
-
- response = gtk_dialog_run(GTK_DIALOG(dialog));
-
- if( response != GTK_RESPONSE_YES ) {
- debug_print("'No' clicked, returning\n");
- gtk_widget_destroy(dialog);
+ alertpanel_error(_("Can't create the folder '%s'."), new_folder);
+ g_free(new_folder);
return;
}
- g_return_if_fail(rmcache_widget != NULL);
-
- rmcache = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(rmcache_widget) );
-
- gtk_widget_destroy(dialog);
-
- if( folderview->opened == folderview->selected ||
- gtk_cmctree_is_ancestor(ctree,
- folderview->selected,
- folderview->opened) ) {
- summary_clear_all(folderview->summaryview);
- folderview->opened = NULL;
- }
-
- rssyl_remove_feed_props((RSSylFolderItem *)item);
-
- if( rmcache == TRUE )
- rssyl_remove_feed_cache(item);
-
- if( item->folder->klass->remove_folder(item->folder, item) < 0 ) {
- gchar *tmp;
- tmp = g_markup_printf_escaped(_("Can't remove feed '%s'."), item->name);
- alertpanel_error("%s", tmp);
- g_free(tmp);
- if( folderview->opened == folderview->selected )
- summary_show(folderview->summaryview,
- folderview->summaryview->folder_item);
- return;
- }
+ g_free(new_folder);
folder_write_list();
}
-void rssyl_remove_folder_cb(GtkAction *action, gpointer data)
+void rssyl_remove_folder_cb(GtkAction *action,
+ gpointer data)
{
- FolderView *folderview = (FolderView *)data;
+ FolderView *folderview = (FolderView*)data;
GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
FolderItem *item;
gchar *message, *name;
@@ -263,45 +179,82 @@ void rssyl_remove_folder_cb(GtkAction *action, gpointer data)
}
-void rssyl_refresh_cb(GtkAction *action, gpointer data)
+void rssyl_rename_cb(GtkAction *action,
+ gpointer *data)
{
- FolderView *folderview = (FolderView *)data;
FolderItem *item;
- RSSylFolderItem *ritem;
-
+ gchar *new_folder;
+ gchar *name;
+ gchar *message;
+ FolderView *folderview = (FolderView*)data;
item = folderview_get_selected_item(folderview);
g_return_if_fail(item != NULL);
+ g_return_if_fail(item->path != NULL);
g_return_if_fail(item->folder != NULL);
- ritem = (RSSylFolderItem *)item;
+ name = trim_string(item->name, 32);
+ message = g_strdup_printf(_("Input new name for '%s':"), name);
+ new_folder = input_dialog(_("Rename folder"), message, name);
+ g_free(message);
+ g_free(name);
+ if (!new_folder) return;
+ AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
+
+ if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
+ alertpanel_error(_("'%c' can't be included in folder name."),
+ G_DIR_SEPARATOR);
+ return;
+ }
- if (prefs_common_get_prefs()->work_offline &&
- !inc_offline_should_override(TRUE,
- ngettext(
- "Claws Mail needs network access in order "
- "to update the feed.",
- "Claws Mail needs network access in order "
- "to update the feeds.", 1))) {
- return;
+ if (folder_find_child_item_by_name(folder_item_parent(item), new_folder)) {
+ name = trim_string(new_folder, 32);
+ alertpanel_error(_("The folder '%s' already exists."), name);
+ g_free(name);
+ return;
}
- main_window_cursor_wait(mainwindow_get_mainwindow());
- rssyl_update_feed(ritem);
- main_window_cursor_normal(mainwindow_get_mainwindow());
+ if (folder_item_rename(item, new_folder) < 0) {
+ alertpanel_error(_("The folder could not be renamed.\n"
+ "The new folder name is not allowed."));
+ return;
+ }
+
+ folder_item_prefs_save_config(item);
+ folder_write_list();
}
-void rssyl_refresh_all_cb(GtkAction *action, gpointer data)
+void rssyl_refresh_feed_cb(GtkAction *action,
+ gpointer data)
{
- main_window_cursor_wait(mainwindow_get_mainwindow());
- rssyl_refresh_all_feeds();
- main_window_cursor_normal(mainwindow_get_mainwindow());
+ FolderView *folderview = (FolderView*)data;
+ FolderItem *item = NULL;
+ RFolderItem *ritem = NULL;
+
+ item = folderview_get_selected_item(folderview);
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(item->folder != NULL);
+
+ ritem = (RFolderItem *)item;
+
+ /* Offline check */
+ if( prefs_common.work_offline &&
+ !inc_offline_should_override(TRUE,
+ ngettext("Claws-Mail needs network access in order "
+ "to update the feed.",
+ "Claws-Mail needs network access in order "
+ "to update feeds.", 1))) {
+ return;
+ }
+
+ /* Update feed, displaying errors if any. */
+ rssyl_update_feed(ritem, TRUE);
}
void rssyl_prop_cb(GtkAction *action, gpointer data)
{
- FolderView *folderview = (FolderView *)data;
+ FolderView *folderview = (FolderView*)data;
FolderItem *item;
- RSSylFolderItem *ritem;
+ RFolderItem *ritem;
item = folderview_get_selected_item(folderview);
g_return_if_fail(item != NULL);
@@ -309,74 +262,103 @@ void rssyl_prop_cb(GtkAction *action, gpointer data)
debug_print("RSSyl: rssyl_prop_cb() for '%s'\n", item->name);
- ritem = (RSSylFolderItem *)item;
- rssyl_get_feed_props(ritem);
+ ritem = (RFolderItem *)item;
+
rssyl_gtk_prop(ritem);
}
-void rssyl_rename_cb(GtkAction *action, gpointer data)
+void rssyl_update_all_cb( GtkAction *action, gpointer data)
{
- FolderView *folderview = (FolderView *)data;
FolderItem *item;
- gchar *new_folder;
- gchar *name;
- gchar *message;
+ FolderView *folderview = (FolderView*)data;
item = folderview_get_selected_item(folderview);
g_return_if_fail(item != NULL);
- g_return_if_fail(item->path != NULL);
g_return_if_fail(item->folder != NULL);
- name = trim_string(item->name, 32);
- message = g_strdup_printf(_("Input new name for '%s':"), name);
- new_folder = input_dialog(_("Rename folder"), message, item->name);
- g_free(message);
- g_free(name);
- if (!new_folder) return;
- AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
+ debug_print("RSSyl: rssyl_update_all_cb(): clicked on '%s'\n", item->name);
- if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
- alertpanel_error(_("'%c' can't be included in folder name."),
- G_DIR_SEPARATOR);
+ if( item->folder->klass != rssyl_folder_get_class() ) {
+ debug_print("RSSyl: this is not a RSSyl folder, returning\n");
return;
}
- if (folder_find_child_item_by_name(folder_item_parent(item), new_folder)) {
- name = trim_string(new_folder, 32);
- alertpanel_error(_("The folder '%s' already exists."), name);
- g_free(name);
+ rssyl_update_recursively(item);
+}
+
+void rssyl_remove_mailbox_cb(GtkAction *action, gpointer data)
+{
+ FolderView *folderview = (FolderView *)data;
+ FolderItem *item = NULL;
+ gchar *n, *message;
+ AlertValue avalue;
+
+ item = folderview_get_selected_item(folderview);
+
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(item->folder != NULL);
+
+ if( folder_item_parent(item) )
return;
- }
- if (folder_item_rename(item, new_folder) < 0) {
- alertpanel_error(_("The folder could not be renamed.\n"
- "The new folder name is not allowed."));
+ n = trim_string(item->folder->name, 32);
+ message = g_strdup_printf(_("Really remove the feed tree `%s' ?\n"), n);
+ avalue = alertpanel_full(_("Remove feed tree"), message,
+ GTK_STOCK_CANCEL, _("_Remove"), NULL, FALSE,
+ NULL, ALERT_WARNING, G_ALERTDEFAULT);
+ g_free(message);
+ g_free(n);
+
+ if( avalue != G_ALERTALTERNATE )
+ return;
+
+ folderview_unselect(folderview);
+ summary_clear_all(folderview->summaryview);
+
+ n = folder_item_get_path(item);
+ if( remove_dir_recursive(n) < 0 ) {
+ g_warning("can't remove directory '%s'\n", n);
+ g_free(n);
return;
}
- folder_item_prefs_save_config_recursive(item);
- folder_write_list();
+ g_free(n);
+ folder_destroy(item->folder);
}
void rssyl_import_feed_list_cb(GtkAction *action, gpointer data)
{
FolderView *folderview = (FolderView *)data;
- debug_print("RSSyl: rssyl_import_feed_cb\n");
+ GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
+ FolderItem *item = NULL;
+ gchar *path = NULL;
+ OPMLImportCtx *ctx = NULL;
- FolderItem *item;
- gchar *opmlfile = NULL;
+ debug_print("RSSyl: import_feed_list_cb\n");
- item = folderview_get_selected_item(folderview);
+ /* Ask user for a file to import */
+ path = filesel_select_file_open_with_filter(
+ _("Select an OPML file"), NULL, "*.opml");
+ if (!is_file_exist(path)) {
+ g_free(path);
+ return;
+ }
+
+ /* Find the destination folder for the import */
+ g_return_if_fail(folderview->selected != NULL);
+ item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
g_return_if_fail(item != NULL);
g_return_if_fail(item->folder != NULL);
- opmlfile = filesel_select_file_open_with_filter(
- _("Select a .opml file"), NULL, "*.opml");
-
- if (!is_file_exist(opmlfile)) {
- g_free(opmlfile);
- return;
- }
+ ctx = malloc( sizeof(OPMLImportCtx) );
+ ctx->failures = 0;
+ ctx->depth = rssyl_folder_depth(item);
+ ctx->current = NULL;
+ ctx->current = g_slist_append(ctx->current, item);
+
+ /* Start the whole shebang - call libfeed's OPML parser with correct
+ * user function */
+ opml_process(path, rssyl_opml_import_func, (gpointer)ctx);
- rssyl_opml_import(opmlfile, item);
+ g_free(ctx);
}
diff --git a/src/plugins/rssyl/rssyl_cb_menu.h b/src/plugins/rssyl/rssyl_cb_menu.h
index 098f43c..258f9a5 100644
--- a/src/plugins/rssyl/rssyl_cb_menu.h
+++ b/src/plugins/rssyl/rssyl_cb_menu.h
@@ -7,14 +7,13 @@
#include "folderview.h"
void rssyl_new_feed_cb(GtkAction *action, gpointer data);
-void rssyl_remove_feed_cb(GtkAction *action, gpointer data);
-void rssyl_remove_rss_cb(GtkAction *action, gpointer data);
-void rssyl_refresh_cb(GtkAction *action, gpointer data);
-void rssyl_prop_cb(GtkAction *action, gpointer data);
-void rssyl_import_feed_list_cb(GtkAction *action, gpointer data);
-void rssyl_refresh_all_cb(GtkAction *action, gpointer data);
void rssyl_rename_cb(GtkAction *action, gpointer data);
void rssyl_new_folder_cb(GtkAction *action, gpointer data);
void rssyl_remove_folder_cb(GtkAction *action, gpointer data);
+void rssyl_refresh_feed_cb(GtkAction *action, gpointer data);
+void rssyl_prop_cb(GtkAction *action, gpointer data);
+void rssyl_update_all_cb(GtkAction *action, gpointer data);
+void rssyl_remove_mailbox_cb(GtkAction *action, gpointer data);
+void rssyl_import_feed_list_cb(GtkAction *action, gpointer data);
#endif /* __RSSYL_MENU_FEED */
diff --git a/src/plugins/rssyl/rssyl_deleted.c b/src/plugins/rssyl/rssyl_deleted.c
new file mode 100644
index 0000000..2d39adb
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_deleted.c
@@ -0,0 +1,354 @@
+/*
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
+ *
+ * - handling of info about user-deleted feed items
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <string.h>
+
+/* Claws Mail includes */
+#include <codeconv.h>
+#include <common/utils.h>
+
+/* Local includes */
+#include "rssyl.h"
+#include "parse822.h"
+#include "strutils.h"
+
+static RDeletedItem *_new_deleted_item()
+{
+ RDeletedItem *ditem = g_new0(RDeletedItem, 1);
+
+ ditem->id = NULL;
+ ditem->title = NULL;
+ ditem->date_published = -1;
+ ditem->date_modified = -1;
+
+ return ditem;
+}
+
+static void _free_deleted_item(gpointer d, gpointer user_data)
+{
+ RDeletedItem *ditem = (RDeletedItem *)d;
+
+ if (ditem == NULL)
+ return;
+
+ g_free(ditem->id);
+ g_free(ditem->title);
+ g_free(ditem);
+}
+
+void rssyl_deleted_free(GSList *deleted_items)
+{
+ if (deleted_items != NULL) {
+ debug_print("RSSyl: releasing list of deleted items\n");
+ g_slist_foreach(deleted_items, _free_deleted_item, NULL);
+ g_slist_free(deleted_items);
+ deleted_items = NULL;
+ }
+}
+
+static gchar * _deleted_file_path(RFolderItem *ritem)
+{
+ gchar *itempath, *deleted_file;
+
+ itempath = folder_item_get_path(&ritem->item);
+ deleted_file = g_strconcat(itempath, G_DIR_SEPARATOR_S, RSSYL_DELETED_FILE, NULL);
+ g_free(itempath);
+
+ return deleted_file;
+}
+
+/***************************************************************/
+GSList *rssyl_deleted_update(RFolderItem *ritem)
+{
+ gchar *deleted_file, *contents, **lines, **line;
+ GError *error = NULL;
+ guint i = 0;
+ RDeletedItem *ditem = NULL;
+ GSList *deleted_items = NULL;
+
+ g_return_val_if_fail(ritem != NULL, NULL);
+
+ deleted_file = _deleted_file_path(ritem);
+
+ debug_print("RSSyl: getting list of deleted items from '%s'\n", deleted_file);
+
+ if (!g_file_test(deleted_file, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+ debug_print("RSSyl: '%s' doesn't exist, ignoring\n", deleted_file);
+ return NULL;
+ }
+
+ g_file_get_contents(deleted_file, &contents, NULL, &error);
+
+ if (error)
+ g_warning("GError: '%s'\n", error->message);
+
+ if (contents != NULL) {
+ lines = strsplit_no_copy(contents, '\n');
+ } else {
+ g_warning("Couldn't read '%s', ignoring\n", deleted_file);
+ g_free(deleted_file);
+ return NULL;
+ }
+
+ g_free(deleted_file);
+
+ while (lines[i]) {
+ line = g_strsplit(lines[i], ": ", 2);
+ if (line[0] && line[1] && strlen(line[0]) && strlen(line[1])) {
+ if (!strcmp(line[0], "ID")) {
+ ditem = _new_deleted_item();
+ ditem->id = g_strdup(line[1]);
+ } else if (ditem != NULL && !strcmp(line[0], "TITLE")) {
+ ditem->title = g_strdup(line[1]);
+ } else if (ditem != NULL && !strcmp(line[0], "DPUB")) {
+ ditem->date_published = atoi(line[1]);
+ } else if (ditem != NULL && !strcmp(line[0], "DMOD")) {
+ ditem->date_modified = atoi(line[1]);
+ deleted_items = g_slist_prepend(deleted_items, ditem);
+ ditem = NULL;
+ }
+ }
+
+ g_strfreev(line);
+ i++;
+ }
+
+ g_free(lines);
+ g_free(contents);
+
+ debug_print("RSSyl: got %d deleted items\n", g_slist_length(deleted_items));
+ return deleted_items;
+}
+
+static void _store_one_deleted_item(gpointer data, gpointer user_data)
+{
+ RDeletedItem *ditem = (RDeletedItem *)data;
+ FILE *f = (FILE *)user_data;
+ gboolean err = FALSE;
+
+ if (ditem == NULL || ditem->id == NULL)
+ return;
+
+ err |= (fprintf(f,
+ "ID: %s\n"
+ "TITLE: %s\n"
+ "DPUB: %ld\n"
+ "DMOD: %ld\n",
+ ditem->id, ditem->title,
+ ditem->date_published, ditem->date_modified) < 0);
+
+ if (err)
+ debug_print("RSSyl: Error during writing deletion file.\n");
+}
+
+static void rssyl_deleted_store_internal(GSList *deleted_items, const gchar *deleted_file)
+{
+ FILE *f;
+
+ if (g_file_test(deleted_file, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
+ g_remove(deleted_file);
+
+ if (g_slist_length(deleted_items) == 0)
+ return;
+
+ if ((f = g_fopen(deleted_file, "w")) == NULL) {
+ debug_print("RSSyl: Couldn't open '%s', ignoring.\n", deleted_file);
+ return;
+ }
+
+ g_slist_foreach(deleted_items, (GFunc)_store_one_deleted_item,
+ (gpointer)f);
+
+ fclose(f);
+ debug_print("RSSyl: written and closed deletion file\n");
+}
+
+void rssyl_deleted_store(RFolderItem *ritem)
+{
+ gchar *path;
+
+ g_return_if_fail(ritem != NULL);
+
+ path = _deleted_file_path(ritem);
+ rssyl_deleted_store_internal(ritem->deleted_items, path);
+}
+
+
+/* Creates a FeedItem from a message file and uses the data to add a item
+ * to the list of deleted stuff. */
+void rssyl_deleted_add(RFolderItem *ritem, gchar *path)
+{
+ FeedItem *fitem = NULL;
+ RDeletedItem *ditem = NULL;
+ GSList *deleted_items = rssyl_deleted_update(ritem);
+ gchar *deleted_file = NULL;
+
+ if (!(fitem = rssyl_parse_folder_item_file(path)))
+ return;
+
+ ditem = _new_deleted_item();
+ ditem->id = g_strdup(feed_item_get_id(fitem));
+ ditem->title = conv_unmime_header(feed_item_get_title(fitem),
+ CS_UTF_8, FALSE);
+ ditem->date_published = feed_item_get_date_published(fitem);
+ ditem->date_modified = feed_item_get_date_modified(fitem);
+
+ deleted_items = g_slist_prepend(deleted_items, ditem);
+
+ deleted_file = _deleted_file_path(ritem);
+ rssyl_deleted_store_internal(deleted_items, deleted_file);
+ g_free(deleted_file);
+
+ rssyl_deleted_free(deleted_items);
+}
+
+static gint _rssyl_deleted_check_func(gconstpointer a, gconstpointer b)
+{
+ RDeletedItem *ditem = (RDeletedItem *)a;
+ FeedItem *fitem = (FeedItem *)b;
+
+ g_return_val_if_fail(ditem != NULL, -10);
+ g_return_val_if_fail(fitem != NULL, -20);
+
+ /* Following must match:
+ * ID, ... */
+ if (!ditem->id || !feed_item_get_id(fitem) ||
+ strcmp(ditem->id, feed_item_get_id(fitem)))
+ return -1;
+
+ /* title, ... */
+ if (!ditem->title || !feed_item_get_title(fitem) ||
+ strcmp(ditem->title, feed_item_get_title(fitem)))
+ return -2;
+
+ /* time of publishing, ... */
+ if (ditem->date_published != -1 &&
+ ditem->date_published != feed_item_get_date_published(fitem))
+ return -3;
+
+ /* and the time of last modification must be greater
+ * (this means that the item was updated since deletion, and possibly
+ * contains new data, so we add it again) */
+ if (ditem->date_modified != -1 &&
+ ditem->date_modified < feed_item_get_date_modified(fitem))
+ return -4;
+
+ return 0;
+}
+
+/* Returns TRUE if fitem is found among the deleted stuff. */
+gboolean rssyl_deleted_check(GSList *deleted_items, FeedItem *fitem)
+{
+ if (g_slist_find_custom(deleted_items, (gconstpointer)fitem,
+ _rssyl_deleted_check_func) != NULL)
+ return TRUE;
+
+ return FALSE;
+}
+
+/******** Expiring ********/
+struct _RDelExpireCtx {
+ RDeletedItem *ditem;
+ gboolean delete;
+};
+
+typedef struct _RDelExpireCtx RDelExpireCtx;
+
+static void _rssyl_deleted_expire_func_f(gpointer data, gpointer user_data)
+{
+ FeedItem *fitem = (FeedItem *)data;
+ RDelExpireCtx *ctx = (RDelExpireCtx *)user_data;
+
+ /* Following must match:
+ * ID, ... */
+ if (!ctx->ditem->id || !feed_item_get_id(fitem) ||
+ strcmp(ctx->ditem->id, feed_item_get_id(fitem)))
+ return;
+
+ /* title, ... */
+ if (!ctx->ditem->title || !feed_item_get_title(fitem) ||
+ strcmp(ctx->ditem->title, feed_item_get_title(fitem)))
+ return;
+
+ /* time of publishing, ... */
+ if (ctx->ditem->date_published != feed_item_get_date_published(fitem))
+ return;
+
+ /* and the time of last modification must be greater
+ * (this means that the item was updated since deletion, and possibly
+ * contains new data, so we add it again) */
+ if (ctx->ditem->date_modified != feed_item_get_date_modified(fitem))
+ return;
+
+ ctx->delete = FALSE;
+}
+
+/* Checks each item in deleted items list against feed and removes it if
+ * it is not found there anymore. */
+void rssyl_deleted_expire(RFolderItem *ritem, Feed *feed)
+{
+ GSList *d = NULL, *d2;
+ RDelExpireCtx *ctx = NULL;
+ RDeletedItem *ditem;
+
+ g_return_if_fail(ritem != NULL);
+ g_return_if_fail(feed != NULL);
+
+ ritem->deleted_items = rssyl_deleted_update(ritem);
+
+ /* Iterate over all items in the list */
+ d = ritem->deleted_items;
+ while (d) {
+ ditem = (RDeletedItem *)d->data;
+ ctx = g_new0(RDelExpireCtx, 1);
+ ctx->ditem = ditem;
+ ctx->delete = TRUE;
+
+ /* Adjust ctx->delete accordingly */
+ feed_foreach_item(feed, _rssyl_deleted_expire_func_f, (gpointer)ctx);
+
+ /* Remove the item if necessary */
+ if (ctx->delete) {
+ debug_print("RSSyl: (DELETED) removing '%s' from list\n", ditem->title);
+ d2 = d->next;
+ ritem->deleted_items = g_slist_remove_link(ritem->deleted_items, d);
+ d = d2;
+ continue;
+ } else {
+ d = d->next;
+ }
+
+ g_free(ctx);
+ }
+
+ /* Write the new list to disk */
+ rssyl_deleted_store(ritem);
+
+ /* And clean up after myself */
+ rssyl_deleted_free(ritem->deleted_items);
+}
diff --git a/src/plugins/rssyl/rssyl_deleted.h b/src/plugins/rssyl/rssyl_deleted.h
new file mode 100644
index 0000000..d3c198d
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_deleted.h
@@ -0,0 +1,14 @@
+#ifndef __RSSYL_DELETED_H
+#define __RSSYL_DELETED_H
+
+#include <glib.h>
+
+#include "rssyl.h"
+
+GSList *rssyl_deleted_update(RFolderItem *ritem);
+void *rssyl_deleted_free(GSList *deleted_items);
+void rssyl_deleted_add(RFolderItem *ritem, gchar *path);
+gboolean rssyl_deleted_check(GSList *deleted_items, FeedItem *fitem);
+void rssyl_deleted_expire(RFolderItem *ritem, Feed *feed);
+
+#endif /* __RSSYL_DELETED_H */
diff --git a/src/plugins/rssyl/rssyl_feed.c b/src/plugins/rssyl/rssyl_feed.c
new file mode 100644
index 0000000..46edc01
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_feed.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <glib/gi18n.h>
+
+/* Claws Mail includes */
+#include <folder.h>
+#include <alertpanel.h>
+#include <procheader.h>
+#include <prefs_common.h>
+#include <mainwindow.h>
+
+/* Local includes */
+#include "libfeed/feeditem.h"
+#include "libfeed/date.h"
+#include "rssyl.h"
+#include "rssyl_feed.h"
+#include "rssyl_prefs.h"
+#include "rssyl_update_feed.h"
+#include "strutils.h"
+
+FolderItem *rssyl_feed_subscribe_new(FolderItem *parent, const gchar *url,
+ gboolean verbose)
+{
+ gchar *myurl = NULL, *tmpname = NULL;
+ FolderItem *new_item = NULL;
+ RFolderItem *ritem = NULL;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail(parent != NULL, FALSE);
+ g_return_val_if_fail(url != NULL, FALSE);
+
+ log_print(LOG_PROTOCOL, RSSYL_LOG_SUBSCRIBING, url);
+
+ if( !strncmp(url, "feed://", 7) )
+ myurl = g_strdup(url+7);
+ else if( !strncmp(url, "feed:", 5) )
+ myurl = g_strdup(url+5);
+ else
+ myurl = g_strdup(url);
+
+ myurl = g_strchomp(myurl);
+
+ gtk_cmclist_freeze(GTK_CMCLIST(mainwindow_get_mainwindow()->folderview->ctree));
+ folder_item_update_freeze();
+
+ /* Create a feed folder with generic name. */
+ tmpname = g_strdup_printf("%s.%ld", RSSYL_NEW_FOLDER_NAME, (long int)time(NULL));
+ new_item = folder_create_folder(parent, tmpname);
+ g_free(tmpname);
+ if( !new_item ) {
+ if( verbose )
+ alertpanel_error(_("Couldn't create folder for new feed '%s'."),
+ myurl);
+ g_free(myurl);
+ return NULL;
+ }
+
+ /* Set it up as a RSSyl folder */
+ ritem = (RFolderItem *)new_item;
+ ritem->url = g_strdup(myurl);
+
+ /* Try to update it, delete if failed.
+ * (it is renamed in rssyl_update_feed(). */
+ if( (success = rssyl_update_feed(ritem, verbose)) == FALSE )
+ new_item->folder->klass->remove_folder(new_item->folder, new_item);
+ else {
+ folder_item_scan(new_item);
+ folder_write_list();
+ }
+
+ folder_item_update_thaw();
+ gtk_cmclist_thaw(GTK_CMCLIST(mainwindow_get_mainwindow()->folderview->ctree));
+
+ if( success )
+ log_print(LOG_PROTOCOL, RSSYL_LOG_SUBSCRIBED, ritem->official_title,
+ ritem->url);
+ else {
+ debug_print("RSSyl: Failed to add feed '%s'\n", myurl);
+ g_free(myurl);
+ return NULL;
+ }
+
+ return new_item;
+}
+
+MsgInfo *rssyl_feed_parse_item_to_msginfo(gchar *file, MsgFlags flags,
+ gboolean a, gboolean b, FolderItem *item)
+{
+ MsgInfo *msginfo;
+
+ g_return_val_if_fail(item != NULL, NULL);
+
+ msginfo = procheader_parse_file(file, flags, a, b);
+ if (msginfo)
+ msginfo->folder = item;
+
+ return msginfo;
+}
+
+gboolean rssyl_refresh_timeout_cb(gpointer data)
+{
+ RRefreshCtx *ctx = (RRefreshCtx *)data;
+ time_t tt = time(NULL);
+ gchar *tmpdate = NULL;
+
+ g_return_val_if_fail(ctx != NULL, FALSE);
+
+ if( prefs_common.work_offline)
+ return TRUE;
+
+ if( ctx->ritem == NULL || ctx->ritem->url == NULL ) {
+ debug_print("RSSyl: refresh_timeout_cb - ritem or url NULL\n");
+ g_free(ctx);
+ return FALSE;
+ }
+
+ if( ctx->id != ctx->ritem->refresh_id ) {
+ tmpdate = createRFC822Date(&tt);
+ debug_print("RSSyl: %s: timeout id changed, stopping: %d != %d\n",
+ tmpdate, ctx->id, ctx->ritem->refresh_id);
+ g_free(tmpdate);
+ g_free(ctx);
+ return FALSE;
+ }
+
+ tmpdate = createRFC822Date(&tt);
+ debug_print(" %s: refresh %s (%d)\n", tmpdate, ctx->ritem->url,
+ ctx->ritem->refresh_id);
+ g_free(tmpdate);
+ rssyl_update_feed(ctx->ritem, FALSE);
+
+ return TRUE;
+}
+
+void rssyl_feed_start_refresh_timeout(RFolderItem *ritem)
+{
+ RRefreshCtx *ctx;
+ guint source_id;
+ RPrefs *rsprefs = NULL;
+
+ g_return_if_fail(ritem != NULL);
+
+ if( ritem->default_refresh_interval ) {
+ rsprefs = rssyl_prefs_get();
+ if( !rsprefs->refresh_enabled )
+ return;
+ ritem->refresh_interval = rsprefs->refresh;
+ }
+
+ ctx = g_new0(RRefreshCtx, 1);
+ ctx->ritem = ritem;
+
+ source_id = g_timeout_add(ritem->refresh_interval * 60 * 1000,
+ (GSourceFunc)rssyl_refresh_timeout_cb, ctx );
+ ritem->refresh_id = source_id;
+ ctx->id = source_id;
+
+ debug_print("RSSyl: start_refresh_timeout - %d min (id %d)\n",
+ ritem->refresh_interval, ctx->id);
+}
diff --git a/src/plugins/rssyl/rssyl_feed.h b/src/plugins/rssyl/rssyl_feed.h
new file mode 100644
index 0000000..e34fc10
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_feed.h
@@ -0,0 +1,27 @@
+#ifndef __RSSYL_FEED_H
+#define __RSSYL_FEED_H
+
+#include <glib.h>
+
+#include <folder.h>
+
+#include "rssyl.h"
+
+#define RSSYL_LOG_SUBSCRIBING _("RSSyl: Subscribing new feed: %s\n")
+#define RSSYL_LOG_SUBSCRIBED _("RSSyl: New feed subscribed: '%s' (%s)\n")
+#define RSSYL_LOG_UPDATING _("RSSyl: Updating feed: %s\n")
+#define RSSYL_LOG_UPDATED _("RSSyl: Feed update finished: %s\n")
+#define RSSYL_LOG_ERROR_FETCH _("RSSyl: Error fetching feed at '%s': %s\n")
+#define RSSYL_LOG_ERROR_NOFEED _("RSSyl: No valid feed found at '%s'\n")
+#define RSSYL_LOG_ERROR_PROC _("RSSyl: Couldn't process feed at '%s'\n")
+#define RSSYL_LOG_ABORTED_EXITING _("RSSyl: Application is exiting, couldn't finish updating feed at '%s'\n")
+
+FolderItem *rssyl_feed_subscribe_new(FolderItem *parent, const gchar *url,
+ gboolean verbose);
+
+MsgInfo *rssyl_feed_parse_item_to_msginfo(gchar *file, MsgFlags flags,
+ gboolean a, gboolean b, FolderItem *item);
+
+void rssyl_feed_start_refresh_timeout(RFolderItem *ritem);
+
+#endif /* __RSSYL_FEED_H */
diff --git a/src/plugins/rssyl/rssyl_feed_props.c b/src/plugins/rssyl/rssyl_feed_props.c
new file mode 100644
index 0000000..f6a2d89
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_feed_props.c
@@ -0,0 +1,566 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
+ *
+ * - Plugin preferences
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+
+/* Claws Mail includes */
+#include <mainwindow.h>
+
+/* Local includes */
+#include "rssyl.h"
+#include "rssyl_feed.h"
+#include "rssyl_feed_props.h"
+#include "rssyl_prefs.h"
+#include "rssyl_update_feed.h"
+
+static void rssyl_gtk_prop_store(RFolderItem *ritem)
+{
+ gchar *url;
+ gint x, old_ri, old_fetch_comments;
+ gboolean use_default_ri = FALSE, keep_old = FALSE;
+ FolderItem *item;
+
+ g_return_if_fail(ritem != NULL);
+ g_return_if_fail(ritem->feedprop != NULL);
+
+ url = (gchar *)gtk_entry_get_text(GTK_ENTRY(ritem->feedprop->url));
+
+ if( strlen(url) ) {
+ if( ritem->url ) {
+ g_free(ritem->url);
+ }
+ ritem->url = g_strdup(url);
+ }
+
+ use_default_ri = gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(ritem->feedprop->default_refresh_interval));
+ ritem->default_refresh_interval = use_default_ri;
+ debug_print("store: default refresh interval is %s\n",
+ ( use_default_ri ? "ON" : "OFF" ) );
+
+ /* Use default if checkbutton is set */
+ if( use_default_ri )
+ x = rssyl_prefs_get()->refresh;
+ else
+ x = gtk_spin_button_get_value_as_int(
+ GTK_SPIN_BUTTON(ritem->feedprop->refresh_interval) );
+
+ old_ri = ritem->refresh_interval;
+ ritem->refresh_interval = x;
+
+ /* Set timer for next automatic refresh, if needed. */
+ if( x > 0 ) {
+ if( old_ri != x || ritem->refresh_id == 0 ) {
+ debug_print("RSSyl: GTK - refresh interval changed to %d , updating "
+ "timeout\n", ritem->refresh_interval);
+ rssyl_feed_start_refresh_timeout(ritem);
+ }
+ } else
+ ritem->refresh_id = 0;
+
+ old_fetch_comments = ritem->fetch_comments;
+ ritem->fetch_comments = gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(ritem->feedprop->fetch_comments));
+
+ if (!old_fetch_comments && ritem->fetch_comments) {
+ /* reset the RFolderItem's mtime to be sure we get all
+ * available comments */
+ ritem->item.mtime = 0;
+ }
+
+ ritem->fetch_comments_max_age = gtk_spin_button_get_value_as_int(
+ GTK_SPIN_BUTTON(ritem->feedprop->fetch_comments_max_age));
+
+ keep_old = gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(ritem->feedprop->keep_old));
+ ritem->keep_old = keep_old;
+
+ ritem->silent_update =
+ gtk_combo_box_get_active(GTK_COMBO_BOX(ritem->feedprop->silent_update));
+
+ ritem->write_heading = gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(ritem->feedprop->write_heading));
+
+ ritem->ignore_title_rename = gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(ritem->feedprop->ignore_title_rename));
+
+ ritem->ssl_verify_peer = gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(ritem->feedprop->ssl_verify_peer));
+
+ /* Store updated properties */
+ item = &ritem->item;
+ item->folder->klass->item_get_xml(item->folder, item);
+}
+
+static gboolean
+rssyl_feedprop_togglebutton_toggled_cb(GtkToggleButton *tb,
+ gpointer data)
+{
+ gboolean active = gtk_toggle_button_get_active(tb);
+ RFeedProp *feedprop = (RFeedProp *)data;
+ GtkWidget *sb = NULL;
+
+ if( (GtkWidget *)tb == feedprop->default_refresh_interval ) {
+ active = !active;
+ sb = feedprop->refresh_interval;
+ } else if( (GtkWidget *)tb == feedprop->fetch_comments ) {
+ sb = feedprop->fetch_comments_max_age;
+ }
+
+ g_return_val_if_fail(sb != NULL, FALSE);
+
+ gtk_widget_set_sensitive(sb, active);
+
+ return FALSE;
+}
+
+
+static gboolean
+rssyl_props_cancel_cb(GtkWidget *widget, gpointer data)
+{
+ RFolderItem *ritem = (RFolderItem *)data;
+
+ debug_print("RSSyl: Cancel pressed\n");
+
+ gtk_widget_destroy(ritem->feedprop->window);
+
+ return FALSE;
+}
+
+static gboolean
+rssyl_props_ok_cb(GtkWidget *widget, gpointer data)
+{
+ RFolderItem *ritem = (RFolderItem *)data;
+
+ debug_print("RSSyl: OK pressed\n");
+ rssyl_gtk_prop_store(ritem);
+
+ gtk_widget_destroy(ritem->feedprop->window);
+
+ return FALSE;
+}
+
+static gboolean
+rssyl_props_trim_cb(GtkWidget *widget, gpointer data)
+{
+ RFolderItem *ritem = (RFolderItem *)data;
+ gboolean k = ritem->keep_old;
+
+ if( k )
+ ritem->keep_old = FALSE;
+
+ rssyl_update_feed(ritem, FALSE);
+
+ if( k )
+ ritem->keep_old = TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+rssyl_props_key_press_cb(GtkWidget *widget, GdkEventKey *event,
+ gpointer data)
+{
+ if (event) {
+ switch (event->keyval) {
+ case GDK_Escape:
+ rssyl_props_cancel_cb(widget, data);
+ return TRUE;
+ case GDK_Return:
+ case GDK_KP_Enter:
+ rssyl_props_ok_cb(widget, data);
+ return TRUE;
+ default:
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+
+void rssyl_gtk_prop(RFolderItem *ritem)
+{
+ MainWindow *mainwin = mainwindow_get_mainwindow();
+ RFeedProp *feedprop;
+ GtkWidget *vbox, *urllabel, *urlframe, *urlalign, *table, *label,
+ *hsep, *sep, *bbox, *cancel_button, *cancel_align,
+ *cancel_hbox, *cancel_image, *cancel_label, *ok_button, *ok_align,
+ *ok_hbox, *ok_image, *ok_label, *trim_button, *silent_update_label;
+ GtkObject *adj;
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+ GtkTooltips *tooltips;
+#endif
+ gint refresh;
+ gint row = 0;
+
+ g_return_if_fail(ritem != NULL);
+
+ feedprop = g_new0(RFeedProp, 1);
+
+ /**** Create required widgets ****/
+
+ /* Window */
+ feedprop->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+ tooltips = gtk_tooltips_new();
+ gtk_tooltips_enable(tooltips);
+#endif
+
+ /* URL entry */
+ feedprop->url = gtk_entry_new();
+ gtk_entry_set_text(GTK_ENTRY(feedprop->url), ritem->url);
+
+ /* "Use default refresh interval" checkbutton */
+ feedprop->default_refresh_interval = gtk_check_button_new_with_mnemonic(
+ _("Use default refresh interval"));
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(feedprop->default_refresh_interval),
+ ritem->default_refresh_interval);
+
+ if( ritem->refresh_interval >= 0 && !ritem->default_refresh_interval )
+ refresh = ritem->refresh_interval;
+ else
+ refresh = rssyl_prefs_get()->refresh;
+
+ /* "Keep old items" checkbutton */
+ feedprop->keep_old = gtk_check_button_new_with_mnemonic(
+ _("Keep old items"));
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(feedprop->keep_old),
+ ritem->keep_old);
+
+ /* "Trim" button */
+ trim_button = gtk_button_new_with_mnemonic(_("_Trim"));
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+ gtk_tooltips_set_tip(tooltips, trim_button,
+ _("Update feed, deleting items which are no longer in the source feed"), NULL);
+#else
+ gtk_widget_set_tooltip_text(trim_button,
+ _("Update feed, deleting items which are no longer in the source feed"));
+#endif
+
+ feedprop->fetch_comments = gtk_check_button_new_with_mnemonic(
+ _("Fetch comments if possible"));
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(feedprop->fetch_comments),
+ ritem->fetch_comments);
+
+ /* Fetch comments max age spinbutton */
+ adj = gtk_adjustment_new(ritem->fetch_comments_max_age,
+ -1, 100000, 1, 10, 0);
+ feedprop->fetch_comments_max_age = gtk_spin_button_new(GTK_ADJUSTMENT(adj),
+ 1, 0);
+
+ /* Refresh interval spinbutton */
+ adj = gtk_adjustment_new(refresh,
+ 0, 100000, 10, 100, 0);
+ feedprop->refresh_interval = gtk_spin_button_new(GTK_ADJUSTMENT(adj),
+ 1, 0);
+
+ /* Silent update - combobox */
+ feedprop->silent_update = gtk_combo_box_new_text();
+ gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
+ _("Always mark as new"));
+ gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
+ _("If only its text changed"));
+ gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
+ _("Never mark as new"));
+ gtk_combo_box_set_active(GTK_COMBO_BOX(feedprop->silent_update),
+ ritem->silent_update);
+
+ feedprop->write_heading = gtk_check_button_new_with_mnemonic(
+ _("Add item title to top of message"));
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(feedprop->write_heading),
+ ritem->write_heading);
+
+ /* Ignore title rename - checkbox */
+ feedprop->ignore_title_rename = gtk_check_button_new_with_mnemonic(
+ _("Ignore title rename"));
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(feedprop->ignore_title_rename),
+ ritem->ignore_title_rename);
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+ gtk_tooltips_set_tip(tooltips, feedprop->ignore_title_rename,
+ _("Enable this to keep current folder name, even if feed author changes title of the feed."), NULL);
+#else
+ gtk_widget_set_tooltip_text(feedprop->ignore_title_rename,
+ _("Enable this to keep current folder name, even if feed author changes title of the feed."));
+#endif
+
+ /* Verify SSL peer certificate */
+ feedprop->ssl_verify_peer = gtk_check_button_new_with_label(
+ _("Verify SSL certificate validity"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(feedprop->ssl_verify_peer),
+ ritem->ssl_verify_peer);
+
+ /* === Now pack all the widgets */
+ vbox = gtk_vbox_new(FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(feedprop->window), vbox);
+
+ /* URL frame */
+ urlframe = gtk_frame_new(NULL);
+ gtk_container_set_border_width(GTK_CONTAINER(urlframe), 5);
+ gtk_frame_set_label_align(GTK_FRAME(urlframe), 0.05, 0.5);
+ gtk_frame_set_shadow_type(GTK_FRAME(urlframe), GTK_SHADOW_ETCHED_OUT);
+ gtk_box_pack_start(GTK_BOX(vbox), urlframe, FALSE, FALSE, 0);
+
+ /* Label for URL frame */
+ urllabel = gtk_label_new(_("<b>Source URL:</b>"));
+ gtk_label_set_use_markup(GTK_LABEL(urllabel), TRUE);
+ gtk_misc_set_padding(GTK_MISC(urllabel), 5, 0);
+ gtk_frame_set_label_widget(GTK_FRAME(urlframe), urllabel);
+
+ /* URL entry (+ alignment in frame) */
+ urlalign = gtk_alignment_new(0, 0.5, 1, 1);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(urlalign), 5, 5, 5, 5);
+ gtk_container_add(GTK_CONTAINER(urlframe), urlalign);
+
+ gtk_entry_set_activates_default(GTK_ENTRY(feedprop->url), TRUE);
+ gtk_container_add(GTK_CONTAINER(urlalign), feedprop->url);
+
+ /* Table for remaining properties */
+ table = gtk_table_new(11, 2, FALSE);
+ gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
+
+ /* Fetch comments - checkbutton */
+ gtk_table_attach(GTK_TABLE(table), feedprop->fetch_comments,
+ 0, 2, row, row+1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 10, 0);
+ g_signal_connect(G_OBJECT(feedprop->fetch_comments), "toggled",
+ G_CALLBACK(rssyl_feedprop_togglebutton_toggled_cb),
+ (gpointer)feedprop);
+
+ row++;
+ /* Fetch comments max age - label */
+ label = gtk_label_new(_("<b>Fetch comments on posts aged less than:</b>\n"
+ "<small>(In days; set to -1 to fetch all comments)</small>"));
+ gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 10, 5);
+
+ /* Fetch comments max age - spinbutton */
+ gtk_widget_set_sensitive(feedprop->fetch_comments_max_age,
+ ritem->fetch_comments);
+ gtk_table_attach(GTK_TABLE(table), feedprop->fetch_comments_max_age,
+ 1, 2, row, row+1,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 10, 5);
+
+ row++;
+ /* Separator below comments max age */
+ hsep = gtk_hseparator_new();
+ gtk_widget_set_size_request(hsep, -1, 10);
+ gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 10, 5);
+
+ row++;
+ /* Keep old items - checkbutton */
+ gtk_table_attach(GTK_TABLE(table), feedprop->keep_old,
+ 0, 1, row, row+1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 10, 0);
+
+ /* 'Trim' - button */
+ gtk_table_attach(GTK_TABLE(table), trim_button,
+ 1, 2, row, row+1,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 10, 0);
+ g_signal_connect(G_OBJECT(trim_button), "clicked",
+ G_CALLBACK(rssyl_props_trim_cb), ritem);
+
+ row++;
+ hsep = gtk_hseparator_new();
+ gtk_widget_set_size_request(hsep, -1, 10);
+ gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 10, 5);
+
+ row++;
+ /* Use default refresh interval - checkbutton */
+ gtk_table_attach(GTK_TABLE(table), feedprop->default_refresh_interval,
+ 0, 2, row, row+1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 10, 0);
+ g_signal_connect(G_OBJECT(feedprop->default_refresh_interval), "toggled",
+ G_CALLBACK(rssyl_feedprop_togglebutton_toggled_cb),
+ (gpointer)feedprop);
+
+ row++;
+ /* Refresh interval - label */
+ label = gtk_label_new(_("<b>Refresh interval in minutes:</b>\n"
+ "<small>(Set to 0 to disable automatic refreshing for this feed)"
+ "</small>"));
+ gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 10, 5);
+
+ /* Refresh interval - spinbutton */
+ gtk_widget_set_sensitive(feedprop->refresh_interval,
+ !ritem->default_refresh_interval);
+ gtk_table_attach(GTK_TABLE(table), feedprop->refresh_interval, 1, 2, row, row+1,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 10, 5);
+
+ row++;
+ hsep = gtk_hseparator_new();
+ gtk_widget_set_size_request(hsep, -1, 10);
+ gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 10, 5);
+
+ row++;
+ /* Silent update - label */
+ silent_update_label =
+ gtk_label_new(_("<b>If an item changes, do not mark it as new:</b>"));
+ gtk_label_set_use_markup(GTK_LABEL(silent_update_label), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(silent_update_label), 0, 0.5);
+ gtk_table_attach(GTK_TABLE(table), silent_update_label, 0, 1, row, row+1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 10, 5);
+
+ gtk_table_attach(GTK_TABLE(table), feedprop->silent_update, 1, 2, row, row+1,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 10, 5);
+
+ row++;
+ hsep = gtk_hseparator_new();
+ gtk_widget_set_size_request(hsep, -1, 10);
+ gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 10, 5);
+
+ row++;
+
+ /* Write heading - checkbox */
+ gtk_table_attach(GTK_TABLE(table), feedprop->write_heading,
+ 0, 2, row, row+1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 10, 0);
+
+
+ row++;
+
+ /* Ignore title rename - checkbutton */
+ gtk_table_attach(GTK_TABLE(table), feedprop->ignore_title_rename,
+ 0, 1, row, row+1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 10, 0);
+
+ row++;
+
+ /* Verify SSL peer certificate - checkbutton */
+ gtk_table_attach(GTK_TABLE(table), feedprop->ssl_verify_peer,
+ 0, 1, row, row+1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 10, 0);
+
+ row++;
+
+ /* Separator above the button box */
+ sep = gtk_hseparator_new();
+ gtk_widget_set_size_request(sep, -1, 10);
+ gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
+
+ /* Buttonbox */
+ bbox = gtk_hbutton_box_new();
+ gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing(GTK_BOX(bbox), 5);
+ gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
+
+ /* Cancel button */
+ cancel_button = gtk_button_new();
+ gtk_container_add(GTK_CONTAINER(bbox), cancel_button);
+
+ cancel_align = gtk_alignment_new(0.5, 0.5, 0, 0);
+ gtk_container_add(GTK_CONTAINER(cancel_button), cancel_align);
+
+ cancel_hbox = gtk_hbox_new(FALSE, 2);
+ gtk_container_add(GTK_CONTAINER(cancel_align), cancel_hbox);
+
+ cancel_image = gtk_image_new_from_stock(GTK_STOCK_CANCEL,
+ GTK_ICON_SIZE_BUTTON);
+ gtk_box_pack_start(GTK_BOX(cancel_hbox), cancel_image, FALSE, FALSE, 0);
+
+ cancel_label = gtk_label_new_with_mnemonic(_("_Cancel"));
+ gtk_box_pack_end(GTK_BOX(cancel_hbox), cancel_label, FALSE, FALSE, 0);
+
+ g_signal_connect(G_OBJECT(cancel_button), "clicked",
+ G_CALLBACK(rssyl_props_cancel_cb), ritem);
+
+ /* OK button */
+ ok_button = gtk_button_new();
+ gtk_container_add(GTK_CONTAINER(bbox), ok_button);
+ GTK_WIDGET_SET_FLAGS(ok_button, GTK_CAN_DEFAULT );
+
+ ok_align = gtk_alignment_new(0.5, 0.5, 0, 0);
+ gtk_container_add(GTK_CONTAINER(ok_button), ok_align);
+
+ ok_hbox = gtk_hbox_new(FALSE, 2);
+ gtk_container_add(GTK_CONTAINER(ok_align), ok_hbox);
+
+ ok_image = gtk_image_new_from_stock(GTK_STOCK_OK,
+ GTK_ICON_SIZE_BUTTON);
+ gtk_box_pack_start(GTK_BOX(ok_hbox), ok_image, FALSE, FALSE, 0);
+
+ ok_label = gtk_label_new_with_mnemonic(_("_OK"));
+ gtk_box_pack_end(GTK_BOX(ok_hbox), ok_label, FALSE, FALSE, 0);
+
+ g_signal_connect(G_OBJECT(ok_button), "clicked",
+ G_CALLBACK(rssyl_props_ok_cb), ritem);
+
+ /* Set some misc. stuff */
+ gtk_window_set_title(GTK_WINDOW(feedprop->window),
+ g_strdup(_("Set feed properties")) );
+ gtk_window_set_modal(GTK_WINDOW(feedprop->window), TRUE);
+ gtk_window_set_transient_for(GTK_WINDOW(feedprop->window),
+ GTK_WINDOW(mainwin->window) );
+
+ /* Attach callbacks to handle Enter and Escape keys */
+ g_signal_connect(G_OBJECT(feedprop->window), "key_press_event",
+ G_CALLBACK(rssyl_props_key_press_cb), ritem);
+
+ /* ...and voila! */
+ gtk_widget_show_all(feedprop->window);
+ gtk_widget_grab_default(ok_button);
+
+ /* Unselect the text in URL entry */
+ gtk_editable_select_region(GTK_EDITABLE(feedprop->url), 0, 0);
+
+ ritem->feedprop = feedprop;
+}
diff --git a/src/plugins/rssyl/rssyl_feed_props.h b/src/plugins/rssyl/rssyl_feed_props.h
new file mode 100644
index 0000000..5aa4539
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_feed_props.h
@@ -0,0 +1,24 @@
+#ifndef __RSSYL_FEED_PROPS
+#define __RSSYL_FEED_PROPS
+
+#include "rssyl.h"
+
+void rssyl_gtk_prop(RFolderItem *ritem);
+
+struct _RFeedProp {
+ GtkWidget *window;
+ GtkWidget *url;
+ GtkWidget *default_refresh_interval;
+ GtkWidget *refresh_interval;
+ GtkWidget *keep_old;
+ GtkWidget *fetch_comments;
+ GtkWidget *fetch_comments_max_age;
+ GtkWidget *silent_update;
+ GtkWidget *write_heading;
+ GtkWidget *ignore_title_rename;
+ GtkWidget *ssl_verify_peer;
+};
+
+typedef struct _RFeedProp RFeedProp;
+
+#endif /* __RSSYL_FEED_PROPS */
diff --git a/src/plugins/rssyl/rssyl_gtk.c b/src/plugins/rssyl/rssyl_gtk.c
index 24c2abe..dc6e72a 100644
--- a/src/plugins/rssyl/rssyl_gtk.c
+++ b/src/plugins/rssyl/rssyl_gtk.c
@@ -1,5 +1,5 @@
/*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 1999-2004 Hiroyuki Yamamoto
* This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
*
@@ -22,101 +22,85 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
-#include "claws-features.h"
#endif
-#include <glib.h>
-#include <glib/gi18n.h>
-
+/* Global includes */
#include <gtk/gtk.h>
+#include <glib/gi18n.h>
-#include "gtk/menu.h"
-#include "mainwindow.h"
-#include "inputdialog.h"
-#include "folderview.h"
-#include "alertpanel.h"
-#include "summaryview.h"
-
-#include "main.h"
-#include "gtkutils.h"
+/* Claws Mail includes */
+#include <gtk/menu.h>
+#include <mainwindow.h>
+#include <inputdialog.h>
+#include <folderview.h>
+#include <alertpanel.h>
+#include <main.h>
+#include <summaryview.h>
-#include "feed.h"
-#include "feedprops.h"
+/* Local includes */
#include "rssyl.h"
-#include "rssyl_cb_gtk.h"
-#include "rssyl_cb_menu.h"
-#include "rssyl_gtk.h"
#include "rssyl_prefs.h"
+#include "rssyl_gtk.h"
+#include "rssyl_cb_menu.h"
static char *rssyl_popup_menu_labels[] =
{
N_("_Refresh feed"),
- N_("Refresh _all feeds"),
+ N_("Feed pr_operties"),
+ N_("Rena_me..."),
+ N_("R_efresh recursively"),
N_("Subscribe _new feed..."),
- N_("_Unsubscribe feed..."),
- N_("Feed pr_operties..."),
+ N_("Create new _folder..."),
N_("Import feed list..."),
- N_("Rena_me..."),
- N_("_Create new folder..."),
N_("_Delete folder..."),
- N_("Remove folder _tree..."),
+ N_("Remove tree"),
NULL
};
static GtkActionEntry rssyl_popup_entries[] =
{
- {"FolderViewPopup/RefreshFeed", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_refresh_cb) },
- {"FolderViewPopup/RefreshAllFeeds", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_refresh_all_cb) },
-
- {"FolderViewPopup/NewFeed", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_new_feed_cb) },
- {"FolderViewPopup/RemoveFeed", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_remove_feed_cb) },
- {"FolderViewPopup/FeedProperties", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_prop_cb) },
- {"FolderViewPopup/ImportFeedlist", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_import_feed_list_cb) },
-
- {"FolderViewPopup/RenameFolder", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_rename_cb) },
-
- {"FolderViewPopup/NewFolder", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_new_folder_cb) },
- {"FolderViewPopup/RemoveFolder", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_remove_folder_cb) },
-
- {"FolderViewPopup/RemoveMailbox", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_remove_rss_cb) },
-
+ {"FolderViewPopup/RefreshFeed", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_refresh_feed_cb) },
+ {"FolderViewPopup/FeedProperties", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_prop_cb) },
+ {"FolderViewPopup/RenameFolder", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_rename_cb) },
+ {"FolderViewPopup/RefreshAllFeeds", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_update_all_cb) },
+ {"FolderViewPopup/NewFeed", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_new_feed_cb) },
+ {"FolderViewPopup/NewFolder", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_new_folder_cb) },
+ {"FolderViewPopup/ImportFeedList", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_import_feed_list_cb) },
+ {"FolderViewPopup/RemoveFolder", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_remove_folder_cb) },
+ {"FolderViewPopup/RemoveMailbox", NULL, NULL, NULL, NULL, G_CALLBACK(rssyl_remove_mailbox_cb) }
};
static void rssyl_add_menuitems(GtkUIManager *ui_manager, FolderItem *item)
{
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RefreshFeed", "FolderViewPopup/RefreshFeed", GTK_UI_MANAGER_MENUITEM)
- MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RefreshAllFeeds", "FolderViewPopup/RefreshAllFeeds", GTK_UI_MANAGER_MENUITEM)
- MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
- MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "NewFeed", "FolderViewPopup/NewFeed", GTK_UI_MANAGER_MENUITEM)
- MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RemoveFeed", "FolderViewPopup/RemoveFeed", GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "FeedProperties", "FolderViewPopup/FeedProperties", GTK_UI_MANAGER_MENUITEM)
- MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "ImportFeedlist", "FolderViewPopup/ImportFeedlist", GTK_UI_MANAGER_MENUITEM)
- MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS2", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RenameFolder", "FolderViewPopup/RenameFolder", GTK_UI_MANAGER_MENUITEM)
- MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS3", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RefreshAllFeeds", "FolderViewPopup/RefreshAllFeeds", GTK_UI_MANAGER_MENUITEM)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS2", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "NewFeed", "FolderViewPopup/NewFeed", GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "NewFolder", "FolderViewPopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "ImportFeedList", "FolderViewPopup/ImportFeedList", GTK_UI_MANAGER_MENUITEM)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS3", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RemoveFolder", "FolderViewPopup/RemoveFolder", GTK_UI_MANAGER_MENUITEM)
- MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS4", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS4", "FolderView/Popup/---", GTK_UI_MANAGER_SEPARATOR)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RemoveMailbox", "FolderViewPopup/RemoveMailbox", GTK_UI_MANAGER_MENUITEM)
- MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS5", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
+ MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorRSS5", "FolderView/Popup/---", GTK_UI_MANAGER_SEPARATOR)
}
static void rssyl_set_sensitivity(GtkUIManager *ui_manager, FolderItem *item)
{
#define SET_SENS(name, sens) \
cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens)
-
- RSSylFolderItem *ritem = (RSSylFolderItem *)item;
- SET_SENS("FolderViewPopup/RefreshFeed", folder_item_parent(item) != NULL && ritem->url);
- SET_SENS("FolderViewPopup/RefreshAllFeeds", folder_item_parent(item) == NULL );
- SET_SENS("FolderViewPopup/NewFeed", TRUE);
- SET_SENS("FolderViewPopup/ImportFeedlist", TRUE );
- SET_SENS("FolderViewPopup/RemoveFeed", folder_item_parent(item) != NULL && ritem->url );
+ RFolderItem *ritem = (RFolderItem *)item;
+ SET_SENS("FolderViewPopup/RefreshFeed", folder_item_parent(item) != NULL && ritem->url );
SET_SENS("FolderViewPopup/FeedProperties", folder_item_parent(item) != NULL && ritem->url );
SET_SENS("FolderViewPopup/RenameFolder", folder_item_parent(item) != NULL );
+ SET_SENS("FolderViewPopup/RefreshAllFeeds", TRUE );
+ SET_SENS("FolderViewPopup/NewFeed", TRUE);
SET_SENS("FolderViewPopup/NewFolder", TRUE );
- SET_SENS("FolderViewPopup/RemoveFolder", folder_item_parent(item) != NULL && !ritem->url );
- SET_SENS("FolderViewPopup/RemoveMailbox", folder_item_parent(item) == NULL );
+ SET_SENS("FolderViewPopup/RemoveFolder", folder_item_parent(item) != NULL);
+ SET_SENS("FolderViewPopup/RemoveMailbox", folder_item_parent(item) == NULL);
#undef SET_SENS
}
@@ -133,20 +117,10 @@ static FolderViewPopup rssyl_popup =
rssyl_set_sensitivity
};
-static void rssyl_fill_popup_menu_labels(void)
-{
- gint i;
-
- for( i = 0; rssyl_popup_menu_labels[i] != NULL; i++ ) {
- (rssyl_popup_entries[i]).label = _(rssyl_popup_menu_labels[i]);
- }
-}
-
static void rssyl_add_mailbox(GtkAction *action, gpointer callback_data)
{
MainWindow *mainwin = (MainWindow *) callback_data;
- gchar *path;
- gchar *base = NULL;
+ gchar *path = NULL, *tmp = NULL;
Folder *folder;
path = input_dialog(_("Add RSS folder tree"),
@@ -160,10 +134,10 @@ static void rssyl_add_mailbox(GtkAction *action, gpointer callback_data)
return;
}
- base = g_path_get_basename(path);
- folder = folder_new(folder_get_class_from_string("rssyl"),
- base, path);
- g_free(base);
+ tmp = g_path_get_basename(path);
+ folder = folder_new(folder_get_class_from_string("rssyl"), tmp, path);
+ g_free(tmp);
+ g_free(path);
if( folder->klass->create_tree(folder) < 0 ) {
alertpanel_error(_("Creation of folder tree failed.\n"
@@ -179,24 +153,30 @@ static void rssyl_add_mailbox(GtkAction *action, gpointer callback_data)
folderview_set(mainwin->folderview);
}
+
static GtkActionEntry mainwindow_add_mailbox[] = {{
"File/AddMailbox/RSSyl",
- NULL, N_("RSSyl..."), NULL, NULL, G_CALLBACK(rssyl_add_mailbox)
+ NULL, "RSSyl...", NULL, NULL, G_CALLBACK(rssyl_add_mailbox)
}};
+static void rssyl_fill_popup_menu_labels(void) {
+ gint i;
+
+ for (i = 0; rssyl_popup_menu_labels[i] != NULL; i++) {
+ (rssyl_popup_entries[i].label = _(rssyl_popup_menu_labels[i]));
+ }
+}
+
static guint main_menu_id = 0;
void rssyl_gtk_init(void)
{
MainWindow *mainwin = mainwindow_get_mainwindow();
-
gtk_action_group_add_actions(mainwin->action_group, mainwindow_add_mailbox,
1, (gpointer)mainwin);
MENUITEM_ADDUI_ID_MANAGER(mainwin->ui_manager, "/Menu/File/AddMailbox", "RSSyl",
"File/AddMailbox/RSSyl", GTK_UI_MANAGER_MENUITEM,
- main_menu_id)
-
-
+ main_menu_id);
rssyl_fill_popup_menu_labels();
folderview_register_popup(&rssyl_popup);
}
@@ -222,482 +202,5 @@ void rssyl_gtk_done(void)
MENUITEM_REMUI_MANAGER(mainwin->ui_manager,mainwin->action_group, "File/AddMailbox/RSSyl", main_menu_id);
main_menu_id = 0;
-}
-
-/***********************************************/
-
-static RSSylFeedProp *rssyl_gtk_prop_real(RSSylFolderItem *ritem)
-{
- MainWindow *mainwin = mainwindow_get_mainwindow();
- RSSylFeedProp *feedprop;
- GtkWidget *vbox, *urllabel, *urlframe, *urlalign, *table, *refresh_label,
- *expired_label, *hsep, *sep, *bbox, *cancel_button, *cancel_align,
- *cancel_hbox, *cancel_image, *cancel_label, *ok_button, *ok_align,
- *ok_hbox, *ok_image, *ok_label, *silent_update_label;
-
- GtkObject *refresh_adj, *expired_adj, *fetch_comments_for_adj;
- gint refresh;
- gint row = 0;
-
- g_return_val_if_fail(ritem != NULL, NULL);
-
- feedprop = g_new0(RSSylFeedProp, 1);
-
- /* Create required widgets */
-
- /* Window */
- feedprop->window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "rssyl_gtk");
-
- /* URL entry */
- feedprop->url = gtk_entry_new();
- gtk_entry_set_text(GTK_ENTRY(feedprop->url), ritem->url);
-
- /* "Use default refresh interval" checkbutton */
- feedprop->default_refresh_interval = gtk_check_button_new_with_mnemonic(
- _("Use default refresh interval"));
- gtk_toggle_button_set_active(
- GTK_TOGGLE_BUTTON(feedprop->default_refresh_interval),
- ritem->default_refresh_interval);
-
- if( ritem->refresh_interval >= 0 && !ritem->default_refresh_interval )
- refresh = ritem->refresh_interval;
- else
- refresh = rssyl_prefs_get()->refresh;
-
- /* "Keep default number of expired items" checkbutton */
- feedprop->default_expired_num = gtk_check_button_new_with_mnemonic(
- _("Keep default number of expired entries"));
- gtk_toggle_button_set_active(
- GTK_TOGGLE_BUTTON(feedprop->default_expired_num),
- ritem->default_expired_num);
-
- feedprop->fetch_comments = gtk_check_button_new_with_mnemonic(
- _("Fetch comments if possible"));
- gtk_toggle_button_set_active(
- GTK_TOGGLE_BUTTON(feedprop->fetch_comments),
- ritem->fetch_comments);
-
- /* Refresh interval spinbutton */
- fetch_comments_for_adj = gtk_adjustment_new(ritem->fetch_comments_for,
- -1, 100000, 1, 10, 0);
- feedprop->fetch_comments_for = gtk_spin_button_new(GTK_ADJUSTMENT(fetch_comments_for_adj),
- 1, 0);
-
- /* Refresh interval spinbutton */
- refresh_adj = gtk_adjustment_new(refresh,
- 0, 100000, 1, 10, 0);
- feedprop->refresh_interval = gtk_spin_button_new(GTK_ADJUSTMENT(refresh_adj),
- 1, 0);
-
- /* Expired num spinbutton */
- expired_adj = gtk_adjustment_new(ritem->expired_num, -1, 100000, 1, 10, 0);
- feedprop->expired_num = gtk_spin_button_new(GTK_ADJUSTMENT(expired_adj),
- 1, 0);
-
- vbox = gtk_vbox_new(FALSE, 0);
- gtk_container_add(GTK_CONTAINER(feedprop->window), vbox);
-
- /* URL frame */
- urlframe = gtk_frame_new(NULL);
- gtk_container_set_border_width(GTK_CONTAINER(urlframe), 5);
- gtk_frame_set_label_align(GTK_FRAME(urlframe), 0.05, 0.5);
- gtk_frame_set_shadow_type(GTK_FRAME(urlframe), GTK_SHADOW_ETCHED_OUT);
- gtk_box_pack_start(GTK_BOX(vbox), urlframe, FALSE, FALSE, 0);
-
- /* Label for URL frame */
- urllabel = gtk_label_new(_("<b>Source URL:</b>"));
- gtk_label_set_use_markup(GTK_LABEL(urllabel), TRUE);
- gtk_misc_set_padding(GTK_MISC(urllabel), 5, 0);
- gtk_frame_set_label_widget(GTK_FRAME(urlframe), urllabel);
-
- /* URL entry (+ alignment in frame) */
- urlalign = gtk_alignment_new(0, 0.5, 1, 1);
- gtk_alignment_set_padding(GTK_ALIGNMENT(urlalign), 5, 5, 5, 5);
- gtk_container_add(GTK_CONTAINER(urlframe), urlalign);
-
- gtk_entry_set_activates_default(GTK_ENTRY(feedprop->url), TRUE);
- gtk_container_add(GTK_CONTAINER(urlalign), feedprop->url);
-
- /* Table for remaining properties */
- table = gtk_table_new(8, 2, FALSE);
- gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
-
- /* Fetch comments - checkbutton */
- gtk_table_attach(GTK_TABLE(table), feedprop->fetch_comments,
- 0, 2, row, row+1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 10, 0);
- g_signal_connect(G_OBJECT(feedprop->fetch_comments), "toggled",
- G_CALLBACK(rssyl_fetch_comments_toggled_cb),
- (gpointer)feedprop->fetch_comments_for);
- row++;
-
- /* Fetch comments for - label */
- refresh_label = gtk_label_new(_("<b>Fetch comments on posts aged less than:</b>\n"
- "<small>(In days; set to -1 to fetch all comments)"
- "</small>"));
- gtk_label_set_use_markup(GTK_LABEL(refresh_label), TRUE);
- gtk_misc_set_alignment(GTK_MISC(refresh_label), 0, 0.5);
- gtk_table_attach(GTK_TABLE(table), refresh_label, 0, 1, row, row+1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 10, 5);
-
- /* Fetch comments for - spinbutton */
- gtk_widget_set_sensitive(feedprop->fetch_comments_for,
- ritem->fetch_comments);
- gtk_table_attach(GTK_TABLE(table), feedprop->fetch_comments_for, 1, 2, row, row+1,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 10, 5);
-
- row++;
- hsep = gtk_hseparator_new();
- gtk_widget_set_size_request(hsep, -1, 10);
- gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 10, 5);
-
- row++;
- /* Use default refresh interval - checkbutton */
- gtk_table_attach(GTK_TABLE(table), feedprop->default_refresh_interval,
- 0, 2, row, row+1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 10, 0);
- g_signal_connect(G_OBJECT(feedprop->default_refresh_interval), "toggled",
- G_CALLBACK(rssyl_default_refresh_interval_toggled_cb),
- (gpointer)feedprop->refresh_interval);
- row++;
- /* Refresh interval - label */
- refresh_label = gtk_label_new(_("<b>Refresh interval in minutes:</b>\n"
- "<small>(Set to 0 to disable automatic refreshing for this feed)"
- "</small>"));
- gtk_label_set_use_markup(GTK_LABEL(refresh_label), TRUE);
- gtk_misc_set_alignment(GTK_MISC(refresh_label), 0, 0.5);
- gtk_table_attach(GTK_TABLE(table), refresh_label, 0, 1, row, row+1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 10, 5);
-
- /* Refresh interval - spinbutton */
- gtk_widget_set_sensitive(feedprop->refresh_interval,
- !ritem->default_refresh_interval);
- gtk_table_attach(GTK_TABLE(table), feedprop->refresh_interval, 1, 2, row, row+1,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 10, 5);
- row++;
- hsep = gtk_hseparator_new();
- gtk_widget_set_size_request(hsep, -1, 10);
- gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 10, 5);
-
- row++;
- /* Use default number for expired - checkbutton */
- gtk_table_attach(GTK_TABLE(table), feedprop->default_expired_num, 0, 2, row, row+1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 10, 0);
- g_signal_connect(G_OBJECT(feedprop->default_expired_num), "toggled",
- G_CALLBACK(rssyl_default_expired_num_toggled_cb),
- (gpointer)feedprop->expired_num);
-
- row++;
- /* Expired items - label */
- expired_label = gtk_label_new(_("<b>Number of expired entries to keep:"
- "</b>\n<small>(Set to -1 if you want to keep expired entries)"
- "</small>"));
- gtk_label_set_use_markup(GTK_LABEL(expired_label), TRUE);
- gtk_misc_set_alignment(GTK_MISC(expired_label), 0, 0.5);
- gtk_table_attach(GTK_TABLE(table), expired_label, 0, 1, row, row+1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 10, 5);
-
- /* Expired items - spinbutton */
- gtk_widget_set_sensitive(feedprop->expired_num,
- !ritem->default_expired_num);
- gtk_table_attach(GTK_TABLE(table), feedprop->expired_num, 1, 2, row, row+1,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 10, 5);
-
- row++;
- hsep = gtk_hseparator_new();
- gtk_widget_set_size_request(hsep, -1, 10);
- gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 10, 5);
-
- row++;
- /* Silent update - label */
- silent_update_label =
- gtk_label_new(_("<b>If an item changes, do not mark it as unread:</b>"));
- gtk_label_set_use_markup(GTK_LABEL(silent_update_label), TRUE);
- gtk_misc_set_alignment(GTK_MISC(silent_update_label), 0, 0.5);
- gtk_table_attach(GTK_TABLE(table), silent_update_label, 0, 1, row, row+1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 10, 5);
-
- /* Silent update - combobox */
- feedprop->silent_update = gtk_combo_box_new_text();
- gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
- _("Always mark as unread"));
- gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
- _("If only its text has changed"));
- gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
- _("Never mark as unread"));
- gtk_table_attach(GTK_TABLE(table), feedprop->silent_update, 1, 2, row, row+1,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 10, 5);
- gtk_combo_box_set_active(GTK_COMBO_BOX(feedprop->silent_update),
- ritem->silent_update);
-
- row++;
- hsep = gtk_hseparator_new();
- gtk_widget_set_size_request(hsep, -1, 10);
- gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 10, 5);
-
- row++;
- feedprop->ssl_verify_peer_checkbtn = gtk_check_button_new_with_label(
- _("Verify SSL certificate validity"));
- gtk_widget_show(feedprop->ssl_verify_peer_checkbtn);
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(feedprop->ssl_verify_peer_checkbtn),
- ritem->ssl_verify_peer);
- gtk_table_attach(GTK_TABLE(table), feedprop->ssl_verify_peer_checkbtn, 0, 1, row, row+1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 10, 5);
-
-
- /* Separator above the button box */
- sep = gtk_hseparator_new();
- gtk_widget_set_size_request(sep, -1, 10);
- gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
-
- /* Buttonbox */
- bbox = gtk_hbutton_box_new();
- gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
- gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
- gtk_box_set_spacing(GTK_BOX(bbox), 5);
- gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
-
- /* Cancel button */
- cancel_button = gtk_button_new();
- gtk_container_add(GTK_CONTAINER(bbox), cancel_button);
-
- cancel_align = gtk_alignment_new(0.5, 0.5, 0, 0);
- gtk_container_add(GTK_CONTAINER(cancel_button), cancel_align);
-
- cancel_hbox = gtk_hbox_new(FALSE, 2);
- gtk_container_add(GTK_CONTAINER(cancel_align), cancel_hbox);
-
- cancel_image = gtk_image_new_from_stock(GTK_STOCK_CANCEL,
- GTK_ICON_SIZE_BUTTON);
- gtk_box_pack_start(GTK_BOX(cancel_hbox), cancel_image, FALSE, FALSE, 0);
-
- cancel_label = gtk_label_new_with_mnemonic(_("_Cancel"));
- gtk_box_pack_end(GTK_BOX(cancel_hbox), cancel_label, FALSE, FALSE, 0);
-
- g_signal_connect(G_OBJECT(cancel_button), "clicked",
- G_CALLBACK(rssyl_props_cancel_cb), ritem);
-
- /* OK button */
- ok_button = gtk_button_new();
- gtk_container_add(GTK_CONTAINER(bbox), ok_button);
- gtkut_widget_set_can_default(ok_button, TRUE);
-
- ok_align = gtk_alignment_new(0.5, 0.5, 0, 0);
- gtk_container_add(GTK_CONTAINER(ok_button), ok_align);
-
- ok_hbox = gtk_hbox_new(FALSE, 2);
- gtk_container_add(GTK_CONTAINER(ok_align), ok_hbox);
-
- ok_image = gtk_image_new_from_stock(GTK_STOCK_OK,
- GTK_ICON_SIZE_BUTTON);
- gtk_box_pack_start(GTK_BOX(ok_hbox), ok_image, FALSE, FALSE, 0);
-
- ok_label = gtk_label_new_with_mnemonic(_("_OK"));
- gtk_box_pack_end(GTK_BOX(ok_hbox), ok_label, FALSE, FALSE, 0);
-
- g_signal_connect(G_OBJECT(ok_button), "clicked",
- G_CALLBACK(rssyl_props_ok_cb), ritem);
-
- /* Set some misc. stuff */
- gtk_window_set_title(GTK_WINDOW(feedprop->window),
- g_strdup(_("Set feed properties")) );
- gtk_window_set_modal(GTK_WINDOW(feedprop->window), TRUE);
- gtk_window_set_transient_for(GTK_WINDOW(feedprop->window),
- GTK_WINDOW(mainwin->window) );
-
- /* Attach callbacks to handle Enter and Escape keys */
- g_signal_connect(G_OBJECT(feedprop->window), "key_press_event",
- G_CALLBACK(rssyl_props_key_press_cb), ritem);
-
- /* ...and voila! */
- gtk_widget_show_all(feedprop->window);
- gtk_widget_grab_default(ok_button);
-
- /* Unselect the text in URL entry */
- gtk_editable_select_region(GTK_EDITABLE(feedprop->url), 0, 0);
-
- ritem->feedprop = feedprop;
-
- return feedprop;
-}
-
-void rssyl_gtk_prop(RSSylFolderItem *ritem)
-{
- g_return_if_fail(ritem != NULL);
-
- rssyl_gtk_prop_real(ritem);
-}
-
-void rssyl_gtk_prop_store(RSSylFolderItem *ritem)
-{
- gchar *url;
- gint x, old_ri, old_ex, old_fetch_comments;
- gboolean use_default_ri = FALSE, use_default_ex = FALSE;
-
- g_return_if_fail(ritem != NULL);
- g_return_if_fail(ritem->feedprop != NULL);
-
- url = (gchar *)gtk_entry_get_text(GTK_ENTRY(ritem->feedprop->url));
-
- if( strlen(url) ) {
- if( ritem->url ) {
- g_free(ritem->url);
- }
- ritem->url = g_strdup(url);
- }
-
- use_default_ri = gtk_toggle_button_get_active(
- GTK_TOGGLE_BUTTON(ritem->feedprop->default_refresh_interval));
- ritem->default_refresh_interval = use_default_ri;
- debug_print("store: default is %s\n", ( use_default_ri ? "ON" : "OFF" ) );
-
- /* Use default if checkbutton is set */
- if( use_default_ri )
- x = rssyl_prefs_get()->refresh;
- else
- x = gtk_spin_button_get_value_as_int(
- GTK_SPIN_BUTTON(ritem->feedprop->refresh_interval) );
-
- old_ri = ritem->refresh_interval;
- ritem->refresh_interval = x;
-
- /* Update refresh interval setting if it has changed and has a sane value */
- if( old_ri != x && x >= 0 ) {
- debug_print("RSSyl: GTK - refresh interval changed to %d , updating "
- "timeout\n", ritem->refresh_interval);
- /* Value of 0 means we do not want to update automatically */
- if( x > 0 )
- rssyl_start_refresh_timeout(ritem);
- }
-
- old_fetch_comments = ritem->fetch_comments;
- ritem->fetch_comments = gtk_toggle_button_get_active(
- GTK_TOGGLE_BUTTON(ritem->feedprop->fetch_comments));
-
- ritem->fetch_comments_for = gtk_spin_button_get_value_as_int(
- GTK_SPIN_BUTTON(ritem->feedprop->fetch_comments_for));
-
- if (!old_fetch_comments && ritem->fetch_comments) {
- /* reset the RSSylFolderItem's mtime to be sure we get all
- * available comments */
- ritem->item.mtime = 0;
- }
-
- use_default_ex = gtk_toggle_button_get_active(
- GTK_TOGGLE_BUTTON(ritem->feedprop->default_expired_num));
- ritem->default_expired_num = use_default_ex;
- debug_print("store: default is %s\n", ( use_default_ex ? "ON" : "OFF" ) );
-
- /* Use default if checkbutton is set */
- if( use_default_ex )
- x = rssyl_prefs_get()->expired;
- else
- x = gtk_spin_button_get_value_as_int(
- GTK_SPIN_BUTTON(ritem->feedprop->expired_num) );
-
- old_ex = ritem->expired_num;
- ritem->expired_num = x;
-
- ritem->silent_update =
- gtk_combo_box_get_active(GTK_COMBO_BOX(ritem->feedprop->silent_update));
- if( ritem->silent_update < 0 )
- ritem->silent_update = 0;
-
- ritem->ssl_verify_peer = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
- (ritem->feedprop->ssl_verify_peer_checkbtn));;
-
- rssyl_store_feed_props(ritem);
-
- debug_print("last_count %d, x %d, old_ex %d\n", ritem->last_count, x, old_ex);
-
- /* update if new setting is lower, or if it was changed from -1 */
- if( ritem->last_count != 0 && x != -1 && (old_ex > x || old_ex == -1) ) {
- debug_print("RSSyl: GTK - expired_num has changed to %d, expiring\n",
- ritem->expired_num);
- rssyl_expire_items(ritem);
- }
-}
-
-GtkWidget *rssyl_feed_removal_dialog(gchar *name, GtkWidget **rmcache_widget)
-{
- gchar *message;
- GtkWidget *dialog, *vbox, *hbox, *image, *vbox2, *label, *cb, *aa,
- *bno, *byes;
- MainWindow *mainwin = mainwindow_get_mainwindow();
-
- g_return_val_if_fail(name != NULL, NULL);
-
- dialog = gtk_dialog_new();
- gtk_window_set_title(GTK_WINDOW(dialog), _("Unsubscribe feed"));
- gtk_window_set_type_hint(GTK_WINDOW(dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
-
- vbox = GTK_DIALOG(dialog)->vbox;
-
- hbox = gtk_hbox_new(FALSE, 0);
- gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
-
- /* Question icon */
- image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION,
- GTK_ICON_SIZE_DIALOG);
- gtk_misc_set_alignment(GTK_MISC(image), 0.5, 0.30);
- gtk_misc_set_padding(GTK_MISC(image), 12, 0);
- gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
-
- vbox2 = gtk_vbox_new(FALSE, 0);
- gtk_box_pack_start(GTK_BOX(hbox), vbox2, TRUE, TRUE, 0);
-
- /* Dialog text label */
- label = gtk_label_new("");
- gtk_misc_set_alignment(GTK_MISC(label), 0.1, 0);
- gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
- gtk_misc_set_padding(GTK_MISC(label), 0, 12);
- message = g_markup_printf_escaped("<span size='x-large'><b>%s</b></span>"
- "\n\n%s '%s' ?", _("Unsubscribe feed"),
- _("Do you really want to remove feed"), name);
- gtk_label_set_markup(GTK_LABEL(label), message);
- g_free(message);
- gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, FALSE, 0);
-
- /* Remove cache checkbutton */
- cb = gtk_check_button_new_with_mnemonic(_("Remove cached entries"));
- gtk_button_set_focus_on_click(GTK_BUTTON(cb), FALSE);
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb), TRUE);
- gtk_box_pack_start(GTK_BOX(vbox2), cb, FALSE, FALSE, 0);
- *rmcache_widget = cb;
-
- aa = GTK_DIALOG(dialog)->action_area;
- gtk_button_box_set_layout(GTK_BUTTON_BOX(aa), GTK_BUTTONBOX_END);
-
- bno = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
- gtk_dialog_add_action_widget(GTK_DIALOG(dialog), bno, GTK_RESPONSE_NO);
- gtkut_widget_set_can_default(bno, TRUE);
-
- byes = gtk_button_new_with_mnemonic(_("_Unsubscribe"));
- gtk_dialog_add_action_widget(GTK_DIALOG(dialog), byes, GTK_RESPONSE_YES);
-
- gtk_widget_grab_default(bno);
- gtk_window_set_transient_for(GTK_WINDOW(dialog),
- GTK_WINDOW(mainwin->window) );
- return dialog;
}
diff --git a/src/plugins/rssyl/rssyl_gtk.h b/src/plugins/rssyl/rssyl_gtk.h
index a670a6b..6a97fc8 100644
--- a/src/plugins/rssyl/rssyl_gtk.h
+++ b/src/plugins/rssyl/rssyl_gtk.h
@@ -7,27 +7,11 @@
#include "rssyl.h"
-struct _RSSylFeedProp {
- GtkWidget *window;
- GtkWidget *url;
- GtkWidget *default_refresh_interval;
- GtkWidget *refresh_interval;
- GtkWidget *default_expired_num;
- GtkWidget *expired_num;
- GtkWidget *fetch_comments;
- GtkWidget *fetch_comments_for;
- GtkWidget *silent_update;
- GtkWidget *ssl_verify_peer_checkbtn;
-};
-
-typedef struct _RSSylFeedProp RSSylFeedProp;
-
void rssyl_gtk_init(void);
void rssyl_gtk_done(void);
-void rssyl_gtk_prop(RSSylFolderItem *ritem);
-void rssyl_gtk_prop_store(RSSylFolderItem *ritem);
-
GtkWidget *rssyl_feed_removal_dialog(gchar *name, GtkWidget **rmcache_widget);
+void rssyl_gtk_prop(RFolderItem *ritem);
+
#endif /* __RSSYL_GTK */
diff --git a/src/plugins/rssyl/rssyl_parse_feed.c b/src/plugins/rssyl/rssyl_parse_feed.c
new file mode 100644
index 0000000..88dc406
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_parse_feed.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <glib/gi18n.h>
+
+/* Claws Mail includes */
+#include <log.h>
+#include <codeconv.h>
+#include <main.h>
+#include <procmsg.h>
+
+/* Local includes */
+#include "libfeed/feed.h"
+#include "libfeed/feeditem.h"
+#include "libfeed/date.h"
+#include "parse822.h"
+#include "rssyl.h"
+#include "rssyl_add_item.h"
+#include "rssyl_deleted.h"
+#include "rssyl_feed.h"
+#include "rssyl_parse_feed.h"
+#include "rssyl_prefs.h"
+#include "strutils.h"
+
+static void rssyl_foreach_parse_func(gpointer data, gpointer user_data)
+{
+ FeedItem *feed_item = (FeedItem *)data;
+ RFolderItem *ritem = (RFolderItem *)user_data;
+
+ rssyl_add_item(ritem, feed_item);
+}
+
+struct _RSSylExpireItemsCtx {
+ gboolean exists;
+ FeedItem *item;
+};
+
+typedef struct _RSSylExpireItemsCtx RSSylExpireItemsCtx;
+
+static void expire_items_func(gpointer data, gpointer user_data)
+{
+ RSSylExpireItemsCtx *ctx = (RSSylExpireItemsCtx *)user_data;
+ FeedItem *item = (FeedItem *)data;
+ gchar *id = NULL, *id2 = NULL;
+
+ if( (id = feed_item_get_id(item)) == NULL )
+ id = feed_item_get_url(item);
+
+ if( id == NULL )
+ return;
+
+ if( (id2 = feed_item_get_id(ctx->item)) == NULL )
+ id2 = feed_item_get_url(ctx->item);
+
+ if( id2 == NULL )
+ return;
+
+ /* Simply check ID, as we should have up-to-date items right now. */
+ if( !strcmp(id, id2) )
+ ctx->exists = TRUE;
+}
+
+static void rssyl_expire_items(RFolderItem *ritem, Feed *feed)
+{
+ FeedItem *item = NULL;
+ GSList *i = NULL;
+ RSSylExpireItemsCtx *ctx = NULL;
+ RFeedCtx *fctx;
+
+ debug_print("RSSyl: rssyl_expire_items()\n");
+
+ g_return_if_fail(ritem != NULL);
+ g_return_if_fail(ritem->items != NULL);
+ g_return_if_fail(feed != NULL);
+
+ ctx = malloc( sizeof(RSSylExpireItemsCtx) );
+
+ /* Check each locally stored item, if it is still in the upstream
+ * feed - xnay it if not. */
+ for( i = ritem->items; i != NULL; i = i->next ) {
+ item = (FeedItem *)i->data;
+
+ /* Do not expire comments, they expire with their parents */
+ if (feed_item_get_parent_id(item) != NULL)
+ continue;
+
+ ctx->exists = FALSE;
+ ctx->item = item;
+ feed_foreach_item(feed, expire_items_func, ctx);
+
+ if( !ctx->exists ) {
+ fctx = (RFeedCtx *)item->data;
+ /* TODO: expire item's comments (items with our parent_id) */
+ g_remove(fctx->path);
+ }
+ }
+
+ g_free(ctx);
+}
+
+/* -------------------------------------------------------------------------
+ * rssyl_parse_feed() */
+
+gboolean rssyl_parse_feed(RFolderItem *ritem, Feed *feed)
+{
+ gchar *tmp = NULL, *tmp2 = NULL;
+ gint i = 1;
+
+ g_return_val_if_fail(ritem != NULL, FALSE);
+ g_return_val_if_fail(feed != NULL, FALSE);
+ g_return_val_if_fail(feed->title != NULL, FALSE);
+
+ debug_print("RSSyl: parse_feed\n");
+
+ /* Set the last_update timestamp here, so it is the same for all items */
+ ritem->last_update = time(NULL);
+
+ /* If the upstream feed changed its title, change name of our folder
+ * accordingly even if user has renamed it before. This makes sure that
+ * user will be aware of the upstream title change. */
+ if( !ritem->ignore_title_rename &&
+ (ritem->official_title == NULL ||
+ strcmp(feed->title, ritem->official_title)) ) {
+ g_free(ritem->official_title);
+ ritem->official_title = g_strdup(feed->title);
+
+ tmp = rssyl_format_string(feed->title, TRUE, TRUE);
+
+ tmp2 = g_strdup(tmp);
+ while (folder_item_rename(&ritem->item, tmp2) != 0 && i < 20) {
+ g_free(tmp2);
+ tmp2 = g_strdup_printf("%s__%d", tmp, ++i);
+ debug_print("RSSyl: couldn't rename, trying '%s'\n", tmp2);
+ }
+ /* TODO: handle case when i reaches 20 */
+
+ g_free(tmp);
+ g_free(tmp2);
+
+ /* FIXME: update name in properties */
+ /* FIXME: store feed properties */
+ }
+
+ folder_item_update_freeze();
+
+ /* Read contents of folder, so we can check for duplicates/updates */
+ rssyl_folder_read_existing(ritem);
+
+ if( claws_is_exiting() ) {
+ debug_print("RSSyl: Claws-Mail is exiting, bailing out\n");
+ log_print(LOG_PROTOCOL, RSSYL_LOG_ABORTED_EXITING, ritem->url);
+ folder_item_update_thaw();
+ return TRUE;
+ }
+
+ /* Populate the ->deleted_items list so that we can check it when
+ * adding each item. */
+ ritem->deleted_items = rssyl_deleted_update(ritem);
+
+ /* Parse each item in the feed, adding or updating existing items if
+ * necessary */
+ if( feed_n_items(feed) > 0 )
+ feed_foreach_item(feed, rssyl_foreach_parse_func, (gpointer)ritem);
+
+ if( !ritem->keep_old && !ritem->fetching_comments ) {
+ rssyl_folder_read_existing(ritem);
+ rssyl_expire_items(ritem, feed);
+ }
+
+ rssyl_deleted_free(ritem->deleted_items);
+
+ folder_item_scan(&ritem->item);
+ folder_item_update_thaw();
+
+ if( !ritem->fetching_comments )
+ log_print(LOG_PROTOCOL, RSSYL_LOG_UPDATED, ritem->url);
+
+ return TRUE;
+}
diff --git a/src/plugins/rssyl/rssyl_parse_feed.h b/src/plugins/rssyl/rssyl_parse_feed.h
new file mode 100644
index 0000000..5e4a3f3
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_parse_feed.h
@@ -0,0 +1,16 @@
+#ifndef __RSSYL_PARSE_FEED
+#define __RSSYL_PARSE_FEED
+
+#include <glib.h>
+
+#include "rssyl.h"
+#include "libfeed/feed.h"
+
+#define RSSYL_TMP_TEMPLATE "rssylXXXXXX"
+
+#define RSSYL_TEXT_START "<!-- RSSyl text start -->"
+#define RSSYL_TEXT_END "<!-- RSSyl text end -->"
+
+gboolean rssyl_parse_feed(RFolderItem *ritem, Feed *feed);
+
+#endif /* __RSSYL_PARSE_FEED */
diff --git a/src/plugins/rssyl/rssyl_prefs.c b/src/plugins/rssyl/rssyl_prefs.c
index 97b2b83..6b8b050 100644
--- a/src/plugins/rssyl/rssyl_prefs.c
+++ b/src/plugins/rssyl/rssyl_prefs.c
@@ -22,39 +22,43 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
-#include "claws-features.h"
#endif
+/* Global includes */
#include <glib.h>
#include <glib/gi18n.h>
-#include "common/defs.h"
-#include "common/utils.h"
-#include "gtk/gtkutils.h"
-#include "prefs_gtk.h"
+/* Claws Mail includes */
+#include <common/defs.h>
+#include <prefs_gtk.h>
+#include <mainwindow.h>
+/* Local includes */
+#include "rssyl.h"
#include "rssyl_prefs.h"
+#include "rssyl_feed.h"
-static RSSylPrefsPage rssyl_prefs_page;
-RSSylPrefs rssyl_prefs;
+static RPrefsPage rssyl_gtk_prefs_page;
+RPrefs rssyl_prefs;
static void destroy_rssyl_prefs_page(PrefsPage *page);
static void create_rssyl_prefs_page(PrefsPage *page,
GtkWindow *window, gpointer data);
static void save_rssyl_prefs(PrefsPage *page);
-
-static PrefParam param[] = {
- { "refresh_interval", RSSYL_PREF_DEFAULT_REFRESH, &rssyl_prefs.refresh, P_INT,
- NULL, NULL, NULL },
- { "expired_keep", RSSYL_PREF_DEFAULT_EXPIRED, &rssyl_prefs.expired, P_INT,
- NULL, NULL, NULL },
- { "refresh_on_startup", "FALSE", &rssyl_prefs.refresh_on_startup, P_BOOL,
- NULL, NULL, NULL },
- { "cookies_path", "", &rssyl_prefs.cookies_path, P_STRING,
- NULL, NULL, NULL },
- { "ssl_verify_peer", "TRUE", &rssyl_prefs.ssl_verify_peer, P_BOOL,
- NULL, NULL, NULL },
- { 0, 0, 0, 0, 0, 0, 0 }
+static void rssyl_apply_prefs(void);
+
+ static PrefParam param[] = {
+ { "refresh_interval", PREF_DEFAULT_REFRESH, &rssyl_prefs.refresh, P_INT,
+ NULL, NULL, NULL },
+ { "refresh_on_startup", "FALSE", &rssyl_prefs.refresh_on_startup, P_BOOL,
+ NULL, NULL, NULL },
+ { "refresh_enabled", "TRUE", &rssyl_prefs.refresh_enabled, P_BOOL,
+ NULL, NULL, NULL },
+ { "cookies_path", "", &rssyl_prefs.cookies_path, P_STRING,
+ NULL, NULL, NULL },
+ { "ssl_verify_peer", "TRUE", &rssyl_prefs.ssl_verify_peer, P_BOOL,
+ NULL, NULL, NULL },
+ { 0, 0, 0, 0, 0, 0, 0 }
};
void rssyl_prefs_init(void)
@@ -71,98 +75,119 @@ void rssyl_prefs_init(void)
prefs_read_config(param, PREFS_BLOCK_NAME, rcpath, NULL);
g_free(rcpath);
- rssyl_prefs_page.page.path = path;
- rssyl_prefs_page.page.create_widget = create_rssyl_prefs_page;
- rssyl_prefs_page.page.destroy_widget = destroy_rssyl_prefs_page;
- rssyl_prefs_page.page.save_page = save_rssyl_prefs;
- rssyl_prefs_page.page.weight = 30.0;
+ rssyl_gtk_prefs_page.page.path = path;
+ rssyl_gtk_prefs_page.page.create_widget = create_rssyl_prefs_page;
+ rssyl_gtk_prefs_page.page.destroy_widget = destroy_rssyl_prefs_page;
+ rssyl_gtk_prefs_page.page.save_page = save_rssyl_prefs;
+ rssyl_gtk_prefs_page.page.weight = 30.0;
- prefs_gtk_register_page((PrefsPage *) &rssyl_prefs_page);
+ prefs_gtk_register_page((PrefsPage *) &rssyl_gtk_prefs_page);
}
void rssyl_prefs_done(void)
{
- prefs_gtk_unregister_page((PrefsPage *) &rssyl_prefs_page);
+ prefs_gtk_unregister_page((PrefsPage *) &rssyl_gtk_prefs_page);
+}
+
+/* Toggle the refresh timeout spinbutton sensitivity after the
+ * checkbutton was toggled. */
+static gboolean
+rssyl_refresh_enabled_toggled_cb(GtkToggleButton *tb, gpointer data)
+{
+ gtk_widget_set_sensitive(GTK_WIDGET(data),
+ gtk_toggle_button_get_active(tb));
+ return FALSE;
}
static void create_rssyl_prefs_page(PrefsPage *page,
GtkWindow *window, gpointer data)
{
- RSSylPrefsPage *prefs_page = (RSSylPrefsPage *) page;
+ int row = 0;
+ RPrefsPage *prefs_page = (RPrefsPage *) page;
GtkWidget *table;
- GtkWidget *refresh;
- GtkWidget *expired;
+ GtkWidget *refresh, *refresh_enabled;
+ GtkWidget *label;
GtkWidget *refresh_on_startup;
+ GtkObject *refresh_adj;
GtkWidget *cookies_path;
- GtkWidget *ssl_verify_peer_checkbtn;
- GtkWidget *label;
- GtkObject *refresh_adj, *expired_adj;
+ GtkWidget *ssl_verify_peer;
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+ GtkTooltips *tooltips;
+
+ tooltips = gtk_tooltips_new();
+ gtk_tooltips_enable(tooltips);
+#endif
- table = gtk_table_new(RSSYL_NUM_PREFS, 2, FALSE);
- gtk_container_set_border_width(GTK_CONTAINER(table), 6);
+ table = gtk_table_new(3, 2, FALSE);
+ gtk_container_set_border_width(GTK_CONTAINER(table), 5);
gtk_table_set_row_spacings(GTK_TABLE(table), VSPACING_NARROW);
gtk_table_set_col_spacings(GTK_TABLE(table), 8);
- label = gtk_label_new(_("Default refresh interval in minutes"));
- gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
- gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1,
- GTK_FILL, 0, 0, 0);
+ /* Refresh interval */
+ refresh_enabled = gtk_check_button_new_with_label(
+ _("Default refresh interval in minutes"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(refresh_enabled),
+ rssyl_prefs.refresh_enabled);
+ gtk_table_attach(GTK_TABLE(table), refresh_enabled, 0, 1, row, row+1,
+ GTK_FILL | GTK_EXPAND, 0, 0, 0);
refresh_adj = gtk_adjustment_new(rssyl_prefs.refresh,
- 0, 100000, 1, 10, 0);
+ 1, 100000, 1, 10, 0);
refresh = gtk_spin_button_new(GTK_ADJUSTMENT(refresh_adj), 1, 0);
- gtk_table_attach(GTK_TABLE(table), refresh, 1, 2, 0, 1,
+ gtk_widget_set_sensitive(GTK_WIDGET(refresh), rssyl_prefs.refresh_enabled);
+ gtk_table_attach(GTK_TABLE(table), refresh, 1, 2, row, row+1,
GTK_FILL, 0, 0, 0);
- CLAWS_SET_TIP(refresh,
- _("Set to 0 to disable automatic refreshing"));
- label = gtk_label_new(_("Default number of expired items to keep"));
- gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
- gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2,
- GTK_FILL, 0, 0, 0);
-
- expired_adj = gtk_adjustment_new(rssyl_prefs.expired,
- -1, 100000, 1, 10, 0);
- expired = gtk_spin_button_new(GTK_ADJUSTMENT(expired_adj), 1, 0);
- gtk_table_attach(GTK_TABLE(table), expired, 1, 2, 1, 2,
- GTK_FILL, 0, 0, 0);
- CLAWS_SET_TIP(expired,
- _("Set to -1 to keep expired items"));
+ g_signal_connect(G_OBJECT(refresh_enabled), "toggled",
+ G_CALLBACK(rssyl_refresh_enabled_toggled_cb), refresh);
+ row++;
+ /* Whether to refresh all feeds on CM startup */
refresh_on_startup = gtk_check_button_new_with_label(
_("Refresh all feeds on application start"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(refresh_on_startup),
rssyl_prefs.refresh_on_startup);
- gtk_table_attach(GTK_TABLE(table), refresh_on_startup, 0, 2, 3, 4,
+ gtk_table_attach(GTK_TABLE(table), refresh_on_startup, 0, 2, row, row+1,
GTK_FILL | GTK_EXPAND, 0, 0, 0);
+ row++;
+ /* Path to cookies file for libcurl to use */
label = gtk_label_new(_("Path to cookies file"));
- gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5,
- GTK_FILL, 0, 0, 0);
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1,
+ GTK_FILL | GTK_EXPAND, 0, 0, 0);
gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
- cookies_path = gtk_entry_new ();
+ cookies_path = gtk_entry_new();
gtk_entry_set_text(GTK_ENTRY(cookies_path), rssyl_prefs.cookies_path);
- gtk_table_attach(GTK_TABLE(table), cookies_path, 1, 2, 4, 5,
- GTK_FILL | GTK_EXPAND, 0, 0, 0);
- CLAWS_SET_TIP(cookies_path,
+ gtk_table_attach(GTK_TABLE(table), cookies_path, 1, 2, row, row+1,
+ GTK_FILL, 0, 0, 0);
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+ gtk_tooltips_set_tip(tooltips, cookies_path,
+ _("Path to Netscape-style cookies.txt file containing your cookies"), NULL);
+#else
+ gtk_widget_set_tooltip_text(cookies_path,
_("Path to Netscape-style cookies.txt file containing your cookies"));
+#endif
- ssl_verify_peer_checkbtn = gtk_check_button_new_with_label(
- _("Verify SSL certificate validity for new feeds"));
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ssl_verify_peer_checkbtn),
+ row++;
+
+ /* Whether to verify SSL peer certificate */
+ ssl_verify_peer = gtk_check_button_new_with_label(
+ _("Verify SSL certificates validity for new feeds"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ssl_verify_peer),
rssyl_prefs.ssl_verify_peer);
- gtk_table_attach(GTK_TABLE(table), ssl_verify_peer_checkbtn, 0, 2, 5, 6,
+ gtk_table_attach(GTK_TABLE(table), ssl_verify_peer, 0, 2, row, row+1,
GTK_FILL | GTK_EXPAND, 0, 0, 0);
gtk_widget_show_all(table);
+ /* Store pointers to relevant widgets */
prefs_page->page.widget = table;
+ prefs_page->refresh_enabled = refresh_enabled;
prefs_page->refresh = refresh;
- prefs_page->expired = expired;
prefs_page->refresh_on_startup = refresh_on_startup;
prefs_page->cookies_path = cookies_path;
- prefs_page->ssl_verify_peer_checkbtn = ssl_verify_peer_checkbtn;
+ prefs_page->ssl_verify_peer = ssl_verify_peer;
}
static void destroy_rssyl_prefs_page(PrefsPage *page)
@@ -172,23 +197,25 @@ static void destroy_rssyl_prefs_page(PrefsPage *page)
static void save_rssyl_prefs(PrefsPage *page)
{
- RSSylPrefsPage *prefs_page = (RSSylPrefsPage *)page;
+ RPrefsPage *prefs_page = (RPrefsPage *)page;
PrefFile *pref_file;
gchar *rc_file_path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
COMMON_RC, NULL);
+ /* Grab values from GTK widgets */
+ rssyl_prefs.refresh_enabled = gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(prefs_page->refresh_enabled));
rssyl_prefs.refresh = gtk_spin_button_get_value_as_int(
GTK_SPIN_BUTTON(prefs_page->refresh));
- rssyl_prefs.expired = gtk_spin_button_get_value_as_int(
- GTK_SPIN_BUTTON(prefs_page->expired));
rssyl_prefs.refresh_on_startup = gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(prefs_page->refresh_on_startup));
g_free(rssyl_prefs.cookies_path);
rssyl_prefs.cookies_path = g_strdup(gtk_entry_get_text(
- GTK_ENTRY(prefs_page->cookies_path)));
+ GTK_ENTRY(prefs_page->cookies_path)));
rssyl_prefs.ssl_verify_peer = gtk_toggle_button_get_active(
- GTK_TOGGLE_BUTTON(prefs_page->ssl_verify_peer_checkbtn));
+ GTK_TOGGLE_BUTTON(prefs_page->ssl_verify_peer));
+ /* Store prefs in rc file */
pref_file = prefs_write_open(rc_file_path);
g_free(rc_file_path);
@@ -201,14 +228,56 @@ static void save_rssyl_prefs(PrefsPage *page)
return;
}
- if (fprintf(pref_file->fp, "\n") < 0) {
- FILE_OP_ERROR(rc_file_path, "fprintf");
- prefs_file_close_revert(pref_file);
- } else
- prefs_file_close(pref_file);
+ fprintf(pref_file->fp, "\n");
+ prefs_file_close(pref_file);
+
+ rssyl_apply_prefs();
}
-RSSylPrefs *rssyl_prefs_get(void)
+RPrefs *rssyl_prefs_get(void)
{
return &rssyl_prefs;
}
+
+static void rssyl_start_default_refresh_timeouts_func(FolderItem *item,
+ gpointer data)
+{
+ RFolderItem *ritem = (RFolderItem *)item;
+ guint prefs_interval = GPOINTER_TO_UINT(data);
+
+ if( !IS_RSSYL_FOLDER_ITEM(item) )
+ return;
+
+ if( folder_item_parent(item) == NULL || ritem->url == NULL )
+ return;
+
+ /* Feeds which use default refresh interval */
+ if( ritem->default_refresh_interval ) {
+ /* Start a new timer if the default value has changed
+ * (ritem->refresh_interval should contain previous default
+ * value in this case). */
+ if( ritem->refresh_interval != prefs_interval ) {
+ ritem->refresh_interval = prefs_interval;
+ rssyl_feed_start_refresh_timeout(ritem);
+ }
+ }
+}
+
+static void rssyl_start_default_refresh_timeouts(void)
+{
+ RPrefs *rsprefs = rssyl_prefs_get();
+
+ folder_func_to_all_folders(
+ (FolderItemFunc)rssyl_start_default_refresh_timeouts_func,
+ GUINT_TO_POINTER(rsprefs->refresh));
+}
+
+/* rssyl_apply_prefs():
+ * Do what's needed to start using newly set preferences */
+static void rssyl_apply_prefs(void)
+{
+ /* Update refresh timeouts for feeds which use default interval. */
+ rssyl_start_default_refresh_timeouts();
+
+ /* Nothing else here, so far... */
+}
diff --git a/src/plugins/rssyl/rssyl_prefs.h b/src/plugins/rssyl/rssyl_prefs.h
index 15248ce..51325f6 100644
--- a/src/plugins/rssyl/rssyl_prefs.h
+++ b/src/plugins/rssyl/rssyl_prefs.h
@@ -3,34 +3,31 @@
#define PREFS_BLOCK_NAME "rssyl"
-#define RSSYL_NUM_PREFS 4
+#define PREF_DEFAULT_REFRESH "180"
-#define RSSYL_PREF_DEFAULT_REFRESH "180"
-#define RSSYL_PREF_DEFAULT_EXPIRED "-1"
+typedef struct _RPrefs RPrefs;
-typedef struct _RSSylPrefs RSSylPrefs;
-
-struct _RSSylPrefs {
+struct _RPrefs {
+ gboolean refresh_enabled;
gint refresh;
- gint expired;
gboolean refresh_on_startup;
gchar *cookies_path;
gboolean ssl_verify_peer;
};
-typedef struct _RSSylPrefsPage RSSylPrefsPage;
+typedef struct _RPrefsPage RPrefsPage;
-struct _RSSylPrefsPage {
+struct _RPrefsPage {
PrefsPage page;
+ GtkWidget *refresh_enabled;
GtkWidget *refresh;
- GtkWidget *expired;
GtkWidget *refresh_on_startup;
GtkWidget *cookies_path;
- GtkWidget *ssl_verify_peer_checkbtn;
+ GtkWidget *ssl_verify_peer;
};
void rssyl_prefs_init(void);
void rssyl_prefs_done(void);
-RSSylPrefs *rssyl_prefs_get(void);
+RPrefs *rssyl_prefs_get(void);
#endif /* __RSSYL_PREFS */
diff --git a/src/plugins/rssyl/rssyl_subscribe.c b/src/plugins/rssyl/rssyl_subscribe.c
new file mode 100644
index 0000000..3bdbc73
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_subscribe.c
@@ -0,0 +1,151 @@
+/*
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
+ *
+ * - DESCRIPTION HERE
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Global includes */
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+/* Claws Mail includes */
+#include <alertpanel.h>
+#include <folder.h>
+#include <log.h>
+#include <common/utils.h>
+
+/* Local includes */
+#include "libfeed/feed.h"
+#include "libfeed/feeditem.h"
+#include "rssyl.h"
+#include "rssyl_add_item.h"
+#include "rssyl_feed.h"
+#include "rssyl_update_feed.h"
+#include "rssyl_subscribe_gtk.h"
+#include "strutils.h"
+
+static void rssyl_subscribe_foreach_func(gpointer data, gpointer user_data)
+{
+ RFolderItem *ritem = (RFolderItem *)user_data;
+ FeedItem *feed_item = (FeedItem *)data;
+
+ g_return_if_fail(ritem != NULL);
+ g_return_if_fail(feed_item != NULL);
+
+ rssyl_add_item(ritem, feed_item);
+}
+
+gboolean rssyl_subscribe(FolderItem *parent, const gchar *url,
+ gboolean verbose)
+{
+ gchar *myurl = NULL, *tmpname = NULL, *tmpname2 = NULL;
+ RFetchCtx *ctx;
+ FolderItem *new_item;
+ RFolderItem *ritem;
+ gint i = 1;
+ RSubCtx *sctx;
+
+ g_return_val_if_fail(parent != NULL, FALSE);
+ g_return_val_if_fail(url != NULL, FALSE);
+
+ log_print(LOG_PROTOCOL, RSSYL_LOG_SUBSCRIBING, url);
+
+ myurl = my_normalize_url(url);
+
+ /* Fetch the feed. */
+ ctx = rssyl_prep_fetchctx_from_url(myurl);
+ g_free(myurl);
+ g_return_val_if_fail(ctx != NULL, FALSE);
+
+ rssyl_fetch_feed(ctx, verbose);
+
+ debug_print("RSSyl: fetch success == %s\n",
+ ctx->success ? "TRUE" : "FALSE");
+
+ if (!ctx->success) {
+ /* User notification was already handled inside rssyl_fetch_feed(),
+ * let's just return quietly. */
+ feed_free(ctx->feed);
+ g_free(ctx->error);
+ g_free(ctx);
+ return FALSE;
+ }
+
+ if (verbose) {
+ sctx = g_new0(RSubCtx, 1);
+ sctx->feed = ctx->feed;
+
+ debug_print("RSSyl: Calling subscribe dialog routine...\n");
+ rssyl_subscribe_dialog(sctx);
+
+ if (sctx->feed == NULL) {
+ debug_print("RSSyl: User cancelled subscribe.\n");
+ g_free(sctx);
+ return FALSE;
+ }
+ }
+
+ /* OK, feed is succesfully fetched and correct, let's add it to CM. */
+
+ /* Create a folder for it. */
+ tmpname = rssyl_format_string(ctx->feed->title, TRUE, TRUE);
+ tmpname2 = g_strdup(tmpname);
+ while (folder_find_child_item_by_name(parent, tmpname2) != 0 && i < 20) {
+ debug_print("RSSyl: Folder '%s' already exists, trying another name\n",
+ tmpname2);
+ g_free(tmpname2);
+ tmpname2 = g_strdup_printf("%s__%d", tmpname, ++i);
+ }
+ /* TODO: handle cases where i reaches 20 */
+
+ folder_item_update_freeze();
+
+ new_item = folder_create_folder(parent, tmpname2);
+ g_free(tmpname);
+ g_free(tmpname2);
+
+ if (!new_item) {
+ if (verbose)
+ alertpanel_error(_("Couldn't create folder for new feed '%s'."),
+ myurl);
+ feed_free(ctx->feed);
+ g_free(ctx->error);
+ g_free(ctx);
+ g_free(myurl);
+ return FALSE;
+ }
+
+ debug_print("RSSyl: Adding '%s'\n", ctx->feed->url);
+
+ ritem = (RFolderItem *)new_item;
+ ritem->url = g_strdup(ctx->feed->url);
+
+ if (feed_n_items(ctx->feed) > 0)
+ feed_foreach_item(ctx->feed, rssyl_subscribe_foreach_func, (gpointer)ritem);
+
+ folder_item_scan(new_item);
+ folder_write_list();
+ folder_item_update_thaw();
+
+ return TRUE;
+}
diff --git a/src/plugins/rssyl/rssyl_subscribe.h b/src/plugins/rssyl/rssyl_subscribe.h
new file mode 100644
index 0000000..52b80f9
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_subscribe.h
@@ -0,0 +1,6 @@
+#ifndef __RSSYL_SUBSCRIBE_H
+#define __RSSYL_SUBSCRIBE_H
+
+gboolean rssyl_subscribe(FolderItem *parent, const gchar *url, gboolean verbose);
+
+#endif /* __RSSYL_SUBSCRIBE_H */
diff --git a/src/plugins/rssyl/rssyl_subscribe_gtk.c b/src/plugins/rssyl/rssyl_subscribe_gtk.c
new file mode 100644
index 0000000..3f63440
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_subscribe_gtk.c
@@ -0,0 +1,109 @@
+/*
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ * This file (C) 2005 Andrej Kacian <andrej at kacian.sk>
+ *
+ * - Dialog which appears when manually subscribing a new feed.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Global includes */
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+/* Claws Mail includes */
+#include <mainwindow.h>
+
+/* Local includes */
+#include "libfeed/feed.h"
+#include "rssyl_subscribe_gtk.h"
+
+void rssyl_subscribe_dialog(RSubCtx *ctx) {
+ GtkWidget *win, *vbox, *titleframe, *titlelabel;
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+ GtkTooltips *tooltips;
+#endif
+ gint ret;
+ gchar *newtitle;
+
+ g_return_if_fail(ctx != NULL);
+ g_return_if_fail(ctx->feed != NULL);
+
+ /* Create window */
+ win = gtk_dialog_new_with_buttons(_("Subscribe new feed?"),
+ GTK_WINDOW(mainwindow_get_mainwindow()->window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+ GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_dialog_set_default_response(GTK_DIALOG(win), GTK_RESPONSE_ACCEPT);
+
+ vbox = gtk_dialog_get_content_area(GTK_DIALOG(win));
+
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+ tooltips = gtk_tooltips_new();
+ gtk_tooltips_enable(tooltips);
+#endif
+
+ /* Feed title */
+ titleframe = gtk_frame_new(NULL);
+ gtk_container_set_border_width(GTK_CONTAINER(titleframe), 5);
+ gtk_frame_set_label_align(GTK_FRAME(titleframe), 0.05, 0.5);
+ gtk_frame_set_shadow_type(GTK_FRAME(titleframe), GTK_SHADOW_ETCHED_OUT);
+ gtk_box_pack_start(GTK_BOX(vbox), titleframe, FALSE, FALSE, 0);
+
+ titlelabel = gtk_label_new(_("<b>Feed folder:</b>"));
+ gtk_label_set_use_markup(GTK_LABEL(titlelabel), TRUE);
+ gtk_misc_set_padding(GTK_MISC(titlelabel), 5, 0);
+ gtk_frame_set_label_widget(GTK_FRAME(titleframe), titlelabel);
+
+ ctx->title = gtk_entry_new();
+ gtk_entry_set_text(GTK_ENTRY(ctx->title), feed_get_title(ctx->feed));
+ gtk_entry_set_activates_default(GTK_ENTRY(ctx->title), TRUE);
+#if !(GTK_CHECK_VERSION(2, 12, 0))
+ gtk_tooltips_set_tip(tooltips, ctx->title,
+ _("Instead of using official title, you can enter a different folder "
+ "name for the feed."), NULL);
+#else
+ gtk_widget_set_tooltip_text(ctx->title,
+ _("Instead of using official title, you can enter a different folder "
+ "name for the feed."));
+#endif
+ gtk_container_add(GTK_CONTAINER(titleframe), ctx->title);
+
+ gtk_widget_show_all(vbox);
+
+ ret = gtk_dialog_run(GTK_DIALOG(win));
+
+ if (ret == GTK_RESPONSE_ACCEPT) {
+ /* Modify ctx->feed based on user changes in dialog */
+ newtitle = (gchar *)gtk_entry_get_text(GTK_ENTRY(ctx->title));
+ if (strcmp(feed_get_title(ctx->feed), newtitle)) {
+ debug_print("RSSyl: Using feed title '%s'\n", newtitle);
+ feed_set_title(ctx->feed, newtitle);
+ }
+ } else {
+ /* Destroy the feed to signal outside that user cancelled subscribing */
+ feed_free(ctx->feed);
+ ctx->feed = NULL;
+ }
+
+ gtk_widget_destroy(win);
+}
diff --git a/src/plugins/rssyl/rssyl_subscribe_gtk.h b/src/plugins/rssyl/rssyl_subscribe_gtk.h
new file mode 100644
index 0000000..2d40b13
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_subscribe_gtk.h
@@ -0,0 +1,15 @@
+#ifndef __RSSYL_SUBSCRIBE_GTK_H
+#define __RSSYL_SUBSCRIBE_GTK_H
+
+#include "libfeed/feed.h"
+
+struct _RSubCtx {
+ Feed *feed;
+ GtkWidget *title;
+};
+
+typedef struct _RSubCtx RSubCtx;
+
+void rssyl_subscribe_dialog(RSubCtx *ctx);
+
+#endif /* __RSSYL_SUBSCRIBE_GTK_H */
diff --git a/src/plugins/rssyl/rssyl_update_comments.c b/src/plugins/rssyl/rssyl_update_comments.c
new file mode 100644
index 0000000..c54142d
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_update_comments.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <pthread.h>
+
+/* Claws Mail includes */
+#include <log.h>
+#include <mainwindow.h>
+#include <statusbar.h>
+#include <main.h>
+
+/* Local includes */
+#include "libfeed/feed.h"
+#include "rssyl.h"
+#include "rssyl_feed.h"
+#include "rssyl_parse_feed.h"
+#include "rssyl_update_feed.h"
+#include "parse822.h"
+
+static void rssyl_update_reference_func(gpointer data, gpointer user_data)
+{
+ FeedItem *item = (FeedItem *)data;
+ gchar *parent_id = (gchar *)user_data;
+
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(user_data != NULL);
+
+ feed_item_set_parent_id(item, parent_id);
+}
+
+void rssyl_update_comments(RFolderItem *ritem)
+{
+ FolderItem *item = &ritem->item;
+ FeedItem *fi = NULL;
+ RFetchCtx *ctx = NULL;
+ DIR *dp;
+ struct dirent *d;
+ gint num;
+ gchar *path, *msg, *fname;
+ MainWindow *mainwin = mainwindow_get_mainwindow();
+
+ g_return_if_fail(ritem != NULL);
+
+ if( ritem->fetch_comments == FALSE )
+ return;
+
+ path = folder_item_get_path(item);
+ g_return_if_fail(path != NULL);
+
+ debug_print("RSSyl: starting to parse comments, path is '%s'\n", path);
+
+ if( (dp = opendir(path)) == NULL ) {
+ FILE_OP_ERROR(item->path, "opendir");
+ g_free(path);
+ return;
+ }
+
+ ritem->fetching_comments = TRUE;
+
+ while( (d = readdir(dp)) != NULL ) {
+ if (claws_is_exiting()) {
+ closedir(dp);
+ g_free(path);
+ debug_print("RSSyl: bailing out, app is exiting\n");
+ }
+
+ if( (num = to_number(d->d_name)) > 0 && d->d_type == DT_REG ) {
+ debug_print("RSSyl: starting to parse '%s'\n", d->d_name);
+
+ fname = g_strdup_printf("%s%c%s", path, G_DIR_SEPARATOR, d->d_name);
+ if( (fi = rssyl_parse_folder_item_file(fname)) != NULL ) {
+ if( feed_item_get_comments_url(fi) && feed_item_get_id(fi) &&
+ (ritem->fetch_comments_max_age == -1 ||
+ time(NULL) - feed_item_get_date_modified(fi) <= ritem->fetch_comments_max_age*86400)) {
+ msg = g_strdup_printf(_("Updating comments for '%s'..."),
+ feed_item_get_title(fi));
+ debug_print("RSSyl: updating comments for '%s' (%s)\n",
+ feed_item_get_title(fi), feed_item_get_comments_url(fi));
+ STATUSBAR_PUSH(mainwin, msg);
+
+ ctx = rssyl_prep_fetchctx_from_url(feed_item_get_comments_url(fi));
+ g_return_if_fail(ctx != NULL);
+ feed_set_ssl_verify_peer(ctx->feed, ritem->ssl_verify_peer);
+
+ rssyl_fetch_feed(ctx, FALSE);
+
+ if( ctx->success && feed_n_items(ctx->feed) > 0 ) {
+ g_free(ctx->feed->title);
+ ctx->feed->title = g_strdup(ritem->official_title);
+
+ feed_foreach_item(ctx->feed, rssyl_update_reference_func,
+ feed_item_get_id(fi));
+
+ if( !rssyl_parse_feed(ritem, ctx->feed) ) {
+ debug_print("RSSyl: Error processing comments feed\n");
+ log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_PROC, ctx->feed->url);
+ }
+ }
+ }
+
+ STATUSBAR_POP(mainwin);
+
+ feed_item_free(fi);
+ }
+
+ g_free(fname);
+ }
+ }
+
+ closedir(dp);
+ g_free(path);
+
+ ritem->fetching_comments = FALSE;
+
+ debug_print("RSSyl: rssyl_update_comments() is done\n");
+}
diff --git a/src/plugins/rssyl/rssyl_update_comments.h b/src/plugins/rssyl/rssyl_update_comments.h
new file mode 100644
index 0000000..3ce56e4
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_update_comments.h
@@ -0,0 +1,12 @@
+
+
+#ifndef __RSSYL_UPDATE_COMMENTS
+#define __RSSYL_UPDATE_COMMENTS
+
+#include <glib.h>
+
+#include "rssyl.h"
+
+void rssyl_update_comments(RFolderItem *ritem);
+
+#endif /* __RSSYL_UPDATE_COMMENTS */
diff --git a/src/plugins/rssyl/rssyl_update_feed.c b/src/plugins/rssyl/rssyl_update_feed.c
new file mode 100644
index 0000000..8a97f90
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_update_feed.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <pthread.h>
+
+/* Claws Mail includes */
+#include <common/claws.h>
+#include <mainwindow.h>
+#include <statusbar.h>
+#include <alertpanel.h>
+#include <log.h>
+#include <prefs_common.h>
+#include <inc.h>
+#include <main.h>
+
+/* Local includes */
+#include "libfeed/feed.h"
+#include "rssyl.h"
+#include "rssyl_deleted.h"
+#include "rssyl_feed.h"
+#include "rssyl_parse_feed.h"
+#include "rssyl_prefs.h"
+#include "rssyl_update_comments.h"
+
+/* rssyl_fetch_feed_thr() */
+
+static void *rssyl_fetch_feed_thr(void *arg)
+{
+ RFetchCtx *ctx = (RFetchCtx *)arg;
+
+ /* Fetch and parse the feed. */
+ ctx->response_code = feed_update(ctx->feed, -1);
+
+ /* Signal main thread that we're done here. */
+ ctx->ready = TRUE;
+
+ return NULL;
+}
+
+/* rssyl_fetch_feed() */
+RFetchCtx *rssyl_fetch_feed(RFetchCtx *ctx, gboolean verbose)
+{
+#ifdef USE_PTHREAD
+ pthread_t pt;
+#endif
+
+ g_return_if_fail(ctx != NULL);
+
+#ifdef USE_PTHREAD
+ if( pthread_create(&pt, PTHREAD_CREATE_JOINABLE, rssyl_fetch_feed_thr,
+ (void *)ctx) != 0 ) {
+ /* Bummer, couldn't create thread. Continue non-threaded. */
+ rssyl_fetch_feed_thr(ctx);
+ } else {
+ /* Thread created, let's wait until it finishes. */
+ debug_print("RSSyl: waiting for thread to finish (timeout: %ds)\n",
+ feed_get_timeout(ctx->feed));
+ while( !ctx->ready ) {
+ claws_do_idle();
+ }
+
+ debug_print("RSSyl: thread finished\n");
+ pthread_join(pt, NULL);
+ }
+#else
+ debug_print("RSSyl: no pthreads available, running non-threaded fetch\n");
+ rssyl_fetch_feed_thr(ctx);
+#endif
+
+ if( ctx->response_code == FEED_ERR_INIT ) {
+ debug_print("RSSyl: libfeed reports init error from libcurl\n");
+ ctx->error = g_strdup("Internal error");
+ } else if( ctx->response_code == FEED_ERR_FETCH ) {
+ debug_print("RSSyl: libfeed reports some other error from libcurl\n");
+ ctx->error = g_strdup(ctx->feed->fetcherr);
+ } else if( ctx->response_code >= 400 && ctx->response_code < 500 ) {
+ switch( ctx->response_code ) {
+ case 401:
+ ctx->error = g_strdup(_("401 (Authorisation required)"));
+ break;
+ case 403:
+ ctx->error = g_strdup(_("403 (Unauthorised)"));
+ break;
+ case 404:
+ ctx->error = g_strdup(_("404 (Not found)"));
+ break;
+ default:
+ ctx->error = g_strdup_printf(_("Error %d"), ctx->response_code);
+ break;
+ }
+ }
+
+ /* Here we handle "imperfect" conditions. If verbose is TRUE, we also
+ * display error dialogs for user. We always log the error. */
+ if( ctx->error != NULL ) {
+ /* libcurl wasn't happy */
+ debug_print("RSSyl: Error: %s\n", ctx->error);
+ if( verbose )
+ alertpanel_error(C_("First parameter is URL, second is error text",
+ "Error fetching feed at\n<b>%s</b>:\n\n%s"),
+ feed_get_url(ctx->feed), ctx->error);
+
+ log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_FETCH, ctx->feed->url, ctx->error);
+
+ ctx->success = FALSE;
+ } else {
+ if( ctx->feed == NULL || feed_get_title(ctx->feed) == NULL ) {
+ /* libcurl was happy, but libfeed wasn't */
+ debug_print("RSSyl: Error reading feed\n");
+ if( verbose )
+ alertpanel_error(_("No valid feed found at\n<b>%s</b>"),
+ feed_get_url(ctx->feed));
+ log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_NOFEED, ctx->feed->url);
+ ctx->success = FALSE;
+ }
+ }
+}
+
+RFetchCtx *rssyl_prep_fetchctx_from_item(RFolderItem *ritem)
+{
+ RFetchCtx *ctx = NULL;
+
+ g_return_val_if_fail(ritem != NULL, NULL);
+
+ ctx = g_new0(RFetchCtx, 1);
+ ctx->feed = feed_new(ritem->url);
+ ctx->error = NULL;
+ ctx->success = TRUE;
+ ctx->ready = FALSE;
+
+ feed_set_timeout(ctx->feed, prefs_common.io_timeout_secs);
+ feed_set_cookies_path(ctx->feed, rssyl_prefs_get()->cookies_path);
+ feed_set_ssl_verify_peer(ctx->feed, ritem->ssl_verify_peer);
+
+ return ctx;
+}
+
+RFetchCtx *rssyl_prep_fetchctx_from_url(gchar *url)
+{
+ RFetchCtx *ctx = NULL;
+
+ g_return_val_if_fail(url != NULL, NULL);
+
+ ctx = g_new0(RFetchCtx, 1);
+ ctx->feed = feed_new(url);
+ ctx->error = NULL;
+ ctx->success = TRUE;
+ ctx->ready = FALSE;
+
+ feed_set_timeout(ctx->feed, prefs_common.io_timeout_secs);
+ feed_set_cookies_path(ctx->feed, rssyl_prefs_get()->cookies_path);
+ feed_set_ssl_verify_peer(ctx->feed, rssyl_prefs_get()->ssl_verify_peer);
+
+ return ctx;
+}
+
+/* rssyl_update_feed() */
+
+gboolean rssyl_update_feed(RFolderItem *ritem, gboolean verbose)
+{
+ RFetchCtx *ctx = NULL;
+ MainWindow *mainwin = mainwindow_get_mainwindow();
+ gchar *msg = NULL;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail(ritem != NULL, FALSE);
+ g_return_val_if_fail(ritem->url != NULL, FALSE);
+
+ debug_print("RSSyl: starting to update '%s' (%s)\n",
+ ritem->item.name, ritem->url);
+
+ log_print(LOG_PROTOCOL, RSSYL_LOG_UPDATING, ritem->url);
+
+ msg = g_strdup_printf(_("Updating feed '%s'..."), ritem->item.name);
+ STATUSBAR_PUSH(mainwin, msg);
+ g_free(msg);
+
+ GTK_EVENTS_FLUSH();
+
+ /* Prepare context for fetching the feed file */
+ ctx = rssyl_prep_fetchctx_from_item(ritem);
+ g_return_val_if_fail(ctx != NULL, FALSE);
+
+ /* Fetch the feed file */
+ rssyl_fetch_feed(ctx, verbose);
+
+ debug_print("RSSyl: fetch done; success == %s\n",
+ ctx->success ? "TRUE" : "FALSE");
+
+ debug_print("RSSyl: STARTING TO PARSE FEED\n");
+ if( ctx->success && !(ctx->success = rssyl_parse_feed(ritem, ctx->feed)) ) {
+ /* both libcurl and libfeed were happy, but we weren't */
+ debug_print("RSSyl: Error processing feed\n");
+ if( verbose )
+ alertpanel_error(_("Couldn't process feed at\n<b>%s</b>\n\nPlease contact developers, this should not happen."),
+ feed_get_url(ctx->feed));
+
+ log_error(LOG_PROTOCOL, RSSYL_LOG_ERROR_PROC, ctx->feed->url);
+ }
+
+ debug_print("RSSyl: FEED PARSED\n");
+
+ STATUSBAR_POP(mainwin);
+
+ if( claws_is_exiting() ) {
+ feed_free(ctx->feed);
+ g_free(ctx->error);
+ g_free(ctx);
+ return success;
+ }
+
+ if( ritem->fetch_comments )
+ rssyl_update_comments(ritem);
+
+ /* Prune our deleted items list of items which are no longer in
+ * upstream feed. */
+ rssyl_deleted_expire(ritem, ctx->feed);
+
+ /* Clean up. */
+ success = ctx->success;
+ feed_free(ctx->feed);
+ g_free(ctx->error);
+ g_free(ctx);
+
+ return success;
+}
+
+static gboolean rssyl_update_recursively_func(GNode *node, gpointer data)
+{
+ FolderItem *item;
+ RFolderItem *ritem;
+
+ g_return_val_if_fail(node->data != NULL, FALSE);
+
+ item = FOLDER_ITEM(node->data);
+ ritem = (RFolderItem *)item;
+
+ if( ritem->url != NULL ) {
+ debug_print("RSSyl: Updating feed '%s'\n", item->name);
+ rssyl_update_feed(ritem, FALSE);
+ } else
+ debug_print("RSSyl: Updating in folder '%s'\n", item->name);
+
+ return FALSE;
+}
+
+void rssyl_update_recursively(FolderItem *item)
+{
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(item->folder != NULL);
+
+ if( item->folder->klass != rssyl_folder_get_class() )
+ return;
+
+ debug_print("Recursively updating '%s'\n", item->name);
+
+ g_node_traverse(item->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+ rssyl_update_recursively_func, NULL);
+}
+
+void rssyl_update_all_func(FolderItem *item, gpointer data)
+{
+ /* Only try to refresh our feed folders */
+ if( !IS_RSSYL_FOLDER_ITEM(item) )
+ return;
+
+ if( folder_item_parent(item) == NULL )
+ rssyl_update_recursively(item);
+}
+
+void rssyl_update_all_feeds(void)
+{
+ if (prefs_common.work_offline &&
+ !inc_offline_should_override(TRUE,
+ _("Claws Mail needs network access in order to update your feeds.")) ) {
+ return;
+ }
+
+ folder_func_to_all_folders((FolderItemFunc)rssyl_update_all_func, NULL);
+}
diff --git a/src/plugins/rssyl/rssyl_update_feed.h b/src/plugins/rssyl/rssyl_update_feed.h
new file mode 100644
index 0000000..f72d04a
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_update_feed.h
@@ -0,0 +1,19 @@
+#ifndef __RSSYL_UPDATE_FEED
+#define __RSSYL_UPDATE_FEED
+
+#include <glib.h>
+
+#include "rssyl.h"
+
+void rssyl_fetch_feed(RFetchCtx *ctx, gboolean verbose);
+
+RFetchCtx *rssyl_prep_fetchctx_from_url(gchar *url);
+RFetchCtx *rssyl_prep_fetchctx_from_item(RFolderItem *ritem);
+
+gboolean rssyl_update_feed(RFolderItem *ritem, gboolean verbose);
+
+void rssyl_update_recursively(FolderItem *item);
+
+void rssyl_update_all_feeds(void);
+
+#endif /* __RSSYL_UPDATE_FEED */
diff --git a/src/plugins/rssyl/rssyl_update_format.c b/src/plugins/rssyl/rssyl_update_format.c
new file mode 100644
index 0000000..8284450
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_update_format.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2006 Andrej Kacian <andrej at kacian.sk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Global includes */
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+/* Claws Mail includes */
+#include <alertpanel.h>
+#include <log.h>
+#include <mainwindow.h>
+
+/* Local includes */
+#include "old_feeds.h"
+#include "rssyl.h"
+#include "rssyl_feed.h"
+#include "strutils.h"
+
+struct _RUpdateFormatCtx {
+ FolderItem *o_prev;
+ FolderItem *o_parent;
+ FolderItem *n_prev;
+ FolderItem *n_parent;
+ Folder *n_first;
+ GSList *oldfeeds;
+ GSList *oldroots;
+ gboolean reached_first_new;
+};
+
+typedef struct _RUpdateFormatCtx RUpdateFormatCtx;
+
+extern FolderClass rssyl_class;
+
+static void rssyl_update_format_move_contents(FolderItem *olditem,
+ FolderItem *newitem);
+static gchar *_old_rssyl_item_get_path(Folder *folder, FolderItem *item);
+static void _delete_old_roots_func(gpointer data, gpointer user_data);
+
+static void rssyl_update_format_func(FolderItem *item, gpointer data)
+{
+ RFolderItem *ritem;
+ RUpdateFormatCtx *ctx = (RUpdateFormatCtx *)data;
+ Folder *f = NULL;
+ FolderItem *new_item = NULL;
+ gchar *name;
+ OldRFeed *of;
+
+ if( !IS_RSSYL_FOLDER_ITEM(item) )
+ return;
+
+ /* Do not do anything once we reached first new folder
+ * (which we created earlier in this process) */
+ if( ctx->reached_first_new )
+ return;
+
+ if( item->folder == ctx->n_first ) {
+ ctx->reached_first_new = TRUE;
+ debug_print("RSSyl: (FORMAT) reached first new folder\n");
+ return;
+ }
+
+ debug_print("RSSyl: (FORMAT) item '%s'\n", item->name);
+
+ if( folder_item_parent(item) == NULL ) {
+ /* Root rssyl folder */
+ ctx->oldroots = g_slist_prepend(ctx->oldroots, item);
+
+ /* Create its counterpart */
+ name = rssyl_strreplace(folder_item_get_name(item), " (RSSyl)", "");
+ debug_print("RSSyl: (FORMAT) adding new root folder '%s'\n", name);
+ f = folder_new(rssyl_folder_get_class(), name, NULL);
+ g_free(name);
+ g_return_if_fail(f != NULL);
+ folder_add(f);
+
+ folder_write_list();
+
+ new_item = FOLDER_ITEM(f->node->data);
+
+ /* If user has more than one old rssyl foldertrees, keep the n_first
+ * pointer at the beginning of first one. */
+ if (ctx->n_first == NULL)
+ ctx->n_first = f;
+
+ ctx->n_parent = new_item;
+ } else {
+ /* Non-root folder */
+
+ if (folder_item_parent(item) == ctx->o_prev) {
+ /* We went one step deeper in folder hierarchy, adjust pointers
+ * to parents */
+ ctx->o_parent = ctx->o_prev;
+ ctx->n_parent = ctx->n_prev;
+ } else if (folder_item_parent(item) != ctx->o_parent) {
+ /* We are not in same folder anymore, which can only mean we have
+ * moved up in the hierarchy. Find a correct parent */
+ while (folder_item_parent(item) != ctx->o_parent) {
+ ctx->o_parent = folder_item_parent(ctx->o_parent);
+ ctx->n_parent = folder_item_parent(ctx->n_parent);
+ if (ctx->o_parent == NULL) {
+ /* This shouldn't happen, unless we are magically moved to a
+ * completely different folder structure */
+ debug_print("RSSyl: MISHAP WHILE UPGRADING STORAGE FORMAT: couldn't find folder parent\n");
+ alertpanel_error(_("Internal problem while upgrading storage format. This should not happen. Please report this, with debug output attached.\n"));
+ return;
+ }
+ }
+ } else {
+ /* We have remained in the same subfolder, nothing to do here */
+ }
+
+ debug_print("RSSyl: (FORMAT) adding folder '%s'\n", item->name);
+ new_item = folder_create_folder(ctx->n_parent, item->name);
+
+ if (new_item == NULL) {
+ debug_print("RSSyl: (FORMAT) couldn't add folder '%s', skipping it\n",
+ item->name);
+ return;
+ }
+
+ of = rssyl_old_feed_get_by_name(ctx->oldfeeds, item->name);
+ if (of != NULL && of->url != NULL) {
+ /* Folder with an actual subscribed feed */
+ debug_print("RSSyl: (FORMAT) making '%s' a feed with URL '%s'\n",
+ item->name, of->url);
+
+ ritem = (RFolderItem *)new_item;
+ ritem->url = g_strdup(of->url);
+
+ rssyl_feed_start_refresh_timeout(ritem);
+
+ /* TODO: copy feed preferences from old structure */
+ ritem->official_title = g_strdup(of->official_name);
+ ritem->default_refresh_interval =
+ (of->default_refresh_interval != 0 ? TRUE : FALSE);
+ ritem->refresh_interval = of->refresh_interval;
+ ritem->keep_old = (of->expired_num > -1 ? TRUE : FALSE);
+ ritem->fetch_comments =
+ (of->fetch_comments != 0 ? TRUE : FALSE);
+ ritem->fetch_comments_max_age = of->fetch_comments_for;
+ ritem->silent_update = of->silent_update;
+ }
+
+ rssyl_update_format_move_contents(item, new_item);
+
+ /* Store folderlist with the new folder */
+ folder_item_scan(new_item);
+ folder_write_list();
+ }
+
+ ctx->o_prev = item;
+ ctx->n_prev = new_item;
+}
+
+
+void rssyl_update_format()
+{
+ RUpdateFormatCtx *ctx = NULL;
+ GSList *oldfeeds;
+ gchar *old_feeds_xml = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+ RSSYL_DIR, G_DIR_SEPARATOR_S, "feeds.xml", NULL);
+
+ if (!g_file_test(old_feeds_xml,
+ G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+ g_free(old_feeds_xml);
+ return;
+ }
+
+ debug_print("RSSyl: Old format found, updating.\n");
+
+ oldfeeds = rssyl_old_feed_metadata_parse(old_feeds_xml);
+
+ /* We find all rssyl root folders and perform magic on each */
+ ctx = g_new0(RUpdateFormatCtx, 1);
+ ctx->o_prev = NULL;
+ ctx->o_parent = NULL;
+ ctx->n_prev = NULL;
+ ctx->n_parent = NULL;
+ ctx->n_first = NULL;
+ ctx->oldfeeds = oldfeeds;
+ ctx->oldroots = NULL;
+ ctx->reached_first_new = FALSE;
+
+ folder_item_update_freeze();
+
+ /* Go through all RSSyl folders, making new copies */
+ folder_func_to_all_folders((FolderItemFunc)rssyl_update_format_func, ctx);
+
+ g_slist_foreach(ctx->oldroots, _delete_old_roots_func, NULL);
+ g_slist_free(ctx->oldroots);
+
+ folder_item_update_thaw();
+
+ g_free(ctx);
+
+ g_remove(old_feeds_xml);
+ g_free(old_feeds_xml);
+}
+
+static void _delete_old_roots_func(gpointer data, gpointer user_data)
+{
+ FolderItem *item = (FolderItem *)data;
+
+ folder_destroy(item->folder);
+}
+
+/* Copy each item in a feed to the new directory */
+static void rssyl_update_format_move_contents(FolderItem *olditem,
+ FolderItem *newitem)
+{
+ gchar *oldpath, *newpath, *fname, *fpath, *nfpath;
+ GDir *d = NULL;
+ GError *error = NULL;
+
+ oldpath = _old_rssyl_item_get_path(NULL, olditem);
+ newpath = folder_item_get_path(newitem);
+
+ if ((d = g_dir_open(oldpath, 0, &error)) == NULL) {
+ debug_print("RSSyl: (FORMAT) couldn't open dir '%s': %s\n", oldpath,
+ error->message);
+ g_error_free(error);
+ return;
+ }
+
+ debug_print("RSSyl: (FORMAT) moving contents of '%s' to '%s'\n",
+ oldpath, newpath);
+
+ while ((fname = (gchar *)g_dir_read_name(d)) != NULL) {
+ fpath = g_strconcat(oldpath, G_DIR_SEPARATOR_S, fname, NULL);
+ if (to_number(fname) > 0 && g_file_test(fpath, G_FILE_TEST_IS_REGULAR)) {
+ nfpath = g_strconcat(newpath, G_DIR_SEPARATOR_S, fname, NULL);
+ move_file(fpath, nfpath, FALSE);
+ g_free(nfpath);
+ }
+ g_remove(fpath);
+ g_free(fpath);
+ }
+
+ g_dir_close(d);
+ g_rmdir(oldpath);
+
+ g_free(oldpath);
+ g_free(newpath);
+}
+
+static gchar *_old_rssyl_item_get_path(Folder *folder, FolderItem *item)
+{
+ gchar *result, *tmp;
+
+ if (folder_item_parent(item) == NULL)
+ return g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR, NULL);
+
+ tmp = rssyl_strreplace(item->name, "/", "\\");
+ result = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, RSSYL_DIR,
+ G_DIR_SEPARATOR_S, tmp, NULL);
+ g_free(tmp);
+ return result;
+}
diff --git a/src/plugins/rssyl/rssyl_update_format.h b/src/plugins/rssyl/rssyl_update_format.h
new file mode 100644
index 0000000..7e3a858
--- /dev/null
+++ b/src/plugins/rssyl/rssyl_update_format.h
@@ -0,0 +1,6 @@
+#ifndef __RSSYL_UPDATE_FORMAT
+#define __RSSYL_UPDATE_FORMAT
+
+void rssyl_update_format();
+
+#endif /* __RSSYL_UPDATE_FORMAT */
diff --git a/src/plugins/rssyl/strreplace.c b/src/plugins/rssyl/strreplace.c
deleted file mode 100644
index 7d4322c..0000000
--- a/src/plugins/rssyl/strreplace.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2005 Andrej Kacian <andrej at kacian.sk>
- *
- * - a strreplace function (something like sed's s/foo/bar/g)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <glib.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-#include "common/utils.h"
-
-gchar *rssyl_strreplace(const gchar *source, gchar *pattern,
- gchar *replacement)
-{
- gchar *new, *w_new;
- const gchar *c;
- guint count = 0, final_length;
- size_t len_pattern, len_replacement;
-
-/*
- debug_print("RSSyl: ======= strreplace: '%s': '%s'->'%s'\n", source, pattern,
- replacement);
-*/
-
- if( source == NULL || pattern == NULL ) {
- debug_print("RSSyl: source or pattern is NULL!!!\n");
- return NULL;
- }
-
- if( !g_utf8_validate(source, -1, NULL) ) {
- debug_print("RSSyl: source is not an UTF-8 encoded text\n");
- return NULL;
- }
-
- if( !g_utf8_validate(pattern, -1, NULL) ) {
- debug_print("RSSyl: pattern is not an UTF-8 encoded text\n");
- return NULL;
- }
-
- len_pattern = strlen(pattern);
- len_replacement = strlen(replacement);
-
- c = source;
- while( ( c = g_strstr_len(c, strlen(c), pattern) ) ) {
- count++;
- c += len_pattern;
- }
-
-/*
- debug_print("RSSyl: ==== count = %d\n", count);
-*/
-
- final_length = strlen(source)
- - ( count * len_pattern )
- + ( count * len_replacement );
-
- new = malloc(final_length + 1);
- w_new = new;
- memset(new, '\0', final_length + 1);
-
- c = source;
-
- while( *c != '\0' ) {
- if( !memcmp(c, pattern, len_pattern) ) {
- gboolean break_after_rep = FALSE;
- int i;
- if (*(c + len_pattern) == '\0')
- break_after_rep = TRUE;
- for (i = 0; i < len_replacement; i++) {
- *w_new = replacement[i];
- w_new++;
- }
- if (break_after_rep)
- break;
- c = c + len_pattern;
- } else {
- *w_new = *c;
- w_new++;
- c++;
- }
- }
- return new;
-}
-
-gchar *rssyl_sanitize_string(const gchar *str, gboolean strip_nl)
-{
- gchar *new = NULL;
- const gchar *c = str;
- gchar *new_ptr;
- if( str == NULL )
- return NULL;
-
- new_ptr = new = malloc(strlen(str) + 1);
- if (new == NULL)
- return NULL;
- memset(new, '\0', strlen(str) + 1);
-
- while( *c != '\0' ) {
- if( !g_ascii_isspace(*c) || *c == ' ' || (!strip_nl && *c == '\n') ) {
- *new_ptr = *c;
- new_ptr++;
- }
- c++;
- }
-
- return new;
-}
diff --git a/src/plugins/rssyl/strreplace.h b/src/plugins/rssyl/strreplace.h
deleted file mode 100644
index 37c29dc..0000000
--- a/src/plugins/rssyl/strreplace.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __STRREPLACE_H
-#define __STRREPLACE_H
-
-gchar *rssyl_strreplace(const gchar *source, gchar *pattern,
- gchar *replacement);
-gchar *rssyl_sanitize_string(const gchar *str, gboolean strip_nl);
-
-#endif /* __STRREPLACE_H */
diff --git a/src/plugins/rssyl/strutils.c b/src/plugins/rssyl/strutils.c
new file mode 100644
index 0000000..3d9f1c5
--- /dev/null
+++ b/src/plugins/rssyl/strutils.c
@@ -0,0 +1,289 @@
+/*
+ * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2005 Andrej Kacian <andrej at kacian.sk>
+ *
+ * - a strreplace function (something like sed's s/foo/bar/g)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Global includes */
+#include <glib.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+/* Claws Mail includes */
+#include <common/utils.h>
+
+/* Local includes */
+/* (shouldn't be any) */
+
+gchar *rssyl_strreplace(gchar *source, gchar *pattern,
+ gchar *replacement)
+{
+ gchar *new, *w_new = NULL, *c;
+ guint count = 0, final_length;
+ size_t len_pattern, len_replacement;
+
+ /*
+ debug_print("RSSyl: ======= strreplace: '%s': '%s'->'%s'\n", source, pattern,
+ replacement);
+ */
+
+ if( source == NULL || pattern == NULL ) {
+ debug_print("RSSyl: source or pattern is NULL!!!\n");
+ return source;
+ }
+
+ if( !g_utf8_validate(source, -1, NULL) ) {
+ debug_print("RSSyl: source is not an UTF-8 encoded text\n");
+ return source;
+ }
+
+ if( !g_utf8_validate(pattern, -1, NULL) ) {
+ debug_print("RSSyl: pattern is not an UTF-8 encoded text\n");
+ return source;
+ }
+
+ len_pattern = strlen(pattern);
+ len_replacement = strlen(replacement);
+
+ c = source;
+ while( ( c = g_strstr_len(c, strlen(c), pattern) ) ) {
+ count++;
+ c += len_pattern;
+ }
+
+ /*
+ debug_print("RSSyl: ==== count = %d\n", count);
+ */
+
+ final_length = strlen(source)
+ - ( count * len_pattern )
+ + ( count * len_replacement );
+
+ new = malloc(final_length + 1);
+ w_new = new;
+ memset(new, '\0', final_length + 1);
+
+ c = source;
+
+ while( *c != '\0' ) {
+ if( !memcmp(c, pattern, len_pattern) ) {
+ gboolean break_after_rep = FALSE;
+ int i;
+ if (*(c + len_pattern) == '\0')
+ break_after_rep = TRUE;
+ for (i = 0; i < len_replacement; i++) {
+ *w_new = replacement[i];
+ w_new++;
+ }
+ if (break_after_rep)
+ break;
+ c = c + len_pattern;
+ } else {
+ *w_new = *c;
+ w_new++;
+ c++;
+ }
+ }
+ return new;
+}
+
+typedef struct _RSSyl_HTMLSymbol RSSyl_HTMLSymbol;
+struct _RSSyl_HTMLSymbol
+{
+ gchar *const key;
+ gchar *const val;
+};
+
+static RSSyl_HTMLSymbol symbol_list[] = {
+ { "<", "<" },
+ { ">", ">" },
+ { "&", "&" },
+ { """, "\"" },
+ { "‘", "'" },
+ { "’", "'" },
+ { "“", "\"" },
+ { "”", "\"" },
+ { " ", " " },
+ { "™", "(TM)" },
+ { "", "(TM)" },
+ { "'", "'" },
+ { "…", "..." },
+ { "…", "..." },
+ { "—", "-" },
+ { NULL, NULL }
+};
+
+static RSSyl_HTMLSymbol tag_list[] = {
+ { "<cite>", "\"" },
+ { "</cite>", "\"" },
+ { "<i>", "" },
+ { "</i>", "" },
+ { "<em>", "" },
+ { "</em>", "" },
+ { "<b>", "" },
+ { "</b>", "" },
+ { "<nobr>", "" },
+ { "</nobr>", "" },
+ { "<wbr>", "" },
+ { NULL, NULL }
+};
+
+gchar *rssyl_replace_html_stuff(gchar *text,
+ gboolean symbols, gboolean tags)
+{
+ gchar *tmp = NULL, *wtext = NULL;
+ gint i;
+
+ g_return_val_if_fail(text != NULL, NULL);
+
+ wtext = g_strdup(text);
+
+ /* Ugly, needlessly traverses the string again and again. Probably
+ * could use a rewrite. */
+ if( symbols ) {
+ for( i = 0; symbol_list[i].key != NULL; i++ ) {
+ if( g_strstr_len(text, strlen(text), symbol_list[i].key) ) {
+ tmp = rssyl_strreplace(wtext, symbol_list[i].key, symbol_list[i].val);
+ wtext = g_strdup(tmp);
+ g_free(tmp);
+ }
+ }
+ }
+
+ if( tags ) {
+ for( i = 0; tag_list[i].key != NULL; i++ ) {
+ if( g_strstr_len(text, strlen(text), symbol_list[i].key) ) {
+ tmp = rssyl_strreplace(wtext, tag_list[i].key, tag_list[i].val);
+ wtext = g_strdup(tmp);
+ g_free(tmp);
+ }
+ }
+ }
+
+ return wtext;
+}
+
+static gchar *rssyl_sanitize_string(gchar *str, gboolean strip_nl)
+{
+ gchar *new = NULL, *c = str, *n = NULL;
+
+ if( str == NULL )
+ return NULL;
+
+ n = new = malloc(strlen(str) + 1);
+ memset(new, '\0', strlen(str) + 1);
+
+ while( *c != '\0' ) {
+ if( !isspace(*c) || *c == ' ' || (!strip_nl && *c == '\n') ) {
+ *n = *c;
+ n++;
+ }
+ c++;
+ }
+
+ return new;
+}
+
+/* rssyl_format_string()
+ * - return value needs to be freed
+ */
+gchar *rssyl_format_string(gchar *str, gboolean replace_html,
+ gboolean strip_nl)
+{
+ gchar *res = NULL, *tmp = NULL;
+
+ g_return_val_if_fail(str != NULL, NULL);
+
+ if (replace_html)
+ tmp = rssyl_replace_html_stuff(str, TRUE, TRUE);
+ else
+ tmp = g_strdup(str);
+
+ res = rssyl_sanitize_string(tmp, strip_nl);
+ g_free(tmp);
+
+ g_strstrip(res);
+
+ return res;
+}
+
+/* this functions splits a string into an array of string, by
+ * returning an array of pointers to positions of the delimiter
+ * in the original string and replacing this delimiter with a
+ * NULL. It does not duplicate memory, hence you should only
+ * free the array and not its elements, and you should not
+ * free the original string before you're done with the array.
+ * maybe could be part of the core (utils.c).
+ */
+gchar **strsplit_no_copy(gchar *str, char delimiter)
+{
+ gchar **array = g_new(gchar *, 1);
+ int i = 0;
+ gchar *cur = str, *next;
+
+ array[i] = cur;
+ i++;
+ while ((next = strchr(cur, delimiter)) != NULL) {
+ *(next) = '\0';
+ array = g_realloc(array, (sizeof(gchar *)) * (i + 1));
+ array[i] = next + 1;
+ cur = next + 1;
+ i++;
+ }
+ array = g_realloc(array, (sizeof(gchar *)) * (i + 1));
+ array[i] = NULL;
+ return array;
+}
+
+/* This is a very dumb function - it just strips <, > and everything between
+ * them. */
+void strip_html(gchar *str)
+{
+ gchar *p = str;
+ gboolean intag = FALSE;
+
+ while (*p) {
+ if (*p == '<')
+ intag = TRUE;
+ else if (*p == '>')
+ intag = FALSE;
+
+ if (*p == '<' || *p == '>' || intag)
+ memmove(p, p + 1, strlen(p));
+ else
+ p++;
+ }
+}
+
+gchar *my_normalize_url(const gchar *url)
+{
+ gchar *myurl = NULL;
+
+ if (!strncmp(url, "feed://", 7))
+ myurl = g_strdup(url+7);
+ else if (!strncmp(url, "feed:", 5))
+ myurl = g_strdup(url+5);
+ else
+ myurl = g_strdup(url);
+
+ return myurl;
+}
diff --git a/src/plugins/rssyl/strutils.h b/src/plugins/rssyl/strutils.h
new file mode 100644
index 0000000..2976e6f
--- /dev/null
+++ b/src/plugins/rssyl/strutils.h
@@ -0,0 +1,19 @@
+#ifndef __STRUTILS_H
+#define __STRUTILS_H
+
+gchar *rssyl_strreplace(gchar *source, gchar *pattern,
+ gchar *replacement);
+
+gchar *rssyl_replace_html_stuff(gchar *text,
+ gboolean symbols, gboolean tags);
+
+gchar *rssyl_format_string(gchar *str, gboolean replace_html,
+ gboolean strip_nl);
+
+gchar **strsplit_no_copy(gchar *str, char delimiter);
+
+void strip_html(gchar *str);
+
+gchar *my_normalize_url(const gchar *url);
+
+#endif /* __STRUTILS_H */
-----------------------------------------------------------------------
hooks/post-receive
--
Claws Mail
More information about the Commits
mailing list