Commit 51b13899 authored by Lucian Langa's avatar Lucian Langa
Browse files

correctly parse atom description construct (deb bug #528827)

parent 7c560f56
2009-05-25 Lucian Langa <lucilanga@gnome.org>
* src/fetch.c (fetch_unblocking): sanitize url before fetching (strip
whitespace)
* src/file-gio.c (gio_finish_feed): correctly handle errors
when fetching files
* src/parser.c (layer_find_tag), (parse_channel_line): correctly parse
atom description construct (debian bug #528827)
* src/rss-config-factory.c (build_dialog_add), (feeds_dialog_add),
(delete_response): correctly escape markup text
* src/rss-html-rendering.glade: add cookie import option
* src/rss.c (browser_write), (mycall), (gecko_click),
(finish_feed), (generic_finish_feed), (finish_website),
(update_feed_image), (rss_delete_feed), (store_folder_deleted):
2009-05-18 Lucian Langa <lucilanga@gnome.org>
* src/rss-config-factory.c (feeds_dialog_disable),
......
......@@ -58,3 +58,7 @@
* display links from content in status bar
* grey out disabled folders (feeds)
* feed check runtime validation
* wrong send and receive count of articles after import
* handle 404 for images in comments
* possibly prefer content:encoded (CDATA) over description on certiain atom feeds
* gtkhtml does not handle script properly
......@@ -241,6 +241,20 @@
</long>
</locale>
</schema>
<schema>
<key>/schemas/apps/evolution/evolution-rss/show_comments</key>
<applyto>/apps/evolution/evolution-rss/show_comments</applyto>
<owner>evolution-rss</owner>
<type>bool</type>
<default>true</default>
<locale name="C">
<short>Show articles comments</short>
<long>
It will display article's comments by default if present.
</long>
</locale>
</schema>
<schema>
<key>/schemas/apps/evolution/evolution-rss/use_proxy</key>
......
......@@ -27,6 +27,7 @@
#include "file-gio.h"
#include "network-soup.h"
#include "fetch.h"
#define d(x)
GString*
fetch_blocking(gchar *url, GSList *headers, GString *post,
......@@ -73,7 +74,11 @@ fetch_unblocking(gchar *url, NetStatusCallback cb, gpointer data,
GError **err)
{
gchar *scheme = NULL;
scheme = g_uri_parse_scheme(url);
scheme = g_uri_parse_scheme(g_strstrip(url));
d(g_print("scheme:%s=>url:%s\n", scheme, url));
if (!scheme)
return FALSE;
if (!g_ascii_strcasecmp(scheme, "file")) {
g_free(scheme);
......
......@@ -55,11 +55,11 @@ gio_finish_feed (GObject *object, GAsyncResult *res, gpointer user_data)
res,
&file_contents, &file_size,
NULL, NULL);
rfmsg->status_code = SOUP_STATUS_OK;
rfmsg->body = file_contents;
rfmsg->length = file_size;
generic_finish_feed(rfmsg, user_data);
if (result) {
if (result) {
rfmsg->status_code = SOUP_STATUS_OK;
rfmsg->body = file_contents;
rfmsg->length = file_size;
generic_finish_feed(rfmsg, user_data);
g_free (file_contents);
}
g_free(rfmsg);
......
......@@ -498,7 +498,6 @@ net_get_unblocking(gchar *url,
soup_session_async_new();
if (rss_soup_jar) {
g_print("juvr\n");
soup_session_add_feature(soup_sess, SOUP_SESSION_FEATURE(rss_soup_jar));
}
proxify_session(proxy, soup_sess, url);
......@@ -703,5 +702,5 @@ abort_all_soup(void)
void
rss_soup_init(void)
{
//rss_soup_jar = soup_cookie_jar_sqlite_new ("/home/cooly/.newcookies.sqlite", FALSE);
rss_soup_jar = soup_cookie_jar_sqlite_new ("/home/cooly/.evolution/mail/rss/rss-cookies.sqlite", FALSE);
}
......@@ -159,8 +159,9 @@ xml_parse_sux (const char *buf, int len)
ctxt->vctxt.warning = my_xml_parser_error_handler;
xmlCtxtUseOptions(ctxt, XML_PARSE_DTDLOAD
| XML_PARSE_NOENT
| XML_PARSE_NOCDATA);
| XML_PARSE_NOENT);
// | XML_PARSE_NOCDATA);
xmlParseDocument (ctxt);
......@@ -490,30 +491,29 @@ layer_find_tag (xmlNodePtr node,
}
}
}
}
if (strcasecmp ((char *)node->name, match)==0) {
if (node->children != NULL) {
if (node->children->type == 1 //XML_NODE_ELEMENT
/* || node->children->type == 3 */ //XML_NODE_TEXT
|| node->children->next != NULL) {
d(g_print("NODE DUMP:%s|\n", xmlNodeGetContent(node->children->next)));
gchar *nodetype = (gchar *)xmlGetProp(node, (xmlChar *)"type");
if (!strcasecmp(nodetype, "xhtml")) { // test this with "html" or smth else
//this looses html entities
len = xmlNodeDump(buf, node->doc, node->children, 0, 0);
content = g_strdup_printf("%s", xmlBufferContent(buf));
xmlBufferFree(buf);
} else
content = (char *)xmlNodeGetContent(node->children);
if (nodetype)
xmlFree(nodetype);
return content;
} else { //in case was not a standard module process node normally
//above case should handle all modules
if (strcasecmp ((char *)node->name, match)==0) {
if (node->type == 1) { //XML_NODE_ELEMENT
gchar *nodetype = (gchar *)xmlGetProp(node, (xmlChar *)"type");
//we need separate xhtml parsing because of xmlNodegetcontent substitutes html entities
if (nodetype && !strcasecmp(nodetype, "xhtml")) { // test this with "html" or smth else
//this looses html entities
len = xmlNodeDump(buf, node->doc, node, 0, 0);
content = g_strdup_printf("%s", xmlBufferContent(buf));
xmlBufferFree(buf);
} else {
content = (char *)xmlNodeGetContent(node);
}
if (nodetype)
xmlFree(nodetype);
return content;
} else {
xmlBufferFree(buf);
return fail;
}
}
}
}
node = node->next;
}
xmlBufferFree(buf);
......@@ -882,11 +882,11 @@ parse_channel_line(xmlNode *top, gchar *feed_name, char *main_date)
}
}
//FIXME this might need xmlFree when namespacing
b = layer_find_tag (top, "description",
layer_find_tag (top, "content",
b = layer_find_tag (top, "content", //we prefer content first <--
layer_find_tag (top, "description", //it seems description is rather shorten version of the content, so |
layer_find_tag (top, "summary",
NULL)));
if (b)
if (b && strlen(b))
b = g_strstrip(b);
else
b = g_strdup(layer_find (top, "description",
......
......@@ -71,6 +71,27 @@ typedef struct {
GtkWidget *check5;
} UIData;
typedef struct _setupfeed {
GladeXML *gui;
GtkWidget *treeview;
GtkWidget *add_feed;
GtkWidget *check1;
GtkWidget *check2;
GtkWidget *check3;
GtkWidget *check4;
GtkWidget *spin;
GtkWidget *use_proxy;
GtkWidget *host_proxy;
GtkWidget *port_proxy;
GtkWidget *proxy_details;
GtkWidget *details;
GtkWidget *import;
GtkWidget *import_fs;
GtkWidget *export_fs;
GtkWidget *export;
GtkWidget *combo_hbox;
} setupfeed;
static void feeds_dialog_edit(GtkDialog *d, gpointer data);
static void
......@@ -374,7 +395,7 @@ build_dialog_add(gchar *url, gchar *feed_text)
GtkWidget *entry2 = (GtkWidget *)glade_xml_get_widget (gui, "entry2");
if (url != NULL) {
flabel = g_strdup_printf("%s: <b>%s</b>", _("Folder"),
flabel = g_markup_printf_escaped("%s: <b>%s</b>", _("Folder"),
lookup_feed_folder(feed_text));
gtk_label_set_text(GTK_LABEL(entry2), flabel);
gtk_label_set_use_markup(GTK_LABEL(entry2), 1);
......@@ -601,15 +622,13 @@ feeds_dialog_add(GtkDialog *d, gpointer data)
gtk_widget_show_all(msg_feeds);
while (gtk_events_pending ())
gtk_main_iteration ();
if (feed->feed_url && strlen(feed->feed_url))
{
if (feed->feed_url && strlen(feed->feed_url)) {
text = feed->feed_url;
feed->feed_url = sanitize_url(feed->feed_url);
g_free(text);
if (g_hash_table_find(rf->hr,
check_if_match,
feed->feed_url))
{
feed->feed_url)) {
rss_error(NULL, NULL, _("Error adding feed."),
_("Feed already exists!"));
goto out;
......@@ -638,7 +657,6 @@ rss_delete_rec (CamelStore *store, CamelFolderInfo *fi, CamelException *ex)
CamelFolder *folder;
d(printf ("deleting folder '%s'\n", fi->full_name));
printf ("deleting folder '%s'\n", fi->full_name);
if (!(folder = camel_store_get_folder (store, fi->full_name, 0, ex)))
return;
......@@ -790,38 +808,12 @@ delete_response(GtkWidget *selector, guint response, gpointer user_data)
GtkTreeModel *model;
GtkTreeIter iter;
gchar *name;
CamelException ex;
if (response == GTK_RESPONSE_OK) {
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(user_data));
if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
gtk_tree_model_get (model, &iter, 3, &name, -1);
if (gconf_client_get_bool(rss_gconf, GCONF_KEY_REMOVE_FOLDER, NULL)) {
//delete folder
CamelStore *store = mail_component_peek_local_store(NULL);
gchar *full_path = g_strdup_printf("%s/%s",
lookup_main_folder(),
lookup_feed_folder(name));
delete_feed_folder_alloc(lookup_feed_folder(name));
camel_exception_init (&ex);
rss_delete_folders (store, full_path, &ex);
if (camel_exception_is_set (&ex)) {
e_error_run(NULL,
"mail:no-delete-folder", full_path, ex.desc, NULL);
camel_exception_clear (&ex);
}
g_free(full_path);
//also remove status file
gchar *url = g_hash_table_lookup(rf->hr,
g_hash_table_lookup(rf->hrname,
name));
gchar *buf = gen_md5(url);
gchar *feed_dir = rss_component_peek_base_directory(mail_component_peek());
gchar *feed_name = g_strdup_printf("%s/%s", feed_dir, buf);
g_free(feed_dir);
g_free(buf);
unlink(feed_name);
}
remove_feed_hash(name);
rss_delete_feed(name,
gconf_client_get_bool(rss_gconf, GCONF_KEY_REMOVE_FOLDER, NULL));
g_free(name);
}
store_redraw(GTK_TREE_VIEW(rf->treeview));
......@@ -1052,8 +1044,7 @@ import_one_feed(gchar *url, gchar *title)
/* we'll get rid of this as soon as we fetch unblocking */
if (g_hash_table_find(rf->hr,
check_if_match,
feed->feed_url))
{
feed->feed_url)) {
rss_error(NULL, feed->feed_name, _("Error adding feed."),
_("Feed already exists!"));
return FALSE;
......@@ -1181,8 +1172,7 @@ import_opml(gchar *file)
while ((src = iterate_import_file(src, &url, &name, type))) {
if (url && strlen(url)) {
g_print("url:%s\n", url);
if (rf->cancel)
{
if (rf->cancel) {
if (src) xmlFree(src);
rf->cancel = 0;
goto out;
......@@ -1210,8 +1200,7 @@ import_opml(gchar *file)
save_gconf_feed();
if (src)
xmlFree(src);
}
else
} else
src = html_find(src, "outline");
}
......@@ -1227,8 +1216,7 @@ select_file_response(GtkWidget *selector, guint response, gpointer user_data)
{
if (response == GTK_RESPONSE_OK) {
char *name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (selector));
if (name)
{
if (name) {
gtk_widget_hide(selector);
import_opml(name);
g_free(name);
......@@ -1988,6 +1976,7 @@ rss_config_control_new (void)
sf->check1 = glade_xml_get_widget(sf->gui, "checkbutton1");
sf->check2 = glade_xml_get_widget(sf->gui, "checkbutton2");
sf->check3 = glade_xml_get_widget(sf->gui, "checkbutton3");
sf->check4 = glade_xml_get_widget(sf->gui, "checkbutton4");
sf->spin = glade_xml_get_widget(sf->gui, "spinbutton1");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sf->check1),
......@@ -2011,6 +2000,12 @@ rss_config_control_new (void)
"clicked",
G_CALLBACK(start_check_cb),
GCONF_KEY_DISPLAY_SUMMARY);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sf->check4),
gconf_client_get_bool(rss_gconf, GCONF_KEY_SHOW_COMMENTS, NULL));
g_signal_connect(sf->check4,
"clicked",
G_CALLBACK(start_check_cb),
GCONF_KEY_SHOW_COMMENTS);
#if (EVOLUTION_VERSION < 21900) // include devel too
......
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--*- mode: xml -*-->
<?xml version="1.0"?>
<glade-interface>
<!-- interface-requires gtk+ 2.16 -->
<!-- interface-naming-policy toplevel-contextual -->
<widget class="GtkWindow" id="window1">
<child>
<widget class="GtkVBox" id="settingsbox">
......@@ -10,7 +10,7 @@
<widget class="GtkFrame" id="html-rendering">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">GTK_SHADOW_NONE</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
......@@ -34,6 +34,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
......@@ -43,6 +44,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
......@@ -50,20 +52,23 @@
<property name="visible">True</property>
<child>
<widget class="GtkCheckButton" id="checkbutton1">
<property name="can_focus">True</property>
<property name="label" translatable="yes">Block pop-up windows</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="enable_java">
<property name="label" translatable="yes">Enable Java</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Enable Java</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
......@@ -72,17 +77,48 @@
</child>
<child>
<widget class="GtkCheckButton" id="enable_js">
<property name="label" translatable="yes">Enable JavaScript</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Enable JavaScript</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox3">
<property name="visible">True</property>
<child>
<widget class="GtkCheckButton" id="checkbutton2">
<property name="label" translatable="yes">Accept cookies from sites</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="button1">
<property name="label" translatable="yes">Import Cookies</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="position">3</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
......@@ -100,6 +136,7 @@
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
......@@ -146,12 +183,15 @@
</packing>
</child>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">GTK_SHADOW_NONE</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
......@@ -161,13 +201,16 @@
<property name="visible">True</property>
<child>
<widget class="GtkCheckButton" id="status_icon">
<property name="label" translatable="yes">Show icon in notification area</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Show icon in notification area</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment3">
......@@ -175,11 +218,11 @@
<property name="xscale">0.80000001192092896</property>
<child>
<widget class="GtkCheckButton" id="blink_icon">
<property name="label" translatable="yes">Blink icon in notification area</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Blink icon in notification area</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
</child>
......@@ -190,11 +233,11 @@
</child>
<child>
<widget class="GtkCheckButton" id="feed_icon">
<property name="label" translatable="yes">Show feed icon</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Show feed icon</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
......
This diff is collapsed.
......@@ -153,7 +153,7 @@ GQueue *status_msg;
gchar *flat_status_msg;
GPtrArray *filter_uids;
static CamelDataCache *http_cache;
static CamelDataCache *http_cache = NULL;
static volatile int org_gnome_rss_controls_counter_id = 0;
......@@ -442,7 +442,7 @@ statuscb(NetStatusType status, gpointer statusdata, gpointer data)
gtk_progress_bar_set_fraction((GtkProgressBar *)rf->progress_bar, fraction);
}
if (rf->sr_feed) {
gchar *furl = g_strdup_printf("<b>%s</b>: %s", _("Feed"), (char *)data);
gchar *furl = g_markup_printf_escaped("<b>%s</b>: %s", _("Feed"), (char *)data);
gtk_label_set_markup (GTK_LABEL (rf->sr_feed), furl);
g_free(furl);
}
......@@ -473,16 +473,19 @@ browser_write(gchar *string, gint length, gchar *base)
switch (engine) {
case 2:
#ifdef HAVE_GECKO
gtk_moz_embed_open_stream(GTK_MOZ_EMBED(rf->mozembed),
base, "text/html");
while (len > 0) {
if (len > 4096) {
gtk_moz_embed_append_data(GTK_MOZ_EMBED(rf->mozembed),
str, 4096);
str+=4096;
} else
gtk_moz_embed_append_data(GTK_MOZ_EMBED(rf->mozembed),
str, len);
len-=4096;
if (len > 4096) {
gtk_moz_embed_append_data(GTK_MOZ_EMBED(rf->mozembed),
str, 4096);
str+=4096;
} else
gtk_moz_embed_append_data(GTK_MOZ_EMBED(rf->mozembed),
str, len);
len-=4096;
}
gtk_moz_embed_close_stream(GTK_MOZ_EMBED(rf->mozembed));
#endif
break;
case 1:
......@@ -1326,13 +1329,8 @@ mycall (GtkWidget *widget, GtkAllocation *event, gpointer data)
if (po->mozembedwindow && rf->mozembed)
if(GTK_IS_WIDGET(po->mozembedwindow) && height > 0)
{
#ifdef HAVE_GECKO
if (engine == 2)
gtk_moz_embed_open_stream(GTK_MOZ_EMBED(rf->mozembed),
po->website, "text/html");
#endif
//browser_write("test", 4);
if (!browser_fetching) {
browser_write("Formatting...", 13, "file:///");
browser_fetching=1;
fetch_unblocking(
po->website,
......@@ -1543,7 +1541,7 @@ gecko_click(GtkMozEmbed *mozembed, gpointer dom_event, gpointer user_data)
if (button == 0)
gtk_moz_embed_load_url(GTK_MOZ_EMBED(rf->mozembed), link);
g_print("button:%d\n", button);
return TRUE;
return FALSE;
}
#endif
......@@ -1750,8 +1748,7 @@ pfree(EMFormatHTMLPObject *o)
}
guint engine = gconf_client_get_int(rss_gconf, GCONF_KEY_HTML_RENDER, NULL);
#ifdef HAVE_GECKO
if (engine == 2)
{
if (engine == 2) {
gtk_moz_embed_stop_load(GTK_MOZ_EMBED(rf->mozembed));
// gtk_moz_embed_pop_startup();
}
......@@ -1977,7 +1974,8 @@ render_body: if (category)
frame_colour & 0xffffff, content_colour & 0xffffff, text_colour & 0xffffff,
buff);
if (comments) {
if (comments &&
gconf_client_get_bool (rss_gconf, GCONF_KEY_SHOW_COMMENTS, NULL)) {
if (commstream) {
camel_stream_printf (fstream,
"<div style=\"border: solid #%06x 0px; background-color: #%06x; padding: 2px; color: #%06x;\">",
......@@ -2613,7 +2611,7 @@ generic_finish_feed(rfMessage *msg, gpointer user_data)
#ifdef EVOLUTION_2_12
if (rf->sr_feed && !deleted) {
gchar *furl = g_strdup_printf("<b>%s</b>: %s", _("Feed"), (gchar *)user_data);
gchar *furl = g_markup_printf_escaped("<b>%s</b>: %s", _("Feed"), (gchar *)user_data);
gtk_label_set_markup (GTK_LABEL (rf->sr_feed), furl);
gtk_label_set_justify(GTK_LABEL (rf->sr_feed), GTK_JUSTIFY_LEFT);