Project

General

Profile

« Previous | Next » 

Revision 1289

Added by kweitzel almost 15 years ago

Branch 2.8.1 merged back into Trunk

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
/**
28
 * PHPMailer - PHP email transport class
29
 * @package PHPMailer
30
 * @author Andy Prevost
31
 * @copyright 2004 - 2009 Andy Prevost
32
 */
33

  
34
class PHPMailer {
35

  
36
  /////////////////////////////////////////////////
37
  // PROPERTIES, PUBLIC
38
  /////////////////////////////////////////////////
39

  
40
  /**
41
   * Email priority (1 = High, 3 = Normal, 5 = low).
42
   * @var int
43
   */
44
  var $Priority          = 3;
45

  
46
  /**
47
   * Sets the CharSet of the message.
48
   * @var string
49
   */
50
  var $CharSet           = 'iso-8859-1';
51

  
52
  /**
53
   * Sets the Content-type of the message.
54
   * @var string
55
   */
56
  var $ContentType        = 'text/plain';
57

  
58
  /**
59
   * Sets the Encoding of the message. Options for this are "8bit",
60
   * "7bit", "binary", "base64", and "quoted-printable".
61
   * @var string
62
   */
63
  var $Encoding          = '8bit';
64

  
65
  /**
66
   * Holds the most recent mailer error message.
67
   * @var string
68
   */
69
  var $ErrorInfo         = '';
70

  
71
  /**
72
   * Sets the From email address for the message.
73
   * @var string
74
   */
75
  var $From              = 'root@localhost';
76

  
77
  /**
78
   * Sets the From name of the message.
79
   * @var string
80
   */
81
  var $FromName          = 'Root User';
82

  
83
  /**
84
   * Sets the Sender email (Return-Path) of the message.  If not empty,
85
   * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
86
   * @var string
87
   */
88
  var $Sender            = '';
89

  
90
  /**
91
   * Sets the Subject of the message.
92
   * @var string
93
   */
94
  var $Subject           = '';
95

  
96
  /**
97
   * Sets the Body of the message.  This can be either an HTML or text body.
98
   * If HTML then run IsHTML(true).
99
   * @var string
100
   */
101
  var $Body              = '';
102

  
103
  /**
104
   * Sets the text-only body of the message.  This automatically sets the
105
   * email to multipart/alternative.  This body can be read by mail
106
   * clients that do not have HTML email capability such as mutt. Clients
107
   * that can read HTML will view the normal Body.
108
   * @var string
109
   */
110
  var $AltBody           = '';
111

  
112
  /**
113
   * Sets word wrapping on the body of the message to a given number of
114
   * characters.
115
   * @var int
116
   */
117
  var $WordWrap          = 0;
118

  
119
  /**
120
   * Method to send mail: ("mail", "sendmail", or "smtp").
121
   * @var string
122
   */
123
  var $Mailer            = 'mail';
124

  
125
  /**
126
   * Sets the path of the sendmail program.
127
   * @var string
128
   */
129
  var $Sendmail          = '/usr/sbin/sendmail';
130

  
131
  /**
132
   * Path to PHPMailer plugins.  This is now only useful if the SMTP class
133
   * is in a different directory than the PHP include path.
134
   * @var string
135
   */
136
  var $PluginDir         = '';
137

  
138
  /**
139
   * Holds PHPMailer version.
140
   * @var string
141
   */
142
  var $Version           = "2.0.4";
143

  
144
  /**
145
   * Sets the email address that a reading confirmation will be sent.
146
   * @var string
147
   */
148
  var $ConfirmReadingTo  = '';
149

  
150
  /**
151
   * Sets the hostname to use in Message-Id and Received headers
152
   * and as default HELO string. If empty, the value returned
153
   * by SERVER_NAME is used or 'localhost.localdomain'.
154
   * @var string
155
   */
156
  var $Hostname          = '';
157

  
158
  /**
159
   * Sets the message ID to be used in the Message-Id header.
160
   * If empty, a unique id will be generated.
161
   * @var string
162
   */
163
  var $MessageID         = '';
164

  
165
  /////////////////////////////////////////////////
166
  // PROPERTIES FOR SMTP
167
  /////////////////////////////////////////////////
168

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

  
179
  /**
180
   * Sets the default SMTP server port.
181
   * @var int
182
   */
183
  var $Port        = 25;
184

  
185
  /**
186
   * Sets the SMTP HELO of the message (Default is $Hostname).
187
   * @var string
188
   */
189
  var $Helo        = '';
190

  
191
  /**
192
   * Sets connection prefix.
193
   * Options are "", "ssl" or "tls"
194
   * @var string
195
   */
196
  var $SMTPSecure = "";
197

  
198
  /**
199
   * Sets SMTP authentication. Utilizes the Username and Password variables.
200
   * @var bool
201
   */
202
  var $SMTPAuth     = false;
203

  
204
  /**
205
   * Sets SMTP username.
206
   * @var string
207
   */
208
  var $Username     = '';
209

  
210
  /**
211
   * Sets SMTP password.
212
   * @var string
213
   */
214
  var $Password     = '';
215

  
216
  /**
217
   * Sets the SMTP server timeout in seconds. This function will not
218
   * work with the win32 version.
219
   * @var int
220
   */
221
  var $Timeout      = 10;
222

  
223
  /**
224
   * Sets SMTP class debugging on or off.
225
   * @var bool
226
   */
227
  var $SMTPDebug    = false;
228

  
229
  /**
230
   * Prevents the SMTP connection from being closed after each mail
231
   * sending.  If this is set to true then to close the connection
232
   * requires an explicit call to SmtpClose().
233
   * @var bool
234
   */
235
  var $SMTPKeepAlive = false;
236

  
237
  /**
238
   * Provides the ability to have the TO field process individual
239
   * emails, instead of sending to entire TO addresses
240
   * @var bool
241
   */
242
  var $SingleTo = false;
243

  
244
  /////////////////////////////////////////////////
245
  // PROPERTIES, PRIVATE
246
  /////////////////////////////////////////////////
247

  
248
  var $smtp            = NULL;
249
  var $to              = array();
250
  var $cc              = array();
251
  var $bcc             = array();
252
  var $ReplyTo         = array();
253
  var $attachment      = array();
254
  var $CustomHeader    = array();
255
  var $message_type    = '';
256
  var $boundary        = array();
257
  var $language        = array();
258
  var $error_count     = 0;
259
  var $LE              = "\n";
260
  var $sign_cert_file  = "";
261
  var $sign_key_file   = "";
262
  var $sign_key_pass   = "";
263

  
264
  /////////////////////////////////////////////////
265
  // METHODS, VARIABLES
266
  /////////////////////////////////////////////////
267

  
268
  /**
269
   * Sets message type to HTML.
270
   * @param bool $bool
271
   * @return void
272
   */
273
  function IsHTML($bool) {
274
    if($bool == true) {
275
      $this->ContentType = 'text/html';
276
    } else {
277
      $this->ContentType = 'text/plain';
278
    }
279
  }
280

  
281
  /**
282
   * Sets Mailer to send message using SMTP.
283
   * @return void
284
   */
285
  function IsSMTP() {
286
    $this->Mailer = 'smtp';
287
  }
288

  
289
  /**
290
   * Sets Mailer to send message using PHP mail() function.
291
   * @return void
292
   */
293
  function IsMail() {
294
    $this->Mailer = 'mail';
295
  }
296

  
297
  /**
298
   * Sets Mailer to send message using the $Sendmail program.
299
   * @return void
300
   */
301
  function IsSendmail() {
302
    $this->Mailer = 'sendmail';
303
  }
304

  
305
  /**
306
   * Sets Mailer to send message using the qmail MTA.
307
   * @return void
308
   */
309
  function IsQmail() {
310
    $this->Sendmail = '/var/qmail/bin/sendmail';
311
    $this->Mailer = 'sendmail';
312
  }
313

  
314
  /////////////////////////////////////////////////
315
  // METHODS, RECIPIENTS
316
  /////////////////////////////////////////////////
317

  
318
  /**
319
   * Adds a "To" address.
320
   * @param string $address
321
   * @param string $name
322
   * @return void
323
   */
324
  function AddAddress($address, $name = '') {
325
    $cur = count($this->to);
326
    $this->to[$cur][0] = trim($address);
327
    $this->to[$cur][1] = $name;
328
  }
329

  
330
  /**
331
   * Adds a "Cc" address. Note: this function works
332
   * with the SMTP mailer on win32, not with the "mail"
333
   * mailer.
334
   * @param string $address
335
   * @param string $name
336
   * @return void
337
   */
338
  function AddCC($address, $name = '') {
339
    $cur = count($this->cc);
340
    $this->cc[$cur][0] = trim($address);
341
    $this->cc[$cur][1] = $name;
342
  }
343

  
344
  /**
345
   * Adds a "Bcc" address. Note: this function works
346
   * with the SMTP mailer on win32, not with the "mail"
347
   * mailer.
348
   * @param string $address
349
   * @param string $name
350
   * @return void
351
   */
352
  function AddBCC($address, $name = '') {
353
    $cur = count($this->bcc);
354
    $this->bcc[$cur][0] = trim($address);
355
    $this->bcc[$cur][1] = $name;
356
  }
357

  
358
  /**
359
   * Adds a "Reply-To" address.
360
   * @param string $address
361
   * @param string $name
362
   * @return void
363
   */
364
  function AddReplyTo($address, $name = '') {
365
    $cur = count($this->ReplyTo);
366
    $this->ReplyTo[$cur][0] = trim($address);
367
    $this->ReplyTo[$cur][1] = $name;
368
  }
369

  
370
  /////////////////////////////////////////////////
371
  // METHODS, MAIL SENDING
372
  /////////////////////////////////////////////////
373

  
374
  /**
375
   * Creates message and assigns Mailer. If the message is
376
   * not sent successfully then it returns false.  Use the ErrorInfo
377
   * variable to view description of the error.
378
   * @return bool
379
   */
380
  function Send() {
381
    $header = '';
382
    $body = '';
383
    $result = true;
384

  
385
    if((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
386
      $this->SetError($this->Lang('provide_address'));
387
      return false;
388
    }
389

  
390
    /* Set whether the message is multipart/alternative */
391
    if(!empty($this->AltBody)) {
392
      $this->ContentType = 'multipart/alternative';
393
    }
394

  
395
    $this->error_count = 0; // reset errors
396
    $this->SetMessageType();
397
    $header .= $this->CreateHeader();
398
    $body = $this->CreateBody();
399

  
400
    if($body == '') {
401
      return false;
402
    }
403

  
404
    /* Choose the mailer */
405
    switch($this->Mailer) {
406
      case 'sendmail':
407
        $result = $this->SendmailSend($header, $body);
408
        break;
409
      case 'smtp':
410
        $result = $this->SmtpSend($header, $body);
411
        break;
412
      case 'mail':
413
        $result = $this->MailSend($header, $body);
414
        break;
415
      default:
416
        $result = $this->MailSend($header, $body);
417
        break;
418
        //$this->SetError($this->Mailer . $this->Lang('mailer_not_supported'));
419
        //$result = false;
420
        //break;
421
    }
422

  
423
    return $result;
424
  }
425

  
426
  /**
427
   * Sends mail using the $Sendmail program.
428
   * @access private
429
   * @return bool
430
   */
431
  function SendmailSend($header, $body) {
432
    if ($this->Sender != '') {
433
      $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
434
    } else {
435
      $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
436
    }
437

  
438
    if(!@$mail = popen($sendmail, 'w')) {
439
      $this->SetError($this->Lang('execute') . $this->Sendmail);
440
      return false;
441
    }
442

  
443
    fputs($mail, $header);
444
    fputs($mail, $body);
445

  
446
    $result = pclose($mail);
447
    if (version_compare(phpversion(), '4.2.3') == -1) {
448
      $result = $result >> 8 & 0xFF;
449
    }
450
    if($result != 0) {
451
      $this->SetError($this->Lang('execute') . $this->Sendmail);
452
      return false;
453
    }
454
    return true;
455
  }
456

  
457
  /**
458
   * Sends mail using the PHP mail() function.
459
   * @access private
460
   * @return bool
461
   */
462
  function MailSend($header, $body) {
463

  
464
    $to = '';
465
    for($i = 0; $i < count($this->to); $i++) {
466
      if($i != 0) { $to .= ', '; }
467
      $to .= $this->AddrFormat($this->to[$i]);
468
    }
469

  
470
    $toArr = split(',', $to);
471

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

  
493
    if (isset($old_from)) {
494
      ini_set('sendmail_from', $old_from);
495
    }
496

  
497
    if(!$rt) {
498
      $this->SetError($this->Lang('instantiate'));
499
      return false;
500
    }
501

  
502
    return true;
503
  }
504

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

  
517
    if(!$this->SmtpConnect()) {
518
      return false;
519
    }
520

  
521
    $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
522
    if(!$this->smtp->Mail($smtp_from)) {
523
      $error = $this->Lang('from_failed') . $smtp_from;
524
      $this->SetError($error);
525
      $this->smtp->Reset();
526
      return false;
527
    }
528

  
529
    /* Attempt to send attach all recipients */
530
    for($i = 0; $i < count($this->to); $i++) {
531
      if(!$this->smtp->Recipient($this->to[$i][0])) {
532
        $bad_rcpt[] = $this->to[$i][0];
533
      }
534
    }
535
    for($i = 0; $i < count($this->cc); $i++) {
536
      if(!$this->smtp->Recipient($this->cc[$i][0])) {
537
        $bad_rcpt[] = $this->cc[$i][0];
538
      }
539
    }
540
    for($i = 0; $i < count($this->bcc); $i++) {
541
      if(!$this->smtp->Recipient($this->bcc[$i][0])) {
542
        $bad_rcpt[] = $this->bcc[$i][0];
543
      }
544
    }
545

  
546
    if(count($bad_rcpt) > 0) { // Create error message
547
      for($i = 0; $i < count($bad_rcpt); $i++) {
548
        if($i != 0) {
549
          $error .= ', ';
550
        }
551
        $error .= $bad_rcpt[$i];
552
      }
553
      $error = $this->Lang('recipients_failed') . $error;
554
      $this->SetError($error);
555
      $this->smtp->Reset();
556
      return false;
557
    }
558

  
559
    if(!$this->smtp->Data($header . $body)) {
560
      $this->SetError($this->Lang('data_not_accepted'));
561
      $this->smtp->Reset();
562
      return false;
563
    }
564
    if($this->SMTPKeepAlive == true) {
565
      $this->smtp->Reset();
566
    } else {
567
      $this->SmtpClose();
568
    }
569

  
570
    return true;
571
  }
572

  
573
  /**
574
   * Initiates a connection to an SMTP server.  Returns false if the
575
   * operation failed.
576
   * @access private
577
   * @return bool
578
   */
579
  function SmtpConnect() {
580
    if($this->smtp == NULL) {
581
      $this->smtp = new SMTP();
582
    }
583

  
584
    $this->smtp->do_debug = $this->SMTPDebug;
585
    $hosts = explode(';', $this->Host);
586
    $index = 0;
587
    $connection = ($this->smtp->Connected());
588

  
589
    /* Retry while there is no connection */
590
    while($index < count($hosts) && $connection == false) {
591
      $hostinfo = array();
592
      if(eregi('^(.+):([0-9]+)$', $hosts[$index], $hostinfo)) {
593
        $host = $hostinfo[1];
594
        $port = $hostinfo[2];
595
      } else {
596
        $host = $hosts[$index];
597
        $port = $this->Port;
598
      }
599

  
600
      if($this->smtp->Connect(((!empty($this->SMTPSecure))?$this->SMTPSecure.'://':'').$host, $port, $this->Timeout)) {
601
        if ($this->Helo != '') {
602
          $this->smtp->Hello($this->Helo);
603
        } else {
604
          $this->smtp->Hello($this->ServerHostname());
605
        }
606

  
607
        $connection = true;
608
        if($this->SMTPAuth) {
609
          if(!$this->smtp->Authenticate($this->Username, $this->Password)) {
610
            $this->SetError($this->Lang('authenticate'));
611
            $this->smtp->Reset();
612
            $connection = false;
613
          }
614
        }
615
      }
616
      $index++;
617
    }
618
    if(!$connection) {
619
      $this->SetError($this->Lang('connect_host'));
620
    }
621

  
622
    return $connection;
623
  }
624

  
625
  /**
626
   * Closes the active SMTP session if one exists.
627
   * @return void
628
   */
629
  function SmtpClose() {
630
    if($this->smtp != NULL) {
631
      if($this->smtp->Connected()) {
632
        $this->smtp->Quit();
633
        $this->smtp->Close();
634
      }
635
    }
636
  }
637

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

  
670
    return true;
671
  }
