Project

General

Profile

« Previous | Next » 

Revision 1463

Added by Dietmar over 13 years ago

fixed Ticket 1050 Bug in include/phpmailer/class.phpmailer.php with Lotus Notes
fixed Ticket 573, 939 Bad formatting of e-mail received from form submissions
fixed Ticket 1009 cannot change user password without changing Email in preference

View differences:

class.phpmailer.php
1
<?php
2
/*~ class.phpmailer.php
3
.---------------------------------------------------------------------------.
4
|  Software: PHPMailer - PHP email class                                    |
5
|   Version: 2.0.4                                                          |
6
|   Contact: via sourceforge.net support pages (also www.codeworxtech.com)  |
7
|      Info: http://phpmailer.sourceforge.net                               |
8
|   Support: http://sourceforge.net/projects/phpmailer/                     |
9
| ------------------------------------------------------------------------- |
10
|    Author: Andy Prevost (project admininistrator)                         |
11
|    Author: Brent R. Matzelle (original founder)                           |
12
| Copyright (c) 2004-2007, Andy Prevost. All Rights Reserved.               |
13
| Copyright (c) 2001-2003, Brent R. Matzelle                                |
14
| ------------------------------------------------------------------------- |
15
|   License: Distributed under the Lesser General Public License (LGPL)     |
16
|            http://www.gnu.org/copyleft/lesser.html                        |
17
| This program is distributed in the hope that it will be useful - WITHOUT  |
18
| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     |
19
| FITNESS FOR A PARTICULAR PURPOSE.                                         |
20
| ------------------------------------------------------------------------- |
21
| We offer a number of paid services (www.codeworxtech.com):                |
22
| - Web Hosting on highly optimized fast and secure servers                 |
23
| - Technology Consulting                                                   |
24
| - Oursourcing (highly qualified programmers and graphic designers)        |
25
'---------------------------------------------------------------------------'
26
/*
27
    Ticket #783
28
    fix Function "set_magic_quotes_runtime" is depriciated in PHP 5.3.x 2009/11/25
29

  
30

  
31
*/
32

  
33

  
34
/**
35
 * PHPMailer - PHP email transport class
36
 * @package PHPMailer
37
 * @author Andy Prevost
38
 * @copyright 2004 - 2009 Andy Prevost
39
 */
40

  
41
class PHPMailer {
42

  
43
  /////////////////////////////////////////////////
44
  // PROPERTIES, PUBLIC
45
  /////////////////////////////////////////////////
46

  
47
  /**
48
   * Email priority (1 = High, 3 = Normal, 5 = low).
49
  * @var int
50
   */
51
  var $Priority          = 3;
52

  
53
  /**
54
   * Sets the CharSet of the message.
55
  * @var string
56
   */
57
  var $CharSet           = 'iso-8859-1';
58

  
59
  /**
60
   * Sets the Content-type of the message.
61
  * @var string
62
   */
63
  var $ContentType        = 'text/plain';
64

  
65
  /**
66
   * Sets the Encoding of the message. Options for this are "8bit",
67
   * "7bit", "binary", "base64", and "quoted-printable".
68
  * @var string
69
   */
70
  var $Encoding          = '8bit';
71

  
72
  /**
73
   * Holds the most recent mailer error message.
74
  * @var string
75
   */
76
  var $ErrorInfo         = '';
77

  
78
  /**
79
   * Sets the From email address for the message.
80
  * @var string
81
   */
82
  var $From              = 'root@localhost';
83

  
84
  /**
85
   * Sets the From name of the message.
86
  * @var string
87
   */
88
  var $FromName          = 'Root User';
89

  
90
  /**
91
   * Sets the Sender email (Return-Path) of the message.  If not empty,
92
   * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
93
  * @var string
94
   */
95
  var $Sender            = '';
96

  
97
  /**
98
   * Sets the Subject of the message.
99
  * @var string
100
   */
101
  var $Subject           = '';
102

  
103
  /**
104
   * Sets the Body of the message.  This can be either an HTML or text body.
105
   * If HTML then run IsHTML(true).
106
  * @var string
107
   */
108
  var $Body              = '';
109

  
110
  /**
111
   * Sets the text-only body of the message.  This automatically sets the
112
   * email to multipart/alternative.  This body can be read by mail
113
   * clients that do not have HTML email capability such as mutt. Clients
114
   * that can read HTML will view the normal Body.
115
  * @var string
116
   */
117
  var $AltBody           = '';
118

  
119
  /**
120
   * Sets word wrapping on the body of the message to a given number of
121
   * characters.
122
  * @var int
123
   */
124
  var $WordWrap          = 0;
125

  
126
  /**
127
   * Method to send mail: ("mail", "sendmail", or "smtp").
128
  * @var string
129
   */
130
  var $Mailer            = 'mail';
131

  
132
  /**
133
   * Sets the path of the sendmail program.
134
  * @var string
135
   */
136
  var $Sendmail          = '/usr/sbin/sendmail';
137

  
138
  /**
139
   * Path to PHPMailer plugins.  This is now only useful if the SMTP class
140
   * is in a different directory than the PHP include path.
141
  * @var string
142
   */
143
  var $PluginDir         = '';
144

  
145
  /**
146
   * Holds PHPMailer version.
147
  * @var string
148
   */
149
  var $Version           = "2.0.4";
150

  
151
  /**
152
   * Sets the email address that a reading confirmation will be sent.
153
  * @var string
154
   */
155
  var $ConfirmReadingTo  = '';
156

  
157
  /**
158
   * Sets the hostname to use in Message-Id and Received headers
159
   * and as default HELO string. If empty, the value returned
160
   * by SERVER_NAME is used or 'localhost.localdomain'.
161
  * @var string
162
   */
163
  var $Hostname          = '';
164

  
165
  /**
166
   * Sets the message ID to be used in the Message-Id header.
167
   * If empty, a unique id will be generated.
168
  * @var string
169
   */
170
  var $MessageID         = '';
171

  
172
  /////////////////////////////////////////////////
173
  // PROPERTIES FOR SMTP
174
  /////////////////////////////////////////////////
175

  
176
  /**
177
   * Sets the SMTP hosts.  All hosts must be separated by a
178
   * semicolon.  You can also specify a different port
179
   * for each host by using this format: [hostname:port]
180
   * (e.g. "smtp1.example.com:25;smtp2.example.com").
181
   * Hosts will be tried in order.
182
  * @var string
183
   */
184
  var $Host        = 'localhost';
185

  
186
  /**
187
   * Sets the default SMTP server port.
188
  * @var int
189
   */
190
  var $Port        = 25;
191

  
192
  /**
193
   * Sets the SMTP HELO of the message (Default is $Hostname).
194
  * @var string
195
   */
196
  var $Helo        = '';
197

  
198
  /**
199
   * Sets connection prefix.
200
   * Options are "", "ssl" or "tls"
201
  * @var string
202
   */
203
  var $SMTPSecure = "";
204

  
205
  /**
206
   * Sets SMTP authentication. Utilizes the Username and Password variables.
207
  * @var bool
208
   */
209
  var $SMTPAuth     = false;
210

  
211
  /**
212
   * Sets SMTP username.
213
  * @var string
214
   */
215
  var $Username     = '';
216

  
217
  /**
218
   * Sets SMTP password.
219
  * @var string
220
   */
221
  var $Password     = '';
222

  
223
  /**
224
   * Sets the SMTP server timeout in seconds. This function will not
225
   * work with the win32 version.
226
  * @var int
227
   */
228
  var $Timeout      = 10;
229

  
230
  /**
231
   * Sets SMTP class debugging on or off.
232
  * @var bool
233
   */
234
  var $SMTPDebug    = false;
235

  
236
  /**
237
   * Prevents the SMTP connection from being closed after each mail
238
   * sending.  If this is set to true then to close the connection
239
   * requires an explicit call to SmtpClose().
240
  * @var bool
241
   */
242
  var $SMTPKeepAlive = false;
243

  
244
  /**
245
   * Provides the ability to have the TO field process individual
246
   * emails, instead of sending to entire TO addresses
247
  * @var bool
248
   */
249
  var $SingleTo = false;
250

  
251
  /////////////////////////////////////////////////
252
  // PROPERTIES, PRIVATE
253
  /////////////////////////////////////////////////
254

  
255
  var $smtp            = NULL;
256
  var $to              = array();
257
  var $cc              = array();
258
  var $bcc             = array();
259
  var $ReplyTo         = array();
260
  var $attachment      = array();
261
  var $CustomHeader    = array();
262
  var $message_type    = '';
263
  var $boundary        = array();
264
  var $language        = array();
265
  var $error_count     = 0;
266
  var $LE              = "\n";
267
  var $sign_cert_file  = "";
268
  var $sign_key_file   = "";
269
  var $sign_key_pass   = "";
270

  
271
  /////////////////////////////////////////////////
272
  // METHODS, VARIABLES
273
  /////////////////////////////////////////////////
274

  
275
  /**
276
   * Sets message type to HTML.
277
  * @param bool $bool
278
  * @return void
279
   */
280
  function IsHTML($bool) {
281
    if($bool == true) {
282
      $this->ContentType = 'text/html';
283
    } else {
284
      $this->ContentType = 'text/plain';
285
    }
286
  }
287

  
288
  /**
289
   * Sets Mailer to send message using SMTP.
290
  * @return void
291
   */
292
  function IsSMTP() {
293
    $this->Mailer = 'smtp';
294
  }
295

  
296
  /**
297
   * Sets Mailer to send message using PHP mail() function.
298
  * @return void
299
   */
300
  function IsMail() {
301
    $this->Mailer = 'mail';
302
  }
303

  
304
  /**
305
   * Sets Mailer to send message using the $Sendmail program.
306
  * @return void
307
   */
308
  function IsSendmail() {
309
    $this->Mailer = 'sendmail';
310
  }
311

  
312
  /**
313
   * Sets Mailer to send message using the qmail MTA.
314
  * @return void
315
   */
316
  function IsQmail() {
317
    $this->Sendmail = '/var/qmail/bin/sendmail';
318
    $this->Mailer = 'sendmail';
319
  }
320

  
321
  /////////////////////////////////////////////////
322
  // METHODS, RECIPIENTS
323
  /////////////////////////////////////////////////
324

  
325
  /**
326
   * Adds a "To" address.
327
  * @param string $address
328
  * @param string $name
329
  * @return void
330
   */
331
  function AddAddress($address, $name = '') {
332
    $cur = count($this->to);
333
    $this->to[$cur][0] = trim($address);
334
    $this->to[$cur][1] = $name;
335
  }
336

  
337
  /**
338
   * Adds a "Cc" address. Note: this function works
339
   * with the SMTP mailer on win32, not with the "mail"
340
   * mailer.
341
  * @param string $address
342
  * @param string $name
343
  * @return void
344
   */
345
  function AddCC($address, $name = '') {
346
    $cur = count($this->cc);
347
    $this->cc[$cur][0] = trim($address);
348
    $this->cc[$cur][1] = $name;
349
  }
350

  
351
  /**
352
   * Adds a "Bcc" address. Note: this function works
353
   * with the SMTP mailer on win32, not with the "mail"
354
   * mailer.
355
  * @param string $address
356
  * @param string $name
357
  * @return void
358
   */
359
  function AddBCC($address, $name = '') {
360
    $cur = count($this->bcc);
361
    $this->bcc[$cur][0] = trim($address);
362
    $this->bcc[$cur][1] = $name;
363
  }
364

  
365
  /**
366
   * Adds a "Reply-To" address.
367
  * @param string $address
368
  * @param string $name
369
  * @return void
370
   */
371
  function AddReplyTo($address, $name = '') {
372
    $cur = count($this->ReplyTo);
373
    $this->ReplyTo[$cur][0] = trim($address);
374
    $this->ReplyTo[$cur][1] = $name;
375
  }
376

  
377
  /////////////////////////////////////////////////
378
  // METHODS, MAIL SENDING
379
  /////////////////////////////////////////////////
380

  
381
  /**
382
   * Creates message and assigns Mailer. If the message is
383
   * not sent successfully then it returns false.  Use the ErrorInfo
384
   * variable to view description of the error.
385
  * @return bool
386
   */
387
  function Send() {
388
    $header = '';
389
    $body = '';
390
    $result = true;
391

  
392
    if((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
393
      $this->SetError($this->Lang('provide_address'));
394
      return false;
395
    }
396

  
397
    /* Set whether the message is multipart/alternative */
398
    if(!empty($this->AltBody)) {
399
      $this->ContentType = 'multipart/alternative';
400
    }
401

  
402
    $this->error_count = 0; // reset errors
403
    $this->SetMessageType();
404
    $header .= $this->CreateHeader();
405
    $body = $this->CreateBody();
406

  
407
    if($body == '') {
408
      return false;
409
    }
410

  
411
    /* Choose the mailer */
412
    switch($this->Mailer) {
413
      case 'sendmail':
414
        $result = $this->SendmailSend($header, $body);
415
        break;
416
      case 'smtp':
417
        $result = $this->SmtpSend($header, $body);
418
        break;
419
      case 'mail':
420
        $result = $this->MailSend($header, $body);
421
        break;
422
      default:
423
        $result = $this->MailSend($header, $body);
424
        break;
425
        //$this->SetError($this->Mailer . $this->Lang('mailer_not_supported'));
426
        //$result = false;
427
        //break;
428
    }
429

  
430
    return $result;
431
  }
432

  
433
  /**
434
   * Sends mail using the $Sendmail program.
435
  * @access private
436
  * @return bool
437
   */
438
  function SendmailSend($header, $body) {
439
    if ($this->Sender != '') {
440
      $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
441
    } else {
442
      $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
443
    }
444

  
445
    if(!@$mail = popen($sendmail, 'w')) {
446
      $this->SetError($this->Lang('execute') . $this->Sendmail);
447
      return false;
448
    }
449

  
450
    fputs($mail, $header);
451
    fputs($mail, $body);
452

  
453
    $result = pclose($mail);
454
    if (version_compare(phpversion(), '4.2.3') == -1) {
455
      $result = $result >> 8 & 0xFF;
456
    }
457
    if($result != 0) {
458
      $this->SetError($this->Lang('execute') . $this->Sendmail);
459
      return false;
460
    }
461
    return true;
462
  }
463

  
464
  /**
465
   * Sends mail using the PHP mail() function.
466
  * @access private
467
  * @return bool
468
   */
469
  function MailSend($header, $body) {
470

  
471
    $to = '';
472
    for($i = 0; $i < count($this->to); $i++) {
473
      if($i != 0) { $to .= ', '; }
474
      $to .= $this->AddrFormat($this->to[$i]);
475
    }
476

  
477
    $toArr = explode(",", $to);
478

  
479
    $params = sprintf("-oi -f %s", $this->Sender);
480
    if ($this->Sender != '' && strlen(ini_get('safe_mode')) < 1) {
481
      $old_from = ini_get('sendmail_from');
482
      ini_set('sendmail_from', $this->Sender);
483
      if ($this->SingleTo === true && count($toArr) > 1) {
484
        foreach ($toArr as $key => $val) {
485
          $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
486
        }
487
      } else {
488
        $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
489
      }
490
    } else {
491
      if ($this->SingleTo === true && count($toArr) > 1) {
492
        foreach ($toArr as $key => $val) {
493
          $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
494
        }
495
      } else {
496
        $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header);
497
      }
498
    }
499

  
500
    if (isset($old_from)) {
501
      ini_set('sendmail_from', $old_from);
502
    }
503

  
504
    if(!$rt) {
505
      $this->SetError($this->Lang('instantiate'));
506
      return false;
507
    }
508

  
509
    return true;
510
  }
511

  
512
  /**
513
   * Sends mail via SMTP using PhpSMTP (Author:
514
   * Chris Ryan).  Returns bool.  Returns false if there is a
515
   * bad MAIL FROM, RCPT, or DATA input.
516
  * @access private
517
  * @return bool
518
   */
519
  function SmtpSend($header, $body) {
520
    include_once($this->PluginDir . 'class.smtp.php');
521
    $error = '';
522
    $bad_rcpt = array();
523

  
524
    if(!$this->SmtpConnect()) {
525
      return false;
526
    }
527

  
528
    $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
529
    if(!$this->smtp->Mail($smtp_from)) {
530
      $error = $this->Lang('from_failed') . $smtp_from;
531
      $this->SetError($error);
532
      $this->smtp->Reset();
533
      return false;
534
    }
535

  
536
    /* Attempt to send attach all recipients */
537
    for($i = 0; $i < count($this->to); $i++) {
538
      if(!$this->smtp->Recipient($this->to[$i][0])) {
539
        $bad_rcpt[] = $this->to[$i][0];
540
      }
541
    }
542
    for($i = 0; $i < count($this->cc); $i++) {
543
      if(!$this->smtp->Recipient($this->cc[$i][0])) {
544
        $bad_rcpt[] = $this->cc[$i][0];
545
      }
546
    }
547
    for($i = 0; $i < count($this->bcc); $i++) {
548
      if(!$this->smtp->Recipient($this->bcc[$i][0])) {
549
        $bad_rcpt[] = $this->bcc[$i][0];
550
      }
551
    }
552

  
553
    if(count($bad_rcpt) > 0) { // Create error message
554
      for($i = 0; $i < count($bad_rcpt); $i++) {
555
        if($i != 0) {
556
          $error .= ', ';
557
        }
558
        $error .= $bad_rcpt[$i];
559
      }
560
      $error = $this->Lang('recipients_failed') . $error;
561
      $this->SetError($error);
562
      $this->smtp->Reset();
563
      return false;
564
    }
565

  
566
    if(!$this->smtp->Data($header . $body)) {
567
      $this->SetError($this->Lang('data_not_accepted'));
568
      $this->smtp->Reset();
569
      return false;
570
    }
571
    if($this->SMTPKeepAlive == true) {
572
      $this->smtp->Reset();
573
    } else {
574
      $this->SmtpClose();
575
    }
576

  
577
    return true;
578
  }
579

  
580
  /**
581
   * Initiates a connection to an SMTP server.  Returns false if the
582
   * operation failed.
583
  * @access private
584
  * @return bool
585
   */
586
  function SmtpConnect()
587
  {
588
    if($this->smtp == NULL)
589
    {
590
      $this->smtp = new SMTP();
591
    }
592

  
593
    $this->smtp->do_debug = $this->SMTPDebug;
594
    $hosts = explode(';', $this->Host);
595
    $index = 0;
596
    $connection = ($this->smtp->Connected());
597

  
598
    /* Retry while there is no connection */
599
    while($index < count($hosts) && $connection == false)
600
    {
601
      $hostinfo = array();
602
      if(preg_match('/(.+):([0-9]+)/', $hosts[$index], $hostinfo))
603
      {
604
        $host = $hostinfo[1];
605
        $port = $hostinfo[2];
606
      } else {
607
        $host = $hosts[$index];
608
        $port = $this->Port;
609
      }
610

  
611
      if($this->smtp->Connect(((!empty($this->SMTPSecure))?$this->SMTPSecure.'://':'').$host, $port, $this->Timeout)) {
612
        if ($this->Helo != '') {
613
          $this->smtp->Hello($this->Helo);
614
        } else {
615
          $this->smtp->Hello($this->ServerHostname());
616
        }
617

  
618
        $connection = true;
619
        if($this->SMTPAuth) {
620
          if(!$this->smtp->Authenticate($this->Username, $this->Password)) {
621
            $this->SetError($this->Lang('authenticate'));
622
            $this->smtp->Reset();
623
            $connection = false;
624
          }
625
        }
626
      }
627
      $index++;
628
    }
629
    if(!$connection) {
630
      $this->SetError($this->Lang('connect_host'));
631
    }
632

  
633
    return $connection;
634
  }
635

  
636
  /**
637
   * Closes the active SMTP session if one exists.
638
  * @return void
639
   */
640
  function SmtpClose() {
641
    if($this->smtp != NULL) {
642
      if($this->smtp->Connected()) {
643
        $this->smtp->Quit();
644
        $this->smtp->Close();
645
      }
646
    }
647
  }
648

  
649
  /**
650
   * Sets the language for all class error messages.  Returns false
651
   * if it cannot load the language file.  The default language type
652
   * is English.
653
  * @param string $lang_type Type of language (e.g. Portuguese: "br")
654
  * @param string $lang_path Path to the language file directory
655
  * @access public
656
  * @return bool
657
   */
658
  function SetLanguage($lang_type, $lang_path = 'language/') {
659
    if(file_exists($lang_path.'phpmailer.lang-'.$lang_type.'.php')) {
660
      include($lang_path.'phpmailer.lang-'.$lang_type.'.php');
661
    } elseif (file_exists($lang_path.'phpmailer.lang-en.php')) {
662
      include($lang_path.'phpmailer.lang-en.php');
663
    } else {
664
      $PHPMAILER_LANG = array();
665
      $PHPMAILER_LANG["provide_address"]      = 'You must provide at least one ' .
666
      $PHPMAILER_LANG["mailer_not_supported"] = ' mailer is not supported.';
667
      $PHPMAILER_LANG["execute"]              = 'Could not execute: ';
668
      $PHPMAILER_LANG["instantiate"]          = 'Could not instantiate mail function.';
669
      $PHPMAILER_LANG["authenticate"]         = 'SMTP Error: Could not authenticate.';
670
      $PHPMAILER_LANG["from_failed"]          = 'The following From address failed: ';
671
      $PHPMAILER_LANG["recipients_failed"]    = 'SMTP Error: The following ' .
672
      $PHPMAILER_LANG["data_not_accepted"]    = 'SMTP Error: Data not accepted.';
673
      $PHPMAILER_LANG["connect_host"]         = 'SMTP Error: Could not connect to SMTP host.';
674
      $PHPMAILER_LANG["file_access"]          = 'Could not access file: ';
675
      $PHPMAILER_LANG["file_open"]            = 'File Error: Could not open file: ';
676
      $PHPMAILER_LANG["encoding"]             = 'Unknown encoding: ';
677
      $PHPMAILER_LANG["signing"]              = 'Signing Error: ';
678
    }
679
    $this->language = $PHPMAILER_LANG;
680

  
681
    return true;
682
  }
683

  
684
  /////////////////////////////////////////////////
685
  // METHODS, MESSAGE CREATION
686
  /////////////////////////////////////////////////
687

  
688
  /**
689
   * Creates recipient headers.
690
  * @access private
691
  * @return string
692
   */
693
  function AddrAppend($type, $addr) {
694
    $addr_str = $type . ': ';
695
    $addr_str .= $this->AddrFormat($addr[0]);
696
    if(count($addr) > 1) {
697
      for($i = 1; $i < count($addr); $i++) {
698
        $addr_str .= ', ' . $this->AddrFormat($addr[$i]);
699
      }
700
    }
701
    $addr_str .= $this->LE;
702

  
703
    return $addr_str;
704
  }
705

  
706
  /**
707
   * Formats an address correctly.
708
  * @access private
709
  * @return string
710
   */
711
  function AddrFormat($addr) {
712
    if(empty($addr[1])) {
713
      $formatted = $this->SecureHeader($addr[0]);
714
    } else {
715
      $formatted = $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">";
716
    }
717

  
718
    return $formatted;
719
  }
720

  
721
  /**
722
   * Wraps message for use with mailers that do not
723
   * automatically perform wrapping and for quoted-printable.
724
   * Original written by philippe.
725
  * @access private
726
  * @return string
727
   */
728
  function WrapText($message, $length, $qp_mode = false) {
729
    $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
730
    // If utf-8 encoding is used, we will need to make sure we don't
731
    // split multibyte characters when we wrap
732
    $is_utf8 = (strtolower($this->CharSet) == "utf-8");
733

  
734
    $message = $this->FixEOL($message);
735
    if (substr($message, -1) == $this->LE) {
736
      $message = substr($message, 0, -1);
737
    }
738

  
739
    $line = explode($this->LE, $message);
740
    $message = '';
741
    for ($i=0 ;$i < count($line); $i++) {
742
      $line_part = explode(' ', $line[$i]);
743
      $buf = '';
744
      for ($e = 0; $e<count($line_part); $e++) {
745
        $word = $line_part[$e];
746
        if ($qp_mode and (strlen($word) > $length)) {
747
          $space_left = $length - strlen($buf) - 1;
748
          if ($e != 0) {
749
            if ($space_left > 20) {
750
              $len = $space_left;
751
              if ($is_utf8) {
752
                $len = $this->UTF8CharBoundary($word, $len);
753
              } elseif (substr($word, $len - 1, 1) == "=") {
754
                $len--;
755
              } elseif (substr($word, $len - 2, 1) == "=") {
756
                $len -= 2;
757
              }
758
              $part = substr($word, 0, $len);
759
              $word = substr($word, $len);
760
              $buf .= ' ' . $part;
761
              $message .= $buf . sprintf("=%s", $this->LE);
762
            } else {
763
              $message .= $buf . $soft_break;
764
            }
765
            $buf = '';
766
          }
767
          while (strlen($word) > 0) {
768
            $len = $length;
769
            if ($is_utf8) {
770
              $len = $this->UTF8CharBoundary($word, $len);
771
            } elseif (substr($word, $len - 1, 1) == "=") {
772
              $len--;
773
            } elseif (substr($word, $len - 2, 1) == "=") {
774
              $len -= 2;
775
            }
776
            $part = substr($word, 0, $len);
777
            $word = substr($word, $len);
778

  
779
            if (strlen($word) > 0) {
780
              $message .= $part . sprintf("=%s", $this->LE);
781
            } else {
782
              $buf = $part;
783
            }
784
          }
785
        } else {
786
          $buf_o = $buf;
787
          $buf .= ($e == 0) ? $word : (' ' . $word);
788

  
789
          if (strlen($buf) > $length and $buf_o != '') {
790
            $message .= $buf_o . $soft_break;
791
            $buf = $word;
792
          }
793
        }
794
      }
795
      $message .= $buf . $this->LE;
796
    }
797

  
798
    return $message;
799
  }
800

  
801
  /**
802
   * Finds last character boundary prior to maxLength in a utf-8
803
   * quoted (printable) encoded string.
804
   * Original written by Colin Brown.
805
  * @access private
806
  * @param string $encodedText utf-8 QP text
807
  * @param int    $maxLength   find last character boundary prior to this length
808
  * @return int
809
   */
810
  function UTF8CharBoundary($encodedText, $maxLength) {
811
    $foundSplitPos = false;
812
    $lookBack = 3;
813
    while (!$foundSplitPos) {
814
      $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
815
      $encodedCharPos = strpos($lastChunk, "=");
816
      if ($encodedCharPos !== false) {
817
        // Found start of encoded character byte within $lookBack block.
818
        // Check the encoded byte value (the 2 chars after the '=')
819
        $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
820
        $dec = hexdec($hex);
821
        if ($dec < 128) { // Single byte character.
822
          // If the encoded char was found at pos 0, it will fit
823
          // otherwise reduce maxLength to start of the encoded char
824
          $maxLength = ($encodedCharPos == 0) ? $maxLength :
825
          $maxLength - ($lookBack - $encodedCharPos);
826
          $foundSplitPos = true;
827
        } elseif ($dec >= 192) { // First byte of a multi byte character
828
          // Reduce maxLength to split at start of character
829
          $maxLength = $maxLength - ($lookBack - $encodedCharPos);
830
          $foundSplitPos = true;
831
        } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
832
          $lookBack += 3;
833
        }
834
      } else {
835
        // No encoded character found
836
        $foundSplitPos = true;
837
      }
838
    }
839
    return $maxLength;
840
  }
