summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Kinkade <nkinkade@nkinka.de>2009-03-22 16:27:20 +0000
committerNathan Kinkade <nkinkade@nkinka.de>2009-03-22 16:27:20 +0000
commitf3d6fc7903f711d367ca293c5e6560ea6b49cf06 (patch)
tree6541045d34e4d968c4233479ff695cca8996c955
parent1197b457d40b295c8927a2a6cbacc1b69ee9b276 (diff)
Added some documentation for the NPK theme and also a patch file for core RoundCube file to make the theme fully functional.
-rw-r--r--roundcubemail/skins/npk/INSTALL34
-rw-r--r--roundcubemail/skins/npk/README36
-rw-r--r--roundcubemail/skins/npk/roundcube_npk_skin.patch420
3 files changed, 490 insertions, 0 deletions
diff --git a/roundcubemail/skins/npk/INSTALL b/roundcubemail/skins/npk/INSTALL
new file mode 100644
index 000000000..382391dc4
--- /dev/null
+++ b/roundcubemail/skins/npk/INSTALL
@@ -0,0 +1,34 @@
+GENERAL
+=======
+Other that the note below about patches, installing this skin should be
+as easy as dropping the npk directory that contains this INSTALL file
+into your skins directory and then selecting it in the user interface.
+This skin *should* still be mostly usable even if you don't apply the
+patches, with the notable exceptions of the "Copy to" and "Not Spam"
+buttons not working ... I haven't tested this without the patches, so I
+might be wrong, and if I am then feel free to let me know.
+
+BACKUP
+======
+Before you attempt to apply the patch mentioned below, simply make a
+backup copy of your entire RoundCube install directory. No need to
+backup the database for this, though you should be doing that anyway.
+If the patch doesn't cleanly apply then it might be difficult to undo
+it, so having a backup copy of the RoundCube install should make it
+trivial to recover from a failed patch -- just delete the roundcube
+directory where the patch failed, and then copy or move the old one back
+into place.
+
+
+PATCHES
+=======
+Because this theme includes some new funtionality to the RoundCube
+interface, it also requires a few changes to a couple core RoundCube
+files, as well as the addition of one file. I have included a patch
+file in this directory called roundcube_npk_skin.patch. Assuming that
+you are in the same directory that contains the directory
+"roundcubemail," you could apply the patch like:
+
+ $ patch -p1 < rc_npk_skin.patch
+
+... otherwise apply patch in the way that makes sense for your setup.
diff --git a/roundcubemail/skins/npk/README b/roundcubemail/skins/npk/README
new file mode 100644
index 000000000..71c96a706
--- /dev/null
+++ b/roundcubemail/skins/npk/README
@@ -0,0 +1,36 @@
+This skin is by and large the same as the default theme, but instead of
+images for buttons, it uses styled texual buttons, and also moves the
+message controls to the top where they are easier to see and access. It
+also adds some new functionality to the interface:
+
+* An "Archive" button which allows you to move any number of messages to
+ a preconfigured archive folder with one click. Configurable in the
+ "Special Folders" section of the Preferences.
+
+* A "Move to" button/dropdown, which allows you to move any number of
+ messages from the current folder to any other folder, without having
+ to drag-n-drop.
+
+* A "Copy to" button/dropdown, which allows you to copy any number of
+ messages from the current folder to any other folder.
+
+* A "Not Spam" button which only appears when you are in the configured
+ Spam/Junk folder. This button first copies the message(s) from the
+ Spam folder to the INBOX, then moves them to a configurable folder, in
+ my case a folder called HamNotSpam. In my personal setup, this folder
+ is processed by DSPAM (http://dspam.nuclearelephant.com/) to allow it to
+ train itself by recognizing that it mis-categorized legitimate email as
+ spam. On this same note, I personally have a SpamNotHam folder, but for
+ this there is no need for a button since you can just use the "Move to"
+ dropdown or drag-n-drop the message(s). If you don't configure a
+ Ham-not-spam folder in your preferences then the "Not Spam" button will
+ not appear. Setting it only makes sense if you have a spam filter that
+ needs to be trained.
+
+* A "Shred" button which only appears when you are in the configured
+ Trash folder. This button allows you to permanently remove messages.
+
+Not only do I find the textual buttons easier to read, more intuitive
+and more visually appealing than images, but eliminating the images
+makes the front page around 15KB to 20KB smaller ... not much, but it's
+something.
diff --git a/roundcubemail/skins/npk/roundcube_npk_skin.patch b/roundcubemail/skins/npk/roundcube_npk_skin.patch
new file mode 100644
index 000000000..eaf4ffc39
--- /dev/null
+++ b/roundcubemail/skins/npk/roundcube_npk_skin.patch
@@ -0,0 +1,420 @@
+diff --git a/roundcubemail/program/include/main.inc b/roundcubemail/program/include/main.inc
+index 9adcd4c..c243d7b 100644
+--- a/roundcubemail/program/include/main.inc
++++ b/roundcubemail/program/include/main.inc
+@@ -1043,6 +1043,7 @@ function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $at
+ $maxlength = intval($attrib['maxlength']);
+ $realnames = (bool)$attrib['realnames'];
+ $msgcounts = $RCMAIL->imap->get_cache('messagecount');
++ $mailboxaction = ($attrib['mailboxaction']) ? $attrib['mailboxaction'] : 'list';
+
+ $idx = 0;
+ $out = '';
+@@ -1100,7 +1101,7 @@ function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $at
+ $html_name = Q($foldername . ($unread ? " ($unread)" : ''));
+ $link_attrib = $folder['virtual'] ? array() : array(
+ 'href' => rcmail_url('', array('_mbox' => $folder['id'])),
+- 'onclick' => sprintf("return %s.command('list','%s',this)", JS_OBJECT_NAME, $js_name),
++ 'onclick' => sprintf("return %s.command('%s','%s',this)", JS_OBJECT_NAME, $mailboxaction, $js_name),
+ 'title' => $title,
+ );
+
+diff --git a/roundcubemail/program/include/rcube_imap.php b/roundcubemail/program/include/rcube_imap.php
+index 788b0ff..c89a4ff 100644
+--- a/roundcubemail/program/include/rcube_imap.php
++++ b/roundcubemail/program/include/rcube_imap.php
+@@ -1758,6 +1766,45 @@ class rcube_imap
+ return $moved;
+ }
+
++ /**
++ * Copy a message from one mailbox to another
++ *
++ * @param string List of UIDs to move, separated by comma
++ * @param string Target mailbox
++ * @param string Source mailbox
++ * @return boolean True on success, False on error
++ */
++ function copy_message($uids, $to_mbox, $from_mbox='')
++ {
++ $to_mbox = $this->_mod_mailbox($to_mbox);
++ $from_mbox = $from_mbox ? $this->_mod_mailbox($from_mbox) : $this->mailbox;
++
++ // make sure mailbox exists
++ if ($to_mbox != 'INBOX' && !in_array($to_mbox, $this->_list_mailboxes()))
++ {
++ if (in_array($to_mbox_in, $this->default_folders))
++ $this->create_mailbox($to_mbox_in, TRUE);
++ else
++ return FALSE;
++ }
++
++ // convert the list of uids to array
++ $a_uids = is_string($uids) ? explode(',', $uids) : (is_array($uids) ? $uids : NULL);
++
++ // exit if no message uids are specified
++ if (!is_array($a_uids))
++ return false;
++
++ // convert uids to message ids
++ $a_mids = array();
++ foreach ($a_uids as $uid)
++ $a_mids[] = $this->_uid2id($uid, $from_mbox);
++
++ $iil_copy = iil_C_Copy($this->conn, join(',', $a_mids), $from_mbox, $to_mbox);
++ $copied = !($iil_copy === false || $iil_copy < 0);
++
++ return $copied;
++ }
+
+ /**
+ * Mark messages as deleted and expunge mailbox
+diff --git a/roundcubemail/program/js/app.js b/roundcubemail/program/js/app.js
+index 0398442..4daf023 100644
+--- a/roundcubemail/program/js/app.js
++++ b/roundcubemail/program/js/app.js
+@@ -160,7 +160,7 @@ function rcube_webmail()
+
+ if (this.env.action=='show' || this.env.action=='preview')
+ {
+- this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', 'mark', 'viewsource', 'print', 'load-attachment', 'load-headers', true);
++ this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'copyto', 'delete', 'mark', 'viewsource', 'print', 'load-attachment', 'load-headers', true);
+ if (this.env.next_uid)
+ {
+ this.enable_command('nextmessage', true);
+@@ -277,7 +277,7 @@ function rcube_webmail()
+ if ((this.env.action=='add' || this.env.action=='edit') && this.gui_objects.editform)
+ this.enable_command('save', true);
+ else
+- this.enable_command('search', 'reset-search', 'moveto', 'import', true);
++ this.enable_command('search', 'reset-search', 'moveto', 'copyto', 'import', true);
+
+ if (this.contact_list && this.contact_list.rowcount > 0)
+ this.enable_command('export', true);
+@@ -547,6 +547,29 @@ function rcube_webmail()
+ this.reset_qsearch();
+
+ this.list_mailbox(props);
++
++ // Only show the "Not Spam" button if the user has configured a
++ // a hamnotspam_mbox AND we are in the predefined junk_mailbox.
++ // Else only show the "Shred" button if we are currently
++ // in the predefined trash_mbox. Else show the archive button
++ // but only if the user has configured the archive_mailbox.
++ if (this.env.mailbox == this.env.junk_mailbox) {
++ if (this.env.hamnotspam_mailbox) {
++ rcube_find_object('notjunkbutton').style.display = 'inline';
++ rcube_find_object('archivemessagesbutton').style.display = 'none';
++ rcube_find_object('shredbutton').style.display = 'none';
++ }
++ } else if (this.env.mailbox == this.env.trash_mailbox) {
++ rcube_find_object('shredbutton').style.display = 'inline';
++ rcube_find_object('archivemessagesbutton').style.display = 'none';
++ rcube_find_object('notjunkbutton').style.display = 'none';
++ } else {
++ if (this.env.archive_mailbox) {
++ rcube_find_object('archivemessagesbutton').style.display = 'inline';
++ rcube_find_object('shredbutton').style.display = 'none';
++ rcube_find_object('notjunkbutton').style.display = 'none';
++ }
++ }
+
+ if (this.env.trash_mailbox)
+ this.set_alttext('delete', this.env.mailbox != this.env.trash_mailbox ? 'movemessagetotrash' : 'deletemessage');
+@@ -725,6 +748,11 @@ function rcube_webmail()
+ this.copy_contact(null, props);
+ break;
+
++ case 'copyto':
++ if (this.task == 'mail')
++ this.copy_messages(props);
++ break;
++
+ case 'mark':
+ if (props)
+ this.mark_message(props);
+@@ -1343,12 +1371,12 @@ function rcube_webmail()
+ {
+ this.enable_command('reply', 'reply-all', 'forward', false);
+ this.enable_command('show', 'print', selected);
+- this.enable_command('delete', 'moveto', 'mark', (list.selection.length > 0 ? true : false));
++ this.enable_command('delete', 'moveto', 'copyto', 'mark', (list.selection.length > 0 ? true : false));
+ }
+ else
+ {
+ this.enable_command('show', 'reply', 'reply-all', 'forward', 'print', selected);
+- this.enable_command('delete', 'moveto', 'mark', (list.selection.length > 0 ? true : false));
++ this.enable_command('delete', 'moveto', 'copyto', 'mark', (list.selection.length > 0 ? true : false));
+ }
+
+ // start timer for message preview (wait for double click)
+@@ -1752,6 +1780,29 @@ function rcube_webmail()
+ this._with_selected_messages('moveto', lock, add_url, (this.env.flag_for_deletion ? false : true));
+ };
+
++ // copy selected messages to the specified mailbox
++ this.copy_messages = function(mbox)
++ {
++ // exit if current or no mailbox specified or if selection is empty
++ if (!mbox || mbox == this.env.mailbox || (!this.env.uid && (!this.message_list || !this.message_list.get_selection().length)))
++ return;
++
++ var lock = false;
++ var add_url = '&_target_mbox='+urlencode(mbox)+'&_from='+(this.env.action ? this.env.action : '');
++
++ // show wait message
++ if (this.env.action=='show')
++ {
++ lock = true;
++ this.set_busy(true, 'copyingmessage');
++ }
++
++ // Hide message command buttons until a message is selected
++ this.enable_command('reply', 'reply-all', 'forward', 'delete', 'mark', 'print', false);
++
++ this._with_selected_messages('copyto', lock, add_url, false);
++ };
++
+ // delete selected messages from the current mailbox
+ this.delete_messages = function()
+ {
+@@ -4009,6 +4066,6 @@ function rcube_webmail()
+ if (this.env.contentframe)
+ this.show_contentframe(false);
+ // disable commands useless when mailbox is empty
+- this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', 'mark', 'viewsource',
++ this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'copyto', 'delete', 'mark', 'viewsource',
+ 'print', 'load-attachment', 'purge', 'expunge', 'select-all', 'select-none', 'sort', false);
+ }
+diff --git a/roundcubemail/program/localization/en_US/labels.inc b/roundcubemail/program/localization/en_US/labels.inc
+index 39b145c..75305d3 100644
+--- a/roundcubemail/program/localization/en_US/labels.inc
++++ b/roundcubemail/program/localization/en_US/labels.inc
+@@ -37,7 +37,8 @@ $labels['inbox'] = 'Inbox';
+ $labels['drafts'] = 'Drafts';
+ $labels['sent'] = 'Sent';
+ $labels['trash'] = 'Trash';
+-$labels['junk'] = 'Junk';
++$labels['junk'] = 'Spam';
++$labels['hamnotspam'] = 'Ham-not-spam';
+
+ // message listing
+ $labels['subject'] = 'Subject';
+@@ -60,6 +64,7 @@ $labels['threadsfromto'] = 'Threads $from to $to of $count';
+ $labels['messagenrof'] = 'Message $nr of $count';
+
+ $labels['moveto'] = 'Move to...';
++$labels['copyto'] = 'Copy to...';
+ $labels['download'] = 'Download';
+
+ $labels['filename'] = 'File name';
+@@ -169,6 +174,29 @@ $labels['resetsearch'] = 'Reset search';
+
+ $labels['openinextwin'] = 'Open in new window';
+
++// button bar labels for npk theme
++$labels['buttonbararchive'] = 'Archive';
++$labels['buttonbarcompose'] = 'Compose';
++$labels['buttonbarmark'] = 'Mark';
++$labels['buttonbarreply'] = 'Reply';
++$labels['buttonbarreplyall'] = 'Reply to all';
++$labels['buttonbarforward'] = 'Forward';
++$labels['buttonbarmove'] = 'Move';
++$labels['buttonbarcopy'] = 'Copy';
++$labels['buttonbarnotjunk'] = 'Not Spam';
++$labels['buttonbarviewsource'] = 'Source';
++$labels['buttonbarback'] = 'Back';
++$labels['buttonbarsend'] = 'Send';
++$labels['buttonbarshred'] = 'Shred';
++$labels['buttonbarspellcheck'] = 'Spellcheck';
++$labels['buttonbaraddcontact'] = 'Add';
++
++$labels['archivemessages'] = 'Move to archives folder';
++$labels['movemessages'] = 'Move to selected folder';
++$labels['copymessages'] = 'Copy to selected folder';
++$labels['notjunkmessages'] = 'Copy to Inbox, then move to HamNotSpam';
++$labels['shredmessages'] = 'Permanently delete message(s)';
++
+ // message compose
+ $labels['compose'] = 'Compose a message';
+ $labels['savemessage'] = 'Save this draft';
+diff --git a/roundcubemail/program/localization/en_US/messages.inc b/roundcubemail/program/localization/en_US/messages.inc
+index ed63c7c..56e3065 100644
+--- a/roundcubemail/program/localization/en_US/messages.inc
++++ b/roundcubemail/program/localization/en_US/messages.inc
+@@ -43,7 +43,8 @@ $messages['sendingfailed'] = 'Failed to send message';
+ $messages['senttooquickly'] = 'Please wait $sec sec(s). before sending this message';
+ $messages['errorsavingsent'] = 'An error occured while saving sent message';
+ $messages['errorsaving'] = 'An error occured while saving';
+-$messages['errormoving'] = 'Could not move the message';
++$messages['errormoving'] = 'Could not move the message(s)';
++$messages['errorcopying'] = 'Could not copy the message(s)';
+ $messages['errordeleting'] = 'Could not delete the message';
+ $messages['deletecontactconfirm'] = 'Do you really want to delete the selected contact(s)?';
+ $messages['deletemessagesconfirm'] = 'Do you really want to delete the selected message(s)?';
+@@ -80,7 +81,8 @@ $messages['copysuccess'] = 'Successfully copied $nr addresses';
+ $messages['copyerror'] = 'Could not copy any addresses';
+ $messages['sourceisreadonly'] = 'This address source is read only';
+ $messages['errorsavingcontact'] = 'Could not save the contact address';
+-$messages['movingmessage'] = 'Moving message...';
++$messages['movingmessage'] = 'Moving message(s)...';
++$messages['copyingmessage'] = 'Copying message(s)...';
+ $messages['receiptsent'] = 'Successfully sent a read receipt';
+ $messages['errorsendingreceipt'] = 'Could not send the receipt';
+ $messages['nodeletelastidentity'] = 'You cannot delete this identity, it\'s your last one.';
+diff --git a/roundcubemail/program/steps/mail/copy.inc b/roundcubemail/program/steps/mail/copy.inc
+new file mode 100644
+index 0000000..2a2e4ea
+--- /dev/null
++++ b/roundcubemail/program/steps/mail/copy.inc
+@@ -0,0 +1,90 @@
++<?php
++
++/*
++ +-----------------------------------------------------------------------+
++ | program/steps/mail/copy.inc |
++ | |
++ | This file is part of the RoundCube Webmail client |
++ | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland |
++ | Licensed under the GNU GPL |
++ | |
++ | PURPOSE: |
++ | Copy the submitted messages to a specific mailbox |
++ | |
++ +-----------------------------------------------------------------------+
++ | Author: Thomas Bruederli <roundcube@gmail.com> |
++ +-----------------------------------------------------------------------+
++
++*/
++
++// count messages before changing anything
++$old_count = $IMAP->messagecount(NULL, rcmail::get_instance()->imap->threading?'THREADS':'ALL');
++$old_pages = ceil($old_count / $IMAP->page_size);
++
++// copy messages
++if ($RCMAIL->action=='copyto' && !empty($_POST['_uid']) && !empty($_POST['_target_mbox'])) {
++ $count = sizeof(explode(',', ($uids = get_input_value('_uid', RCUBE_INPUT_POST))));
++ $target = get_input_value('_target_mbox', RCUBE_INPUT_POST);
++ $mbox = get_input_value('_mbox', RCUBE_INPUT_POST);
++
++ $copied = $IMAP->copy_message($uids, $target, $mbox);
++
++ if (!$copied) {
++ // send error message
++ $OUTPUT->command('list_mailbox');
++ $OUTPUT->show_message('errormoving', 'error');
++ $OUTPUT->send();
++ exit;
++ }
++
++}
++// unknown action or missing query param
++else {
++ exit;
++}
++// refresh saved search set after moving some messages
++if (($search_request = get_input_value('_search', RCUBE_INPUT_GPC)) && $IMAP->search_set) {
++ $_SESSION['search'][$search_request] = $IMAP->refresh_search();
++}
++
++$msg_count = $IMAP->messagecount(NULL, rcmail::get_instance()->imap->threading?'THREADS':'ALL');
++$pages = ceil($msg_count / $IMAP->page_size);
++$nextpage_count = $old_count - $IMAP->page_size * $IMAP->list_page;
++$remaining = $msg_count - $IMAP->page_size * ($IMAP->list_page - 1);
++
++// jump back one page (user removed the whole last page)
++if ($IMAP->list_page > 1 && $nextpage_count <= 0 && $remaining == 0) {
++ $IMAP->set_page($IMAP->list_page-1);
++ $_SESSION['page'] = $IMAP->list_page;
++ $jump_back = true;
++}
++
++// update message count display
++$OUTPUT->set_env('pagecount', $pages);
++$OUTPUT->set_env('messagecount', $msg_count);
++$OUTPUT->set_env('current_page', $IMAP->list_page);
++$OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($msg_count));
++
++// update mailboxlist
++$OUTPUT->command('set_unread_count', $mbox, $IMAP->messagecount($mbox, 'UNSEEN'), ($mbox == 'INBOX'));
++
++$OUTPUT->command('set_quota', rcmail_quota_content($IMAP->get_quota()));
++
++// add new rows from next page (if any)
++if ($addrows && $_POST['_from']!='show' && ($jump_back || $nextpage_count > 0)) {
++ $sort_col = isset($_SESSION['sort_col']) ? $_SESSION['sort_col'] : $CONFIG['message_sort_col'];
++ $sort_order = isset($_SESSION['sort_order']) ? $_SESSION['sort_order'] : $CONFIG['message_sort_order'];
++
++ $a_headers = $IMAP->list_headers($mbox, NULL, $sort_col, $sort_order);
++ if (!$jump_back) {
++ if ($_SESSION['threads'])
++ // TODO: count number of roots deleted and slice that many roots from the end of $a_headers
++ $OUTPUT->command('message_list.clear');
++ else
++ $a_headers = array_slice($a_headers, -$count, $count);
++ }
++ rcmail_js_message_list($a_headers);
++}
++
++// send response
++$OUTPUT->send();
+diff --git a/roundcubemail/program/steps/mail/func.inc b/roundcubemail/program/steps/mail/func.inc
+index bac4946..89c566f 100644
+--- a/roundcubemail/program/steps/mail/func.inc
++++ b/roundcubemail/program/steps/mail/func.inc
+@@ -96,6 +96,10 @@ if (empty($RCMAIL->action) || $RCMAIL->action == 'list')
+ $OUTPUT->set_env('drafts_mailbox', $CONFIG['drafts_mbox']);
+ if ($CONFIG['junk_mbox'])
+ $OUTPUT->set_env('junk_mailbox', $CONFIG['junk_mbox']);
++ if ($CONFIG['archive_mbox'])
++ $OUTPUT->set_env('archive_mailbox', $CONFIG['archive_mbox']);
++ if ($CONFIG['hamnotspam_mbox'])
++ $OUTPUT->set_env('hamnotspam_mailbox', $CONFIG['hamnotspam_mbox']);
+
+ if (!$OUTPUT->ajax_call)
+ $OUTPUT->add_label('checkingmail', 'deletemessage', 'movemessagetotrash', 'movingmessage');
+diff --git a/roundcubemail/program/steps/settings/func.inc b/roundcubemail/program/steps/settings/func.inc
+index 6515ae4..cc34e68 100644
+--- a/roundcubemail/program/steps/settings/func.inc
++++ b/roundcubemail/program/steps/settings/func.inc
+@@ -321,14 +321,24 @@ function rcmail_user_prefs_block($part, $no_override, $attrib)
+ $table->add(null, $select->show($config['sent_mbox'], array('name' => "_sent_mbox")));
+ }
+
++ if (!isset($no_override['trash_mbox'])) {
++ $table->add('title', Q(rcube_label('trash')));
++ $table->add(null, $select->show($config['trash_mbox'], array('name' => "_trash_mbox")));
++ }
++
++ if (!isset($no_override['archive_mbox'])) {
++ $table->add('title', Q(rcube_label('buttonbararchive')));
++ $table->add(null, $select->show($config['archive_mbox'], array('name' => "_archive_mbox")));
++ }
++
+ if (!isset($no_override['junk_mbox'])) {
+ $table->add('title', Q(rcube_label('junk')));
+ $table->add(null, $select->show($config['junk_mbox'], array('name' => "_junk_mbox")));
+ }
+
+- if (!isset($no_override['trash_mbox'])) {
+- $table->add('title', Q(rcube_label('trash')));
+- $table->add(null, $select->show($config['trash_mbox'], array('name' => "_trash_mbox")));
++ if (!isset($no_override['hamnotspam_mbox'])) {
++ $table->add('title', Q(rcube_label('hamnotspam')));
++ $table->add(null, $select->show($config['hamnotspam_mbox'], array('name' => "_hamnotspam_mbox")));
+ }
+
+ $out = html::tag('fieldset', null, html::tag('legend', null, Q(rcube_label('specialfolders'))) . $table->show($attrib));
+diff --git a/roundcubemail/program/steps/settings/save_prefs.inc b/roundcubemail/program/steps/settings/save_prefs.inc
+index 09cf63d..b67c73f 100644
+--- a/roundcubemail/program/steps/settings/save_prefs.inc
++++ b/roundcubemail/program/steps/settings/save_prefs.inc
+@@ -46,6 +46,8 @@ $a_user_prefs = array(
+ 'sent_mbox' => get_input_value('_sent_mbox', RCUBE_INPUT_POST),
+ 'junk_mbox' => get_input_value('_junk_mbox', RCUBE_INPUT_POST),
+ 'trash_mbox' => get_input_value('_trash_mbox', RCUBE_INPUT_POST),
++ 'archive_mbox' => get_input_value('_archive_mbox', RCUBE_INPUT_POST),
++ 'hamnotspam_mbox' => get_input_value('_hamnotspam_mbox', RCUBE_INPUT_POST)
+ );
+
+ // don't override these parameters