Example #1
0
/*
 * Add, remove or replace the specified flags of the messages.
 */
int
request_store(const char *server, const char *port, const char *user,
    const char *mesg, const char *mode, const char *flags)
{
	int t, r;
	session *s;

	if (!(s = session_find(server, port, user)))
		return -1;

	t = imap_store(s, mesg, mode, flags);
	if ((r = response_generic(s, t)) == -1)
		goto fail;

	if (xstrcasestr(flags, "\\Deleted") && get_option_boolean("expunge"))
		if (response_generic(s, imap_expunge(s)) == -1)
			goto fail;

	return r;
fail:
	close_connection(s);
	session_destroy(s);

	return -1;
}
Example #2
0
/*
 * Core function to go to idle state.
 */
static int
ifcore_idle(lua_State *lua)
{
	int r;
	char *event;

	event = NULL;

	if (lua_gettop(lua) != 1)
		luaL_error(lua, "wrong number of arguments");
	luaL_checktype(lua, 1, LUA_TLIGHTUSERDATA);

	if (get_option_boolean("reenter"))
		while ((r = request_idle((session *)(lua_topointer(lua, 1)),
		    &event)) == STATUS_NONE);
	else
		r = request_idle((session *)(lua_topointer(lua, 1)), &event);

	lua_pop(lua, 1);

	if (r == -1)
		return 0;

	lua_pushboolean(lua, (r == STATUS_OK));

	if (!event)
		return 1;

	lua_pushstring(lua, event);

	xfree(event);

	return 2;
}
Example #3
0
/*
 * Get server data and make sure there is a continuation response inside them.
 */
int
response_continuation(session *ssn, int tag)
{
	int r;
	ssize_t n;

	buffer_reset(&ibuf);

	do {
		buffer_check(&ibuf, ibuf.len + INPUT_BUF);
		if ((n = receive_response(ssn, ibuf.data + ibuf.len, 0, 1)) ==
		    -1)
			return -1;
		ibuf.len += n;

		if (check_bye(ibuf.data))
			return STATUS_BYE;
	} while ((r = check_tag(ibuf.data, ssn, tag)) == STATUS_NONE &&
	    !check_continuation(ibuf.data));

	if (r == STATUS_NO &&
	    (check_trycreate(ibuf.data) || get_option_boolean("create")))
		return STATUS_TRYCREATE;

	if (r == STATUS_NONE)
		return STATUS_CONTINUE;

	return r;
}
Example #4
0
/*
 * Auxiliary function to create a mailbox.
 */
int
create_mailbox(session *ssn, const char *mbox)
{
	int r;
	const char *m;

	m = apply_namespace(mbox, ssn->ns.prefix, ssn->ns.delim);

	if ((r = response_generic(ssn, imap_create(ssn, m))) == -1)
		return -1;

	if (get_option_boolean("subscribe"))
		if (response_generic(ssn, imap_subscribe(ssn, m)) == -1)
			return -1;

	return r;
}
Example #5
0
/*
 * Add, remove or replace the specified flags of the messages.
 */
int
request_store(session *ssn, const char *mesg, const char *mode, const char
    *flags)
{
	int t, r;

	TRY(t = send_request(ssn, "UID STORE %s %sFLAGS.SILENT (%s)", mesg, 
	    (!strncasecmp(mode, "add", 3) ? "+" :
	    !strncasecmp(mode, "remove", 6) ? "-" : ""), flags));
	TRY(r = response_generic(ssn, t));

	if (xstrcasestr(flags, "\\Deleted") && get_option_boolean("expunge")) {
		TRY(t = send_request(ssn, "EXPUNGE"));
		TRY(response_generic(ssn, t));
	}

	return r;
}
Example #6
0
/*
 * Append supplied message to the specified mailbox.
 */
