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

« back to all changes in this revision

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

  • Committer: William Grant
  • Date: 2009-02-23 23:47:02 UTC
  • mfrom: (1099.1.211 new-dispatch)
  • Revision ID: grantw@unimelb.edu.au-20090223234702-db4b1llly46ignwo
Merge from lp:~ivle-dev/ivle/new-dispatch.

Pretty much everything changes. Reread the setup docs. Backup your databases.
Every file is now in a different installed location, the configuration system
is rewritten, the dispatch system is rewritten, URLs are different, the
database is different, worksheets and exercises are no longer on the
filesystem, we use a templating engine, jail service protocols are rewritten,
we don't repeat ourselves, we have authorization rewritten, phpBB is gone,
and probably lots of other things that I cannot remember.

This is certainly the biggest commit I have ever made, and hopefully
the largest I ever will.

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'