10
10
#include "var-expand.h"
11
#include "imap-resp-code.h"
12
#include "imap-util.h"
13
#include "mail-namespace.h"
11
14
#include "commands.h"
12
#include "mail-namespace.h"
14
16
#include <stdlib.h>
15
17
#include <unistd.h>
17
19
extern struct mail_storage_callbacks mail_storage_callbacks;
20
struct imap_module_register imap_module_register = { 0 };
19
22
static struct client *my_client; /* we don't need more than one currently */
21
static bool client_handle_input(struct client *client);
23
24
static void client_idle_timeout(struct client *client)
25
26
if (client->output_lock == NULL)
27
28
client_destroy(client, "Disconnected for inactivity");
30
struct client *client_create(int fd_in, int fd_out,
31
struct mail_namespace *namespaces)
31
struct client *client_create(int fd_in, int fd_out, struct mail_user *user)
33
33
struct client *client;
34
struct mail_namespace *ns;
35
36
/* always use nonblocking I/O */
36
37
net_set_nonblock(fd_in, TRUE);
49
50
client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
50
51
client_idle_timeout, client);
52
client->command_pool = pool_alloconly_create("client command", 1024*12);
53
client->namespaces = namespaces;
53
client->command_pool =
54
pool_alloconly_create(MEMPOOL_GROWING"client command", 2048);
55
while (namespaces != NULL) {
56
mail_storage_set_callbacks(namespaces->storage,
57
for (ns = user->namespaces; ns != NULL; ns = ns->next) {
58
mail_storage_set_callbacks(ns->storage,
57
59
&mail_storage_callbacks, client);
58
namespaces = namespaces->next;
61
62
i_assert(my_client == NULL);
159
161
if (client->input_lock != NULL)
160
162
client_command_cancel(&client->input_lock);
162
if (client->mailbox != NULL)
164
if (client->mailbox != NULL) {
165
client_search_updates_free(client);
163
166
mailbox_close(&client->mailbox);
164
mail_namespaces_deinit(&client->namespaces);
168
mail_user_unref(&client->user);
166
170
if (client->free_parser != NULL)
167
171
imap_parser_destroy(&client->free_parser);
358
372
static struct client_command_context *
359
373
client_command_find_with_flags(struct client_command_context *new_cmd,
360
enum command_flags flags)
374
enum command_flags flags,
375
enum client_command_state max_state)
362
377
struct client_command_context *cmd;
364
379
cmd = new_cmd->client->command_queue;
365
380
for (; cmd != NULL; cmd = cmd->next) {
366
if (cmd != new_cmd && (cmd->cmd_flags & flags) != 0)
381
if (cmd->state <= max_state &&
382
cmd != new_cmd && (cmd->cmd_flags & flags) != 0)
372
388
static bool client_command_check_ambiguity(struct client_command_context *cmd)
374
390
enum command_flags flags;
391
enum client_command_state max_state =
392
CLIENT_COMMAND_STATE_WAIT_UNAMBIGUITY;
375
393
bool broken_client = FALSE;
395
if ((cmd->cmd_flags & COMMAND_FLAG_REQUIRES_SYNC) != 0 &&
396
!imap_sync_is_allowed(cmd->client))
377
399
if ((cmd->cmd_flags & COMMAND_FLAG_BREAKS_MAILBOX) ==
378
400
COMMAND_FLAG_BREAKS_MAILBOX) {
379
401
/* there must be no other command running that uses the
380
402
selected mailbox */
381
403
flags = COMMAND_FLAG_USES_MAILBOX;
404
max_state = CLIENT_COMMAND_STATE_DONE;
382
405
} else if ((cmd->cmd_flags & COMMAND_FLAG_USES_SEQS) != 0) {
383
406
/* no existing command must be breaking sequences */
384
407
flags = COMMAND_FLAG_BREAKS_SEQS;
393
if (client_command_find_with_flags(cmd, flags) == NULL) {
416
if (client_command_find_with_flags(cmd, flags, max_state) == NULL) {
394
417
if (cmd->client->syncing) {
395
418
/* don't do anything until syncing is finished */
421
if (cmd->client->mailbox_change_lock != NULL &&
422
cmd->client->mailbox_change_lock != cmd) {
423
/* don't do anything until mailbox is fully
401
430
if (broken_client) {
402
431
client_send_line(cmd->client,
403
"* BAD Command pipelining results in ambiguity.");
432
"* BAD ["IMAP_RESP_CODE_CLIENTBUG"] "
433
"Command pipelining results in ambiguity.");
484
void client_continue_pending_input(struct client **_client)
517
void client_continue_pending_input(struct client *client)
486
struct client *client = *_client;
489
521
i_assert(!client->handling_input);
491
if (client->disconnected) {
492
if (!client->destroyed)
493
client_destroy(client, NULL);
498
523
if (client->input_lock != NULL) {
499
524
/* there's a command that has locked the input */
500
525
struct client_command_context *cmd = client->input_lock;
514
544
/* if there's unread data in buffer, handle it. */
515
545
(void)i_stream_get_data(client->input, &size);
517
(void)client_handle_input(client);
546
if (size > 0 && !client->disconnected) {
547
if (client_handle_input(client))
548
client_continue_pending_input(client);
520
552
/* Skip incoming data until newline is found,
684
718
} while (ret && !client->disconnected && client->io != NULL);
685
719
client->handling_input = FALSE;
687
if (client->output->closed) {
688
client_destroy(client, NULL);
692
io_remove(&client->io);
694
client_add_missing_io(client);
695
if (!handled_commands)
722
io_remove(&client->io);
724
client_add_missing_io(client);
725
if (!handled_commands)
698
ret = cmd_sync_delayed(client);
700
client_continue_pending_input(&client);
728
if (client->input_lock == NULL)
729
cmd_sync_delayed(client);
705
733
void client_input(struct client *client)
801
if (client->output->closed) {
834
(void)cmd_sync_delayed(client);
835
o_stream_uncork(client->output);
836
if (client->disconnected)
802
837
client_destroy(client, NULL);
805
(void)cmd_sync_delayed(client);
806
o_stream_uncork(client->output);
807
client_continue_pending_input(&client);
839
client_continue_pending_input(client);
843
bool client_handle_search_save_ambiguity(struct client_command_context *cmd)
845
struct client_command_context *old_cmd = cmd->next;
847
/* search only commands that were added before this command
848
(commands are prepended to the queue, so they're after ourself) */
849
for (; old_cmd != NULL; old_cmd = old_cmd->next) {
850
if (old_cmd->search_save_result)
856
/* ambiguity, wait until it's over */
857
i_assert(cmd->state == CLIENT_COMMAND_STATE_WAIT_INPUT);
858
cmd->client->input_lock = cmd;
859
cmd->state = CLIENT_COMMAND_STATE_WAIT_UNAMBIGUITY;
860
io_remove(&cmd->client->io);
864
void client_enable(struct client *client, enum mailbox_feature features)
866
struct mailbox_status status;
868
if ((client->enabled_features & features) == features)
871
client->enabled_features |= features;
872
if (client->mailbox == NULL)
875
mailbox_enable(client->mailbox, features);
876
if ((features & MAILBOX_FEATURE_CONDSTORE) != 0) {
877
/* CONDSTORE being enabled while mailbox is selected.
878
Notify client of the latest HIGHESTMODSEQ. */
879
mailbox_get_status(client->mailbox,
880
STATUS_HIGHESTMODSEQ, &status);
881
client_send_line(client, t_strdup_printf(
882
"* OK [HIGHESTMODSEQ %llu] Highest",
883
(unsigned long long)status.highest_modseq));
887
struct imap_search_update *
888
client_search_update_lookup(struct client *client, const char *tag,
891
struct imap_search_update *updates;
892
unsigned int i, count;
894
if (!array_is_created(&client->search_updates))
897
updates = array_get_modifiable(&client->search_updates, &count);
898
for (i = 0; i < count; i++) {
899
if (strcmp(updates[i].tag, tag) == 0) {
907
void client_search_updates_free(struct client *client)
909
struct imap_search_update *updates;
910
unsigned int i, count;
912
if (!array_is_created(&client->search_updates))
915
updates = array_get_modifiable(&client->search_updates, &count);
916
for (i = 0; i < count; i++) {
917
i_free(updates[i].tag);
918
mailbox_search_result_free(&updates[i].result);
920
array_clear(&client->search_updates);
812
923
void clients_init(void)