Postie - Version 1.4.9

Version Description

(2012.12.10) = * Fixed bug where date, author, etc didn't get set. * Fixed bug where Postie was treating attached images as strings * Fixed bug where inline images were not being attached correctly * Fixed bug where the subject was not being decoded correctly if the charset was different from the system charset * Fixed bug where base64 strings were being double decoded.

Download this release

Release Info

Developer WayneAllen
Plugin Icon 128x128 Postie
Version 1.4.9
Comparing to
See all releases

Code changes from version 1.4.8 to 1.4.9

Files changed (10) hide show
  1. Revision +2 -0
  2. deploy/_deploy.txt +1 -1
  3. docs/Changes.txt +7 -0
  4. docs/Postie.txt +1 -1
  5. get_mail.php +2 -2
  6. mimedecode.php +132 -153
  7. postie-functions.php +60 -35
  8. postie.php +2 -2
  9. postieIMAP.php +5 -10
  10. readme.txt +8 -1
Revision CHANGED
@@ -0,0 +1,2 @@
 
 
1
+ Revision: 636678
2
+ Last Changed Date: 2012-12-09 19:05:40 -0800 (Sun, 09 Dec 2012)
deploy/_deploy.txt CHANGED
@@ -5,4 +5,4 @@ update version number in docs\postie.txt
5
  run deploy.cmd
6
  commit
7
  branch trunk to new version
8
- add release post on http://postieplugin.com/
5
  run deploy.cmd
6
  commit
7
  branch trunk to new version
8
+ add release post on http://postieplugin.com/ & http://wordpress.org/support/plugin/postie
docs/Changes.txt CHANGED
@@ -4,6 +4,13 @@
4
 
5
  == CHANGELOG ==
6
 
 
 
 
 
 
 
 
7
  = 1.4.8 (2012.12.09) =
8
  * fix collisions with simple_html_dom
9
  * fix bug when trying to get file name from MIME part
4
 
5
  == CHANGELOG ==
6
 
7
+ = 1.4.9 (2012.12.10) =
8
+ * Fixed bug where date, author, etc didn't get set.
9
+ * Fixed bug where Postie was treating attached images as strings
10
+ * Fixed bug where inline images were not being attached correctly
11
+ * Fixed bug where the subject was not being decoded correctly if the charset was different from the system charset
12
+ * Fixed bug where base64 strings were being double decoded.
13
+
14
  = 1.4.8 (2012.12.09) =
15
  * fix collisions with simple_html_dom
16
  * fix bug when trying to get file name from MIME part
docs/Postie.txt CHANGED
@@ -6,7 +6,7 @@ Plugin URI: http://PostiePlugin.com/
6
  Tags: e-mail, email
7
  Requires at least: 3.0
8
  Tested up to: 3.4.2
9
- Stable tag: 1.4.8
10
  License: GPLv2 or later
11
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
 
6
  Tags: e-mail, email
7
  Requires at least: 3.0
8
  Tested up to: 3.4.2
9
+ Stable tag: 1.4.9
10
  License: GPLv2 or later
11
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
 
