- #1291750 by sun: Updated for new PHPMailer project home.
[project/phpmailer.git] / phpmailer.module
1 <?php
2
3 /**
4 * @file
5 * Integrates the PHPMailer library for SMTP e-mail delivery.
6 */
7
8 /**
9 * Implementation of hook_perm().
10 */
11 function phpmailer_permission() {
12 return array(
13 'administer phpmailer settings' => array(
14 'title' => t('Administer PHPMailer settings'),
15 'restrict access' => TRUE,
16 ),
17 );
18 }
19
20 /**
21 * Implementation of hook_menu().
22 */
23 function phpmailer_menu() {
24 $items['admin/config/system/phpmailer'] = array(
25 'title' => 'PHPMailer',
26 'description' => 'Configure PHPMailer settings.',
27 'page callback' => 'drupal_get_form',
28 'page arguments' => array('phpmailer_settings_form'),
29 'access arguments' => array('administer phpmailer settings'),
30 'file' => 'phpmailer.admin.inc',
31 );
32 // @todo Move to Mime Mail project.
33 $items['phpmailer/preview'] = array(
34 'title' => 'Mail preview',
35 'page callback' => 'phpmailer_preview',
36 'access callback' => 'phpmailer_preview_access',
37 'file' => 'phpmailer.admin.inc',
38 'type' => MENU_CALLBACK,
39 );
40 return $items;
41 }
42
43 /**
44 * Implementation of hook_form_FORM_ID_alter().
45 */
46 function phpmailer_form_mimemail_admin_settings_alter(&$form, &$form_state) {
47 // Hide the Mime Mail global enabler setting if phpmailer is used to deliver
48 // e-mails (they can't be both active).
49 if (phpmailer_enabled()) {
50 $mimemail_alter = &$form['mimemail']['mimemail_alter'];
51 $mimemail_alter['#disabled'] = TRUE;
52 $mimemail_alter['#default_value'] = 0;
53 $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')));
54 }
55 // @todo Move to MimeMail project.
56 $form['preview'] = array(
57 '#type' => 'item',
58 '#title' => t('Preview'),
59 '#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'))),
60 );
61 $form['buttons']['#weight'] = 10;
62 }
63
64 /**
65 * Determine if PHPMailer is used to deliver e-mails.
66 */
67 function phpmailer_enabled() {
68 // We need to rely on our 'smtp_on' variable, since PHPMailer may not be
69 // configured as the default mail system.
70 return (bool) variable_get('smtp_on', 0);
71 }
72
73 /**
74 * Implementation of hook_mailengine().
75 */
76 function phpmailer_mailengine($op, $message = array()) {
77 if (!phpmailer_library_exists()) {
78 return;
79 }
80
81 switch ($op) {
82 case 'list':
83 return array(
84 'name' => t('PHPMailer'),
85 'description' => t('Mailing engine using the PHPMailer library.'),
86 );
87
88 case 'settings':
89 $form['info']['#value'] = t('To configure your mail server settings, visit the <a href="@url">PHPMailer settings page</a>.', array('@url' => url('admin/config/system/phpmailer')));
90 return $form;
91
92 case 'multiple':
93 case 'single':
94 case 'send':
95 module_load_include('inc', 'phpmailer', 'includes/phpmailer.mimemail');
96 return mimemail_phpmailer_send($message);
97 }
98 }
99
100 /**
101 * Extract address and optional display name of an e-mail address.
102 *
103 * @param $string
104 * A string containing one or more valid e-mail address(es) separated with
105 * commas.
106 *
107 * @return
108 * An array containing all found e-mail addresses split into mail and name.
109 *
110 * @see http://tools.ietf.org/html/rfc5322#section-3.4
111 */
112 function phpmailer_parse_address($string) {
113 $parsed = array();
114
115 // The display name may contain commas (3.4). Extract all quoted strings
116 // (3.2.4) to a stack and replace them with a placeholder to prevent
117 // splitting at wrong places.
118 $string = preg_replace('/(".*?(?<!\\\\)")/e', '_phpmailer_stack("$1")', $string);
119
120 // Build a regex that matches a name-addr (3.4).
121 // @see valid_email_address()
122 $user = '[a-zA-Z0-9_\-\.\+\^!#\$%&*+\/\=\?\`\|\{\}~\']+';
123 $domain = '(?:(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.?)+';
124 $ipv4 = '[0-9]{1,3}(?:\.[0-9]{1,3}){3}';
125 $ipv6 = '[0-9a-fA-F]{1,4}(?:\:[0-9a-fA-F]{1,4}){7}';
126 $address = "$user@(?:$domain|(?:\[(?:$ipv4|$ipv6)\]))";
127 $adr_rx = "/^(?P<name>.*)\s<(?P<address>$address)>$/";
128
129 // Split string into multiple parts and process each.
130 foreach (explode(',', $string) as $email) {
131 // Re-inject stripped placeholders.
132 $email = preg_replace('/\x01/e', '_phpmailer_stack()', trim($email));
133 // Check if it's a name-addr or a plain address (3.4).
134 if (preg_match($adr_rx, $email, $matches)) {
135 // PHPMailer expects an unencoded display name.
136 $parsed[] = array('mail' => $matches['address'], 'name' => mime_header_decode(stripslashes($matches['name'])));
137 }
138 else {
139 $parsed[] = array('mail' => trim($email, '<>'), 'name' => '');
140 }
141 }
142 return $parsed;
143 }
144
145 /**
146 * Implements a FIFO stack to store extracted quoted strings.
147 */
148 function _phpmailer_stack($string = NULL) {
149 static $stack = array();
150
151 if (!isset($string)) {
152 // Unescape quoted characters (3.2.4) to prevent double escaping.
153 return str_replace(array('\"', '\\\\'), array('"', '\\'), array_shift($stack));
154 }
155 // Remove surrounding quotes and push on stack.
156 array_push($stack, substr($string, 1, -1));
157 // Return placeholder substitution. 0x01 may never appear outside a quoted
158 // string (3.2.3).
159 return "\x01";
160 }
161
162 /**
163 * Menu access callback; Determine access for HTML mail preview page.
164 */
165 function phpmailer_preview_access() {
166 if (module_exists('mimemail')) {
167 return user_access('administer phpmailer settings');
168 }
169 return FALSE;
170 }
171
172 /**
173 * Implementation of hook_enable().
174 */
175 function phpmailer_enable() {
176 if (!phpmailer_enabled() && !(module_exists('mimemail') && variable_get('mimemail_engine', 'mimemail') == 'phpmailer')) {
177 $t = get_t();
178 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'))));
179 }
180 }
181
182 /**
183 * Implementation of hook_disable().
184 */
185 function phpmailer_disable() {
186 if (phpmailer_enabled()) {
187 // Remove PHPMailer from all mail keys it is configured for.
188 $mail_system = variable_get('mail_system', array('default-system' => 'DefaultMailSystem'));
189 foreach ($mail_system as $key => $class) {
190 if ($class == 'DrupalPHPMailer') {
191 if ($key != 'default-system') {
192 unset($mail_system[$key]);
193 }
194 else {
195 $mail_system[$key] = 'DefaultMailSystem';
196 }
197 }
198 }
199 variable_set('mail_system', $mail_system);
200
201 variable_del('smtp_on');
202 drupal_set_message(t('PHPMailer has been disabled.'));
203 }
204 if (module_exists('mimemail') && variable_get('mimemail_engine', 'mimemail') == 'phpmailer') {
205 variable_del('mimemail_engine');
206 drupal_set_message(t('MimeMail e-mail engine has been reset to default.'), 'warning');
207 }
208 }
209
210 /**
211 * Implements hook_registry_files_alter().
212 *
213 * @todo Consider to move this into Libraries API.
214 */
215 function phpmailer_registry_files_alter(&$files, $modules) {
216 $library_path = libraries_get_path('phpmailer');
217 if (!$library_path) {
218 return;
219 }
220 foreach (array('class.phpmailer.php', 'class.smtp.php') as $filename) {
221 $files[$library_path . '/' . $filename] = array(
222 'module' => 'phpmailer',
223 'weight' => 0,
224 );
225 }
226 }
227
228 /**
229 * Verify that PHPMailer libraries exist.
230 */
231 function phpmailer_library_exists() {
232 $library_path = libraries_get_path('phpmailer');
233 if (!$library_path) {
234 return FALSE;
235 }
236 foreach (array('class.phpmailer.php', 'class.smtp.php') as $filename) {
237 if (!file_exists(DRUPAL_ROOT . '/' . $library_path . '/' . $filename)) {
238 return FALSE;
239 }
240 }
241 return TRUE;
242 }