more sync with sylpheed 0.5.1cvs6
[claws.git] / src / scoring.c
1 #include <ctype.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <errno.h>
5 #include <stdio.h>
6 #include "defs.h"
7 #include "intl.h"
8 #include "utils.h"
9 #include "procheader.h"
10 #include "matcher.h"
11 #include "scoring.h"
12 #include "prefs.h"
13 #include "folder.h"
14
15 #define PREFSBUFSIZE            1024
16
17
18 GSList * global_scoring;
19
20 ScoringProp * scoringprop_parse(gchar ** str)
21 {
22         gchar * tmp;
23         gint key;
24         ScoringProp * scoring;
25         gint score;
26         MatcherList * matchers;
27
28         tmp = * str;
29
30         matchers = matcherlist_parse(&tmp);
31         if (tmp == NULL) {
32                 * str = NULL;
33                 return NULL;
34         }
35
36         key = matcher_parse_keyword(&tmp);
37
38         if (tmp == NULL) {
39                 matcherlist_free(matchers);
40                 * str = NULL;
41                 return NULL;
42         }
43
44         if (key != MATCHING_SCORE) {
45                 matcherlist_free(matchers);
46                 * str = NULL;
47                 return NULL;
48         }
49
50         score = matcher_parse_number(&tmp);
51
52         if (tmp == NULL) {
53                 matcherlist_free(matchers);
54                 * str = NULL;
55                 return NULL;
56         }
57
58         scoring = scoringprop_new(matchers, score);
59
60         * str = tmp;
61         return scoring;
62 }
63
64
65 ScoringProp * scoringprop_new(MatcherList * matchers, int score)
66 {
67         ScoringProp * scoring;
68
69         scoring = g_new0(ScoringProp, 1);
70         scoring->matchers = matchers;
71         scoring->score = score;
72
73         return scoring;
74 }
75
76 void scoringprop_free(ScoringProp * prop)
77 {
78         matcherlist_free(prop->matchers);
79         g_free(prop);
80 }
81
82 gint scoringprop_score_message(ScoringProp * scoring, MsgInfo * info)
83 {
84         if (matcherlist_match(scoring->matchers, info))
85                 return scoring->score;
86         else
87                 return 0;
88 }
89
90 gint score_message(GSList * scoring_list, MsgInfo * info)
91 {
92         gint score = 0;
93         gint add_score;
94         GSList * l;
95
96         for(l = scoring_list ; l != NULL ; l = g_slist_next(l)) {
97                 ScoringProp * scoring = (ScoringProp *) l->data;
98                 
99                 add_score = (scoringprop_score_message(scoring, info));
100                 if (add_score == MAX_SCORE || add_score == MIN_SCORE) {
101                         score = add_score;
102                         break;
103                 }
104                 score += add_score;
105         }
106         return score;
107 }
108
109 #if 0
110 static void scoringprop_print(ScoringProp * prop)
111 {
112         GSList * l;
113
114         if (prop == NULL) {
115                 printf("no scoring\n");
116                 return;
117         }
118
119         printf("----- scoring ------\n");
120         for(l = prop->matchers ; l != NULL ; l = g_slist_next(l)) {
121                 matcherprop_print((MatcherProp *) l->data);
122         }
123         printf("cond: %s\n", prop->bool_and ? "and" : "or");
124         printf("score: %i\n", prop->score);
125 }
126 #endif
127
128 /*
129   syntax for scoring config
130
131   file ~/.sylpheed/scoringrc
132
133   header "x-mailing" match "toto" score -10
134   subject match "regexp" & to regexp "regexp" score 50
135   subject match "regexp" | to regexpcase "regexp" | age_sup 5 score 30
136
137   if score is = MIN_SCORE (-999), no more match is done in the list
138   if score is = MAX_SCORE (-999), no more match is done in the list
139  */
140
141 /*
142 void prefs_scoring_read_config(void)
143 {
144         gchar *rcpath;
145         FILE *fp;
146         gchar buf[PREFSBUFSIZE];
147
148         debug_print(_("Reading headers configuration...\n"));
149
150         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, SCORING_RC, NULL);
151         if ((fp = fopen(rcpath, "r")) == NULL) {
152                 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
153                 g_free(rcpath);
154                 prefs_scoring = NULL;
155                 return;
156         }
157         g_free(rcpath);
158
159         while (prefs_scoring != NULL) {
160                 ScoringProp * scoring = (ScoringProp *) prefs_scoring->data;
161                 scoringprop_free(scoring);
162                 prefs_scoring = g_slist_remove(prefs_scoring, scoring);
163         }
164
165         while (fgets(buf, sizeof(buf), fp) != NULL) {
166                 ScoringProp * scoring;
167                 gchar * tmp;
168
169                 g_strchomp(buf);
170
171                 if ((*buf != '#') && (*buf != '\0')) {
172                         tmp = buf;
173                         scoring = scoringprop_parse(&tmp);
174                         if (tmp != NULL) {
175                                 prefs_scoring = g_slist_append(prefs_scoring,
176                                                                scoring);
177                         }
178                         else {
179                                 g_warning(_("syntax error : %s\n"), buf);
180                         }
181                 }
182         }
183
184         fclose(fp);
185 }
186 */
187
188 gchar * scoringprop_to_string(ScoringProp * prop)
189 {
190         gchar * list_str;
191         gchar * score_str;
192         gchar * scoring_str;
193
194         list_str = matcherlist_to_string(prop->matchers);
195
196         if (list_str == NULL)
197                 return NULL;
198
199         score_str = itos(prop->score);
200         scoring_str = g_strconcat(list_str, " score ", score_str, NULL);
201         g_free(list_str);
202
203         return scoring_str;
204 }
205
206 /*
207 void prefs_scoring_write_config(void)
208 {
209         gchar *rcpath;
210         PrefFile *pfile;
211         GSList *cur;
212         ScoringProp * prop;
213
214         debug_print(_("Writing scoring configuration...\n"));
215
216         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, SCORING_RC, NULL);
217
218         if ((pfile = prefs_write_open(rcpath)) == NULL) {
219                 g_warning(_("failed to write configuration to file\n"));
220                 g_free(rcpath);
221                 return;
222         }
223
224         for (cur = prefs_scoring; cur != NULL; cur = cur->next) {
225                 gchar *scoring_str;
226
227                 prop = (ScoringProp *) cur->data;
228                 scoring_str = scoringprop_to_string(prop);
229                 if (fputs(scoring_str, pfile->fp) == EOF ||
230                     fputc('\n', pfile->fp) == EOF) {
231                         FILE_OP_ERROR(rcpath, "fputs || fputc");
232                         prefs_write_close_revert(pfile);
233                         g_free(rcpath);
234                         g_free(scoring_str);
235                         return;
236                 }
237                 g_free(scoring_str);
238         }
239
240         g_free(rcpath);
241
242         if (prefs_write_close(pfile) < 0) {
243                 g_warning(_("failed to write configuration to file\n"));
244                 return;
245         }
246 }
247 */
248
249 void prefs_scoring_free(GSList * prefs_scoring)
250 {
251         while (prefs_scoring != NULL) {
252                 ScoringProp * scoring = (ScoringProp *) prefs_scoring->data;
253                 scoringprop_free(scoring);
254                 prefs_scoring = g_slist_remove(prefs_scoring, scoring);
255         }
256 }
257
258 static gboolean prefs_scoring_free_func(GNode *node, gpointer data)
259 {
260         FolderItem *item = node->data;
261
262         if(!item->prefs)
263                 return FALSE;
264
265         prefs_scoring_free(item->prefs->scoring);
266         item->prefs->scoring = NULL;
267
268         return FALSE;
269 }
270
271 static void prefs_scoring_clear()
272 {
273         GList * cur;
274
275         for (cur = folder_get_list() ; cur != NULL ; cur = g_list_next(cur)) {
276                 Folder *folder;
277
278                 folder = (Folder *) cur->data;
279                 g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
280                                 prefs_scoring_free_func, NULL);
281         }
282
283         prefs_scoring_free(global_scoring);
284         global_scoring = NULL;
285 }
286
287 void prefs_scoring_read_config(void)
288 {
289         gchar *rcpath;
290         FILE *fp;
291         gchar buf[PREFSBUFSIZE];
292         GSList * prefs_scoring = NULL;
293         FolderItem * item = NULL;
294
295         debug_print(_("Reading headers configuration...\n"));
296
297         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, SCORING_RC, NULL);
298         if ((fp = fopen(rcpath, "r")) == NULL) {
299                 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
300                 g_free(rcpath);
301                 prefs_scoring = NULL;
302                 return;
303         }
304         g_free(rcpath);
305
306         prefs_scoring_clear();
307
308         while (fgets(buf, sizeof(buf), fp) != NULL) {
309                 ScoringProp * scoring;
310                 gchar * tmp;
311
312                 g_strchomp(buf);
313
314                 if (g_strcasecmp(buf, "[global]") == 0) {
315                         if (item != NULL) {
316                                 item->prefs->scoring = prefs_scoring;
317                                 item = NULL;
318                                 prefs_scoring = global_scoring;
319                         }
320                 }
321                 else if ((*buf == '[') && buf[strlen(buf) - 1] == ']') {
322                         gchar * id;
323
324                         if (item == NULL)
325                                 global_scoring = prefs_scoring;
326                         else
327                                 item->prefs->scoring = prefs_scoring;
328
329                         id = buf + 1;
330                         id[strlen(id) - 1] = '\0';
331
332                         item = folder_find_item_from_identifier(id);
333                         if (item == NULL)
334                                 prefs_scoring = global_scoring;
335                         else
336                                 prefs_scoring = item->prefs->scoring;
337                 }
338                 else if ((*buf != '#') && (*buf != '\0')) {
339                         tmp = buf;
340                         scoring = scoringprop_parse(&tmp);
341                         if (tmp != NULL) {
342                                 prefs_scoring = g_slist_append(prefs_scoring,
343                                                                scoring);
344                         }
345                         else {
346                                 /* debug */
347                                 g_warning(_("syntax error : %s\n"), buf);
348                         }
349                 }
350         }
351
352         if (item == NULL)
353                 global_scoring = prefs_scoring;
354         else
355                 item->prefs->scoring = prefs_scoring;
356
357         fclose(fp);
358 }
359
360 static void prefs_scoring_write(FILE * fp, GSList * prefs_scoring)
361 {
362         GSList * cur;
363
364         for (cur = prefs_scoring; cur != NULL; cur = cur->next) {
365                 gchar *scoring_str;
366                 ScoringProp * prop;
367
368                 prop = (ScoringProp *) cur->data;
369                 scoring_str = scoringprop_to_string(prop);
370                 if (fputs(scoring_str, fp) == EOF ||
371                     fputc('\n', fp) == EOF) {
372                         FILE_OP_ERROR("scoring config", "fputs || fputc");
373                         g_free(scoring_str);
374                         return;
375                 }
376                 g_free(scoring_str);
377         }
378 }
379
380 static gboolean prefs_scoring_write_func(GNode *node, gpointer data)
381 {
382         FolderItem *item = node->data;
383         FILE * fp = data;
384
385         if (item->prefs->scoring != NULL) {
386                 gchar * id = folder_item_get_identifier(item);
387
388                 fprintf(fp, "[%s]\n", id);
389                 g_free(id);
390
391                 prefs_scoring_write(fp, item->prefs->scoring);
392
393                 fputc('\n', fp);
394         }
395
396         return FALSE;
397 }
398
399 static void prefs_scoring_save(FILE * fp)
400 {
401         GList * cur;
402
403         fputs("[global]\n", fp);
404         prefs_scoring_write(fp, global_scoring);
405         fputc('\n', fp);
406
407         for (cur = folder_get_list() ; cur != NULL ; cur = g_list_next(cur)) {
408                 Folder *folder;
409
410                 folder = (Folder *) cur->data;
411                 g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
412                                 prefs_scoring_write_func, fp);
413         }
414 }
415
416 void prefs_scoring_write_config(void)
417 {
418         gchar *rcpath;
419         PrefFile *pfile;
420         GSList *cur;
421         ScoringProp * prop;
422
423         debug_print(_("Writing scoring configuration...\n"));
424
425         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, SCORING_RC, NULL);
426
427         if ((pfile = prefs_write_open(rcpath)) == NULL) {
428                 g_warning(_("failed to write configuration to file\n"));
429                 g_free(rcpath);
430                 return;
431         }
432
433
434         prefs_scoring_save(pfile->fp);
435
436         g_free(rcpath);
437
438         if (prefs_write_close(pfile) < 0) {
439                 g_warning(_("failed to write configuration to file\n"));
440                 return;
441         }
442 }