get_mail.php CHANGED
@@ -39,9 +39,11 @@ foreach ($emails as $email) {
39
  //sanity check to see if there is any info in the message
40
  if ($email == NULL) {
41
  $message = __('Dang, message is empty!', 'postie');
 
42
  continue;
43
  } else if ($email == 'already read') {
44
  $message = __("There does not seem to be any new mail.", 'postie');
 
45
  continue;
46
  }
47
 
@@ -67,8 +69,6 @@ foreach ($emails as $email) {
67
  if (function_exists('memory_get_usage'))
68
  EchoInfo("memory at end of e-mail processing:" . memory_get_usage());
69
 
70
- EchoInfo($message);
71
-
72
  if (!ini_get('safe_mode')) {
73
  ini_set('memory_limit', $original_mem_limit);
74
  }
39
  //sanity check to see if there is any info in the message
40
  if ($email == NULL) {
41
  $message = __('Dang, message is empty!', 'postie');
42
+ EchoInfo($message);
43
  continue;
44
  } else if ($email == 'already read') {
45
  $message = __("There does not seem to be any new mail.", 'postie');
46
+ EchoInfo($message);
47
  continue;
48
  }
49
 
69
  if (function_exists('memory_get_usage'))
70
  EchoInfo("memory at end of e-mail processing:" . memory_get_usage());
71
 
 
 
72
  if (!ini_get('safe_mode')) {
73
  ini_set('memory_limit', $original_mem_limit);
74
  }
mimedecode.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
  /**
3
  * The Mail_mimeDecode class is used to decode mail/mime messages
4
  *
@@ -55,8 +56,6 @@
55
  * @version CVS: $Id: mimeDecode.php 305875 2010-12-01 07:17:10Z alan_k $
56
  * @link http://pear.php.net/package/Mail_mime
57
  */
58
-
59
-
60
  /**
61
  * require PEAR
62
  *
@@ -64,7 +63,6 @@
64
  */
65
  require_once 'PEAR.php';
66
 
67
-
68
  /**
69
  * The Mail_mimeDecode class is used to decode mail/mime messages
70
  *
@@ -88,8 +86,8 @@ require_once 'PEAR.php';
88
  * @version Release: @package_version@
89
  * @link http://pear.php.net/package/Mail_mime
90
  */
91
- class Mail_mimeDecode extends PEAR
92
- {
93
  /**
94
  * The raw email to decode
95
  *
@@ -165,16 +163,15 @@ class Mail_mimeDecode extends PEAR
165
  * @param string The input to decode
166
  * @access public
167
  */
168
- function Mail_mimeDecode($input)
169
- {
170
- list($header, $body) = $this->_splitBodyHeader($input);
171
-
172
- $this->_input = $input;
173
- $this->_header = $header;
174
- $this->_body = $body;
175
- $this->_decode_bodies = false;
176
  $this->_include_bodies = true;
177
- $this->_rfc822_bodies = false;
178
  }
179
 
180
  /**
@@ -194,32 +191,31 @@ class Mail_mimeDecode extends PEAR
194
  * @return object Decoded results
195
  * @access public
196
  */
197
- function decode($params = null)
198
- {
199
  // determine if this method has been called statically
200
  $isStatic = empty($this) || !is_a($this, __CLASS__);
201
 
202
  // Have we been called statically?
203
- // If so, create an object and pass details to that.
204
  if ($isStatic AND isset($params['input'])) {
205
 
206
  $obj = new Mail_mimeDecode($params['input']);
207
  $structure = $obj->decode($params);
208
 
209
- // Called statically but no input
210
  } elseif ($isStatic) {
211
  return PEAR::raiseError('Called statically and no input given');
212
 
213
- // Called via an object
214
  } else {
215
  $this->_include_bodies = isset($params['include_bodies']) ?
216
- $params['include_bodies'] : false;
217
- $this->_decode_bodies = isset($params['decode_bodies']) ?
218
- $params['decode_bodies'] : false;
219
  $this->_decode_headers = isset($params['decode_headers']) ?
220
- $params['decode_headers'] : false;
221
- $this->_rfc822_bodies = isset($params['rfc_822bodies']) ?
222
- $params['rfc_822bodies'] : false;
223
 
224
  $structure = $this->_decode($this->_header, $this->_body);
225
  if ($structure === false) {
@@ -240,8 +236,7 @@ class Mail_mimeDecode extends PEAR
240
  * @return object Results of decoding process
241
  * @access private
242
  */
243
- function _decode($headers, $body, $default_ctype = 'text/plain')
244
- {
245
  $return = new stdClass;
246
  $return->headers = array();
247
  $headers = $this->_parseHeaders($headers);
@@ -249,12 +244,10 @@ class Mail_mimeDecode extends PEAR
249
  foreach ($headers as $value) {
250
  $value['value'] = $this->_decode_headers ? $this->_decodeHeader($value['value']) : $value['value'];
251
  if (isset($return->headers[strtolower($value['name'])]) AND !is_array($return->headers[strtolower($value['name'])])) {
252
- $return->headers[strtolower($value['name'])] = array($return->headers[strtolower($value['name'])]);
253
  $return->headers[strtolower($value['name'])][] = $value['value'];
254
-
255
  } elseif (isset($return->headers[strtolower($value['name'])])) {
256
  $return->headers[strtolower($value['name'])][] = $value['value'];
257
-
258
  } else {
259
  $return->headers[strtolower($value['name'])] = $value['value'];
260
  }
@@ -269,12 +262,12 @@ class Mail_mimeDecode extends PEAR
269
  $content_type = $this->_parseHeaderValue($headers[$key]['value']);
270
 
271
  if (preg_match('/([0-9a-z+.-]+)\/([0-9a-z+.-]+)/i', $content_type['value'], $regs)) {
272
- $return->ctype_primary = $regs[1];
273
  $return->ctype_secondary = $regs[2];
274
  }
275
 
276
  if (isset($content_type['other'])) {
277
- foreach($content_type['other'] as $p_name => $p_value) {
278
  $return->ctype_parameters[$p_name] = $p_value;
279
  }
280
  }
@@ -282,9 +275,9 @@ class Mail_mimeDecode extends PEAR
282
 
283
  case 'content-disposition':
284
  $content_disposition = $this->_parseHeaderValue($headers[$key]['value']);
285
- $return->disposition = $content_disposition['value'];
286
  if (isset($content_disposition['other'])) {
287
- foreach($content_disposition['other'] as $p_name => $p_value) {
288
  $return->d_parameters[$p_name] = $p_value;
289
  }
290
  }
@@ -317,7 +310,7 @@ class Mail_mimeDecode extends PEAR
317
  case 'multipart/related':
318
  case 'multipart/mixed':
319
  case 'application/vnd.wap.multipart.related':
320
- if(!isset($content_type['other']['boundary'])){
321
  $this->_error = 'No boundary found for ' . $content_type['value'] . ' part';
322
  return false;
323
  }
@@ -328,34 +321,33 @@ class Mail_mimeDecode extends PEAR
328
  for ($i = 0; $i < count($parts); $i++) {
329
  list($part_header, $part_body) = $this->_splitBodyHeader($parts[$i]);
330
  $part = $this->_decode($part_header, $part_body, $default_ctype);
331
- if($part === false)
332
  $part = $this->raiseError($this->_error);
333
  $return->parts[] = $part;
334
  }
335
  break;
336
 
337
  case 'message/rfc822':
338
- if ($this->_rfc822_bodies) {
339
- $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
340
- $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body);
341
- }
342
  $obj = new Mail_mimeDecode($body);
343
  $return->parts[] = $obj->decode(array('include_bodies' => $this->_include_bodies,
344
- 'decode_bodies' => $this->_decode_bodies,
345
- 'decode_headers' => $this->_decode_headers));
346
  unset($obj);
347
  break;
348
 
349
  default:
350
- if(!isset($content_transfer_encoding['value']))
351
  $content_transfer_encoding['value'] = '7bit';
352
  $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $content_transfer_encoding['value']) : $body) : null;
353
  break;
354
  }
355
-
356
  } else {
357
  $ctype = explode('/', $default_ctype);
358
- $return->ctype_primary = $ctype[0];
359
  $return->ctype_secondary = $ctype[1];
360
  $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body) : $body) : null;
361
  }
@@ -371,8 +363,7 @@ class Mail_mimeDecode extends PEAR
371
  * @param string $mime_number Internal use only.
372
  * @return array Mime numbers
373
  */
374
- function &getMimeNumbers(&$structure, $no_refs = false, $mime_number = '', $prepend = '')
375
- {
376
  $return = array();
377
  if (!empty($structure->parts)) {
378
  if ($mime_number != '') {
@@ -381,9 +372,9 @@ class Mail_mimeDecode extends PEAR
381
  }
382
  for ($i = 0; $i < count($structure->parts); $i++) {
383
 
384
-
385
  if (!empty($structure->headers['content-type']) AND substr(strtolower($structure->headers['content-type']), 0, 8) == 'message/') {
386
- $prepend = $prepend . $mime_number . '.';
387
  $_mime_number = '';
388
  } else {
389
  $_mime_number = ($mime_number == '' ? $i + 1 : sprintf('%s.%s', $mime_number, $i + 1));
@@ -401,7 +392,7 @@ class Mail_mimeDecode extends PEAR
401
  $structure->mime_id = $prepend . $mime_number;
402
  $no_refs ? $return[$prepend . $mime_number] = '' : $return[$prepend . $mime_number] = &$structure;
403
  }
404
-
405
  return $return;
406
  }
407
 
@@ -414,14 +405,13 @@ class Mail_mimeDecode extends PEAR
414
  * @return array Contains header and body section
415
  * @access private
416
  */
417
- function _splitBodyHeader($input)
418
- {
419
  if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) {
420
  return array($match[1], $match[2]);
421
  }
422
  // bug #17325 - empty bodies are allowed. - we just check that at least one line
423
  // of headers exist..
424
- if (count(explode("\n",$input))) {
425
  return array($input, '');
426
  }
427
  $this->_error = 'Could not split header and body';
@@ -436,30 +426,29 @@ class Mail_mimeDecode extends PEAR
436
  * @return array Contains parsed headers
437
  * @access private
438
  */
439
- function _parseHeaders($input)
440
- {
441
 
442
  if ($input !== '') {
443
  // Unfold the input
444
- $input = preg_replace("/\r?\n/", "\r\n", $input);
445
  //#7065 - wrapping.. with encoded stuff.. - probably not needed,
446
  // wrapping space should only get removed if the trailing item on previous line is a
447
  // encoded character
448
- $input = preg_replace("/=\r\n(\t| )+/", '=', $input);
449
- $input = preg_replace("/\r\n(\t| )+/", ' ', $input);
450
-
451
  $headers = explode("\r\n", trim($input));
452
 
453
  foreach ($headers as $value) {
454
  $hdr_name = substr($value, 0, $pos = strpos($value, ':'));
455
- $hdr_value = substr($value, $pos+1);
456
- if($hdr_value[0] == ' ')
457
  $hdr_value = substr($hdr_value, 1);
458
 
459
  $return[] = array(
460
- 'name' => $hdr_name,
461
- 'value' => $hdr_value
462
- );
463
  }
464
  } else {
465
  $return = array();
@@ -479,8 +468,7 @@ class Mail_mimeDecode extends PEAR
479
  * @return array Contains parsed result
480
  * @access private
481
  */
482
- function _parseHeaderValue($input)
483
- {
484
 
485
  if (($pos = strpos($input, ';')) === false) {
486
  $input = $this->_decode_headers ? $this->_decodeHeader($input) : $input;
@@ -493,7 +481,7 @@ class Mail_mimeDecode extends PEAR
493
  $value = substr($input, 0, $pos);
494
  $value = $this->_decode_headers ? $this->_decodeHeader($value) : $value;
495
  $return['value'] = trim($value);
496
- $input = trim(substr($input, $pos+1));
497
 
498
  if (!strlen($input) > 0) {
499
  return $return;
@@ -508,19 +496,19 @@ class Mail_mimeDecode extends PEAR
508
  $lq = ''; // last quote..
509
 
510
  while ($i < $l) {
511
-
512
  $c = $input[$i];
513
  //var_dump(array('i'=>$i,'c'=>$c,'q'=>$q, 'lq'=>$lq, 'key'=>$key, 'val' =>$val));
514
 
515
  $escaped = false;
516
  if ($c == '\\') {
517
  $i++;
518
- if ($i == $l-1) { // end of string.
519
  break;
520
  }
521
  $escaped = true;
522
  $c = $input[$i];
523
- }
524
 
525
 
526
  // state - in key..
@@ -533,7 +521,7 @@ class Mail_mimeDecode extends PEAR
533
  }
534
  if (!$escaped && $c == ';') {
535
  if ($key) { // a key without a value..
536
- $key= trim($key);
537
  $return['other'][$key] = '';
538
  $return['other'][strtolower($key)] = '';
539
  }
@@ -543,12 +531,12 @@ class Mail_mimeDecode extends PEAR
543
  $i++;
544
  continue;
545
  }
546
-
547
  // state - in value.. (as $val is set..)
548
 
549
  if ($q === false) {
550
  // not in quote yet.
551
- if ((!strlen($val) || $lq !== false) && $c == ' ' || $c == "\t") {
552
  $i++;
553
  continue; // skip leading spaces after '=' or after '"'
554
  }
@@ -594,25 +582,24 @@ class Mail_mimeDecode extends PEAR
594
  $i++;
595
  continue;
596
  }
597
-
598
  // state - in quote..
599
  if (!$escaped && $c == $q) { // potential exit state..
600
-
601
  // end of quoted string..
602
  $lq = $q;
603
  $q = false;
604
  $i++;
605
  continue;
606
  }
607
-
608
  // normal char inside of quoted string..
609
  $val.= $c;
610
  $i++;
611
  }
612
-
613
  // do we have anything left..
614
  if (strlen(trim($key)) || $val !== false) {
615
-
616
  $val = trim($val);
617
  $added = false;
618
  if ($val !== false && preg_match('/\*[0-9]+$/', $key)) {
@@ -633,10 +620,10 @@ class Mail_mimeDecode extends PEAR
633
  }
634
  }
635
  // decode values.
636
- foreach($return['other'] as $key =>$val) {
637
  $return['other'][$key] = $this->_decode_headers ? $this->_decodeHeader($val) : $val;
638
  }
639
- //print_r($return);
640
  return $return;
641
  }
642
 
@@ -648,8 +635,7 @@ class Mail_mimeDecode extends PEAR
648
  * @return array Contains array of resulting mime parts
649
  * @access private
650
  */
651
- function _boundarySplit($input, $boundary)
652
- {
653
  $parts = array();
654
 
655
  $bs_possible = substr($boundary, 2, -2);
@@ -658,15 +644,15 @@ class Mail_mimeDecode extends PEAR
658
  if ($boundary == $bs_check) {
659
  $boundary = $bs_possible;
660
  }
661
- $tmp = preg_split("/--".preg_quote($boundary, '/')."((?=\s)|--)/", $input);
662
 
663
- $len = count($tmp) -1;
664
  for ($i = 1; $i < $len; $i++) {
665
  if (strlen(trim($tmp[$i]))) {
666
  $parts[] = $tmp[$i];
667
  }
668
  }
669
-
670
  // add the last part on if it does not end with the 'closing indicator'
671
  if (!empty($tmp[$len]) && strlen(trim($tmp[$len])) && $tmp[$len][0] != '-') {
672
  $parts[] = $tmp[$len];
@@ -684,29 +670,28 @@ class Mail_mimeDecode extends PEAR
684
  * @return string Decoded header value
685
  * @access private
686
  */
687
- function _decodeHeader($input)
688
- {
689
  // Remove white space between encoded-words
690
  $input = preg_replace('/(=\?[^?]+\?(q|b)\?[^?]*\?=)(\s)+=\?/i', '\1=?', $input);
691
 
692
  // For each encoded-word...
693
  while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)/i', $input, $matches)) {
694
 
695
- $encoded = $matches[1];
696
- $charset = $matches[2];
697
  $encoding = $matches[3];
698
- $text = $matches[4];
699
 
700
  switch (strtolower($encoding)) {
701
  case 'b':
702
- $text = base64_decode($text);
703
  break;
704
 
705
  case 'q':
706
  $text = str_replace('_', ' ', $text);
707
  preg_match_all('/=([a-f0-9]{2})/i', $text, $matches);
708
- foreach($matches[1] as $value)
709
- $text = str_replace('='.$value, chr(hexdec($value)), $text);
710
  break;
711
  }
712
 
@@ -725,8 +710,7 @@ class Mail_mimeDecode extends PEAR
725
  * @return string Decoded body
726
  * @access private
727
  */
728
- function _decodeBody($input, $encoding = '7bit')
729
- {
730
  switch (strtolower($encoding)) {
731
  case '7bit':
732
  return $input;
@@ -753,13 +737,12 @@ class Mail_mimeDecode extends PEAR
753
  * @return string Decoded body
754
  * @access private
755
  */
756
- function _quotedPrintableDecode($input)
757
- {
758
  // Remove soft line breaks
759
  $input = preg_replace("/=\r?\n/", '', $input);
760
 
761
  // Replace encoded characters
762
- $input = preg_replace('/=([a-f0-9]{2})/ie', "chr(hexdec('\\1'))", $input);
763
 
764
  return $input;
765
  }
@@ -779,14 +762,13 @@ class Mail_mimeDecode extends PEAR
779
  * @access public
780
  * @author Unknown
781
  */
782
- function &uudecode($input)
783
- {
784
  // Find all uuencoded sections
785
  preg_match_all("/begin ([0-7]{3}) (.+)\r?\n(.+)\r?\nend/Us", $input, $matches);
786
 
787
  for ($j = 0; $j < count($matches[3]); $j++) {
788
 
789
- $str = $matches[3][$j];
790
  $filename = $matches[2][$j];
791
  $fileperm = $matches[1][$j];
792
 
@@ -797,27 +779,27 @@ class Mail_mimeDecode extends PEAR
797
  for ($i = 0; $i < $strlen; $i++) {
798
  $pos = 1;
799
  $d = 0;
800
- $len=(int)(((ord(substr($str[$i],0,1)) -32) - ' ') & 077);
801
 
802
  while (($d + 3 <= $len) AND ($pos + 4 <= strlen($str[$i]))) {
803
- $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
804
- $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
805
- $c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20);
806
- $c3 = (ord(substr($str[$i],$pos+3,1)) ^ 0x20);
807
  $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));
808
 
809
  $file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2));
810
 
811
- $file .= chr(((($c2 - ' ') & 077) << 6) | (($c3 - ' ') & 077));
812
 
813
  $pos += 4;
814
  $d += 3;
815
  }
816
 
817
  if (($d + 2 <= $len) && ($pos + 3 <= strlen($str[$i]))) {
818
- $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
819
- $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
820
- $c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20);
821
  $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));
822
 
823
  $file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2));
@@ -827,10 +809,9 @@ class Mail_mimeDecode extends PEAR
827
  }
828
 
829
  if (($d + 1 <= $len) && ($pos + 2 <= strlen($str[$i]))) {
830
- $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
831
- $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
832
  $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));
833
-
834
  }
835
  }
