phpBB
Statistics
| Revision:

root / trunk / phpBB / includes / functions_messenger.php

History | View | Annotate | Download (43.2 kB)

1 4553 psotfx
<?php
2 7736 acydburn
/**
3 5114 acydburn
*
4 5114 acydburn
* @package phpBB3
5 7736 acydburn
* @copyright (c) 2005 phpBB Group
6 11653 git-gate
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
7 5114 acydburn
*
8 5114 acydburn
*/
9 4553 psotfx
10 5114 acydburn
/**
11 8146 acydburn
* @ignore
12 8146 acydburn
*/
13 8146 acydburn
if (!defined('IN_PHPBB'))
14 8146 acydburn
{
15 8146 acydburn
        exit;
16 8146 acydburn
}
17 8146 acydburn
18 8146 acydburn
/**
19 6058 acydburn
* Messenger
20 5114 acydburn
* @package phpBB3
21 5114 acydburn
*/
22 4553 psotfx
class messenger
23 4553 psotfx
{
24 6380 naderman
        var $vars, $msg, $extra_headers, $replyto, $from, $subject;
25 5023 acydburn
        var $addresses = array();
26 4553 psotfx
27 4777 acydburn
        var $mail_priority = MAIL_NORMAL_PRIORITY;
28 5023 acydburn
        var $use_queue = true;
29 9823 acydburn
30 9823 acydburn
        var $tpl_obj = NULL;
31 4553 psotfx
        var $tpl_msg = array();
32 9364 acydburn
        var $eol = "\n";
33 4553 psotfx
34 6015 acydburn
        /**
35 6015 acydburn
        * Constructor
36 6015 acydburn
        */
37 4777 acydburn
        function messenger($use_queue = true)
38 4583 psotfx
        {
39 7909 acydburn
                global $config;
40 7909 acydburn
41 7909 acydburn
                $this->use_queue = (!$config['email_package_size']) ? false : $use_queue;
42 5023 acydburn
                $this->subject = '';
43 9364 acydburn
44 9364 acydburn
                // Determine EOL character (\n for UNIX, \r\n for Windows and \r for Mac)
45 9364 acydburn
                $this->eol = (!defined('PHP_EOL')) ? (($eol = strtolower(substr(PHP_OS, 0, 3))) == 'win') ? "\r\n" : (($eol == 'mac') ? "\r" : "\n") : PHP_EOL;
46 9427 acydburn
                $this->eol = (!$this->eol) ? "\n" : $this->eol;
47 4583 psotfx
        }
48 4583 psotfx
49 6015 acydburn
        /**
50 6015 acydburn
        * Resets all the data (address, template file, etc etc) to default
51 6015 acydburn
        */
52 4553 psotfx
        function reset()
53 4553 psotfx
        {
54 6564 acydburn
                $this->addresses = $this->extra_headers = array();
55 6564 acydburn
                $this->vars = $this->msg = $this->replyto = $this->from = '';
56 4777 acydburn
                $this->mail_priority = MAIL_NORMAL_PRIORITY;
57 4553 psotfx
        }
58 4553 psotfx
59 6015 acydburn
        /**
60 6015 acydburn
        * Sets an email address to send to
61 6015 acydburn
        */
62 4553 psotfx
        function to($address, $realname = '')
63 4553 psotfx
        {
64 6803 acydburn
                global $config;
65 6803 acydburn
66 9389 acydburn
                if (!trim($address))
67 9389 acydburn
                {
68 9389 acydburn
                        return;
69 9389 acydburn
                }
70 9389 acydburn
71 5003 acydburn
                $pos = isset($this->addresses['to']) ? sizeof($this->addresses['to']) : 0;
72 6803 acydburn
73 4553 psotfx
                $this->addresses['to'][$pos]['email'] = trim($address);
74 6803 acydburn
75 6803 acydburn
                // If empty sendmail_path on windows, PHP changes the to line
76 7830 acydburn
                if (!$config['smtp_delivery'] && DIRECTORY_SEPARATOR == '\\')
77 6803 acydburn
                {
78 6803 acydburn
                        $this->addresses['to'][$pos]['name'] = '';
79 6803 acydburn
                }
80 6803 acydburn
                else
81 6803 acydburn
                {
82 6803 acydburn
                        $this->addresses['to'][$pos]['name'] = trim($realname);
83 6803 acydburn
                }
84 4553 psotfx
        }
85 4553 psotfx
86 6015 acydburn
        /**
87 6015 acydburn
        * Sets an cc address to send to
88 6015 acydburn
        */
89 4553 psotfx
        function cc($address, $realname = '')
90 4553 psotfx
        {
91 9389 acydburn
                if (!trim($address))
92 9389 acydburn
                {
93 9389 acydburn
                        return;
94 9389 acydburn
                }
95 9389 acydburn
96 5003 acydburn
                $pos = isset($this->addresses['cc']) ? sizeof($this->addresses['cc']) : 0;
97 4553 psotfx
                $this->addresses['cc'][$pos]['email'] = trim($address);
98 4805 acydburn
                $this->addresses['cc'][$pos]['name'] = trim($realname);
99 4553 psotfx
        }
100 4553 psotfx
101 6015 acydburn
        /**
102 6015 acydburn
        * Sets an bcc address to send to
103 6015 acydburn
        */
104 4553 psotfx
        function bcc($address, $realname = '')
105 4553 psotfx
        {
106 9389 acydburn
                if (!trim($address))
107 9389 acydburn
                {
108 9389 acydburn
                        return;
109 9389 acydburn
                }
110 9389 acydburn
111 5003 acydburn
                $pos = isset($this->addresses['bcc']) ? sizeof($this->addresses['bcc']) : 0;
112 4553 psotfx
                $this->addresses['bcc'][$pos]['email'] = trim($address);
113 5003 acydburn
                $this->addresses['bcc'][$pos]['name'] = trim($realname);
114 4553 psotfx
        }
115 4553 psotfx
116 6015 acydburn
        /**
117 6015 acydburn
        * Sets a im contact to send to
118 6015 acydburn
        */
119 4583 psotfx
        function im($address, $realname = '')
120 4583 psotfx
        {
121 9078 acydburn
                // IM-Addresses could be empty
122 9389 acydburn
                if (!trim($address))
123 9078 acydburn
                {
124 9078 acydburn
                        return;
125 9078 acydburn
                }
126 9078 acydburn
127 5003 acydburn
                $pos = isset($this->addresses['im']) ? sizeof($this->addresses['im']) : 0;
128 4583 psotfx
                $this->addresses['im'][$pos]['uid'] = trim($address);
129 4583 psotfx
                $this->addresses['im'][$pos]['name'] = trim($realname);
130 4583 psotfx
        }
131 4583 psotfx
132 6015 acydburn
        /**
133 6015 acydburn
        * Set the reply to address
134 6015 acydburn
        */
135 4553 psotfx
        function replyto($address)
136 4553 psotfx
        {
137 4553 psotfx
                $this->replyto = trim($address);
138 4553 psotfx
        }
139 4553 psotfx
140 6015 acydburn
        /**
141 6015 acydburn
        * Set the from address
142 6015 acydburn
        */
143 4553 psotfx
        function from($address)
144 4553 psotfx
        {
145 4553 psotfx
                $this->from = trim($address);
146 4553 psotfx
        }
147 4553 psotfx
148 6015 acydburn
        /**
149 6015 acydburn
        * set up subject for mail
150 6015 acydburn
        */
151 4553 psotfx
        function subject($subject = '')
152 4553 psotfx
        {
153 4553 psotfx
                $this->subject = trim($subject);
154 4553 psotfx
        }
155 4553 psotfx
156 6015 acydburn
        /**
157 6015 acydburn
        * set up extra mail headers
158 6015 acydburn
        */
159 4553 psotfx
        function headers($headers)
160 4553 psotfx
        {
161 6564 acydburn
                $this->extra_headers[] = trim($headers);
162 4553 psotfx
        }
163 4553 psotfx
164 6015 acydburn
        /**
165 11567 git-gate
        * Adds X-AntiAbuse headers
166 11567 git-gate
        *
167 11567 git-gate
        * @param array $config                Configuration array
168 11567 git-gate
        * @param user $user                        A user object
169 11567 git-gate
        *
170 11567 git-gate
        * @return null
171 11567 git-gate
        */
172 11567 git-gate
        function anti_abuse_headers($config, $user)
173 11567 git-gate
        {
174 11567 git-gate
                $this->headers('X-AntiAbuse: Board servername - ' . mail_encode($config['server_name']));
175 11567 git-gate
                $this->headers('X-AntiAbuse: User_id - ' . $user->data['user_id']);
176 11567 git-gate
                $this->headers('X-AntiAbuse: Username - ' . mail_encode($user->data['username']));
177 11567 git-gate
                $this->headers('X-AntiAbuse: User IP - ' . $user->ip);
178 11567 git-gate
        }
179 11567 git-gate
180 11567 git-gate
        /**
181 6015 acydburn
        * Set the email priority
182 6015 acydburn
        */
183 4777 acydburn
        function set_mail_priority($priority = MAIL_NORMAL_PRIORITY)
184 4777 acydburn
        {
185 4777 acydburn
                $this->mail_priority = $priority;
186 4777 acydburn
        }
187 4777 acydburn
188 6015 acydburn
        /**
189 6015 acydburn
        * Set email template to use
190 6015 acydburn
        */
191 9957 acydburn
        function template($template_file, $template_lang = '', $template_path = '')
192 4553 psotfx
        {
193 11557 git-gate
                global $config, $phpbb_root_path, $phpEx, $user, $phpbb_extension_manager;
194 4553 psotfx
195 4553 psotfx
                if (!trim($template_file))
196 4553 psotfx
                {
197 9823 acydburn
                        trigger_error('No template file for emailing set.', E_USER_ERROR);
198 4553 psotfx
                }
199 4553 psotfx
200 4553 psotfx
                if (!trim($template_lang))
201 4553 psotfx
                {
202 10558 git-gate
                        // fall back to board default language if the user's language is
203 10558 git-gate
                        // missing $template_file.  If this does not exist either,
204 10558 git-gate
                        // $tpl->set_custom_template will do a trigger_error
205 6015 acydburn
                        $template_lang = basename($config['default_lang']);
206 4553 psotfx
                }
207 4553 psotfx
208 9823 acydburn
                // tpl_msg now holds a template object we can use to parse the template file
209 9823 acydburn
                if (!isset($this->tpl_msg[$template_lang . $template_file]))
210 4553 psotfx
                {
211 11358 git-gate
                        $template_locator = new phpbb_template_locator();
212 11557 git-gate
                        $template_path_provider = new phpbb_template_extension_path_provider($phpbb_extension_manager, new phpbb_template_path_provider());
213 11557 git-gate
                        $this->tpl_msg[$template_lang . $template_file] = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $template_locator, $template_path_provider);
214 9823 acydburn
                        $tpl = &$this->tpl_msg[$template_lang . $template_file];
215 4553 psotfx
216 10558 git-gate
                        $fallback_template_path = false;
217 10558 git-gate
218 9957 acydburn
                        if (!$template_path)
219 9957 acydburn
                        {
220 9957 acydburn
                                $template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/';
221 9957 acydburn
                                $template_path .= $template_lang . '/email';
222 10558 git-gate
223 10558 git-gate
                                // we can only specify default language fallback when the path is not a custom one for which we
224 10558 git-gate
                                // do not know the default language alternative
225 10558 git-gate
                                if ($template_lang !== basename($config['default_lang']))
226 10558 git-gate
                                {
227 10558 git-gate
                                        $fallback_template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/';
228 10558 git-gate
                                        $fallback_template_path .= basename($config['default_lang']) . '/email';
229 10558 git-gate
                                }
230 9957 acydburn
                        }
231 4553 psotfx
232 10558 git-gate
                        $tpl->set_custom_template($template_path, $template_lang . '_email', $fallback_template_path);
233 4553 psotfx
234 9823 acydburn
                        $tpl->set_filenames(array(
235 9823 acydburn
                                'body'                => $template_file . '.txt',
236 9823 acydburn
                        ));
237 4553 psotfx
                }
238 4553 psotfx
239 9823 acydburn
                $this->tpl_obj = &$this->tpl_msg[$template_lang . $template_file];
240 9823 acydburn
                $this->vars = &$this->tpl_obj->_rootref;
241 9823 acydburn
                $this->tpl_msg = '';
242 4553 psotfx
243 4553 psotfx
                return true;
244 4553 psotfx
        }
