imap-client.c revision 4cf07bf088edb68380175817e27758d9b6c01891
/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
#include "imap-common.h"
#include "ioloop.h"
#include "llist.h"
#include "str.h"
#include "hostpid.h"
#include "network.h"
#include "istream.h"
#include "ostream.h"
#include "var-expand.h"
#include "master-service.h"
#include "imap-resp-code.h"
#include "imap-util.h"
#include "mail-namespace.h"
#include "mail-storage-service.h"
#include "imap-commands.h"
#include <stdlib.h>
#include <unistd.h>
extern struct mail_storage_callbacks mail_storage_callbacks;
struct imap_module_register imap_module_register = { 0 };
unsigned int imap_client_count = 0;
{
}
struct mail_storage_service_user *service_user,
const struct imap_settings *set)
{
const char *ident;
/* always use nonblocking I/O */
else {
}
if (ident != NULL) {
}
if (hook_client_created != NULL)
return client;
}
{
bool cmd_ret;
/* a bit kludgy check: cancel command only if it has context
set. currently only append command matches this check. all
other commands haven't even started the processing yet. */
break;
/* fall through */
break;
/* commands haven't started yet */
break;
i_unreached();
}
} else {
}
}
{
static struct var_expand_table static_tab[] = {
};
struct var_expand_table *tab;
}
{
t_strdup_printf("Connection closed: %m");
}
{
struct client_command_context *cmd;
if (!client->disconnected) {
}
/* finish off all the queued commands. */
}
/* handle the input_lock command last. it might have been waiting on
other queued commands (although we probably should just drop the
command at that point since it hasn't started running. but this may
change in future). */
}
if (client->anvil_sent) {
"\n", NULL));
}
}
{
}
{
if (client->disconnected)
return;
}
{
}
{
return -1;
return -1;
/* buffer full, try flushing */
}
return 1;
}
{
return;
tag = "*";
}
const char *msg)
{
bool fatal;
if (fatal) {
return;
}
}
else {
}
"Too many invalid IMAP commands.");
}
/* client_read_args() failures rely on this being set, so that the
command processing is stopped even while command function returns
FALSE. */
}
{
int ret;
/* all parameters read successfully */
return TRUE;
} else if (ret == -2) {
/* need more data */
/* disconnected */
}
return FALSE;
} else {
/* error, or missing arguments */
"Missing arguments");
return FALSE;
}
}
unsigned int count, ...)
{
const char *str;
unsigned int i;
return FALSE;
for (i = 0; i < count; i++) {
if (IMAP_ARG_IS_EOL(&imap_args[i])) {
break;
}
break;
}
}
return i == count;
}
static struct client_command_context *
enum command_flags flags,
{
struct client_command_context *cmd;
return cmd;
}
return NULL;
}
{
enum command_flags flags;
enum client_command_state max_state =
bool broken_client = FALSE;
return TRUE;
/* there must be no other command running that uses the
selected mailbox */
/* no existing command must be breaking sequences */
/* if existing command uses sequences, we'll have to block */
} else {
return FALSE;
}
/* don't do anything until syncing is finished */
return TRUE;
}
/* don't do anything until mailbox is fully
return TRUE;
}
return FALSE;
}
if (broken_client) {
"Command pipelining results in ambiguity.");
}
return TRUE;
}
static struct client_command_context *
{
struct client_command_context *cmd;
} else {
}
return cmd;
}
{
/* reset input idle time because command output might have taken a
long time and we don't want to disconnect client immediately then */
}
if (!cmd->param_error)
client->bad_counter = 0;
else {
}
/* no commands left in the queue, we can clear the pool */
}
}
{
}
}
{
/* there's a command that has locked the input */
return;
/* the command is waiting for existing ambiguity causing
commands to finish. */
if (client_command_check_ambiguity(cmd)) {
/* we could be waiting for existing sync to finish */
if (!cmd_sync_delayed(client))
return;
return;
}
}
/* if there's unread data in buffer, handle it. */
if (client_handle_input(client))
}
}
/* Skip incoming data until newline is found,
returns TRUE if newline was found. */
{
const unsigned char *data;
for (i = 0; i < data_size; i++) {
if (data[i] == '\n') {
i++;
break;
}
}
return !client->input_skip_line;
}
{
"Disconnected for inactivity in reading our output");
}
{
/* need more input */
return FALSE;
}
/* waiting for something */
/* this is mainly for APPEND. */
}
return TRUE;
}
/* output is blocking, we can execute more commands */
/* disconnect sooner if client isn't reading our output */
}
return TRUE;
}
{
/* command is being executed - continue it */
/* command execution was finished */
return TRUE;
}
return client_handle_unfinished_cmd(cmd);
}
return FALSE; /* need more data */
}
return FALSE; /* need more data */
}
/* command not given - cmd_func is already NULL. */
if (client_command_check_ambiguity(cmd)) {
/* do nothing until existing commands are finished */
return FALSE;
}
}
/* unknown command */
return TRUE;
} else {
return client_command_input(cmd);
}
}
{
*remove_io_r = FALSE;
*remove_io_r = TRUE;
return FALSE;
}
}
if (client->input_skip_line) {
/* first eat the previous command line */
if (!client_skip_line(client))
return FALSE;
}
/* don't bother creating a new client command before there's at least
some input */
if (size == 0)
return FALSE;
/* beginning a new command */
/* wait for some of the commands to finish */
*remove_io_r = TRUE;
return FALSE;
}
}
{
do {
T_BEGIN {
} T_END;
if (ret)
if (remove_io)
else
if (!handled_commands)
return FALSE;
return TRUE;
}
{
struct client_command_context *cmd;
if (bytes == -1) {
/* disconnected */
return;
}
/* parameter word is longer than max. input buffer size.
this is most likely an error, so skip the new data
until newline is found. */
}
if (client->disconnected)
else
}
{
bool finished;
/* continue processing command */
if (!finished)
(void)client_handle_unfinished_cmd(cmd);
else {
/* command execution was finished */
}
}
{
struct client_command_context *cmd;
int ret;
return 1;
}
/* mark all commands non-executed */
}
/* go through the entire commands list every time in case
multiple commands were freed. temp_executed keeps track of
which messages we've called so far */
if (!cmd->temp_executed &&
break;
}
}
/* all commands executed */
break;
}
}
(void)cmd_sync_delayed(client);
if (client->disconnected)
else
return ret;
}
{
/* search only commands that were added before this command
(commands are prepended to the queue, so they're after ourself) */
if (old_cmd->search_save_result)
break;
}
return FALSE;
/* ambiguity, wait until it's over */
return TRUE;
}
{
struct mailbox_status status;
return;
return;
if ((features & MAILBOX_FEATURE_CONDSTORE) != 0) {
/* CONDSTORE being enabled while mailbox is selected.
Notify client of the latest HIGHESTMODSEQ. */
"* OK [HIGHESTMODSEQ %llu] Highest",
(unsigned long long)status.highest_modseq));
}
}
struct imap_search_update *
unsigned int *idx_r)
{
struct imap_search_update *updates;
unsigned int i, count;
return NULL;
for (i = 0; i < count; i++) {
*idx_r = i;
return &updates[i];
}
}
return NULL;
}
{
struct imap_search_update *update;
return;
}
}
void clients_destroy_all(void)
{
while (imap_clients != NULL) {
}
}