commit | author | age
|
48e9c1
|
1 |
<?php |
T |
2 |
/* |
|
3 |
+-------------------------------------------------------------------------+ |
|
4 |
| User Interface for the Enigma Plugin | |
|
5 |
| | |
|
6 |
| This program is free software; you can redistribute it and/or modify | |
|
7 |
| it under the terms of the GNU General Public License version 2 | |
|
8 |
| as published by the Free Software Foundation. | |
|
9 |
| | |
|
10 |
| This program is distributed in the hope that it will be useful, | |
|
11 |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
12 |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
13 |
| GNU General Public License for more details. | |
|
14 |
| | |
|
15 |
| You should have received a copy of the GNU General Public License along | |
|
16 |
| with this program; if not, write to the Free Software Foundation, Inc., | |
|
17 |
| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
|
18 |
| | |
|
19 |
+-------------------------------------------------------------------------+ |
|
20 |
| Author: Aleksander Machniak <alec@alec.pl> | |
|
21 |
+-------------------------------------------------------------------------+ |
|
22 |
*/ |
|
23 |
|
|
24 |
class enigma_ui |
|
25 |
{ |
|
26 |
private $rc; |
|
27 |
private $enigma; |
|
28 |
private $home; |
|
29 |
private $css_added; |
|
30 |
private $data; |
|
31 |
|
|
32 |
|
|
33 |
function __construct($enigma_plugin, $home='') |
|
34 |
{ |
|
35 |
$this->enigma = $enigma_plugin; |
|
36 |
$this->rc = $enigma_plugin->rc; |
|
37 |
// we cannot use $enigma_plugin->home here |
|
38 |
$this->home = $home; |
|
39 |
} |
|
40 |
|
|
41 |
/** |
|
42 |
* UI initialization and requests handlers. |
|
43 |
* |
|
44 |
* @param string Preferences section |
|
45 |
*/ |
|
46 |
function init($section='') |
|
47 |
{ |
|
48 |
$this->enigma->include_script('enigma.js'); |
|
49 |
|
|
50 |
// Enigma actions |
|
51 |
if ($this->rc->action == 'plugin.enigma') { |
|
52 |
$action = get_input_value('_a', RCUBE_INPUT_GPC); |
|
53 |
|
|
54 |
switch ($action) { |
|
55 |
case 'keyedit': |
|
56 |
$this->key_edit(); |
|
57 |
break; |
|
58 |
case 'keyimport': |
|
59 |
$this->key_import(); |
|
60 |
break; |
|
61 |
case 'keysearch': |
|
62 |
case 'keylist': |
|
63 |
$this->key_list(); |
|
64 |
break; |
|
65 |
case 'keyinfo': |
|
66 |
default: |
|
67 |
$this->key_info(); |
|
68 |
} |
|
69 |
} |
|
70 |
// Message composing UI |
|
71 |
else if ($this->rc->action == 'compose') { |
|
72 |
$this->compose_ui(); |
|
73 |
} |
|
74 |
// Preferences UI |
|
75 |
else { // if ($this->rc->action == 'edit-prefs') { |
|
76 |
if ($section == 'enigmacerts') { |
|
77 |
$this->rc->output->add_handlers(array( |
|
78 |
'keyslist' => array($this, 'tpl_certs_list'), |
|
79 |
'keyframe' => array($this, 'tpl_cert_frame'), |
|
80 |
'countdisplay' => array($this, 'tpl_certs_rowcount'), |
|
81 |
'searchform' => array($this->rc->output, 'search_form'), |
|
82 |
)); |
|
83 |
$this->rc->output->set_pagetitle($this->enigma->gettext('enigmacerts')); |
|
84 |
$this->rc->output->send('enigma.certs'); |
|
85 |
} |
|
86 |
else { |
|
87 |
$this->rc->output->add_handlers(array( |
|
88 |
'keyslist' => array($this, 'tpl_keys_list'), |
|
89 |
'keyframe' => array($this, 'tpl_key_frame'), |
|
90 |
'countdisplay' => array($this, 'tpl_keys_rowcount'), |
|
91 |
'searchform' => array($this->rc->output, 'search_form'), |
|
92 |
)); |
|
93 |
$this->rc->output->set_pagetitle($this->enigma->gettext('enigmakeys')); |
|
94 |
$this->rc->output->send('enigma.keys'); |
|
95 |
} |
|
96 |
} |
|
97 |
} |
|
98 |
|
|
99 |
/** |
|
100 |
* Adds CSS style file to the page header. |
|
101 |
*/ |
|
102 |
function add_css() |
|
103 |
{ |
|
104 |
if ($this->css_loaded) |
|
105 |
return; |
|
106 |
|
|
107 |
$skin = $this->rc->config->get('skin'); |
|
108 |
if (!file_exists($this->home . "/skins/$skin/enigma.css")) |
|
109 |
$skin = 'default'; |
|
110 |
|
|
111 |
$this->enigma->include_stylesheet("skins/$skin/enigma.css"); |
|
112 |
$this->css_added = true; |
|
113 |
} |
|
114 |
|
|
115 |
/** |
|
116 |
* Template object for key info/edit frame. |
|
117 |
* |
|
118 |
* @param array Object attributes |
|
119 |
* |
|
120 |
* @return string HTML output |
|
121 |
*/ |
|
122 |
function tpl_key_frame($attrib) |
|
123 |
{ |
|
124 |
if (!$attrib['id']) { |
|
125 |
$attrib['id'] = 'rcmkeysframe'; |
|
126 |
} |
|
127 |
|
|
128 |
$attrib['name'] = $attrib['id']; |
|
129 |
|
|
130 |
$this->rc->output->set_env('contentframe', $attrib['name']); |
|
131 |
$this->rc->output->set_env('blankpage', $attrib['src'] ? |
|
132 |
$this->rc->output->abs_url($attrib['src']) : 'program/blank.gif'); |
|
133 |
|
|
134 |
return html::tag('iframe', $attrib); |
|
135 |
} |
|
136 |
|
|
137 |
/** |
|
138 |
* Template object for list of keys. |
|
139 |
* |
|
140 |
* @param array Object attributes |
|
141 |
* |
|
142 |
* @return string HTML content |
|
143 |
*/ |
|
144 |
function tpl_keys_list($attrib) |
|
145 |
{ |
|
146 |
// add id to message list table if not specified |
|
147 |
if (!strlen($attrib['id'])) { |
|
148 |
$attrib['id'] = 'rcmenigmakeyslist'; |
|
149 |
} |
|
150 |
|
|
151 |
// define list of cols to be displayed |
|
152 |
$a_show_cols = array('name'); |
|
153 |
|
|
154 |
// create XHTML table |
|
155 |
$out = rcube_table_output($attrib, array(), $a_show_cols, 'id'); |
|
156 |
|
|
157 |
// set client env |
|
158 |
$this->rc->output->add_gui_object('keyslist', $attrib['id']); |
|
159 |
$this->rc->output->include_script('list.js'); |
|
160 |
|
|
161 |
// add some labels to client |
|
162 |
$this->rc->output->add_label('enigma.keyconfirmdelete'); |
|
163 |
|
|
164 |
return $out; |
|
165 |
} |
|
166 |
|
|
167 |
/** |
|
168 |
* Key listing (and searching) request handler |
|
169 |
*/ |
|
170 |
private function key_list() |
|
171 |
{ |
|
172 |
$this->enigma->load_engine(); |
|
173 |
|
|
174 |
$pagesize = $this->rc->config->get('pagesize', 100); |
|
175 |
$page = max(intval(get_input_value('_p', RCUBE_INPUT_GPC)), 1); |
|
176 |
$search = get_input_value('_q', RCUBE_INPUT_GPC); |
|
177 |
|
|
178 |
// define list of cols to be displayed |
|
179 |
$a_show_cols = array('name'); |
|
180 |
$result = array(); |
|
181 |
|
|
182 |
// Get the list |
|
183 |
$list = $this->enigma->engine->list_keys($search); |
|
184 |
|
|
185 |
if ($list && ($list instanceof enigma_error)) |
|
186 |
$this->rc->output->show_message('enigma.keylisterror', 'error'); |
|
187 |
else if (empty($list)) |
|
188 |
$this->rc->output->show_message('enigma.nokeysfound', 'notice'); |
|
189 |
else { |
|
190 |
if (is_array($list)) { |
|
191 |
// Save the size |
|
192 |
$listsize = count($list); |
|
193 |
|
|
194 |
// Sort the list by key (user) name |
|
195 |
usort($list, array('enigma_key', 'cmp')); |
|
196 |
|
|
197 |
// Slice current page |
|
198 |
$list = array_slice($list, ($page - 1) * $pagesize, $pagesize); |
|
199 |
|
|
200 |
$size = count($list); |
|
201 |
|
|
202 |
// Add rows |
|
203 |
foreach($list as $idx => $key) { |
|
204 |
$this->rc->output->command('enigma_add_list_row', |
|
205 |
array('name' => Q($key->name), 'id' => $key->id)); |
|
206 |
} |
|
207 |
} |
|
208 |
} |
|
209 |
|
|
210 |
$this->rc->output->set_env('search_request', $search); |
|
211 |
$this->rc->output->set_env('pagecount', ceil($listsize/$pagesize)); |
|
212 |
$this->rc->output->set_env('current_page', $page); |
|
213 |
$this->rc->output->command('set_rowcount', |
|
214 |
$this->get_rowcount_text($listsize, $size, $page)); |
|
215 |
|
|
216 |
$this->rc->output->send(); |
|
217 |
} |
|
218 |
|
|
219 |
/** |
|
220 |
* Template object for list records counter. |
|
221 |
* |
|
222 |
* @param array Object attributes |
|
223 |
* |
|
224 |
* @return string HTML output |
|
225 |
*/ |
|
226 |
function tpl_keys_rowcount($attrib) |
|
227 |
{ |
|
228 |
if (!$attrib['id']) |
|
229 |
$attrib['id'] = 'rcmcountdisplay'; |
|
230 |
|
|
231 |
$this->rc->output->add_gui_object('countdisplay', $attrib['id']); |
|
232 |
|
|
233 |
return html::span($attrib, $this->get_rowcount_text()); |
|
234 |
} |
|
235 |
|
|
236 |
/** |
|
237 |
* Returns text representation of list records counter |
|
238 |
*/ |
|
239 |
private function get_rowcount_text($all=0, $curr_count=0, $page=1) |
|
240 |
{ |
|
241 |
if (!$curr_count) |
|
242 |
$out = $this->enigma->gettext('nokeysfound'); |
|
243 |
else { |
|
244 |
$pagesize = $this->rc->config->get('pagesize', 100); |
|
245 |
$first = ($page - 1) * $pagesize; |
|
246 |
|
|
247 |
$out = $this->enigma->gettext(array( |
|
248 |
'name' => 'keysfromto', |
|
249 |
'vars' => array( |
|
250 |
'from' => $first + 1, |
|
251 |
'to' => $first + $curr_count, |
|
252 |
'count' => $all) |
|
253 |
)); |
|
254 |
} |
|
255 |
|
|
256 |
return $out; |
|
257 |
} |
|
258 |
|
|
259 |
/** |
|
260 |
* Key information page handler |
|
261 |
*/ |
|
262 |
private function key_info() |
|
263 |
{ |
|
264 |
$id = get_input_value('_id', RCUBE_INPUT_GET); |
|
265 |
|
|
266 |
$this->enigma->load_engine(); |
|
267 |
$res = $this->enigma->engine->get_key($id); |
|
268 |
|
|
269 |
if ($res instanceof enigma_key) |
|
270 |
$this->data = $res; |
|
271 |
else { // error |
|
272 |
$this->rc->output->show_message('enigma.keyopenerror', 'error'); |
|
273 |
$this->rc->output->command('parent.enigma_loadframe'); |
|
274 |
$this->rc->output->send('iframe'); |
|
275 |
} |
|
276 |
|
|
277 |
$this->rc->output->add_handlers(array( |
|
278 |
'keyname' => array($this, 'tpl_key_name'), |
|
279 |
'keydata' => array($this, 'tpl_key_data'), |
|
280 |
)); |
|
281 |
|
|
282 |
$this->rc->output->set_pagetitle($this->enigma->gettext('keyinfo')); |
|
283 |
$this->rc->output->send('enigma.keyinfo'); |
|
284 |
} |
|
285 |
|
|
286 |
/** |
|
287 |
* Template object for key name |
|
288 |
*/ |
|
289 |
function tpl_key_name($attrib) |
|
290 |
{ |
|
291 |
return Q($this->data->name); |
|
292 |
} |
|
293 |
|
|
294 |
/** |
|
295 |
* Template object for key information page content |
|
296 |
*/ |
|
297 |
function tpl_key_data($attrib) |
|
298 |
{ |
|
299 |
$out = ''; |
|
300 |
$table = new html_table(array('cols' => 2)); |
|
301 |
|
|
302 |
// Key user ID |
|
303 |
$table->add('title', $this->enigma->gettext('keyuserid')); |
|
304 |
$table->add(null, Q($this->data->name)); |
|
305 |
// Key ID |
|
306 |
$table->add('title', $this->enigma->gettext('keyid')); |
|
307 |
$table->add(null, $this->data->subkeys[0]->get_short_id()); |
|
308 |
// Key type |
|
309 |
$keytype = $this->data->get_type(); |
|
310 |
if ($keytype == enigma_key::TYPE_KEYPAIR) |
|
311 |
$type = $this->enigma->gettext('typekeypair'); |
|
312 |
else if ($keytype == enigma_key::TYPE_PUBLIC) |
|
313 |
$type = $this->enigma->gettext('typepublickey'); |
|
314 |
$table->add('title', $this->enigma->gettext('keytype')); |
|
315 |
$table->add(null, $type); |
|
316 |
// Key fingerprint |
|
317 |
$table->add('title', $this->enigma->gettext('fingerprint')); |
|
318 |
$table->add(null, $this->data->subkeys[0]->get_fingerprint()); |
|
319 |
|
|
320 |
$out .= html::tag('fieldset', null, |
|
321 |
html::tag('legend', null, |
|
322 |
$this->enigma->gettext('basicinfo')) . $table->show($attrib)); |
|
323 |
|
|
324 |
// Subkeys |
|
325 |
$table = new html_table(array('cols' => 6)); |
|
326 |
// Columns: Type, ID, Algorithm, Size, Created, Expires |
|
327 |
|
|
328 |
$out .= html::tag('fieldset', null, |
|
329 |
html::tag('legend', null, |
|
330 |
$this->enigma->gettext('subkeys')) . $table->show($attrib)); |
|
331 |
|
|
332 |
// Additional user IDs |
|
333 |
$table = new html_table(array('cols' => 2)); |
|
334 |
// Columns: User ID, Validity |
|
335 |
|
|
336 |
$out .= html::tag('fieldset', null, |
|
337 |
html::tag('legend', null, |
|
338 |
$this->enigma->gettext('userids')) . $table->show($attrib)); |
|
339 |
|
|
340 |
return $out; |
|
341 |
} |
|
342 |
|
|
343 |
/** |
|
344 |
* Key import page handler |
|
345 |
*/ |
|
346 |
private function key_import() |
|
347 |
{ |
|
348 |
// Import process |
|
349 |
if ($_FILES['_file']['tmp_name'] && is_uploaded_file($_FILES['_file']['tmp_name'])) { |
|
350 |
$this->enigma->load_engine(); |
|
351 |
$result = $this->enigma->engine->import_key($_FILES['_file']['tmp_name'], true); |
|
352 |
|
|
353 |
if (is_array($result)) { |
|
354 |
// reload list if any keys has been added |
|
355 |
if ($result['imported']) { |
|
356 |
$this->rc->output->command('parent.enigma_list', 1); |
|
357 |
} |
|
358 |
else |
|
359 |
$this->rc->output->command('parent.enigma_loadframe'); |
|
360 |
|
|
361 |
$this->rc->output->show_message('enigma.keysimportsuccess', 'confirmation', |
|
362 |
array('new' => $result['imported'], 'old' => $result['unchanged'])); |
|
363 |
|
|
364 |
$this->rc->output->send('iframe'); |
|
365 |
} |
|
366 |
else |
|
367 |
$this->rc->output->show_message('enigma.keysimportfailed', 'error'); |
|
368 |
} |
|
369 |
else if ($err = $_FILES['_file']['error']) { |
|
370 |
if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) { |
|
371 |
$this->rc->output->show_message('filesizeerror', 'error', |
|
372 |
array('size' => show_bytes(parse_bytes(ini_get('upload_max_filesize'))))); |
|
373 |
} else { |
|
374 |
$this->rc->output->show_message('fileuploaderror', 'error'); |
|
375 |
} |
|
376 |
} |
|
377 |
|
|
378 |
$this->rc->output->add_handlers(array( |
|
379 |
'importform' => array($this, 'tpl_key_import_form'), |
|
380 |
)); |
|
381 |
|
|
382 |
$this->rc->output->set_pagetitle($this->enigma->gettext('keyimport')); |
|
383 |
$this->rc->output->send('enigma.keyimport'); |
|
384 |
} |
|
385 |
|
|
386 |
/** |
|
387 |
* Template object for key import (upload) form |
|
388 |
*/ |
|
389 |
function tpl_key_import_form($attrib) |
|
390 |
{ |
|
391 |
$attrib += array('id' => 'rcmKeyImportForm'); |
|
392 |
|
|
393 |
$upload = new html_inputfield(array('type' => 'file', 'name' => '_file', |
|
394 |
'id' => 'rcmimportfile', 'size' => 30)); |
|
395 |
|
|
396 |
$form = html::p(null, |
|
397 |
Q($this->enigma->gettext('keyimporttext'), 'show') |
|
398 |
. html::br() . html::br() . $upload->show() |
|
399 |
); |
|
400 |
|
|
401 |
$this->rc->output->add_label('selectimportfile', 'importwait'); |
|
402 |
$this->rc->output->add_gui_object('importform', $attrib['id']); |
|
403 |
|
|
404 |
$out = $this->rc->output->form_tag(array( |
|
405 |
'action' => $this->rc->url(array('action' => 'plugin.enigma', 'a' => 'keyimport')), |
|
406 |
'method' => 'post', |
|
407 |
'enctype' => 'multipart/form-data') + $attrib, |
|
408 |
$form); |
|
409 |
|
|
410 |
return $out; |
|
411 |
} |
|
412 |
|
|
413 |
private function compose_ui() |
|
414 |
{ |
|
415 |
// Options menu button |
|
416 |
// @TODO: make this work with non-default skins |
|
417 |
$this->enigma->add_button(array( |
|
418 |
'name' => 'enigmamenu', |
|
419 |
'imagepas' => 'skins/default/enigma.png', |
|
420 |
'imageact' => 'skins/default/enigma.png', |
|
421 |
'onclick' => "rcmail_ui.show_popup('enigmamenu', true); return false", |
|
422 |
'title' => 'securityoptions', |
|
423 |
'domain' => 'enigma', |
|
424 |
), 'toolbar'); |
|
425 |
|
|
426 |
// Options menu contents |
|
427 |
$this->enigma->add_hook('render_page', array($this, 'compose_menu')); |
|
428 |
} |
|
429 |
|
|
430 |
function compose_menu($p) |
|
431 |
{ |
|
432 |
$menu = new html_table(array('cols' => 2)); |
|
433 |
$chbox = new html_checkbox(array('value' => 1)); |
|
434 |
|
|
435 |
$menu->add(null, html::label(array('for' => 'enigmadefaultopt'), |
|
436 |
Q($this->enigma->gettext('identdefault')))); |
|
437 |
$menu->add(null, $chbox->show(1, array('name' => '_enigma_default', 'id' => 'enigmadefaultopt'))); |
|
438 |
|
|
439 |
$menu->add(null, html::label(array('for' => 'enigmasignopt'), |
|
440 |
Q($this->enigma->gettext('signmsg')))); |
|
441 |
$menu->add(null, $chbox->show(1, array('name' => '_enigma_sign', 'id' => 'enigmasignopt'))); |
|
442 |
|
|
443 |
$menu->add(null, html::label(array('for' => 'enigmacryptopt'), |
|
444 |
Q($this->enigma->gettext('encryptmsg')))); |
|
445 |
$menu->add(null, $chbox->show(1, array('name' => '_enigma_crypt', 'id' => 'enigmacryptopt'))); |
|
446 |
|
|
447 |
$menu = html::div(array('id' => 'enigmamenu', 'class' => 'popupmenu'), |
|
448 |
$menu->show()); |
|
449 |
|
|
450 |
$p['content'] = preg_replace('/(<form name="form"[^>]+>)/i', '\\1'."\n$menu", $p['content']); |
|
451 |
|
|
452 |
return $p; |
|
453 |
|
|
454 |
} |
|
455 |
|
|
456 |
} |