From fe8ff85d7eabb370d85fc31ca55b9a6c6f86a356 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Thu, 15 Oct 2015 02:58:06 -0400
Subject: [PATCH] Move skin-specific code for compose encryption button to the skin

---
 program/js/common.js |  239 +++++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 188 insertions(+), 51 deletions(-)

diff --git a/program/js/common.js b/program/js/common.js
index 2b20ff5..329ffb5 100644
--- a/program/js/common.js
+++ b/program/js/common.js
@@ -1,24 +1,35 @@
-/*
- +-----------------------------------------------------------------------+
- | Roundcube common js library                                           |
- |                                                                       |
- | This file is part of the Roundcube web development suite              |
- | Copyright (C) 2005-2012, The Roundcube Dev Team                       |
- |                                                                       |
- | Licensed under the GNU General Public License version 3 or            |
- | any later version with exceptions for skins & plugins.                |
- | See the README file for a full license statement.                     |
- |                                                                       |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com>                        |
- +-----------------------------------------------------------------------+
-*/
+/**
+ * Roundcube common js library
+ *
+ * This file is part of the Roundcube Webmail client
+ *
+ * @licstart  The following is the entire license notice for the
+ * JavaScript code in this file.
+ *
+ * Copyright (c) 2005-2014, The Roundcube Dev Team
+ *
+ * The JavaScript code in this page is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GNU GPL) as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option)
+ * any later version.  The code is distributed WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
+ *
+ * As additional permission under GNU GPL version 3 section 7, you
+ * may distribute non-source (e.g., minimized or compacted) forms of
+ * that code without the copy of the GNU GPL normally required by
+ * section 4, provided you include this license notice and a URL
+ * through which recipients can access the Corresponding Source.
+ *
+ * @licend  The above is the entire license notice
+ * for the JavaScript code in this file.
+ */
 
 // Constants
 var CONTROL_KEY = 1;
 var SHIFT_KEY = 2;
 var CONTROL_SHIFT_KEY = 3;
-
 
 /**
  * Default browser check class
@@ -28,8 +39,6 @@
 {
   var n = navigator;
 
-  this.ver = parseFloat(n.appVersion);
-  this.appver = n.appVersion;
   this.agent = n.userAgent;
   this.agent_lc = n.userAgent.toLowerCase();
   this.name = n.appName;
@@ -53,19 +62,20 @@
   this.ie = (document.all && !window.opera) || (this.win && this.agent_lc.indexOf('trident/') > 0);
 
   if (this.ie) {
-    this.ie7 = this.appver.indexOf('MSIE 7') > 0;
-    this.ie8 = this.appver.indexOf('MSIE 8') > 0;
-    this.ie9 = this.appver.indexOf('MSIE 9') > 0;
+    this.ie7 = n.appVersion.indexOf('MSIE 7') > 0;
+    this.ie8 = n.appVersion.indexOf('MSIE 8') > 0;
+    this.ie9 = n.appVersion.indexOf('MSIE 9') > 0;
   }
   else if (window.opera) {
-    this.opera = true;
+    this.opera = true; // Opera < 15
     this.vendver = opera.version();
   }
   else {
     this.chrome = this.agent_lc.indexOf('chrome') > 0;
-    this.safari = !this.chrome && (this.webkit || this.agent_lc.indexOf('safari') > 0);
+    this.opera = this.webkit && this.agent.indexOf(' OPR/') > 0; // Opera >= 15
+    this.safari = !this.chrome && !this.opera && (this.webkit || this.agent_lc.indexOf('safari') > 0);
     this.konq = this.agent_lc.indexOf('konqueror') > 0;
-    this.mz = this.dom && !this.chrome && !this.safari && !this.konq && this.agent.indexOf('Mozilla') >= 0;
+    this.mz = this.dom && !this.chrome && !this.safari && !this.konq && !this.opera && this.agent.indexOf('Mozilla') >= 0;
     this.iphone = this.safari && (this.agent_lc.indexOf('iphone') > 0 || this.agent_lc.indexOf('ipod') > 0);
     this.ipad = this.safari && this.agent_lc.indexOf('ipad') > 0;
   }
@@ -92,7 +102,7 @@
   this.xmlhttp_test = function()
   {
     var activeX_test = new Function("try{var o=new ActiveXObject('Microsoft.XMLHTTP');return true;}catch(err){return false;}");
-    this.xmlhttp = (window.XMLHttpRequest || (window.ActiveXObject && activeX_test()));
+    this.xmlhttp = window.XMLHttpRequest || (('ActiveXObject' in window) && activeX_test());
     return this.xmlhttp;
   };
 
@@ -212,7 +222,7 @@
     p.element = document;
 
   if (!p.object._rc_events)
-    p.object._rc_events = [];
+    p.object._rc_events = {};
 
   var key = p.event + '*' + p.method;
   if (!p.object._rc_events[key])
@@ -267,6 +277,28 @@
   e.cancelBubble = true;
 
   return false;
+},
+
+/**
+ * Determine whether the given event was trigered from keyboard
+ */
+is_keyboard: function(e)
+{
+  return e && (
+      (e.pointerType !== undefined && e.pointerType !== 'mouse') ||       // IE 11+
+      (e.mozInputSource && e.mozInputSource == e.MOZ_SOURCE_KEYBOARD) ||  // Firefox
+      (e.offsetX === 0 && e.offsetY === 0) || // Opera
+      (!e.pageX && (e.pageY || 0) <= 0 && !e.clientX && (e.clientY || 0) <= 0) ||  // others
+      (bw.ie && rcube_event._last_keyboard_event && rcube_event._last_keyboard_event.target == e.target)  // hack for IE <= 10
+    );
+},
+
+/**
+ * Accept event if triggered from keyboard action (e.g. <Enter>)
+ */
+keyboard_only: function(e)
+{
+  return rcube_event.is_keyboard(e) ? true : rcube_event.cancel(e);
 },
 
 touchevent: function(e)
