]>
Commit | Line | Data |
---|---|---|
fe91d611 AM |
1 | diff --git a/src/auth/passdb-pam.c b/src/auth/passdb-pam.c |
2 | --- a/src/auth/passdb-pam.c | |
3 | +++ b/src/auth/passdb-pam.c | |
4 | @@ -229,8 +229,7 @@ static int pam_auth(struct auth_request | |
5 | } | |
6 | } | |
7 | ||
8 | - /* FIXME: this doesn't actually work since we're in the child | |
9 | - process.. */ | |
10 | + /* FIXME: this works only with blocking=yes */ | |
11 | status = pam_get_item(pamh, PAM_USER, (linux_const void **)&item); | |
12 | if (status != PAM_SUCCESS) { | |
13 | *error = t_strdup_printf("pam_get_item() failed: %s", | |
14 | diff --git a/src/imap/client.c b/src/imap/client.c | |
15 | --- a/src/imap/client.c | |
16 | +++ b/src/imap/client.c | |
17 | @@ -485,13 +485,18 @@ int _client_output(void *context) | |
18 | ||
19 | static void idle_timeout(void *context __attr_unused__) | |
20 | { | |
21 | - time_t idle_time; | |
22 | + time_t idle_time, last_change; | |
23 | ||
24 | if (my_client == NULL) | |
25 | return; | |
26 | ||
27 | - idle_time = ioloop_time - | |
28 | + /* We mostly want to check last_input here, but if there is a very long | |
29 | + running command (like copying thousands of messages), we don't want | |
30 | + to disconnect the client just after the command was finished. | |
31 | + But any output that IDLE has sent should be ignored. */ | |
32 | + last_change = my_client->idling ? my_client->last_input : | |
33 | I_MAX(my_client->last_input, my_client->last_output); | |
34 | + idle_time = ioloop_time - last_change; | |
35 | ||
36 | if (my_client->command_pending && | |
37 | o_stream_get_buffer_used_size(my_client->output) > 0 && | |
38 | diff --git a/src/imap/client.h b/src/imap/client.h | |
39 | --- a/src/imap/client.h | |
40 | +++ b/src/imap/client.h | |
41 | @@ -52,6 +52,7 @@ struct client { | |
42 | unsigned int input_pending:1; | |
43 | unsigned int output_pending:1; | |
44 | unsigned int handling_input:1; | |
45 | + unsigned int idling:1; | |
46 | unsigned int input_skip_line:1; /* skip all the data until we've | |
47 | found a new line */ | |
48 | }; | |
49 | diff --git a/src/imap/cmd-append.c b/src/imap/cmd-append.c | |
50 | --- a/src/imap/cmd-append.c | |
51 | +++ b/src/imap/cmd-append.c | |
52 | @@ -285,8 +285,7 @@ static bool cmd_append_continue_parsing( | |
53 | if (ctx->msg_size == 0) { | |
54 | /* no message data, abort */ | |
55 | client_send_tagline(cmd, "NO Append aborted."); | |
56 | - cmd_append_finish(ctx); | |
57 | - return TRUE; | |
58 | + return cmd_append_cancel(ctx, nonsync); | |
59 | } | |
60 | ||
61 | /* save the mail */ | |
62 | diff --git a/src/imap/cmd-idle.c b/src/imap/cmd-idle.c | |
63 | --- a/src/imap/cmd-idle.c | |
64 | +++ b/src/imap/cmd-idle.c | |
65 | @@ -56,6 +56,7 @@ static void idle_finish(struct cmd_idle_ | |
66 | if (client->mailbox != NULL) | |
67 | mailbox_notify_changes(client->mailbox, 0, NULL, NULL); | |
68 | ||
69 | + client->idling = FALSE; | |
70 | if (done_ok) | |
71 | client_send_tagline(ctx->cmd, "OK Idle completed."); | |
72 | else | |
73 | @@ -263,6 +264,7 @@ bool cmd_idle(struct client_command_cont | |
74 | client->io = io_add(i_stream_get_fd(client->input), | |
75 | IO_READ, idle_client_input, ctx); | |
76 | ||
77 | + client->idling = TRUE; | |
78 | client->command_pending = TRUE; | |
79 | cmd->func = cmd_idle_continue; | |
80 | cmd->context = ctx; | |
81 | diff --git a/src/imap/cmd-list.c b/src/imap/cmd-list.c | |
82 | --- a/src/imap/cmd-list.c | |
83 | +++ b/src/imap/cmd-list.c | |
84 | @@ -135,6 +135,15 @@ list_namespace_mailboxes(struct client * | |
85 | continue; | |
86 | str_append(name_str, ctx->ns->prefix); | |
87 | } | |
88 | + if ((list->flags & MAILBOX_NOCHILDREN) != 0 && | |
89 | + strncmp(ctx->ns->prefix, "INBOX", 5) == 0 && | |
90 | + ctx->ns->prefix[5] == ctx->ns->sep) { | |
91 | + /* FIXME: It's unlikely there's only a single | |
92 | + INBOX mailbox, but it's possible. We should | |
93 | + check that instead of assuming it. */ | |
94 | + list->flags |= MAILBOX_CHILDREN; | |
95 | + list->flags &= ~MAILBOX_NOCHILDREN; | |
96 | + } | |
97 | } else { | |
98 | str_append(name_str, ctx->ns->prefix); | |
99 | } | |
100 | diff --git a/src/imap/imap-fetch.c b/src/imap/imap-fetch.c | |
101 | --- a/src/imap/imap-fetch.c | |
102 | +++ b/src/imap/imap-fetch.c | |
103 | @@ -322,6 +322,7 @@ int imap_fetch(struct imap_fetch_context | |
104 | ctx->line_finished = TRUE; | |
105 | if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0) | |
106 | return -1; | |
107 | + ctx->client->last_output = ioloop_time; | |
108 | ||
109 | ctx->cur_mail = NULL; | |
110 | ctx->cur_handler = 0; | |
111 | @@ -362,12 +363,11 @@ int imap_fetch_deinit(struct imap_fetch_ | |
112 | mailbox_header_lookup_deinit(&ctx->all_headers_ctx); | |
113 | ||
114 | if (ctx->trans != NULL) { | |
115 | - if (ctx->failed) | |
116 | - mailbox_transaction_rollback(&ctx->trans); | |
117 | - else { | |
118 | - if (mailbox_transaction_commit(&ctx->trans, 0) < 0) | |
119 | - ctx->failed = TRUE; | |
120 | - } | |
121 | + /* even if something failed, we want to commit changes to | |
122 | + cache, as well as possible \Seen flag changes for FETCH | |
123 | + replies we returned so far. */ | |
124 | + if (mailbox_transaction_commit(&ctx->trans, 0) < 0) | |
125 | + ctx->failed = TRUE; | |
126 | } | |
127 | return ctx->failed ? -1 : 0; | |
128 | } | |
129 | diff --git a/src/lib-index/mail-transaction-log-view.c b/src/lib-index/mail-transaction-log-view.c | |
130 | --- a/src/lib-index/mail-transaction-log-view.c | |
131 | +++ b/src/lib-index/mail-transaction-log-view.c | |
132 | @@ -97,9 +97,10 @@ mail_transaction_log_view_set(struct mai | |
133 | uint32_t max_file_seq, uoff_t max_file_offset, | |
134 | enum mail_transaction_type type_mask) | |
135 | { | |
136 | - struct mail_transaction_log_file *file, *first; | |
137 | + struct mail_transaction_log_file *file, *const *files; | |
138 | + unsigned int i; | |
139 | uint32_t seq; | |
140 | - uoff_t end_offset; | |
141 | + uoff_t start_offset, end_offset; | |
142 | int ret; | |
143 | ||
144 | i_assert(view->log != NULL); | |
145 | @@ -159,12 +160,8 @@ mail_transaction_log_view_set(struct mai | |
146 | return -1; | |
147 | } | |
148 | ||
149 | - end_offset = min_file_seq == max_file_seq ? | |
150 | - max_file_offset : (uoff_t)-1; | |
151 | - ret = mail_transaction_log_file_map(file, min_file_offset, end_offset); | |
152 | - if (ret <= 0) | |
153 | - return ret; | |
154 | - first = file; | |
155 | + view->tail = file; | |
156 | + view->head = file; | |
157 | ||
158 | for (seq = min_file_seq+1; seq <= max_file_seq; seq++) { | |
159 | file = file->next; | |
160 | @@ -192,40 +189,57 @@ mail_transaction_log_view_set(struct mai | |
161 | /* missing files in the middle */ | |
162 | return 0; | |
163 | } | |
164 | - | |
165 | + view->head = file; | |
166 | + } | |
167 | + | |
168 | + /* we have all of them. update refcounts. */ | |
169 | + mail_transaction_log_view_unref_all(view); | |
170 | + | |
171 | + /* reference all used files */ | |
172 | + for (file = view->tail;; file = file->next) { | |
173 | + array_append(&view->file_refs, &file, 1); | |
174 | + file->refcount++; | |
175 | + | |
176 | + if (file == view->head) | |
177 | + break; | |
178 | + } | |
179 | + | |
180 | + /* Map the files only after we've found them all. Otherwise if we map | |
181 | + one file and then another file just happens to get rotated, we could | |
182 | + include both files in the view but skip the last transactions from | |
183 | + the first file. | |
184 | + | |
185 | + We're mapping the files in reverse order so that _log_file_map() | |
186 | + can verify that prev_file_offset matches how far it actually managed | |
187 | + to sync the file. */ | |
188 | + files = array_idx(&view->file_refs, 0); | |
189 | + for (i = array_count(&view->file_refs); i > 0; i--) { | |
190 | + file = files[i-1]; | |
191 | + start_offset = file->hdr.file_seq == min_file_seq ? | |
192 | + min_file_offset : file->hdr.hdr_size; | |
193 | end_offset = file->hdr.file_seq == max_file_seq ? | |
194 | max_file_offset : (uoff_t)-1; | |
195 | - ret = mail_transaction_log_file_map(file, file->hdr.hdr_size, | |
196 | + ret = mail_transaction_log_file_map(file, start_offset, | |
197 | end_offset); | |
198 | if (ret <= 0) | |
199 | return ret; | |
200 | } | |
201 | ||
202 | + i_assert(max_file_seq == (uint32_t)-1 || | |
203 | + max_file_seq == view->head->hdr.file_seq); | |
204 | i_assert(max_file_offset == (uoff_t)-1 || | |
205 | - max_file_offset <= file->sync_offset); | |
206 | - | |
207 | - /* we have all of them. update refcounts. */ | |
208 | - mail_transaction_log_view_unref_all(view); | |
209 | - | |
210 | - view->tail = first; | |
211 | - view->head = view->log->head; | |
212 | - | |
213 | - /* reference all used files */ | |
214 | - for (file = view->tail; file != NULL; file = file->next) { | |
215 | - array_append(&view->file_refs, &file, 1); | |
216 | - file->refcount++; | |
217 | - } | |
218 | + max_file_offset <= view->head->sync_offset); | |
219 | ||
220 | view->prev_file_seq = 0; | |
221 | view->prev_file_offset = 0; | |
222 | ||
223 | - view->cur = first; | |
224 | + view->cur = view->tail; | |
225 | view->cur_offset = min_file_offset; | |
226 | ||
227 | view->min_file_seq = min_file_seq; | |
228 | view->min_file_offset = min_file_offset; | |
229 | view->max_file_seq = max_file_seq; | |
230 | - view->max_file_offset = max_file_offset; | |
231 | + view->max_file_offset = I_MIN(max_file_offset, view->head->sync_offset); | |
232 | view->type_mask = type_mask; | |
233 | view->broken = FALSE; | |
234 | ||
235 | diff --git a/src/lib-index/mail-transaction-log.c b/src/lib-index/mail-transaction-log.c | |
236 | --- a/src/lib-index/mail-transaction-log.c | |
237 | +++ b/src/lib-index/mail-transaction-log.c | |
238 | @@ -1145,15 +1145,20 @@ mail_transaction_log_file_sync(struct ma | |
239 | if (file->sync_offset - file->buffer_offset + hdr_size > size) | |
240 | break; | |
241 | file->sync_offset += hdr_size; | |
242 | + hdr_size = 0; | |
243 | } | |
244 | ||
245 | avail = file->sync_offset - file->buffer_offset; | |
246 | - if (avail != size && avail >= sizeof(*hdr)) { | |
247 | - /* record goes outside the file we've seen. or if | |
248 | - we're accessing the log file via unlocked mmaped | |
249 | - memory, it may be just that the memory was updated | |
250 | - after we checked the file size. */ | |
251 | - if (file->locked || file->mmap_base == NULL) { | |
252 | + if (avail != size) { | |
253 | + /* There's more data than we could sync at the moment. If the | |
254 | + last record's size wasn't valid, we can't know if it will | |
255 | + be updated unless we've locked the log. | |
256 | + | |
257 | + Without locking we can be sure only if we're not using | |
258 | + mmaping, because with mmaping the data and the file size | |
259 | + can get updated at any time. */ | |
260 | + if (file->locked || | |
261 | + (hdr_size != 0 && file->mmap_base == NULL)) { | |
262 | if (hdr_size != 0) { | |
263 | mail_transaction_log_file_set_corrupted(file, | |
264 | "hdr.size too large (%u)", hdr_size); | |
265 | diff --git a/src/lib-storage/mail-copy.c b/src/lib-storage/mail-copy.c | |
266 | --- a/src/lib-storage/mail-copy.c | |
267 | +++ b/src/lib-storage/mail-copy.c | |
268 | @@ -2,7 +2,7 @@ | |
269 | ||
270 | #include "lib.h" | |
271 | #include "istream.h" | |
272 | -#include "mail-storage.h" | |
273 | +#include "mail-storage-private.h" | |
274 | #include "mail-copy.h" | |
275 | ||
276 | int mail_storage_copy(struct mailbox_transaction_context *t, struct mail *mail, | |
277 | @@ -31,6 +31,8 @@ int mail_storage_copy(struct mailbox_tra | |
278 | } | |
279 | ||
280 | if (input->stream_errno != 0) { | |
281 | + mail_storage_set_critical(t->box->storage, | |
282 | + "copy: i_stream_read() failed: %m"); | |
283 | mailbox_save_cancel(&ctx); | |
284 | return -1; | |
285 | } | |
286 | diff --git a/src/lib/ioloop-notify-inotify.c b/src/lib/ioloop-notify-inotify.c | |
287 | --- a/src/lib/ioloop-notify-inotify.c | |
288 | +++ b/src/lib/ioloop-notify-inotify.c | |
289 | @@ -155,7 +155,12 @@ void io_loop_notify_handler_init(struct | |
290 | ||
291 | ctx->inotify_fd = inotify_init(); | |
292 | if (ctx->inotify_fd == -1) { | |
293 | - i_error("inotify_init() failed: %m"); | |
294 | + if (errno != EMFILE) | |
295 | + i_error("inotify_init() failed: %m"); | |
296 | + else { | |
297 | + i_warning("Inotify instance limit for user exceeded, " | |
298 | + "disabling."); | |
299 | + } | |
300 | ctx->disabled = TRUE; | |
301 | return; | |
302 | } | |
303 | diff --git a/src/lib/lib-signals.c b/src/lib/lib-signals.c | |
304 | --- a/src/lib/lib-signals.c | |
305 | +++ b/src/lib/lib-signals.c | |
306 | @@ -21,10 +21,11 @@ struct signal_handler { | |
307 | /* Remember that these are accessed inside signal handler which may be called | |
308 | even while we're initializing/deinitializing. Try hard to keep everything | |
309 | in consistent state. */ | |
310 | -static struct signal_handler *signal_handlers[MAX_SIGNAL_VALUE+1]; | |
311 | -static int sig_pipe_fd[2]; | |
312 | - | |
313 | -static struct io *io_sig; | |
314 | +static struct signal_handler *signal_handlers[MAX_SIGNAL_VALUE+1] = { NULL, }; | |
315 | +static int sig_pipe_fd[2] = { -1, -1 }; | |
316 | + | |
317 | +static bool signals_initialized = FALSE; | |
318 | +static struct io *io_sig = NULL; | |
319 | ||
320 | static void sig_handler(int signo) | |
321 | { | |
322 | @@ -99,6 +100,18 @@ static void signal_read(void *context __ | |
323 | } | |
324 | } | |
325 | ||
326 | +static void lib_signals_set(int signo, bool ignore) | |
327 | +{ | |
328 | + struct sigaction act; | |
329 | + | |
330 | + if (sigemptyset(&act.sa_mask) < 0) | |
331 | + i_fatal("sigemptyset(): %m"); | |
332 | + act.sa_flags = 0; | |
333 | + act.sa_handler = ignore ? sig_ignore : sig_handler; | |
334 | + if (sigaction(signo, &act, NULL) < 0) | |
335 | + i_fatal("sigaction(%d): %m", signo); | |
336 | +} | |
337 | + | |
338 | void lib_signals_set_handler(int signo, bool delayed, | |
339 | signal_handler_t *handler, void *context) | |
340 | { | |
341 | @@ -109,17 +122,10 @@ void lib_signals_set_handler(int signo, | |
342 | signo, MAX_SIGNAL_VALUE); | |
343 | } | |
344 | ||
345 | - if (signal_handlers[signo] == NULL) { | |
346 | + if (signal_handlers[signo] == NULL && | |
347 | + (handler == NULL || signals_initialized)) { | |
348 | /* first handler for this signal */ | |
349 | - struct sigaction act; | |
350 | - | |
351 | - if (sigemptyset(&act.sa_mask) < 0) | |
352 | - i_fatal("sigemptyset(): %m"); | |
353 | - act.sa_flags = 0; | |
354 | - act.sa_handler = handler != NULL ? sig_handler : sig_ignore; | |
355 | - if (sigaction(signo, &act, NULL) < 0) | |
356 | - i_fatal("sigaction(%d): %m", signo); | |
357 | - | |
358 | + lib_signals_set(signo, handler == NULL); | |
359 | if (handler == NULL) { | |
360 | /* we're ignoring the handler, just return */ | |
361 | return; | |
362 | @@ -133,7 +139,10 @@ void lib_signals_set_handler(int signo, | |
363 | i_fatal("pipe() failed: %m"); | |
364 | fd_close_on_exec(sig_pipe_fd[0], TRUE); | |
365 | fd_close_on_exec(sig_pipe_fd[1], TRUE); | |
366 | - io_sig = io_add(sig_pipe_fd[0], IO_READ, signal_read, NULL); | |
367 | + if (signals_initialized) { | |
368 | + io_sig = io_add(sig_pipe_fd[0], IO_READ, | |
369 | + signal_read, NULL); | |
370 | + } | |
371 | } | |
372 | ||
373 | h = i_new(struct signal_handler, 1); | |
374 | @@ -186,10 +195,18 @@ void lib_signals_unset_handler(int signo | |
375 | ||
376 | void lib_signals_init(void) | |
377 | { | |
378 | - sig_pipe_fd[0] = sig_pipe_fd[1] = -1; | |
379 | - io_sig = NULL; | |
380 | - | |
381 | - memset(signal_handlers, 0, sizeof(signal_handlers)); | |
382 | + int i; | |
383 | + | |
384 | + signals_initialized = TRUE; | |
385 | + | |
386 | + /* add signals that were already registered */ | |
387 | + for (i = 0; i < MAX_SIGNAL_VALUE; i++) { | |
388 | + if (signal_handlers[i] != NULL) | |
389 | + lib_signals_set(i, FALSE); | |
390 | + } | |
391 | + | |
392 | + if (sig_pipe_fd[0] != -1) | |
393 | + io_sig = io_add(sig_pipe_fd[0], IO_READ, signal_read, NULL); | |
394 | } | |
395 | ||
396 | void lib_signals_deinit(void) | |
397 | diff --git a/src/plugins/quota/quota-maildir.c b/src/plugins/quota/quota-maildir.c | |
398 | --- a/src/plugins/quota/quota-maildir.c | |
399 | +++ b/src/plugins/quota/quota-maildir.c | |
400 | @@ -234,7 +234,7 @@ static int maildirsize_write(struct mail | |
401 | if (fd == -1) { | |
402 | if (errno == EAGAIN) { | |
403 | /* someone's just in the middle of updating it */ | |
404 | - return -1; | |
405 | + return 1; | |
406 | } | |
407 | ||
408 | mail_storage_set_critical(storage, | |
409 | diff --git a/src/plugins/quota/quota.c b/src/plugins/quota/quota.c | |
410 | --- a/src/plugins/quota/quota.c | |
411 | +++ b/src/plugins/quota/quota.c | |
412 | @@ -373,7 +373,8 @@ void quota_free(struct quota_transaction | |
413 | ||
414 | const char *quota_last_error(struct quota *quota) | |
415 | { | |
416 | - return quota->last_error != NULL ? quota->last_error : "Unknown error"; | |
417 | + return quota->last_error != NULL ? quota->last_error : | |
418 | + "Unknown quota error"; | |
419 | } | |
420 | ||
421 | void quota_set_error(struct quota *quota, const char *errormsg) | |
422 | diff --git a/src/pop3/client.c b/src/pop3/client.c | |
423 | --- a/src/pop3/client.c | |
424 | +++ b/src/pop3/client.c | |
425 | @@ -102,7 +102,7 @@ static int init_mailbox(struct client *c | |
426 | mail_free(&mail); | |
427 | if (mailbox_search_deinit(&ctx) < 0) { | |
428 | client_send_storage_error(client); | |
429 | - mailbox_transaction_rollback(&t); | |
430 | + (void)mailbox_transaction_commit(&t, 0); | |
431 | break; | |
432 | } | |
433 | ||
434 | @@ -113,8 +113,9 @@ static int init_mailbox(struct client *c | |
435 | return TRUE; | |
436 | } | |
437 | ||
438 | - /* well, sync and try again */ | |
439 | - mailbox_transaction_rollback(&t); | |
440 | + /* well, sync and try again. we might have cached virtual | |
441 | + sizes, make sure they get committed. */ | |
442 | + (void)mailbox_transaction_commit(&t, 0); | |
443 | } | |
444 | ||
445 | if (i == 2) |