ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/repos/FreeBSDAdmin/Mail/SpamUpdate.c
(Generate patch)

Comparing FreeBSDAdmin/Mail/SpamUpdate.c (file contents):
Revision 815 by douglas, 2006-07-03T14:03:04-07:00 vs.
Revision 827 by douglas, 2006-07-06T01:41:14-07:00

# Line 6 | Line 6
6  
7   #include <assert.h>
8   #include <sys/types.h>
9 #include <regex.h>
9   #include <setjmp.h>
10 + #include <signal.h>
11   #include <stdbool.h>
12   #include <stdio.h>
13   #include <sys/wait.h>
# Line 17 | Line 17
17   #define NEGATIVE "Spam/False Negative"
18   #define POSITIVE "Spam/False Positive"
19  
20 < #define SED "/usr/bin/sed"
21 < #define ASSASSIN "/usr/local/bin/spamassassin"
20 > /*#define SED "/usr/bin/sed"
21 > #define ASSASSIN "/usr/local/bin/spamassassin"*/
22 > #define SPAMC "/usr/local/bin/spamc"
23 > #define SPAMD "/var/run/spamd/spamd.sock"
24  
25 < #define INDENT "s/^/    /"
26 < #define PERIOD "s/[^.]$/&./"
25 > /*#define INDENT "s/^/    /"
26 > #define PERIOD "s/[^.]$/&./"*/
27  
28   #define TEMP "/tmp/SpamUpdate.XXXXXX"
29  
30   static jmp_buf environment;
31   static char *error = NULL;
32   static bool debug = false;
33 + static sigset_t set;
34   static MAILSTREAM *streams[2];
35 + static uint8_t critical = 0;
36   static unsigned long *messages[] = { NULL, NULL };
37   static size_t counts[] = { 0, 0 };
38  
39 < /*static*/ int check(int value, jmp_buf environment)
39 > static int check(int value, jmp_buf environment)
40   {
41          if (value == -1)
42                  longjmp(environment, 1);
# Line 40 | Line 44 | static size_t counts[] = { 0, 0 };
44          return value;
45   }
46  
47 < /*static*/ char *fcheck(char *value, FILE *stream, jmp_buf environment)
47 > /*static char *fcheck(char *value, FILE *stream, jmp_buf environment)
48   {
49          if (!value)
50          {
# Line 58 | Line 62 | static size_t counts[] = { 0, 0 };
62          }
63  
64          return value;
65 < }
65 > }*/
66  
67   static void *mcheck(void *value, jmp_buf environment)
68   {
# Line 68 | Line 72 | static void *mcheck(void *value, jmp_buf
72          return value;
73   }
74  
75 < /*static*/ int regcheck(int value, const regex_t *regex, jmp_buf environment)
72 < {
73 <        if (value && value != REG_NOMATCH)
74 <        {
75 <                char exception[regerror(value, regex, NULL, 0)];
76 <
77 <                regerror(value, regex, exception, sizeof (exception));
78 <                longjmp(environment, (int)exception);
79 <        }
80 <
81 <        return value;
82 < }
83 <
84 < static void learn(jmp_buf environment)
75 > static void learn()
76   {
77 <        typedef struct { const char *verb, *args, *mailbox; } Job;
77 >        typedef struct { const char *verb, *learn, *collab, *mailbox; } Job;
78          
79 <        Job jobs[] = { { .verb = "reporting", .args = "-rR", .mailbox = NEGATIVE }, { .verb = "revoking", .args = "-kW", .mailbox = POSITIVE } };
79 >        Job jobs[] = { { .verb = "report", .learn = "spam", .collab = "report", .mailbox = NEGATIVE }, { .verb = "revok", .learn = "ham", .collab = "revoke", .mailbox = POSITIVE } };
80  
81          for (Job *job = jobs; job != jobs + sizeof (jobs) / sizeof (*jobs); ++job)
82          {
83 <                printf("\nLearning and %s from the %s mailbox:\n", job->verb, job->mailbox);
83 >                printf("\nLearning and %sing from the %s mailbox:\n", job->verb, job->mailbox);
84  
85                  SEARCHPGM search = { .undeleted = 1 };
86                  
87                  mail_search_full(streams[job - jobs], NIL, &search, SE_UID);
88  
89 <                unsigned long *messages_ = messages[job - jobs];
90 <                size_t count = counts[job - jobs];
91 <                char files[count][sizeof (TEMP) / sizeof (char)];
89 >                const unsigned long *messages_ = messages[job - jobs];
90 >                const size_t count = counts[job - jobs];
91 >                size_t learned = 0;
92  
93                  for (size_t index = 0; index != count; ++index)
94                  {
95                          unsigned long size;
96                          char *header = mcheck(mail_fetchheader_full(streams[job - jobs], messages_[index], NIL, &size, FT_UID), environment);
97 +                        char file[sizeof (TEMP) / sizeof (char)] = TEMP;
98 +                        int file_ = check(mkstemp(file), environment);
99 +
100 +                        check(write(file_, header, size), environment);
101  
102 <                        strcpy(files[index], TEMP);
102 >                        char *text = mcheck(mail_fetchtext_full(streams[job - jobs], messages_[index], &size, FT_UID), environment);
103  
104 <                        int file = check(mkstemp(files[index]), environment);
104 >                        check(write(file_, text, size), environment);
105 >                        check(lseek(file_, 0, SEEK_SET), environment);
106  
107 <                        check(write(file, header, size), environment);
107 >                        pid_t learn;
108  
109 <                        char *text = mcheck(mail_fetchtext_full(streams[job - jobs], messages_[index], &size, FT_UID), environment);
109 >                        if (!(learn = check(fork(), environment)))
110 >                        {
111 >                                check(dup2(file_, 0), environment);
112 >                                check(execl(SPAMC, "spamc", "-L", job->learn, "-U", SPAMD, NULL), environment);
113 >                        }
114 >
115 >                        pid_t collab;
116 >
117 >                        if (!(collab = check(fork(), environment)))
118 >                        {
119 >                                check(dup2(file_, 0), environment);
120 >                                check(execl(SPAMC, "spamc", "-L", job->collab, "-U", SPAMD, NULL), environment);
121 >                        }
122 >
123 >                        check(close(file_), environment);
124 >                        check(unlink(file), environment);
125 >
126 >                        int status;
127  
128 <                        check(write(file, text, size), environment);
129 <                        check(close(file), environment);
128 >                        check(waitpid(learn, &status, 0), environment);
129 >
130 >                        if (WEXITSTATUS(status) == 5)
131 >                                ++learned;
132 >
133 >                        check(waitpid(collab, &status, 0), environment);
134                  }
135  
136 <                int pipe_[2];
136 >                printf("    %u message(s) learned and %u message(s) %sed.\n", learned, count, job->verb);
137 >        }
138 > }
139 >
140 > // XXX: this is going to be moved to a deliver daemon that will run more often
141 > /*static void deliver()
142 > {
143 >        printf("\nDelivering messages from the " POSITIVE " mailbox:\n");
144 >
145 >        const unsigned long *messages_ = messages[1];
146 >        const size_t count = counts[1];
147 >
148 >        streams[0] = mcheck(mail_open(streams[0], "INBOX", (debug ? OP_DEBUG : 0) | OP_SHORTCACHE), environment);
149  
150 <                check(pipe(pipe_), environment);
150 >        for (int index = 0; index != count; ++index)
151 >        {
152 >                int out[2], in[2];
153 >
154 >                check(pipe(out), environment);
155 >                check(pipe(in), environment);
156  
157                  pid_t assassin;
158  
159                  if (!(assassin = check(fork(), environment)))
160                  {
161 <                        check(dup2(pipe_[1], 1), environment);
162 <                        check(close(pipe_[0]), environment);
161 >                        check(dup2(out[0], 0), environment);
162 >                        check(close(out[1]), environment);
163 >                        check(dup2(in[1], 1), environment);
164 >                        check(close(in[0]), environment);
165 >                        check(execl(ASSASSIN, "spamassassin", "-d", NULL), environment);
166 >                }
167  
168 <                        const char *args[count ? count + 3 : 5];
169 <                        
132 <                        args[0] = "spamassassin";
133 <                        args[1] = job->args;
134 <
135 <                        if (count)
136 <                                for (size_t index = 0; index != count; ++index)
137 <                                        args[index + 2] = files[index];
138 <                        else
139 <                        {
140 <                                args[2] = "--mbox";
141 <                                args[3] = "/dev/null";
142 <                        }
168 >                check(close(out[0]), environment);
169 >                check(close(in[1]), environment);
170  
171 <                        args[count ? count + 2 : 4] = NULL;
171 >                unsigned long size;
172 >                char *header = mcheck(mail_fetchheader_full(streams[1], messages_[index], NIL, &size, FT_UID), environment);
173  
174 <                        check(execv(ASSASSIN, (char *const *)args), environment);
175 <                }
174 >                check(write(out[1], header, size), environment);
175 >
176 >                char *text = mcheck(mail_fetchtext_full(streams[1], messages_[index], &size, FT_UID), environment);
177 >
178 >                check(write(out[1], text, size), environment);
179 >                check(close(out[1]), environment);
180  
181 <                check(close(pipe_[1]), environment);
181 >                FILE *assassin_ = fdopen(in[0], "r");
182 >                size_t size_;
183 >                bool header_ = true;
184 >                char *message = NULL;
185  
186 <                pid_t sed;
186 >                size = 0;
187  
188 <                if (!(sed = check(fork(), environment)))
188 >                do
189                  {
190 <                        check(dup2(pipe_[0], 0), environment);
191 <                        check(execl(SED, "sed", "-e", INDENT, "-e", PERIOD, NULL), environment);
190 >                        char *line = fcheck(fgetln(assassin_, &size_), assassin_, environment);
191 >
192 >                        message = message ? realloc(message, (size + size_) * sizeof (char)) : malloc((size + size_) * sizeof (char));
193 >
194 >                        memcpy(message + size, line, size_);
195 >
196 >                        size += size_;
197 >
198 >                        if (header_)
199 >                        {
200 >                                if (size_ == 1)
201 >                                {
202 >                                        assert(*line == '\n');
203 >
204 >                                        header_ = false;
205 >
206 >                                        goto crlf;
207 >                                }
208 >                                else if (size_ == 2 && !memcmp(line, "\r\n", 2))
209 >                                        header_ = false;
210 >                                else if (!(size_ > 2 && !memcmp(line + size_ - 2, "\r\n", 2)))
211 >                                {
212 > crlf:                           assert(message);
213 >
214 >                                        message = realloc(message, ++size * sizeof (char));
215 >
216 >                                        memcpy(message + size - 2, "\r\n", 2);
217 >                                }
218 >                        }
219                  }
220 +                while (size_ != 0);
221  
222 <                check(close(pipe_[0]), environment);
222 >                if (fclose(assassin_))
223 >                        longjmp(environment, 1);
224  
225                  int status;
226  
227                  check(waitpid(assassin, &status, 0), environment);
228 <                check(waitpid(sed, &status, 0), environment);
228 >
229 >                STRING message_;
230 >
231 >                INIT(&message_, mail_string, message, size);
232 >                mcheck((void *)mail_append_full(streams[0], "INBOX", "\\Seen", NIL, &message_), environment);
233 >                free(message);
234 >        }
235 >
236 >        streams[0] = mcheck(mail_open(streams[0], NEGATIVE, debug ? OP_DEBUG : 0), environment);
237 >
238 >        printf("    %u message(s) delivered.\n", count);
239 > }*/
240 >
241 > void delete()
242 > {
243 >        char *mailboxes[] = { NEGATIVE, POSITIVE };
244 >
245 >        for (char **mailbox = mailboxes; mailbox != mailboxes + sizeof (mailboxes) / sizeof (*mailboxes); ++mailbox)
246 >        {
247 >                printf("\nDeleting messages from the %s mailbox:\n", *mailbox);
248 >
249 >                const unsigned long *messages_ = messages[mailbox - mailboxes];
250 >                const size_t count = counts[mailbox - mailboxes];
251 >                char *sequence = calloc(1, sizeof (char));
252 >                size_t size = 1;
253  
254                  for (size_t index = 0; index != count; ++index)
255 <                        check(unlink(files[index]), environment);
255 >                {
256 >                        char *message;
257 >
258 >                        asprintf(&message, "%lu%s", messages_[index], index + 1 != count ? "," : "");
259 >
260 >                        sequence = realloc(sequence, (size += strlen(message)) * sizeof (char));
261 >
262 >                        strlcat(sequence, message, size);
263 >                        free(message);
264 >                }
265 >
266 >                mail_setflag_full(streams[mailbox - mailboxes], sequence, "\\Deleted", ST_UID | ST_SILENT);
267 >                free(sequence);
268 >                printf("    %u message(s) marked deleted.\n", count);
269          }
270   }
271  
# Line 197 | Line 298 | int main(int argc, char *argv[])
298                  else
299                          return printf("Usage: %s [-debug]\n", argv[0]), 1;
300  
301 <        printf("Information:\n    If you receive Spam in your Inbox mailbox, copy it to the " NEGATIVE " mailbox.\n\n    If you receive mail that is not Spam in your Assassin mailbox, copy it to the " POSITIVE " mailbox.\n");
301 >        printf("Information:\n    If you receive spam in your Inbox mailbox, copy it to the " NEGATIVE " mailbox.\n\n    If you receive mail that is not spam in your Spam/Assassin mailbox, copy it to the " POSITIVE " mailbox.\n");
302 >
303 >        check(sigemptyset(&set), environment);
304 >        check(sigaddset(&set, SIGHUP), environment);
305 >        check(sigaddset(&set, SIGINT), environment);
306  
307   #       include <c-client/linkage.c>
308  
309          streams[0] = mcheck(mail_open(NIL, NEGATIVE, debug ? OP_DEBUG : 0), environment);
310          streams[1] = mcheck(mail_open(NIL, POSITIVE, debug ? OP_DEBUG : 0), environment);
311  
312 <        learn(environment);
312 >        learn();
313 >        //deliver();
314 >        delete();
315          mail_close(streams[0]);
316          mail_close(streams[1]);
317 +        free(messages[0]);
318 +        free(messages[1]);
319  
320          return 0;
321   }
# Line 224 | Line 333 | void mm_searched(MAILSTREAM *stream, uns
333                          assert(messages[index]);
334  
335                          messages[index][counts[index] - 1] = number;
336 +
337 +                        break;
338                  }
339   }
340  
# Line 248 | Line 359 | void mm_login(NETMBX *mb, char *user, ch
359  
360   void mm_critical(MAILSTREAM *stream)
361   {
362 <        fprintf(stderr, "critical\n");
362 >        if (!critical++)
363 >                check(sigprocmask(SIG_BLOCK, &set, NULL), environment);
364   }
365  
366   void mm_nocritical(MAILSTREAM *stream)
367   {
368 <        fprintf(stderr, "nocritical\n");
368 >        if (!--critical)
369 >                check(sigprocmask(SIG_UNBLOCK, &set, NULL), environment);
370   }
371  
372   long mm_diskerror(MAILSTREAM *stream, long errcode, long serious)

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines