~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to www/php/phpBB3/includes/functions_messenger.php

  • Committer: dcoles
  • Date: 2008-02-13 04:10:55 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:443
Added Forum application along with unmodifed version of phpBB3 "Olympus" 3.0.0

Show diffs side-by-side

added added

removed removed

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