Beispiel #1
0
static gint smtp_auth_login(SMTPSession *session)
{
	session->state = SMTP_AUTH;
	session->auth_type = SMTPAUTH_LOGIN;

	if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "AUTH LOGIN") < 0)
		return SM_ERROR;
	log_print(LOG_PROTOCOL, "ESMTP> AUTH LOGIN\n");

	return SM_OK;
}
Beispiel #2
0
static gint smtp_auth_cram_md5(SMTPSession *session)
{
	session->state = SMTP_AUTH;
	session->auth_type = SMTPAUTH_CRAM_MD5;

	if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "AUTH CRAM-MD5") < 0)
		return SM_ERROR;
	log_print(LOG_PROTOCOL, "ESMTP> AUTH CRAM-MD5\n");

	return SM_OK;
}
Beispiel #3
0
static gint sieve_auth_login(SieveSession *session)
{
	session->state = SIEVE_AUTH;
	session->auth_type = SIEVEAUTH_LOGIN;

	if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
				"Authenticate \"LOGIN\"") < 0)
		return SE_ERROR;
	log_print(LOG_PROTOCOL, "Sieve> Authenticate LOGIN\n");

	return SE_OK;
}
Beispiel #4
0
static gint sieve_auth_cram_md5(SieveSession *session)
{
	session->state = SIEVE_AUTH;
	session->auth_type = SIEVEAUTH_CRAM_MD5;

	if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
				"Authenticate \"CRAM-MD5\"") < 0)
		return SE_ERROR;
	log_print(LOG_PROTOCOL, "Sieve> Authenticate CRAM-MD5\n");

	return SE_OK;
}
Beispiel #5
0
static gint smtp_auth_plain(SMTPSession *session)
{
	gchar buf[MESSAGEBUFSIZE];

	/* 
 	 * +1      +1      +1
	 * \0<user>\0<pass>\0 
	 */
	int b64len = (1 + strlen(session->user) + 1 + strlen(session->pass) + 1);
	gchar *b64buf = g_malloc(b64len);

	/* use the char *ptr to walk the base64 string with embedded \0 */
	char  *a = b64buf;
	int  b64cnt = 0;

	session->state = SMTP_AUTH_PLAIN;
	session->auth_type = SMTPAUTH_PLAIN;

	memset(buf, 0, sizeof buf);

	/*
	 * have to construct the string bit by bit. sprintf can't do it in one.
	 * first field is null, so string is \0<user>\0<password>
	 */
	*a = 0;
	a++;

	g_snprintf (a, b64len - 1, "%s", session->user);

	b64cnt = strlen(session->user)+1;
	a += b64cnt;

	g_snprintf (a, b64len - b64cnt - 1, "%s", session->pass);
	b64cnt += strlen(session->pass) + 1;	

	/*
	 * reuse the char *ptr to offset into the textbuf to meld
	 * the plaintext ESMTP message and the base64 string value
	 */
	strcpy(buf, "AUTH PLAIN ");
	a = buf + strlen(buf);
	base64_encode(a, b64buf, b64cnt);

	if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf) < 0)
		return SM_ERROR;

	log_print(LOG_PROTOCOL, "ESMTP> [AUTH PLAIN]\n");

	g_free(b64buf);

	return SM_OK;
}
Beispiel #6
0
static gint smtp_helo(SMTPSession *session)
{
	gchar buf[MSGBUFSIZE];

	session->state = SMTP_HELO;

	g_snprintf(buf, sizeof(buf), "HELO %s",
		   session->hostname ? session->hostname : get_domain_name());
	session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf);
	log_print("SMTP> %s\n", buf);

	return SM_OK;
}
Beispiel #7
0
static void pop3_gen_send(Pop3Session *session, const gchar *format, ...)
{
	gchar buf[POPBUFSIZE + 1];
	va_list args;

	va_start(args, format);
	g_vsnprintf(buf, sizeof(buf) - 2, format, args);
	va_end(args);

	if (!g_ascii_strncasecmp(buf, "PASS ", 5))
		log_print(LOG_PROTOCOL, "POP3> PASS ********\n");
	else
		log_print(LOG_PROTOCOL, "POP3> %s\n", buf);

	session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf);
}
Beispiel #8
0
static gint smtp_ehlo(SMTPSession *session)
{
	gchar buf[MESSAGEBUFSIZE];

	session->state = SMTP_EHLO;

	session->avail_auth_type = 0;

	g_snprintf(buf, sizeof(buf), "EHLO %s",
		   session->hostname ? session->hostname : get_domain_name());
	if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf) < 0)
		return SM_ERROR;
	log_print(LOG_PROTOCOL, "ESMTP> %s\n", buf);

	return SM_OK;
}
Beispiel #9
0
static gint smtp_auth_login_user_recv(SMTPSession *session, const gchar *msg)
{
	gchar buf[MSGBUFSIZE];

	session->state = SMTP_AUTH_LOGIN_PASS;

	if (!strncmp(msg, "334 ", 4))
		base64_encode(buf, session->pass, strlen(session->pass));
	else
		/* Server rejects AUTH */
		g_snprintf(buf, sizeof(buf), "*");

	session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf);
	log_print("ESMTP> [PASSWORD]\n");

	return SM_OK;
}
Beispiel #10
0
static void sieve_queue_send(SieveSession *session, SieveState next_state,
		gchar *msg, sieve_session_data_cb_fn cb, gpointer data)
{
	gboolean queue = FALSE;
	SieveCommand *cmd = g_new0(SieveCommand, 1);
	cmd->session = session;
	cmd->next_state = next_state;
	cmd->msg = msg;
	cmd->data = data;
	cmd->cb = cb;

	if (!session_is_connected(SESSION(session))) {
		log_print(LOG_PROTOCOL, "Sieve: connecting to %s:%hu\n",
				session->host, session->port);
		if (sieve_session_connect(session) < 0) {
			sieve_connect_finished(SESSION(session), FALSE);
		}
		queue = TRUE;
	} else if (session->state == SIEVE_RETRY_AUTH) {
		log_print(LOG_PROTOCOL, _("Sieve: retrying auth\n"));
		if (sieve_auth(session) == SE_AUTHFAIL)
			sieve_error(session, _("Auth method not available"));
		queue = TRUE;
	} else if (session->state != SIEVE_READY) {
		log_print(LOG_PROTOCOL, "Sieve: in state %d\n", session->state);
		queue = TRUE;
	}

	if (queue) {
		session->send_queue = g_slist_prepend(session->send_queue, cmd);
	} else {
		if (session->current_cmd)
			command_free(session->current_cmd);
		session->current_cmd = cmd;
		session->state = next_state;
		log_send(session, cmd);
		if (session_send_msg(SESSION(session), SESSION_SEND, cmd->msg) < 0) {
			/* error */
		}
	}
}
Beispiel #11
0
static gint smtp_rcpt(SMTPSession *session)
{
	gchar buf[MSGBUFSIZE];
	gchar *to;

	g_return_val_if_fail(session->cur_to != NULL, SM_ERROR);

	session->state = SMTP_RCPT;

	to = (gchar *)session->cur_to->data;

	if (strchr(to, '<'))
		g_snprintf(buf, sizeof(buf), "RCPT TO:%s", to);
	else
		g_snprintf(buf, sizeof(buf), "RCPT TO:<%s>", to);
	session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf);
	log_print("SMTP> %s\n", buf);

	session->cur_to = session->cur_to->next;

	return SM_OK;
}
Beispiel #12
0
static gint smtp_auth_login_user_recv(SMTPSession *session, const gchar *msg)
{
	gchar *tmp;

	session->state = SMTP_AUTH_LOGIN_PASS;

	if (!strncmp(msg, "334 ", 4)) {
		tmp = g_base64_encode(session->pass, strlen(session->pass));
	} else {
		/* Server rejects AUTH */
		tmp = g_strdup("*");
	}

	if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, tmp) < 0) {
		g_free(tmp);
		return SM_ERROR;
	}
	g_free(tmp);

	log_print(LOG_PROTOCOL, "ESMTP> [PASSWORD]\n");

	return SM_OK;
}
Beispiel #13
0
static gint smtp_auth_recv(SMTPSession *session, const gchar *msg)
{
	gchar buf[MSGBUFSIZE];

	switch (session->auth_type) {
	case SMTPAUTH_LOGIN:
		session->state = SMTP_AUTH_LOGIN_USER;

		if (!strncmp(msg, "334 ", 4)) {
			base64_encode(buf, session->user, strlen(session->user));

			session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
					 buf);
			log_print("ESMTP> [USERID]\n");
		} else {
			/* Server rejects AUTH */
			session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
					 "*");
			log_print("ESMTP> *\n");
		}
		break;
	case SMTPAUTH_CRAM_MD5:
		session->state = SMTP_AUTH_CRAM_MD5;

		if (!strncmp(msg, "334 ", 4)) {
			gchar *response;
			gchar *response64;
			gchar *challenge;
			gint challengelen;
			guchar hexdigest[33];

			challenge = g_malloc(strlen(msg + 4) + 1);
			challengelen = base64_decode(challenge, msg + 4, -1);
			challenge[challengelen] = '\0';
			log_print("ESMTP< [Decoded: %s]\n", challenge);

			g_snprintf(buf, sizeof(buf), "%s", session->pass);
			md5_hex_hmac(hexdigest, challenge, challengelen,
				     buf, strlen(session->pass));
			g_free(challenge);

			response = g_strdup_printf
				("%s %s", session->user, hexdigest);
			log_print("ESMTP> [Encoded: %s]\n", response);

			response64 = g_malloc((strlen(response) + 3) * 2 + 1);
			base64_encode(response64, response, strlen(response));
			g_free(response);

			session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
					 response64);
			log_print("ESMTP> %s\n", response64);
			g_free(response64);
		} else {
			/* Server rejects AUTH */
			session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
					 "*");
			log_print("ESMTP> *\n");
		}
		break;
	case SMTPAUTH_DIGEST_MD5:
        default:
        	/* stop smtp_auth when no correct authtype */
		session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "*");
		log_print("ESMTP> *\n");
		break;
	}

	return SM_OK;
}
Beispiel #14
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;
}
Beispiel #15
0
static gint sieve_auth_recv(SieveSession *session, const gchar *msg)
{
	gchar buf[MESSAGEBUFSIZE], *tmp;

	switch (session->auth_type) {
	case SIEVEAUTH_LOGIN:
		session->state = SIEVE_AUTH_LOGIN_USER;

		if (strstr(msg, "VXNlcm5hbWU6")) {
			tmp = g_base64_encode(session->user, strlen(session->user));
			g_snprintf(buf, sizeof(buf), "\"%s\"", tmp);

			if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf) < 0) {
				g_free(tmp);
				return SE_ERROR;
			}
			g_free(tmp);
			log_print(LOG_PROTOCOL, "Sieve> [USERID]\n");
		} else {
			/* Server rejects AUTH */
			if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
					 "\"*\"") < 0)
				return SE_ERROR;
			log_print(LOG_PROTOCOL, "Sieve> *\n");
		}
		break;
	case SIEVEAUTH_CRAM_MD5:
		session->state = SIEVE_AUTH_CRAM_MD5;

		if (msg[0] == '"') {
			gchar *response;
			gchar *response64;
			gchar *challenge, *tmp;
			gsize challengelen;
			guchar hexdigest[33];

			tmp = g_base64_decode(msg + 1, &challengelen);
			challenge = g_strndup(tmp, challengelen);
			g_free(tmp);
			log_print(LOG_PROTOCOL, "Sieve< [Decoded: %s]\n", challenge);

			g_snprintf(buf, sizeof(buf), "%s", session->pass);
			md5_hex_hmac(hexdigest, challenge, challengelen,
				     buf, strlen(session->pass));
			g_free(challenge);

			response = g_strdup_printf
				("%s %s", session->user, hexdigest);
			log_print(LOG_PROTOCOL, "Sieve> [Encoded: %s]\n", response);

			response64 = g_base64_encode(response, strlen(response));
			g_free(response);

			response = g_strdup_printf("\"%s\"", response64);
			g_free(response64);

			if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
					 response) < 0) {
				g_free(response);
				return SE_ERROR;
			}
			log_print(LOG_PROTOCOL, "Sieve> %s\n", response);
			g_free(response);
		} else {
			/* Server rejects AUTH */
			if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
					 "\"*\"") < 0)
				return SE_ERROR;
			log_print(LOG_PROTOCOL, "Sieve> *\n");
		}
		break;
	default:
		/* stop sieve_auth when no correct authtype */
		if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "*") < 0)
			return SE_ERROR;
		log_print(LOG_PROTOCOL, "Sieve> *\n");
		break;
	}

	return SE_OK;
}
Beispiel #16
0
static gint smtp_auth_recv(SMTPSession *session, const gchar *msg)
{
	gchar buf[MESSAGEBUFSIZE], *tmp;

	switch (session->auth_type) {
	case SMTPAUTH_LOGIN:
		session->state = SMTP_AUTH_LOGIN_USER;

		if (!strncmp(msg, "334 ", 4)) {
			tmp = g_base64_encode(session->user, strlen(session->user));

			if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
					 tmp) < 0) {
				g_free(tmp);
				return SM_ERROR;
			}
			g_free(tmp);
			log_print(LOG_PROTOCOL, "ESMTP> [USERID]\n");
		} else {
			/* Server rejects AUTH */
			if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
					 "*") < 0)
				return SM_ERROR;
			log_print(LOG_PROTOCOL, "ESMTP> *\n");
		}
		break;
	case SMTPAUTH_CRAM_MD5:
		session->state = SMTP_AUTH_CRAM_MD5;

		if (!strncmp(msg, "334 ", 4)) {
			gchar *response;
			gchar *response64;
			gchar *challenge;
			gsize challengelen;
			guchar hexdigest[33];

			challenge = g_base64_decode_zero(msg + 4, &challengelen);
			log_print(LOG_PROTOCOL, "ESMTP< [Decoded: %s]\n", challenge);

			g_snprintf(buf, sizeof(buf), "%s", session->pass);
			md5_hex_hmac(hexdigest, challenge, challengelen,
				     buf, strlen(session->pass));
			g_free(challenge);

			response = g_strdup_printf
				("%s %s", session->user, hexdigest);
			log_print(LOG_PROTOCOL, "ESMTP> [Encoded: %s]\n", response);

			response64 = g_base64_encode(response, strlen(response));
			g_free(response);

			if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
					 response64) < 0) {
				g_free(response64);
				return SM_ERROR;
			}
			log_print(LOG_PROTOCOL, "ESMTP> %s\n", response64);
			g_free(response64);
		} else {
			/* Server rejects AUTH */
			if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
					 "*") < 0)
				return SM_ERROR;
			log_print(LOG_PROTOCOL, "ESMTP> *\n");
		}
		break;
	case SMTPAUTH_DIGEST_MD5:
        default:
        	/* stop smtp_auth when no correct authtype */
		if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "*") < 0)
			return SM_ERROR;
		log_print(LOG_PROTOCOL, "ESMTP> *\n");
		break;
	}

	return SM_OK;
}