@@ -330,13 +362,17 @@
 triggerEvent: function(evt, e)
 {
   var ret, h;
+
   if (e === undefined)
     e = this;
   else if (typeof e === 'object')
     e.event = evt;
 
-  if (this._events && this._events[evt] && !this._event_exec) {
-    this._event_exec = true;
+  if (!this._event_exec)
+    this._event_exec = {};
+
+  if (this._events && this._events[evt] && !this._event_exec[evt]) {
+    this._event_exec[evt] = true;
     for (var i=0; i < this._events[evt].length; i++) {
       if ((h = this._events[evt][i])) {
         if (typeof h.func === 'function')
@@ -359,7 +395,8 @@
     }
   }
 
-  this._event_exec = false;
+  delete this._event_exec[evt];
+
   if (e.event) {
     try {
       delete e.event;
@@ -411,7 +448,7 @@
       ],
       icann_addr = 'mailtest\\x40('+icann_domains.join('|')+')',
       word = '('+atom+'|'+quoted_string+')',
-      delim = '[,;\s\n]',
+      delim = '[,;\\s\\n]',
       local_part = word+'(\\x2e'+word+')*',
       addr_spec = '(('+local_part+'\\x40'+domain+')|('+icann_addr+'))',
       reg1 = inline ? new RegExp('(^|<|'+delim+')'+addr_spec+'($|>|'+delim+')', 'i') : new RegExp('^'+addr_spec+'$', 'i');
@@ -455,21 +492,25 @@
 function rcube_find_object(id, d)
 {
   var n, f, obj, e;
-  if(!d) d = document;
 
-  if(d.getElementsByName && (e = d.getElementsByName(id)))
+  if (!d) d = document;
+
+  if (d.getElementById)
+    if (obj = d.getElementById(id))
+      return obj;
+
+  if (!obj && d.getElementsByName && (e = d.getElementsByName(id)))
     obj = e[0];
-  if(!obj && d.getElementById)
-    obj = d.getElementById(id);
-  if(!obj && d.all)
+
+  if (!obj && d.all)
     obj = d.all[id];
 
-  if(!obj && d.images.length)
+  if (!obj && d.images.length)
     obj = d.images[id];
 
   if (!obj && d.forms.length) {
     for (f=0; f<d.forms.length; f++) {
-      if(d.forms[f].name == id)
+      if (d.forms[f].name == id)
         obj = d.forms[f];
       else if(d.forms[f].elements[id])
         obj = d.forms[f].elements[id];
@@ -477,7 +518,8 @@
   }
 
   if (!obj && d.layers) {
-    if (d.layers[id]) obj = d.layers[id];
+    if (d.layers[id])
+      obj = d.layers[id];
     for (n=0; !obj && n<d.layers.length; n++)
       obj = rcube_find_object(id, d.layers[n].document);
   }
@@ -491,8 +533,8 @@
   var mouse = rcube_event.get_mouse_pos(ev),
     pos = $(obj).offset();
 
-  return ((mouse.x >= pos.left) && (mouse.x < (pos.left + obj.offsetWidth)) &&
-    (mouse.y >= pos.top) && (mouse.y < (pos.top + obj.offsetHeight)));
+  return (mouse.x >= pos.left) && (mouse.x < (pos.left + obj.offsetWidth)) &&
+    (mouse.y >= pos.top) && (mouse.y < (pos.top + obj.offsetHeight));
 };
 
 
@@ -504,6 +546,7 @@
       (path ? "; path=" + path : "") +
       (domain ? "; domain=" + domain : "") +
       (secure ? "; secure" : "");
+
   document.cookie = curCookie;
 };
 
@@ -570,6 +613,11 @@
   };
 }
 
+// array utility function
+jQuery.last = function(arr) {
+  return arr && arr.length ? arr[arr.length-1] : undefined;
+}
+
 // jQuery plugin to emulate HTML5 placeholder attributes on input elements
 jQuery.fn.placeholder = function(text) {
   return this.each(function() {
@@ -606,12 +654,89 @@
   });
 };
 
+// function to parse query string into an object
+rcube_parse_query = function(query)
+{
+  if (!query)
+    return {};
 
-// This code was written by Tyler Akins and has been placed in the
-// public domain.  It would be nice if you left this header intact.
+  var params = {}, e, k, v,
+    re = /([^&=]+)=?([^&]*)/g,
+    decodeRE = /\+/g, // Regex for replacing addition symbol with a space
+    decode = function (str) { return decodeURIComponent(str.replace(decodeRE, ' ')); };
+
+  query = query.replace(/\?/, '');
+
+  while (e = re.exec(query)) {
+    k = decode(e[1]);
+    v = decode(e[2]);
+
+    if (k.substring(k.length - 2) === '[]') {
+      k = k.substring(0, k.length - 2);
+      (params[k] || (params[k] = [])).push(v);
+    }
+    else
+      params[k] = v;
+  }
+
+  return params;
+};
+
+
 // Base64 code from Tyler Akins -- http://rumkin.com
 var Base64 = (function () {
   var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+
+  // private method for UTF-8 encoding
+  var utf8_encode = function(string) {
+    string = string.replace(/\r\n/g, "\n");
+    var utftext = '';
+
+    for (var n = 0; n < string.length; n++) {
+      var c = string.charCodeAt(n);
+
+      if (c < 128) {
+        utftext += String.fromCharCode(c);
+      }
+      else if(c > 127 && c < 2048) {
+        utftext += String.fromCharCode((c >> 6) | 192);
+        utftext += String.fromCharCode((c & 63) | 128);
+      }
+      else {
+        utftext += String.fromCharCode((c >> 12) | 224);
+        utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+        utftext += String.fromCharCode((c & 63) | 128);
+      }
+    }
+
+    return utftext;
+  };
+
+  // private method for UTF-8 decoding
+  var utf8_decode = function (utftext) {
+    var i = 0, string = '', c = c2 = c3 = 0;
+
+    while (i < utftext.length) {
+      c = utftext.charCodeAt(i);
+      if (c < 128) {
+        string += String.fromCharCode(c);
+        i++;
+      }
+      else if (c > 191 && c < 224) {
+        c2 = utftext.charCodeAt(i + 1);
+        string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
+        i += 2;
+      }
+      else {
+        c2 = utftext.charCodeAt(i + 1);
+        c3 = utftext.charCodeAt(i + 2);
+        string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
+        i += 3;
+      }
+    }
+
+    return string;
+  };
 
   var obj = {
     /**
@@ -619,12 +744,19 @@
      * @param {String} input The string to encode in base64.
      */
     encode: function (input) {
-      if (typeof(window.btoa) === 'function')
-        return btoa(input);
+      if (typeof(window.btoa) === 'function') {
+        // it may fail on unicode characters, the fallback can handle them
+        try {
+          return btoa(input);
+        }
+        catch (e) {};
+      }
+
+      input = utf8_encode(input);
 
       var chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0, output = '', len = input.length;
 
-      do {
+      while (i < len) {
         chr1 = input.charCodeAt(i++);
         chr2 = input.charCodeAt(i++);
         chr3 = input.charCodeAt(i++);
@@ -642,7 +774,7 @@
         output = output
           + keyStr.charAt(enc1) + keyStr.charAt(enc2)
           + keyStr.charAt(enc3) + keyStr.charAt(enc4);
-      } while (i < len);
+      }
 
       return output;
     },
@@ -652,8 +784,13 @@
      * @param {String} input The string to decode.
      */
     decode: function (input) {
-      if (typeof(window.atob) === 'function')
-         return atob(input);
+      if (typeof(window.atob) === 'function') {
+        // it may fail on unicode characters, the fallback can handle them
+        try {
+          return utf8_decode(atob(input));
+        }
+        catch (e) {};
+      }
 
       var chr1, chr2, chr3, enc1, enc2, enc3, enc4, len, i = 0, output = '';
 
@@ -661,7 +798,7 @@
       input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
       len = input.length;
 
-      do {
+      while (i < len) {
         enc1 = keyStr.indexOf(input.charAt(i++));
         enc2 = keyStr.indexOf(input.charAt(i++));
         enc3 = keyStr.indexOf(input.charAt(i++));
@@ -677,9 +814,9 @@
           output = output + String.fromCharCode(chr2);
         if (enc4 != 64)
           output = output + String.fromCharCode(chr3);
-      } while (i < len);
+      }
 
-      return output;
+      return utf8_decode(output);
     }
   };
 

--
Gitblit v1.9.1