1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 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) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * @overview
 26  * This file contains the Zimlet manager class.
 27  */
 28 
 29 /**
 30  * Creates the Zimlet manager.
 31  * @class
 32  * This class represents the Zimlet manager.
 33  * 
 34  */
 35 ZmZimletMgr = function() {
 36 	this._ZIMLETS = [];
 37 	this._ZIMLETS_BY_ID = {};
 38 	this._CONTENT_ZIMLETS = [];
 39 	this._serviceZimlets = [];
 40 	this._requestNotHandledByAnyZimlet = [];
 41 	this.loaded = false;
 42 };
 43 
 44 ZmZimletMgr.prototype.constructor = ZmZimletMgr;
 45 
 46 /**
 47  * Returns a string representation of the object.
 48  * 
 49  * @return		{String}		a string representation of the object
 50  */
 51 ZmZimletMgr.prototype.toString =
 52 function() {
 53 	return "ZmZimletMgr";
 54 };
 55 
 56 //
 57 // Constants
 58 //
 59 
 60 ZmZimletMgr._RE_REMOTE = /^((https?|ftps?):\x2f\x2f|\x2f)/;
 61 
 62 /**
 63 * List of Core Zimlets.
 64 * com_zimbra_apptsummary|com_zimbra_date|com_zimbra_dnd|com_zimbra_email|com_zimbra_linkedin|com_zimbra_phone|com_zimbra_webex|com_zimbra_social|com_zimbra_srchhighlighter|com_zimbra_url
 65 */
 66 ZmZimletMgr.CORE_ZIMLETS = /com_zimbra_apptsummary|com_zimbra_date|com_zimbra_dnd|com_zimbra_email|com_zimbra_linkedin|com_zimbra_phone|com_zimbra_webex|com_zimbra_social|com_zimbra_srchhighlighter|com_zimbra_url/;
 67 
 68 /**
 69  * If the Zimlet's config_template has  hasSensitiveData = true, it will be considered as sensitive Zimlet
 70  * and such zimlets are disabled (by-default) in mixed-mode.
 71  * System admin can set: mcf zimbraZimletDataSensitiveInMixedModeDisabled FALSE (instead of TRUE), to enable
 72  */
 73 ZmZimletMgr.HAS_SENSITIVE_DATA_CONFIG_NAME = "hasSensitiveData";
 74 
 75 //
 76 // Public methods
 77 //
 78 
 79 /**
 80  * Checks if the manager is loaded.
 81  * 
 82  * @return	{Boolean}	<code>true</code> if loaded; <code>false</code> otherwise
 83  */
 84 ZmZimletMgr.prototype.isLoaded =
 85 function() {
 86 	return this.loaded;
 87 };
 88 
 89 /**
 90  * Loads the zimlets.
 91  * 
 92  * @param	{Array}	zimletArray		an array of {@link ZmZimlet} objects
 93  * @param	{Array}	userProps		an array of properties
 94  * @param	{String}	target		the target
 95  * @param	{AjxCallback}	callback	the callback
 96  * @param	{Boolean}	sync		<code>true</code> for synchronous
 97  * 
 98  * @private
 99  */
