Add support for setting/retrieving special-use mailboxes from IMAP server
authorMichael M Slusarz <slusarz@curecanti.org>
Fri, 20 Aug 2010 22:47:28 +0000 (16:47 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Fri, 20 Aug 2010 22:57:22 +0000 (16:57 -0600)
imp/docs/CHANGES
imp/docs/RFCS
imp/lib/Folder.php
imp/lib/Prefs/Ui.php
imp/templates/prefs/drafts.html
imp/templates/prefs/sentmail.html
imp/templates/prefs/spam.html
imp/templates/prefs/specialuse.html [new file with mode: 0644]
imp/templates/prefs/trash.html

index 9e99a7c..8a6154b 100644 (file)
@@ -2,6 +2,8 @@
 v5.0-git
 --------
 
+[mms] Add support for setting/retrieving special-use mailboxes from IMAP
+      server.
 [mms] Add preference to control if we check for recipient PGP public keys
       when replying (Request #7962).
 [mms] Add preference to allow for automatic spam reporting when explicitly
index e81860b..91d5043 100644 (file)
@@ -51,8 +51,9 @@ RFC 5530        IMAP Response Codes
 RFC 5550        Lemonade Profile (specifically [2.8] - $Forwarded flag)
 RFC 5819        LIST-STATUS
 
-draft-ietf-morg-sortdisplay-02     SORT=DISPLAY
-draft-ietf-morg-inthread-00        THREAD=REFS
+draft-ietf-morg-list-specialuse-02  CREATE-SPECIAL-USE
+draft-ietf-morg-sortdisplay-02      SORT=DISPLAY
+draft-ietf-morg-inthread-00         THREAD=REFS
 
 
 POP3
index 560ea4d..f8534ba 100644 (file)
 class IMP_Folder
 {
     /**
+     * Mapping of special-use keys to their IMP equivalents.
+     *
+     * @var array
+     */
+    static public $specialUse = array(
+        'drafts' => '\\drafts',
+        'sent' => '\\sent',
+        'spam' => '\\junk',
+        'trash' => '\\trash'
+    );
+
+    /**
      * Keep around identical lists so that we don't hit the server more that
      * once in the same page for the same thing.
      *
@@ -212,6 +224,17 @@ class IMP_Folder
      *
      * @param string $folder      The folder to be created (UTF7-IMAP).
      * @param boolean $subscribe  Subscribe to folder?
+     * @param array $opts         Additional options:
+     * <pre>
+     * 'drafts' - (boolean) Is this a drafts mailbox?
+     *            DEFAULT: false
+     * 'spam' - (boolean) Is this a spam mailbox?
+     *          DEFAULT: false
+     * 'sent' - (boolean) Is this a sent-mail mailbox?
+     *          DEFAULT: false
+     * 'trash' - (boolean) Is this a trash mailbox?
+     *          DEFAULT: false
+     * </pre>
      *
      * @return boolean  Whether or not the folder was successfully created.
      * @throws Horde_Exception
@@ -245,9 +268,17 @@ class IMP_Folder
             return false;
         }
 
+        /* Special use flags. */
+        $special_use = array();
+        foreach ($this->specialUse as $key => $val) {
+            if (!empty($this->_opts[$key])) {
+                $special_use[] = $val;
+            }
+        }
+
         /* Attempt to create the mailbox. */
         try {
-            $GLOBALS['injector']->getInstance('IMP_Imap')->getOb()->createMailbox($folder);
+            $GLOBALS['injector']->getInstance('IMP_Imap')->getOb()->createMailbox($folder, array('special_use' => $special_use));
         } catch (Horde_Imap_Client_Exception $e) {
             $notification->push(sprintf(_("The folder \"%s\" was not created. This is what the server said"), IMP::displayFolder($folder)) . ': ' . $e->getMessage(), 'horde.error');
             return false;
index 7b6954d..ff1a9b9 100644 (file)
  */
 class IMP_Prefs_Ui
 {
+    /* Mailbox identifiers. */
+    const FLIST_SPECIALUSE = "specialuse\0";
+
+    /**
+     * Cached folder list.
+     *
+     * @var array
+     */
+    protected $_cache = null;
+
     /**
      * Populate dynamically-generated preference values.
      *
@@ -430,7 +440,7 @@ class IMP_Prefs_Ui
             return false;
 
         case 'draftsselect':
-            return $this->_updateSpecialFolders('drafts_folder', IMP::formMbox($ui->vars->drafts, false), $ui->vars->drafts_folder_new, $ui);
+            return $this->_updateSpecialFolders('drafts_folder', IMP::formMbox($ui->vars->drafts, false), $ui->vars->drafts_folder_new, 'drafts', $ui);
 
         case 'encryptselect':
             return $prefs->setValue('default_encrypt', $ui->vars->default_encrypt);
@@ -471,7 +481,7 @@ class IMP_Prefs_Ui
             return $this->_updateSource($ui);
 
         case 'spamselect':
-            return $this->_updateSpecialFolders('spam_folder', IMP::formMbox($ui->vars->spam, false), $ui->vars->spam_new, $ui);
+            return $this->_updateSpecialFolders('spam_folder', IMP::formMbox($ui->vars->spam, false), $ui->vars->spam_new, 'spam', $ui);
 
         case 'stationerymanagement':
             return $this->_updateStationeryManagement($ui);
@@ -870,6 +880,7 @@ class IMP_Prefs_Ui
             'new_folder' => true,
             'selected' => IMP::folderPref($GLOBALS['prefs']->getValue('drafts_folder'), true)
         )));
+        $t->set('special_use', $this->_getSpecialUse(IMP_Folder::$specialUse['drafts']));
 
         return $t->fetch(IMP_TEMPLATES . '/prefs/drafts.html');
     }
@@ -1253,6 +1264,7 @@ class IMP_Prefs_Ui
             'filter' => array('INBOX'),
             'new_folder' => true
         )));
+        $t->set('special_use', $this->_getSpecialUse(IMP_Folder::$specialUse['sentmail']));
 
         return $t->fetch(IMP_TEMPLATES . '/prefs/sentmail.html');
     }
@@ -1275,16 +1287,20 @@ class IMP_Prefs_Ui
 
         $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'));
+            $sent_mail_folder = Horde_String::convertCharset($ui->vars->sent_mail_folder_new, $GLOBALS['registry']->getCharset(), 'UTF7-IMAP');
+        } elseif (strpos($sent_mail_folder, self::FLIST_SPECIALUSE) === 0) {
+            $sent_mail_folder = substr($folder, strlen(self::FLIST_SPECIALUSE));
         } elseif (($sent_mail_folder == IMP::PREF_DEFAULT) &&
                   ($sm_default = $prefs->getDefault('sent_mail_folder'))) {
-            $sent_mail_folder = $GLOBALS['injector']->getInstance('IMP_Imap')->getOb()->appendNamespace($sm_default);
+            $sent_mail_folder = $sm_default;
         }
 
+        $sent_mail_folder = $GLOBALS['injector']->getInstance('IMP_Imap')->getOb()->appendNamespace($sent_mail_folder);
+
         if ($sent_mail_folder) {
             $imp_folder = $GLOBALS['injector']->getInstance('IMP_Folder');
             if (!$imp_folder->exists($sent_mail_folder) &&
-                !$imp_folder->create($sent_mail_folder, $prefs->getValue('subscribe'))) {
+                !$imp_folder->create($sent_mail_folder, $prefs->getValue('subscribe'), array('sent' => true))) {
                 return false;
             }
         }
@@ -1542,6 +1558,7 @@ class IMP_Prefs_Ui
             'new_folder' => true,
             'selected' => IMP::folderPref($GLOBALS['prefs']->getValue('spam_folder'), true)
         )));
+        $t->set('special_use', $this->_getSpecialUse(IMP_Folder::$specialUse['junk']));
 
         return $t->fetch(IMP_TEMPLATES . '/prefs/spam.html');
     }
@@ -1693,6 +1710,7 @@ class IMP_Prefs_Ui
             'new_folder' => true,
             'selected' => ($use_vtrash ? null : IMP::folderPref($GLOBALS['prefs']->getValue('trash_folder'), true))
         )));
+        $t->set('special_use', $this->_getSpecialUse(IMP_Folder::$specialUse['trash']));
 
         return $t->fetch(IMP_TEMPLATES . '/prefs/trash.html');
     }
@@ -1711,23 +1729,18 @@ class IMP_Prefs_Ui
         $trash = IMP::formMbox($ui->vars->trash, false);
 
         if ($trash == IMP::PREF_VTRASH) {
-            if ($prefs->isLocked('use_vtrash')) {
-                return false;
-            }
-
-            $prefs->setValue('use_vtrash', 1);
-            $prefs->setValue('trash_folder', '');
-        } else {
-            if ($prefs->isLocked('trash_folder')) {
-                return false;
-            }
-
-            if ($this->_updateSpecialFolders('trash_folder', $trash, $ui->vars->trash_new, $ui)) {
-                $prefs->setValue('use_vtrash', 0);
-                $prefs->setDirty('trash_folder', true);
+            if (!$prefs->isLocked('use_vtrash')) {
+                $prefs->setValue('use_vtrash', 1);
+                $prefs->setValue('trash_folder', '');
                 return true;
             }
+        } elseif ($this->_updateSpecialFolders('trash_folder', $trash, $ui->vars->trash_new, 'trash', $ui)) {
+            $prefs->setValue('use_vtrash', 0);
+            $prefs->setDirty('trash_folder', true);
+            return true;
         }
+
+        return false;
     }
 
     /* Utility functions. */
@@ -1738,11 +1751,12 @@ class IMP_Prefs_Ui
      * @param string $pref             The pref name to update.
      * @param string $folder           The old name.
      * @param string $new              The new name.
+     * @param string $type             Folder type: 'drafts', 'spam', 'trash'.
      * @param Horde_Core_Prefs_Ui $ui  The UI object.
      *
      * @return boolean  True if preferences were updated.
      */
-    protected function _updateSpecialFolders($pref, $folder, $new, $ui)
+    protected function _updateSpecialFolders($pref, $folder, $new, $type, $ui)
     {
         global $prefs;
 
@@ -1755,10 +1769,12 @@ class IMP_Prefs_Ui
             return $prefs->setValue($pref, '');
         }
 
-        if (!empty($new)) {
+        if (strpos($folder, self::FLIST_SPECIALUSE) === 0) {
+            $folder = substr($folder, strlen(self::FLIST_SPECIALUSE));
+        } elseif (!empty($new)) {
             $new = Horde_String::convertCharset($new, $GLOBALS['registry']->getCharset(), 'UTF7-IMAP');
             $folder = $GLOBALS['injector']->getInstance('IMP_Imap')->getOb()->appendNamespace($new);
-            if (!$GLOBALS['injector']->getInstance('IMP_Folder')->create($folder, $prefs->getValue('subscribe'))) {
+            if (!$GLOBALS['injector']->getInstance('IMP_Folder')->create($folder, $prefs->getValue('subscribe'), array($type => true))) {
                 $folder = null;
             }
         }
@@ -1768,4 +1784,42 @@ class IMP_Prefs_Ui
             : false;
     }
 
+    /**
+     * Get the list of special use mailboxes of a certain type.
+     *
+     * @param string $use  The special-use flag.
+     *
+     * @return string  HTML code.
+     */
+    protected function _getSpecialUse($use)
+    {
+        if (is_null($this->_cache)) {
+            $this->_cache = $GLOBALS['injector']->getInstance('IMP_Imap')->getOb()->listMailboxes('*', Horde_Imap_Client::MBOX_ALL, array(
+                'attributes' => true,
+                'special_use' => true,
+                'sort' => true
+            ));
+        }
+
+        $special_use = array();
+        foreach ($this->_cache as $key => $val) {
+            if (in_array($use, $val['attributes'])) {
+                $special_use[] = array(
+                    'l' => htmlspecialchars(IMP::getLabel($val)),
+                    'v' => IMP::formMbox(FLIST_SPECIALUSE . $key, true)
+                );
+            }
+        }
+
+        if (empty($special_use)) {
+            return '';
+        }
+
+        $t = $GLOBALS['injector']->createInstance('Horde_Template');
+        $t->setOption('gettext', true);
+        $t->set('special_use', $special_use);
+
+        return $t->fetch(IMP_TEMPLATES . '/prefs/specialuse.html');
+    }
+
 }
index f471799..ddc999f 100644 (file)
@@ -5,6 +5,7 @@
  <div>
   <select id="drafts" name="drafts">
    <option value="<tag:nofolder />"><gettext>None</gettext></option>
+   <tag:special_use />
    <tag:flist />
   </select>
  </div>
index 16c6f92..b24ffd0 100644 (file)
@@ -6,6 +6,7 @@
   <select name="sent_mail_folder" id="sent_mail_folder">
    <option value=""><gettext>None</gettext></option>
    <option value="<tag:default />" selected="selected"><gettext>Use Default Value</gettext></option>
+   <tag:special_use />
    <tag:flist />
   </select>
  </div>
index d3d9ae6..6ceb5d8 100644 (file)
@@ -5,6 +5,7 @@
  <div>
   <select id="spam" name="spam">
    <option value="<tag:nofolder />"><gettext>None</gettext></option>
+   <tag:special_use />
    <tag:flist />
   </select>
  </div>
diff --git a/imp/templates/prefs/specialuse.html b/imp/templates/prefs/specialuse.html
new file mode 100644 (file)
index 0000000..cf34f33
--- /dev/null
@@ -0,0 +1,5 @@
+<loop:special_use>
+<option value="" disabled="disabled">- - - - - - - - - -</option>
+<option value="<tag:special_use.v />"><gettext>Server Suggestion:</gettext> <tag:special_use.l /></option>
+<option value="" disabled="disabled">- - - - - - - - - -</option>
+</loop:special_use>
index 3706418..5994d69 100644 (file)
@@ -6,6 +6,7 @@
   <select id="trash" name="trash">
    <option value="<tag:nofolder />"><gettext>None</gettext></option>
    <option value="<tag:vtrash />"<if:vtrash_select> selected="selected"</if:vtrash_select>><gettext>Use Virtual Trash</gettext></option>
+   <tag:special_use />
    <tag:flist />
   </select>
  </div>