int
request_append(session *ssn, const char *mbox, const char *mesg, size_t
    mesglen, const char *flags, const char *date)
{
	int t, r;
	const char *m;

	m = apply_namespace(mbox, ssn->ns.prefix, ssn->ns.delim);

	TRY(t = send_request(ssn, "APPEND \"%s\"%s%s%s%s%s%s {%d}", m,
	    (flags ? " (" : ""), (flags ? flags : ""),
	    (flags ? ")" : ""), (date ? " \"" : ""),
	    (date ? date : ""), (date ? "\"" : ""), mesglen));
	TRY(r = response_continuation(ssn, t));
	if (r == STATUS_CONTINUE) {
		TRY(send_continuation(ssn, mesg, mesglen)); 
		TRY(r = response_generic(ssn, t));
	}

	if (r == STATUS_TRYCREATE) {
		TRY(t = send_request(ssn, "CREATE \"%s\"", m));
		TRY(response_generic(ssn, t));
		if (get_option_boolean("subscribe")) {
			TRY(t = send_request(ssn, "SUBSCRIBE \"%s\"", m));
			TRY(response_generic(ssn, t));
		}
		TRY(t = send_request(ssn, "APPEND \"%s\"%s%s%s%s%s%s {%d}", m,
		    (flags ? " (" : ""), (flags ? flags : ""),
		    (flags ? ")" : ""), (date ? " \"" : ""),
		    (date ? date : ""), (date ? "\"" : ""), mesglen));
		TRY(r = response_continuation(ssn, t));
		if (r == STATUS_CONTINUE) {
			TRY(send_continuation(ssn, mesg, mesglen)); 
			TRY(r = response_generic(ssn, t));
		}
	}

	return r;
}
Example #7
0
/*
 * Copy the specified messages to another mailbox.
 */
int
request_copy(session *ssn, const char *mesg, const char *mbox)
{
	int t, r;
	const char *m;

	m = apply_namespace(mbox, ssn->ns.prefix, ssn->ns.delim);

	TRY(t = send_request(ssn, "UID COPY %s \"%s\"", mesg, m));
	TRY(r = response_generic(ssn, t));
	if (r == STATUS_TRYCREATE) {
		TRY(t = send_request(ssn, "CREATE \"%s\"", m));
		TRY(response_generic(ssn, t));
		if (get_option_boolean("subscribe")) {
			TRY(t = send_request(ssn, "SUBSCRIBE \"%s\"", m));
			TRY(response_generic(ssn, t));
		}
		TRY(t = send_request(ssn, "UID COPY %s \"%s\"", mesg, m));
		TRY(r = response_generic(ssn, t));
	}

	return r;
}
Example #8
0
/*
 * Connect to the server, login to the IMAP server, get it's capabilities, get
 * the namespace of the mailboxes.
 */
int
request_login(const char *server, const char *port, const char *ssl,
    const char *user, const char *pass)
{
	int r = -1, rg = -1;
	session *s;

	if ((s = session_find(server, port, user)))
		return STATUS_RESPONSE_NONE;

	s = session_new();

	s->server = xstrdup(server);
	s->port = xstrdup(port);
	s->username = xstrdup(user);

	if (ssl && strncasecmp(ssl, "tls1", 4) &&
	    strncasecmp(ssl, "ssl3", 4) && strncasecmp(ssl, "ssl2", 4))
		ssl = NULL;

	if (open_connection(s, server, port, ssl) == -1)
		goto fail;

	if ((rg = response_greeting(s)) == -1)
		goto fail;

	if (opts.debug)
		if (response_generic(s, imap_noop(s)) == -1)
			goto fail;

	if (response_capability(s, imap_capability(s)) == -1)
		goto fail;

#ifndef NO_SSLTLS
	if (!ssl && s->capabilities & CAPABILITY_STARTTLS &&
	    get_option_boolean("starttls"))
		switch (response_generic(s, imap_starttls(s))) {
		case STATUS_RESPONSE_OK:
			if (open_secure_connection(s, server, port, "tls1")
			    == -1)
				goto fail;
			if (response_capability(s, imap_capability(s)) == -1)
				goto fail;
			break;
		case -1:
			goto fail;
			break;
		}
#endif

	if (rg != STATUS_RESPONSE_PREAUTH) {
#ifndef NO_CRAMMD5
		if (s->capabilities & CAPABILITY_CRAMMD5 &&
		    get_option_boolean("crammd5")) {
			if ((r = auth_cram_md5(s, user, pass)) == -1)
				goto fail;
		}
#endif
		if (r != STATUS_RESPONSE_OK &&
		    (r = response_generic(s, imap_login(s, user, pass))) == -1)
			goto fail;

		if (r == STATUS_RESPONSE_NO) {
			error("username %s or password rejected at %s\n",
			    user, server);
			goto fail;
		}
	} else {
		r = STATUS_RESPONSE_PREAUTH;
	}

	if (response_capability(s, imap_capability(s)) == -1)
		goto fail;

	if (s->capabilities & CAPABILITY_NAMESPACE &&
	    get_option_boolean("namespace")) {
		if (response_namespace(s, imap_namespace(s)) == -1)
			goto fail;
	}

	return r;
fail:
	close_connection(s);
	session_destroy(s);

	return -1;
}
Example #9
0
/*
 * Initialize SSL/TLS connection.
 */
