client.c revision 00b2227d6ff65629707670b7b8dfd236fced8293
/* Copyright (C) 2002 Timo Sirainen */
#include "common.h"
#include "buffer.h"
#include "hash.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "process-title.h"
#include "safe-memset.h"
#include "str.h"
#include "strescape.h"
#include "imap-parser.h"
#include "client.h"
#include "client-authenticate.h"
#include "auth-client.h"
#include "ssl-proxy.h"
#include "imap-proxy.h"
/* max. size of one parameter in line, or max reply length in SASL
authentication */
#define MAX_INBUF_SIZE 4096
/* max. size of output buffer. if it gets full, the client is disconnected.
SASL authentication gives the largest output. */
#define MAX_OUTBUF_SIZE 4096
/* maximum length for IMAP command line. */
#define MAX_IMAP_LINE 8192
/* Disconnect client after idling this many seconds */
#define CLIENT_LOGIN_IDLE_TIMEOUT 60
/* Disconnect client when it sends too many bad commands */
#define CLIENT_MAX_BAD_COMMANDS 10
/* When max. number of simultaneous connections is reached, few of the
oldest connections are disconnected. Since we have to go through the whole
client hash, it's faster if we disconnect multiple clients. */
#define CLIENT_DESTROY_OLDEST_COUNT 16
#endif
static struct hash_table *clients;
{
const char *addr;
if (!verbose_proctitle || !process_per_connection)
return;
addr = "??";
}
{
FALSE);
}
/* 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') {
return TRUE;
}
}
return FALSE;
}
{
const char *auths;
return t_strconcat(CAPABILITY_STRING,
" STARTTLS" : "",
}
{
return TRUE;
}
{
int fd_ssl;
if (fd_ssl == -1) {
return;
}
/* CRLF is lost from buffer when streams are reopened. */
}
static void client_output_starttls(void *context)
{
int ret;
return;
}
if (ret > 0)
}
{
return TRUE;
}
if (!ssl_initialized) {
return TRUE;
}
/* remove input handler, SSL proxy gives us a new fd. we also have to
remove it in case we have to wait for buffer to be flushed */
}
/* the buffer has to be flushed */
} else {
}
return TRUE;
}
{
return TRUE;
}
{
return TRUE;
}
{
return cmd_capability(client);
return cmd_starttls(client);
return cmd_logout(client);
return -1;
}
{
const char *msg;
if (client->cmd_finished) {
/* clear the previous command from memory. don't do this
immediately after handling command since we need the
cmd_tag to stay some time after authentication commands. */
/* remove \r\n */
if (!client_skip_line(client))
return FALSE;
}
}
return FALSE; /* need more data */
}
return FALSE; /* need more data */
}
case -1:
/* error */
if (fatal) {
return FALSE;
}
return TRUE;
case -2:
/* not enough data */
return FALSE;
}
ret = -1;
else
if (ret < 0) {
"* BYE Too many invalid IMAP commands.");
"Too many invalid commands");
return FALSE;
}
"BAD Error in IMAP command received by server.");
}
return ret != 0;
}
{
case -2:
/* buffer full */
return FALSE;
case -1:
/* disconnected */
return FALSE;
default:
/* something was read */
return TRUE;
}
}
void client_input(void *context)
{
if (!client_read(client))
return;
if (!auth_client_is_connected(auth_client)) {
/* we're not yet connected to auth process -
don't allow any commands */
"* OK Waiting for authentication process to respond..");
} else {
while (client_handle_input(client)) ;
}
}
static void client_destroy_oldest(void)
{
struct hash_iterate_context *iter;
int i;
/* find the oldest clients and put them to destroy-buffer */
for (i = 0; i < CLIENT_DESTROY_OLDEST_COUNT; i++) {
if (destroy_buf[i] == NULL ||
/* @UNSAFE */
sizeof(destroy_buf) -
(i+1) * sizeof(struct imap_client *));
destroy_buf[i] = client;
break;
}
}
}
/* then kill them */
for (i = 0; i < CLIENT_DESTROY_OLDEST_COUNT; i++) {
if (destroy_buf[i] == NULL)
break;
"Disconnected: Connection queue full");
}
}
{
struct imap_client *client;
const char *addr;
/* reached max. users count, kill few of the
oldest connections */
}
/* always use nonblocking I/O */
main_ref();
if (greeting_capability)
}
{
return;
}
}
}
}
}
}
}
{
"Refer to server log for more information.");
}
{
}
{
return TRUE;
main_unref();
return FALSE;
}
{
}
{
}
{
}
}
{
struct hash_iterate_context *iter;
}
}
unsigned int clients_get_count(void)
{
}
void clients_notify_auth_connected(void)
{
struct hash_iterate_context *iter;
if (client->input_blocked) {
}
}
}
void clients_destroy_all(void)
{
struct hash_iterate_context *iter;
}
}
void clients_init(void)
{
}
void clients_deinit(void)
{
}