Mercurial > hg > rc1
comparison plugins/enigma/lib/enigma_ui.php @ 0:1e000243b222
vanilla 1.3.3 distro, I hope
| author | Charlie Root |
|---|---|
| date | Thu, 04 Jan 2018 15:50:29 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:1e000243b222 |
|---|---|
| 1 <?php | |
| 2 | |
| 3 /** | |
| 4 +-------------------------------------------------------------------------+ | |
| 5 | User Interface for the Enigma Plugin | | |
| 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 class enigma_ui | |
| 19 { | |
| 20 private $rc; | |
| 21 private $enigma; | |
| 22 private $home; | |
| 23 private $css_loaded; | |
| 24 private $js_loaded; | |
| 25 private $data; | |
| 26 private $keys_parts = array(); | |
| 27 private $keys_bodies = array(); | |
| 28 | |
| 29 | |
| 30 function __construct($enigma_plugin, $home='') | |
| 31 { | |
| 32 $this->enigma = $enigma_plugin; | |
| 33 $this->rc = $enigma_plugin->rc; | |
| 34 $this->home = $home; // we cannot use $enigma_plugin->home here | |
| 35 } | |
| 36 | |
| 37 /** | |
| 38 * UI initialization and requests handlers. | |
| 39 * | |
| 40 * @param string Preferences section | |
| 41 */ | |
| 42 function init() | |
| 43 { | |
| 44 $this->add_js(); | |
| 45 | |
| 46 $action = rcube_utils::get_input_value('_a', rcube_utils::INPUT_GPC); | |
| 47 | |
| 48 if ($this->rc->action == 'plugin.enigmakeys') { | |
| 49 switch ($action) { | |
| 50 case 'delete': | |
| 51 $this->key_delete(); | |
| 52 break; | |
| 53 /* | |
| 54 case 'edit': | |
| 55 $this->key_edit(); | |
| 56 break; | |
| 57 */ | |
| 58 case 'import': | |
| 59 $this->key_import(); | |
| 60 break; | |
| 61 | |
| 62 case 'export': | |
| 63 $this->key_export(); | |
| 64 break; | |
| 65 | |
| 66 case 'generate': | |
| 67 $this->key_generate(); | |
| 68 break; | |
| 69 | |
| 70 case 'create': | |
| 71 $this->key_create(); | |
| 72 break; | |
| 73 | |
| 74 case 'search': | |
| 75 case 'list': | |
| 76 $this->key_list(); | |
| 77 break; | |
| 78 | |
| 79 case 'info': | |
| 80 $this->key_info(); | |
| 81 break; | |
| 82 } | |
| 83 | |
| 84 $this->rc->output->add_handlers(array( | |
| 85 'keyslist' => array($this, 'tpl_keys_list'), | |
| 86 'keyframe' => array($this, 'tpl_key_frame'), | |
| 87 'countdisplay' => array($this, 'tpl_keys_rowcount'), | |
| 88 'searchform' => array($this->rc->output, 'search_form'), | |
| 89 )); | |
| 90 | |
| 91 $this->rc->output->set_pagetitle($this->enigma->gettext('enigmakeys')); | |
| 92 $this->rc->output->send('enigma.keys'); | |
| 93 } | |
| 94 /* | |
| 95 // Preferences UI | |
| 96 else if ($this->rc->action == 'plugin.enigmacerts') { | |
| 97 $this->rc->output->add_handlers(array( | |
| 98 'keyslist' => array($this, 'tpl_certs_list'), | |
| 99 'keyframe' => array($this, 'tpl_cert_frame'), | |
| 100 'countdisplay' => array($this, 'tpl_certs_rowcount'), | |
| 101 'searchform' => array($this->rc->output, 'search_form'), | |
| 102 )); | |
| 103 | |
| 104 $this->rc->output->set_pagetitle($this->enigma->gettext('enigmacerts')); | |
| 105 $this->rc->output->send('enigma.certs'); | |
| 106 } | |
| 107 */ | |
| 108 // Message composing UI | |
| 109 else if ($this->rc->action == 'compose') { | |
| 110 $this->compose_ui(); | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 /** | |
| 115 * Adds CSS style file to the page header. | |
| 116 */ | |
| 117 function add_css() | |
| 118 { | |
| 119 if ($this->css_loaded) { | |
| 120 return; | |
| 121 } | |
| 122 | |
| 123 $skin_path = $this->enigma->local_skin_path(); | |
| 124 $this->enigma->include_stylesheet("$skin_path/enigma.css"); | |
| 125 $this->css_loaded = true; | |
| 126 } | |
| 127 | |
| 128 /** | |
| 129 * Adds javascript file to the page header. | |
| 130 */ | |
| 131 function add_js() | |
| 132 { | |
| 133 if ($this->js_loaded) { | |
| 134 return; | |
| 135 } | |
| 136 | |
| 137 $this->enigma->include_script('enigma.js'); | |
| 138 | |
| 139 $this->js_loaded = true; | |
| 140 } | |
| 141 | |
| 142 /** | |
| 143 * Initializes key password prompt | |
| 144 * | |
| 145 * @param enigma_error $status Error object with key info | |
| 146 * @param array $params Optional prompt parameters | |
| 147 */ | |
| 148 function password_prompt($status, $params = array()) | |
| 149 { | |
| 150 $data = $status->getData('missing'); | |
| 151 | |
| 152 if (empty($data)) { | |
| 153 $data = $status->getData('bad'); | |
| 154 } | |
| 155 | |
| 156 $keyid = key($data); | |
| 157 $data = array( | |
| 158 'keyid' => $params['keyid'] ?: $keyid, | |
| 159 'user' => $data[$keyid] | |
| 160 ); | |
| 161 | |
| 162 // With GnuPG 2.1 user name may not be specified (e.g. on private | |
| 163 // key export), we'll get the key information and set the name appropriately | |
| 164 if ($keyid && $params['keyid'] && strpos($data['user'], $keyid) !== false) { | |
| 165 $key = $this->enigma->engine->get_key($params['keyid']); | |
| 166 if ($key && $key->name) { | |
| 167 $data['user'] = $key->name; | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 if (!empty($params)) { | |
| 172 $data = array_merge($params, $data); | |
| 173 } | |
| 174 | |
| 175 if (preg_match('/^(send|plugin.enigmaimport|plugin.enigmakeys)$/', $this->rc->action)) { | |
| 176 $this->rc->output->command('enigma_password_request', $data); | |
| 177 } | |
| 178 else { | |
| 179 $this->rc->output->set_env('enigma_password_request', $data); | |
| 180 } | |
| 181 | |
| 182 // add some labels to client | |
| 183 $this->rc->output->add_label('enigma.enterkeypasstitle', 'enigma.enterkeypass', | |
| 184 'save', 'cancel'); | |
| 185 | |
| 186 $this->add_css(); | |
| 187 $this->add_js(); | |
| 188 } | |
| 189 | |
| 190 /** | |
| 191 * Template object for key info/edit frame. | |
| 192 * | |
| 193 * @param array Object attributes | |
| 194 * | |
| 195 * @return string HTML output | |
| 196 */ | |
| 197 function tpl_key_frame($attrib) | |
| 198 { | |
| 199 return $this->rc->output->frame($attrib, true); | |
| 200 } | |
| 201 | |
| 202 /** | |
| 203 * Template object for list of keys. | |
| 204 * | |
| 205 * @param array Object attributes | |
| 206 * | |
| 207 * @return string HTML content | |
| 208 */ | |
| 209 function tpl_keys_list($attrib) | |
| 210 { | |
| 211 // add id to message list table if not specified | |
| 212 if (!strlen($attrib['id'])) { | |
| 213 $attrib['id'] = 'rcmenigmakeyslist'; | |
| 214 } | |
| 215 | |
| 216 // define list of cols to be displayed | |
| 217 $a_show_cols = array('name'); | |
| 218 | |
| 219 // create XHTML table | |
| 220 $out = $this->rc->table_output($attrib, array(), $a_show_cols, 'id'); | |
| 221 | |
| 222 // set client env | |
| 223 $this->rc->output->add_gui_object('keyslist', $attrib['id']); | |
| 224 $this->rc->output->include_script('list.js'); | |
| 225 | |
| 226 // add some labels to client | |
| 227 $this->rc->output->add_label('enigma.keyremoveconfirm', 'enigma.keyremoving', | |
| 228 'enigma.keyexportprompt', 'enigma.withprivkeys', 'enigma.onlypubkeys', 'enigma.exportkeys' | |
| 229 ); | |
| 230 | |
| 231 return $out; | |
| 232 } | |
| 233 | |
| 234 /** | |
| 235 * Key listing (and searching) request handler | |
| 236 */ | |
| 237 private function key_list() | |
| 238 { | |
| 239 $this->enigma->load_engine(); | |
| 240 | |
| 241 $pagesize = $this->rc->config->get('pagesize', 100); | |
| 242 $page = max(intval(rcube_utils::get_input_value('_p', rcube_utils::INPUT_GPC)), 1); | |
| 243 $search = rcube_utils::get_input_value('_q', rcube_utils::INPUT_GPC); | |
| 244 | |
| 245 // Get the list | |
| 246 $list = $this->enigma->engine->list_keys($search); | |
| 247 | |
| 248 if ($list && ($list instanceof enigma_error)) | |
| 249 $this->rc->output->show_message('enigma.keylisterror', 'error'); | |
| 250 else if (empty($list)) | |
| 251 $this->rc->output->show_message('enigma.nokeysfound', 'notice'); | |
| 252 else if (is_array($list)) { | |
| 253 // Save the size | |
| 254 $listsize = count($list); | |
| 255 | |
| 256 // Sort the list by key (user) name | |
| 257 usort($list, array('enigma_key', 'cmp')); | |
| 258 | |
| 259 // Slice current page | |
| 260 $list = array_slice($list, ($page - 1) * $pagesize, $pagesize); | |
| 261 $size = count($list); | |
| 262 | |
| 263 // Add rows | |
| 264 foreach ($list as $key) { | |
| 265 $this->rc->output->command('enigma_add_list_row', array( | |
| 266 'name' => rcube::Q($key->name), | |
| 267 'id' => $key->id, | |
| 268 'flags' => $key->is_private() ? 'p' : '' | |
| 269 )); | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 $this->rc->output->set_env('rowcount', $size); | |
| 274 $this->rc->output->set_env('search_request', $search); | |
| 275 $this->rc->output->set_env('pagecount', ceil($listsize/$pagesize)); | |
| 276 $this->rc->output->set_env('current_page', $page); | |
| 277 $this->rc->output->command('set_rowcount', | |
| 278 $this->get_rowcount_text($listsize, $size, $page)); | |
| 279 | |
| 280 $this->rc->output->send(); | |
| 281 } | |
| 282 | |
| 283 /** | |
| 284 * Template object for list records counter. | |
| 285 * | |
| 286 * @param array Object attributes | |
| 287 * | |
| 288 * @return string HTML output | |
| 289 */ | |
| 290 function tpl_keys_rowcount($attrib) | |
| 291 { | |
| 292 if (!$attrib['id']) | |
| 293 $attrib['id'] = 'rcmcountdisplay'; | |
| 294 | |
| 295 $this->rc->output->add_gui_object('countdisplay', $attrib['id']); | |
| 296 | |
| 297 return html::span($attrib, $this->get_rowcount_text()); | |
| 298 } | |
| 299 | |
| 300 /** | |
| 301 * Returns text representation of list records counter | |
| 302 */ | |
| 303 private function get_rowcount_text($all=0, $curr_count=0, $page=1) | |
| 304 { | |
| 305 if (!$curr_count) { | |
| 306 $out = $this->enigma->gettext('nokeysfound'); | |
| 307 } | |
| 308 else { | |
| 309 $pagesize = $this->rc->config->get('pagesize', 100); | |
| 310 $first = ($page - 1) * $pagesize; | |
| 311 | |
| 312 $out = $this->enigma->gettext(array( | |
| 313 'name' => 'keysfromto', | |
| 314 'vars' => array( | |
| 315 'from' => $first + 1, | |
| 316 'to' => $first + $curr_count, | |
| 317 'count' => $all) | |
| 318 )); | |
| 319 } | |
| 320 | |
| 321 return $out; | |
| 322 } | |
| 323 | |
| 324 /** | |
| 325 * Key information page handler | |
| 326 */ | |
| 327 private function key_info() | |
| 328 { | |
| 329 $this->enigma->load_engine(); | |
| 330 | |
| 331 $id = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GET); | |
| 332 $res = $this->enigma->engine->get_key($id); | |
| 333 | |
| 334 if ($res instanceof enigma_key) { | |
| 335 $this->data = $res; | |
| 336 } | |
| 337 else { // error | |
| 338 $this->rc->output->show_message('enigma.keyopenerror', 'error'); | |
| 339 $this->rc->output->command('parent.enigma_loadframe'); | |
| 340 $this->rc->output->send('iframe'); | |
| 341 } | |
| 342 | |
| 343 $this->rc->output->add_handlers(array( | |
| 344 'keyname' => array($this, 'tpl_key_name'), | |
| 345 'keydata' => array($this, 'tpl_key_data'), | |
| 346 )); | |
| 347 | |
| 348 $this->rc->output->set_pagetitle($this->enigma->gettext('keyinfo')); | |
| 349 $this->rc->output->send('enigma.keyinfo'); | |
| 350 } | |
| 351 | |
| 352 /** | |
| 353 * Template object for key name | |
| 354 */ | |
| 355 function tpl_key_name($attrib) | |
| 356 { | |
| 357 return rcube::Q($this->data->name); | |
| 358 } | |
| 359 | |
| 360 /** | |
| 361 * Template object for key information page content | |
| 362 */ | |
| 363 function tpl_key_data($attrib) | |
| 364 { | |
| 365 $out = ''; | |
| 366 $table = new html_table(array('cols' => 2)); | |
| 367 | |
| 368 // Key user ID | |
| 369 $table->add('title', $this->enigma->gettext('keyuserid')); | |
| 370 $table->add(null, rcube::Q($this->data->name)); | |
| 371 | |
| 372 // Key ID | |
| 373 $table->add('title', $this->enigma->gettext('keyid')); | |
| 374 $table->add(null, $this->data->subkeys[0]->get_short_id()); | |
| 375 | |
| 376 // Key type | |
| 377 $keytype = $this->data->get_type(); | |
| 378 if ($keytype == enigma_key::TYPE_KEYPAIR) { | |
| 379 $type = $this->enigma->gettext('typekeypair'); | |
| 380 } | |
| 381 else if ($keytype == enigma_key::TYPE_PUBLIC) { | |
| 382 $type = $this->enigma->gettext('typepublickey'); | |
| 383 } | |
| 384 $table->add('title', $this->enigma->gettext('keytype')); | |
| 385 $table->add(null, $type); | |
| 386 | |
| 387 // Key fingerprint | |
| 388 $table->add('title', $this->enigma->gettext('fingerprint')); | |
| 389 $table->add(null, $this->data->subkeys[0]->get_fingerprint()); | |
| 390 | |
| 391 $out .= html::tag('fieldset', null, | |
| 392 html::tag('legend', null, | |
| 393 $this->enigma->gettext('basicinfo')) . $table->show($attrib)); | |
| 394 | |
| 395 // Subkeys | |
| 396 $table = new html_table(array('cols' => 5, 'id' => 'enigmasubkeytable', 'class' => 'records-table')); | |
| 397 | |
| 398 $table->add_header('id', $this->enigma->gettext('subkeyid')); | |
| 399 $table->add_header('algo', $this->enigma->gettext('subkeyalgo')); | |
| 400 $table->add_header('created', $this->enigma->gettext('subkeycreated')); | |
| 401 $table->add_header('expires', $this->enigma->gettext('subkeyexpires')); | |
| 402 $table->add_header('usage', $this->enigma->gettext('subkeyusage')); | |
| 403 | |
| 404 $now = time(); | |
| 405 $date_format = $this->rc->config->get('date_format', 'Y-m-d'); | |
| 406 $usage_map = array( | |
| 407 enigma_key::CAN_ENCRYPT => $this->enigma->gettext('typeencrypt'), | |
| 408 enigma_key::CAN_SIGN => $this->enigma->gettext('typesign'), | |
| 409 enigma_key::CAN_CERTIFY => $this->enigma->gettext('typecert'), | |
| 410 enigma_key::CAN_AUTHENTICATE => $this->enigma->gettext('typeauth'), | |
| 411 ); | |
| 412 | |
| 413 foreach ($this->data->subkeys as $subkey) { | |
| 414 $algo = $subkey->get_algorithm(); | |
| 415 if ($algo && $subkey->length) { | |
| 416 $algo .= ' (' . $subkey->length . ')'; | |
| 417 } | |
| 418 | |
| 419 $usage = array(); | |
| 420 foreach ($usage_map as $key => $text) { | |
| 421 if ($subkey->usage & $key) { | |
| 422 $usage[] = $text; | |
| 423 } | |
| 424 } | |
| 425 | |
| 426 $table->add('id', $subkey->get_short_id()); | |
| 427 $table->add('algo', $algo); | |
| 428 $table->add('created', $subkey->created ? $this->rc->format_date($subkey->created, $date_format, false) : ''); | |
| 429 $table->add('expires', $subkey->expires ? $this->rc->format_date($subkey->expires, $date_format, false) : $this->enigma->gettext('expiresnever')); | |
| 430 $table->add('usage', implode(',', $usage)); | |
| 431 $table->set_row_attribs($subkey->revoked || ($subkey->expires && $subkey->expires < $now) ? 'deleted' : ''); | |
| 432 } | |
| 433 | |
| 434 $out .= html::tag('fieldset', null, | |
| 435 html::tag('legend', null, | |
| 436 $this->enigma->gettext('subkeys')) . $table->show()); | |
| 437 | |
| 438 // Additional user IDs | |
| 439 $table = new html_table(array('cols' => 2, 'id' => 'enigmausertable', 'class' => 'records-table')); | |
| 440 | |
| 441 $table->add_header('id', $this->enigma->gettext('userid')); | |
| 442 $table->add_header('valid', $this->enigma->gettext('uservalid')); | |
| 443 | |
| 444 foreach ($this->data->users as $user) { | |
| 445 $username = $user->name; | |
| 446 if ($user->comment) { | |
| 447 $username .= ' (' . $user->comment . ')'; | |
| 448 } | |
| 449 $username .= ' <' . $user->email . '>'; | |
| 450 | |
| 451 $table->add('id', rcube::Q(trim($username))); | |
| 452 $table->add('valid', $this->enigma->gettext($user->valid ? 'valid' : 'unknown')); | |
| 453 $table->set_row_attribs($user->revoked || !$user->valid ? 'deleted' : ''); | |
| 454 } | |
| 455 | |
| 456 $out .= html::tag('fieldset', null, | |
| 457 html::tag('legend', null, | |
| 458 $this->enigma->gettext('userids')) . $table->show()); | |
| 459 | |
| 460 return $out; | |
| 461 } | |
| 462 | |
| 463 /** | |
| 464 * Key(s) export handler | |
| 465 */ | |
| 466 private function key_export() | |
| 467 { | |
| 468 $keys = rcube_utils::get_input_value('_keys', rcube_utils::INPUT_POST); | |
| 469 $priv = rcube_utils::get_input_value('_priv', rcube_utils::INPUT_POST); | |
| 470 $engine = $this->enigma->load_engine(); | |
| 471 $list = $keys == '*' ? $engine->list_keys() : explode(',', $keys); | |
| 472 | |
| 473 if (is_array($list) && ($fp = fopen('php://memory', 'rw'))) { | |
| 474 $filename = 'export.pgp'; | |
| 475 if (count($list) == 1) { | |
| 476 $filename = (is_object($list[0]) ? $list[0]->id : $list[0]) . '.pgp'; | |
| 477 } | |
| 478 | |
| 479 $status = null; | |
| 480 foreach ($list as $key) { | |
| 481 $keyid = is_object($key) ? $key->id : $key; | |
| 482 $status = $engine->export_key($keyid, $fp, (bool) $priv); | |
| 483 | |
| 484 if ($status instanceof enigma_error) { | |
| 485 $code = $status->getCode(); | |
| 486 | |
| 487 if ($code == enigma_error::BADPASS) { | |
| 488 $this->password_prompt($status, array( | |
| 489 'input_keys' => $keys, | |
| 490 'input_priv' => 1, | |
| 491 'input_task' => 'settings', | |
| 492 'input_action' => 'plugin.enigmakeys', | |
| 493 'input_a' => 'export', | |
| 494 'action' => '?', | |
| 495 'iframe' => true, | |
| 496 'nolock' => true, | |
| 497 'keyid' => $keyid, | |
| 498 )); | |
| 499 fclose($fp); | |
| 500 $this->rc->output->send('iframe'); | |
| 501 } | |
| 502 } | |
| 503 } | |
| 504 | |
| 505 // send downlaod headers | |
| 506 header('Content-Type: application/pgp-keys'); | |
| 507 header('Content-Disposition: attachment; filename="' . $filename . '"'); | |
| 508 | |
| 509 rewind($fp); | |
| 510 while (!feof($fp)) { | |
| 511 echo fread($fp, 1024 * 1024); | |
| 512 } | |
| 513 fclose($fp); | |
| 514 } | |
| 515 | |
| 516 exit; | |
| 517 } | |
| 518 | |
| 519 /** | |
| 520 * Key import (page) handler | |
| 521 */ | |
| 522 private function key_import() | |
| 523 { | |
| 524 // Import process | |
| 525 if ($data = rcube_utils::get_input_value('_keys', rcube_utils::INPUT_POST)) { | |
| 526 $this->enigma->load_engine(); | |
| 527 $this->enigma->engine->password_handler(); | |
| 528 | |
| 529 $result = $this->enigma->engine->import_key($data); | |
| 530 | |
| 531 if (is_array($result)) { | |
| 532 if (rcube_utils::get_input_value('_generated', rcube_utils::INPUT_POST)) { | |
| 533 $this->rc->output->command('enigma_key_create_success'); | |
| 534 $this->rc->output->show_message('enigma.keygeneratesuccess', 'confirmation'); | |
| 535 } | |
| 536 else { | |
| 537 $this->rc->output->show_message('enigma.keysimportsuccess', 'confirmation', | |
| 538 array('new' => $result['imported'], 'old' => $result['unchanged'])); | |
| 539 | |
| 540 if ($result['imported'] && !empty($_POST['_refresh'])) { | |
| 541 $this->rc->output->command('enigma_list', 1, false); | |
| 542 } | |
| 543 } | |
| 544 } | |
| 545 else { | |
| 546 $this->rc->output->show_message('enigma.keysimportfailed', 'error'); | |
| 547 } | |
| 548 | |
| 549 $this->rc->output->send(); | |
| 550 } | |
| 551 else if ($_FILES['_file']['tmp_name'] && is_uploaded_file($_FILES['_file']['tmp_name'])) { | |
| 552 $this->enigma->load_engine(); | |
| 553 $result = $this->enigma->engine->import_key($_FILES['_file']['tmp_name'], true); | |
| 554 | |
| 555 if (is_array($result)) { | |
| 556 // reload list if any keys has been added | |
| 557 if ($result['imported']) { | |
| 558 $this->rc->output->command('parent.enigma_list', 1); | |
| 559 } | |
| 560 else { | |
| 561 $this->rc->output->command('parent.enigma_loadframe'); | |
| 562 } | |
| 563 | |
| 564 $this->rc->output->show_message('enigma.keysimportsuccess', 'confirmation', | |
| 565 array('new' => $result['imported'], 'old' => $result['unchanged'])); | |
| 566 } | |
| 567 else if ($result instanceof enigma_error && $result->getCode() == enigma_error::BADPASS) { | |
| 568 $this->password_prompt($result); | |
| 569 } | |
| 570 else { | |
| 571 $this->rc->output->show_message('enigma.keysimportfailed', 'error'); | |
| 572 } | |
| 573 | |
| 574 $this->rc->output->send('iframe'); | |
| 575 } | |
| 576 else if ($err = $_FILES['_file']['error']) { | |
| 577 if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) { | |
| 578 $this->rc->output->show_message('filesizeerror', 'error', | |
| 579 array('size' => $this->rc->show_bytes(rcube_utils::max_upload_size()))); | |
| 580 } else { | |
| 581 $this->rc->output->show_message('fileuploaderror', 'error'); | |
| 582 } | |
| 583 | |
| 584 $this->rc->output->send('iframe'); | |
| 585 } | |
| 586 | |
| 587 $this->rc->output->add_handlers(array( | |
| 588 'importform' => array($this, 'tpl_key_import_form'), | |
| 589 )); | |
| 590 | |
| 591 $this->rc->output->set_pagetitle($this->enigma->gettext('keyimport')); | |
| 592 $this->rc->output->send('enigma.keyimport'); | |
| 593 } | |
| 594 | |
| 595 /** | |
| 596 * Template object for key import (upload) form | |
| 597 */ | |
| 598 function tpl_key_import_form($attrib) | |
| 599 { | |
| 600 $attrib += array('id' => 'rcmKeyImportForm'); | |
| 601 | |
| 602 $upload = new html_inputfield(array('type' => 'file', 'name' => '_file', | |
| 603 'id' => 'rcmimportfile', 'size' => 30)); | |
| 604 $search = new html_inputfield(array('type' => 'text', 'name' => '_search', | |
| 605 'id' => 'rcmimportsearch', 'size' => 30)); | |
| 606 | |
| 607 $upload_button = new html_inputfield(array( | |
| 608 'type' => 'button', | |
| 609 'value' => $this->rc->gettext('import'), | |
| 610 'class' => 'button', | |
| 611 'onclick' => "return rcmail.command('plugin.enigma-import','',this,event)", | |
| 612 )); | |
| 613 | |
| 614 $search_button = new html_inputfield(array( | |
| 615 'type' => 'button', | |
| 616 'value' => $this->rc->gettext('search'), | |
| 617 'class' => 'button', | |
| 618 'onclick' => "return rcmail.command('plugin.enigma-import-search','',this,event)", | |
| 619 )); | |
| 620 | |
| 621 $upload_form = html::div(null, | |
| 622 rcube::Q($this->enigma->gettext('keyimporttext'), 'show') | |
| 623 . html::br() . html::br() . $upload->show() | |
| 624 . html::br() . html::br() . $upload_button->show() | |
| 625 ); | |
| 626 | |
| 627 $search_form = html::div(null, | |
| 628 rcube::Q($this->enigma->gettext('keyimportsearchtext'), 'show') | |
| 629 . html::br() . html::br() . $search->show() | |
| 630 . html::br() . html::br() . $search_button->show() | |
| 631 ); | |
| 632 | |
| 633 $form = html::tag('fieldset', '', html::tag('legend', null, $this->enigma->gettext('keyimportlabel')) . $upload_form) | |
| 634 . html::tag('fieldset', '', html::tag('legend', null, $this->enigma->gettext('keyimportsearchlabel')) . $search_form); | |
| 635 | |
| 636 $this->rc->output->add_label('selectimportfile', 'importwait', 'nopubkeyfor', 'nopubkeyforsender', | |
| 637 'encryptnoattachments','encryptedsendialog','searchpubkeyservers', 'importpubkeys', | |
| 638 'encryptpubkeysfound', 'search', 'close', 'import', 'keyid', 'keylength', 'keyexpired', | |
| 639 'keyrevoked', 'keyimportsuccess', 'keyservererror'); | |
| 640 $this->rc->output->add_gui_object('importform', $attrib['id']); | |
| 641 $this->rc->output->include_script('publickey.js'); | |
| 642 | |
| 643 $out = $this->rc->output->form_tag(array( | |
| 644 'action' => $this->rc->url(array('action' => $this->rc->action, 'a' => 'import')), | |
| 645 'method' => 'post', | |
| 646 'enctype' => 'multipart/form-data') + $attrib, | |
| 647 $form | |
| 648 ); | |
| 649 | |
| 650 return $out; | |
| 651 } | |
| 652 | |
| 653 /** | |
| 654 * Server-side key pair generation handler | |
| 655 */ | |
| 656 private function key_generate() | |
| 657 { | |
| 658 // Crypt_GPG does not support key generation for multiple identities | |
| 659 // It is also very slow (which is problematic because it may exceed | |
| 660 // request time limit) and requires entropy generator | |
| 661 // That's why we use only OpenPGP.js method of key generation | |
| 662 return; | |
| 663 | |
| 664 $user = rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST, true); | |
| 665 $pass = rcube_utils::get_input_value('_password', rcube_utils::INPUT_POST, true); | |
| 666 $size = (int) rcube_utils::get_input_value('_size', rcube_utils::INPUT_POST); | |
| 667 | |
| 668 if ($size > 4096) { | |
| 669 $size = 4096; | |
| 670 } | |
| 671 | |
| 672 $ident = rcube_mime::decode_address_list($user, 1, false); | |
| 673 | |
| 674 if (empty($ident)) { | |
| 675 $this->rc->output->show_message('enigma.keygenerateerror', 'error'); | |
| 676 $this->rc->output->send(); | |
| 677 } | |
| 678 | |
| 679 $this->enigma->load_engine(); | |
| 680 $result = $this->enigma->engine->generate_key(array( | |
| 681 'user' => $ident[1]['name'], | |
| 682 'email' => $ident[1]['mailto'], | |
| 683 'password' => $pass, | |
| 684 'size' => $size, | |
| 685 )); | |
| 686 | |
| 687 if ($result instanceof enigma_key) { | |
| 688 $this->rc->output->command('enigma_key_create_success'); | |
| 689 $this->rc->output->show_message('enigma.keygeneratesuccess', 'confirmation'); | |
| 690 } | |
| 691 else { | |
| 692 $this->rc->output->show_message('enigma.keygenerateerror', 'error'); | |
| 693 } | |
| 694 | |
| 695 $this->rc->output->send(); | |
| 696 } | |
| 697 | |
| 698 /** | |
| 699 * Key generation page handler | |
| 700 */ | |
| 701 private function key_create() | |
| 702 { | |
| 703 $this->enigma->include_script('openpgp.min.js'); | |
| 704 | |
| 705 $this->rc->output->add_handlers(array( | |
| 706 'keyform' => array($this, 'tpl_key_create_form'), | |
| 707 )); | |
| 708 | |
| 709 $this->rc->output->set_pagetitle($this->enigma->gettext('keygenerate')); | |
| 710 $this->rc->output->send('enigma.keycreate'); | |
| 711 } | |
| 712 | |
| 713 /** | |
| 714 * Template object for key generation form | |
| 715 */ | |
| 716 function tpl_key_create_form($attrib) | |
| 717 { | |
| 718 $attrib += array('id' => 'rcmKeyCreateForm'); | |
| 719 $table = new html_table(array('cols' => 2)); | |
| 720 | |
| 721 // get user's identities | |
| 722 $identities = $this->rc->user->list_identities(null, true); | |
| 723 $checkbox = new html_checkbox(array('name' => 'identity[]')); | |
| 724 foreach ((array) $identities as $idx => $ident) { | |
| 725 $name = empty($ident['name']) ? ($ident['email']) : $ident['ident']; | |
| 726 $identities[$idx] = html::label(null, $checkbox->show($name, array('value' => $name)) . rcube::Q($name)); | |
| 727 } | |
| 728 | |
| 729 $table->add('title', html::label('key-name', rcube::Q($this->enigma->gettext('newkeyident')))); | |
| 730 $table->add(null, implode($identities, "\n")); | |
| 731 | |
| 732 // Key size | |
| 733 $select = new html_select(array('name' => 'size', 'id' => 'key-size')); | |
| 734 $select->add($this->enigma->gettext('key2048'), '2048'); | |
| 735 $select->add($this->enigma->gettext('key4096'), '4096'); | |
| 736 | |
| 737 $table->add('title', html::label('key-size', rcube::Q($this->enigma->gettext('newkeysize')))); | |
| 738 $table->add(null, $select->show()); | |
| 739 | |
| 740 // Password and confirm password | |
| 741 $table->add('title', html::label('key-pass', rcube::Q($this->enigma->gettext('newkeypass')))); | |
| 742 $table->add(null, rcube_output::get_edit_field('password', '', | |
| 743 array('id' => 'key-pass', 'size' => $attrib['size'], 'required' => true), 'password')); | |
| 744 | |
| 745 $table->add('title', html::label('key-pass-confirm', rcube::Q($this->enigma->gettext('newkeypassconfirm')))); | |
| 746 $table->add(null, rcube_output::get_edit_field('password-confirm', '', | |
| 747 array('id' => 'key-pass-confirm', 'size' => $attrib['size'], 'required' => true), 'password')); | |
| 748 | |
| 749 $this->rc->output->add_gui_object('keyform', $attrib['id']); | |
| 750 $this->rc->output->add_label('enigma.keygenerating', 'enigma.formerror', | |
| 751 'enigma.passwordsdiffer', 'enigma.keygenerateerror', 'enigma.noidentselected', | |
| 752 'enigma.keygennosupport'); | |
| 753 | |
| 754 return $this->rc->output->form_tag(array(), $table->show($attrib)); | |
| 755 } | |
| 756 | |
| 757 /** | |
| 758 * Key deleting | |
| 759 */ | |
| 760 private function key_delete() | |
| 761 { | |
| 762 $keys = rcube_utils::get_input_value('_keys', rcube_utils::INPUT_POST); | |
| 763 $engine = $this->enigma->load_engine(); | |
| 764 | |
| 765 foreach ((array)$keys as $key) { | |
| 766 $res = $engine->delete_key($key); | |
| 767 | |
| 768 if ($res !== true) { | |
| 769 $this->rc->output->show_message('enigma.keyremoveerror', 'error'); | |
| 770 $this->rc->output->command('enigma_list'); | |
| 771 $this->rc->output->send(); | |
| 772 } | |
| 773 } | |
| 774 | |
| 775 $this->rc->output->command('enigma_list'); | |
| 776 $this->rc->output->show_message('enigma.keyremovesuccess', 'confirmation'); | |
| 777 $this->rc->output->send(); | |
| 778 } | |
| 779 | |
| 780 /** | |
| 781 * Init compose UI (add task button and the menu) | |
| 782 */ | |
| 783 private function compose_ui() | |
| 784 { | |
| 785 $this->add_css(); | |
| 786 | |
| 787 // Options menu button | |
| 788 $this->enigma->add_button(array( | |
| 789 'type' => 'link', | |
| 790 'command' => 'plugin.enigma', | |
| 791 'onclick' => "rcmail.command('menu-open', 'enigmamenu', event.target, event)", | |
| 792 'class' => 'button enigma', | |
| 793 'title' => 'encryptionoptions', | |
| 794 'label' => 'encryption', | |
| 795 'domain' => $this->enigma->ID, | |
| 796 'width' => 32, | |
| 797 'height' => 32, | |
| 798 'aria-owns' => 'enigmamenu', | |
| 799 'aria-haspopup' => 'true', | |
| 800 'aria-expanded' => 'false', | |
| 801 ), 'toolbar'); | |
| 802 | |
| 803 $locks = (array) $this->rc->config->get('enigma_options_lock'); | |
| 804 $menu = new html_table(array('cols' => 2)); | |
| 805 $chbox = new html_checkbox(array('value' => 1)); | |
| 806 | |
| 807 $menu->add(null, html::label(array('for' => 'enigmasignopt'), | |
| 808 rcube::Q($this->enigma->gettext('signmsg')))); | |
| 809 $menu->add(null, $chbox->show($this->rc->config->get('enigma_sign_all') ? 1 : 0, | |
| 810 array( | |
| 811 'name' => '_enigma_sign', | |
| 812 'id' => 'enigmasignopt', | |
| 813 'disabled' => in_array('sign', $locks), | |
| 814 ))); | |
| 815 | |
| 816 $menu->add(null, html::label(array('for' => 'enigmaencryptopt'), | |
| 817 rcube::Q($this->enigma->gettext('encryptmsg')))); | |
| 818 $menu->add(null, $chbox->show($this->rc->config->get('enigma_encrypt_all') ? 1 : 0, | |
| 819 array( | |
| 820 'name' => '_enigma_encrypt', | |
| 821 'id' => 'enigmaencryptopt', | |
| 822 'disabled' => in_array('encrypt', $locks), | |
| 823 ))); | |
| 824 | |
| 825 $menu->add(null, html::label(array('for' => 'enigmaattachpubkeyopt'), | |
| 826 rcube::Q($this->enigma->gettext('attachpubkeymsg')))); | |
| 827 $menu->add(null, $chbox->show($this->rc->config->get('enigma_attach_pubkey') ? 1 : 0, | |
| 828 array( | |
| 829 'name' => '_enigma_attachpubkey', | |
| 830 'id' => 'enigmaattachpubkeyopt', | |
| 831 'disabled' => in_array('pubkey', $locks), | |
| 832 ))); | |
| 833 | |
| 834 $menu = html::div(array('id' => 'enigmamenu', 'class' => 'popupmenu'), $menu->show()); | |
| 835 | |
| 836 // Options menu contents | |
| 837 $this->rc->output->add_footer($menu); | |
| 838 } | |
| 839 | |
| 840 /** | |
| 841 * Handler for message_body_prefix hook. | |
| 842 * Called for every displayed (content) part of the message. | |
| 843 * Adds infobox about signature verification and/or decryption | |
| 844 * status above the body. | |
| 845 * | |
| 846 * @param array Original parameters | |
| 847 * | |
| 848 * @return array Modified parameters | |
| 849 */ | |
| 850 function status_message($p) | |
| 851 { | |
| 852 // skip: not a message part | |
| 853 if ($p['part'] instanceof rcube_message) { | |
| 854 return $p; | |
| 855 } | |
| 856 | |
| 857 // skip: message has no signed/encoded content | |
| 858 if (!$this->enigma->engine) { | |
| 859 return $p; | |
| 860 } | |
| 861 | |
| 862 $engine = $this->enigma->engine; | |
| 863 $part_id = $p['part']->mime_id; | |
| 864 $messages = array(); | |
| 865 | |
| 866 // Decryption status | |
| 867 if (($found = $this->find_part_id($part_id, $engine->decryptions)) !== null | |
| 868 && ($status = $engine->decryptions[$found]) | |
| 869 ) { | |
| 870 $attach_scripts = true; | |
| 871 | |
| 872 // show the message only once | |
| 873 unset($engine->decryptions[$found]); | |
| 874 | |
| 875 // display status info | |
| 876 $attrib['id'] = 'enigma-message'; | |
| 877 | |
| 878 if ($status instanceof enigma_error) { | |
| 879 $attrib['class'] = 'enigmaerror'; | |
| 880 $code = $status->getCode(); | |
| 881 | |
| 882 if ($code == enigma_error::KEYNOTFOUND) { | |
| 883 $msg = rcube::Q(str_replace('$keyid', enigma_key::format_id($status->getData('id')), | |
| 884 $this->enigma->gettext('decryptnokey'))); | |
| 885 } | |
| 886 else if ($code == enigma_error::BADPASS) { | |
| 887 $missing = $status->getData('missing'); | |
| 888 $label = 'decrypt' . (!empty($missing) ? 'no' : 'bad') . 'pass'; | |
| 889 $msg = rcube::Q($this->enigma->gettext($label)); | |
| 890 $this->password_prompt($status); | |
| 891 } | |
| 892 else { | |
| 893 $msg = rcube::Q($this->enigma->gettext('decrypterror')); | |
| 894 } | |
| 895 } | |
| 896 else if ($status === enigma_engine::ENCRYPTED_PARTIALLY) { | |
| 897 $attrib['class'] = 'enigmawarning'; | |
| 898 $msg = rcube::Q($this->enigma->gettext('decryptpartial')); | |
| 899 } | |
| 900 else { | |
| 901 $attrib['class'] = 'enigmanotice'; | |
| 902 $msg = rcube::Q($this->enigma->gettext('decryptok')); | |
| 903 } | |
| 904 | |
| 905 $attrib['msg'] = $msg; | |
| 906 $messages[] = $attrib; | |
| 907 } | |
| 908 | |
| 909 // Signature verification status | |
| 910 if (($found = $this->find_part_id($part_id, $engine->signatures)) !== null | |
| 911 && ($sig = $engine->signatures[$found]) | |
| 912 ) { | |
| 913 $attach_scripts = true; | |
| 914 | |
| 915 // show the message only once | |
| 916 unset($engine->signatures[$found]); | |
| 917 | |
| 918 // display status info | |
| 919 $attrib['id'] = 'enigma-message'; | |
| 920 | |
| 921 if ($sig instanceof enigma_signature) { | |
| 922 $sender = $sig->name ?: ''; | |
| 923 if ($sig->email) { | |
| 924 $sender .= ' <' . $sig->email . '>'; | |
| 925 } | |
| 926 | |
| 927 if ($sig->valid === enigma_error::UNVERIFIED) { | |
| 928 $attrib['class'] = 'enigmawarning'; | |
| 929 $msg = str_replace('$sender', $sender, $this->enigma->gettext('sigunverified')); | |
| 930 $msg = str_replace('$keyid', $sig->id, $msg); | |
| 931 $msg = rcube::Q($msg); | |
| 932 } | |
| 933 else if ($sig->valid) { | |
| 934 $attrib['class'] = $sig->partial ? 'enigmawarning' : 'enigmanotice'; | |
| 935 $label = 'sigvalid' . ($sig->partial ? 'partial' : ''); | |
| 936 $msg = rcube::Q(str_replace('$sender', $sender, $this->enigma->gettext($label))); | |
| 937 } | |
| 938 else { | |
| 939 $attrib['class'] = 'enigmawarning'; | |
| 940 if ($sender) { | |
| 941 $msg = rcube::Q(str_replace('$sender', $sender, $this->enigma->gettext('siginvalid'))); | |
| 942 } | |
| 943 else { | |
| 944 $msg = rcube::Q(str_replace('$keyid', enigma_key::format_id($sig->id), | |
| 945 $this->enigma->gettext('signokey'))); | |
| 946 } | |
| 947 } | |
| 948 } | |
| 949 else if ($sig && $sig->getCode() == enigma_error::KEYNOTFOUND) { | |
| 950 $attrib['class'] = 'enigmawarning'; | |
| 951 $msg = rcube::Q(str_replace('$keyid', enigma_key::format_id($sig->getData('id')), | |
| 952 $this->enigma->gettext('signokey'))); | |
| 953 } | |
| 954 else { | |
| 955 $attrib['class'] = 'enigmaerror'; | |
| 956 $msg = rcube::Q($this->enigma->gettext('sigerror')); | |
| 957 } | |
| 958 /* | |
| 959 $msg .= ' ' . html::a(array('href' => "#sigdetails", | |
| 960 'onclick' => rcmail_output::JS_OBJECT_NAME.".command('enigma-sig-details')"), | |
| 961 rcube::Q($this->enigma->gettext('showdetails'))); | |
| 962 */ | |
| 963 // test | |
| 964 // $msg .= '<br /><pre>'.$sig->body.'</pre>'; | |
| 965 | |
| 966 $attrib['msg'] = $msg; | |
| 967 $messages[] = $attrib; | |
| 968 } | |
| 969 | |
| 970 if ($count = count($messages)) { | |
| 971 if ($count == 2 && $messages[0]['class'] == $messages[1]['class']) { | |
| 972 $p['prefix'] .= html::div($messages[0], $messages[0]['msg'] . ' ' . $messages[1]['msg']); | |
| 973 } | |
| 974 else { | |
| 975 foreach ($messages as $msg) { | |
| 976 $p['prefix'] .= html::div($msg, $msg['msg']); | |
| 977 } | |
| 978 } | |
| 979 } | |
| 980 | |
| 981 if ($attach_scripts) { | |
| 982 // add css and js script | |
| 983 $this->add_css(); | |
| 984 $this->add_js(); | |
| 985 } | |
| 986 | |
| 987 return $p; | |
| 988 } | |
| 989 | |
| 990 /** | |
| 991 * Handler for message_load hook. | |
| 992 * Check message bodies and attachments for keys/certs. | |
| 993 */ | |
| 994 function message_load($p) | |
| 995 { | |
| 996 $engine = $this->enigma->load_engine(); | |
| 997 | |
| 998 // handle keys/certs in attachments | |
| 999 foreach ((array) $p['object']->attachments as $attachment) { | |
| 1000 if ($engine->is_keys_part($attachment)) { | |
| 1001 $this->keys_parts[] = $attachment->mime_id; | |
| 1002 } | |
| 1003 } | |
| 1004 | |
| 1005 // the same with message bodies | |
| 1006 foreach ((array) $p['object']->parts as $part) { | |
| 1007 if ($engine->is_keys_part($part)) { | |
| 1008 $this->keys_parts[] = $part->mime_id; | |
| 1009 $this->keys_bodies[] = $part->mime_id; | |
| 1010 } | |
| 1011 } | |
| 1012 | |
| 1013 // @TODO: inline PGP keys | |
| 1014 | |
| 1015 if ($this->keys_parts) { | |
| 1016 $this->enigma->add_texts('localization'); | |
| 1017 } | |
| 1018 | |
| 1019 return $p; | |
| 1020 } | |
| 1021 | |
| 1022 /** | |
| 1023 * Handler for template_object_messagebody hook. | |
| 1024 * This callback function adds a box below the message content | |
| 1025 * if there is a key/cert attachment available | |
| 1026 */ | |
| 1027 function message_output($p) | |
| 1028 { | |
| 1029 foreach ($this->keys_parts as $part) { | |
| 1030 // remove part's body | |
| 1031 if (in_array($part, $this->keys_bodies)) { | |
| 1032 $p['content'] = ''; | |
| 1033 } | |
| 1034 | |
| 1035 // add box below message body | |
| 1036 $p['content'] .= html::p(array('class' => 'enigmaattachment'), | |
| 1037 html::a(array( | |
| 1038 'href' => "#", | |
| 1039 'onclick' => "return ".rcmail_output::JS_OBJECT_NAME.".enigma_import_attachment('".rcube::JQ($part)."')", | |
| 1040 'title' => $this->enigma->gettext('keyattimport')), | |
| 1041 html::span(null, $this->enigma->gettext('keyattfound')))); | |
| 1042 | |
| 1043 $attach_scripts = true; | |
| 1044 } | |
| 1045 | |
| 1046 if ($attach_scripts) { | |
| 1047 // add css and js script | |
| 1048 $this->add_css(); | |
| 1049 $this->add_js(); | |
| 1050 } | |
| 1051 | |
| 1052 return $p; | |
| 1053 } | |
| 1054 | |
| 1055 /** | |
| 1056 * Handle message_ready hook (encryption/signing/attach public key) | |
| 1057 */ | |
| 1058 function message_ready($p) | |
| 1059 { | |
| 1060 $savedraft = !empty($_POST['_draft']) && empty($_GET['_saveonly']); | |
| 1061 $sign_enable = (bool) rcube_utils::get_input_value('_enigma_sign', rcube_utils::INPUT_POST); | |
| 1062 $encrypt_enable = (bool) rcube_utils::get_input_value('_enigma_encrypt', rcube_utils::INPUT_POST); | |
| 1063 $pubkey_enable = (bool) rcube_utils::get_input_value('_enigma_attachpubkey', rcube_utils::INPUT_POST); | |
| 1064 $locks = (array) $this->rc->config->get('enigma_options_lock'); | |
| 1065 | |
| 1066 if (in_array('sign', $locks)) { | |
| 1067 $sign_enable = (bool) $this->rc->config->get('enigma_sign_all'); | |
| 1068 } | |
| 1069 if (in_array('encrypt', $locks)) { | |
| 1070 $encrypt_enable = (bool) $this->rc->config->get('enigma_encrypt_all'); | |
| 1071 } | |
| 1072 if (in_array('pubkey', $locks)) { | |
| 1073 $pubkey_enable = (bool) $this->rc->config->get('enigma_attach_pubkey'); | |
| 1074 } | |
| 1075 | |
| 1076 if (!$savedraft && $pubkey_enable) { | |
| 1077 $engine = $this->enigma->load_engine(); | |
| 1078 $engine->attach_public_key($p['message']); | |
| 1079 } | |
| 1080 | |
| 1081 if ($encrypt_enable) { | |
| 1082 $engine = $this->enigma->load_engine(); | |
| 1083 $mode = !$savedraft && $sign_enable ? enigma_engine::ENCRYPT_MODE_SIGN : null; | |
| 1084 $status = $engine->encrypt_message($p['message'], $mode, $savedraft); | |
| 1085 $mode = 'encrypt'; | |
| 1086 } | |
| 1087 else if (!$savedraft && $sign_enable) { | |
| 1088 $engine = $this->enigma->load_engine(); | |
| 1089 $status = $engine->sign_message($p['message'], enigma_engine::SIGN_MODE_MIME); | |
| 1090 $mode = 'sign'; | |
| 1091 } | |
| 1092 | |
| 1093 if ($mode && ($status instanceof enigma_error)) { | |
| 1094 $code = $status->getCode(); | |
| 1095 | |
| 1096 if ($code == enigma_error::KEYNOTFOUND) { | |
| 1097 $vars = array('email' => $status->getData('missing')); | |
| 1098 $msg = 'enigma.' . $mode . 'nokey'; | |
| 1099 } | |
| 1100 else if ($code == enigma_error::BADPASS) { | |
| 1101 $this->password_prompt($status); | |
| 1102 } | |
| 1103 else { | |
| 1104 $msg = 'enigma.' . $mode . 'error'; | |
| 1105 } | |
| 1106 | |
| 1107 if ($msg) { | |
| 1108 if ($vars && $vars['email']) { | |
| 1109 $this->rc->output->command('enigma_key_not_found', array( | |
| 1110 'email' => $vars['email'], | |
| 1111 'text' => $this->rc->gettext(array('name' => $msg, 'vars' => $vars)), | |
| 1112 'title' => $this->enigma->gettext('keynotfound'), | |
| 1113 'button' => $this->enigma->gettext('findkey'), | |
| 1114 )); | |
| 1115 } | |
| 1116 else { | |
| 1117 $this->rc->output->show_message($msg, 'error', $vars); | |
| 1118 } | |
| 1119 } | |
| 1120 | |
| 1121 $this->rc->output->send('iframe'); | |
| 1122 } | |
| 1123 | |
| 1124 return $p; | |
| 1125 } | |
| 1126 | |
| 1127 /** | |
| 1128 * Handler for message_compose_body hook | |
| 1129 * Display error when the message cannot be encrypted | |
| 1130 * and provide a way to try again with a password. | |
| 1131 */ | |
| 1132 function message_compose($p) | |
| 1133 { | |
| 1134 $engine = $this->enigma->load_engine(); | |
| 1135 | |
| 1136 // skip: message has no signed/encoded content | |
| 1137 if (!$this->enigma->engine) { | |
| 1138 return $p; | |
| 1139 } | |
| 1140 | |
| 1141 $engine = $this->enigma->engine; | |
| 1142 $locks = (array) $this->rc->config->get('enigma_options_lock'); | |
| 1143 | |
| 1144 // Decryption status | |
| 1145 foreach ($engine->decryptions as $status) { | |
| 1146 if ($status instanceof enigma_error) { | |
| 1147 $code = $status->getCode(); | |
| 1148 | |
| 1149 if ($code == enigma_error::KEYNOTFOUND) { | |
| 1150 $msg = rcube::Q(str_replace('$keyid', enigma_key::format_id($status->getData('id')), | |
| 1151 $this->enigma->gettext('decryptnokey'))); | |
| 1152 } | |
| 1153 else if ($code == enigma_error::BADPASS) { | |
| 1154 $this->password_prompt($status, array('compose-init' => true)); | |
| 1155 return $p; | |
| 1156 } | |
| 1157 else { | |
| 1158 $msg = rcube::Q($this->enigma->gettext('decrypterror')); | |
| 1159 } | |
| 1160 } | |
| 1161 } | |
| 1162 | |
| 1163 if ($msg) { | |
| 1164 $this->rc->output->show_message($msg, 'error'); | |
| 1165 } | |
| 1166 | |
| 1167 // Check sign/ecrypt options for signed/encrypted drafts | |
| 1168 if (!in_array('encrypt', $locks)) { | |
| 1169 $this->rc->output->set_env('enigma_force_encrypt', !empty($engine->decryptions)); | |
| 1170 } | |
| 1171 if (!in_array('sign', $locks)) { | |
| 1172 $this->rc->output->set_env('enigma_force_sign', !empty($engine->signatures)); | |
| 1173 } | |
| 1174 | |
| 1175 return $p; | |
| 1176 } | |
| 1177 | |
| 1178 /** | |
| 1179 * Handler for keys/certs import request action | |
| 1180 */ | |
| 1181 function import_file() | |
| 1182 { | |
| 1183 $uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST); | |
| 1184 $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST); | |
| 1185 $mime_id = rcube_utils::get_input_value('_part', rcube_utils::INPUT_POST); | |
| 1186 $storage = $this->rc->get_storage(); | |
| 1187 $engine = $this->enigma->load_engine(); | |
| 1188 | |
| 1189 if ($uid && $mime_id) { | |
| 1190 // Note: we get the attachment body via rcube_message class | |
| 1191 // to support keys inside encrypted messages (#5285) | |
| 1192 $message = new rcube_message($uid, $mbox); | |
| 1193 | |
| 1194 // Check if we don't need to ask for password again | |
| 1195 foreach ($engine->decryptions as $status) { | |
| 1196 if ($status instanceof enigma_error) { | |
| 1197 if ($status->getCode() == enigma_error::BADPASS) { | |
| 1198 $this->password_prompt($status, array( | |
| 1199 'input_uid' => $uid, | |
| 1200 'input_mbox' => $mbox, | |
| 1201 'input_part' => $mime_id, | |
| 1202 'input_task' => 'mail', | |
| 1203 'input_action' => 'plugin.enigmaimport', | |
| 1204 'action' => '?', | |
| 1205 'iframe' => true, | |
| 1206 )); | |
| 1207 $this->rc->output->send($this->rc->output->type == 'html' ? 'iframe' : null); | |
| 1208 return; | |
| 1209 } | |
| 1210 } | |
| 1211 } | |
| 1212 | |
| 1213 if ($engine->is_keys_part($message->mime_parts[$mime_id])) { | |
| 1214 $part = $message->get_part_body($mime_id); | |
| 1215 } | |
| 1216 } | |
| 1217 | |
| 1218 if ($part && is_array($result = $engine->import_key($part))) { | |
| 1219 $this->rc->output->show_message('enigma.keysimportsuccess', 'confirmation', | |
| 1220 array('new' => $result['imported'], 'old' => $result['unchanged'])); | |
| 1221 } | |
| 1222 else { | |
| 1223 $this->rc->output->show_message('enigma.keysimportfailed', 'error'); | |
| 1224 } | |
| 1225 | |
| 1226 $this->rc->output->send($this->rc->output->type == 'html' ? 'iframe' : null); | |
| 1227 } | |
| 1228 | |
| 1229 /** | |
| 1230 * Check if the part or its parent exists in the array | |
| 1231 * of decryptions/signatures. Returns found ID. | |
| 1232 */ | |
| 1233 private function find_part_id($part_id, $data) | |
| 1234 { | |
| 1235 $ids = explode('.', $part_id); | |
| 1236 $i = 0; | |
| 1237 $count = count($ids); | |
| 1238 | |
| 1239 while ($i < $count && strlen($part = implode('.', array_slice($ids, 0, ++$i)))) { | |
| 1240 if (array_key_exists($part, $data)) { | |
| 1241 return $part; | |
| 1242 } | |
| 1243 } | |
| 1244 } | |
| 1245 } |
