~ubuntu-branches/ubuntu/vivid/liferea/vivid-proposed

« back to all changes in this revision

Viewing changes to src/rule.c

  • Committer: Package Import Robot
  • Author(s): bojo42
  • Date: 2012-03-29 14:17:21 UTC
  • mfrom: (1.3.9) (3.2.5 sid)
  • Revision ID: package-import@ubuntu.com-20120329141721-tbfopcrc5797wxt7
Tags: 1.8.3-0.1ubuntu1
* New upstream release (LP: #290666, #371754, #741543, #716688)
* Merge from Debian unstable (LP: #935147), remaining changes:
* debian/patches:
  - drop gtk-status-icon.patch & notification-append as in upstream
  - drop fix_systray_behavior as mostly upstreamed and rest seems unused
  - 01_ubuntu_feedlists: update & rename, move planets to "Open Source"  
  - add_X-Ubuntu-Gettext-Domain: rebase
  - libunity.patch: rebase, apply before indicator patch (liferea_shell.c)
  - libindicate_increase_version.patch: exclude from libindicate.patch
  - deactivate libindicate.patch, seems partly upstreamed and needs rework
* debian/control: libindicate-dev, libindicate-gtk-dev & libunity-dev
* debian/liferea.indicate & liferea.install: ship indicator desktop file
* debian/rules: enable libindicate

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/**
2
 
 * @file rule.c  DB based item matching rule handling
 
2
 * @file rule.c  item matching rules used by search folders
3
3
 *
4
 
 * Copyright (C) 2003-2008 Lars Lindner <lars.lindner@gmail.com>
 
4
 * Copyright (C) 2003-2010 Lars Lindner <lars.lindner@gmail.com>
5
5
 *
6
6
 * This program is free software; you can redistribute it and/or modify
7
7
 * it under the terms of the GNU General Public License as published by
18
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
19
 */
20
20
 
21
 
#ifdef HAVE_CONFIG_H
22
 
#  include <config.h>
23
 
#endif
 
21
#include "rule.h"
24
22
 
25
 
#include <string.h> /* For strstr() */
 
23
#include <string.h>
26
24
 
27
25
#include "common.h"
28
 
#include "db.h"
29
26
#include "debug.h"
30
 
#include "rule.h"
31
27
 
32
28
#define ITEM_MATCH_RULE_ID              "exact"
33
29
#define ITEM_TITLE_MATCH_RULE_ID        "exact_title"
34
30
#define ITEM_DESC_MATCH_RULE_ID         "exact_desc"
35
 
 
36
 
typedef struct condition {
37
 
        guint   tables;         /**< tables used by the condition */
38
 
        gchar   *sql;           /**< SQL of the condition */
39
 
} *conditionPtr;
40
 
   
41
 
/** function type used to query SQL WHERE clause condition for rules */
42
 
typedef conditionPtr (*ruleConditionFunc)       (rulePtr rule);
43
 
 
44
 
/** function type used to check in memory items */
45
 
typedef gboolean (*ruleCheckFunc)       (rulePtr rule, itemPtr item);
46
 
   
47
 
/* the rule function list is used to create popup menues in ui_vfolder.c */
48
 
struct ruleInfo *ruleFunctions = NULL;
49
 
gint nrOfRuleFunctions = 0;
 
31
 
 
32
/** list of available search folder rules */
 
33
static GSList *ruleFunctions = NULL;
 
34
 
 
35
static void rule_init (void);
 
36
 
 
37
GSList *
 
38
rule_get_available_rules (void)
 
39
{
 
40
        if (!ruleFunctions)
 
41
                rule_init ();
 
42
                
 
43
        return ruleFunctions;
 
44
}
50
45
 
51
46
/* rule creation */
52
47
 
53
48
rulePtr
54
 
rule_new (struct vfolder *vfolder,
55
 
          const gchar *ruleId,
 
49
rule_new (const gchar *ruleId,
56
50
          const gchar *value,
57
51
          gboolean additive) 
58
52
{
59
 
        ruleInfoPtr     ruleInfo;
60
 
        rulePtr         rule;
61
 
        int             i;
62
 
        
63
 
        if (!ruleFunctions)
64
 
                rule_init ();
65
 
        
66
 
        for (i = 0, ruleInfo = ruleFunctions; i < nrOfRuleFunctions; i++, ruleInfo++) 
67
 
        {
68
 
                if (0 == strcmp (ruleInfo->ruleId, ruleId)) 
69
 
                {
70
 
                        rule = (rulePtr) g_new0 (struct rule, 1);
 
53
        GSList          *iter;
 
54
        
 
55
        iter = rule_get_available_rules ();
 
56
        while (iter) {
 
57
                ruleInfoPtr ruleInfo = (ruleInfoPtr)iter->data;
 
58
                if (0 == strcmp (ruleInfo->ruleId, ruleId)) {
 
59
                        rulePtr rule = (rulePtr) g_new0 (struct rule, 1);
71
60
                        rule->ruleInfo = ruleInfo;
72
61
                        rule->additive = additive;
73
 
                        rule->vp = vfolder;             
74
62
                        rule->value = common_strreplace (g_strdup (value), "'", "");    
75
63
                        return rule;
76
64
                }
 
65
                
 
66
                iter = g_slist_next (iter);
77
67
        }       
78
68
        return NULL;
79
69
}
87
77
 
88
78
/* rule conditions */
89
79
 
90
 
static conditionPtr
91
 
rule_condition_feed_title_match (rulePtr rule) 
92
 
{
93
 
        conditionPtr    condition;
94
 
 
95
 
        condition = g_new0 (struct condition, 1);
96
 
        condition->tables = QUERY_TABLE_NODE;
97
 
        condition->sql = g_strdup_printf ("node.title LIKE '%%%s%%'", rule->value);
98
 
        
99
 
        return condition;
100
 
}
101
 
 
102
 
static conditionPtr
103
 
rule_condition_item_title_match (rulePtr rule) 
104
 
{
105
 
        conditionPtr    condition;
106
 
 
107
 
        condition = g_new0 (struct condition, 1);
108
 
        condition->tables = QUERY_TABLE_ITEMS;
109
 
        condition->sql = g_strdup_printf ("items.title LIKE '%%%s%%'", rule->value);
110
 
        
111
 
        return condition;
112
 
}
113
 
 
114
 
static conditionPtr
115
 
rule_condition_item_description_match (rulePtr rule) 
116
 
{
117
 
        conditionPtr    condition;
118
 
        
119
 
        condition = g_new0 (struct condition, 1);
120
 
        condition->tables = QUERY_TABLE_ITEMS;
121
 
        condition->sql = g_strdup_printf ("items.description LIKE '%%%s%%'", rule->value);
122
 
        
123
 
        return condition;
124
 
}
125
 
 
126
 
static conditionPtr
127
 
rule_condition_item_match (rulePtr rule) 
128
 
{
129
 
        conditionPtr    condition;
130
 
        
131
 
        condition = g_new0 (struct condition, 1);
132
 
        condition->tables = QUERY_TABLE_ITEMS;
133
 
        condition->sql = g_strdup_printf ("(items.title LIKE '%%%s%%' OR items.description LIKE '%%%s%%')", rule->value, rule->value);
134
 
        
135
 
        return condition;
136
 
}
137
 
 
138
 
static conditionPtr
139
 
rule_condition_item_is_unread (rulePtr rule) 
140
 
{
141
 
        conditionPtr    condition;
142
 
        
143
 
        condition = g_new0 (struct condition, 1);
144
 
        condition->tables = QUERY_TABLE_ITEMS;
145
 
        condition->sql = g_strdup ("items.read = 0");
146
 
        
147
 
        return condition;
 
80
static gboolean
 
81
rule_check_item_title (rulePtr rule, itemPtr item)
 
82
{
 
83
        return (NULL != g_strstr_len (item->title, -1, rule->value));
 
84
}
 
85
 
 
86
static gboolean
 
87
rule_check_item_description (rulePtr rule, itemPtr item)
 
88
{
 
89
        return (NULL != g_strstr_len (item->description, -1, rule->value));
 
90
}
 
91
 
 
92
static gboolean
 
93
rule_check_item_all (rulePtr rule, itemPtr item)
 
94
{
 
95
        return rule_check_item_title (rule, item) || rule_check_item_description (rule, item);
148
96
}
149
97
 
150
98
static gboolean
153
101
        return (0 == item->readStatus);
154
102
}
155
103
 
156
 
static conditionPtr
157
 
rule_condition_item_is_flagged (rulePtr rule) 
158
 
{
159
 
        conditionPtr    condition;
160
 
        
161
 
        condition = g_new0 (struct condition, 1);
162
 
        condition->tables = QUERY_TABLE_ITEMS;
163
 
        condition->sql = g_strdup ("items.marked = 1");
164
 
        
165
 
        return condition;
166
 
}
167
 
 
168
104
static gboolean
169
105
rule_check_item_is_flagged (rulePtr rule, itemPtr item)
170
106
{
171
107
        return (1 == item->flagStatus);
172
108
}
173
109
 
174
 
static conditionPtr
175
 
rule_condition_item_was_updated (rulePtr rule)
176
 
{
177
 
        conditionPtr    condition;
178
 
        
179
 
        condition = g_new0 (struct condition, 1);
180
 
        condition->tables = QUERY_TABLE_ITEMS;
181
 
        condition->sql = g_strdup ("items.updated = 1");
182
 
        
183
 
        return condition;
184
 
}
185
 
 
186
 
static conditionPtr
187
 
rule_condition_item_has_enclosure (rulePtr rule) 
188
 
{
189
 
        conditionPtr    condition;
190
 
        
191
 
        condition = g_new0 (struct condition, 1);
192
 
        condition->tables = QUERY_TABLE_METADATA | QUERY_TABLE_ITEMS;
193
 
        condition->sql = g_strdup ("metadata.key = 'enclosure'");
194
 
        
195
 
        return condition;
196
 
}
197
 
 
198
 
static conditionPtr
199
 
rule_condition_item_has_category (rulePtr rule)
200
 
{
201
 
        conditionPtr    condition;
202
 
        
203
 
        condition = g_new0 (struct condition, 1);
204
 
        condition->tables = QUERY_TABLE_METADATA | QUERY_TABLE_ITEMS;
205
 
        condition->sql = g_strdup_printf ("(metadata.key = 'category' AND metadata.value = '%s')", rule->value);
206
 
        
207
 
        return condition;
208
 
}
209
 
 
210
 
static void
211
 
rule_merge_sql (gchar **sql, const gchar *operator, const gchar *condition)
212
 
{
213
 
        if (!*sql) {
214
 
                *sql = g_strdup (condition);
215
 
        } else {
216
 
                gchar *old = *sql;
217
 
                *sql = g_strdup_printf ("%s %s %s", old, operator, condition);
218
 
                g_free (old);
219
 
        }
220
 
}
221
 
 
222
 
static queryPtr
223
 
query_create (GSList *rules, gboolean anyMatch)
224
 
{
225
 
        queryPtr        query;
226
 
        GSList          *iter;
227
 
        GSList          *additive = NULL;
228
 
        GSList          *negative = NULL;
229
 
        
230
 
        /* First process all rules to SQL conditions and sort
231
 
           them into the additive and negative lists. While 
232
 
           doing so also collect the necessary the table set. */
233
 
        query = g_new0 (struct query, 1);
234
 
        iter = rules;
235
 
        while (iter) {
236
 
                rulePtr rule = (rulePtr)iter->data;
237
 
                conditionPtr condition;
238
 
                
239
 
                condition = (*((ruleConditionFunc)rule->ruleInfo->queryFunc)) (rule);
240
 
                
241
 
                /* Negate the SQL condition if necessary */
242
 
                if (rule->additive) {
243
 
                        additive = g_slist_append (additive, condition->sql);
244
 
                } else {
245
 
                        gchar *tmp = condition->sql;
246
 
                        condition->sql = g_strdup_printf ("NOT(%s)", condition->sql);
247
 
                        g_free (tmp);
248
 
                        
249
 
                        negative = g_slist_append (negative, condition->sql);
250
 
                }
251
 
 
252
 
                query->tables |= condition->tables;
253
 
                g_free (condition);
254
 
                iter = g_slist_next (iter);
255
 
        }
256
 
        
257
 
        /* Constructing query by ... */
258
 
          
259
 
        /* a) joining all additive matches (OR'ing and AND'ing according to "any or all rules matching" parameter) */
260
 
        iter = additive;
261
 
        while (iter) {
262
 
                gchar *sql = (gchar *)iter->data;
263
 
                rule_merge_sql (&query->conditions, anyMatch?"OR":"AND", sql);
264
 
                g_free (sql);
265
 
                iter = g_slist_next (iter);
266
 
        }
267
 
        g_slist_free (additive);
268
 
        
269
 
        /* b) and AND'ing all negative matches to the positive match list */            
270
 
        if (negative) {
271
 
                gchar *tmp = query->conditions;
272
 
                query->conditions = g_strdup_printf ("(%s)", query->conditions);
273
 
                g_free (tmp);
274
 
 
275
 
                iter = negative;
276
 
                while (iter) {
277
 
                        gchar *sql = (gchar *)iter->data;
278
 
                        rule_merge_sql (&query->conditions, "AND", sql);
279
 
                        g_free (sql);
280
 
                        iter = g_slist_next (iter);
281
 
                }
282
 
                g_slist_free (negative);
283
 
        }
284
 
        
285
 
        return query;
286
 
}
287
 
 
288
 
static void
289
 
query_free (queryPtr query)
290
 
{
291
 
        g_free (query->conditions);
292
 
        g_free (query);
293
 
}
294
 
 
295
 
void
296
 
rules_to_view (GSList *rules, gboolean anyMatch, const gchar *id)
297
 
{
298
 
        queryPtr        query;
299
 
 
300
 
        if (0 == g_slist_length (rules))
301
 
                return; 
302
 
                
303
 
        query = query_create (rules, anyMatch);
304
 
        query->columns = QUERY_COLUMN_ITEM_ID | QUERY_COLUMN_ITEM_READ_STATUS;
305
 
        db_view_create (id, query);
306
 
        query_free (query);
307
 
}
308
 
 
309
 
gboolean
310
 
rules_check_item (GSList *rules, gboolean anyMatch, itemPtr item)
311
 
{
312
 
        gboolean        result;
313
 
        queryPtr        query;
314
 
        
315
 
        if (0 == g_slist_length (rules))
316
 
                return FALSE;
317
 
        
318
 
        /* first try in memory checks (for "unread" and "important" search folder)... */
319
 
        if (1 == g_slist_length (rules)) {
320
 
                rulePtr rule = (rulePtr) rules->data;
321
 
                ruleCheckFunc func = rule->ruleInfo->checkFunc;
322
 
                if (func) {
323
 
                        result = (*func) (rules->data, item);
324
 
                        return (rule->additive)?result:!result;
325
 
                }
326
 
        }
327
 
 
328
 
        /* if not possible query DB */
329
 
        query = query_create (rules, anyMatch); 
330
 
        query->columns = QUERY_COLUMN_ITEM_ID;
331
 
        result = db_item_check (item->id, query);
332
 
        query_free (query);
333
 
        
334
 
        return result;
 
110
static gboolean
 
111
rule_check_item_has_enc (rulePtr rule, itemPtr item)
 
112
{
 
113
        return FALSE; // FIXME
 
114
}
 
115
 
 
116
static gboolean
 
117
rule_check_item_category (rulePtr rule, itemPtr item)
 
118
{
 
119
        return FALSE; // FIXME
335
120
}
336
121
 
337
122
/* rule initialization */
338
123
 
339
124
static void
340
 
rule_add (ruleConditionFunc queryFunc,
341
 
          ruleCheckFunc checkFunc,
 
125
rule_info_add (ruleCheckFunc checkFunc,
342
126
          const gchar *ruleId, 
343
127
          gchar *title,
344
128
          gchar *positive,
345
129
          gchar *negative,
346
130
          gboolean needsParameter)
347
131
{
 
132
        ruleInfoPtr     ruleInfo;
348
133
 
349
 
        ruleFunctions = (ruleInfoPtr) g_realloc (ruleFunctions, sizeof (struct ruleInfo) * (nrOfRuleFunctions + 1));
350
 
        if (NULL == ruleFunctions)
351
 
                g_error("could not allocate memory!");
352
 
                
353
 
        ruleFunctions[nrOfRuleFunctions].ruleId = ruleId;
354
 
        ruleFunctions[nrOfRuleFunctions].title = title;
355
 
        ruleFunctions[nrOfRuleFunctions].positive = positive;
356
 
        ruleFunctions[nrOfRuleFunctions].negative = negative;
357
 
        ruleFunctions[nrOfRuleFunctions].needsParameter = needsParameter;       
358
 
        ruleFunctions[nrOfRuleFunctions].checkFunc = checkFunc;
359
 
        ruleFunctions[nrOfRuleFunctions].queryFunc = queryFunc; 
360
 
        nrOfRuleFunctions++;
 
134
        ruleInfo = (ruleInfoPtr) g_new0 (struct ruleInfo, 1);
 
135
        ruleInfo->ruleId = ruleId;
 
136
        ruleInfo->title = title;
 
137
        ruleInfo->positive = positive;
 
138
        ruleInfo->negative = negative;
 
139
        ruleInfo->needsParameter = needsParameter;      
 
140
        ruleInfo->checkFunc = checkFunc;
 
141
        ruleFunctions = g_slist_append (ruleFunctions, ruleInfo);
361
142
}
362
143
 
363
 
void
 
144
static void
364
145
rule_init (void) 
365
146
{
366
147
        debug_enter ("rule_init");
368
149
        /*        SQL condition builder function        in-memory check function        feedlist.opml rule id           rule menu label         positive menu option    negative menu option    has param */ 
369
150
        /*        ========================================================================================================================================================================================*/
370
151
        
371
 
        rule_add (rule_condition_item_match,            NULL,                           ITEM_MATCH_RULE_ID,             _("Item"),              _("does contain"),      _("does not contain"),  TRUE);
372
 
        rule_add (rule_condition_item_title_match,      NULL,                           ITEM_TITLE_MATCH_RULE_ID,       _("Item title"),        _("does contain"),      _("does not contain"),  TRUE);
373
 
        rule_add (rule_condition_item_description_match, NULL,                          ITEM_DESC_MATCH_RULE_ID,        _("Item body"),         _("does contain"),      _("does not contain"),  TRUE);
374
 
        rule_add (rule_condition_feed_title_match,      NULL,                           "feed_title",                   _("Feed title"),        _("does contain"),      _("does not contain"),  TRUE);
375
 
        rule_add (rule_condition_item_is_unread,        rule_check_item_is_unread,      "unread",                       _("Read status"),       _("is unread"),         _("is read"),           FALSE);
376
 
        rule_add (rule_condition_item_is_flagged,       rule_check_item_is_flagged,     "flagged",                      _("Flag status"),       _("is flagged"),        _("is unflagged"),      FALSE);
377
 
        rule_add (rule_condition_item_was_updated,      NULL,                           "updated",                      _("Update status"),     _("was updated"),       _("was not updated"),   FALSE);
378
 
        rule_add (rule_condition_item_has_enclosure,    NULL,                           "enclosure",                    _("Podcast"),           _("included"),          _("not included"),      FALSE);
379
 
        rule_add (rule_condition_item_has_category,     NULL,                           "category",                     _("Category"),          _("is set"),            _("is not set"),        TRUE);
 
152
        rule_info_add (rule_check_item_all,             ITEM_MATCH_RULE_ID,             _("Item"),              _("does contain"),      _("does not contain"),  TRUE);
 
153
        rule_info_add (rule_check_item_title,           ITEM_TITLE_MATCH_RULE_ID,       _("Item title"),        _("does contain"),      _("does not contain"),  TRUE);
 
154
        rule_info_add (rule_check_item_description,     ITEM_DESC_MATCH_RULE_ID,        _("Item body"),         _("does contain"),      _("does not contain"),  TRUE);
 
155
        rule_info_add (rule_check_item_is_unread,       "unread",                       _("Read status"),       _("is unread"),         _("is read"),           FALSE);
 
156
        rule_info_add (rule_check_item_is_flagged,      "flagged",                      _("Flag status"),       _("is flagged"),        _("is unflagged"),      FALSE);
 
157
        rule_info_add (rule_check_item_has_enc,         "enclosure",                    _("Podcast"),           _("included"),          _("not included"),      FALSE);
 
158
        rule_info_add (rule_check_item_category,        "category",                     _("Category"),          _("is set"),            _("is not set"),        TRUE);
380
159
 
381
160
        debug_exit ("rule_init");
382
161
}