672

  
673
  /////////////////////////////////////////////////
674
  // METHODS, MESSAGE CREATION
675
  /////////////////////////////////////////////////
676

  
677
  /**
678
   * Creates recipient headers.
679
   * @access private
680
   * @return string
681
   */
682
  function AddrAppend($type, $addr) {
683
    $addr_str = $type . ': ';
684
    $addr_str .= $this->AddrFormat($addr[0]);
685
    if(count($addr) > 1) {
686
      for($i = 1; $i < count($addr); $i++) {
687
        $addr_str .= ', ' . $this->AddrFormat($addr[$i]);
688
      }
689
    }
690
    $addr_str .= $this->LE;
691

  
692
    return $addr_str;
693
  }
694

  
695
  /**
696
   * Formats an address correctly.
697
   * @access private
698
   * @return string
699
   */
700
  function AddrFormat($addr) {
701
    if(empty($addr[1])) {
702
      $formatted = $this->SecureHeader($addr[0]);
703
    } else {
704
      $formatted = $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">";
705
    }
706

  
707
    return $formatted;
708
  }
709

  
710
  /**
711
   * Wraps message for use with mailers that do not
712
   * automatically perform wrapping and for quoted-printable.
713
   * Original written by philippe.
714
   * @access private
715
   * @return string
716
   */