int
open_secure_connection(session *ssn)
{
	int r, e;
	SSL_CTX *ctx;

	if (!ssn->sslproto) {
		ctx = ssl23ctx;
	} else if (!strcasecmp(ssn->sslproto, "ssl3")) {
		ctx = ssl3ctx;
	} else if (!strcasecmp(ssn->sslproto, "tls1")) {
		ctx = tls1ctx;
	} else if (!strcasecmp(ssn->sslproto, "tls1.1")) {
#if OPENSSL_VERSION_NUMBER >= 0x01000100fL
		ctx = tls11ctx;
#else
		ctx = tls1ctx;
#endif
	} else if (!strcasecmp(ssn->sslproto, "tls1.2")) {
#if OPENSSL_VERSION_NUMBER >= 0x01000100fL
		ctx = tls12ctx;
#else
		ctx = tls1ctx;
#endif
	} else {
		ctx = ssl23ctx;
	}

	if (!(ssn->sslconn = SSL_new(ctx)))
		goto fail;

	SSL_set_fd(ssn->sslconn, ssn->socket);

	for (;;) {
		if ((r = SSL_connect(ssn->sslconn)) > 0)
			break;

		switch (SSL_get_error(ssn->sslconn, r)) {
		case SSL_ERROR_ZERO_RETURN:
			error("initiating SSL connection to %s; the "
			    "connection has been closed cleanly\n",
			    ssn->server);
			goto fail;
		case SSL_ERROR_NONE:
		case SSL_ERROR_WANT_CONNECT:
		case SSL_ERROR_WANT_ACCEPT:
		case SSL_ERROR_WANT_X509_LOOKUP:
		case SSL_ERROR_WANT_READ:
		case SSL_ERROR_WANT_WRITE:
			break;
		case SSL_ERROR_SYSCALL:
			e = ERR_get_error();
			if (e == 0 && r == 0)
				error("initiating SSL connection to %s; EOF in "
				    "violation of the protocol\n", ssn->server);
			else if (e == 0 && r == -1)
				error("initiating SSL connection to %s; %s\n",
				    ssn->server, strerror(errno));
			else
				error("initiating SSL connection to %s; %s\n",
				    ssn->server, ERR_error_string(e, NULL));
			goto fail;
		case SSL_ERROR_SSL:
			error("initiating SSL connection to %s; %s\n",
			    ssn->server, ERR_error_string(ERR_get_error(),
			    NULL));
			goto fail;
		default:
			break;
		}
	}
	if (get_option_boolean("certificates") && get_cert(ssn) == -1)
		goto fail;

	return 0;

fail:
	ssn->sslconn = NULL;

	return -1;
}
Example #10
0
/*
 * Connect to the server, login to the IMAP server, get it's capabilities, get
 * the namespace of the mailboxes.
 */
