Bug #201807 - Cannot specify sendmail parameters
authorMilan Crha <mcrha@redhat.com>
Wed, 17 Oct 2012 17:46:42 +0000 (19:46 +0200)
committerMilan Crha <mcrha@redhat.com>
Wed, 17 Oct 2012 17:47:29 +0000 (19:47 +0200)
camel/providers/sendmail/camel-sendmail-settings.c
camel/providers/sendmail/camel-sendmail-settings.h
camel/providers/sendmail/camel-sendmail-transport.c

index 2389f3b..2863afc 100644 (file)
 struct _CamelSendmailSettingsPrivate {
        GMutex *property_lock;
        gchar *custom_binary;
+       gchar *custom_args;
 
        gboolean use_custom_binary;
+       gboolean use_custom_args;
 };
 
 enum {
        PROP_0,
        PROP_USE_CUSTOM_BINARY,
-       PROP_CUSTOM_BINARY
+       PROP_USE_CUSTOM_ARGS,
+       PROP_CUSTOM_BINARY,
+       PROP_CUSTOM_ARGS
 };
 
 G_DEFINE_TYPE (CamelSendmailSettings, camel_sendmail_settings, CAMEL_TYPE_SETTINGS)
@@ -50,11 +54,23 @@ sendmail_settings_set_property (GObject *object,
                                g_value_get_boolean (value));
                        return;
 
+               case PROP_USE_CUSTOM_ARGS:
+                       camel_sendmail_settings_set_use_custom_args (
+                               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;
+
+               case PROP_CUSTOM_ARGS:
+                       camel_sendmail_settings_set_custom_args (
+                               CAMEL_SENDMAIL_SETTINGS (object),
+                               g_value_get_string (value));
+                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -74,12 +90,26 @@ sendmail_settings_get_property (GObject *object,
                                CAMEL_SENDMAIL_SETTINGS (object)));
                        return;
 