717
  function WrapText($message, $length, $qp_mode = false) {
718
    $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
719
    // If utf-8 encoding is used, we will need to make sure we don't
720
    // split multibyte characters when we wrap
721
    $is_utf8 = (strtolower($this->CharSet) == "utf-8");
722

  
723
    $message = $this->FixEOL($message);
724
    if (substr($message, -1) == $this->LE) {
725
      $message = substr($message, 0, -1);
726
    }
727

  
728
    $line = explode($this->LE, $message);
729
    $message = '';
730
    for ($i=0 ;$i < count($line); $i++) {
731
      $line_part = explode(' ', $line[$i]);
732
      $buf = '';
733
      for ($e = 0; $e<count($line_part); $e++) {
734
        $word = $line_part[$e];
735
        if ($qp_mode and (strlen($word) > $length)) {
736
          $space_left = $length - strlen($buf) - 1;
737
          if ($e != 0) {
738
            if ($space_left > 20) {
739
              $len = $space_left;
740
              if ($is_utf8) {
741
                $len = $this->UTF8CharBoundary($word, $len);
742
              } elseif (substr($word, $len - 1, 1) == "=") {
743
                $len--;
744
              } elseif (substr($word, $len - 2, 1) == "=") {
745
                $len -= 2;
746
              }
747
              $part = substr($word, 0, $len);
748
              $word = substr($word, $len);
749
              $buf .= ' ' . $part;
750
              $message .= $buf . sprintf("=%s", $this->LE);
751
            } else {
752
              $message .= $buf . $soft_break;
753
            }
754
            $buf = '';
755
          }
756
          while (strlen($word) > 0) {
757
            $len = $length;
758
            if ($is_utf8) {
759
              $len = $this->UTF8CharBoundary($word, $len);
760
            } elseif (substr($word, $len - 1, 1) == "=") {
761
              $len--;
762
            } elseif (substr($word, $len - 2, 1) == "=") {
763
              $len -= 2;
764
            }
765
            $part = substr($word, 0, $len);
766
            $word = substr($word, $len);
767

  
768
            if (strlen($word) > 0) {
769
              $message .= $part . sprintf("=%s", $this->LE);
770
            } else {
771
              $buf = $part;
772
            }
773
          }
774
        } else {
775
          $buf_o = $buf;
776
          $buf .= ($e == 0) ? $word : (' ' . $word);
777

  
778
          if (strlen($buf) > $length and $buf_o != '') {
779
            $message .= $buf_o . $soft_break;
780
            $buf = $word;
781
          }
782
        }
783
      }
784
      $message .= $buf . $this->LE;
785
    }
786

  
787
    return $message;
788
  }
