Initial PGP & S/MIME compose support for DIMP
authorMichael M Slusarz <slusarz@curecanti.org>
Thu, 6 May 2010 16:21:04 +0000 (10:21 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Fri, 7 May 2010 20:45:37 +0000 (14:45 -0600)
imp/compose-dimp.php
imp/docs/CHANGES
imp/js/compose-dimp.js
imp/lib/Ajax/Application.php
imp/lib/Ajax/Imple/PassphraseDialog.php
imp/lib/IMP.php
imp/lib/Ui/Compose.php
imp/message-dimp.php
imp/templates/dimp/chunks/compose.php
imp/templates/dimp/javascript_defs_dimp.php
imp/themes/dimp/screen.css

index 3fd3acd..a195fc8 100644 (file)
@@ -212,6 +212,12 @@ $scripts = array(
     array('TextareaResize.js', 'horde')
 );
 
+if (!($prefs->isLocked('default_encrypt')) &&
+    ($prefs->getValue('use_pgp') || $prefs->getValue('use_smime'))) {
+    $scripts[] = array('dialog.js', 'imp');
+    $scripts[] = array('redbox.js', 'horde');
+}
+
 IMP::status();
 IMP_Dimp::header($title, $scripts);
 echo $t->fetch(IMP_TEMPLATES . '/dimp/compose/compose.html');
index dd8d077..904f9e0 100644 (file)
@@ -2,6 +2,7 @@
 v5.0-git
 --------
 
+[mms] Add PGP & S/MIME compose support to DIMP.
 [mms] Check for incorrect identity on compose if a single recipient address
       is tied to a different identity than the sending identity.
 [mms] Use CATENATE (RFC 4469), if available, to strip MIME parts (Request
index e157605..77344b3 100644 (file)
 var DimpCompose = {
     // Variables defaulting to empty/false:
     //   auto_save_interval, compose_cursor, disabled, drafts_mbox,
-    //   editor_wait, is_popup, knl_p, knl_sm, last_msg, loaded, old_identity,
-    //   rte, skip_spellcheck, spellcheck, sc_submit, uploading
+    //   editor_wait, is_popup, knl, last_msg, loaded, old_action,
+    //   old_identity, rte, skip_spellcheck, spellcheck, sc_submit, uploading
+
+    knl: {},
 
     confirmCancel: function()
     {
@@ -74,7 +76,7 @@ var DimpCompose = {
     {
         var identity = IMP_Compose_Base.getIdentity($F('identity'));
 
-        this.setSentMailLabel(identity.id.smf_name, identity.id.smf_display, true);
+        this.setPopdownLabel('sm', identity.id.smf_name, identity.id.smf_display);
         $('bcc').setValue(identity.id.bcc);
         this.setSaveSentMail(identity.id.smf_save);
 
@@ -95,45 +97,53 @@ var DimpCompose = {
         }
     },
 
-    setSentMailLabel: function(s, l, sel)
+    createPopdown: function(id, opts)
     {
-        var label = $('sent_mail_folder_label');
+        this.knl[id] = {
+            knl: new KeyNavList(opts.base, {
+                esc: true,
+                list: opts.data,
+                onChoose: this.setPopdownLabel.bind(this, id)
+            }),
+            opts: opts
+        };
+
+        $(opts.label).insert({ after: new Element('SPAN', { className: 'popdownImg' }).observe('click', function(e) { if (!this.disabled) { this.knl[id].knl.show(); this.knl[id].knl.ignoreClick(e); e.stop(); } }.bindAsEventListener(this)) });
+    },
+
+    setPopdownLabel: function(id, s, l)
+    {
+        var k = this.knl[id],
+            label = $(k.opts.label),
+            input = $(k.opts.input);
 
         if (!label) {
             return;
         }
 
         if (!l) {
-            l = DIMP.conf_compose.flist.find(function(f) {
+            l = k.opts.data.find(function(f) {
                 return f.v == s;
             });
-            l = l.f || l.v;
+            l = (id == 'sm')
+                ? (l.f || l.v)
+                : l.l;
         }
 
-        $('save_sent_mail_folder').setValue(s);
-        $('sent_mail_folder_label').writeAttribute('title', l.escapeHTML()).setText(l.truncate(15)).up(1).show();
+        $(input).setValue(s);
+        $(label).writeAttribute('title', l.escapeHTML()).setText(l.truncate(15)).up(1).show();
 
-        if (DIMP.conf_compose.flist && sel) {
-            this.knl_sm.setSelected(s);
+        if (id == 'sm') {
+            k.knl.setSelected(s);
         }
     },
 
-    setPriorityLabel: function(s, l)
+    retrySubmit: function(action)
     {
-        var label = $('priority_label');
-
-        if (!label) {
-            return;
-        }
-
-        if (!l) {
-            l = DIMP.conf_compose.priority.find(function(f) {
-                return f.v == s;
-            });
+        if (this.old_action) {
+            this.uniqueSubmit(this.old_action);
+            this.old_action = null;
         }
-
-        $('priority').setValue(s);
-        $('priority_label').setText(l.l);
     },
 
     uniqueSubmit: function(action)
@@ -289,11 +299,18 @@ var DimpCompose = {
                 this.resizeMsgArea();
                 break;
             }
-        } else if (!Object.isUndefined(d.identity)) {
-            this.old_identity = $F('identity');
-            $('identity').setValue(d.identity);
-            this.changeIdentity();
-            $('noticerow', 'identitychecknotice').invoke('show');
+        } else {
+            if (!Object.isUndefined(d.identity)) {
+                this.old_identity = $F('identity');
+                $('identity').setValue(d.identity);
+                this.changeIdentity();
+                $('noticerow', 'identitychecknotice').invoke('show');
+            }
+
+            if (!Object.isUndefined(d.encryptjs)) {
+                this.old_action = d.action;
+                eval(d.encryptjs.join(';'));
+            }
         }
 
         this.setDisabled(false);
@@ -467,7 +484,7 @@ var DimpCompose = {
         if (DIMP.conf_compose.cc) {
             this.toggleCC('cc', true);
         }
-        this.setSentMailLabel(identity.id.smf_name, identity.id.smf_display, true);
+        this.setPopdownLabel('sm', identity.id.smf_name, identity.id.smf_display);
         this.setSaveSentMail(identity.id.smf_save);
         if (header.bcc) {
             $('bcc').setValue(header.bcc);
@@ -866,26 +883,37 @@ var DimpCompose = {
             document.observe('SpellChecker:before', this._onSpellCheckBefore.bind(this));
         }
 
-        /* Create folderlist. */
+        /* Create sent-mail list. */
         if (DIMP.conf_compose.flist) {
-            this.knl_sm = new KeyNavList('save_sent_mail', {
-                esc: true,
-                list: DIMP.conf_compose.flist,
-                onChoose: this.setSentMailLabel.bind(this)
+            this.createPopdown('sm', {
+                base: 'save_sent_mail',
+                data: DIMP.conf_compose.flist,
+                input: 'save_sent_mail_folder',
+                label: 'sent_mail_folder_label'
             });
-            this.knl_sm.setSelected(IMP_Compose_Base.getIdentity($F('identity')).id.smf_name);
-            $('sent_mail_folder_label').insert({ after: new Element('SPAN', { className: 'popdownImg' }).observe('click', function(e) { if (!this.disabled) { this.knl_sm.show(); this.knl_sm.ignoreClick(e); e.stop(); } }.bindAsEventListener(this)) });
+            this.setPopdownLabel('sm', IMP_Compose_Base.getIdentity($F('identity')).id.smf_name);
         }
 
         /* Create priority list. */
         if (DIMP.conf_compose.priority) {
-            this.knl_p = new KeyNavList('priority_label', {
-                esc: true,
-                list: DIMP.conf_compose.priority,
-                onChoose: this.setPriorityLabel.bind(this)
+            this.createPopdown('p', {
+                base: 'priority_label',
+                data: DIMP.conf_compose.priority,
+                input: 'priority',
+                label: 'priority_label'
+            });
+            this.setPopdownLabel('p', $F('priority'));
+        }
+
+        /* Create encryption list. */
+        if (DIMP.conf_compose.encrypt) {
+            this.createPopdown('e', {
+                base: $('encrypt_label').up(),
+                data: DIMP.conf_compose.encrypt,
+                input: 'encrypt',
+                label: 'encrypt_label'
             });
-            this.setPriorityLabel('normal');
-            $('priority_label').insert({ after: new Element('SPAN', { className: 'popdownImg' }).observe('click', function(e) { if (!this.disabled) { this.knl_p.show(); this.knl_p.ignoreClick(e); e.stop(); } }.bindAsEventListener(this)) });
+            this.setPopdownLabel('e', $F('encrypt'));
         }
 
         // Automatically resize compose address fields.
@@ -921,3 +949,15 @@ document.observe('TextareaResize:resize', DimpCompose.resizeMsgArea.bind(DimpCom
 
 /* Click handler. */
 DimpCore.clickHandler = DimpCore.clickHandler.wrap(DimpCompose.clickHandler.bind(DimpCompose));
+
+/* Catch dialog actions. */
+document.observe('IMPDialog:success', function(e) {
+    switch (e.memo) {
+    case 'pgpPersonal':
+    case 'pgpSymmetric':
+    case 'smimePersonal':
+        IMPDialog.noreload = true;
+        DimpCompose.retrySubmit();
+        break;
+    }
+});
index c91c2c1..a3356a8 100644 (file)
@@ -1324,6 +1324,8 @@ class IMP_Ajax_Application extends Horde_Ajax_Application_Base
      * See the list of variables needed for _dimpComposeSetup(). Additional
      * variables used:
      * <pre>
+     * 'encrypt' - (integer) The encryption method to use
+     *             (IMP ENCRYPT constants).
      * 'html' - (integer) In HTML compose mode?
      * 'message' - (string) The message text.
      * 'priority' - TODO
@@ -1337,6 +1339,7 @@ class IMP_Ajax_Application extends Horde_Ajax_Application_Base
      * <pre>
      * 'action' - (string) The AJAX action string
      * 'draft_delete' - (integer) TODO
+     * 'encryptjs' - (array) Javascript to run after encryption failure.
      * 'identity' - (integer) If set, this is the identity that is tied to
      *              the current recipient address.
      * 'log' - (array) TODO
@@ -1372,6 +1375,7 @@ class IMP_Ajax_Application extends Horde_Ajax_Application_Base
         $imptree->eltDiffStart();
 
         $options = array(
+            'encrypt' => ($GLOBALS['prefs']->isLocked('default_encrypt') ? $prefs->getValue('default_encrypt') : $this->_vars->encrypt),
             'identity' => $identity,
             'priority' => $this->_vars->priority,
             'readreceipt' => $this->_vars->request_read_receipt,
@@ -1389,12 +1393,38 @@ class IMP_Ajax_Application extends Horde_Ajax_Application_Base
             $sent = $imp_compose->buildAndSendMessage($this->_vars->message, $headers, Horde_Nls::getEmailCharset(), $this->_vars->html, $options);
         } catch (IMP_Compose_Exception $e) {
             $result->success = 0;
-            $GLOBALS['notification']->push($e);
 
             if (!is_null($e->tied_identity)) {
                 $result->identity = $e->tied_identity;
             }
 
+            if ($e->encrypt) {
+                $imp_ui = $GLOBALS['injector']->getInstance('IMP_Ui_Compose');
+                switch ($e->encrypt) {
+                case 'pgp_symmetric_passphrase_dialog':
+                    $imp_ui->passphraseDialog('pgp_symm', $imp_compose->getCacheId());
+                    break;
+
+                case 'pgp_passphrase_dialog':
+                    $imp_ui->passphraseDialog('pgp');
+                    break;
+
+                case 'smime_passphrase_dialog':
+                    $imp_ui->passphraseDialog('smime');
+                    break;
+                }
+
+                Horde::startBuffer();
+                Horde::outputInlineScript(true);
+                if ($js_inline = Horde::endBuffer()) {
+                    $result->encryptjs = array($js_inline);
+                }
+            } else {
+                /* Don't push notification if showing passphrase dialog -
+                 * passphrase dialog contains the necessary information. */
+                $GLOBALS['notification']->push($e);
+            }
+
             return $result;
         }
 
@@ -1516,7 +1546,7 @@ class IMP_Ajax_Application extends Horde_Ajax_Application_Base
             return array($result);
         }
 
-        $imp_ui = new IMP_Ui_Compose();
+        $imp_ui = $GLOBALS['injector']->getInstance('IMP_Ui_Compose');
         $headers['to'] = $imp_ui->getAddressList($this->_vars->to);
         if ($GLOBALS['prefs']->getValue('compose_cc')) {
             $headers['cc'] = $imp_ui->getAddressList($this->_vars->cc);
index e85021d..cbe53e8 100644 (file)
@@ -136,7 +136,7 @@ class IMP_Ajax_Imple_PassphraseDialog extends Horde_Ajax_Imple_Base
                     $imp_pgp = $GLOBALS['injector']->getInstance('IMP_Crypt_Pgp');
                     if ((($vars->type == 'pgpPersonal') &&
                          $imp_pgp->storePassphrase('personal', $vars->dialog_input)) ||
-                        (($vars->type == 'pgpSymmeetric') &&
+                        (($vars->type == 'pgpSymmetric') &&
                          $imp_pgp->storePassphrase('symmetric', $vars->dialog_input, $vars->symmetricid))) {
                         $result->success = 1;
                     } else {
index 8032a67..8d5ba8b 100644 (file)
@@ -827,7 +827,7 @@ class IMP
             $default = $GLOBALS['prefs']->getValue('default_encrypt');
         }
 
-        $enc_opts = array(self::ENCRYPT_NONE => _("No Encryption"));
+        $enc_opts = array(self::ENCRYPT_NONE => _("None"));
         $output = '';
 
         if (!empty($GLOBALS['conf']['gnupg']['path']) &&
index 7326804..6b5150d 100644 (file)
@@ -260,7 +260,7 @@ class IMP_Ui_Compose
             break;
         }
 
-        Horde_Ajax_Imple::factory(array('imp', 'PassphraseDialog'), array('params' => $params, 'type' => $type))->attach();
+        Horde_Ajax_Imple::factory(array('imp', 'PassphraseDialog'), array('onload' => true, 'params' => $params, 'type' => $type))->attach();
     }
 
     /**
index 7bf5e54..a6815d3 100644 (file)
@@ -76,6 +76,12 @@ if (!$disable_compose) {
     $scripts[] = array('compose-base.js', 'imp');
     $scripts[] = array('compose-dimp.js', 'imp');
 
+    if (!($prefs->isLocked('default_encrypt')) &&
+        ($prefs->getValue('use_pgp') || $prefs->getValue('use_smime'))) {
+        $scripts[] = array('dialog.js', 'imp');
+        $scripts[] = array('redbox.js', 'horde');
+        }
+
     $js_onload = $compose_result['jsonload'];
 }
 
index 0e63787..9c50b7c 100644 (file)
@@ -13,6 +13,7 @@
  */
 
 $d_read = $GLOBALS['prefs']->getValue('disposition_request_read');
+$encrypt_list = (($GLOBALS['prefs']->isLocked('default_encrypt')) && ($GLOBALS['prefs']->getValue('use_pgp') || $GLOBALS['prefs']->getValue('use_smime')));
 $save_attach = $GLOBALS['prefs']->getValue('save_attachments');
 
 /* Determine if compose mode is disabled. */
@@ -76,6 +77,12 @@ $compose_disable = !IMP::canCompose();
     <input id="priority" name="priority" type="hidden" value="normal" />
    </div>
 <?php endif; ?>
+<?php if (!is_null($encrypt_list)): ?>
+   <div>
+    <?php echo _("Encryption:") ?> <span id="encrypt_label"></span>
+    <input id="encrypt" name="encrypt" type="hidden" value="<?php echo IMP::ENCRYPT_NONE ?>" />
+   </div>
+<?php endif; ?>
   </div>
   <table>
    <tr>
index e13f392..9d94edd 100644 (file)
@@ -195,6 +195,19 @@ if (in_array(basename($_SERVER['PHP_SELF']), array('compose-dimp.php', 'message-
             )
         );
     }
+
+    if (!($GLOBALS['prefs']->isLocked('default_encrypt')) &&
+        ($GLOBALS['prefs']->getValue('use_pgp') ||
+         $GLOBALS['prefs']->getValue('use_smime'))) {
+        $encrypt = array();
+        foreach (IMP::encryptList(null, true) as $key => $val) {
+            $encrypt[] = array(
+                'l' => htmlspecialchars($val),
+                'v' => intval($key)
+            );
+        }
+        $code['conf_compose']['encrypt'] = $encrypt;
+    }
 }
 
 Horde::addInlineScript(array(
index e2907b8..b8d1a6e 100644 (file)
@@ -409,7 +409,7 @@ div.vpRowVert.flagUnseen {
     text-decoration: underline;
 }
 
-#priority_label {
+#encrypt_label, #priority_label {
     cursor: default;
     font-weight: bold;
 }