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

Annotation of /imapfilter/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.53 - (hide annotations)
Sun Jul 27 17:39:45 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
Changes since 1.52: +81 -90 lines
File MIME type: text/plain
New structure to hold information about connection's socket, ssl socket, capabilities, namespace.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26