88dc406126d155c4067290b08116486a12aea50d
[claws.git] / src / plugins / rssyl / rssyl_parse_feed.c
1 /*
2  * Copyright (C) 2006 Andrej Kacian <andrej@kacian.sk>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public
15  * License along with this program; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 /* Global includes */
25 #include <glib.h>
26 #include <glib/gi18n.h>
27
28 /* Claws Mail includes */
29 #include <log.h>
30 #include <codeconv.h>
31 #include <main.h>
32 #include <procmsg.h>
33
34 /* Local includes */
35 #include "libfeed/feed.h"
36 #include "libfeed/feeditem.h"
37 #include "libfeed/date.h"
38 #include "parse822.h"
39 #include "rssyl.h"
40 #include "rssyl_add_item.h"
41 #include "rssyl_deleted.h"
42 #include "rssyl_feed.h"
43 #include "rssyl_parse_feed.h"
44 #include "rssyl_prefs.h"
45 #include "strutils.h"
46
47 static void rssyl_foreach_parse_func(gpointer data, gpointer user_data)
48 {
49         FeedItem *feed_item = (FeedItem *)data;
50         RFolderItem *ritem = (RFolderItem *)user_data;
51
52         rssyl_add_item(ritem, feed_item);
53 }
54
55 struct _RSSylExpireItemsCtx {
56         gboolean exists;
57         FeedItem *item;
58 };
59
60 typedef struct _RSSylExpireItemsCtx RSSylExpireItemsCtx;
61
62 static void expire_items_func(gpointer data, gpointer user_data)
63 {
64         RSSylExpireItemsCtx *ctx = (RSSylExpireItemsCtx *)user_data;
65         FeedItem *item = (FeedItem *)data;
66         gchar *id = NULL, *id2 = NULL;
67
68         if( (id = feed_item_get_id(item)) == NULL )
69                 id = feed_item_get_url(item);
70
71         if( id == NULL )
72                 return;
73
74         if( (id2 = feed_item_get_id(ctx->item)) == NULL )
75                 id2 = feed_item_get_url(ctx->item);
76
77         if( id2 == NULL )
78                 return;
79
80         /* Simply check ID, as we should have up-to-date items right now. */
81         if( !strcmp(id, id2) )
82                 ctx->exists = TRUE;
83 }
84
85 static void rssyl_expire_items(RFolderItem *ritem, Feed *feed)
86 {
87         FeedItem *item = NULL;
88         GSList *i = NULL;
89         RSSylExpireItemsCtx *ctx = NULL;
90         RFeedCtx *fctx;
91
92         debug_print("RSSyl: rssyl_expire_items()\n");
93
94         g_return_if_fail(ritem != NULL);
95         g_return_if_fail(ritem->items != NULL);
96         g_return_if_fail(feed != NULL);
97
98         ctx = malloc( sizeof(RSSylExpireItemsCtx) );
99
100         /* Check each locally stored item, if it is still in the upstream
101          * feed - xnay it if not. */
102         for( i = ritem->items; i != NULL; i = i->next ) {
103                 item = (FeedItem *)i->data;
104
105                 /* Do not expire comments, they expire with their parents */
106                 if (feed_item_get_parent_id(item) != NULL)
107                         continue;
108
109                 ctx->exists = FALSE;
110                 ctx->item = item;
111                 feed_foreach_item(feed, expire_items_func, ctx);
112
113                 if( !ctx->exists ) {
114                         fctx = (RFeedCtx *)item->data;
115                         /* TODO: expire item's comments (items with our parent_id) */
116                         g_remove(fctx->path);
117                 }
118         }
119
120         g_free(ctx);
121 }
122
123 /* -------------------------------------------------------------------------
124  * rssyl_parse_feed() */
125
126 gboolean rssyl_parse_feed(RFolderItem *ritem, Feed *feed)
127 {
128         gchar *tmp = NULL, *tmp2 = NULL;
129         gint i = 1;
130
131         g_return_val_if_fail(ritem != NULL, FALSE);
132         g_return_val_if_fail(feed != NULL, FALSE);
133         g_return_val_if_fail(feed->title != NULL, FALSE);
134
135         debug_print("RSSyl: parse_feed\n");
136
137         /* Set the last_update timestamp here, so it is the same for all items */
138         ritem->last_update = time(NULL);
139
140         /* If the upstream feed changed its title, change name of our folder
141          * accordingly even if user has renamed it before. This makes sure that
142          * user will be aware of the upstream title change. */
143         if( !ritem->ignore_title_rename &&
144                         (ritem->official_title == NULL ||
145                         strcmp(feed->title, ritem->official_title)) ) {
146                 g_free(ritem->official_title);
147                 ritem->official_title = g_strdup(feed->title);
148
149                 tmp = rssyl_format_string(feed->title, TRUE, TRUE);
150
151                 tmp2 = g_strdup(tmp);
152                 while (folder_item_rename(&ritem->item, tmp2) != 0 && i < 20) {
153                         g_free(tmp2);
154                         tmp2 = g_strdup_printf("%s__%d", tmp, ++i);
155                         debug_print("RSSyl: couldn't rename, trying '%s'\n", tmp2);
156                 }
157                 /* TODO: handle case when i reaches 20 */
158         
159                 g_free(tmp);
160                 g_free(tmp2);
161
162                 /* FIXME: update name in properties */
163                 /* FIXME: store feed properties */
164         }
165
166         folder_item_update_freeze();
167
168         /* Read contents of folder, so we can check for duplicates/updates */
169         rssyl_folder_read_existing(ritem);
170
171         if( claws_is_exiting() ) {
172                 debug_print("RSSyl: Claws-Mail is exiting, bailing out\n");
173                 log_print(LOG_PROTOCOL, RSSYL_LOG_ABORTED_EXITING, ritem->url);
174                 folder_item_update_thaw();
175                 return TRUE;
176         }
177
178         /* Populate the ->deleted_items list so that we can check it when
179          * adding each item. */
180         ritem->deleted_items = rssyl_deleted_update(ritem);
181
182         /* Parse each item in the feed, adding or updating existing items if
183          * necessary */
184         if( feed_n_items(feed) > 0 )
185                 feed_foreach_item(feed, rssyl_foreach_parse_func, (gpointer)ritem);
186
187         if( !ritem->keep_old && !ritem->fetching_comments ) {
188                 rssyl_folder_read_existing(ritem);
189                 rssyl_expire_items(ritem, feed);
190         }
191
192         rssyl_deleted_free(ritem->deleted_items);
193
194         folder_item_scan(&ritem->item);
195         folder_item_update_thaw();
196
197         if( !ritem->fetching_comments )
198                 log_print(LOG_PROTOCOL, RSSYL_LOG_UPDATED, ritem->url);
199
200         return TRUE;
201 }