789

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

  
831
  /**
832
   * Set the body wrapping.
833
   * @access private
834
   * @return void
835
   */
836
  function SetWordWrap() {
837
    if($this->WordWrap < 1) {
838
      return;
839
    }
840

  
841
    switch($this->message_type) {
842
      case 'alt':
843
        /* fall through */
844
      case 'alt_attachments':
845
        $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
846
        break;
847
      default:
848
        $this->Body = $this->WrapText($this->Body, $this->WordWrap);
849
        break;
850
    }
851
  }
852

  
853
  /**
854
   * Assembles message header.
855
   * @access private
856
   * @return string
857
   */
858
  function CreateHeader() {
859
    $result = '';
860

  
861
    /* Set the boundaries */
862
    $uniq_id = md5(uniqid(time()));
863
    $this->boundary[1] = 'b1_' . $uniq_id;
864
    $this->boundary[2] = 'b2_' . $uniq_id;
865

  
866
    $result .= $this->HeaderLine('Date', $this->RFCDate());
867
    if($this->Sender == '') {
868
      $result .= $this->HeaderLine('Return-Path', trim($this->From));
869
    } else {
870
      $result .= $this->HeaderLine('Return-Path', trim($this->Sender));
871
    }
872

  
873
    /* To be created automatically by mail() */
874
    if($this->Mailer != 'mail') {
875
      if(count($this->to) > 0) {
876
        $result .= $this->AddrAppend('To', $this->to);
877
      } elseif (count($this->cc) == 0) {
878
        $result .= $this->HeaderLine('To', 'undisclosed-recipients:;');
879
      }
880
    }
881

  
882
    $from = array();
883
    $from[0][0] = trim($this->From);
884
    $from[0][1] = $this->FromName;
885
    $result .= $this->AddrAppend('From', $from);
886

  
887
    /* sendmail and mail() extract Cc from the header before sending */
888
    if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->cc) > 0)) {
889
      $result .= $this->AddrAppend('Cc', $this->cc);
890
    }
