Commit 9c57918e 9c57918efb596b918322bd6ba8aeeabc2cfd6a57 by Alain Magloire

A small cleanup of the IMAP code.

	* mailbox/folder_imap.c (imap_body):  Destry the cache header
	if it was previously set on a SCAN.
	* mailbox/mbx_imap.c (delete_to_string): New function, to generate
	a string of IMAP message numbers.
	(imap_expunge): use delete_to_string;
	(attribute_string): Removed.
	(flags_string): Removed.
	(flags_to_string): Replace attribute_string() and flags_string().
	(message_operation): Rename to fetch_operation.
	* mailbox/include/imap0.h(struct _f_imap): field func and id
	removed, never used.
1 parent cf69f401
1 2001-10-11 Alain Magloire 1 2001-10-11 Alain Magloire
2 2
3 A small cleanup of the IMAP code.
4
5 * mailbox/folder_imap.c (imap_body): Destry the cache header
6 if it was previously set on a SCAN.
7 * mailbox/mbx_imap.c (delete_to_string): New function, to generate
8 a string of IMAP message numbers.
9 (imap_expunge): use delete_to_string;
10 (attribute_string): Removed.
11 (flags_string): Removed.
12 (flags_to_string): Replace attribute_string() and flags_string().
13 (message_operation): Rename to fetch_operation.
14 * mailbox/include/imap0.h(struct _f_imap): field func and id
15 removed, never used.
16
17 2001-10-11 Alain Magloire
18
3 * mailbox/folder_imap.c (imap_quoted_string): Free the buffer. 19 * mailbox/folder_imap.c (imap_quoted_string): Free the buffer.
4 (imap_string): Free the buffer. 20 (imap_string): Free the buffer.
5 (imap_body): Check if we already have the fheader header. 21 (imap_body): Check if we already have the fheader header.
...@@ -7,14 +23,15 @@ ...@@ -7,14 +23,15 @@
7 23
8 2001-10-11 Alain Magloire 24 2001-10-11 Alain Magloire
9 25
10 In order to boost performance, when doing the scan we use 26 In order to boost performance, when doing the scan, we use
11 the approach of downloading part of the header of the total 27 the approach of downloading a subset of the header from all
12 set of messages. The it was done before is that the headers 28 of messages. The way it was done before was that the headers
13 were ask one by one per message. This was causing performance 29 were requested one by one per message. This was causing performance
14 delay because we were doing a lot of small transaction on 30 issues because we were doing a lot of small transactions on
15 the TCP/IP stack. By bundling the entire thing in one request 31 the TCP/IP stack. By bundling the entire thing in one request
16 there was much less transcation and the speed was increase 32 "a0000 FETCH 1:* (FLAGS RFC822.SIZE BODY.PEEK[HEADER.FIELDS(..)])\r\n"
17 by a factor of 10++. 33 there were less transcations and the speed was increase
34 by a factor of 100+.
18 The Imap code folder_imap.c and mbx_imap.c is now messy. 35 The Imap code folder_imap.c and mbx_imap.c is now messy.
19 The rewrite in mailbox2 should clean this up though. 36 The rewrite in mailbox2 should clean this up though.
20 37
......
...@@ -61,6 +61,7 @@ record_t imap_record = &_imap_record; ...@@ -61,6 +61,7 @@ record_t imap_record = &_imap_record;
61 #ifndef HAVE_STRTOK_R 61 #ifndef HAVE_STRTOK_R
62 char *strtok_r __P ((char *, const char *, char **)); 62 char *strtok_r __P ((char *, const char *, char **));
63 #endif 63 #endif
64
64 /* Concrete IMAP implementation. */ 65 /* Concrete IMAP implementation. */
65 static int folder_imap_open __P ((folder_t, int)); 66 static int folder_imap_open __P ((folder_t, int));
66 static int folder_imap_create __P ((folder_t)); 67 static int folder_imap_create __P ((folder_t));
...@@ -122,7 +123,7 @@ _folder_imap_init (folder_t folder) ...@@ -122,7 +123,7 @@ _folder_imap_init (folder_t folder)
122 return 0; 123 return 0;
123 } 124 }
124 125
125 /* Destroy the resources. */ 126 /* Destroy the folder resources. */
126 static void 127 static void
127 folder_imap_destroy (folder_t folder) 128 folder_imap_destroy (folder_t folder)
128 { 129 {
...@@ -1374,9 +1375,12 @@ imap_body (f_imap_t f_imap, char **ptr) ...@@ -1374,9 +1375,12 @@ imap_body (f_imap_t f_imap, char **ptr)
1374 } 1375 }
1375 } 1376 }
1376 status = imap_string (f_imap, ptr); 1377 status = imap_string (f_imap, ptr);
1377 if (f_imap->callback.msg_imap->fheader == NULL 1378
1378 && f_imap->state == IMAP_SCAN_ACK && f_imap->callback.total) 1379 /* If the state scan. Catch it here. */
1380 if (f_imap->state == IMAP_SCAN_ACK)
1379 { 1381 {
1382 if (f_imap->callback.msg_imap->fheader)
1383 header_destroy (&f_imap->callback.msg_imap->fheader, NULL);
1380 status = header_create (&f_imap->callback.msg_imap->fheader, 1384 status = header_create (&f_imap->callback.msg_imap->fheader,
1381 f_imap->callback.buffer, f_imap->callback.total, 1385 f_imap->callback.buffer, f_imap->callback.total,
1382 NULL); 1386 NULL);
......
...@@ -39,7 +39,7 @@ extern "C" { ...@@ -39,7 +39,7 @@ extern "C" {
39 #endif /*__P */ 39 #endif /*__P */
40 40
41 #define CLEAR_STATE(f_imap) \ 41 #define CLEAR_STATE(f_imap) \
42 f_imap->selected = NULL, f_imap->id = 0, f_imap->func = NULL, f_imap->state = IMAP_NO_STATE 42 f_imap->selected = NULL, f_imap->state = IMAP_NO_STATE
43 43
44 /* Clear the state and close the stream. */ 44 /* Clear the state and close the stream. */
45 #define CHECK_ERROR_CLOSE(folder, f_imap, status) \ 45 #define CHECK_ERROR_CLOSE(folder, f_imap, status) \
...@@ -136,8 +136,6 @@ struct _f_imap ...@@ -136,8 +136,6 @@ struct _f_imap
136 m_imap_t selected; 136 m_imap_t selected;
137 137
138 enum imap_state state; 138 enum imap_state state;
139 void *func;
140 size_t id;
141 139
142 size_t seq; /* Sequence number to build a tag. */ 140 size_t seq; /* Sequence number to build a tag. */
143 char *capa; /* Cabilities of the server. */ 141 char *capa; /* Cabilities of the server. */
......
...@@ -39,61 +39,63 @@ ...@@ -39,61 +39,63 @@
39 39
40 #define MU_IMAP_CACHE_HEADERS "Bcc Cc Content-Language Content-Transfer-Encoding Content-Type Date From In-Reply-To Message-ID Reference Reply-To Sender Subject To X-UIDL" 40 #define MU_IMAP_CACHE_HEADERS "Bcc Cc Content-Language Content-Transfer-Encoding Content-Type Date From In-Reply-To Message-ID Reference Reply-To Sender Subject To X-UIDL"
41 41
42 /* Functions to overload the mailbox_t API. */ 42 /* mailbox_t API. */
43 static void mailbox_imap_destroy __P ((mailbox_t)); 43 static void mailbox_imap_destroy __P ((mailbox_t));
44 static int mailbox_imap_open __P ((mailbox_t, int)); 44 static int mailbox_imap_open __P ((mailbox_t, int));
45 static int mailbox_imap_close __P ((mailbox_t)); 45 static int mailbox_imap_close __P ((mailbox_t));
46 static int imap_uidvalidity __P ((mailbox_t, unsigned long *)); 46 static int imap_uidvalidity __P ((mailbox_t, unsigned long *));
47 static int imap_uidnext __P ((mailbox_t, size_t *)); 47 static int imap_uidnext __P ((mailbox_t, size_t *));
48 static int imap_expunge __P ((mailbox_t)); 48 static int imap_expunge __P ((mailbox_t));
49 static int imap_get_message __P ((mailbox_t, size_t, message_t *)); 49 static int imap_get_message __P ((mailbox_t, size_t, message_t *));
50 static int imap_messages_count __P ((mailbox_t, size_t *)); 50 static int imap_messages_count __P ((mailbox_t, size_t *));
51 static int imap_messages_recent __P ((mailbox_t, size_t *)); 51 static int imap_messages_recent __P ((mailbox_t, size_t *));
52 static int imap_message_unseen __P ((mailbox_t, size_t *)); 52 static int imap_message_unseen __P ((mailbox_t, size_t *));
53 static int imap_scan __P ((mailbox_t, size_t, size_t *)); 53 static int imap_scan __P ((mailbox_t, size_t, size_t *));
54 static int imap_is_updated __P ((mailbox_t)); 54 static int imap_is_updated __P ((mailbox_t));
55 static int imap_append_message __P ((mailbox_t, message_t)); 55 static int imap_append_message __P ((mailbox_t, message_t));
56 static int imap_copy_message __P ((mailbox_t, message_t)); 56 static int imap_copy_message __P ((mailbox_t, message_t));
57 57
58 /* Message API. */ 58 /* message_t API. */
59 59 static int imap_submessage_size __P ((msg_imap_t, size_t *));
60 static int imap_submessage_size __P ((msg_imap_t, size_t *)); 60 static int imap_message_size __P ((message_t, size_t *));
61 static int imap_message_size __P ((message_t, size_t *)); 61 static int imap_message_lines __P ((message_t, size_t *));
62 static int imap_message_lines __P ((message_t, size_t *)); 62 static int imap_message_fd __P ((stream_t, int *));
63 static int imap_message_fd __P ((stream_t, int *)); 63 static int imap_message_read __P ((stream_t , char *, size_t, off_t, size_t *));
64 static int imap_message_read __P ((stream_t , char *, size_t, off_t, size_t *)); 64 static int imap_message_uid __P ((message_t, size_t *));
65 static int imap_message_uid __P ((message_t, size_t *)); 65
66 66 /* mime_t API. */
67 /* Mime handling. */ 67 static int imap_is_multipart __P ((message_t, int *));
68 static int imap_is_multipart __P ((message_t, int *)); 68 static int imap_get_num_parts __P ((message_t, size_t *));
69 static int imap_get_num_parts __P ((message_t, size_t *)); 69 static int imap_get_part __P ((message_t, size_t, message_t *));
70 static int imap_get_part __P ((message_t, size_t, message_t *)); 70
71 71 /* envelope_t API */
72 /* Envelope. */ 72 static int imap_envelope_sender __P ((envelope_t, char *, size_t, size_t *));
73 static int imap_envelope_sender __P ((envelope_t, char *, size_t, size_t *)); 73 static int imap_envelope_date __P ((envelope_t, char *, size_t, size_t *));
74 static int imap_envelope_date __P ((envelope_t, char *, size_t, size_t *)); 74
75 75 /* attribute_t API */
76 /* Attributes. */ 76 static int imap_attr_get_flags __P ((attribute_t, int *));
77 static int imap_attr_get_flags __P ((attribute_t, int *)); 77 static int imap_attr_set_flags __P ((attribute_t, int));
78 static int imap_attr_set_flags __P ((attribute_t, int)); 78 static int imap_attr_unset_flags __P ((attribute_t, int));
79 static int imap_attr_unset_flags __P ((attribute_t, int)); 79
80 80 /* header_t API. */
81 /* Header. */ 81 static int imap_header_read __P ((header_t, char*, size_t, off_t, size_t *));
82 static int imap_header_read __P ((header_t, char*, size_t, off_t, size_t *)); 82 static int imap_header_get_value __P ((header_t, const char*, char *, size_t, size_t *));
83 static int imap_header_get_value __P ((header_t, const char*, char *, size_t, size_t *)); 83 static int imap_header_get_fvalue __P ((header_t, const char*, char *, size_t, size_t *));
84 static int imap_header_get_fvalue __P ((header_t, const char*, char *, size_t, size_t *)); 84
85 85 /* body_t API. */
86 /* Body. */ 86 static int imap_body_read __P ((stream_t, char *, size_t, off_t, size_t *));
87 static int imap_body_read __P ((stream_t, char *, size_t, off_t, size_t *)); 87 static int imap_body_size __P ((body_t, size_t *));
88 static int imap_body_size __P ((body_t, size_t *)); 88 static int imap_body_lines __P ((body_t, size_t *));
89 static int imap_body_lines __P ((body_t, size_t *)); 89 static int imap_body_fd __P ((stream_t, int *));
90 static int imap_body_fd __P ((stream_t, int *)); 90
91 91 /* Helpers. */
92 /* Private. */ 92 static int imap_get_fd __P ((msg_imap_t, int *));
93 static int imap_get_fd __P ((msg_imap_t, int *)); 93 static int imap_get_message0 __P ((msg_imap_t, message_t *));
94 static int imap_get_message0 __P ((msg_imap_t, message_t *)); 94 static int fetch_operation __P ((f_imap_t, msg_imap_t, char *, size_t, size_t *));
95 static int message_operation __P ((f_imap_t, msg_imap_t, char *, size_t, size_t *)); 95 static void free_subparts __P ((msg_imap_t));
96 static void free_subparts __P ((msg_imap_t)); 96 static int flags_to_string __P ((char **, int));
97 static int delete_to_string __P ((m_imap_t, char **));
98 static int is_same_folder __P ((mailbox_t, message_t));
97 99
98 /* Initialize the concrete object mailbox_t by overloading the function of the 100 /* Initialize the concrete object mailbox_t by overloading the function of the
99 structure. */ 101 structure. */
...@@ -102,7 +104,7 @@ _mailbox_imap_init (mailbox_t mailbox) ...@@ -102,7 +104,7 @@ _mailbox_imap_init (mailbox_t mailbox)
102 { 104 {
103 m_imap_t m_imap; 105 m_imap_t m_imap;
104 size_t name_len = 0; 106 size_t name_len = 0;
105 m_imap = mailbox->data = calloc (1, sizeof (*m_imap)); 107 m_imap = mailbox->data = calloc (1, sizeof *m_imap);
106 if (m_imap == NULL) 108 if (m_imap == NULL)
107 return ENOMEM; 109 return ENOMEM;
108 110
...@@ -161,8 +163,10 @@ free_subparts (msg_imap_t msg_imap) ...@@ -161,8 +163,10 @@ free_subparts (msg_imap_t msg_imap)
161 { 163 {
162 size_t i; 164 size_t i;
163 for (i = 0; i < msg_imap->num_parts; i++) 165 for (i = 0; i < msg_imap->num_parts; i++)
164 if (msg_imap->parts[i]) 166 {
165 free_subparts (msg_imap->parts[i]); 167 if (msg_imap->parts[i])
168 free_subparts (msg_imap->parts[i]);
169 }
166 170
167 if (msg_imap->message) 171 if (msg_imap->message)
168 message_destroy (&(msg_imap->message), msg_imap); 172 message_destroy (&(msg_imap->message), msg_imap);
...@@ -173,7 +177,7 @@ free_subparts (msg_imap_t msg_imap) ...@@ -173,7 +177,7 @@ free_subparts (msg_imap_t msg_imap)
173 free(msg_imap); 177 free(msg_imap);
174 } 178 }
175 179
176 /* Give back all the resources. But is does not mean to shutdown the channel 180 /* Give back all the resources. But it does not mean to shutdown the channel
177 this is done on the folder. */ 181 this is done on the folder. */
178 static void 182 static void
179 mailbox_imap_destroy (mailbox_t mailbox) 183 mailbox_imap_destroy (mailbox_t mailbox)
...@@ -191,8 +195,10 @@ mailbox_imap_destroy (mailbox_t mailbox) ...@@ -191,8 +195,10 @@ mailbox_imap_destroy (mailbox_t mailbox)
191 monitor_wrlock (mailbox->monitor); 195 monitor_wrlock (mailbox->monitor);
192 /* Destroy the imap messages and ressources associated to them. */ 196 /* Destroy the imap messages and ressources associated to them. */
193 for (i = 0; i < m_imap->imessages_count; i++) 197 for (i = 0; i < m_imap->imessages_count; i++)
194 if (m_imap->imessages[i]) 198 {
195 free_subparts (m_imap->imessages[i]); 199 if (m_imap->imessages[i])
200 free_subparts (m_imap->imessages[i]);
201 }
196 if (m_imap->imessages) 202 if (m_imap->imessages)
197 free (m_imap->imessages); 203 free (m_imap->imessages);
198 if (m_imap->name) 204 if (m_imap->name)
...@@ -203,9 +209,10 @@ mailbox_imap_destroy (mailbox_t mailbox) ...@@ -203,9 +209,10 @@ mailbox_imap_destroy (mailbox_t mailbox)
203 } 209 }
204 } 210 }
205 211
206 /* If the connection was not up it is open by the folder. It is not necessary 212 /* If the connection was not up it is open by the folder since the stream
207 to set this mailbox selected on the folder, there maybe on going operation. 213 socket is actually created by the folder. It is not necessary
208 But on any operation, if is not selected will send the SELECT. */ 214 to set select the mailbox right away, there are maybe on going operations.
215 But on any operation by a particular mailbox, it will be selected first. */
209 static int 216 static int
210 mailbox_imap_open (mailbox_t mailbox, int flags) 217 mailbox_imap_open (mailbox_t mailbox, int flags)
211 { 218 {
...@@ -249,8 +256,10 @@ mailbox_imap_close (mailbox_t mailbox) ...@@ -249,8 +256,10 @@ mailbox_imap_close (mailbox_t mailbox)
249 monitor_wrlock (mailbox->monitor); 256 monitor_wrlock (mailbox->monitor);
250 /* Destroy the imap messages and ressources associated to them. */ 257 /* Destroy the imap messages and ressources associated to them. */
251 for (i = 0; i < m_imap->imessages_count; i++) 258 for (i = 0; i < m_imap->imessages_count; i++)
252 if (m_imap->imessages[i]) 259 {
253 free_subparts (m_imap->imessages[i]); 260 if (m_imap->imessages[i])
261 free_subparts (m_imap->imessages[i]);
262 }
254 if (m_imap->imessages) 263 if (m_imap->imessages)
255 free (m_imap->imessages); 264 free (m_imap->imessages);
256 m_imap->imessages = NULL; 265 m_imap->imessages = NULL;
...@@ -260,8 +269,10 @@ mailbox_imap_close (mailbox_t mailbox) ...@@ -260,8 +269,10 @@ mailbox_imap_close (mailbox_t mailbox)
260 m_imap->unseen = 0; 269 m_imap->unseen = 0;
261 monitor_unlock (mailbox->monitor); 270 monitor_unlock (mailbox->monitor);
262 } 271 }
272 break;
263 273
264 default: 274 default:
275 /* mu_error ("imap_close unknown state: reconnect\n");*/
265 break; 276 break;
266 } 277 }
267 278
...@@ -281,25 +292,27 @@ imap_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg) ...@@ -281,25 +292,27 @@ imap_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
281 m_imap_t m_imap = mailbox->data; 292 m_imap_t m_imap = mailbox->data;
282 msg_imap_t msg_imap; 293 msg_imap_t msg_imap;
283 int status = 0; 294 int status = 0;
284 size_t i;
285 295
286 if (pmsg == NULL || msgno == 0 || msgno > m_imap->messages_count) 296 if (pmsg == NULL || msgno == 0 || msgno > m_imap->messages_count)
287 return EINVAL; 297 return EINVAL;
288 298
299 /* Check to see if we have already this message. */
289 monitor_rdlock (mailbox->monitor); 300 monitor_rdlock (mailbox->monitor);
290 /* See if we have already this message. */ 301 {
291 for (i = 0; i < m_imap->imessages_count; i++) 302 size_t i;
292 { 303 for (i = 0; i < m_imap->imessages_count; i++)
293 if (m_imap->imessages[i]) 304 {
294 { 305 if (m_imap->imessages[i])
295 if (m_imap->imessages[i]->num == msgno) 306 {
296 { 307 if (m_imap->imessages[i]->num == msgno)
297 *pmsg = m_imap->imessages[i]->message; 308 {
298 monitor_unlock (mailbox->monitor); 309 *pmsg = m_imap->imessages[i]->message;
299 return 0; 310 monitor_unlock (mailbox->monitor);
300 } 311 return 0;
301 } 312 }
302 } 313 }
314 }
315 }
303 monitor_unlock (mailbox->monitor); 316 monitor_unlock (mailbox->monitor);
304 317
305 /* Allocate a concrete imap message. */ 318 /* Allocate a concrete imap message. */
...@@ -317,7 +330,7 @@ imap_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg) ...@@ -317,7 +330,7 @@ imap_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
317 { 330 {
318 msg_imap_t *m ; 331 msg_imap_t *m ;
319 m = realloc (m_imap->imessages, 332 m = realloc (m_imap->imessages,
320 (m_imap->imessages_count + 1) * sizeof (*m)); 333 (m_imap->imessages_count + 1) * sizeof *m);
321 if (m == NULL) 334 if (m == NULL)
322 { 335 {
323 message_destroy (pmsg, msg_imap); 336 message_destroy (pmsg, msg_imap);
...@@ -331,7 +344,6 @@ imap_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg) ...@@ -331,7 +344,6 @@ imap_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
331 monitor_unlock (mailbox->monitor); 344 monitor_unlock (mailbox->monitor);
332 345
333 msg_imap->message = *pmsg; 346 msg_imap->message = *pmsg;
334 msg_imap->m_imap = m_imap;
335 } 347 }
336 else 348 else
337 free (msg_imap); 349 free (msg_imap);
...@@ -346,7 +358,7 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg) ...@@ -346,7 +358,7 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg)
346 message_t msg = NULL; 358 message_t msg = NULL;
347 mailbox_t mailbox = msg_imap->m_imap->mailbox; 359 mailbox_t mailbox = msg_imap->m_imap->mailbox;
348 360
349 /* Create the message. */ 361 /* Create the message and its stream. */
350 { 362 {
351 stream_t stream = NULL; 363 stream_t stream = NULL;
352 if ((status = message_create (&msg, msg_imap)) != 0 364 if ((status = message_create (&msg, msg_imap)) != 0
...@@ -379,9 +391,6 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg) ...@@ -379,9 +391,6 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg)
379 message_set_header (msg, header, msg_imap); 391 message_set_header (msg, header, msg_imap);
380 } 392 }
381 393
382 /* We do not create any special attribute, since nothing is send to the
383 server. When the attributes change they are cache, they are only
384 sent to the server on mailbox_close or mailbox_expunge. */
385 /* Create the attribute. */ 394 /* Create the attribute. */
386 { 395 {
387 attribute_t attribute; 396 attribute_t attribute;
...@@ -442,6 +451,7 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg) ...@@ -442,6 +451,7 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg)
442 message_set_uid (msg, imap_message_uid, msg_imap); 451 message_set_uid (msg, imap_message_uid, msg_imap);
443 message_set_mailbox (msg, mailbox, msg_imap); 452 message_set_mailbox (msg, mailbox, msg_imap);
444 453
454 /* We are done here. */
445 *pmsg = msg; 455 *pmsg = msg;
446 return 0; 456 return 0;
447 } 457 }
...@@ -480,8 +490,8 @@ imap_uidnext (mailbox_t mailbox, size_t *puidnext) ...@@ -480,8 +490,8 @@ imap_uidnext (mailbox_t mailbox, size_t *puidnext)
480 490
481 /* There is no explicit call to get the message count. The count is send on 491 /* There is no explicit call to get the message count. The count is send on
482 a SELECT/EXAMINE command it is also sent async, meaning it will be piggy 492 a SELECT/EXAMINE command it is also sent async, meaning it will be piggy
483 back on other server response as an untag "EXIST" response. But we still 493 back on other server response as an untag "EXIST" response. The
484 send a SELECT. */ 494 function is also use as a way to select mailbox by other functions. */
485 static int 495 static int
486 imap_messages_count (mailbox_t mailbox, size_t *pnum) 496 imap_messages_count (mailbox_t mailbox, size_t *pnum)
487 { 497 {
...@@ -497,9 +507,6 @@ imap_messages_count (mailbox_t mailbox, size_t *pnum) ...@@ -497,9 +507,6 @@ imap_messages_count (mailbox_t mailbox, size_t *pnum)
497 return 0; 507 return 0;
498 } 508 }
499 509
500 /* Put the mailbox as selected. */
501 f_imap->selected = m_imap;
502
503 switch (f_imap->state) 510 switch (f_imap->state)
504 { 511 {
505 case IMAP_NO_STATE: 512 case IMAP_NO_STATE:
...@@ -521,10 +528,13 @@ imap_messages_count (mailbox_t mailbox, size_t *pnum) ...@@ -521,10 +528,13 @@ imap_messages_count (mailbox_t mailbox, size_t *pnum)
521 break; 528 break;
522 529
523 default: 530 default:
524 CHECK_EAGAIN (f_imap, status); 531 /*mu_error ("imap_message_count unknown state: reconnect\n");*/
525 return status; 532 break;
526 } 533 }
527 534
535 /* Put the mailbox as selected. */
536 f_imap->selected = m_imap;
537
528 if (pnum) 538 if (pnum)
529 *pnum = m_imap->messages_count; 539 *pnum = m_imap->messages_count;
530 540
...@@ -532,7 +542,14 @@ imap_messages_count (mailbox_t mailbox, size_t *pnum) ...@@ -532,7 +542,14 @@ imap_messages_count (mailbox_t mailbox, size_t *pnum)
532 return status; 542 return status;
533 } 543 }
534 544
535 /* We simulate by sending a notification for the total of msgno. */ 545 /* Usually when this function is call it is because there is an oberver
546 attach an the client is try to build some sort of list/tree header
547 as the scanning progress. But doing this for each message can be
548 time consuming and inefficient. So we bundle all the request
549 into one and ask the server for everything "FETCH 1:*". The good
550 side is that everything will be faster and we do not do lot of small
551 transcation but rather a big one. The bad thing is that every thing
552 will be cache in the structure using a lot of memory. */
536 static int 553 static int
537 imap_scan (mailbox_t mailbox, size_t msgno, size_t *pcount) 554 imap_scan (mailbox_t mailbox, size_t msgno, size_t *pcount)
538 { 555 {
...@@ -571,8 +588,8 @@ imap_scan (mailbox_t mailbox, size_t msgno, size_t *pcount) ...@@ -571,8 +588,8 @@ imap_scan (mailbox_t mailbox, size_t msgno, size_t *pcount)
571 break; 588 break;
572 589
573 default: 590 default:
574 CHECK_EAGAIN (f_imap, status); 591 /*mu_error ("imap_scan unknown state: reconnect\n");*/
575 return status; 592 return EINVAL;
576 } 593 }
577 594
578 f_imap->state = IMAP_NO_STATE; 595 f_imap->state = IMAP_NO_STATE;
...@@ -585,7 +602,7 @@ imap_scan (mailbox_t mailbox, size_t msgno, size_t *pcount) ...@@ -585,7 +602,7 @@ imap_scan (mailbox_t mailbox, size_t msgno, size_t *pcount)
585 { 602 {
586 if (observable_notify (mailbox->observable, MU_EVT_MESSAGE_ADD) != 0) 603 if (observable_notify (mailbox->observable, MU_EVT_MESSAGE_ADD) != 0)
587 break; 604 break;
588 if (((i + 1) % 10) == 0) 605 if (((i + 1) % 100) == 0)
589 { 606 {
590 observable_notify (mailbox->observable, MU_EVT_MAILBOX_PROGRESS); 607 observable_notify (mailbox->observable, MU_EVT_MAILBOX_PROGRESS);
591 } 608 }
...@@ -593,7 +610,7 @@ imap_scan (mailbox_t mailbox, size_t msgno, size_t *pcount) ...@@ -593,7 +610,7 @@ imap_scan (mailbox_t mailbox, size_t msgno, size_t *pcount)
593 return 0; 610 return 0;
594 } 611 }
595 612
596 /* Send a NOOP and see if the count has change. */ 613 /* Send a NOOP and see if the count has changed. */
597 static int 614 static int
598 imap_is_updated (mailbox_t mailbox) 615 imap_is_updated (mailbox_t mailbox)
599 { 616 {
...@@ -602,14 +619,15 @@ imap_is_updated (mailbox_t mailbox) ...@@ -602,14 +619,15 @@ imap_is_updated (mailbox_t mailbox)
602 f_imap_t f_imap = m_imap->f_imap; 619 f_imap_t f_imap = m_imap->f_imap;
603 int status = 0; 620 int status = 0;
604 621
622 /* Selected. */
623 status = imap_messages_count (mailbox, &oldcount);
624 if (status != 0)
625 return status;
626
605 /* Send a noop, and let imap piggy pack the information. */ 627 /* Send a noop, and let imap piggy pack the information. */
606 switch (f_imap->state) 628 switch (f_imap->state)
607 { 629 {
608 case IMAP_NO_STATE: 630 case IMAP_NO_STATE:
609 /* Selected. */
610 status = imap_messages_count (mailbox, &oldcount);
611 if (status != 0)
612 return status;
613 status = imap_writeline (f_imap, "g%d NOOP\r\n", f_imap->seq++); 631 status = imap_writeline (f_imap, "g%d NOOP\r\n", f_imap->seq++);
614 CHECK_ERROR (f_imap, status); 632 CHECK_ERROR (f_imap, status);
615 MAILBOX_DEBUG0 (mailbox, MU_DEBUG_PROT, f_imap->buffer); 633 MAILBOX_DEBUG0 (mailbox, MU_DEBUG_PROT, f_imap->buffer);
...@@ -624,8 +642,10 @@ imap_is_updated (mailbox_t mailbox) ...@@ -624,8 +642,10 @@ imap_is_updated (mailbox_t mailbox)
624 status = imap_parse (f_imap); 642 status = imap_parse (f_imap);
625 CHECK_EAGAIN (f_imap, status); 643 CHECK_EAGAIN (f_imap, status);
626 MAILBOX_DEBUG0 (mailbox, MU_DEBUG_PROT, f_imap->buffer); 644 MAILBOX_DEBUG0 (mailbox, MU_DEBUG_PROT, f_imap->buffer);
645 break;
627 646
628 default: 647 default:
648 /*mu_error ("imap_noop unknown state: reconnect\n"); */
629 break; 649 break;
630 } 650 }
631 f_imap->state = IMAP_NO_STATE; 651 f_imap->state = IMAP_NO_STATE;
...@@ -633,53 +653,53 @@ imap_is_updated (mailbox_t mailbox) ...@@ -633,53 +653,53 @@ imap_is_updated (mailbox_t mailbox)
633 } 653 }
634 654
635 655
636 /* FIXME: Not asyn, please fix to make usable when non blocking. */ 656 /* It is only here that the Deleted flags are sent. Expunge is not
657 call rather the mailbox is close explicitely, letting the server
658 do the expunge without sending the notifications. It's faster. */
637 static int 659 static int
638 imap_expunge (mailbox_t mailbox) 660 imap_expunge (mailbox_t mailbox)
639 { 661 {
640 size_t i;
641 int status; 662 int status;
642 m_imap_t m_imap = mailbox->data; 663 m_imap_t m_imap = mailbox->data;
643 f_imap_t f_imap = m_imap->f_imap; 664 f_imap_t f_imap = m_imap->f_imap;
644 665
645 /* Select first. */ 666 /* Select first. */
646 status = imap_messages_count (mailbox, &i); 667 status = imap_messages_count (mailbox, NULL);
647 if (status != 0) 668 if (status != 0)
648 return status; 669 return status;
649 670
650 for (i = 0; i < m_imap->imessages_count; ++i) 671 switch (f_imap->state)
651 { 672 {
652 if (m_imap->imessages[i]->flags & MU_ATTRIBUTE_DELETED) 673 case IMAP_NO_STATE:
653 { 674 {
654 switch (f_imap->state) 675 char *set;
655 { 676 status = delete_to_string (m_imap, &set);
656 case IMAP_NO_STATE: 677 CHECK_ERROR (f_imap, status);
657 status = imap_writeline (f_imap, 678 status = imap_writeline (f_imap,
658 "g%d STORE %d +FLAGS.SILENT (\\Deleted)\r\n", 679 "g%d STORE %s +FLAGS.SILENT (\\Deleted)\r\n",
659 f_imap->seq++, 680 f_imap->seq++, set);
660 m_imap->imessages[i]->num); 681 free (set);
661 CHECK_ERROR (f_imap, status); 682 CHECK_ERROR (f_imap, status);
662 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer); 683 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
663 f_imap->state = IMAP_STORE; 684 f_imap->state = IMAP_STORE;
664 685 }
665 case IMAP_STORE: 686
666 /* Send DELETE. */ 687 /* Send DELETE. */
667 status = imap_send (f_imap); 688 case IMAP_STORE:
668 CHECK_EAGAIN (f_imap, status); 689 status = imap_send (f_imap);
669 f_imap->state = IMAP_STORE_ACK; 690 CHECK_EAGAIN (f_imap, status);
670 691 f_imap->state = IMAP_STORE_ACK;
671 case IMAP_STORE_ACK: 692
672 status = imap_parse (f_imap); 693 case IMAP_STORE_ACK:
673 CHECK_EAGAIN (f_imap, status); 694 status = imap_parse (f_imap);
674 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer); 695 CHECK_EAGAIN (f_imap, status);
675 f_imap->state = IMAP_NO_STATE; 696 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
676 697 f_imap->state = IMAP_NO_STATE;
677 default: 698
678 /* mu_error ("imap_expunge: unknow state\n"); */ 699 default:
679 break; 700 /* mu_error ("imap_expunge: unknow state\n"); */
680 } /* switch (state) */ 701 break;
681 } /* message_get_attribute() */ 702 }
682 } /* for */
683 703
684 /* Tell the server to delete the messages but without sending the 704 /* Tell the server to delete the messages but without sending the
685 EXPUNGE response. We can do the calculations. */ 705 EXPUNGE response. We can do the calculations. */
...@@ -687,95 +707,11 @@ imap_expunge (mailbox_t mailbox) ...@@ -687,95 +707,11 @@ imap_expunge (mailbox_t mailbox)
687 return status; 707 return status;
688 } 708 }
689 709
690 static int
691 attribute_string (attribute_t attribute, char **pbuf)
692 {
693 char *abuf = *pbuf;
694 if (attribute_is_deleted (attribute))
695 {
696 char *tmp = realloc (abuf, strlen (abuf) + strlen ("\\Deleted") + 2);
697 if (tmp == NULL)
698 {
699 free (abuf);
700 return ENOMEM;
701 }
702 abuf = tmp;
703 if (*abuf)
704 strcat (abuf, " ");
705 strcat (abuf, "\\Deleted");
706 }
707 if (attribute_is_seen (attribute) || attribute_is_read (attribute))
708 {
709 char *tmp = realloc (abuf, strlen (abuf) + strlen ("\\Seen") + 2);
710 if (tmp == NULL)
711 {
712 free (abuf);
713 return ENOMEM;
714 }
715 abuf = tmp;
716 if (*abuf)
717 strcat (abuf, " ");
718 strcat (abuf, "\\Seen");
719 }
720 if (attribute_is_answered (attribute))
721 {
722 char *tmp = realloc (abuf, strlen (abuf) + strlen ("\\Answered") + 2);
723 if (tmp == NULL)
724 {
725 free (abuf);
726 return ENOMEM;
727 }
728 abuf = tmp;
729 if (*abuf)
730 strcat (abuf, " ");
731 strcat (abuf, "\\Answered");
732 }
733 if (attribute_is_draft (attribute))
734 {
735 char *tmp = realloc (abuf, strlen (abuf) + strlen ("\\Draft") + 2);
736 if (tmp == NULL)
737 {
738 free (abuf);
739 return ENOMEM;
740 }
741 abuf = tmp;
742 if (*abuf)
743 strcat (abuf, " ");
744 strcat (abuf, "\\Draft");
745 }
746 if (attribute_is_flagged (attribute))
747 {
748 char *tmp = realloc (abuf, strlen (abuf) + strlen ("\\Flagged") + 2);
749 if (tmp == NULL)
750 {
751 free (abuf);
752 return ENOMEM;
753 }
754 abuf = tmp;
755 if (*abuf)
756 strcat (abuf, " ");
757 strcat (abuf, "\\Flagged");
758 }
759 *pbuf = abuf;
760 return 0;
761 }
762
763 static int
764 is_same_folder (mailbox_t mailbox, message_t msg)
765 {
766 mailbox_t mbox = NULL;
767 message_get_mailbox (msg, &mbox);
768 return (mbox != NULL && mbox->url != NULL
769 && url_is_same_scheme (mbox->url, mailbox->url)
770 && url_is_same_host (mbox->url, mailbox->url)
771 && url_is_same_port (mbox->url, mailbox->url));
772 }
773
774 /* Not Nonblocking safe. */ 710 /* Not Nonblocking safe. */
775 /* DANGER: The message_t object makes no guarenty the size and the lines 711 /* DANGER: The message_t object makes no guaranty about the size and the lines
776 that it returns are exact if its pointing to non-local file messages. 712 that it returns, if its pointing to non-local file messages.
777 FIXME: So we should download the message to a floating message so to 713 FIXME: So we should download the message to a floating message so to
778 make sure that we know the exacte size then transmit it back the IMAP 714 make sure that we know the exact size then transmit it back the IMAP
779 server. */ 715 server. */
780 static int 716 static int
781 imap_append_message (mailbox_t mailbox, message_t msg) 717 imap_append_message (mailbox_t mailbox, message_t msg)
...@@ -788,13 +724,11 @@ imap_append_message (mailbox_t mailbox, message_t msg) ...@@ -788,13 +724,11 @@ imap_append_message (mailbox_t mailbox, message_t msg)
788 /* FIXME: Can we append to self. */ 724 /* FIXME: Can we append to self. */
789 725
790 /* Check to see if we are selected. If the message was not modified 726 /* Check to see if we are selected. If the message was not modified
791 and came from the imap folder. use COPY.*/ 727 and came from the same imap folder. use COPY.*/
792 if (f_imap->selected != m_imap && !message_is_modified (msg) 728 if (f_imap->selected != m_imap && !message_is_modified (msg)
793 && is_same_folder (mailbox, msg)) 729 && is_same_folder (mailbox, msg))
794 return imap_copy_message (mailbox, msg); 730 return imap_copy_message (mailbox, msg);
795 731
796 /* FIXME: Do we need to get the envelope_date? */
797
798 switch (f_imap->state) 732 switch (f_imap->state)
799 { 733 {
800 case IMAP_NO_STATE: 734 case IMAP_NO_STATE:
...@@ -808,8 +742,10 @@ imap_append_message (mailbox_t mailbox, message_t msg) ...@@ -808,8 +742,10 @@ imap_append_message (mailbox_t mailbox, message_t msg)
808 *abuf = '\0'; 742 *abuf = '\0';
809 { 743 {
810 attribute_t attribute = NULL; 744 attribute_t attribute = NULL;
745 int flags = 0;
811 message_get_attribute (msg, &attribute); 746 message_get_attribute (msg, &attribute);
812 status = attribute_string (attribute, &abuf); 747 attribute_get_flags (attribute, &flags);
748 status = flags_to_string (&abuf, flags);
813 if (status != 0) 749 if (status != 0)
814 return status; 750 return status;
815 if (*abuf != '\0') 751 if (*abuf != '\0')
...@@ -825,16 +761,29 @@ imap_append_message (mailbox_t mailbox, message_t msg) ...@@ -825,16 +761,29 @@ imap_append_message (mailbox_t mailbox, message_t msg)
825 abuf = tmp; 761 abuf = tmp;
826 } 762 }
827 } 763 }
764
765 /* Get the mailbox filepath. */
828 { 766 {
829 size_t n = 0; 767 size_t n = 0;
830 url_get_path (mailbox->url, NULL, 0, &n); 768 url_get_path (mailbox->url, NULL, 0, &n);
831 if (n == 0) 769 if (n == 0)
832 return EINVAL; 770 {
771 free (abuf);
772 return EINVAL;
773 }
833 path = calloc (n + 1, sizeof (*path)); 774 path = calloc (n + 1, sizeof (*path));
834 if (path == NULL) 775 if (path == NULL)
835 return ENOMEM; 776 {
777 free (abuf);
778 return ENOMEM;
779 }
836 url_get_path (mailbox->url, path, n + 1, NULL); 780 url_get_path (mailbox->url, path, n + 1, NULL);
837 } 781 }
782
783 /* FIXME: we need to get the envelope_date and use it.
784 currently it is ignored. */
785
786 /* Get the total size, assuming that it is in UNIX format. */
838 lines = size = 0; 787 lines = size = 0;
839 message_size (msg, &size); 788 message_size (msg, &size);
840 message_lines (msg, &lines); 789 message_lines (msg, &lines);
...@@ -900,14 +849,15 @@ imap_append_message (mailbox_t mailbox, message_t msg) ...@@ -900,14 +849,15 @@ imap_append_message (mailbox_t mailbox, message_t msg)
900 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer); 849 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
901 850
902 default: 851 default:
903 /* mu_error ("imap_expunge: unknow state\n"); */ 852 /* mu_error ("imap_append: unknow state\n"); */
904 break; 853 break;
905 } 854 }
906 f_imap->state = IMAP_NO_STATE; 855 f_imap->state = IMAP_NO_STATE;
907 return status; 856 return status;
908 } 857 }
909 858
910 /* Not Nonblocking safe. */ 859 /* If the message is on the same server. Use the COPY command much more
860 efficient. */
911 static int 861 static int
912 imap_copy_message (mailbox_t mailbox, message_t msg) 862 imap_copy_message (mailbox_t mailbox, message_t msg)
913 { 863 {
...@@ -921,17 +871,15 @@ imap_copy_message (mailbox_t mailbox, message_t msg) ...@@ -921,17 +871,15 @@ imap_copy_message (mailbox_t mailbox, message_t msg)
921 case IMAP_NO_STATE: 871 case IMAP_NO_STATE:
922 { 872 {
923 char *path; 873 char *path;
874 size_t n = 0;
924 /* Check for a valid mailbox name. */ 875 /* Check for a valid mailbox name. */
925 { 876 url_get_path (mailbox->url, NULL, 0, &n);
926 size_t n = 0; 877 if (n == 0)
927 url_get_path (mailbox->url, NULL, 0, &n); 878 return EINVAL;
928 if (n == 0) 879 path = calloc (n + 1, sizeof (*path));
929 return EINVAL; 880 if (path == NULL)
930 path = calloc (n + 1, sizeof (*path)); 881 return ENOMEM;
931 if (path == NULL) 882 url_get_path (mailbox->url, path, n + 1, NULL);
932 return ENOMEM;
933 url_get_path (mailbox->url, path, n + 1, NULL);
934 }
935 status = imap_writeline (f_imap, "g%d COPY %d %s\r\n", f_imap->seq++, 883 status = imap_writeline (f_imap, "g%d COPY %d %s\r\n", f_imap->seq++,
936 msg_imap->num, path); 884 msg_imap->num, path);
937 free (path); 885 free (path);
...@@ -957,7 +905,7 @@ imap_copy_message (mailbox_t mailbox, message_t msg) ...@@ -957,7 +905,7 @@ imap_copy_message (mailbox_t mailbox, message_t msg)
957 return status; 905 return status;
958 } 906 }
959 907
960 /* Message. */ 908 /* Message read overload */
961 static int 909 static int
962 imap_message_read (stream_t stream, char *buffer, size_t buflen, 910 imap_message_read (stream_t stream, char *buffer, size_t buflen,
963 off_t offset, size_t *plen) 911 off_t offset, size_t *plen)
...@@ -974,32 +922,28 @@ imap_message_read (stream_t stream, char *buffer, size_t buflen, ...@@ -974,32 +922,28 @@ imap_message_read (stream_t stream, char *buffer, size_t buflen,
974 /* Select first. */ 922 /* Select first. */
975 if (f_imap->state == IMAP_NO_STATE) 923 if (f_imap->state == IMAP_NO_STATE)
976 { 924 {
925 char *section = NULL;
977 int status = imap_messages_count (m_imap->mailbox, NULL); 926 int status = imap_messages_count (m_imap->mailbox, NULL);
978 if (status != 0) 927 if (status != 0)
979 return status; 928 return status;
980 /* We strip the \r, but the offset/size on the imap server is with that 929
981 octet so add it in the offset, since it's the number of lines. */
982 if (msg_imap->part) 930 if (msg_imap->part)
983 { 931 section = section_name (msg_imap);
984 char *section = section_name (msg_imap); 932
985 status = imap_writeline (f_imap, 933 /* We have strip the \r, but the offset on the imap server is with that
986 "g%d FETCH %d BODY.PEEK[%s]<%d.%d>\r\n", 934 octet(CFLF) so add it in the offset, it's the number of lines. */
987 f_imap->seq++, msg_imap->num, 935 status = imap_writeline (f_imap,
988 (section) ? section : "", 936 "g%d FETCH %d BODY.PEEK[%s]<%d.%d>\r\n",
989 offset + msg_imap->message_lines, buflen); 937 f_imap->seq++, msg_imap->num,
990 if (section) 938 (section) ? section : "",
991 free (section); 939 offset + msg_imap->message_lines, buflen);
992 } 940 if (section)
993 else 941 free (section);
994 status = imap_writeline (f_imap,
995 "g%d FETCH %d BODY.PEEK[]<%d.%d>\r\n",
996 f_imap->seq++, msg_imap->num,
997 offset + msg_imap->message_lines, buflen);
998 CHECK_ERROR (f_imap, status); 942 CHECK_ERROR (f_imap, status);
999 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer); 943 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
1000 f_imap->state = IMAP_FETCH; 944 f_imap->state = IMAP_FETCH;
1001 } 945 }
1002 return message_operation (f_imap, msg_imap, buffer, buflen, plen); 946 return fetch_operation (f_imap, msg_imap, buffer, buflen, plen);
1003 } 947 }
1004 948
1005 static int 949 static int
...@@ -1056,9 +1000,7 @@ imap_message_size (message_t msg, size_t *psize) ...@@ -1056,9 +1000,7 @@ imap_message_size (message_t msg, size_t *psize)
1056 the full size of mime messages, so the message_size retrieved from 1000 the full size of mime messages, so the message_size retrieved from
1057 doing a bodystructure represents rather the body_size. */ 1001 doing a bodystructure represents rather the body_size. */
1058 if (msg_imap->parent) 1002 if (msg_imap->parent)
1059 { 1003 return imap_submessage_size (msg_imap, psize);
1060 return imap_submessage_size (msg_imap, psize);
1061 }
1062 1004
1063 if (msg_imap->message_size == 0) 1005 if (msg_imap->message_size == 0)
1064 { 1006 {
...@@ -1078,7 +1020,7 @@ imap_message_size (message_t msg, size_t *psize) ...@@ -1078,7 +1020,7 @@ imap_message_size (message_t msg, size_t *psize)
1078 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer); 1020 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
1079 f_imap->state = IMAP_FETCH; 1021 f_imap->state = IMAP_FETCH;
1080 } 1022 }
1081 status = message_operation (f_imap, msg_imap, 0, 0, 0); 1023 status = fetch_operation (f_imap, msg_imap, 0, 0, 0);
1082 } 1024 }
1083 1025
1084 if (status == 0) 1026 if (status == 0)
...@@ -1116,7 +1058,7 @@ imap_message_uid (message_t msg, size_t *puid) ...@@ -1116,7 +1058,7 @@ imap_message_uid (message_t msg, size_t *puid)
1116 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer); 1058 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
1117 f_imap->state = IMAP_FETCH; 1059 f_imap->state = IMAP_FETCH;
1118 } 1060 }
1119 status = message_operation (f_imap, msg_imap, 0, 0, 0); 1061 status = fetch_operation (f_imap, msg_imap, 0, 0, 0);
1120 if (status != 0) 1062 if (status != 0)
1121 return status; 1063 return status;
1122 *puid = msg_imap->uid; 1064 *puid = msg_imap->uid;
...@@ -1159,7 +1101,7 @@ imap_is_multipart (message_t msg, int *ismulti) ...@@ -1159,7 +1101,7 @@ imap_is_multipart (message_t msg, int *ismulti)
1159 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer); 1101 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
1160 f_imap->state = IMAP_FETCH; 1102 f_imap->state = IMAP_FETCH;
1161 } 1103 }
1162 status = message_operation (f_imap, msg_imap, 0, 0, 0); 1104 status = fetch_operation (f_imap, msg_imap, 0, 0, 0);
1163 if (status != 0) 1105 if (status != 0)
1164 return status; 1106 return status;
1165 if (ismulti) 1107 if (ismulti)
...@@ -1295,7 +1237,7 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen, ...@@ -1295,7 +1237,7 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen,
1295 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer); 1237 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
1296 f_imap->state = IMAP_FETCH; 1238 f_imap->state = IMAP_FETCH;
1297 } 1239 }
1298 status = message_operation (f_imap, msg_imap, datebuf, sizeof datebuf, NULL); 1240 status = fetch_operation (f_imap, msg_imap, datebuf, sizeof datebuf, NULL);
1299 if (status != 0) 1241 if (status != 0)
1300 return status; 1242 return status;
1301 1243
...@@ -1363,7 +1305,7 @@ imap_attr_get_flags (attribute_t attribute, int *pflags) ...@@ -1363,7 +1305,7 @@ imap_attr_get_flags (attribute_t attribute, int *pflags)
1363 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer); 1305 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
1364 f_imap->state = IMAP_FETCH; 1306 f_imap->state = IMAP_FETCH;
1365 } 1307 }
1366 status = message_operation (f_imap, msg_imap, NULL, 0, NULL); 1308 status = fetch_operation (f_imap, msg_imap, NULL, 0, NULL);
1367 if (status == 0) 1309 if (status == 0)
1368 { 1310 {
1369 if (pflags) 1311 if (pflags)
...@@ -1373,79 +1315,6 @@ imap_attr_get_flags (attribute_t attribute, int *pflags) ...@@ -1373,79 +1315,6 @@ imap_attr_get_flags (attribute_t attribute, int *pflags)
1373 } 1315 }
1374 1316
1375 static int 1317 static int
1376 flags_string (int flag, char **pbuf)
1377 {
1378 char *abuf = *pbuf;
1379 if (flag & MU_ATTRIBUTE_DELETED)
1380 {
1381 char *tmp = realloc (abuf, strlen (abuf) + strlen ("\\Deleted") + 2);
1382 if (tmp == NULL)
1383 {
1384 free (abuf);
1385 return ENOMEM;
1386 }
1387 abuf = tmp;
1388 if (*abuf)
1389 strcat (abuf, " ");
1390 strcat (abuf, "\\Deleted");
1391 }
1392 if ((flag & MU_ATTRIBUTE_SEEN) || (flag & MU_ATTRIBUTE_READ))
1393 {
1394 char *tmp = realloc (abuf, strlen (abuf) + strlen ("\\Seen") + 2);
1395 if (tmp == NULL)
1396 {
1397 free (abuf);
1398 return ENOMEM;
1399 }
1400 abuf = tmp;
1401 if (*abuf)
1402 strcat (abuf, " ");
1403 strcat (abuf, "\\Seen");
1404 }
1405 if (flag & MU_ATTRIBUTE_ANSWERED)
1406 {
1407 char *tmp = realloc (abuf, strlen (abuf) + strlen ("\\Answered") + 2);
1408 if (tmp == NULL)
1409 {
1410 free (abuf);
1411 return ENOMEM;
1412 }
1413 abuf = tmp;
1414 if (*abuf)
1415 strcat (abuf, " ");
1416 strcat (abuf, "\\Answered");
1417 }
1418 if (flag & MU_ATTRIBUTE_DRAFT)
1419 {
1420 char *tmp = realloc (abuf, strlen (abuf) + strlen ("\\Draft") + 2);
1421 if (tmp == NULL)
1422 {
1423 free (abuf);
1424 return ENOMEM;
1425 }
1426 abuf = tmp;
1427 if (*abuf)
1428 strcat (abuf, " ");
1429 strcat (abuf, "\\Draft");
1430 }
1431 if (flag & MU_ATTRIBUTE_FLAGGED)
1432 {
1433 char *tmp = realloc (abuf, strlen (abuf) + strlen ("\\Flagged") + 2);
1434 if (tmp == NULL)
1435 {
1436 free (abuf);
1437 return ENOMEM;
1438 }
1439 abuf = tmp;
1440 if (*abuf)
1441 strcat (abuf, " ");
1442 strcat (abuf, "\\Flagged");
1443 }
1444 *pbuf = abuf;
1445 return 0;
1446 }
1447
1448 static int
1449 imap_attr_set_flags (attribute_t attribute, int flag) 1318 imap_attr_set_flags (attribute_t attribute, int flag)
1450 { 1319 {
1451 message_t msg = attribute_get_owner (attribute); 1320 message_t msg = attribute_get_owner (attribute);
...@@ -1467,7 +1336,7 @@ imap_attr_set_flags (attribute_t attribute, int flag) ...@@ -1467,7 +1336,7 @@ imap_attr_set_flags (attribute_t attribute, int flag)
1467 if (abuf == NULL) 1336 if (abuf == NULL)
1468 return ENOMEM; 1337 return ENOMEM;
1469 *abuf = '\0'; 1338 *abuf = '\0';
1470 status = flags_string (flag, &abuf); 1339 status = flags_to_string (&abuf, flag);
1471 if (status != 0) 1340 if (status != 0)
1472 return status; 1341 return status;
1473 /* No flags to send?? */ 1342 /* No flags to send?? */
...@@ -1484,7 +1353,7 @@ imap_attr_set_flags (attribute_t attribute, int flag) ...@@ -1484,7 +1353,7 @@ imap_attr_set_flags (attribute_t attribute, int flag)
1484 msg_imap->flags |= flag; 1353 msg_imap->flags |= flag;
1485 f_imap->state = IMAP_FETCH; 1354 f_imap->state = IMAP_FETCH;
1486 } 1355 }
1487 return message_operation (f_imap, msg_imap, NULL, 0, NULL); 1356 return fetch_operation (f_imap, msg_imap, NULL, 0, NULL);
1488 } 1357 }
1489 1358
1490 static int 1359 static int
...@@ -1509,7 +1378,7 @@ imap_attr_unset_flags (attribute_t attribute, int flag) ...@@ -1509,7 +1378,7 @@ imap_attr_unset_flags (attribute_t attribute, int flag)
1509 if (abuf == NULL) 1378 if (abuf == NULL)
1510 return ENOMEM; 1379 return ENOMEM;
1511 *abuf = '\0'; 1380 *abuf = '\0';
1512 status = flags_string (flag, &abuf); 1381 status = flags_to_string (&abuf, flag);
1513 if (status != 0) 1382 if (status != 0)
1514 return status; 1383 return status;
1515 /* No flags to send?? */ 1384 /* No flags to send?? */
...@@ -1526,7 +1395,7 @@ imap_attr_unset_flags (attribute_t attribute, int flag) ...@@ -1526,7 +1395,7 @@ imap_attr_unset_flags (attribute_t attribute, int flag)
1526 msg_imap->flags &= ~flag; 1395 msg_imap->flags &= ~flag;
1527 f_imap->state = IMAP_FETCH; 1396 f_imap->state = IMAP_FETCH;
1528 } 1397 }
1529 return message_operation (f_imap, msg_imap, NULL, 0, NULL); 1398 return fetch_operation (f_imap, msg_imap, NULL, 0, NULL);
1530 } 1399 }
1531 1400
1532 /* Header. */ 1401 /* Header. */
...@@ -1566,7 +1435,7 @@ imap_header_get_value (header_t header, const char *field, char * buffer, ...@@ -1566,7 +1435,7 @@ imap_header_get_value (header_t header, const char *field, char * buffer,
1566 } 1435 }
1567 1436
1568 value = calloc (len, sizeof (*value)); 1437 value = calloc (len, sizeof (*value));
1569 status = message_operation (f_imap, msg_imap, value, len, &len); 1438 status = fetch_operation (f_imap, msg_imap, value, len, &len);
1570 if (status == 0) 1439 if (status == 0)
1571 { 1440 {
1572 char *colon; 1441 char *colon;
...@@ -1641,7 +1510,7 @@ imap_header_get_fvalue (header_t header, const char *field, char * buffer, ...@@ -1641,7 +1510,7 @@ imap_header_get_fvalue (header_t header, const char *field, char * buffer,
1641 /* Should be enough for our needs. */ 1510 /* Should be enough for our needs. */
1642 len = 2048; 1511 len = 2048;
1643 value = calloc (len, sizeof *value); 1512 value = calloc (len, sizeof *value);
1644 status = message_operation (f_imap, msg_imap, value, len, &len); 1513 status = fetch_operation (f_imap, msg_imap, value, len, &len);
1645 if (status == 0) 1514 if (status == 0)
1646 { 1515 {
1647 status = header_create (&msg_imap->fheader, value, len, NULL); 1516 status = header_create (&msg_imap->fheader, value, len, NULL);
...@@ -1669,33 +1538,29 @@ imap_header_read (header_t header, char *buffer, size_t buflen, off_t offset, ...@@ -1669,33 +1538,29 @@ imap_header_read (header_t header, char *buffer, size_t buflen, off_t offset,
1669 /* Select first. */ 1538 /* Select first. */
1670 if (f_imap->state == IMAP_NO_STATE) 1539 if (f_imap->state == IMAP_NO_STATE)
1671 { 1540 {
1541 char *section = NULL;
1672 int status = imap_messages_count (m_imap->mailbox, NULL); 1542 int status = imap_messages_count (m_imap->mailbox, NULL);
1673 if (status != 0) 1543 if (status != 0)
1674 return status; 1544 return status;
1545
1546 if (msg_imap->part)
1547 section = section_name (msg_imap);
1548
1675 /* We strip the \r, but the offset/size on the imap server is with that 1549 /* We strip the \r, but the offset/size on the imap server is with that
1676 octet so add it in the offset, since it's the number of lines. */ 1550 octet so add it in the offset, since it's the number of lines. */
1677 if (msg_imap->part) 1551 status = imap_writeline (f_imap,
1678 { 1552 "g%d FETCH %d BODY.PEEK[%s.MIME]<%d.%d>\r\n",
1679 char *section = section_name (msg_imap); 1553 f_imap->seq++, msg_imap->num,
1680 status = imap_writeline (f_imap, 1554 (section) ? section : "",
1681 "g%d FETCH %d BODY.PEEK[%s.MIME]<%d.%d>\r\n", 1555 offset + msg_imap->header_lines, buflen);
1682 f_imap->seq++, msg_imap->num, 1556 if (section)
1683 (section) ? section : "", 1557 free (section);
1684 offset + msg_imap->header_lines, buflen);
1685 if (section)
1686 free (section);
1687 }
1688 else
1689 status = imap_writeline (f_imap,
1690 "g%d FETCH %d BODY.PEEK[HEADER]<%d.%d>\r\n",
1691 f_imap->seq++, msg_imap->num,
1692 offset + msg_imap->header_lines, buflen);
1693 CHECK_ERROR (f_imap, status); 1558 CHECK_ERROR (f_imap, status);
1694 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer); 1559 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
1695 f_imap->state = IMAP_FETCH; 1560 f_imap->state = IMAP_FETCH;
1696 1561
1697 } 1562 }
1698 return message_operation (f_imap, msg_imap, buffer, buflen, plen); 1563 return fetch_operation (f_imap, msg_imap, buffer, buflen, plen);
1699 } 1564 }
1700 1565
1701 /* Body. */ 1566 /* Body. */
...@@ -1771,33 +1636,29 @@ imap_body_read (stream_t stream, char *buffer, size_t buflen, off_t offset, ...@@ -1771,33 +1636,29 @@ imap_body_read (stream_t stream, char *buffer, size_t buflen, off_t offset,
1771 /* Select first. */ 1636 /* Select first. */
1772 if (f_imap->state == IMAP_NO_STATE) 1637 if (f_imap->state == IMAP_NO_STATE)
1773 { 1638 {
1639 char *section = NULL;
1774 status = imap_messages_count (m_imap->mailbox, NULL); 1640 status = imap_messages_count (m_imap->mailbox, NULL);
1775 if (status != 0) 1641 if (status != 0)
1776 return status; 1642 return status;
1643
1644 if (msg_imap->part)
1645 section = section_name (msg_imap);
1646
1777 /* We strip the \r, but the offset/size on the imap server is with the 1647 /* We strip the \r, but the offset/size on the imap server is with the
1778 octet, so add it since it's the number of lines. */ 1648 octet, so add it since it's the number of lines. */
1779 if (msg_imap->part) 1649 status = imap_writeline (f_imap,
1780 { 1650 "g%d FETCH %d BODY.PEEK[%s]<%d.%d>\r\n",
1781 char *section = section_name (msg_imap); 1651 f_imap->seq++, msg_imap->num,
1782 status = imap_writeline (f_imap, 1652 (section) ? section: "",
1783 "g%d FETCH %d BODY.PEEK[%s]<%d.%d>\r\n", 1653 offset + msg_imap->body_lines, buflen);
1784 f_imap->seq++, msg_imap->num, 1654 if (section)
1785 (section) ? section: "", 1655 free (section);
1786 offset + msg_imap->body_lines, buflen);
1787 if (section)
1788 free (section);
1789 }
1790 else
1791 status = imap_writeline (f_imap,
1792 "g%d FETCH %d BODY.PEEK[TEXT]<%d.%d>\r\n",
1793 f_imap->seq++, msg_imap->num,
1794 offset + msg_imap->body_lines, buflen);
1795 CHECK_ERROR (f_imap, status); 1656 CHECK_ERROR (f_imap, status);
1796 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer); 1657 MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
1797 f_imap->state = IMAP_FETCH; 1658 f_imap->state = IMAP_FETCH;
1798 1659
1799 } 1660 }
1800 status = message_operation (f_imap, msg_imap, buffer, buflen, plen); 1661 status = fetch_operation (f_imap, msg_imap, buffer, buflen, plen);
1801 if (oldbuf) 1662 if (oldbuf)
1802 oldbuf[0] = buffer[0]; 1663 oldbuf[0] = buffer[0];
1803 return status; 1664 return status;
...@@ -1824,8 +1685,9 @@ imap_get_fd (msg_imap_t msg_imap, int *pfd) ...@@ -1824,8 +1685,9 @@ imap_get_fd (msg_imap_t msg_imap, int *pfd)
1824 return EINVAL; 1685 return EINVAL;
1825 } 1686 }
1826 1687
1688 /* Since so many operations are fetch, we regoup this into one function. */
1827 static int 1689 static int
1828 message_operation (f_imap_t f_imap, msg_imap_t msg_imap, char *buffer, 1690 fetch_operation (f_imap_t f_imap, msg_imap_t msg_imap, char *buffer,
1829 size_t buflen, size_t *plen) 1691 size_t buflen, size_t *plen)
1830 { 1692 {
1831 int status = 0; 1693 int status = 0;
...@@ -1835,7 +1697,6 @@ message_operation (f_imap_t f_imap, msg_imap_t msg_imap, char *buffer, ...@@ -1835,7 +1697,6 @@ message_operation (f_imap_t f_imap, msg_imap_t msg_imap, char *buffer,
1835 case IMAP_FETCH: 1697 case IMAP_FETCH:
1836 status = imap_send (f_imap); 1698 status = imap_send (f_imap);
1837 CHECK_EAGAIN (f_imap, status); 1699 CHECK_EAGAIN (f_imap, status);
1838 /* Set the callback, we want the results. */
1839 if (f_imap->callback.buffer) 1700 if (f_imap->callback.buffer)
1840 free (f_imap->callback.buffer); 1701 free (f_imap->callback.buffer);
1841 f_imap->callback.buffer = NULL; 1702 f_imap->callback.buffer = NULL;
...@@ -1859,14 +1720,15 @@ message_operation (f_imap_t f_imap, msg_imap_t msg_imap, char *buffer, ...@@ -1859,14 +1720,15 @@ message_operation (f_imap_t f_imap, msg_imap_t msg_imap, char *buffer,
1859 if (status == 0 && f_imap->isopen == 0 && f_imap->callback.total == 0) 1720 if (status == 0 && f_imap->isopen == 0 && f_imap->callback.total == 0)
1860 status = EBADF; 1721 status = EBADF;
1861 1722
1862 /* Clear the callback. */
1863 buflen = min (buflen, f_imap->callback.total); 1723 buflen = min (buflen, f_imap->callback.total);
1864 if (buffer && f_imap->callback.buffer) 1724 if (f_imap->callback.buffer)
1865 memcpy (buffer, f_imap->callback.buffer, buflen); 1725 {
1726 if (buffer)
1727 memcpy (buffer, f_imap->callback.buffer, buflen);
1728 free (f_imap->callback.buffer);
1729 }
1866 if (plen) 1730 if (plen)
1867 *plen = buflen; 1731 *plen = buflen;
1868 if (f_imap->callback.buffer)
1869 free (f_imap->callback.buffer);
1870 f_imap->callback.buffer = NULL; 1732 f_imap->callback.buffer = NULL;
1871 f_imap->callback.buflen = 0; 1733 f_imap->callback.buflen = 0;
1872 f_imap->callback.total = 0; 1734 f_imap->callback.total = 0;
...@@ -1876,3 +1738,144 @@ message_operation (f_imap_t f_imap, msg_imap_t msg_imap, char *buffer, ...@@ -1876,3 +1738,144 @@ message_operation (f_imap_t f_imap, msg_imap_t msg_imap, char *buffer,
1876 f_imap->state = IMAP_NO_STATE; 1738 f_imap->state = IMAP_NO_STATE;
1877 return status; 1739 return status;
1878 } 1740 }
1741
1742 /* Decide whether the message came from the same folder as the mailbox. */
1743 static int
1744 is_same_folder (mailbox_t mailbox, message_t msg)
1745 {
1746 mailbox_t mbox = NULL;
1747 message_get_mailbox (msg, &mbox);
1748 return (mbox != NULL && mbox->url != NULL
1749 && url_is_same_scheme (mbox->url, mailbox->url)
1750 && url_is_same_host (mbox->url, mailbox->url)
1751 && url_is_same_port (mbox->url, mailbox->url));
1752 }
1753
1754 /* Convert flag attribute to IMAP String attributes. */
1755 static int
1756 flags_to_string (char **pbuf, int flag)
1757 {
1758 char *abuf = *pbuf;
1759 if (flag & MU_ATTRIBUTE_DELETED)
1760 {
1761 char *tmp = realloc (abuf, strlen (abuf) + strlen ("\\Deleted") + 2);
1762 if (tmp == NULL)
1763 {
1764 free (abuf);
1765 return ENOMEM;
1766 }
1767 abuf = tmp;
1768 if (*abuf)
1769 strcat (abuf, " ");
1770 strcat (abuf, "\\Deleted");
1771 }
1772 if ((flag & MU_ATTRIBUTE_SEEN) || (flag & MU_ATTRIBUTE_READ))
1773 {
1774 char *tmp = realloc (abuf, strlen (abuf) + strlen ("\\Seen") + 2);
1775 if (tmp == NULL)
1776 {
1777 free (abuf);
1778 return ENOMEM;
1779 }
1780 abuf = tmp;
1781 if (*abuf)
1782 strcat (abuf, " ");
1783 strcat (abuf, "\\Seen");
1784 }
1785 if (flag & MU_ATTRIBUTE_ANSWERED)
1786 {
1787 char *tmp = realloc (abuf, strlen (abuf) + strlen ("\\Answered") + 2);
1788 if (tmp == NULL)
1789 {
1790 free (abuf);
1791 return ENOMEM;
1792 }
1793 abuf = tmp;
1794 if (*abuf)
1795 strcat (abuf, " ");
1796 strcat (abuf, "\\Answered");
1797 }
1798 if (flag & MU_ATTRIBUTE_DRAFT)
1799 {
1800 char *tmp = realloc (abuf, strlen (abuf) + strlen ("\\Draft") + 2);
1801 if (tmp == NULL)
1802 {
1803 free (abuf);
1804 return ENOMEM;
1805 }
1806 abuf = tmp;
1807 if (*abuf)
1808 strcat (abuf, " ");
1809 strcat (abuf, "\\Draft");
1810 }
1811 if (flag & MU_ATTRIBUTE_FLAGGED)
1812 {
1813 char *tmp = realloc (abuf, strlen (abuf) + strlen ("\\Flagged") + 2);
1814 if (tmp == NULL)
1815 {
1816 free (abuf);
1817 return ENOMEM;
1818 }
1819 abuf = tmp;
1820 if (*abuf)
1821 strcat (abuf, " ");
1822 strcat (abuf, "\\Flagged");
1823 }
1824 *pbuf = abuf;
1825 return 0;
1826 }
1827
1828 /* Convert a suite of number to IMAP message number. */
1829 static int
1830 delete_to_string (m_imap_t m_imap, char **pset)
1831 {
1832 size_t i, prev = 0, is_range = 0;
1833 char *set = calloc (1, 1);
1834
1835 if (set == NULL)
1836 return ENOMEM;
1837
1838 /* Reformat the number for IMAP. */
1839 for (i = 0; i < m_imap->imessages_count; ++i)
1840 {
1841 if (m_imap->imessages[i]->flags & MU_ATTRIBUTE_DELETED)
1842 {
1843 char *tmp;
1844 char buf[128];
1845 size_t cur = m_imap->imessages[i]->num;
1846 *buf = '\0';
1847 /* The first number. */
1848 if (prev == 0)
1849 {
1850 snprintf (buf, sizeof buf, "%d", cur);
1851 }
1852 /* Is it still a sequence? */
1853 else if ((prev + 1) == cur)
1854 {
1855 is_range = 1;
1856 continue;
1857 }
1858 /* We had a previous seqence. */
1859 else if (is_range)
1860 {
1861 snprintf (buf, sizeof buf, ":%d,%d", prev, cur);
1862 is_range = 0;
1863 }
1864 else
1865 {
1866 snprintf (buf, sizeof buf, ",%d", cur);
1867 }
1868 prev = cur;
1869 tmp = realloc (set, strlen (set) + strlen (buf) + 1);
1870 if (tmp == NULL)
1871 {
1872 free (set);
1873 return ENOMEM;
1874 }
1875 set = tmp;
1876 strcat (set, buf);
1877 }
1878 } /* for () */
1879 *pset = set;
1880 return 0;
1881 }
......