374 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			374 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
/**
 | 
						|
 * @file
 | 
						|
 * Provide UI for controlling the mail_system variable.
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * Implements hook_init().
 | 
						|
 *
 | 
						|
 * Caches the list of MailSystemInterface classes, and removes classes
 | 
						|
 * from the mail_system variable which are no longer available.
 | 
						|
 *
 | 
						|
 * @see mailsystem_get_classes()
 | 
						|
 */
 | 
						|
function mailsystem_init() {
 | 
						|
  mailsystem_get_classes();
 | 
						|
  // @todo Remove this when issue #299138 gets resolved.
 | 
						|
  if (!function_exists('mailsystem_html_to_text')) {
 | 
						|
    module_load_include('inc', 'mailsystem', 'html_to_text');
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Implements hook_permission().
 | 
						|
 *
 | 
						|
 * Defines a permission for managing the mail_system variable.
 | 
						|
 */
 | 
						|
function mailsystem_permission() {
 | 
						|
  return array(
 | 
						|
    'administer mailsystem' => array(
 | 
						|
      'title' => t('Administer Mail System'),
 | 
						|
      'description' => t(
 | 
						|
        'Select the default, per-module, and per-mailing <a href="!interface"><code>@interface</code></a> to use for formatting and sending email messages.',
 | 
						|
        array(
 | 
						|
          '!interface' => url('http://api.drupal.org/api/drupal/includes--mail.inc/interface/MailSystemInterface/7'),
 | 
						|
          '@interface' => 'MailSystemInterface',
 | 
						|
        )
 | 
						|
      ),
 | 
						|
    ),
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Implements hook_menu().
 | 
						|
 */
 | 
						|
function mailsystem_menu() {
 | 
						|
  $items['admin/config/system/mailsystem'] = array(
 | 
						|
    'title' => 'Mail System',
 | 
						|
    'description' => 'Configure per-module Mail System settings.',
 | 
						|
    'page callback' => 'drupal_get_form',
 | 
						|
    'page arguments' => array('mailsystem_admin_settings'),
 | 
						|
    'access arguments' => array('administer mailsystem'),
 | 
						|
    'file' => 'mailsystem.admin.inc',
 | 
						|
  );
 | 
						|
  return $items;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns the id for the default mail_system setting.
 | 
						|
 */
 | 
						|
function mailsystem_default_id() {
 | 
						|
  // @todo: Is there a way to get this from core?
 | 
						|
  return 'default-system';
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns the value for the default mail_system setting.
 | 
						|
 */
 | 
						|
function mailsystem_default_value() {
 | 
						|
  // @todo: Is there a way to get this from core?
 | 
						|
  return 'DefaultMailSystem';
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns the default settings for the mail_system variable.
 | 
						|
 */
 | 
						|
function mailsystem_defaults() {
 | 
						|
  return array(mailsystem_default_id() => mailsystem_default_value());
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns the current mail_system settings.
 | 
						|
 *
 | 
						|
 * @return The contents of the mail_system variable merged with its defaults.
 | 
						|
 */
 | 
						|
function mailsystem_get() {
 | 
						|
  return array_merge(
 | 
						|
    mailsystem_defaults(),
 | 
						|
    variable_get('mail_system', mailsystem_defaults())
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns the default list of MailSystemInterface methods.
 | 
						|
 *
 | 
						|
 * @return
 | 
						|
 *   An array whose keys are the names of the methods defined by
 | 
						|
 *   MailSystemInterface and whose values are the default class used to
 | 
						|
 *   provide that method.
 | 
						|
 */
 | 
						|
function mailsystem_default_methods() {
 | 
						|
  $mail_system = mailsystem_get();
 | 
						|
  $default_class = $mail_system[mailsystem_default_id()];
 | 
						|
  $methods = get_class_methods('MailSystemInterface');
 | 
						|
  return array_combine(
 | 
						|
    $methods,
 | 
						|
    array_fill(0, count($methods), $default_class)
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Creates and registers a new MailSystemInterface class.
 | 
						|
 *
 | 
						|
 * The newly-created class gets its name and each of its class methods from the
 | 
						|
 * other classes specified by the $class parameter.
 | 
						|
 *
 | 
						|
 * @param $class An associative array of ($method_name => $class_name) tuples,
 | 
						|
 * where each $method_name is the name of a class method to be created, and
 | 
						|
 * each $class_name is the name of a class to use for that method.
 | 
						|
 *
 | 
						|
 * @return
 | 
						|
 *   The name of the newly-created class if successful; otherwise FALSE.
 | 
						|
 */
 | 
						|
function mailsystem_create_class($classes) {
 | 
						|
  // Merge in defaults.
 | 
						|
  $classes += mailsystem_default_methods();
 | 
						|
  ksort($classes);
 | 
						|
  // Do not create a new class whose methods all derive from the same class.
 | 
						|
  if (count(array_unique($classes)) === 1) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
  $class_name = implode('__', $classes);
 | 
						|
  // Ensure that the mailsystem directory exists.
 | 
						|
  // First we try the private filesystem.
 | 
						|
  $private_files = variable_get('file_private_path', '');
 | 
						|
  $private_files_full = $private_files . '/mailsystem';
 | 
						|
  $public_files = variable_get('file_public_path', conf_path() . '/files');
 | 
						|
  $public_files_full = $public_files . '/mailsystem';
 | 
						|
  if ($private_files && file_prepare_directory($private_files_full, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
 | 
						|
    $class_dir = $private_files . '/mailsystem';
 | 
						|
  }
 | 
						|
  // If private filesystem is not defined or writable, we use the public filesystem.
 | 
						|
  elseif (file_prepare_directory($public_files_full, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
 | 
						|
    $class_dir = $public_files . '/mailsystem';
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
  // Build the class filename.
 | 
						|
  $class_file = $class_dir . DIRECTORY_SEPARATOR . "$class_name.mail.inc";
 | 
						|
  // Build the class implementation as a string.
 | 
						|
  $class_contents = '<?php
 | 
						|
class ' . $class_name . ' implements MailSystemInterface {';
 | 
						|
  // Create a protected variable to hold each method class.
 | 
						|
  foreach (array_keys($classes) as $method) {
 | 
						|
    $class_contents .= '
 | 
						|
  protected $' . $method . 'Class;';
 | 
						|
  }
 | 
						|
  // Create a class construction function to populate the variables.
 | 
						|
  $class_contents .= '
 | 
						|
  public function __construct() {';
 | 
						|
  foreach ($classes as $method => $class) {
 | 
						|
    $class_contents .= '
 | 
						|
    if (drupal_autoload_class(\'' . $class . '\')) {
 | 
						|
      $this->' . $method . 'Class = new ' . $class . ';
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      $this->' . $method . 'Class = new ' . mailsystem_default_value() . ';
 | 
						|
    }';
 | 
						|
  }
 | 
						|
  $class_contents .= '
 | 
						|
  }';
 | 
						|
  // Create each class method.
 | 
						|
  foreach (array_keys($classes) as $method) {
 | 
						|
    $class_contents .= '
 | 
						|
  public function ' . $method . '(array $message) {
 | 
						|
    return $this->' . $method . 'Class->' . $method . '($message);
 | 
						|
  }';
 | 
						|
  }
 | 
						|
  $class_contents .= '
 | 
						|
}
 | 
						|
';
 | 
						|
  if (file_unmanaged_save_data($class_contents, $class_file, FILE_EXISTS_REPLACE)) {
 | 
						|
    // Remove any conflicting registry entries to avoid a database error.
 | 
						|
    $class_condition = db_and()
 | 
						|
      ->condition('name', $class_name)
 | 
						|
      ->condition('type', 'class');
 | 
						|
    $file_condition = db_and()
 | 
						|
      ->condition('filename', $class_file);
 | 
						|
    db_delete('registry_file')
 | 
						|
      ->condition($file_condition)
 | 
						|
      ->execute();
 | 
						|
    db_delete('registry')->condition(
 | 
						|
      db_or()->condition($class_condition)
 | 
						|
      ->condition($file_condition)
 | 
						|
    )->execute();
 | 
						|
    // Make sure that registry functions are available.
 | 
						|
    require_once 'includes/registry.inc';
 | 
						|
    // Parse the newly-created class file and add it to the registry.
 | 
						|
    _registry_parse_file($class_file, $class_contents, 'mailsystem');
 | 
						|
    // Clear the mailsystem caches so that it will pick up the new class.
 | 
						|
    drupal_static_reset('mailsystem_get_classes');
 | 
						|
    cache_clear_all('mailsystem_get_classes', 'cache');
 | 
						|
    drupal_set_message(
 | 
						|
      t('Class <code>%class</code> written to <code>%file</code>.',
 | 
						|
        array('%class' => $class_name, '%file' => $class_file)
 | 
						|
      )
 | 
						|
    );
 | 
						|
  }
 | 
						|
  return $class_name;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Helps other modules safely set their own key within mail_system.  This
 | 
						|
 * function should be called from hook_enable() implementations.
 | 
						|
 *
 | 
						|
 * @param $setting  An associative array ($id => $value) where:
 | 
						|
 *   - $id is the machine-readable module name optionally followed by '_'
 | 
						|
 *     and a key.
 | 
						|
 *   - $value is one of
 | 
						|
 *     - (string) The name of a class that implements MailSystemInterface.
 | 
						|
 *     - (array) An associative array whose keys are the names of methods
 | 
						|
 *       defined by MailSystemInterface and whose values are the names of
 | 
						|
 *       the class to use for that method.
 | 
						|
 *
 | 
						|
 * @see drupal_mail(), mailsystem_default_methods()
 | 
						|
 */
 | 
						|
function mailsystem_set(array $setting) {
 | 
						|
  $mail_system = mailsystem_get();
 | 
						|
  foreach ($setting as $key => $class) {
 | 
						|
    if (is_array($class)) {
 | 
						|
      unset($setting[$key]);
 | 
						|
      if ($new_class = mailsystem_create_class($class)) {
 | 
						|
        $setting[$key] = $new_class;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  variable_set('mail_system', array_merge(mailsystem_get(), $setting));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Helps other modules safely remove their settings from mail_system.  This
 | 
						|
 * function should be called from the other module's hook_disable() function.
 | 
						|
 *
 | 
						|
 * @param $setting  An associative array ($module => $classname) describing
 | 
						|
 * a module and associated MailSystemInterface class that are being disabled.
 | 
						|
 *   - $module is the machine-readable module name.
 | 
						|
 *   - $classname is a class that implements MailSystemInterface.
 | 
						|
 *
 | 
						|
 * If $classname is empty, only the $module entry is removed.
 | 
						|
 *
 | 
						|
 * @param $class
 | 
						|
 *   The name of the class to be removed, if any.
 | 
						|
 */
 | 
						|
function mailsystem_clear(array $setting) {
 | 
						|
  variable_set(
 | 
						|
    'mail_system',
 | 
						|
    array_merge(
 | 
						|
      mailsystem_defaults(),
 | 
						|
      array_diff_key(array_diff(mailsystem_get(), $setting), $setting)
 | 
						|
    )
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns a list of classes which implement MailSystemInterface.
 | 
						|
 */
 | 
						|
function &mailsystem_get_classes() {
 | 
						|
  // Load static cache.
 | 
						|
  $mailsystem_classes = &drupal_static(__FUNCTION__);
 | 
						|
  // Check persistent cache if necessary.
 | 
						|
  if (!isset($mailsystem_classes) && $cache = cache_get('mailsystem_get_classes')) {
 | 
						|
    $mailsystem_classes = $cache->data;
 | 
						|
  }
 | 
						|
  // Load from db if no cache was hit.
 | 
						|
  if (!isset($mailsystem_classes)) {
 | 
						|
    $mailsystem_classes = array();
 | 
						|
    // @todo Is there a better way to find all mail-related classes?
 | 
						|
    $declared_classes = get_declared_classes();
 | 
						|
    $all_classes = array_combine(
 | 
						|
      $declared_classes,
 | 
						|
      array_fill(0, count($declared_classes), 0)
 | 
						|
    );
 | 
						|
    $mail_classes = db_select('registry', 'registry')
 | 
						|
      ->distinct()
 | 
						|
      ->fields('registry', array('name', 'filename'))
 | 
						|
      ->where("type=:type AND ( filename like :filename OR name like :name )",
 | 
						|
        // Making the HUGE assumption that all classes which implement
 | 
						|
        // MailSystemInterface have filenames containing '.mail.' or
 | 
						|
        // classnames ending in 'MailSystem'.
 | 
						|
        array(
 | 
						|
          ':type' => 'class',
 | 
						|
          ':name' => '%MailSystem',
 | 
						|
          ':filename' => '%.mail.%',
 | 
						|
        )
 | 
						|
      )
 | 
						|
      ->execute()
 | 
						|
      ->fetchAllKeyed();
 | 
						|
    foreach ($mail_classes as $classname => $classfile) {
 | 
						|
      if (file_exists($classfile)
 | 
						|
        && drupal_autoload_class($classname)
 | 
						|
      ) {
 | 
						|
        $all_classes[$classname] = 1;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    foreach ($all_classes as $classname => $autoload) {
 | 
						|
      if (($autoload || preg_match('/MailSystem/', $classname))
 | 
						|
        && ($object = new $classname)
 | 
						|
        && ($object instanceof MailSystemInterface)
 | 
						|
      ) {
 | 
						|
        $mailsystem_classes[$classname] = $classname;
 | 
						|
      }
 | 
						|
      elseif ($autoload) {
 | 
						|
        // Clear classes that are no longer available.
 | 
						|
        db_delete('registry')
 | 
						|
          ->condition('name', $classname)
 | 
						|
          ->execute();
 | 
						|
      }
 | 
						|
    }
 | 
						|
    foreach (array_unique(mailsystem_get()) as $classname) {
 | 
						|
      if (class_exists($classname)) {
 | 
						|
        $mailsystem_classes[$classname] = $classname;
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        mailsystem_clear(array(mailsystem_default_id() => $classname));
 | 
						|
      }
 | 
						|
    }
 | 
						|
    ksort($mailsystem_classes);
 | 
						|
    // Store in persistent cache.
 | 
						|
    cache_set('mailsystem_get_classes', $mailsystem_classes, 'cache', CACHE_TEMPORARY);
 | 
						|
  }
 | 
						|
  return $mailsystem_classes;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
* Implements hook_theme_registry_alter().
 | 
						|
*/
 | 
						|
function mailsystem_theme_registry_alter(&$theme_registry) {
 | 
						|
  module_load_include('inc', 'mailsystem', 'mailsystem.theme');
 | 
						|
  return mailsystem_theme_theme_registry_alter($theme_registry);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Retrieves the key of the theme used to render the emails.
 | 
						|
 *
 | 
						|
 * @todo Add some kind of hook to let other modules alter this behavior.
 | 
						|
 */
 | 
						|
function mailsystem_get_mail_theme() {
 | 
						|
  global $theme_key;
 | 
						|
  $theme = variable_get('mailsystem_theme', 'current');
 | 
						|
  switch ($theme) {
 | 
						|
    case 'default':
 | 
						|
      $theme = variable_get('theme_default', NULL);
 | 
						|
      break;
 | 
						|
 | 
						|
    case 'current':
 | 
						|
      $theme = $theme_key;
 | 
						|
      break;
 | 
						|
 | 
						|
    case 'domain':
 | 
						|
      // Fetch the theme for the current domain.
 | 
						|
      if (module_exists('domain_theme')) {
 | 
						|
        // Assign the selected theme, based on the active domain.
 | 
						|
        global $_domain;
 | 
						|
        $domain_theme = domain_theme_lookup($_domain['domain_id']);
 | 
						|
        // The above returns -1 on failure.
 | 
						|
        $theme = ($domain_theme != -1) ? $domain_theme['theme'] : $theme_key;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
  }
 | 
						|
  return $theme;
 | 
						|
}
 |