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

Contents of /imapfilter/request.c

Parent Directory Parent Directory | Revision Log Revision Log


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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26