struct sieve_binary *sieve_compile_script (struct sieve_script *script, struct sieve_error_handler *ehandler, enum sieve_compile_flags flags, enum sieve_error *error_r) { struct sieve_ast *ast; struct sieve_binary *sbin; enum sieve_error error, *errorp; if ( error_r != NULL ) errorp = error_r; else errorp = &error; *errorp = SIEVE_ERROR_NONE; /* Parse */ if ( (ast = sieve_parse(script, ehandler, errorp)) == NULL ) { switch ( *errorp ) { case SIEVE_ERROR_NOT_FOUND: if (error_r == NULL) { sieve_error(ehandler, sieve_script_name(script), "script not found"); } break; default: sieve_error(ehandler, sieve_script_name(script), "parse failed"); } return NULL; } /* Validate */ if ( !sieve_validate(ast, ehandler, flags, errorp) ) { sieve_error(ehandler, sieve_script_name(script), "validation failed"); sieve_ast_unref(&ast); return NULL; } /* Generate */ if ( (sbin=sieve_generate(ast, ehandler, flags, errorp)) == NULL ) { sieve_error(ehandler, sieve_script_name(script), "code generation failed"); sieve_ast_unref(&ast); return NULL; } /* Cleanup */ sieve_ast_unref(&ast); return sbin; }
static gint sieve_auth(SieveSession *session) { SieveAuthType forced_auth_type = session->forced_auth_type; if (!session->use_auth) { session->state = SIEVE_READY; sieve_connected(session, TRUE); return SE_OK; } session->state = SIEVE_AUTH; sieve_error(session, _("Authenticating...")); if ((forced_auth_type == SIEVEAUTH_CRAM_MD5 || forced_auth_type == 0) && (session->avail_auth_type & SIEVEAUTH_CRAM_MD5) != 0) return sieve_auth_cram_md5(session); else if ((forced_auth_type == SIEVEAUTH_LOGIN || forced_auth_type == 0) && (session->avail_auth_type & SIEVEAUTH_LOGIN) != 0) return sieve_auth_login(session); else if ((forced_auth_type == SIEVEAUTH_PLAIN || forced_auth_type == 0) && (session->avail_auth_type & SIEVEAUTH_PLAIN) != 0) return sieve_auth_plain(session); else if (forced_auth_type == 0) { log_warning(LOG_PROTOCOL, _("No Sieve auth method available\n")); session->state = SIEVE_RETRY_AUTH; return SE_AUTHFAIL; } else { log_warning(LOG_PROTOCOL, _("Selected Sieve auth method not available\n")); session->state = SIEVE_RETRY_AUTH; return SE_AUTHFAIL; } return SE_OK; }
struct sieve_binary *sieve_open (struct sieve_instance *svinst, const char *script_location, const char *script_name, struct sieve_error_handler *ehandler, enum sieve_compile_flags flags, enum sieve_error *error_r) { struct sieve_script *script; struct sieve_binary *sbin; enum sieve_error error; /* First open the scriptfile itself */ if ( (script=sieve_script_create_open (svinst, script_location, script_name, &error)) == NULL ) { /* Failed */ if (error_r != NULL) *error_r = error; switch ( error ) { case SIEVE_ERROR_NOT_FOUND: sieve_error(ehandler, script_name, "script not found"); break; default: sieve_internal_error(ehandler, script_name, "failed to open script"); } return NULL; } sbin = sieve_open_script(script, ehandler, flags, error_r); /* Drop script reference, if sbin != NULL it holds a reference of its own. * Otherwise the script object is freed here. */ sieve_script_unref(&script); return sbin; }
struct sieve_binary *sieve_compile (struct sieve_instance *svinst, const char *script_location, const char *script_name, struct sieve_error_handler *ehandler, enum sieve_compile_flags flags, enum sieve_error *error_r) { struct sieve_script *script; struct sieve_binary *sbin; enum sieve_error error; if ( (script = sieve_script_create_open (svinst, script_location, script_name, &error)) == NULL ) { if (error_r != NULL) *error_r = error; switch ( error ) { case SIEVE_ERROR_NOT_FOUND: sieve_error(ehandler, script_name, "script not found"); break; default: sieve_internal_error(ehandler, script_name, "failed to open script"); } return NULL; } sbin = sieve_compile_script(script, ehandler, flags, error_r); if ( svinst->debug && sbin != NULL ) { sieve_sys_debug(svinst, "Script `%s' from %s successfully compiled", sieve_script_name(script), sieve_script_location(script)); } sieve_script_unref(&script); return sbin; }
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; }
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 */ } } }
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; }