/[imapfilter]/imapfilter/request.c
ViewVC logotype

Contents of /imapfilter/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.20 - (show annotations)
Fri Jan 25 17:10:17 2002 UTC (22 years, 2 months ago) by lefcha
Branch: MAIN
Changes since 1.19: +8 -7 lines
File MIME type: text/plain
Merged changes from version 0.7.2.

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5
6 #include "config.h"
7 #include "imapfilter.h"
8 #include "data.h"
9
10
11 extern unsigned int options;
12 extern unsigned int capabilities;
13
14 static struct {
15 char prefix[NAMESPACE_PREFIX_LEN];
16 char delim;
17 } namesp;
18
19
20 #ifdef DEBUG
21 /*
22 * Test/ping server.
23 */
24 int test(void)
25 {
26 return server_response(imap_noop());
27 }
28 #endif
29
30
31 /*
32 * Check server's capabilities.
33 */
34 int check_capabilities(void)
35 {
36 capabilities = CAPABILITY_NONE;
37
38 return capability_response(imap_capability());
39 }
40
41
42 /*
43 * Get namespace of mail server's mailboxes.
44 */
45 int check_namespace(void)
46 {
47 namesp.prefix[0] = namesp.delim = 0;
48
49 if (!(options & OPTION_NAMESPACE) ||
50 !(capabilities & CAPABILITY_NAMESPACE))
51 return 0;
52 else
53 return namespace_response(imap_namespace(),
54 namesp.prefix, namesp.delim);
55 }
56
57
58 /*
59 * Login to server.
60 */
61 int login(char *user, char *pass)
62 {
63 log_info(LOG_USERNAME, user);
64
65 return server_response(imap_login(user, pass));
66 }
67
68
69 /*
70 * Open mailbox in read-write mode.
71 */
72 int select_mailbox(char *mbox)
73 {
74 int r;
75
76 if (mailbox_status(mbox) == -2)
77 return -2; /* No messages exist. No filters need to
78 be applied. */
79
80 r = select_response(imap_select(apply_namespace(mbox, namesp.prefix,
81 namesp.delim)));
82
83 log_info(LOG_MAILBOX, mbox);
84
85 return r;
86 }
87
88
89 /*
90 * Get mailbox's status.
91 */
92 int mailbox_status(char *mbox)
93 {
94 return status_response(imap_status(apply_namespace(mbox, namesp.prefix,
95 namesp.delim),
96 "MESSAGES RECENT UNSEEN"), mbox);
97 }
98
99
100 /*
101 * Close examined/selected mailbox.
102 */
103 int close_mailbox(void)
104 {
105 return server_response(imap_close());
106 }
107
108
109 /*
110 * Logout from server.
111 */
112 int logout(void)
113 {
114 return server_response(imap_logout());
115 }
116
117
118 /*
119 * Match and apply filters assigned to a mailbox.
120 */
121 int apply_filters(filter_t ** filters)
122 {
123 int i;
124 char *mesgs;
125
126 for (i = 0; filters[i]; i++) {
127 mesgs = NULL;
128
129 if (match_filter(filters[i], &mesgs))
130 continue;
131
132 log_info(LOG_FILTER, filters[i]->key);
133
134 apply_action(mesgs, &(filters[i]->action.type),
135 filters[i]->action.destmbox, filters[i]->action.args);
136
137 xfree(mesgs);
138 }
139
140 return 0;
141 }
142
143
144 /*
145 * Generate the search request by the masks of the filter and try to
146 * match the generated filter.
147 */
148 int match_filter(filter_t * filter, char **mesgs)
149 {
150 char *search;
151
152 if (filter->mode == FILTER_MODE_OR)
153 search = generate_filter_or(filter->masks, filter->masknum,
154 filter->masklen);
155 else
156 search = generate_filter_and(filter->masks, filter->masknum,
157 filter->masklen);
158
159 search_response(imap_search(search), mesgs);
160
161 xfree(search);
162
163 if (!*mesgs)
164 return 1;
165
166 return 0;
167 }
168
169
170 /*
171 * Empty the FIFO inventory.
172 */
173 void empty_fifo(mask_t ** mfifo)
174 {
175 mfifo[0] = NULL;
176
177 queue_fifo(NULL, NULL);
178 dequeue_fifo(NULL);
179 }
180
181
182 /*
183 * Add item to FIFO inventory.
184 */
185 void queue_fifo(mask_t ** mfifo, mask_t * mask)
186 {
187 static unsigned int i;
188
189 if (!mfifo) {
190 i = 0;
191 return;
192 }
193 mfifo[i++] = mask;
194 mfifo[i] = NULL;
195 }
196
197
198 /*
199 * Get next item from FIFO inventory.
200 */
201 mask_t *dequeue_fifo(mask_t ** mfifo)
202 {
203 static unsigned int j;
204
205 if (!mfifo) {
206 j = 0;
207 return NULL;
208 }
209 return mfifo[j++];
210 }
211
212
213 /*
214 * Generate the filter search command from the masks, assuming that
215 * masks are AND-ed.
216 */
217 char *generate_filter_and(mask_t * mask, unsigned int masknum,
218 unsigned int masklen)
219 {
220 const unsigned int searchbuf = masklen + masknum * 6 + 8;
221 unsigned int len = 0;
222 char *search;
223 mask_t *tmp;
224
225 search = (char *) xmalloc(sizeof(char) * searchbuf);
226
227 search[0] = 0;
228
229 tmp = mask;
230 if (!tmp) {
231 strncat(search, "ALL ", searchbuf - len - 1);
232 len += 4;
233 } else
234 while ((tmp = tmp->next)) {
235 if (tmp->type != MASK_TYPE_OR) {
236 strncat(search, "ALL ", searchbuf - len - 1);
237 len += 4;
238 break;
239 }
240 }
241
242 tmp = NULL;
243 while (mask) {
244 tmp = mask;
245 mask = mask->next;
246
247 if (mask && mask->type == MASK_TYPE_OR) {
248 strncat(search, "OR (", searchbuf - len - 1);
249 len += 4;
250
251 strncat(search, tmp->body, searchbuf - len - 1);
252 len = strlen(search);
253 search[len] = ' ';
254 search[++len] = 0;
255
256 search[len - 1] = ')';
257 search[len] = ' ';
258 search[++len] = 0;
259
260 if (!mask->next || mask->next->type != MASK_TYPE_OR) {
261 search[len] = '(';
262 search[++len] = 0;
263 strncat(search, mask->body, searchbuf - len - 1);
264 len = strlen(search);
265 search[len] = ')';
266 search[++len] = ' ';
267 search[++len] = 0;
268 mask = mask->next;
269 }
270 } else {
271 strncat(search, tmp->body, searchbuf - len - 1);
272 len = strlen(search);
273 search[len] = ' ';
274 search[++len] = 0;
275 }
276 }
277
278 search[len - 1] = 0;
279
280 return search;
281 }
282
283
284 /*
285 * Generate the filter search command from the masks, assuming that
286 * masks are OR-ed
287 */
288 char *generate_filter_or(mask_t * mask, unsigned int masknum,
289 unsigned int masklen)
290 {
291 const unsigned int searchbuf = masklen + masknum * 6 + 8;
292 unsigned int len = 0;
293 char *search;
294 mask_t **mfifo; /* Mailbox FIFO queue. */
295 mask_t *mf; /* Mask returned from FIFO. */
296
297 search = (char *) xmalloc(sizeof(char) * searchbuf);
298 mfifo = (mask_t **) xmalloc(sizeof(mask_t *) * (masknum + 1));
299
300 search[0] = 0;
301 empty_fifo(mfifo);
302
303 strncat(search, "ALL ", searchbuf - len - 1);
304 len += 4;
305
306 while (mask) {
307 queue_fifo(mfifo, mask);
308 mask = mask->next;
309
310 while (mask && mask->type == MASK_TYPE_AND) {
311 queue_fifo(mfifo, mask);
312 mask = mask->next;
313 }
314
315 if (mask) {
316 if (len == 4 && search[0] == 'A')
317 search[0] = len = 0;
318
319 strncat(search, "OR ", searchbuf - len - 1);
320 len += 3;
321 }
322 if (search[0] != 'A') {
323 search[len] = '(';
324 search[++len] = 0;
325 }
326 while ((mf = dequeue_fifo(mfifo))) {
327 strncat(search, mf->body, searchbuf - len - 1);
328 len = strlen(search);
329 search[len] = ' ';
330 search[++len] = 0;
331 }
332
333 if (strchr(search, '(')) {
334 search[len - 1] = ')';
335 search[len] = ' ';
336 search[++len] = 0;
337 }
338 empty_fifo(mfifo);
339 }
340
341 search[len - 1] = 0;
342
343 xfree(mfifo);
344
345 return search;
346 }
347
348
349 /*
350 * Apply the appropriate action.
351 */
352 int apply_action(char *mesgs, unsigned int *type, char *destmbox,
353 char *args)
354 {
355 unsigned int cnt;
356
357 if (!*mesgs)
358 return 0;
359
360 log_info(LOG_ACTION, type);
361 log_info(LOG_DESTINATION_MAILBOX, destmbox);
362
363 cnt = convert_messages(mesgs);
364
365 switch (*type) {
366 case FILTER_ACTION_DELETE:
367 info("%d message%s deleted.\n", cnt, plural(cnt));
368 action_delete(mesgs, args);
369 break;
370 case FILTER_ACTION_COPY:
371 info("%d message%s copied to mailbox \"%s\".\n", cnt, plural(cnt),
372 destmbox);
373 action_copy(mesgs, apply_namespace(destmbox, namesp.prefix,
374 namesp.delim), args);
375 break;
376 case FILTER_ACTION_MOVE:
377 info("%d message%s moved to mailbox \"%s\".\n", cnt, plural(cnt),
378 destmbox);
379 action_move(mesgs, apply_namespace(destmbox, namesp.prefix,
380 namesp.delim), args);
381 break;
382 case FILTER_ACTION_LIST:
383 info("%d message%s listed.\n", cnt, plural(cnt));
384 action_list(mesgs, args);
385 break;
386 }
387
388 if (!*args)
389 log_info(LOG_WRITE, NULL);
390
391 return 0;
392 }
393
394
395 /*
396 * Delete messages and optionally list some of their headers.
397 */
398 int action_delete(char *mesgs, char *args)
399 {
400 const char *delim = " ";
401 char *tok, *mcp, *m, *acp = NULL, *occur;
402
403 m = mcp = xstrdup(mesgs);
404
405 if (*args) {
406 acp = xstrdup(args);
407 while ((occur = strchr(acp, ',')))
408 *occur = ' ';
409 }
410 while ((tok = strsep(&m, delim))) {
411 if (*args)
412 fetch_response(imap_fetch(tok, acp, 0));
413
414 server_response(imap_store(tok, "\\Deleted"));
415 }
416
417 xfree(mcp);
418
419 if (*args)
420 xfree(acp);
421
422 return 0;
423 }
424
425
426 /*
427 * Copy messages to specified mailbox.
428 */
429 int action_copy(char *mesgs, char *destmbox, char *args)
430 {
431 int r = 0;
432 const char *delim = " ";
433 char *tok, *mcp, *m, *acp = NULL, *occur;
434
435 m = mcp = xstrdup(mesgs);
436
437 if (*args) {
438 acp = xstrdup(args);
439
440 while ((occur = strchr(acp, ',')))
441 *occur = ' ';
442 }
443 while ((tok = strsep(&m, delim))) {
444 if (*args)
445 fetch_response(imap_fetch(tok, acp, 0));
446
447 if ((r = copy_response(imap_copy(tok, destmbox))) == RESPONSE_TRYCREATE)
448 if (!server_response(imap_create(destmbox)))
449 r = copy_response(imap_copy(tok, destmbox));
450 }
451
452 xfree(mcp);
453
454 if (*args)
455 xfree(acp);
456
457 return r;
458 }
459
460
461 /*
462 * Move messages to specified mailbox.
463 */
464 int action_move(char *mesgs, char *destmbox, char *args)
465 {
466 if (!action_copy(mesgs, destmbox, args))
467 action_delete(mesgs, "\0");
468
469 /* CLOSE -> SELECT much faster than EXPUNGE -> SELECT */
470 /* server_response(imap_expunge()); */
471
472 return 0;
473 }
474
475
476 /*
477 * List user selected headers of messages.
478 */
479 int action_list(char *mesgs, char *args)
480 {
481 const char *delim = " ";
482 char *tok, *mcp, *m, *acp, *occur;
483
484 if (!*args)
485 return 0;
486
487 m = mcp = xstrdup(mesgs);
488 acp = xstrdup(args);
489
490 while ((occur = strchr(acp, ',')))
491 *occur = ' ';
492
493 while ((tok = strsep(&m, delim)))
494 fetch_response(imap_fetch(tok, acp, 1));
495
496 xfree(mcp);
497 xfree(acp);
498
499 return 0;
500 }
501
502
503 /*
504 * Convert messages with contiguous sequence number to the corresponding
505 * number range, eg. 1 2 3 5 7 8 --> 1:3 5 7:8
506 */
507 unsigned int convert_messages(char *mesgs)
508 {
509 unsigned int cnt, maxlen;
510 unsigned int start, end, tmp;
511 char *cp, *tail, *m;
512
513 cnt = start = end = tmp = 0;
514 maxlen = strlen(mesgs) + 1;
515 tail = NULL;
516
517 cp = xstrdup(mesgs);
518 m = mesgs;
519
520 start = (unsigned int) strtoul(cp, &tail, 10);
521 cnt++;
522 end = start;
523
524 do {
525 if (tail) {
526 tmp = (unsigned int) strtoul(tail, &tail, 10);
527 if (tmp)
528 cnt++;
529 else
530 tail = NULL;
531 }
532 if (tmp == end + 1)
533 end++;
534 else {
535 if (start == end) {
536 xstrncpy(m, ultostr(start, 10), maxlen);
537 m += strlen(m);
538 } else {
539 xstrncpy(m, ultostr(start, 10), maxlen - 1);
540 m += strlen(m);
541 *m = ':';
542 *++m = 0;
543 xstrncpy(m, ultostr(end, 10), maxlen);
544 m += strlen(m);
545 }
546
547 if (tail && m - mesgs < maxlen) {
548 *m = ' ';
549 *++m = 0;
550 }
551 start = end = tmp;
552 }
553 } while (tmp);
554
555 xfree(cp);
556
557 return cnt;
558 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26