1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011-2021 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <mailutils/errno.h>
26 #include <mailutils/stream.h>
27 #include <mailutils/message.h>
28 #include <mailutils/folder.h>
29 #include <mailutils/assoc.h>
30 #include <mailutils/url.h>
31 #include <mailutils/io.h>
32 #include <mailutils/nls.h>
33 #include <mailutils/diag.h>
34 #include <mailutils/filter.h>
35 #include <mailutils/observer.h>
36 #include <mailutils/envelope.h>
37 #include <mailutils/address.h>
38 #include <mailutils/attribute.h>
39 #include <mailutils/header.h>
40 #include <mailutils/body.h>
41 #include <mailutils/msgset.h>
42 #include <mailutils/sys/imap.h>
43 #include <mailutils/sys/message.h>
44
45 #define _imap_mbx_clrerr(imbx) ((imbx)->last_error = 0)
46 #define _imap_mbx_errno(imbx) ((imbx)->last_error)
47 #define _imap_mbx_uptodate(imbx) ((imbx)->flags & _MU_IMAP_MBX_UPTODATE)
48
49 static int _imap_mbx_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount);
50 static int _imap_mbx_is_updated (mu_mailbox_t mbox);
51
52 /* ------------------------------- */
53 /* Auxiliary message functions */
54 /* ------------------------------- */
55
56 static inline size_t
_imap_msg_no(struct _mu_imap_message * imsg)57 _imap_msg_no (struct _mu_imap_message *imsg)
58 {
59 return imsg->msgno;
60 }
61
62 static int
_imap_fetch_with_callback(mu_imap_t imap,mu_msgset_t msgset,char * items,mu_imap_callback_t cb,void * data)63 _imap_fetch_with_callback (mu_imap_t imap, mu_msgset_t msgset, char *items,
64 mu_imap_callback_t cb, void *data)
65 {
66 int rc;
67
68 mu_imap_register_callback_function (imap, MU_IMAP_CB_FETCH, cb, data);
69 rc = mu_imap_fetch (imap, 0, msgset, items);
70 mu_imap_register_callback_function (imap, MU_IMAP_CB_FETCH, NULL, NULL);
71 return rc;
72 }
73
74 static void
_imap_msg_free(struct _mu_imap_message * msg)75 _imap_msg_free (struct _mu_imap_message *msg)
76 {
77 mu_message_imapenvelope_free (msg->env);
78 mu_stream_destroy (&msg->header_stream);
79 mu_message_destroy (&msg->message, msg);
80 free (msg);
81 }
82
83 struct save_closure
84 {
85 mu_stream_t save_stream;
86 size_t size;
87 struct _mu_imap_message *imsg;
88 };
89
90 static int
_save_message_parser(void * item,void * data)91 _save_message_parser (void *item, void *data)
92 {
93 union mu_imap_fetch_response *resp = item;
94 struct save_closure *clos = data;
95
96 if (resp->type == MU_IMAP_FETCH_BODY)
97 {
98 struct _mu_imap_message *imsg = clos->imsg;
99 struct _mu_imap_mailbox *imbx = imsg->imbx;
100 int rc;
101 mu_stream_t istr, flt;
102 mu_off_t size;
103
104 rc = mu_static_memory_stream_create (&istr, resp->body.text,
105 strlen (resp->body.text));
106
107 if (rc)
108 {
109 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
110 (_("mu_static_memory_stream_create: %s"),
111 mu_strerror (rc)));
112 imbx->last_error = rc;
113 return 0;
114 }
115
116 rc = mu_filter_create (&flt, istr, "CRLF", MU_FILTER_DECODE,
117 MU_STREAM_READ);
118 mu_stream_unref (istr);
119 if (rc)
120 {
121 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
122 (_("mu_filter_create: %s"), mu_strerror (rc)));
123 imbx->last_error = rc;
124 return 0;
125 }
126
127 rc = mu_stream_copy (clos->save_stream, flt, 0, &size);
128 mu_stream_destroy (&flt);
129 if (rc)
130 {
131 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
132 (_("copying to cache failed: %s"), mu_strerror (rc)));
133 imbx->last_error = rc;
134 return 0;
135 }
136 clos->size = size;
137 }
138 else
139 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE0,
140 (_("fetch returned a not requested item %d"),
141 resp->type));
142 return 0;
143 }
144
145 static void
_save_message_callback(void * data,int code,size_t sdat,void * pdat)146 _save_message_callback (void *data, int code, size_t sdat, void *pdat)
147 {
148 mu_list_t list = pdat;
149 mu_list_foreach (list, _save_message_parser, data);
150 }
151
152 static int
__imap_msg_get_stream(struct _mu_imap_message * imsg,size_t msgno,mu_stream_t * pstr)153 __imap_msg_get_stream (struct _mu_imap_message *imsg, size_t msgno,
154 mu_stream_t *pstr)
155 {
156 int rc;
157 struct _mu_imap_mailbox *imbx = imsg->imbx;
158 mu_folder_t folder = imbx->mbox->folder;
159 mu_imap_t imap = folder->data;
160
161 if (!(imsg->flags & _MU_IMAP_MSG_CACHED))
162 {
163 mu_msgset_t msgset;
164
165 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
166 (_("caching message %lu"), (unsigned long) msgno));
167 if (!imbx->cache)
168 {
169 rc = mu_temp_stream_create (&imbx->cache, 0);
170 if (rc)
171 /* FIXME: Try to recover first */
172 return rc;
173
174 mu_stream_set_buffer (imbx->cache, mu_buffer_full, 8192);
175 }
176
177 rc = mu_stream_seek (imbx->cache, 0, MU_SEEK_END, &imsg->offset);
178 if (rc)
179 return rc;
180
181 rc = mu_msgset_create (&msgset, NULL, MU_MSGSET_NUM);
182 if (rc == 0)
183 {
184 struct save_closure clos;
185
186 clos.imsg = imsg;
187 clos.save_stream = imbx->cache;
188 clos.size = 0;
189
190 rc = mu_msgset_add_range (msgset, msgno, msgno, MU_MSGSET_NUM);
191 if (rc == 0)
192 {
193 _imap_mbx_clrerr (imbx);
194 rc = _imap_fetch_with_callback (imap, msgset, "BODY[]",
195 _save_message_callback, &clos);
196 }
197 mu_msgset_free (msgset);
198 if (rc == 0 && !_imap_mbx_errno (imbx))
199 {
200 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
201 (_("cached message %lu: offset=%lu, size=%lu"),
202 (unsigned long) msgno,
203 (unsigned long) imsg->offset,
204 (unsigned long) clos.size));
205 imsg->message_size = clos.size;
206 }
207 }
208
209 if (rc)
210 return rc;
211
212 imsg->flags |= _MU_IMAP_MSG_CACHED;
213 }
214 return mu_streamref_create_abridged (pstr, imbx->cache,
215 imsg->offset,
216 imsg->offset + imsg->message_size - 1);
217 }
218
219 static int
_imap_msg_scan(struct _mu_imap_message * imsg)220 _imap_msg_scan (struct _mu_imap_message *imsg)
221 {
222 int rc;
223 mu_stream_t stream;
224 struct mu_message_scan scan;
225 size_t msgno = _imap_msg_no (imsg);
226
227 if (imsg->flags & _MU_IMAP_MSG_SCANNED)
228 return 0;
229
230 rc = __imap_msg_get_stream (imsg, msgno, &stream);
231 if (rc)
232 return rc;
233
234 scan.flags = MU_SCAN_SEEK | MU_SCAN_SIZE;
235 scan.message_start = 0;
236 scan.message_size = imsg->message_size;
237 rc = mu_stream_scan_message (stream, &scan);
238 mu_stream_unref (stream);
239
240 if (rc == 0)
241 {
242 imsg->body_start = scan.body_start;
243 imsg->body_end = scan.body_end;
244 imsg->header_lines = scan.header_lines;
245 imsg->body_lines = scan.body_lines;
246 imsg->message_lines = imsg->header_lines + 1 + imsg->body_lines;
247 imsg->flags |= _MU_IMAP_MSG_SCANNED;
248 }
249
250 return rc;
251 }
252
253 /* ------------------------------- */
254 /* Message envelope */
255 /* ------------------------------- */
256
257 static int
_imap_env_date(mu_envelope_t env,char * buf,size_t len,size_t * pnwrite)258 _imap_env_date (mu_envelope_t env, char *buf, size_t len,
259 size_t *pnwrite)
260 {
261 struct _mu_imap_message *imsg = mu_envelope_get_owner (env);
262 mu_stream_t str;
263 int rc;
264
265 if (!buf)
266 rc = mu_nullstream_create (&str, MU_STREAM_WRITE);
267 else
268 rc = mu_fixed_memory_stream_create (&str, buf, len, MU_STREAM_WRITE);
269 if (rc == 0)
270 {
271 mu_stream_stat_buffer statbuf;
272 mu_stream_set_stat (str, MU_STREAM_STAT_MASK (MU_STREAM_STAT_OUT),
273 statbuf);
274 rc = mu_c_streamftime (str, MU_DATETIME_FROM,
275 &imsg->env->date, &imsg->env->tz);
276 if (rc == 0)
277 rc = mu_stream_write (str, "", 1, NULL);
278 mu_stream_destroy (&str);
279 if (rc == 0 && pnwrite)
280 /* Do not count terminating null character */
281 *pnwrite = statbuf[MU_STREAM_STAT_OUT] - 1;
282 }
283 return rc;
284 }
285
286 static int
_imap_env_sender(mu_envelope_t env,char * buf,size_t len,size_t * pnwrite)287 _imap_env_sender (mu_envelope_t env, char *buf, size_t len,
288 size_t *pnwrite)
289 {
290 struct _mu_imap_message *imsg = mu_envelope_get_owner (env);
291 mu_address_t addr = imsg->env->sender ? imsg->env->sender : imsg->env->from;
292
293 if (!addr)
294 return MU_ERR_NOENT;
295 return mu_address_get_email (addr, 1, buf, len, pnwrite);
296 }
297
298 static int
_imap_msg_env_setup(struct _mu_imap_message * imsg,mu_message_t message)299 _imap_msg_env_setup (struct _mu_imap_message *imsg, mu_message_t message)
300 {
301 mu_envelope_t env;
302 int rc = mu_envelope_create (&env, imsg);
303 if (rc == 0)
304 {
305 mu_envelope_set_sender (env, _imap_env_sender, imsg);
306 mu_envelope_set_date (env, _imap_env_date, imsg);
307 rc = mu_message_set_envelope (message, env, imsg);
308 }
309 return rc;
310 }
311
312 /* ------------------------------- */
313 /* Message attributes */
314 /* ------------------------------- */
315 static int
_imap_attr_get_flags(mu_attribute_t attr,int * pflags)316 _imap_attr_get_flags (mu_attribute_t attr, int *pflags)
317 {
318 struct _mu_imap_message *imsg = mu_attribute_get_owner (attr);
319
320 if (!imsg)
321 return EINVAL;
322 if (pflags)
323 *pflags = imsg->attr_flags;
324 return 0;
325 }
326
327 static int
_imap_attr_set_flags(mu_attribute_t attr,int flags)328 _imap_attr_set_flags (mu_attribute_t attr, int flags)
329 {
330 struct _mu_imap_message *imsg = mu_attribute_get_owner (attr);
331
332 if (!imsg)
333 return EINVAL;
334 imsg->attr_flags |= flags;
335 imsg->flags |= _MU_IMAP_MSG_ATTRCHG;
336 return 0;
337 }
338
339 static int
_imap_attr_clr_flags(mu_attribute_t attr,int flags)340 _imap_attr_clr_flags (mu_attribute_t attr, int flags)
341 {
342 struct _mu_imap_message *imsg = mu_attribute_get_owner (attr);
343
344 if (!imsg)
345 return EINVAL;
346 imsg->attr_flags &= ~flags;
347 imsg->flags |= _MU_IMAP_MSG_ATTRCHG;
348 return 0;
349 }
350
351 int
_imap_msg_attr_setup(struct _mu_imap_message * imsg,mu_message_t message)352 _imap_msg_attr_setup (struct _mu_imap_message *imsg, mu_message_t message)
353 {
354 mu_attribute_t attribute;
355 int rc = mu_attribute_create (&attribute, imsg);
356 if (rc == 0)
357 {
358 mu_attribute_set_get_flags (attribute, _imap_attr_get_flags, imsg);
359 mu_attribute_set_set_flags (attribute, _imap_attr_set_flags, imsg);
360 mu_attribute_set_unset_flags (attribute, _imap_attr_clr_flags, imsg);
361 rc = mu_message_set_attribute (message, attribute, imsg);
362 }
363 return rc;
364 }
365
366 /* ------------------------------- */
367 /* Header functions */
368 /* ------------------------------- */
369 static int
_imap_hdr_fill(void * data,char ** pbuf,size_t * plen)370 _imap_hdr_fill (void *data, char **pbuf, size_t *plen)
371 {
372 struct _mu_imap_message *imsg = data;
373 mu_stream_t str = imsg->header_stream;
374 char *buf;
375 mu_off_t size;
376 int rc = 0;
377
378 mu_stream_size (str, &size);
379 buf = malloc (size + 1);
380 if (!buf)
381 rc = ENOMEM;
382 else
383 {
384 mu_stream_seek (str, 0, MU_SEEK_SET, NULL);
385 rc = mu_stream_read (str, buf, size, NULL);
386 if (rc == 0)
387 {
388 *pbuf = buf;
389 *plen = size;
390 }
391 else
392 {
393 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
394 ("mu_stream_read: %s", mu_strerror (rc)));
395 free (buf);
396 }
397 }
398 return rc;
399 }
400
401 static int
_imap_msg_header_setup(struct _mu_imap_message * imsg,mu_message_t message)402 _imap_msg_header_setup (struct _mu_imap_message *imsg, mu_message_t message)
403 {
404 int rc;
405 mu_header_t header = NULL;
406
407 rc = mu_header_create (&header, NULL, 0);
408 if (rc)
409 return rc;
410 mu_header_set_fill (header, _imap_hdr_fill, imsg);
411 return mu_message_set_header (message, header, imsg);
412 }
413
414 /* ------------------------------- */
415 /* Body functions */
416 /* ------------------------------- */
417 static int
_imap_body_get_stream(mu_body_t body,mu_stream_t * pstr)418 _imap_body_get_stream (mu_body_t body, mu_stream_t *pstr)
419 {
420 mu_message_t msg = mu_body_get_owner (body);
421 struct _mu_imap_message *imsg = mu_message_get_owner (msg);
422 struct _mu_imap_mailbox *imbx = imsg->imbx;
423 int rc;
424
425 rc = _imap_msg_scan (imsg);
426 if (rc)
427 return rc;
428 return mu_streamref_create_abridged (pstr, imbx->cache,
429 imsg->offset + imsg->body_start,
430 imsg->offset + imsg->body_end - 1);
431 }
432
433 static int
_imap_body_size(mu_body_t body,size_t * psize)434 _imap_body_size (mu_body_t body, size_t *psize)
435 {
436 mu_message_t msg = mu_body_get_owner (body);
437 struct _mu_imap_message *imsg = mu_message_get_owner (msg);
438 int rc;
439
440 rc = _imap_msg_scan (imsg);
441 if (rc)
442 return rc;
443 *psize = imsg->body_end - imsg->body_start;
444 return 0;
445 }
446
447 static int
_imap_body_lines(mu_body_t body,size_t * psize)448 _imap_body_lines (mu_body_t body, size_t *psize)
449 {
450 mu_message_t msg = mu_body_get_owner (body);
451 struct _mu_imap_message *imsg = mu_message_get_owner (msg);
452 int rc;
453
454 rc = _imap_msg_scan (imsg);
455 if (rc)
456 return rc;
457 *psize = imsg->body_lines;
458 return 0;
459 }
460
461 static int
_imap_mbx_body_setup(struct _mu_imap_message * imsg,mu_message_t message)462 _imap_mbx_body_setup (struct _mu_imap_message *imsg, mu_message_t message)
463 {
464 int rc;
465 mu_body_t body;
466
467 /* FIXME: The owner of the body *must* be the message it belongs to. */
468 rc = mu_body_create (&body, message);
469 if (rc)
470 return rc;
471
472 mu_body_set_get_stream (body, _imap_body_get_stream, message);
473 mu_body_set_size (body, _imap_body_size, message);
474 mu_body_set_lines (body, _imap_body_lines, message);
475
476 return mu_message_set_body (message, body, imsg);
477 }
478
479
480 /* ------------------------------- */
481 /* Message functions */
482 /* ------------------------------- */
483
484 static int
_imap_msg_get_stream(mu_message_t msg,mu_stream_t * pstr)485 _imap_msg_get_stream (mu_message_t msg, mu_stream_t *pstr)
486 {
487 struct _mu_imap_message *imsg = mu_message_get_owner (msg);
488 return __imap_msg_get_stream (imsg, _imap_msg_no (imsg), pstr);
489 }
490
491 static int
_imap_msg_size(mu_message_t msg,size_t * psize)492 _imap_msg_size (mu_message_t msg, size_t *psize)
493 {
494 struct _mu_imap_message *imsg = mu_message_get_owner (msg);
495 *psize = imsg->message_size;
496 return 0;
497 }
498
499 static int
_imap_msg_lines(mu_message_t msg,size_t * plines,int quick)500 _imap_msg_lines (mu_message_t msg, size_t *plines, int quick)
501 {
502 struct _mu_imap_message *imsg = mu_message_get_owner (msg);
503 struct _mu_imap_mailbox *imbx = imsg->imbx;
504 mu_mailbox_t mbox = imbx->mbox;
505
506 if (!(imsg->flags & _MU_IMAP_MSG_LINES))
507 {
508 int rc;
509
510 if (quick && !(imsg->flags & _MU_IMAP_MSG_CACHED))
511 return MU_ERR_INFO_UNAVAILABLE;
512 if (!_imap_mbx_uptodate (imbx))
513 _imap_mbx_scan (mbox, 1, NULL);
514 rc = _imap_msg_scan (imsg);
515 if (rc)
516 return rc;
517 }
518 *plines = imsg->message_lines;
519 return 0;
520 }
521
522 static int
_copy_imapenvelope(struct mu_imapenvelope * env,struct mu_imapenvelope const * src)523 _copy_imapenvelope (struct mu_imapenvelope *env,
524 struct mu_imapenvelope const *src)
525 {
526 env->date = src->date;
527 env->tz = src->tz;
528
529 if (src->subject && (env->subject = strdup (src->subject)) == NULL)
530 return ENOMEM;
531 if (src->from && (env->from = mu_address_dup (src->from)) == NULL)
532 return ENOMEM;
533 if (src->sender && (env->sender = mu_address_dup (src->sender)) == NULL)
534 return ENOMEM;
535 if (src->reply_to && (env->reply_to = mu_address_dup (src->reply_to))
536 == NULL)
537 return ENOMEM;
538 if (src->to && (env->to = mu_address_dup (src->to)) == NULL)
539 return ENOMEM;
540 if (src->cc && (env->cc = mu_address_dup (src->cc)) == NULL)
541 return ENOMEM;
542 if (src->bcc && (env->bcc = mu_address_dup (src->bcc)) == NULL)
543 return ENOMEM;
544 if (src->in_reply_to && (env->in_reply_to = strdup (src->in_reply_to))
545 == NULL)
546 return ENOMEM;
547 if (src->message_id && (env->message_id = strdup (src->message_id)) == NULL)
548 return ENOMEM;
549 return 0;
550 }
551
552 static int
_imap_msg_imapenvelope(mu_message_t msg,struct mu_imapenvelope ** penv)553 _imap_msg_imapenvelope (mu_message_t msg, struct mu_imapenvelope **penv)
554 {
555 struct _mu_imap_message *imsg = mu_message_get_owner (msg);
556 int rc = 0;
557 struct mu_imapenvelope *env = calloc (1, sizeof (*env));
558
559 if (!env)
560 return ENOMEM;
561 rc = _copy_imapenvelope (env, imsg->env);
562 if (rc)
563 mu_message_imapenvelope_free (env);
564 else
565 *penv = env;
566 return rc;
567 }
568
569 static int
fetch_bodystructure_parser(void * item,void * data)570 fetch_bodystructure_parser (void *item, void *data)
571 {
572 union mu_imap_fetch_response *resp = item;
573 struct mu_bodystructure **pbs = data;
574
575 if (resp->type == MU_IMAP_FETCH_BODYSTRUCTURE)
576 {
577 *pbs = resp->bodystructure.bs;
578 resp->bodystructure.bs = NULL;
579 }
580 else
581 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE0,
582 (_("fetch returned a not requested item %d"),
583 resp->type));
584 return 0;
585 }
586
587 static void
_imap_bodystructure_callback(void * data,int code,size_t sdat,void * pdat)588 _imap_bodystructure_callback (void *data, int code, size_t sdat, void *pdat)
589 {
590 mu_list_t list = pdat;
591 mu_list_foreach (list, fetch_bodystructure_parser, data);
592 }
593
594 static int
_imap_msg_bodystructure(mu_message_t msg,struct mu_bodystructure ** pbs)595 _imap_msg_bodystructure (mu_message_t msg, struct mu_bodystructure **pbs)
596 {
597 struct _mu_imap_message *imsg = mu_message_get_owner (msg);
598 struct _mu_imap_mailbox *imbx = imsg->imbx;
599 mu_imap_t imap = imbx->mbox->folder->data;
600 int rc;
601 mu_msgset_t msgset;
602
603 rc = mu_msgset_create (&msgset, NULL, MU_MSGSET_NUM);
604 if (rc == 0)
605 {
606 size_t msgno = _imap_msg_no (imsg);
607 rc = mu_msgset_add_range (msgset, msgno, msgno, MU_MSGSET_NUM);
608 if (rc == 0)
609 rc = _imap_fetch_with_callback (imap, msgset, "BODYSTRUCTURE",
610 _imap_bodystructure_callback, pbs);
611 mu_msgset_free (msgset);
612 }
613 return rc;
614 }
615
616 static void
_imap_msg_detach(mu_message_t msg)617 _imap_msg_detach (mu_message_t msg)
618 {
619 struct _mu_imap_message *imsg = mu_message_get_owner (msg);
620 imsg->message = NULL;
621 }
622
623 static int
_imap_mbx_get_message(mu_mailbox_t mailbox,size_t msgno,mu_message_t * pmsg)624 _imap_mbx_get_message (mu_mailbox_t mailbox, size_t msgno, mu_message_t *pmsg)
625 {
626 struct _mu_imap_mailbox *imbx = mailbox->data;
627 struct _mu_imap_message *imsg;
628 int rc;
629
630 /* If we did not start a scanning yet do it now. */
631 if (!_imap_mbx_uptodate (imbx))
632 _imap_mbx_scan (mailbox, 1, NULL);
633
634 if (msgno > imbx->msgs_cnt)
635 return MU_ERR_NOENT;
636
637 imsg = imbx->msgs[msgno - 1];
638 if (!imsg->message)
639 {
640 mu_message_t msg;
641
642 rc = mu_message_create (&msg, imsg);
643 if (rc)
644 return rc;
645
646 msg->_detach = _imap_msg_detach;
647
648 mu_message_set_get_stream (msg, _imap_msg_get_stream, imsg);
649 mu_message_set_size (msg, _imap_msg_size, imsg);
650 mu_message_set_lines (msg, _imap_msg_lines, imsg);
651 mu_message_set_imapenvelope (msg, _imap_msg_imapenvelope, imsg);
652 mu_message_set_bodystructure (msg, _imap_msg_bodystructure, imsg);
653
654 do
655 {
656 rc = _imap_msg_env_setup (imsg, msg);
657 if (rc)
658 break;
659 rc = _imap_msg_attr_setup (imsg, msg);
660 if (rc)
661 break;
662 rc = _imap_msg_header_setup (imsg, msg);
663 if (rc)
664 break;
665 rc = _imap_mbx_body_setup (imsg, msg);
666 }
667 while (0);
668
669 if (rc)
670 {
671 mu_message_destroy (&msg, imsg);
672 return rc;
673 }
674 imsg->message = msg;
675
676 }
677 *pmsg = imsg->message;
678 return 0;
679 }
680
681 /* ------------------------------- */
682 /* Mailbox functions */
683 /* ------------------------------- */
684 static int
_imap_realloc_messages(struct _mu_imap_mailbox * imbx,size_t count)685 _imap_realloc_messages (struct _mu_imap_mailbox *imbx, size_t count)
686 {
687 if (count > imbx->msgs_max)
688 {
689 struct _mu_imap_message **newmsgs = realloc (imbx->msgs,
690 count * sizeof (*newmsgs));
691 if (!newmsgs)
692 return ENOMEM;
693 memset (newmsgs + imbx->msgs_max, 0,
694 sizeof (*newmsgs) * (count - imbx->msgs_max));
695 imbx->msgs = newmsgs;
696 imbx->msgs_max = count;
697 }
698 return 0;
699 }
700
701 static void
_imap_mbx_destroy(mu_mailbox_t mailbox)702 _imap_mbx_destroy (mu_mailbox_t mailbox)
703 {
704 size_t i;
705 struct _mu_imap_mailbox *imbx = mailbox->data;
706
707 if (!imbx)
708 return;
709
710 if (imbx->msgs)
711 {
712 for (i = 0; i < imbx->msgs_cnt; i++)
713 _imap_msg_free (imbx->msgs[i]);
714 free (imbx->msgs);
715 }
716 mu_stream_unref (imbx->cache);
717 free (imbx);
718 mailbox->data = NULL;
719 }
720
721 static void
_imap_update_callback(void * data,int code,size_t sdat,void * pdat)722 _imap_update_callback (void *data, int code, size_t sdat, void *pdat)
723 {
724 struct _mu_imap_mailbox *imbx = data;
725 memcpy (&imbx->stats, pdat, sizeof (imbx->stats));
726 imbx->flags &= ~_MU_IMAP_MBX_UPTODATE;
727 }
728
729 static void
_imap_expunge_callback(void * data,int code,size_t msgno,void * pdat)730 _imap_expunge_callback (void *data, int code, size_t msgno, void *pdat)
731 {
732 struct _mu_imap_mailbox *imbx = data;
733 size_t n;
734
735 if (msgno > imbx->msgs_cnt)
736 {
737 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
738 ("_imap_expunge_callback called with invalid message number: %lu",
739 (unsigned long)msgno));
740 return;
741 }
742 _imap_msg_free (imbx->msgs[msgno - 1]);
743 n = imbx->msgs_cnt - msgno;
744 if (n)
745 {
746 size_t i;
747
748 memmove (imbx->msgs + msgno - 1, imbx->msgs + msgno,
749 n * sizeof (imbx->msgs[0]));
750 for (i = msgno - 1; i < imbx->msgs_cnt; i++)
751 imbx->msgs[i]->msgno = i + 1;
752 }
753 imbx->msgs_cnt--;
754 }
755
756 static int
_imap_mbx_open(mu_mailbox_t mbox,int flags)757 _imap_mbx_open (mu_mailbox_t mbox, int flags)
758 {
759 struct _mu_imap_mailbox *imbx = mbox->data;
760 mu_folder_t folder = mbox->folder;
761 int rc;
762 const char *mbox_name;
763 mu_url_t url;
764 mu_imap_t imap;
765
766 mbox->flags = flags;
767
768 rc = mu_mailbox_get_url (mbox, &url);
769 if (rc)
770 return rc;
771 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
772 (_("opening mailbox %s"), mu_url_to_string (url)));
773 rc = mu_url_sget_path (url, &mbox_name);
774 if (rc == MU_ERR_NOENT)
775 mbox_name = "INBOX";
776 else if (rc)
777 return rc;
778
779 rc = mu_folder_open (folder, flags);
780 if (rc)
781 return rc;
782
783 imap = folder->data;
784
785 mu_imap_register_callback_function (imap, MU_IMAP_CB_RECENT_COUNT,
786 _imap_update_callback,
787 imbx);
788 mu_imap_register_callback_function (imap, MU_IMAP_CB_MESSAGE_COUNT,
789 _imap_update_callback,
790 imbx);
791 mu_imap_register_callback_function (imap, MU_IMAP_CB_EXPUNGE,
792 _imap_expunge_callback,
793 imbx);
794
795 rc = mu_imap_select (imap, mbox_name,
796 flags & (MU_STREAM_WRITE|MU_STREAM_APPEND),
797 &imbx->stats);
798 if (rc)
799 return rc;
800
801 if (imbx->stats.flags & MU_IMAP_STAT_MESSAGE_COUNT)
802 rc = _imap_realloc_messages (imbx, imbx->stats.message_count);
803
804 _imap_mbx_scan (mbox, 1, NULL);
805
806 return rc;
807 }
808
809 static int
_imap_mbx_close(mu_mailbox_t mbox)810 _imap_mbx_close (mu_mailbox_t mbox)
811 {
812 int rc;
813 mu_folder_t folder = mbox->folder;
814 mu_imap_t imap = folder->data;
815
816 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
817 (_("closing mailbox %s"), mu_url_to_string (mbox->url)));
818 if (mu_imap_capability_test (imap, "UNSELECT", NULL) == 0)
819 rc = mu_imap_unselect (imap);
820 else
821 rc = mu_imap_close (imap);
822 return rc;
823 }
824
825 static int
_imap_messages_count(mu_mailbox_t mbox,size_t * pcount)826 _imap_messages_count (mu_mailbox_t mbox, size_t *pcount)
827 {
828 struct _mu_imap_mailbox *imbx = mbox->data;
829 if (imbx->stats.flags & MU_IMAP_STAT_MESSAGE_COUNT)
830 *pcount = imbx->stats.message_count;
831 else
832 return MU_ERR_INFO_UNAVAILABLE;
833 return 0;
834 }
835
836 static int
_imap_messages_recent(mu_mailbox_t mbox,size_t * pcount)837 _imap_messages_recent (mu_mailbox_t mbox, size_t *pcount)
838 {
839 struct _mu_imap_mailbox *imbx = mbox->data;
840 if (imbx->stats.flags & MU_IMAP_STAT_RECENT_COUNT)
841 *pcount = imbx->stats.recent_count;
842 else
843 {
844 int rc;
845 mu_folder_t folder = mbox->folder;
846 mu_imap_t imap = folder->data;
847 mu_msgset_t msgset;
848
849 rc = mu_imap_search (imap, 0, "RECENT", &msgset);
850 if (rc)
851 return rc;
852
853 rc = mu_msgset_count (msgset, pcount);
854 mu_msgset_free (msgset);
855 return rc;
856 }
857 return 0;
858 }
859
860 static int
_imap_uidnext(mu_mailbox_t mbox,size_t * pn)861 _imap_uidnext (mu_mailbox_t mbox, size_t *pn)
862 {
863 struct _mu_imap_mailbox *imbx = mbox->data;
864 if (imbx->stats.flags & MU_IMAP_STAT_UIDNEXT)
865 *pn = imbx->stats.uidnext;
866 else
867 return MU_ERR_INFO_UNAVAILABLE;
868 return 0;
869 }
870
871 static int
_imap_message_unseen(mu_mailbox_t mbox,size_t * pn)872 _imap_message_unseen (mu_mailbox_t mbox, size_t *pn)
873 {
874 struct _mu_imap_mailbox *imbx = mbox->data;
875 if (imbx->stats.flags & MU_IMAP_STAT_FIRST_UNSEEN)
876 *pn = imbx->stats.first_unseen;
877 else
878 {
879 int rc;
880 mu_folder_t folder = mbox->folder;
881 mu_imap_t imap = folder->data;
882 mu_msgset_t msgset;
883 mu_list_t list;
884
885 rc = mu_imap_search (imap, 0, "UNSEEN", &msgset);
886 if (rc)
887 return rc;
888
889 if (mu_msgset_is_empty (msgset))
890 {
891 mu_msgset_free (msgset);
892 return MU_ERR_NOENT;
893 }
894
895 rc = mu_msgset_get_list (msgset, &list);
896 if (rc == 0)
897 {
898 struct mu_msgrange *r;
899 rc = mu_list_head (list, (void **) &r);
900 if (rc == 0)
901 *pn = r->msg_beg;
902 }
903 mu_msgset_free (msgset);
904 return rc;
905 }
906 return 0;
907 }
908
909 static int
_imap_uidvalidity(mu_mailbox_t mbox,unsigned long * pn)910 _imap_uidvalidity (mu_mailbox_t mbox, unsigned long *pn)
911 {
912 struct _mu_imap_mailbox *imbx = mbox->data;
913 if (imbx->stats.flags & MU_IMAP_STAT_UIDVALIDITY)
914 *pn = imbx->stats.uidvalidity;
915 else
916 return MU_ERR_INFO_UNAVAILABLE;
917 return 0;
918 }
919
920 struct attr_tab
921 {
922 size_t start;
923 size_t end;
924 int attr_flags;
925 };
926
927 static int
attr_tab_cmp(void const * a,void const * b)928 attr_tab_cmp (void const *a, void const *b)
929 {
930 struct attr_tab const *ta = a;
931 struct attr_tab const *tb = b;
932
933 if (ta->attr_flags < tb->attr_flags)
934 return -1;
935 else if (ta->attr_flags > tb->attr_flags)
936 return 1;
937
938 if (ta->start < tb->start)
939 return -1;
940 else if (ta->start > tb->start)
941 return 1;
942 return 0;
943 }
944
945 static int
aggregate_attributes(struct _mu_imap_mailbox * imbx,struct attr_tab ** ptab,size_t * pcnt)946 aggregate_attributes (struct _mu_imap_mailbox *imbx,
947 struct attr_tab **ptab, size_t *pcnt)
948 {
949 size_t i, j;
950 size_t count;
951 struct attr_tab *tab;
952
953 /* Pass 1: Count modified attributes */
954 count = 0;
955 for (i = 0; i < imbx->msgs_cnt; i++)
956 {
957 if (imbx->msgs[i]->flags & _MU_IMAP_MSG_ATTRCHG)
958 count++;
959 }
960
961 if (count == 0)
962 {
963 *ptab = NULL;
964 *pcnt = 0;
965 return 0;
966 }
967
968 /* Pass 2: Create and populate expanded array */
969 tab = calloc (count, sizeof (*tab));
970 if (!tab)
971 return ENOMEM;
972 for (i = j = 0; i < imbx->msgs_cnt; i++)
973 {
974 if (imbx->msgs[i]->flags & _MU_IMAP_MSG_ATTRCHG)
975 {
976 tab[j].start = tab[j].end = i;
977 tab[j].attr_flags = imbx->msgs[i]->attr_flags;
978 j++;
979 }
980 }
981
982 /* Sort the array */
983 qsort (tab, count, sizeof (tab[0]), attr_tab_cmp);
984
985 /* Pass 3: Coalesce message ranges */
986 for (i = j = 0; i < count; i++)
987 {
988 if (i == j)
989 continue;
990 else if ((tab[i].attr_flags == tab[j].attr_flags) &&
991 (tab[i].start == tab[j].end + 1))
992 tab[j].end++;
993 else
994 tab[++j] = tab[i];
995 }
996
997 *ptab = tab;
998 *pcnt = j + 1;
999 return 0;
1000 }
1001
1002 static int
_imap_mbx_gensync(mu_mailbox_t mbox,int * pdel)1003 _imap_mbx_gensync (mu_mailbox_t mbox, int *pdel)
1004 {
1005 struct _mu_imap_mailbox *imbx = mbox->data;
1006 mu_folder_t folder = mbox->folder;
1007 mu_imap_t imap = folder->data;
1008 size_t i, j;
1009 mu_msgset_t msgset;
1010 int rc;
1011 int delflg = 0;
1012 struct attr_tab *tab;
1013 size_t count;
1014
1015 rc = mu_msgset_create (&msgset, NULL, MU_MSGSET_NUM);
1016 if (rc)
1017 return rc;
1018
1019 rc = aggregate_attributes (imbx, &tab, &count);
1020 if (rc)
1021 {
1022 /* Too bad, but try to use naive approach */
1023 for (i = 0; i < imbx->msgs_cnt; i++)
1024 {
1025 if (imbx->msgs[i]->flags & _MU_IMAP_MSG_ATTRCHG)
1026 {
1027 mu_msgset_clear (msgset);
1028 mu_msgset_add_range (msgset, i + 1, i + 1, MU_MSGSET_NUM);
1029 if (rc)
1030 break;
1031 rc = mu_imap_store_flags (imap, 0, msgset,
1032 MU_IMAP_STORE_SET|MU_IMAP_STORE_SILENT,
1033 imbx->msgs[i]->attr_flags);
1034 delflg |= imbx->msgs[i]->attr_flags & MU_ATTRIBUTE_DELETED;
1035 if (rc)
1036 break;
1037 }
1038 }
1039 }
1040 else
1041 {
1042 for (i = j = 0; i < count; i++)
1043 {
1044 if (j < i)
1045 {
1046 if (tab[j].attr_flags != tab[i].attr_flags)
1047 {
1048 rc = mu_imap_store_flags (imap, 0, msgset,
1049 MU_IMAP_STORE_SET|
1050 MU_IMAP_STORE_SILENT,
1051 tab[j].attr_flags);
1052 delflg |= tab[j].attr_flags & MU_ATTRIBUTE_DELETED;
1053 if (rc)
1054 break;
1055 mu_msgset_clear (msgset);
1056 j = i;
1057 }
1058 }
1059 if (tab[i].end == tab[i].start)
1060 rc = mu_msgset_add_range (msgset,
1061 tab[i].start + 1, tab[i].start + 1,
1062 MU_MSGSET_NUM);
1063 else
1064 rc = mu_msgset_add_range (msgset,
1065 tab[i].start + 1, tab[i].end + 1,
1066 MU_MSGSET_NUM);
1067 if (rc)
1068 break;
1069 }
1070
1071 if (rc == 0 && j < i)
1072 {
1073 rc = mu_imap_store_flags (imap, 0, msgset,
1074 MU_IMAP_STORE_SET|MU_IMAP_STORE_SILENT,
1075 tab[j].attr_flags);
1076 delflg |= tab[j].attr_flags & MU_ATTRIBUTE_DELETED;
1077 }
1078 free (tab);
1079 }
1080 mu_msgset_free (msgset);
1081
1082 if (rc)
1083 return rc;
1084
1085 if (pdel)
1086 *pdel = delflg;
1087
1088 return 0;
1089 }
1090
1091 static int
_imap_mbx_expunge(mu_mailbox_t mbox)1092 _imap_mbx_expunge (mu_mailbox_t mbox)
1093 {
1094 int rc, del = 0;
1095
1096 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
1097 (_("expunging mailbox %s"), mu_url_to_string (mbox->url)));
1098 rc = _imap_mbx_gensync (mbox, &del);
1099 if (rc == 0 && del)
1100 {
1101 mu_folder_t folder = mbox->folder;
1102 mu_imap_t imap = folder->data;
1103 rc = mu_imap_expunge (imap);
1104 }
1105 return rc;
1106 }
1107
1108 static int
_imap_mbx_sync(mu_mailbox_t mbox)1109 _imap_mbx_sync (mu_mailbox_t mbox)
1110 {
1111 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
1112 (_("synchronizing mailbox %s"), mu_url_to_string (mbox->url)));
1113 return _imap_mbx_gensync (mbox, NULL);
1114 }
1115
1116 static int
_imap_mbx_append_message(mu_mailbox_t mbox,mu_message_t msg)1117 _imap_mbx_append_message (mu_mailbox_t mbox, mu_message_t msg)
1118 {
1119 int rc;
1120 mu_folder_t folder = mbox->folder;
1121 mu_imap_t imap = folder->data;
1122 mu_url_t url;
1123 const char *mbox_name;
1124
1125 rc = mu_mailbox_get_url (mbox, &url);
1126 if (rc)
1127 return rc;
1128 rc = mu_url_sget_path (url, &mbox_name);
1129 if (rc)
1130 return rc;
1131 return mu_imap_append_message (imap, mbox_name, 0, NULL, NULL, msg);
1132 }
1133
1134 static int _compute_lines (struct mu_bodystructure *bs, size_t *pcount);
1135
1136 static int
sum_lines(void * item,void * data)1137 sum_lines (void *item, void *data)
1138 {
1139 struct mu_bodystructure *bs = item;
1140 size_t *pn = data;
1141 size_t n;
1142 int rc;
1143
1144 rc = _compute_lines (bs, &n);
1145 if (rc)
1146 return rc;
1147 *pn += n;
1148 return 0;
1149 }
1150
1151 static int
_compute_lines(struct mu_bodystructure * bs,size_t * pcount)1152 _compute_lines (struct mu_bodystructure *bs, size_t *pcount)
1153 {
1154 switch (bs->body_message_type)
1155 {
1156 case mu_message_other:
1157 break;
1158
1159 case mu_message_text:
1160 *pcount = bs->v.text.body_lines;
1161 return 0;
1162
1163 case mu_message_rfc822:
1164 *pcount = bs->v.rfc822.body_lines;
1165 return 0;
1166
1167 case mu_message_multipart:
1168 *pcount = 0;
1169 return mu_list_foreach (bs->v.multipart.body_parts, sum_lines, pcount);
1170 }
1171 return MU_ERR_USER0;
1172 }
1173
1174 static int
fetch_response_parser(void * item,void * data)1175 fetch_response_parser (void *item, void *data)
1176 {
1177 union mu_imap_fetch_response *resp = item;
1178 struct _mu_imap_message *imsg = data;
1179
1180 switch (resp->type)
1181 {
1182 case MU_IMAP_FETCH_UID:
1183 imsg->uid = resp->uid.uid;
1184 break;
1185
1186 case MU_IMAP_FETCH_FLAGS:
1187 imsg->attr_flags = resp->flags.flags;
1188 break;
1189
1190 case MU_IMAP_FETCH_ENVELOPE:
1191 imsg->env = resp->envelope.imapenvelope;
1192 resp->envelope.imapenvelope = NULL; /* Steal the envelope */
1193 break;
1194
1195 case MU_IMAP_FETCH_RFC822_SIZE:
1196 imsg->message_size = resp->rfc822_size.size;
1197 break;
1198
1199 case MU_IMAP_FETCH_BODYSTRUCTURE:
1200 {
1201 size_t n;
1202 if (_compute_lines (resp->bodystructure.bs, &n) == 0)
1203 {
1204 imsg->message_lines = n;
1205 imsg->flags |= _MU_IMAP_MSG_LINES;
1206 }
1207 }
1208 break;
1209
1210 case MU_IMAP_FETCH_BODY:
1211 {
1212 int rc;
1213 struct save_closure clos;
1214 clos.imsg = imsg;
1215 rc = mu_memory_stream_create (&clos.save_stream, MU_STREAM_RDWR);
1216 if (rc == 0)
1217 {
1218 rc = _save_message_parser (resp, &clos);
1219 if (rc == 0)
1220 imsg->header_stream = clos.save_stream;
1221 else
1222 mu_stream_destroy (&clos.save_stream);
1223 }
1224 else
1225 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
1226 ("mu_static_memory_stream_create: %s",
1227 mu_strerror (rc)));
1228 }
1229 break;
1230
1231 default:
1232 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE0,
1233 (_("fetch returned a not requested item %d"),
1234 resp->type));
1235 break;
1236 }
1237 return 0;
1238 }
1239
1240 static void
_imap_fetch_callback(void * data,int code,size_t sdat,void * pdat)1241 _imap_fetch_callback (void *data, int code, size_t sdat, void *pdat)
1242 {
1243 struct _mu_imap_mailbox *imbx = data;
1244 mu_mailbox_t mbox = imbx->mbox;
1245 mu_list_t list = pdat;
1246 int rc;
1247 struct _mu_imap_message *imsg;
1248
1249 rc = _imap_realloc_messages (imbx, sdat);
1250 if (rc)
1251 {
1252 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
1253 (_("cannot reallocate array of messages: %s"),
1254 mu_strerror (rc)));
1255 imbx->last_error = rc;
1256 return;
1257 }
1258 if (imbx->msgs_cnt < sdat)
1259 imbx->msgs_cnt = sdat;
1260
1261 if (!imbx->msgs[sdat - 1])
1262 {
1263 imbx->msgs[sdat - 1] = calloc (1, sizeof (imbx->msgs[sdat - 1][0]));
1264 if (!imbx->msgs[sdat - 1])
1265 {
1266 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
1267 (_("cannot allocate imap message: %s"),
1268 mu_strerror (errno)));
1269 imbx->last_error = errno;
1270 return;
1271 }
1272 imbx->msgs[sdat - 1]->msgno = sdat;
1273 }
1274
1275 imsg = imbx->msgs[sdat - 1];
1276 imsg->imbx = imbx;
1277 mu_list_foreach (list, fetch_response_parser, imsg);
1278
1279 if (mbox->observable)
1280 {
1281 if (((sdat + 1) % 10) == 0)
1282 mu_observable_notify (imbx->mbox->observable,
1283 MU_EVT_MAILBOX_PROGRESS, NULL);
1284 }
1285 }
1286
1287 static int
_imap_mbx_scan(mu_mailbox_t mbox,size_t msgno,size_t * pcount)1288 _imap_mbx_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount)
1289 {
1290 struct _mu_imap_mailbox *imbx = mbox->data;
1291 mu_folder_t folder = mbox->folder;
1292 mu_imap_t imap = folder->data;
1293 mu_msgset_t msgset;
1294 int rc;
1295 static char _imap_scan_items[] = "(UID FLAGS ENVELOPE RFC822.SIZE BODY BODY.PEEK[HEADER])";
1296
1297 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
1298 (_("scanning mailbox %s"), mu_url_to_string (mbox->url)));
1299 if (imbx->stats.message_count > 0)
1300 {
1301 rc = mu_msgset_create (&msgset, NULL, MU_MSGSET_NUM);
1302 if (rc)
1303 return rc;
1304 rc = mu_msgset_add_range (msgset, msgno, MU_MSGNO_LAST, MU_MSGSET_NUM);
1305 if (rc)
1306 {
1307 mu_msgset_free (msgset);
1308 return rc;
1309 }
1310
1311 _imap_mbx_clrerr (imbx);
1312 rc = _imap_fetch_with_callback (imap, msgset, _imap_scan_items,
1313 _imap_fetch_callback, imbx);
1314 mu_msgset_free (msgset);
1315 if (rc == 0)
1316 rc = _imap_mbx_errno (imbx);
1317 if (rc == 0)
1318 {
1319 size_t i;
1320 mu_off_t total = 0;
1321
1322 imbx->flags |= _MU_IMAP_MBX_UPTODATE;
1323
1324 for (i = 1; i <= imbx->msgs_cnt; i++)
1325 {
1326 total += imbx->msgs[i-1]->message_size;
1327 /* MU_EVT_MESSAGE_ADD must be delivered only when it is already
1328 possible to retrieve the message in question. It could not be
1329 done in the fetch handler for obvious reasons. Hence the extra
1330 loop. */
1331 if (mbox->observable)
1332 mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD, &i);
1333 }
1334 if (pcount)
1335 *pcount = imbx->msgs_cnt;
1336 }
1337 }
1338 else
1339 {
1340 rc = 0;
1341 imbx->flags |= _MU_IMAP_MBX_UPTODATE;
1342 if (pcount)
1343 *pcount = 0;
1344 }
1345 return rc;
1346 }
1347
1348 static int
_imap_mbx_is_updated(mu_mailbox_t mbox)1349 _imap_mbx_is_updated (mu_mailbox_t mbox)
1350 {
1351 struct _mu_imap_mailbox *imbx = mbox->data;
1352 mu_folder_t folder = mbox->folder;
1353 mu_imap_t imap = folder->data;
1354 int rc;
1355
1356 rc = mu_imap_noop (imap);
1357 if (rc)
1358 {
1359 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
1360 (_("mu_imap_noop: %s"), mu_strerror (rc)));
1361 imbx->last_error = rc;
1362 }
1363 return _imap_mbx_uptodate(imbx);
1364 }
1365
1366 static int
_imap_copy_to_mailbox(mu_mailbox_t mbox,mu_msgset_t msgset,const char * mailbox,int flags)1367 _imap_copy_to_mailbox (mu_mailbox_t mbox, mu_msgset_t msgset,
1368 const char *mailbox, int flags)
1369 {
1370 struct _mu_imap_mailbox *imbx = mbox->data;
1371 mu_folder_t folder = mbox->folder;
1372 mu_imap_t imap = folder->data;
1373 int rc;
1374
1375 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
1376 (_("copying messages to mailbox %s"), mailbox));
1377 _imap_mbx_clrerr (imbx);
1378
1379 rc = mu_imap_copy (imap, flags & MU_MAILBOX_COPY_UID, msgset, mailbox);
1380 if (rc)
1381 {
1382 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
1383 (_("mu_imap_copy: %s"), mu_strerror (rc)));
1384 if (rc)
1385 {
1386 if (mu_imap_response_code (imap) == MU_IMAP_RESPONSE_TRYCREATE)
1387 {
1388 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
1389 (_("creating mailbox %s"), mailbox));
1390 rc = mu_imap_mailbox_create (imap, mailbox);
1391 if (rc == 0)
1392 rc = mu_imap_copy (imap, flags & MU_MAILBOX_COPY_UID,
1393 msgset, mailbox);
1394 }
1395 }
1396 imbx->last_error = rc;
1397 }
1398 return rc;
1399 }
1400
1401 int
_mu_imap_mailbox_init(mu_mailbox_t mailbox)1402 _mu_imap_mailbox_init (mu_mailbox_t mailbox)
1403 {
1404 struct _mu_imap_mailbox *mbx = calloc (1, sizeof (*mbx));
1405
1406 if (!mbx)
1407 return ENOMEM;
1408 mbx->mbox = mailbox;
1409 mailbox->data = mbx;
1410
1411 mailbox->_destroy = _imap_mbx_destroy;
1412 mailbox->_open = _imap_mbx_open;
1413 mailbox->_close = _imap_mbx_close;
1414 mailbox->_expunge = _imap_mbx_expunge;
1415
1416 mailbox->_messages_count = _imap_messages_count;
1417 mailbox->_messages_recent = _imap_messages_recent;
1418 mailbox->_message_unseen = _imap_message_unseen;
1419 mailbox->_get_uidvalidity = _imap_uidvalidity;
1420 mailbox->_uidnext = _imap_uidnext;
1421
1422 mailbox->_scan = _imap_mbx_scan;
1423 mailbox->_is_updated = _imap_mbx_is_updated;
1424 mailbox->_get_message = _imap_mbx_get_message;
1425 mailbox->_sync = _imap_mbx_sync;
1426
1427 mailbox->_append_message = _imap_mbx_append_message;
1428 mailbox->_copy = _imap_copy_to_mailbox;
1429
1430 return 0;
1431 }
1432