836
  $files[] = array('filename' => $filename, 'fileperm' => $fileperm, 'filedata' => $file);
@@ -858,32 +839,31 @@ class Mail_mimeDecode extends PEAR
858
  * @access public
859
  * @author Alan Knowles <alan@akbkhome.com>
860
  */
861
- function getSendArray()
862
- {
863
  // prevent warning if this is not set
864
  $this->_decode_headers = FALSE;
865
- $headerlist =$this->_parseHeaders($this->_header);
866
  $to = "";
867
  if (!$headerlist) {
868
  return $this->raiseError("Message did not contain headers");
869
  }
870
- foreach($headerlist as $item) {
871
  $header[$item['name']] = $item['value'];
872
  switch (strtolower($item['name'])) {
873
  case "to":
874
  case "cc":
875
  case "bcc":
876
- $to .= ",".$item['value'];
877
  default:
878
- break;
879
  }
880
  }
881
  if ($to == "") {
882
  return $this->raiseError("Message did not contain any recipents");
883
  }
884
- $to = substr($to,1);
885
- return array($to,$header,$this->_body);
886
- }
887
 
888
  /**
889
  * Returns a xml copy of the output of
@@ -902,14 +882,13 @@ class Mail_mimeDecode extends PEAR
902
  * @return string XML version of input
903
  * @access public
904
  */
905
- function getXML($input)
906
- {
907
- $crlf = "\r\n";
908
- $output = '<?xml version=\'1.0\'?>' . $crlf .
909
- '<!DOCTYPE email SYSTEM "http://www.phpguru.org/xmail/xmail.dtd">' . $crlf .
910
- '<email>' . $crlf .
911
- Mail_mimeDecode::_getXML($input) .
912
- '</email>';
913
 
914
  return $output;
915
  }
@@ -924,12 +903,11 @@ class Mail_mimeDecode extends PEAR
924
  * @return string XML version of input
925
  * @access private
926
  */
927
- function _getXML($input, $indent = 1)
928
- {
929
- $htab = "\t";
930
- $crlf = "\r\n";
931
- $output = '';
932
- $headers = @(array)$input->headers;
933
 
934
  foreach ($headers as $hdr_name => $hdr_value) {
935
 
@@ -939,7 +917,7 @@ class Mail_mimeDecode extends PEAR
939
  $output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value[$i], $indent);
940
  }
941
 
942
- // Only one header of this sort
943
  } else {
944
  $output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value, $indent);
945
  }
@@ -948,12 +926,12 @@ class Mail_mimeDecode extends PEAR
948
  if (!empty($input->parts)) {
949
  for ($i = 0; $i < count($input->parts); $i++) {
950
  $output .= $crlf . str_repeat($htab, $indent) . '<mimepart>' . $crlf .
951
- Mail_mimeDecode::_getXML($input->parts[$i], $indent+1) .
952
- str_repeat($htab, $indent) . '</mimepart>' . $crlf;
953
  }
954
  } elseif (isset($input->body)) {
955
  $output .= $crlf . str_repeat($htab, $indent) . '<body><![CDATA[' .
956
- $input->body . ']]></body>' . $crlf;
957
  }
958
 
959
  return $output;
@@ -968,22 +946,21 @@ class Mail_mimeDecode extends PEAR
968
  * @return string XML version of input
969
  * @access private
970
  */
