Bug #549819 - Cannot specify a custom sendmail program
authorMilan Crha <mcrha@redhat.com>
Mon, 17 Sep 2012 16:35:10 +0000 (18:35 +0200)
committerMilan Crha <mcrha@redhat.com>
Mon, 17 Sep 2012 16:35:10 +0000 (18:35 +0200)
camel/providers/sendmail/Makefile.am
camel/providers/sendmail/camel-sendmail-provider.c
camel/providers/sendmail/camel-sendmail-settings.c [new file with mode: 0644]
camel/providers/sendmail/camel-sendmail-settings.h [new file with mode: 0644]
camel/providers/sendmail/camel-sendmail-transport.c

index 8466eb0..b656a56 100644 (file)
@@ -15,6 +15,8 @@ libcamelsendmail_la_CPPFLAGS = \
        $(NULL)
 
 libcamelsendmail_la_SOURCES =                  \
+       camel-sendmail-settings.h               \
+       camel-sendmail-settings.c               \
        camel-sendmail-provider.c               \
        camel-sendmail-transport.c
 
index f5a82f3..d913b85 100644 (file)
@@ -44,6 +44,8 @@ static CamelProvider sendmail_provider = {
 
        0, /* url_flags */
 
+       NULL,  /* conf entries */
+
        NULL,  /* port entries */
 
        /* ... */
diff --git a/camel/providers/sendmail/camel-sendmail-settings.c b/camel/providers/sendmail/camel-sendmail-settings.c
new file mode 100644 (file)
index 0000000..2389f3b
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * camel-sendmail-settings.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "camel-sendmail-settings.h"
+
+#define CAMEL_SENDMAIL_SETTINGS_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), CAMEL_TYPE_SENDMAIL_SETTINGS, CamelSendmailSettingsPrivate))
+
+struct _CamelSendmailSettingsPrivate {
+       GMutex *property_lock;
+       gchar *custom_binary;
+
+       gboolean use_custom_binary;
+};
+
+enum {
+       PROP_0,
+       PROP_USE_CUSTOM_BINARY,
+       PROP_CUSTOM_BINARY
+};
+
+G_DEFINE_TYPE (CamelSendmailSettings, camel_sendmail_settings, CAMEL_TYPE_SETTINGS)
+
+static void
+sendmail_settings_set_property (GObject *object,
+                               guint property_id,
+                               const GValue *value,
+                               GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_USE_CUSTOM_BINARY:
+                       camel_sendmail_settings_set_use_custom_binary (
+                               CAMEL_SENDMAIL_SETTINGS (object),
+                               g_value_get_boolean (value));
+                       return;
+
+               case PROP_CUSTOM_BINARY:
+                       camel_sendmail_settings_set_custom_binary (
+                               CAMEL_SENDMAIL_SETTINGS (object),
+                               g_value_get_string (value));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+sendmail_settings_get_property (GObject *object,
+                               guint property_id,
+                               GValue *value,
+                               GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_USE_CUSTOM_BINARY:
+                       g_value_set_boolean (
+                               value,
+                               camel_sendmail_settings_get_use_custom_binary (
+                               CAMEL_SENDMAIL_SETTINGS (object)));
+                       return;
+
+               case PROP_CUSTOM_BINARY:
+                       g_value_take_string (
+                               value,
+                               camel_sendmail_settings_dup_custom_binary (
+                               CAMEL_SENDMAIL_SETTINGS (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+sendmail_settings_finalize (GObject *object)
+{
+       CamelSendmailSettingsPrivate *priv;
+
+       priv = CAMEL_SENDMAIL_SETTINGS_GET_PRIVATE (object);
+
+       g_mutex_free (priv->property_lock);
+
+       g_free (priv->custom_binary);
+
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (camel_sendmail_settings_parent_class)->finalize (object);
+}
+
+static void
+camel_sendmail_settings_class_init (CamelSendmailSettingsClass *class)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (CamelSendmailSettingsPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->set_property = sendmail_settings_set_property;
+       object_class->get_property = sendmail_settings_get_property;
+       object_class->finalize = sendmail_settings_finalize;
+
+       g_object_class_install_property (
+               object_class,
+               PROP_USE_CUSTOM_BINARY,
+               g_param_spec_boolean (
+                       "use-custom-binary",
+                       "Use Custom Binary",
+                       "Whether the custom-binary property identifies binary to run",
+                       FALSE,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_CUSTOM_BINARY,
+               g_param_spec_string (
+                       "custom-binary",
+                       "Custom Binary",
+                       "Custom binary to run, instead of sendmail",
+                       NULL,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_STATIC_STRINGS));
+}
+
+static void
+camel_sendmail_settings_init (CamelSendmailSettings *settings)
+{
+       settings->priv = CAMEL_SENDMAIL_SETTINGS_GET_PRIVATE (settings);
+       settings->priv->property_lock = g_mutex_new ();
+}
+
+/**
+ * camel_sendmail_settings_get_use_custom_binary:
+ * @settings: a #CamelSendmailSettings
+ *
+ * Returns whether the 'custom-binary' property should be used as binary to run, instead of sendmail.
+ *
+ * Returns: whether the 'custom-binary' property should be used as binary to run, instead of sendmail
+ *
+ * Since: 3.8
+ **/
+gboolean
+camel_sendmail_settings_get_use_custom_binary (CamelSendmailSettings *settings)
+{
+       g_return_val_if_fail (CAMEL_IS_SENDMAIL_SETTINGS (settings), FALSE);
+
+       return settings->priv->use_custom_binary;
+}
+
+/**
+ * camel_sendmail_settings_set_use_custom_binary:
+ * @settings: a #CamelSendmailSettings
+ * @use_custom_binary: whether to use custom binary
+ *
+ * Sets whether to use custom binary, instead of sendmail.
+ *
+ * Since: 3.8
+ **/
+void
+camel_sendmail_settings_set_use_custom_binary (CamelSendmailSettings *settings,
+                                              gboolean use_custom_binary)
+{
+       g_return_if_fail (CAMEL_IS_SENDMAIL_SETTINGS (settings));
+
+       if ((settings->priv->use_custom_binary ? 1 : 0) == (use_custom_binary ? 1 : 0))
+               return;
+
+       settings->priv->use_custom_binary = use_custom_binary;
+
+       g_object_notify (G_OBJECT (settings), "use-custom-binary");
+}
+
+/**
+ * camel_sendmail_settings_get_custom_binary:
+ * @settings: a #CamelSendmailSettings
+ *
+ * Returns the custom binary to run, instead of sendmail.
+ *
+ * Returns: the custom binary to run, instead of sendmail, or %NULL
+ *
+ * Since: 3.8
+ **/
+const gchar *
+camel_sendmail_settings_get_custom_binary (CamelSendmailSettings *settings)
+{
+       g_return_val_if_fail (CAMEL_IS_SENDMAIL_SETTINGS (settings), NULL);
+
+       return settings->priv->custom_binary;
+}
+
+/**
+ * camel_sendmail_settings_dup_custom_binary:
+ * @settings: a #CamelSendmailSettings
+ *
+ * Thread-safe variation of camel_sendmail_settings_get_custom_binary().
+ * Use this function when accessing @settings from multiple threads.
+ *
+ * The returned string should be freed with g_free() when no longer needed.
+ *
+ * Returns: a newly-allocated copy of #CamelSendmailSettings:custom-binary
+ *
+ * Since: 3.8
+ **/
+gchar *
+camel_sendmail_settings_dup_custom_binary (CamelSendmailSettings *settings)
+{
+       const gchar *protected;
+       gchar *duplicate;
+
+       g_return_val_if_fail (CAMEL_IS_SENDMAIL_SETTINGS (settings), NULL);
+
+       g_mutex_lock (settings->priv->property_lock);
+
+       protected = camel_sendmail_settings_get_custom_binary (settings);
+       duplicate = g_strdup (protected);
+
+       g_mutex_unlock (settings->priv->property_lock);
+
+       return duplicate;
+}
+
+/**
+ * camel_sendmail_settings_set_custom_binary:
+ * @settings: a #CamelSendmailSettings
+ * @custom_binary: a custom binary name, or %NULL
+ *
+ * Sets the custom binary name to run, instead of sendmail.
+ *
+ * Since: 3.8
+ **/
+void
+camel_sendmail_settings_set_custom_binary (CamelSendmailSettings *settings,
+                                          const gchar *custom_binary)
+{
+       g_return_if_fail (CAMEL_IS_SENDMAIL_SETTINGS (settings));
+
+       /* The default namespace is an empty string. */
+       if (custom_binary && !*custom_binary)
+               custom_binary = NULL;
+
+       g_mutex_lock (settings->priv->property_lock);
+
+       if (g_strcmp0 (settings->priv->custom_binary, custom_binary) == 0) {
+               g_mutex_unlock (settings->priv->property_lock);
+               return;
+       }
+
+       g_free (settings->priv->custom_binary);
+       settings->priv->custom_binary = g_strdup (custom_binary);
+
+       g_mutex_unlock (settings->priv->property_lock);
+
+       g_object_notify (G_OBJECT (settings), "custom-binary");
+}
diff --git a/camel/providers/sendmail/camel-sendmail-settings.h b/camel/providers/sendmail/camel-sendmail-settings.h
new file mode 100644 (file)
index 0000000..a85ec82
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * camel-sendmail-settings.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef CAMEL_SENDMAIL_SETTINGS_H
+#define CAMEL_SENDMAIL_SETTINGS_H
+
+#include <camel/camel.h>
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_SENDMAIL_SETTINGS \
+       (camel_sendmail_settings_get_type ())
+#define CAMEL_SENDMAIL_SETTINGS(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), CAMEL_TYPE_SENDMAIL_SETTINGS, CamelSendmailSettings))
+#define CAMEL_SENDMAIL_SETTINGS_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), CAMEL_TYPE_SENDMAIL_SETTINGS, CamelSendmailSettingsClass))
+#define CAMEL_IS_SENDMAIL_SETTINGS(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), CAMEL_TYPE_SENDMAIL_SETTINGS))
+#define CAMEL_IS_SENDMAIL_SETTINGS_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), CAMEL_TYPE_SENDMAIL_SETTINGS))
+#define CAMEL_SENDMAIL_SETTINGS_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), CAMEL_TYPE_SENDMAIL_SETTINGS))
+
+G_BEGIN_DECLS
+
+typedef struct _CamelSendmailSettings CamelSendmailSettings;
+typedef struct _CamelSendmailSettingsClass CamelSendmailSettingsClass;
+typedef struct _CamelSendmailSettingsPrivate CamelSendmailSettingsPrivate;
+
+struct _CamelSendmailSettings {
+       CamelSettings parent;
+       CamelSendmailSettingsPrivate *priv;
+};
+
+struct _CamelSendmailSettingsClass {
+       CamelSettingsClass parent_class;
+};
+
+GType          camel_sendmail_settings_get_type        (void);
+gboolean       camel_sendmail_settings_get_use_custom_binary   (CamelSendmailSettings *settings);
+void           camel_sendmail_settings_set_use_custom_binary   (CamelSendmailSettings *settings,
+                                                                gboolean use_custom_binary);
+const gchar *  camel_sendmail_settings_get_custom_binary       (CamelSendmailSettings *settings);
+gchar *                camel_sendmail_settings_dup_custom_binary       (CamelSendmailSettings *settings);
+void           camel_sendmail_settings_set_custom_binary       (CamelSendmailSettings *settings,
+                                                                const gchar *custom_binary);
+
+G_END_DECLS
+
+#endif /* CAMEL_SENDMAIL_SETTINGS_H */
index 1b4c626..9404a28 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <glib/gi18n-lib.h>
 
+#include "camel-sendmail-settings.h"
 #include "camel-sendmail-transport.h"
 
 G_DEFINE_TYPE (
@@ -66,6 +67,9 @@ sendmail_send_to_sync (CamelTransport *transport,
        CamelMimeFilter *crlf;
        sigset_t mask, omask;
        CamelStream *out;
+       CamelSendmailSettings *settings;
+       const gchar *binary = SENDMAIL_PATH;
+       gchar *custom_binary = NULL;
        gboolean success;
        pid_t pid;
 
@@ -75,9 +79,19 @@ sendmail_send_to_sync (CamelTransport *transport,
        if (!success)
                return FALSE;
 
+       settings = CAMEL_SENDMAIL_SETTINGS (camel_service_ref_settings (CAMEL_SERVICE (transport)));
+
+       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;
+       }
+
+       g_object_unref (settings);
+
        len = camel_address_length (recipients);
        argv = g_malloc ((len + 6) * sizeof (gchar *));
-       argv[0] = "sendmail";
+       argv[0] = binary;
        argv[1] = "-i";
        argv[2] = "-f";
        argv[3] = from_addr;
@@ -123,11 +137,12 @@ sendmail_send_to_sync (CamelTransport *transport,
                g_set_error (
                        error, G_IO_ERROR,
                        g_io_error_from_errno (errno),
-                       _("Could not create pipe to sendmail: %s: "
-                       "mail not sent"), g_strerror (errno));
+                       _("Could not create pipe to '%s': %s: "
+                       "mail not sent"), binary, g_strerror (errno));
 
                /* restore the bcc headers */
                header->next = savedbcc;
+               g_free (custom_binary);
 
                return FALSE;
        }
@@ -145,8 +160,8 @@ sendmail_send_to_sync (CamelTransport *transport,
                g_set_error (
                        error, G_IO_ERROR,
                        g_io_error_from_errno (errno),
-                       _("Could not fork sendmail: %s: "
-                       "mail not sent"), g_strerror (errno));
+                       _("Could not fork '%s': %s: "
+                       "mail not sent"), binary, g_strerror (errno));
                close (fd[0]);
                close (fd[1]);
                sigprocmask (SIG_SETMASK, &omask, NULL);
@@ -154,6 +169,7 @@ sendmail_send_to_sync (CamelTransport *transport,
 
                /* restore the bcc headers */
                header->next = savedbcc;
+               g_free (custom_binary);
 
                return FALSE;
        case 0:
@@ -167,7 +183,7 @@ sendmail_send_to_sync (CamelTransport *transport,
                }
                close (fd[1]);
 
-               execv (SENDMAIL_PATH, (gchar **) argv);
+               execv (binary, (gchar **) argv);
                _exit (255);
        }
        g_free (argv);
@@ -201,6 +217,7 @@ sendmail_send_to_sync (CamelTransport *transport,
 
                /* restore the bcc headers */
                header->next = savedbcc;
+               g_free (custom_binary);
 
                return FALSE;
        }
@@ -219,25 +236,29 @@ sendmail_send_to_sync (CamelTransport *transport,
        if (!WIFEXITED (wstat)) {
                g_set_error (
                        error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
-                       _("sendmail exited with signal %s: mail not sent."),
-                       g_strsignal (WTERMSIG (wstat)));
+                       _("'%s' exited with signal %s: mail not sent."),
+                       binary, g_strsignal (WTERMSIG (wstat)));
+               g_free (custom_binary);
                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."),
-                               SENDMAIL_PATH);
+                               _("Could not execute '%s': mail not sent."),
+                               binary);
                } else {
                        g_set_error (
                                error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
-                               _("sendmail exited with status %d: "
+                               _("'%s' exited with status %d: "
                                "mail not sent."),
-                               WEXITSTATUS (wstat));
+                               binary, WEXITSTATUS (wstat));
                }
+               g_free (custom_binary);
                return FALSE;
        }
 
+       g_free (custom_binary);
+
        return TRUE;
 }
 
@@ -249,6 +270,7 @@ camel_sendmail_transport_class_init (CamelSendmailTransportClass *class)
 
        service_class = CAMEL_SERVICE_CLASS (class);
        service_class->get_name = sendmail_get_name;
+       service_class->settings_type = CAMEL_TYPE_SENDMAIL_SETTINGS;
 
        transport_class = CAMEL_TRANSPORT_CLASS (class);
        transport_class->send_to_sync = sendmail_send_to_sync;