home *** CD-ROM | disk | FTP | other *** search
/ Chip 2011 November / CHIP_2011_11.iso / Programy / Narzedzia / AIMP2 / aimp_2.61.583.exe / $TEMP / YandexPackSetup.msi / fil1B932810AB57451412FF973063D263CA < prev    next >
Text File  |  2010-07-12  |  34KB  |  870 lines

  1. function BarApplication(core) {
  2.     this._barCore = core;
  3.     this._logger = this._barCore.Log4Moz.repository.getLogger(core.appName + ".App");
  4.     this._dirs._barApp = this;
  5.     this._controllerName = this.name + "OverlayController";
  6.     this._updater = new this._barCore.Lib.Update(this);
  7.     
  8.     this._init();
  9.     try {
  10.         this._cleanupPreferences();
  11.     }
  12.     catch (e) {
  13.         this._logger.error("Failed cleaning preferences. " + this._barCore.Lib.misc.formatError(e));
  14.     }
  15. }
  16.  
  17. BarApplication.prototype = {
  18.     get defaultWidgetsInfo() {
  19.         return this._presetWidgetsInfo;
  20.     },
  21.     
  22.     get name() {
  23.         return this._barCore.appName;
  24.     },
  25.     
  26.     getNewControllerID: function barApp_getNewControllerID() {
  27.         return this._newCID++;
  28.     },
  29.     
  30.     getNewWidgetInstanceID: function barApp_getNewWidgetInstanceID() {
  31.         return "" + Date.now() + this._newWID++;
  32.     },
  33.     
  34.     get localeString() {
  35.         if (!this._localeString) {
  36.             try {
  37.                 let localeFromPref = this.core.Preferences.get("general.useragent.locale", "");
  38.                 if (localeFromPref && /^([a-z]{2})(\-|$)/.test(localeFromPref)) {
  39.                     this._localeString = localeFromPref;
  40.                 } else {
  41.                     let xulChromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry);
  42.                     this._localeString = xulChromeReg.getSelectedLocale("global");
  43.                 }
  44.             } catch(e) {
  45.                 return "ru";
  46.             }
  47.         }
  48.         
  49.         return this._localeString || "ru";
  50.     },
  51.     
  52.     get core() {
  53.         return this._barCore;
  54.     },
  55.     
  56.     get directories() {
  57.         return this._dirs;
  58.     },
  59.     
  60.     get packageManager() {
  61.         return this._pacMan;
  62.     },
  63.     
  64.     get widgetLibrary() {
  65.         return this._widgetLib;
  66.     },
  67.     
  68.     get overlayProvider() {
  69.         return this._overlayProvider;
  70.     },
  71.     
  72.     restartWidgets: function barApp_restartWidgets(packageID) {
  73.         this.switchWidgets(packageID, false);
  74.         this.packageManager.reloadPackage(packageID);
  75.         this.switchWidgets(packageID, true);
  76.     },
  77.     
  78.     switchWidgets: function barApp_switchWidgets(packageID, on) {
  79.         this.forEachWindow(
  80.             function(controller) {
  81.                 controller.switchWidgets(packageID, on);
  82.             });
  83.     },
  84.     
  85.     forEachWindow: function barApp_forEachWindow(func, contextObj) {
  86.         if (typeof func !== "function")
  87.             throw new this._barCore.Lib.CustomErrors.EArgType("func", "Function", typeof func);
  88.         var windows = this.core.Lib.misc.getNavigatorWindows();
  89.         for each (let window in windows) {
  90.             let controller = window[this._controllerName];
  91.             if (controller)
  92.                 func.call(contextObj, controller);
  93.         }
  94.     },
  95.     
  96.     installPreset: function barApp_installPreset(url) {
  97.         this._barCore.Lib.misc.openWindow({
  98.             url: "chrome://" + this.name + "/content/custombar/dialogs/package-management/install/install.xul",
  99.             features: "__popup__",
  100.             name: "package-management-install",
  101.             mode: "install",
  102.             preset: url,
  103.             application: this
  104.         });
  105.     },
  106.     
  107.     navigate: function barApp_navigate(srcWnd, unsafeURL, target, wndWidth, wndHeight, yandexAction, callerProto) {
  108.         const ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
  109.         
  110.         let uri = ioService.newURI(unsafeURL, null, null);
  111.         if (!(uri && /^(http|ftp)s?$/.test(uri.scheme)))
  112.             throw new this._barCore.Lib.CustomErrors.ESecurityViolation("application.navigate", "URL=" + unsafeURL);
  113.         
  114.         let url = uri.spec;
  115.         
  116.         if (!target)
  117.             target = "current tab";
  118.         
  119.         switch (target) {
  120.             case "current tab":
  121.                 target = "tab";
  122.                 break;
  123.             case "new tab":
  124.                 target = "new-tab";
  125.                 break;
  126.             case "new window":
  127.                 target = "window";
  128.                 break;
  129.         }
  130.         
  131.         if (yandexAction) {
  132.             let packageURI = ioService.newURI(this.packageManager.getPackageInfo(callerProto.unit.unitPackage.id).uri, null, null);
  133.             if (!this.isTrustedPackageURI(packageURI))
  134.                 yandexAction = undefined;
  135.         }
  136.         
  137.         if (target != "new popup") {
  138.             var statData = undefined;
  139.             if (yandexAction)
  140.                 statData = {action: yandexAction};
  141.             
  142.             srcWnd.Ya.loadURI(url, target, statData);
  143.         }
  144.         
  145.         switch (target) {
  146.             case "new popup": {
  147.                 let sizeFeatures = (wndWidth && wndHeight) ? ",width=" + wndWidth + ",height=" + wndHeight : "";
  148.                 srcWnd.openDialog("chrome://" + this.name + "/content/custombar/dialogs/popup_browser/popup_browser.xul", "_blank",
  149.                                   "chrome,all,dialog=no,resizable" + sizeFeatures, url, wndWidth, wndHeight);
  150.                 break;
  151.             }
  152.         }
  153.     },
  154.     
  155.     selectBestPackage: function BarApp_selectBestPackage(manifest /* XB.PackageManifest */) {
  156.         if (!(manifest instanceof this._barCore.Lib.XB.PackageManifest))
  157.             throw new this._barCore.Lib.CustomErrors.EArgType("manifest", "PackageManifest",
  158.                                                               manifest ? manifest.constructor.name : typeof manifest);
  159.         var coreVersion = parseInt(this.core.version, 10),
  160.             bestPackageInfo = null,
  161.             bestVersion = "0",
  162.             bestPackageInfo2 = null,
  163.             bestVersion2 = "0";
  164.         
  165.         var comparator = Components.classes["@mozilla.org/xpcom/version-comparator;1"]
  166.             .getService(Components.interfaces.nsIVersionComparator);
  167.         for each(let packageInfo in manifest.packagesInfo) {
  168.             if (packageInfo.platformMin <= coreVersion) {
  169.                 let newerPackage = (comparator.compare(packageInfo.version, bestVersion) > 0),
  170.                     newerPlatform = bestPackageInfo && (packageInfo.platformMin > bestPackageInfo.platformMin);
  171.                 if (newerPackage || newerPlatform) {
  172.                     bestPackageInfo = packageInfo;
  173.                     bestVersion = packageInfo.version;
  174.                 }
  175.             }
  176.             else {
  177.                 if (comparator.compare(packageInfo.version, bestVersion2) > 0) {
  178.                     bestPackageInfo2 = packageInfo;
  179.                     bestVersion2 = packageInfo.version;
  180.                 }
  181.             }
  182.         }
  183.         return [bestPackageInfo, bestPackageInfo2];
  184.     },
  185.     
  186.     isYandexHost: function barApp_isYandexHost(hostName) {
  187.         return this._yandexHostsPattern.test(hostName);
  188.     },
  189.     
  190.     isTrustedPresetUri: function barApp_isTrustedPresetUri(uri /*nsIURI*/) {
  191.         if (!(uri instanceof Ci.nsIURI))
  192.             throw new this._barApp.core.Lib.CustomErrors.EArgType("uri", "nsIURI", typeof uri);
  193.         
  194.         if ((uri.scheme != "http") && (uri.scheme != "https"))
  195.             return false;
  196.         
  197.         return (uri.host == this._downloadHost) ||
  198.                ((this._approvedCompsHosts.indexOf(uri.host) >= 0) && uri.path.indexOf("/components/approved") == 0);
  199.     },  // boolean
  200.     
  201.     isTrustedPackageURI: function BarApp_isTrustedPackageURI(uri /*nsIURI*/) {
  202.         if (!(uri instanceof Ci.nsIURI))
  203.             throw new this._barApp.core.Lib.CustomErrors.EArgType("uri", "nsIURI", typeof uri);
  204.         
  205.         if ((uri.scheme != "http") && (uri.scheme != "https")) {
  206.             return false;
  207.         }
  208.         
  209.         return (uri.host == this._downloadHost) || ((uri.host == this._barHost) && (uri.path.indexOf("/packages") == 0));
  210.     },
  211.     
  212.     isPreinstalledPackage: function BarApp_isPreinstalledPackage(packageID) {
  213.         return (packageID == "http://bar.yandex.ru/packages/yandexbar" ||
  214.                 packageID == "http://bar.yandex.ru/packages/samples");
  215.     },  // boolean
  216.     
  217.     isPreinstalledWidget: function barApp_isPreinstalledWidget(protoID) {
  218.         return (this._preinstalledWidgetsIDs.indexOf(protoID) >= 0);
  219.     },
  220.     
  221.     finalize: function barApp_finalize() {
  222.         this._widgetLib.finalize();
  223.         this._pacMan.finalize();
  224.         this._widgetLib = null;
  225.         this._pacMan = null;
  226.         this._overlayProvider.clear();
  227.         this._overlayProvider = null;
  228.         
  229.         this._barCore.Lib.XB.finalize();
  230.         
  231.         this._presetWidgetsInfo = null;
  232.         
  233.         this._logger = null;
  234.         this._barCore = null;
  235.     },
  236.     
  237.     onNewNavigatorReady: function barApp_onNewNavigatorReady(controller) {
  238.         try {
  239.             var autoPresetURL = this._autoPresetURL;
  240.             if (autoPresetURL && (this._newCID == 1)) {
  241.                 let cookieManager = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager);
  242.                 cookieManager.remove("." + this._autoPresetCookieDomain, this._autoPresetCookieName, "/", false);
  243.                 this.installPreset(autoPresetURL);
  244.             }
  245.         }
  246.         catch (e) {
  247.             this._logger.error("Could not check autoinstalled preset. " + this._barCore.Lib.misc.formatError(e));
  248.         }
  249.     },
  250.     
  251.     _barCore: null,
  252.     _logger: null,
  253.     _presetWidgetsInfo: null,
  254.     _overlayProvider: null,
  255.     _newCID: 0,
  256.     _newWID: 0,
  257.     _localeString: null,
  258.     _controllerName: null,
  259.     _yandexHostsPattern: /(^|\.)yandex\.(ru|ua|by|kz|net|com)$/i,
  260.     _downloadHost: "download.yandex.ru",
  261.     _barHost: "bar.yandex.ru",
  262.     _approvedCompsHosts: ["toolbar.yandex.ru", "bar.yandex.ru"],
  263.     _autoPresetCookieDomain: "bar.yandex.ru",
  264.     _autoPresetCookieName: "bar-install-preset",
  265.     _dirs: {
  266.         get XBRoot() {
  267.             var dirFile = Cc["@mozilla.org/file/directory_service;1"]
  268.                 .getService(Ci.nsIProperties).get("ProfD", Ci.nsIFile);
  269.             dirFile.append(this.XBDirName);
  270.             this._forceDir(dirFile);
  271.             return dirFile;
  272.         },
  273.         
  274.         get XBPackages() {
  275.             let packagesDir = this.XBRoot;
  276.             packagesDir.append("packages");
  277.             this._forceDir(packagesDir);
  278.             return packagesDir;
  279.         },
  280.         
  281.         get XBPresets() {
  282.             let presetsDir = this.XBRoot;
  283.             presetsDir.append("presets");
  284.             this._forceDir(presetsDir);
  285.             return presetsDir;
  286.         },
  287.         
  288.         get XBTemp() {
  289.             var dirFile = this.XBRoot;
  290.             dirFile.append("temp");
  291.             this._forceDir(dirFile);
  292.             return dirFile;
  293.         },
  294.         
  295.         get content() {
  296.             var contentDirFile = this._barApp.core.extensionPathFile;
  297.             contentDirFile.append("chrome");
  298.             contentDirFile.append("content");
  299.             contentDirFile.append("custombar");
  300.             return contentDirFile;
  301.         },
  302.         
  303.         get XBDirName() {
  304.             return this._xbDirName || (this._xbDirName = this._barApp.name + "-xb");
  305.         },
  306.         
  307.         _barApp: null,
  308.         
  309.         _forceDir: function baxbd_forceDir(dirFile, perm) {
  310.             perm = perm || 0755;
  311.             if (!(dirFile.exists() && dirFile.isDirectory()))
  312.                 dirFile.create(Ci.nsIFile.DIRECTORY_TYPE, perm);
  313.         }
  314.     },
  315.     _pacMan: null,
  316.     _widgetLib: null,
  317.     _preinstalledWidgetsIDs: null,
  318.     _updater: null,
  319.     
  320.     get _autoPresetURL() {
  321.         var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
  322.         var autoPresetCookieURI = ioService.newURI("http://" + this._autoPresetCookieDomain + "/", null, null);
  323.         var cookieService = Cc["@mozilla.org/cookieService;1"].getService().QueryInterface(Ci.nsICookieService);
  324.         var cookieString = cookieService.getCookieString(autoPresetCookieURI, null);
  325.         
  326.         var presetURL;
  327.         if (cookieString) {
  328.             var cookies = cookieString.split(";");
  329.             for each (let cookie in cookies) {
  330.                 let separatorPos = cookie.indexOf("=");
  331.                 if (separatorPos == -1)
  332.                     continue;
  333.                 
  334.                 let cookieName = this._barCore.Lib.sysutils.trimAllSpaces( cookie.substring(0, separatorPos) );
  335.                 if (cookieName == this._autoPresetCookieName)
  336.                     presetURL = unescape( cookie.substring(separatorPos + 1) );
  337.             }
  338.         }
  339.         
  340.         this.__defineGetter__("_autoPresetURL", function() presetURL);
  341.         return this._autoPresetURL;
  342.     },
  343.     
  344.     _init: function barApp_init() {
  345.         this._logger.config("Initializing...");
  346.         this._barCore.Lib.XB.init(this);
  347.         this._initPackageSystem();
  348.         this._initWidgetLibrary();
  349.         this._loadDefaultpreset();
  350.         this._setOverlayProvider();
  351.         this._logger.config("Init done");
  352.     },
  353.     
  354.     _initPackageSystem: function barApp__initPackageSystem() {
  355.         this._logger.config("Scanning installed packages");
  356.         var packagesDir = this._dirs.content;
  357.         packagesDir.append("packages");
  358.         var packagesCommonDir = packagesDir.clone();
  359.         packagesCommonDir.append("common");
  360.         
  361.         this._pacMan = new this._PacMan(this, [packagesCommonDir]);
  362.     },
  363.     
  364.     _initWidgetLibrary: function barApp__initWidgetLibrary() {
  365.         this._widgetLib = new this._WidgetLibrary(this);
  366.         
  367.         try {
  368.             var preinstIDsFile = this.directories.content;
  369.             preinstIDsFile.append("preinstalled_widgets.json");
  370.             this._preinstalledWidgetsIDs = this.core.JSON.parse(this.core.Lib.sysutils.readTextFile(preinstIDsFile));
  371.             this._widgetLib.acquaintWithWidgets(this._preinstalledWidgetsIDs);
  372.         }
  373.         catch (e) {
  374.             this._logger.error("Could not load preinstalled widgets list. " + this.core.Lib.misc.formatError(e));
  375.         }
  376.     },
  377.     
  378.     _loadDefaultpreset: function barApp__loadDefaultpreset() {
  379.         this._logger.config("Loading application default preset");
  380.  
  381.         try {
  382.             var presetChromeURL = "chrome://" + this.name + "/locale/base_preset.xml";
  383.             var presetRequest = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
  384.             presetRequest.open("GET", presetChromeURL, false);
  385.             presetRequest.send(null);
  386.             var presetDoc = presetRequest.responseXML;
  387.             
  388.             var widgetPreset = new this._barCore.Lib.XB.Preset(presetDoc, "");
  389.             this._presetWidgetsInfo = widgetPreset.widgetsInfo;
  390.         }
  391.         catch (e) {
  392.             this._logger.error("Failed loading default preset.\n" + this._barCore.Lib.misc.formatError(e));
  393.             this._logger.debug("Stack trace:\n" + e.stack);
  394.         }
  395.     },
  396.     
  397.     _setOverlayProvider: function barApp__setOverlayProvider() {
  398.         this._logger.config("Adding XUL overlay provider");
  399.         this._overlayProvider = new this._barCore.Lib.OverlayProvider(this);
  400.         var appProtocol = Cc["@mozilla.org/network/protocol;1?name=" + this.name]
  401.             .getService(Ci.nsIProtocolHandler).wrappedJSObject;
  402.         appProtocol.addDataProvider(this._overlayProvider);
  403.     },
  404.     
  405.     _cleanupPreferences: function barApp__clearPreferences() {
  406.         let prefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
  407.         let xbWidgetsPrefBranch = prefService.getBranch(this.name + ".xbwidgets.");
  408.         
  409.         let branchKeys = xbWidgetsPrefBranch.getChildList("", {});
  410.         let widgetSettingKeyPattern = /^(.+#.+)\.(\d+)\..+$/;
  411.         let currentSetData = this._overlayProvider.currentSetIds;
  412.         for each (let key in branchKeys) {
  413.             let keyMatch = key.match(widgetSettingKeyPattern);
  414.             if (!keyMatch)
  415.                 continue;
  416.             
  417.             let prefProtoID = keyMatch[1];
  418.             let prefInstID = keyMatch[2];
  419.             let instArray = currentSetData[prefProtoID];
  420.             if (!instArray) {
  421.                 xbWidgetsPrefBranch.deleteBranch(prefProtoID);
  422.             }
  423.             else {
  424.                 if (instArray.indexOf(prefInstID) < 0) {
  425.                     let settingKey = prefProtoID + "." + prefInstID;
  426.                     xbWidgetsPrefBranch.deleteBranch(settingKey);
  427.                 }
  428.             }
  429.         }
  430.     }
  431. };
  432.  
  433. BarApplication.prototype._PacMan = function PacMan_constructor(barApp, extraPackagesDirs) {
  434.     this._logger = barApp.core.Log4Moz.repository.getLogger(barApp.name + ".pacman");
  435.     this._barApp = barApp;
  436.     this._packagesInfo = {};
  437.     this._cachedPackages = {};
  438.     
  439.     if (extraPackagesDirs && !(extraPackagesDirs instanceof Array))
  440.         throw new this._barApp.core.Lib.CustomErrors.EArgType("extraPackagesDirs", "Array", typeof extraPackagesDirs);
  441.     this._extraPackagesDirs = extraPackagesDirs;
  442.     this.rescanPackages();
  443. };
  444.  
  445. BarApplication.prototype._PacMan.prototype = {
  446.     constructor: BarApplication._PacMan,
  447.     
  448.     get packagesIDs() {
  449.         var IDs = [];
  450.         for (let id in this._packagesInfo) {
  451.             IDs.push(id);
  452.         }
  453.         return IDs;
  454.     },
  455.     
  456.     rescanPackages: function barPacMan_rescanPackages() {
  457.         this._logger.debug("Looking for packages...");
  458.         
  459.         this._unloadPackages();
  460.         this._packagesInfo = {};
  461.         
  462.         var packagesDir = this._barApp.directories.XBPackages;
  463.         var entries = packagesDir.directoryEntries;
  464.         while (entries.hasMoreElements()) {
  465.             let packageDir = entries.getNext().QueryInterface(Ci.nsIFile);
  466.             if (packageDir.isDirectory()) {
  467.                 let packageInfo = this._checkPackageDir(packageDir);
  468.                 if (!packageInfo)
  469.                     continue;
  470.                 
  471.                 let properDirName = this._makePkgDirName(packageInfo.id);
  472.                 if (properDirName !== packageDir.leafName)
  473.                     packageDir.moveTo(null, properDirName);
  474.                 
  475.                 this._logger.debug(this._consts.STR_FOUND_PACKAGE + packageDir.leafName);
  476.                 this._packagesInfo[packageInfo.id] = packageInfo;
  477.             }
  478.         }
  479.         
  480.         if (this._extraPackagesDirs) {
  481.             for each (let packageDir in this._extraPackagesDirs) {
  482.                 let packageInfo = this._checkPackageDir(packageDir);
  483.                 if (packageInfo) {
  484.                     this._logger.debug(this._consts.STR_FOUND_PACKAGE + packageDir.leafName);
  485.                     this._packagesInfo[packageInfo.id] = packageInfo;
  486.                 }
  487.             }
  488.         }
  489.     },
  490.     
  491.     installPackage: function barPacMan_installPackage(srcFile, packageInfo) {
  492.         if (!(srcFile instanceof Ci.nsILocalFile))
  493.             throw new this._barApp.core.Lib.CustomErrors.EArgType("srcFile", "nsILocalFile", typeof srcFile);
  494.         this._validatePackageInfo(packageInfo);
  495.         
  496.         var packageDir;
  497.         if (srcFile.isDirectory()) {
  498.             packageDir = srcFile.clone();
  499.         }
  500.         else {
  501.             packageDir = srcFile.clone();
  502.             packageDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0755);
  503.             this._barApp.core.Lib.sysutils.extractZipArchive(srcFile, packageDir);
  504.             srcFile.remove();
  505.         }
  506.         
  507.         if (this.isPackageInstalled(packageInfo.id))
  508.             this.unloadPackage(packageInfo.id);
  509.         
  510.         var packagesDirectory = this._barApp.directories.XBPackages;
  511.         var destDirName = this._makePkgDirName(packageInfo.id);
  512.         /** NOTE!:
  513.          * For some reason FF 3.5 does not mutate nsIFile after calling its' moveTo method (at least on Linux).
  514.          * So we have to make another nsIFile pointing to the final package destination.
  515.          */
  516.         var destPackageDir = packagesDirectory.clone();
  517.         destPackageDir.append(destDirName);
  518.         
  519.         var destDir = packagesDirectory.clone();
  520.         destDir.append(destDirName);
  521.         this._barApp.core.Lib.misc.removeFileSafe(destDir);
  522.         
  523.         try {
  524.             packageDir.moveTo(packagesDirectory, destDirName);
  525.         }
  526.         catch (e) {
  527.             this._barApp.core.Lib.misc.removeFileSafe(destDir);
  528.             this._barApp.core.Lib.misc.removeFileSafe(srcFile);
  529.             
  530.             throw e;
  531.         }
  532.         
  533.         let metaInfoFile = destPackageDir.clone();
  534.         metaInfoFile.append(this._consts.STR_PKGINFO_FILE_NAME);
  535.         this._barApp.core.Lib.sysutils.writeTextFile(metaInfoFile, this._barApp.core.JSON.stringify(packageInfo), 0644);
  536.         
  537.         packageInfo.installDir = destPackageDir;
  538.         this._packagesInfo[packageInfo.id] = packageInfo;
  539.     },
  540.     
  541.     uninstallPackage: function barPacMan_uninstallPackage(packageID) {
  542.         this.unloadPackage(packageID);
  543.         var dir = this._getPackageInstallInfo(packageID).installDir;
  544.         try {
  545.             dir.remove(true);
  546.         }
  547.         finally {
  548.             delete this._packagesInfo[packageID];
  549.         }
  550.     },
  551.     
  552.     isPackageInstalled: function barPacMan_isPackageInstalled(packageID) {
  553.         return !!this._packagesInfo[packageID];
  554.     },
  555.     
  556.     getPackage: function barPacMan_getPackage(packageID) {
  557.         let pkg = this._cachedPackages[packageID];
  558.         if (pkg)
  559.             return pkg;
  560.         
  561.         let packageInfo = this.getPackageInfo(packageID);
  562.         let package_ = new this._barApp.core.Lib.XB.WidgetPackage(packageInfo.installDir, packageID);
  563.         this._cachedPackages[packageID] = package_;
  564.         return package_;
  565.     },
  566.     
  567.     unloadPackage: function barPacMan_unloadPackage(packageID) {
  568.         if (!this._packagesInfo[packageID])
  569.             throw new Error(this._consts.ERR_NO_SUCH_PACKAGE + " " + packageID);
  570.         this._barApp.widgetLibrary.flushPackageProtos(packageID);
  571.         var pkg = this._cachedPackages[packageID];
  572.         if (!pkg) return;
  573.         pkg.finalize();
  574.         delete this._cachedPackages[packageID];
  575.     },
  576.     
  577.     reloadPackage: function barPacMan_reloadPackage(packageID) {
  578.         this.unloadPackage(packageID);
  579.         this.getPackage(packageID);
  580.     },
  581.     
  582.     finalize: function barPacMan_finalize() {
  583.         this._unloadPackages();
  584.         this._cachedPackages = null;
  585.         this._packagesInfo = null;
  586.     },
  587.     
  588.     getPackageInfo: function barpacMan_getPackageInfo(packageID) {
  589.         var packageInfo = this._getPackageInstallInfo(packageID);
  590.         packageInfo = this._barApp.core.Lib.sysutils.copyObj(packageInfo, false);
  591.         packageInfo.installDir = packageInfo.installDir.clone();
  592.         return packageInfo;
  593.     },
  594.     
  595.     _unloadPackages: function barPacMan__unloadPackages() {
  596.         for (let packageID in this._cachedPackages) {
  597.             try {
  598.                 this.unloadPackage(packageID);
  599.             }
  600.             catch (e) {
  601.                 this._logger.error("Error finalizing package " + packageID + ". " +
  602.                                    this._barApp.core.Lib.misc.formatError(e));
  603.             }
  604.         }
  605.     },
  606.     
  607.     _getPackageInstallInfo: function barPacMan__getPackageInstallInfo(packageID) {
  608.         var packageInfo = this._packagesInfo[packageID];
  609.         if (!packageInfo) {
  610.             this._logger.warn("barPacMan_getPackageInstallInfo: " +
  611.                               this._consts.ERR_NO_SUCH_PACKAGE + " " + packageID);
  612.             throw new Error(this._consts.ERR_NO_SUCH_PACKAGE + " " + packageID);
  613.         }
  614.         return packageInfo;
  615.     },
  616.     
  617.     _checkPackageDir: function barPacMan__checkPackageDir(packageDir) {
  618.         var dirName = "";
  619.         
  620.         try {
  621.             dirName = packageDir.leafName;
  622.             this._logger.trace("Checking directory " + dirName);
  623.             
  624.             let pkgInfoFile = packageDir.clone();
  625.             pkgInfoFile.append(this._consts.STR_PKGINFO_FILE_NAME);
  626.             
  627.             if ( !(pkgInfoFile.exists() && pkgInfoFile.isReadable()) ) {
  628.                 this._logger.warn("Directory '" + dirName + "' does not contain a valid package");
  629.                 return null;
  630.             }
  631.             
  632.             var packageInfo = this._barApp.core.JSON.parse( this._barApp.core.Lib.sysutils.readTextFile(pkgInfoFile) );
  633.             if ((typeof packageInfo == 'object') && !(packageInfo instanceof Object))
  634.                 packageInfo.__proto__ = Object.prototype;
  635.             this._validatePackageInfo(packageInfo);
  636.             
  637.             packageInfo.installDir = packageDir;
  638.             
  639.             return packageInfo;
  640.         }
  641.         catch (e) {
  642.             this._logger.warn("An error occured while checking package directory " + dirName + ". " +
  643.                               this._barApp.core.Lib.misc.formatError(e));
  644.             return null;
  645.         }
  646.     },
  647.     
  648.     _validatePackageInfo: function BarPacMan_validatePackageInfo(packageInfo) {
  649.         if (!(packageInfo instanceof Object))
  650.             throw this._barApp.core.Lib.CustomErrors.EArgType("packageInfo", "Object", packageInfo);
  651.             
  652.         for (let propName in this._metainfoPropNames)
  653.             if (!(propName in packageInfo))
  654.                 throw new SyntaxError(this._consts.ERR_CORRUPT_PKGINFOFILE + " (" + propName + ")");
  655.         
  656.         for (let propName in packageInfo)
  657.             if (!(propName in this._metainfoPropNames))
  658.                 delete packageInfo[propName];
  659.     },
  660.     
  661.     _makePkgDirName: function barPacMan__makePkgDirName(packageID) {
  662.         return this._barApp.core.Lib.misc.stringMD5(packageID);
  663.     },
  664.     
  665.     _backgroundDownload: function barPacMan__backgroundDownload(pkgManURL, context) {
  666.         let progressWatcher = context.progressWatcher;
  667.         if (progressWatcher) {
  668.             if ((typeof progressWatcher.onProgress != "function") ||
  669.                 (typeof progressWatcher.shouldCancel != "function") ||
  670.                 (typeof progressWatcher.beforeFilesReplaced != "function"))
  671.                 throw new TypeError(this._consts.ERR_PROGRESS_WATCHER_INTF);
  672.         }
  673.         
  674.         let destPkgFile = this._barApp.directories.XBTemp;
  675.         destPkgFile.append("tmp-" + encodeURIComponent(pkgManURL));
  676.         this._barApp._logger.debug("Starting BG download " + pkgManURL);
  677.         let downloadTask = new this._DownloadTask(this, this._barApp, pkgManURL, destPkgFile, context);
  678.         
  679.         let bgThread = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager).newThread(0);
  680.         bgThread.dispatch(downloadTask, bgThread.DISPATCH_NORMAL);
  681.         
  682.         var currentThread = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager).currentThread;
  683.         while (!downloadTask.finished) {
  684.             if (progressWatcher) {
  685.                 progressWatcher.onProgress(downloadTask.progress);
  686.                 if (progressWatcher.shouldCancel())
  687.                     downloadTask.cancel();
  688.             }
  689.             currentThread.processNextEvent(true);
  690.         }
  691.         
  692.         if (downloadTask.error)
  693.             throw downloadTask.error;
  694.         
  695.         if (progressWatcher)
  696.             progressWatcher.onProgress(downloadTask.progress);
  697.     },
  698.     
  699.     _consts: {
  700.         STR_PKGINFO_FILE_NAME: ".package.json",
  701.         STR_ARRAY_EXPECTED: "Array expected",
  702.         STR_FOUND_PACKAGE: "Found a package in directory ",
  703.         
  704.         ERR_NO_SUCH_PACKAGE: "No such package",
  705.         ERR_PKGINFO_REQUIRED: "Package inforamtion required",
  706.         ERR_CORRUPT_PKGINFOFILE: "Package information file is corrupt",
  707.         ERR_WRONG_MANIFEST_SYNTAX: "Wrong manifest syntax",
  708.         ERR_WRONG_PKGID: "Manifest declares wrong package ID",
  709.         ERR_PROGRESS_WATCHER_INTF: "Progress watcher object does not support proper interface"
  710.     },
  711.     
  712.     _metainfoPropNames: {id: 0, uri: 0, version: 0, platformMin: 0, __proto__: null},
  713.     _barApp: null,
  714.     _logger: null,
  715.     _packagesInfo: null,
  716.     _cachedPackages: null,
  717.     _extraPackagesDirs: undefined
  718. };
  719.  
  720. BarApplication.prototype._WidgetLibrary = function BarWidgetLib(application) {
  721.     this._barApp = application;
  722.     this._logger = application.core.Log4Moz.repository.getLogger(application.name + ".WLib");
  723.     this._knownWidgets = {};
  724.     this._packages = {};
  725.     
  726.     try {
  727.         this._loadKnownWidgets();
  728.     }
  729.     catch (e) {
  730.         this._logger.error("An error occured while loading known widgets. " +
  731.                            this._barApp.core.Lib.misc.formatError(e));
  732.     }
  733. };
  734.  
  735. BarApplication.prototype._WidgetLibrary.prototype = {
  736.     constructor: BarApplication.prototype._WidgetLibrary,
  737.     
  738.     clear: function WidgetLibrary_clear() {
  739.         this._packages = {};
  740.         this._knownWidgets = {};
  741.     },
  742.     
  743.     finalize: function WidgetLibrary_finalize() {
  744.         this._saveKnownWidgetsData();
  745.         this.clear();
  746.         this._logger = null;
  747.     },
  748.     
  749.     acquaintWithWidgets: function WidgetLibrary_acquaintWithWidgets(protoIDsArray) {
  750.         for each (let protoID in protoIDsArray) {
  751.             if (!this._knownWidgets[protoID])
  752.                 this._knownWidgets[protoID] = this._loadWidgetProto(protoID);
  753.         }
  754.         this._saveKnownWidgetsData();
  755.     },
  756.     
  757.     forgetWidgets: function WidgetLibrary_forgetWidget(protoIDsArray) {
  758.         for each (let protoID in protoIDsArray) {
  759.             if (protoID in this._knownWidgets) {
  760.                 delete this._knownWidgets[protoID];
  761.             }
  762.         }
  763.         this._saveKnownWidgetsData();
  764.     },
  765.     
  766.     getWidgetProto: function WidgetLibrary_getWidgetProto(protoID) {
  767.         if (!this._barApp.core.Lib.sysutils.isString(protoID))
  768.             throw new this._barApp.core.Lib.CustomErrors.EArgType("protoID", "String", typeof protoID);
  769.         return this._knownWidgets[protoID] || this._loadWidgetProto(protoID);
  770.     },
  771.     
  772.     getWidgetProtos: function WidgetLibrary_getWidgetProtos(fromPackageID) {
  773.         var result = [];
  774.         for (let protoID in this._knownWidgets) {
  775.             if (fromPackageID) {
  776.                 let [packageID, ] = this.parseWidgetProtoID(protoID);
  777.                 if (packageID !== fromPackageID)
  778.                     continue;
  779.             }
  780.             result.push(this.getWidgetProto(protoID));
  781.         }
  782.         return result;
  783.     },
  784.     
  785.     getWidgetProtoIDs: function WidgetLibrary_getWidgetProtoIDs(fromPackageID) {
  786.         var result = [];
  787.         for (let protoID in this._knownWidgets) {
  788.             if (fromPackageID) {
  789.                 let [packageID, ] = this.parseWidgetProtoID(protoID);
  790.                 if (packageID !== fromPackageID)
  791.                     continue;
  792.             }
  793.             result.push(protoID);
  794.         }
  795.         return result;
  796.     },
  797.     
  798.     isKnownWidget: function WidgetLibrary_isKnownWidget(prototypeId) {
  799.         return prototypeId in this._knownWidgets;
  800.     },
  801.     
  802.     persist: function WidgetLibrary_persist() {
  803.         this._saveKnownWidgetsData();
  804.     },
  805.     
  806.     flushPackageProtos: function WidgetLibrary_flushPackageProtos(packageID) {
  807.         for (let protoID in this._knownWidgets) {
  808.             let widgetProto = this._knownWidgets[protoID];
  809.             if (widgetProto)
  810.                 if ( !packageID || (widgetProto.unit.unitPackage.id == packageID) )
  811.                     this._knownWidgets[protoID] = undefined;
  812.         }
  813.     },
  814.     
  815.     parseWidgetProtoID: function WidgetLibrary_parseWidgetProtoID(protoID) {
  816.         var separatorPos = protoID.indexOf("#");
  817.         var packageID = protoID.substring(0, separatorPos);
  818.         var widgetName = protoID.substring(separatorPos + 1);
  819.         return [packageID, widgetName];
  820.     },
  821.     
  822.     _consts: {
  823.         STR_KNOWN_WIDGETS_FILE_NAME: "known_widgets.json",
  824.         
  825.         ERR_UNIT_HAS_NO_WIDGET: "Unit does not define a widget"
  826.     },
  827.     _barApp: null,
  828.     _logger: null,
  829.     _packages: null,
  830.     _knownWidgets: null,
  831.     
  832.     _loadKnownWidgets: function WidgetLibrary__loadKnownWidgets() {
  833.         let dataFile = this._barApp.directories.XBRoot;
  834.         dataFile.append(this._consts.STR_KNOWN_WIDGETS_FILE_NAME);
  835.         if (dataFile.exists() && dataFile.isFile() && dataFile.isReadable()) {
  836.             let protoIDsArray = this._barApp.core.JSON.parse( this._barApp.core.Lib.sysutils.readTextFile(dataFile) );
  837.             
  838.             let knownWidgetsListChanged = false;
  839.             for each (let protoID in protoIDsArray) {
  840.                 try {
  841.                     this._knownWidgets[protoID] = this._loadWidgetProto(protoID);
  842.                 }
  843.                 catch (e) {
  844.                     this._logger.warn("Previously known widget \"" + protoID +
  845.                                       "\" could not be loaded. Will forget it. Error: " +
  846.                                       this._barApp.core.Lib.misc.formatError(e));
  847.                 }
  848.             }
  849.             
  850.             if (knownWidgetsListChanged)
  851.                 this._saveKnownWidgetsData();
  852.         }
  853.     },
  854.     
  855.     _saveKnownWidgetsData: function WidgetLibrary__saveKnownWidgetsData() {
  856.         let dataFile = this._barApp.directories.XBRoot;
  857.         dataFile.append(this._consts.STR_KNOWN_WIDGETS_FILE_NAME);
  858.         this._barApp.core.Lib.sysutils.writeTextFile(dataFile,
  859.                                                      this._barApp.core.JSON.stringify(this.getWidgetProtoIDs()), 0644);
  860.     },
  861.     
  862.     _loadWidgetProto: function WidgetLibrary__loadWidgetProto(protoID) {
  863.         var [packageID, widgetName] = this.parseWidgetProtoID(protoID);
  864.         var package_ = this._barApp.packageManager.getPackage(packageID);
  865.         var proto = package_.getUnit(widgetName).widgetProto;
  866.         if (!proto)
  867.             throw new Error(this._consts.ERR_UNIT_HAS_NO_WIDGET);
  868.         return proto;
  869.     }
  870. };