971
- function _getXML_helper($hdr_name, $hdr_value, $indent)
972
- {
973
- $htab = "\t";
974
- $crlf = "\r\n";
975
  $return = '';
976
 
977
  $new_hdr_value = ($hdr_name != 'received') ? Mail_mimeDecode::_parseHeaderValue($hdr_value) : array('value' => $hdr_value);
978
- $new_hdr_name = str_replace(' ', '-', ucwords(str_replace('-', ' ', $hdr_name)));
979
 
980
  // Sort out any parameters
981
  if (!empty($new_hdr_value['other'])) {
982
  foreach ($new_hdr_value['other'] as $paramname => $paramvalue) {
983
  $params[] = str_repeat($htab, $indent) . $htab . '<parameter>' . $crlf .
984
- str_repeat($htab, $indent) . $htab . $htab . '<paramname>' . htmlspecialchars($paramname) . '</paramname>' . $crlf .
985
- str_repeat($htab, $indent) . $htab . $htab . '<paramvalue>' . htmlspecialchars($paramvalue) . '</paramvalue>' . $crlf .
986
- str_repeat($htab, $indent) . $htab . '</parameter>' . $crlf;
987
  }
988
 
989
  $params = implode('', $params);
@@ -992,12 +969,14 @@ class Mail_mimeDecode extends PEAR
992
  }
993
 
994
  $return = str_repeat($htab, $indent) . '<header>' . $crlf .
995
- str_repeat($htab, $indent) . $htab . '<headername>' . htmlspecialchars($new_hdr_name) . '</headername>' . $crlf .
996
- str_repeat($htab, $indent) . $htab . '<headervalue>' . htmlspecialchars($new_hdr_value['value']) . '</headervalue>' . $crlf .
997
- $params .
998
- str_repeat($htab, $indent) . '</header>' . $crlf;
999
 
1000
  return $return;
1001
  }
1002
 
1003
- } // End of class
 
 
1
  <?php
2
+
3
  /**
4
  * The Mail_mimeDecode class is used to decode mail/mime messages
5
  *
56
  * @version CVS: $Id: mimeDecode.php 305875 2010-12-01 07:17:10Z alan_k $
57
  * @link http://pear.php.net/package/Mail_mime
58
  */
 
 
59
  /**
60
  * require PEAR
61
  *
63
  */
64
  require_once 'PEAR.php';
65
 
 
66
  /**
67
  * The Mail_mimeDecode class is used to decode mail/mime messages
68
  *
86
  * @version Release: @package_version@
87
  * @link http://pear.php.net/package/Mail_mime
88
  */
89
+ class Mail_mimeDecode extends PEAR {
90
+
91
  /**
92
  * The raw email to decode
93
  *
163
  * @param string The input to decode
164
  * @access public
165
  */
166
+ function Mail_mimeDecode($input) {
167
+ list($header, $body) = $this->_splitBodyHeader($input);
168
+
169
+ $this->_input = $input;
170
+ $this->_header = $header;
171
+ $this->_body = $body;
172
+ $this->_decode_bodies = false;
 
173
  $this->_include_bodies = true;
174
+ $this->_rfc822_bodies = false;
175
  }
176
 
177
  /**
191
  * @return object Decoded results
192
  * @access public
193
  */
194
+ function decode($params = null) {
 
195
  // determine if this method has been called statically
196
  $isStatic = empty($this) || !is_a($this, __CLASS__);
197
 
198
  // Have we been called statically?
199
+ // If so, create an object and pass details to that.
200
  if ($isStatic AND isset($params['input'])) {
201
 
202
  $obj = new Mail_mimeDecode($params['input']);
203
  $structure = $obj->decode($params);
204
 
205
+ // Called statically but no input
206
  } elseif ($isStatic) {
207
  return PEAR::raiseError('Called statically and no input given');
208
 
209
+ // Called via an object
210
  } else {
211
  $this->_include_bodies = isset($params['include_bodies']) ?
212
+ $params['include_bodies'] : false;
213
+ $this->_decode_bodies = isset($params['decode_bodies']) ?
214
+ $params['decode_bodies'] : false;
215
  $this->_decode_headers = isset($params['decode_headers']) ?
216
+ $params['decode_headers'] : false;
217
+ $this->_rfc822_bodies = isset($params['rfc_822bodies']) ?
218
+ $params['rfc_822bodies'] : false;
219
 
220
  $structure = $this->_decode($this->_header, $this->_body);
221
  if ($structure === false) {
236
  * @return object Results of decoding process
237
  * @access private
238
  */
239
+ function _decode($headers, $body, $default_ctype = 'text/plain') {
 
240
  $return = new stdClass;
241
  $return->headers = array();
242
  $headers = $this->_parseHeaders($headers);
244
  foreach ($headers as $value) {
245
  $value['value'] = $this->_decode_headers ? $this->_decodeHeader($value['value']) : $value['value'];
246
  if (isset($return->headers[strtolower($value['name'])]) AND !is_array($return->headers[strtolower($value['name'])])) {
247
+ $return->headers[strtolower($value['name'])] = array($return->headers[strtolower($value['name'])]);
248
  $return->headers[strtolower($value['name'])][] = $value['value'];
 
249
  } elseif (isset($return->headers[strtolower($value['name'])])) {
250
  $return->headers[strtolower($value['name'])][] = $value['value'];
 
251
  } else {
252
  $return->headers[strtolower($value['name'])] = $value['value'];
253
  }
262
  $content_type = $this->_parseHeaderValue($headers[$key]['value']);
263
 
264
  if (preg_match('/([0-9a-z+.-]+)\/([0-9a-z+.-]+)/i', $content_type['value'], $regs)) {
265
+ $return->ctype_primary = $regs[1];
266
  $return->ctype_secondary = $regs[2];
267
  }
268
 
269
  if (isset($content_type['other'])) {
270
+ foreach ($content_type['other'] as $p_name => $p_value) {
271
  $return->ctype_parameters[$p_name] = $p_value;
272
  }
273
  }
275
 
276
  case 'content-disposition':
277
  $content_disposition = $this->_parseHeaderValue($headers[$key]['value']);
278
+ $return->disposition = $content_disposition['value'];
279
  if (isset($content_disposition['other'])) {
280
+ foreach ($content_disposition['other'] as $p_name => $p_value) {
281
  $return->d_parameters[$p_name] = $p_value;
282
  }
283
  }
310
  case 'multipart/related':
311
  case 'multipart/mixed':
312
  case 'application/vnd.wap.multipart.related':
313
+ if (!isset($content_type['other']['boundary'])) {
314
  $this->_error = 'No boundary found for ' . $content_type['value'] . ' part';
315
  return false;
316
  }
321
  for ($i = 0; $i < count($parts); $i++) {
322
  list($part_header, $part_body) = $this->_splitBodyHeader($parts[$i]);
323
  $part = $this->_decode($part_header, $part_body, $default_ctype);
324
+ if ($part === false)
325
  $part = $this->raiseError($this->_error);
326
  $return->parts[] = $part;
327
  }
328
  break;
329
 
330
  case 'message/rfc822':
331
+ if ($this->_rfc822_bodies) {
332
+ $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
333
+ $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body);
334
+ }
335
  $obj = new Mail_mimeDecode($body);
336
  $return->parts[] = $obj->decode(array('include_bodies' => $this->_include_bodies,
337
+ 'decode_bodies' => $this->_decode_bodies,
338
+ 'decode_headers' => $this->_decode_headers));
339
  unset($obj);
340
  break;
341
 
342
  default:
343
+ if (!isset($content_transfer_encoding['value']))
344
  $content_transfer_encoding['value'] = '7bit';
345
  $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $content_transfer_encoding['value']) : $body) : null;
346
  break;
347
  }
 
348
  } else {
349
  $ctype = explode('/', $default_ctype);
350
+ $return->ctype_primary = $ctype[0];
351
  $return->ctype_secondary = $ctype[1];
352
  $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body) : $body) : null;
353
  }
363
  * @param string $mime_number Internal use only.
364
  * @return array Mime numbers
365
  */