891

  
892
    /* sendmail and mail() extract Bcc from the header before sending */
893
    if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) {
894
      $result .= $this->AddrAppend('Bcc', $this->bcc);
895
    }
896

  
897
    if(count($this->ReplyTo) > 0) {
898
      $result .= $this->AddrAppend('Reply-To', $this->ReplyTo);
899
    }
900

  
901
    /* mail() sets the subject itself */
902
    if($this->Mailer != 'mail') {
903
      $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject)));
904
    }
905

  
906
    if($this->MessageID != '') {
907
      $result .= $this->HeaderLine('Message-ID',$this->MessageID);
908
    } else {
909
      $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
910
    }
911
    $result .= $this->HeaderLine('X-Priority', $this->Priority);
912
    $result .= $this->HeaderLine('X-Mailer', 'PHPMailer (phpmailer.sourceforge.net) [version ' . $this->Version . ']');
913

  
914
    if($this->ConfirmReadingTo != '') {
915
      $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
916
    }
917

  
918
    // Add custom headers
919
    for($index = 0; $index < count($this->CustomHeader); $index++) {
920
      $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
921
    }
922
    if (!$this->sign_key_file) {
923
      $result .= $this->HeaderLine('MIME-Version', '1.0');
924
      $result .= $this->GetMailMIME();
925
    }
926

  
927
    return $result;
928
  }
929

  
930
  /**
931
   * Returns the message MIME.
932
   * @access private
933
   * @return string
934
   */
935
  function GetMailMIME() {
936
    $result = '';
937
    switch($this->message_type) {
938
      case 'plain':
939
        $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
940
        $result .= sprintf("Content-Type: %s; charset=\"%s\"", $this->ContentType, $this->CharSet);
941
        break;
942
      case 'attachments':
943
        /* fall through */
944
      case 'alt_attachments':
945
        if($this->InlineImageExists()){
946
          $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 'multipart/related', $this->LE, $this->LE, $this->boundary[1], $this->LE);
947
        } else {
948
          $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
949
          $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
950
        }
951
        break;
952
      case 'alt':
953
        $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
954
        $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
955
        break;
956
    }
957

  
958
    if($this->Mailer != 'mail') {
959
      $result .= $this->LE.$this->LE;
960
    }
961

  
962
    return $result;
963
  }
964

  
965
  /**
966
   * Assembles the message body.  Returns an empty string on failure.
967
   * @access private
968
   * @return string
969
   */
970
  function CreateBody() {
971
    $result = '';
972
    if ($this->sign_key_file) {
973
      $result .= $this->GetMailMIME();
974
    }
975

  
976
    $this->SetWordWrap();
977

  
978
    switch($this->message_type) {
979
      case 'alt':
980
        $result .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
981
        $result .= $this->EncodeString($this->AltBody, $this->Encoding);
982
        $result .= $this->LE.$this->LE;
983
        $result .= $this->GetBoundary($this->boundary[1], '', 'text/html', '');
984
        $result .= $this->EncodeString($this->Body, $this->Encoding);
985
        $result .= $this->LE.$this->LE;
986
        $result .= $this->EndBoundary($this->boundary[1]);
987
        break;
988
      case 'plain':
989
        $result .= $this->EncodeString($this->Body, $this->Encoding);
990
        break;
991
      case 'attachments':
992
        $result .= $this->GetBoundary($this->boundary[1], '', '', '');
993
        $result .= $this->EncodeString($this->Body, $this->Encoding);
994
        $result .= $this->LE;
995
        $result .= $this->AttachAll();
996
        break;
997
      case 'alt_attachments':
998
        $result .= sprintf("--%s%s", $this->boundary[1], $this->LE);
999
        $result .= sprintf("Content-Type: %s;%s" . "\tboundary=\"%s\"%s", 'multipart/alternative', $this->LE, $this->boundary[2], $this->LE.$this->LE);
1000
        $result .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '') . $this->LE; // Create text body
1001
        $result .= $this->EncodeString($this->AltBody, $this->Encoding);
1002
        $result .= $this->LE.$this->LE;
1003
        $result .= $this->GetBoundary($this->boundary[2], '', 'text/html', '') . $this->LE; // Create the HTML body
1004
        $result .= $this->EncodeString($this->Body, $this->Encoding);
1005
        $result .= $this->LE.$this->LE;
1006
        $result .= $this->EndBoundary($this->boundary[2]);
1007
        $result .= $this->AttachAll();
1008
        break;
1009
    }
