Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

enigma_mime_message.php 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. <?php
  2. /**
  3. +-------------------------------------------------------------------------+
  4. | Mail_mime wrapper for the Enigma Plugin |
  5. | |
  6. | Copyright (C) 2010-2015 The Roundcube Dev Team |
  7. | |
  8. | Licensed under the GNU General Public License version 3 or |
  9. | any later version with exceptions for skins & plugins. |
  10. | See the README file for a full license statement. |
  11. | |
  12. +-------------------------------------------------------------------------+
  13. | Author: Aleksander Machniak <alec@alec.pl> |
  14. +-------------------------------------------------------------------------+
  15. */
  16. class enigma_mime_message extends Mail_mime
  17. {
  18. const PGP_SIGNED = 1;
  19. const PGP_ENCRYPTED = 2;
  20. protected $type;
  21. protected $message;
  22. protected $body;
  23. protected $signature;
  24. protected $encrypted;
  25. protected $micalg;
  26. /**
  27. * Object constructor
  28. *
  29. * @param Mail_mime Original message
  30. * @param int Output message type
  31. */
  32. function __construct($message, $type)
  33. {
  34. $this->message = $message;
  35. $this->type = $type;
  36. // clone parameters
  37. foreach (array_keys($this->build_params) as $param) {
  38. $this->build_params[$param] = $message->getParam($param);
  39. }
  40. // clone headers
  41. $this->headers = $message->headers();
  42. // \r\n is must-have here
  43. $this->body = $message->get() . "\r\n";
  44. }
  45. /**
  46. * Check if the message is multipart (requires PGP/MIME)
  47. *
  48. * @return bool True if it is multipart, otherwise False
  49. */
  50. public function isMultipart()
  51. {
  52. return $this->message instanceof enigma_mime_message
  53. || $this->message->isMultipart() || $this->message->getHTMLBody();
  54. }
  55. /**
  56. * Get e-mail address of message sender
  57. *
  58. * @return string Sender address
  59. */
  60. public function getFromAddress()
  61. {
  62. // get sender address
  63. $headers = $this->message->headers();
  64. $from = rcube_mime::decode_address_list($headers['From'], 1, false, null, true);
  65. $from = $from[1];
  66. return $from;
  67. }
  68. /**
  69. * Get recipients' e-mail addresses
  70. *
  71. * @return array Recipients' addresses
  72. */
  73. public function getRecipients()
  74. {
  75. // get sender address
  76. $headers = $this->message->headers();
  77. $to = rcube_mime::decode_address_list($headers['To'], null, false, null, true);
  78. $cc = rcube_mime::decode_address_list($headers['Cc'], null, false, null, true);
  79. $bcc = rcube_mime::decode_address_list($headers['Bcc'], null, false, null, true);
  80. $recipients = array_unique(array_merge($to, $cc, $bcc));
  81. $recipients = array_diff($recipients, array('undisclosed-recipients:'));
  82. return $recipients;
  83. }
  84. /**
  85. * Get original message body, to be encrypted/signed
  86. *
  87. * @return string Message body
  88. */
  89. public function getOrigBody()
  90. {
  91. $_headers = $this->message->headers();
  92. $headers = array();
  93. if ($_headers['Content-Transfer-Encoding']
  94. && stripos($_headers['Content-Type'], 'multipart') === false
  95. ) {
  96. $headers[] = 'Content-Transfer-Encoding: ' . $_headers['Content-Transfer-Encoding'];
  97. }
  98. $headers[] = 'Content-Type: ' . $_headers['Content-Type'];
  99. return implode("\r\n", $headers) . "\r\n\r\n" . $this->body;
  100. }
  101. /**
  102. * Register signature attachment
  103. *
  104. * @param string Signature body
  105. * @param string Hash algorithm name
  106. */
  107. public function addPGPSignature($body, $algorithm = null)
  108. {
  109. $this->signature = $body;
  110. $this->micalg = $algorithm;
  111. // Reset Content-Type to be overwritten with valid boundary
  112. unset($this->headers['Content-Type']);
  113. unset($this->headers['Content-Transfer-Encoding']);
  114. }
  115. /**
  116. * Register encrypted body
  117. *
  118. * @param string Encrypted body
  119. */
  120. public function setPGPEncryptedBody($body)
  121. {
  122. $this->encrypted = $body;
  123. // Reset Content-Type to be overwritten with valid boundary
  124. unset($this->headers['Content-Type']);
  125. unset($this->headers['Content-Transfer-Encoding']);
  126. }
  127. /**
  128. * Builds the multipart message.
  129. *
  130. * @param array $params Build parameters that change the way the email
  131. * is built. Should be associative. See $_build_params.
  132. * @param resource $filename Output file where to save the message instead of
  133. * returning it
  134. * @param boolean $skip_head True if you want to return/save only the message
  135. * without headers
  136. *
  137. * @return mixed The MIME message content string, null or PEAR error object
  138. */
  139. public function get($params = null, $filename = null, $skip_head = false)
  140. {
  141. if (!empty($params)) {
  142. foreach ($params as $key => $value) {
  143. $this->build_params[$key] = $value;
  144. }
  145. }
  146. $this->checkParams();
  147. if ($this->type == self::PGP_SIGNED) {
  148. $params = array(
  149. 'preamble' => "This is an OpenPGP/MIME signed message (RFC 4880 and 3156)",
  150. 'content_type' => "multipart/signed; protocol=\"application/pgp-signature\"",
  151. 'eol' => $this->build_params['eol'],
  152. );
  153. if ($this->micalg) {
  154. $params['content_type'] .= "; micalg=pgp-" . $this->micalg;
  155. }
  156. $message = new Mail_mimePart('', $params);
  157. if (!empty($this->body)) {
  158. $headers = $this->message->headers();
  159. $params = array('content_type' => $headers['Content-Type']);
  160. if ($headers['Content-Transfer-Encoding']
  161. && stripos($headers['Content-Type'], 'multipart') === false
  162. ) {
  163. $params['encoding'] = $headers['Content-Transfer-Encoding'];
  164. }
  165. $message->addSubpart($this->body, $params);
  166. }
  167. if (!empty($this->signature)) {
  168. $message->addSubpart($this->signature, array(
  169. 'filename' => 'signature.asc',
  170. 'content_type' => 'application/pgp-signature',
  171. 'disposition' => 'attachment',
  172. 'description' => 'OpenPGP digital signature',
  173. ));
  174. }
  175. }
  176. else if ($this->type == self::PGP_ENCRYPTED) {
  177. $params = array(
  178. 'preamble' => "This is an OpenPGP/MIME encrypted message (RFC 4880 and 3156)",
  179. 'content_type' => "multipart/encrypted; protocol=\"application/pgp-encrypted\"",
  180. 'eol' => $this->build_params['eol'],
  181. );
  182. $message = new Mail_mimePart('', $params);
  183. $message->addSubpart('Version: 1', array(
  184. 'content_type' => 'application/pgp-encrypted',
  185. 'description' => 'PGP/MIME version identification',
  186. ));
  187. $message->addSubpart($this->encrypted, array(
  188. 'content_type' => 'application/octet-stream',
  189. 'description' => 'PGP/MIME encrypted message',
  190. 'disposition' => 'inline',
  191. 'filename' => 'encrypted.asc',
  192. ));
  193. }
  194. // Use saved boundary
  195. if (!empty($this->build_params['boundary'])) {
  196. $boundary = $this->build_params['boundary'];
  197. }
  198. else {
  199. $boundary = null;
  200. }
  201. // Write output to file
  202. if ($filename) {
  203. // Append mimePart message headers and body into file
  204. $headers = $message->encodeToFile($filename, $boundary, $skip_head);
  205. if ($this->isError($headers)) {
  206. return $headers;
  207. }
  208. $this->headers = array_merge($this->headers, $headers);
  209. return;
  210. }
  211. else {
  212. $output = $message->encode($boundary, $skip_head);
  213. if ($this->isError($output)) {
  214. return $output;
  215. }
  216. $this->headers = array_merge($this->headers, $output['headers']);
  217. return $output['body'];
  218. }
  219. }
  220. /**
  221. * Get Content-Type and Content-Transfer-Encoding headers of the message
  222. *
  223. * @return array Headers array
  224. */
  225. protected function contentHeaders()
  226. {
  227. $this->checkParams();
  228. $eol = $this->build_params['eol'] ?: "\r\n";
  229. // multipart message: and boundary
  230. if (!empty($this->build_params['boundary'])) {
  231. $boundary = $this->build_params['boundary'];
  232. }
  233. else if (!empty($this->headers['Content-Type'])
  234. && preg_match('/boundary="([^"]+)"/', $this->headers['Content-Type'], $m)
  235. ) {
  236. $boundary = $m[1];
  237. }
  238. else {
  239. $boundary = '=_' . md5(rand() . microtime());
  240. }
  241. $this->build_params['boundary'] = $boundary;
  242. if ($this->type == self::PGP_SIGNED) {
  243. $headers['Content-Type'] = "multipart/signed;$eol"
  244. ." protocol=\"application/pgp-signature\";$eol"
  245. ." boundary=\"$boundary\"";
  246. if ($this->micalg) {
  247. $headers['Content-Type'] .= ";{$eol} micalg=pgp-" . $this->micalg;
  248. }
  249. }
  250. else if ($this->type == self::PGP_ENCRYPTED) {
  251. $headers['Content-Type'] = "multipart/encrypted;$eol"
  252. ." protocol=\"application/pgp-encrypted\";$eol"
  253. ." boundary=\"$boundary\"";
  254. }
  255. return $headers;
  256. }
  257. }