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

Contents of /imapfilter/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.17.2.1 - (show annotations)
Wed Dec 5 09:55:12 2001 UTC (22 years, 4 months ago) by lefcha
Branch: release-0_7-patches
Changes since 1.17: +30 -3 lines
File MIME type: text/plain
Take into consideration namespace.

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 apply_namespace(filters[i]->action.destmbox,
133 namesp.prefix, namesp.delim),
134 filters[i]->action.args);
135
136 free(mesgs);
137 }
138
139 return 0;
140 }
141
142
143 /*
144 * Generate the search request by the masks of the filter and try to
145 * match the generated filter.
146 */
147 int match_filter(filter_t * filter, char **mesgs)
148 {
149 char *search;
150
151 if (filter->mode == FILTER_MODE_OR)
152 search = generate_filter_or(filter->masks, filter->masknum,
153 filter->masklen);
154 else
155 search = generate_filter_and(filter->masks, filter->masknum,
156 filter->masklen);
157
158 search_response(imap_search(search), mesgs);
159
160 free(search);
161
162 if (!*mesgs)
163 return 1;
164
165 return 0;
166 }
167
168
169 /*
170 * Empty the FIFO inventory.
171 */
172 void empty_fifo(mask_t ** mfifo)
173 {
174 mfifo[0] = NULL;
175
176 queue_fifo(NULL, NULL);
177 dequeue_fifo(NULL);
178 }
179
180
181 /*
182 * Add item to FIFO inventory.
183 */
184 void queue_fifo(mask_t ** mfifo, mask_t * mask)
185 {
186 static unsigned int i;
187
188 if (!mfifo) {
189 i = 0;
190 return;
191 }
192 mfifo[i++] = mask;
193 mfifo[i] = NULL;
194 }
195
196
197 /*
198 * Get next item from FIFO inventory.
199 */
200 mask_t *dequeue_fifo(mask_t ** mfifo)
201 {
202 static unsigned int j;
203
204 if (!mfifo) {
205 j = 0;
206 return NULL;
207 }
208 return mfifo[j++];
209 }
210
211
212 /*
213 * Generate the filter search command from the masks, assuming that
214 * masks are AND-ed.
215 */
216 char *generate_filter_and(mask_t * mask, unsigned int masknum,
217 unsigned int masklen)
218 {
219 const unsigned int searchbuf = masklen + masknum * 6 + 8;
220 unsigned int len = 0;
221 char *search;
222 mask_t *tmp;
223
224 search = (char *) xmalloc(sizeof(char) * searchbuf);
225
226 search[0] = 0;
227
228 tmp = mask;
229 if (!tmp) {
230 strncat(search, "ALL ", searchbuf - len - 1);
231 len += 4;
232 } else
233 while ((tmp = tmp->next)) {
234 if (tmp->type != MASK_TYPE_OR) {
235 strncat(search, "ALL ", searchbuf - len - 1);
236 len += 4;
237 break;
238 }
239 }
240
241 tmp = NULL;
242 while (mask) {
243 tmp = mask;
244 mask = mask->next;
245
246 if (mask && mask->type == MASK_TYPE_OR) {
247 strncat(search, "OR (", searchbuf - len - 1);
248 len += 4;
249
250 strncat(search, tmp->body, searchbuf - len - 1);
251 len = strlen(search);
252 search[len] = ' ';
253 search[++len] = 0;
254
255 search[len - 1] = ')';
256 search[len] = ' ';
257 search[++len] = 0;
258
259 if (!mask->next || mask->next->type != MASK_TYPE_OR) {
260 search[len] = '(';
261 search[++len] = 0;
262 strncat(search, mask->body, searchbuf - len - 1);
263 len = strlen(search);
264 search[len] = ')';
265 search[++len] = ' ';
266 search[++len] = 0;
267 mask = mask->next;
268 }
269 } else {
270 strncat(search, tmp->body, searchbuf - len - 1);
271 len = strlen(search);
272 search[len] = ' ';
273 search[++len] = 0;
274 }
275 }
276
277 search[len - 1] = 0;
278
279 return search;
280 }
281
282
283 /*
284 * Generate the filter search command from the masks, assuming that
285 * masks are OR-ed
286 */
287 char *generate_filter_or(mask_t * mask, unsigned int masknum,
288 unsigned int masklen)
289 {
290 const unsigned int searchbuf = masklen + masknum * 6 + 8;
291 unsigned int len = 0;
292 char *search;
293 mask_t **mfifo; /* Mailbox FIFO queue. */
294 mask_t *mf; /* Mask returned from FIFO. */
295
296 search = (char *) xmalloc(sizeof(char) * searchbuf);
297 mfifo = (mask_t **) xmalloc(sizeof(mask_t *) * (masknum + 1));
298
299 search[0] = 0;
300 empty_fifo(mfifo);
301
302 strncat(search, "ALL ", searchbuf - len - 1);
303 len += 4;
304
305 while (mask) {
306 queue_fifo(mfifo, mask);
307 mask = mask->next;
308
309 while (mask && mask->type == MASK_TYPE_AND) {
310 queue_fifo(mfifo, mask);
311 mask = mask->next;
312 }
313
314 if (mask) {
315 if (len == 4 && search[0] == 'A')
316 search[0] = len = 0;
317
318 strncat(search, "OR ", searchbuf - len - 1);
319 len += 3;
320 }
321 if (search[0] != 'A') {
322 search[len] = '(';
323 search[++len] = 0;
324 }
325 while ((mf = dequeue_fifo(mfifo))) {
326 strncat(search, mf->body, searchbuf - len - 1);
327 len = strlen(search);
328 search[len] = ' ';
329 search[++len] = 0;
330 }
331
332 if (strchr(search, '(')) {
333 search[len - 1] = ')';
334 search[len] = ' ';
335 search[++len] = 0;
336 }
337 empty_fifo(mfifo);
338 }
339
340 search[len - 1] = 0;
341
342 free(mfifo);
343
344 return search;
345 }
346
347
348 /*
349 * Apply the appropriate action.
350 */
351 int apply_action(char *mesgs, unsigned int *type, char *destmbox,
352 char *args)
353 {
354 unsigned int cnt;
355
356 if (!*mesgs)
357 return 0;
358
359 log_info(LOG_ACTION, type);
360 log_info(LOG_DESTINATION_MAILBOX, destmbox);
361
362 cnt = convert_messages(mesgs);
363
364 switch (*type) {
365 case FILTER_ACTION_DELETE:
366 info("%d message%s deleted.\n", cnt, plural(cnt));
367 action_delete(mesgs, args);
368 break;
369 case FILTER_ACTION_COPY:
370 info("%d message%s copied to mailbox %s.\n", cnt, plural(cnt),
371 destmbox);
372 action_copy(mesgs, destmbox, args);
373 break;
374 case FILTER_ACTION_MOVE:
375 info("%d message%s moved to mailbox %s.\n", cnt, plural(cnt),
376 destmbox);
377 action_move(mesgs, destmbox, 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