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

Contents of /imapfilter/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.12 - (show annotations)
Tue Nov 6 17:41:27 2001 UTC (22 years, 5 months ago) by lefcha
Branch: MAIN
Changes since 1.11: +14 -13 lines
File MIME type: text/plain
Dynamically allocate response buffer.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26