841

  
842
  /**
843
   * Set the body wrapping.
844
  * @access private
845
  * @return void
846
   */
847
  function SetWordWrap() {
848
    if($this->WordWrap < 1) {
849
      return;
850
    }
851

  
852
    switch($this->message_type) {
853
      case 'alt':
854
        /* fall through */
855
      case 'alt_attachments':
856
        $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
857
        break;
858
      default:
859
        $this->Body = $this->WrapText($this->Body, $this->WordWrap);
860
        break;
861
    }
862
  }
863

  
864
  /**
865
   * Assembles message header.
866
  * @access private
867
  * @return string
868
   */
869
  function CreateHeader() {
870
    $result = '';
871

  
872
    /* Set the boundaries */
873
    $uniq_id = md5(uniqid(time()));
874
    $this->boundary[1] = 'b1_' . $uniq_id;
875
    $this->boundary[2] = 'b2_' . $uniq_id;
876

  
877
    $result .= $this->HeaderLine('Date', $this->RFCDate());
878
    if($this->Sender == '') {
879
      $result .= $this->HeaderLine('Return-Path', trim($this->From));
880
    } else {
881
      $result .= $this->HeaderLine('Return-Path', trim($this->Sender));
882
    }
883

  
884
    /* To be created automatically by mail() */
885
    if($this->Mailer != 'mail') {
886
      if(count($this->to) > 0) {
887
        $result .= $this->AddrAppend('To', $this->to);
888
      } elseif (count($this->cc) == 0) {
889
        $result .= $this->HeaderLine('To', 'undisclosed-recipients:;');
890
      }
891
    }
892

  
893
    $from = array();
894
    $from[0][0] = trim($this->From);
895
    $from[0][1] = $this->FromName;
896
    $result .= $this->AddrAppend('From', $from);
897

  
898
    /* sendmail and mail() extract Cc from the header before sending */
899
    if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->cc) > 0)) {
900
      $result .= $this->AddrAppend('Cc', $this->cc);
901
    }
