pop3c-client.c revision 1864cbe7efd4839e12609878122b847975a8a0bc
/* Copyright (c) 2011-2012 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "network.h"
#include "istream.h"
#include "istream-dot.h"
#include "istream-seekable.h"
#include "ostream.h"
#include "iostream-rawlog.h"
#include "iostream-ssl.h"
#include "close-keep-errno.h"
#include "safe-mkstemp.h"
#include "base64.h"
#include "str.h"
#include "dns-lookup.h"
#include "pop3c-client.h"
#include <unistd.h>
enum pop3c_client_state {
/* No connection */
/* Trying to connect */
/* Connected, trying to authenticate */
/* Post-authentication, asking for capabilities */
/* Authenticated, ready to accept commands */
};
struct pop3c_client {
struct pop3c_client_settings set;
struct ssl_iostream_context *ssl_ctx;
int fd;
struct ssl_iostream *ssl_iostream;
enum pop3c_client_state state;
enum pop3c_capability capabilities;
void *login_context;
unsigned int async_commands;
const char *input_line;
unsigned int handshake_failed:1;
unsigned int running:1;
};
static void
struct pop3c_client *
{
struct pop3c_client *client;
struct ssl_iostream_settings ssl_set;
const char *source;
i_error("pop3c(%s): Couldn't initialize SSL context",
source);
}
}
return client;
}
static void
{
}
}
{
client->async_commands = 0;
i_error("close(pop3c) failed: %m");
}
"Disconnected");
}
{
}
{
}
{
i_error("pop3c(%s): connect(%s, %u) timed out after %u seconds",
break;
case POP3C_CLIENT_STATE_DONE:
i_error("pop3c(%s): Command timed out after %u seconds",
break;
default:
i_error("pop3c(%s): Authentication timed out after %u seconds",
break;
}
}
{
bool timeout_added = FALSE;
ioloop = io_loop_create();
/* we're connecting, start DNS lookup after our ioloop
is created */
struct dns_lookup_settings dns_set;
}
}
{
i_debug("pop3c(%s): Authenticating as %s",
} else {
i_debug("pop3c(%s): Authenticating as %s for user %s",
}
}
} else {
}
}
static const char *
{
} else {
}
}
{
}
static int
{
const char *reply;
if (!success) {
i_error("pop3c(%s): Server sent invalid banner: %s",
return -1;
}
break;
case POP3C_CLIENT_STATE_USER:
if (!success) {
i_error("pop3c(%s): USER failed: %s",
return -1;
}
break;
case POP3C_CLIENT_STATE_AUTH:
if (line[0] != '+') {
i_error("pop3c(%s): AUTH PLAIN failed: %s",
return -1;
}
break;
case POP3C_CLIENT_STATE_PASS:
line;
} else if (!success) {
i_error("pop3c(%s): Authentication failed: %s",
}
if (!success)
return -1;
break;
case POP3C_CLIENT_STATE_CAPA:
break;
}
break;
case POP3C_CLIENT_STATE_DONE:
i_unreached();
}
return 0;
}
{
/* we need to read as much as we can with SSL streams to avoid
hanging */
return;
}
}
/* disconnected */
i_error("pop3c(%s): Server disconnected unexpectedly",
} else if (!client->handshake_failed) {
}
i_error("pop3c(%s): Server disconnected: %s",
}
}
}
static int pop3c_client_ssl_handshaked(void *context)
{
/* skip certificate checks */
return 0;
i_error("pop3c(%s): SSL certificate not received",
} else {
i_error("pop3c(%s): Received invalid SSL certificate",
}
i_error("pop3c(%s): SSL certificate doesn't match host name",
} else {
i_debug("pop3c(%s): SSL handshake successful",
}
return 0;
}
return -1;
}
{
struct ssl_iostream_settings ssl_set;
const char *source;
return -1;
}
}
/* recreate rawlog after STARTTLS */
}
&client->ssl_iostream) < 0) {
i_error("pop3c(%s): Couldn't initialize SSL client",
return -1;
}
client);
return -1;
}
}
return 0;
}
{
int err;
if (err != 0) {
i_error("pop3c(%s): connect(%s, %u) failed: %s",
return;
}
if (pop3c_client_ssl_init(client) < 0)
}
}
{
return;
}
}
}
}
static void
{
i_error("pop3c(%s): dns_lookup() failed: %s",
return;
}
}
{
return;
}
}
{
}
enum pop3c_capability
{
return client->capabilities;
}
{
/* disconnected */
i_error("pop3c(%s): Server disconnected unexpectedly",
}
}
static int
{
*error_r = "Disconnected";
return -1;
}
return 0;
}
static int
{
const char *line;
*error_r = "Disconnected";
return -1;
}
while (client->async_commands > 0) {
return -1;
client->async_commands--;
}
return 0;
}
const char **reply_r)
{
const char *line;
int ret;
return -1;
return -1;
ret = 0;
ret = -1;
} else {
ret = -1;
}
if (**reply_r == ' ')
*reply_r += 1;
return ret;
}
{
const char *error;
return;
}
return;
}
client->async_commands++;
}
{
int fd;
if (fd == -1) {
return -1;
}
/* we just want the fd, unlink it */
/* shouldn't happen.. */
return -1;
}
return fd;
}
{
}
if (ret != 0) {
i_error("pop3c(%s): Server disconnected unexpectedly",
}
}
}
{
/* read the +OK / -ERR */
return -1;
/* read the stream */
/* read any pending data from the stream */
*error_r = "Disconnected";
return -1;
}
/* if this stream is used by some filter stream, make the filter
stream blocking */
return 0;
}