/*! *\brief child and parent cleanup (child closes first) * *\param session Contains session information * *\return 0 : success */ static gint session_close(Session *session) { g_return_val_if_fail(session != NULL, -1); if (session->conn_id > 0) { sock_connect_async_cancel(session->conn_id); session->conn_id = 0; debug_print("session (%p): connection cancelled\n", session); } session_set_timeout(session, 0); if (session->io_tag > 0) { g_source_remove(session->io_tag); session->io_tag = 0; } if (session->sock) { sock_close(session->sock); session->sock = NULL; session->state = SESSION_DISCONNECTED; debug_print("session (%p): closed\n", session); } return 0; }
static gboolean session_write_data_cb(SockInfo *source, GIOCondition condition, gpointer data) { Session *session = SESSION(data); guint write_buf_len; 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); write_buf_len = session->write_buf_len; ret = session_write_buf(session); if (ret < 0) { session->state = SESSION_ERROR; return FALSE; } else if (ret > 0) { struct timeval tv_cur; gettimeofday(&tv_cur, NULL); if (tv_cur.tv_sec - session->tv_prev.tv_sec > 0 || tv_cur.tv_usec - session->tv_prev.tv_usec > UI_REFRESH_INTERVAL) { session_set_timeout(session, session->timeout_interval); session->send_data_progressive_notify (session, session->write_buf_p - session->write_buf, write_buf_len, session->send_data_progressive_notify_data); gettimeofday(&session->tv_prev, NULL); } return TRUE; } if (session->io_tag > 0) { g_source_remove(session->io_tag); session->io_tag = 0; } /* callback */ ret = session->send_data_finished(session, write_buf_len); session->send_data_notify(session, write_buf_len, session->send_data_notify_data); return FALSE; }
static gboolean session_read_data_cb(SockInfo *source, GIOCondition condition, gpointer data) { Session *session = SESSION(data); GByteArray *data_buf; gint terminator_len; gboolean complete = FALSE; guint data_len; gint ret; g_return_val_if_fail(condition == G_IO_IN, FALSE); session_set_timeout(session, session->timeout_interval); if (session->read_buf_len == 0) { gint read_len; read_len = sock_read(session->sock, session->read_buf, SESSION_BUFFSIZE); if (read_len == 0) { g_warning("sock_read: received EOF\n"); session->state = SESSION_EOF; return FALSE; } if (read_len < 0) { switch (errno) { case EAGAIN: return TRUE; default: g_warning("sock_read: %s\n", g_strerror(errno)); session->state = SESSION_ERROR; return FALSE; } } session->read_buf_len = read_len; } data_buf = session->read_data_buf; terminator_len = strlen(session->read_data_terminator); if (session->read_buf_len == 0) return TRUE; g_byte_array_append(data_buf, session->read_buf_p, session->read_buf_len); session->read_buf_len = 0; session->read_buf_p = session->read_buf; /* check if data is terminated */ if (data_buf->len >= terminator_len) { if (memcmp(data_buf->data, session->read_data_terminator, terminator_len) == 0) complete = TRUE; else if (data_buf->len >= terminator_len + 2 && memcmp(data_buf->data + data_buf->len - (terminator_len + 2), "\r\n", 2) == 0 && memcmp(data_buf->data + data_buf->len - terminator_len, session->read_data_terminator, terminator_len) == 0) complete = TRUE; } /* incomplete read */ if (!complete) { struct timeval tv_cur; gettimeofday(&tv_cur, NULL); if (tv_cur.tv_sec - session->tv_prev.tv_sec > 0 || tv_cur.tv_usec - session->tv_prev.tv_usec > UI_REFRESH_INTERVAL) { session->recv_data_progressive_notify (session, data_buf->len, 0, session->recv_data_progressive_notify_data); gettimeofday(&session->tv_prev, NULL); } return TRUE; } /* complete */ if (session->io_tag > 0) { g_source_remove(session->io_tag); session->io_tag = 0; } data_len = data_buf->len - terminator_len; /* callback */ ret = session->recv_data_finished(session, (gchar *)data_buf->data, data_len); g_byte_array_set_size(data_buf, 0); session->recv_data_notify(session, data_len, session->recv_data_notify_data); if (ret < 0) session->state = SESSION_ERROR; return FALSE; }
static gboolean session_read_msg_cb(SockInfo *source, GIOCondition condition, gpointer data) { Session *session = SESSION(data); gchar buf[SESSION_BUFFSIZE]; gint line_len; gchar *newline; gchar *msg; gint ret; g_return_val_if_fail(condition == G_IO_IN, FALSE); session_set_timeout(session, session->timeout_interval); if (session->read_buf_len == 0) { gint read_len; read_len = sock_read(session->sock, session->read_buf, SESSION_BUFFSIZE - 1); if (read_len == 0) { g_warning("sock_read: received EOF\n"); session->state = SESSION_EOF; return FALSE; } if (read_len < 0) { switch (errno) { case EAGAIN: return TRUE; default: g_warning("sock_read: %s\n", g_strerror(errno)); session->state = SESSION_ERROR; return FALSE; } } session->read_buf_len = read_len; } if ((newline = memchr(session->read_buf_p, '\n', session->read_buf_len)) != NULL) line_len = newline - session->read_buf_p + 1; else line_len = session->read_buf_len; if (line_len == 0) return TRUE; memcpy(buf, session->read_buf_p, line_len); buf[line_len] = '\0'; g_string_append(session->read_msg_buf, buf); session->read_buf_len -= line_len; if (session->read_buf_len == 0) session->read_buf_p = session->read_buf; else session->read_buf_p += line_len; /* incomplete read */ if (buf[line_len - 1] != '\n') return TRUE; /* complete */ if (session->io_tag > 0) { g_source_remove(session->io_tag); session->io_tag = 0; } /* callback */ msg = g_strdup(session->read_msg_buf->str); strretchomp(msg); g_string_truncate(session->read_msg_buf, 0); ret = session->recv_msg(session, msg); session->recv_msg_notify(session, msg, session->recv_msg_notify_data); g_free(msg); if (ret < 0) session->state = SESSION_ERROR; return FALSE; }
static gboolean sieve_read_chunk_cb(SockInfo *source, GIOCondition condition, gpointer data) { SieveSession *sieve_session = SIEVE_SESSION(data); Session *session = &sieve_session->session; gint data_len; gint ret; cm_return_val_if_fail(condition == G_IO_IN, FALSE); session_set_timeout(session, session->timeout_interval); if (session->read_buf_len == 0) { gint read_len = -1; if (session->sock) read_len = sock_read(session->sock, session->read_buf, SESSION_BUFFSIZE - 1); if (read_len == -1 && session->state == SESSION_DISCONNECTED) { g_warning ("sock_read: session disconnected"); if (session->io_tag > 0) { g_source_remove(session->io_tag); session->io_tag = 0; } return FALSE; } if (read_len == 0) { g_warning("sock_read: received EOF"); session->state = SESSION_EOF; return FALSE; } if (read_len < 0) { switch (errno) { case EAGAIN: return TRUE; default: g_warning("sock_read: %s", g_strerror(errno)); session->state = SESSION_ERROR; return FALSE; } } session->read_buf_len = read_len; } data_len = MIN(session->read_buf_len, sieve_session->octets_remaining); sieve_session->octets_remaining -= data_len; session->read_buf_len -= data_len; session->read_buf_p[data_len] = '\0'; /* progress callback */ sieve_read_chunk(sieve_session, session->read_buf_p, data_len); if (session->read_buf_len == 0) { session->read_buf_p = session->read_buf; } else { session->read_buf_p += data_len; } /* incomplete read */ if (sieve_session->octets_remaining > 0) return TRUE; /* complete */ if (session->io_tag > 0) { g_source_remove(session->io_tag); session->io_tag = 0; } /* completion callback */ ret = sieve_read_chunk_done(sieve_session); if (ret < 0) session->state = SESSION_ERROR; return FALSE; }
static IncState inc_pop3_session_do(IncSession *session) { Pop3Session *pop3_session = POP3_SESSION(session->session); IncProgressDialog *inc_dialog = (IncProgressDialog *)session->data; gchar *server; gchar *account_name; gushort port; gchar *buf; debug_print("getting new messages of account %s...\n", pop3_session->ac_prefs->account_name); pop3_session->ac_prefs->last_pop_login_time = time(NULL); buf = g_strdup_printf(_("%s: Retrieving new messages"), pop3_session->ac_prefs->recv_server); gtk_window_set_title(GTK_WINDOW(inc_dialog->dialog->window), buf); g_free(buf); server = pop3_session->ac_prefs->recv_server; account_name = pop3_session->ac_prefs->account_name; #ifdef USE_GNUTLS port = pop3_session->ac_prefs->set_popport ? pop3_session->ac_prefs->popport : pop3_session->ac_prefs->ssl_pop == SSL_TUNNEL ? 995 : 110; SESSION(pop3_session)->ssl_type = pop3_session->ac_prefs->ssl_pop; if (pop3_session->ac_prefs->ssl_pop != SSL_NONE) SESSION(pop3_session)->nonblocking = pop3_session->ac_prefs->use_nonblocking_ssl; #else if (pop3_session->ac_prefs->ssl_pop != SSL_NONE) { if (alertpanel_full(_("Insecure connection"), _("This connection is configured to be secured " "using SSL, but SSL is not available in this " "build of Claws Mail. \n\n" "Do you want to continue connecting to this " "server? The communication would not be " "secure."), GTK_STOCK_CANCEL, _("Con_tinue connecting"), NULL, FALSE, NULL, ALERT_WARNING, G_ALERTDEFAULT) != G_ALERTALTERNATE) return INC_CANCEL; } port = pop3_session->ac_prefs->set_popport ? pop3_session->ac_prefs->popport : 110; #endif buf = g_strdup_printf(_("Account '%s': Connecting to POP3 server: %s:%d..."), account_name, server, port); statuswindow_print_all("%s", buf); log_message(LOG_PROTOCOL, "%s\n", buf); progress_dialog_set_label(inc_dialog->dialog, buf); GTK_EVENTS_FLUSH(); g_free(buf); session_set_timeout(SESSION(pop3_session), prefs_common.io_timeout_secs * 1000); if (session_connect(SESSION(pop3_session), server, port) < 0) { if(!prefs_common.no_recv_err_panel) { if((prefs_common.recv_dialog_mode == RECV_DIALOG_ALWAYS) || ((prefs_common.recv_dialog_mode == RECV_DIALOG_MANUAL) && focus_window)) { manage_window_focus_in(inc_dialog->dialog->window, NULL, NULL); } alertpanel_error(_("Can't connect to POP3 server: %s:%d"), server, port); manage_window_focus_out(inc_dialog->dialog->window, NULL, NULL); } else { log_error(LOG_PROTOCOL, _("Can't connect to POP3 server: %s:%d\n"), server, port); } session->inc_state = INC_CONNECT_ERROR; statuswindow_pop_all(); return INC_CONNECT_ERROR; } while (session_is_running(SESSION(pop3_session)) && session->inc_state != INC_CANCEL) gtk_main_iteration(); if (session->inc_state == INC_SUCCESS) { switch (pop3_session->error_val) { case PS_SUCCESS: switch (SESSION(pop3_session)->state) { case SESSION_ERROR: if (pop3_session->state == POP3_READY) session->inc_state = INC_CONNECT_ERROR; else session->inc_state = INC_ERROR; break; case SESSION_EOF: session->inc_state = INC_EOF; break; case SESSION_TIMEOUT: session->inc_state = INC_TIMEOUT; break; default: session->inc_state = INC_SUCCESS; break; } break; case PS_AUTHFAIL: session->inc_state = INC_AUTH_FAILED; break; case PS_IOERR: session->inc_state = INC_IO_ERROR; break; case PS_SOCKET: session->inc_state = INC_SOCKET_ERROR; break; case PS_LOCKBUSY: session->inc_state = INC_LOCKED; break; default: session->inc_state = INC_ERROR; break; } } session_disconnect(SESSION(pop3_session)); statusbar_pop_all(); return session->inc_state; }
gint send_message_smtp_full(PrefsAccount *ac_prefs, GSList *to_list, FILE *fp, gboolean keep_session) { Session *session; SMTPSession *smtp_session; gushort port = 0; gchar buf[BUFFSIZE]; gint ret = 0; gboolean was_inited = FALSE; MsgInfo *tmp_msginfo = NULL; MsgFlags flags = {0, 0}; long fp_pos = 0; gchar spec_from[BUFFSIZE]; ProxyInfo *proxy_info = NULL; cm_return_val_if_fail(ac_prefs != NULL, -1); cm_return_val_if_fail(ac_prefs->address != NULL, -1); cm_return_val_if_fail(ac_prefs->smtp_server != NULL, -1); cm_return_val_if_fail(to_list != NULL, -1); cm_return_val_if_fail(fp != NULL, -1); /* get the From address used, not necessarily the ac_prefs', * because it's editable. */ fp_pos = ftell(fp); if (fp_pos < 0) { perror("ftell"); return -1; } tmp_msginfo = procheader_parse_stream(fp, flags, TRUE, FALSE); if (fseek(fp, fp_pos, SEEK_SET) < 0) { perror("fseek"); return -1; } if (tmp_msginfo && tmp_msginfo->extradata && tmp_msginfo->extradata->resent_from) { strncpy2(spec_from, tmp_msginfo->extradata->resent_from, BUFFSIZE-1); extract_address(spec_from); } else if (tmp_msginfo && tmp_msginfo->from) { strncpy2(spec_from, tmp_msginfo->from, BUFFSIZE-1); extract_address(spec_from); } else { strncpy2(spec_from, ac_prefs->address, BUFFSIZE-1); } if (tmp_msginfo) { procmsg_msginfo_free(&tmp_msginfo); } if (!ac_prefs->session) { /* we can't reuse a previously initialised session */ session = smtp_session_new(ac_prefs); session->ssl_cert_auto_accept = ac_prefs->ssl_certs_auto_accept; smtp_session = SMTP_SESSION(session); if (ac_prefs->set_domain && ac_prefs->domain && strlen(ac_prefs->domain)) { smtp_session->hostname = g_strdup(ac_prefs->domain); } else { smtp_session->hostname = NULL; } #ifdef USE_GNUTLS port = ac_prefs->set_smtpport ? ac_prefs->smtpport : ac_prefs->ssl_smtp == SSL_TUNNEL ? SSMTP_PORT : SMTP_PORT; session->ssl_type = ac_prefs->ssl_smtp; if (ac_prefs->ssl_smtp != SSL_NONE) session->nonblocking = ac_prefs->use_nonblocking_ssl; if (ac_prefs->set_gnutls_priority && ac_prefs->gnutls_priority && strlen(ac_prefs->gnutls_priority)) session->gnutls_priority = g_strdup(ac_prefs->gnutls_priority); session->use_tls_sni = ac_prefs->use_tls_sni; #else if (ac_prefs->ssl_smtp != SSL_NONE) { if (alertpanel_full(_("Insecure connection"), _("This connection is configured to be secured " "using SSL/TLS, but SSL/TLS is not available " "in this build of Claws Mail. \n\n" "Do you want to continue connecting to this " "server? The communication would not be " "secure."), GTK_STOCK_CANCEL, _("Con_tinue connecting"), NULL, ALERTFOCUS_FIRST, FALSE, NULL, ALERT_WARNING) != G_ALERTALTERNATE) { session_destroy(session); return -1; } } port = ac_prefs->set_smtpport ? ac_prefs->smtpport : SMTP_PORT; #endif if (ac_prefs->use_smtp_auth) { smtp_session->forced_auth_type = ac_prefs->smtp_auth_type; if (ac_prefs->smtp_userid && strlen(ac_prefs->smtp_userid)) { smtp_session->user = g_strdup(ac_prefs->smtp_userid); if (password_get(smtp_session->user, ac_prefs->smtp_server, "smtp", port, &(smtp_session->pass))) { /* NOP */; } else if ((smtp_session->pass = passwd_store_get_account(ac_prefs->account_id, PWS_ACCOUNT_SEND)) == NULL) { smtp_session->pass = input_dialog_query_password_keep (ac_prefs->smtp_server, smtp_session->user, &(ac_prefs->session_smtp_passwd)); if (!smtp_session->pass) { session_destroy(session); return -1; } } } else { smtp_session->user = g_strdup(ac_prefs->userid); if (password_get(smtp_session->user, ac_prefs->smtp_server, "smtp", port, &(smtp_session->pass))) { /* NOP */; } else if ((smtp_session->pass = passwd_store_get_account( ac_prefs->account_id, PWS_ACCOUNT_RECV)) == NULL) { smtp_session->pass = input_dialog_query_password_keep (ac_prefs->smtp_server, smtp_session->user, &(ac_prefs->session_smtp_passwd)); if (!smtp_session->pass) { session_destroy(session); return -1; } } } } else { smtp_session->user = NULL; smtp_session->pass = NULL; } send_dialog = send_progress_dialog_create(); send_dialog->session = session; smtp_session->dialog = send_dialog; progress_dialog_list_set(send_dialog->dialog, 0, NULL, ac_prefs->smtp_server, _("Connecting")); if (ac_prefs->pop_before_smtp && (ac_prefs->protocol == A_POP3) && (time(NULL) - ac_prefs->last_pop_login_time) > (60 * ac_prefs->pop_before_smtp_timeout)) { g_snprintf(buf, sizeof(buf), _("Doing POP before SMTP...")); log_message(LOG_PROTOCOL, "%s\n", buf); progress_dialog_set_label(send_dialog->dialog, buf); progress_dialog_list_set_status(send_dialog->dialog, 0, _("POP before SMTP")); GTK_EVENTS_FLUSH(); inc_pop_before_smtp(ac_prefs); } g_snprintf(buf, sizeof(buf), _("Account '%s': Connecting to SMTP server: %s:%d..."), ac_prefs->account_name, ac_prefs->smtp_server, port); progress_dialog_set_label(send_dialog->dialog, buf); log_message(LOG_PROTOCOL, "%s\n", buf); session_set_recv_message_notify(session, send_recv_message, send_dialog); session_set_send_data_progressive_notify (session, send_send_data_progressive, send_dialog); session_set_send_data_notify(session, send_send_data_finished, send_dialog); } else { /* everything is ready to start at MAIL FROM:, just * reinit useful variables. */ session = SESSION(ac_prefs->session); ac_prefs->session = NULL; smtp_session = SMTP_SESSION(session); smtp_session->state = SMTP_HELO; send_dialog = (SendProgressDialog *)smtp_session->dialog; was_inited = TRUE; } /* This has to be initialised for every mail sent */ smtp_session->from = g_strdup(spec_from); smtp_session->to_list = to_list; smtp_session->cur_to = to_list; smtp_session->send_data = (guchar *)get_outgoing_rfc2822_str(fp); smtp_session->send_data_len = strlen((gchar *)smtp_session->send_data); if (ac_prefs->use_proxy && ac_prefs->use_proxy_for_send) { if (ac_prefs->use_default_proxy) { proxy_info = (ProxyInfo *)&(prefs_common.proxy_info); if (proxy_info->use_proxy_auth) proxy_info->proxy_pass = passwd_store_get(PWS_CORE, PWS_CORE_PROXY, PWS_CORE_PROXY_PASS); } else { proxy_info = (ProxyInfo *)&(ac_prefs->proxy_info); if (proxy_info->use_proxy_auth) proxy_info->proxy_pass = passwd_store_get_account(ac_prefs->account_id, PWS_ACCOUNT_PROXY_PASS); } } SESSION(smtp_session)->proxy_info = proxy_info; session_set_timeout(session, prefs_common.io_timeout_secs * 1000); /* connect if necessary */ if (!was_inited && session_connect(session, ac_prefs->smtp_server, port) < 0) { session_destroy(session); send_progress_dialog_destroy(send_dialog); ac_prefs->session = NULL; return -1; } debug_print("send_message_smtp(): begin event loop\n"); if (was_inited) { /* as the server is quiet, start sending ourselves */ smtp_from(smtp_session); } while (session_is_running(session) && send_dialog->cancelled == FALSE && SMTP_SESSION(session)->state != SMTP_MAIL_SENT_OK) gtk_main_iteration(); if (SMTP_SESSION(session)->error_val == SM_AUTHFAIL) { if (ac_prefs->session_smtp_passwd) { g_free(ac_prefs->session_smtp_passwd); ac_prefs->session_smtp_passwd = NULL; } ret = -1; } else if (SMTP_SESSION(session)->state == SMTP_MAIL_SENT_OK) { log_message(LOG_PROTOCOL, "%s\n", _("Mail sent successfully.")); ret = 0; } else if (session->state == SESSION_EOF && SMTP_SESSION(session)->state == SMTP_QUIT) { /* consider EOF right after QUIT successful */ log_warning(LOG_PROTOCOL, "%s\n", _("Connection closed by the remote host.")); ret = 0; } else if (session->state == SESSION_ERROR || session->state == SESSION_EOF || session->state == SESSION_TIMEOUT || SMTP_SESSION(session)->state == SMTP_ERROR || SMTP_SESSION(session)->error_val != SM_OK) ret = -1; else if (send_dialog->cancelled == TRUE) ret = -1; if (ret == -1) { manage_window_focus_in(send_dialog->dialog->window, NULL, NULL); send_put_error(session); manage_window_focus_out(send_dialog->dialog->window, NULL, NULL); } /* if we should close the connection, let's do it. * Close it in case of error, too, as it helps reinitializing things * easier. */ if (!keep_session || ret != 0) { if (session_is_connected(session)) smtp_quit(smtp_session); while (session_is_connected(session) && !send_dialog->cancelled) gtk_main_iteration(); session_destroy(session); ac_prefs->session = NULL; send_progress_dialog_destroy(send_dialog); } else { g_free(smtp_session->from); g_free(smtp_session->send_data); g_free(smtp_session->error_msg); } if (keep_session && ret == 0 && ac_prefs->session == NULL) ac_prefs->session = SMTP_SESSION(session); statusbar_pop_all(); statusbar_verbosity_set(FALSE); return ret; }