902

  
903
    /* sendmail and mail() extract Bcc from the header before sending */
904
    if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) {
905
      $result .= $this->AddrAppend('Bcc', $this->bcc);
906
    }
907

  
908
    if(count($this->ReplyTo) > 0) {
909
      $result .= $this->AddrAppend('Reply-To', $this->ReplyTo);
910
    }
911

  
912
    /* mail() sets the subject itself */
913
    if($this->Mailer != 'mail') {
914
      $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject)));
915
    }
916

  
917
    if($this->MessageID != '') {
918
      $result .= $this->HeaderLine('Message-ID',$this->MessageID);
919
    } else {
920
      $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
921
    }
922
    $result .= $this->HeaderLine('X-Priority', $this->Priority);
923
    $result .= $this->HeaderLine('X-Mailer', 'PHPMailer (phpmailer.sourceforge.net) [version ' . $this->Version . ']');
924

  
925
    if($this->ConfirmReadingTo != '') {
926
      $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
927
    }
928

  
929
    // Add custom headers
930
    for($index = 0; $index < count($this->CustomHeader); $index++) {
931
      $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
932
    }
933
    if (!$this->sign_key_file) {
934
      $result .= $this->HeaderLine('MIME-Version', '1.0');
935
      $result .= $this->GetMailMIME();
936
    }