366
+ function &getMimeNumbers(&$structure, $no_refs = false, $mime_number = '', $prepend = '') {
 
367
  $return = array();
368
  if (!empty($structure->parts)) {
369
  if ($mime_number != '') {
372
  }
373
  for ($i = 0; $i < count($structure->parts); $i++) {
374
 
375
+
376
  if (!empty($structure->headers['content-type']) AND substr(strtolower($structure->headers['content-type']), 0, 8) == 'message/') {
377
+ $prepend = $prepend . $mime_number . '.';
378
  $_mime_number = '';
379
  } else {
380
  $_mime_number = ($mime_number == '' ? $i + 1 : sprintf('%s.%s', $mime_number, $i + 1));
392
  $structure->mime_id = $prepend . $mime_number;
393
  $no_refs ? $return[$prepend . $mime_number] = '' : $return[$prepend . $mime_number] = &$structure;
394
  }
395
+
396
  return $return;
397
  }
398
 
405
  * @return array Contains header and body section
406
  * @access private
407
  */
408
+ function _splitBodyHeader($input) {
 
409
  if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) {
410
  return array($match[1], $match[2]);
411
  }
412
  // bug #17325 - empty bodies are allowed. - we just check that at least one line
413
  // of headers exist..
414
+ if (count(explode("\n", $input))) {
415
  return array($input, '');
416
  }
417
  $this->_error = 'Could not split header and body';
426
  * @return array Contains parsed headers
427
  * @access private
428
  */
429
+ function _parseHeaders($input) {
 
430
 
431
  if ($input !== '') {
432
  // Unfold the input
433
+ $input = preg_replace("/\r?\n/", "\r\n", $input);
434
  //#7065 - wrapping.. with encoded stuff.. - probably not needed,
435
  // wrapping space should only get removed if the trailing item on previous line is a
436
  // encoded character
437
+ $input = preg_replace("/=\r\n(\t| )+/", '=', $input);
438
+ $input = preg_replace("/\r\n(\t| )+/", ' ', $input);
439
+
440
  $headers = explode("\r\n", trim($input));
441
 
442
  foreach ($headers as $value) {
443
  $hdr_name = substr($value, 0, $pos = strpos($value, ':'));
444
+ $hdr_value = substr($value, $pos + 1);
445
+ if ($hdr_value[0] == ' ')
446
  $hdr_value = substr($hdr_value, 1);
447
 
448
  $return[] = array(
449
+ 'name' => $hdr_name,
450
+ 'value' => $hdr_value
451
+ );
452
  }
453
  } else {
454
  $return = array();
468
  * @return array Contains parsed result
469
  * @access private
470
  */
471
+ function _parseHeaderValue($input) {
 
472
 
473
  if (($pos = strpos($input, ';')) === false) {
474
  $input = $this->_decode_headers ? $this->_decodeHeader($input) : $input;
481
  $value = substr($input, 0, $pos);
482
  $value = $this->_decode_headers ? $this->_decodeHeader($value) : $value;
483
  $return['value'] = trim($value);
484
+ $input = trim(substr($input, $pos + 1));
485
 
486
  if (!strlen($input) > 0) {
487
  return $return;
496
  $lq = ''; // last quote..
497
 
498
  while ($i < $l) {
499
+
500
  $c = $input[$i];
501
  //var_dump(array('i'=>$i,'c'=>$c,'q'=>$q, 'lq'=>$lq, 'key'=>$key, 'val' =>$val));
502
 
503
  $escaped = false;
504
  if ($c == '\\') {
505
  $i++;
506
+ if ($i == $l - 1) { // end of string.
507
  break;
508
  }
509
  $escaped = true;
510
  $c = $input[$i];
511
+ }
512
 
513
 
514
  // state - in key..
521
  }
522
  if (!$escaped && $c == ';') {
523
  if ($key) { // a key without a value..
524
+ $key = trim($key);
525
  $return['other'][$key] = '';
526
  $return['other'][strtolower($key)] = '';
527
  }
531
  $i++;
532
  continue;
533
  }
534
+
535
  // state - in value.. (as $val is set..)
536
 
537
  if ($q === false) {
538
  // not in quote yet.
539
+ if ((!strlen($val) || $lq !== false) && $c == ' ' || $c == "\t") {
540
  $i++;
541
  continue; // skip leading spaces after '=' or after '"'
542
  }
582
  $i++;
583
  continue;
584
  }
585
+
586
  // state - in quote..
587
  if (!$escaped && $c == $q) { // potential exit state..
 
588
  // end of quoted string..
589
  $lq = $q;
590
  $q = false;
591
  $i++;
592
  continue;
593
  }
594
+
595
  // normal char inside of quoted string..
596
  $val.= $c;
597
  $i++;
598
  }
599
+
600
  // do we have anything left..
601
  if (strlen(trim($key)) || $val !== false) {
602
+
603
  $val = trim($val);
604
  $added = false;
605
  if ($val !== false && preg_match('/\*[0-9]+$/', $key)) {
620
  }
621
  }
622
  // decode values.
623
+ foreach ($return['other'] as $key => $val) {
624
  $return['other'][$key] = $this->_decode_headers ? $this->_decodeHeader($val) : $val;
625
  }
626
+ //print_r($return);
627
  return $return;
628
  }
629
 
635
  * @return array Contains array of resulting mime parts
636
  * @access private
637
  */
638
+ function _boundarySplit($input, $boundary) {
 
639
  $parts = array();
640
 
641
  $bs_possible = substr($boundary, 2, -2);
644
  if ($boundary == $bs_check) {
645
  $boundary = $bs_possible;
646
  }
647
+ $tmp = preg_split("/--" . preg_quote($boundary, '/') . "((?=\s)|--)/", $input);
648
 
649
+ $len = count($tmp) - 1;
650
  for ($i = 1; $i < $len; $i++) {
651
  if (strlen(trim($tmp[$i]))) {
652
  $parts[] = $tmp[$i];
653
  }
654
  }
655
+
656
  // add the last part on if it does not end with the 'closing indicator'
657
  if (!empty($tmp[$len]) && strlen(trim($tmp[$len])) && $tmp[$len][0] != '-') {
658
  $parts[] = $tmp[$len];
670
  * @return string Decoded header value
671
  * @access private
672
  */
673
+ function _decodeHeader($input) {
 
674
  // Remove white space between encoded-words
675
  $input = preg_replace('/(=\?[^?]+\?(q|b)\?[^?]*\?=)(\s)+=\?/i', '\1=?', $input);
676
 
677
  // For each encoded-word...
678
  while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)/i', $input, $matches)) {
679
 
680
+ $encoded = $matches[1];
681
+ $charset = $matches[2];
682
  $encoding = $matches[3];
683
+ $text = $matches[4];
684
 
685
  switch (strtolower($encoding)) {
686
  case 'b':
687
+ $text = iconv($charset, "UTF-8//TRANSLIT", base64_decode($text));
688
  break;
689
 
690
  case 'q':
691
  $text = str_replace('_', ' ', $text);
692
  preg_match_all('/=([a-f0-9]{2})/i', $text, $matches);
693
+ foreach ($matches[1] as $value)
694
+ $text = str_replace('=' . $value, chr(hexdec($value)), $text);
695
  break;
696
  }
697
 
710
  * @return string Decoded body
711
  * @access private
712
  */
713
+ function _decodeBody($input, $encoding = '7bit') {
 
714
  switch (strtolower($encoding)) {
715
  case '7bit':
716
  return $input;
737
  * @return string Decoded body
738
  * @access private
739
  */
740
+ function _quotedPrintableDecode($input) {
 
741
  // Remove soft line breaks
742
  $input = preg_replace("/=\r?\n/", '', $input);
743
 
744
  // Replace encoded characters
745
+ $input = preg_replace('/=([a-f0-9]{2})/ie', "chr(hexdec('\\1'))", $input);
746
 
747
  return $input;
748
  }
762
  * @access public
763
  * @author Unknown
764
  */
765
+ function &uudecode($input) {
 
766
  // Find all uuencoded sections
767
  preg_match_all("/begin ([0-7]{3}) (.+)\r?\n(.+)\r?\nend/Us", $input, $matches);
768
 
769
  for ($j = 0; $j < count($matches[3]); $j++) {
770
 
771
+ $str = $matches[3][$j];
772
  $filename = $matches[2][$j];
773
  $fileperm = $matches[1][$j];
774
 
779
  for ($i = 0; $i < $strlen; $i++) {
780
  $pos = 1;
781
  $d = 0;
782
+ $len = (int) (((ord(substr($str[$i], 0, 1)) - 32) - ' ') & 077);
783
 
784
  while (($d + 3 <= $len) AND ($pos + 4 <= strlen($str[$i]))) {
785
+ $c0 = (ord(substr($str[$i], $pos, 1)) ^ 0x20);
786
+ $c1 = (ord(substr($str[$i], $pos + 1, 1)) ^ 0x20);
787
+ $c2 = (ord(substr($str[$i], $pos + 2, 1)) ^ 0x20);
788
+ $c3 = (ord(substr($str[$i], $pos + 3, 1)) ^ 0x20);
789
  $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));
790
 
791
  $file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2));
792
 
793
+ $file .= chr(((($c2 - ' ') & 077) << 6) | (($c3 - ' ') & 077));
794
 
795
  $pos += 4;
796
  $d += 3;
797
  }
798
 
799
  if (($d + 2 <= $len) && ($pos + 3 <= strlen($str[$i]))) {
800
+ $c0 = (ord(substr($str[$i], $pos, 1)) ^ 0x20);
801
+ $c1 = (ord(substr($str[$i], $pos + 1, 1)) ^ 0x20);
802
+ $c2 = (ord(substr($str[$i], $pos + 2, 1)) ^ 0x20);
803
  $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));
804
 
805
  $file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2));
809
  }
810
 
811
  if (($d + 1 <= $len) && ($pos + 2 <= strlen($str[$i]))) {
812
+ $c0 = (ord(substr($str[$i], $pos, 1)) ^ 0x20);
813
+ $c1 = (ord(substr($str[$i], $pos + 1, 1)) ^ 0x20);
814
  $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));
 
815
  }
816
  }
817
  $files[] = array('filename' => $filename, 'fileperm' => $fileperm, 'filedata' => $file);
839
  * @access public
840
  * @author Alan Knowles <alan@akbkhome.com>
841
  */
842
+ function getSendArray() {
 
843
  // prevent warning if this is not set
844
  $this->_decode_headers = FALSE;
845
+ $headerlist = $this->_parseHeaders($this->_header);
846
  $to = "";
847
  if (!$headerlist) {
848
  return $this->raiseError("Message did not contain headers");
849
  }
850
+ foreach ($headerlist as $item) {
851
  $header[$item['name']] = $item['value'];
852
  switch (strtolower($item['name'])) {
853
  case "to":
854
  case "cc":
855
  case "bcc":
856
+ $to .= "," . $item['value'];
857
  default:
858
+ break;
859
  }
860
  }
861
  if ($to == "") {
862
  return $this->raiseError("Message did not contain any recipents");
863
  }
864
+ $to = substr($to, 1);
865
+ return array($to, $header, $this->_body);
866
+ }
867
 
868
  /**
869
  * Returns a xml copy of the output of
882
  * @return string XML version of input
883
  * @access public
884
  */
885
+ function getXML($input) {
886
+ $crlf = "\r\n";
887
+ $output = '<?xml version=\'1.0\'?>' . $crlf .
888
+ '<!DOCTYPE email SYSTEM "http://www.phpguru.org/xmail/xmail.dtd">' . $crlf .
889
+ '<email>' . $crlf .
890
+ Mail_mimeDecode::_getXML($input) .
891
+ '</email>';
 
892
 
893
  return $output;
894
  }
903
  * @return string XML version of input
904
  * @access private
905
  */
906
+ function _getXML($input, $indent = 1) {
907
+ $htab = "\t";
908
+ $crlf = "\r\n";
909
+ $output = '';
910
+ $headers = @(array) $input->headers;
 
911
 
912
  foreach ($headers as $hdr_name => $hdr_value) {
913
 
917
  $output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value[$i], $indent);
918
  }
919
 
920
+ // Only one header of this sort
921
  } else {
922
  $output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value, $indent);
