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

Annotation of /imapfilter/request.c

Parent Directory Parent Directory | Revision Log Revision Log


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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26