Mercurial > dovecot > core-2.2
annotate src/lib-storage/index/imapc/imapc-mailbox.c @ 12615:3dde816d945d
imapc: Write large message bodies to temp files rather than keeping in memory.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 31 Jan 2011 04:02:04 +0200 |
parents | 391ba80cb125 |
children | 4fdf3084f74f |
rev | line source |
---|---|
12590 | 1 /* Copyright (c) 2011 Dovecot authors, see the included COPYING file */ |
2 | |
3 #include "lib.h" | |
12592
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
4 #include "ioloop.h" |
12590 | 5 #include "imap-arg.h" |
6 #include "imap-util.h" | |
7 #include "imapc-client.h" | |
8 #include "imapc-seqmap.h" | |
9 #include "imapc-storage.h" | |
10 | |
12592
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
11 #define NOTIFY_DELAY_MSECS 500 |
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
12 |
12595
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
13 static void imapc_mailbox_init_delayed_trans(struct imapc_mailbox *mbox) |
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
14 { |
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
15 if (mbox->delayed_sync_trans != NULL) |
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
16 return; |
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
17 |
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
18 mbox->delayed_sync_trans = |
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
19 mail_index_transaction_begin(mbox->box.view, |
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
20 MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL); |
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
21 mbox->delayed_sync_view = |
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
22 mail_index_transaction_open_updated_view(mbox->delayed_sync_trans); |
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
23 } |
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
24 |
12604
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
25 static void |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
26 imapc_newmsgs_callback(const struct imapc_command_reply *reply, |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
27 void *context) |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
28 { |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
29 struct imapc_mailbox *mbox = context; |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
30 |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
31 if (reply->state == IMAPC_COMMAND_STATE_OK) |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
32 ; |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
33 else if (reply->state == IMAPC_COMMAND_STATE_NO) { |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
34 imapc_copy_error_from_reply(mbox->storage, MAIL_ERROR_PARAMS, |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
35 reply); |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
36 } else { |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
37 mail_storage_set_critical(&mbox->storage->storage, |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
38 "imapc: Command failed: %s", reply->text_full); |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
39 } |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
40 if (mbox->opening) |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
41 imapc_client_stop(mbox->storage->client); |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
42 } |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
43 |
12590 | 44 static void imapc_untagged_exists(const struct imapc_untagged_reply *reply, |
45 struct imapc_mailbox *mbox) | |
46 { | |
47 uint32_t rcount = reply->num; | |
48 const struct mail_index_header *hdr; | |
49 struct imapc_seqmap *seqmap; | |
50 uint32_t next_lseq, next_rseq; | |
51 | |
52 if (mbox == NULL) | |
53 return; | |
54 | |
55 seqmap = imapc_client_mailbox_get_seqmap(mbox->client_box); | |
56 next_lseq = mail_index_view_get_messages_count(mbox->box.view) + 1; | |
57 next_rseq = imapc_seqmap_lseq_to_rseq(seqmap, next_lseq); | |
58 if (next_rseq > rcount) | |
59 return; | |
60 | |
61 hdr = mail_index_get_header(mbox->box.view); | |
62 | |
63 mbox->new_msgs = TRUE; | |
12604
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
64 imapc_client_mailbox_cmdf(mbox->client_box, imapc_newmsgs_callback, |
0e5c36a54ce8
imapc: Added support for saving and copying messages.
Timo Sirainen <tss@iki.fi>
parents:
12600
diff
changeset
|
65 mbox, "UID FETCH %u:* FLAGS", hdr->next_uid); |
12590 | 66 } |
67 | |
12592
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
68 static void imapc_mailbox_idle_timeout(struct imapc_mailbox *mbox) |
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
69 { |
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
70 timeout_remove(&mbox->to_idle); |
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
71 if (mbox->box.notify_callback != NULL) |
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
72 mbox->box.notify_callback(&mbox->box, mbox->box.notify_context); |
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
73 } |
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
74 |
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
75 static void imapc_mailbox_idle_notify(struct imapc_mailbox *mbox) |
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
76 { |
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
77 if (mbox->box.notify_callback != NULL && mbox->to_idle == NULL) { |
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
78 mbox->to_idle = |
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
79 timeout_add(NOTIFY_DELAY_MSECS, |
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
80 imapc_mailbox_idle_timeout, mbox); |
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
81 } |
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
82 } |
12590 | 83 |
84 static void imapc_untagged_fetch(const struct imapc_untagged_reply *reply, | |
85 struct imapc_mailbox *mbox) | |
86 { | |
87 uint32_t seq = reply->num; | |
88 struct imapc_seqmap *seqmap; | |
89 const struct imap_arg *list, *flags_list; | |
90 const char *atom; | |
91 const struct mail_index_record *rec; | |
92 enum mail_flags flags; | |
93 uint32_t uid, old_count; | |
94 unsigned int i, j; | |
12609
391ba80cb125
imapc: Send UID FETCH commands with larger uidset parameter if possible.
Timo Sirainen <tss@iki.fi>
parents:
12604
diff
changeset
|
95 ARRAY_TYPE(const_string) keywords = ARRAY_INIT; |
12590 | 96 bool seen_flags = FALSE; |
97 | |
98 if (mbox == NULL || seq == 0 || !imap_arg_get_list(reply->args, &list)) | |
99 return; | |
100 | |
101 uid = 0; flags = 0; | |
102 for (i = 0; list[i].type != IMAP_ARG_EOL; i += 2) { | |
103 if (!imap_arg_get_atom(&list[i], &atom)) | |
104 return; | |
105 | |
106 if (strcasecmp(atom, "UID") == 0) { | |
107 if (!imap_arg_get_atom(&list[i+1], &atom) || | |
108 str_to_uint32(atom, &uid) < 0) | |
109 return; | |
110 } else if (strcasecmp(atom, "FLAGS") == 0) { | |
111 if (!imap_arg_get_list(&list[i+1], &flags_list)) | |
112 return; | |
113 | |
12600
ba3c0ee558f5
imapc: Added support for keywords.
Timo Sirainen <tss@iki.fi>
parents:
12595
diff
changeset
|
114 t_array_init(&keywords, 8); |
12590 | 115 seen_flags = TRUE; |
116 for (j = 0; flags_list[j].type != IMAP_ARG_EOL; j++) { | |
117 if (!imap_arg_get_atom(&flags_list[j], &atom)) | |
118 return; | |
119 if (atom[0] == '\\') | |
120 flags |= imap_parse_system_flag(atom); | |
12600
ba3c0ee558f5
imapc: Added support for keywords.
Timo Sirainen <tss@iki.fi>
parents:
12595
diff
changeset
|
121 else { |
ba3c0ee558f5
imapc: Added support for keywords.
Timo Sirainen <tss@iki.fi>
parents:
12595
diff
changeset
|
122 /* keyword */ |
ba3c0ee558f5
imapc: Added support for keywords.
Timo Sirainen <tss@iki.fi>
parents:
12595
diff
changeset
|
123 array_append(&keywords, &atom, 1); |
ba3c0ee558f5
imapc: Added support for keywords.
Timo Sirainen <tss@iki.fi>
parents:
12595
diff
changeset
|
124 } |
12590 | 125 } |
126 } | |
127 } | |
128 | |
129 seqmap = imapc_client_mailbox_get_seqmap(mbox->client_box); | |
130 seq = imapc_seqmap_rseq_to_lseq(seqmap, seq); | |
131 | |
132 if (mbox->cur_fetch_mail != NULL && mbox->cur_fetch_mail->seq == seq) { | |
133 i_assert(uid == 0 || mbox->cur_fetch_mail->uid == uid); | |
12615
3dde816d945d
imapc: Write large message bodies to temp files rather than keeping in memory.
Timo Sirainen <tss@iki.fi>
parents:
12609
diff
changeset
|
134 imapc_fetch_mail_update(mbox->cur_fetch_mail, reply, list); |
12590 | 135 } |
136 | |
12595
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
137 imapc_mailbox_init_delayed_trans(mbox); |
12590 | 138 old_count = mail_index_view_get_messages_count(mbox->delayed_sync_view); |
139 if (seq > old_count) { | |
140 if (uid == 0) | |
141 return; | |
142 i_assert(seq == old_count + 1); | |
143 mail_index_append(mbox->delayed_sync_trans, uid, &seq); | |
144 } | |
145 rec = mail_index_lookup(mbox->delayed_sync_view, seq); | |
146 if (seen_flags && rec->flags != flags) { | |
147 mail_index_update_flags(mbox->delayed_sync_trans, seq, | |
148 MODIFY_REPLACE, flags); | |
149 } | |
12600
ba3c0ee558f5
imapc: Added support for keywords.
Timo Sirainen <tss@iki.fi>
parents:
12595
diff
changeset
|
150 if (seen_flags) { |
ba3c0ee558f5
imapc: Added support for keywords.
Timo Sirainen <tss@iki.fi>
parents:
12595
diff
changeset
|
151 struct mail_keywords *kw; |
ba3c0ee558f5
imapc: Added support for keywords.
Timo Sirainen <tss@iki.fi>
parents:
12595
diff
changeset
|
152 |
ba3c0ee558f5
imapc: Added support for keywords.
Timo Sirainen <tss@iki.fi>
parents:
12595
diff
changeset
|
153 (void)array_append_space(&keywords); |
ba3c0ee558f5
imapc: Added support for keywords.
Timo Sirainen <tss@iki.fi>
parents:
12595
diff
changeset
|
154 kw = mail_index_keywords_create(mbox->box.index, |
ba3c0ee558f5
imapc: Added support for keywords.
Timo Sirainen <tss@iki.fi>
parents:
12595
diff
changeset
|
155 array_idx(&keywords, 0)); |
ba3c0ee558f5
imapc: Added support for keywords.
Timo Sirainen <tss@iki.fi>
parents:
12595
diff
changeset
|
156 mail_index_update_keywords(mbox->delayed_sync_trans, seq, |
ba3c0ee558f5
imapc: Added support for keywords.
Timo Sirainen <tss@iki.fi>
parents:
12595
diff
changeset
|
157 MODIFY_REPLACE, kw); |
ba3c0ee558f5
imapc: Added support for keywords.
Timo Sirainen <tss@iki.fi>
parents:
12595
diff
changeset
|
158 mail_index_keywords_unref(&kw); |
ba3c0ee558f5
imapc: Added support for keywords.
Timo Sirainen <tss@iki.fi>
parents:
12595
diff
changeset
|
159 } |
12592
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
160 imapc_mailbox_idle_notify(mbox); |
12590 | 161 } |
162 | |
163 static void imapc_untagged_expunge(const struct imapc_untagged_reply *reply, | |
164 struct imapc_mailbox *mbox) | |
165 { | |
166 struct imapc_seqmap *seqmap; | |
167 uint32_t lseq, rseq = reply->num; | |
168 | |
169 if (mbox == NULL || rseq == 0) | |
170 return; | |
171 | |
172 seqmap = imapc_client_mailbox_get_seqmap(mbox->client_box); | |
173 lseq = imapc_seqmap_rseq_to_lseq(seqmap, rseq); | |
12595
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
174 imapc_seqmap_expunge(seqmap, rseq); |
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
175 |
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
176 imapc_mailbox_init_delayed_trans(mbox); |
12590 | 177 mail_index_expunge(mbox->delayed_sync_trans, lseq); |
12592
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
178 |
475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
Timo Sirainen <tss@iki.fi>
parents:
12590
diff
changeset
|
179 imapc_mailbox_idle_notify(mbox); |
12590 | 180 } |
181 | |
182 static void | |
183 imapc_resp_text_uidvalidity(const struct imapc_untagged_reply *reply, | |
184 struct imapc_mailbox *mbox) | |
185 { | |
186 uint32_t uid_validity; | |
187 | |
188 if (mbox == NULL || reply->resp_text_value == NULL || | |
189 str_to_uint32(reply->resp_text_value, &uid_validity) < 0) | |
190 return; | |
191 | |
12595
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
192 imapc_mailbox_init_delayed_trans(mbox); |
12590 | 193 mail_index_update_header(mbox->delayed_sync_trans, |
194 offsetof(struct mail_index_header, uid_validity), | |
195 &uid_validity, sizeof(uid_validity), TRUE); | |
196 } | |
197 | |
198 static void | |
199 imapc_resp_text_uidnext(const struct imapc_untagged_reply *reply, | |
200 struct imapc_mailbox *mbox) | |
201 { | |
202 uint32_t uid_next; | |
203 | |
204 if (mbox == NULL || reply->resp_text_value == NULL || | |
205 str_to_uint32(reply->resp_text_value, &uid_next) < 0) | |
206 return; | |
207 | |
12595
5d97dfa9d86c
imapc: Fixed mailbox deletion and some error handling. Code cleanups.
Timo Sirainen <tss@iki.fi>
parents:
12592
diff
changeset
|
208 imapc_mailbox_init_delayed_trans(mbox); |
12590 | 209 mail_index_update_header(mbox->delayed_sync_trans, |
210 offsetof(struct mail_index_header, next_uid), | |
211 &uid_next, sizeof(uid_next), FALSE); | |
212 } | |
213 | |
214 void imapc_mailbox_register_untagged(struct imapc_mailbox *mbox, | |
215 const char *key, | |
216 imapc_mailbox_callback_t *callback) | |
217 { | |
218 struct imapc_mailbox_event_callback *cb; | |
219 | |
220 cb = array_append_space(&mbox->untagged_callbacks); | |
221 cb->name = p_strdup(mbox->box.pool, key); | |
222 cb->callback = callback; | |
223 } | |
224 | |
225 void imapc_mailbox_register_resp_text(struct imapc_mailbox *mbox, | |
226 const char *key, | |
227 imapc_mailbox_callback_t *callback) | |
228 { | |
229 struct imapc_mailbox_event_callback *cb; | |
230 | |
231 cb = array_append_space(&mbox->resp_text_callbacks); | |
232 cb->name = p_strdup(mbox->box.pool, key); | |
233 cb->callback = callback; | |
234 } | |
235 | |
236 void imapc_mailbox_register_callbacks(struct imapc_mailbox *mbox) | |
237 { | |
238 imapc_mailbox_register_untagged(mbox, "EXISTS", | |
239 imapc_untagged_exists); | |
240 imapc_mailbox_register_untagged(mbox, "FETCH", | |
241 imapc_untagged_fetch); | |
242 imapc_mailbox_register_untagged(mbox, "EXPUNGE", | |
243 imapc_untagged_expunge); | |
244 imapc_mailbox_register_resp_text(mbox, "UIDVALIDITY", | |
245 imapc_resp_text_uidvalidity); | |
246 imapc_mailbox_register_resp_text(mbox, "UIDNEXT", | |
247 imapc_resp_text_uidnext); | |
248 } |