937

  
938
    return $result;
939
  }
940

  
941
  /**
942
   * Returns the message MIME.
943
  * @access private
944
  * @return string
945
   */
946
  function GetMailMIME() {
947
    $result = '';
948
    switch($this->message_type) {
949
      case 'plain':
950
        $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
951
        $result .= sprintf("Content-Type: %s; charset=\"%s\"", $this->ContentType, $this->CharSet);
952
        break;
953
      case 'attachments':
954
        /* fall through */
955
      case 'alt_attachments':
956
        if($this->InlineImageExists()){
957
          $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 'multipart/related', $this->LE, $this->LE, $this->boundary[1], $this->LE);
958
        } else {
959
          $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
960
          $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
961
        }
962
        break;
963
      case 'alt':
964
        $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
965
        $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
966
        break;
967
    }
968

  
969
    if($this->Mailer != 'mail') {
970
      $result .= $this->LE.$this->LE;
971
    }
972

  
973
    return $result;
974
  }
975

  
976
  /**
977
   * Assembles the message body.  Returns an empty string on failure.
978
  * @access private
979
  * @return string
980
   */
981
  function CreateBody() {
982
    $result = '';
983
    if ($this->sign_key_file) {
984
      $result .= $this->GetMailMIME();
985
    }
986

  
987
    $this->SetWordWrap();
988

  
989
    switch($this->message_type) {
990
      case 'alt':
991
        $result .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
992
        $result .= $this->EncodeString($this->AltBody, $this->Encoding);
993
        $result .= $this->LE.$this->LE;
994
        $result .= $this->GetBoundary($this->boundary[1], '', 'text/html', '');
995
        $result .= $this->EncodeString($this->Body, $this->Encoding);
996
        $result .= $this->LE.$this->LE;
997
        $result .= $this->EndBoundary($this->boundary[1]);
998
        break;
999
      case 'plain':
1000
        $result .= $this->EncodeString($this->Body, $this->Encoding);
1001
        break;
1002
      case 'attachments':
1003
        $result .= $this->GetBoundary($this->boundary[1], '', '', '');
1004
        $result .= $this->EncodeString($this->Body, $this->Encoding);
1005
        $result .= $this->LE;
1006
        $result .= $this->AttachAll();
1007
        break;
1008
      case 'alt_attachments':
1009
        $result .= sprintf("--%s%s", $this->boundary[1], $this->LE);
1010
        $result .= sprintf("Content-Type: %s;%s" . "\tboundary=\"%s\"%s", 'multipart/alternative', $this->LE, $this->boundary[2], $this->LE.$this->LE);
1011
        $result .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '') . $this->LE; // Create text body
1012
        $result .= $this->EncodeString($this->AltBody, $this->Encoding);
1013
        $result .= $this->LE.$this->LE;
1014
        $result .= $this->GetBoundary($this->boundary[2], '', 'text/html', '') . $this->LE; // Create the HTML body
1015
        $result .= $this->EncodeString($this->Body, $this->Encoding);
1016
        $result .= $this->LE.$this->LE;
1017
        $result .= $this->EndBoundary($this->boundary[2]);
1018
        $result .= $this->AttachAll();
1019
        break;
1020
    }
