1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2013, 2014, 2016 Synacor, Inc.
  5  *
  6  * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at: https://www.zimbra.com/license
  9  * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15
 10  * have been added to cover use of software over a computer network and provide for limited attribution
 11  * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B.
 12  *
 13  * Software distributed under the License is distributed on an "AS IS" basis,
 14  * WITHOUT WARRANTY OF ANY KIND, either express or implied.
 15  * See the License for the specific language governing rights and limitations under the License.
 16  * The Original Code is Zimbra Open Source Web Client.
 17  * The Initial Developer of the Original Code is Zimbra, Inc.  All rights to the Original Code were
 18  * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015.
 19  *
 20  * All portions of the code are Copyright (C) 2007, 2008, 2009, 2010, 2011, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * Does nothing (static class).
 26  * @constructor
 27  * @class
 28  * 
 29  * This class provides static methods to determine which standard plugins are
 30  * installed in the browser.
 31  *
 32  * @private
 33  */
 34 AjxPluginDetector = function() {
 35 }
 36 
 37 AjxPluginDetector.canDetectPlugins =
 38 function() {
 39 	return AjxEnv.isIE || (navigator.plugins && navigator.plugins.length > 0);
 40 };
 41 
 42 AjxPluginDetector.detectFlash =
 43 function() {
 44 	if(AjxEnv.isIE) {
 45 		return AjxPluginDetector.detectActiveXControl('ShockwaveFlash.ShockwaveFlash.1');
 46 	} else {
 47 		return AjxPluginDetector.detectPlugin('Shockwave','Flash'); 
 48 	}
 49 };
 50 
 51 AjxPluginDetector.detectPDFReader =
 52 function(){
 53     if(AjxEnv.isIE){
 54         return  ( AjxPluginDetector.detectActiveXControl('PDF.PdfCtrl.5')
 55                 || AjxPluginDetector.detectActiveXControl('AcroExch.Document') );
 56     }else{
 57         var hasPDFReader = false;
 58         if(AjxEnv.isChrome){
 59             hasPDFReader = AjxPluginDetector.detectPlugin('Chrome PDF Viewer');
 60         }else if(AjxEnv.isFirefox){
 61             hasPDFReader = AjxPluginDetector.detectPlugin('Firefox PDF Plugin for Mac OS X');
 62         }
 63         if(!hasPDFReader){
 64             hasPDFReader = AjxPluginDetector.detectPlugin('Adobe Acrobat');
 65         }
 66         return hasPDFReader;
 67     }
 68 };
 69 
 70 AjxPluginDetector.detectDirector =
 71 function() { 
 72 	if(AjxEnv.isIE) {
 73 		return AjxPluginDetector.detectActiveXControl('SWCtl.SWCtl.1');
 74 	} else {
 75 		return AjxPluginDetector.detectPlugin('Shockwave','Director');
 76 	}
 77 };
 78 
 79 AjxPluginDetector.detectQuickTime =
 80 function() {
 81 	if(AjxEnv.isIE) {
 82 		return AjxPluginDetector.detectQuickTimeActiveXControl();
 83 	} else {
 84 		return AjxPluginDetector.detectPlugin('QuickTime');
 85 	}
 86 };
 87 
 88 // If quicktime is installed, returns the version as an array: [major, minor, build]
 89 AjxPluginDetector.getQuickTimeVersion =
 90 function() {
 91 	if(AjxEnv.isIE) {
 92 		var object = new ActiveXObject("QuickTimeCheckObject.QuickTimeCheck.1");
 93 		DBG.println(AjxDebug.DBG1, "AjxPluginDetector: Quicktime is " + object.IsQuickTimeAvailable(0) ? "available" : "not available");
 94 		if (object.IsQuickTimeAvailable(0)) {
 95 			try {
 96 				var version = Number(object.QuickTimeVersion).toString(16);
 97 				var result = [];
 98 				for(var i = 0; i < 3; i++) {
 99 					result[i] = Number(version.charAt(i));
100 				}
101 				return result;
102 			} catch(e) {
103 				DBG.println(AjxDebug.DBG1, "AjxPluginDetector: Error while checking QuickTimeVersion: " + e);
104 			}
105 		}
106 		return null;
107 	} else {
108 		var match = AjxPluginDetector.matchPluginName(/QuickTime Plug-in (\d+)\.?(\d+)?\.?(\d+)?/);
109 		if (match) {
110 			DBG.println("AjxPluginDetector: able to find match for QuickTime plugin with version: " + match);
111 			var result = [];
112 			for(var i = 0; i < 3; i++) {
113 				result[i] = Number(match[i + 1] || 0);
114 			}
115 			return result;
116 		} else {
117 			DBG.println("AjxPluginDetector: unable to find match for QuickTime plugin with version");
118 			return null;
119 		}
120 	}
121 };
122 
123 /**
124  * This code is part of JQuery's Flash plugin.
125  * http://jquery.lukelutman.com/plugins/flash/
126  *
127  * @return Flash plugin version
128  */
129 AjxPluginDetector.getFlashVersion =
130 function() {
131     var flashVersion = "0,0,0";
132     // ie
133     try {
134         try {
135             // avoid fp6 minor version lookup issues
136             // see: http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-explorer-flash-6/
137             var axo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash.6');
138             try {
139                 axo.AllowScriptAccess = 'always';
140             }
141             catch(e) {
142                 return '6,0,0';
143             }
144         } catch(e) {
145             }
146         flashVersion = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1];
147         // other browsers
148     } catch(e) {
149         try {
150             if (navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin) {
151                 flashVersion = (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]).description.replace(/\D+/g, ",").match(/^,?(.+),?$/)[1];
152             }
153         } catch(e) {
154         }
155     }
156 	return flashVersion;
157 };
158 
159 AjxPluginDetector.detectReal =
160 function() {
161 	if(AjxEnv.isIE) {
162 		return AjxPluginDetector.detectActiveXControl('rmocx.RealPlayer G2 Control') ||
163 		       AjxPluginDetector.detectActiveXControl('RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)') ||
164 		       AjxPluginDetector.detectActiveXControl('RealVideo.RealVideo(tm) ActiveX Control (32-bit)');
165 	} else {
166 		return AjxPluginDetector.detectPlugin('RealPlayer');
167 	}
168 };
169 
170 AjxPluginDetector.detectWindowsMedia =
171 function() {
172 	if(AjxEnv.isIE) {
173 		return AjxPluginDetector.detectActiveXControl('MediaPlayer.MediaPlayer.1');
174 	} else {
175 		return AjxPluginDetector.detectPlugin('Windows Media');
176 	}
177 };
178 
179 AjxPluginDetector.detectPlugin =
180 function() {
181 	DBG.println(AjxDebug.DBG1, "-----------------------<br>AjxPluginDetector: Looking for plugin: [" + AjxPluginDetector._argumentsToString(AjxPluginDetector.detectPlugin.arguments) + "]");
182 	var names = AjxPluginDetector.detectPlugin.arguments;
183 	var allPlugins = navigator.plugins;
184 	var pluginsArrayLength = allPlugins.length;
185 	for (var pluginsArrayCounter=0; pluginsArrayCounter < pluginsArrayLength; pluginsArrayCounter++ ) {
186 	    // loop through all desired names and check each against the current plugin name
187 	    var numFound = 0;
188 	    for(var namesCounter=0; namesCounter < names.length; namesCounter++) {
189 			// if desired plugin name is found in either plugin name or description
190 			if (allPlugins[pluginsArrayCounter]) {
191 				if( (allPlugins[pluginsArrayCounter].name.indexOf(names[namesCounter]) >= 0)) {
192 					// this name was found
193 					DBG.println(AjxDebug.DBG1, "AjxPluginDetector: found name match '" + allPlugins[pluginsArrayCounter].name + "'");
194 					numFound++;
195 				} else if (allPlugins[pluginsArrayCounter].description.indexOf(names[namesCounter]) >= 0) {
196 					// this name was found
197 					DBG.println(AjxDebug.DBG1, "AjxPluginDetector: found description match '" + allPlugins[pluginsArrayCounter].description + "'");
198 					numFound++;
199 				}
200 			}
201 	    }
202 	    // now that we have checked all the required names against this one plugin,
203 	    // if the number we found matches the total number provided then we were successful
204 	    if(numFound == names.length) {
205 			DBG.println(AjxDebug.DBG1, "AjxPluginDetector: Found plugin!<br>-----------------------");
206 			return true;
207 	    } else if (numFound) {
208 			DBG.println(AjxDebug.DBG1, "AjxPluginDetector: Found partial plugin match, numFound=" + numFound);
209 		}
210 	}
211 	DBG.println(AjxDebug.DBG1, "AjxPluginDetector: Failed to find plugin.<br>-----------------------");
212 	return false;
213 };
214 
215 AjxPluginDetector.matchPluginName =
216 function(regExp) {
217 	var allPlugins = navigator.plugins;
218 	var pluginsArrayLength = allPlugins.length;
219 	for (var pluginsArrayCounter=0; pluginsArrayCounter < pluginsArrayLength; pluginsArrayCounter++ ) {
220 		var match = allPlugins[pluginsArrayCounter].name.match(regExp);
221 		if (match) {
222 			return match;
223 		}
224 	}
225 	return null;
226 };
227 
228 AjxPluginDetector.detectActiveXControl =
229 function(progId) {
230 	try {
231 		new ActiveXObject(progId);
232 		DBG.println(AjxDebug.DBG1, "AjxPluginDetector: found ActiveXObject '" + progId + "'");
233 		return true;
234 	} catch (e) {
235 		DBG.println(AjxDebug.DBG1, "AjxPluginDetector: unable to find ActiveXObject '" + progId + "'");
236 		return false;
237 	}
238 };
239 
240 AjxPluginDetector.detectQuickTimeActiveXControl =
241 function(progId) {
242 	try {
243 		var object = new ActiveXObject("QuickTimeCheckObject.QuickTimeCheck.1");
244 		return object.IsQuickTimeAvailable(0);
245 	} catch (e) {
246 		return false;
247 	}
248 };
249 
250 // Util method to log arguments, which to my surprise are not actually an array.
251 AjxPluginDetector._argumentsToString =
252 function(args) {
253 	var array = [];
254 	for (var i = 0, count = args.length; i < count; i++) {
255 		array[i] = args[i];
256 	}
257 	return array.join(',')
258 };