923
  }
926
  if (!empty($input->parts)) {
927
  for ($i = 0; $i < count($input->parts); $i++) {
928
  $output .= $crlf . str_repeat($htab, $indent) . '<mimepart>' . $crlf .
929
+ Mail_mimeDecode::_getXML($input->parts[$i], $indent + 1) .
930
+ str_repeat($htab, $indent) . '</mimepart>' . $crlf;
931
  }
932
  } elseif (isset($input->body)) {
933
  $output .= $crlf . str_repeat($htab, $indent) . '<body><![CDATA[' .
934
+ $input->body . ']]></body>' . $crlf;
935
  }
936
 
937
  return $output;
946
  * @return string XML version of input
947
  * @access private
948
  */
949
+ function _getXML_helper($hdr_name, $hdr_value, $indent) {
950
+ $htab = "\t";
951
+ $crlf = "\r\n";
 
952
  $return = '';
953
 
954
  $new_hdr_value = ($hdr_name != 'received') ? Mail_mimeDecode::_parseHeaderValue($hdr_value) : array('value' => $hdr_value);
955
+ $new_hdr_name = str_replace(' ', '-', ucwords(str_replace('-', ' ', $hdr_name)));
956
 
957
  // Sort out any parameters
958
  if (!empty($new_hdr_value['other'])) {
959
  foreach ($new_hdr_value['other'] as $paramname => $paramvalue) {
960
  $params[] = str_repeat($htab, $indent) . $htab . '<parameter>' . $crlf .
961
+ str_repeat($htab, $indent) . $htab . $htab . '<paramname>' . htmlspecialchars($paramname) . '</paramname>' . $crlf .
962
+ str_repeat($htab, $indent) . $htab . $htab . '<paramvalue>' . htmlspecialchars($paramvalue) . '</paramvalue>' . $crlf .
963
+ str_repeat($htab, $indent) . $htab . '</parameter>' . $crlf;
964
  }
965
 
966
  $params = implode('', $params);
969
  }
970
 
971
  $return = str_repeat($htab, $indent) . '<header>' . $crlf .
972
+ str_repeat($htab, $indent) . $htab . '<headername>' . htmlspecialchars($new_hdr_name) . '</headername>' . $crlf .
973
+ str_repeat($htab, $indent) . $htab . '<headervalue>' . htmlspecialchars($new_hdr_value['value']) . '</headervalue>' . $crlf .
974
+ $params .
975
+ str_repeat($htab, $indent) . '</header>' . $crlf;
976
 
977
  return $return;
978
  }
979
 
980
+ }
981
+
982
+ // End of class
postie-functions.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  /*
4
- $Id: postie-functions.php 636381 2012-12-10 02:23:45Z WayneAllen $
5
  */
6
 
7
  /* TODO
@@ -200,8 +200,8 @@ function PostEmail($poster, $mimeDecodedEmail, $config) {
200
  'email_author' => $postAuthorDetails['email'],
201
  'post_date' => $post_date,
202
  'post_date_gmt' => $post_date_gmt,
203
- 'post_content' => $content,
204
- 'post_title' => $subject,
205
  'post_type' => $post_type, /* Added by Raam Dev <raam@raamdev.com> */
206
  'ping_status' => get_option('default_ping_status'),
207
  'post_category' => $post_categories,