100 ZmZimletMgr.prototype.loadZimlets =
101 function(zimletArray, userProps, target, callback, sync) {
102 	var href = window.location.href.toLowerCase();
103 	if(href.indexOf("zimlets=none") > 0 || appCtxt.isWebClientOffline()) {
104 		return;
105 	} else if(href.indexOf("zimlets=core") > 0) {
106 		zimletArray = this._getCoreZimlets(zimletArray);
107 	}
108 	var isHttp = document.location.protocol == ZmSetting.PROTO_HTTP;
109 	var isMixedMode = appCtxt.get(ZmSetting.PROTOCOL_MODE) == ZmSetting.PROTO_MIXED;
110 	var showAllZimlets = href.indexOf("zimlets=all") > 0;
111 	if(isMixedMode && !appCtxt.isOffline && !showAllZimlets && isHttp
112 			&& appCtxt.get(ZmSetting.DISABLE_SENSITIVE_ZIMLETS_IN_MIXED_MODE) == "TRUE") {
113 		zimletArray = this._getNonSensitiveZimlets(zimletArray);
114 	}
115 	var packageCallback = callback ? new AjxCallback(this, this._loadZimlets, [zimletArray, userProps, target, callback, sync]) : null;
116 	AjxPackage.require({ name: "Zimlet", callback: packageCallback });
117 	if (!callback) {
118 		this._loadZimlets(zimletArray, userProps, target, callback, sync);
119 	}
120 };
121 
122 
123 /**
124  * Returns non-sensitive Zimlets whose config_template.xml file does not contain "hasSensitiveData=true"
125  * @param	{Array}	zimletArray	an array of {@link ZmZimlet} objects
126  *
127  * @private
128  */
129 ZmZimletMgr.prototype._getNonSensitiveZimlets =
130 function(zimletArray) {
131 	if (!zimletArray || !zimletArray.length) {
132 		return;
133 	}
134 	var nonSensitiveZimlets = [];
135 	var len = zimletArray.length;
136 	for(var i = 0; i < len; i++) {
137 		var configProps = [];
138 		var zimletObj = zimletArray[i];
139 		var isSensitiveZimlet = false;
140 		var zimletName = zimletObj.zimlet && zimletObj.zimlet[0] ? zimletObj.zimlet[0].name : "";
141 		var zimletConfig = zimletObj.zimletConfig;
142 
143 		if(zimletConfig)  {
144 			if(zimletConfig[0]
145 					&& zimletConfig[0].global
146 					&& zimletConfig[0].global[0]
147 					&& zimletConfig[0].global[0].property) {
148 
149 				configProps = zimletConfig[0].global[0].property;
150 				for(var j = 0; j < configProps.length; j++) {
151 					var property = configProps[j];
152 					if(property.name == ZmZimletMgr.HAS_SENSITIVE_DATA_CONFIG_NAME && property._content == "true") {
153 						isSensitiveZimlet = true;
154 						break;
155 					}
156 				}
157 			}
158 		}
159 		if(!isSensitiveZimlet) {
160 			nonSensitiveZimlets.push(zimletObj);
161 		}
162 	}
163 	return nonSensitiveZimlets;
164 };
165 
166 /**
167  * Returng an array with only core-Zimlets. This is used when we want to debug with only core-zimlets (?zimlets=core)
168  * @param	{Array}	zimletArray		an array of {@link ZmZimlet} objects
169  *
170  * @private
171  */
172 ZmZimletMgr.prototype._getCoreZimlets =
173 function(zimletArray) {
174 	if (!zimletArray || !zimletArray.length) {
175 		return;
176 	}
177 	var coreZimlets = [];
178 	var len = zimletArray.length;
179 	for(var i = 0; i < len; i++) {			
180 		var zimletObj = zimletArray[i].zimlet;
181 		var zimletName = zimletObj && zimletObj[0] ? zimletObj[0].name : "";
182 		if(ZmZimletMgr.CORE_ZIMLETS.test(zimletName)) {
183 			coreZimlets.push(zimletArray[i]);
184 		}		
185 	}
186 	return coreZimlets;
187 };
188 
189 /**
190  * @private
191  */
192 ZmZimletMgr.prototype._loadZimlets =
193 function(zimletArray, userProps, target, callback, sync) {
194 	var z;
195 	var loadZimletArray = [];
196 	var targetRe = new RegExp("\\b"+(target || "main")+"\\b");
197 	for (var i=0; i < zimletArray.length; i++) {
198 		var zimletObj = zimletArray[i];
199 		var zimlet0 = zimletObj.zimlet[0];
200 		// NOTE: Only instantiate zimlet context for specified target
201 		if (!targetRe.test(zimlet0.target || "main")) { continue; }
202 		z = new ZmZimletContext(i, zimletObj);
203 		this._ZIMLETS_BY_ID[z.name] = z;
204 		this._ZIMLETS.push(z);
205 		loadZimletArray.push(zimletObj);
206 	}
207 	if (userProps) {
208 		for (i = 0; i < userProps.length; ++i) {
209 			var p = userProps[i];
210 			z = this._ZIMLETS_BY_ID[p.zimlet];
211 			if (z) {
212 				z.setPropValue(p.name, p._content);
213 			}
214 		}
215 	}
216 	if (!appCtxt.isChildWindow) {
217 		var panelZimlets = this.getPanelZimlets();
218 		if (panelZimlets && panelZimlets.length > 0) {
219 			var zimletTree = appCtxt.getZimletTree();
220 			if (!zimletTree) {
221 				zimletTree = new ZmFolderTree(ZmOrganizer.ZIMLET);
222 				var account = appCtxt.multiAccounts && appCtxt.accountList.mainAccount;
223 				appCtxt.setTree(ZmOrganizer.ZIMLET, zimletTree, account);
224 			}
225 			zimletTree.reset();
226 			zimletTree.loadFromJs(panelZimlets, "zimlet");
227 		} else { // reset overview tree accordingly
228 			this._resetOverviewTree();
229 		}
230 	}
231 
232 	// load zimlet code/CSS
233 	var zimletNames = this._getZimletNames(loadZimletArray);
234 	this._loadIncludes(loadZimletArray, zimletNames, (sync ? callback : null) );
235 	this._loadStyles(loadZimletArray, zimletNames);
236 
237 	if (callback && !sync) {
238 		callback.run();
239 	}
240 };
241 
242 /**
243  * @private
244  */
245 ZmZimletMgr.prototype._resetOverviewTree =
246 function() {
247 	var zimletTree = appCtxt.getZimletTree();
248 	if (zimletTree) {
249 		var panelZimlets = this.getPanelZimlets();
250 		zimletTree.loadFromJs(panelZimlets, "zimlet");
251 		var overview = appCtxt.getCurrentApp().getOverview();
252 		if (overview) {
253 			var treeView =  overview.getTreeView(ZmOrganizer.ZIMLET);
254 			if (treeView && (!panelZimlets || !panelZimlets.length)) {
255 				treeView.clear(); //Clear the tree if thr are no panel zimlets
256 			}
257 		}
258 	}
259 };
260 
261 /**
262  * Gets the panel zimlets.
263  * 
264  * @return	{Array}	an array of objects
265  */
266 ZmZimletMgr.prototype.getPanelZimlets =
267 function() {
268 	var panelZimlets = [];
269 	for (var i = 0; i < this._ZIMLETS.length; i++) {
270 		if (this._ZIMLETS[i].zimletPanelItem) {
271 			DBG.println(AjxDebug.DBG2, "Zimlets - add to panel " + this._ZIMLETS[i].name);
272 			panelZimlets.push(this._ZIMLETS[i]);
273 		}
274 	}
275 	return panelZimlets;
276 };
277 
278 /**
279  * Gets the indexed zimlets.
280  * 
281  * @return	{Array}	an array of objects
282  */
283 ZmZimletMgr.prototype.getIndexedZimlets =
284 function() {
285 	var indexedZimlets = [];
286 	for (var i=0; i < this._ZIMLETS.length; i++) {
287 		if (this._ZIMLETS[i].keyword) {
288 			DBG.println(AjxDebug.DBG2, "Zimlets - add to indexed " + this._ZIMLETS[i].name);
289 			indexedZimlets.push(this._ZIMLETS[i]);
290 		}
291 	}
292 	return indexedZimlets;
293 };
294 
295 /**
296  * Gets the portlet zimlets.
297  * 
298  * @return	{Array}	an array of objects
299  */
300 ZmZimletMgr.prototype.getPortletZimlets =
301 function() {
302 	if (!this._portletArray) {
303 		this._portletArray = [];
304 		this._portletMap = {};
305 		for (var i = 0; i < this._ZIMLETS.length; i++) {
306 			var zimlet = this._ZIMLETS[i];
307 			if (zimlet.portlet) {
308 				this._portletArray.push(zimlet);
309 				this._portletMap[zimlet.name] = zimlet;
310 			}
311 		}
312 	}
313 	return this._portletArray;
314 };
315 
316 /**
317  * Gets the portlets hash.
318  * 
319  * @return	{Hash}	the portlets hash
320  */
321 ZmZimletMgr.prototype.getPortletZimletsHash =
322 function() {
323 	this.getPortletZimlets();
324 	return this._portletMap;
325 };
326 
327 /**
328  * Registers the content zimlet.
329  * 
330  * @param	{ZmZimlet}	zimletObj		the zimlet
331  * @param	{constant}	type			the type
332  * @param	{constant}	priority		the priority
333  * 
334  * @private
335  */
336 ZmZimletMgr.prototype.registerContentZimlet =
337 function(zimletObj, type, priority) {
338 	var i = this._CONTENT_ZIMLETS.length;
339 	this._CONTENT_ZIMLETS[i] = zimletObj;
340 	this._CONTENT_ZIMLETS[i].type = type;
341 	this._CONTENT_ZIMLETS[i].prio = priority;
342 	DBG.println(AjxDebug.DBG2, "Zimlets - registerContentZimlet(): " + this._CONTENT_ZIMLETS[i]._zimletContext.name);
343 };
344 
345 /**
346  * Gets the content zimlets.
347  * 
348  * @return	{Array}	an array of objects
349  */
350 ZmZimletMgr.prototype.getContentZimlets =
351 function() {
352 	return this._CONTENT_ZIMLETS;
353 };
354 
355 /**
356  * Gets the zimlets.
357  * 
358  * @return	{Array}	an array of {@link ZmZimletContext} objects
359  */
360 ZmZimletMgr.prototype.getZimlets =
361 function() {
362 	return this._ZIMLETS;
363 };
364 
365 /**
366  * Gets the zimlets hash.
367  * 
368  * @return	{Hash}	as hash of zimlets
369  */
370 ZmZimletMgr.prototype.getZimletsHash =
371 function() {
372 	return this._ZIMLETS_BY_ID;
373 };
374 
375 /**
376  * Checks if the zimlet exists.
377  * 
378  * @param	{String}	name		the name
379  * @return	{ZmZimletContext}	the zimlet or <code>null</code> if not found
380  */
381 ZmZimletMgr.prototype.zimletExists =
382 function(name) {
383 	return this._ZIMLETS_BY_ID[name];
384 };
385 
386 /**
387  * Gets the zimlet.
388  * 
389  * @param	{String}	name		the name
390  * @return	{ZmZimletContext}	the zimlet or <code>null</code> if not found
391  */
392 ZmZimletMgr.prototype.getZimletByName =
393 function(name) {
394 	for (var i = 0; i < this._ZIMLETS.length; i++) {
395 		var z = this._ZIMLETS[i];
396 		if (z && (z.name == name))
397 		{
398 			return z;
399 		}
400 	}
401     return null;
402 };
403 
404 /**
405  * Handles zimlet notification.
406  * 
407  * @param	{Object}	event	the event
408  * @param	{Object}	args	the arguments
409  * 
410  * @return true if any zimlet handled the notification
411  * 
412  * @private
413  */
414 ZmZimletMgr.prototype.notifyZimlets =
415 function(event, args) {
416 	
417 	args = AjxUtil.toArray(args);
418 
419 	var handled = false;
420 	for (var i = 0; i < this._ZIMLETS.length; ++i) {
421 		var z = this._ZIMLETS[i].handlerObject;
422 		if (z && z.isZmObjectHandler && z.getEnabled() && (typeof z[event] == "function")) {
423 			var result = args ? z[event].apply(z, args) : z[event].apply(z);	// IE cannot handle empty args
424 			handled = handled || result;
425 		}
426 	}
427 	
428 	return handled;
429 };
430 
431 ZmZimletMgr.prototype.notifyZimlet =
432 function(zimletName, event, args) {
433 	var zimlet = this.getZimletByName(zimletName);
434 	var z = zimlet && zimlet.handlerObject;
435 	if (z && z.isZmObjectHandler && z.getEnabled() && (typeof z[event] == "function")) {
436 		return (args ? z[event].apply(z, args) : z[event].apply(z));	// IE cannot handle empty args
437 	}
438 };
439 
440 /**
441  * Processes a request (from core-zcs to zimlets) and returns value of the
442  * first zimlet that serves the request.
443  * PS: 
444  * - Requestor must handle 'null' value
445  * - stores/caches the zimlet for a given request to improve performance.
446  * - also stores _requestNotHandledByAnyZimlet if no zimlet handles this
447  *	request(in the current session), again to improve performance.
448  * e.g: appCtxt.getZimletMgr().processARequest("getMailCellStyle", item, field)
449  * 
450  * @private
451  */
452 ZmZimletMgr.prototype.processARequest =
453 function(request) {
454 	if (this._requestNotHandledByAnyZimlet[request]) { return null; }
455 
456 	var args = new Array(arguments.length - 1);
457 	for (var i = 0; i < args.length;) {
458 		args[i] = arguments[++i];
459 	}
460 	var sz = this._serviceZimlets[request];
461 	if (sz) { // if we already know a zimlet that serves this request, use it.
462 		return sz[request].apply(sz, args);
463 	}
464 
465 	var a = this._ZIMLETS;
466 	for (var i = 0; i < a.length; ++i) {
467 		var z = a[i].handlerObject;
468 		if (z && (z instanceof ZmZimletBase) && z.getEnabled() &&
469 			(typeof z[request] == "function"))
470 		{
471 			 this._serviceZimlets[request] = z;//store 
472 			 return z[request].apply(z, args);
473 		}
474 	}
475 	if (this.isLoaded()) { // add to an array to indicate that no zimlet implements this request
476 		this._requestNotHandledByAnyZimlet[request]=request;
477 	}
478 	return null;
479 };
480 
481 //
482 // Protected methods
483 //
484 
485 /**
486  * @private
487  */
488 ZmZimletMgr.prototype._getZimletNames =
489 function(zimletArray) {
490 	var array = new Array(zimletArray ? zimletArray.length : 0);
491 	for (var i = 0; i < zimletArray.length; i++) {
492 		array[i] = zimletArray[i].zimlet[0].name;
493 	}
494 	return array;
495 };
496 
497 /**
498  * @private
499  */
500 ZmZimletMgr.prototype._loadIncludes =
501 function(zimletArray, zimletNames, callback) {
502 	var includes = this.__getIncludes(zimletArray, zimletNames, true);
503 	var includesCallback = new AjxCallback(this, this._finished_loadIncludes, [zimletNames, callback]);
504 
505 	AjxInclude(includes, null, includesCallback, ZmZimletBase.PROXY);
506 };
507 
508 /**
509  * @private
510  */
511 ZmZimletMgr.prototype._finished_loadIncludes =
512 function(zimletNames, callback) {
513 	if (!appCtxt.isChildWindow) {
514 		this.renameZimletsLabel();
515 	}
516 	this.loaded = true;
517 	var zimlets = this.getZimletsHash();
518 	for (var i = 0; i < zimletNames.length; i++) {
519 		var showedDialog = false;
520 		var name = zimletNames[i];
521 		try {
522 			zimlets[name]._finished_loadIncludes();
523 		} catch (e) {
524 			if (!showedDialog) {
525 				var dialog = appCtxt.getErrorDialog();
526 				var message = AjxMessageFormat.format(ZmMsg.zimletInitError, name);
527 				dialog.setMessage(message, e.toString(), DwtMessageDialog.CRITICAL_STYLE);
528 				dialog.popup();
529 				showedDialog = true;
530 			}
531 			DBG.println(AjxDebug.DBG1, "Error initializing zimlet '" + name + "': " + e);
532 		}
533 	}
534 	if (appCtxt.get(ZmSetting.PORTAL_ENABLED) && !appCtxt.isChildWindow) {
535 		var params = {
536 			name: "Portal",
537 			callback: (new AjxCallback(this, this._finished_loadIncludes2, [callback]))
538 		};
539 		AjxPackage.require(params);
540 	} else {
541 		this._finished_loadIncludes2(callback);
542 	}
543 };
544 
545 /**
546  * @private
547  */
548 ZmZimletMgr.prototype._finished_loadIncludes2 =
549 function(callback) {
550 	appCtxt.allZimletsLoaded();
551 
552 	if (callback) {
553 		callback.run();
554 	}
555 };
556 
557 /**
558  * @private
559  */
560 ZmZimletMgr.prototype._loadStyles =
561 function(zimletArray, zimletNames) {
562 	var head = document.getElementsByTagName("head")[0];
563 	var includes = this.__getIncludes(zimletArray, zimletNames, false);
564 	for (var i = 0; i < includes.length; i++) {
565 		var style = document.createElement("link");
566 		style.type = "text/css";
567 		style.rel = "stylesheet";
568 		style.href = includes[i];
569 
570 		head.appendChild(style);
571 
572 		// XXX: say what?!
573 		style.disabled = true;
574 		style.disabled = false;
575 	}
576 };
577 
578 //
579 // Private methods
580 //
581 
582 /**
583  * @private
584  */
585 ZmZimletMgr.prototype.__getIncludes =
586 function(zimletArray, zimletNames, isJS) {
587     // get language info
588     var languageId = null;
589     var countryId = null;
590     if (appCtxt.get(ZmSetting.LOCALE_NAME)) {
591         var locale = appCtxt.get(ZmSetting.LOCALE_NAME) || "";
592         var parts = locale.split("_");
593         languageId = parts[0];
594         countryId = parts[1];
595     }
596     var locid = "";
597     if (languageId) locid += "&language="+languageId;
598     if (countryId) locid += "&country="+countryId;
599 
600     // add cache killer to each url
601     var query = [
602         "?v=", window.cacheKillerVersion
603 //        window.appDevMode ? new Date().getTime() : window.cacheKillerVersion
604     ].join("");
605 
606     // add messages for all zimlets
607     var includes = [];
608     if (window.appDevMode && isJS) {
609         var zimlets = appCtxt.get(ZmSetting.ZIMLETS) || [];
610         if(appCtxt.isChildWindow) {
611             var winOpener = window.opener || window;
612             zimlets = winOpener.appCtxt.get(ZmSetting.ZIMLETS) || []
613         }
614         for (var i = 0; i < zimlets.length; i++) {
615             var zimlet = zimlets[i].zimlet[0];
616             includes.push([appContextPath, "/res/", zimlet.name, ".js", query, locid].join(""));
617         }
618     }
619 
620 	// add remote urls
621 	for (var i = 0; i < zimletArray.length; i++) {
622 		var zimlet = zimletArray[i].zimlet[0];
623 		var baseUrl = zimletArray[i].zimletContext[0].baseUrl;
624 		var isDevZimlet = baseUrl.match("/_dev/");
625 
626 		// include links
627 		var links = (isJS ? zimlet.include : zimlet.includeCSS) || [];
628 		for (var j = 0; j < links.length; j++) {
629 			var url = links[j]._content;
630 			if (ZmZimletMgr._RE_REMOTE.test(url)) {
631 				var fullurl = [ ZmZimletBase.PROXY, AjxStringUtil.urlComponentEncode(url) ].join("");
632 				includes.push(fullurl);
633 				continue;
634 			}
635 			if (window.appDevMode || isDevZimlet) {
636                 var debug = isDevZimlet ? "&debug=1" : "";
637 				includes.push([baseUrl, url, query, locid, debug].join(""));
638 			}
639 		}
640 	}
641 
642 	// add link to aggregated files
643 	if (!window.appDevMode) {
644 		var cosId = null;
645 		if (appCtxt.getSettings() && appCtxt.getSettings().getInfoResponse && appCtxt.getSettings().getInfoResponse.cos) {
646 			cosId = appCtxt.getSettings().getInfoResponse.cos.id;
647 		}
648 		var extension = (!AjxEnv.isIE || (!AjxEnv.isIE6 && AjxEnv.isIE6up)) ? appExtension : "";
649 		includes.unshift([
650 			"/service/zimlet/res/Zimlets-nodev_all",
651 			(isJS ? (".js" + extension) : ".css"),
652 			(languageId ? "?language=" + languageId : ""),
653 			(countryId ? "&country=" + countryId : ""),
654 			(cosId ? "&cosId=" + cosId : "")  // For an explanation of why we add cosId here, please see bug #58979
655 		].join(""));
656 	}
657 
658 	return includes;
659 };
660 
661 /**
662  * Renames the zimlets label.
663  * 
664  * @private
665  */
666 ZmZimletMgr.prototype.renameZimletsLabel =
667 function() {
668 	var treeController = appCtxt.getOverviewController().getTreeController("ZIMLET");
669 	var treeView = (treeController) ? treeController.getTreeView("Mail") : null;
670 	var root = (treeView) ? treeView.getItems()[0] : null;
671 	if (root) {
672 		var items = root.getItems();
673 		for (var i = 0; i < items.length; i++) {
674 			this.changeZimletLabel(items[i]);
675 		}
676 	}
677 };
678 
679 /**
680  * Changes the zimlet label.
681  * 
682  * @param	{Object}	item		the item
683  */
684 ZmZimletMgr.prototype.changeZimletLabel =
685 function(item) {
686 	var zimlet = item.getData(Dwt.KEY_OBJECT);
687 	if (zimlet) {
688 		var currentLabel = zimlet.getName();
689 		var regEx = /\$/;
690 		if (currentLabel.match(regEx)) {
691 			var replaceLabel = currentLabel.replace(/\${msg./,'').replace(/}/,'');
692 			var zimletContextName = zimlet.getZimletContext().name;
693 			if (window[zimletContextName]) {
694 				var str = window[zimletContextName][replaceLabel];
695 				if (str) {
696 					item.setText(str);
697 					zimlet.setName(str);
698 				}
699 			}
700 		}
701 	}
702 };
703