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>
26 #include "gtk/inputdialog.h"
32 #include "managesieve.h"
33 #include "sieve_editor.h"
34 #include "sieve_prefs.h"
36 GSList *sessions = NULL;
38 static void sieve_session_destroy(Session *session);
39 static gint sieve_pop_send_queue(SieveSession *session);
40 static void sieve_session_reset(SieveSession *session);
42 void sieve_sessions_close()
45 g_slist_free_full(sessions, (GDestroyNotify)session_destroy);
50 void noop_data_cb_fn(SieveSession *session, gpointer cb_data,
56 /* remove all command callbacks with a given data pointer */
57 void sieve_sessions_discard_callbacks(gpointer user_data)
61 SieveSession *session;
64 for (item = sessions; item; item = item->next) {
65 session = (SieveSession *)item->data;
66 cmd = session->current_cmd;
67 if (cmd && cmd->data == user_data)
68 cmd->cb = noop_data_cb_fn;
69 for (queue = session->send_queue; queue; queue = queue->next) {
70 cmd = (SieveCommand *)item->data;
71 if (cmd && cmd->data == user_data)
72 cmd->cb = noop_data_cb_fn;
77 void command_free(SieveCommand *cmd) {
82 void sieve_session_handle_status(SieveSession *session,
83 sieve_session_error_cb_fn on_error,
84 sieve_session_connected_cb_fn on_connected,
87 session->on_error = on_error;
88 session->on_connected = on_connected;
89 session->cb_data = data;
92 static void sieve_error(SieveSession *session, const gchar *msg)
94 if (session->on_error)
95 session->on_error(session, msg, session->cb_data);
98 static void sieve_connected(SieveSession *session, gboolean connected)
100 if (session->on_connected)
101 session->on_connected(session, connected, session->cb_data);
104 static gint sieve_auth_recv(SieveSession *session, const gchar *msg)
106 gchar buf[MESSAGEBUFSIZE], *tmp;
108 switch (session->auth_type) {
109 case SIEVEAUTH_LOGIN:
110 session->state = SIEVE_AUTH_LOGIN_USER;
112 if (strstr(msg, "VXNlcm5hbWU6")) {
113 tmp = g_base64_encode(session->user, strlen(session->user));
114 g_snprintf(buf, sizeof(buf), "\"%s\"", tmp);
116 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf) < 0) {
121 log_print(LOG_PROTOCOL, "Sieve> [USERID]\n");
123 /* Server rejects AUTH */
124 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
127 log_print(LOG_PROTOCOL, "Sieve> *\n");
130 case SIEVEAUTH_CRAM_MD5:
131 session->state = SIEVE_AUTH_CRAM_MD5;
136 gchar *challenge, *tmp;
138 guchar hexdigest[33];
140 tmp = g_base64_decode(msg + 1, &challengelen);
141 challenge = g_strndup(tmp, challengelen);
143 log_print(LOG_PROTOCOL, "Sieve< [Decoded: %s]\n", challenge);
145 g_snprintf(buf, sizeof(buf), "%s", session->pass);
146 md5_hex_hmac(hexdigest, challenge, challengelen,
147 buf, strlen(session->pass));
150 response = g_strdup_printf
151 ("%s %s", session->user, hexdigest);
152 log_print(LOG_PROTOCOL, "Sieve> [Encoded: %s]\n", response);
154 response64 = g_base64_encode(response, strlen(response));
157 response = g_strdup_printf("\"%s\"", response64);
160 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
165 log_print(LOG_PROTOCOL, "Sieve> %s\n", response);
168 /* Server rejects AUTH */
169 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
172 log_print(LOG_PROTOCOL, "Sieve> *\n");
176 /* stop sieve_auth when no correct authtype */
177 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "*") < 0)
179 log_print(LOG_PROTOCOL, "Sieve> *\n");
186 static gint sieve_auth_login_user_recv(SieveSession *session, const gchar *msg)
190 session->state = SIEVE_AUTH_LOGIN_PASS;
192 if (strstr(msg, "UGFzc3dvcmQ6")) {
193 tmp2 = g_base64_encode(session->pass, strlen(session->pass));
194 tmp = g_strdup_printf("\"%s\"", tmp2);
197 /* Server rejects AUTH */
198 tmp = g_strdup("\"*\"");
201 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, tmp) < 0) {
207 log_print(LOG_PROTOCOL, "Sieve> [PASSWORD]\n");
213 static gint sieve_auth_cram_md5(SieveSession *session)
215 session->state = SIEVE_AUTH;
216 session->auth_type = SIEVEAUTH_CRAM_MD5;
218 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
219 "Authenticate \"CRAM-MD5\"") < 0)
221 log_print(LOG_PROTOCOL, "Sieve> Authenticate CRAM-MD5\n");
226 static gint sieve_auth_plain(SieveSession *session)
228 gchar buf[MESSAGEBUFSIZE], *b64buf, *out;
231 session->state = SIEVE_AUTH_PLAIN;
232 session->auth_type = SIEVEAUTH_PLAIN;
234 memset(buf, 0, sizeof buf);
236 /* "\0user\0password" */
237 len = sprintf(buf, "%c%s%c%s", '\0', session->user, '\0', session->pass);
238 b64buf = g_base64_encode(buf, len);
239 out = g_strconcat("Authenticate \"PLAIN\" \"", b64buf, "\"", NULL);
242 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, out) < 0) {
249 log_print(LOG_PROTOCOL, "Sieve> [Authenticate PLAIN]\n");
254 static gint sieve_auth_login(SieveSession *session)
256 session->state = SIEVE_AUTH;
257 session->auth_type = SIEVEAUTH_LOGIN;
259 if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
260 "Authenticate \"LOGIN\"") < 0)
262 log_print(LOG_PROTOCOL, "Sieve> Authenticate LOGIN\n");
267 static gint sieve_auth(SieveSession *session)
269 SieveAuthType forced_auth_type = session->forced_auth_type;
271 if (!session->use_auth) {
272 session->state = SIEVE_READY;
273 sieve_connected(session, TRUE);
274 return sieve_pop_send_queue(session);
277 session->state = SIEVE_AUTH;
278 sieve_error(session, _("Authenticating..."));
280 if ((forced_auth_type == SIEVEAUTH_CRAM_MD5 || forced_auth_type == 0) &&
281 (session->avail_auth_type & SIEVEAUTH_CRAM_MD5) != 0)
282 return sieve_auth_cram_md5(session);
283 else if ((forced_auth_type == SIEVEAUTH_LOGIN || forced_auth_type == 0) &&
284 (session->avail_auth_type & SIEVEAUTH_LOGIN) != 0)
285 return sieve_auth_login(session);
286 else if ((forced_auth_type == SIEVEAUTH_PLAIN || forced_auth_type == 0) &&
287 (session->avail_auth_type & SIEVEAUTH_PLAIN) != 0)
288 return sieve_auth_plain(session);
289 else if (forced_auth_type == 0) {
290 log_warning(LOG_PROTOCOL, _("No Sieve auth method available\n"));
291 session->state = SIEVE_RETRY_AUTH;
294 log_warning(LOG_PROTOCOL, _("Selected Sieve auth method not available\n"));
295 session->state = SIEVE_RETRY_AUTH;
302 static void sieve_session_putscript_cb(SieveSession *session, SieveResult *result)
304 /* Remove script name from the beginning the response,
305 * which are added by Dovecot/Pigeonhole */
306 gchar *start, *desc = result->description;
308 if (g_str_has_prefix(desc, "NULL_") && (start = strchr(desc+5, ':'))) {
312 /* TODO: match against known script name, in case it contains
313 * weird text like ": line " */
314 } else if ((start = strstr(desc, ": line ")) ||
315 (start = strstr(desc, ": error"))) {
318 result->description = desc;
320 /* pass along the callback */
321 session->current_cmd->cb(session, result, session->current_cmd->data);
324 static inline gboolean response_is_ok(const char *msg)
326 return !strncmp(msg, "OK", 2) && (!msg[2] || msg[2] == ' ');
329 static inline gboolean response_is_no(const char *msg)
331 return !strncmp(msg, "NO", 2) && (!msg[2] || msg[2] == ' ');
334 static inline gboolean response_is_bye(const char *msg)
336 return !strncmp(msg, "BYE", 3) && (!msg[3] || msg[3] == ' ');
339 static void sieve_got_capability(SieveSession *session, gchar *cap_name,
342 if (strcmp(cap_name, "SASL") == 0) {
343 SieveAuthType auth_type = 0;
345 for (auth = cap_value; auth && auth[0]; auth = end) {
346 if ((end = strchr(auth, ' ')))
348 if (strcmp(auth, "PLAIN") == 0) {
349 auth_type |= SIEVEAUTH_PLAIN;
350 } else if (strcmp(auth, "CRAM-MD5") == 0) {
351 auth_type |= SIEVEAUTH_CRAM_MD5;
352 } else if (strcmp(auth, "LOGIN") == 0) {
353 auth_type |= SIEVEAUTH_LOGIN;
356 session->avail_auth_type = auth_type;
358 } else if (strcmp(cap_name, "STARTTLS") == 0) {
359 session->capability.starttls = TRUE;
363 static void log_send(SieveSession *session, SieveCommand *cmd)
365 gchar *end, *msg = cmd->msg;
366 if (cmd->next_state == SIEVE_PUTSCRIPT && (end = strchr(msg, '\n'))) {
367 /* Don't log the script data */
368 msg = g_strndup(msg, end - msg);
369 log_print(LOG_PROTOCOL, "Sieve> %s\n", msg);
373 log_print(LOG_PROTOCOL, "Sieve> %s\n", msg);
376 static gint sieve_pop_send_queue(SieveSession *session)
379 GSList *send_queue = session->send_queue;
384 cmd = (SieveCommand *)send_queue->data;
385 session->send_queue = g_slist_next(send_queue);
386 g_slist_free_1(send_queue);
388 log_send(session, cmd);
389 session->state = cmd->next_state;
390 if (session->current_cmd)
391 command_free(session->current_cmd);
392 session->current_cmd = cmd;
393 if (session_send_msg(SESSION(session), SESSION_SEND, cmd->msg) < 0)
399 static void parse_split(gchar *line, gchar **first_word, gchar **second_word)
406 if (line[0] == '"' && ((second = strchr(line + 1, '"')))) {
409 if (second[0] == ' ')
411 } else if ((second = strchr(line, ' '))) {
416 if (second && second[0] == '"' &&
417 ((end = strchr(second + 1, '"')))) {
423 *second_word = second;
426 static void unquote_inplace(gchar *str)
431 for (src = str+1, dest = str; src && *src && *src != '"'; src++) {
440 static void parse_response(gchar *msg, SieveResult *result)
442 /* response status */
443 gchar *end = strchr(msg, ' ');
446 result->success = strcmp(msg, "OK") == 0;
447 result->has_status = TRUE;
449 result->code = SIEVE_CODE_NONE;
450 result->description = NULL;
451 result->has_octets = FALSE;
460 if (msg[0] == '(' && (end = strchr(msg, ')'))) {
464 strcmp(msg, "WARNINGS") == 0 ? SIEVE_CODE_WARNINGS :
465 strcmp(msg, "TRYLATER") == 0 ? SIEVE_CODE_TRYLATER :
471 result->code = SIEVE_CODE_NONE;
475 if (msg[0] == '{' && (end = strchr(msg, '}'))) {
478 if (msg[0] == '0' && msg+1 == end) {
479 result->has_octets = TRUE;
483 (result->octets = g_ascii_strtoll(msg, NULL, 10)) != 0;
489 result->has_octets = FALSE;
495 unquote_inplace(msg);
496 result->description = msg;
498 result->description = NULL;
502 static gint sieve_session_recv_msg(Session *session, const gchar *msg)
504 SieveSession *sieve_session = SIEVE_SESSION(session);
508 switch (sieve_session->state) {
509 case SIEVE_GETSCRIPT_DATA:
510 log_print(LOG_PROTOCOL, "Sieve< [GETSCRIPT data]\n");
513 log_print(LOG_PROTOCOL, "Sieve< %s\n", msg);
514 if (response_is_bye(msg)) {
516 parse_response((gchar *)msg, &result);
517 if (!result.description)
518 status = g_strdup(_("Disconnected"));
519 else if (g_str_has_prefix(result.description, "Disconnected"))
520 status = g_strdup(result.description);
522 status = g_strdup_printf(_("Disconnected: %s"), result.description);
523 sieve_session->error = SE_ERROR;
524 sieve_error(sieve_session, status);
525 sieve_session->state = SIEVE_DISCONNECTED;
531 switch (sieve_session->state) {
532 case SIEVE_CAPABILITIES:
533 if (response_is_ok(msg)) {
534 /* capabilities list done */
537 if (sieve_session->tls_init_done == FALSE &&
538 sieve_session->config->tls_type != SIEVE_TLS_NO) {
539 if (sieve_session->capability.starttls) {
540 log_print(LOG_PROTOCOL, "Sieve> STARTTLS\n");
541 session_send_msg(session, SESSION_SEND, "STARTTLS");
542 sieve_session->state = SIEVE_STARTTLS;
543 } else if (sieve_session->config->tls_type == SIEVE_TLS_YES) {
544 log_warning(LOG_PROTOCOL, "Sieve: does not support STARTTLS\n");
545 sieve_session->state = SIEVE_ERROR;
547 log_warning(LOG_PROTOCOL, "Sieve: continuing without TLS\n");
548 sieve_session->state = SIEVE_CAPABILITIES;
553 /* authenticate after getting capabilities */
554 if (!sieve_session->authenticated) {
555 ret = sieve_auth(sieve_session);
557 sieve_session->state = SIEVE_READY;
558 sieve_connected(sieve_session, TRUE);
559 ret = sieve_pop_send_queue(sieve_session);
562 /* got a capability */
563 gchar *cap_name, *cap_value;
564 parse_split((gchar *)msg, &cap_name, &cap_value);
565 sieve_got_capability(sieve_session, cap_name, cap_value);
569 log_warning(LOG_PROTOCOL,
570 _("unhandled message on Sieve session: %s\n"), msg);
574 if (session_start_tls(session) < 0) {
575 sieve_session->state = SIEVE_ERROR;
576 sieve_session->error = SE_ERROR;
577 sieve_error(sieve_session, _("TLS failed"));
580 sieve_session->tls_init_done = TRUE;
581 sieve_session->state = SIEVE_CAPABILITIES;
586 ret = sieve_auth_recv(sieve_session, msg);
588 case SIEVE_AUTH_LOGIN_USER:
589 ret = sieve_auth_login_user_recv(sieve_session, msg);
591 case SIEVE_AUTH_PLAIN:
592 case SIEVE_AUTH_LOGIN_PASS:
593 case SIEVE_AUTH_CRAM_MD5:
594 if (response_is_no(msg)) {
595 log_print(LOG_PROTOCOL, "Sieve auth failed\n");
596 session->state = SIEVE_RETRY_AUTH;
598 } else if (response_is_ok(msg)) {
599 log_print(LOG_PROTOCOL, "Sieve auth completed\n");
600 sieve_error(sieve_session, _(""));
601 sieve_session->authenticated = TRUE;
602 sieve_session->state = SIEVE_READY;
603 sieve_connected(sieve_session, TRUE);
604 ret = sieve_pop_send_queue(sieve_session);
608 if (!response_is_ok(msg)) {
609 sieve_session->state = SIEVE_ERROR;
611 sieve_session->state = SIEVE_READY;
613 case SIEVE_LISTSCRIPTS:
614 if (response_is_no(msg)) {
615 /* got an error. probably not authenticated. */
616 sieve_session->current_cmd->cb(sieve_session, NULL,
617 sieve_session->current_cmd->data);
618 sieve_session->state = SIEVE_READY;
619 ret = sieve_pop_send_queue(sieve_session);
620 } else if (response_is_ok(msg)) {
622 sieve_session->state = SIEVE_READY;
623 sieve_session->error = SE_OK;
624 sieve_session->current_cmd->cb(sieve_session,
625 (gpointer)&(SieveScript){0},
626 sieve_session->current_cmd->data);
627 ret = sieve_pop_send_queue(sieve_session);
629 /* got a script name */
631 gchar *script_status;
633 parse_split((gchar *)msg, &script.name, &script_status);
634 script.active = (script_status &&
635 strcasecmp(script_status, "active") == 0);
637 sieve_session->current_cmd->cb(sieve_session, (gpointer)&script,
638 sieve_session->current_cmd->data);
642 case SIEVE_RENAMESCRIPT:
643 if (response_is_no(msg)) {
645 sieve_session->current_cmd->cb(sieve_session, NULL,
646 sieve_session->current_cmd->data);
647 } else if (response_is_ok(msg)) {
648 sieve_session->current_cmd->cb(sieve_session, (void*)TRUE,
649 sieve_session->current_cmd->data);
651 log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n"));
653 sieve_session->state = SIEVE_READY;
655 case SIEVE_SETACTIVE:
656 if (response_is_no(msg)) {
658 sieve_session->current_cmd->cb(sieve_session, NULL,
659 sieve_session->current_cmd->data);
660 } else if (response_is_ok(msg)) {
661 sieve_session->current_cmd->cb(sieve_session, (void*)TRUE,
662 sieve_session->current_cmd->data);
664 log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n"));
666 sieve_session->state = SIEVE_READY;
668 case SIEVE_GETSCRIPT:
669 if (response_is_no(msg)) {
670 sieve_session->current_cmd->cb(sieve_session, (void *)-1,
671 sieve_session->current_cmd->data);
672 sieve_session->state = SIEVE_READY;
674 parse_response((gchar *)msg, &result);
675 sieve_session->state = SIEVE_GETSCRIPT_DATA;
679 case SIEVE_GETSCRIPT_DATA:
680 if (response_is_ok(msg)) {
681 sieve_session->state = SIEVE_READY;
682 sieve_session->current_cmd->cb(sieve_session, NULL,
683 sieve_session->current_cmd->data);
685 sieve_session->current_cmd->cb(sieve_session, (gchar *)msg,
686 sieve_session->current_cmd->data);
690 case SIEVE_PUTSCRIPT:
691 parse_response((gchar *)msg, &result);
692 if (result.has_octets) {
693 sieve_session->state = SIEVE_PUTSCRIPT_DATA;
695 sieve_session->state = SIEVE_READY;
697 sieve_session_putscript_cb(sieve_session, &result);
700 case SIEVE_PUTSCRIPT_DATA:
702 sieve_session->state = SIEVE_READY;
704 result.has_status = FALSE;
705 result.has_octets = FALSE;
707 result.code = SIEVE_CODE_NONE;
708 result.description = (gchar *)msg;
709 sieve_session_putscript_cb(sieve_session, &result);
713 case SIEVE_DELETESCRIPT:
714 parse_response((gchar *)msg, &result);
715 if (!result.success) {
716 sieve_session->current_cmd->cb(sieve_session, result.description,
717 sieve_session->current_cmd->data);
719 sieve_session->current_cmd->cb(sieve_session, NULL,
720 sieve_session->current_cmd->data);
722 sieve_session->state = SIEVE_READY;
725 log_warning(LOG_PROTOCOL, _("error occurred on Sieve session. data: %s\n"), msg);
726 sieve_session->error = SE_ERROR;
728 case SIEVE_RETRY_AUTH:
729 log_warning(LOG_PROTOCOL, _("unhandled message on Sieve session: %s\n"),
731 ret = sieve_auth(sieve_session);
734 log_warning(LOG_PROTOCOL, _("unhandled message on Sieve session: %d\n"),
735 sieve_session->state);
736 sieve_session->error = SE_ERROR;
741 return session_recv_msg(session);
742 else if (ret == SE_AUTHFAIL) {
743 sieve_error(sieve_session, _("Auth failed"));
744 sieve_session->state = SIEVE_ERROR;
745 sieve_session->error = SE_ERROR;
751 static gint sieve_recv_message(Session *session, const gchar *msg,
757 static gint sieve_cmd_noop(SieveSession *session)
759 log_print(LOG_PROTOCOL, "Sieve> NOOP\n");
760 session->state = SIEVE_NOOP;
761 if (session_send_msg(SESSION(session), SESSION_SEND, "NOOP") < 0) {
762 session->state = SIEVE_ERROR;
763 session->error = SE_ERROR;
769 static gboolean sieve_ping(gpointer data)
771 Session *session = SESSION(data);
772 SieveSession *sieve_session = SIEVE_SESSION(session);
774 if (sieve_session->state == SIEVE_ERROR || session->state == SESSION_ERROR)
776 if (sieve_session->state != SIEVE_READY)
779 return sieve_cmd_noop(sieve_session) == 0;
782 static void sieve_session_destroy(Session *session)
784 SieveSession *sieve_session = SIEVE_SESSION(session);
785 g_free(sieve_session->pass);
786 if (sieve_session->current_cmd)
787 command_free(sieve_session->current_cmd);
788 sessions = g_slist_remove(sessions, (gconstpointer)session);
791 static void sieve_connect_finished(Session *session, gboolean success)
794 sieve_connected(SIEVE_SESSION(session), FALSE);
798 static gint sieve_session_connect(SieveSession *session)
800 session->state = SIEVE_CAPABILITIES;
801 session->authenticated = FALSE;
802 session->tls_init_done = FALSE;
803 return session_connect(SESSION(session), session->host,
807 static SieveSession *sieve_session_new(PrefsAccount *account)
809 SieveSession *session;
810 session = g_new0(SieveSession, 1);
811 session_init(SESSION(session), account, FALSE);
813 session->account = account;
815 SESSION(session)->recv_msg = sieve_session_recv_msg;
816 SESSION(session)->destroy = sieve_session_destroy;
817 SESSION(session)->connect_finished = sieve_connect_finished;
818 session_set_recv_message_notify(SESSION(session), sieve_recv_message, NULL);
820 sieve_session_reset(session);
824 static void sieve_session_reset(SieveSession *session)
826 PrefsAccount *account = session->account;
827 SieveAccountConfig *config = sieve_prefs_account_get_config(account);
828 gboolean reuse_auth = (config->auth == SIEVEAUTH_REUSE);
830 g_slist_free_full(session->send_queue, (GDestroyNotify)command_free);
832 session_disconnect(SESSION(session));
834 SESSION(session)->ssl_cert_auto_accept = account->ssl_certs_auto_accept;
835 SESSION(session)->nonblocking = account->use_nonblocking_ssl;
836 session->authenticated = FALSE;
837 session->current_cmd = NULL;
838 session->send_queue = NULL;
839 session->state = SIEVE_CAPABILITIES;
840 session->tls_init_done = FALSE;
841 session->avail_auth_type = 0;
842 session->auth_type = 0;
843 session->config = config;
844 session->host = config->use_host ? config->host : account->recv_server;
845 session->port = config->use_port ? config->port : SIEVE_PORT;
846 session->user = reuse_auth ? account->userid : session->config->userid;
847 session->forced_auth_type = config->auth_type;
848 session_register_ping(SESSION(session), sieve_ping);
851 g_free(session->pass);
852 if (config->auth == SIEVEAUTH_NONE) {
853 session->pass = NULL;
854 } else if (reuse_auth && account->passwd) {
855 session->pass = g_strdup(account->passwd);
856 } else if (config->passwd && config->passwd[0]) {
857 session->pass = g_strdup(config->passwd);
858 } else if (password_get(session->user, session->host, "sieve",
859 session->port, &session->pass)) {
861 session->pass = input_dialog_query_password_keep(session->host,
862 session->user, &(session->pass));
864 if (!session->pass) {
865 session->pass = g_strdup("");
866 session->use_auth = FALSE;
868 session->use_auth = TRUE;
872 SESSION(session)->ssl_type =
873 (config->tls_type == SIEVE_TLS_NO) ? SSL_NONE : SSL_STARTTLS;
877 /* When an account config is changed, reset associated sessions. */
878 void sieve_account_prefs_updated(PrefsAccount *account)
881 SieveSession *session;
883 for (item = sessions; item; item = item->next) {
884 session = (SieveSession *)item->data;
885 if (session->account == account) {
886 log_print(LOG_PROTOCOL, "Sieve: resetting session\n");
887 sieve_session_reset(session);
892 SieveSession *sieve_session_get_for_account(PrefsAccount *account)
894 SieveSession *session;
898 for (item = sessions; item; item = item->next) {
899 session = (SieveSession *)item->data;
900 if (session->account == account) {
906 session = sieve_session_new(account);
907 sessions = g_slist_prepend(sessions, session);
912 static void sieve_queue_send(SieveSession *session, SieveState next_state,
913 gchar *msg, sieve_session_data_cb_fn cb, gpointer data)
915 gboolean queue = FALSE;
916 SieveCommand *cmd = g_new0(SieveCommand, 1);
917 cmd->next_state = next_state;
922 if (!session_is_connected(SESSION(session))) {
923 log_print(LOG_PROTOCOL, "Sieve: connecting to %s:%hu\n",
924 session->host, session->port);
925 if (sieve_session_connect(session) < 0) {
926 sieve_connect_finished(SESSION(session), FALSE);
929 } else if (session->state == SIEVE_RETRY_AUTH) {
930 log_print(LOG_PROTOCOL, _("Sieve: retrying auth\n"));
931 if (sieve_auth(session) == SE_AUTHFAIL)
932 sieve_error(session, _("Auth method not available"));
934 } else if (session->state != SIEVE_READY) {
935 log_print(LOG_PROTOCOL, "Sieve: in state %d\n", session->state);
940 session->send_queue = g_slist_prepend(session->send_queue, cmd);
942 if (session->current_cmd)
943 command_free(session->current_cmd);
944 session->current_cmd = cmd;
945 session->state = next_state;
946 log_send(session, cmd);
947 if (session_send_msg(SESSION(session), SESSION_SEND, cmd->msg) < 0) {
953 void sieve_session_list_scripts(SieveSession *session,
954 sieve_session_data_cb_fn cb, gpointer data)
956 gchar *msg = g_strdup("LISTSCRIPTS");
957 sieve_queue_send(session, SIEVE_LISTSCRIPTS, msg, cb, data);
960 void sieve_session_add_script(SieveSession *session, const gchar *filter_name,
961 sieve_session_data_cb_fn cb, gpointer data)
964 gchar *msg = g_strdup("LISTSCRIPTS");
965 sieve_queue_send(session, SIEVE_LISTSCRIPTS, msg, cb, data);
969 void sieve_session_set_active_script(SieveSession *session,
970 const gchar *filter_name,
971 sieve_session_data_cb_fn cb, gpointer data)
973 gchar *msg = g_strdup_printf("SETACTIVE \"%s\"",
974 filter_name ? filter_name : "");
976 cb(session, (void*)FALSE, data);
980 sieve_queue_send(session, SIEVE_SETACTIVE, msg, cb, data);
983 void sieve_session_rename_script(SieveSession *session,
984 const gchar *name_old, const char *name_new,
985 sieve_session_data_cb_fn cb, gpointer data)
987 gchar *msg = g_strdup_printf("RENAMESCRIPT \"%s\" \"%s\"",
990 sieve_queue_send(session, SIEVE_RENAMESCRIPT, msg, cb, data);
993 void sieve_session_get_script(SieveSession *session, const gchar *filter_name,
994 sieve_session_data_cb_fn cb, gpointer data)
996 gchar *msg = g_strdup_printf("GETSCRIPT \"%s\"",
999 sieve_queue_send(session, SIEVE_GETSCRIPT, msg, cb, data);
1002 void sieve_session_put_script(SieveSession *session, const gchar *filter_name,
1003 gint len, const gchar *script_contents,
1004 sieve_session_data_cb_fn cb, gpointer data)
1006 /* TODO: refactor so don't have to copy the whole script here */
1007 gchar *msg = g_strdup_printf("PUTSCRIPT \"%s\" {%u+}\r\n%s",
1008 filter_name, len, script_contents);
1010 sieve_queue_send(session, SIEVE_PUTSCRIPT, msg, cb, data);
1013 void sieve_session_check_script(SieveSession *session,
1014 gint len, const gchar *script_contents,
1015 sieve_session_data_cb_fn cb, gpointer data)
1017 gchar *msg = g_strdup_printf("CHECKSCRIPT {%u+}\r\n%s",
1018 len, script_contents);
1020 sieve_queue_send(session, SIEVE_PUTSCRIPT, msg, cb, data);
1023 void sieve_session_delete_script(SieveSession *session,
1024 const gchar *filter_name,
1025 sieve_session_data_cb_fn cb, gpointer data)
1027 gchar *msg = g_strdup_printf("DELETESCRIPT \"%s\"",
1030 sieve_queue_send(session, SIEVE_DELETESCRIPT, msg, cb, data);