/* Well, since Solaris is a tad broken wrt its 'mbox' folder format,
 * we must convert it to a real mbox format.  Thankfully this is
 * mostly pretty easy */
static gint
camel_movemail_solaris (gint oldsfd,
                        gint dfd,
                        GError **error)
{
    CamelMimeParser *mp;
    gchar *buffer;
    gint len;
    gint sfd;
    CamelMimeFilter *ffrom;
    gint ret = 1;
    gchar *from = NULL;

    /* need to dup as the mime parser will close on finish */
    sfd = dup (oldsfd);
    if (sfd == -1) {
        g_set_error (
            error, G_IO_ERROR,
            g_io_error_from_errno (errno),
            _("Error copying mail temp file: %s"),
            g_strerror (errno));
        return -1;
    }

    mp = camel_mime_parser_new ();
    camel_mime_parser_scan_from (mp, TRUE);
    camel_mime_parser_init_with_fd (mp, sfd);

    ffrom = camel_mime_filter_from_new ();

    while (camel_mime_parser_step (mp, &buffer, &len) == CAMEL_MIME_PARSER_STATE_FROM) {
        g_return_val_if_fail (camel_mime_parser_from_line (mp), -1);
        from = g_strdup (camel_mime_parser_from_line (mp));
        if (camel_mime_parser_step (mp, &buffer, &len) != CAMEL_MIME_PARSER_STATE_FROM_END) {
            CamelNameValueArray *headers;
            const gchar *cl;
            gint length;
            gint start, body;
            goffset newpos;

            ret = 0;

            start = camel_mime_parser_tell_start_from (mp);
            body = camel_mime_parser_tell (mp);

            if (write (dfd, from, strlen (from)) != strlen (from))
                goto fail;

            /* write out headers, but NOT content-length header */
            headers = camel_mime_parser_dup_headers (mp);
            if (solaris_header_write (dfd, headers) == -1) {
                camel_name_value_array_free (headers);
                goto fail;
            }

            camel_name_value_array_free (headers);
            cl = camel_mime_parser_header (mp, "content-length", NULL);
            if (cl == NULL) {
                g_warning ("Required Content-Length header is missing from solaris mail box @ %d", (gint) camel_mime_parser_tell (mp));
                camel_mime_parser_drop_step (mp);
                camel_mime_parser_drop_step (mp);
                camel_mime_parser_step (mp, &buffer, &len);
                camel_mime_parser_unstep (mp);
                length = camel_mime_parser_tell_start_from (mp) - body;
                newpos = -1;
            } else {
                length = atoi (cl);
                camel_mime_parser_drop_step (mp);
                camel_mime_parser_drop_step (mp);
                newpos = length + body;
            }
            /* copy body->length converting From lines */
            if (camel_movemail_copy_filter (sfd, dfd, body, length, ffrom) == -1)
                goto fail;
            if (newpos != -1)
                camel_mime_parser_seek (mp, newpos, SEEK_SET);
        } else {
            g_error ("Inalid parser state: %d", camel_mime_parser_state (mp));
        }
        g_free (from);
    }

    g_object_unref (mp);
    g_object_unref (ffrom);

    return ret;

fail:
    g_free (from);

    g_set_error (
        error, G_IO_ERROR,
        g_io_error_from_errno (errno),
        _("Error copying mail temp file: %s"),
        g_strerror (errno));

    g_object_unref (mp);
    g_object_unref (ffrom);

    return -1;
}
Exemple #2
0
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;
}