1010

  
1011
    if($this->IsError()) {
1012
      $result = '';
1013
    } else if ($this->sign_key_file) {
1014
      $file = tempnam("", "mail");
1015
      $fp = fopen($file, "w");
1016
      fwrite($fp, $result);
1017
      fclose($fp);
1018
      $signed = tempnam("", "signed");
1019

  
1020
      if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_cert_file, array("file://".$this->sign_key_file, $this->sign_key_pass), null)) {
1021
        $fp = fopen($signed, "r");
1022
        $result = fread($fp, filesize($this->sign_key_file));
1023
        $result = '';
1024
        while(!feof($fp)){
1025
          $result = $result . fread($fp, 1024);
1026
        }
1027
        fclose($fp);
1028
      } else {
1029
        $this->SetError($this->Lang("signing").openssl_error_string());
1030
        $result = '';
1031
      }
1032

  
1033
      unlink($file);
1034
      unlink($signed);
1035
    }
1036

  
1037
    return $result;
1038
  }
1039

  
1040
  /**
1041
   * Returns the start of a message boundary.
1042
   * @access private
1043
   */
1044
  function GetBoundary($boundary, $charSet, $contentType, $encoding) {
1045
    $result = '';
1046
    if($charSet == '') {
1047
      $charSet = $this->CharSet;
1048
    }
1049
    if($contentType == '') {
1050
      $contentType = $this->ContentType;
1051
    }
1052
    if($encoding == '') {
1053
      $encoding = $this->Encoding;
1054
    }
1055
    $result .= $this->TextLine('--' . $boundary);
1056
    $result .= sprintf("Content-Type: %s; charset = \"%s\"", $contentType, $charSet);
1057
    $result .= $this->LE;
1058
    $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding);
1059
    $result .= $this->LE;
1060

  
1061
    return $result;
1062
  }
1063

  
1064
  /**
1065
   * Returns the end of a message boundary.
1066
   * @access private
1067
   */
1068
  function EndBoundary($boundary) {
1069
    return $this->LE . '--' . $boundary . '--' . $this->LE;
1070
  }
1071

  
1072
  /**
1073
   * Sets the message type.
1074
   * @access private
1075
   * @return void
1076
   */
1077
  function SetMessageType() {
1078
    if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) {
1079
      $this->message_type = 'plain';
1080
    } else {
1081
      if(count($this->attachment) > 0) {
1082
        $this->message_type = 'attachments';
1083
      }
1084
      if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) {
1085
        $this->message_type = 'alt';
1086
      }
1087
      if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) {
1088
        $this->message_type = 'alt_attachments';
1089
      }
1090
    }
1091
  }
1092

  
1093
  /* Returns a formatted header line.
1094
   * @access private
1095
   * @return string
1096
   */
1097
  function HeaderLine($name, $value) {
1098
    return $name . ': ' . $value . $this->LE;
1099
  }
1100

  
1101
  /**
1102
   * Returns a formatted mail line.
1103
   * @access private
1104
   * @return string
1105
   */
1106
  function TextLine($value) {
1107
    return $value . $this->LE;
1108
  }
1109

  
1110
  /////////////////////////////////////////////////
1111
  // CLASS METHODS, ATTACHMENTS
1112
  /////////////////////////////////////////////////
1113

  
1114
  /**
1115
   * Adds an attachment from a path on the filesystem.
1116
   * Returns false if the file could not be found
1117
   * or accessed.
1118
   * @param string $path Path to the attachment.
1119
   * @param string $name Overrides the attachment name.
1120
   * @param string $encoding File encoding (see $Encoding).
1121
   * @param string $type File extension (MIME) type.
1122
   * @return bool
1123
   */
1124
  function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
1125
    if(!@is_file($path)) {
1126
      $this->SetError($this->Lang('file_access') . $path);
1127
      return false;
1128
    }
1129

  
1130
    $filename = basename($path);
1131
    if($name == '') {
1132
      $name = $filename;
1133
    }
1134

  
1135
    $cur = count($this->attachment);
1136
    $this->attachment[$cur][0] = $path;
1137
    $this->attachment[$cur][1] = $filename;
1138
    $this->attachment[$cur][2] = $name;
1139
    $this->attachment[$cur][3] = $encoding;
1140
    $this->attachment[$cur][4] = $type;
1141
    $this->attachment[$cur][5] = false; // isStringAttachment
1142
    $this->attachment[$cur][6] = 'attachment';
1143
    $this->attachment[$cur][7] = 0;
1144

  
1145
    return true;
1146
  }
1147

  
1148
  /**
1149
   * Attaches all fs, string, and binary attachments to the message.
1150
   * Returns an empty string on failure.
1151
   * @access private
1152
   * @return string
1153
   */
1154
  function AttachAll() {
1155
    /* Return text of body */
1156
    $mime = array();
1157

  
1158
    /* Add all attachments */
1159
    for($i = 0; $i < count($this->attachment); $i++) {
1160
      /* Check for string attachment */
1161
      $bString = $this->attachment[$i][5];
1162
      if ($bString) {
1163
        $string = $this->attachment[$i][0];
1164
      } else {
1165
        $path = $this->attachment[$i][0];
1166
      }
1167

  
1168
      $filename    = $this->attachment[$i][1];
1169
      $name        = $this->attachment[$i][2];
1170
      $encoding    = $this->attachment[$i][3];
1171
      $type        = $this->attachment[$i][4];
1172
      $disposition = $this->attachment[$i][6];
1173
      $cid         = $this->attachment[$i][7];
1174

  
1175
      $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE);
1176
      $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE);
1177
      $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
1178

  
1179
      if($disposition == 'inline') {
1180
        $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
1181
      }
1182

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

  
1185
      /* Encode as string attachment */