245 4553 psotfx
246 6015 acydburn
        /**
247 6015 acydburn
        * assign variables to email template
248 6015 acydburn
        */
249 4553 psotfx
        function assign_vars($vars)
250 4553 psotfx
        {
251 9823 acydburn
                if (!is_object($this->tpl_obj))
252 9823 acydburn
                {
253 9823 acydburn
                        return;
254 9823 acydburn
                }
255 9823 acydburn
256 9823 acydburn
                $this->tpl_obj->assign_vars($vars);
257 4553 psotfx
        }
258 4553 psotfx
259 9823 acydburn
        function assign_block_vars($blockname, $vars)
260 9823 acydburn
        {
261 9823 acydburn
                if (!is_object($this->tpl_obj))
262 9823 acydburn
                {
263 9823 acydburn
                        return;
264 9823 acydburn
                }
265 9823 acydburn
266 9823 acydburn
                $this->tpl_obj->assign_block_vars($blockname, $vars);
267 9823 acydburn
        }
268 9823 acydburn
269 6015 acydburn
        /**
270 6015 acydburn
        * Send the mail out to the recipients set previously in var $this->addresses
271 6015 acydburn
        */
272 4978 acydburn
        function send($method = NOTIFY_EMAIL, $break = false)
273 4553 psotfx
        {
274 4553 psotfx
                global $config, $user;
275 4553 psotfx
276 6546 acydburn
                // We add some standard variables we always use, no need to specify them always
277 9823 acydburn
                if (!isset($this->vars['U_BOARD']))
278 9823 acydburn
                {
279 9823 acydburn
                        $this->assign_vars(array(
280 9823 acydburn
                                'U_BOARD'        => generate_board_url(),
281 9823 acydburn
                        ));
282 9823 acydburn
                }
283 6546 acydburn
284 9823 acydburn
                if (!isset($this->vars['EMAIL_SIG']))
285 9823 acydburn
                {
286 9823 acydburn
                        $this->assign_vars(array(
287 9823 acydburn
                                'EMAIL_SIG'        => str_replace('<br />', "\n", "-- \n" . htmlspecialchars_decode($config['board_email_sig'])),
288 9823 acydburn
                        ));
289 9823 acydburn
                }
290 4553 psotfx
291 9823 acydburn
                if (!isset($this->vars['SITENAME']))
292 9823 acydburn
                {
293 9823 acydburn
                        $this->assign_vars(array(
294 9823 acydburn
                                'SITENAME'        => htmlspecialchars_decode($config['sitename']),
295 9823 acydburn
                        ));
296 9823 acydburn
                }
297 4553 psotfx
298 9823 acydburn
                // Parse message through template
299 9823 acydburn
                $this->msg = trim($this->tpl_obj->assign_display('body'));
300 9823 acydburn
301 10052 acydburn
                // Because we use \n for newlines in the body message we need to fix line encoding errors for those admins who uploaded email template files in the wrong encoding
302 10052 acydburn
                $this->msg = str_replace("\r\n", "\n", $this->msg);
303 10052 acydburn
304 4553 psotfx
                // We now try and pull a subject from the email body ... if it exists,
305 4553 psotfx
                // do this here because the subject may contain a variable
306 4553 psotfx
                $drop_header = '';
307 4553 psotfx
                $match = array();
308 4553 psotfx
                if (preg_match('#^(Subject:(.*?))$#m', $this->msg, $match))
309 4553 psotfx
                {
310 6977 acydburn
                        $this->subject = (trim($match[2]) != '') ? trim($match[2]) : (($this->subject != '') ? $this->subject : $user->lang['NO_EMAIL_SUBJECT']);
311 4553 psotfx
                        $drop_header .= '[\r\n]*?' . preg_quote($match[1], '#');
312 4553 psotfx
                }
313 4553 psotfx
                else
314 4553 psotfx
                {
315 6977 acydburn
                        $this->subject = (($this->subject != '') ? $this->subject : $user->lang['NO_EMAIL_SUBJECT']);
316 4553 psotfx
                }
317 4553 psotfx
318 4553 psotfx
                if ($drop_header)
319 4553 psotfx
                {
320 4553 psotfx
                        $this->msg = trim(preg_replace('#' . $drop_header . '#s', '', $this->msg));
321 4553 psotfx
                }
322 4553 psotfx
323 4978 acydburn
                if ($break)
324 4978 acydburn
                {
325 5967 acydburn
                        return true;
326 4978 acydburn
                }
327 4978 acydburn
328 4553 psotfx
                switch ($method)
329 4553 psotfx
                {
330 4553 psotfx
                        case NOTIFY_EMAIL:
331 4898 acydburn
                                $result = $this->msg_email();
332 5784 acydburn
                        break;
333 5784 acydburn
334 4553 psotfx
                        case NOTIFY_IM:
335 4805 acydburn
                                $result = $this->msg_jabber();
336 5784 acydburn
                        break;
337 6015 acydburn
338 4553 psotfx
                        case NOTIFY_BOTH:
339 4898 acydburn
                                $result = $this->msg_email();
340 4553 psotfx
                                $this->msg_jabber();
341 5784 acydburn
                        break;
342 4553 psotfx
                }
343 4553 psotfx
344 4553 psotfx
                $this->reset();
345 4805 acydburn
                return $result;
346 4553 psotfx
        }
347 4553 psotfx
348 6015 acydburn
        /**
349 6015 acydburn
        * Add error message to log
350 6015 acydburn
        */
351 4553 psotfx
        function error($type, $msg)
352 4553 psotfx
        {
353 11368 git-gate
                global $user, $phpEx, $phpbb_root_path, $config, $request;
354 4553 psotfx
355 4595 psotfx
                // Session doesn't exist, create it
356 6057 grahamje
                if (!isset($user->session_id) || $user->session_id === '')
357 6057 grahamje
                {
358 6057 grahamje
                        $user->session_begin();
359 6057 grahamje
                }
360 4595 psotfx
361 11368 git-gate
                $calling_page = htmlspecialchars_decode($request->server('PHP_SELF'));
362 6715 acydburn
363 6715 acydburn
                $message = '';
364 6715 acydburn
                switch ($type)
365 6715 acydburn
                {
366 6715 acydburn
                        case 'EMAIL':
367 6715 acydburn
                                $message = '<strong>EMAIL/' . (($config['smtp_delivery']) ? 'SMTP' : 'PHP/' . $config['email_function_name'] . '()') . '</strong>';
368 6715 acydburn
                        break;
369 6715 acydburn
370 6715 acydburn
                        default:
371 6715 acydburn
                                $message = "<strong>$type</strong>";
372 6715 acydburn
                        break;
373 6715 acydburn
                }
374 6715 acydburn
375 8075 acydburn
                $message .= '<br /><em>' . htmlspecialchars($calling_page) . '</em><br /><br />' . $msg . '<br />';
376 6715 acydburn
                add_log('critical', 'LOG_ERROR_' . $type, $message);
377 4553 psotfx
        }
378 4553 psotfx
379 6015 acydburn
        /**
380 6015 acydburn
        * Save to queue
381 6015 acydburn
        */
382 5114 acydburn
        function save_queue()
383 5114 acydburn
        {
384 5194 acydburn
                global $config;
385 5194 acydburn
386 5194 acydburn
                if ($config['email_package_size'] && $this->use_queue && !empty($this->queue))
387 5114 acydburn
                {
388 5114 acydburn
                        $this->queue->save();
389 7909 acydburn
                        return;
390 5114 acydburn
                }
391 5114 acydburn
        }
392 4553 psotfx
393 6015 acydburn
        /**
394 6564 acydburn
        * Return email header
395 6564 acydburn
        */
396 6564 acydburn
        function build_header($to, $cc, $bcc)
397 6564 acydburn
        {
398 6564 acydburn
                global $config;
399 6564 acydburn
400 9364 acydburn
                // We could use keys here, but we won't do this for 3.0.x to retain backwards compatibility
401 6564 acydburn
                $headers = array();
402 6564 acydburn
403 6564 acydburn
                $headers[] = 'From: ' . $this->from;
404 6564 acydburn
405 6564 acydburn
                if ($cc)
406 6564 acydburn
                {
407 6564 acydburn
                        $headers[] = 'Cc: ' . $cc;
408 6564 acydburn
                }
409 6564 acydburn
410 6564 acydburn
                if ($bcc)
411 6564 acydburn
                {
412 6564 acydburn
                        $headers[] = 'Bcc: ' . $bcc;
413 6564 acydburn
                }
414 6564 acydburn
415 6564 acydburn
                $headers[] = 'Reply-To: ' . $this->replyto;
416 6564 acydburn
                $headers[] = 'Return-Path: <' . $config['board_email'] . '>';
417 6564 acydburn
                $headers[] = 'Sender: <' . $config['board_email'] . '>';
418 6564 acydburn
                $headers[] = 'MIME-Version: 1.0';
419 6564 acydburn
                $headers[] = 'Message-ID: <' . md5(unique_id(time())) . '@' . $config['server_name'] . '>';
420 8232 acydburn
                $headers[] = 'Date: ' . date('r', time());
421 6564 acydburn
                $headers[] = 'Content-Type: text/plain; charset=UTF-8'; // format=flowed
422 6564 acydburn
                $headers[] = 'Content-Transfer-Encoding: 8bit'; // 7bit
423 6564 acydburn
424 6564 acydburn
                $headers[] = 'X-Priority: ' . $this->mail_priority;
425 6564 acydburn
                $headers[] = 'X-MSMail-Priority: ' . (($this->mail_priority == MAIL_LOW_PRIORITY) ? 'Low' : (($this->mail_priority == MAIL_NORMAL_PRIORITY) ? 'Normal' : 'High'));
426 10014 acydburn
                $headers[] = 'X-Mailer: phpBB3';
427 6564 acydburn
                $headers[] = 'X-MimeOLE: phpBB3';
428 6564 acydburn
                $headers[] = 'X-phpBB-Origin: phpbb://' . str_replace(array('http://', 'https://'), array('', ''), generate_board_url());
429 6564 acydburn
430 6564 acydburn
                if (sizeof($this->extra_headers))
431 6564 acydburn
                {
432 9364 acydburn
                        $headers = array_merge($headers, $this->extra_headers);
433 6564 acydburn
                }
434 6564 acydburn
435 9364 acydburn
                return $headers;
436 6564 acydburn
        }
437 6564 acydburn
438 6564 acydburn
        /**
439 6015 acydburn
        * Send out emails
440 6015 acydburn
        */
441 4898 acydburn
        function msg_email()