+               case PROP_USE_CUSTOM_ARGS:
+                       g_value_set_boolean (
+                               value,
+                               camel_sendmail_settings_get_use_custom_args (
+                               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;
+
+               case PROP_CUSTOM_ARGS:
+                       g_value_take_string (
+                               value,
+                               camel_sendmail_settings_dup_custom_args (
+                               CAMEL_SENDMAIL_SETTINGS (object)));
+                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -95,6 +125,7 @@ sendmail_settings_finalize (GObject *object)
        g_mutex_free (priv->property_lock);
 
        g_free (priv->custom_binary);
+       g_free (priv->custom_args);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (camel_sendmail_settings_parent_class)->finalize (object);
@@ -126,6 +157,18 @@ camel_sendmail_settings_class_init (CamelSendmailSettingsClass *class)
 
        g_object_class_install_property (
                object_class,
+               PROP_USE_CUSTOM_ARGS,
+               g_param_spec_boolean (
+                       "use-custom-args",
+                       "Use Custom Arguments",
+                       "Whether the custom-args property identifies arguments to use",
+                       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",
@@ -135,6 +178,18 @@ camel_sendmail_settings_class_init (CamelSendmailSettingsClass *class)
                        G_PARAM_READWRITE |
                        G_PARAM_CONSTRUCT |
                        G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_CUSTOM_ARGS,
+               g_param_spec_string (
+                       "custom-args",
+                       "Custom Arguments",
+                       "Custom arguments to use, instead of default (predefined) arguments",
+                       NULL,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -186,6 +241,47 @@ camel_sendmail_settings_set_use_custom_binary (CamelSendmailSettings *settings,
 }
 
 /**
+ * camel_sendmail_settings_get_use_custom_args:
+ * @settings: a #CamelSendmailSettings
+ *
+ * Returns whether the 'custom-args' property should be used as arguments to use, instead of default arguments.
+ *
+ * Returns: whether the 'custom-args' property should be used as arguments to use, instead of default arguments
+ *
+ * Since: 3.8
+ **/
+gboolean
+camel_sendmail_settings_get_use_custom_args (CamelSendmailSettings *settings)
+{
+       g_return_val_if_fail (CAMEL_IS_SENDMAIL_SETTINGS (settings), FALSE);
+
+       return settings->priv->use_custom_args;
+}
+
+/**
+ * camel_sendmail_settings_set_use_custom_args:
+ * @settings: a #CamelSendmailSettings
+ * @use_custom_args: whether to use custom arguments
+ *
+ * Sets whether to use custom arguments, instead of default arguments.
+ *
+ * Since: 3.8
+ **/
+void
+camel_sendmail_settings_set_use_custom_args (CamelSendmailSettings *settings,
+                                            gboolean use_custom_args)
+{
+       g_return_if_fail (CAMEL_IS_SENDMAIL_SETTINGS (settings));
+
+       if ((settings->priv->use_custom_args ? 1 : 0) == (use_custom_args ? 1 : 0))
+               return;
+
+       settings->priv->use_custom_args = use_custom_args;
+
+       g_object_notify (G_OBJECT (settings), "use-custom-args");
+}
+
+/**
  * camel_sendmail_settings_get_custom_binary:
  * @settings: a #CamelSendmailSettings
  *
@@ -267,3 +363,86 @@ camel_sendmail_settings_set_custom_binary (CamelSendmailSettings *settings,
 
        g_object_notify (G_OBJECT (settings), "custom-binary");
 }
+
+/**
+ * camel_sendmail_settings_get_custom_args:
+ * @settings: a #CamelSendmailSettings
+ *
+ * Returns the custom arguments to use, instead of default arguments.
+ *
+ * Returns: the custom arguments to use, instead of default arguments, or %NULL
+ *
+ * Since: 3.8
+ **/
+const gchar *
+camel_sendmail_settings_get_custom_args (CamelSendmailSettings *settings)
+{
+       g_return_val_if_fail (CAMEL_IS_SENDMAIL_SETTINGS (settings), NULL);
+
+       return settings->priv->custom_args;
+}
+
+/**
+ * camel_sendmail_settings_dup_custom_args:
+ * @settings: a #CamelSendmailSettings
+ *
+ * Thread-safe variation of camel_sendmail_settings_get_custom_args().
+ * 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-args
+ *
+ * Since: 3.8
+ **/
+gchar *
+camel_sendmail_settings_dup_custom_args (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_args (settings);
+       duplicate = g_strdup (protected);
+
+       g_mutex_unlock (settings->priv->property_lock);
+
+       return duplicate;
+}
+
+/**
+ * camel_sendmail_settings_set_custom_args:
+ * @settings: a #CamelSendmailSettings
+ * @custom_args: a custom arguments, or %NULL
+ *
+ * Sets the custom arguments to use, instead of default arguments.
+ *
+ * Since: 3.8
+ **/
+void
+camel_sendmail_settings_set_custom_args (CamelSendmailSettings *settings,
+                                       const gchar *custom_args)
+{
+       g_return_if_fail (CAMEL_IS_SENDMAIL_SETTINGS (settings));
+
+       /* The default namespace is an empty string. */
+       if (custom_args && !*custom_args)
+               custom_args = NULL;
+
+       g_mutex_lock (settings->priv->property_lock);
+
+       if (g_strcmp0 (settings->priv->custom_args, custom_args) == 0) {
+               g_mutex_unlock (settings->priv->property_lock);
+               return;
+       }
+
+       g_free (settings->priv->custom_args);
+       settings->priv->custom_args = g_strdup (custom_args);
+
+       g_mutex_unlock (settings->priv->property_lock);
+
+       g_object_notify (G_OBJECT (settings), "custom-args");
+}
index a85ec82..c33d4ee 100644 (file)
@@ -59,11 +59,21 @@ 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);
 
+gboolean       camel_sendmail_settings_get_use_custom_args     (CamelSendmailSettings *settings);
+void           camel_sendmail_settings_set_use_custom_args     (CamelSendmailSettings *settings,
+                                                                gboolean use_custom_args);
+
+const gchar *  camel_sendmail_settings_get_custom_args         (CamelSendmailSettings *settings);
+gchar *                camel_sendmail_settings_dup_custom_args         (CamelSendmailSettings *settings);
+void           camel_sendmail_settings_set_custom_args         (CamelSendmailSettings *settings,
+                                                                const gchar *custom_args);
+
 G_END_DECLS
 
 #endif /* CAMEL_SENDMAIL_SETTINGS_H */
index 9404a28..f570cbd 100644 (file)
@@ -52,6 +52,63 @@ sendmail_get_name (CamelService *service,
                return g_strdup (_("Mail delivery via the sendmail program"));
 }
 
+static GPtrArray *
+parse_sendmail_args (const gchar *binary,
+                    const gchar *args,
+                    const gchar *from_addr,
+                    CamelAddress *recipients)
+{
+       GPtrArray *args_arr;
+       gint ii, len, argc = 0;
+       gchar **argv = NULL;
+
+       g_return_val_if_fail (binary != NULL, NULL);
+       g_return_val_if_fail (args != NULL, NULL);
+       g_return_val_if_fail (from_addr != NULL, NULL);
+
+       len = camel_address_length (recipients);
+
+       args_arr = g_ptr_array_new_full (5, g_free);
+       g_ptr_array_add (args_arr, g_strdup (binary));
+
+       if (args && g_shell_parse_argv (args, &argc, &argv, NULL) && argc > 0 && argv) {
+               for (ii = 0; ii < argc; ii++) {
+                       const gchar *arg = argv[ii];
+
+                       if (g_strcmp0 (arg, "%F") == 0) {
+                               g_ptr_array_add (args_arr, g_strdup (from_addr));
+                       } else if (g_strcmp0 (arg, "%R") == 0) {
+                               gint jj;
+
+                               for (jj = 0; jj < len; jj++) {
+                                       const gchar *addr = NULL;
+
+                                       if (!camel_internet_address_get (
+                                               CAMEL_INTERNET_ADDRESS (recipients), jj, NULL, &addr)) {
+
+                                               /* should not happen, as the array is checked beforehand */
+
+                                               g_ptr_array_free (args_arr, TRUE);
+                                               g_strfreev (argv);
+
+                                               return NULL;
+                                       }
+
+                                       g_ptr_array_add (args_arr, g_strdup (addr));
+                               }
+                       } else {
+                               g_ptr_array_add (args_arr, g_strdup (arg));
+                       }
+               }
+
+               g_strfreev (argv);
+       }
+
+       g_ptr_array_add (args_arr, NULL);
+
+       return args_arr;
+}
+
 static gboolean
 sendmail_send_to_sync (CamelTransport *transport,
                        CamelMimeMessage *message,
@@ -61,7 +118,8 @@ sendmail_send_to_sync (CamelTransport *transport,
                        GError **error)
 {
        struct _camel_header_raw *header, *savedbcc, *n, *tail;
-       const gchar *from_addr, *addr, **argv;
+       const gchar *from_addr, *addr;
+       GPtrArray *argv_arr;
        gint i, len, fd[2], nullfd, wstat;
        CamelStream *filter;
        CamelMimeFilter *crlf;
@@ -69,7 +127,7 @@ sendmail_send_to_sync (CamelTransport *transport,
        CamelStream *out;
        CamelSendmailSettings *settings;
        const gchar *binary = SENDMAIL_PATH;
-       gchar *custom_binary = NULL;
+       gchar *custom_binary = NULL, *custom_args = NULL;
        gboolean success;
        pid_t pid;
 
@@ -87,16 +145,16 @@ sendmail_send_to_sync (CamelTransport *transport,
                        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);
-       argv = g_malloc ((len + 6) * sizeof (gchar *));
-       argv[0] = binary;
-       argv[1] = "-i";
-       argv[2] = "-f";
-       argv[3] = from_addr;
-       argv[4] = "--";
-
        for (i = 0; i < len; i++) {
                success = camel_internet_address_get (
                        CAMEL_INTERNET_ADDRESS (recipients), i, NULL, &addr);
@@ -105,14 +163,28 @@ sendmail_send_to_sync (CamelTransport *transport,
                        g_set_error (
                                error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
                                _("Could not parse recipient list"));
-                       g_free (argv);
+                       g_free (custom_binary);
+                       g_free (custom_args);
+
                        return FALSE;
                }
-
-               argv[i + 5] = addr;
        }
 
-       argv[i + 5] = NULL;
+       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 */
        savedbcc = NULL;
@@ -143,6 +215,8 @@ sendmail_send_to_sync (CamelTransport *transport,
                /* restore the bcc headers */
                header->next = savedbcc;
                g_free (custom_binary);
+               g_free (custom_args);
+               g_ptr_array_free (argv_arr, TRUE);
 
                return FALSE;
        }
@@ -165,11 +239,12 @@ sendmail_send_to_sync (CamelTransport *transport,
                close (fd[0]);
                close (fd[1]);
                sigprocmask (SIG_SETMASK, &omask, NULL);
-               g_free (argv);
 
                /* restore the bcc headers */
                header->next = savedbcc;
                g_free (custom_binary);
+               g_free (custom_args);
+               g_ptr_array_free (argv_arr, TRUE);
 
                return FALSE;
        case 0:
@@ -183,10 +258,11 @@ sendmail_send_to_sync (CamelTransport *transport,
                }
                close (fd[1]);
 
-               execv (binary, (gchar **) argv);
+               execv (binary, (gchar **) argv_arr->pdata);
                _exit (255);
        }
-       g_free (argv);
+
+       g_ptr_array_free (argv_arr, TRUE);
 
        /* Parent process. Write the message out. */
        close (fd[0]);
@@ -218,6 +294,7 @@ sendmail_send_to_sync (CamelTransport *transport,
                /* restore the bcc headers */
                header->next = savedbcc;
                g_free (custom_binary);
+               g_free (custom_args);
 
                return FALSE;
        }
@@ -239,6 +316,8 @@ sendmail_send_to_sync (CamelTransport *transport,
                        _("'%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) {
@@ -254,10 +333,13 @@ sendmail_send_to_sync (CamelTransport *transport,
                                binary, WEXITSTATUS (wstat));
                }
                g_free (custom_binary);
+               g_free (custom_args);
+
                return FALSE;
        }
 
        g_free (custom_binary);
+       g_free (custom_args);
 
        return TRUE;
 }