1021

  
1022
    if($this->IsError()) {
1023
      $result = '';
1024
    } else if ($this->sign_key_file) {
1025
      $file = tempnam("", "mail");
1026
      $fp = fopen($file, "w");
1027
      fwrite($fp, $result);
1028
      fclose($fp);
1029
      $signed = tempnam("", "signed");
1030

  
1031
      if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_cert_file, array("file://".$this->sign_key_file, $this->sign_key_pass), null)) {
1032
        $fp = fopen($signed, "r");
1033
        $result = fread($fp, filesize($this->sign_key_file));
1034
        $result = '';
1035
        while(!feof($fp)){
1036
          $result = $result . fread($fp, 1024);
1037
        }
1038
        fclose($fp);
1039
      } else {
1040
        $this->SetError($this->Lang("signing").openssl_error_string());
1041
        $result = '';
1042
      }
1043

  
1044
      unlink($file);
1045
      unlink($signed);
1046
    }
1047

  
1048
    return $result;
1049
  }
1050

  
1051
  /**
1052
   * Returns the start of a message boundary.
1053
  * @access private
1054
   */
1055
  function GetBoundary($boundary, $charSet, $contentType, $encoding) {
1056
    $result = '';
1057
    if($charSet == '') {
1058
      $charSet = $this->CharSet;
1059
    }
1060
    if($contentType == '') {
1061
      $contentType = $this->ContentType;
1062
    }
1063
    if($encoding == '') {
1064
      $encoding = $this->Encoding;
1065
    }
1066
    $result .= $this->TextLine('--' . $boundary);
1067
    $result .= sprintf("Content-Type: %s; charset = \"%s\"", $contentType, $charSet);
1068
    $result .= $this->LE;
1069
    $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding);
1070
    $result .= $this->LE;
1071

  
1072
    return $result;
1073
  }
1074

  
1075
  /**
1076
   * Returns the end of a message boundary.
1077
  * @access private
1078
   */
1079
  function EndBoundary($boundary) {
1080
    return $this->LE . '--' . $boundary . '--' . $this->LE;
1081
  }
1082

  
1083
  /**
1084
   * Sets the message type.
1085
  * @access private
1086
  * @return void
1087
   */
1088
  function SetMessageType() {
1089
    if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) {
1090
      $this->message_type = 'plain';
1091
    } else {
1092
      if(count($this->attachment) > 0) {
1093
        $this->message_type = 'attachments';
1094
      }
1095
      if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) {
1096
        $this->message_type = 'alt';
1097
      }
1098
      if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) {
1099
        $this->message_type = 'alt_attachments';
1100
      }
1101
    }
1102
  }
1103

  
1104
  /* Returns a formatted header line.
1105
  * @access private
1106
  * @return string
1107
   */
1108
  function HeaderLine($name, $value) {
1109
    return $name . ': ' . $value . $this->LE;
1110
  }
1111

  
1112
  /**
1113
   * Returns a formatted mail line.
1114
  * @access private
1115
  * @return string
1116
   */
1117
  function TextLine($value) {
1118
    return $value . $this->LE;
1119
  }
1120

  
1121
  /////////////////////////////////////////////////
1122
  // CLASS METHODS, ATTACHMENTS
1123
  /////////////////////////////////////////////////
1124

  
1125
  /**
1126
   * Adds an attachment from a path on the filesystem.
1127
   * Returns false if the file could not be found
1128
   * or accessed.
1129
  * @param string $path Path to the attachment.
1130
  * @param string $name Overrides the attachment name.
1131
  * @param string $encoding File encoding (see $Encoding).
1132
  * @param string $type File extension (MIME) type.
1133
  * @return bool
1134
   */
1135
  function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
1136
    if(!@is_file($path)) {
1137
      $this->SetError($this->Lang('file_access') . $path);
1138
      return false;
1139
    }
