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

Annotation of /imapfilter/request.c

Parent Directory Parent Directory | Revision Log Revision Log


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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26