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; }
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 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; }
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; }