1186
      if($bString) {
1187
        $mime[] = $this->EncodeString($string, $encoding);
1188
        if($this->IsError()) {
1189
          return '';
1190
        }
1191
        $mime[] = $this->LE.$this->LE;
1192
      } else {
1193
        $mime[] = $this->EncodeFile($path, $encoding);
1194
        if($this->IsError()) {
1195
          return '';
1196
        }
1197
        $mime[] = $this->LE.$this->LE;
1198
      }
1199
    }
1200

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

  
1203
    return join('', $mime);
1204
  }
1205

  
1206
  /**
1207
   * Encodes attachment in requested format.  Returns an
1208
   * empty string on failure.
1209
   * @access private
1210
   * @return string
1211
   */
1212
  function EncodeFile ($path, $encoding = 'base64') {
1213
    if(!@$fd = fopen($path, 'rb')) {
1214
      $this->SetError($this->Lang('file_open') . $path);
1215
      return '';
1216
    }
1217
    $magic_quotes = get_magic_quotes_runtime();
1218
    set_magic_quotes_runtime(0);
1219
    $file_buffer = fread($fd, filesize($path));
1220
    $file_buffer = $this->EncodeString($file_buffer, $encoding);
1221
    fclose($fd);
1222
    set_magic_quotes_runtime($magic_quotes);
1223

  
1224
    return $file_buffer;
1225
  }
1226

  
1227
  /**
1228
   * Encodes string to requested format. Returns an
1229
   * empty string on failure.
1230
   * @access private
1231
   * @return string
1232
   */
1233
  function EncodeString ($str, $encoding = 'base64') {
1234
    $encoded = '';
1235
    switch(strtolower($encoding)) {
1236
      case 'base64':
1237
        /* chunk_split is found in PHP >= 3.0.6 */
1238
        $encoded = chunk_split(base64_encode($str), 76, $this->LE);
1239
        break;
1240
      case '7bit':
1241
      case '8bit':
1242
        $encoded = $this->FixEOL($str);
1243
        if (substr($encoded, -(strlen($this->LE))) != $this->LE)
1244
          $encoded .= $this->LE;
1245
        break;
1246
      case 'binary':
1247
        $encoded = $str;
1248
        break;
1249
      case 'quoted-printable':
1250
        $encoded = $this->EncodeQP($str);
1251
        break;
1252
      default:
1253
        $this->SetError($this->Lang('encoding') . $encoding);
1254
        break;
1255
    }
1256
    return $encoded;
1257
  }
1258

  
1259
  /**
1260
   * Encode a header string to best of Q, B, quoted or none.
1261
   * @access private
1262
   * @return string
1263
   */
1264
  function EncodeHeader ($str, $position = 'text') {
1265
    $x = 0;
1266

  
1267
    switch (strtolower($position)) {
1268
      case 'phrase':
1269
        if (!preg_match('/[\200-\377]/', $str)) {
1270
          /* Can't use addslashes as we don't know what value has magic_quotes_sybase. */
1271
          $encoded = addcslashes($str, "\0..\37\177\\\"");
1272
          if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
1273
            return ($encoded);
1274
          } else {
1275
            return ("\"$encoded\"");
1276
          }
1277
        }
1278
        $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
1279
        break;
1280
      case 'comment':
1281
        $x = preg_match_all('/[()"]/', $str, $matches);
1282
        /* Fall-through */
1283
      case 'text':
1284
      default:
1285
        $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
1286
        break;
1287
    }
1288

  
1289
    if ($x == 0) {
1290
      return ($str);
1291
    }
1292

  
1293
    $maxlen = 75 - 7 - strlen($this->CharSet);
1294
    /* Try to select the encoding which should produce the shortest output */
1295
    if (strlen($str)/3 < $x) {
1296
      $encoding = 'B';
1297
      if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) {
1298
     // Use a custom function which correctly encodes and wraps long
1299
     // multibyte strings without breaking lines within a character
1300
        $encoded = $this->Base64EncodeWrapMB($str);
1301
      } else {
1302
        $encoded = base64_encode($str);
1303
        $maxlen -= $maxlen % 4;
1304
        $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
1305
      }
1306
    } else {
1307
      $encoding = 'Q';
1308
      $encoded = $this->EncodeQ($str, $position);
1309
      $encoded = $this->WrapText($encoded, $maxlen, true);
1310
      $encoded = str_replace('='.$this->LE, "\n", trim($encoded));
1311
    }
1312

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

  
1316
    return $encoded;
1317
  }
1318

  
1319
  /**
1320
   * Checks if a string contains multibyte characters.
1321
   * @access private
1322
   * @param string $str multi-byte text to wrap encode
1323
   * @return bool
1324
   */
1325
  function HasMultiBytes($str) {
1326
    if (function_exists('mb_strlen')) {
1327
      return (strlen($str) > mb_strlen($str, $this->CharSet));
1328
    } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
1329
      return False;
1330
    }
1331
  }
1332

  
1333
  /**
1334
   * Correctly encodes and wraps long multibyte strings for mail headers
1335
   * without breaking lines within a character.
1336
   * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php
1337
   * @access private
1338
   * @param string $str multi-byte text to wrap encode
1339
   * @return string
1340
   */
