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

Contents of /imapfilter/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.17.2.2 - (show annotations)
Wed Dec 5 21:17:11 2001 UTC (22 years, 3 months ago) by lefcha
Branch: release-0_7-patches
Changes since 1.17.2.1: +5 -5 lines
File MIME type: text/plain
Small fix.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26