442 4553 psotfx
        {
443 4553 psotfx
                global $config, $user;
444 4553 psotfx
445 4553 psotfx
                if (empty($config['email_enable']))
446 4553 psotfx
                {
447 4553 psotfx
                        return false;
448 4553 psotfx
                }
449 4553 psotfx
450 9389 acydburn
                // Addresses to send to?
451 9389 acydburn
                if (empty($this->addresses) || (empty($this->addresses['to']) && empty($this->addresses['cc']) && empty($this->addresses['bcc'])))
452 9389 acydburn
                {
453 9389 acydburn
                        // Send was successful. ;)
454 9389 acydburn
                        return true;
455 9389 acydburn
                }
456 9389 acydburn
457 4553 psotfx
                $use_queue = false;
458 4777 acydburn
                if ($config['email_package_size'] && $this->use_queue)
459 4553 psotfx
                {
460 4553 psotfx
                        if (empty($this->queue))
461 4553 psotfx
                        {
462 4553 psotfx
                                $this->queue = new queue();
463 4777 acydburn
                                $this->queue->init('email', $config['email_package_size']);
464 4553 psotfx
                        }
465 4553 psotfx
                        $use_queue = true;
466 4553 psotfx
                }
467 4553 psotfx
468 6564 acydburn
                if (empty($this->replyto))
469 6564 acydburn
                {
470 6826 acydburn
                        $this->replyto = '<' . $config['board_contact'] . '>';
471 6564 acydburn
                }
472 6564 acydburn
473 6564 acydburn
                if (empty($this->from))
474 6564 acydburn
                {
475 6827 acydburn
                        $this->from = '<' . $config['board_contact'] . '>';
476 6564 acydburn
                }
477 6564 acydburn
478 9530 toonarmy
                $encode_eol = ($config['smtp_delivery']) ? "\r\n" : $this->eol;
479 9530 toonarmy
480 6564 acydburn
                // Build to, cc and bcc strings
481 4553 psotfx
                $to = $cc = $bcc = '';
482 4553 psotfx
                foreach ($this->addresses as $type => $address_ary)
483 4553 psotfx
                {
484 5023 acydburn
                        if ($type == 'im')
485 5023 acydburn
                        {
486 5023 acydburn
                                continue;
487 5023 acydburn
                        }
488 5023 acydburn
489 4553 psotfx
                        foreach ($address_ary as $which_ary)
490 4553 psotfx
                        {
491 10011 toonarmy
                                $$type .= (($$type != '') ? ', ' : '') . (($which_ary['name'] != '') ? mail_encode($which_ary['name'], $encode_eol) . ' <' . $which_ary['email'] . '>' : $which_ary['email']);
492 4553 psotfx
                        }
493 4553 psotfx
                }
494 4553 psotfx
495 4553 psotfx
                // Build header
496 6564 acydburn
                $headers = $this->build_header($to, $cc, $bcc);
497 4553 psotfx
498 6380 naderman
                // Send message ...
499 4553 psotfx
                if (!$use_queue)
500 4553 psotfx
                {
501 8090 acydburn
                        $mail_to = ($to == '') ? 'undisclosed-recipients:;' : $to;
502 4553 psotfx
                        $err_msg = '';
503 4553 psotfx
504 6193 acydburn
                        if ($config['smtp_delivery'])
505 6193 acydburn
                        {
506 8034 acydburn
                                $result = smtpmail($this->addresses, mail_encode($this->subject), wordwrap(utf8_wordwrap($this->msg), 997, "\n", true), $err_msg, $headers);
507 6193 acydburn
                        }
508 6193 acydburn
                        else
509 6193 acydburn
                        {
510 10014 acydburn
                                $result = phpbb_mail($mail_to, $this->subject, $this->msg, $headers, $this->eol, $err_msg);
511 6193 acydburn
                        }
512 4778 psotfx
513 4553 psotfx
                        if (!$result)
514 4553 psotfx
                        {
515 6715 acydburn
                                $this->error('EMAIL', $err_msg);
516 4777 acydburn
                                return false;
517 4553 psotfx
                        }
518 4553 psotfx
                }
519 4553 psotfx
                else
520 4553 psotfx
                {
521 4553 psotfx
                        $this->queue->put('email', array(
522 4553 psotfx
                                'to'                        => $to,
523 4553 psotfx
                                'addresses'                => $this->addresses,
524 4553 psotfx
                                'subject'                => $this->subject,
525 4553 psotfx
                                'msg'                        => $this->msg,
526 4553 psotfx
                                'headers'                => $headers)
527 4553 psotfx
                        );
528 4553 psotfx
                }
529 4805 acydburn
530 4553 psotfx
                return true;
531 4553 psotfx
        }
532 4553 psotfx
533 6015 acydburn
        /**
534 6015 acydburn
        * Send jabber message out
535 6015 acydburn
        */
536 4553 psotfx
        function msg_jabber()
537 4553 psotfx
        {
538 4553 psotfx
                global $config, $db, $user, $phpbb_root_path, $phpEx;
539 4553 psotfx
540 4553 psotfx
                if (empty($config['jab_enable']) || empty($config['jab_host']) || empty($config['jab_username']) || empty($config['jab_password']))
541 4553 psotfx
                {
542 4553 psotfx
                        return false;
543 4553 psotfx
                }
544 4553 psotfx
545 9078 acydburn
                if (empty($this->addresses['im']))
546 9078 acydburn
                {
547 9389 acydburn
                        // Send was successful. ;)
548 9389 acydburn
                        return true;
549 9078 acydburn
                }
550 9078 acydburn
551 4553 psotfx
                $use_queue = false;
552 4777 acydburn
                if ($config['jab_package_size'] && $this->use_queue)
553 4553 psotfx
                {
554 4553 psotfx
                        if (empty($this->queue))
555 4553 psotfx
                        {
556 4553 psotfx
                                $this->queue = new queue();
557 4777 acydburn
                                $this->queue->init('jabber', $config['jab_package_size']);
558 4553 psotfx
                        }
559 4553 psotfx
                        $use_queue = true;
560 4553 psotfx
                }
561 4553 psotfx
562 4553 psotfx
                $addresses = array();
563 4583 psotfx
                foreach ($this->addresses['im'] as $type => $uid_ary)
564 4553 psotfx
                {
565 4583 psotfx
                        $addresses[] = $uid_ary['uid'];
566 4553 psotfx
                }
567 4553 psotfx
                $addresses = array_unique($addresses);
568 4553 psotfx
569 4553 psotfx
                if (!$use_queue)
570 4553 psotfx
                {
571 6771 acydburn
                        include_once($phpbb_root_path . 'includes/functions_jabber.' . $phpEx);
572 11646 git-gate
                        $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], htmlspecialchars_decode($config['jab_password']), $config['jab_use_ssl']);
573 4553 psotfx
574 5116 acydburn
                        if (!$this->jabber->connect())
575 4553 psotfx
                        {
576 8075 acydburn
                                $this->error('JABBER', $user->lang['ERR_JAB_CONNECT'] . '<br />' . $this->jabber->get_log());
577 4898 acydburn
                                return false;
578 4553 psotfx
                        }
579 4553 psotfx
580 7687 acydburn
                        if (!$this->jabber->login())
581 4553 psotfx
                        {
582 8075 acydburn
                                $this->error('JABBER', $user->lang['ERR_JAB_AUTH'] . '<br />' . $this->jabber->get_log());
583 4898 acydburn
                                return false;
584 4553 psotfx
                        }
585 4553 psotfx
586 4553 psotfx
                        foreach ($addresses as $address)
587 4553 psotfx
                        {
588 7687 acydburn
                                $this->jabber->send_message($address, $this->msg, $this->subject);
589 4553 psotfx
                        }
590 4553 psotfx
591 5116 acydburn
                        $this->jabber->disconnect();
592 4553 psotfx
                }
593 4553 psotfx
                else
594 4553 psotfx
                {
595 4553 psotfx
                        $this->queue->put('jabber', array(
596 4553 psotfx
                                'addresses'                => $addresses,
597 6015 acydburn
                                'subject'                => $this->subject,
598 6015 acydburn
                                'msg'                        => $this->msg)
599 4553 psotfx
                        );
600 4553 psotfx
                }
601 4553 psotfx
                unset($addresses);
602 4553 psotfx
                return true;
603 4553 psotfx
        }
604 4553 psotfx
}
605 4553 psotfx
606 5114 acydburn
/**
607 6058 acydburn
* handling email and jabber queue
608 5114 acydburn
* @package phpBB3
609 5114 acydburn
*/
610 4553 psotfx
class queue
611 4553 psotfx
{
612 4553 psotfx
        var $data = array();
613 4553 psotfx
        var $queue_data = array();
614 4553 psotfx
        var $package_size = 0;
615 4553 psotfx
        var $cache_file = '';
616 9429 acydburn
        var $eol = "\n";
617 4553 psotfx
618 6015 acydburn
        /**
619 6015 acydburn
        * constructor
620 6015 acydburn
        */
621 4553 psotfx
        function queue()
622 4553 psotfx
        {
623 4553 psotfx
                global $phpEx, $phpbb_root_path;
624 4553 psotfx
625 4553 psotfx
                $this->data = array();
626 4553 psotfx
                $this->cache_file = "{$phpbb_root_path}cache/queue.$phpEx";
627 9429 acydburn
628 9429 acydburn
                // Determine EOL character (\n for UNIX, \r\n for Windows and \r for Mac)
629 9429 acydburn
                $this->eol = (!defined('PHP_EOL')) ? (($eol = strtolower(substr(PHP_OS, 0, 3))) == 'win') ? "\r\n" : (($eol == 'mac') ? "\r" : "\n") : PHP_EOL;
630 9429 acydburn
                $this->eol = (!$this->eol) ? "\n" : $this->eol;
631 4553 psotfx
        }
632 6015 acydburn
633 6015 acydburn
        /**
634 6015 acydburn
        * Init a queue object
635 6015 acydburn
        */
636 4553 psotfx
        function init($object, $package_size)
637 4553 psotfx
        {
638 4553 psotfx
                $this->data[$object] = array();
639 4553 psotfx
                $this->data[$object]['package_size'] = $package_size;
640 4553 psotfx
                $this->data[$object]['data'] = array();
641 4553 psotfx
        }
642 4553 psotfx
643 6015 acydburn
        /**
644 6015 acydburn
        * Put object in queue
645 6015 acydburn
        */
646 4553 psotfx
        function put($object, $scope)
647 4553 psotfx
        {
648 4553 psotfx
                $this->data[$object]['data'][] = $scope;
649 4553 psotfx
        }
650 4553 psotfx
651 6015 acydburn
        /**
652 10832 git-gate
        * Obtains exclusive lock on queue cache file.
653 10832 git-gate
        * Returns resource representing the lock
654 10832 git-gate
        */
655 10832 git-gate
        function lock()
656 10832 git-gate
        {
657 10832 git-gate
                // For systems that can't have two processes opening
658 10832 git-gate
                // one file for writing simultaneously
659 10832 git-gate
                if (file_exists($this->cache_file . '.lock'))
660 10832 git-gate
                {
661 10832 git-gate
                        $mode = 'rb';
662 10832 git-gate
                }
663 10832 git-gate
                else
664 10832 git-gate
                {
665 10832 git-gate
                        $mode = 'wb';
666 10832 git-gate
                }
667 10832 git-gate
668 10832 git-gate
                $lock_fp = @fopen($this->cache_file . '.lock', $mode);
669 10832 git-gate
670 10832 git-gate
                if ($mode == 'wb')
671 10832 git-gate
                {
672 10832 git-gate
                        if (!$lock_fp)
673 10832 git-gate
                        {
674 10832 git-gate
                                // Two processes may attempt to create lock file at the same time.
675 10832 git-gate
                                // Have the losing process try opening the lock file again for reading
676 10832 git-gate
                                // on the assumption that the winning process created it
677 10832 git-gate
                                $mode = 'rb';
678 10832 git-gate
                                $lock_fp = @fopen($this->cache_file . '.lock', $mode);
679 10832 git-gate
                        }
680 10832 git-gate
                        else
681 10832 git-gate
                        {
682 10832 git-gate
                                // Only need to set mode when the lock file is written
683 10832 git-gate
                                @chmod($this->cache_file . '.lock', 0666);
684 10832 git-gate
                        }
685 10832 git-gate
                }
686 10832 git-gate
687 10832 git-gate
                if ($lock_fp)
688 10832 git-gate
                {
689 10832 git-gate
                        @flock($lock_fp, LOCK_EX);
690 10832 git-gate
                }
691 10832 git-gate
692 10832 git-gate
                return $lock_fp;
693 10832 git-gate
        }
694 10832 git-gate
695 10832 git-gate
        /**
696 10832 git-gate
        * Releases lock on queue cache file, using resource obtained from lock()
697 10832 git-gate
        */
698 10832 git-gate
        function unlock($lock_fp)
699 10832 git-gate
        {
700 10832 git-gate
                // lock() will return null if opening lock file, and thus locking, failed.
701 10832 git-gate
                // Accept null values here so that client code does not need to check them
702 10832 git-gate
                if ($lock_fp)
703 10832 git-gate
                {
704 10832 git-gate
                        @flock($lock_fp, LOCK_UN);
705 10832 git-gate
                        fclose($lock_fp);
706 10832 git-gate
                }
707 10832 git-gate
        }
708 10832 git-gate
709 10832 git-gate
        /**
710 6015 acydburn
        * Process queue
711 6015 acydburn
        * Using lock file
712 6015 acydburn
        */
713 4553 psotfx
        function process()
714 4553 psotfx
        {
715 8075 acydburn
                global $db, $config, $phpEx, $phpbb_root_path, $user;
716 4553 psotfx
717 10832 git-gate
                $lock_fp = $this->lock();
718 10832 git-gate
719 5116 acydburn
                set_config('last_queue_run', time(), true);
720 4553 psotfx
721 10832 git-gate
                if (!file_exists($this->cache_file) || filemtime($this->cache_file) > time() - $config['queue_interval'])
722 4904 acydburn
                {
723 10832 git-gate
                        $this->unlock($lock_fp);
724 4904 acydburn
                        return;
725 4904 acydburn
                }
726 4904 acydburn
727 4553 psotfx
                include($this->cache_file);
728 4553 psotfx
729 4553 psotfx
                foreach ($this->queue_data as $object => $data_ary)
730 4553 psotfx
                {
731 5241 acydburn
                        @set_time_limit(0);
732 4553 psotfx
733 5241 acydburn
                        if (!isset($data_ary['package_size']))
734 5241 acydburn
                        {
735 5241 acydburn
                                $data_ary['package_size'] = 0;
736 5241 acydburn
                        }
737 5241 acydburn
738 4599 psotfx
                        $package_size = $data_ary['package_size'];
739 6478 acydburn
                        $num_items = (!$package_size || sizeof($data_ary['data']) < $package_size) ? sizeof($data_ary['data']) : $package_size;
740 4553 psotfx
741 10751 git-gate
                        /*
742 10751 git-gate
                        * This code is commented out because it causes problems on some web hosts.
743 10751 git-gate
                        * The core problem is rather restrictive email sending limits.
744 10751 git-gate
                        * This code is nly useful if you have no such restrictions from the
745 10751 git-gate
                        * web host and the package size setting is wrong.
746 10751 git-gate
747 8025 acydburn
                        // If the amount of emails to be sent is way more than package_size than we need to increase it to prevent backlogs...
748 8025 acydburn
                        if (sizeof($data_ary['data']) > $package_size * 2.5)
749 8025 acydburn
                        {
750 8025 acydburn
                                $num_items = sizeof($data_ary['data']);
751 8025 acydburn
                        }
752 10751 git-gate
                        */
753 8025 acydburn
754 4553 psotfx
                        switch ($object)
755 4553 psotfx
                        {
756 4553 psotfx
                                case 'email':
757 4553 psotfx
                                        // Delete the email queued objects if mailing is disabled
758 4553 psotfx
                                        if (!$config['email_enable'])
759 4553 psotfx
                                        {
760 4553 psotfx
                                                unset($this->queue_data['email']);
761 4600 psotfx
                                                continue 2;
762 4553 psotfx
                                        }
763 5784 acydburn
                                break;
764 4553 psotfx
765 4553 psotfx
                                case 'jabber':
766 4553 psotfx
                                        if (!$config['jab_enable'])
767 4553 psotfx
                                        {
768 4553 psotfx
                                                unset($this->queue_data['jabber']);
769 4600 psotfx
                                                continue 2;
770 4553 psotfx
                                        }
771 4553 psotfx
772 8241 acydburn
                                        include_once($phpbb_root_path . 'includes/functions_jabber.' . $phpEx);
773 11646 git-gate
                                        $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], htmlspecialchars_decode($config['jab_password']), $config['jab_use_ssl']);
774 4553 psotfx
775 5116 acydburn
                                        if (!$this->jabber->connect())
776 4553 psotfx
                                        {
777 8075 acydburn
                                                messenger::error('JABBER', $user->lang['ERR_JAB_CONNECT']);
778 4600 psotfx
                                                continue 2;
779 4553 psotfx
                                        }
780 4553 psotfx
781 7687 acydburn
                                        if (!$this->jabber->login())
782 4553 psotfx
                                        {
783 8075 acydburn
                                                messenger::error('JABBER', $user->lang['ERR_JAB_AUTH']);
784 4600 psotfx
                                                continue 2;
785 4553 psotfx
                                        }
786 4553 psotfx
787 5784 acydburn
                                break;
788 5784 acydburn
789 4553 psotfx
                                default:
790 10832 git-gate
                                        $this->unlock($lock_fp);
791 4553 psotfx
                                        return;
792 4553 psotfx
                        }
793 4553 psotfx
794 4553 psotfx
                        for ($i = 0; $i < $num_items; $i++)
795 4553 psotfx
                        {
796 5678 acydburn
                                // Make variables available...
797 4553 psotfx
                                extract(array_shift($this->queue_data[$object]['data']));
798 4553 psotfx
799 4553 psotfx
                                switch ($object)
800 4553 psotfx
                                {
801 4553 psotfx
                                        case 'email':
802 4553 psotfx
                                                $err_msg = '';
803 8090 acydburn
                                                $to = (!$to) ? 'undisclosed-recipients:;' : $to;
804 4553 psotfx
805 6839 acydburn
                                                if ($config['smtp_delivery'])
806 6839 acydburn
                                                {
807 8034 acydburn
                                                        $result = smtpmail($addresses, mail_encode($subject), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $err_msg, $headers);
808 6839 acydburn
                                                }
809 6839 acydburn
                                                else
810 6839 acydburn
                                                {
811 10014 acydburn
                                                        $result = phpbb_mail($to, $subject, $msg, $headers, $this->eol, $err_msg);
812 6839 acydburn
                                                }
813 4682 acydburn
814 4553 psotfx
                                                if (!$result)
815 4553 psotfx
                                                {
816 6715 acydburn
                                                        messenger::error('EMAIL', $err_msg);
817 6436 acydburn
                                                        continue 2;
818 4553 psotfx
                                                }
819 5784 acydburn
                                        break;
820 4553 psotfx
821 4553 psotfx
                                        case 'jabber':
822 4553 psotfx
                                                foreach ($addresses as $address)
823 4553 psotfx
                                                {
824 7687 acydburn
                                                        if ($this->jabber->send_message($address, $msg, $subject) === false)
825 6436 acydburn
                                                        {
826 6771 acydburn
                                                                messenger::error('JABBER', $this->jabber->get_log());
827 6436 acydburn
                                                                continue 3;
828 6436 acydburn
                                                        }
829 4553 psotfx
                                                }
830 5784 acydburn
                                        break;
831 4553 psotfx
                                }
832 4553 psotfx
                        }
833 4553 psotfx
834 4553 psotfx
                        // No more data for this object? Unset it
835 5117 acydburn
                        if (!sizeof($this->queue_data[$object]['data']))
836 4553 psotfx
                        {
837 4553 psotfx
                                unset($this->queue_data[$object]);
838 4553 psotfx
                        }
839 4553 psotfx
840 4553 psotfx
                        // Post-object processing
841 4553 psotfx
                        switch ($object)
842 4553 psotfx
                        {
843 4553 psotfx
                                case 'jabber':
844 4553 psotfx
                                        // Hang about a couple of secs to ensure the messages are
845 4553 psotfx
                                        // handled, then disconnect
846 5116 acydburn
                                        $this->jabber->disconnect();
847 5784 acydburn
                                break;
848 4553 psotfx
                        }
849 4553 psotfx
                }
850 8763 acydburn
851 4553 psotfx
                if (!sizeof($this->queue_data))
852 4553 psotfx
                {
853 4558 psotfx
                        @unlink($this->cache_file);
854 4553 psotfx
                }
855 4553 psotfx
                else
856 4553 psotfx
                {
857 8971 acydburn
                        if ($fp = @fopen($this->cache_file, 'wb'))
858 4553 psotfx
                        {
859 9363 acydburn
                                fwrite($fp, "<?php\nif (!defined('IN_PHPBB')) exit;\n\$this->queue_data = unserialize(" . var_export(serialize($this->queue_data), true) . ");\n\n?>");
860 4553 psotfx
                                fclose($fp);
861 7813 acydburn
862 9208 toonarmy
                                phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE);
863 4553 psotfx
                        }
864 4553 psotfx
                }
865 4553 psotfx
866 10832 git-gate
                $this->unlock($lock_fp);
867 4553 psotfx
        }
868 4553 psotfx
869 6015 acydburn
        /**
870 6015 acydburn
        * Save queue
871 6015 acydburn
        */
872 4553 psotfx
        function save()
873 4553 psotfx
        {
874 4777 acydburn
                if (!sizeof($this->data))
875 4777 acydburn
                {
876 4777 acydburn
                        return;
877 4777 acydburn
                }
878 8763 acydburn
879 10832 git-gate
                $lock_fp = $this->lock();
880 10832 git-gate
881 4553 psotfx
                if (file_exists($this->cache_file))
882 4553 psotfx
                {
883 4553 psotfx
                        include($this->cache_file);
884 8763 acydburn
885 4553 psotfx
                        foreach ($this->queue_data as $object => $data_ary)
886 4553 psotfx
                        {
887 5117 acydburn
                                if (isset($this->data[$object]) && sizeof($this->data[$object]))
888 4553 psotfx
                                {
889 4553 psotfx
                                        $this->data[$object]['data'] = array_merge($data_ary['data'], $this->data[$object]['data']);
890 4553 psotfx
                                }
891 5117 acydburn
                                else
892 5117 acydburn
                                {
893 5117 acydburn
                                        $this->data[$object]['data'] = $data_ary['data'];
894 5117 acydburn
                                }
895 4553 psotfx
                        }
896 4553 psotfx
                }
897 4553 psotfx
898 5973 acydburn
                if ($fp = @fopen($this->cache_file, 'w'))
899 4553 psotfx
                {
900 9363 acydburn
                        fwrite($fp, "<?php\nif (!defined('IN_PHPBB')) exit;\n\$this->queue_data = unserialize(" . var_export(serialize($this->data), true) . ");\n\n?>");
901 4553 psotfx
                        fclose($fp);
902 7813 acydburn
903 9208 toonarmy
                        phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE);
904 4553 psotfx
                }
905 10832 git-gate
906 10832 git-gate
                $this->unlock($lock_fp);
907 4553 psotfx
        }
