2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2015 the Claws Mail Team
4 * Copyright (C) 2014-2015 Charles Lehner
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <glib/gi18n.h>
27 #include "gtk/inputdialog.h"
33 #include "managesieve.h"
34 #include "sieve_editor.h"
35 #include "sieve_prefs.h"
37 GSList *sessions = NULL;
39 static void sieve_session_destroy(Session *session);
40 static gint sieve_pop_send_queue(SieveSession *session);
41 static void sieve_session_reset(SieveSession *session);
42 static void command_free(SieveCommand *cmd);
43 static void command_abort(SieveCommand *cmd);
44 static void command_cb(SieveCommand *cmd, gpointer result);
46 void sieve_sessions_close()
49 g_slist_free_full(sessions, (GDestroyNotify)session_destroy);
54 /* remove all command callbacks with a given data pointer */
55 void sieve_sessions_discard_callbacks(gpointer user_data)
60 SieveSession *session;
63 for (item = sessions; item; item = item->next) {
64 session = (SieveSession *)item->data;
65 cmd = session->current_cmd;
66 /* abort current command handler */
67 if (cmd && cmd->data == user_data) {
69 session->current_cmd = NULL;
71 /* abort queued command handlers */
72 for (queue = session->send_queue; queue; queue = queue->next) {
73 cmd = (SieveCommand *)queue->data;
74 if (cmd && cmd->data == user_data) {
76 prev->next = queue->next;
78 session->send_queue = NULL;
80 g_slist_free_1(queue);
88 static void command_cb(SieveCommand *cmd, gpointer result)
91 cmd->cb(cmd->session, FALSE, result, cmd->data);
94 static void command_abort(SieveCommand *cmd)
96 cmd->cb(cmd->session, TRUE, NULL, cmd->data);
101 static void command_free(SieveCommand *cmd)
107 void sieve_session_handle_status(SieveSession *session,
108 sieve_session_error_cb_fn on_error,
109 sieve_session_connected_cb_fn on_connected,
112 session->on_error = on_error;
113 session->on_connected = on_connected;
114 session->cb_data = data;
117 static void sieve_error(SieveSession *session, const gchar *msg)
119 if (session->on_error)
120 session->on_error(session, msg, session->cb_data);
123 static void sieve_connected(SieveSession *session, gboolean connected)
125 if (session->on_connected)
126 session->on_connected(session, connected, session->cb_data);
129 static gint sieve_auth_recv(SieveSession *session, const gchar *msg)
131 gchar buf[MESSAGEBUFSIZE], *tmp;
133 switch (session->auth_type) {
134 case SIEVEAUTH_LOGIN:
135 session->state = SIEVE_AUTH_LOGIN_USER;
137 if (strstr(msg, "VXNlcm5hbWU6")) {
138 tmp = g_base64_encode(session->user, strlen(session->user));
139 g_snprintf(buf, sizeof(buf), "\"%s\"", tmp);
141 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf) < 0) {
146 log_print(LOG_PROTOCOL, "Sieve> [USERID]\n");
148 /* Server rejects AUTH */
149 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
152 log_print(LOG_PROTOCOL, "Sieve> *\n");
155 case SIEVEAUTH_CRAM_MD5:
156 session->state = SIEVE_AUTH_CRAM_MD5;
161 gchar *challenge, *tmp;
163 guchar hexdigest[33];
165 tmp = g_base64_decode(msg + 1, &challengelen);
166 challenge = g_strndup(tmp, challengelen);
168 log_print(LOG_PROTOCOL, "Sieve< [Decoded: %s]\n", challenge);
170 g_snprintf(buf, sizeof(buf), "%s", session->pass);
171 md5_hex_hmac(hexdigest, challenge, challengelen,
172 buf, strlen(session->pass));
175 response = g_strdup_printf
176 ("%s %s", session->user, hexdigest);
177 log_print(LOG_PROTOCOL, "Sieve> [Encoded: %s]\n", response);
179 response64 = g_base64_encode(response, strlen(response));
182 response = g_strdup_printf("\"%s\"", response64);
185 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
190 log_print(LOG_PROTOCOL, "Sieve> %s\n", response);
193 /* Server rejects AUTH */
194 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
197 log_print(LOG_PROTOCOL, "Sieve> *\n");
201 /* stop sieve_auth when no correct authtype */
202 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "*") < 0)
204 log_print(LOG_PROTOCOL, "Sieve> *\n");
211 static gint sieve_auth_login_user_recv(SieveSession *session, const gchar *msg)
215 session->state = SIEVE_AUTH_LOGIN_PASS;
217 if (strstr(msg, "UGFzc3dvcmQ6")) {
218 tmp2 = g_base64_encode(session->pass, strlen(session->pass));
219 tmp = g_strdup_printf("\"%s\"", tmp2);
222 /* Server rejects AUTH */
223 tmp = g_strdup("\"*\"");
226 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, tmp) < 0) {
232 log_print(LOG_PROTOCOL, "Sieve> [PASSWORD]\n");
238 static gint sieve_auth_cram_md5(SieveSession *session)
240 session->state = SIEVE_AUTH;
241 session->auth_type = SIEVEAUTH_CRAM_MD5;
243 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
244 "Authenticate \"CRAM-MD5\"") < 0)
246 log_print(LOG_PROTOCOL, "Sieve> Authenticate CRAM-MD5\n");
251 static gint sieve_auth_plain(SieveSession *session)
253 gchar buf[MESSAGEBUFSIZE], *b64buf, *out;
256 session->state = SIEVE_AUTH_PLAIN;
257 session->auth_type = SIEVEAUTH_PLAIN;
259 memset(buf, 0, sizeof buf);
261 /* "\0user\0password" */
262 len = sprintf(buf, "%c%s%c%s", '\0', session->user, '\0', session->pass);
263 b64buf = g_base64_encode(buf, len);
264 out = g_strconcat("Authenticate \"PLAIN\" \"", b64buf, "\"", NULL);
267 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, out) < 0) {
274 log_print(LOG_PROTOCOL, "Sieve> [Authenticate PLAIN]\n");
279 static gint sieve_auth_login(SieveSession *session)
281 session->state = SIEVE_AUTH;
282 session->auth_type = SIEVEAUTH_LOGIN;
284 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
285 "Authenticate \"LOGIN\"") < 0)
287 log_print(LOG_PROTOCOL, "Sieve> Authenticate LOGIN\n");
292 static gint sieve_auth(SieveSession *session)
294 SieveAuthType forced_auth_type = session->forced_auth_type;
296 if (!session->use_auth) {
297 session->state = SIEVE_READY;
298 sieve_connected(session, TRUE);
299 return sieve_pop_send_queue(session);
302 session->state = SIEVE_AUTH;
303 sieve_error(session, _("Authenticating..."));
305 if ((forced_auth_type == SIEVEAUTH_CRAM_MD5 || forced_auth_type == 0) &&
306 (session->avail_auth_type & SIEVEAUTH_CRAM_MD5) != 0)
307 return sieve_auth_cram_md5(session);
308 else if ((forced_auth_type == SIEVEAUTH_LOGIN || forced_auth_type == 0) &&
309 (session->avail_auth_type & SIEVEAUTH_LOGIN) != 0)
310 return sieve_auth_login(session);
311 else if ((forced_auth_type == SIEVEAUTH_PLAIN || forced_auth_type == 0) &&
312 (session->avail_auth_type & SIEVEAUTH_PLAIN) != 0)
313 return sieve_auth_plain(session);
314 else if (forced_auth_type == 0) {
315 log_warning(LOG_PROTOCOL, _("No Sieve auth method available\n"));
316 session->state = SIEVE_RETRY_AUTH;
319 log_warning(LOG_PROTOCOL, _("Selected Sieve auth method not available\n"));
320 session->state = SIEVE_RETRY_AUTH;
327 static void sieve_session_putscript_cb(SieveSession *session, SieveResult *result)
329 /* Remove script name from the beginning the response,
330 * which are added by Dovecot/Pigeonhole */
331 gchar *start, *desc = result->description;
333 if (g_str_has_prefix(desc, "NULL_") && (start = strchr(desc+5, ':'))) {
337 /* TODO: match against known script name, in case it contains
338 * weird text like ": line " */
339 } else if ((start = strstr(desc, ": line ")) ||
340 (start = strstr(desc, ": error"))) {
343 result->description = desc;
345 /* pass along the callback */
346 command_cb(session->current_cmd, result);
349 static inline gboolean response_is_ok(const char *msg)
351 return !strncmp(msg, "OK", 2) && (!msg[2] || msg[2] == ' ');
354 static inline gboolean response_is_no(const char *msg)
356 return !strncmp(msg, "NO", 2) && (!msg[2] || msg[2] == ' ');
359 static inline gboolean response_is_bye(const char *msg)
361 return !strncmp(msg, "BYE", 3) && (!msg[3] || msg[3] == ' ');
364 static void sieve_got_capability(SieveSession *session, gchar *cap_name,
367 if (strcmp(cap_name, "SASL") == 0) {
368 SieveAuthType auth_type = 0;
370 for (auth = cap_value; auth && auth[0]; auth = end) {
371 if ((end = strchr(auth, ' ')))
373 if (strcmp(auth, "PLAIN") == 0) {
374 auth_type |= SIEVEAUTH_PLAIN;
375 } else if (strcmp(auth, "CRAM-MD5") == 0) {
376 auth_type |= SIEVEAUTH_CRAM_MD5;
377 } else if (strcmp(auth, "LOGIN") == 0) {
378 auth_type |= SIEVEAUTH_LOGIN;
381 session->avail_auth_type = auth_type;
383 } else if (strcmp(cap_name, "STARTTLS") == 0) {
384 session->capability.starttls = TRUE;
388 static void log_send(SieveSession *session, SieveCommand *cmd)
390 gchar *end, *msg = cmd->msg;
391 if (cmd->next_state == SIEVE_PUTSCRIPT && (end = strchr(msg, '\n'))) {
392 /* Don't log the script data */
393 msg = g_strndup(msg, end - msg);
394 log_print(LOG_PROTOCOL, "Sieve> %s\n", msg);
398 log_print(LOG_PROTOCOL, "Sieve> %s\n", msg);
401 static gint sieve_pop_send_queue(SieveSession *session)
404 GSList *send_queue = session->send_queue;
409 cmd = (SieveCommand *)send_queue->data;
410 session->send_queue = g_slist_next(send_queue);
411 g_slist_free_1(send_queue);
413 log_send(session, cmd);
414 session->state = cmd->next_state;
415 if (session->current_cmd)
416 command_free(session->current_cmd);
417 session->current_cmd = cmd;
418 if (session_send_msg(SESSION(session), SESSION_SEND, cmd->msg) < 0)
424 static void parse_split(gchar *line, gchar **first_word, gchar **second_word)
431 if (line[0] == '"' && ((second = strchr(line + 1, '"')))) {
434 if (second[0] == ' ')
436 } else if ((second = strchr(line, ' '))) {
441 if (second && second[0] == '"' &&
442 ((end = strchr(second + 1, '"')))) {
448 *second_word = second;
451 static void unquote_inplace(gchar *str)
456 for (src = str+1, dest = str; src && *src && *src != '"'; src++) {
465 static void parse_response(gchar *msg, SieveResult *result)
469 /* response status */
470 if (isalpha(msg[0])) {
471 end = strchr(msg, ' ');
477 result->success = strcmp(msg, "OK") == 0;
478 result->has_status = TRUE;
481 result->has_status = FALSE;
485 if (msg[0] == '(' && (end = strchr(msg, ')'))) {
489 strcmp(msg, "WARNINGS") == 0 ? SIEVE_CODE_WARNINGS :
490 strcmp(msg, "TRYLATER") == 0 ? SIEVE_CODE_TRYLATER :
496 result->code = SIEVE_CODE_NONE;
500 if (msg[0] == '{' && (end = strchr(msg, '}'))) {
503 if (msg[0] == '0' && msg+1 == end) {
504 result->has_octets = TRUE;
508 (result->octets = g_ascii_strtoll(msg, NULL, 10)) != 0;
514 result->has_octets = FALSE;
520 unquote_inplace(msg);
521 result->description = msg;
523 result->description = NULL;
527 static gint sieve_session_recv_msg(Session *session, const gchar *msg)
529 SieveSession *sieve_session = SIEVE_SESSION(session);
533 switch (sieve_session->state) {
534 case SIEVE_GETSCRIPT_DATA:
535 log_print(LOG_PROTOCOL, "Sieve< [GETSCRIPT data]\n");
538 log_print(LOG_PROTOCOL, "Sieve< %s\n", msg);
539 if (response_is_bye(msg)) {
541 parse_response((gchar *)msg, &result);
542 if (!result.description)
543 status = g_strdup(_("Disconnected"));
544 else if (g_str_has_prefix(result.description, "Disconnected"))
545 status = g_strdup(result.description);
547 status = g_strdup_printf(_("Disconnected: %s"), result.description);
548 sieve_session->error = SE_ERROR;
549 sieve_error(sieve_session, status);
550 sieve_session->state = SIEVE_DISCONNECTED;
556 switch (sieve_session->state) {
557 case SIEVE_CAPABILITIES:
558 if (response_is_ok(msg)) {
559 /* capabilities list done */
562 if (sieve_session->tls_init_done == FALSE &&
563 sieve_session->config->tls_type != SIEVE_TLS_NO) {
564 if (sieve_session->capability.starttls) {
565 log_print(LOG_PROTOCOL, "Sieve> STARTTLS\n");
566 session_send_msg(session, SESSION_SEND, "STARTTLS");
567 sieve_session->state = SIEVE_STARTTLS;
568 } else if (sieve_session->config->tls_type == SIEVE_TLS_YES) {
569 log_warning(LOG_PROTOCOL, "Sieve: does not support STARTTLS\n");
570 sieve_session->state = SIEVE_ERROR;
572 log_warning(LOG_PROTOCOL, "Sieve: continuing without TLS\n");
573 sieve_session->state = SIEVE_CAPABILITIES;
578 /* authenticate after getting capabilities */
579 if (!sieve_session->authenticated) {
580 ret = sieve_auth(sieve_session);
582 sieve_session->state = SIEVE_READY;
583 sieve_connected(sieve_session, TRUE);
584 ret = sieve_pop_send_queue(sieve_session);
587 /* got a capability */
588 gchar *cap_name, *cap_value;
589 parse_split((gchar *)msg, &cap_name, &cap_value);
590 sieve_got_capability(sieve_session, cap_name, cap_value);
594 log_warning(LOG_PROTOCOL,
595 _("unhandled message on Sieve session: %s\n"), msg);
599 if (session_start_tls(session) < 0) {
600 sieve_session->state = SIEVE_ERROR;
601 sieve_session->error = SE_ERROR;
602 sieve_error(sieve_session, _("TLS failed"));
605 sieve_session->tls_init_done = TRUE;
606 sieve_session->state = SIEVE_CAPABILITIES;
611 ret = sieve_auth_recv(sieve_session, msg);
613 case SIEVE_AUTH_LOGIN_USER:
614 ret = sieve_auth_login_user_recv(sieve_session, msg);
616 case SIEVE_AUTH_PLAIN:
617 case SIEVE_AUTH_LOGIN_PASS:
618 case SIEVE_AUTH_CRAM_MD5:
619 if (response_is_no(msg)) {
620 log_print(LOG_PROTOCOL, "Sieve auth failed\n");
621 session->state = SIEVE_RETRY_AUTH;
623 } else if (response_is_ok(msg)) {
624 log_print(LOG_PROTOCOL, "Sieve auth completed\n");
625 sieve_error(sieve_session, "");
626 sieve_session->authenticated = TRUE;
627 sieve_session->state = SIEVE_READY;
628 sieve_connected(sieve_session, TRUE);
629 ret = sieve_pop_send_queue(sieve_session);
633 if (!response_is_ok(msg)) {
634 sieve_session->state = SIEVE_ERROR;
636 sieve_session->state = SIEVE_READY;
638 case SIEVE_LISTSCRIPTS:
639 if (response_is_no(msg)) {
640 /* got an error. probably not authenticated. */
641 command_cb(sieve_session->current_cmd, NULL);
642 sieve_session->state = SIEVE_READY;
643 ret = sieve_pop_send_queue(sieve_session);
644 } else if (response_is_ok(msg)) {
646 sieve_session->state = SIEVE_READY;
647 sieve_session->error = SE_OK;
648 command_cb(sieve_session->current_cmd,
649 (gpointer)&(SieveScript){0});
650 ret = sieve_pop_send_queue(sieve_session);
652 /* got a script name */
654 gchar *script_status;
656 parse_split((gchar *)msg, &script.name, &script_status);
657 script.active = (script_status &&
658 strcasecmp(script_status, "active") == 0);
660 command_cb(sieve_session->current_cmd,
665 case SIEVE_RENAMESCRIPT:
666 if (response_is_no(msg)) {
668 command_cb(sieve_session->current_cmd, NULL);
669 } else if (response_is_ok(msg)) {
670 command_cb(sieve_session->current_cmd, (void*)TRUE);
672 log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n"));
674 sieve_session->state = SIEVE_READY;
676 case SIEVE_SETACTIVE:
677 if (response_is_no(msg)) {
679 command_cb(sieve_session->current_cmd, NULL);
680 } else if (response_is_ok(msg)) {
681 command_cb(sieve_session->current_cmd, (void*)TRUE);
683 log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n"));
685 sieve_session->state = SIEVE_READY;
687 case SIEVE_GETSCRIPT:
688 if (response_is_no(msg)) {
689 command_cb(sieve_session->current_cmd, (void *)-1);
690 sieve_session->state = SIEVE_READY;
692 parse_response((gchar *)msg, &result);
693 sieve_session->state = SIEVE_GETSCRIPT_DATA;
694 /* account for newline */
695 sieve_session->octets_remaining = result.octets + 1;
699 case SIEVE_GETSCRIPT_DATA:
700 if (sieve_session->octets_remaining > 0) {
701 command_cb(sieve_session->current_cmd, (gchar *)msg);
702 sieve_session->octets_remaining -= strlen(msg) + 1;
703 } else if (response_is_ok(msg)) {
704 sieve_session->state = SIEVE_READY;
705 command_cb(sieve_session->current_cmd, NULL);
707 log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n"));
711 case SIEVE_PUTSCRIPT:
712 parse_response((gchar *)msg, &result);
713 if (result.has_octets) {
714 sieve_session->state = SIEVE_PUTSCRIPT_DATA;
716 sieve_session->state = SIEVE_READY;
718 sieve_session_putscript_cb(sieve_session, &result);
721 case SIEVE_PUTSCRIPT_DATA:
723 sieve_session->state = SIEVE_READY;
725 result.has_status = FALSE;
726 result.has_octets = FALSE;
728 result.code = SIEVE_CODE_NONE;
729 result.description = (gchar *)msg;
730 sieve_session_putscript_cb(sieve_session, &result);
734 case SIEVE_DELETESCRIPT:
735 parse_response((gchar *)msg, &result);
736 if (!result.success) {
737 command_cb(sieve_session->current_cmd,
740 command_cb(sieve_session->current_cmd, NULL);
742 sieve_session->state = SIEVE_READY;
745 log_warning(LOG_PROTOCOL, _("error occurred on Sieve session. data: %s\n"), msg);
746 sieve_session->error = SE_ERROR;
748 case SIEVE_RETRY_AUTH:
749 log_warning(LOG_PROTOCOL, _("unhandled message on Sieve session: %s\n"),
751 ret = sieve_auth(sieve_session);
754 log_warning(LOG_PROTOCOL, _("unhandled message on Sieve session: %d\n"),
755 sieve_session->state);
756 sieve_session->error = SE_ERROR;
761 return session_recv_msg(session);
762 else if (ret == SE_AUTHFAIL) {
763 sieve_error(sieve_session, _("Auth failed"));
764 sieve_session->state = SIEVE_ERROR;
765 sieve_session->error = SE_ERROR;
771 static gint sieve_recv_message(Session *session, const gchar *msg,
777 static gint sieve_cmd_noop(SieveSession *session)
779 log_print(LOG_PROTOCOL, "Sieve> NOOP\n");
780 session->state = SIEVE_NOOP;
781 if (session_send_msg(SESSION(session), SESSION_SEND, "NOOP") < 0) {
782 session->state = SIEVE_ERROR;
783 session->error = SE_ERROR;
789 static gboolean sieve_ping(gpointer data)
791 Session *session = SESSION(data);
792 SieveSession *sieve_session = SIEVE_SESSION(session);
794 if (sieve_session->state == SIEVE_ERROR || session->state == SESSION_ERROR)
796 if (sieve_session->state != SIEVE_READY)
799 return sieve_cmd_noop(sieve_session) == 0;
802 static void sieve_session_destroy(Session *session)
804 SieveSession *sieve_session = SIEVE_SESSION(session);
805 g_free(sieve_session->pass);
806 if (sieve_session->current_cmd)
807 command_abort(sieve_session->current_cmd);
808 sessions = g_slist_remove(sessions, (gconstpointer)session);
809 g_slist_free_full(sieve_session->send_queue,
810 (GDestroyNotify)command_abort);
813 static void sieve_connect_finished(Session *session, gboolean success)
816 sieve_connected(SIEVE_SESSION(session), FALSE);
820 static gint sieve_session_connect(SieveSession *session)
822 session->state = SIEVE_CAPABILITIES;
823 session->authenticated = FALSE;
824 session->tls_init_done = FALSE;
825 return session_connect(SESSION(session), session->host,
829 static SieveSession *sieve_session_new(PrefsAccount *account)
831 SieveSession *session;
832 session = g_new0(SieveSession, 1);
833 session_init(SESSION(session), account, FALSE);
835 session->account = account;
837 SESSION(session)->recv_msg = sieve_session_recv_msg;
838 SESSION(session)->destroy = sieve_session_destroy;
839 SESSION(session)->connect_finished = sieve_connect_finished;
840 session_set_recv_message_notify(SESSION(session), sieve_recv_message, NULL);
842 sieve_session_reset(session);
846 static void sieve_session_reset(SieveSession *session)
848 PrefsAccount *account = session->account;
849 SieveAccountConfig *config = sieve_prefs_account_get_config(account);
850 gboolean reuse_auth = (config->auth == SIEVEAUTH_REUSE);
852 g_slist_free_full(session->send_queue, (GDestroyNotify)command_abort);
854 session_disconnect(SESSION(session));
856 SESSION(session)->ssl_cert_auto_accept = account->ssl_certs_auto_accept;
857 SESSION(session)->nonblocking = account->use_nonblocking_ssl;
858 session->authenticated = FALSE;
859 session->current_cmd = NULL;
860 session->send_queue = NULL;
861 session->state = SIEVE_CAPABILITIES;
862 session->tls_init_done = FALSE;
863 session->avail_auth_type = 0;
864 session->auth_type = 0;
865 session->config = config;
866 session->host = config->use_host ? config->host : account->recv_server;
867 session->port = config->use_port ? config->port : SIEVE_PORT;
868 session->user = reuse_auth ? account->userid : session->config->userid;
869 session->forced_auth_type = config->auth_type;
870 session_register_ping(SESSION(session), sieve_ping);
873 g_free(session->pass);
874 if (config->auth == SIEVEAUTH_NONE) {
875 session->pass = NULL;
876 } else if (reuse_auth && account->passwd) {
877 session->pass = g_strdup(account->passwd);
878 } else if (config->passwd && config->passwd[0]) {
879 session->pass = g_strdup(config->passwd);
880 } else if (password_get(session->user, session->host, "sieve",
881 session->port, &session->pass)) {
883 session->pass = input_dialog_query_password_keep(session->host,
884 session->user, &(session->pass));
886 if (!session->pass) {
887 session->pass = g_strdup("");
888 session->use_auth = FALSE;
890 session->use_auth = TRUE;
894 SESSION(session)->ssl_type =
895 (config->tls_type == SIEVE_TLS_NO) ? SSL_NONE : SSL_STARTTLS;
899 /* When an account config is changed, reset associated sessions. */
900 void sieve_account_prefs_updated(PrefsAccount *account)
903 SieveSession *session;
905 for (item = sessions; item; item = item->next) {
906 session = (SieveSession *)item->data;
907 if (session->account == account) {
908 log_print(LOG_PROTOCOL, "Sieve: resetting session\n");
909 sieve_session_reset(session);
914 SieveSession *sieve_session_get_for_account(PrefsAccount *account)
916 SieveSession *session;
920 for (item = sessions; item; item = item->next) {
921 session = (SieveSession *)item->data;
922 if (session->account == account) {
928 session = sieve_session_new(account);
929 sessions = g_slist_prepend(sessions, session);
934 static void sieve_queue_send(SieveSession *session, SieveState next_state,
935 gchar *msg, sieve_session_data_cb_fn cb, gpointer data)
937 gboolean queue = FALSE;
938 SieveCommand *cmd = g_new0(SieveCommand, 1);
939 cmd->session = session;
940 cmd->next_state = next_state;
945 if (!session_is_connected(SESSION(session))) {
946 log_print(LOG_PROTOCOL, "Sieve: connecting to %s:%hu\n",
947 session->host, session->port);
948 if (sieve_session_connect(session) < 0) {
949 sieve_connect_finished(SESSION(session), FALSE);
952 } else if (session->state == SIEVE_RETRY_AUTH) {
953 log_print(LOG_PROTOCOL, _("Sieve: retrying auth\n"));
954 if (sieve_auth(session) == SE_AUTHFAIL)
955 sieve_error(session, _("Auth method not available"));
957 } else if (session->state != SIEVE_READY) {
958 log_print(LOG_PROTOCOL, "Sieve: in state %d\n", session->state);
963 session->send_queue = g_slist_prepend(session->send_queue, cmd);
965 if (session->current_cmd)
966 command_free(session->current_cmd);
967 session->current_cmd = cmd;
968 session->state = next_state;
969 log_send(session, cmd);
970 if (session_send_msg(SESSION(session), SESSION_SEND, cmd->msg) < 0) {
976 void sieve_session_list_scripts(SieveSession *session,
977 sieve_session_data_cb_fn cb, gpointer data)
979 gchar *msg = g_strdup("LISTSCRIPTS");
980 sieve_queue_send(session, SIEVE_LISTSCRIPTS, msg, cb, data);
983 void sieve_session_add_script(SieveSession *session, const gchar *filter_name,
984 sieve_session_data_cb_fn cb, gpointer data)
987 gchar *msg = g_strdup("LISTSCRIPTS");
988 sieve_queue_send(session, SIEVE_LISTSCRIPTS, msg, cb, data);
992 void sieve_session_set_active_script(SieveSession *session,
993 const gchar *filter_name,
994 sieve_session_data_cb_fn cb, gpointer data)
996 gchar *msg = g_strdup_printf("SETACTIVE \"%s\"",
997 filter_name ? filter_name : "");
999 cb(session, FALSE, (void*)FALSE, data);
1003 sieve_queue_send(session, SIEVE_SETACTIVE, msg, cb, data);
1006 void sieve_session_rename_script(SieveSession *session,
1007 const gchar *name_old, const char *name_new,
1008 sieve_session_data_cb_fn cb, gpointer data)
1010 gchar *msg = g_strdup_printf("RENAMESCRIPT \"%s\" \"%s\"",
1011 name_old, name_new);
1013 sieve_queue_send(session, SIEVE_RENAMESCRIPT, msg, cb, data);
1016 void sieve_session_get_script(SieveSession *session, const gchar *filter_name,
1017 sieve_session_data_cb_fn cb, gpointer data)
1019 gchar *msg = g_strdup_printf("GETSCRIPT \"%s\"",
1022 sieve_queue_send(session, SIEVE_GETSCRIPT, msg, cb, data);
1025 void sieve_session_put_script(SieveSession *session, const gchar *filter_name,
1026 gint len, const gchar *script_contents,
1027 sieve_session_data_cb_fn cb, gpointer data)
1029 /* TODO: refactor so don't have to copy the whole script here */
1030 gchar *msg = g_strdup_printf("PUTSCRIPT \"%s\" {%u+}\r\n%s",
1031 filter_name, len, script_contents);
1033 sieve_queue_send(session, SIEVE_PUTSCRIPT, msg, cb, data);
1036 void sieve_session_check_script(SieveSession *session,
1037 gint len, const gchar *script_contents,
1038 sieve_session_data_cb_fn cb, gpointer data)
1040 gchar *msg = g_strdup_printf("CHECKSCRIPT {%u+}\r\n%s",
1041 len, script_contents);
1043 sieve_queue_send(session, SIEVE_PUTSCRIPT, msg, cb, data);
1046 void sieve_session_delete_script(SieveSession *session,
1047 const gchar *filter_name,
1048 sieve_session_data_cb_fn cb, gpointer data)
1050 gchar *msg = g_strdup_printf("DELETESCRIPT \"%s\"",
1053 sieve_queue_send(session, SIEVE_DELETESCRIPT, msg, cb, data);