1341
  function Base64EncodeWrapMB($str) {
1342
    $start = "=?".$this->CharSet."?B?";
1343
    $end = "?=";
1344
    $encoded = "";
1345

  
1346
    $mb_length = mb_strlen($str, $this->CharSet);
1347
    // Each line must have length <= 75, including $start and $end
1348
    $length = 75 - strlen($start) - strlen($end);
1349
    // Average multi-byte ratio
1350
    $ratio = $mb_length / strlen($str);
1351
    // Base64 has a 4:3 ratio
1352
    $offset = $avgLength = floor($length * $ratio * .75);
1353

  
1354
    for ($i = 0; $i < $mb_length; $i += $offset) {
1355
      $lookBack = 0;
1356

  
1357
      do {
1358
        $offset = $avgLength - $lookBack;
1359
        $chunk = mb_substr($str, $i, $offset, $this->CharSet);
1360
        $chunk = base64_encode($chunk);
1361
        $lookBack++;
1362
      }
1363
      while (strlen($chunk) > $length);
1364

  
1365
      $encoded .= $chunk . $this->LE;
1366
    }
1367

  
1368
    // Chomp the last linefeed
1369
    $encoded = substr($encoded, 0, -strlen($this->LE));
1370
    return $encoded;
1371
  }
1372

  
1373
  /**
1374
   * Encode string to quoted-printable.
1375
   * @access private
1376
   * @return string
1377
   */
1378
  function EncodeQP( $input = '', $line_max = 76, $space_conv = false ) {
1379
    $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
1380
    $lines = preg_split('/(?:\r\n|\r|\n)/', $input);
1381
    $eol = "\r\n";
1382
    $escape = '=';
1383
    $output = '';
1384
    while( list(, $line) = each($lines) ) {
1385
      $linlen = strlen($line);
1386
      $newline = '';
1387
      for($i = 0; $i < $linlen; $i++) {
1388
        $c = substr( $line, $i, 1 );
1389
        $dec = ord( $c );
1390
        if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E
1391
          $c = '=2E';
1392
        }
1393
        if ( $dec == 32 ) {
1394
          if ( $i == ( $linlen - 1 ) ) { // convert space at eol only
1395
            $c = '=20';
1396
          } else if ( $space_conv ) {
1397
            $c = '=20';
1398
          }
1399
        } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required
1400
          $h2 = floor($dec/16);
1401
          $h1 = floor($dec%16);
1402
          $c = $escape.$hex[$h2].$hex[$h1];
1403
        }
1404
        if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted
1405
          $output .= $newline.$escape.$eol; //  soft line break; " =\r\n" is okay
1406
          $newline = '';
1407
          // check if newline first character will be point or not
1408
          if ( $dec == 46 ) {
1409
            $c = '=2E';
1410
          }
1411
        }
1412
        $newline .= $c;
1413
      } // end of for
1414
      $output .= $newline.$eol;
1415
    } // end of while
1416
    return $output;
1417
  }
1418

  
1419
  /**
1420
   * Encode string to q encoding.
1421
   * @access private
1422
   * @return string
1423
   */
1424
  function EncodeQ ($str, $position = 'text') {
1425
    /* There should not be any EOL in the string */
1426
    $encoded = preg_replace("[\r\n]", '', $str);
1427

  
1428
    switch (strtolower($position)) {
1429
      case 'phrase':
1430
        $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
1431
        break;
1432
      case 'comment':
1433
        $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
1434
      case 'text':
1435
      default:
1436
        /* Replace every high ascii, control =, ? and _ characters */
1437
        $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
1438
              "'='.sprintf('%02X', ord('\\1'))", $encoded);
1439
        break;
1440
    }
1441

  
1442
    /* Replace every spaces to _ (more readable than =20) */
1443
    $encoded = str_replace(' ', '_', $encoded);
1444

  
1445
    return $encoded;
1446
  }
1447

  
1448
  /**
1449
   * Adds a string or binary attachment (non-filesystem) to the list.
1450
   * This method can be used to attach ascii or binary data,
1451
   * such as a BLOB record from a database.
1452
   * @param string $string String attachment data.
1453
   * @param string $filename Name of the attachment.
1454
   * @param string $encoding File encoding (see $Encoding).
1455
   * @param string $type File extension (MIME) type.
1456
   * @return void
1457
   */
1458
  function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') {
1459
    /* Append to $attachment array */
1460
    $cur = count($this->attachment);
1461
    $this->attachment[$cur][0] = $string;
1462
    $this->attachment[$cur][1] = $filename;
1463
    $this->attachment[$cur][2] = $filename;
1464
    $this->attachment[$cur][3] = $encoding;
1465
    $this->attachment[$cur][4] = $type;
1466
    $this->attachment[$cur][5] = true; // isString
1467
    $this->attachment[$cur][6] = 'attachment';
1468
    $this->attachment[$cur][7] = 0;
1469
  }
1470

  
1471
  /**
1472
   * Adds an embedded attachment.  This can include images, sounds, and
1473
   * just about any other document.  Make sure to set the $type to an
1474
   * image type.  For JPEG images use "image/jpeg" and for GIF images
1475
   * use "image/gif".
1476
   * @param string $path Path to the attachment.
1477
   * @param string $cid Content ID of the attachment.  Use this to identify
1478
   *        the Id for accessing the image in an HTML form.
1479
   * @param string $name Overrides the attachment name.
1480
   * @param string $encoding File encoding (see $Encoding).
1481
   * @param string $type File extension (MIME) type.
1482
   * @return bool
1483
   */
1484
  function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
1485

  
1486
    if(!@is_file($path)) {
1487
      $this->SetError($this->Lang('file_access') . $path);
1488
      return false;
1489
    }
1490

  
1491
    $filename = basename($path);
1492
    if($name == '') {
1493
      $name = $filename;
1494
    }
1495

  
1496
    /* Append to $attachment array */
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff