phpBB
Statistics
| Revision:

root / branches / phpBB-3_0_0 / phpBB / includes / functions_messenger.php

History | View | Annotate | Download (41.5 kB)

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