From 901ae790dddca1c8bf9bf36b3ba4cd91623a43b7 Mon Sep 17 00:00:00 2001
From: Lorenz Schori <lo@znerol.ch>
Date: Thu, 29 Mar 2012 12:02:18 +0200
Subject: [PATCH 2/2] Adapt admin interface to mailsystem delegate

---
 mailsystem.admin.inc |  335 ++++++++++++++++++++++++++++----------------------
 mailsystem.module    |    8 +-
 2 files changed, 196 insertions(+), 147 deletions(-)

diff --git a/mailsystem.admin.inc b/mailsystem.admin.inc
index da093e9..05408ba 100644
--- a/mailsystem.admin.inc
+++ b/mailsystem.admin.inc
@@ -1,10 +1,58 @@
 <?php
 
 /**
- * @file
- * Administrative form for setting the mail_system variable.
+ * Return a list of modules implementing hook_mail.
  */
-function mailsystem_admin_settings() {
+function mailsystem_admin_get_mail_modules() {
+  $modules = module_implements('mail');
+  $result = array();
+
+  foreach ($modules as $module) {
+    $info = system_get_info('module', $module);
+    $description = empty($info['package']) ? t('Other') : $info['package'];
+    $description .= ' » ' . $info['name'];
+    $result[$module] = $description;
+  }
+
+  return $result;
+}
+
+function mailsystem_admin_read_settings() {
+  $mail_system = mailsystem_get();
+
+  $settings = array();
+  foreach ($mail_system as $id => $class) {
+    if ($class == 'MailsystemDelegateMailSystem') {
+      $settings[$id] = variable_get('mailsystem_delegate:' . $id);
+    }
+    else {
+      $settings[$id]['mail'] = $class;
+      $settings[$id]['format'] = $class;
+    }
+  }
+
+  return $settings;
+}
+
+/**
+ * Return a list of classes suitable for mail-formatting
+ */
+function mailsystem_admin_get_delivery_classes() {
+  $delivery_classes = mailsystem_get_classes();
+  unset($delivery_classes['MailsystemDelegateMailSystem']);
+  return $delivery_classes;
+}
+
+/**
+ * Return a list of classes suitable for formatting email
+ */
+function mailsystem_admin_get_formatter_classes() {
+  $formatter_classes = mailsystem_get_classes();
+  unset($formatter_classes['MailsystemDelegateMailSystem']);
+  return $formatter_classes;
+}
+
+function mailsystem_admin_settings($form, &$form_state) {
   $args = array(
     '!interface' => url('http://api.drupal.org/api/drupal/includes--mail.inc/interface/MailSystemInterface/7'),
     '@interface' => 'MailSystemInterface',
@@ -17,20 +65,12 @@ function mailsystem_admin_settings() {
     '%module' => 'module',
     '%key' => 'key',
   );
-  $form = array('#submit' => array('mailsystem_admin_settings_submit'));
-  $mail_system = mailsystem_get();
-  $mail_defaults = mailsystem_defaults();
-  $mailsystem_classes = mailsystem_get_classes();
-  $descriptions = array();
-  foreach (system_rebuild_module_data() as $item) {
-    if ($item->status) {
-      $descriptions[$item->name] = (
-        empty($item->info['package'])
-        ? '' : $item->info['package']
-      ) . ' » ' . t('!module module', array('!module' => $item->info['name']));
-    }
-  }
-  asort($descriptions);
+
+  $mail_system = mailsystem_admin_read_settings();
+  $delivery_classes = mailsystem_admin_get_delivery_classes();
+  $formatter_classes = mailsystem_admin_get_formatter_classes();
+  $mail_modules = mailsystem_admin_get_mail_modules();
+
   $form['mailsystem'] = array(
     '#type' => 'fieldset',
     '#title' => t('Mail System Settings'),
@@ -40,113 +80,93 @@ function mailsystem_admin_settings() {
     '#collapsible' => FALSE,
     '#tree' => TRUE,
   );
+
   $form['mailsystem'][mailsystem_default_id()] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Site-wide default mail system'),
+  );
+  $form['mailsystem'][mailsystem_default_id()]['mail'] = array(
     '#type' => 'select',
-    '#title' => t(
-      'Site-wide default <a href="!interface"><code>@interface</code></a> class', $args
-    ),
-    '#options' => $mailsystem_classes,
-    '#default_value' => $mail_system[mailsystem_default_id()],
+    '#title' => t('Delivery'),
+    '#options' => $delivery_classes,
+    '#default_value' => $mail_system[mailsystem_default_id()]['mail'],
+    '#description' => t('Class used to send the mail'),
   );
-  $mailsystem_classes = array(
-    mailsystem_default_id() => t('Remove this setting.')
-  ) + $mailsystem_classes;
-  foreach (array_diff_key($mail_system, $mail_defaults) as $id => $class) {
-    // Separate $id into $module and $key.
-    $module = $id;
-    while ($module && empty($descriptions[$module])) {
-      // Remove a key from the end
-      $module = implode('_', explode('_', $module, -1));
-    }
-    // If an array key of the $mail_system variable is neither "default-system"
-    // nor begins with a module name, then it should be unset.
-    if (empty($module)) {
-      watchdog('mailsystem', "Removing bogus mail_system key %id.", array('%id' => $id), WATCHDOG_WARNING);
-      unset($mail_system[$id]);
-      continue;
-    }
-    // Set $title to the human-readable module name.
-    $title = preg_replace('/^.* » /', '', $descriptions[$module]);
-    if ($key = substr($id, strlen($module) + 1)) {
-      $title .= " ($key key)";
-    }
-    $title .= ' class';
+  $form['mailsystem'][mailsystem_default_id()]['format'] = array(
+    '#type' => 'select',
+    '#title' => t('Formatting'),
+    '#options' => $formatter_classes,
+    '#default_value' => $mail_system[mailsystem_default_id()]['format'],
+    '#description' => t('Class used to format the body of the mail'),
+  );
+
+  unset($mail_system[mailsystem_default_id()]);
+
+  foreach ($mail_system as $id => $settings) {
     $form['mailsystem'][$id] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Custom settings for mail-id %id', array('%id' => $id)),
+    );
+    $form['mailsystem'][$id]['mail'] = array(
       '#type' => 'select',
-      '#title' => $title,
-      '#options' => $mailsystem_classes,
-      '#default_value' => $class,
+      '#title' => t('Delivery'),
+      '#options' => $delivery_classes,
+      '#default_value' => $settings['mail'],
+      '#description' => t('Class used to send the mail'),
     );
-    unset($descriptions[$module]);
-  }
-  // Generate a list of themes which may used to render emails.
-  $theme_options = array('current' => t('Current'), 'default' => t('Default'));
-  if (module_exists('domain_theme')) {
-    $theme_options['domain'] = t('Domain Theme');
-  }
-  // Get a list of all themes.
-  $themes = list_themes();
-  foreach ($themes as $name => $theme) {
-    if ($theme->status == 1) {
-      $theme_options[$name] = $theme->info['name'];
-    }
-  }
-  $form['mailsystem']['mailsystem_theme'] = array(
+    $form['mailsystem'][$id]['format'] = array(
       '#type' => 'select',
-      '#title' => t('Theme to render the emails'),
-      '#description' => t('Select the theme that will be used to render the emails. This can be either the current theme, the default theme, the domain theme or any active theme.'),
-      '#options' => $theme_options,
-      '#default_value' => variable_get('mailsystem_theme', 'current'),
-  );
-  $form['class'] = array(
+      '#title' => t('Formatting'),
+      '#options' => $formatter_classes,
+      '#default_value' => $settings['format'],
+      '#description' => t('Class used to format the body of the mail'),
+    );
+    $form['mailsystem'][$id]['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Remove custom settings for mail-id @id', array('@id' => $id)),
+      '#submit' => array('mailsystem_admin_remove_setting_submit'),
+    );
+  }
+
+  $form['mailsystem']['add-custom-settings'] = array(
     '#type' => 'fieldset',
-    '#title' => t('New Class'),
-    '#description' => t(
-      'Create a new <a href="!interface"><code>@interface</code></a> that inherits its methods from other classes. The new class will be named after the other classes it uses.', $args
-    ),
+    '#title' => t('Add custom settings'),
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
-    '#tree' => TRUE,
+    '#element_validate' => array('mailsystem_admin_add_setting_validate'),
   );
-  $mailsystem_classes[mailsystem_default_id()] = '--Select--';
-  $form['class']['format'] = array(
+  $form['mailsystem']['add-custom-settings']['module'] = array(
     '#type' => 'select',
-    '#title' => t(
-      'Class to use for the <a href="!format"><code>@format</code></a> method', $args
-    ),
-    '#options' => $mailsystem_classes,
+    '#title' => t('Module'),
+    '#options' => $mail_modules,
   );
-  $form['class']['mail'] = array(
-    '#type' => 'select',
-    '#title' => t(
-      'Class to use for the <a href="!mail"><code>@mail</code></a> method', $args
-    ),
-    '#options' => $mailsystem_classes,
+  $form['mailsystem']['add-custom-settings']['key'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Key'),
+    '#size' => 30,
+    '#description' => t('An optional key which further specifies the mail in question. You may have to examine the source code of the <a href="!hook_mail_url">hook_mail</a> implementation of the module in question in order to find an appropriate value', array('!hook_mail_url' => 'http://api.drupal.org/api/drupal/modules%21system%21system.api.php/function/hook_mail/7')),
   );
-  $form['identifier'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('New Setting'),
-    '#description' => t('Add a new %module and %key to the settings list.',
-      array(
-        '%module' => 'module',
-        '%key' => 'key',
-      )
-    ),
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-    '#tree' => TRUE,
+  $form['mailsystem']['add-custom-settings']['mail'] = array(
+    '#type' => 'select',
+    '#title' => t('Delivery'),
+    '#options' => $delivery_classes,
+    '#description' => t('Class used to send the mail'),
   );
-  array_unshift($descriptions, t('-- Select --'));
-  $form['identifier']['module'] = array(
+  $form['mailsystem']['add-custom-settings']['format'] = array(
     '#type' => 'select',
-    '#title' => t('Module'),
-    '#options' => $descriptions,
+    '#title' => t('Formatting'),
+    '#options' => $formatter_classes,
+    '#description' => t('Class used to format the body of the mail'),
   );
-  $form['identifier']['key'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Key'),
-    '#size' => 80,
+  $form['mailsystem']['add-custom-settings']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Add custom settings'),
+    '#submit' => array('mailsystem_admin_add_setting_submit'),
+    '#limit_validation_errors' => array(
+      array('mailsystem', 'add-custom-settings'),
+    ),
   );
+
   $form['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Save settings'),
@@ -155,49 +175,74 @@ function mailsystem_admin_settings() {
 }
 
 /**
- * Processes mailsystem_admin_settings form.
+ * Form API validate callback: Add an additional custom setting for a module/key.
  */
-function mailsystem_admin_settings_submit($form, &$form_state) {
-  variable_set('mailsystem_theme', $form_state['values']['mailsystem']['mailsystem_theme']);
-  // Rebuild the theme registry to make changes needed by theme rendering.
-  drupal_theme_rebuild();
-  unset($form_state['values']['mailsystem']['mailsystem_theme']);
-
-  $default_id = mailsystem_default_id();
-  $mail_system = array(
-    $default_id => (
-      empty($form_state['values'][$default_id])
-      ? mailsystem_default_value()
-      : $form_state['values'][$default_id]
-    )
-  );
-  foreach (element_children($form_state['values']['mailsystem']) as $module) {
-    $class = $form_state['values']['mailsystem'][$module];
-    if (!empty($class) && $class != $default_id) {
-      $mail_system[$module] = $class;
-    }
-  }
-  unset($form_state['values']['mailsystem']);
-  if ($form_state['values']['class']['format'] === mailsystem_default_id()) {
-    unset($form_state['values']['class']['format']);
+function mailsystem_admin_add_setting_validate($fieldset, &$form_state) {
+  $module = $fieldset['module']['#value'];
+  $key = $fieldset['key']['#value'];
+  $id = $module;
+  if (!empty($key)) {
+    $id .= '_' . $key;
   }
-  if ($form_state['values']['class']['mail'] === mailsystem_default_id()) {
-    unset($form_state['values']['class']['mail']);
+
+  // FIXME: check if we already have a setting for this id
+
+  $form_state['new_settings_id'] = $id;
+}
+
+/**
+ * Form API submit callback: Add an additional custom setting for a module/key.
+ */
+function mailsystem_admin_add_setting_submit($form, &$form_state) {
+  $values = $form_state['values']['mailsystem']['add-custom-settings'];
+
+  $id = $form_state['new_settings_id'];
+  mailsystem_admin_save_custom_setting($id, $values);
+
+  drupal_set_message(t('Added new custom setting for mail-id %id',
+    array('%id' => $id)));
+}
+
+/**
+ * Form API submit callback: Remove a custom setting.
+ */
+function mailsystem_admin_remove_setting_submit($form, &$form_state) {
+  $parents = $form_state['triggering_element']['#parents'];
+  array_pop($parents); // submit
+  $id = array_pop($parents); // fieldset
+
+  mailsystem_clear(array($id => $id));
+
+  drupal_set_message(t('Removed custom setting for mail-id %id',
+    array('%id' => $id)));
+}
+
+/**
+ * Form API submit callback: save settings.
+ */
+function mailsystem_admin_settings_submit($form, &$form_state) {
+  unset($form_state['values']['mailsystem']['add-custom-settings']);
+
+  foreach ($form_state['values']['mailsystem'] as $id => $values) {
+    mailsystem_admin_save_custom_setting($id, $values);
   }
-  if ($form_state['values']['class']) {
-    $new_class = mailsystem_create_class($form_state['values']['class']);
+
+  drupal_set_message(t('Saved settings for mailsystem'));
+}
+
+
+/**
+ * Helper function. Writes the setting values for a given mail-id.
+ */
+function mailsystem_admin_save_custom_setting($id, $values) {
+  if ($values['format'] != $values['mail']) {
+    $value = array(
+      'mail' => $values['mail'],
+      'format' => $values['format'],
+    );
   }
   else {
-    $new_class = $mail_system[mailsystem_default_id()];
-  }
-  unset($form_state['values']['class']);
-  if ($id = $form_state['values']['identifier']['module']) {
-    if (!empty($form_state['values']['identifier']['key'])) {
-      $id .= '_' . $form_state['values']['identifier']['key'];
-    }
-    $mail_system[$id] = $new_class;
+    $value = $values['mail'];
   }
-  unset($form_state['values']['identifier']);
-  variable_set('mail_system', $mail_system);
-  drupal_set_message(t('The configuration options have been saved.'));
+  mailsystem_set(array($id => $value));
 }
diff --git a/mailsystem.module b/mailsystem.module
index be7922d..3166749 100644
--- a/mailsystem.module
+++ b/mailsystem.module
@@ -109,10 +109,11 @@ function mailsystem_get() {
  */
 function mailsystem_set(array $setting) {
   $mail_system = mailsystem_get();
-  foreach ($setting as $key => $class) {
+  foreach ($setting as $id => $class) {
+    variable_del('mailsystem_delegate:' . $id);
     if (is_array($class)) {
       // Save the settings for our delegateer-class into a variable
-      $setting[$key] = mailsystem_delegate_set_mailsystem_settings($key, $class);
+      $setting[$id] = mailsystem_delegate_set_mailsystem_settings($id, $class);
     }
   }
   variable_set('mail_system', array_merge(mailsystem_get(), $setting));
@@ -140,6 +141,9 @@ function mailsystem_clear(array $setting) {
       array_diff_key(array_diff(mailsystem_get(), $setting), $setting)
     )
   );
+  foreach (array_keys($setting) as $id) {
+    variable_del('mailsystem_delegate:' . $id);
+  }
 }
 
 /**
-- 
1.7.4.1

