client.c revision c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "login-common.h"
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher#include "buffer.h"
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher#include "ioloop.h"
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek#include "istream.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "ostream.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "safe-memset.h"
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek#include "str.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "strescape.h"
7465d6a1ef6e83825dba3a4dc4dda7271671aba0Jakub Hrozek#include "imap-parser.h"
ad805face83ba7d67b1cf2067a1982c7e63d1060Jakub Hrozek#include "imap-id.h"
ad805face83ba7d67b1cf2067a1982c7e63d1060Jakub Hrozek#include "imap-resp-code.h"
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek#include "master-service.h"
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher#include "master-auth.h"
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher#include "client.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "client-authenticate.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "auth-client.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "ssl-proxy.h"
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek#include "imap-proxy.h"
36b56482ca1e53d832accef0354124fd79711172Jakub Hrozek#include "imap-login-settings.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include <stdlib.h>
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek/* maximum length for IMAP command line. */
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek#define MAX_IMAP_LINE 8192
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek/* Disconnect client when it sends too many bad commands */
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek#define CLIENT_MAX_BAD_COMMANDS 10
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozekconst char *login_protocol = "imap";
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozekconst char *login_process_name = "imap-login";
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozekunsigned int login_default_port = 143;
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghervoid login_process_preinit(void)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher login_set_roots = imap_login_setting_roots;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher/* Skip incoming data until newline is found,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher returns TRUE if newline was found. */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherbool client_skip_line(struct imap_client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
f10ebaa51ecdcbbd10f171d19fe8e680e5bc74aaJakub Hrozek const unsigned char *data;
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek size_t i, data_size;
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek data = i_stream_get_data(client->common.input, &data_size);
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek for (i = 0; i < data_size; i++) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (data[i] == '\n') {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_stream_skip(client->common.input, i+1);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic const char *get_capability(struct client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher struct imap_client *imap_client = (struct imap_client *)client;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher const char *auths, *cap_str;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cap_str = *imap_client->set->imap_capability != '\0' ?
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher imap_client->set->imap_capability : CAPABILITY_BANNER_STRING;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher auths = client_authenticate_get_capabilities(client);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return t_strconcat(cap_str,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher (ssl_initialized && !client->tls) ? " STARTTLS" : "",
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->set->disable_plaintext_auth &&
f10ebaa51ecdcbbd10f171d19fe8e680e5bc74aaJakub Hrozek !client->secured ? " LOGINDISABLED" : "",
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek auths, NULL);
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek}
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozekstatic int cmd_capability(struct imap_client *imap_client)
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek{
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek struct client *client = &imap_client->common;
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek /* Client is required to send CAPABILITY after STARTTLS, so the
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek capability resp-code workaround checks only pre-STARTTLS
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek CAPABILITY commands. */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!client->starttls)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher imap_client->client_ignores_capability_resp_code = TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_raw(client, t_strconcat(
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "* CAPABILITY ", get_capability(client), "\r\n", NULL));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(client, CLIENT_CMD_REPLY_OK, "Capability completed.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return 1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int cmd_starttls(struct imap_client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_cmd_starttls(&client->common);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return 1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
f10ebaa51ecdcbbd10f171d19fe8e680e5bc74aaJakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic void
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherclient_update_info(struct imap_client *client, const struct imap_arg *args)
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek{
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek const char *key, *value;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!imap_arg_get_list(args, &args))
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher while (imap_arg_get_string(&args[0], &key) &&
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher imap_arg_get_nstring(&args[1], &value)) {
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (strcasecmp(key, "x-originating-ip") == 0)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher (void)net_addr2ip(value, &client->common.ip);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher else if (strcasecmp(key, "x-originating-port") == 0)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher client->common.remote_port = atoi(value);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher else if (strcasecmp(key, "x-connected-ip") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher (void)net_addr2ip(value, &client->common.local_ip);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher else if (strcasecmp(key, "x-connected-port") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->common.local_port = atoi(value);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher args += 2;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher }
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher}
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int cmd_id(struct imap_client *client, const struct imap_arg *args)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher const char *env, *value;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!client->id_logged) {
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher client->id_logged = TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->common.trusted)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_update_info(client, args);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher env = getenv("IMAP_ID_LOG");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher value = imap_id_args_get_log_reply(args, env);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (value != NULL) {
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher client_log(&client->common,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher t_strdup_printf("ID sent: %s", value));
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher env = getenv("IMAP_ID_SEND");
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher client_send_raw(&client->common,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher t_strdup_printf("* ID %s\r\n", imap_id_reply_generate(env)));
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_OK, "ID completed.");
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return 1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int cmd_noop(struct imap_client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "NOOP completed.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return 1;
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek}
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozekstatic int cmd_logout(struct imap_client *client)
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek{
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek client_send_line(&client->common, CLIENT_CMD_REPLY_BYE, "Logging out");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "Logout completed.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_destroy(&client->common, "Aborted login");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return 1;
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek}
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozekstatic int cmd_enable(struct imap_client *client)
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek{
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek client_send_raw(&client->common, "* ENABLED\r\n");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "ENABLE ignored in non-authenticated state.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return 1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int client_command_execute(struct imap_client *client, const char *cmd,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const struct imap_arg *args)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cmd = t_str_ucase(cmd);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (strcmp(cmd, "LOGIN") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return cmd_login(client, args);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (strcmp(cmd, "AUTHENTICATE") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return cmd_authenticate(client, args);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (strcmp(cmd, "CAPABILITY") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return cmd_capability(client);
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek if (strcmp(cmd, "STARTTLS") == 0)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return cmd_starttls(client);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (strcmp(cmd, "ID") == 0)
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return cmd_id(client, args);
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (strcmp(cmd, "NOOP") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return cmd_noop(client);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (strcmp(cmd, "LOGOUT") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return cmd_logout(client);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (strcmp(cmd, "ENABLE") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return cmd_enable(client);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return -2;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher}
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic bool client_handle_input(struct imap_client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const struct imap_arg *args;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const char *msg;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher int ret;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher bool fatal;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_assert(!client->common.authenticating);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->cmd_finished) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* clear the previous command from memory. don't do this
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher immediately after handling command since we need the
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cmd_tag to stay some time after authentication commands. */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->cmd_tag = NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->cmd_name = NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher imap_parser_reset(client->parser);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* remove \r\n */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->skip_line) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!client_skip_line(client))
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher client->skip_line = FALSE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->cmd_finished = FALSE;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->cmd_tag == NULL) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->cmd_tag = imap_parser_read_word(client->parser);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->cmd_tag == NULL)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE; /* need more data */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->cmd_name == NULL) {
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher client->cmd_name = imap_parser_read_word(client->parser);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->cmd_name == NULL)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE; /* need more data */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher switch (imap_parser_read_args(client->parser, 0, 0, &args)) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher case -1:
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* error */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher msg = imap_parser_get_error(client->parser, &fatal);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher if (fatal) {
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek client_send_line(&client->common,
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek CLIENT_CMD_REPLY_BYE, msg);
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek client_destroy(&client->common,
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek t_strconcat("Disconnected: ", msg, NULL));
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek return FALSE;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek }
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek client_send_line(&client->common, CLIENT_CMD_REPLY_BAD, msg);
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek client->cmd_finished = TRUE;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek client->skip_line = TRUE;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek return TRUE;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek case -2:
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek /* not enough data */
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek return FALSE;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek }
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek /* we read the entire line - skip over the CRLF */
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek if (!client_skip_line(client))
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek i_unreached();
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek if (*client->cmd_tag == '\0')
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek ret = -1;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek else
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek ret = client_command_execute(client, client->cmd_name, args);
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek client->cmd_finished = TRUE;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek if (ret == -2 && strcasecmp(client->cmd_tag, "LOGIN") == 0) {
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek "First parameter in line is IMAP's command tag, "
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek "not the command name. Add that before the command, "
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek "like: a login user pass");
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek } else if (ret < 0) {
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek if (*client->cmd_tag == '\0')
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek client->cmd_tag = "*";
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek if (++client->common.bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek client_send_line(&client->common, CLIENT_CMD_REPLY_BYE,
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek "Too many invalid IMAP commands.");
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek client_destroy(&client->common,
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek "Disconnected: Too many invalid commands");
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek return FALSE;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek }
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek "Error in IMAP command received by server.");
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek }
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek return ret != 0 && !client->common.destroyed;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek}
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozekstatic void imap_client_input(struct client *client)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek{
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek struct imap_client *imap_client = (struct imap_client *)client;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (!client_read(client))
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek return;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek client_ref(client);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek o_stream_cork(imap_client->common.output);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek for (;;) {
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek if (!auth_client_is_connected(auth_client)) {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek /* we're not currently connected to auth process -
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek don't allow any commands */
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek client_send_line(client, CLIENT_CMD_REPLY_STATUS,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek AUTH_SERVER_WAITING_MSG);
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek if (client->to_auth_waiting != NULL)
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek timeout_remove(&client->to_auth_waiting);
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek client->input_blocked = TRUE;
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek break;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek } else {
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek if (!client_handle_input(imap_client))
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek break;
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek }
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek }
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek o_stream_uncork(imap_client->common.output);
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek client_unref(&client);
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek}
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozekstatic struct client *imap_client_alloc(pool_t pool)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek{
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek struct imap_client *imap_client;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek imap_client = p_new(pool, struct imap_client, 1);
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek return &imap_client->common;
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek}
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozekstatic void imap_client_create(struct client *client, void **other_sets)
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek{
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek struct imap_client *imap_client = (struct imap_client *)client;
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek imap_client->set = other_sets[0];
7465d6a1ef6e83825dba3a4dc4dda7271671aba0Jakub Hrozek imap_client->parser =
7465d6a1ef6e83825dba3a4dc4dda7271671aba0Jakub Hrozek imap_parser_create(imap_client->common.input,
7465d6a1ef6e83825dba3a4dc4dda7271671aba0Jakub Hrozek imap_client->common.output, MAX_IMAP_LINE);
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek client->io = io_add(client->fd, IO_READ, client_input, client);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek}
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozekstatic void imap_client_destroy(struct client *client)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek{
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek struct imap_client *imap_client = (struct imap_client *)client;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek i_free_and_null(imap_client->proxy_backend_capability);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek imap_parser_destroy(&imap_client->parser);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek}
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozekstatic void imap_client_send_greeting(struct client *client)
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek{
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek string_t *greet;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek greet = t_str_new(128);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek str_append(greet, "* OK ");
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek str_printfa(greet, "[CAPABILITY %s] ", get_capability(client));
7465d6a1ef6e83825dba3a4dc4dda7271671aba0Jakub Hrozek str_append(greet, client->set->login_greeting);
7465d6a1ef6e83825dba3a4dc4dda7271671aba0Jakub Hrozek str_append(greet, "\r\n");
7465d6a1ef6e83825dba3a4dc4dda7271671aba0Jakub Hrozek
7465d6a1ef6e83825dba3a4dc4dda7271671aba0Jakub Hrozek client_send_raw(client, str_c(greet));
4c9419d98b89a6161a3dde11f9f80be39d12e72aJakub Hrozek client->greeting_sent = TRUE;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek}
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozekstatic void imap_client_starttls(struct client *client)
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek{
7465d6a1ef6e83825dba3a4dc4dda7271671aba0Jakub Hrozek struct imap_client *imap_client = (struct imap_client *)client;
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek imap_parser_destroy(&imap_client->parser);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek imap_client->parser =
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek imap_parser_create(imap_client->common.input,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek imap_client->common.output, MAX_IMAP_LINE);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek /* CRLF is lost from buffer when streams are reopened. */
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek imap_client->skip_line = FALSE;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek}
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozekstatic void
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozekimap_client_send_line(struct client *client, enum client_cmd_reply reply,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek const char *text)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek{
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek struct imap_client *imap_client = (struct imap_client *)client;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek const char *resp_code = NULL;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek const char *prefix = "NO";
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek bool tagged = TRUE;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek switch (reply) {
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek case CLIENT_CMD_REPLY_OK:
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek prefix = "OK";
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek break;
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek case CLIENT_CMD_REPLY_AUTH_FAILED:
7465d6a1ef6e83825dba3a4dc4dda7271671aba0Jakub Hrozek resp_code = IMAP_RESP_CODE_AUTHFAILED;
7465d6a1ef6e83825dba3a4dc4dda7271671aba0Jakub Hrozek break;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek case CLIENT_CMD_REPLY_AUTHZ_FAILED:
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek resp_code = IMAP_RESP_CODE_AUTHZFAILED;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek break;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek case CLIENT_CMD_REPLY_AUTH_FAIL_TEMP:
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek resp_code = IMAP_RESP_CODE_UNAVAILABLE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher break;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher case CLIENT_CMD_REPLY_AUTH_FAIL_REASON:
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher resp_code = "ALERT";
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher break;
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek case CLIENT_CMD_REPLY_AUTH_FAIL_NOSSL:
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher resp_code = IMAP_RESP_CODE_PRIVACYREQUIRED;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher break;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher case CLIENT_CMD_REPLY_BAD:
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher prefix = "BAD";
7465d6a1ef6e83825dba3a4dc4dda7271671aba0Jakub Hrozek break;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher case CLIENT_CMD_REPLY_BYE:
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher prefix = "BYE";
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher tagged = FALSE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher break;
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek case CLIENT_CMD_REPLY_STATUS:
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher prefix = "OK";
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher tagged = FALSE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher break;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher case CLIENT_CMD_REPLY_STATUS_BAD:
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek prefix = "BAD";
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher tagged = FALSE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher resp_code = "ALERT";
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher break;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher T_BEGIN {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher string_t *line = t_str_new(256);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek if (tagged)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher str_append(line, imap_client->cmd_tag);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher else
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher str_append_c(line, '*');
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher str_append_c(line, ' ');
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek str_append(line, prefix);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher str_append_c(line, ' ');
36b56482ca1e53d832accef0354124fd79711172Jakub Hrozek if (resp_code != NULL)
36b56482ca1e53d832accef0354124fd79711172Jakub Hrozek str_printfa(line, "[%s] ", resp_code);
7465d6a1ef6e83825dba3a4dc4dda7271671aba0Jakub Hrozek str_append(line, text);
36b56482ca1e53d832accef0354124fd79711172Jakub Hrozek str_append(line, "\r\n");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_raw_data(client, str_data(line),
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher str_len(line));
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek } T_END;
056302a92862fda16351d7192600746746f38e5dStephen Gallagher}
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallaghervoid clients_init(void)
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher{
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek}
056302a92862fda16351d7192600746746f38e5dStephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghervoid clients_deinit(void)
36b56482ca1e53d832accef0354124fd79711172Jakub Hrozek{
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek clients_destroy_all();
36b56482ca1e53d832accef0354124fd79711172Jakub Hrozek}
36b56482ca1e53d832accef0354124fd79711172Jakub Hrozek
36b56482ca1e53d832accef0354124fd79711172Jakub Hrozekstruct client_vfuncs client_vfuncs = {
36b56482ca1e53d832accef0354124fd79711172Jakub Hrozek imap_client_alloc,
36b56482ca1e53d832accef0354124fd79711172Jakub Hrozek imap_client_create,
36b56482ca1e53d832accef0354124fd79711172Jakub Hrozek imap_client_destroy,
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher imap_client_send_greeting,
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek imap_client_starttls,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher imap_client_input,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher imap_client_send_line,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher imap_client_auth_handle_reply,
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher NULL,
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek NULL,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher imap_proxy_reset,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher imap_proxy_parse_line
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher};
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher