Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. <?php
  2. /**
  3. +-------------------------------------------------------------------------+
  4. | Enigma Plugin for Roundcube |
  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. /**
  17. * This class contains only hooks and action handlers.
  18. * Most plugin logic is placed in enigma_engine and enigma_ui classes.
  19. */
  20. class enigma extends rcube_plugin
  21. {
  22. public $task = 'mail|settings|cli';
  23. public $rc;
  24. public $engine;
  25. public $ui;
  26. private $env_loaded = false;
  27. /**
  28. * Plugin initialization.
  29. */
  30. function init()
  31. {
  32. $this->rc = rcube::get_instance();
  33. if ($this->rc->task == 'mail') {
  34. // message parse/display hooks
  35. $this->add_hook('message_part_structure', array($this, 'part_structure'));
  36. $this->add_hook('message_part_body', array($this, 'part_body'));
  37. $this->add_hook('message_body_prefix', array($this, 'status_message'));
  38. $this->register_action('plugin.enigmaimport', array($this, 'import_file'));
  39. $this->register_action('plugin.enigmakeys', array($this, 'preferences_ui'));
  40. // load the Enigma plugin configuration
  41. $this->load_config();
  42. $enabled = $this->rc->config->get('enigma_encryption', true);
  43. // message displaying
  44. if ($this->rc->action == 'show' || $this->rc->action == 'preview' || $this->rc->action == 'print') {
  45. $this->add_hook('message_load', array($this, 'message_load'));
  46. $this->add_hook('template_object_messagebody', array($this, 'message_output'));
  47. }
  48. // message composing
  49. else if ($enabled && $this->rc->action == 'compose') {
  50. $this->add_hook('message_compose_body', array($this, 'message_compose'));
  51. $this->load_ui();
  52. $this->ui->init();
  53. }
  54. // message sending (and draft storing)
  55. else if ($enabled && $this->rc->action == 'send') {
  56. $this->add_hook('message_ready', array($this, 'message_ready'));
  57. }
  58. $this->password_handler();
  59. }
  60. else if ($this->rc->task == 'settings') {
  61. // add hooks for Enigma settings
  62. $this->add_hook('settings_actions', array($this, 'settings_actions'));
  63. $this->add_hook('preferences_sections_list', array($this, 'preferences_sections_list'));
  64. $this->add_hook('preferences_list', array($this, 'preferences_list'));
  65. $this->add_hook('preferences_save', array($this, 'preferences_save'));
  66. // register handler for keys/certs management
  67. $this->register_action('plugin.enigmakeys', array($this, 'preferences_ui'));
  68. // $this->register_action('plugin.enigmacerts', array($this, 'preferences_ui'));
  69. $this->load_ui();
  70. if (empty($_REQUEST['_framed']) || strpos($this->rc->action, 'plugin.enigma') === 0) {
  71. $this->ui->add_css();
  72. }
  73. $this->password_handler();
  74. }
  75. else if ($this->rc->task == 'cli') {
  76. $this->add_hook('user_delete_commit', array($this, 'user_delete'));
  77. }
  78. $this->add_hook('refresh', array($this, 'refresh'));
  79. }
  80. /**
  81. * Plugin environment initialization.
  82. */
  83. function load_env()
  84. {
  85. if ($this->env_loaded) {
  86. return;
  87. }
  88. $this->env_loaded = true;
  89. // Add include path for Enigma classes and drivers
  90. $include_path = $this->home . '/lib' . PATH_SEPARATOR;
  91. $include_path .= ini_get('include_path');
  92. set_include_path($include_path);
  93. // load the Enigma plugin configuration
  94. $this->load_config();
  95. // include localization (if wasn't included before)
  96. $this->add_texts('localization/');
  97. }
  98. /**
  99. * Plugin UI initialization.
  100. */
  101. function load_ui($all = false)
  102. {
  103. if (!$this->ui) {
  104. // load config/localization
  105. $this->load_env();
  106. // Load UI
  107. $this->ui = new enigma_ui($this, $this->home);
  108. }
  109. if ($all) {
  110. $this->ui->add_css();
  111. $this->ui->add_js();
  112. }
  113. }
  114. /**
  115. * Plugin engine initialization.
  116. */
  117. function load_engine()
  118. {
  119. if ($this->engine) {
  120. return $this->engine;
  121. }
  122. // load config/localization
  123. $this->load_env();
  124. return $this->engine = new enigma_engine($this);
  125. }
  126. /**
  127. * Handler for message_part_structure hook.
  128. * Called for every part of the message.
  129. *
  130. * @param array Original parameters
  131. *
  132. * @return array Modified parameters
  133. */
  134. function part_structure($p)
  135. {
  136. $this->load_engine();
  137. return $this->engine->part_structure($p);
  138. }
  139. /**
  140. * Handler for message_part_body hook.
  141. * Called to get body of a message part.
  142. *
  143. * @param array Original parameters
  144. *
  145. * @return array Modified parameters
  146. */
  147. function part_body($p)
  148. {
  149. $this->load_engine();
  150. return $this->engine->part_body($p);
  151. }
  152. /**
  153. * Handler for settings_actions hook.
  154. * Adds Enigma settings section into preferences.
  155. *
  156. * @param array Original parameters
  157. *
  158. * @return array Modified parameters
  159. */
  160. function settings_actions($args)
  161. {
  162. // add labels
  163. $this->add_texts('localization/');
  164. // register as settings action
  165. $args['actions'][] = array(
  166. 'action' => 'plugin.enigmakeys',
  167. 'class' => 'enigma keys',
  168. 'label' => 'enigmakeys',
  169. 'title' => 'enigmakeys',
  170. 'domain' => 'enigma',
  171. );
  172. /*
  173. $args['actions'][] = array(
  174. 'action' => 'plugin.enigmacerts',
  175. 'class' => 'enigma certs',
  176. 'label' => 'enigmacerts',
  177. 'title' => 'enigmacerts',
  178. 'domain' => 'enigma',
  179. );
  180. */
  181. return $args;
  182. }
  183. /**
  184. * Handler for preferences_sections_list hook.
  185. * Adds Encryption settings section into preferences sections list.
  186. *
  187. * @param array Original parameters
  188. *
  189. * @return array Modified parameters
  190. */
  191. function preferences_sections_list($p)
  192. {
  193. $p['list']['enigma'] = array(
  194. 'id' => 'enigma', 'section' => $this->gettext('encryption'),
  195. );
  196. return $p;
  197. }
  198. /**
  199. * Handler for preferences_list hook.
  200. * Adds options blocks into Enigma settings sections in Preferences.
  201. *
  202. * @param array Original parameters
  203. *
  204. * @return array Modified parameters
  205. */
  206. function preferences_list($p)
  207. {
  208. if ($p['section'] != 'enigma') {
  209. return $p;
  210. }
  211. $no_override = array_flip((array)$this->rc->config->get('dont_override'));
  212. $p['blocks']['main']['name'] = $this->gettext('mainoptions');
  213. if (!isset($no_override['enigma_encryption'])) {
  214. if (!$p['current']) {
  215. $p['blocks']['main']['content'] = true;
  216. return $p;
  217. }
  218. $field_id = 'rcmfd_enigma_encryption';
  219. $input = new html_checkbox(array(
  220. 'name' => '_enigma_encryption',
  221. 'id' => $field_id,
  222. 'value' => 1,
  223. ));
  224. $p['blocks']['main']['options']['enigma_encryption'] = array(
  225. 'title' => html::label($field_id, $this->gettext('supportencryption')),
  226. 'content' => $input->show(intval($this->rc->config->get('enigma_encryption'))),
  227. );
  228. }
  229. if (!isset($no_override['enigma_signatures'])) {
  230. if (!$p['current']) {
  231. $p['blocks']['main']['content'] = true;
  232. return $p;
  233. }
  234. $field_id = 'rcmfd_enigma_signatures';
  235. $input = new html_checkbox(array(
  236. 'name' => '_enigma_signatures',
  237. 'id' => $field_id,
  238. 'value' => 1,
  239. ));
  240. $p['blocks']['main']['options']['enigma_signatures'] = array(
  241. 'title' => html::label($field_id, $this->gettext('supportsignatures')),
  242. 'content' => $input->show(intval($this->rc->config->get('enigma_signatures'))),
  243. );
  244. }
  245. if (!isset($no_override['enigma_decryption'])) {
  246. if (!$p['current']) {
  247. $p['blocks']['main']['content'] = true;
  248. return $p;
  249. }
  250. $field_id = 'rcmfd_enigma_decryption';
  251. $input = new html_checkbox(array(
  252. 'name' => '_enigma_decryption',
  253. 'id' => $field_id,
  254. 'value' => 1,
  255. ));
  256. $p['blocks']['main']['options']['enigma_decryption'] = array(
  257. 'title' => html::label($field_id, $this->gettext('supportdecryption')),
  258. 'content' => $input->show(intval($this->rc->config->get('enigma_decryption'))),
  259. );
  260. }
  261. if (!isset($no_override['enigma_sign_all'])) {
  262. if (!$p['current']) {
  263. $p['blocks']['main']['content'] = true;
  264. return $p;
  265. }
  266. $field_id = 'rcmfd_enigma_sign_all';
  267. $input = new html_checkbox(array(
  268. 'name' => '_enigma_sign_all',
  269. 'id' => $field_id,
  270. 'value' => 1,
  271. ));
  272. $p['blocks']['main']['options']['enigma_sign_all'] = array(
  273. 'title' => html::label($field_id, $this->gettext('signdefault')),
  274. 'content' => $input->show($this->rc->config->get('enigma_sign_all') ? 1 : 0),
  275. );
  276. }
  277. if (!isset($no_override['enigma_encrypt_all'])) {
  278. if (!$p['current']) {
  279. $p['blocks']['main']['content'] = true;
  280. return $p;
  281. }
  282. $field_id = 'rcmfd_enigma_encrypt_all';
  283. $input = new html_checkbox(array(
  284. 'name' => '_enigma_encrypt_all',
  285. 'id' => $field_id,
  286. 'value' => 1,
  287. ));
  288. $p['blocks']['main']['options']['enigma_encrypt_all'] = array(
  289. 'title' => html::label($field_id, $this->gettext('encryptdefault')),
  290. 'content' => $input->show($this->rc->config->get('enigma_encrypt_all') ? 1 : 0),
  291. );
  292. }
  293. if (!isset($no_override['enigma_attach_pubkey'])) {
  294. if (!$p['current']) {
  295. $p['blocks']['main']['content'] = true;
  296. return $p;
  297. }
  298. $field_id = 'rcmfd_enigma_attach_pubkey';
  299. $input = new html_checkbox(array(
  300. 'name' => '_enigma_attach_pubkey',
  301. 'id' => $field_id,
  302. 'value' => 1,
  303. ));
  304. $p['blocks']['main']['options']['enigma_attach_pubkey'] = array(
  305. 'title' => html::label($field_id, $this->gettext('attachpubkeydefault')),
  306. 'content' => $input->show($this->rc->config->get('enigma_attach_pubkey') ? 1 : 0),
  307. );
  308. }
  309. if (!isset($no_override['enigma_password_time'])) {
  310. if (!$p['current']) {
  311. $p['blocks']['main']['content'] = true;
  312. return $p;
  313. }
  314. $field_id = 'rcmfd_enigma_password_time';
  315. $select = new html_select(array('name' => '_enigma_password_time', 'id' => $field_id));
  316. foreach (array(1, 5, 10, 15, 30) as $m) {
  317. $label = $this->gettext(array('name' => 'nminutes', 'vars' => array('m' => $m)));
  318. $select->add($label, $m);
  319. }
  320. $select->add($this->gettext('wholesession'), 0);
  321. $p['blocks']['main']['options']['enigma_password_time'] = array(
  322. 'title' => html::label($field_id, $this->gettext('passwordtime')),
  323. 'content' => $select->show(intval($this->rc->config->get('enigma_password_time'))),
  324. );
  325. }
  326. return $p;
  327. }
  328. /**
  329. * Handler for preferences_save hook.
  330. * Executed on Enigma settings form submit.
  331. *
  332. * @param array Original parameters
  333. *
  334. * @return array Modified parameters
  335. */
  336. function preferences_save($p)
  337. {
  338. if ($p['section'] == 'enigma') {
  339. $p['prefs'] = array(
  340. 'enigma_signatures' => (bool) rcube_utils::get_input_value('_enigma_signatures', rcube_utils::INPUT_POST),
  341. 'enigma_decryption' => (bool) rcube_utils::get_input_value('_enigma_decryption', rcube_utils::INPUT_POST),
  342. 'enigma_encryption' => (bool) rcube_utils::get_input_value('_enigma_encryption', rcube_utils::INPUT_POST),
  343. 'enigma_sign_all' => (bool) rcube_utils::get_input_value('_enigma_sign_all', rcube_utils::INPUT_POST),
  344. 'enigma_encrypt_all' => (bool) rcube_utils::get_input_value('_enigma_encrypt_all', rcube_utils::INPUT_POST),
  345. 'enigma_attach_pubkey' => (bool) rcube_utils::get_input_value('_enigma_attach_pubkey', rcube_utils::INPUT_POST),
  346. 'enigma_password_time' => intval(rcube_utils::get_input_value('_enigma_password_time', rcube_utils::INPUT_POST)),
  347. );
  348. }
  349. return $p;
  350. }
  351. /**
  352. * Handler for keys/certs management UI template.
  353. */
  354. function preferences_ui()
  355. {
  356. $this->load_ui();
  357. $this->ui->init();
  358. }
  359. /**
  360. * Handler for message_body_prefix hook.
  361. * Called for every displayed (content) part of the message.
  362. * Adds infobox about signature verification and/or decryption
  363. * status above the body.
  364. *
  365. * @param array Original parameters
  366. *
  367. * @return array Modified parameters
  368. */
  369. function status_message($p)
  370. {
  371. $this->load_ui();
  372. return $this->ui->status_message($p);
  373. }
  374. /**
  375. * Handler for message_load hook.
  376. * Check message bodies and attachments for keys/certs.
  377. */
  378. function message_load($p)
  379. {
  380. $this->load_ui();
  381. return $this->ui->message_load($p);
  382. }
  383. /**
  384. * Handler for template_object_messagebody hook.
  385. * This callback function adds a box below the message content
  386. * if there is a key/cert attachment available
  387. */
  388. function message_output($p)
  389. {
  390. $this->load_ui();
  391. return $this->ui->message_output($p);
  392. }
  393. /**
  394. * Handler for attached keys/certs import
  395. */
  396. function import_file()
  397. {
  398. $this->load_ui();
  399. $this->ui->import_file();
  400. }
  401. /**
  402. * Handle password submissions
  403. */
  404. function password_handler()
  405. {
  406. $this->load_engine();
  407. $this->engine->password_handler();
  408. }
  409. /**
  410. * Handle message_ready hook (encryption/signing)
  411. */
  412. function message_ready($p)
  413. {
  414. $this->load_ui();
  415. return $this->ui->message_ready($p);
  416. }
  417. /**
  418. * Handle message_compose_body hook
  419. */
  420. function message_compose($p)
  421. {
  422. $this->load_ui();
  423. return $this->ui->message_compose($p);
  424. }
  425. /**
  426. * Handler for refresh hook.
  427. */
  428. function refresh($p)
  429. {
  430. // calling enigma_engine constructor to remove passwords
  431. // stored in session after expiration time
  432. $this->load_engine();
  433. return $p;
  434. }
  435. /**
  436. * Handle delete_user_commit hook
  437. */
  438. function user_delete($p)
  439. {
  440. $this->load_engine();
  441. $p['abort'] = $p['abort'] || !$this->engine->delete_user_data($p['username']);
  442. return $p;
  443. }
  444. }