18
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
#include <string.h> /* For strstr() */
27
25
#include "common.h"
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"
36
typedef struct condition {
37
guint tables; /**< tables used by the condition */
38
gchar *sql; /**< SQL of the condition */
41
/** function type used to query SQL WHERE clause condition for rules */
42
typedef conditionPtr (*ruleConditionFunc) (rulePtr rule);
44
/** function type used to check in memory items */
45
typedef gboolean (*ruleCheckFunc) (rulePtr rule, itemPtr item);
47
/* the rule function list is used to create popup menues in ui_vfolder.c */
48
struct ruleInfo *ruleFunctions = NULL;
49
gint nrOfRuleFunctions = 0;
32
/** list of available search folder rules */
33
static GSList *ruleFunctions = NULL;
35
static void rule_init (void);
38
rule_get_available_rules (void)
51
46
/* rule creation */
54
rule_new (struct vfolder *vfolder,
49
rule_new (const gchar *ruleId,
56
50
const gchar *value,
66
for (i = 0, ruleInfo = ruleFunctions; i < nrOfRuleFunctions; i++, ruleInfo++)
68
if (0 == strcmp (ruleInfo->ruleId, ruleId))
70
rule = (rulePtr) g_new0 (struct rule, 1);
55
iter = rule_get_available_rules ();
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;
74
62
rule->value = common_strreplace (g_strdup (value), "'", "");
66
iter = g_slist_next (iter);
88
78
/* rule conditions */
91
rule_condition_feed_title_match (rulePtr rule)
93
conditionPtr condition;
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);
103
rule_condition_item_title_match (rulePtr rule)
105
conditionPtr condition;
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);
115
rule_condition_item_description_match (rulePtr rule)
117
conditionPtr condition;
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);
127
rule_condition_item_match (rulePtr rule)
129
conditionPtr condition;
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);
139
rule_condition_item_is_unread (rulePtr rule)
141
conditionPtr condition;
143
condition = g_new0 (struct condition, 1);
144
condition->tables = QUERY_TABLE_ITEMS;
145
condition->sql = g_strdup ("items.read = 0");
81
rule_check_item_title (rulePtr rule, itemPtr item)
83
return (NULL != g_strstr_len (item->title, -1, rule->value));
87
rule_check_item_description (rulePtr rule, itemPtr item)
89
return (NULL != g_strstr_len (item->description, -1, rule->value));
93
rule_check_item_all (rulePtr rule, itemPtr item)
95
return rule_check_item_title (rule, item) || rule_check_item_description (rule, item);
153
101
return (0 == item->readStatus);
157
rule_condition_item_is_flagged (rulePtr rule)
159
conditionPtr condition;
161
condition = g_new0 (struct condition, 1);
162
condition->tables = QUERY_TABLE_ITEMS;
163
condition->sql = g_strdup ("items.marked = 1");
169
105
rule_check_item_is_flagged (rulePtr rule, itemPtr item)
171
107
return (1 == item->flagStatus);
175
rule_condition_item_was_updated (rulePtr rule)
177
conditionPtr condition;
179
condition = g_new0 (struct condition, 1);
180
condition->tables = QUERY_TABLE_ITEMS;
181
condition->sql = g_strdup ("items.updated = 1");
187
rule_condition_item_has_enclosure (rulePtr rule)
189
conditionPtr condition;
191
condition = g_new0 (struct condition, 1);
192
condition->tables = QUERY_TABLE_METADATA | QUERY_TABLE_ITEMS;
193
condition->sql = g_strdup ("metadata.key = 'enclosure'");
199
rule_condition_item_has_category (rulePtr rule)
201
conditionPtr condition;
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);
211
rule_merge_sql (gchar **sql, const gchar *operator, const gchar *condition)
214
*sql = g_strdup (condition);
217
*sql = g_strdup_printf ("%s %s %s", old, operator, condition);
223
query_create (GSList *rules, gboolean anyMatch)
227
GSList *additive = NULL;
228
GSList *negative = NULL;
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);
236
rulePtr rule = (rulePtr)iter->data;
237
conditionPtr condition;
239
condition = (*((ruleConditionFunc)rule->ruleInfo->queryFunc)) (rule);
241
/* Negate the SQL condition if necessary */
242
if (rule->additive) {
243
additive = g_slist_append (additive, condition->sql);
245
gchar *tmp = condition->sql;
246
condition->sql = g_strdup_printf ("NOT(%s)", condition->sql);
249
negative = g_slist_append (negative, condition->sql);
252
query->tables |= condition->tables;
254
iter = g_slist_next (iter);
257
/* Constructing query by ... */
259
/* a) joining all additive matches (OR'ing and AND'ing according to "any or all rules matching" parameter) */
262
gchar *sql = (gchar *)iter->data;
263
rule_merge_sql (&query->conditions, anyMatch?"OR":"AND", sql);
265
iter = g_slist_next (iter);
267
g_slist_free (additive);
269
/* b) and AND'ing all negative matches to the positive match list */
271
gchar *tmp = query->conditions;
272
query->conditions = g_strdup_printf ("(%s)", query->conditions);
277
gchar *sql = (gchar *)iter->data;
278
rule_merge_sql (&query->conditions, "AND", sql);
280
iter = g_slist_next (iter);
282
g_slist_free (negative);
289
query_free (queryPtr query)
291
g_free (query->conditions);
296
rules_to_view (GSList *rules, gboolean anyMatch, const gchar *id)
300
if (0 == g_slist_length (rules))
303
query = query_create (rules, anyMatch);
304
query->columns = QUERY_COLUMN_ITEM_ID | QUERY_COLUMN_ITEM_READ_STATUS;
305
db_view_create (id, query);
310
rules_check_item (GSList *rules, gboolean anyMatch, itemPtr item)
315
if (0 == g_slist_length (rules))
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;
323
result = (*func) (rules->data, item);
324
return (rule->additive)?result:!result;
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);
111
rule_check_item_has_enc (rulePtr rule, itemPtr item)
113
return FALSE; // FIXME
117
rule_check_item_category (rulePtr rule, itemPtr item)
119
return FALSE; // FIXME
337
122
/* rule initialization */
340
rule_add (ruleConditionFunc queryFunc,
341
ruleCheckFunc checkFunc,
125
rule_info_add (ruleCheckFunc checkFunc,
342
126
const gchar *ruleId,
346
130
gboolean needsParameter)
132
ruleInfoPtr ruleInfo;
349
ruleFunctions = (ruleInfoPtr) g_realloc (ruleFunctions, sizeof (struct ruleInfo) * (nrOfRuleFunctions + 1));
350
if (NULL == ruleFunctions)
351
g_error("could not allocate memory!");
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;
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);
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
/* ========================================================================================================================================================================================*/
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);
381
160
debug_exit ("rule_init");