comparison program/steps/settings/folders.inc @ 0:4681f974d28b

vanilla 1.3.3 distro, I hope
author Charlie Root
date Thu, 04 Jan 2018 15:52:31 -0500
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4681f974d28b
1 <?php
2
3 /**
4 +-----------------------------------------------------------------------+
5 | program/steps/settings/folders.inc |
6 | |
7 | This file is part of the Roundcube Webmail client |
8 | Copyright (C) 2005-2013, The Roundcube Dev Team |
9 | |
10 | Licensed under the GNU General Public License version 3 or |
11 | any later version with exceptions for skins & plugins. |
12 | See the README file for a full license statement. |
13 | |
14 | PURPOSE: |
15 | Provide functionality of folders management |
16 | |
17 +-----------------------------------------------------------------------+
18 | Author: Thomas Bruederli <roundcube@gmail.com> |
19 | Author: Aleksander Machniak <alec@alec.pl> |
20 +-----------------------------------------------------------------------+
21 */
22
23 // init IMAP connection
24 $STORAGE = $RCMAIL->get_storage();
25
26 // subscribe mailbox
27 if ($RCMAIL->action == 'subscribe') {
28 $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
29
30 if (strlen($mbox)) {
31 $result = $STORAGE->subscribe(array($mbox));
32
33 // Handle virtual (non-existing) folders
34 if (!$result && $STORAGE->get_error_code() == -1 &&
35 $STORAGE->get_response_code() == rcube_storage::TRYCREATE
36 ) {
37 $result = $STORAGE->create_folder($mbox, true);
38 if ($result) {
39 // @TODO: remove 'virtual' class of folder's row
40 }
41 }
42
43 if ($result) {
44 // Handle subscription of protected folder (#1487656)
45 if ($RCMAIL->config->get('protect_default_folders')
46 && $STORAGE->is_special_folder($mbox)
47 ) {
48 $OUTPUT->command('disable_subscription', $mbox);
49 }
50
51 $OUTPUT->show_message('foldersubscribed', 'confirmation');
52 }
53 else {
54 $RCMAIL->display_server_error('errorsaving');
55 $OUTPUT->command('reset_subscription', $mbox, false);
56 }
57 }
58 }
59 // unsubscribe mailbox
60 else if ($RCMAIL->action == 'unsubscribe') {
61 $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
62
63 if (strlen($mbox)) {
64 $result = $STORAGE->unsubscribe(array($mbox));
65
66 if ($result) {
67 $OUTPUT->show_message('folderunsubscribed', 'confirmation');
68 }
69 else {
70 $RCMAIL->display_server_error('errorsaving');
71 $OUTPUT->command('reset_subscription', $mbox, true);
72 }
73 }
74 }
75 // delete an existing mailbox
76 else if ($RCMAIL->action == 'delete-folder') {
77 $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
78
79 if (strlen($mbox)) {
80 $plugin = $RCMAIL->plugins->exec_hook('folder_delete', array('name' => $mbox));
81
82 if (!$plugin['abort']) {
83 $deleted = $STORAGE->delete_folder($plugin['name']);
84 }
85 else {
86 $deleted = $plugin['result'];
87 }
88
89 // #1488692: update session
90 if ($deleted && $_SESSION['mbox'] === $mbox) {
91 $RCMAIL->session->remove('mbox');
92 }
93 }
94
95 if ($OUTPUT->ajax_call && $deleted) {
96 // Remove folder and subfolders rows
97 $OUTPUT->command('remove_folder_row', $mbox);
98 $OUTPUT->show_message('folderdeleted', 'confirmation');
99 // Clear content frame
100 $OUTPUT->command('subscription_select');
101 $OUTPUT->command('set_quota', $RCMAIL->quota_content());
102 }
103 else if (!$deleted) {
104 $RCMAIL->display_server_error('errorsaving');
105 }
106 }
107 // rename an existing mailbox
108 else if ($RCMAIL->action == 'rename-folder') {
109 $name = trim(rcube_utils::get_input_value('_folder_newname', rcube_utils::INPUT_POST, true));
110 $oldname = rcube_utils::get_input_value('_folder_oldname', rcube_utils::INPUT_POST, true);
111
112 if (strlen($name) && strlen($oldname)) {
113 $rename = rcmail_rename_folder($oldname, $name);
114 }
115
116 if ($rename && $OUTPUT->ajax_call) {
117 rcmail_update_folder_row($name, $oldname);
118 }
119 else if (!$rename) {
120 $RCMAIL->display_server_error('errorsaving');
121 }
122 }
123 // clear mailbox
124 else if ($RCMAIL->action == 'purge') {
125 $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
126 $delimiter = $STORAGE->get_hierarchy_delimiter();
127 $trash_mbox = $RCMAIL->config->get('trash_mbox');
128 $trash_regexp = '/^' . preg_quote($trash . $delimiter, '/') . '/';
129
130 // we should only be purging trash (or their subfolders)
131 if (!strlen($trash_mbox) || $mbox === $trash_mbox
132 || preg_match($trash_regexp, $mbox)
133 ) {
134 $success = $STORAGE->delete_message('*', $mbox);
135 $delete = true;
136 }
137 // move to Trash
138 else {
139 $success = $STORAGE->move_message('1:*', $trash_mbox, $mbox);
140 $delete = false;
141 }
142
143 if ($success) {
144 $OUTPUT->set_env('messagecount', 0);
145 if ($delete) {
146 $OUTPUT->show_message('folderpurged', 'confirmation');
147 $OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $mbox));
148 }
149 else {
150 $OUTPUT->show_message('messagemoved', 'confirmation');
151 }
152 $_SESSION['unseen_count'][$mbox] = 0;
153 $OUTPUT->command('show_folder', $mbox, null, true);
154 }
155 else {
156 $RCMAIL->display_server_error('errorsaving');
157 }
158 }
159 // get mailbox size
160 else if ($RCMAIL->action == 'folder-size') {
161 $name = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
162
163 $size = $STORAGE->folder_size($name);
164
165 // @TODO: check quota and show percentage usage of specified mailbox?
166
167 if ($size !== false) {
168 $OUTPUT->command('folder_size_update', $RCMAIL->show_bytes($size));
169 }
170 else {
171 $RCMAIL->display_server_error();
172 }
173 }
174
175 if ($OUTPUT->ajax_call) {
176 $OUTPUT->send();
177 }
178
179 $OUTPUT->set_pagetitle($RCMAIL->gettext('folders'));
180 $OUTPUT->set_env('prefix_ns', $STORAGE->get_namespace('prefix'));
181 $OUTPUT->set_env('quota', (bool) $STORAGE->get_capability('QUOTA'));
182 $OUTPUT->include_script('treelist.js');
183
184 // add some labels to client
185 $OUTPUT->add_label('deletefolderconfirm', 'purgefolderconfirm', 'folderdeleting',
186 'foldermoving', 'foldersubscribing', 'folderunsubscribing', 'quota');
187
188 // register UI objects
189 $OUTPUT->add_handlers(array(
190 'foldersubscription' => 'rcmail_subscription_form',
191 'folderframe' => 'rcmail_folder_frame',
192 'folderfilter' => 'rcmail_folder_filter',
193 'quotadisplay' => array($RCMAIL, 'quota_display'),
194 ));
195
196 $OUTPUT->send('folders');
197
198
199 // build table with all folders listed by server
200 function rcmail_subscription_form($attrib)
201 {
202 global $RCMAIL, $OUTPUT;
203
204 list($form_start, $form_end) = get_form_tags($attrib, 'folders');
205 unset($attrib['form']);
206
207 if (!$attrib['id']) {
208 $attrib['id'] = 'rcmSubscriptionlist';
209 }
210
211 $STORAGE = $RCMAIL->get_storage();
212
213 // get folders from server
214 $STORAGE->clear_cache('mailboxes', true);
215
216 $a_unsubscribed = $STORAGE->list_folders();
217 $a_subscribed = $STORAGE->list_folders_subscribed('', '*', null, null, true); // unsorted
218 $delimiter = $STORAGE->get_hierarchy_delimiter();
219 $namespace = $STORAGE->get_namespace();
220 $special_folders = array_flip(array_merge(array('inbox' => 'INBOX'), $STORAGE->get_special_folders()));
221 $protect_default = $RCMAIL->config->get('protect_default_folders');
222 $seen = array();
223 $list_folders = array();
224
225 // pre-process folders list
226 foreach ($a_unsubscribed as $i => $folder) {
227 $folder_id = $folder;
228 $folder = $STORAGE->mod_folder($folder);
229 $foldersplit = explode($delimiter, $folder);
230 $name = rcube_charset::convert(array_pop($foldersplit), 'UTF7-IMAP');
231 $parent_folder = join($delimiter, $foldersplit);
232 $level = count($foldersplit);
233
234 // add any necessary "virtual" parent folders
235 if ($parent_folder && !isset($seen[$parent_folder])) {
236 for ($i=1; $i<=$level; $i++) {
237 $ancestor_folder = join($delimiter, array_slice($foldersplit, 0, $i));
238 if ($ancestor_folder && !$seen[$ancestor_folder]++) {
239 $ancestor_name = rcube_charset::convert($foldersplit[$i-1], 'UTF7-IMAP');
240 $list_folders[] = array(
241 'id' => $ancestor_folder,
242 'name' => $ancestor_name,
243 'level' => $i-1,
244 'virtual' => true,
245 );
246 }
247 }
248 }
249
250 // Handle properly INBOX.INBOX situation
251 if (isset($seen[$folder])) {
252 continue;
253 }
254
255 $seen[$folder]++;
256
257 $list_folders[] = array(
258 'id' => $folder_id,
259 'name' => $name,
260 'level' => $level,
261 );
262 }
263
264 unset($seen);
265
266 $checkbox_subscribe = new html_checkbox(array(
267 'name' => '_subscribed[]',
268 'title' => $RCMAIL->gettext('changesubscription'),
269 'onclick' => rcmail_output::JS_OBJECT_NAME.".command(this.checked?'subscribe':'unsubscribe',this.value)",
270 ));
271
272 $js_folders = array();
273 $folders = array();
274 $collapsed = (string) $RCMAIL->config->get('collapsed_folders');
275
276 // create list of available folders
277 foreach ($list_folders as $i => $folder) {
278 $sub_key = array_search($folder['id'], $a_subscribed);
279 $subscribed = $sub_key !== false;
280 $special = $folder['id'] == 'INBOX' || isset($special_folders[$folder['id']]);
281 $protected = $folder['id'] == 'INBOX' || ($protect_default && $special);
282 $noselect = false;
283 $classes = array();
284
285 $folder_utf8 = rcube_charset::convert($folder['id'], 'UTF7-IMAP');
286 $display_folder = rcube::Q($special ? $RCMAIL->localize_foldername($folder['id'], false, true) : $folder['name']);
287
288 if ($folder['virtual']) {
289 $classes[] = 'virtual';
290 }
291
292 // Check \Noselect flag (of existing folder)
293 if (!$protected && in_array($folder['id'], $a_unsubscribed)) {
294 $attrs = $STORAGE->folder_attributes($folder['id']);
295 $noselect = in_array_nocase('\\Noselect', $attrs);
296 }
297
298 $disabled = (($protected && $subscribed) || $noselect);
299
300 // Below we will disable subscription option for "virtual" folders
301 // according to namespaces, but only if they aren't already subscribed.
302 // User should be able to unsubscribe from the folder
303 // even if it doesn't exists or is not accessible (OTRS:1000059)
304 if (!$subscribed && !$disabled && !empty($namespace) && $folder['virtual']) {
305 // check if the folder is a namespace prefix, then disable subscription option on it
306 if (!$disabled && $folder['level'] == 0) {
307 $fname = $folder['id'] . $delimiter;
308 foreach ($namespace as $ns) {
309 if (is_array($ns)) {
310 foreach ($ns as $item) {
311 if ($item[0] === $fname) {
312 $disabled = true;
313 break 2;
314 }
315 }
316 }
317 }
318 }
319 // check if the folder is an other users virtual-root folder, then disable subscription option on it
320 if (!$disabled && $folder['level'] == 1 && !empty($namespace['other'])) {
321 $parts = explode($delimiter, $folder['id']);
322 $fname = $parts[0] . $delimiter;
323 foreach ($namespace['other'] as $item) {
324 if ($item[0] === $fname) {
325 $disabled = true;
326 break;
327 }
328 }
329 }
330 // check if the folder is shared, then disable subscription option on it (if not subscribed already)
331 if (!$disabled) {
332 $tmp_ns = array_merge((array)$namespace['other'], (array)$namespace['shared']);
333 foreach ($tmp_ns as $item) {
334 if (strlen($item[0]) && strpos($folder['id'], $item[0]) === 0) {
335 $disabled = true;
336 break;
337 }
338 }
339 }
340 }
341
342 $is_collapsed = strpos($collapsed, '&'.rawurlencode($folder['id']).'&') !== false;
343 $folder_id = rcube_utils::html_identifier($folder['id'], true);
344
345 if ($folder_class = $RCMAIL->folder_classname($folder['id'])) {
346 $classes[] = $folder_class;
347 }
348
349 $folders[$folder['id']] = array(
350 'idx' => $folder_id,
351 'folder_imap' => $folder['id'],
352 'folder' => $folder_utf8,
353 'display' => $display_folder,
354 'protected' => $protected || $folder['virtual'],
355 'class' => join(' ', $classes),
356 'subscribed' => $subscribed,
357 'level' => $folder['level'],
358 'collapsed' => $is_collapsed,
359 'content' => html::a(array('href' => '#'), $display_folder)
360 . $checkbox_subscribe->show(($subscribed ? $folder['id'] : ''),
361 array('value' => $folder['id'], 'disabled' => $disabled ? 'disabled' : ''))
362 );
363 }
364
365 $plugin = $RCMAIL->plugins->exec_hook('folders_list', array('list' => $folders));
366
367 // add drop-target representing 'root'
368 $root = array(
369 'idx' => rcube_utils::html_identifier('*', true),
370 'folder_imap' => '*',
371 'folder' => '',
372 'display' => '',
373 'protected' => true,
374 'class' => 'root',
375 'content' => '<span>&nbsp;</span>',
376 );
377
378 $folders = array();
379 $plugin['list'] = array_values($plugin['list']);
380
381 array_unshift($plugin['list'], $root);
382
383 for ($i = 0, $length = count($plugin['list']); $i<$length; $i++) {
384 $folders[] = rcmail_folder_tree_element($plugin['list'], $i, $js_folders);
385 }
386
387 $OUTPUT->add_gui_object('subscriptionlist', $attrib['id']);
388 $OUTPUT->set_env('subscriptionrows', $js_folders);
389 $OUTPUT->set_env('defaultfolders', array_keys($special_folders));
390 $OUTPUT->set_env('collapsed_folders', $collapsed);
391 $OUTPUT->set_env('delimiter', $delimiter);
392
393 return $form_start . html::tag('ul', $attrib, implode('', $folders), html::$common_attrib) . $form_end;
394 }
395
396 function rcmail_folder_tree_element($folders, &$key, &$js_folders)
397 {
398 $data = $folders[$key];
399 $idx = 'rcmli' . $data['idx'];
400
401 $js_folders[$data['folder_imap']] = array($data['folder'], $data['display'], $data['protected']);
402 $content = $data['content'];
403 $attribs = array(
404 'id' => $idx,
405 'class' => trim($data['class'] . ' mailbox')
406 );
407
408 $children = array();
409 while ($folders[$key+1] && $folders[$key+1]['level'] > $data['level']) {
410 $key++;
411 $children[] = rcmail_folder_tree_element($folders, $key, $js_folders);
412 }
413
414 if (!empty($children)) {
415 $content .= html::div('treetoggle ' . ($data['collapsed'] ? 'collapsed' : 'expanded'), '&nbsp;')
416 . html::tag('ul', array('style' => ($data['collapsed'] ? "display:none" : null)),
417 implode("\n", $children));
418 }
419
420 return html::tag('li', $attribs, $content);
421 }
422
423 function rcmail_folder_frame($attrib)
424 {
425 global $OUTPUT;
426
427 if (!$attrib['id']) {
428 $attrib['id'] = 'rcmfolderframe';
429 }
430
431 return $OUTPUT->frame($attrib, true);
432 }
433
434 function rcmail_folder_filter($attrib)
435 {
436 global $RCMAIL;
437
438 $storage = $RCMAIL->get_storage();
439 $namespace = $storage->get_namespace();
440
441 if (empty($namespace['personal']) && empty($namespace['shared']) && empty($namespace['other'])) {
442 return '';
443 }
444
445 if (!$attrib['id']) {
446 $attrib['id'] = 'rcmfolderfilter';
447 }
448
449 $attrib['onchange'] = rcmail_output::JS_OBJECT_NAME . '.folder_filter(this.value)';
450
451 $roots = array();
452 $select = new html_select($attrib);
453 $select->add($RCMAIL->gettext('all'), '---');
454
455 foreach (array_keys($namespace) as $type) {
456 foreach ((array)$namespace[$type] as $ns) {
457 $root = rtrim($ns[0], $ns[1]);
458 $label = $RCMAIL->gettext('namespace.' . $type);
459
460 if (count($namespace[$type]) > 1) {
461 $label .= ' (' . rcube_charset::convert($root, 'UTF7-IMAP', RCUBE_CHARSET) . ')';
462 }
463
464 $select->add($label, $root);
465
466 if (strlen($root)) {
467 $roots[] = $root;
468 }
469 }
470 }
471
472 $RCMAIL->output->add_gui_object('foldersfilter', $attrib['id']);
473 $RCMAIL->output->set_env('ns_roots', $roots);
474
475 return $select->show();
476 }
477
478 function rcmail_rename_folder($oldname, $newname)
479 {
480 global $RCMAIL;
481
482 $storage = $RCMAIL->get_storage();
483 $delimiter = $storage->get_hierarchy_delimiter();
484
485 $plugin = $RCMAIL->plugins->exec_hook('folder_rename', array(
486 'oldname' => $oldname, 'newname' => $newname));
487
488 if (!$plugin['abort']) {
489 $renamed = $storage->rename_folder($oldname, $newname);
490 }
491 else {
492 $renamed = $plugin['result'];
493 }
494
495 // update per-folder options for modified folder and its subfolders
496 if ($renamed) {
497 $a_threaded = (array) $RCMAIL->config->get('message_threading', array());
498 $oldprefix = '/^' . preg_quote($oldname . $delimiter, '/') . '/';
499
500 foreach ($a_threaded as $key => $val) {
501 if ($key == $oldname) {
502 unset($a_threaded[$key]);
503 $a_threaded[$newname] = $val;
504 }
505 else if (preg_match($oldprefix, $key)) {
506 unset($a_threaded[$key]);
507 $a_threaded[preg_replace($oldprefix, $newname.$delimiter, $key)] = $val;
508 }
509 }
510
511 $RCMAIL->user->save_prefs(array('message_threading' => $a_threaded));
512
513 // #1488692: update session
514 if ($_SESSION['mbox'] === $oldname) {
515 $_SESSION['mbox'] = $newname;
516 }
517
518 return true;
519 }
520
521 return false;
522 }