Message.class.php 31 KB

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