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