mime.class.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. <?php
  2. /**
  3. * mime.class
  4. *
  5. * Copyright (c) 2002 The SquirrelMail Project Team
  6. * Licensed under the GNU GPL. For full terms see the file COPYING.
  7. *
  8. *
  9. * This contains functions needed to handle mime messages.
  10. *
  11. * $Id$
  12. */
  13. class msg_header {
  14. /** msg_header contains generic variables for values that **/
  15. /** could be in a header. **/
  16. var $type0 = '', $type1 = '', $boundary = '', $charset = '',
  17. $encoding='', $size = 0, $to = array(), $from = '', $date = '',
  18. $cc = array(), $bcc = array(), $reply_to = '', $subject = '',
  19. $id = 0, $mailbox = '', $description = '', $filename = '',
  20. $entity_id = 0, $message_id = 0, $name = '', $priority = 3, $type = '',
  21. $disposition = '', $md5='', $language='',$dnt = '', $xmailer = '';
  22. /*
  23. * returns addres_list of supplied argument
  24. * arguments: array('to', 'from', ...) or just a string like 'to'.
  25. * result: string: address1, addres2, ....
  26. */
  27. function setVar($var, $value) {
  28. $this->{$var} = $value;
  29. }
  30. /*
  31. * function to get the addres strings out of the header.
  32. * Arguments: string or array of strings !
  33. * example1: header->getAddr_s('to').
  34. * example2: header->getAddr_s(array('to','cc','bcc'))
  35. */
  36. function getAddr_s($arr) {
  37. if (is_array($arr)) {
  38. $s = '';
  39. foreach($arr as $arg ) {
  40. $result = $this->getAddr_s($arg);
  41. if ($result) {
  42. $s .= ', ' . $result;
  43. }
  44. }
  45. if ($s) $s = substr($s,2);
  46. return $s;
  47. } else {
  48. $s = '';
  49. eval('$addr = $this->'.$arr.';') ;
  50. if (is_array($addr)) {
  51. foreach ($addr as $addr_o) {
  52. if (is_object($addr_o)) {
  53. $s .= $addr_o->getAddress() . ', ';
  54. }
  55. }
  56. $s = substr($s,0,-2);
  57. } else {
  58. if (is_object($addr)) {
  59. $s .= $addr->getAddress();
  60. }
  61. }
  62. return $s;
  63. }
  64. }
  65. function getAddr_a($arg, $excl_arr=array(), $arr = array()) {
  66. if (is_array($arg)) {
  67. foreach($arg as $argument ) {
  68. $arr = $this->getAddr_a($argument, $excl_arr, $arr);
  69. }
  70. return $arr;
  71. } else {
  72. eval('$addr = $this->'.$arg.';') ;
  73. if (is_array($addr)) {
  74. foreach ($addr as $addr_o) {
  75. if (is_object($addr_o)) {
  76. if (isset($addr_o->host) && $addr_o->host !='') {
  77. $email = $addr_o->mailbox.'@'.$addr_o->host;
  78. } else {
  79. $email = $addr_o->mailbox;
  80. }
  81. $email = strtolower($email);
  82. if ($email && !isset($arr[$email]) && !isset($excl_arr[$email])) {
  83. $arr[$email] = $addr_o->personal;
  84. }
  85. }
  86. }
  87. } else {
  88. if (is_object($addr)) {
  89. if (isset($addr->host)) {
  90. $email = $addr->mailbox.'@'.$addr->host;
  91. } else {
  92. $email = $addr->mailbox;
  93. }
  94. $email = strtolower($email);
  95. if ($email && !isset($arr[$email]) && !isset($excl_arr[$email])) {
  96. $arr[$email] = $addr->personal;
  97. }
  98. }
  99. }
  100. return $arr;
  101. }
  102. }
  103. }
  104. class address_structure {
  105. var $personal = '', $adl = '', $mailbox = '', $host = '', $group = '';
  106. function getAddress($full=true) {
  107. if (is_object($this)) {
  108. if (isset($this->host) && $this->host !='') {
  109. $email = '<'.$this->mailbox.'@'.$this->host.'>';
  110. } else {
  111. $email = $this->mailbox;
  112. }
  113. if (trim($this->personal) !='') {
  114. if ($email) {
  115. $addr = '"' . $this->personal . '" ' .$email;
  116. } else {
  117. $addr = $this->personal;
  118. }
  119. $best_dpl = $this->personal;
  120. } else {
  121. $addr = $email;
  122. $best_dpl = $email;
  123. }
  124. if ($full) {
  125. return $addr;
  126. } else {
  127. return $best_dpl;
  128. }
  129. } else return '';
  130. }
  131. }
  132. class message {
  133. /** message is the object that contains messages. It is a recursive
  134. object in that through the $entities variable, it can contain
  135. more objects of type message. See documentation in mime.txt for
  136. a better description of how this works.
  137. **/
  138. var $header = '', $entities = array(), $mailbox = 'INBOX', $id = 0,
  139. $envelope = '', $parent_ent, $entity, $type0='', $type1='',
  140. $parent = '', $decoded_body='',
  141. $is_seen = 0, $is_answered = 0, $is_deleted = 0, $is_flagged = 0,
  142. $is_mdnsent = 0;
  143. function setEnt($ent) {
  144. $this->entity_id= $ent;
  145. }
  146. function setBody($body) {
  147. $this->decoded_body = $body;
  148. }
  149. function addEntity ($msg) {
  150. $msg->parent = &$this;
  151. $this->entities[] = $msg;
  152. }
  153. function addRFC822Header($read) {
  154. $header = new msg_header();
  155. $this->header = sqimap_parse_RFC822Header($read,$header);
  156. }
  157. function getEntity($ent) {
  158. $cur_ent = $this->entity_id;
  159. $msg = $this;
  160. if ($cur_ent == '' || $cur_ent == '0') {
  161. $cur_ent_a = array();
  162. } else {
  163. $cur_ent_a = explode('.',$this->entity_id);
  164. }
  165. $ent_a = explode('.',$ent);
  166. $cnt = count($ent_a);
  167. for ($i=0;$i<$cnt -1;$i++) {
  168. if (isset($cur_ent_a[$i]) && $cur_ent_a[$i] != $ent_a[$i]) {
  169. $msg = $msg->parent;
  170. $cur_ent_a = explode('.',$msg->entity_id);
  171. $i--;
  172. } else if (!isset($cur_ent_a[$i])) {
  173. if (isset($msg->entities[($ent_a[$i]-1)])) {
  174. $msg = $msg->entities[($ent_a[$i]-1)];
  175. } else {
  176. $msg = $msg->entities[0];
  177. }
  178. }
  179. if ($msg->type0 == 'message' && $msg->type1 == 'rfc822') {
  180. /*this is a header for a message/rfc822 entity */
  181. $msg = $msg->entities[0];
  182. }
  183. }
  184. if ($msg->type0 == 'message' && $msg->type1 == 'rfc822') {
  185. /*this is a header for a message/rfc822 entity */
  186. $msg = $msg->entities[0];
  187. }
  188. if (isset($msg->entities[($ent_a[$cnt-1])-1])) {
  189. $msg = $msg->entities[($ent_a[$cnt-1]-1)];
  190. }
  191. return $msg;
  192. }
  193. function getMailbox() {
  194. $msg = $this;
  195. while (is_object($msg->parent)) {
  196. $msg = $msg->parent;
  197. }
  198. return $msg->mailbox;
  199. }
  200. /*
  201. * Bodystructure parser, a recursive function for generating the
  202. * entity-tree with all the mime-parts.
  203. *
  204. * It follows RFC2060 and stores all the described fields in the
  205. * message object.
  206. *
  207. * Question/Bugs:
  208. *
  209. * Ask for me (Marc Groot Koerkamp, stekkel@users.sourceforge.net.
  210. *
  211. */
  212. function &parseStructure($read, $i=0, $message = false) {
  213. $arg_no = 0;
  214. $arg_a = array();
  215. $cnt = strlen($read);
  216. while ($i < $cnt) {
  217. $char = strtoupper($read{$i});
  218. switch ($char) {
  219. case '(':
  220. if ($arg_no == 0 ) {
  221. if (!isset($msg)) {
  222. $msg = new message();
  223. $hdr = new msg_header();
  224. $hdr->type0 = 'text';
  225. $hdr->type1 = 'plain';
  226. $hdr->encoding = 'us-ascii';
  227. if ($this->type0 == 'message' && $this->type1 == 'rfc822') {
  228. $msg->entity_id = $this->entity_id .'.0'; /* header of message/rfc822 */
  229. } else if (isset($this->entity_id) && $this->entity_id !='') {
  230. $ent_no = count($this->entities)+1;
  231. $par_ent = substr($this->entity_id,-2);
  232. if ($par_ent{0} == '.') {
  233. $par_ent = $par_ent{1};
  234. }
  235. if ($par_ent == '0') {
  236. $ent_no = count($this->entities)+1;
  237. if ($ent_no > 0) {
  238. $ent = substr($this->entity_id,0,strrpos($this->entity_id,'.'));
  239. if ($ent) {
  240. $ent = $ent . ".$ent_no";
  241. } else {
  242. $ent = $ent_no;
  243. }
  244. $msg->entity_id = $ent;
  245. } else {
  246. $msg->entity_id = $ent_no;
  247. }
  248. } else {
  249. $ent = $this->entity_id . ".$ent_no";
  250. $msg->entity_id = $ent;
  251. }
  252. } else {
  253. $msg->entity_id = '0';
  254. }
  255. } else {
  256. $msg->header->type0 = 'multipart';
  257. $msg->type0 = 'multipart';
  258. while ($read{$i} == '(') {
  259. $msg->addEntity($msg->parseStructure($read,&$i));
  260. }
  261. }
  262. } else {
  263. switch ($arg_no) {
  264. case 1:
  265. /* multipart properties */
  266. $i++;
  267. $arg_a[] = $this->parseProperties($read,&$i);
  268. $arg_no++;
  269. break;
  270. case 2:
  271. if (isset($msg->type0) && $msg->type0 == 'multipart') {
  272. $i++;
  273. $arg_a[]= $msg->parseDisposition($read,&$i);
  274. } else { /* properties */
  275. /* properties */
  276. $arg_a[] = $msg->parseProperties($read,&$i);
  277. }
  278. $arg_no++;
  279. break;
  280. case 3:
  281. if (isset($msg->type0) && $msg->type0 == 'multipart') {
  282. $i++;
  283. $arg_a[]= $msg->parseLanguage($read,&$i);
  284. }
  285. case 7:
  286. if ($arg_a[0] == 'message' && $arg_a[1] == 'rfc822') {
  287. $msg->header->type0 = $arg_a[0];
  288. $msg->type0 = $arg_a[0];
  289. $msg->header->type1 = $arg_a[1];
  290. $msg->type1 = $arg_a[1];
  291. $msg->parseEnvelope($read,&$i,&$hdr);
  292. $i++;
  293. while ($i < $cnt && $read{$i} != '(') {
  294. $i++;
  295. }
  296. $msg->addEntity($msg->parseStructure($read,&$i));
  297. }
  298. break;
  299. case 8:
  300. $i++;
  301. $arg_a[] = $msg->parseDisposition($read,&$i);
  302. $arg_no++;
  303. break;
  304. case 9:
  305. if ($arg_a[0] == 'text' ||
  306. ($arg_a[0] == 'message' && $arg_a[1] == 'rfc822')) {
  307. $i++;
  308. $arg_a[] = $msg->parseDisposition($read,&$i);
  309. } else {
  310. $i++;
  311. $arg_a[] = $msg->parseLanguage($read,&$i);
  312. }
  313. $arg_no++;
  314. break;
  315. case 10:
  316. if ($arg_a[0] == 'text' ||
  317. ($arg_a[0] == 'message' && $arg_a[1] == 'rfc822')) {
  318. $i++;
  319. $arg_a[] = $msg->parseLanguage($read,&$i);
  320. } else {
  321. $msg->parseParenthesis($read,&$i);
  322. $arg_a[] = ''; /* not yet desribed in rfc2060 */
  323. }
  324. $arg_no++;
  325. break;
  326. default:
  327. /* unknown argument, skip this part */
  328. $msg->parseParenthesis($read,&$i);
  329. $arg_a[] = '';
  330. $arg_no++;
  331. break;
  332. } /* switch */
  333. }
  334. break;
  335. case '"':
  336. /* inside an entity -> start processing */
  337. $debug = substr($read,$i,20);
  338. $arg_s = $msg->parseQuote($read,&$i);
  339. $arg_no++;
  340. if ($arg_no < 3) $arg_s = strtolower($arg_s); /* type0 and type1 */
  341. $arg_a[] = $arg_s;
  342. break;
  343. case 'N':
  344. /* probably NIL argument */
  345. if (strtoupper(substr($read,$i,4)) == 'NIL ' ||
  346. strtoupper(substr($read,$i,4)) == 'NIL)') {
  347. $arg_a[] = '';
  348. $arg_no++;
  349. $i = $i+2;
  350. }
  351. break;
  352. case '{':
  353. /* process the literal value */
  354. $arg_a[] = $msg->parseLiteral($read,&$i);
  355. $arg_no++;
  356. break;
  357. case (is_numeric($read{$i}) ):
  358. /* process integers */
  359. if ($read{$i} == ' ') break;
  360. $arg_s = $read{$i};;
  361. $i++;
  362. while (preg_match('/\d+/',$read{$i})) { // != ' ') {
  363. $arg_s .= $read{$i};
  364. $i++;
  365. }
  366. $arg_no++;
  367. $arg_a[] = $arg_s;
  368. break;
  369. case ')':
  370. if (isset($msg->type0) && $msg->type0 == 'multipart') {
  371. $multipart = true;
  372. } else {
  373. $multipart = false;
  374. }
  375. if (!$multipart) {
  376. if ($arg_a[0] == 'text' ||
  377. ($arg_a[0] == 'message' && $arg_a[1] == 'rfc822')) {
  378. $shifted_args = true;
  379. } else {
  380. $shifted_args = false;
  381. }
  382. $hdr->type0 = $arg_a[0];
  383. $hdr->type1 = $arg_a[1];
  384. $msg->type0 = $arg_a[0];
  385. $msg->type1 = $arg_a[1];
  386. $arr = $arg_a[2];
  387. if (is_array($arr)) {
  388. foreach($arr as $name => $value) {
  389. $hdr->{$name} = $value;
  390. }
  391. }
  392. $hdr->id = str_replace( '<', '', str_replace( '>', '', $arg_a[3] ) );
  393. $hdr->description = $arg_a[4];
  394. $hdr->encoding = strtolower($arg_a[5]);
  395. $hdr->entity_id = $msg->entity_id;
  396. $hdr->size = $arg_a[6];
  397. if ($shifted_args) {
  398. $hdr->lines = $arg_a[7];
  399. if (isset($arg_a[8])) {
  400. $hdr->md5 = $arg_a[8];
  401. }
  402. if (isset($arg_a[9])) {
  403. $hdr->disposition = $arg_a[9];
  404. }
  405. if (isset($arg_a[10])) {
  406. $hdr->language = $arg_a[10];
  407. }
  408. } else {
  409. if (isset($arg_a[7])) {
  410. $hdr->md5 = $arg_a[7];
  411. }
  412. if (isset($arg_a[8])) {
  413. $hdr->disposition = $arg_a[8];
  414. }
  415. if (isset($arg_a[9])) {
  416. $hdr->language = $arg_a[9];
  417. }
  418. }
  419. $msg->header = $hdr;
  420. $arg_no = 0;
  421. $i++;
  422. if (substr($msg->entity_id,-2) == '.0' && $msg->type0 !='multipart') {
  423. $msg->entity_id++;
  424. }
  425. return $msg;
  426. } else {
  427. $hdr->type0 = 'multipart';
  428. $hdr->type1 = $arg_a[0];
  429. $msg->type0 = 'multipart';
  430. $msg->type1 = $arg_a[0];
  431. if (isset($arg_a[1])) {
  432. $arr = $arg_a[1];
  433. if (is_array($arr)) {
  434. foreach($arr as $name => $value) {
  435. $hdr->{$name} = $value;
  436. }
  437. }
  438. }
  439. if (isset($arg_a[2])) {
  440. $hdr->disposition = $arg_a[2];
  441. }
  442. if (isset($arg_a[3])) {
  443. $hdr->language = $arg_a[3];
  444. }
  445. $msg->header = $hdr;
  446. return $msg;
  447. }
  448. default:
  449. break;
  450. } /* switch */
  451. $i++;
  452. } /* while */
  453. } /* parsestructure */
  454. function parseProperties($read, $i) {
  455. $properties = array();
  456. $arg_s = '';
  457. $prop_name = '';
  458. while ($read{$i} != ')') {
  459. if ($read{$i} == '"') {
  460. $arg_s = $this->parseQuote($read,&$i);
  461. } else if ($read{$i} == '{') {
  462. $arg_s = $this->parseLiteral($read,&$i);
  463. }
  464. if ($prop_name == '' && $arg_s) {
  465. $prop_name = strtolower($arg_s);
  466. $properties[$prop_name] = '';
  467. $arg_s = '';
  468. } elseif ($prop_name != '' && $arg_s != '') {
  469. $properties[$prop_name] = $arg_s;
  470. $prop_name = '';
  471. $arg_s = '';
  472. }
  473. $i++;
  474. }
  475. return $properties;
  476. }
  477. function parseEnvelope($read, $i, $hdr) {
  478. $arg_no = 0;
  479. $arg_a = array();
  480. $cnt = strlen($read);
  481. while ($i< $cnt && $read{$i} != ')') {
  482. $i++;
  483. $char = strtoupper($read{$i});
  484. switch ($char) {
  485. case '"':
  486. $arg_a[] = $this->parseQuote($read,&$i);
  487. $arg_no++;
  488. break;
  489. case '{':
  490. $arg_a[] = $this->parseLiteral($read,&$i);
  491. $arg_no++;
  492. break;
  493. case 'N':
  494. /* probably NIL argument */
  495. if (strtoupper(substr($read,$i,3)) == 'NIL') {
  496. $arg_a[] = '';
  497. $arg_no++;
  498. $i = $i+2;
  499. }
  500. break;
  501. case '(':
  502. /* Address structure
  503. * With group support.
  504. * Note: Group support is useless on SMTP connections
  505. * because the protocol doesn't support it
  506. */
  507. $addr_a = array();
  508. $group = '';
  509. $a=0;
  510. while ($i < $cnt && $read{$i} != ')') {
  511. if ($read{$i} == '(') {
  512. $addr = $this->parseAddress($read,&$i);
  513. if ($addr->host == '' && $addr->mailbox != '') {
  514. /* start of group */
  515. $group = $addr->mailbox;
  516. $group_addr = $addr;
  517. $j = $a;
  518. } elseif ($group && $addr->host == '' && $addr->mailbox == '') {
  519. /* end group */
  520. if ($a == $j+1) { /* no group members */
  521. $group_addr->group = $group;
  522. $group_addr->mailbox = '';
  523. $group_addr->personal = "$group: Undisclosed recipients;";
  524. $addr_a[] = $group_addr;
  525. $group ='';
  526. }
  527. } else {
  528. $addr->group = $group;
  529. $addr_a[] = $addr;
  530. }
  531. $a++;
  532. }
  533. $i++;
  534. }
  535. $arg_a[] = $addr_a;
  536. break;
  537. default:
  538. break;
  539. }
  540. $i++;
  541. }
  542. if (count($arg_a) > 9) {
  543. /* argument 1: date */
  544. $d = strtr($arg_a[0], array(' ' => ' '));
  545. $d = explode(' ', $d);
  546. $hdr->date = getTimeStamp($d);
  547. /* argument 2: subject */
  548. if (!trim($arg_a[1])) {
  549. $arg_a[1]= _("(no subject)");
  550. }
  551. $hdr->subject = $arg_a[1];
  552. /* argument 3: from */
  553. $hdr->from = $arg_a[2][0];
  554. /* argument 4: sender */
  555. $hdr->sender = $arg_a[3][0];
  556. /* argument 5: reply-to */
  557. $hdr->replyto = $arg_a[4][0];
  558. /* argument 6: to */
  559. $hdr->to = $arg_a[5];
  560. /* argument 7: cc */
  561. $hdr->cc = $arg_a[6];
  562. /* argument 8: bcc */
  563. $hdr->bcc = $arg_a[7];
  564. /* argument 9: in-reply-to */
  565. $hdr->inreplyto = $arg_a[8];
  566. /* argument 10: message-id */
  567. $hdr->message_id = $arg_a[9];
  568. }
  569. }
  570. function parseLiteral($read, $i) {
  571. $lit_cnt = '';
  572. $i++;
  573. while ($read{$i} != '}') {
  574. $lit_cnt .= $read{$i};
  575. $i++;
  576. }
  577. $lit_cnt +=2; /* add the { and } characters */
  578. $s = '';
  579. for ($j = 0; $j < $lit_cnt; $j++) {
  580. $i++;
  581. $s .= $read{$i};
  582. }
  583. return $s;
  584. }
  585. function parseQuote($read, $i) {
  586. $i++;
  587. $s = '';
  588. while ($read{$i} != '"') {
  589. if ($read{$i} == '\\') {
  590. $i++;
  591. }
  592. $s .= $read{$i};
  593. $i++;
  594. }
  595. return $s;
  596. }
  597. function parseAddress($read, $i) {
  598. $arg_a = array();
  599. while ($read{$i} != ')' ) { //&& $i < count($read)) {
  600. $char = strtoupper($read{$i});
  601. switch ($char) {
  602. case '"':
  603. $arg_a[] = $this->parseQuote($read,&$i);
  604. break;
  605. case '{':
  606. $arg_a[] = $this->parseLiteral($read,&$i);
  607. break;
  608. case 'N':
  609. if (strtolower(substr($read,$i,3)) == 'nil') {
  610. $arg_a[] = '';
  611. $i = $i+2;
  612. }
  613. break;
  614. default:
  615. break;
  616. }
  617. $i++;
  618. }
  619. if (count($arg_a) == 4) {
  620. $adr = new address_structure();
  621. $adr->personal = $arg_a[0];
  622. $adr->adl = $arg_a[1];
  623. $adr->mailbox = $arg_a[2];
  624. $adr->host = $arg_a[3];
  625. } else {
  626. $adr = '';
  627. }
  628. return $adr;
  629. }
  630. function parseDisposition($read,&$i) {
  631. $arg_a = array();
  632. while ($read{$i} != ')') {
  633. switch ($read{$i}) {
  634. case '"':
  635. $arg_a[] = $this->parseQuote($read,&$i);
  636. break;
  637. case '{':
  638. $arg_a[] = $this->parseLiteral($read,&$i);
  639. break;
  640. case '(':
  641. $arg_a[] = $this->parseProperties($read,&$i);
  642. break;
  643. default:
  644. break;
  645. }
  646. $i++;
  647. }
  648. if (isset($arg_a[0])) {
  649. $disp = new disposition($arg_a[0]);
  650. if (isset($arg_a[1])) {
  651. $disp->properties = $arg_a[1];
  652. }
  653. }
  654. if (is_object($disp)) {
  655. return $disp;
  656. }
  657. }
  658. function parseLanguage($read,&$i) {
  659. /* no idea how to process this one without examples */
  660. $arg_a = array();
  661. while ($read{$i} != ')') {
  662. switch ($read{$i}) {
  663. case '"':
  664. $arg_a[] = $this->parseQuote($read,&$i);
  665. break;
  666. case '{':
  667. $arg_a[] = $this->parseLiteral($read,&$i);
  668. break;
  669. case '(':
  670. $arg_a[] = $this->parseProperties($read,&$i);
  671. break;
  672. default:
  673. break;
  674. }
  675. $i++;
  676. }
  677. if (isset($arg_a[0])) {
  678. $lang = new language($arg_a[0]);
  679. if (isset($arg_a[1])) {
  680. $lang->properties = $arg_a[1];
  681. }
  682. }
  683. if (is_object($lang)) {
  684. return $lang;
  685. } else {
  686. return '';
  687. }
  688. }
  689. function parseParenthesis($read,&$i) {
  690. while ($read{$i} != ')') {
  691. switch ($read{$i}) {
  692. case '"':
  693. $this->parseQuote($read,&$i);
  694. break;
  695. case '{':
  696. $this->parseLiteral($read,&$i);
  697. break;
  698. case '(':
  699. $this->parseParenthesis($read,&$i);
  700. break;
  701. default:
  702. break;
  703. }
  704. $i++;
  705. }
  706. }
  707. function findDisplayEntity ($entity = array(), $alt_order = array('text/plain','text/html')) {
  708. $found = false;
  709. $type = $this->type0.'/'.$this->type1;
  710. if ( $type == 'multipart/alternative') {
  711. $msg = $this->findAlternativeEntity($alt_order);
  712. if (count($msg->entities) == 0) {
  713. $entity[] = $msg->entity_id;
  714. } else {
  715. $msg->findDisplayEntity(&$entity, $alt_order);
  716. }
  717. $found = true;
  718. } else if ( $type == 'multipart/related') {
  719. $msgs = $this->findRelatedEntity();
  720. for ($i = 0; $i < count($msgs); $i++) {
  721. $msg = $msgs[$i];
  722. if (count($msg->entities) == 0) {
  723. $entity[] = $msg->entity_id;
  724. } else {
  725. $msg->findDisplayEntity(&$entity,$alt_order);
  726. }
  727. $found = true;
  728. }
  729. } else if ( $this->type0 == 'text' &&
  730. ( $this->type1 == 'plain' ||
  731. $this->type1 == 'html' ||
  732. $this->type1 == 'message') &&
  733. isset($this->entity_id) ) {
  734. if (count($this->entities) == 0) {
  735. if (strtolower($this->header->disposition->name) != 'attachment') {
  736. $entity[] = $this->entity_id;
  737. }
  738. }
  739. }
  740. $i = 0;
  741. while ( isset($this->entities[$i]) && !$found &&
  742. (strtolower($this->entities[$i]->header->disposition->name)
  743. != 'attachment') &&
  744. ($this->entities[$i]->type0 != 'message' &&
  745. $this->entities[$i]->type1 != 'rfc822' )
  746. )
  747. {
  748. $this->entities[$i]->findDisplayEntity(&$entity, $alt_order);
  749. $i++;
  750. }
  751. if ( !isset($entity[0]) ) {
  752. $entity[]="";
  753. }
  754. return( $entity );
  755. }
  756. function findAlternativeEntity ($alt_order) {
  757. /* if we are dealing with alternative parts then we choose the best
  758. * viewable message supported by SM.
  759. */
  760. $best_view = 0;
  761. $ent_id = 0;
  762. $k = 0;
  763. for ($i = 0; $i < count($this->entities); $i ++) {
  764. $type = $this->entities[$i]->header->type0.'/'.$this->entities[$i]->header->type1;
  765. if ($type == 'multipart/related') {
  766. $type = $this->entities[$i]->header->type;
  767. }
  768. for ($j = $k; $j < count($alt_order); $j++) {
  769. if ($alt_order[$j] == $type && $j > $best_view) {
  770. $best_view = $j;
  771. $ent_id = $i;
  772. $k = $j;
  773. }
  774. }
  775. }
  776. return $this->entities[$ent_id];
  777. }
  778. function findRelatedEntity () {
  779. $msgs = array();
  780. for ($i = 0; $i < count($this->entities); $i ++) {
  781. $type = $this->entities[$i]->header->type0.'/'.$this->entities[$i]->header->type1;
  782. if ($this->header->type == $type) {
  783. $msgs[] = $this->entities[$i];
  784. }
  785. }
  786. return $msgs;
  787. }
  788. function getAttachments($exclude_id=array(), $result = array()) {
  789. if ($this->type0 == 'message' && $this->type1 == 'rfc822') {
  790. $this = $this->entities[0];
  791. }
  792. if (count($this->entities)) {
  793. foreach ($this->entities as $entity) {
  794. $exclude = false;
  795. foreach ($exclude_id as $excl) {
  796. if ($entity->entity_id == $excl) {
  797. $exclude = true;
  798. }
  799. }
  800. if (!$exclude) {
  801. if ($entity->type0 == 'multipart' &&
  802. $entity->type1 != 'related') {
  803. $result = $entity->getAttachments($exclude_id, $result);
  804. } else if ($entity->type0 != 'multipart') {
  805. $result[] = $entity;
  806. }
  807. }
  808. }
  809. } else {
  810. $exclude = false;
  811. foreach ($exclude_id as $excl) {
  812. if ($this->entity_id == $excl) {
  813. $exclude = true;
  814. }
  815. }
  816. if (!$exclude) {
  817. $result[] = $this;
  818. }
  819. }
  820. return $result;
  821. }
  822. }
  823. class disposition {
  824. function disposition($name) {
  825. $this->name = $name;
  826. $this->properties = array();
  827. }
  828. }
  829. class language {
  830. function language($name) {
  831. $this->name = $name;
  832. $this->properties = array();
  833. }
  834. }
  835. ?>