Exemple #1
0
static gboolean session_write_msg_cb(SockInfo *source, GIOCondition condition,
				     gpointer data)
{
	Session *session = SESSION(data);
	gint ret;

	g_return_val_if_fail(condition == G_IO_OUT, FALSE);
	g_return_val_if_fail(session->write_buf != NULL, FALSE);
	g_return_val_if_fail(session->write_buf_p != NULL, FALSE);
	g_return_val_if_fail(session->write_buf_len > 0, FALSE);

	ret = session_write_buf(session);

	if (ret < 0) {
		session->state = SESSION_ERROR;
		return FALSE;
	} else if (ret > 0)
		return TRUE;

	if (session->io_tag > 0) {
		g_source_remove(session->io_tag);
		session->io_tag = 0;
	}

	session_recv_msg(session);

	return FALSE;
}
Exemple #2
0
static void sieve_read_chunk(SieveSession *session, gchar *data, guint len)
{
	log_print(LOG_PROTOCOL, "Sieve< [%u bytes]\n", len);

	switch (session->state) {
	case SIEVE_GETSCRIPT_DATA:
		command_cb(session->current_cmd, (gchar *)data);
		break;
	case SIEVE_SETACTIVE:
		/* Dovecot shows a script's warnings when making it active */
		/* TODO: append message in case it is very long*/
		strretchomp(data);
		sieve_error(session, data);
		break;
	case SIEVE_PUTSCRIPT: {
		SieveResult result = {.description = (gchar *)data};
		sieve_session_putscript_cb(session, &result);
		break;
	}
	default:
		log_warning(LOG_PROTOCOL,
				_("error occurred on SIEVE session\n"));
	}
}