908 4553 psotfx
}
909 4553 psotfx
910 5114 acydburn
/**
911 5114 acydburn
* Replacement or substitute for PHP's mail command
912 5114 acydburn
*/
913 9364 acydburn
function smtpmail($addresses, $subject, $message, &$err_msg, $headers = false)
914 4553 psotfx
{
915 4805 acydburn
        global $config, $user;
916 4553 psotfx
917 4553 psotfx
        // Fix any bare linefeeds in the message to make it RFC821 Compliant.
918 4553 psotfx
        $message = preg_replace("#(?<!\r)\n#si", "\r\n", $message);
919 4553 psotfx
920 9364 acydburn
        if ($headers !== false)
921 4553 psotfx
        {
922 9364 acydburn
                if (!is_array($headers))
923 4553 psotfx
                {
924 9364 acydburn
                        // Make sure there are no bare linefeeds in the headers
925 9364 acydburn
                        $headers = preg_replace('#(?<!\r)\n#si', "\n", $headers);
926 9364 acydburn
                        $headers = explode("\n", $headers);
927 4553 psotfx
                }
928 4553 psotfx
929 4553 psotfx
                // Ok this is rather confusing all things considered,
930 4553 psotfx
                // but we have to grab bcc and cc headers and treat them differently
931 4553 psotfx
                // Something we really didn't take into consideration originally
932 9364 acydburn
                $headers_used = array();
933 6826 acydburn
934 9364 acydburn
                foreach ($headers as $header)
935 4553 psotfx
                {
936 6826 acydburn
                        if (strpos(strtolower($header), 'cc:') === 0 || strpos(strtolower($header), 'bcc:') === 0)
937 4553 psotfx
                        {
938 9364 acydburn
                                continue;
939 4553 psotfx
                        }
940 9364 acydburn
                        $headers_used[] = trim($header);
941 4553 psotfx
                }
942 4553 psotfx
943 9364 acydburn
                $headers = chop(implode("\r\n", $headers_used));
944 4553 psotfx
        }
945 4553 psotfx
946 4553 psotfx
        if (trim($subject) == '')
947 4553 psotfx
        {
948 6015 acydburn
                $err_msg = (isset($user->lang['NO_EMAIL_SUBJECT'])) ? $user->lang['NO_EMAIL_SUBJECT'] : 'No email subject specified';
949 4774 acydburn
                return false;
950 4553 psotfx
        }
951 4553 psotfx
952 4553 psotfx
        if (trim($message) == '')
953 4553 psotfx
        {
954 6015 acydburn
                $err_msg = (isset($user->lang['NO_EMAIL_MESSAGE'])) ? $user->lang['NO_EMAIL_MESSAGE'] : 'Email message was blank';
955 4774 acydburn
                return false;
956 4553 psotfx
        }
957 4553 psotfx
958 4553 psotfx
        $mail_rcpt = $mail_to = $mail_cc = array();
959 4553 psotfx
960 4553 psotfx
        // Build correct addresses for RCPT TO command and the client side display (TO, CC)
961 6352 acydburn
        if (isset($addresses['to']) && sizeof($addresses['to']))
962 4553 psotfx
        {
963 6352 acydburn
                foreach ($addresses['to'] as $which_ary)
964 6352 acydburn
                {
965 6380 naderman
                        $mail_to[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name'])) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>';
966 6352 acydburn
                        $mail_rcpt['to'][] = '<' . trim($which_ary['email']) . '>';
967 6352 acydburn
                }
968 4553 psotfx
        }
969 4553 psotfx
970 4979 acydburn
        if (isset($addresses['bcc']) && sizeof($addresses['bcc']))
971 4553 psotfx
        {
972 4979 acydburn
                foreach ($addresses['bcc'] as $which_ary)
973 4979 acydburn
                {
974 4979 acydburn
                        $mail_rcpt['bcc'][] = '<' . trim($which_ary['email']) . '>';
975 4979 acydburn
                }
976 4553 psotfx
        }
977 4553 psotfx
978 4979 acydburn
        if (isset($addresses['cc']) && sizeof($addresses['cc']))
979 4553 psotfx
        {
980 4979 acydburn
                foreach ($addresses['cc'] as $which_ary)
981 4979 acydburn
                {
982 6380 naderman
                        $mail_cc[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name'])) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>';
983 4979 acydburn
                        $mail_rcpt['cc'][] = '<' . trim($which_ary['email']) . '>';
984 4979 acydburn
                }
985 4553 psotfx
        }
986 4553 psotfx
987 6352 acydburn
        $smtp = new smtp_class();
988 4774 acydburn
989 6114 acydburn
        $errno = 0;
990 6114 acydburn
        $errstr = '';
991 6114 acydburn
992 6352 acydburn
        $smtp->add_backtrace('Connecting to ' . $config['smtp_host'] . ':' . $config['smtp_port']);
993 6352 acydburn
994 6015 acydburn
        // Ok we have error checked as much as we can to this point let's get on it already.
995 11429 git-gate
        if (!class_exists('phpbb_error_collector'))
996 11429 git-gate
        {
997 11429 git-gate
                global $phpbb_root_path, $phpEx;
998 11429 git-gate
                include($phpbb_root_path . 'includes/error_collector.' . $phpEx);
999 11429 git-gate
        }
1000 11429 git-gate
        $collector = new phpbb_error_collector;
1001 11429 git-gate
        $collector->install();
1002 7909 acydburn
        $smtp->socket = fsockopen($config['smtp_host'], $config['smtp_port'], $errno, $errstr, 20);
1003 11429 git-gate
        $collector->uninstall();
1004 11429 git-gate
        $error_contents = $collector->format_errors();
1005 7909 acydburn
1006 7909 acydburn
        if (!$smtp->socket)
1007 4553 psotfx
        {
1008 6846 acydburn
                if ($errstr)
1009 6846 acydburn
                {
1010 6846 acydburn
                        $errstr = utf8_convert_message($errstr);
1011 6846 acydburn
                }
1012 6846 acydburn
1013 6015 acydburn
                $err_msg = (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr";
1014 7909 acydburn
                $err_msg .= ($error_contents) ? '<br /><br />' . htmlspecialchars($error_contents) : '';
1015 4774 acydburn
                return false;
1016 4553 psotfx
        }
1017 4553 psotfx
1018 4553 psotfx
        // Wait for reply
1019 4774 acydburn
        if ($err_msg = $smtp->server_parse('220', __LINE__))
1020 4553 psotfx
        {
1021 6352 acydburn
                $smtp->close_session($err_msg);
1022 4774 acydburn
                return false;
1023 4553 psotfx
        }
1024 4553 psotfx
1025 4774 acydburn
        // Let me in. This function handles the complete authentication process
1026 11646 git-gate
        if ($err_msg = $smtp->log_into_server($config['smtp_host'], $config['smtp_username'], htmlspecialchars_decode($config['smtp_password']), $config['smtp_auth_method']))
1027 4553 psotfx
        {
1028 6352 acydburn
                $smtp->close_session($err_msg);
1029 4774 acydburn
                return false;
1030 4553 psotfx
        }
1031 4553 psotfx
1032 4553 psotfx
        // From this point onward most server response codes should be 250
1033 4553 psotfx
        // Specify who the mail is from....
1034 7007 acydburn
        $smtp->server_send('MAIL FROM:<' . $config['board_email'] . '>');
1035 4774 acydburn
        if ($err_msg = $smtp->server_parse('250', __LINE__))
1036 4553 psotfx
        {
1037 6352 acydburn
                $smtp->close_session($err_msg);
1038 4774 acydburn
                return false;
1039 4553 psotfx
        }
1040 4553 psotfx
1041 4553 psotfx
        // Specify each user to send to and build to header.
1042 4553 psotfx
        $to_header = implode(', ', $mail_to);
1043 4553 psotfx
        $cc_header = implode(', ', $mail_cc);
1044 4553 psotfx
1045 4553 psotfx
        // Now tell the MTA to send the Message to the following people... [TO, BCC, CC]
1046 4775 acydburn
        $rcpt = false;
1047 4553 psotfx
        foreach ($mail_rcpt as $type => $mail_to_addresses)
1048 4553 psotfx
        {
1049 4553 psotfx
                foreach ($mail_to_addresses as $mail_to_address)
1050 4553 psotfx
                {
1051 4553 psotfx
                        // Add an additional bit of error checking to the To field.
1052 4553 psotfx
                        if (preg_match('#[^ ]+\@[^ ]+#', $mail_to_address))
1053 4553 psotfx
                        {
1054 4777 acydburn
                                $smtp->server_send("RCPT TO:$mail_to_address");
1055 4774 acydburn
                                if ($err_msg = $smtp->server_parse('250', __LINE__))
1056 4553 psotfx
                                {
1057 4775 acydburn
                                        // We continue... if users are not resolved we do not care
1058 4775 acydburn
                                        if ($smtp->numeric_response_code != 550)
1059 4775 acydburn
                                        {
1060 6352 acydburn
                                                $smtp->close_session($err_msg);
1061 4775 acydburn
                                                return false;
1062 4775 acydburn
                                        }
1063 4553 psotfx
                                }
1064 4775 acydburn
                                else
1065 4775 acydburn
                                {
1066 4775 acydburn
                                        $rcpt = true;
1067 4775 acydburn
                                }
1068 4553 psotfx
                        }
1069 4553 psotfx
                }
1070 4553 psotfx
        }
1071 4553 psotfx
1072 4775 acydburn
        // We try to send messages even if a few people do not seem to have valid email addresses, but if no one has, we have to exit here.
1073 4775 acydburn
        if (!$rcpt)
1074 4775 acydburn
        {
1075 5241 acydburn
                $user->session_begin();
1076 6015 acydburn
                $err_msg .= '<br /><br />';
1077 6015 acydburn
                $err_msg .= (isset($user->lang['INVALID_EMAIL_LOG'])) ? sprintf($user->lang['INVALID_EMAIL_LOG'], htmlspecialchars($mail_to_address)) : '<strong>' . htmlspecialchars($mail_to_address) . '</strong> possibly an invalid email address?';
1078 6352 acydburn
                $smtp->close_session($err_msg);
1079 4775 acydburn
                return false;
1080 4775 acydburn
        }
1081 4775 acydburn
1082 4553 psotfx
        // Ok now we tell the server we are ready to start sending data
1083 4777 acydburn
        $smtp->server_send('DATA');
1084 4553 psotfx
1085 4553 psotfx
        // This is the last response code we look for until the end of the message.
1086 4774 acydburn
        if ($err_msg = $smtp->server_parse('354', __LINE__))
1087 4553 psotfx
        {
1088 6352 acydburn
                $smtp->close_session($err_msg);
1089 4774 acydburn
                return false;
1090 4553 psotfx
        }
1091 4553 psotfx
1092 4553 psotfx
        // Send the Subject Line...
1093 4777 acydburn
        $smtp->server_send("Subject: $subject");
1094 4553 psotfx
1095 4553 psotfx
        // Now the To Header.
1096 8090 acydburn
        $to_header = ($to_header == '') ? 'undisclosed-recipients:;' : $to_header;
1097 4777 acydburn
        $smtp->server_send("To: $to_header");
1098 4553 psotfx
1099 4553 psotfx
        // Now the CC Header.
1100 4553 psotfx
        if ($cc_header != '')
1101 4553 psotfx
        {
1102 4777 acydburn
                $smtp->server_send("CC: $cc_header");
1103 4553 psotfx
        }
1104 4553 psotfx
1105 4553 psotfx
        // Now any custom headers....
1106 9364 acydburn
        if ($headers !== false)
1107 9364 acydburn
        {
1108 9364 acydburn
                $smtp->server_send("$headers\r\n");
1109 9364 acydburn
        }
1110 4553 psotfx
1111 4553 psotfx
        // Ok now we are ready for the message...
1112 4777 acydburn
        $smtp->server_send($message);
1113 4553 psotfx
1114 4553 psotfx
        // Ok the all the ingredients are mixed in let's cook this puppy...
1115 4777 acydburn
        $smtp->server_send('.');
1116 4774 acydburn
        if ($err_msg = $smtp->server_parse('250', __LINE__))
1117 4553 psotfx
        {
1118 6352 acydburn
                $smtp->close_session($err_msg);
1119 4774 acydburn
                return false;
1120 4553 psotfx
        }
1121 4553 psotfx
1122 4553 psotfx
        // Now tell the server we are done and close the socket...
1123 4777 acydburn
        $smtp->server_send('QUIT');
1124 6352 acydburn
        $smtp->close_session($err_msg);
1125 4553 psotfx
1126 4774 acydburn
        return true;
1127 4553 psotfx
}
1128 4553 psotfx
1129 5114 acydburn
/**
1130 5114 acydburn
* SMTP Class
1131 5114 acydburn
* Auth Mechanisms originally taken from the AUTH Modules found within the PHP Extension and Application Repository (PEAR)
1132 5114 acydburn
* See docs/AUTHORS for more details
1133 6058 acydburn
* @package phpBB3
1134 5114 acydburn
*/
1135 4774 acydburn
class smtp_class
1136 4553 psotfx
{
1137 4774 acydburn
        var $server_response = '';
1138 4774 acydburn
        var $socket = 0;
1139 11678 git-gate
        protected $socket_tls = false;
1140 4774 acydburn
        var $responses = array();
1141 4774 acydburn
        var $commands = array();
1142 4774 acydburn
        var $numeric_response_code = 0;
1143 4774 acydburn
1144 6352 acydburn
        var $backtrace = false;
1145 6352 acydburn
        var $backtrace_log = array();
1146 6352 acydburn
1147 6352 acydburn
        function smtp_class()
1148 6352 acydburn
        {
1149 7631 acydburn
                // Always create a backtrace for admins to identify SMTP problems
1150 7631 acydburn
                $this->backtrace = true;
1151 7631 acydburn
                $this->backtrace_log = array();
1152 6352 acydburn
        }
1153 6352 acydburn
1154 6015 acydburn
        /**
1155 6352 acydburn
        * Add backtrace message for debugging
1156 6352 acydburn
        */
1157 6352 acydburn
        function add_backtrace($message)
1158 6352 acydburn
        {
1159 6352 acydburn
                if ($this->backtrace)
1160 6352 acydburn
                {
1161 7631 acydburn
                        $this->backtrace_log[] = utf8_htmlspecialchars($message);
1162 6352 acydburn
                }
1163 6352 acydburn
        }
1164 6352 acydburn
1165 6352 acydburn
        /**
1166 6015 acydburn
        * Send command to smtp server
1167 6015 acydburn
        */
1168 6352 acydburn
        function server_send($command, $private_info = false)
1169 4553 psotfx
        {
1170 4777 acydburn
                fputs($this->socket, $command . "\r\n");
1171 4898 acydburn
1172 6915 acydburn
                (!$private_info) ? $this->add_backtrace("# $command") : $this->add_backtrace('# Omitting sensitive information');
1173 6352 acydburn
1174 4898 acydburn
                // We could put additional code here
1175 4553 psotfx
        }
1176 6352 acydburn
1177 6015 acydburn
        /**
1178 6015 acydburn
        * We use the line to give the support people an indication at which command the error occurred
1179 6015 acydburn
        */
1180 4774 acydburn
        function server_parse($response, $line)
1181 4774 acydburn
        {
1182 6015 acydburn
                global $user;
1183 6015 acydburn
1184 4774 acydburn
                $this->server_response = '';
1185 4774 acydburn
                $this->responses = array();
1186 4774 acydburn
                $this->numeric_response_code = 0;
1187 4553 psotfx
1188 4774 acydburn
                while (substr($this->server_response, 3, 1) != ' ')
1189 4774 acydburn
                {
1190 4774 acydburn
                        if (!($this->server_response = fgets($this->socket, 256)))
1191 4774 acydburn
                        {
1192 6015 acydburn
                                return (isset($user->lang['NO_EMAIL_RESPONSE_CODE'])) ? $user->lang['NO_EMAIL_RESPONSE_CODE'] : 'Could not get mail server response codes';
1193 4774 acydburn
                        }
1194 4774 acydburn
                        $this->responses[] = substr(rtrim($this->server_response), 4);
1195 4774 acydburn
                        $this->numeric_response_code = (int) substr($this->server_response, 0, 3);
1196 6352 acydburn
1197 6352 acydburn
                        $this->add_backtrace("LINE: $line <- {$this->server_response}");
1198 4774 acydburn
                }
1199 4774 acydburn
1200 4774 acydburn
                if (!(substr($this->server_response, 0, 3) == $response))
1201 4774 acydburn
                {
1202 4774 acydburn
                        $this->numeric_response_code = (int) substr($this->server_response, 0, 3);
1203 6015 acydburn
                        return (isset($user->lang['EMAIL_SMTP_ERROR_RESPONSE'])) ? sprintf($user->lang['EMAIL_SMTP_ERROR_RESPONSE'], $line, $this->server_response) : "Ran into problems sending Mail at <strong>Line $line</strong>. Response: $this->server_response";
1204 4774 acydburn
                }
1205 4774 acydburn
1206 4774 acydburn
                return 0;
1207 4774 acydburn
        }
1208 4774 acydburn
1209 6015 acydburn
        /**
1210 6015 acydburn
        * Close session
1211 6015 acydburn
        */
1212 6352 acydburn
        function close_session(&$err_msg)
1213 4777 acydburn
        {
1214 4777 acydburn
                fclose($this->socket);
1215 6352 acydburn
1216 6352 acydburn
                if ($this->backtrace)
1217 6352 acydburn
                {
1218 6715 acydburn
                        $message = '<h1>Backtrace</h1><p>' . implode('<br />', $this->backtrace_log) . '</p>';
1219 6352 acydburn
                        $err_msg .= $message;
1220 6352 acydburn
                }
1221 4777 acydburn
        }
1222 8763 acydburn
1223 6015 acydburn
        /**
1224 6015 acydburn
        * Log into server and get possible auth codes if neccessary
1225 6015 acydburn
        */
1226 4774 acydburn
        function log_into_server($hostname, $username, $password, $default_auth_method)
1227 4553 psotfx
        {
1228 5859 acydburn
                global $user;
1229 5859 acydburn
1230 4774 acydburn
                $err_msg = '';
1231 4774 acydburn
1232 10178 acydburn
                // Here we try to determine the *real* hostname (reverse DNS entry preferrably)
1233 10178 acydburn
                $local_host = $user->host;
1234 10178 acydburn
1235 10178 acydburn
                if (function_exists('php_uname'))
1236 10178 acydburn
                {
1237 10178 acydburn
                        $local_host = php_uname('n');
1238 10178 acydburn
1239 10178 acydburn
                        // Able to resolve name to IP
1240 10178 acydburn
                        if (($addr = @gethostbyname($local_host)) !== $local_host)
1241 10178 acydburn
                        {
1242 10178 acydburn
                                // Able to resolve IP back to name
1243 10178 acydburn
                                if (($name = @gethostbyaddr($addr)) !== $addr)
1244 10178 acydburn
                                {
1245 10178 acydburn
                                        $local_host = $name;
1246 10178 acydburn
                                }
1247 10178 acydburn
                        }
1248 10178 acydburn
                }
1249 10178 acydburn
1250 4774 acydburn
                // If we are authenticating through pop-before-smtp, we
1251 4774 acydburn
                // have to login ones before we get authenticated
1252 8146 acydburn
                // NOTE: on some configurations the time between an update of the auth database takes so
1253 6352 acydburn
                // long that the first email send does not work. This is not a biggie on a live board (only
1254 6352 acydburn
                // the install mail will most likely fail) - but on a dynamic ip connection this might produce
1255 6352 acydburn
                // severe problems and is not fixable!
1256 4774 acydburn
                if ($default_auth_method == 'POP-BEFORE-SMTP' && $username && $password)
1257 4774 acydburn
                {
1258 6352 acydburn
                        global $config;
1259 6352 acydburn
1260 6352 acydburn
                        $errno = 0;
1261 6352 acydburn
                        $errstr = '';
1262 6352 acydburn
1263 6352 acydburn
                        $this->server_send("QUIT");
1264 6352 acydburn
                        fclose($this->socket);
1265 6352 acydburn
1266 4774 acydburn
                        $result = $this->pop_before_smtp($hostname, $username, $password);
1267 4774 acydburn
                        $username = $password = $default_auth_method = '';
1268 6352 acydburn
1269 6352 acydburn
                        // We need to close the previous session, else the server is not
1270 6352 acydburn
                        // able to get our ip for matching...
1271 6352 acydburn
                        if (!$this->socket = @fsockopen($config['smtp_host'], $config['smtp_port'], $errno, $errstr, 10))
1272 6352 acydburn
                        {
1273 6846 acydburn
                                if ($errstr)
1274 6846 acydburn
                                {
1275 6846 acydburn
                                        $errstr = utf8_convert_message($errstr);
1276 6846 acydburn
                                }
1277 6846 acydburn
1278 6352 acydburn
                                $err_msg = (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr";
1279 6352 acydburn
                                return $err_msg;
1280 6352 acydburn
                        }
1281 6352 acydburn
1282 6352 acydburn
                        // Wait for reply
1283 6352 acydburn
                        if ($err_msg = $this->server_parse('220', __LINE__))
1284 6352 acydburn
                        {
1285 6352 acydburn
                                $this->close_session($err_msg);
1286 6352 acydburn
                                return $err_msg;
1287 6352 acydburn
                        }
1288 4774 acydburn
                }
1289 4774 acydburn
1290 11678 git-gate
                $hello_result = $this->hello($local_host);
1291 11678 git-gate
                if (!is_null($hello_result))
1292 4774 acydburn
                {
1293 11678 git-gate
                        return $hello_result;
1294 11678 git-gate
                }
1295 11678 git-gate
1296 11678 git-gate
                // SMTP STARTTLS (RFC 3207)
1297 11678 git-gate
                if (!$this->socket_tls)
1298 11678 git-gate
                {
1299 11678 git-gate
                        $this->socket_tls = $this->starttls();
1300 11678 git-gate
1301 11678 git-gate
                        if ($this->socket_tls)
1302 4774 acydburn
                        {
1303 11678 git-gate
                                // Switched to TLS
1304 11678 git-gate
                                // RFC 3207: "The client MUST discard any knowledge obtained from the server, [...]"
1305 11678 git-gate
                                // So say hello again
1306 11678 git-gate
                                $hello_result = $this->hello($local_host);
1307 4774 acydburn
1308 11678 git-gate
                                if (!is_null($hello_result))
1309 11678 git-gate
                                {
1310 11678 git-gate
                                        return $hello_result;
1311 11678 git-gate
                                }
1312 4774 acydburn
                        }
1313 4774 acydburn
                }
1314 4774 acydburn
1315 4774 acydburn
                // If we are not authenticated yet, something might be wrong if no username and passwd passed
1316 4774 acydburn
                if (!$username || !$password)
1317 4774 acydburn
                {
1318 4774 acydburn
                        return false;
1319 4774 acydburn
                }
1320 8763 acydburn
1321 4774 acydburn
                if (!isset($this->commands['AUTH']))
1322 4774 acydburn
                {
1323 6015 acydburn
                        return (isset($user->lang['SMTP_NO_AUTH_SUPPORT'])) ? $user->lang['SMTP_NO_AUTH_SUPPORT'] : 'SMTP server does not support authentication';
1324 4774 acydburn
                }
1325 4774 acydburn
1326 4774 acydburn
                // Get best authentication method
1327 4775 acydburn
                $available_methods = explode(' ', $this->commands['AUTH']);
1328 4774 acydburn
1329 4774 acydburn
                // Define the auth ordering if the default auth method was not found
1330 5866 acydburn
                $auth_methods = array('PLAIN', 'LOGIN', 'CRAM-MD5', 'DIGEST-MD5');
1331 4774 acydburn
                $method = '';
1332 4774 acydburn
1333 4774 acydburn
                if (in_array($default_auth_method, $available_methods))
1334 4774 acydburn
                {
1335 4774 acydburn
                        $method = $default_auth_method;
1336 4774 acydburn
                }
1337 4774 acydburn
                else
1338 4774 acydburn
                {
1339 4774 acydburn
                        foreach ($auth_methods as $_method)
1340 4774 acydburn
                        {
1341 4774 acydburn
                                if (in_array($_method, $available_methods))
1342 4774 acydburn
                                {
1343 4774 acydburn
                                        $method = $_method;
1344 4774 acydburn
                                        break;
1345 4774 acydburn
                                }
1346 4774 acydburn
                        }
1347 4775 acydburn
                }
1348 4774 acydburn
1349 4774 acydburn
                if (!$method)
1350 4774 acydburn
                {
1351 6015 acydburn
                        return (isset($user->lang['NO_SUPPORTED_AUTH_METHODS'])) ? $user->lang['NO_SUPPORTED_AUTH_METHODS'] : 'No supported authentication methods';
1352 4774 acydburn
                }
1353 4774 acydburn
1354 4774 acydburn
                $method = strtolower(str_replace('-', '_', $method));
1355 4774 acydburn
                return $this->$method($username, $password);
1356 4553 psotfx
        }
1357 4553 psotfx
1358 6015 acydburn
        /**
1359 11678 git-gate
        * SMTP EHLO/HELO
1360 11678 git-gate
        *
1361 11678 git-gate
        * @return mixed                Null if the authentication process is supposed to continue
1362 11678 git-gate
        *                                        False if already authenticated
1363 11678 git-gate
        *                                        Error message (string) otherwise
1364 11678 git-gate
        */
1365 11678 git-gate
        protected function hello($hostname)
1366 11678 git-gate
        {
1367 11678 git-gate
                // Try EHLO first
1368 11678 git-gate
                $this->server_send("EHLO $hostname");
1369 11678 git-gate
                if ($err_msg = $this->server_parse('250', __LINE__))
1370 11678 git-gate
                {
1371 11678 git-gate
                        // a 503 response code means that we're already authenticated
1372 11678 git-gate
                        if ($this->numeric_response_code == 503)
1373 11678 git-gate
                        {
1374 11678 git-gate
                                return false;
1375 11678 git-gate
                        }
1376 11678 git-gate
1377 11678 git-gate
                        // If EHLO fails, we try HELO
1378 11678 git-gate
                        $this->server_send("HELO $hostname");
1379 11678 git-gate
                        if ($err_msg = $this->server_parse('250', __LINE__))
1380 11678 git-gate
                        {
1381 11678 git-gate
                                return ($this->numeric_response_code == 503) ? false : $err_msg;
1382 11678 git-gate
                        }
1383 11678 git-gate
                }
1384 11678 git-gate
1385 11678 git-gate
                foreach ($this->responses as $response)
1386 11678 git-gate
                {
1387 11678 git-gate
                        $response = explode(' ', $response);
1388 11678 git-gate
                        $response_code = $response[0];
1389 11678 git-gate
                        unset($response[0]);
1390 11678 git-gate
                        $this->commands[$response_code] = implode(' ', $response);
1391 11678 git-gate
                }
1392 11678 git-gate
        }
1393 11678 git-gate
1394 11678 git-gate
        /**
1395 11678 git-gate
        * SMTP STARTTLS (RFC 3207)
1396 11678 git-gate
        *
1397 11678 git-gate
        * @return bool                Returns true if TLS was started
1398 11678 git-gate
        *                                        Otherwise false
1399 11678 git-gate
        */
1400 11678 git-gate
        protected function starttls()
1401 11678 git-gate
        {
1402 11678 git-gate
                if (!function_exists('stream_socket_enable_crypto'))
1403 11678 git-gate
                {
1404 11678 git-gate
                        return false;
1405 11678 git-gate
                }
1406 11678 git-gate
1407 11678 git-gate
                if (!isset($this->commands['STARTTLS']))
1408 11678 git-gate
                {
1409 11678 git-gate
                        return false;
1410 11678 git-gate
                }
1411 11678 git-gate
1412 11678 git-gate
                $this->server_send('STARTTLS');
1413 11678 git-gate
1414 11678 git-gate
                if ($err_msg = $this->server_parse('220', __LINE__))
1415 11678 git-gate
                {
1416 11678 git-gate
                        return false;
1417 11678 git-gate
                }
1418 11678 git-gate
1419 11678 git-gate
                $result = false;
1420 11678 git-gate
                $stream_meta = stream_get_meta_data($this->socket);
1421 11678 git-gate
1422 11678 git-gate
                if (socket_set_blocking($this->socket, 1));
1423 11678 git-gate
                {
1424 11678 git-gate
                        $result = stream_socket_enable_crypto($this->socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
1425 11678 git-gate
                        socket_set_blocking($this->socket, (int) $stream_meta['blocked']);
1426 11678 git-gate
                }
1427 11678 git-gate
1428 11678 git-gate
                return $result;
1429 11678 git-gate
        }
1430 11678 git-gate
1431 11678 git-gate
        /**
1432 6015 acydburn
        * Pop before smtp authentication
1433 6015 acydburn
        */
1434 4774 acydburn
        function pop_before_smtp($hostname, $username, $password)
1435 4774 acydburn
        {
1436 6015 acydburn
                global $user;
1437 6015 acydburn
1438 6352 acydburn
                if (!$this->socket = @fsockopen($hostname, 110, $errno, $errstr, 10))
1439 4774 acydburn
                {
1440 6846 acydburn
                        if ($errstr)
1441 6846 acydburn
                        {
1442 6846 acydburn
                                $errstr = utf8_convert_message($errstr);
1443 6846 acydburn
                        }
1444 6846 acydburn
1445 6015 acydburn
                        return (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr";
1446 4774 acydburn
                }
1447 6015 acydburn
1448 6352 acydburn
                $this->server_send("USER $username", true);
1449 6352 acydburn
                if ($err_msg = $this->server_parse('+OK', __LINE__))
1450 4774 acydburn
                {
1451 6352 acydburn
                        return $err_msg;
1452 4774 acydburn
                }
1453 6352 acydburn
1454 6352 acydburn
                $this->server_send("PASS $password", true);
1455 6352 acydburn
                if ($err_msg = $this->server_parse('+OK', __LINE__))
1456 4774 acydburn
                {
1457 6352 acydburn
                        return $err_msg;
1458 4774 acydburn
                }
1459 4774 acydburn
1460 4777 acydburn
                $this->server_send('QUIT');
1461 4774 acydburn
                fclose($this->socket);
1462 4774 acydburn
1463 4774 acydburn
                return false;
1464 4774 acydburn
        }
1465 6015 acydburn
1466 6015 acydburn
        /**
1467 6015 acydburn
        * Plain authentication method
1468 6015 acydburn
        */
1469 4774 acydburn
        function plain($username, $password)
1470 4774 acydburn
        {
1471 4777 acydburn
                $this->server_send('AUTH PLAIN');
1472 4774 acydburn
                if ($err_msg = $this->server_parse('334', __LINE__))
1473 4774 acydburn
                {
1474 4774 acydburn
                        return ($this->numeric_response_code == 503) ? false : $err_msg;
1475 4774 acydburn
                }
1476 4774 acydburn
1477 4774 acydburn
                $base64_method_plain = base64_encode("\0" . $username . "\0" . $password);
1478 6352 acydburn
                $this->server_send($base64_method_plain, true);
1479 4774 acydburn
                if ($err_msg = $this->server_parse('235', __LINE__))
1480 4774 acydburn
                {
1481 4774 acydburn
                        return $err_msg;
1482 4774 acydburn
                }
1483 4774 acydburn
1484 4774 acydburn
                return false;
1485 4774 acydburn
        }
1486 4774 acydburn
1487 6015 acydburn
        /**
1488 6015 acydburn
        * Login authentication method
1489 6015 acydburn
        */
1490 4774 acydburn
        function login($username, $password)
1491 4774 acydburn
        {
1492 4777 acydburn
                $this->server_send('AUTH LOGIN');
1493 4774 acydburn
                if ($err_msg = $this->server_parse('334', __LINE__))
1494 4774 acydburn
                {
1495 4774 acydburn
                        return ($this->numeric_response_code == 503) ? false : $err_msg;
1496 4774 acydburn
                }
1497 4774 acydburn
1498 6352 acydburn
                $this->server_send(base64_encode($username), true);
1499 4774 acydburn
                if ($err_msg = $this->server_parse('334', __LINE__))
1500 4774 acydburn
                {
1501 4774 acydburn
                        return $err_msg;
1502 4774 acydburn
                }
1503 4774 acydburn
1504 6352 acydburn
                $this->server_send(base64_encode($password), true);
1505 4774 acydburn
                if ($err_msg = $this->server_parse('235', __LINE__))
1506 4774 acydburn
                {
1507 4774 acydburn
                        return $err_msg;
1508 4774 acydburn
                }
1509 4774 acydburn
1510 4774 acydburn
                return false;
1511 4774 acydburn
        }
1512 4774 acydburn
1513 6015 acydburn
        /**
1514 6015 acydburn
        * cram_md5 authentication method
1515 6015 acydburn
        */
1516 4774 acydburn
        function cram_md5($username, $password)
1517 4774 acydburn
        {
1518 4777 acydburn
                $this->server_send('AUTH CRAM-MD5');
1519 4774 acydburn
                if ($err_msg = $this->server_parse('334', __LINE__))
1520 4774 acydburn
                {
1521 4774 acydburn
                        return ($this->numeric_response_code == 503) ? false : $err_msg;
1522 4774 acydburn
                }
1523 4774 acydburn
1524 4774 acydburn
                $md5_challenge = base64_decode($this->responses[0]);
1525 4774 acydburn
                $password = (strlen($password) > 64) ? pack('H32', md5($password)) : ((strlen($password) < 64) ? str_pad($password, 64, chr(0)) : $password);
1526 4774 acydburn
                $md5_digest = md5((substr($password, 0, 64) ^ str_repeat(chr(0x5C), 64)) . (pack('H32', md5((substr($password, 0, 64) ^ str_repeat(chr(0x36), 64)) . $md5_challenge))));
1527 4774 acydburn
1528 4774 acydburn
                $base64_method_cram_md5 = base64_encode($username . ' ' . $md5_digest);
1529 4774 acydburn
1530 6352 acydburn
                $this->server_send($base64_method_cram_md5, true);
1531 4774 acydburn
                if ($err_msg = $this->server_parse('235', __LINE__))
1532 4774 acydburn
                {
1533 4774 acydburn
                        return $err_msg;
1534 4774 acydburn
                }
1535 4774 acydburn
1536 4774 acydburn
                return false;
1537 4774 acydburn
        }
1538 4774 acydburn
1539 6015 acydburn
        /**
1540 6015 acydburn
        * digest_md5 authentication method
1541 6015 acydburn
        * A real pain in the ***
1542 6015 acydburn
        */
1543 4774 acydburn
        function digest_md5($username, $password)
1544 4774 acydburn
        {
1545 6015 acydburn
                global $config, $user;
1546 4774 acydburn
1547 4777 acydburn
                $this->server_send('AUTH DIGEST-MD5');
1548 4774 acydburn
                if ($err_msg = $this->server_parse('334', __LINE__))
1549 4774 acydburn
                {
1550 4774 acydburn
                        return ($this->numeric_response_code == 503) ? false : $err_msg;
1551 4774 acydburn
                }
1552 4774 acydburn
1553 4774 acydburn
                $md5_challenge = base64_decode($this->responses[0]);
1554 8763 acydburn
1555 4836 acydburn
                // Parse the md5 challenge - from AUTH_SASL (PEAR)
1556 4774 acydburn
                $tokens = array();
1557 4774 acydburn
                while (preg_match('/^([a-z-]+)=("[^"]+(?<!\\\)"|[^,]+)/i', $md5_challenge, $matches))
1558 4774 acydburn
                {
1559 4774 acydburn
                        // Ignore these as per rfc2831
1560 4774 acydburn
                        if ($matches[1] == 'opaque' || $matches[1] == 'domain')
1561 4774 acydburn
                        {
1562 4774 acydburn
                                $md5_challenge = substr($md5_challenge, strlen($matches[0]) + 1);
1563 4774 acydburn
                                continue;
1564 4774 acydburn
                        }
1565 4774 acydburn
1566 4774 acydburn
                        // Allowed multiple "realm" and "auth-param"
1567 4774 acydburn
                        if (!empty($tokens[$matches[1]]) && ($matches[1] == 'realm' || $matches[1] == 'auth-param'))
1568 4774 acydburn
                        {
1569 4774 acydburn
                                if (is_array($tokens[$matches[1]]))
1570 4774 acydburn
                                {
1571 4774 acydburn
                                        $tokens[$matches[1]][] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
1572 4774 acydburn
                                }
1573 4774 acydburn
                                else
1574 4774 acydburn
                                {
1575 4775 acydburn
                                        $tokens[$matches[1]] = array($tokens[$matches[1]], preg_replace('/^"(.*)"$/', '\\1', $matches[2]));
1576 4775 acydburn
                                }
1577 8146 acydburn
                        }
1578 4774 acydburn
                        else if (!empty($tokens[$matches[1]])) // Any other multiple instance = failure
1579 4774 acydburn
                        {
1580 4774 acydburn
                                $tokens = array();
1581 4774 acydburn
                                break;
1582 4774 acydburn
                        }
1583 4774 acydburn
                        else
1584 4774 acydburn
                        {
1585 4774 acydburn
                                $tokens[$matches[1]] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
1586 4774 acydburn
                        }
1587 4774 acydburn
1588 4774 acydburn
                        // Remove the just parsed directive from the challenge
1589 4774 acydburn
                        $md5_challenge = substr($md5_challenge, strlen($matches[0]) + 1);
1590 4774 acydburn
                }
1591 4774 acydburn
1592 4774 acydburn
                // Realm
1593 4774 acydburn
                if (empty($tokens['realm']))
1594 4774 acydburn
                {
1595 8449 acydburn
                        $tokens['realm'] = (function_exists('php_uname')) ? php_uname('n') : $user->host;
1596 4774 acydburn
                }
1597 5859 acydburn
1598 4774 acydburn
                // Maxbuf
1599 4774 acydburn
                if (empty($tokens['maxbuf']))
1600 4774 acydburn
                {
1601 4774 acydburn
                        $tokens['maxbuf'] = 65536;
1602 4774 acydburn
                }
1603 4775 acydburn
1604 4774 acydburn
                // Required: nonce, algorithm
1605 4774 acydburn
                if (empty($tokens['nonce']) || empty($tokens['algorithm']))
1606 4774 acydburn
                {
1607 4775 acydburn
                        $tokens = array();
1608 4775 acydburn
                }
1609 4775 acydburn
                $md5_challenge = $tokens;
1610 4774 acydburn
1611 4774 acydburn
                if (!empty($md5_challenge))
1612 4774 acydburn
                {
1613 4774 acydburn
                        $str = '';
1614 4774 acydburn
                        for ($i = 0; $i < 32; $i++)
1615 4774 acydburn
                        {
1616 4774 acydburn
                                $str .= chr(mt_rand(0, 255));
1617 4775 acydburn
                        }
1618 4775 acydburn
                        $cnonce = base64_encode($str);
1619 4774 acydburn
1620 4775 acydburn
                        $digest_uri = 'smtp/' . $config['smtp_host'];
1621 4774 acydburn
1622 4774 acydburn
                        $auth_1 = sprintf('%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $username, $md5_challenge['realm'], $password))), $md5_challenge['nonce'], $cnonce);
1623 4774 acydburn
                        $auth_2 = 'AUTHENTICATE:' . $digest_uri;
1624 4774 acydburn
                        $response_value = md5(sprintf('%s:%s:00000001:%s:auth:%s', md5($auth_1), $md5_challenge['nonce'], $cnonce, md5($auth_2)));
1625 4774 acydburn
1626 4774 acydburn
                        $input_string = sprintf('username="%s",realm="%s",nonce="%s",cnonce="%s",nc="00000001",qop=auth,digest-uri="%s",response=%s,%d', $username, $md5_challenge['realm'], $md5_challenge['nonce'], $cnonce, $digest_uri, $response_value, $md5_challenge['maxbuf']);
1627 4775 acydburn
                }
1628 4774 acydburn
                else
1629 4774 acydburn
                {
1630 6015 acydburn
                        return (isset($user->lang['INVALID_DIGEST_CHALLENGE'])) ? $user->lang['INVALID_DIGEST_CHALLENGE'] : 'Invalid digest challenge';
1631 4775 acydburn
                }
1632 6015 acydburn
1633 4774 acydburn
                $base64_method_digest_md5 = base64_encode($input_string);
1634 6352 acydburn
                $this->server_send($base64_method_digest_md5, true);
1635 4774 acydburn
                if ($err_msg = $this->server_parse('334', __LINE__))
1636 4774 acydburn
                {
1637 4774 acydburn
                        return $err_msg;
1638 4774 acydburn
                }
1639 4774 acydburn
1640 4777 acydburn
                $this->server_send(' ');
1641 4774 acydburn
                if ($err_msg = $this->server_parse('235', __LINE__))
1642 4774 acydburn
                {
1643 4774 acydburn
                        return $err_msg;
1644 4774 acydburn
                }
1645 6015 acydburn
1646 4774 acydburn
                return false;
1647 4774 acydburn
        }
1648 4553 psotfx
}
1649 4553 psotfx
1650 5114 acydburn
/**
1651 6639 acydburn
* Encodes the given string for proper display in UTF-8.
1652 6564 acydburn
*
1653 6565 acydburn
* This version is using base64 encoded data. The downside of this
1654 6564 acydburn
* is if the mail client does not understand this encoding the user
1655 6564 acydburn
* is basically doomed with an unreadable subject.
1656 6639 acydburn
*
1657 6642 acydburn
* Please note that this version fully supports RFC 2045 section 6.8.
1658 9530 toonarmy
*
1659 9530 toonarmy
* @param string $eol End of line we are using (optional to be backwards compatible)
1660 5114 acydburn
*/
1661 9530 toonarmy
function mail_encode($str, $eol = "\r\n")
1662 4578 psotfx
{
1663 4578 psotfx
        // define start delimimter, end delimiter and spacer
1664 6642 acydburn
        $start = "=?UTF-8?B?";
1665 6642 acydburn
        $end = "?=";
1666 9530 toonarmy
        $delimiter = "$eol ";
1667 4578 psotfx
1668 9449 acydburn
        // Maximum length is 75. $split_length *must* be a multiple of 4, but <= 75 - strlen($start . $delimiter . $end)!!!
1669 9449 acydburn
        $split_length = 60;
1670 6639 acydburn
        $encoded_str = base64_encode($str);
1671 4578 psotfx
1672 6642 acydburn
        // If encoded string meets the limits, we just return with the correct data.
1673 6642 acydburn
        if (strlen($encoded_str) <= $split_length)
1674 6639 acydburn
        {
1675 6639 acydburn
                return $start . $encoded_str . $end;
1676 6639 acydburn
        }
1677 4578 psotfx
1678 6642 acydburn
        // If there is only ASCII data, we just return what we want, correctly splitting the lines.
1679 6640 acydburn
        if (strlen($str) === utf8_strlen($str))
1680 6640 acydburn
        {
1681 9430 acydburn
                return $start . implode($end . $delimiter . $start, str_split($encoded_str, $split_length)) . $end;
1682 6640 acydburn
        }
1683 6640 acydburn
1684 6642 acydburn
        // UTF-8 data, compose encoded lines
1685 6642 acydburn
        $array = utf8_str_split($str);
1686 6642 acydburn
        $str = '';
1687 4578 psotfx
1688 6642 acydburn
        while (sizeof($array))
1689 6639 acydburn
        {
1690 6642 acydburn
                $text = '';
1691 6639 acydburn
1692 6700 davidmj
                while (sizeof($array) && intval((strlen($text . $array[0]) + 2) / 3) << 2 <= $split_length)
1693 6639 acydburn
                {
1694 6642 acydburn
                        $text .= array_shift($array);
1695 6639 acydburn
                }
1696 6639 acydburn
1697 9430 acydburn
                $str .= $start . base64_encode($text) . $end . $delimiter;
1698 6639 acydburn
        }
1699 6639 acydburn
1700 9430 acydburn
        return substr($str, 0, -strlen($delimiter));
1701 4578 psotfx
}
1702 4578 psotfx
1703 10014 acydburn
/**
1704 10014 acydburn
* Wrapper for sending out emails with the PHP's mail function
1705 10014 acydburn
*/
1706 10014 acydburn
function phpbb_mail($to, $subject, $msg, $headers, $eol, &$err_msg)
1707 10014 acydburn
{
1708 11429 git-gate
        global $config, $phpbb_root_path, $phpEx;
1709 10014 acydburn
1710 10014 acydburn
        // We use the EOL character for the OS here because the PHP mail function does not correctly transform line endings. On Windows SMTP is used (SMTP is \r\n), on UNIX a command is used...
1711 10014 acydburn
        // Reference: http://bugs.php.net/bug.php?id=15841
1712 10014 acydburn
        $headers = implode($eol, $headers);
1713 10014 acydburn
1714 11429 git-gate
        if (!class_exists('phpbb_error_collector'))
1715 11429 git-gate
        {
1716 11429 git-gate
                include($phpbb_root_path . 'includes/error_collector.' . $phpEx);
1717 11429 git-gate
        }
1718 11429 git-gate
1719 11429 git-gate
        $collector = new phpbb_error_collector;
1720 11429 git-gate
        $collector->install();
1721 11429 git-gate
1722 10014 acydburn
        // On some PHP Versions mail() *may* fail if there are newlines within the subject.
1723 10014 acydburn
        // Newlines are used as a delimiter for lines in mail_encode() according to RFC 2045 section 6.8.
1724 10015 acydburn
        // Because PHP can't decide what is wanted we revert back to the non-RFC-compliant way of separating by one space (Use '' as parameter to mail_encode() results in SPACE used)
1725 10015 acydburn
        $result = $config['email_function_name']($to, mail_encode($subject, ''), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $headers);
1726 10014 acydburn
1727 11429 git-gate
        $collector->uninstall();
1728 11429 git-gate
        $err_msg = $collector->format_errors();
1729 11429 git-gate
1730 10014 acydburn
        return $result;
1731 10014 acydburn
}