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