1140

  
1141
    $filename = basename($path);
1142
    if($name == '') {
1143
      $name = $filename;
1144
    }
1145

  
1146
    $cur = count($this->attachment);
1147
    $this->attachment[$cur][0] = $path;
1148
    $this->attachment[$cur][1] = $filename;
1149
    $this->attachment[$cur][2] = $name;
1150
    $this->attachment[$cur][3] = $encoding;
1151
    $this->attachment[$cur][4] = $type;
1152
    $this->attachment[$cur][5] = false; // isStringAttachment
1153
    $this->attachment[$cur][6] = 'attachment';
1154
    $this->attachment[$cur][7] = 0;
1155

  
1156
    return true;
1157
  }
1158

  
1159
  /**
1160
   * Attaches all fs, string, and binary attachments to the message.
1161
   * Returns an empty string on failure.
1162
  * @access private
1163
  * @return string
1164
   */
1165
  function AttachAll() {
1166
    /* Return text of body */
1167
    $mime = array();
1168

  
1169
    /* Add all attachments */
1170
    for($i = 0; $i < count($this->attachment); $i++) {
1171
      /* Check for string attachment */
1172
      $bString = $this->attachment[$i][5];
1173
      if ($bString) {
1174
        $string = $this->attachment[$i][0];
1175
      } else {
1176
        $path = $this->attachment[$i][0];
1177
      }
1178

  
1179
      $filename    = $this->attachment[$i][1];
1180
      $name        = $this->attachment[$i][2];
1181
      $encoding    = $this->attachment[$i][3];
1182
      $type        = $this->attachment[$i][4];
1183
      $disposition = $this->attachment[$i][6];
1184
      $cid         = $this->attachment[$i][7];
1185

  
1186
      $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE);
1187
      $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE);
1188
      $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
1189

  
1190
      if($disposition == 'inline') {
1191
        $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
1192
      }
1193

  
1194
      $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE);
1195

  
1196
      /* Encode as string attachment */
1197
      if($bString) {
1198
        $mime[] = $this->EncodeString($string, $encoding);
1199
        if($this->IsError()) {
1200
          return '';
1201
        }
1202
        $mime[] = $this->LE.$this->LE;
1203
      } else {
1204
        $mime[] = $this->EncodeFile($path, $encoding);
1205
        if($this->IsError()) {
1206
          return '';
1207
        }
1208
        $mime[] = $this->LE.$this->LE;
1209
      }
1210
    }
1211

  
1212
    $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE);
1213

  
1214
    return join('', $mime);
1215
  }
1216

  
1217
  /**
1218
   * Encodes attachment in requested format.  Returns an
1219
   * empty string on failure.
1220
  * @access private
1221
  * @return string
1222
   */
1223
  function EncodeFile ($path, $encoding = 'base64') {
1224
    if(!@$fd = fopen($path, 'rb')) {
1225
      $this->SetError($this->Lang('file_open') . $path);
1226
      return '';
1227
    }
1228

  
1229
    if(version_compare(PHP_VERSION, '5.3.0', '<'))
1230
    {
1231
        $magic_quotes = get_magic_quotes_runtime();
1232
        set_magic_quotes_runtime(0); // Disable magic_quotes_runtime
1233
    }
1234

  
1235
    $file_buffer = fread($fd, filesize($path));
1236
    $file_buffer = $this->EncodeString($file_buffer, $encoding);
1237
    fclose($fd);
1238

  
1239
    if(version_compare(PHP_VERSION, '5.3.0', '<'))
1240
    {
1241
        set_magic_quotes_runtime($magic_quotes);
1242
    }
1243

  
1244
    return $file_buffer;
1245
  }
1246

  
1247
  /**
1248
   * Encodes string to requested format. Returns an
1249
   * empty string on failure.
1250
  * @access private
1251
  * @return string
1252
   */
1253
  function EncodeString ($str, $encoding = 'base64') {
1254
    $encoded = '';
1255
    switch(strtolower($encoding)) {
1256
      case 'base64':
1257
        /* chunk_split is found in PHP >= 3.0.6 */
1258
        $encoded = chunk_split(base64_encode($str), 76, $this->LE);
1259
        break;
1260
      case '7bit':
1261
      case '8bit':
1262
        $encoded = $this->FixEOL($str);
1263
        if (substr($encoded, -(strlen($this->LE))) != $this->LE)
1264
          $encoded .= $this->LE;
1265
        break;
1266
      case 'binary':
1267
        $encoded = $str;
1268
        break;
1269
      case 'quoted-printable':
1270
        $encoded = $this->EncodeQP($str);
1271
        break;
1272
      default:
1273
        $this->SetError($this->Lang('encoding') . $encoding);
1274
        break;
1275
    }
1276
    return $encoded;
1277
  }
1278

  
1279
  /**
1280
   * Encode a header string to best of Q, B, quoted or none.
1281
  * @access private
1282
  * @return string
1283
   */
1284
  function EncodeHeader ($str, $position = 'text') {
1285
    $x = 0;
1286

  
1287
    switch (strtolower($position)) {
1288
      case 'phrase':
1289
        if (!preg_match('/[\200-\377]/', $str)) {
1290
          /* Can't use addslashes as we don't know what value has magic_quotes_sybase. */
1291
          $encoded = addcslashes($str, "\0..\37\177\\\"");
1292
          if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
1293
            return ($encoded);
1294
          } else {
1295
            return ("\"$encoded\"");
1296
          }
1297
        }
1298
        $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
1299
        break;
1300
      case 'comment':
1301
        $x = preg_match_all('/[()"]/', $str, $matches);
1302
        /* Fall-through */
1303
      case 'text':
1304
      default:
1305
        $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
1306
        break;
1307
    }
1308

  
1309
    if ($x == 0) {
1310
      return ($str);
1311
    }
1312

  
1313
    $maxlen = 75 - 7 - strlen($this->CharSet);
1314
    /* Try to select the encoding which should produce the shortest output */
1315
    if (strlen($str)/3 < $x) {
1316
      $encoding = 'B';
1317
      if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) {
1318
     // Use a custom function which correctly encodes and wraps long
1319
     // multibyte strings without breaking lines within a character
1320
        $encoded = $this->Base64EncodeWrapMB($str);
1321
      } else {
1322
        $encoded = base64_encode($str);
1323
        $maxlen -= $maxlen % 4;
1324
        $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
1325
      }
