Add explicit saveDelayedErrors() member function
[squirrelmail.git] / class / mime / Rfc822Header.class.php
CommitLineData
19d470aa 1<?php
2
3/**
4 * Rfc822Header.class.php
5 *
0f459286 6 * This file contains functions needed to handle headers in mime messages.
19d470aa 7 *
47ccfad4 8 * @copyright &copy; 2003-2006 The SquirrelMail Project Team
4b4abf93 9 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
883d9cd3 10 * @version $Id$
2b646597 11 * @package squirrelmail
0f459286 12 * @subpackage mime
13 * @since 1.3.2
19d470aa 14 */
15
2b646597 16/**
0f459286 17 * MIME header class
19d470aa 18 * input: header_string or array
0f459286 19 * You must call parseHeader() function after creating object in order to fill object's
20 * parameters.
21 * @todo FIXME: there is no constructor function and class should ignore all input args.
2b646597 22 * @package squirrelmail
0f459286 23 * @subpackage mime
24 * @since 1.3.0
19d470aa 25 */
26class Rfc822Header {
9ed80157 27 /**
28 * Date header
29 * @var mixed
30 */
31 var $date = -1;
32 /**
33 * Subject header
34 * @var string
35 */
36 var $subject = '';
37 /**
38 * From header
39 * @var array
40 */
41 var $from = array();
42 /**
43 * @var mixed
44 */
45 var $sender = '';
46 /**
47 * Reply-To header
48 * @var array
49 */
50 var $reply_to = array();
51 /**
52 * Mail-Followup-To header
53 * @var array
54 */
55 var $mail_followup_to = array();
56 /**
57 * To header
58 * @var array
59 */
60 var $to = array();
61 /**
62 * Cc header
63 * @var array
64 */
65 var $cc = array();
66 /**
67 * Bcc header
68 * @var array
69 */
70 var $bcc = array();
71 /**
72 * In-reply-to header
73 * @var string
74 */
75 var $in_reply_to = '';
76 /**
77 * Message-ID header
78 * @var string
79 */
80 var $message_id = '';
81 /**
82 * References header
83 * @var string
84 */
85 var $references = '';
86 /**
87 * @var mixed
88 */
89 var $mime = false;
90 /**
ae1c6dbe 91 * Content Type object
92 * @var object
9ed80157 93 */
94 var $content_type = '';
95 /**
96 * @var mixed
97 */
98 var $disposition = '';
99 /**
100 * X-Mailer header
101 * @var string
102 */
103 var $xmailer = '';
104 /**
105 * Priority header
106 * @var integer
107 */
108 var $priority = 3;
109 /**
110 * @var mixed
111 */
112 var $dnt = '';
113 /**
114 * @var mixed
115 */
116 var $encoding = '';
117 /**
118 * @var mixed
119 */
120 var $content_id = '';
121 /**
122 * @var mixed
123 */
124 var $content_desc = '';
125 /**
126 * @var mixed
127 */
128 var $mlist = array();
129 /**
130 * Extra header
131 * only needed for constructing headers in delivery class
132 * @var array
133 */
134 var $more_headers = array();
135
0f459286 136 /**
137 * @param mixed $hdr string or array with message headers
138 */
19d470aa 139 function parseHeader($hdr) {
140 if (is_array($hdr)) {
141 $hdr = implode('', $hdr);
142 }
2a9b0fad 143 /* First we replace \r\n by \n and unfold the header */
0f459286 144 /* FIXME: unfolding header with multiple spaces "\n( +)" */
2a9b0fad 145 $hdr = trim(str_replace(array("\r\n", "\n\t", "\n "),array("\n", ' ', ' '), $hdr));
19d470aa 146
147 /* Now we can make a new header array with */
148 /* each element representing a headerline */
2a9b0fad 149 $hdr = explode("\n" , $hdr);
19d470aa 150 foreach ($hdr as $line) {
151 $pos = strpos($line, ':');
152 if ($pos > 0) {
153 $field = substr($line, 0, $pos);
340d67c2 154 if (!strstr($field,' ')) { /* valid field */
155 $value = trim(substr($line, $pos+1));
156 $this->parseField($field, $value);
157 }
19d470aa 158 }
159 }
ae1c6dbe 160 if (!is_object($this->content_type)) {
19d470aa 161 $this->parseContentType('text/plain; charset=us-ascii');
162 }
163 }
164
0f459286 165 /**
166 * @param string $value
167 * @return string
168 */
19d470aa 169 function stripComments($value) {
170 $result = '';
19d470aa 171 $cnt = strlen($value);
172 for ($i = 0; $i < $cnt; ++$i) {
173 switch ($value{$i}) {
174 case '"':
175 $result .= '"';
176 while ((++$i < $cnt) && ($value{$i} != '"')) {
177 if ($value{$i} == '\\') {
178 $result .= '\\';
179 ++$i;
180 }
181 $result .= $value{$i};
182 }
bf489229 183 if($i < $cnt) {
184 $result .= $value{$i};
185 }
19d470aa 186 break;
187 case '(':
188 $depth = 1;
189 while (($depth > 0) && (++$i < $cnt)) {
190 switch($value{$i}) {
191 case '\\':
192 ++$i;
193 break;
194 case '(':
195 ++$depth;
196 break;
197 case ')':
198 --$depth;
199 break;
200 default:
201 break;
202 }
203 }
204 break;
205 default:
206 $result .= $value{$i};
207 break;
208 }
209 }
210 return $result;
211 }
212
0f459286 213 /**
214 * Parse header field according to field type
215 * @param string $field field name
216 * @param string $value field value
217 */
19d470aa 218 function parseField($field, $value) {
219 $field = strtolower($field);
220 switch($field) {
221 case 'date':
340d67c2 222 $value = $this->stripComments($value);
19d470aa 223 $d = strtr($value, array(' ' => ' '));
224 $d = explode(' ', $d);
225 $this->date = getTimeStamp($d);
226 break;
227 case 'subject':
228 $this->subject = $value;
229 break;
230 case 'from':
231 $this->from = $this->parseAddress($value,true);
232 break;
233 case 'sender':
234 $this->sender = $this->parseAddress($value);
235 break;
236 case 'reply-to':
237 $this->reply_to = $this->parseAddress($value, true);
238 break;
b268e66b 239 case 'mail-followup-to':
240 $this->mail_followup_to = $this->parseAddress($value, true);
241 break;
19d470aa 242 case 'to':
243 $this->to = $this->parseAddress($value, true);
244 break;
245 case 'cc':
246 $this->cc = $this->parseAddress($value, true);
247 break;
248 case 'bcc':
249 $this->bcc = $this->parseAddress($value, true);
250 break;
251 case 'in-reply-to':
252 $this->in_reply_to = $value;
253 break;
254 case 'message-id':
340d67c2 255 $value = $this->stripComments($value);
19d470aa 256 $this->message_id = $value;
257 break;
340d67c2 258 case 'references':
259 $value = $this->stripComments($value);
260 $this->references = $value;
261 break;
262 case 'x-confirm-reading-to':
263 case 'return-receipt-to':
19d470aa 264 case 'disposition-notification-to':
340d67c2 265 $value = $this->stripComments($value);
19d470aa 266 $this->dnt = $this->parseAddress($value);
267 break;
268 case 'mime-version':
340d67c2 269 $value = $this->stripComments($value);
19d470aa 270 $value = str_replace(' ', '', $value);
271 $this->mime = ($value == '1.0' ? true : $this->mime);
272 break;
273 case 'content-type':
340d67c2 274 $value = $this->stripComments($value);
19d470aa 275 $this->parseContentType($value);
276 break;
277 case 'content-disposition':
340d67c2 278 $value = $this->stripComments($value);
19d470aa 279 $this->parseDisposition($value);
280 break;
cfebb724 281 case 'content-transfer-encoding':
282 $this->encoding = $value;
283 break;
284 case 'content-description':
285 $this->content_desc = $value;
286 break;
287 case 'content-id':
288 $value = $this->stripComments($value);
289 $this->content_id = $value;
290 break;
19d470aa 291 case 'user-agent':
292 case 'x-mailer':
340d67c2 293 $this->xmailer = $value;
19d470aa 294 break;
295 case 'x-priority':
bddb3448 296 case 'importance':
297 case 'priority':
298 $this->priority = $this->parsePriority($value);
19d470aa 299 break;
300 case 'list-post':
340d67c2 301 $value = $this->stripComments($value);
19d470aa 302 $this->mlist('post', $value);
303 break;
304 case 'list-reply':
cfebb724 305 $value = $this->stripComments($value);
19d470aa 306 $this->mlist('reply', $value);
307 break;
308 case 'list-subscribe':
cfebb724 309 $value = $this->stripComments($value);
19d470aa 310 $this->mlist('subscribe', $value);
311 break;
312 case 'list-unsubscribe':
340d67c2 313 $value = $this->stripComments($value);
19d470aa 314 $this->mlist('unsubscribe', $value);
315 break;
316 case 'list-archive':
340d67c2 317 $value = $this->stripComments($value);
19d470aa 318 $this->mlist('archive', $value);
319 break;
320 case 'list-owner':
340d67c2 321 $value = $this->stripComments($value);
19d470aa 322 $this->mlist('owner', $value);
323 break;
324 case 'list-help':
340d67c2 325 $value = $this->stripComments($value);
19d470aa 326 $this->mlist('help', $value);
327 break;
ba4d5a32 328 case 'list-id':
329 $value = $this->stripComments($value);
330 $this->mlist('id', $value);
331 break;
19d470aa 332 default:
333 break;
334 }
335 }
14882b16 336
0f459286 337 /**
338 * @param string $address
339 * @return array
340 */
14882b16 341 function getAddressTokens($address) {
342 $aTokens = array();
14882b16 343 $aSpecials = array('(' ,'<' ,',' ,';' ,':');
344 $aReplace = array(' (',' <',' ,',' ;',' :');
345 $address = str_replace($aSpecials,$aReplace,$address);
55243181 346 $iCnt = strlen($address);
14882b16 347 $i = 0;
348 while ($i < $iCnt) {
349 $cChar = $address{$i};
350 switch($cChar)
351 {
352 case '<':
353 $iEnd = strpos($address,'>',$i+1);
354 if (!$iEnd) {
355 $sToken = substr($address,$i);
356 $i = $iCnt;
357 } else {
358 $sToken = substr($address,$i,$iEnd - $i +1);
359 $i = $iEnd;
360 }
361 $sToken = str_replace($aReplace, $aSpecials,$sToken);
cfebb724 362 if ($sToken) $aTokens[] = $sToken;
14882b16 363 break;
364 case '"':
365 $iEnd = strpos($address,$cChar,$i+1);
0b4d4be7 366 if ($iEnd) {
367 // skip escaped quotes
368 $prev_char = $address{$iEnd-1};
369 while ($prev_char === '\\' && substr($address,$iEnd-2,2) !== '\\\\') {
370 $iEnd = strpos($address,$cChar,$iEnd+1);
371 if ($iEnd) {
372 $prev_char = $address{$iEnd-1};
373 } else {
374 $prev_char = false;
375 }
376 }
377 }
14882b16 378 if (!$iEnd) {
379 $sToken = substr($address,$i);
380 $i = $iCnt;
381 } else {
382 // also remove the surrounding quotes
383 $sToken = substr($address,$i+1,$iEnd - $i -1);
384 $i = $iEnd;
385 }
386 $sToken = str_replace($aReplace, $aSpecials,$sToken);
72956ab6 387 if ($sToken) $aTokens[] = $sToken;
14882b16 388 break;
389 case '(':
0b4d4be7 390 array_pop($aTokens); //remove inserted space
14882b16 391 $iEnd = strpos($address,')',$i);
392 if (!$iEnd) {
393 $sToken = substr($address,$i);
394 $i = $iCnt;
395 } else {
55243181 396 $iDepth = 1;
397 $iComment = $i;
398 while (($iDepth > 0) && (++$iComment < $iCnt)) {
399 $cCharComment = $address{$iComment};
400 switch($cCharComment) {
401 case '\\':
402 ++$iComment;
403 break;
404 case '(':
405 ++$iDepth;
406 break;
407 case ')':
408 --$iDepth;
409 break;
410 default:
411 break;
412 }
413 }
414 if ($iDepth == 0) {
415 $sToken = substr($address,$i,$iComment - $i +1);
416 $i = $iComment;
417 } else {
418 $sToken = substr($address,$i,$iEnd - $i + 1);
419 $i = $iEnd;
420 }
14882b16 421 }
0b4d4be7 422 // check the next token in case comments appear in the middle of email addresses
423 $prevToken = end($aTokens);
424 if (!in_array($prevToken,$aSpecials,true)) {
43c0e295 425 if ($i+1<strlen($address) && !in_array($address{$i+1},$aSpecials,true)) {
0b4d4be7 426 $iEnd = strpos($address,' ',$i+1);
427 if ($iEnd) {
428 $sNextToken = trim(substr($address,$i+1,$iEnd - $i -1));
429 $i = $iEnd-1;
430 } else {
a5ae4bc8 431 $sNextToken = trim(substr($address,$i+1));
0b4d4be7 432 $i = $iCnt;
433 }
434 // remove the token
435 array_pop($aTokens);
436 // create token and add it again
437 $sNewToken = $prevToken . $sNextToken;
1f0269d6 438 if($sNewToken) $aTokens[] = $sNewToken;
0b4d4be7 439 }
440 }
14882b16 441 $sToken = str_replace($aReplace, $aSpecials,$sToken);
cfebb724 442 if ($sToken) $aTokens[] = $sToken;
14882b16 443 break;
444 case ',':
0b4d4be7 445 case ':':
14882b16 446 case ';':
447 case ' ':
448 $aTokens[] = $cChar;
449 break;
450 default:
451 $iEnd = strpos($address,' ',$i+1);
452 if ($iEnd) {
453 $sToken = trim(substr($address,$i,$iEnd - $i));
454 $i = $iEnd-1;
455 } else {
456 $sToken = trim(substr($address,$i));
457 $i = $iCnt;
458 }
459 if ($sToken) $aTokens[] = $sToken;
460 }
461 ++$i;
462 }
463 return $aTokens;
464 }
0f459286 465
466 /**
467 * @param array $aStack
468 * @param array $aComment
469 * @param string $sEmail
470 * @param string $sGroup
471 * @return object AddressStructure object
472 */
14882b16 473 function createAddressObject(&$aStack,&$aComment,&$sEmail,$sGroup='') {
0b4d4be7 474 //$aStack=explode(' ',implode('',$aStack));
14882b16 475 if (!$sEmail) {
476 while (count($aStack) && !$sEmail) {
477 $sEmail = trim(array_pop($aStack));
478 }
479 }
480 if (count($aStack)) {
481 $sPersonal = trim(implode('',$aStack));
cfebb724 482 } else {
14882b16 483 $sPersonal = '';
484 }
485 if (!$sPersonal && count($aComment)) {
486 $sComment = trim(implode(' ',$aComment));
487 $sPersonal .= $sComment;
488 }
489 $oAddr =& new AddressStructure();
490 if ($sPersonal && substr($sPersonal,0,2) == '=?') {
491 $oAddr->personal = encodeHeader($sPersonal);
492 } else {
493 $oAddr->personal = $sPersonal;
494 }
0b4d4be7 495 // $oAddr->group = $sGroup;
14882b16 496 $iPosAt = strpos($sEmail,'@');
497 if ($iPosAt) {
498 $oAddr->mailbox = substr($sEmail, 0, $iPosAt);
499 $oAddr->host = substr($sEmail, $iPosAt+1);
500 } else {
501 $oAddr->mailbox = $sEmail;
502 $oAddr->host = false;
503 }
14882b16 504 $sEmail = '';
505 $aStack = $aComment = array();
506 return $oAddr;
507 }
508
0f459286 509 /**
510 * recursive function for parsing address strings and storing them in an address stucture object.
340d67c2 511 * personal name: encoded: =?charset?Q|B?string?=
512 * quoted: "string"
513 * normal: string
514 * email : <mailbox@host>
515 * : mailbox@host
516 * This function is also used for validating addresses returned from compose
14882b16 517 * That's also the reason that the function became a little bit huge
0f459286 518 * @param string $address
519 * @param boolean $ar return array instead of only the first element
520 * @param array $addr_ar (obsolete) array with parsed addresses
521 * @param string $group (obsolete)
522 * @param string $host default domainname in case of addresses without a domainname
523 * @param string $lookup (since) callback function for lookup of address strings which are probably nicks (without @)
524 * @return mixed array with AddressStructure objects or only one address_structure object.
e74ba378 525 */
14882b16 526 function parseAddress($address,$ar=false,$aAddress=array(),$sGroup='',$sHost='',$lookup=false) {
527 $aTokens = $this->getAddressTokens($address);
8d8da447 528 $sPersonal = $sEmail = $sGroup = '';
14882b16 529 $aStack = $aComment = array();
530 foreach ($aTokens as $sToken) {
531 $cChar = $sToken{0};
532 switch ($cChar)
340d67c2 533 {
534 case '=':
14882b16 535 case '"':
536 case ' ':
cfebb724 537 $aStack[] = $sToken;
340d67c2 538 break;
14882b16 539 case '(':
540 $aComment[] = substr($sToken,1,-1);
340d67c2 541 break;
3fcadedb 542 case ';':
14882b16 543 if ($sGroup) {
29f842a4 544 $aAddress[] = $this->createAddressObject($aStack,$aComment,$sEmail,$sGroup);
14882b16 545 $oAddr = end($aAddress);
0b4d4be7 546 if(!$oAddr || ((isset($oAddr)) && !$oAddr->mailbox && !$oAddr->personal)) {
547 $sEmail = $sGroup . ':;';
cfebb724 548 }
0b4d4be7 549 $aAddress[] = $this->createAddressObject($aStack,$aComment,$sEmail,$sGroup);
14882b16 550 $sGroup = '';
551 $aStack = $aComment = array();
552 break;
340d67c2 553 }
14882b16 554 case ',':
555 $aAddress[] = $this->createAddressObject($aStack,$aComment,$sEmail,$sGroup);
556 break;
cfebb724 557 case ':':
29f842a4 558 $sGroup = trim(implode(' ',$aStack));
0b4d4be7 559 $sGroup = preg_replace('/\s+/',' ',$sGroup);
14882b16 560 $aStack = array();
561 break;
562 case '<':
563 $sEmail = trim(substr($sToken,1,-1));
564 break;
565 case '>':
566 /* skip */
cfebb724 567 break;
14882b16 568 default: $aStack[] = $sToken; break;
19d470aa 569 }
570 }
14882b16 571 /* now do the action again for the last address */
572 $aAddress[] = $this->createAddressObject($aStack,$aComment,$sEmail);
573 /* try to lookup the addresses in case of invalid email addresses */
574 $aProcessedAddress = array();
575 foreach ($aAddress as $oAddr) {
576 $aAddrBookAddress = array();
577 if (!$oAddr->host) {
578 $grouplookup = false;
340d67c2 579 if ($lookup) {
14882b16 580 $aAddr = call_user_func_array($lookup,array($oAddr->mailbox));
581 if (isset($aAddr['email'])) {
582 if (strpos($aAddr['email'],',')) {
583 $grouplookup = true;
584 $aAddrBookAddress = $this->parseAddress($aAddr['email'],true);
585 } else {
586 $iPosAt = strpos($aAddr['email'], '@');
587 $oAddr->mailbox = substr($aAddr['email'], 0, $iPosAt);
588 $oAddr->host = substr($aAddr['email'], $iPosAt+1);
589 if (isset($aAddr['name'])) {
590 $oAddr->personal = $aAddr['name'];
591 } else {
592 $oAddr->personal = encodeHeader($sPersonal);
593 }
594 }
595 }
340d67c2 596 }
14882b16 597 if (!$grouplookup && !$oAddr->mailbox) {
598 $oAddr->mailbox = trim($sEmail);
599 if ($sHost && $oAddr->mailbox) {
600 $oAddr->host = $sHost;
340d67c2 601 }
8b53b4ba 602 } else if (!$grouplookup && !$oAddr->host) {
603 if ($sHost && $oAddr->mailbox) {
604 $oAddr->host = $sHost;
605 }
cfebb724 606 }
14882b16 607 }
608 if (!$aAddrBookAddress && $oAddr->mailbox) {
609 $aProcessedAddress[] = $oAddr;
610 } else {
cfebb724 611 $aProcessedAddress = array_merge($aProcessedAddress,$aAddrBookAddress);
14882b16 612 }
340d67c2 613 }
cfebb724 614 if ($ar) {
14882b16 615 return $aProcessedAddress;
19d470aa 616 } else {
14882b16 617 return $aProcessedAddress[0];
19d470aa 618 }
cfebb724 619 }
19d470aa 620
bddb3448 621 /**
622 * Normalise the different Priority headers into a uniform value,
623 * namely that of the X-Priority header (1, 3, 5). Supports:
0f459286 624 * Priority, X-Priority, Importance.
bddb3448 625 * X-MS-Mail-Priority is not parsed because it always coincides
626 * with one of the other headers.
627 *
628 * NOTE: this is actually a duplicate from the function in
629 * functions/imap_messages. I'm not sure if it's ok here to call
630 * that function?
ba17b6c7 631 * @param string $sValue literal priority name
0f459286 632 * @return integer
bddb3448 633 */
ba17b6c7 634 function parsePriority($sValue) {
635 // don't use function call inside array_shift.
636 $aValue = split('/\w/',trim($sValue));
637 $value = strtolower(array_shift($aValue));
638
bddb3448 639 if ( is_numeric($value) ) {
640 return $value;
641 }
642 if ( $value == 'urgent' || $value == 'high' ) {
643 return 1;
644 } elseif ( $value == 'non-urgent' || $value == 'low' ) {
645 return 5;
646 }
647 // default is normal priority
648 return 3;
649 }
650
0f459286 651 /**
652 * @param string $value content type header
653 */
19d470aa 654 function parseContentType($value) {
655 $pos = strpos($value, ';');
656 $props = '';
657 if ($pos > 0) {
658 $type = trim(substr($value, 0, $pos));
38d6fba7 659 $props = trim(substr($value, $pos+1));
19d470aa 660 } else {
661 $type = $value;
662 }
663 $content_type = new ContentType($type);
664 if ($props) {
665 $properties = $this->parseProperties($props);
666 if (!isset($properties['charset'])) {
667 $properties['charset'] = 'us-ascii';
668 }
669 $content_type->properties = $this->parseProperties($props);
670 }
671 $this->content_type = $content_type;
672 }
cfebb724 673
0f459286 674 /**
675 * RFC2184
676 * @param array $aParameters
677 * @return array
678 */
cfebb724 679 function processParameters($aParameters) {
2ddf00ae 680 $aResults = array();
cfebb724 681 $aCharset = array();
682 // handle multiline parameters
2ddf00ae 683 foreach($aParameters as $key => $value) {
cfebb724 684 if ($iPos = strpos($key,'*')) {
685 $sKey = substr($key,0,$iPos);
686 if (!isset($aResults[$sKey])) {
687 $aResults[$sKey] = $value;
688 if (substr($key,-1) == '*') { // parameter contains language/charset info
689 $aCharset[] = $sKey;
690 }
691 } else {
692 $aResults[$sKey] .= $value;
693 }
694 } else {
695 $aResults[$key] = $value;
696 }
697 }
698 foreach ($aCharset as $key) {
699 $value = $aResults[$key];
700 // extract the charset & language
701 $charset = substr($value,0,strpos($value,"'"));
702 $value = substr($value,strlen($charset)+1);
703 $language = substr($value,0,strpos($value,"'"));
704 $value = substr($value,strlen($charset)+1);
0f459286 705 /* FIXME: What's the status of charset decode with language information ????
706 * Maybe language information contains only ascii text and charset_decode()
707 * only runs htmlspecialchars() on it. If it contains 8bit information, you
708 * get html encoded text in charset used by selected translation.
709 */
cfebb724 710 $value = charset_decode($charset,$value);
711 $aResults[$key] = $value;
2ddf00ae 712 }
cfebb724 713 return $aResults;
2ddf00ae 714 }
19d470aa 715
0f459286 716 /**
717 * @param string $value
718 * @return array
719 */
19d470aa 720 function parseProperties($value) {
721 $propArray = explode(';', $value);
722 $propResultArray = array();
723 foreach ($propArray as $prop) {
724 $prop = trim($prop);
725 $pos = strpos($prop, '=');
726 if ($pos > 0) {
727 $key = trim(substr($prop, 0, $pos));
728 $val = trim(substr($prop, $pos+1));
bbb92b4c 729 if (strlen($val) > 0 && $val{0} == '"') {
19d470aa 730 $val = substr($val, 1, -1);
731 }
732 $propResultArray[$key] = $val;
733 }
734 }
2ddf00ae 735 return $this->processParameters($propResultArray);
19d470aa 736 }
737
0f459286 738 /**
739 * Fills disposition object in rfc822Header object
740 * @param string $value
741 */
19d470aa 742 function parseDisposition($value) {
743 $pos = strpos($value, ';');
744 $props = '';
745 if ($pos > 0) {
746 $name = trim(substr($value, 0, $pos));
fc9269ec 747 $props = trim(substr($value, $pos+1));
19d470aa 748 } else {
749 $name = $value;
750 }
751 $props_a = $this->parseProperties($props);
752 $disp = new Disposition($name);
753 $disp->properties = $props_a;
754 $this->disposition = $disp;
755 }
756
0f459286 757 /**
758 * Fills mlist array keys in rfc822Header object
759 * @param string $field
760 * @param string $value
761 */
19d470aa 762 function mlist($field, $value) {
763 $res_a = array();
764 $value_a = explode(',', $value);
765 foreach ($value_a as $val) {
766 $val = trim($val);
767 if ($val{0} == '<') {
768 $val = substr($val, 1, -1);
769 }
770 if (substr($val, 0, 7) == 'mailto:') {
771 $res_a['mailto'] = substr($val, 7);
772 } else {
773 $res_a['href'] = $val;
774 }
775 }
776 $this->mlist[$field] = $res_a;
777 }
778
0f459286 779 /**
780 * function to get the address strings out of the header.
19d470aa 781 * example1: header->getAddr_s('to').
782 * example2: header->getAddr_s(array('to', 'cc', 'bcc'))
0f459286 783 * @param mixed $arr string or array of strings
784 * @param string $separator
785 * @param boolean $encoded (since 1.4.0) return encoded or plain text addresses
786 * @return string
19d470aa 787 */
2c9ecd11 788 function getAddr_s($arr, $separator = ',',$encoded=false) {
19d470aa 789 $s = '';
790
791 if (is_array($arr)) {
792 foreach($arr as $arg) {
2c9ecd11 793 if ($this->getAddr_s($arg, $separator, $encoded)) {
8d8da447 794 $s .= $separator;
19d470aa 795 }
796 }
797 $s = ($s ? substr($s, 2) : $s);
798 } else {
2c9ecd11 799 $addr = $this->{$arr};
19d470aa 800 if (is_array($addr)) {
801 foreach ($addr as $addr_o) {
802 if (is_object($addr_o)) {
2c9ecd11 803 if ($encoded) {
804 $s .= $addr_o->getEncodedAddress() . $separator;
805 } else {
806 $s .= $addr_o->getAddress() . $separator;
807 }
19d470aa 808 }
809 }
810 $s = substr($s, 0, -strlen($separator));
811 } else {
812 if (is_object($addr)) {
2c9ecd11 813 if ($encoded) {
814 $s .= $addr->getEncodedAddress();
815 } else {
816 $s .= $addr->getAddress();
817 }
19d470aa 818 }
819 }
820 }
821 return $s;
822 }
823
0f459286 824 /**
825 * function to get the array of addresses out of the header.
826 * @param mixed $arg string or array of strings
827 * @param array $excl_arr array of excluded email addresses
828 * @param array $arr array of added email addresses
829 * @return array
830 */
19d470aa 831 function getAddr_a($arg, $excl_arr = array(), $arr = array()) {
832 if (is_array($arg)) {
833 foreach($arg as $argument) {
834 $arr = $this->getAddr_a($argument, $excl_arr, $arr);
835 }
836 } else {
340d67c2 837 $addr = $this->{$arg};
19d470aa 838 if (is_array($addr)) {
839 foreach ($addr as $next_addr) {
840 if (is_object($next_addr)) {
841 if (isset($next_addr->host) && ($next_addr->host != '')) {
842 $email = $next_addr->mailbox . '@' . $next_addr->host;
843 } else {
844 $email = $next_addr->mailbox;
845 }
846 $email = strtolower($email);
847 if ($email && !isset($arr[$email]) && !isset($excl_arr[$email])) {
848 $arr[$email] = $next_addr->personal;
849 }
850 }
851 }
852 } else {
853 if (is_object($addr)) {
854 $email = $addr->mailbox;
855 $email .= (isset($addr->host) ? '@' . $addr->host : '');
856 $email = strtolower($email);
857 if ($email && !isset($arr[$email]) && !isset($excl_arr[$email])) {
858 $arr[$email] = $addr->personal;
859 }
860 }
861 }
862 }
863 return $arr;
864 }
cfebb724 865
0f459286 866 /**
867 * @param mixed $address array or string
868 * @param boolean $recurs
869 * @return mixed array, boolean
870 * @since 1.3.2
871 */
d0719411 872 function findAddress($address, $recurs = false) {
340d67c2 873 $result = false;
d0719411 874 if (is_array($address)) {
340d67c2 875 $i=0;
d0719411 876 foreach($address as $argument) {
877 $match = $this->findAddress($argument, true);
340d67c2 878 if ($match[1]) {
879 return $i;
880 } else {
881 if (count($match[0]) && !$result) {
882 $result = $i;
883 }
884 }
cfebb724 885 ++$i;
340d67c2 886 }
887 } else {
888 if (!is_array($this->cc)) $this->cc = array();
889 $srch_addr = $this->parseAddress($address);
890 $results = array();
891 foreach ($this->to as $to) {
892 if ($to->host == $srch_addr->host) {
893 if ($to->mailbox == $srch_addr->mailbox) {
894 $results[] = $srch_addr;
895 if ($to->personal == $srch_addr->personal) {
896 if ($recurs) {
897 return array($results, true);
898 } else {
899 return true;
900 }
901 }
902 }
903 }
d0719411 904 }
0f459286 905 foreach ($this->cc as $cc) {
340d67c2 906 if ($cc->host == $srch_addr->host) {
907 if ($cc->mailbox == $srch_addr->mailbox) {
908 $results[] = $srch_addr;
909 if ($cc->personal == $srch_addr->personal) {
910 if ($recurs) {
911 return array($results, true);
912 } else {
913 return true;
914 }
915 }
916 }
917 }
918 }
919 if ($recurs) {
920 return array($results, false);
921 } elseif (count($result)) {
922 return true;
923 } else {
924 return false;
cfebb724 925 }
340d67c2 926 }
1465f80c 927 //exit;
340d67c2 928 return $result;
d0719411 929 }
19d470aa 930
0f459286 931 /**
932 * @param string $type0 media type
933 * @param string $type1 media subtype
934 * @return array media properties
935 * @todo check use of media type arguments
936 */
19d470aa 937 function getContentType($type0, $type1) {
938 $type0 = $this->content_type->type0;
939 $type1 = $this->content_type->type1;
940 return $this->content_type->properties;
941 }
942}