/* write the headers back out again, but not he Content-Length header, because we dont * want to maintain it! */ static gint solaris_header_write (gint fd, CamelNameValueArray *headers) { struct iovec iv[4]; gint outlen = 0, len; guint ii; const gchar *header_name = NULL, *header_value = NULL; iv[1].iov_base = ":"; iv[1].iov_len = 1; iv[3].iov_base = "\n"; iv[3].iov_len = 1; for (ii = 0; camel_name_value_array_get (headers, ii, &header_name, &header_value); ii++) { if (g_ascii_strcasecmp (header_name, "Content-Length")) { iv[0].iov_base = header_name; iv[0].iov_len = strlen (header_name); iv[2].iov_base = header_value; iv[2].iov_len = strlen (header_value); do { len = writev (fd, iv, 4); } while (len == -1 && errno == EINTR); if (len == -1) return -1; outlen += len; } } do { len = write (fd, "\n", 1); } while (len == -1 && errno == EINTR); if (len == -1) return -1; outlen += 1; d (printf ("Wrote %d bytes of headers\n", outlen)); return outlen; }
static gboolean sendmail_send_to_sync (CamelTransport *transport, CamelMimeMessage *message, CamelAddress *from, CamelAddress *recipients, gboolean *out_sent_message_saved, GCancellable *cancellable, GError **error) { CamelNameValueArray *previous_headers = NULL; const gchar *header_name = NULL, *header_value = NULL; const gchar *from_addr, *addr; GPtrArray *argv_arr; gint i, len, fd[2], nullfd, wstat; CamelStream *filter; CamelMimeFilter *crlf; sigset_t mask, omask; CamelStream *out; CamelSendmailSettings *settings; const gchar *binary = SENDMAIL_PATH; gchar *custom_binary = NULL, *custom_args = NULL; gboolean success; pid_t pid; guint ii; success = camel_internet_address_get ( CAMEL_INTERNET_ADDRESS (from), 0, NULL, &from_addr); if (!success) { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Failed to read From address")); return FALSE; } settings = CAMEL_SENDMAIL_SETTINGS (camel_service_ref_settings (CAMEL_SERVICE (transport))); if (!camel_sendmail_settings_get_send_in_offline (settings)) { CamelSession *session; gboolean is_online; session = camel_service_ref_session (CAMEL_SERVICE (transport)); is_online = session && camel_session_get_online (session); g_clear_object (&session); if (!is_online) { g_set_error ( error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE, _("Message send in offline mode is disabled")); return FALSE; } } if (camel_sendmail_settings_get_use_custom_binary (settings)) { custom_binary = camel_sendmail_settings_dup_custom_binary (settings); if (custom_binary && *custom_binary) binary = custom_binary; } if (camel_sendmail_settings_get_use_custom_args (settings)) { custom_args = camel_sendmail_settings_dup_custom_args (settings); /* means no arguments used */ if (!custom_args) custom_args = g_strdup (""); } g_object_unref (settings); len = camel_address_length (recipients); for (i = 0; i < len; i++) { success = camel_internet_address_get ( CAMEL_INTERNET_ADDRESS (recipients), i, NULL, &addr); if (!success) { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Could not parse recipient list")); g_free (custom_binary); g_free (custom_args); return FALSE; } } argv_arr = parse_sendmail_args ( binary, custom_args ? custom_args : "-i -f %F -- %R", from_addr, recipients); if (!argv_arr) { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Could not parse arguments")); g_free (custom_binary); g_free (custom_args); return FALSE; } /* unlink the bcc headers */ previous_headers = camel_medium_dup_headers (CAMEL_MEDIUM (message)); camel_medium_remove_header (CAMEL_MEDIUM (message), "Bcc"); if (pipe (fd) == -1) { g_set_error ( error, G_IO_ERROR, g_io_error_from_errno (errno), _("Could not create pipe to “%s”: %s: " "mail not sent"), binary, g_strerror (errno)); /* restore the bcc headers */ for (ii = 0; camel_name_value_array_get (previous_headers, ii, &header_name, &header_value); ii++) { if (!g_ascii_strcasecmp (header_name, "Bcc")) { camel_medium_add_header (CAMEL_MEDIUM (message), header_name, header_value); } } camel_name_value_array_free (previous_headers); g_free (custom_binary); g_free (custom_args); g_ptr_array_free (argv_arr, TRUE); return FALSE; } /* Block SIGCHLD so the calling application doesn't notice * sendmail exiting before we do. */ sigemptyset (&mask); sigaddset (&mask, SIGCHLD); sigprocmask (SIG_BLOCK, &mask, &omask); pid = fork (); switch (pid) { case -1: g_set_error ( error, G_IO_ERROR, g_io_error_from_errno (errno), _("Could not fork “%s”: %s: " "mail not sent"), binary, g_strerror (errno)); close (fd[0]); close (fd[1]); sigprocmask (SIG_SETMASK, &omask, NULL); /* restore the bcc headers */ for (ii = 0; camel_name_value_array_get (previous_headers, ii, &header_name, &header_value); ii++) { if (!g_ascii_strcasecmp (header_name, "Bcc")) { camel_medium_add_header (CAMEL_MEDIUM (message), header_name, header_value); } } camel_name_value_array_free (previous_headers); g_free (custom_binary); g_free (custom_args); g_ptr_array_free (argv_arr, TRUE); return FALSE; case 0: /* Child process */ nullfd = open ("/dev/null", O_RDWR); dup2 (fd[0], STDIN_FILENO); if (nullfd != -1) { /*dup2 (nullfd, STDOUT_FILENO); dup2 (nullfd, STDERR_FILENO);*/ close (nullfd); } close (fd[1]); execv (binary, (gchar **) argv_arr->pdata); _exit (255); } g_ptr_array_free (argv_arr, TRUE); /* Parent process. Write the message out. */ close (fd[0]); out = camel_stream_fs_new_with_fd (fd[1]); /* XXX Workaround for lame sendmail implementations * that can't handle CRLF eoln sequences. */ filter = camel_stream_filter_new (out); crlf = camel_mime_filter_crlf_new ( CAMEL_MIME_FILTER_CRLF_DECODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY); camel_stream_filter_add (CAMEL_STREAM_FILTER (filter), crlf); g_object_unref (crlf); g_object_unref (out); out = (CamelStream *) filter; if (camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (message), out, cancellable, error) == -1 || camel_stream_close (out, cancellable, error) == -1) { g_object_unref (out); g_prefix_error (error, _("Could not send message: ")); /* Wait for sendmail to exit. */ while (waitpid (pid, &wstat, 0) == -1 && errno == EINTR) ; sigprocmask (SIG_SETMASK, &omask, NULL); /* restore the bcc headers */ for (ii = 0; camel_name_value_array_get (previous_headers, ii, &header_name, &header_value); ii++) { if (!g_ascii_strcasecmp (header_name, "Bcc")) { camel_medium_add_header (CAMEL_MEDIUM (message), header_name, header_value); } } camel_name_value_array_free (previous_headers); g_free (custom_binary); g_free (custom_args); return FALSE; } g_object_unref (out); /* Wait for sendmail to exit. */ while (waitpid (pid, &wstat, 0) == -1 && errno == EINTR) ; sigprocmask (SIG_SETMASK, &omask, NULL); /* restore the bcc headers */ for (ii = 0; camel_name_value_array_get (previous_headers, ii, &header_name, &header_value); ii++) { if (!g_ascii_strcasecmp (header_name, "Bcc")) { camel_medium_add_header (CAMEL_MEDIUM (message), header_name, header_value); } } camel_name_value_array_free (previous_headers); if (!WIFEXITED (wstat)) { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("“%s” exited with signal %s: mail not sent."), binary, g_strsignal (WTERMSIG (wstat))); g_free (custom_binary); g_free (custom_args); return FALSE; } else if (WEXITSTATUS (wstat) != 0) { if (WEXITSTATUS (wstat) == 255) { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Could not execute “%s”: mail not sent."), binary); } else { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("“%s” exited with status %d: " "mail not sent."), binary, WEXITSTATUS (wstat)); } g_free (custom_binary); g_free (custom_args); return FALSE; } g_free (custom_binary); g_free (custom_args); return TRUE; }