static gint sieve_read_chunk_done(SieveSession *session)
{
	gint ret = SE_OK;

	switch (session->state) {
	case SIEVE_GETSCRIPT_DATA:
		/* wait for ending "OK" response */
		break;
	case SIEVE_SETACTIVE:
	case SIEVE_PUTSCRIPT:
		session->state = SIEVE_READY;
		break;
	default:
		log_warning(LOG_PROTOCOL,
				_("error occurred on SIEVE session\n"));
	}

	if (ret == SE_OK && session->state == SIEVE_READY)
		ret = sieve_pop_send_queue(session);

	if (ret == SE_OK)
		return session_recv_msg(SESSION(session));

	return 0;
}
Exemple #3
0
static gint smtp_session_recv_msg(Session *session, const gchar *msg)
{
	SMTPSession *smtp_session = SMTP_SESSION(session);
	gboolean cont = FALSE;

	if (strlen(msg) < 4) {
		log_warning(_("bad SMTP response\n"));
		return -1;
	}

	switch (smtp_session->state) {
	case SMTP_EHLO:
	case SMTP_STARTTLS:
	case SMTP_AUTH:
	case SMTP_AUTH_PLAIN:
	case SMTP_AUTH_LOGIN_USER:
	case SMTP_AUTH_LOGIN_PASS:
	case SMTP_AUTH_CRAM_MD5:
		log_print("ESMTP< %s\n", msg);
		break;
	default:
		log_print("SMTP< %s\n", msg);
		break;
	}

	if (msg[0] == '5' && msg[1] == '0' &&
	    (msg[2] == '4' || msg[2] == '3' || msg[2] == '1')) {
		log_warning(_("error occurred on SMTP session\n"));
		smtp_session->state = SMTP_ERROR;
		smtp_session->error_val = SM_ERROR;
		g_free(smtp_session->error_msg);
		smtp_session->error_msg = g_strdup(msg);
		return -1;
	}

	if (!strncmp(msg, "535", 3)) {
		log_warning(_("error occurred on authentication\n"));
		smtp_session->state = SMTP_ERROR;
		smtp_session->error_val = SM_AUTHFAIL;
		g_free(smtp_session->error_msg);
		smtp_session->error_msg = g_strdup(msg);
		return -1;
	}

	if (msg[0] != '1' && msg[0] != '2' && msg[0] != '3') {
		log_warning(_("error occurred on SMTP session\n"));
		smtp_session->state = SMTP_ERROR;
		smtp_session->error_val = SM_ERROR;
		g_free(smtp_session->error_msg);
		smtp_session->error_msg = g_strdup(msg);
		return -1;
	}

	if (msg[3] == '-')
		cont = TRUE;
	else if (msg[3] != ' ' && msg[3] != '\0') {
		log_warning(_("bad SMTP response\n"));
		smtp_session->state = SMTP_ERROR;
		smtp_session->error_val = SM_UNRECOVERABLE;
		return -1;
	}

	/* ignore all multiline responses except for EHLO */
	if (cont && smtp_session->state != SMTP_EHLO)
		return session_recv_msg(session);

	switch (smtp_session->state) {
	case SMTP_READY:
		if (strstr(msg, "ESMTP"))
			smtp_session->is_esmtp = TRUE;
	case SMTP_CONNECTED:
#if USE_OPENSSL
		if (smtp_session->user || session->ssl_type != SSL_NONE ||
		    smtp_session->is_esmtp)
#else
		if (smtp_session->user || smtp_session->is_esmtp)
#endif
			smtp_ehlo(smtp_session);
		else
			smtp_helo(smtp_session);
		break;
	case SMTP_HELO:
		smtp_from(smtp_session);
		break;
	case SMTP_EHLO:
		smtp_ehlo_recv(smtp_session, msg);
		if (cont == TRUE)
			break;
		if (smtp_session->max_message_size > 0
		&& smtp_session->max_message_size < smtp_session->send_data_len) {
			log_warning(_("Message is too big "
			      "(Maximum size is %s)\n"), 
			      to_human_readable(
			       (off_t)(smtp_session->max_message_size)));

			smtp_session->state = SMTP_ERROR;
			smtp_session->error_val = SM_ERROR;
			return -1;
		}
#if USE_OPENSSL
		if (session->ssl_type == SSL_STARTTLS &&
		    smtp_session->tls_init_done == FALSE) {
			smtp_starttls(smtp_session);
			break;
		}
#endif
		if (smtp_session->user) {
			if (smtp_auth(smtp_session) != SM_OK)
				smtp_from(smtp_session);
		} else
			smtp_from(smtp_session);
		break;
	case SMTP_STARTTLS:
#if USE_OPENSSL
		if (session_start_tls(session) < 0) {
			log_warning(_("can't start TLS session\n"));
			smtp_session->state = SMTP_ERROR;
			smtp_session->error_val = SM_ERROR;
			return -1;
		}
		smtp_session->tls_init_done = TRUE;
		smtp_ehlo(smtp_session);
#endif
		break;
	case SMTP_AUTH:
		smtp_auth_recv(smtp_session, msg);
		break;
	case SMTP_AUTH_LOGIN_USER:
		smtp_auth_login_user_recv(smtp_session, msg);
		break;
	case SMTP_AUTH_PLAIN:
	case SMTP_AUTH_LOGIN_PASS:
	case SMTP_AUTH_CRAM_MD5:
		smtp_from(smtp_session);
		break;
	case SMTP_FROM:
		if (smtp_session->cur_to)
			smtp_rcpt(smtp_session);
		break;
	case SMTP_RCPT:
		if (smtp_session->cur_to)
			smtp_rcpt(smtp_session);
		else
			smtp_data(smtp_session);
		break;
	case SMTP_DATA:
		smtp_send_data(smtp_session);
		break;
	case SMTP_EOM:
		smtp_quit(smtp_session);
		break;
	case SMTP_QUIT:
		session_disconnect(session);
		break;
	case SMTP_ERROR:
	default:
		log_warning(_("error occurred on SMTP session\n"));
		smtp_session->error_val = SM_ERROR;
		return -1;
	}

	if (cont)
		return session_recv_msg(session);

	return 0;
}
Exemple #4
0
static gint sieve_session_recv_msg(Session *session, const gchar *msg)
{
	SieveSession *sieve_session = SIEVE_SESSION(session);
	SieveResult result;
	gint ret = SE_OK;

	log_print(LOG_PROTOCOL, "Sieve< %s\n", msg);
	if (response_is_bye(msg)) {
		gchar *status;
		parse_response((gchar *)msg, &result);
		if (!result.description)
			status = g_strdup(_("Disconnected"));
		else if (g_str_has_prefix(result.description, "Disconnected"))
			status = g_strdup(result.description);
		else
			status = g_strdup_printf(_("Disconnected: %s"), result.description);
		sieve_session->error = SE_ERROR;
		sieve_error(sieve_session, status);
		sieve_session->state = SIEVE_DISCONNECTED;
		g_free(status);
		return -1;
	}

	switch (sieve_session->state) {
	case SIEVE_CAPABILITIES:
		if (response_is_ok(msg)) {
			/* capabilities list done */

#ifdef USE_GNUTLS
			if (sieve_session->tls_init_done == FALSE &&
					sieve_session->config->tls_type != SIEVE_TLS_NO) {
				if (sieve_session->capability.starttls) {
					log_print(LOG_PROTOCOL, "Sieve> STARTTLS\n");
					session_send_msg(session, SESSION_SEND, "STARTTLS");
					sieve_session->state = SIEVE_STARTTLS;
				} else if (sieve_session->config->tls_type == SIEVE_TLS_YES) {
					log_warning(LOG_PROTOCOL, "Sieve: does not support STARTTLS\n");
					sieve_session->state = SIEVE_ERROR;
				} else {
					log_warning(LOG_PROTOCOL, "Sieve: continuing without TLS\n");
					sieve_session->state = SIEVE_READY;
				}
				break;
			}
#endif
			/* authenticate after getting capabilities */
			if (!sieve_session->authenticated) {
				ret = sieve_auth(sieve_session);
			} else {
				sieve_session->state = SIEVE_READY;
				sieve_connected(sieve_session, TRUE);
			}
		} else {
			/* got a capability */
			gchar *cap_name, *cap_value;
			parse_split((gchar *)msg, &cap_name, &cap_value);
			sieve_got_capability(sieve_session, cap_name, cap_value);
		}
		break;
	case SIEVE_READY:
		if (!msg[0])
			break;
		log_warning(LOG_PROTOCOL,
				_("unhandled message on Sieve session: %s\n"), msg);
		break;
	case SIEVE_STARTTLS:
#ifdef USE_GNUTLS
		if (session_start_tls(session) < 0) {
			sieve_session->state = SIEVE_ERROR;
			sieve_session->error = SE_ERROR;
			sieve_error(sieve_session, _("TLS failed"));
			return -1;
		}
		sieve_session->tls_init_done = TRUE;
		sieve_session->state = SIEVE_CAPABILITIES;
#endif
		break;
	case SIEVE_AUTH:
		ret = sieve_auth_recv(sieve_session, msg);
		break;
	case SIEVE_AUTH_LOGIN_USER:
		ret = sieve_auth_login_user_recv(sieve_session, msg);
		break;
	case SIEVE_AUTH_PLAIN:
	case SIEVE_AUTH_LOGIN_PASS:
	case SIEVE_AUTH_CRAM_MD5:
		if (response_is_no(msg)) {
			log_print(LOG_PROTOCOL, "Sieve auth failed\n");
			session->state = SIEVE_RETRY_AUTH;
			ret = SE_AUTHFAIL;
		} else if (response_is_ok(msg)) {
			log_print(LOG_PROTOCOL, "Sieve auth completed\n");
			sieve_error(sieve_session, "");
			sieve_session->authenticated = TRUE;
			sieve_session->state = SIEVE_READY;
			sieve_connected(sieve_session, TRUE);
		}
		break;
	case SIEVE_NOOP:
		if (!response_is_ok(msg)) {
			sieve_session->state = SIEVE_ERROR;
		}
		sieve_session->state = SIEVE_READY;
		break;
	case SIEVE_LISTSCRIPTS:
		if (response_is_no(msg)) {
			/* got an error. probably not authenticated. */
			command_cb(sieve_session->current_cmd, NULL);
			sieve_session->state = SIEVE_READY;
		} else if (response_is_ok(msg)) {
			/* end of list */
			sieve_session->state = SIEVE_READY;
			sieve_session->error = SE_OK;
			command_cb(sieve_session->current_cmd,
					(gpointer)&(SieveScript){0});
		} else {
			/* got a script name */
			SieveScript script;
			gchar *script_status;

			parse_split((gchar *)msg, &script.name, &script_status);
			script.active = (script_status &&
					strcasecmp(script_status, "active") == 0);

			command_cb(sieve_session->current_cmd,
					(gpointer)&script);
		}
		break;
	case SIEVE_RENAMESCRIPT:
		if (response_is_no(msg)) {
			/* error */
			command_cb(sieve_session->current_cmd, NULL);
		} else if (response_is_ok(msg)) {
			command_cb(sieve_session->current_cmd, (void*)TRUE);
		} else {
			log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n"));
		}
		sieve_session->state = SIEVE_READY;
		break;
	case SIEVE_SETACTIVE:
		parse_response((gchar *)msg, &result);
		if (result.success) {
			/* clear status possibly set when setting another
			 * script active. TODO: give textual feedback */
			sieve_error(sieve_session, "");

			command_cb(sieve_session->current_cmd, NULL);
		} else if (result.description) {
			command_cb(sieve_session->current_cmd,
					result.description);
		} else {
			log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n"));
		}
		if (result.has_octets) {
			return sieve_session_recv_chunk(sieve_session,
					result.octets);
		} else {
			sieve_session->state = SIEVE_READY;
		}
		break;
	case SIEVE_GETSCRIPT:
		if (response_is_no(msg)) {
			command_cb(sieve_session->current_cmd, (void *)-1);
			sieve_session->state = SIEVE_READY;
		} else {
			parse_response((gchar *)msg, &result);
			sieve_session->state = SIEVE_GETSCRIPT_DATA;
			return sieve_session_recv_chunk(sieve_session,
					result.octets);
		}
		break;
	case SIEVE_GETSCRIPT_DATA:
		if (!msg[0])
			break;
		sieve_session->state = SIEVE_READY;
		if (response_is_ok(msg)) {
			command_cb(sieve_session->current_cmd, NULL);
		} else if (msg[0]) {
			log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n"));
		}
		break;
	case SIEVE_PUTSCRIPT:
		if (!msg[0])
			break;
		parse_response((gchar *)msg, &result);
		sieve_session_putscript_cb(sieve_session, &result);
		if (result.has_octets) {
			return sieve_session_recv_chunk(sieve_session,
					result.octets);
		} else {
			sieve_session->state = SIEVE_READY;
		}
		break;
	case SIEVE_DELETESCRIPT:
		parse_response((gchar *)msg, &result);
		if (!result.success) {
			command_cb(sieve_session->current_cmd,
					result.description);
		} else {
			command_cb(sieve_session->current_cmd, NULL);
		}
		sieve_session->state = SIEVE_READY;
		break;
	case SIEVE_ERROR:
		log_warning(LOG_PROTOCOL, _("error occurred on Sieve session. data: %s\n"), msg);
		sieve_session->error = SE_ERROR;
		break;
	case SIEVE_RETRY_AUTH:
		log_warning(LOG_PROTOCOL, _("unhandled message on Sieve session: %s\n"),
					msg);
		ret = sieve_auth(sieve_session);
		break;
	default:
		log_warning(LOG_PROTOCOL, _("unhandled message on Sieve session: %d\n"),
					sieve_session->state);
		sieve_session->error = SE_ERROR;
		return -1;
	}

	if (ret == SE_OK && sieve_session->state == SIEVE_READY)
		ret = sieve_pop_send_queue(sieve_session);

	if (ret == SE_OK) {
		return session_recv_msg(session);
	} else if (ret == SE_AUTHFAIL) {
		sieve_error(sieve_session, _("Auth failed"));
		sieve_session->state = SIEVE_ERROR;
		sieve_session->error = SE_ERROR;
	}

	return 0;
}