1 /* register.c -- read input with collect and register to persistent db */
2
3 #include "common.h"
4
5 #include <stdlib.h>
6
7 #include "bogofilter.h"
8 #include "datastore.h"
9 #include "collect.h"
10 #include "format.h"
11 #include "msgcounts.h"
12 #include "rand_sleep.h"
13 #include "register.h"
14 #include "wordhash.h"
15 #include "wordlists.h"
16
17 #define PLURAL(count) ((count == 1) ? "" : "s")
18
19 /*
20 * tokenize text on stdin and register it to a specified list
21 * and possibly out of another list
22 */
register_words(run_t _run_type,wordhash_t * h,u_int32_t msgcount)23 void register_words(run_t _run_type, wordhash_t *h, u_int32_t msgcount)
24 {
25 const char *r="",*u="";
26 dsv_t val;
27 hashnode_t *node;
28 wordprop_t *wordprop;
29 run_t save_run_type = run_type;
30 int retrycount = 60; /* we'll retry an aborted
31 registration five dozen times
32 before giving up. */
33 bool first;
34
35 u_int32_t wordcount = h->count; /* use number of unique tokens */
36
37 /* registrations always go to the default wordlist */
38 wordlist_t *list = get_default_wordlist(word_lists);
39
40 sh_t incr = IX_UNDF, decr = IX_UNDF;
41
42 /* If update directory explicity supplied, setup the wordlists. */
43 if (update_dir) {
44 if (set_wordlist_dir(update_dir, PR_CFG_UPDATE) != 0) {
45 fprintf(stderr, "Can't find HOME or BOGOFILTER_DIR in environment.\n");
46 exit(EX_ERROR);
47 }
48 }
49
50 if (_run_type & REG_SPAM) { r = "s"; incr = IX_SPAM; }
51 if (_run_type & REG_GOOD) { r = "n"; incr = IX_GOOD; }
52 if (_run_type & UNREG_SPAM) { u = "S"; decr = IX_SPAM; }
53 if (_run_type & UNREG_GOOD) { u = "N"; decr = IX_GOOD; }
54
55 if (wordcount == 0)
56 msgcount = 0;
57
58 format_set_counts(wordcount, msgcount);
59 format_log_update(msg_register, msg_register_size, u, r);
60
61 if (verbose)
62 (void)fprintf(dbgout, "# %u word%s, %u message%s\n",
63 wordcount, PLURAL(wordcount), msgcount, PLURAL(msgcount));
64
65 /* When using auto-update with separate wordlists ,
66 datastore.c needs to know which to update */
67
68 run_type = (run_t)(run_type | _run_type);
69
70 first = true;
71
72 retry:
73 if (first)
74 first = false;
75 else {
76 if (verbose)
77 fprintf(stderr, "retrying registration after avoided deadlock...\n");
78 begin_wordlist(list);
79 }
80
81 if (retrycount-- == 0) {
82 fprintf(stderr, "retry count exceeded, giving up.\n");
83 exit(EX_ERROR);
84 }
85
86 for (node = (hashnode_t *)wordhash_first(h); node != NULL; node = (hashnode_t *)wordhash_next(h))
87 {
88 wordprop = (wordprop_t *)node->data;
89 switch (ds_read(list->dsh, node->key, &val)) {
90 case DS_ABORT_RETRY:
91 rand_sleep(4*1000,1000*1000);
92 goto retry;
93 case 0:
94 case 1:
95 break;
96 default:
97 fprintf(stderr, "cannot read from data base.\n");
98 exit(EX_ERROR);
99 }
100 if (incr != IX_UNDF) {
101 u_int32_t *counts = val.count;
102 counts[incr] += wordprop->freq;
103 }
104 if (decr != IX_UNDF) {
105 u_int32_t *counts = val.count;
106 counts[decr] = ((long)counts[decr] < wordprop->freq) ? 0 : counts[decr] - wordprop->freq;
107 }
108 switch (ds_write(list->dsh, node->key, &val)) {
109 case DS_ABORT_RETRY:
110 rand_sleep(4*1000,1000*1000);
111 goto retry;
112 case 0:
113 break;
114 default:
115 fprintf(stderr, "cannot write to data base.\n");
116 exit(EX_ERROR);
117 }
118 }
119
120 switch (ds_get_msgcounts(list->dsh, &val)) {
121 case 0:
122 case 1:
123 break;
124 case DS_ABORT_RETRY:
125 rand_sleep(4 * 1000, 1000 * 1000);
126 goto retry;
127 default:
128 fprintf(stderr, "cannot get message count values.\n");
129 exit(EX_ERROR);
130 }
131 list->msgcount[IX_SPAM] = val.spamcount;
132 list->msgcount[IX_GOOD] = val.goodcount;
133
134 if (incr != IX_UNDF)
135 list->msgcount[incr] += msgcount;
136
137 if (decr != IX_UNDF) {
138 if (list->msgcount[decr] > msgcount)
139 list->msgcount[decr] -= msgcount;
140 else
141 list->msgcount[decr] = 0;
142 }
143
144 val.spamcount = list->msgcount[IX_SPAM];
145 val.goodcount = list->msgcount[IX_GOOD];
146
147 switch (ds_set_msgcounts(list->dsh, &val)) {
148 case 0:
149 break;
150 case DS_ABORT_RETRY:
151 rand_sleep(4 * 1000, 1000 * 1000);
152 goto retry;
153 default:
154 fprintf(stderr, "cannot set message count values\n");
155 exit(EX_ERROR);
156 }
157
158 if (DEBUG_REGISTER(1))
159 (void)fprintf(dbgout, "bogofilter: list %s (%s) - %ul spam, %ul good\n",
160 list->listname, list->bfp->filepath, val.spamcount, val.goodcount);
161
162 run_type = save_run_type;
163 }
164