/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "pop3-common.h"
#include "array.h"
#include "ioloop.h"
#include "net.h"
#include "iostream.h"
#include "istream.h"
#include "ostream.h"
#include "iostream-rawlog.h"
#include "crc32.h"
#include "str.h"
#include "llist.h"
#include "hostpid.h"
#include "file-dotlock.h"
#include "var-expand.h"
#include "master-service.h"
#include "mail-storage.h"
#include "mail-storage-service.h"
#include "mail-autoexpunge.h"
#include "pop3-commands.h"
#include "mail-search-build.h"
#include "mail-namespace.h"
#include <unistd.h>
/* max. length of input command line (spec says 512) */
/* Disconnect client when it sends too many bad commands in a row */
/* Disconnect client after idling this many milliseconds */
/* If client starts idling for this many milliseconds, commit the current
transaction. This allows the mailbox to become unlocked. */
extern struct pop3_client_vfuncs pop3_client_vfuncs;
unsigned int pop3_client_count;
};
.timeout = 10,
.lock_suffix = "",
};
{
/* Can't commit while commands are running */
return;
}
}
{
"Disconnected for inactivity in reading our output");
} else {
}
}
static int
{
int ret;
/* first try to get the virtual size */
if (ret == 0)
return 0;
return -1;
/* virtual size not available with a fast lookup.
fallback to trying the physical size */
if (ret == 0)
return 0;
return -1;
/* no way to quickly get the size. fallback to doing a slow virtual
size lookup */
}
static void
unsigned int msgnum)
{
return;
/* add any messages between this and the previous one that had
a POP3 order defined */
}
{
struct mailbox_transaction_context *t;
unsigned int msgnum;
*failed_uid_r = 0;
} else {
}
client->last_seen_pop3_msn = 0;
client->total_size = 0;
msgnum = 0;
break;
}
msgnum++;
}
if (mailbox_search_deinit(&ctx) < 0)
ret = -1;
if (ret <= 0) {
/* commit the transaction instead of rolling back to make sure
we don't lose data (virtual sizes) added to cache file */
(void)mailbox_transaction_commit(&t);
return ret;
}
}
if (array_is_created(&msgnum_to_seq_map)) {
}
return 1;
}
{
return 0;
&client->deleted_kw) < 0) {
"pop3_deleted_flags: Invalid keyword '%s': %s",
return -1;
}
return 0;
}
{
for (i = 0;; i++) {
MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
ret = -1;
break;
}
if (ret > 0)
return 0;
if (i == 2)
break;
/* well, sync and try again. maybe it works the second time. */
failed_uid = 0;
}
if (ret < 0) {
} else {
/* failed twice in same message */
"Getting size of message UID=%u failed",
} else {
*error_r = "Can't sync mailbox: "
"Messages keep getting expunged";
}
}
return -1;
}
{
switch (var_get_key(++format)) {
case 'v':
mask |= UIDL_UIDVALIDITY;
break;
case 'u':
break;
case 'm':
break;
case 'f':
mask |= UIDL_FILE_NAME;
break;
case 'g':
break;
}
}
}
return mask;
}
{
}
}
{
int ret;
} else {
"can't create a POP3 session lock file");
return -1;
}
i_error("pop3_lock_session: Couldn't create root directory %s: %s",
return -1;
}
if (ret < 0)
else if (ret > 0) {
}
return ret;
}
struct mail_storage_service_user *service_user,
const struct pop3_settings *set)
{
/* always use nonblocking I/O */
client->v = pop3_client_vfuncs;
}
if (client->uidl_keymask == 0)
i_fatal("Invalid pop3_uidl_format");
/* logging uidl_change. we need hashes of the UIDLs */
/* UIDL duplicates aren't allowed, so we'll need to
keep track of them */
}
if (hook_client_created != NULL)
return client;
}
{
const char *ident, *errmsg;
/* refresh proctitle before a potentially long-running init_mailbox() */
return -1;
}
return -1;
}
if (ident != NULL) {
}
return 0;
}
{
/* UIDL command not given */
return "";
}
/* 1..new-1 were probably left to mailbox by previous POP3 session */
for (i = 0, old_hash = 0; i < old_msg_count; i++)
/* assume all except deleted messages were sent to POP3 client */
} else {
(1 << (i % CHAR_BIT))) != 0)
continue;
}
}
else {
return t_strdup_printf("%u/%08x -> %u/%08x",
}
}
{
'o', "uidl_change"))
};
const char *error;
i_error("Failed to expand pop3_logout_format=%s: %s",
}
}
{
}
{
if (client->seen_change_count > 0)
(void)client_update_mails(client);
if (!client->disconnected) {
}
}
/* deinitialize command */
}
/* client didn't QUIT, but we still want to save any changes
done in this transaction. especially the cached virtual
message sizes. */
}
if (client->anvil_sent) {
"\n", NULL));
}
/* Autoexpunging might run for a long time. Disconnect the client
before it starts, and refresh proctitle so it's clear that it's
doing autoexpunging. We've also sent DISCONNECT to anvil already,
because this is background work and shouldn't really be counted
as an active POP3 session for the user. */
}
{
}
{
if (client->disconnected)
return;
}
{
return;
T_BEGIN {
} T_END;
if (ret >= 0) {
if (!POP3_CLIENT_OUTPUT_FULL(client))
/* no more input until client has read
our output */
/* If someone happens to flush output, we want to get
our IO handler back in flush callback */
}
}
}
{
const char *errstr;
"state, please relogin.");
return;
}
switch (error) {
case MAIL_ERROR_TEMP:
case MAIL_ERROR_NOQUOTA:
case MAIL_ERROR_INUSE:
break;
default:
break;
}
}
{
int ret;
*args++ = '\0';
T_BEGIN {
} T_END;
if (ret >= 0) {
client->bad_counter = 0;
TRUE);
break;
}
}
}
return FALSE;
}
return TRUE;
}
{
/* we're still processing a command. wait until it's
finished. */
return;
}
case -1:
/* disconnected */
return;
case -2:
/* line too long, kill it */
return;
}
(void)client_handle_input(client);
}
{
return 1;
}
/* enable input again */
client);
}
if (!client_handle_input(client)) {
/* client got destroyed */
return 1;
}
}
}
/* command not finished yet */
return 0;
/* data still in output buffer, get back here to add IO */
return 0;
} else {
return 1;
}
}
void clients_destroy_all(void)
{
while (pop3_clients != NULL) {
}
}
}
};