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