summaryrefslogtreecommitdiffstats
path: root/phpmailer.module
blob: 1869888ed783c5f03f547939e01dacc591493877 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
<?php

/**
 * @file
 * Integrates the PHPMailer library for SMTP e-mail delivery.
 */

/**
 * Implementation of hook_perm().
 */
function phpmailer_permission() {
  return array(
    'administer phpmailer settings' => array(
      'title' => t('Administer PHPMailer settings'),
      'restrict access' => TRUE,
    ),
  );
}

/**
 * Implementation of hook_menu().
 */
function phpmailer_menu() {
  $items['admin/config/system/phpmailer'] = array(
    'title' => 'PHPMailer',
    'description' => 'Configure PHPMailer settings.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('phpmailer_settings_form'),
    'access arguments' => array('administer phpmailer settings'),
    'file' => 'phpmailer.admin.inc',
  );
  // @todo Move to Mime Mail project.
  $items['phpmailer/preview'] = array(
    'title' => 'Mail preview',
    'page callback' => 'phpmailer_preview',
    'access callback' => 'phpmailer_preview_access',
    'file' => 'phpmailer.admin.inc',
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implementation of hook_form_FORM_ID_alter().
 */
function phpmailer_form_mimemail_admin_settings_alter(&$form, &$form_state) {
  // Hide the Mime Mail global enabler setting if phpmailer is used to deliver
  // e-mails (they can't be both active).
  if (phpmailer_enabled()) {
    $mimemail_alter = &$form['mimemail']['mimemail_alter'];
    $mimemail_alter['#disabled'] = TRUE;
    $mimemail_alter['#default_value'] = 0;
    $mimemail_alter['#description'] = t('PHPMailer has been set to deliver all site messages. To let Mime Mail apply styles and formatting to system e-mails but still use PHPMailer for mail transport, uncheck <em>Use PHPMailer to send e-mails</em> first on the <a href="@url">PHPMailer settings page</a>. Then activate this setting and choose PHPMailer from the list of e-mail engines below.', array('@url' => url('admin/config/system/phpmailer')));
  }
  // @todo Move to MimeMail project.
  $form['preview'] = array(
    '#type' => 'item',
    '#title' => t('Preview'),
    '#value' => t('See a <a href="@url" target="_blank">preview of a styled e-mail</a> using the current message template (<code>mimemail-message.tpl.php</code>).', array('@url' => url('phpmailer/preview'))),
  );
  $form['buttons']['#weight'] = 10;
}

/**
 * Determine if PHPMailer is used to deliver e-mails.
 */
function phpmailer_enabled() {
  // We need to rely on our 'smtp_on' variable, since PHPMailer may not be
  // configured as the default mail system.
  return (bool) variable_get('smtp_on', 0);
}

/**
 * Implementation of hook_mailengine().
 */
function phpmailer_mailengine($op, $message = array()) {
  if (!phpmailer_library_exists()) {
    return;
  }

  switch ($op) {
    case 'list':
      return array(
        'name' => t('PHPMailer'),
        'description' => t('Mailing engine using the PHPMailer library.'),
      );

    case 'settings':
      $form['info']['#markup'] = t('To configure your mail server settings, visit the <a href="@url">PHPMailer settings page</a>.', array('@url' => url('admin/config/system/phpmailer')));
      return $form;

    case 'multiple':
    case 'single':
    case 'send':
      module_load_include('inc', 'phpmailer', 'includes/phpmailer.mimemail');
      // Mimemail API does not load mimemail.inc for other mailengines; we rely
      // on mimemail_rfc_headers(), so ensure that it is loaded.
      module_load_include('inc', 'mimemail');
      return mimemail_phpmailer_send($message);
  }
}

/**
 * Extract address and optional display name of an e-mail address.
 *
 * @param $string
 *   A string containing one or more valid e-mail address(es) separated with
 *   commas.
 *
 * @return
 *   An array containing all found e-mail addresses split into mail and name.
 *
 * @see http://tools.ietf.org/html/rfc5322#section-3.4
 */
function phpmailer_parse_address($string) {
  $parsed = array();

  // The display name may contain commas (3.4). Extract all quoted strings
  // (3.2.4) to a stack and replace them with a placeholder to prevent
  // splitting at wrong places.
  $string = preg_replace_callback('(".*?(?<!\\\\)")', '_phpmailer_stack', $string);

  // Build a regex that matches a name-addr (3.4).
  // @see valid_email_address()
  $user = '[a-zA-Z0-9_\-\.\+\^!#\$%&*+\/\=\?\`\|\{\}~\']+';
  $domain = '(?:(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.?)+';
  $ipv4 = '[0-9]{1,3}(?:\.[0-9]{1,3}){3}';
  $ipv6 = '[0-9a-fA-F]{1,4}(?:\:[0-9a-fA-F]{1,4}){7}';
  $address = "$user@(?:$domain|(?:\[(?:$ipv4|$ipv6)\]))";
  $adr_rx = "/^(?P<name>.*)\s<(?P<address>$address)>$/";

  // Split string into multiple parts and process each.
  foreach (explode(',', $string) as $email) {
    // Re-inject stripped placeholders.
    $email = preg_replace_callback('(\x01)', '_phpmailer_stack', trim($email));
    // Check if it's a name-addr or a plain address (3.4).
    if (preg_match($adr_rx, $email, $matches)) {
      // PHPMailer expects an unencoded display name.
      $parsed[] = array('mail' => $matches['address'], 'name' => mime_header_decode(stripslashes($matches['name'])));
    }
    else {
      $parsed[] = array('mail' => trim($email, '<>'), 'name' => '');
    }
  }
  return $parsed;
}

/**
 * Implements a FIFO stack to store extracted quoted strings.
 */
function _phpmailer_stack($matches = NULL) {
  $string = $matches[0];
  static $stack = array();

  if ($string == "\x01") {
    // Unescape quoted characters (3.2.4) to prevent double escaping.
    return str_replace(array('\"', '\\\\'), array('"', '\\'), array_shift($stack));
  }
  // Remove surrounding quotes and push on stack.
  array_push($stack, substr($string, 1, -1));
  // Return placeholder substitution. 0x01 may never appear outside a quoted
  // string (3.2.3).
  return "\x01";
}

/**
 * Menu access callback; Determine access for HTML mail preview page.
 */
function phpmailer_preview_access() {
  if (module_exists('mimemail')) {
    return user_access('administer phpmailer settings');
  }
  return FALSE;
}

/**
 * Implementation of hook_enable().
 */
function phpmailer_enable() {
  if (!phpmailer_enabled() && !(module_exists('mimemail') && variable_get('mimemail_engine', 'mimemail') == 'phpmailer')) {
    $t = get_t();
    drupal_set_message($t('PHPMailer has been installed, but is currently disabled. <a href="@settings-url">Configure it now</a>.', array('@settings-url' => url('admin/config/system/phpmailer'))));
  }

  if (module_exists('mailsystem')) {
    mailsystem_set(array('phpmailer' => 'DrupalPHPMailer'));
  }
}

/**
 * Implementation of hook_disable().
 */
function phpmailer_disable() {
  if (phpmailer_enabled()) {
    // Remove PHPMailer from all mail keys it is configured for.
    $mail_system = variable_get('mail_system', array('default-system' => 'DefaultMailSystem'));
    foreach ($mail_system as $key => $class) {
      if ($class == 'DrupalPHPMailer') {
        if ($key != 'default-system') {
          unset($mail_system[$key]);
        }
        else {
          $mail_system[$key] = 'DefaultMailSystem';
        }
      }
    }
    variable_set('mail_system', $mail_system);

    variable_del('smtp_on');
    drupal_set_message(t('PHPMailer has been disabled.'));
  }
  if (module_exists('mimemail') && variable_get('mimemail_engine', 'mimemail') == 'phpmailer') {
    variable_del('mimemail_engine');
    drupal_set_message(t('MimeMail e-mail engine has been reset to default.'), 'warning');
  }

  if (module_exists('mailsystem')) {
    mailsystem_clear(array('phpmailer' => 'DrupalPHPMailer'));
  }
}

/**
 * Implements hook_registry_files_alter().
 *
 * @todo Consider to move this into Libraries API.
 */
function phpmailer_registry_files_alter(&$files, $modules) {
  $library_path = libraries_get_path('phpmailer');
  if (!$library_path) {
    return;
  }
  foreach (array('class.phpmailer.php', 'class.smtp.php') as $filename) {
    $files[$library_path . '/' . $filename] = array(
      'module' => 'phpmailer',
      'weight' => 0,
    );
  }
}

/**
 * Verify that PHPMailer libraries exist.
 */
function phpmailer_library_exists() {
  $library_path = libraries_get_path('phpmailer');
  if (!$library_path) {
    return FALSE;
  }
  foreach (array('class.phpmailer.php', 'class.smtp.php') as $filename) {
    if (!file_exists(DRUPAL_ROOT . '/' . $library_path . '/' . $filename)) {
      return FALSE;
    }
  }
  return TRUE;
}