From 42898815201e243f6b36b2daea0825bac1128eaf Mon Sep 17 00:00:00 2001 From: Michael M Slusarz Date: Mon, 16 Aug 2010 23:32:22 -0600 Subject: [PATCH] Fix escaping null characters in mailbox names. The null character can not be used in form elements. However, we use the null character in mailbox names to indicate mailboxes/elements that do not live on the IMAP server - necessary because null is the only character technically not allowed for IMAP mailboxes. So we need to manually call IMP::formMbox() when creating forms to escape mailbox names (and then when reading forms to unescape the names - but most of the time this will be done automatically by IMP::setCurrentMailboxInfo()). --- imp/js/folderprefs.js | 4 +-- imp/lib/Dimp.php | 2 +- imp/lib/IMP.php | 39 +++++++++++++++----- imp/lib/Imap/Tree.php | 12 +++---- imp/lib/LoginTasks/SystemTask/UpgradeFromImp4.php | 14 ++++++++ imp/lib/Message.php | 8 ++--- imp/lib/Prefs/Ui.php | 43 ++++++++++++----------- imp/lib/Search.php | 2 +- imp/mailbox.php | 4 +-- imp/message.php | 4 +-- imp/templates/imp/flist/flist.html | 2 +- imp/templates/prefs/initialpage.html | 3 +- imp/templates/prefs/sentmail.html | 2 +- 13 files changed, 89 insertions(+), 50 deletions(-) diff --git a/imp/js/folderprefs.js b/imp/js/folderprefs.js index cc5cb3f31..2566d6fc4 100644 --- a/imp/js/folderprefs.js +++ b/imp/js/folderprefs.js @@ -18,7 +18,7 @@ var ImpFolderPrefs = { newfolder = $(id + '_new'), sel = $(f[f.selectedIndex]); - if (sel.value == '\0create' && !newfolder) { + if (sel.hasClassName('flistCreate') && !newfolder) { folder = window.prompt(txt, ''); if (!folder.empty()) { if (!newfolder) { @@ -39,7 +39,7 @@ var ImpFolderPrefs = { $('sent_mail_folder').setValue(this.sentmail[e.memo.i]); if (this.origtext) { $('sent_mail_folder_new').remove(); - $('sent_mail_folder').down('[value="\0create"]').update(this.origtext); + $('sent_mail_folder').down('.flistCreate').update(this.origtext); this.origtext = null; } break; diff --git a/imp/lib/Dimp.php b/imp/lib/Dimp.php index bbb92adbe..b7e592b21 100644 --- a/imp/lib/Dimp.php +++ b/imp/lib/Dimp.php @@ -15,7 +15,7 @@ class IMP_Dimp { /* String used to separate indexes. */ - const IDX_SEP = '\0'; + const IDX_SEP = "\0"; /** * Output a dimp-style action (menubar) link. diff --git a/imp/lib/IMP.php b/imp/lib/IMP.php index 343d9f2df..696758057 100644 --- a/imp/lib/IMP.php +++ b/imp/lib/IMP.php @@ -34,8 +34,13 @@ class IMP const MAILBOX_START_LASTPAGE = 4; /* Preferences constants. */ - const PREF_NO_FOLDER = 'nofolder\0'; - const PREF_VTRASH = 'vtrash\0'; + const PREF_DEFAULT = "default\0"; + const PREF_NO_FOLDER = "nofolder\0"; + const PREF_VTRASH = "vtrash\0"; + + /* Folder list actions. */ + const NOTEPAD_EDIT = "notepad\0"; + const TASKLIST_EDIT = "tasklist\0"; /* Sorting constants. */ const IMAP_SORT_DATE = 100; @@ -230,7 +235,7 @@ class IMP $mbox_list[] = array( 'l' => $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($label, 'space2html', array('encode' => true)), 'sel' => (!empty($options['selected']) && ($mbox['val'] === $options['selected'])), - 'v' => htmlspecialchars($mbox['val']) + 'v' => self::formMbox($mbox['val'], true) ); } } @@ -247,7 +252,7 @@ class IMP $vfolder_list[] = array( 'l' => $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($val, 'space2html', array('encode' => true)), 'sel' => ($vfolder_sel == $id), - 'v' => htmlspecialchars($imp_search->createSearchID($id)) + 'v' => self::formMbox($imp_search->createSearchID($id), true) ); } $t->set('vfolder', $vfolder_list); @@ -265,7 +270,7 @@ class IMP foreach ($tasklists as $id => $tasklist) { $tasklist_list[] = array( 'l' => $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($tasklist->get('name'), 'space2html', array('encode' => true)), - 'v' => '\0tasklist_' . $id + 'v' => self::formMbox(self::TASKLIST_EDIT . $id, true) ); } $t->set('tasklist', $tasklist_list); @@ -284,7 +289,7 @@ class IMP foreach ($notepads as $id => $notepad) { $notepad_list[] = array( 'l' => $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($notepad->get('name'), 'space2html', array('encode' => true)), - 'v' => '\0notepad_' . $id + 'v' => self::formMbox(self::NOTEPAD_EDIT . $id, true) ); } $t->set('notepad', $notepad_list); @@ -1060,8 +1065,8 @@ class IMP { if (is_null($mbox)) { $mbox = Horde_Util::getFormData('mailbox'); - self::$mailbox = empty($mbox) ? 'INBOX' : $mbox; - self::$thismailbox = Horde_Util::getFormData('thismailbox', $mbox); + self::$mailbox = empty($mbox) ? 'INBOX' : self::formMbox($mbox, false); + self::$thismailbox = self::formMbox(Horde_Util::getFormData('thismailbox', $mbox), false); self::$uid = Horde_Util::getFormData('uid'); } else { self::$mailbox = $mbox; @@ -1187,4 +1192,22 @@ class IMP ); } + /** + * Converts a mailbox to/from a valid representation that can be used + * in a form element. Needed because null characters (used for various + * internal non-IMAP mailbox representations) will not work in form + * elements. + * + * @param string $mbox The mailbox name. + * @param boolean $to Convert to the form representation? + * + * @return string The converted mailbox. + */ + static public function formMbox($mbox, $to) + { + return $to + ? htmlspecialchars(rawurlencode($mbox), ENT_COMPAT, $GLOBALS['registry']->getCharset()) + : rawurldecode($mbox); + } + } diff --git a/imp/lib/Imap/Tree.php b/imp/lib/Imap/Tree.php index 9cc45432f..1d1b90ea2 100644 --- a/imp/lib/Imap/Tree.php +++ b/imp/lib/Imap/Tree.php @@ -42,10 +42,10 @@ class IMP_Imap_Tree const NEXT_SHOWSUB = 2; const NEXT_NOCHILDREN = 4; - /* The string used to indicate the base of the tree. This must be null - * since this is the only 7-bit character not allowed in IMAP + /* The string used to indicate the base of the tree. This must include + * null since this is the only 7-bit character not allowed in IMAP * mailboxes. */ - const BASE_ELT = '\0'; + const BASE_ELT = "base\0"; /* Defines used with folderList(). */ const FLIST_CONTAINER = 1; @@ -59,11 +59,11 @@ class IMP_Imap_Tree /* Add null to folder key since it allows us to sort by name but * never conflict with an IMAP mailbox. */ - const VFOLDER_KEY = 'vfolder\0'; + const VFOLDER_KEY = "vfolder\0"; /* Defines used with namespace display. */ - const SHARED_KEY = 'shared\0'; - const OTHER_KEY = 'other\0'; + const SHARED_KEY = "shared\0"; + const OTHER_KEY = "other\0"; /** * Tree changed flag. Set when something in the tree has been altered. diff --git a/imp/lib/LoginTasks/SystemTask/UpgradeFromImp4.php b/imp/lib/LoginTasks/SystemTask/UpgradeFromImp4.php index 5fa604c67..28e33faf8 100644 --- a/imp/lib/LoginTasks/SystemTask/UpgradeFromImp4.php +++ b/imp/lib/LoginTasks/SystemTask/UpgradeFromImp4.php @@ -28,6 +28,7 @@ class IMP_LoginTasks_SystemTask_UpgradeFromImp4 extends Horde_LoginTasks_SystemT { $this->_upgradeAbookPrefs(); $this->_upgradeForwardPrefs(); + $this->_upgradeLoginTasks(); $this->_upgradeSortPrefs(); $this->_upgradeVirtualFolders(); } @@ -103,6 +104,19 @@ class IMP_LoginTasks_SystemTask_UpgradeFromImp4 extends Horde_LoginTasks_SystemT } /** + * Upgrade to the new login tasks preferences. + */ + protected function _upgradeForwardPrefs() + { + global $prefs; + + if (!$prefs->isDefault('initial_page') && + ($prefs->getValue('initial_page') == 'folders.php')) { + $prefs->setValue('initial_page', IMP::PREF_FOLDER_PAGE); + } + } + + /** * Check for old, non-existent sort values. See Bug #7296. */ protected function _upgradeSortPrefs() diff --git a/imp/lib/Message.php b/imp/lib/Message.php index bcfc5fded..98f57830f 100644 --- a/imp/lib/Message.php +++ b/imp/lib/Message.php @@ -64,15 +64,15 @@ class IMP_Message /* If the target is a tasklist, handle the move/copy specially. */ if ($conf['tasklist']['use_tasklist'] && - (strpos($targetMbox, '\0tasklist_') === 0)) { - $this->_createTasksOrNotes(str_replace('\0tasklist_', '', $targetMbox), $action, $indices, 'task'); + (strpos($targetMbox, IMP::TASKLIST_EDIT) === 0)) { + $this->_createTasksOrNotes(str_replace(IMP::TASKLIST_EDIT, '', $targetMbox), $action, $indices, 'task'); return true; } /* If the target is a notepad, handle the move/copy specially. */ if ($conf['notepad']['use_notepad'] && - (strpos($targetMbox, '\0notepad_') === 0)) { - $this->_createTasksOrNotes(str_replace('\0notepad_', '', $targetMbox), $action, $indices, 'note'); + (strpos($targetMbox, IMP::NOTEPAD_EDIT) === 0)) { + $this->_createTasksOrNotes(str_replace(IMP::NOTEPAD_EDIT, '', $targetMbox), $action, $indices, 'note'); return true; } diff --git a/imp/lib/Prefs/Ui.php b/imp/lib/Prefs/Ui.php index 377d23cc9..26e4014f9 100644 --- a/imp/lib/Prefs/Ui.php +++ b/imp/lib/Prefs/Ui.php @@ -421,7 +421,7 @@ class IMP_Prefs_Ui return false; case 'draftsselect': - return $this->_updateSpecialFolders('drafts_folder', $ui->vars->drafts, $ui->vars->drafts_folder_new, $ui); + return $this->_updateSpecialFolders('drafts_folder', IMP::formMbox($ui->vars->drafts, false), $ui->vars->drafts_folder_new, $ui); case 'encryptselect': return $prefs->setValue('default_encrypt', $ui->vars->default_encrypt); @@ -431,7 +431,7 @@ class IMP_Prefs_Ui return false; case 'initialpageselect': - return $prefs->setValue('initial_page', $ui->vars->initial_page); + return $prefs->setValue('initial_page', IMP::formMbox($ui->vars->initial_page, false)); case 'pgpprivatekey': $this->_updatePgpPrivateKey($ui); @@ -462,7 +462,7 @@ class IMP_Prefs_Ui return $this->_updateSource($ui); case 'spamselect': - return $this->_updateSpecialFolders('spam_folder', $ui->vars->spam, $ui->vars->spam_new, $ui); + return $this->_updateSpecialFolders('spam_folder', IMP::formMbox($ui->vars->spam, false), $ui->vars->spam_new, $ui); case 'stationerymanagement': return $this->_updateStationeryManagement($ui); @@ -668,7 +668,7 @@ class IMP_Prefs_Ui $folder = empty($ui->vars->folder) ? 'INBOX' - : $ui->vars->folder; + : IMP::formMbox($ui->vars->folder, false); try { $curr_acl = $acl->getACL($folder); @@ -683,7 +683,7 @@ class IMP_Prefs_Ui $t->set('options', IMP::flistSelect(array('selected' => $folder))); $t->set('current', sprintf(_("Current access to %s"), IMP::displayFolder($folder))); - $t->set('folder', $folder); + $t->set('folder', IMP::formMbox($folder, true)); $t->set('noacl', !count($curr_acl)); $t->set('maxrule', 1); @@ -763,6 +763,7 @@ class IMP_Prefs_Ui } $acl = $GLOBALS['injector']->getInstance('IMP_Imap_Acl'); + $folder = IMP::formMbox($ui->vars->folder, false); $rights = array_keys($acl->getRights()); $acl_list = $ui->vars->acl; @@ -777,11 +778,11 @@ class IMP_Prefs_Ui $acl_list[$new_user] = $ui->vars->new_acl; } else { try { - $acl->editACL($ui->vars->folder, $new_user, $ui->vars->new_acl); + $acl->editACL($folder, $new_user, $ui->vars->new_acl); if (count($ui->vars->new_acl)) { - $GLOBALS['notification']->push(sprintf(_("User \"%s\" successfully given the specified rights for the folder \"%s\"."), $new_user, IMP::getLabel($ui->vars->folder)), 'horde.success'); + $GLOBALS['notification']->push(sprintf(_("User \"%s\" successfully given the specified rights for the folder \"%s\"."), $new_user, IMP::getLabel($folder)), 'horde.success'); } else { - $GLOBALS['notification']->push(sprintf(_("All rights on folder \"%s\" successfully removed for user \"%s\"."), IMP::getLabel($ui->vars->folder), $new_user), 'horde.success'); + $GLOBALS['notification']->push(sprintf(_("All rights on folder \"%s\" successfully removed for user \"%s\"."), IMP::getLabel($folder), $new_user), 'horde.success'); } } catch (IMP_Exception $e) { $GLOBALS['notification']->push($e); @@ -791,7 +792,7 @@ class IMP_Prefs_Ui } try { - $curr_acl = $acl->getACL($ui->vars->folder); + $curr_acl = $acl->getACL($folder); } catch (IMP_Exception $e) { $GLOBALS['notification']->notify($e); return; @@ -833,13 +834,13 @@ class IMP_Prefs_Ui * but ignore c and d rights that are sent for BC reasons (RFC * 4314 [2.1.1]. */ $val = array_merge($val, array_diff($curr_acl[$user], array_merge($rights, array('c', 'd')))); - $acl->editACL($ui->vars->folder, $user, $val); + $acl->editACL($folder, $user, $val); if (!count($val)) { if (isset($curr_acl[$user])) { - $GLOBALS['notification']->push(sprintf(_("All rights on folder \"%s\" successfully removed for user \"%s\"."), IMP::getLabel($ui->vars->folder), $user), 'horde.success'); + $GLOBALS['notification']->push(sprintf(_("All rights on folder \"%s\" successfully removed for user \"%s\"."), IMP::getLabel($folder), $user), 'horde.success'); } } else { - $GLOBALS['notification']->push(sprintf(_("User \"%s\" successfully given the specified rights for the folder \"%s\"."), $user, IMP::getLabel($ui->vars->folder)), 'horde.success'); + $GLOBALS['notification']->push(sprintf(_("User \"%s\" successfully given the specified rights for the folder \"%s\"."), $user, IMP::getLabel($folder)), 'horde.success'); } } catch (IMP_Exception $e) { $GLOBALS['notification']->push($e); @@ -1013,7 +1014,8 @@ class IMP_Prefs_Ui $t->set('nofolder', true); } else { $mailbox_selected = $GLOBALS['prefs']->getValue('initial_page'); - $t->set('folder_sel', $mailbox_selected == 'folders.php'); + $t->set('folder_page', IMP::formMbox(IMP::PREF_FOLDER_PAGE, true)); + $t->set('folder_sel', $mailbox_selected == IMP::PREF_FOLDER_PAGE); $t->set('flist', IMP::flistSelect(array( 'inc_vfolder' => true, 'selected' => $mailbox_selected @@ -1242,6 +1244,7 @@ class IMP_Prefs_Ui $t = $GLOBALS['injector']->createInstance('Horde_Template'); $t->setOption('gettext', true); + $t->set('default', IMP::formMbox(IMP::PREF_DEFAULT, true)); $t->set('label', Horde::label('sent_mail_folder', _("Sent mail folder:"))); $t->set('flist', IMP::flistSelect(array( 'filter' => array('INBOX'), @@ -1267,15 +1270,11 @@ class IMP_Prefs_Ui return false; } - $sent_mail_folder = $ui->vars->sent_mail_folder; + $sent_mail_folder = IMP::formMbox($ui->vars->sent_mail_folder, false); if (empty($sent_mail_folder) && $ui->vars->sent_mail_folder_new) { $sent_mail_folder = $GLOBALS['injector']->getInstance('IMP_Imap')->getOb()->appendNamespace(Horde_String::convertCharset($ui->vars->sent_mail_folder_new, $GLOBALS['registry']->getCharset(), 'UTF7-IMAP')); - } elseif (($sent_mail_folder == "\1default") && + } elseif (($sent_mail_folder == IMP::PREF_DEFAULT) && ($sm_default = $prefs->getDefault('sent_mail_folder'))) { - /* Use \1 as the prefix to differentiate from a IMAP mailbox - * potentially named 'default'. \1 is theoretically a valid - * IMAP mailbox character, but it is highly unlikely it exists - * anywhere (and we can't use \0 in form data). */ $sent_mail_folder = $GLOBALS['injector']->getInstance('IMP_Imap')->getOb()->appendNamespace($sm_default); } @@ -1706,7 +1705,9 @@ class IMP_Prefs_Ui { global $prefs; - if ($ui->vars->trash == IMP::PREF_VTRASH) { + $trash = IMP::formMbox($ui->vars->trash, false); + + if ($trash == IMP::PREF_VTRASH) { if ($prefs->isLocked('use_vtrash')) { return false; } @@ -1718,7 +1719,7 @@ class IMP_Prefs_Ui return false; } - if ($this->_updateSpecialFolders('trash_folder', $ui->vars->trash, $ui->vars->trash_new, $ui)) { + if ($this->_updateSpecialFolders('trash_folder', $trash, $ui->vars->trash_new, $ui)) { $prefs->setValue('use_vtrash', 0); $prefs->setDirty('trash_folder', true); return true; diff --git a/imp/lib/Search.php b/imp/lib/Search.php index 74c4987ca..e5dabe474 100644 --- a/imp/lib/Search.php +++ b/imp/lib/Search.php @@ -64,7 +64,7 @@ class IMP_Search { /* The mailbox search prefix. */ - const MBOX_PREFIX = 'impsearch\0'; + const MBOX_PREFIX = "impsearch\0"; /* The special search mailbox names. */ const BASIC_SEARCH = 'impbsearch'; diff --git a/imp/mailbox.php b/imp/mailbox.php index 594d9a5d6..3de12f514 100644 --- a/imp/mailbox.php +++ b/imp/mailbox.php @@ -480,7 +480,7 @@ if ($pageOb['msgcount']) { } $n_template->set('mailbox_url', $mailbox_url); - $n_template->set('mailbox', htmlspecialchars(IMP::$mailbox)); + $n_template->set('mailbox', IMP::formMbox(IMP::$mailbox, true)); if ($pageOb['pagecount'] > 1) { $n_template->set('multiple_page', true); $n_template->set('pages_first', $pages_first); @@ -651,7 +651,7 @@ foreach ($headers as $key => $val) { /* Output the form start. */ $f_template = $injector->createInstance('Horde_Template'); -$f_template->set('mailbox', htmlspecialchars(IMP::$mailbox)); +$f_template->set('mailbox', IMP::formMbox(IMP::$mailbox, true)); $f_template->set('mailbox_token', $mailbox_token); $f_template->set('mailbox_url', $mailbox_url); $f_template->set('sessiontag', Horde_Util::formInput()); diff --git a/imp/message.php b/imp/message.php index 7e98176a5..9fa8b46cc 100644 --- a/imp/message.php +++ b/imp/message.php @@ -408,7 +408,7 @@ if ($search_mbox) { $t_template = $injector->createInstance('Horde_Template'); $t_template->set('message_url', $message_url); $t_template->set('form_input', Horde_Util::formInput()); -$t_template->set('mailbox', htmlspecialchars(IMP::$mailbox)); +$t_template->set('mailbox', IMP::formMbox(IMP::$mailbox, true)); $t_template->set('thismailbox', htmlspecialchars($mailbox_name)); $t_template->set('start', htmlspecialchars($msgindex)); $t_template->set('uid', htmlspecialchars($uid)); @@ -425,7 +425,7 @@ $n_template->set('usepop', $use_pop); $n_template->set('id', 1); if (!$use_pop) { - $n_template->set('mailbox', IMP::$mailbox); + $n_template->set('mailbox', IMP::formMbox(IMP::$mailbox, true)); $tmp = $imp_flags->getFlagList(IMP::$mailbox); $n_template->set('flaglist_set', $tmp['set']); diff --git a/imp/templates/imp/flist/flist.html b/imp/templates/imp/flist/flist.html index 36a932079..4e6a7d849 100644 --- a/imp/templates/imp/flist/flist.html +++ b/imp/templates/imp/flist/flist.html @@ -3,7 +3,7 @@ - + diff --git a/imp/templates/prefs/initialpage.html b/imp/templates/prefs/initialpage.html index 88e6bf8c1..91097178b 100644 --- a/imp/templates/prefs/initialpage.html +++ b/imp/templates/prefs/initialpage.html @@ -7,7 +7,8 @@ - + + diff --git a/imp/templates/prefs/sentmail.html b/imp/templates/prefs/sentmail.html index 54ce6c06a..16c6f9211 100644 --- a/imp/templates/prefs/sentmail.html +++ b/imp/templates/prefs/sentmail.html @@ -5,7 +5,7 @@
-- 2.11.0