@@ -341,7 +341,21 @@ function getPostAuthorDetails(&$subject, &$content, &$mimeDecodedEmail) {
341
  * Otherwise we get them from the headers
342
  */
343
  global $wpdb;
344
- // see if subject starts with Fwd:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
345
  if (preg_match("/(^Fwd:) (.*)/", $subject, $matches)) {
346
  $subject = trim($matches[2]);
347
  if (preg_match("/\nfrom:(.*?)\n/i", $content, $matches)) {
@@ -352,28 +366,13 @@ function getPostAuthorDetails(&$subject, &$content, &$mimeDecodedEmail) {
352
  $theDate = $matches[1];
353
  $mimeDecodedEmail->headers['date'] = $theDate;
354
  }
355
- } else {
356
- $theDate = $mimeDecodedEmail->headers['date'];
357
- $theEmail = RemoveExtraCharactersInEmailAddress(trim(
358
- $mimeDecodedEmail->headers["from"]));
359
- $regAuthor = get_user_by('email', $theEmail);
360
- if ($regAuthor) {
361
- $theAuthor = $regAuthor->user_login;
362
- $theUrl = $regAuthor->user_url;
363
- $theID = $regAuthor->ID;
364
- } else {
365
- $theAuthor = GetNameFromEmail($mimeDecodedEmail->headers['from']);
366
- $theUrl = '';
367
- $theID = '';
368
- }
369
  }
 
370
  // now get rid of forwarding info in the content
371
  $lines = preg_split("/\r\n/", $content);
372
  $newContents = '';
373
  foreach ($lines as $line) {
374
- if (preg_match("/^(from|subject|to|date):.*?/i", $line, $matches) == 0 &&
375
- // preg_match("/^$/i",$line,$matches)==0 &&
376
- preg_match("/^-+\s*forwarded\s*message\s*-+/i", $line, $matches) == 0) {
377
  $newContents.=preg_replace("/\r/", "", $line) . "\n";
378
  }
379
  }
@@ -1041,7 +1040,7 @@ function HandleMessageEncoding($contenttransferencoding, $charset, $body, $blogE
1041
  DebugEcho("encoding: $contenttransferencoding");
1042
 
1043
  if ($contenttransferencoding == 'base64') {
1044
- DebugEcho("base64 detected");
1045
  $body = base64_decode($body);
1046
  $body = iconv($charset, $blogEncoding, $body);
1047
  }
@@ -1133,8 +1132,13 @@ function cp1252_to_utf8($str) {
1133
  function DecodeBase64Part(&$part) {
1134
  if (array_key_exists('content-transfer-encoding', $part->headers)) {
1135
  if (strtolower($part->headers['content-transfer-encoding']) == 'base64') {
1136
- DebugEcho("base64 detected");
1137
- $part->body = iconv($part->ctype_parameters['charset'], 'UTF-8', base64_decode($part->body));
 
 
 
 
 
1138
  }
1139
  }
1140
  }
@@ -1204,17 +1208,19 @@ function DeterminePostDate(&$content, $message_date = NULL, $offset = 0) {
1204
  * This function takes the content of the message - looks for a subject at the begining surrounded by # and then removes that from the content
1205
  */
1206
  function ParseInMessageSubject($content, $defaultTitle) {
 
1207
  if (substr($content, 0, 1) != "#") {
1208
- //print("<p>Didn't start with # '".substr(ltrim($content),0,10)."'");
1209
  return(array($defaultTitle, $content));
1210
  }
1211
  $subjectEndIndex = strpos($content, "#", 1);
1212
  if (!$subjectEndIndex > 0) {
 
1213
  return(array($defaultTitle, $content));
1214
  }
1215
  $subject = substr($content, 1, $subjectEndIndex - 1);
1216
  $content = substr($content, $subjectEndIndex + 1, strlen($content));
1217
- return(array($subject, $content));
1218
  }
1219
 
1220
  /**
@@ -1333,6 +1339,7 @@ function postie_handle_upload(&$file, $overrides = false, $time = null) {
1333
  function wp_handle_upload_error(&$file, $message) {
1334
  return array('error' => $message);
1335
  }
 
1336
  }
1337
 
1338
  // You may define your own function and pass the name in $overrides['upload_error_handler']
@@ -1779,10 +1786,16 @@ function ReplaceImageCIDs(&$content, &$attachments) {
1779
  $used[] = $info[1]; //Index of html to ignore
1780
  }
1781
  }
 
 
1782
  $html = array();
 
 
 
 
1783
  for ($i = 0; $i < count($attachments["html"]); $i++) {
1784
  if (!in_array($i, $used)) {
1785
- $html[] = $attachments["html"][$i];
1786
  }
1787
  }
1788
  $attachments["html"] = $html;
@@ -1857,11 +1870,13 @@ function ReplaceImagePlaceHolders(&$content, $attachments, $config) {
1857
  function GetSubject(&$mimeDecodedEmail, &$content, $config) {
1858
  extract($config);
1859
  global $charset;
1860
- //assign the default title/subject
1861
  if ($mimeDecodedEmail->headers['subject'] == NULL) {
 
1862
  if ($allow_subject_in_mail) {
1863
  list($subject, $content) = ParseInMessageSubject($content, $default_title);
1864
  } else {
 
1865
  $subject = $default_title;
1866
  }
1867
  $mimeDecodedEmail->headers['subject'] = $subject;
@@ -1874,11 +1889,16 @@ function GetSubject(&$mimeDecodedEmail, &$content, $config) {
1874
  } else {
1875
  $encoding = '7bit';
1876
  }
 
 
1877
  if (function_exists('imap_mime_header_decode')) {
1878
  $subject = '';
1879
  $text = $mimeDecodedEmail->headers['subject'];
1880
 
1881
  $elements = imap_mime_header_decode($text);
 
 
 
1882
  for ($i = 0; $i < count($elements); $i++) {
1883
  $thischarset = $elements[$i]->charset;
1884
  if ($thischarset == 'default')
@@ -1886,18 +1906,22 @@ function GetSubject(&$mimeDecodedEmail, &$content, $config) {
1886
 
1887
  $subject.=HandleMessageEncoding($encoding, $thischarset, $elements[$i]->text, $message_encoding, $message_dequote);
1888
  }
 
1889
  }
1890
  if (!$allow_html_in_subject) {
 
1891
  $subject = htmlentities($subject, ENT_COMPAT | ENT_HTML401, $message_encoding);
 
1892
  }
1893
  }
1894
- //This is for ISO-2022-JP - Can anyone confirm that this is still neeeded?
1895
- // escape sequence is 'ESC $ B' == 1b 24 42 hex.
1896
  if (strpos($subject, "\x1b\x24\x42") !== false) {
1897
- // found iso-2022-jp escape sequence in subject... convert!
 
1898
  $subject = iconv("ISO-2022-JP//TRANSLIT", "UTF-8", $subject);
1899
  }
1900
- return($subject);
1901
  }
1902
 
1903
  /**
@@ -1989,9 +2013,7 @@ function GetPostCategories(&$subject, $defaultCategory) {
1989
  * This function just outputs a simple html report about what is being posted in
1990
  */
1991
  function DisplayEmailPost($details) {
1992
- DebugDump($details);
1993
-
1994
- $theFinalContent = $details['post_content'];
1995
  // Report
1996
  EchoInfo('<b>Post Author</b>: ' . $details["post_author"]);
1997
  EchoInfo('<b>Date</b>: ' . $details["post_date"]);
@@ -2551,6 +2573,9 @@ function SafeFileName($filename) {
2551
 
2552
  function DebugEmailOutput(&$email, &$mimeDecodedEmail) {
2553
  if (IsDebugMode()) {
 
 
 
2554
  $fname = POSTIE_ROOT . DIRECTORY_SEPARATOR . "test_emails" . DIRECTORY_SEPARATOR . SafeFileName($mimeDecodedEmail->headers["message-id"]);
2555
  $file = fopen($fname . ".txt ", "w");
2556
  fwrite($file, $email);
1
  <?php
2
 
3
  /*
4
+ $Id: postie-functions.php 636795 2012-12-10 22:00:12Z WayneAllen $
5
  */
6
 
7
  /* TODO
200
  'email_author' => $postAuthorDetails['email'],
201
  'post_date' => $post_date,
202
  'post_date_gmt' => $post_date_gmt,
203
+ 'post_content' => $content,
204
+ 'post_title' => $subject,
205
  'post_type' => $post_type, /* Added by Raam Dev <raam@raamdev.com> */
206
  'ping_status' => get_option('default_ping_status'),
207
  'post_category' => $post_categories,
341
  * Otherwise we get them from the headers
342
  */
343
  global $wpdb;
344
+
345
+ $theDate = $mimeDecodedEmail->headers['date'];
346
+ $theEmail = RemoveExtraCharactersInEmailAddress(trim($mimeDecodedEmail->headers["from"]));
347
+ $regAuthor = get_user_by('email', $theEmail);
348
+ if ($regAuthor) {
349
+ $theAuthor = $regAuthor->user_login;
350
+ $theUrl = $regAuthor->user_url;
351
+ $theID = $regAuthor->ID;
352
+ } else {
353
+ $theAuthor = GetNameFromEmail($mimeDecodedEmail->headers['from']);
354
+ $theUrl = '';
355
+ $theID = '';
356
+ }
357
+
358
+ // see if subject starts with Fwd:
359
  if (preg_match("/(^Fwd:) (.*)/", $subject, $matches)) {
360
  $subject = trim($matches[2]);
361
  if (preg_match("/\nfrom:(.*?)\n/i", $content, $matches)) {
366
  $theDate = $matches[1];
367
  $mimeDecodedEmail->headers['date'] = $theDate;
368
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
369
  }
370
+
371
  // now get rid of forwarding info in the content
372
  $lines = preg_split("/\r\n/", $content);
373
  $newContents = '';
374
  foreach ($lines as $line) {
375
+ if (preg_match("/^(from|subject|to|date):.*?/i", $line, $matches) == 0 && preg_match("/^-+\s*forwarded\s*message\s*-+/i", $line, $matches) == 0) {
 
 
376
  $newContents.=preg_replace("/\r/", "", $line) . "\n";
377
  }
378
  }
1040
  DebugEcho("encoding: $contenttransferencoding");
1041
 
1042
  if ($contenttransferencoding == 'base64') {
1043
+ DebugEcho("HandleMessageEncoding: base64 detected");
1044
  $body = base64_decode($body);
1045
  $body = iconv($charset, $blogEncoding, $body);
1046
  }
1132
  function DecodeBase64Part(&$part) {
1133
  if (array_key_exists('content-transfer-encoding', $part->headers)) {
1134
  if (strtolower($part->headers['content-transfer-encoding']) == 'base64') {
1135
+ DebugEcho("DecodeBase64Part: base64 detected");
1136
+ if (array_key_exists('charset', $part->ctype_parameters)) {
1137
+ $part->body = iconv($part->ctype_parameters['charset'], 'UTF-8', base64_decode($part->body));
1138
+ } else {
1139
+ $part->body = base64_decode($part->body);
1140
+ }
1141
+ $part->headers['content-transfer-encoding']='';
1142
  }
1143
  }
1144
  }
1208
  * This function takes the content of the message - looks for a subject at the begining surrounded by # and then removes that from the content
1209
  */
1210
  function ParseInMessageSubject($content, $defaultTitle) {
1211
+ DebugEcho("Looking for subject in email body");
1212
  if (substr($content, 0, 1) != "#") {
1213
+ DebugEcho("No subject found, using default [1]");
1214
  return(array($defaultTitle, $content));
1215
  }
1216
  $subjectEndIndex = strpos($content, "#", 1);
1217
  if (!$subjectEndIndex > 0) {
1218
+ DebugEcho("No subject found, using default [2]");
1219
  return(array($defaultTitle, $content));
1220
  }
1221
  $subject = substr($content, 1, $subjectEndIndex - 1);
1222
  $content = substr($content, $subjectEndIndex + 1, strlen($content));
1223
+ return array($subject, $content);
1224
  }
1225
 
1226
  /**
1339
  function wp_handle_upload_error(&$file, $message) {
1340
  return array('error' => $message);
1341
  }
1342
+
1343
  }
1344
 
1345
  // You may define your own function and pass the name in $overrides['upload_error_handler']
1786
  $used[] = $info[1]; //Index of html to ignore
1787
  }
1788
  }
1789
+ //DebugEcho("# cid attachments: " . count($used));
1790
+
1791
  $html = array();
1792
+ $att = array_values($attachments["html"]); //make sure there are numeric indexes
1793
+ //DebugDump($attachments["html"]);
1794
+ //DebugDump($att);
1795
+
1796
  for ($i = 0; $i < count($attachments["html"]); $i++) {
1797
  if (!in_array($i, $used)) {
1798
+ $html[] = $att[$i];
1799
  }
1800
  }
1801
  $attachments["html"] = $html;
1870
  function GetSubject(&$mimeDecodedEmail, &$content, $config) {
1871
  extract($config);
1872
  global $charset;
1873
+ //assign the default title/subject
1874
  if ($mimeDecodedEmail->headers['subject'] == NULL) {
1875
+ DebugEcho("No subject in email");
1876
  if ($allow_subject_in_mail) {
1877
  list($subject, $content) = ParseInMessageSubject($content, $default_title);
1878
  } else {
1879
+ DebugEcho("Using default subject");
1880
  $subject = $default_title;
1881
  }
1882
  $mimeDecodedEmail->headers['subject'] = $subject;
1889
  } else {
1890
  $encoding = '7bit';
1891
  }
1892
+ DebugEcho("Subject encoding: $encoding");
1893
+
1894
  if (function_exists('imap_mime_header_decode')) {
1895
  $subject = '';
1896
  $text = $mimeDecodedEmail->headers['subject'];
1897
 
1898
  $elements = imap_mime_header_decode($text);
1899
+ DebugEcho("MIME Header");
1900
+ DebugDump($elements);
1901
+
1902
  for ($i = 0; $i < count($elements); $i++) {
1903
  $thischarset = $elements[$i]->charset;
1904
  if ($thischarset == 'default')
1906
 
1907
  $subject.=HandleMessageEncoding($encoding, $thischarset, $elements[$i]->text, $message_encoding, $message_dequote);
1908
  }
1909
+
1910
  }
1911
  if (!$allow_html_in_subject) {
1912
+ DebugEcho("subject before htmlentities: $subject");
1913
  $subject = htmlentities($subject, ENT_COMPAT | ENT_HTML401, $message_encoding);
1914
+ DebugEcho("subject after htmlentities: $subject");
1915
  }
1916
  }
1917
+ //This is for ISO-2022-JP - Can anyone confirm that this is still neeeded?
1918
+ // escape sequence is 'ESC $ B' == 1b 24 42 hex.
1919
  if (strpos($subject, "\x1b\x24\x42") !== false) {
1920
+ // found iso-2022-jp escape sequence in subject... convert!
1921
+ DebugEcho("extra parsing for ISO-2022-JP");
1922
  $subject = iconv("ISO-2022-JP//TRANSLIT", "UTF-8", $subject);
1923
  }
1924
+ return $subject;
1925
  }
1926
 
1927
  /**
2013
  * This function just outputs a simple html report about what is being posted in
2014
  */
2015
  function DisplayEmailPost($details) {
2016
+ //DebugDump($details);
 
 
2017
  // Report
2018
  EchoInfo('<b>Post Author</b>: ' . $details["post_author"]);
2019
  EchoInfo('<b>Date</b>: ' . $details["post_date"]);
2573
 
2574
  function DebugEmailOutput(&$email, &$mimeDecodedEmail) {
2575
  if (IsDebugMode()) {
2576
+ DebugDump($email);
2577
+ DebugDump($mimeDecodedEmail);
2578
+
2579
  $fname = POSTIE_ROOT . DIRECTORY_SEPARATOR . "test_emails" . DIRECTORY_SEPARATOR . SafeFileName($mimeDecodedEmail->headers["message-id"]);
2580
  $file = fopen($fname . ".txt ", "w");
2581
  fwrite($file, $email);
postie.php CHANGED
@@ -4,7 +4,7 @@
4
  Plugin Name: Postie
5
  Plugin URI: http://PostiePlugin.com/
6
  Description: Signifigantly upgrades the posting by mail features of Word Press (See <a href='options-general.php?page=postie/postie.php'>Settings and options</a>) to configure your e-mail settings. See the <a href='http://wordpress.org/extend/plugins/postie/other_notes'>Readme</a> for usage. Visit the <a href='http://wordpress.org/support/plugin/postie'>postie forum</a> for support.
7
- Version: 1.4.8
8
  Author: Wayne Allen
9
  Author URI: http://allens-home.com/
10
  License: GPL2
@@ -27,7 +27,7 @@
27
  */
28
 
29
  /*
30
- $Id: postie.php 636393 2012-12-10 03:02:12Z WayneAllen $
31
  * -= Requests Pending =-
32
  * German Umlats don't work
33
  * Problems under PHP5
4
  Plugin Name: Postie
5
  Plugin URI: http://PostiePlugin.com/
6
  Description: Signifigantly upgrades the posting by mail features of Word Press (See <a href='options-general.php?page=postie/postie.php'>Settings and options</a>) to configure your e-mail settings. See the <a href='http://wordpress.org/extend/plugins/postie/other_notes'>Readme</a> for usage. Visit the <a href='http://wordpress.org/support/plugin/postie'>postie forum</a> for support.
7
+ Version: 1.4.9
8
  Author: Wayne Allen
9
  Author URI: http://allens-home.com/
10
  License: GPL2
27
  */
28
 
29
  /*
30
+ $Id: postie.php 636795 2012-12-10 22:00:12Z WayneAllen $
31
  * -= Requests Pending =-
32
  * German Umlats don't work
33
  * Problems under PHP5
postieIMAP.php CHANGED
@@ -109,16 +109,12 @@ class PostieIMAP {
109
  * @return string
110
  */
111
  function fetchEmail($index) {
112
- if ($index < 1 || $index > ($this->getNumberOfMessages() + 1)) {
113
- die("Invalid IMAP/POP3 message index!");
114
- }
115
  $header_info = imap_headerinfo($this->_connection, $index);
116
- // if (IsDebugMode()) {
117
- // $header = imap_fetchheader($this->_connection, $index);
118
- // $body = imap_body($this->_connection, $index);
119
- // return $header . $body;
120
- // } else {
121
- if ($header_info->Recent == 'N' || $header_info->Unseen == 'U') {
122
  $email = imap_fetchheader($this->_connection, $index);
123
  $email .= imap_body($this->_connection, $index);
124
 
@@ -126,7 +122,6 @@ class PostieIMAP {
126
  } else {
127
  return 'already read';
128
  }
129
- //}
130
  }
131
 
132
  /**
109
  * @return string
110
  */
111
  function fetchEmail($index) {
112
+ // if ($index < 1 || $index > ($this->getNumberOfMessages() + 1)) {
113
+ // die("Invalid IMAP/POP3 message index!");
114
+ // }
115
  $header_info = imap_headerinfo($this->_connection, $index);
116
+
117
+ if (IsDebugMode() || $header_info->Recent == 'N' || $header_info->Unseen == 'U') {
 
 
 
 
118
  $email = imap_fetchheader($this->_connection, $index);
119
  $email .= imap_body($this->_connection, $index);
120
 
122
  } else {
123
  return 'already read';
124
  }
 
125
  }
126
 
127
  /**
readme.txt CHANGED
@@ -6,7 +6,7 @@ Plugin URI: http://PostiePlugin.com/
6
  Tags: e-mail, email
7
  Requires at least: 3.0
8
  Tested up to: 3.4.2
9
- Stable tag: 1.4.8
10
  License: GPLv2 or later
11
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
 
@@ -359,6 +359,13 @@ It is also possible to turn the WordPress cron off. Please make sure something l
359
 
360
  == CHANGELOG ==
361
 
 
 
 
 
 
 
 
362
  = 1.4.8 (2012.12.09) =
363
  * fix collisions with simple_html_dom
364
  * fix bug when trying to get file name from MIME part
6
  Tags: e-mail, email
7
  Requires at least: 3.0
8
  Tested up to: 3.4.2
9
+ Stable tag: 1.4.9
10
  License: GPLv2 or later
11
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
 
359
 
360
  == CHANGELOG ==
361
 
362
+ = 1.4.9 (2012.12.10) =
363
+ * Fixed bug where date, author, etc didn't get set.
364
+ * Fixed bug where Postie was treating attached images as strings
365
+ * Fixed bug where inline images were not being attached correctly
366
+ * Fixed bug where the subject was not being decoded correctly if the charset was different from the system charset
367
+ * Fixed bug where base64 strings were being double decoded.
368
+
369
  = 1.4.8 (2012.12.09) =
370
  * fix collisions with simple_html_dom
371
  * fix bug when trying to get file name from MIME part