freemail_imap_message_handler.php 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. <?php
  2. class sloodle_freemail_imap_message_handler {
  3. var $_connection = null;
  4. var $_html_message;
  5. var $_plain_message;
  6. var $_charset;
  7. var $_attachments = array();
  8. var $_header;
  9. public function connect($connection_string, $username, $password) {
  10. // Reuse the existing connection if we have one and it's still alive.
  11. if ( !is_null($this->_connection)) {
  12. if (@imap_ping($this->_connection) ) {
  13. return $this->_connection;
  14. }
  15. // Probably won't do anything, but let's be sure.
  16. @imap_close($this->_connection);
  17. }
  18. $this->_connection = @imap_open($connection_string, $username, $password);
  19. return $this->_connection;
  20. }
  21. public function count() {
  22. if (!$this->_connection) {
  23. return null;
  24. }
  25. return @imap_num_msg($this->_connection);
  26. }
  27. public function close() {
  28. if (!$this->_connection) {
  29. return null;
  30. }
  31. return @imap_close($this->_connection);
  32. }
  33. public function delete($mid) {
  34. if (!$this->_connection) {
  35. return null;
  36. }
  37. return @imap_delete($this->_connection, $mid);
  38. }
  39. public function expunge() {
  40. if (!$this->_connection) {
  41. return null;
  42. }
  43. return @imap_expunge($this->_connection);
  44. }
  45. public function load_header($mid) {
  46. return $this->_header = @imap_header($this->_connection,$mid);
  47. }
  48. public function load($mid) {
  49. return $this->_get_msg($mid);
  50. }
  51. public function mark_flagged($mid) {
  52. if (!$this->_connection) {
  53. return null;
  54. }
  55. return @imap_setflag_full($this->_connection, $mid, "\\Flagged");
  56. }
  57. public function get_html_message() {
  58. return $this->_html_message;
  59. }
  60. public function get_plain_message() {
  61. return $this->_plain_message;
  62. }
  63. public function get_charset() {
  64. return $this->_charset;
  65. }
  66. public function get_attachments() {
  67. return $this->_attachments;
  68. }
  69. public function get_header() {
  70. return $this->_header;
  71. }
  72. public function get_subject() {
  73. return $this->_header->subject;
  74. }
  75. public function get_date() {
  76. return $this->_header->date;
  77. }
  78. public function get_to_address() {
  79. return $this->_header->toaddress;
  80. }
  81. public function get_from_address() {
  82. return $this->_header->fromaddress;
  83. }
  84. public function get_size_in_bytes() {
  85. return $this->_header->Size;
  86. }
  87. /*
  88. The following methods are adapted from code found at:
  89. http://php.net/manual/en/function.imap-fetchstructure.php
  90. david at hundsness dot com 02-Sep-2008 02:31
  91. ...who said:
  92. "Here is code to parse and decode all types of messages, including attachments. I've been using something like this for awhile now, so it's pretty robust."
  93. */
  94. private function _get_msg($mid) {
  95. // input $mbox = IMAP stream, $mid = message id
  96. // output all the following:
  97. if (!$mbox = $this->_connection) {
  98. return false;
  99. }
  100. $this->_html_message = $this->_plain_message = $this->_charset = '';
  101. $this->_attachments = array();
  102. // BODY
  103. $s = @imap_fetchstructure($mbox,$mid);
  104. if (!$s->parts) { // simple
  105. $this->_get_part($mid,$s,0); // pass 0 as part-number
  106. } else { // multipart: cycle through each part
  107. foreach ($s->parts as $partno0=>$p) {
  108. $this->_get_part($mid,$p,$partno0+1);
  109. }
  110. }
  111. return true;
  112. }
  113. private function _get_part($mid,$p,$partno) {
  114. // $partno = '1', '2', '2.1', '2.1.3', etc if multipart, 0 if not multipart
  115. if (!$mbox = $this->_connection) {
  116. return false;
  117. }
  118. // DECODE DATA
  119. $data = ($partno)?
  120. @imap_fetchbody($mbox,$mid,$partno): // multipart
  121. @imap_body($mbox,$mid); // not multipart
  122. // Any part may be encoded, even plain text messages, so check everything.
  123. if ($p->encoding==4) {
  124. $data = quoted_printable_decode($data);
  125. } elseif ($p->encoding==3) {
  126. $data = base64_decode($data);
  127. // no need to decode 7-bit, 8-bit, or binary
  128. }
  129. // PARAMETERS
  130. // get all parameters, like charset, filenames of attachments, etc.
  131. $params = array();
  132. if ($p->parameters) {
  133. foreach ($p->parameters as $x) {
  134. $params[ strtolower( $x->attribute ) ] = $x->value;
  135. }
  136. }
  137. if ($p->dparameters) {
  138. foreach ($p->dparameters as $x) {
  139. $params[ strtolower( $x->attribute ) ] = $x->value;
  140. }
  141. }
  142. // ATTACHMENT
  143. // Any part with a filename is an attachment,
  144. // so an attached text file (type 0) is not mistaken as the message.
  145. if ($params['filename'] || $params['name']) {
  146. // filename may be given as 'Filename' or 'Name' or both
  147. $filename = ($params['filename'])? $params['filename'] : $params['name'];
  148. // filename may be encoded, so see imap_mime_header_decode()
  149. $this->_attachments[$filename] = $data; // this is a problem if two files have same name
  150. } elseif ($p->type==0 && $data) {
  151. // TEXT
  152. // Messages may be split in different parts because of inline attachments,
  153. // so append parts together with blank row.
  154. if (strtolower($p->subtype)=='plain') {
  155. $this->_plain_message .= trim($data) ."\n\n";
  156. } else {
  157. $this->_html_message .= $data ."<br><br>";
  158. $this->_charset = $params['charset']; // assume all parts are same charset
  159. }
  160. } elseif ($p->type==2 && $data) {
  161. // EMBEDDED MESSAGE
  162. // Many bounce notifications embed the original message as type 2,
  163. // but AOL uses type 1 (multipart), which is not handled here.
  164. // There are no PHP functions to parse embedded messages,
  165. // so this just appends the raw source to the main message.
  166. $this->_plain_message .= trim($data) ."\n\n";
  167. }
  168. // SUBPART RECURSION
  169. if ($p->parts) {
  170. foreach ($p->parts as $partno0=>$p2) {
  171. $this->_get_part($mid,$p2,$partno.'.'.($partno0+1)); // 1.2, 1.2.1, etc.
  172. }
  173. }
  174. }
  175. }