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

Annotation of /imapfilter/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.50 - (hide annotations)
Sat Jul 26 19:40:20 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
Changes since 1.49: +19 -5 lines
File MIME type: text/plain
Added CRAM-MD5 support.

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.45 #include <time.h>
6 lefcha 1.1
7     #include "config.h"
8     #include "imapfilter.h"
9     #include "data.h"
10    
11    
12 lefcha 1.21 extern int sockpri, sockaux;
13 lefcha 1.1 extern unsigned int options;
14 lefcha 1.41 extern char charset[CHARSET_LEN];
15 lefcha 1.50 extern unsigned int capspri, capsaux;
16 lefcha 1.18
17 lefcha 1.21 namesp_t nsppri, nspaux; /* Primary and auxiliary namespace. */
18 lefcha 1.1
19 lefcha 1.3
20 lefcha 1.2 #ifdef DEBUG
21 lefcha 1.1 /*
22     * Test/ping server.
23     */
24 lefcha 1.42 int
25     test(int *sock)
26 lefcha 1.1 {
27 lefcha 1.42 return server_response(sock, imap_noop(sock));
28 lefcha 1.1 }
29 lefcha 1.25
30 lefcha 1.2 #endif
31 lefcha 1.1
32 lefcha 1.10
33 lefcha 1.1 /*
34 lefcha 1.10 * Check server's capabilities.
35 lefcha 1.1 */
36 lefcha 1.42 int
37     check_capabilities(int *sock)
38 lefcha 1.1 {
39 lefcha 1.50 if (sock == &sockpri)
40     capspri = CAPABILITY_NONE;
41     else
42     capsaux = CAPABILITY_NONE;
43 lefcha 1.18
44 lefcha 1.42 return capability_response(sock, imap_capability(sock));
45 lefcha 1.1 }
46    
47    
48     /*
49 lefcha 1.18 * Get namespace of mail server's mailboxes.
50     */
51 lefcha 1.42 int
52     check_namespace(int *sock, namesp_t * nsp)
53 lefcha 1.18 {
54 lefcha 1.50 unsigned int *caps;
55    
56     caps = (sock == &sockpri ? &capspri : &capsaux);
57 lefcha 1.42 nsp->prefix[0] = nsp->delim = '\0';
58 lefcha 1.18
59 lefcha 1.42 if (!(options & OPTION_NAMESPACE) ||
60 lefcha 1.50 !(*caps & CAPABILITY_NAMESPACE))
61 lefcha 1.42 return 0;
62     else
63     return namespace_response(sock, imap_namespace(sock), nsp);
64 lefcha 1.18 }
65    
66    
67     /*
68 lefcha 1.10 * Login to server.
69 lefcha 1.8 */
70 lefcha 1.42 int
71     login(int *sock, char *user, char *pass)
72 lefcha 1.8 {
73 lefcha 1.42 return server_response(sock, imap_login(sock, user, pass));
74 lefcha 1.21 }
75    
76    
77    
78     /*
79     * Check if a mailbox exists.
80     */
81 lefcha 1.42 int
82 lefcha 1.45 check_mailbox(int *sock, char *mbox)
83 lefcha 1.21 {
84 lefcha 1.45 return server_response(sock, imap_status(sock, mbox, "MESSAGES"));
85 lefcha 1.8 }
86    
87 lefcha 1.18
88 lefcha 1.8 /*
89 lefcha 1.3 * Open mailbox in read-write mode.
90 lefcha 1.1 */
91 lefcha 1.42 int
92     select_mailbox(int *sock, char *mbox, namesp_t * nsp)
93 lefcha 1.1 {
94 lefcha 1.42 int r;
95 lefcha 1.5
96 lefcha 1.42 if (mailbox_status(sock, mbox, nsp) == -2)
97     return -2; /* No messages exist. No filters need to be
98     * applied. */
99 lefcha 1.5
100 lefcha 1.42 r = select_response(sock, imap_select(sock,
101     apply_namespace(mbox, nsp->prefix,
102     nsp->delim)));
103 lefcha 1.5
104 lefcha 1.42 log_info(LOG_MAILBOX, mbox);
105 lefcha 1.5
106 lefcha 1.42 return r;
107 lefcha 1.1 }
108    
109    
110     /*
111 lefcha 1.3 * Get mailbox's status.
112 lefcha 1.1 */
113 lefcha 1.42 int
114     mailbox_status(int *sock, char *mbox, namesp_t * nsp)
115 lefcha 1.1 {
116 lefcha 1.42 return status_response(sock, imap_status(sock,
117     apply_namespace(mbox, nsp->prefix, nsp->delim),
118     "MESSAGES RECENT UNSEEN"), mbox);
119 lefcha 1.16 }
120 lefcha 1.5
121 lefcha 1.9
122 lefcha 1.1 /*
123     * Close examined/selected mailbox.
124     */
125 lefcha 1.42 int
126     close_mailbox(int *sock)
127 lefcha 1.1 {
128 lefcha 1.42 return server_response(sock, imap_close(sock));
129 lefcha 1.1 }
130    
131    
132     /*
133     * Logout from server.
134     */
135 lefcha 1.42 int
136     logout(int *sock)
137 lefcha 1.1 {
138 lefcha 1.42 return logout_response(sock, imap_logout(sock));
139 lefcha 1.1 }
140    
141    
142     /*
143     * Match and apply filters assigned to a mailbox.
144     */
145 lefcha 1.42 int
146 lefcha 1.47 apply_filters(char *mbox, filter_t ** filters)
147 lefcha 1.1 {
148 lefcha 1.42 int i;
149     char *mesgs;
150 lefcha 1.1
151 lefcha 1.42 for (i = 0; filters[i] != NULL; i++) {
152     mesgs = NULL;
153 lefcha 1.1
154 lefcha 1.42 if (match_filter(filters[i], &mesgs))
155     continue;
156 lefcha 1.5
157 lefcha 1.42 log_info(LOG_FILTER, filters[i]->key);
158 lefcha 1.1
159 lefcha 1.47 apply_action(mbox, mesgs, &(filters[i]->action.type),
160 lefcha 1.42 filters[i]->action.raccount, filters[i]->action.destmbox,
161     &filters[i]->action.msgflags, filters[i]->action.args);
162 lefcha 1.12
163 lefcha 1.42 xfree(mesgs);
164     }
165 lefcha 1.1
166 lefcha 1.42 return 0;
167 lefcha 1.1 }
168    
169    
170     /*
171     * Generate the search request by the masks of the filter and try to
172     * match the generated filter.
173     */
174 lefcha 1.42 int
175     match_filter(filter_t * filter, char **mesgs)
176 lefcha 1.1 {
177 lefcha 1.42 char *search;
178 lefcha 1.5
179 lefcha 1.42 if (filter->mode == FILTER_MODE_OR)
180     search = generate_filter_or(filter->masks, filter->masknum,
181     filter->masklen);
182     else
183     search = generate_filter_and(filter->masks, filter->masknum,
184     filter->masklen);
185 lefcha 1.1
186 lefcha 1.42 search_response(&sockpri, imap_search(&sockpri, charset, search),
187     mesgs);
188 lefcha 1.5
189 lefcha 1.42 xfree(search);
190 lefcha 1.5
191 lefcha 1.42 if (*mesgs == '\0')
192     return 1;
193 lefcha 1.5
194 lefcha 1.42 return 0;
195 lefcha 1.1 }
196    
197    
198     /*
199     * Empty the FIFO inventory.
200     */
201 lefcha 1.42 void
202     empty_fifo(mask_t ** mfifo)
203 lefcha 1.1 {
204 lefcha 1.42 mfifo[0] = NULL;
205 lefcha 1.1
206 lefcha 1.42 queue_fifo(NULL, NULL);
207     dequeue_fifo(NULL);
208 lefcha 1.1 }
209    
210    
211     /*
212     * Add item to FIFO inventory.
213     */
214 lefcha 1.42 void
215     queue_fifo(mask_t ** mfifo, mask_t * mask)
216 lefcha 1.1 {
217 lefcha 1.42 static unsigned int i;
218 lefcha 1.1
219 lefcha 1.42 if (mfifo == NULL) {
220     i = 0;
221     return;
222     }
223     mfifo[i++] = mask;
224     mfifo[i] = NULL;
225 lefcha 1.1 }
226    
227    
228     /*
229     * Get next item from FIFO inventory.
230     */
231 lefcha 1.42 mask_t *
232     dequeue_fifo(mask_t ** mfifo)
233 lefcha 1.1 {
234 lefcha 1.42 static unsigned int j;
235 lefcha 1.1
236 lefcha 1.42 if (mfifo == NULL) {
237     j = 0;
238     return NULL;
239     }
240     return mfifo[j++];
241 lefcha 1.1 }
242    
243    
244     /*
245     * Generate the filter search command from the masks, assuming that
246     * masks are AND-ed.
247     */
248 lefcha 1.42 char *
249     generate_filter_and(mask_t * mask, unsigned int masknum,
250     unsigned int masklen)
251     {
252     const unsigned int searchbuf = masklen + masknum * 6 + 8;
253     unsigned int len;
254     char *search;
255     mask_t *tmp;
256 lefcha 1.5
257 lefcha 1.42 len = 0;
258 lefcha 1.5
259 lefcha 1.42 search = (char *)xmalloc(sizeof(char) * searchbuf);
260     search[0] = '\0';
261 lefcha 1.1
262 lefcha 1.42 tmp = mask;
263     if (tmp == NULL) {
264 lefcha 1.12 strncat(search, "ALL ", searchbuf - len - 1);
265     len += 4;
266 lefcha 1.42 } else
267     while ((tmp = tmp->next) != NULL) {
268     if (tmp->type != MASK_TYPE_OR) {
269     strncat(search, "ALL ", searchbuf - len - 1);
270     len += 4;
271     break;
272     }
273     }
274    
275     tmp = NULL;
276     while (mask != NULL) {
277     tmp = mask;
278     mask = mask->next;
279 lefcha 1.1
280 lefcha 1.42 if (mask != NULL && mask->type == MASK_TYPE_OR) {
281     strncat(search, "OR (", searchbuf - len - 1);
282     len += 4;
283    
284     strncat(search, tmp->body, searchbuf - len - 1);
285     len = strlen(search);
286     search[len] = ' ';
287     search[++len] = '\0';
288    
289     search[len - 1] = ')';
290     search[len] = ' ';
291     search[++len] = '\0';
292    
293     if (mask->next == NULL ||
294     mask->next->type != MASK_TYPE_OR) {
295     search[len] = '(';
296     search[++len] = '\0';
297     strncat(search, mask->body,
298     searchbuf - len - 1);
299     len = strlen(search);
300     search[len] = ')';
301     search[++len] = ' ';
302     search[++len] = '\0';
303     mask = mask->next;
304     }
305     } else {
306     strncat(search, tmp->body, searchbuf - len - 1);
307     len = strlen(search);
308     search[len] = ' ';
309     search[++len] = '\0';
310     }
311 lefcha 1.1 }
312 lefcha 1.10
313 lefcha 1.42 search[len - 1] = '\0';
314 lefcha 1.5
315 lefcha 1.42 return search;
316 lefcha 1.1 }
317    
318    
319     /*
320     * Generate the filter search command from the masks, assuming that
321 lefcha 1.22 * masks are OR-ed.
322 lefcha 1.1 */
323 lefcha 1.42 char *
324     generate_filter_or(mask_t * mask, unsigned int masknum,
325     unsigned int masklen)
326     {
327     const unsigned int searchbuf = masklen + masknum * 6 + 8;
328     unsigned int len;
329     char *search;
330     mask_t **mfifo; /* Mailbox FIFO queue. */
331     mask_t *mf; /* Mask returned from FIFO. */
332 lefcha 1.5
333 lefcha 1.42 len = 0;
334 lefcha 1.1
335 lefcha 1.42 search = (char *)xmalloc(sizeof(char) * searchbuf);
336     mfifo = (mask_t **) xmalloc(sizeof(mask_t *) * (masknum + 1));
337 lefcha 1.1
338 lefcha 1.42 search[0] = '\0';
339     empty_fifo(mfifo);
340 lefcha 1.1
341 lefcha 1.42 strncat(search, "ALL ", searchbuf - len - 1);
342     len += 4;
343 lefcha 1.1
344 lefcha 1.42 while (mask != NULL) {
345     queue_fifo(mfifo, mask);
346     mask = mask->next;
347 lefcha 1.1
348 lefcha 1.42 while (mask != NULL && mask->type == MASK_TYPE_AND) {
349     queue_fifo(mfifo, mask);
350     mask = mask->next;
351     }
352    
353     if (mask != NULL) {
354     if (len == 4 && search[0] == 'A') {
355     search[0] = '\0';
356     len = 0;
357     }
358     strncat(search, "OR ", searchbuf - len - 1);
359     len += 3;
360     }
361     if (search[0] != 'A') {
362     search[len] = '(';
363     search[++len] = '\0';
364     }
365     while ((mf = dequeue_fifo(mfifo)) != NULL) {
366     strncat(search, mf->body, searchbuf - len - 1);
367     len = strlen(search);
368     search[len] = ' ';
369     search[++len] = '\0';
370     }
371    
372     if (strchr(search, '(')) {
373     search[len - 1] = ')';
374     search[len] = ' ';
375     search[++len] = '\0';
376     }
377     empty_fifo(mfifo);
378 lefcha 1.1 }
379    
380 lefcha 1.42 search[len - 1] = '\0';
381 lefcha 1.10
382 lefcha 1.42 xfree(mfifo);
383 lefcha 1.3
384 lefcha 1.42 return search;
385 lefcha 1.1 }
386    
387    
388     /*
389     * Apply the appropriate action.
390     */
391 lefcha 1.42 int
392 lefcha 1.47 apply_action(char *mbox, char *mesgs, unsigned int *type, account_t * raccount,
393 lefcha 1.42 char *destmbox, unsigned int *msgflags, char *args)
394 lefcha 1.1 {
395 lefcha 1.42 unsigned int cnt;
396 lefcha 1.5
397 lefcha 1.42 if (*mesgs == '\0')
398     return 0;
399 lefcha 1.25
400 lefcha 1.42 log_info(LOG_ACTION, type);
401     log_info(LOG_DESTINATION_ACCOUNT, raccount->key);
402     log_info(LOG_DESTINATION_MAILBOX, destmbox);
403 lefcha 1.25
404 lefcha 1.42 cnt = count_messages(mesgs);
405 lefcha 1.25
406 lefcha 1.42 switch (*type) {
407     case FILTER_ACTION_DELETE:
408     info("%d message%s deleted.\n", cnt, plural(cnt));
409     action_delete(mesgs, args);
410     break;
411     case FILTER_ACTION_COPY:
412 lefcha 1.49 info("%d message%s copied from \"%s\" to mailbox \"%s\".\n",
413     cnt, plural(cnt), mbox, destmbox);
414 lefcha 1.47 action_copy(mbox, mesgs, apply_namespace(destmbox,
415     nsppri.prefix, nsppri.delim), args);
416 lefcha 1.42 break;
417     case FILTER_ACTION_MOVE:
418 lefcha 1.49 info("%d message%s moved from \"%s\" to mailbox \"%s\".\n",
419     cnt, plural(cnt), mbox, destmbox);
420 lefcha 1.47 action_move(mbox, mesgs, apply_namespace(destmbox,
421     nsppri.prefix, nsppri.delim), args);
422 lefcha 1.42 break;
423     case FILTER_ACTION_RCOPY:
424 lefcha 1.49 info("%d message%s copied from \"%s\" to mailbox "
425     "\"%s\" at account %s.\n", cnt, plural(cnt),
426     mbox, destmbox, raccount->key);
427 lefcha 1.47 action_rcopy(mbox, mesgs, raccount, destmbox, args);
428 lefcha 1.42 break;
429     case FILTER_ACTION_RMOVE:
430 lefcha 1.49 info("%d message%s moved from \"%s\" to mailbox "
431     "\"%s\" at account %s.\n", cnt, plural(cnt),
432     mbox, destmbox, raccount->key);
433 lefcha 1.47 action_rmove(mbox, mesgs, raccount, destmbox, args);
434 lefcha 1.42 break;
435     case FILTER_ACTION_FLAG_REPLACE:
436     case FILTER_ACTION_FLAG_ADD:
437     case FILTER_ACTION_FLAG_REMOVE:
438     info("%d message%s flagged.\n", cnt, plural(cnt));
439     action_flag(mesgs, type, msgflags, args);
440     break;
441     case FILTER_ACTION_LIST:
442     info("%d message%s listed.\n", cnt, plural(cnt));
443     action_list(mesgs, args);
444     break;
445     }
446 lefcha 1.5
447 lefcha 1.43 if (*args == '\0')
448 lefcha 1.48 log_info(LOG_PREAMBLE, NULL);
449 lefcha 1.5
450 lefcha 1.42 return 0;
451 lefcha 1.1 }
452    
453    
454     /*
455     * Delete messages and optionally list some of their headers.
456     */
457 lefcha 1.42 int
458     action_delete(char *mesgs, char *args)
459 lefcha 1.1 {
460 lefcha 1.42 char *tok, *m, *mcp;
461 lefcha 1.23
462 lefcha 1.42 action_list(mesgs, args);
463 lefcha 1.25
464 lefcha 1.42 m = mcp = convert_messages(mesgs);
465 lefcha 1.25
466 lefcha 1.42 tok = strtok_r(m, " ", &m);
467     while (tok) {
468     server_response(&sockpri, imap_store(&sockpri, tok,
469     STORE_FLAG_ADD, "\\Deleted"));
470 lefcha 1.5
471 lefcha 1.42 tok = strtok_r(NULL, " ", &m);
472     }
473 lefcha 1.34
474 lefcha 1.42 if (options & OPTION_EXPUNGE)
475     server_response(&sockpri, imap_expunge(&sockpri));
476 lefcha 1.25
477 lefcha 1.42 xfree(mcp);
478 lefcha 1.10
479 lefcha 1.42 return 0;
480 lefcha 1.1 }
481    
482    
483     /*
484     * Copy messages to specified mailbox.
485     */
486 lefcha 1.42 int
487 lefcha 1.47 action_copy(char *mbox, char *mesgs, char *destmbox, char *args)
488 lefcha 1.1 {
489 lefcha 1.42 int r;
490     char *tok, *mcp, *m;
491 lefcha 1.45 char dm[2][MBOX_NAME_LEN];
492 lefcha 1.42
493     r = 0;
494     tok = NULL;
495 lefcha 1.25
496 lefcha 1.42 action_list(mesgs, args);
497 lefcha 1.25
498 lefcha 1.44 if (strchr(destmbox, '@'))
499     m = mcp = xstrdup(mesgs);
500     else
501     m = mcp = convert_messages(mesgs);
502 lefcha 1.23
503 lefcha 1.45 xstrncpy(dm[0], destmbox, MBOX_NAME_LEN - 1);
504 lefcha 1.47 default_variables(mbox, dm[0]);
505 lefcha 1.45 current_date(dm[0]);
506 lefcha 1.42 tok = strtok_r(m, " ", &m);
507     while (tok != NULL) {
508 lefcha 1.45 xstrncpy(dm[1], dm[0], MBOX_NAME_LEN - 1);
509     message_date(tok, dm[1]);
510 lefcha 1.44
511 lefcha 1.42 if ((r = copy_response(&sockpri, imap_copy(&sockpri, tok,
512 lefcha 1.45 dm[1]))) == RESPONSE_TRYCREATE)
513 lefcha 1.42 if (!server_response(&sockpri, imap_create(&sockpri,
514 lefcha 1.45 dm[1]))) {
515 lefcha 1.42 if ((options & OPTION_SUBSCRIBE))
516     server_response(&sockpri,
517 lefcha 1.45 imap_subscribe(&sockpri, dm[1]));
518 lefcha 1.42 r = copy_response(&sockpri,
519 lefcha 1.45 imap_copy(&sockpri, tok, dm[1]));
520 lefcha 1.42 }
521     tok = strtok_r(NULL, " ", &m);
522     }
523 lefcha 1.23
524 lefcha 1.42 xfree(mcp);
525 lefcha 1.8
526 lefcha 1.42 return r;
527 lefcha 1.1 }
528    
529    
530     /*
531     * Move messages to specified mailbox.
532     */
533 lefcha 1.42 int
534 lefcha 1.47 action_move(char *mbox, char *mesgs, char *destmbox, char *args)
535 lefcha 1.1 {
536 lefcha 1.47 if (!action_copy(mbox, mesgs, destmbox, args))
537 lefcha 1.42 action_delete(mesgs, "\0");
538 lefcha 1.16
539 lefcha 1.42 return 0;
540 lefcha 1.1 }
541    
542    
543     /*
544 lefcha 1.21 * Copy messages to the specified mailbox of another mail server.
545     */
546 lefcha 1.42 int
547 lefcha 1.47 action_rcopy(char *mbox, char *mesgs, account_t * destacc, char *destmbox,
548     char *args)
549 lefcha 1.21 {
550 lefcha 1.42 int r, ta, tf;
551     char *tok, *m, *mcp, *ndm;
552     unsigned int n;
553 lefcha 1.48 char buf[RESPONSE_BUF * 2 + 1];
554 lefcha 1.45 char dm[3][MBOX_NAME_LEN];
555    
556     *dm[0] = *dm[1] = *dm[2] = '\0';
557 lefcha 1.42
558     if (init_connection(&sockaux, destacc->server, destacc->port,
559     destacc->ssl))
560     return ERROR_NETWORK;
561 lefcha 1.25
562 lefcha 1.42 r = greeting_response(&sockaux);
563 lefcha 1.25
564 lefcha 1.21 #ifdef DEBUG
565 lefcha 1.42 test(&sockaux);
566 lefcha 1.21 #endif
567 lefcha 1.25
568 lefcha 1.48 if (r == RESPONSE_BYE || check_capabilities(&sockaux))
569     return ERROR_NETWORK;
570    
571 lefcha 1.42 if (r != RESPONSE_PREAUTH) {
572     if (destacc->passwdattr == PASSWORD_NONE) {
573     printf("Enter password for %s@%s: ", destacc->username,
574     destacc->server);
575     get_password(destacc->password, PASSWORD_LEN);
576     destacc->passwdattr = PASSWORD_PLAIN;
577     }
578 lefcha 1.50 #ifdef CRAM_MD5
579     if (capsaux & CAPABILITY_AUTH_CRAM_MD5)
580     r = imf_cram_md5(&sockaux, destacc->username,
581     destacc->password);
582     else
583     #endif
584     r = login(&sockaux, destacc->username,
585     destacc->password);
586    
587     if (r == RESPONSE_NO) {
588 lefcha 1.42 error("username %s or password rejected at %s\n",
589     destacc->username, destacc->server);
590     return ERROR_NETWORK;
591     }
592     }
593     check_namespace(&sockaux, &nspaux);
594    
595 lefcha 1.45 m = mcp = xstrdup(mesgs);
596 lefcha 1.42
597 lefcha 1.45 xstrncpy(dm[1], destmbox, MBOX_NAME_LEN - 1);
598     current_date(dm[1]);
599 lefcha 1.25
600 lefcha 1.42 tok = strtok_r(m, " ", &m);
601     while (tok != NULL) {
602 lefcha 1.45 xstrncpy(dm[2], dm[1], MBOX_NAME_LEN - 1);
603     message_date(tok, dm[2]);
604    
605     /* apply_namespace() returns a pointer to a static buffer. */
606     ndm = apply_namespace(dm[2], nspaux.prefix, nspaux.delim);
607    
608     /* Check only if mailbox name is different from last one. */
609     if (strncmp(dm[0], dm[2], strlen(dm[2]))) {
610     r = check_mailbox(&sockaux, ndm);
611     if (r == RESPONSE_NO) {
612     server_response(&sockaux,
613     imap_create(&sockaux, ndm));
614     if ((options & OPTION_SUBSCRIBE))
615     server_response(&sockaux,
616     imap_subscribe(&sockaux, ndm));
617     }
618     }
619     xstrncpy(dm[0], dm[2], MBOX_NAME_LEN - 1);
620    
621 lefcha 1.42 fetchsize_response(&sockpri, &n,
622     imap_fetch(&sockpri, tok, "RFC822.SIZE"));
623 lefcha 1.21
624 lefcha 1.42 ta = imap_append(&sockaux, ndm, n);
625    
626     fetch_response(&sockpri, 0, 1, NULL);
627     tf = imap_fetch(&sockpri, tok, "RFC822.HEADER");
628     do {
629     r = fetch_response(&sockpri, tf, 0, buf);
630     socket_write(&sockaux, buf);
631     } while (r == RESPONSE_NONE);
632 lefcha 1.25
633 lefcha 1.42 socket_write(&sockaux, "\r\n");
634 lefcha 1.21
635 lefcha 1.42 fetch_response(&sockpri, 0, 1, NULL);
636     tf = imap_fetch(&sockpri, tok, "BODY[TEXT]");
637     do {
638     r = fetch_response(&sockpri, tf, 0, buf);
639     if (r != RESPONSE_NULLBODY)
640     socket_write(&sockaux, buf);
641     } while (r == RESPONSE_NONE);
642 lefcha 1.25
643 lefcha 1.42 if (r != RESPONSE_NULLBODY)
644     socket_write(&sockaux, "\r\n\r\n");
645     else
646     socket_write(&sockaux, "\r\n");
647 lefcha 1.25
648 lefcha 1.42 append_response(&sockaux, ta);
649 lefcha 1.34
650 lefcha 1.42 tok = strtok_r(NULL, " ", &m);
651     }
652 lefcha 1.21
653 lefcha 1.42 logout(&sockaux);
654 lefcha 1.25
655 lefcha 1.42 action_list(mesgs, args);
656 lefcha 1.25
657 lefcha 1.42 xfree(mcp);
658 lefcha 1.21
659 lefcha 1.42 return 0;
660 lefcha 1.21 }
661    
662    
663     /*
664     * Move messages to the specified mailbox of another mail server.
665     */
666 lefcha 1.42 int
667 lefcha 1.47 action_rmove(char *mbox, char *mesgs, account_t * destacc, char *destmbox,
668     char *args)
669 lefcha 1.21 {
670 lefcha 1.47 if (!action_rcopy(mbox, mesgs, destacc, destmbox, args))
671 lefcha 1.42 action_delete(mesgs, "\0");
672 lefcha 1.25
673 lefcha 1.42 return 0;
674 lefcha 1.21 }
675    
676 lefcha 1.26
677     /*
678 lefcha 1.27 * Flag messages by replacing, adding or removing specified flags.
679 lefcha 1.26 */
680 lefcha 1.42 int
681     action_flag(char *mesgs, unsigned int *type, unsigned int *msgflags,
682     char *args)
683     {
684     unsigned int t;
685     char s[STORE_FLAGS_BUF];
686     char *tok, *m, *mcp;
687    
688     *s = 0;
689    
690     switch (*type) {
691     case FILTER_ACTION_FLAG_ADD:
692     t = STORE_FLAG_ADD;
693     break;
694     case FILTER_ACTION_FLAG_REMOVE:
695     t = STORE_FLAG_REMOVE;
696     break;
697     default:
698     t = STORE_FLAG_REPLACE;
699     }
700    
701     if ((*msgflags != MESSAGE_FLAG_NONE)) {
702     if ((*msgflags & MESSAGE_FLAG_SEEN))
703     strncat(s, "\\Seen ", STORE_FLAGS_BUF - strlen(s) - 1);
704     if ((*msgflags & MESSAGE_FLAG_ANSWERED))
705     strncat(s, "\\Answered ",
706     STORE_FLAGS_BUF - strlen(s) - 1);
707     if ((*msgflags & MESSAGE_FLAG_FLAGGED))
708     strncat(s, "\\Flagged ",
709     STORE_FLAGS_BUF - strlen(s) - 1);
710     if ((*msgflags & MESSAGE_FLAG_DELETED))
711     strncat(s, "\\Deleted ",
712     STORE_FLAGS_BUF - strlen(s) - 1);
713     if ((*msgflags & MESSAGE_FLAG_DRAFT))
714     strncat(s, "\\Draft", STORE_FLAGS_BUF - strlen(s) - 1);
715     if ((s[strlen(s) - 1] == ' '))
716     s[strlen(s) - 1] = 0;
717     }
718     action_list(mesgs, args);
719    
720     m = mcp = convert_messages(mesgs);
721    
722     tok = strtok_r(m, " ", &m);
723     while (tok != NULL) {
724     server_response(&sockpri, imap_store(&sockpri, tok, t, s));
725    
726     tok = strtok_r(NULL, " ", &m);
727     }
728 lefcha 1.34
729 lefcha 1.42 if (options & OPTION_EXPUNGE)
730     server_response(&sockpri, imap_expunge(&sockpri));
731 lefcha 1.26
732 lefcha 1.42 xfree(mcp);
733 lefcha 1.26
734 lefcha 1.42 return 0;
735 lefcha 1.26 }
736 lefcha 1.21
737     /*
738 lefcha 1.1 * List user selected headers of messages.
739     */
740 lefcha 1.42 int
741     action_list(char *mesgs, char *args)
742 lefcha 1.1 {
743 lefcha 1.42 int r, t;
744     char *tok, *mcp, *m;
745     char s[ARGS_LEN + 27];
746 lefcha 1.48 char hdrs[RESPONSE_BUF * 2 + 1];
747 lefcha 1.42
748     if (*args == '\0')
749     return 0;
750    
751     m = mcp = xstrdup(mesgs);
752    
753     snprintf(s, ARGS_LEN + 27 - 1, "BODY.PEEK[HEADER.FIELDS (%s)]", args);
754    
755     tok = strtok_r(m, " ", &m);
756     while (tok != NULL) {
757     /* Reset internal fetch counter. */
758     fetch_response(&sockpri, 0, 1, NULL);
759     t = imap_fetch(&sockpri, tok, s);
760 lefcha 1.48
761     log_info(LOG_PREAMBLE, NULL);
762 lefcha 1.42 do {
763     r = fetch_response(&sockpri, t, 0, hdrs);
764 lefcha 1.48
765     if (*hdrs != '\0') {
766     if (options & OPTION_HEADERS)
767     info("%s\n", hdrs);
768     log_info(LOG_HEADER, hdrs);
769     }
770 lefcha 1.42 } while (r == RESPONSE_NONE);
771    
772     tok = strtok_r(NULL, " ", &m);
773 lefcha 1.33 }
774 lefcha 1.34
775 lefcha 1.42 xfree(mcp);
776 lefcha 1.1
777 lefcha 1.42 return 0;
778 lefcha 1.1 }
779    
780    
781     /*
782 lefcha 1.21 * Count how many messages matched the filter.
783     */
784 lefcha 1.42 unsigned int
785     count_messages(char *mesgs)
786 lefcha 1.21 {
787 lefcha 1.42 unsigned int cnt;
788     char *c;
789 lefcha 1.25
790 lefcha 1.42 cnt = 0;
791     c = mesgs;
792 lefcha 1.21
793 lefcha 1.42 while ((c = strchr(c, ' '))) {
794     cnt++;
795     c++;
796     }
797    
798     return ++cnt;
799 lefcha 1.21 }
800    
801    
802     /*
803 lefcha 1.11 * Convert messages with contiguous sequence number to the corresponding
804 lefcha 1.27 * number range, eg. 1 2 3 5 7 8 --> 1:3 5 7:8 and return a newly allocated
805     * buffer with the results.
806 lefcha 1.1 */
807 lefcha 1.42 char *
808     convert_messages(char *mesgs)
809 lefcha 1.1 {
810 lefcha 1.42 int maxlen;
811     unsigned int start, end, tmp;
812     char *c, *cp, *tail;
813    
814     start = end = tmp = 0;
815     maxlen = strlen(mesgs) + 1;
816     tail = NULL;
817    
818     c = cp = xstrdup(mesgs);
819    
820     start = (unsigned int)strtoul(mesgs, &tail, 10);
821     end = start;
822    
823     do {
824     if (tail != NULL) {
825     tmp = (unsigned int)strtoul(tail, &tail, 10);
826 lefcha 1.43 if (tmp == 0)
827 lefcha 1.42 tail = NULL;
828     }
829     if (tmp == end + 1)
830     end++;
831     else {
832     if (start == end) {
833     xstrncpy(c, ultostr(start, 10), maxlen);
834     c += strlen(c);
835     } else {
836     xstrncpy(c, ultostr(start, 10), maxlen - 1);
837     c += strlen(c);
838     *c = ':';
839     *++c = 0;
840     xstrncpy(c, ultostr(end, 10), maxlen);
841     c += strlen(c);
842     }
843    
844     if (tail != NULL && c - cp < maxlen) {
845     *c = ' ';
846     *++c = 0;
847     }
848     start = end = tmp;
849     }
850 lefcha 1.43 } while (tmp != 0);
851 lefcha 1.1
852 lefcha 1.42 return cp;
853 lefcha 1.44 }
854    
855    
856     /*
857     * Substitute all occurences of the '@' character with the '%' character,
858     * and any double '@' characters with a signle '@' character, returning the
859     * number of replacements.
860     */
861     int
862     substitute_date(char *str)
863     {
864     int n;
865     char *r, *w, *s;
866    
867     n = 0;
868    
869     s = xstrdup(str);
870    
871     for (r = s, w = str; *r != '\0'; r++, w++) {
872     if (*r == '%') {
873     *w++ = '%';
874     *w = '%';
875     } else if (*r == '@') {
876     if (*(r + 1) == '@') {
877     *w = *r++;
878     } else {
879     *w = '%';
880     n++;
881     }
882     } else {
883     *w = *r;
884     }
885     }
886     *w = '\0';
887    
888 lefcha 1.47 xfree(s);
889 lefcha 1.44
890     return n;
891     }
892    
893    
894     /*
895     * Format the destination mailbox according to the current date conversion
896     * specifiers.
897     */
898     void
899     current_date(char *destmbox)
900     {
901     char s[MBOX_NAME_LEN];
902     time_t te;
903     struct tm *tl;
904    
905     if (!strchr(destmbox, '%'))
906     return;
907    
908     te = time(NULL);
909     tl = localtime(&te);
910    
911     if (strftime(s, MBOX_NAME_LEN - 1, destmbox, tl))
912     xstrncpy(destmbox, s, MBOX_NAME_LEN - 1);
913     }
914    
915    
916     /*
917     * Format the destination mailbox according to the message date conversion
918     * specifiers.
919     */
920     void
921     message_date(char *mesg, char *destmbox)
922     {
923     unsigned int t;
924     char s[MBOX_NAME_LEN];
925     struct tm tl;
926 lefcha 1.48 char dbuf[RESPONSE_BUF + 1];
927 lefcha 1.44
928     if (!strchr(destmbox, '@'))
929     return;
930    
931     substitute_date(destmbox);
932    
933     fetch_response(&sockpri, 0, 1, NULL);
934     t = imap_fetch(&sockpri, mesg, "BODY.PEEK[HEADER.FIELDS (DATE)]");
935    
936     while (fetch_response(&sockpri, t, 0, dbuf) == RESPONSE_NONE);
937    
938 lefcha 1.46 if (strptime(dbuf, "Date: %a, %d %b %Y %H:%M:%S", &tl) &&
939 lefcha 1.44 strftime(s, MBOX_NAME_LEN - 1, destmbox, &tl))
940     xstrncpy(destmbox, s, MBOX_NAME_LEN - 1);
941 lefcha 1.47 }
942    
943    
944     /*
945     * Format the destination mailbox according to "default variables" specifiers.
946     */
947     void
948     default_variables(char *mbox, char *destmbox)
949     {
950     char *m, *r, *w, *s;
951    
952     if (!strchr(destmbox, '$'))
953     return;
954    
955     s = xstrdup(destmbox);
956    
957     for (r = s, w = destmbox; *r != '\0';) {
958     if (w - destmbox >= MBOX_NAME_LEN - 1)
959     break;
960     if (*r == '$') {
961     switch (*(r + 1)) {
962     case '_':
963     if (w + strlen(mbox) - destmbox >
964     MBOX_NAME_LEN - 1) {
965     r += 2;
966     break;
967     }
968     for (m = mbox; *m != '\0'; m++, w++)
969     *w = *m;
970     r += 2;
971     break;
972     case '$':
973     *w++ = '$';
974     r += 2;
975     break;
976     default:
977     *w++ = *r++;
978     break;
979     }
980     } else {
981     *w++ = *r++;
982     }
983     }
984     *w = '\0';
985    
986     xfree(s);
987 lefcha 1.1 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26