int
request_login(session **ssnptr, const char *server, const char *port, const
    char *ssl, const char *user, const char *pass)
{
	int t, r, rg = -1, rl = -1; 
	session *ssn = *ssnptr;
	
	if (*ssnptr && (*ssnptr)->socket != -1)
		return STATUS_PREAUTH;

	if (!*ssnptr) {
		ssn = *ssnptr = session_new();

		ssn->server = server;
		ssn->port = port;
		ssn->username = user;
		ssn->password = pass;

		if (strlen(ssl) != 0)
			ssn->sslproto = ssl;
	} else {
		debug("recovering connection: %s://%s@%s:%s/%s\n",
		    ssn->sslproto ?"imaps" : "imap", ssn->username, ssn->server,
		    ssn->port, ssn->selected ? ssn->selected : "");
	}

	if (open_connection(ssn) == -1)
		goto fail;

	CHECK(rg = response_greeting(ssn));

	if (opts.debug) {
		CHECK(t = send_request(ssn, "NOOP"));
		CHECK(response_generic(ssn, t));
	}

	CHECK(t = send_request(ssn, "CAPABILITY"));
	CHECK(response_capability(ssn, t));

	if (!ssn->sslproto && ssn->capabilities & CAPABILITY_STARTTLS &&
	    get_option_boolean("starttls")) {
		CHECK(t = send_request(ssn, "STARTTLS"));
		CHECK(r = response_generic(ssn, t));
		if (r == STATUS_OK) {
			if (open_secure_connection(ssn) == -1)
				goto fail;
			CHECK(t = send_request(ssn, "CAPABILITY"));
			CHECK(response_capability(ssn, t));
		}
	}

	if (rg != STATUS_PREAUTH) {
		if (ssn->capabilities & CAPABILITY_CRAMMD5 &&
		    get_option_boolean("crammd5")) {
			unsigned char *in, *out;
			CHECK(t = send_request(ssn, "AUTHENTICATE CRAM-MD5"));
			CHECK(r = response_authenticate(ssn, t, &in));
			if (r == STATUS_CONTINUE) {
				if ((out = auth_cram_md5(ssn->username,
				    ssn->password, in)) == NULL)
					goto abort;
				CHECK(send_continuation(ssn, (char *)(out),
				    strlen((char *)(out))));
				xfree(out);
				CHECK(rl = response_generic(ssn, t));
			} else
				goto abort;
		}
		if (rl != STATUS_OK) {
			CHECK(t = send_request(ssn, "LOGIN \"%s\" \"%s\"",
			    ssn->username, ssn->password));
			CHECK(rl = response_generic(ssn, t));
		}

		if (rl == STATUS_NO) {
			error("username %s or password rejected at %s\n",
			    ssn->username, ssn->server);
			close_connection(ssn);
			session_destroy(ssn);
			return STATUS_NO;
		}
	} else {
		rl = STATUS_PREAUTH;
	}

	CHECK(t = send_request(ssn, "CAPABILITY"));
	CHECK(response_capability(ssn, t));

	if (ssn->capabilities & CAPABILITY_NAMESPACE &&
	    get_option_boolean("namespace")) {
		CHECK(t = send_request(ssn, "NAMESPACE"));
		CHECK(response_namespace(ssn, t));
	}

	if (ssn->selected) {
		CHECK(t = send_request(ssn, "SELECT \"%s\"",
		    apply_namespace(ssn->selected, ssn->ns.prefix,
		    ssn->ns.delim)));
		CHECK(response_select(ssn, t));
	}

	return rl;
abort:
	close_connection(ssn);
fail:
	session_destroy(ssn);

	return -1;
}
Example #11
0
/*
 * Initialize SSL/TLS connection.
 */
int
open_secure_connection(session *ssn)
{
	int r, e;
	SSL_CTX *ctx;
#if OPENSSL_VERSION_NUMBER >= 0x1000000fL
	const SSL_METHOD *method;
#else		
	SSL_METHOD *method;
#endif

	method = NULL;

	if (ssn->sslproto && (!strncasecmp(ssn->sslproto, "ssl3", 4) ||
	    !strncasecmp(ssn->sslproto, "ssl2", 4)))
		method = SSLv23_client_method();
	else
		method = TLSv1_client_method();

	if (!(ctx = SSL_CTX_new(method)))
		goto fail;

	if (!(ssn->sslconn = SSL_new(ctx)))
		goto fail;

	SSL_set_fd(ssn->sslconn, ssn->socket);

	for (;;) {
		if ((r = SSL_connect(ssn->sslconn)) > 0)
			break;

		switch (SSL_get_error(ssn->sslconn, r)) {
		case SSL_ERROR_ZERO_RETURN:
			error("initiating SSL connection to %s; the "
			    "connection has been closed cleanly\n",
			    ssn->server);
			goto fail;
		case SSL_ERROR_NONE:
		case SSL_ERROR_WANT_CONNECT:
		case SSL_ERROR_WANT_ACCEPT:
		case SSL_ERROR_WANT_X509_LOOKUP:
		case SSL_ERROR_WANT_READ:
		case SSL_ERROR_WANT_WRITE:
			break;
		case SSL_ERROR_SYSCALL:
			e = ERR_get_error();
			if (e == 0 && r == 0)
				error("initiating SSL connection to %s; EOF in "
				    "violation of the protocol\n", ssn->server);
			else if (e == 0 && r == -1)
				error("initiating SSL connection to %s; %s\n",
				    ssn->server, strerror(errno));
			else
				error("initiating SSL connection to %s; %s\n",
				    ssn->server, ERR_error_string(e, NULL));
			goto fail;
		case SSL_ERROR_SSL:
			error("initiating SSL connection to %s; %s\n",
			    ssn->server, ERR_error_string(ERR_get_error(),
			    NULL));
			goto fail;
		default:
			break;
		}
	}
	if (get_option_boolean("certificates") && get_cert(ssn) == -1)
		goto fail;

	SSL_CTX_free(ctx);

	return 0;

fail:
	ssn->sslconn = NULL;
	SSL_CTX_free(ctx);

	return -1;
}