1326
    } else {
1327
      $encoding = 'Q';
1328
      $encoded = $this->EncodeQ($str, $position);
1329
      $encoded = $this->WrapText($encoded, $maxlen, true);
1330
      $encoded = str_replace('='.$this->LE, "\n", trim($encoded));
1331
    }
1332

  
1333
    $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
1334
    $encoded = trim(str_replace("\n", $this->LE, $encoded));
1335

  
1336
    return $encoded;
1337
  }
1338

  
1339
  /**
1340
   * Checks if a string contains multibyte characters.
1341
  * @access private
1342
  * @param string $str multi-byte text to wrap encode
1343
  * @return bool
1344
   */
1345
  function HasMultiBytes($str) {
1346
    if (function_exists('mb_strlen')) {
1347
      return (strlen($str) > mb_strlen($str, $this->CharSet));
1348
    } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
1349
      return False;
1350
    }
1351
  }
1352

  
1353
  /**
1354
   * Correctly encodes and wraps long multibyte strings for mail headers
1355
   * without breaking lines within a character.
1356
   * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php
1357
  * @access private
1358
  * @param string $str multi-byte text to wrap encode
1359
  * @return string
1360
   */
1361
  function Base64EncodeWrapMB($str) {
1362
    $start = "=?".$this->CharSet."?B?";
1363
    $end = "?=";
1364
    $encoded = "";
1365

  
1366
    $mb_length = mb_strlen($str, $this->CharSet);
1367
    // Each line must have length <= 75, including $start and $end
1368
    $length = 75 - strlen($start) - strlen($end);
1369
    // Average multi-byte ratio
1370
    $ratio = $mb_length / strlen($str);
1371
    // Base64 has a 4:3 ratio
1372
    $offset = $avgLength = floor($length * $ratio * .75);
1373

  
1374
    for ($i = 0; $i < $mb_length; $i += $offset) {
1375
      $lookBack = 0;
1376

  
1377
      do {
1378
        $offset = $avgLength - $lookBack;
1379
        $chunk = mb_substr($str, $i, $offset, $this->CharSet);
1380
        $chunk = base64_encode($chunk);
1381
        $lookBack++;
1382
      }
1383
      while (strlen($chunk) > $length);
1384

  
1385
      $encoded .= $chunk . $this->LE;
1386
    }
1387

  
1388
    // Chomp the last linefeed
1389
    $encoded = substr($encoded, 0, -strlen($this->LE));
1390
    return $encoded;
1391
  }
1392

  
1393
  /**
1394
   * Encode string to quoted-printable.
1395
  * @access private
1396
  * @return string
1397
   */
1398
  function EncodeQP( $input = '', $line_max = 76, $space_conv = false ) {
1399
    $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
1400
    $lines = preg_split('/(?:\r\n|\r|\n)/', $input);
1401
    $eol = "\r\n";
1402
    $escape = '=';
1403
    $output = '';
1404
    while( list(, $line) = each($lines) ) {
1405
      $linlen = strlen($line);
1406
      $newline = '';
1407
      for($i = 0; $i < $linlen; $i++) {
1408
        $c = substr( $line, $i, 1 );
1409
        $dec = ord( $c );
1410
        if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E
1411
          $c = '=2E';
1412
        }
1413
        if ( $dec == 32 ) {
1414
          if ( $i == ( $linlen - 1 ) ) { // convert space at eol only
1415
            $c = '=20';
1416
          } else if ( $space_conv ) {
1417
            $c = '=20';
1418
          }
1419
        } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required
1420
          $h2 = floor($dec/16);
1421
          $h1 = floor($dec%16);
1422
          $c = $escape.$hex[$h2].$hex[$h1];
1423
        }
1424
        if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted
1425
          $output .= $newline.$escape.$eol; //  soft line break; " =\r\n" is okay
1426
          $newline = '';
1427
          // check if newline first character will be point or not
1428
          if ( $dec == 46 ) {
1429
            $c = '=2E';
1430
          }
1431
        }
1432
        $newline .= $c;
1433
      } // end of for
1434
      $output .= $newline.$eol;
1435
    } // end of while
1436
    return $output;
1437
  }
1438

  
1439
  /**
1440
   * Encode string to q encoding.
1441
  * @access private
1442
  * @return string
1443
   */
1444
  function EncodeQ ($str, $position = 'text') {
1445
    /* There should not be any EOL in the string */
1446
    $encoded = preg_replace("[\r\n]", '', $str);
1447

  
1448
    switch (strtolower($position)) {
1449
      case 'phrase':
1450
        $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
1451
        break;
1452
      case 'comment':
1453
        $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
1454
      case 'text':
1455
      default:
1456
        /* Replace every high ascii, control =, ? and _ characters */
1457
        $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
1458
              "'='.sprintf('%02X', ord('\\1'))", $encoded);
1459
        break;
1460
    }
1461

  
1462
    /* Replace every spaces to _ (more readable than =20) */
1463
    $encoded = str_replace(' ', '_', $encoded);
1464

  
1465
    return $encoded;
1466
  }
1467

  
1468
  /**
1469
   * Adds a string or binary attachment (non-filesystem) to the list.
1470
   * This method can be used to attach ascii or binary data,
1471
   * such as a BLOB record from a database.
1472
  * @param string $string String attachment data.
1473
  * @param string $filename Name of the attachment.
1474
  * @param string $encoding File encoding (see $Encoding).
1475
  * @param string $type File extension (MIME) type.
1476
  * @return void
1477
   */
1478
  function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') {
1479
    /* Append to $attachment array */
1480
    $cur = count($this->attachment);
1481
    $this->attachment[$cur][0] = $string;
1482
    $this->attachment[$cur][1] = $filename;
1483
    $this->attachment[$cur][2] = $filename;
1484
    $this->attachment[$cur][3] = $encoding;
1485
    $this->attachment[$cur][4] = $type;
1486
    $this->attachment[$cur][5] = true; // isString
1487
    $this->attachment[$cur][6] = 'attachment';
1488
    $this->attachment[$cur][7] = 0;
1489
  }
1490

  
1491
  /**
1492
   * Adds an embedded attachment.  This can include images, sounds, and
1493
   * just about any other document.  Make sure to set the $type to an
1494
   * image type.  For JPEG images use "image/jpeg" and for GIF images
1495
   * use "image/gif".
1496
  * @param string $path Path to the attachment.
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff