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

Contents of /imapfilter/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.10 - (show annotations)
Mon Oct 8 08:52:49 2001 UTC (22 years, 5 months ago) by lefcha
Branch: MAIN
CVS Tags: release-0_6_2
Branch point for: release-0_6_2-patches
Changes since 1.9: +46 -70 lines
File MIME type: text/plain
Fixes and improvements on IMAP4rev1 compliance.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26