home *** CD-ROM | disk | FTP | other *** search
/ Chip 2011 March / Chip_2011.03_CD.iso / Tools / yabar.msi / fil3346EA191FC9074B20FB5710D952C39C < prev    next >
Encoding:
Text File  |  2010-04-16  |  170.7 KB  |  5,533 lines

  1. const Cc = Components.classes;
  2. const Ci = Components.interfaces;
  3. const Cr = Components.results;
  4. const Cu = Components.utils;
  5.  
  6. const EXT_ID = "yasearch@yandex.ru";
  7. const CHROME_IMAGES = "chrome://yasearch/skin/images/";
  8. const CHROME_CONTENT = "chrome://yasearch/content/";
  9.  
  10. Cu.import("resource://gre/modules/XPCOMUtils.jsm");
  11.  
  12. /** ================================================================================ **/
  13.  
  14. ["consts", "utils", "cache_wrapper",
  15.  "ya_storage", "ya_installer", "ya_defence", "ya_bookmarks",
  16.  "ya_overlay", "ya_city", "ya_searchplugin", "ya_uservices",
  17.  "ya_partner", "ya_sshot", "ya_ftab"]
  18. .forEach(
  19.   function(aScriptName) {
  20.     this.loadSubScript(CHROME_CONTENT + "sub-scripts/" + aScriptName + ".js");
  21.   },
  22.   Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
  23. );
  24.  
  25. /** ================================================================================ **/
  26.  
  27. function nsIYaSearch() {
  28.   this.version = "201001200600";
  29.   this.versionBuild = "7394";
  30.   this.VERSION_BUILD = "";
  31.  
  32.   this.wrappedJSObject = this;
  33.   this.debug = false;
  34.   
  35.   this._inited = false;
  36.   
  37.   this.EXT_ID = EXT_ID;
  38.  
  39.   this.prefs = {
  40.     _showBloggersValuePrefName: "yasearch.general.ui.show.bloggers.value",
  41.  
  42.     get showBloggersValue() {
  43.       return gYaSearchService.getBoolPref(this._showBloggersValuePrefName);
  44.     },
  45.  
  46.     set showBloggersValue(val) {
  47.       gYaSearchService.setBoolPref(this._showBloggersValuePrefName, !!val);
  48.       return this.showBloggersValue;
  49.     },
  50.     
  51.     _showCyValuePrefName: "yasearch.general.ui.show.cy.value",
  52.  
  53.     get showCyValue() {
  54.       return gYaSearchService.getBoolPref(this._showCyValuePrefName);
  55.     },
  56.  
  57.     set showCyValue(val) {
  58.       gYaSearchService.setBoolPref(this._showCyValuePrefName, !!val);
  59.       return this.showCyValue;
  60.     },
  61.  
  62.     _highlighterEnabledPrefName: "yasearch.general.ui.highlighter.enabled",
  63.  
  64.     get highlighterEnabled() {
  65.       return gYaSearchService.getBoolPref(this._highlighterEnabledPrefName);
  66.     },
  67.  
  68.     set highlighterEnabled(val) {
  69.       gYaSearchService.setBoolPref(this._highlighterEnabledPrefName, !!val);
  70.       return this.highlighterEnabled;
  71.     },
  72.  
  73.     _showSiteSearchPrefName: "yasearch.general.ui.show.site.search",
  74.  
  75.     get showSiteSearch() {
  76.       return gYaSearchService.getBoolPref(this._showSiteSearchPrefName);
  77.     },
  78.  
  79.     set showSiteSearch(val) {
  80.       gYaSearchService.setBoolPref(this._showSiteSearchPrefName, !!val);
  81.       return this.showSiteSearch;
  82.     },
  83.  
  84.     _searchHistoryEnabledPrefName: "yasearch.general.ui.search.history.enabled",
  85.  
  86.     get searchHistoryEnabled() {
  87.       return gYaSearchService.getBoolPref(this._searchHistoryEnabledPrefName);
  88.     },
  89.  
  90.     set searchHistoryEnabled(val) {
  91.       gYaSearchService.setBoolPref(this._searchHistoryEnabledPrefName, !!val);
  92.       return this.searchHistoryEnabled;
  93.     },
  94.  
  95.     _commandOpenTabPrefName: "yasearch.general.ui.command.open.tab",
  96.  
  97.     get commandOpenTab() {
  98.       return gYaSearchService.getBoolPref(this._commandOpenTabPrefName);
  99.     },
  100.  
  101.     _showCityLabel: "yasearch.general.ui.show.city.label",
  102.  
  103.     get showCityLabel() {
  104.       return gYaSearchService.getBoolPref(this._showCityLabel);
  105.     },
  106.  
  107.     set showCityLabel(val) {
  108.       gYaSearchService.setBoolPref(this._showCityLabel, !!val);
  109.       return this.showCityLabel;
  110.     }
  111.   };
  112.  
  113.   this.updateTimer = {
  114.     "_Login": null,
  115.     "_Guid": null,
  116.     "_GuidRefresh": null,
  117.     "_MailAndFeeds": null,
  118.     "_Bookmarks": null
  119.   };
  120.  
  121.   this.checkTimeOut = {
  122.     "_Login": 5 * MIN_SEC,
  123.     "_Guid": DAY_SECS,
  124.     "_GuidRefresh": 3600010,
  125.     "_MailAndFeeds": 0,
  126.     "_Bookmarks": DAY_SECS
  127.   };
  128.  
  129.   this.feedsCounter = 0;
  130.  
  131.   this._runnedNotifications = [];
  132.  
  133.   this.usersData = {};
  134.  
  135.   this.maxUnreadInXML = 30;
  136.  
  137.   this.showLocalWelcomePage = false;
  138.   this.checkKeywordURL = null;
  139. }
  140.  
  141. nsIYaSearch.prototype = {
  142.   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
  143.                                          Ci.nsIYaSearch,
  144.                                          Ci.nsIObserver,
  145.                                          Ci.nsISupportsWeakReference]),
  146.   
  147.   ASSERT: function() {},
  148.  
  149.   log: function(msg) {
  150.     if (!this.debug)
  151.       return;
  152.  
  153.     var date = new Date();
  154.     var time = [date.getHours(), date.getMinutes(), date.getSeconds()].join(":") + "." + date.getMilliseconds();
  155.  
  156.     msg = "[nsIYaSearch (" + time + ")]: " + msg + "\n";
  157.     CONSOLE_SERVICE.logStringMessage(msg);
  158.  
  159.     //this.tmpLogOutput.write(msg, msg.length);
  160.   },
  161.  
  162.   get tmpLogOutput() {
  163.     if (!this.__tmpLogOutput) {
  164.       var tmpFile = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile);
  165.  
  166.       tmpFile.append("!!_ya_searchlog_");
  167.  
  168.       var os = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
  169.       os.init(tmpFile, 0x02 | 0x08 | 0x20, 0755, 0);
  170.  
  171.       this.__tmpLogOutput = os;
  172.     }
  173.  
  174.     return this.__tmpLogOutput;
  175.   },
  176.   
  177.   isLogin: false,
  178.  
  179.   cookieManager: Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager),
  180.  
  181.   defaultSearchEngineId: "www",
  182.  
  183.   settingsFolderName: "yandex",
  184.   xmlServicesFileName: "services.data.xml",
  185.   xmlServicesFile: null,
  186.   xmlServices: null,
  187.   contentDir: null,
  188.  
  189.   _xsltemplates: {},
  190.   xsltImportRegExp: new RegExp(/<xsl:import href="chrome:\/\/yasearch\/content\/xsl\-templ\/xsl\-(.*)\.xsl"\/>/),
  191.  
  192.   domParser:        Cc["@mozilla.org/xmlextras/domparser;1"].getService(Ci.nsIDOMParser),
  193.   xmlSerializer:    Cc["@mozilla.org/xmlextras/xmlserializer;1"].getService(Ci.nsIDOMSerializer),
  194.   xPathEvaluator:   Cc["@mozilla.org/dom/xpath-evaluator;1"].getService(Ci.nsIDOMXPathEvaluator),
  195.   unSnapshotType:   Ci.nsIDOMXPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
  196.   orSnapshotType:   Ci.nsIDOMXPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
  197.  
  198.   soundService:     Cc["@mozilla.org/sound;1"].createInstance(Ci.nsISound),
  199.  
  200.   windowMediator:   Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator),
  201.   windowWatcher:    Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher),
  202.   promptService:    Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService),
  203.  
  204.   /**--------------------------------------------------------------------------------------------------**/
  205.   _getHostURIFromURL: function(aURL) {
  206.     var host = aURL.replace(/^\s*([-\w]*:\/+)?/, "");
  207.     return this.makeURI("http://" + host);
  208.   },
  209.  
  210.   isCookiesAllowedForHost: function(aURL) {
  211.     var res = null;
  212.  
  213.     var uri = this._getHostURIFromURL(aURL);
  214.     if (!uri)
  215.       return res;
  216.  
  217.     var permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
  218.  
  219.     switch (permissionManager.testPermission(uri, "cookie")) {
  220.       case permissionManager.ALLOW_ACTION:
  221.         res = true;
  222.         break;
  223.  
  224.       case permissionManager.DENY_ACTION:
  225.         res = null;
  226.         break;
  227.  
  228.       case permissionManager.UNKNOWN_ACTION:
  229.       default:
  230.         var cookieBehaviorValue = this.getIntPref("network.cookie.cookieBehavior");
  231.         res = (cookieBehaviorValue === 0);
  232.         break;
  233.     }
  234.  
  235.     return res;
  236.   },
  237.  
  238.   allowCookiesForHost: function(aURL) {
  239.     if (this.isCookiesAllowedForHost(aURL))
  240.       return true;
  241.  
  242.     var uri = this._getHostURIFromURL(aURL);
  243.     if (uri) {
  244.       var permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
  245.       permissionManager.add(uri, "cookie", permissionManager.ALLOW_ACTION);
  246.     }
  247.  
  248.     return this.isCookiesAllowedForHost(aURL);
  249.   },
  250.  
  251.   setSessionFromCookies: function(aCheckExpired) {
  252.     if (!this.isLogin && !this.loginProcessData.username) {
  253.       var loginCookieValue = this.getYandexCookie("yandex_login", aCheckExpired);
  254.       var sessionCookieValue = this.getYandexCookie("Session_id", aCheckExpired);
  255.  
  256.       if (loginCookieValue && sessionCookieValue) {
  257.         this.session = {name: "Id", val: sessionCookieValue};
  258.         this.session = {name: "Login", val: loginCookieValue};
  259.  
  260.         return true;
  261.       }
  262.     }
  263.     
  264.     return false;
  265.   },
  266.  
  267.   checkAuthOnStart: function(aSkipGettingStaticData) {
  268.     if ((typeof aSkipGettingStaticData === "undefined") && !this.yaRootDomain)
  269.       return this.getAuthStaticData(this.checkAuthOnStart.bind(this));
  270.  
  271.     if (this.yaRootDomain && !this.isLogin && !this.loginProcessData.username)
  272.       this.setSessionFromCookies(true);
  273.   },
  274.  
  275.   getAuthStaticData: function(aCallback) {
  276.     this.xmlHttpRequest("https://passport.yandex.ru/bar.txt?" + getNCRndStr(),
  277.                          { callbackFunc: this.getAuthStaticDataCallback.bind(this, aCallback) });
  278.   },
  279.  
  280.   getAuthStaticDataCallback: function(aReq, aCallback) {
  281.     var res = false;
  282.     if (!this.isReqError(aReq)) {
  283.       var staticDataArray = aReq.target.responseText.split(/\r?\n/);
  284.       var rootPass = false;
  285.       var resArray = [];
  286.  
  287.       for (var i = 0, len = staticDataArray.length; i < len; i++) {
  288.         var item = staticDataArray[i].split("#")[0];
  289.         if (/^\/:/.test(item)) {
  290.           if (!rootPass)
  291.             rootPass = item;
  292.         } else if (item.indexOf(":") > 0) {
  293.           resArray.push(item);
  294.         }
  295.       }
  296.  
  297.       if (rootPass) {
  298.         resArray.unshift(G_TIME_NOW, rootPass);
  299.         this.yaAuthStaticData = resArray.join("~~~");
  300.       }
  301.  
  302.       res = !!this.yaRootDomain;
  303.     }
  304.  
  305.     if (aCallback)
  306.       aCallback(res);
  307.   },
  308.  
  309.   __yaAuthStaticData: null,
  310.  
  311.   set yaAuthStaticData(aVal) {
  312.     this.setCharPref("yasearch.auth.static", aVal);
  313.     this.__yaAuthStaticData = null;
  314.     return aVal;
  315.   },
  316.  
  317.   get yaAuthStaticData() {
  318.     if (this.__yaAuthStaticData === null) {
  319.       var staticData = {
  320.         ts: 0,
  321.         get needRefresh() {
  322.           var timeNow = G_TIME_NOW;
  323.           return ((timeNow - this.ts > 1 * DAY_SECS) || this.ts > timeNow) ? true : false;
  324.         },
  325.  
  326.         rootDomain: false,
  327.         rootPass: false,
  328.         rootPasslogin: false,
  329.         rootPasslogout: false,
  330.         allHostsRegExp: false,
  331.         hosts: {}
  332.       };
  333.  
  334.       var data = (this.getCharPref("yasearch.auth.static") || "").split("~~~");
  335.  
  336.       if (data.length > 1 && /^\d+$/.test(data[0])) {
  337.         var lastTime = +data[0];
  338.  
  339.         try {
  340.           var hostStr = data[1];
  341.           var uri = hostStr && /^\/:/.test(hostStr) ? this.makeURI(hostStr.replace(/^\/:/,"")) : null;
  342.         } catch(e){}
  343.  
  344.         if (uri && /https?/.test(uri.scheme)) {
  345.           var allHostsRegExp = [];
  346.  
  347.           staticData.ts = lastTime;
  348.  
  349.           var passUrl = uri.spec;
  350.           staticData.rootPass = passUrl;
  351.  
  352.           passUrl += (/\/$/.test(passUrl) ? "" : "/") + "xml/log";
  353.  
  354.           staticData.rootPasslogin = passUrl + "in";
  355.           staticData.rootPasslogout = passUrl + "out";
  356.  
  357.           var domainArr = uri.host.split(".").reverse();
  358.           staticData.rootDomain = domainArr.length > 1 ? ("." + domainArr[1] + "." + domainArr[0]) : false;
  359.  
  360.           var i = 2, cookies = data[i];
  361.           while (cookies) {
  362.             var hostIndx = cookies.indexOf(":");
  363.  
  364.             if (hostIndx > 2) {
  365.               var host = cookies.substring(0, hostIndx);
  366.  
  367.               var hostReg = host.replace(/(\-|\.)/g,"\\\$1").replace(/^(\*\\\.)/,"(.*\\.)?");
  368.               allHostsRegExp.push(hostReg);
  369.               hostReg = new RegExp("^" + hostReg + "$", "i");
  370.  
  371.               var cookiesArr = [];
  372.               for each (var cook in cookies.substring(++hostIndx).split(","))
  373.                 if (cook > "")
  374.                   cookiesArr.push(cook);
  375.  
  376.               if (cookiesArr.length)
  377.                 staticData.hosts[host] = {cookies: cookiesArr, hostReg: hostReg};
  378.             }
  379.  
  380.             cookies = data[++i];
  381.           }
  382.  
  383.           if (allHostsRegExp.length)
  384.             staticData.allHostsRegExp = new RegExp("^(" + allHostsRegExp.join("|") + ")$", "i");
  385.         }
  386.       }
  387.  
  388.       this.__yaAuthStaticData = staticData;
  389.     }
  390.  
  391.     return this.__yaAuthStaticData;
  392.   },
  393.  
  394.   get yaRootDomain() {
  395.     return this.yaAuthStaticData.rootDomain;
  396.   },
  397.  
  398.   getYandexCookie: function(aName, aCheckExpired) {
  399.     let rootDomain = this.yaRootDomain;
  400.     
  401.     if (rootDomain) {
  402.       const nsICookie = Ci.nsICookie;
  403.       let timeNow = parseInt(G_TIME_NOW / 1000, 10);
  404.       let cookEnum = this.cookieManager.enumerator;
  405.       
  406.       while (cookEnum.hasMoreElements()) {
  407.         let cookie = cookEnum.getNext();
  408.         if (cookie && cookie instanceof nsICookie && cookie.host == rootDomain &&
  409.             cookie.name == aName && cookie.path == "/" && cookie.value.toString() != "" &&
  410.             (aCheckExpired ? timeNow < cookie.expires : true)) {
  411.  
  412.             let res = cookie.value.toString();
  413.             return aName == "Session_id" ? this.checkSessionCookieValue(res) : res;
  414.         }
  415.       }
  416.     }
  417.     
  418.     return false;
  419.   },
  420.  
  421.   checkSessionCookieValue: function(aValue) {
  422.     return (aValue && aValue.length) ? aValue : false;
  423.   },
  424.  
  425.   getBrowserHostCookies: function(aOnlyYandexList) {
  426.     var res = {};
  427.     var allHostsRegExp = aOnlyYandexList ? this.yaAuthStaticData.allHostsRegExp : false;
  428.  
  429.     if (!aOnlyYandexList || allHostsRegExp) {
  430.       const nsICookie = Ci.nsICookie;
  431.  
  432.       var cookEnum = this.cookieManager.enumerator;
  433.       while (cookEnum.hasMoreElements()) {
  434.         var cookie = cookEnum.getNext();
  435.         if (cookie && cookie instanceof nsICookie) {
  436.           var host = cookie.host;
  437.           if (!aOnlyYandexList || allHostsRegExp.test(host)) {
  438.             var newCookie = {};
  439.             for each (var prop in ["name", "value", "host", "path", "expires"])
  440.               newCookie[prop] = cookie[prop];
  441.  
  442.             if (!res[host])
  443.               res[host] = [];
  444.             
  445.             res[host].push(newCookie);
  446.           }
  447.         } else {
  448.           break;
  449.         }
  450.       }
  451.     }
  452.  
  453.     return res;
  454.   },
  455.  
  456.   getAuthDinamicData: function(aType) {
  457.     let url = this.yaAuthStaticData["rootPass" + aType];
  458.  
  459.     if (url) {
  460.       url = this.appendStatData2Url(url + "?" + getNCRndStr(), {});
  461.       return this.xmlHttpRequest(url, {callbackFunc: this.getAuthDinamicDataCallback.bind(this, aType)});
  462.     }
  463.   },
  464.  
  465.   getAuthDinamicDataCallback: function(aReq, aType) {
  466.     var res = false;
  467.  
  468.     if ((aType === "logout" && !this.isLogin) || (aType === "login" && this.isLogin))
  469.       res = this.manageCookies(this.isReqError(aReq) ? false : aReq.target.responseText.replace(/<\?xml .+\?>[\r\n]*/,""), aType);
  470.   },
  471.  
  472.   manageCookies: function(aXmlString, aType) {
  473.     var res = false;
  474.  
  475.     var presentHosts;
  476.  
  477.     var cookieManager = this.cookieManager;
  478.  
  479.     var cookiesXml = this.safeE4Xml(aXmlString, "<mda/>", "mda");
  480.  
  481.     if (cookiesXml.domain.length()) {
  482.       var cookieService = Cc["@mozilla.org/cookieService;1"].getService().QueryInterface(Ci.nsICookieService);
  483.  
  484.       presentHosts = this.getBrowserHostCookies();
  485.  
  486.       var timeNow = G_TIME_NOW;
  487.       var timeNowSec = parseInt(timeNow / 1000, 10);
  488.  
  489.       for (var i = 0, len_i = cookiesXml.domain.length(); i < len_i; i++) {//for each not work in some versions
  490.         var domain = cookiesXml.domain[i];
  491.         var domainId = domain.@id.toString();
  492.  
  493.         for each (var actionTag in domain.*) {
  494.           var action = actionTag.name().toString();
  495.           for (var j = 0, len_j = actionTag.cookie.length(); j < len_j; j++) {
  496.             var cookie = actionTag.cookie[j];
  497.             var cookieName = cookie.@id.toString();
  498.  
  499.             if (cookieName > "") {
  500.  
  501.               var cookiePath = cookie.@path.toString() == "" ? "/" : cookie.@path.toString();
  502.  
  503.               switch (action) {
  504.                 case "remove":
  505.                   cookieManager.remove(domainId, cookieName, cookiePath, false);
  506.                   break;
  507.  
  508.                 case "set":
  509.                   var maxAge = +(cookie["@max-age"].toString());
  510.  
  511.                   if (cookie.@override.toString() != "yes" && presentHosts[domainId]) {
  512.                     for each (var existCookie in presentHosts[domainId]) {
  513.                       if (existCookie.name === cookieName) {
  514.                         if ((existCookie.expires == 0 && maxAge == 0) ||
  515.                             (existCookie.expires > 0 && maxAge > 0 && timeNowSec < existCookie.expires))
  516.                           cookieName = false;
  517.                         break;
  518.                       }
  519.                     }
  520.                   }
  521.  
  522.                   if (cookieName) {
  523.                     var uri = Cc["@mozilla.org/network/standard-url;1"].createInstance(Ci.nsIURI);
  524.                     uri.spec = "http://" + domainId;
  525.  
  526.                     var cookieStr = "" + cookieName + "=" + cookie.text().toString() + ";";
  527.  
  528.                     if (domainId.charAt(0) == ".")
  529.                       cookieStr += "domain=" + domainId + ";";
  530.  
  531.                     cookieStr += "path=" + cookiePath + ";";
  532.  
  533.                     if (maxAge > 0)
  534.                       cookieStr += "expires=" + (new Date(timeNow + maxAge*1000).toGMTString()) + ";"
  535.  
  536.                     cookieService.setCookieString(uri, null, cookieStr, null);
  537.                   }
  538.                   break;
  539.  
  540.                 default:
  541.                   break;
  542.               }
  543.             }
  544.           }
  545.         }
  546.       }
  547.  
  548.       res = true;
  549.  
  550.     } else if (aType == "logout") {
  551.       presentHosts = this.getBrowserHostCookies(true);
  552.       for each (var staticHost in this.yaAuthStaticData.hosts) {
  553.         for (var presentHost in presentHosts) {
  554.           if (staticHost.hostReg.test(presentHost)) {
  555.             var presentCookies = presentHosts[presentHost];
  556.             for each (var staticName in staticHost.cookies) {
  557.               var i = presentCookies.length;
  558.               while (--i > -1) {
  559.                 var presentCookie = presentCookies[i];
  560.                 if (staticName == presentCookie.name) {
  561.                   cookieManager.remove(presentCookie.host, presentCookie.name, presentCookie.path, false);
  562.                   presentCookies.splice(i,1);
  563.                 }
  564.               }
  565.             }
  566.           }
  567.         }
  568.       }
  569.  
  570.       res = true;
  571.  
  572.     }
  573.  
  574.     return res;
  575.   },
  576.  
  577.   /**--------------------------------------------------------------------------------------------------**/
  578.   isFirstDOMWinStuffDone: false,
  579.   
  580.   onBrowserUIStartupComplete: function() {
  581.     if (!this._inited || this.isFirstDOMWinStuffDone)
  582.       return;
  583.     
  584.     this.stringBundle = null;//refresh non-ru-locale strbundle
  585.  
  586.     this.isFirstDOMWinStuffDone = true;
  587.  
  588.     if (this.checkKeywordURL) {
  589.       if (this.checkKeywordURL === "set") {
  590.         this._setKeywordUrl(true);
  591.       } else if (this.checkKeywordURL === "check") {
  592.         this._checkKeywordUrl();
  593.       }
  594.       
  595.       this.checkKeywordURL = null;
  596.     }
  597.     
  598.     if (typeof(gYaSearchPlugin) === "object" && "checkSearchPluginInstall" in gYaSearchPlugin)
  599.       gYaSearchPlugin.checkSearchPluginInstall();
  600.   },
  601.   
  602.   onSessionstoreWindowsRestored: function() {
  603.     if (!this._inited)
  604.       return;
  605.     
  606.     if (this.showLocalWelcomePage) {
  607.       this.showLocalWelcomePage = false;
  608.       new G_Timer(function(){
  609.         gYaSearchService.loadURI("chrome://yasearch/locale/first-start/welcome.html", "tab");
  610.       }, 500);
  611.     }
  612.     
  613.     if (this.isLogin && this.isCountersAutoUpdateEnabled)
  614.       this.refreshHTTPData("mailAndFeeds");
  615.   },
  616.   
  617.   /**--------------------------------------------------------------------------------------------------**/
  618.   init: function() {
  619.     this.debug = this.getBoolPref("yasearch.general.debug.enabled");
  620.     
  621.     if (!this.getBoolPref("yasearch.license.accepted")) {
  622.       if (!this.getBoolPref("yasearch.license.show")) {
  623.         this.setBoolPref("yasearch.license.accepted", true);
  624.       } else {
  625.         try {
  626.           let setupWin = this.windowWatcher.openWindow(null, "chrome://yasearch/content/first-start/wizard.xul",
  627.                                                        null, "centerscreen,modal", null);
  628.           
  629.           if (!this.getBoolPref("yasearch.license.accepted")) {
  630.             let refuseWin = this.windowWatcher.openWindow(null, "chrome://yasearch/content/first-start/license-refuse.xul",
  631.                                                           null, "centerscreen,modal", null);
  632.             Cc["@mozilla.org/extensions/manager;1"].getService(Ci.nsIExtensionManager).disableItem(EXT_ID);
  633.             return;//this._inited = false;
  634.           }
  635.           
  636.         } catch(e) {
  637.           this.log(e);
  638.           return;
  639.         }
  640.       }  
  641.       
  642.       this.resetPref("yasearch.license.hidden");
  643.       
  644.       // persist accepted pref: don't show dialog if fx crash
  645.       try {
  646.         let prefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
  647.         prefService.savePrefFile(null);
  648.       } catch(e) {
  649.         this.log(e);
  650.       }
  651.     }
  652.     
  653.     this._inited = true;
  654.     
  655.     ["cookie-changed",
  656.      "http-on-modify-request",
  657.      "http-on-examine-response"]
  658.     .forEach(function(aTopicName) {
  659.       OBSERVER_SERVICE.addObserver(this, aTopicName, true);
  660.     }, this);
  661.     
  662.     if (typeof(gYaStorage) === "object" && "init" in gYaStorage)
  663.       gYaStorage.init();
  664.     
  665.     if (typeof(gYaInstaller) === "object" && "init" in gYaInstaller)
  666.       gYaInstaller.init();
  667.     
  668.     if (typeof(gYaOverlay) === "object" && "init" in gYaOverlay)
  669.       gYaOverlay.init();
  670.     
  671.     if (null === this.getBoolPref("yasearch.mail.ui.notification.enabled")) {
  672.       let showNotificationsByDefault = !this.isYaOnlineInstalled;
  673.       this.setBoolPref("yasearch.mail.ui.notification.enabled",  showNotificationsByDefault);
  674.       this.setBoolPref("yasearch.feeds.ui.notification.enabled", showNotificationsByDefault);
  675.     }
  676.  
  677.     this.checkTimeOut._MailAndFeeds = this.isCountersAutoUpdateEnabled ?
  678.                                           (this.getIntPref("yasearch.http.update.interval") * MIN_SEC || 0) : 0;
  679.     
  680.     this.appendUserSessionData("data");
  681.  
  682.     this.checkAuthOnStart();
  683.  
  684.     this.hackKnownSkins();
  685.   },
  686.  
  687.   get buttonsInfo() {
  688.     let enumerator = this.windowMediator.getEnumerator("navigator:browser");
  689.     if (enumerator.hasMoreElements()) {
  690.       try {
  691.         let browser = enumerator.getNext();
  692.         return browser.Ya.buttonsObject;
  693.       } catch(e) {}
  694.     }
  695.     return null;
  696.   },
  697.  
  698.   loginProcessData: {},
  699.  
  700.   initLoginProcess: function(aName, aPassword, aTwoWeeks, aManualLogin) {
  701.     if (!aName || !aPassword)
  702.       return false;
  703.  
  704.     this.loginState = this.LOGIN_STATES.REQUEST;
  705.  
  706.     this.loginProcessData = {
  707.       username: aName,
  708.       password: aPassword,
  709.       twoWeeks: aTwoWeeks,
  710.       manualLogin: aManualLogin
  711.     };
  712.  
  713.     if (!this.yaRootDomain)
  714.       this.getAuthStaticData(this.__initLoginProcess.bind(this));
  715.     else
  716.       this.__initLoginProcess();
  717.   },
  718.  
  719.   __initLoginProcess: function() {
  720.     if (!this.yaRootDomain)
  721.       this.loginState = this.LOGIN_STATES.NET_ERROR;
  722.     else
  723.       this.startLoginConnection();
  724.   },
  725.  
  726.   LOGIN_STATES: {
  727.     NO_AUTH: 0,
  728.     ERROR: 1,
  729.     CAPTCHA_ERROR: 2,
  730.     NET_ERROR: 3,
  731.     REQUEST: 4,
  732.     AUTH: 5
  733.   },
  734.  
  735.   _loginState: 0,
  736.  
  737.   get loginState() {
  738.     return this._loginState;
  739.   },
  740.  
  741.   set loginState(val) {
  742.     let newLoginStateValue = parseInt(val, 10);
  743.     
  744.     if (this._loginState !== newLoginStateValue) {
  745.       if (newLoginStateValue < this.LOGIN_STATES.NO_AUTH || newLoginStateValue > this.LOGIN_STATES.AUTH) {
  746.         this.log("loginState: bad value (" + val + ")");
  747.         return this._loginState;
  748.       }
  749.       
  750.       this._loginState = newLoginStateValue;
  751.       
  752.       OBSERVER_SERVICE.notifyObservers(null, "Ya-Login-State-Changed", false);
  753.       
  754.       switch (newLoginStateValue) {
  755.         case this.LOGIN_STATES.AUTH:
  756.         case this.LOGIN_STATES.NO_AUTH:
  757.           OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Login-Status", false);
  758.           break;
  759.         
  760.         default:
  761.           break;
  762.       }
  763.     }
  764.  
  765.     return this._loginState;
  766.   },
  767.  
  768.   talkToServer: function (aURL, aPostData, aCookieData, aReferrer, aCallbackFunc) {
  769.     var uri = this.makeURI(aURL);
  770.  
  771.     var uploadStream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
  772.     if (aPostData)
  773.       uploadStream.setData(aPostData, aPostData.length);
  774.  
  775.     var channel = IO_SERVICE.newChannelFromURI(uri);
  776.  
  777.     this._loginChannel = channel;
  778.  
  779.     var httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
  780.  
  781.     if (aReferrer) {
  782.       var referrerUri = this.makeURI(aReferrer);
  783.       httpChannel.referrer = referrerUri;
  784.     }
  785.  
  786.     if (aPostData) {
  787.       var uploadChannel = channel.QueryInterface(Ci.nsIUploadChannel);
  788.       uploadChannel.setUploadStream(uploadStream, "application/x-www-form-urlencoded", -1);
  789.       httpChannel.requestMethod = "POST";
  790.     }
  791.  
  792.     if (aCookieData)
  793.       for (var run = 0; run < aCookieData.length; run++)
  794.         httpChannel.setRequestHeader("Cookie", aCookieData[run], true);
  795.  
  796.     var observer = new this.observer(aCallbackFunc);
  797.     channel.notificationCallbacks = observer;
  798.     channel.asyncOpen(observer, null);
  799.   },
  800.  
  801.   observer: function(aCallbackFunc) {
  802.     return ({
  803.       data: "",
  804.  
  805.       onStartRequest: function (aRequest, aContext) {
  806.         this.data = "";
  807.       },
  808.  
  809.       onDataAvailable: function (aRequest, aContext, aStream, aSourceOffset, aLength) {
  810.         var scriptableInputStream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream);
  811.         scriptableInputStream.init(aStream);
  812.         this.data += scriptableInputStream.read(aLength);
  813.       },
  814.  
  815.       onStopRequest: function (aRequest, aContext, aStatus) {
  816.         aCallbackFunc({"data": this.data, "request": aRequest});
  817.       },
  818.  
  819.       onStatus: function(aRequest, aContext, aStatus, aStatusArg) {},
  820.       onProgress: function(aRequest, aContext, aProgress, aProgressMax) {},
  821.       onChannelRedirect: function (aOldChannel, aNewChannel, aFlags) {},
  822.       onRedirect : function (aOldChannel, aNewChannel) {},
  823.  
  824.       getAuthPrompt: function(aPromptReason, iid) {
  825.         var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher);
  826.         return ww.getNewAuthPrompter(null);
  827.       },
  828.  
  829.       interfaces: [ Ci.nsISupports,
  830.                     Ci.nsIStreamListener,
  831.                     Ci.nsISupportsWeakReference,
  832.                     Ci.nsIPrompt,
  833.                     Ci.nsIAuthPrompt,
  834.                     Ci.nsIAuthPromptProvider,
  835.                     Ci.nsIProgressEventSink,
  836.                     Ci.nsIInterfaceRequestor,
  837.                     Ci.nsIChannelEventSink,
  838.                     Ci.nsIHttpEventSink,
  839.                     Ci.nsIWebProgress ],
  840.  
  841.       QueryInterface: function(iid) {
  842.         if (!this.interfaces.some( function(v) { return iid.equals(v) } ))
  843.           throw Cr.NS_ERROR_NO_INTERFACE;
  844.  
  845.         if (iid.equals(Ci.nsIPrompt)) {
  846.           var prompt = Cc["@mozilla.org/network/default-prompt;1"].createInstance();
  847.           return prompt.QueryInterface(iid);
  848.         }
  849.  
  850.         if (iid.equals(Ci.nsIAuthPrompt)) {
  851.           var prompt = Cc["@mozilla.org/network/default-auth-prompt;1"].createInstance();
  852.           return prompt.QueryInterface(iid);
  853.         }
  854.  
  855.         return this;
  856.       },
  857.  
  858.       getInterface: function(iid) {
  859.         try {
  860.           return this.QueryInterface(iid);
  861.         } catch(e) {
  862.           return null;
  863.         }
  864.       }
  865.     });
  866.   },
  867.  
  868.   _logoutRequest: null,
  869.  
  870.   cancelLogoutConnection: function() {
  871.     if (this._logoutRequest && this._logoutRequest.channel && this._logoutRequest.channel.isPending())
  872.       this._logoutRequest.channel.cancel(Cr.NS_BINDING_ABORTED);
  873.  
  874.     this._logoutRequest = null;
  875.   },
  876.  
  877.   startLogoutConnection: function() {
  878.     this.cancelLogoutConnection();
  879.  
  880.     var url = "https://passport.yandex.ru/passport?mode=logout&target=bar" +
  881.               "&yu=" + encodeURIComponent(this.getYandexCookie("yandexuid", false) || "");
  882.  
  883.     this._logoutRequest = this.xmlHttpRequest(url, {callbackFunc: this.startLogoutConnectionCallback.bind(this)});
  884.   },
  885.  
  886.   startLogoutConnectionCallback: function(aReq) {
  887.     if (this.isReqError(aReq)) {
  888.       this.manageCookies(false, "logout");
  889.       this.cancelLogoutConnection();
  890.     } else {
  891.       this._logoutRequest = this.getAuthDinamicData("logout");
  892.     }
  893.   },
  894.  
  895.   startLoginConnection: function() {
  896.     this.cancelLogoutConnection();
  897.  
  898.     var data = "login=" + encodeURIComponent(this.loginProcessData.username)
  899.              + "&passwd=" + encodeURIComponent(this.loginProcessData.password)
  900.              + "&retpath=https%3A%2F%2Fpassport.yandex.ru%2Fpassport%3Fmode%3Dpassport%26target%3Dbar"
  901.              + "×tamp=" + G_TIME_NOW;
  902.  
  903.     if (this.loginProcessData.twoWeeks)
  904.       data += "&twoweeks=yes";
  905.  
  906.     this._sessionId = false;
  907.  
  908.     this.talkToServer("https://passport.yandex.ru/passport?mode=auth&target=bar",
  909.                       data, null, "https://passport.yandex.ru/passport?mode=passport&target=bar",
  910.                       this.talkCallback.bind(this));
  911.   },
  912.  
  913.   talkCallback: function(aData) {
  914.     var aRequest = aData.request,
  915.         status = null,
  916.         warningText = "";
  917.  
  918.     try {
  919.       aRequest.QueryInterface(Ci.nsIHttpChannel);
  920.       status = aRequest.responseStatus;
  921.       warningText = aRequest.getResponseHeader("Warning");
  922.     } catch(e) {}
  923.  
  924.     if (!status || (status != 200 && status != 302)) {
  925.       if (!this.loginProcessData.manualLogin)
  926.         this.setTimer("_Login");
  927.  
  928.       this.loginState = this.LOGIN_STATES.NET_ERROR;
  929.     } else if (!this.isLogin) {
  930.       this._loginFailCounter++;
  931.       this.clearAllTimers();
  932.  
  933.       if (/showcaptcha/.test(warningText)) {
  934.         this._loginFailCounter += 3;
  935.         this.loginState = this.LOGIN_STATES.CAPTCHA_ERROR;
  936.       } else {
  937.         this.loginState = this.LOGIN_STATES.ERROR;
  938.       }
  939.  
  940.       this.loginProcessData = {};
  941.       //this.loginProcessData.manualLogin = false;
  942.     }
  943.   },
  944.  
  945.   _loginFailCounter: 0,
  946.  
  947.   get loginFail() {
  948.     return (this._loginFailCounter >= 3);
  949.   },
  950.  
  951.   _sessionId: false,
  952.   _sessionLogin: false,
  953.  
  954.   set session(aData) {
  955.     if (aData.name == "Id")
  956.       aData.val = this.checkSessionCookieValue(aData.val);
  957.  
  958.     if (this.username && aData.name == "Login" && aData.val && aData.val.replace(/\./g, "-") !== this.username && this._sessionId)
  959.       aData.val = false;
  960.  
  961.     this["_session" + aData.name] = aData.val;
  962.  
  963.     if (!aData.val) {
  964.       this.fireAfterLogOut();
  965.     } else {
  966.       if (this._sessionId && this._sessionLogin)
  967.         this.fireAfterLogIn();
  968.     }
  969.   },
  970.  
  971.   get session() {
  972.     return {id: this._sessionId, login: this._sessionLogin};
  973.   },
  974.  
  975.   _username: false,
  976.   
  977.   get username() {
  978.     return this._username;
  979.   },
  980.  
  981.   set username(val) {
  982.     if (!val || val == "")
  983.       val = false;
  984.  
  985.     this._username = val;
  986.  
  987.     if (val && "undefined" == typeof this.usersData[val])
  988.       this.usersData[val] = {};
  989.  
  990.     return val;
  991.   },
  992.  
  993.   fireAfterLogIn: function() {
  994.     if (this.isLogin)
  995.       return;
  996.  
  997.     this._loginFailCounter = 0;
  998.  
  999.     this.isLogin = true;
  1000.  
  1001.     if (this._loginChannel) {
  1002.       this._loginChannel.cancel(true);
  1003.       this._loginChannel = null;
  1004.     }
  1005.     
  1006.     let loginProcessData = this.loginProcessData;
  1007.     if (loginProcessData.manualLogin) {
  1008.       this.passwordManager.storeLoginDetails(loginProcessData.username,
  1009.                                              loginProcessData.password,
  1010.                                              loginProcessData.twoWeeks);
  1011.     }
  1012.  
  1013.     this.username = this.session.login.replace(/\./g, "-");
  1014.  
  1015.     this.clearAllTimers();
  1016.  
  1017.     this.loginState = this.LOGIN_STATES.AUTH;
  1018.  
  1019.     if (this.isCountersAutoUpdateEnabled)
  1020.       this.refreshHTTPData("mailAndFeeds");
  1021.  
  1022.     if (this.bookmarksIsOutOfDate)
  1023.       this.refreshHTTPData("bookmarks");
  1024.  
  1025.     if (this.loginProcessData.username)
  1026.       this.getAuthDinamicData("login");
  1027.  
  1028.     if (this.yaAuthStaticData.needRefresh)
  1029.       this.getAuthStaticData();
  1030.  
  1031.     this.loginProcessData = {};
  1032.   },
  1033.  
  1034.   fireAfterLogOut: function(aClearCookies, aForgetLogin) {
  1035.     if (!this.isLogin)
  1036.       return;
  1037.  
  1038.     this.loginProcessData = {};
  1039.  
  1040.     this.isLogin = false;
  1041.  
  1042.     if (aForgetLogin)
  1043.       this.passwordManager.removeUserData(this.username);
  1044.  
  1045.     if (aClearCookies)
  1046.       new G_Timer(function() { gYaSearchService.startLogoutConnection(); }, 0);
  1047.  
  1048.     this.username = false;
  1049.  
  1050.     this.session = { name: "Login", val: false };
  1051.  
  1052.     this.clearAllTimers();
  1053.  
  1054.     let enumerator = this.windowMediator.getEnumerator("Yasearch:AddDialog");
  1055.     if (enumerator.hasMoreElements()) {
  1056.       while (enumerator.hasMoreElements())
  1057.         enumerator.getNext().document.documentElement.cancelDialog();
  1058.     }
  1059.  
  1060.     this.loginState = this.LOGIN_STATES.NO_AUTH;
  1061.   },
  1062.  
  1063.   clearAllTimers: function() {
  1064.     this.clearTimer("_Login");
  1065.     this.clearTimer("_MailAndFeeds");
  1066.     this.clearTimer("_Bookmarks");
  1067.  
  1068.     this.setNotifyTimer("cancel");
  1069.   },
  1070.  
  1071.   clearTimer: function(type) {
  1072.     if (type && this.updateTimer[type]) {
  1073.       this.updateTimer[type].cancel();
  1074.       this.updateTimer[type] = null;
  1075.     }
  1076.   },
  1077.  
  1078.   setTimer: function(type, aTimeout) {
  1079.     if (!type)
  1080.       throw "nsIYaSearch::setTimer -- no type";
  1081.  
  1082.     aTimeout = aTimeout || this.checkTimeOut[type] || 0;
  1083.  
  1084.     if (this.updateTimer[type])
  1085.       this.updateTimer[type].cancel();
  1086.     else
  1087.       this.updateTimer[type] = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  1088.  
  1089.     if (aTimeout > 0)
  1090.       this.updateTimer[type].initWithCallback(this[type], aTimeout, Ci.nsITimer.TYPE_ONE_SHOT);
  1091.   },
  1092.  
  1093.   _Login: {
  1094.     notify: function(aTimer) {
  1095.       gYaSearchService.startLoginConnection();
  1096.     }
  1097.   },
  1098.  
  1099.   _MailAndFeeds: {
  1100.     notify: function(aTimer) {
  1101.       gYaSearchService.refreshHTTPData("mailAndFeeds");
  1102.     }
  1103.   },
  1104.  
  1105.   _Bookmarks: {
  1106.     notify: function(aTimer) {
  1107.       gYaSearchService.refreshHTTPData("bookmarks");
  1108.     }
  1109.   },
  1110.  
  1111.   _Guid: {
  1112.     notify: function(aTimer) {
  1113.       gYaSearchService.refreshHTTPData("guid");
  1114.     }
  1115.   },
  1116.  
  1117.   _GuidRefresh: {
  1118.     notify: function(aTimer) {
  1119.       gYaSearchService.clearTimer("_GuidRefresh");
  1120.     }
  1121.   },
  1122.  
  1123.   HTTPDataRequests: {
  1124.     _data: {},
  1125.  
  1126.     add: function(aURL, aType, aRequest) {
  1127.       this._data[aURL] = {
  1128.         requestSimpleURL: aURL,
  1129.  
  1130.         request: aRequest,
  1131.         requestTime: G_TIME_NOW,
  1132.         
  1133.         isRequestPending: function() {
  1134.           return !!(this.request && this.request.channel.isPending());
  1135.         },
  1136.         
  1137.         cancelRequest: function() {
  1138.           this.request.channel.cancel(Cr.NS_BINDING_ABORTED);
  1139.         },
  1140.  
  1141.         responseTime: 0,
  1142.         responseIsOK: null,
  1143.  
  1144.         types: {}
  1145.       }
  1146.  
  1147.       this._data[aURL].types[aType] = true;
  1148.     },
  1149.  
  1150.     removeRequest: function(aRequest) {
  1151.       for each (var data in this._data) {
  1152.         if (data.request === aRequest) {
  1153.           data.request = null;
  1154.           return data;
  1155.         }
  1156.       }
  1157.     },
  1158.  
  1159.     canResendRequest: function(aURL, aType) {
  1160.       if (aType == "allServices")
  1161.         return true;
  1162.  
  1163.       let data = this._data[aURL];
  1164.  
  1165.       if (data) {
  1166.         let requestTimeDelta = Math.abs(G_TIME_NOW - data.requestTime);
  1167.  
  1168.         if (data.isRequestPending()) {
  1169.           if (requestTimeDelta > 30000) {
  1170.             data.cancelRequest();
  1171.             return true;
  1172.           }
  1173.  
  1174.           data.types[aType] = true;
  1175.           return false;
  1176.         }
  1177.  
  1178.         let responseTimeDelta = Math.abs(G_TIME_NOW - data.responseTime);
  1179.  
  1180.         if (data.types[aType] && (requestTimeDelta < 1000 || (data.responseIsOK && responseTimeDelta < 5000)))
  1181.           return false;
  1182.  
  1183.         data.responseIsOK = null;
  1184.         data.responseTime = 0;
  1185.       }
  1186.  
  1187.       return true;
  1188.     },
  1189.  
  1190.     processDataFromCache: function(aURL, aType, aData) {
  1191.       if (aData && aData.forceRequest) {// doom cached
  1192.         G_CacheWrapper.writeData(aURL, null);
  1193.         return false;
  1194.       }
  1195.       
  1196.       let lastDataFromCache = G_CacheWrapper.readData(aURL);
  1197.       
  1198.       if (lastDataFromCache) {
  1199.         gYaSearchService.processHTTPDataResponse(lastDataFromCache, aType, aData);
  1200.         return true;
  1201.       }
  1202.       
  1203.       return false;
  1204.     }
  1205.   },
  1206.  
  1207.   manualRefreshHTTPData: function(aType, aData, aCallerElementId) {
  1208.     if (!aData)
  1209.       aData = {};
  1210.  
  1211.     aData.manual = true;
  1212.     aData.callerElementId = aCallerElementId || ("yasearch-" + aType);
  1213.  
  1214.     this.refreshHTTPData(aType, aData);
  1215.   },
  1216.  
  1217.   refreshHTTPData: function(aType, aData, aDelay) {
  1218.     if (!aData)
  1219.       aData = {};
  1220.  
  1221.     //[2do] isAnyVisibleAuthElement
  1222.     
  1223.     new G_Timer(
  1224.       function() {
  1225.         gYaSearchService.__refreshHTTPData(aType, aData);
  1226.       }, aDelay || 10
  1227.     )
  1228.   },
  1229.  
  1230.   __refreshHTTPData: function(aType, aData) {
  1231.     if (!aType || typeof(aType) != "string")
  1232.       throw "No type given in refreshHTTPData";
  1233.  
  1234.     var url,
  1235.         appendTimestamp = false;
  1236.  
  1237.     aData.isCounters = false;
  1238.  
  1239.     switch (aType) {
  1240.       case "allServices":
  1241.         url = this.Counters.getURLForSID("allServices");
  1242.  
  1243.         if (!url)
  1244.           return;
  1245.  
  1246.         aData.isCounters = true;
  1247.  
  1248.         appendTimestamp = true;
  1249.  
  1250.         break;
  1251.  
  1252.       case "mailAndFeeds":
  1253.         this.setTimer("_MailAndFeeds");
  1254.  
  1255.         url = this.Counters.getURLForSID("allCounters");
  1256.  
  1257.         if (!url)
  1258.           return;
  1259.  
  1260.         aData.isCounters = true;
  1261.  
  1262.         break;
  1263.  
  1264.       case "mail":
  1265.       case "lenta":
  1266.       case "money":
  1267.       case "fotki":
  1268.       case "yaru":
  1269.       case "moikrug":
  1270.         url = this.Counters.getURLForSID([aType]);
  1271.  
  1272.         if (!url)
  1273.           return;
  1274.  
  1275.         aData.isCounters = true;
  1276.  
  1277.         break;
  1278.  
  1279.       case "mailList":
  1280.         url = "http://mail.yandex.ru/api/barlist";
  1281.         break;
  1282.  
  1283.       case "bookmarks":
  1284.         url = "http://zakladki.yandex.ru/bar/index.xml?newdescr=true";
  1285.         appendTimestamp = true;
  1286.  
  1287.         break;
  1288.  
  1289.       case "city":
  1290.         this.setTimer(aData.timerName);
  1291.  
  1292.         if (this.yaCity.canRequestDataForCity(aData) == false)
  1293.           return;
  1294.  
  1295.         url = "http://export.yandex.ru/bar/reginfo.xml"  + (aData.cityId == "" ? "" : "?region=" + aData.cityId);
  1296.  
  1297.         appendTimestamp = true;
  1298.  
  1299.         break;
  1300.  
  1301.       case "guid":
  1302.         url = this.generateGUIDStatusURL + this.generateGUIDData;
  1303.         break;
  1304.       
  1305.       default:
  1306.         break;
  1307.     }
  1308.  
  1309.     if (!url)
  1310.       throw new Error("Bad type given in refreshHTTPData");
  1311.  
  1312.     switch (aType) {
  1313.       case "city":
  1314.         if (this.HTTPDataRequests.processDataFromCache(url, aType, aData)) {
  1315.           if (aData && aData.manual) {
  1316.             this.notifyBusyStateOfRequest(aType, true, true, aData.callerElementId);
  1317.             this.notifyBusyStateOfRequest(aType, false, true, aData.callerElementId);
  1318.           }
  1319.           
  1320.           return;
  1321.         }
  1322.         
  1323.         break;
  1324.  
  1325.       default:
  1326.         break;
  1327.     }
  1328.  
  1329.     this.notifyBusyStateOfRequest(aType, true, !!(aData && aData.manual), aData.callerElementId);
  1330.  
  1331.     if (this.HTTPDataRequests.canResendRequest(url, aType)) {
  1332.       var fullUrl = url;
  1333.  
  1334.       if (appendTimestamp)
  1335.         fullUrl += (/\?/.test(fullUrl) ? "&":"?") + "ts=" + G_TIME_NOW;
  1336.  
  1337.       if (!!(aData && aData.manual))
  1338.         fullUrl = this.appendStatData2Url(fullUrl, {});
  1339.  
  1340.       this.HTTPDataRequests.add(url, aType, this.xmlHttpRequest(fullUrl,
  1341.                                                  {callbackFunc: this.refreshHTTPDataCallback.bind(this, aData)} ));
  1342.     } else {
  1343.       this.notifyBusyStateOfRequest(aType, false, !!(aData && aData.manual), aData.callerElementId);
  1344.     }
  1345.   },
  1346.  
  1347.   refreshHTTPDataCallback: function(aReq, aData) {
  1348.     var data = this.HTTPDataRequests.removeRequest(aReq.target);
  1349.  
  1350.     if (!data)
  1351.       return;
  1352.  
  1353.     data.responseTime = G_TIME_NOW;
  1354.  
  1355.     var aType = data.types;
  1356.  
  1357.     if (!aType)
  1358.       throw new Error("No type given in refreshHTTPDataCallback");
  1359.  
  1360.     var isCounters = aData.isCounters;
  1361.  
  1362.     if (this.isReqError(aReq)) {
  1363.       if ("guid" in aType) {
  1364.         this.clearTimer("_GuidRefresh");
  1365.       } else {
  1366.         var nextTime = this.getIntPref("yasearch.http.update.weathertraff.interval") * MIN_SEC || 0;
  1367.         var fiveMin = 5 * MIN_SEC;
  1368.         if (!nextTime || nextTime > fiveMin)
  1369.           nextTime = fiveMin;
  1370.  
  1371.         if ("city" in aType) {
  1372.           this.setTimer("_CityItemTimer" + aData.cityId, nextTime);
  1373.           this.yaCity._setData(aData.cityId);
  1374.         }
  1375.       }
  1376.  
  1377.       data.responseIsOK = false;
  1378.  
  1379.     } else {
  1380.       G_DateUtils.updateServerTimeValue(aReq);
  1381.  
  1382.       var text = this.safeUnicode(aReq.target.responseText);
  1383.  
  1384.       if (!("guid" in aType))
  1385.         this.checkNeedSendGuid();
  1386.  
  1387.       var noAuthError = false;
  1388.  
  1389.       if (isCounters) {
  1390.         var countersError = this.Counters.getCounterError(text);
  1391.         if (countersError && countersError.type == "noauth")
  1392.           noAuthError = true;
  1393.       }
  1394.  
  1395.       if (noAuthError) {
  1396.         data.responseIsOK = false;
  1397.         this.fireAfterLogOut();
  1398.         
  1399.       } else {
  1400.         data.responseIsOK = true;
  1401.  
  1402.         for (var typeStr in aType)
  1403.           this.processHTTPDataResponse(text, typeStr, aData);
  1404.       }
  1405.     }
  1406.  
  1407.     if (data.responseIsOK == false && ("allServices" in aType)) {
  1408.       this.Counters.setAllServicesError(true, true);
  1409.     }
  1410.  
  1411.     if (aData && aData.manual) {
  1412.       for (var typeStr in aType)
  1413.         this.notifyBusyStateOfRequest(typeStr, false, true, aData.callerElementId);
  1414.     }
  1415.  
  1416.     if ("city" in aType)
  1417.       G_CacheWrapper.writeData(data.requestSimpleURL, data.responseIsOK ? text : null);
  1418.   },
  1419.  
  1420.   notifyBusyStateOfRequest: function(aType, aState, aIsManualRequest, aCallerElementId) {
  1421.     if (aIsManualRequest)
  1422.       OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Busy-State", aState + ":" + aCallerElementId);
  1423.   },
  1424.  
  1425.   processHTTPDataResponse: function(aText, aTypeStr, aData) {
  1426.     var isManualRequest = !!(aData && aData.manual);
  1427.  
  1428.     switch (aTypeStr) {
  1429.       case "guid":
  1430.         this.timeGuid = true;
  1431.  
  1432.         OBSERVER_SERVICE.notifyObservers(null, "Ya-GUID-Response", "SENDED");
  1433.  
  1434.         var msg = new XML(this.xmlSerializer.serializeToString(this.domParser.parseFromString(aText.replace(/<\?xml .+\?>[\r\n]*/,"").replace(/(<\/page>)[\r\n]*$/, '$1'), "text/xml")));
  1435.         var showAlert = false, msgTime = msg.@time.toString(), version = msg.@version.toString();
  1436.  
  1437.         var output = { title: msg.title.toString(),
  1438.                         description: msg.description.toString(),
  1439.                         icon: msg.icon.toString() };
  1440.  
  1441.         if (version != "") {
  1442.           if (version > this.barExtensionVersion && Math.abs(this.guidUpdateDS - (G_TIME_NOW/DAY_SECS)) > 6) {
  1443.             msgTime = "error";
  1444.             showAlert = true;
  1445.           } else if (msgTime != "" && msgTime != this.guidMessageTS && msg.addDescription.toString() != "") {
  1446.             output = { title: msg.addTitle.toString(),
  1447.                        description: msg.addDescription.toString(),
  1448.                        icon: msg.addIcon.toString() };
  1449.             showAlert = true;
  1450.           }
  1451.         } else if (msgTime != "" && msgTime != this.guidMessageTS) {
  1452.           showAlert = true;
  1453.         }
  1454.  
  1455.         if (showAlert)
  1456.           this.showPermanentAlert(output.title, output.description, output.icon, msgTime);
  1457.  
  1458.         return;
  1459.  
  1460.       case "city":
  1461.         this.yaCity._setData(aData.cityId, aText.replace(/<\?xml .+\?>[\r\n]*/, ""), true);
  1462.         return;
  1463.  
  1464.       case "bookmarks":
  1465.         var bookmarksResponse = this.yaBookmarks.getServerResponse(aText);
  1466.         if (!bookmarksResponse.error)
  1467.           this.bookmarksDOMMenu = bookmarksResponse.xml;
  1468.         break;
  1469.  
  1470.       case "allServices":
  1471.         this.Counters.setDataFromJS(aText);
  1472.  
  1473.       case "mailAndFeeds":
  1474.         if (this.Counters.error) {
  1475.           if (aTypeStr == "mailAndFeeds")
  1476.             this.setTimer("_MailAndFeeds", this.Counters.errorTimeout);
  1477.           this.Counters.handleError();
  1478.         }
  1479.  
  1480.       case "yaru":
  1481.         this.Counters.setDataFromInbox("yaru", aText);
  1482.         if (aTypeStr == "yaru") break;
  1483.  
  1484.       case "fotki":
  1485.         this.Counters.setDataFromInbox("fotki", aText);
  1486.         if (aTypeStr == "fotki") break;
  1487.  
  1488.       case "money":
  1489.         this.Counters.setDataFromInbox("money", aText);
  1490.         if (aTypeStr == "money") break;
  1491.  
  1492.       case "lenta":
  1493.         this.Counters.setDataFromInbox("lenta", aText);
  1494.         if (aTypeStr == "lenta") break;
  1495.  
  1496.       case "moikrug":
  1497.         this.Counters.setDataFromInbox("moikrug", aText);
  1498.         if (aTypeStr == "moikrug") break;
  1499.  
  1500.       case "mail":
  1501.         this.Counters.setDataFromInbox("mail", aText);
  1502.         var mCount = this.Counters.getCount("mail");
  1503.  
  1504.         if (mCount && (mCount != this.mailCounter || (mCount > 0 && this.mailLastCheckIsOutOfDate))) {
  1505.           this.mailCounter = mCount;
  1506.           this.refreshHTTPData("mailList", aData);
  1507.         } else if (!mCount && mCount != this.mailCounter) {
  1508.           this.mailCounter = mCount;
  1509.           this.mailDOMMenuDoc = false;
  1510.           OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Data", "mailList");
  1511.         }
  1512.         break;
  1513.  
  1514.       case "mailList":
  1515.         this.mailLastCheckIsOutOfDate = false;
  1516.         
  1517.         var doc = null;
  1518.         try {
  1519.           doc = this.domParser.parseFromString(aText, "text/xml");
  1520.           if (!(doc instanceof Ci.nsIDOMDocument) ||
  1521.               !(doc.firstChild.localName == "yandexmenu" || doc.firstChild.localName == "auther"))
  1522.             doc = null;
  1523.         } catch(e) {}
  1524.         
  1525.         if (!doc)
  1526.           break;
  1527.         
  1528.         var authError = this.xPathEvaluator.evaluate("count(//error[@reason='not authenticated'])",
  1529.                                                      doc, null, Ci.nsIDOMXPathResult.NUMBER_TYPE, null);
  1530.         
  1531.         if (authError.numberValue) {
  1532.           this.fireAfterLogOut();
  1533.           return;
  1534.         }
  1535.         
  1536.         var items = this.xPathEvaluator.evaluate("//item/item", doc, null, this.orSnapshotType, null);
  1537.         var newMailCounter = 0,
  1538.             newMailLastMaxId = this.mailLastMaxId,
  1539.             newLastItem;
  1540.  
  1541.         var itemsLength = items.snapshotLength;
  1542.         if (itemsLength > 0 && itemsLength < this.maxUnreadInXML)
  1543.           this.mailCounter = itemsLength;
  1544.         
  1545.         var mailMessageURLPrefix = "http://" + this.getLocaleDependedUrl("MailHost") + "/message?ids=";
  1546.         
  1547.         var increaseNewMailCounter = true;
  1548.         for (var i = 0; i < itemsLength; i++) {
  1549.           let item = items.snapshotItem(i);
  1550.           let id = /\?mesid=(\d+)/.exec(item.getAttribute("url"))[1];
  1551.           
  1552.           item.setAttribute("url", mailMessageURLPrefix + id);
  1553.           
  1554.           if (!increaseNewMailCounter)
  1555.             continue;
  1556.           
  1557.           if (i == 0)
  1558.             this.mailLastMaxId = id;
  1559.           
  1560.           if (id > newMailLastMaxId) {
  1561.             newMailCounter++;
  1562.             newLastItem = newLastItem || item;
  1563.           } else {
  1564.             increaseNewMailCounter = false;
  1565.           }
  1566.         }
  1567.  
  1568.         this.mailDOMMenuDoc = doc;
  1569.  
  1570.         if (newMailCounter > 0) {
  1571.           if (newMailCounter == this.maxUnreadInXML) {
  1572.             let tmp = this.mailCounter - this.mailPermCounter;
  1573.             newMailCounter = tmp >= this.maxUnreadInXML ? tmp : 0;
  1574.           }
  1575.  
  1576.           this.notifyAboutNewItems(aTypeStr, newMailCounter,
  1577.                                     {from: newLastItem.getAttribute("from"),
  1578.                                      title: newLastItem.getAttribute("title")});
  1579.         }
  1580.  
  1581.         this.newMailCounter = newMailCounter;
  1582.         this.mailPermCounter = this.mailCounter;
  1583.         
  1584.         break;
  1585.     }
  1586.  
  1587.     OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Data", aTypeStr);
  1588.   },
  1589.   
  1590.   xmlHttpRequest: function(aUrl, aDetails) {
  1591.     var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
  1592.     
  1593.     //req.mozBackgroundRequest = true;
  1594.     req.open(aDetails.data ? "POST" : "GET", aUrl, true);
  1595.     //req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
  1596.     req.setRequestHeader("Cache-Control", "no-cache");
  1597.  
  1598.     if (aDetails.data) {
  1599.       req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
  1600.       req.setRequestHeader("Connection", "close");
  1601.     }
  1602.     
  1603.     var target = req.QueryInterface(Ci.nsIDOMEventTarget);
  1604.     if (aDetails.callbackFunc) {
  1605.       target.addEventListener("load", aDetails.callbackFunc, false);
  1606.       target.addEventListener("error", aDetails.callbackFunc, false);
  1607.     }
  1608.     
  1609.     req.send(aDetails.data || null);
  1610.     return req;
  1611.   },
  1612.  
  1613.   isReqError: function(aReq) {
  1614.     return !!(!aReq || aReq.type == "error" || !aReq.target || aReq.target.status != 200);
  1615.   },
  1616.   
  1617.   get Counters() {
  1618.     return gYaUServices;
  1619.   },
  1620.   
  1621.   get yaPartner() {
  1622.     return gYaPartner;
  1623.   },
  1624.  
  1625.   get yaCity() {
  1626.     return gYaCity;
  1627.   },
  1628.   
  1629.   get yaBookmarks() {
  1630.     return gYaBookmarks;
  1631.   },
  1632.   
  1633.   get yaOverlay() {
  1634.     return gYaOverlay;
  1635.   },
  1636.   
  1637.   get yaDefence() {
  1638.     return gYaDefence;
  1639.   },
  1640.  
  1641.   get yaFTab() {
  1642.     return gYaFTab;
  1643.   },
  1644.   
  1645.   get yaURLInfo() {
  1646.     return gYaURLInfo;
  1647.   },
  1648.   
  1649.   getFeedsGroups: function(aCallback) {
  1650.     this.xmlHttpRequest("http://lenta.yandex.ru/count.xml",
  1651.                          { callbackFunc: this.getFeedsGroupsCallback.bind(this, aCallback) });
  1652.   },
  1653.  
  1654.   getFeedsGroupsCallback: function(aReq, aCallback) {
  1655.     var mlist = false,
  1656.         doc = false;
  1657.  
  1658.     if (!this.isReqError(aReq))
  1659.       doc = aReq.target.responseXML;
  1660.  
  1661.     if (doc) {//"no auth" case
  1662.       var _doc = this.domParser.parseFromString("<empty/>", "text/xml");
  1663.       function createElement(aElementName) {
  1664.         return _doc.createElementNS(XULNS, aElementName);
  1665.       }
  1666.  
  1667.       var groups = doc.getElementsByTagName("group");
  1668.       var mpopup = createElement("menupopup");
  1669.  
  1670.       var last_group_id = this.feedsLastGroupId;
  1671.       var selected_item = 0;
  1672.  
  1673.       for (var i = 0; i < groups.length; i++) {
  1674.         var mi = createElement("menuitem");
  1675.         mi.setAttribute("label", groups.item(i).getAttribute("title"));
  1676.         
  1677.         var group_id = groups.item(i).getAttribute("id");
  1678.         if (group_id == last_group_id)
  1679.           selected_item = i;
  1680.         
  1681.         mi.setAttribute("group-id", group_id);
  1682.         mpopup.appendChild(mi);
  1683.       }
  1684.  
  1685.       mpopup.selectedIndex = selected_item;
  1686.  
  1687.       mlist = createElement("menulist");
  1688.  
  1689.       mlist.appendChild(mpopup);
  1690.       mlist.setAttribute("id", "yasearch-feeds-select-group");
  1691.  
  1692.       if (groups.length == 0) {
  1693.         mlist.setAttribute("disabled", "true");
  1694.         mpopup.appendChild(createElement("menuitem"));
  1695.       }
  1696.     }
  1697.  
  1698.     if (aCallback)
  1699.       aCallback(mlist);
  1700.   },
  1701.  
  1702.   get feedsCounter() {
  1703.     return this.isLogin ? (this.usersData[this.username]._feedsCounter || 0) : 0;
  1704.   },
  1705.  
  1706.   set feedsCounter(val) {
  1707.     if (this.isLogin)
  1708.       this.usersData[this.username]._feedsCounter = Math.max(val, 0);
  1709.   },
  1710.  
  1711.   get feedsLastGroupId() {
  1712.     return this.isLogin ? (this.usersData[this.username]._feedsLastGroupId || 0) : 0;
  1713.   },
  1714.  
  1715.   set feedsLastGroupId(val) {
  1716.     if (this.isLogin)
  1717.       this.usersData[this.username]._feedsLastGroupId = val;
  1718.   },
  1719.  
  1720.   feedsInsertNewItem: function(aData) {
  1721.     if (aData.group_id) {
  1722.       this.feedsLastGroupId = aData.group_id;
  1723.       this.xmlHttpRequest("http://lenta.yandex.ru/feed_add_url.xml",
  1724.                           { callbackFunc: this.feedsInsertNewItemCallback.bind(this, aData),
  1725.                             data: "url=" + encodeURIComponent(aData.url) + "&group_id=" +
  1726.                                   aData.group_id + "&ajax=1" });
  1727.     } else if (aData.title && aData.title != "") {
  1728.       this.xmlHttpRequest("http://lenta.yandex.ru/feed_add_group_bar.xml",
  1729.                           { callbackFunc: this.feedsInsertNewGroupCallback.bind(this, aData),
  1730.                             data: "title=" + encodeURIComponent(aData.title) + "&ajax=1" });
  1731.     }
  1732.   },
  1733.  
  1734.   feedsInsertNewGroupCallback: function(aReq, aData) {
  1735.     let error;
  1736.     
  1737.     if (this.isReqError(aReq)) {
  1738.       error = "errorNewGroup1";
  1739.     } else {
  1740.       let group_id;
  1741.       
  1742.       let pageXml = gYaSearchService.safeE4Xml(aReq.target.responseText, null, "page");
  1743.       if (pageXml)
  1744.         group_id = pageXml.status.added.@id.toString();
  1745.       
  1746.       if (group_id)
  1747.         aData.group_id = group_id;
  1748.       else
  1749.         error = "errorNewGroup2";
  1750.     }
  1751.  
  1752.     return error ? aData.callback(error) : this.feedsInsertNewItem(aData);
  1753.   },
  1754.  
  1755.   feedsInsertNewItemCallback: function(aReq, aData) {
  1756.     this.feedsLastGroupId = aData.group_id;
  1757.  
  1758.     var error;
  1759.  
  1760.     if (this.isReqError(aReq))
  1761.       error = "errorNewItem1";
  1762.     else if (aReq.target.responseText.indexOf("ok") != 0)
  1763.       error = "errorNewItem2";
  1764.  
  1765.     return aData.callback(error);
  1766.   },
  1767.  
  1768.   get moneyCounter() {
  1769.     return this.isLogin ? (this.usersData[this.username]._moneyCounter || 0) : 0;
  1770.   },
  1771.  
  1772.   set moneyCounter(val) {
  1773.     if (this.isLogin)
  1774.       this.usersData[this.username]._moneyCounter = Math.max(val, 0);
  1775.   },
  1776.  
  1777.   get guidMessageTS() {
  1778.     return this.isLogin && this.usersData[this.username]._guidLastMsgTs ?
  1779.                 this.usersData[this.username]._guidLastMsgTs :
  1780.                 (this.getCharPref("yasearch.guid.lastMsg") || "");
  1781.   },
  1782.  
  1783.   set guidMessageTS(val) {
  1784.     val = val.toString();
  1785.  
  1786.     if (this.isLogin)
  1787.       this.usersData[this.username]._guidLastMsgTs = val;
  1788.  
  1789.     this.setCharPref("yasearch.guid.lastMsg", val);
  1790.   },
  1791.  
  1792.   get guidUpdateDS() {
  1793.     return this.getIntPref("yasearch.guid.lastUpdate");
  1794.   },
  1795.  
  1796.   set guidUpdateDS(val) {
  1797.     val = val ? Math.abs(G_TIME_NOW/DAY_SECS) : 0;
  1798.     this.setIntPref("yasearch.guid.lastUpdate", val);
  1799.   },
  1800.  
  1801.   get mailCounter() {
  1802.     return this.isLogin ? (this.usersData[this.username]._mailCounter || 0) : 0;
  1803.   },
  1804.  
  1805.   set mailCounter(val) {
  1806.     if (this.isLogin)
  1807.       this.usersData[this.username]._mailCounter = Math.max(val, 0);
  1808.   },
  1809.  
  1810.   get newMailCounter() {
  1811.     return this.isLogin ? (this.usersData[this.username]._newMailCounter || 0) : 0;
  1812.   },
  1813.  
  1814.   set newMailCounter(val) {
  1815.     if (this.isLogin)
  1816.       this.usersData[this.username]._newMailCounter = Math.max(val, 0);
  1817.   },
  1818.  
  1819.   get mailPermCounter() {
  1820.     return this.isLogin ? (this.usersData[this.username]._mailPermCounter || 0) : 0;
  1821.   },
  1822.  
  1823.   set mailPermCounter(val) {
  1824.     if (this.isLogin)
  1825.       this.usersData[this.username]._mailPermCounter = Math.max(val, 0);
  1826.   },
  1827.  
  1828.   get mailDOMMenuDoc() {
  1829.     if (!this.isLogin || !this.usersData[this.username]._mailDOMMenuDoc)
  1830.       return false;
  1831.     
  1832.     return this.usersData[this.username]._mailDOMMenuDoc;
  1833.   },
  1834.  
  1835.   set mailDOMMenuDoc(doc) {
  1836.     if (this.isLogin)
  1837.       this.usersData[this.username]._mailDOMMenuDoc = doc;
  1838.   },
  1839.  
  1840.   get mailData() {
  1841.     return {"count": this.mailCounter,
  1842.              "permCount": this.mailPermCounter,
  1843.              "nodes": this.mailDOMMenuDoc ? this.getDOMDocContent("mail-items", this.mailDOMMenuDoc) : false,
  1844.              "lastmaxid": this.mailLastMaxId,
  1845.              "newCount": this.newMailCounter};
  1846.   },
  1847.  
  1848.   get mailLastMaxId() {
  1849.     if (!this.isLogin || !this.usersData[this.username]._mailLastMaxId)
  1850.       return "0";
  1851.  
  1852.     return this.usersData[this.username]._mailLastMaxId;
  1853.   },
  1854.  
  1855.   set mailLastMaxId(id) {
  1856.     if (this.isLogin)
  1857.       this.usersData[this.username]._mailLastMaxId = id.toString();
  1858.   },
  1859.  
  1860.   get mailLastCheckIsOutOfDate() {
  1861.     if (!this.isLogin)
  1862.       return false;
  1863.  
  1864.     let lastCheckTime = this.usersData[this.username]._mailLastCheckTime || 0;
  1865.  
  1866.     return Math.abs(lastCheckTime - G_TIME_NOW) > (30 * MIN_SEC);
  1867.   },
  1868.  
  1869.   set mailLastCheckIsOutOfDate(val) {
  1870.     if (this.isLogin)
  1871.       this.usersData[this.username]._mailLastCheckTime = val ? 0 : G_TIME_NOW;
  1872.   },
  1873.   
  1874.   bookmarksPrepeareDialog: function(aCallback) {
  1875.     this.xmlHttpRequest("http://zakladki.yandex.ru/bar/struct.xml?newdescr=true&" + getNCRndStr(),
  1876.                              { callbackFunc: this.bookmarksPrepeareDialogCallback.bind(this, aCallback) });
  1877.   },
  1878.  
  1879.   bookmarksPrepeareDialogCallback: function(aReq, aCallback) {
  1880.     var res;
  1881.  
  1882.     if (this.isReqError(aReq)) {
  1883.       res = "lost_connection";
  1884.     } else if (!this.isLogin) {
  1885.       res = "auth_required";
  1886.     } else {
  1887.       var bookmarksResponse = this.yaBookmarks.getServerResponse(aReq.target.responseText);
  1888.       if (bookmarksResponse.error && bookmarksResponse.error !== "reg_required") {
  1889.         res = bookmarksResponse.error;
  1890.       } else {
  1891.         var data = bookmarksResponse.error ? "<err/>" : bookmarksResponse.xml.toString();
  1892.         if (res = this.getDOMDocContent("bar-bookmarks-folders", this.domParser.parseFromString(data, "text/xml")))
  1893.           res.setAttribute("disabled", "true");
  1894.         else
  1895.           res = "service";
  1896.       }
  1897.     }
  1898.  
  1899.     if (aCallback)
  1900.       aCallback(res);
  1901.   },
  1902.   
  1903.   bookmarksGetItemById: function(aId) {
  1904.     let item = this.bookmarksRawXml.bookmarks..*.(function::attribute("id") == aId)[0];
  1905.     
  1906.     return {
  1907.       id:       item.@id.toString(),
  1908.       type:     item.localName().toString(),
  1909.       url:      item.@url.toString(),
  1910.       name:     item.@name.toString(),
  1911.       descr:    item.descr.toString(),
  1912.       tags:     item.@tags.toString(),
  1913.       parentId: item.@folder_id.toString() || item.@parent_id.toString()
  1914.     };
  1915.   },
  1916.   
  1917.   bookmarksEditItem: function(aItem) {
  1918.     if (!aItem.id)
  1919.       throw "bookmarksEditItem: no ID";
  1920.  
  1921.     if (aItem.nfolder != "") {
  1922.       var url = "http://zakladki.yandex.ru/bar/addfolder.xml?" + getNCRndStr();
  1923.       url = this.appendStatData2Url(url,{});
  1924.  
  1925.       var data = "name=" + encodeURIComponent(aItem.nfolder) + "&parent_id=" + aItem.folder;
  1926.  
  1927.       this.xmlHttpRequest(url, {data: data, callbackFunc: this.bookmarksInsertNewFolderInXML.bind(this, aItem)});
  1928.  
  1929.     } else {
  1930.  
  1931.       var old = aItem._old_info;
  1932.  
  1933.       aItem.tags = this.yaBookmarks.formatTagsString(aItem.tags);
  1934.  
  1935.       if (old.name != aItem.name || old.descr != aItem.descr || old.url != aItem.url || old.tags != aItem.tags) {
  1936.  
  1937.         var type = aItem.type;
  1938.  
  1939.         var url = "http://zakladki.yandex.ru/bar/update" + type + ".xml?" + getNCRndStr();
  1940.         url = this.appendStatData2Url(url,{});
  1941.  
  1942.         var data = type + "_id=" + aItem.id +
  1943.                     "&name="  + encodeURIComponent(aItem.name) +
  1944.                     "&descr=" + encodeURIComponent(aItem.descr) +
  1945.                     "&tags="  + encodeURIComponent(aItem.tags);
  1946.  
  1947.         if (type == "link")
  1948.           data += "&url=" + encodeURIComponent(aItem.url);
  1949.  
  1950.         this.xmlHttpRequest(url, { data: data, callbackFunc: this.bookmarksEditItemInXML.bind(this, aItem) });
  1951.  
  1952.       } else if (aItem.folderOld != aItem.folder) {
  1953.         this.bookmarksMoveItem(aItem);
  1954.  
  1955.       } else {
  1956.         return aItem.callback();
  1957.       }
  1958.     }
  1959.   },
  1960.  
  1961.   bookmarksEditItemInXML: function(aReq, aItem) {
  1962.     var res;
  1963.  
  1964.     if (this.isReqError(aReq)) {
  1965.       res = "lost_connection";
  1966.     } else if (!this.isLogin) {
  1967.       res = "auth_required";
  1968.     } else {
  1969.       var bookmarksResponse = this.yaBookmarks.getServerResponse(aReq.target.responseText);
  1970.       if (bookmarksResponse.error) {
  1971.         res = bookmarksResponse.error;
  1972.       } else {
  1973.         if (!bookmarksResponse.xml.ok.length()) {
  1974.           res = "service";
  1975.         } else {
  1976.           var bookmarks = this.usersData[this.username]._bookmarksRawXml.bookmarks;
  1977.           var elem = (aItem.type == "folder" ? bookmarks..folder : bookmarks..link).(@id == aItem.id)[0];
  1978.  
  1979.           elem.@name  = aItem.name;
  1980.           elem.@url   = aItem.url;
  1981.           elem.descr  = aItem.descr;
  1982.           elem.@tags  = this.yaBookmarks.formatTagsString(aItem.tags);
  1983.  
  1984.           this.yaBookmarks.refreshBookmarksDOMMenu();
  1985.  
  1986.           if (aItem.folderOld != aItem.folder) {
  1987.             this.bookmarksMoveItem(aItem);
  1988.             return;
  1989.           }
  1990.         }
  1991.       }
  1992.     }
  1993.  
  1994.     return aItem.callback(res);
  1995.   },
  1996.  
  1997.   bookmarksMoveItem: function(aItem) {
  1998.     if (!aItem.id)
  1999.       throw "bookmarksMoveItem: no ID";
  2000.  
  2001.     var url = "http://zakladki.yandex.ru/bar/move.xml?" + getNCRndStr();
  2002.     url = this.appendStatData2Url(url,{});
  2003.  
  2004.     var data =  "folder_id=" + aItem.folder + "&" + (aItem.type == "folder" ? "fid" : "link_id") + "=" + aItem.id;
  2005.  
  2006.     this.xmlHttpRequest(url, { data: data, callbackFunc: this.bookmarksMoveItemInXML.bind(this, aItem) });
  2007.   },
  2008.  
  2009.   bookmarksMoveItemInXML: function(aReq, aItem) {
  2010.     var res;
  2011.  
  2012.     if (this.isReqError(aReq)) {
  2013.       res = "lost_connection";
  2014.     } else if (!this.isLogin) {
  2015.       res = "auth_required";
  2016.     } else {
  2017.       var bookmarksResponse = this.yaBookmarks.getServerResponse(aReq.target.responseText);
  2018.       if (bookmarksResponse.error) {
  2019.         res = bookmarksResponse.error;
  2020.       } else {
  2021.         if (!bookmarksResponse.xml.ok.length()) {
  2022.           res = "service";
  2023.         } else {
  2024.           var bookmarks = this.usersData[this.username]._bookmarksRawXml.bookmarks;
  2025.           var elem = (aItem.type == "folder" ? bookmarks..folder : bookmarks..link).(@id == aItem.id);
  2026.  
  2027.           if (elem[0]) {
  2028.             var clone = new XML(elem[0]);
  2029.             var inFolder = bookmarks..folder.(@id == aItem.folder), inFolderId = inFolder.@id.toString();
  2030.             if (inFolder.@id.toString() == "") {
  2031.               inFolder = bookmarks;
  2032.               inFolderId = "0";
  2033.             }
  2034.  
  2035.             var type = aItem.type;
  2036.  
  2037.             switch (type) {
  2038.               case "folder":
  2039.                 clone.@parent_id = inFolderId;
  2040.  
  2041.                 var len = inFolder.folder.(@name < aItem.name).length()-1;
  2042.                 if (len == -1)
  2043.                   inFolder.folder = clone + inFolder.folder;
  2044.                 else
  2045.                  inFolder.folder[len] += clone;
  2046.                 break;
  2047.  
  2048.               case "link":
  2049.                 clone.@folder_id = inFolderId;
  2050.  
  2051.                 var len = inFolder.links.link.(@name < aItem.name).length()-1;
  2052.                 if (len == -1)
  2053.                   inFolder.links.link = clone + inFolder.links.link;
  2054.                 else
  2055.                   inFolder.links.link[len] += clone;
  2056.                 break;
  2057.             }
  2058.  
  2059.             delete elem[0];
  2060.           }
  2061.         }
  2062.       }
  2063.     }
  2064.  
  2065.     this.yaBookmarks.refreshBookmarksDOMMenu();
  2066.  
  2067.     return aItem.callback(res);
  2068.   },
  2069.  
  2070.   bookmarksDeleteItem: function(aItem) {
  2071.     if (!aItem.id)
  2072.       throw "bookmarksDeleteItem: no ID";
  2073.  
  2074.     var url = "http://zakladki.yandex.ru/bar/del.xml?" + getNCRndStr();
  2075.     url = this.appendStatData2Url(url, {});
  2076.  
  2077.     var data = (aItem.type == "folder" ? "fid" : "link_id") + "=" + encodeURIComponent(aItem.id);
  2078.  
  2079.     this.xmlHttpRequest(url, {data: data, callbackFunc: this.bookmarksDeleteItemInXML.bind(this, aItem)});
  2080.   },
  2081.  
  2082.   bookmarksDeleteItemInXML: function(aReq, aItem) {
  2083.     var res;
  2084.  
  2085.     if (this.isReqError(aReq)) {
  2086.       res = "lost_connection";
  2087.     } else if (!this.isLogin) {
  2088.       res = "auth_required";
  2089.     } else {
  2090.       var bookmarksResponse = this.yaBookmarks.getServerResponse(aReq.target.responseText);
  2091.       if (bookmarksResponse.error) {
  2092.         res = bookmarksResponse.error;
  2093.       } else {
  2094.         if (!bookmarksResponse.xml.ok.length()) {
  2095.           res = "service";
  2096.         } else {
  2097.           var bookmarks = this.usersData[this.username]._bookmarksRawXml.bookmarks;
  2098.           var elem = (aItem.type == "folder" ? bookmarks..folder : bookmarks..link).(@id == aItem.id);
  2099.  
  2100.           if (elem[0]) {
  2101.             delete elem[0];
  2102.  
  2103.             this.yaBookmarks.refreshBookmarksDOMMenu();
  2104.           }
  2105.         }
  2106.       }
  2107.     }
  2108.  
  2109.     return aItem.callback(res);
  2110.   },
  2111.  
  2112.   bookmarksSubscribeCallback: function(aReq, aItem) {
  2113.     this.bookmarksInsertNewItem(aItem);
  2114.   },
  2115.  
  2116.   bookmarksInsertNewItem: function(aItem) {
  2117.     if (this.yaBookmarks.isRegRequired) {
  2118.       this.yaBookmarks.isRegRequired = null;
  2119.       if (!this.yaBookmarks.isRegRequired) {
  2120.         this.xmlHttpRequest("http://passport.yandex.ru/passport?mode=subscribe&from=zakladki",
  2121.                              { callbackFunc: this.bookmarksSubscribeCallback.bind(this, aItem) });
  2122.         return;
  2123.       }
  2124.     }
  2125.  
  2126.     if (aItem.nfolder) {
  2127.       var url = "http://zakladki.yandex.ru/bar/addfolder.xml?" + getNCRndStr();
  2128.       url = this.appendStatData2Url(url, {});
  2129.  
  2130.       var data = "name=" + encodeURIComponent(aItem.nfolder) + "&parent_id=" + aItem.folder;
  2131.  
  2132.       this.xmlHttpRequest(url, {data: data, callbackFunc: this.bookmarksInsertNewFolderInXML.bind(this, aItem)});
  2133.  
  2134.     } else {
  2135.       var url = "http://zakladki.yandex.ru/bar/addlink.xml?" + getNCRndStr();
  2136.       url = this.appendStatData2Url(url, {});
  2137.  
  2138.       var yaruDataAppend = (aItem.yaru && ("feed_id" in aItem.yaru) && ("status" in aItem.yaru)) ?
  2139.                                ("&feed_id=" + encodeURIComponent(aItem.yaru.feed_id) +
  2140.                                 "&status=" + encodeURIComponent(aItem.yaru.status)) : "";
  2141.  
  2142.       var data = "name="        + encodeURIComponent(aItem.name)  +
  2143.                   "&url="        + encodeURIComponent(aItem.url)   +
  2144.                   "&descr="      + encodeURIComponent(aItem.descr) +
  2145.                   "&tags="       + encodeURIComponent(aItem.tags)  +
  2146.                   "&folder_id="  + (aItem.folder || 0) +
  2147.                   "&newfolder="  +
  2148.                   yaruDataAppend +
  2149.                   "&from=barff";
  2150.  
  2151.       this.xmlHttpRequest(url, {data: data, callbackFunc: this.bookmarksInsertNewLinkInXML.bind(this, aItem)});
  2152.     }
  2153.   },
  2154.  
  2155.   bookmarksInsertNewFolderInXML: function(aReq, aItem) {
  2156.     var res;
  2157.  
  2158.     if (this.isReqError(aReq)) {
  2159.       res = "lost_connection";
  2160.     } else if (!this.isLogin) {
  2161.       res = "auth_required";
  2162.     } else {
  2163.       var bookmarksResponse = this.yaBookmarks.getServerResponse(aReq.target.responseText);
  2164.       if (bookmarksResponse.error) {
  2165.         res = bookmarksResponse.error;
  2166.       } else {
  2167.         var newFolderId = bookmarksResponse.xml.ok[0].@id.toString();
  2168.         if (!newFolderId) {
  2169.           res = "service";
  2170.         } else {
  2171.           var bookmarks = this.usersData[this.username]._bookmarksRawXml.bookmarks;
  2172.           var elem = bookmarks..folder.(@id == aItem.folder);
  2173.           var parent = elem.@id.toString() == "" ? bookmarks : elem;
  2174.  
  2175.           var parentId = parent.@id.toString() == "" ? "0" : parent.@id.toString();
  2176.  
  2177.           if (bookmarks..folder.(@id == newFolderId).length() == 0) {
  2178.             var newItem = new XML('<folder id="' + newFolderId + '" parent_id="' + parentId + '"><links/></folder>');
  2179.             newItem.@name = aItem.nfolder;
  2180.  
  2181.             var len = parent.folder.(@name < aItem.nfolder).length()-1;
  2182.             if (len == -1)
  2183.               parent.folder = newItem + parent.folder;
  2184.             else
  2185.               parent.folder[len] += newItem;
  2186.  
  2187.             this.yaBookmarks.refreshBookmarksDOMMenu();
  2188.           }
  2189.  
  2190.           aItem.nfolder = "";
  2191.           aItem.folder = newFolderId;
  2192.  
  2193.           this.yaBookmarks.lastUsedFolder = newFolderId;
  2194.  
  2195.           if (aItem.folderOld) {
  2196.             this.bookmarksEditItem(aItem);
  2197.           } else {
  2198.             this.bookmarksInsertNewItem(aItem);
  2199.           }
  2200.         }
  2201.       }
  2202.     }
  2203.  
  2204.     if (res)
  2205.       return aItem.callback(res);
  2206.   },
  2207.  
  2208.   bookmarksInsertNewLinkInXML: function(aReq, aItem) {
  2209.     var res;
  2210.  
  2211.     if (this.isReqError(aReq)) {
  2212.       res = "lost_connection";
  2213.     } else if (!this.isLogin) {
  2214.       res = "auth_required";
  2215.     } else {
  2216.       var bookmarksResponse = this.yaBookmarks.getServerResponse(aReq.target.responseText);
  2217.       if (bookmarksResponse.error) {
  2218.         res = bookmarksResponse.error;
  2219.       } else {
  2220.         var newLinkId = bookmarksResponse.xml.ok[0].@id.toString();
  2221.         if (!newLinkId || newLinkId == "0") {
  2222.           res = "service";
  2223.         } else {
  2224.           if (bookmarksResponse.xml.ok[0].@yaru_link.toString()) {
  2225.             res = this.getDOMDocContent2("bookmarks/xsl-yaru-post-props.xsl",
  2226.                                           this.domParser.parseFromString(bookmarksResponse.xml.toSource(), "text/xml"));
  2227.           } else {
  2228.             res = null;
  2229.           }
  2230.  
  2231.           try {
  2232.             var _uri = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService).newURI(aItem.url, null, null);
  2233.  
  2234.             aItem.url = "hostPort" in _uri ?
  2235.                         [_uri.scheme, "://", (_uri.scheme == "file" ? "/" : ""), _uri.hostPort, _uri.path].join("") :
  2236.                         _uri.spec;
  2237.           } catch(e) {
  2238.             aItem.url = "http://" + aItem.url;
  2239.           }
  2240.  
  2241.           var bookmarks = this.usersData[this.username]._bookmarksRawXml.bookmarks;
  2242.           var elem = bookmarks..folder.(@id == aItem.folder);
  2243.           var parent = (elem.@id.toString() == "" ? bookmarks : elem).links;
  2244.  
  2245.           var duplicate = !!(bookmarksResponse.xml.ok[0].@duplicate.toString() > "");
  2246.           duplicate = duplicate && parent.link.(@id == newLinkId).length();
  2247.  
  2248.           if (!duplicate) {
  2249.             var newItem = new XML('<link id="' + newLinkId + '" folder_id="' + aItem.folder + '"/>');
  2250.             newItem.@name  = aItem.name;
  2251.             newItem.@url   = aItem.url;
  2252.             newItem.descr = aItem.descr;
  2253.             newItem.@tags  = aItem.tags;
  2254.  
  2255.             var len = parent.link.(@name < aItem.name).length()-1;
  2256.             if (len == -1)
  2257.               parent.link = newItem + parent.link;
  2258.             else
  2259.               parent.link[len] += newItem;
  2260.           }
  2261.  
  2262.           this.yaBookmarks.refreshBookmarksDOMMenu();
  2263.         }
  2264.       }
  2265.     }
  2266.  
  2267.     return aItem.callback(res);
  2268.   },
  2269.  
  2270.   get bookmarksDOMMenu() {
  2271.     if (!this.isLogin)
  2272.       return this.bookmarksDOMMenuDefault;
  2273.  
  2274.     if (!this.usersData[this.username].bookmarksDOMMenu)
  2275.       this.bookmarksDOMMenu = false;
  2276.  
  2277.     return this.usersData[this.username].bookmarksDOMMenu.cloneNode(true);
  2278.   },
  2279.  
  2280.   get bookmarksDOMMenuDefault() {
  2281.     if (!this._bookmarksDOMMenuDefault)
  2282.       this._bookmarksDOMMenuDefault = this.getDOMDocContent("bar-bookmarks",
  2283.                                       this.domParser.parseFromString("<page><bookmarks/></page>", "text/xml"));
  2284.     
  2285.     return this._bookmarksDOMMenuDefault.cloneNode(true);
  2286.   },
  2287.  
  2288.   set bookmarksDOMMenu(aBookmarksXML) {
  2289.     if (!this.isLogin)
  2290.       return false;
  2291.  
  2292.     this.usersData[this.username]._bookmarksRawXml = aBookmarksXML || this.bookmarksRawXml;
  2293.  
  2294.     if (aBookmarksXML)
  2295.       this.usersData[this.username]._bookmarksRawXml.@ts = G_TIME_NOW;
  2296.  
  2297.     this.usersData[this.username].bookmarksDOMMenu =
  2298.         this.getDOMDocContent2("xsl-templ/xsl-bar-bookmarks.xsl",
  2299.             this.domParser.parseFromString(this.usersData[this.username]._bookmarksRawXml, "text/xml"),
  2300.             { addToFolderOnTop: this.getBoolPref("yasearch.general.ui.bookmarks.showaddtofolderontop") });
  2301.  
  2302.     this.yaBookmarks.bookmarksCache.clear(true);//[2do]
  2303.   },
  2304.  
  2305.   get bookmarksRawXml() {
  2306.     return (this.isLogin && this.usersData[this.username]._bookmarksRawXml) ?
  2307.                     this.usersData[this.username]._bookmarksRawXml :
  2308.                     new XML("<page><bookmarks/></page>");
  2309.   },
  2310.  
  2311.   bookmarksGetLinksInFolder: function(aFolderId) {
  2312.     let urlArray = [];
  2313.     let folder = aFolderId ? this.bookmarksRawXml.bookmarks..folder.(@id == aFolderId) : this.bookmarksRawXml.bookmarks;
  2314.     
  2315.     for each (var link in folder.links.link)
  2316.       urlArray.push(link.@url.toString());
  2317.  
  2318.     return urlArray;
  2319.   },
  2320.  
  2321.   get bookmarksIsOutOfDate() {
  2322.     if (this.isLogin && !this.usersData[this.username]._bookmarksRawXml)
  2323.       return true;
  2324.  
  2325.     let lastCheckTime = this.parseIntFromStr(this.bookmarksRawXml.@ts);
  2326.     return !!(lastCheckTime && (Math.abs(G_TIME_NOW - lastCheckTime) > DAY_SECS))
  2327.   },
  2328.  
  2329.   setNotifyTimer: function(cancel) {
  2330.     if (!this._notifyTimer) {
  2331.       this._notifyTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  2332.       this._notifyTimer.initWithCallback(this, 1000, Ci.nsITimer.TYPE_REPEATING_SLACK);
  2333.     } else if (cancel) {
  2334.       this._runnedNotifications = [];
  2335.       this._notifyTimer.cancel();
  2336.       this._notifyTimer = null;
  2337.     }
  2338.   },
  2339.  
  2340.   notify: function(aTimer) {
  2341.     if (!this._runnedNotifications || this._runnedNotifications.length < 1)
  2342.       return this.setNotifyTimer("cancel");
  2343.  
  2344.     var notif = this._runnedNotifications[0];
  2345.     if (notif.isShowing == true)
  2346.       return;
  2347.  
  2348.     if (this.getBoolPref("yasearch." + notif.type + ".ui.notification.enabled")) {
  2349.       notif.isShowing = true;
  2350.  
  2351.       var msg = [(notif.type == "mail" && notif.nmb == 0) ?
  2352.                    this.getFormattedString("mailNotificationMsgPlus", [this.maxUnreadInXML]) :
  2353.                    this.getFormattedStringL18End(notif.type + "NotificationMsg", [notif.nmb])];
  2354.  
  2355.       if (notif.type == "mail") {
  2356.         if (notif.nmb != 1)
  2357.           msg[0] += this.getString("mailNotificationMsgLast");
  2358.  
  2359.         msg.push([notif.mdata.from, notif.mdata.title]);
  2360.       }
  2361.  
  2362.       this.showAlert(this.getString(notif.type + "NotificationTitle"), msg, notif.type);
  2363.     } else {
  2364.       this._runnedNotifications.shift();
  2365.     }
  2366.  
  2367.     if (this.getBoolPref("yasearch." + notif.type + ".ui.soundnotification.enabled"))
  2368.       this.playSoundURL(this.getComplexValue("yasearch." + notif.type + ".ui.soundnotification.uri"));
  2369.   },
  2370.  
  2371.   playSoundURL: function(aSoundUrl) {
  2372.     if (!aSoundUrl || !aSoundUrl.length)
  2373.       return;
  2374.  
  2375.     var uri;
  2376.  
  2377.     try {
  2378.       if (aSoundUrl.indexOf("file://") == -1) {
  2379.         var tempLocalFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
  2380.         tempLocalFile.initWithPath(aSoundUrl);
  2381.         uri = this.makeFileURI(tempLocalFile);
  2382.       } else {
  2383.         uri = this.makeURI(aSoundUrl);
  2384.       }
  2385.  
  2386.       this.soundService.play(uri);
  2387.  
  2388.     } catch(e) {}
  2389.   },
  2390.  
  2391.   notifyAboutNewItems: function(aType, aNewNum, aMailData) {
  2392.     switch (aType) {
  2393.       case "lenta":
  2394.         aType = "feeds";
  2395.         break;
  2396.       case "mailList":
  2397.       //~ case "mail":
  2398.         aType = "mail";
  2399.         break;
  2400.       default:
  2401.         return;
  2402.     }
  2403.  
  2404.     if (this.getBoolPref("yasearch." + aType + ".ui.notification.enabled") ||
  2405.         this.getBoolPref("yasearch." + aType + ".ui.soundnotification.enabled")) {
  2406.       this._runnedNotifications.push({type: aType, nmb: aNewNum, mdata: aMailData, isShowing: false});
  2407.       this.setNotifyTimer();
  2408.     }
  2409.   },
  2410.  
  2411.   _showAlertWithGrowl: function(title, msg, type) {
  2412.       if (this.AppInfo.OS.isMacOS) {
  2413.       try {
  2414.           var listener = {
  2415.           observe: function(aSubject, aTopic, aData) {
  2416.               if (aTopic == "alertclickcallback" && (aData == "mail" || aData == "feeds"))
  2417.               gYaSearchService.loadConditionalURI(aData, "tab", {action: (aData == "mail" ? 1040 : 1120)});
  2418.           }
  2419.         }
  2420.  
  2421.           var alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
  2422.           alertsService.showAlertNotification(CHROME_IMAGES + "bar-logo.png",
  2423.                                             title.split(":")[0], msg, false, type, listener);
  2424.  
  2425.         return true;
  2426.  
  2427.       } catch(e) {}
  2428.     }
  2429.  
  2430.     return false;
  2431.   },
  2432.  
  2433.   showAlert: function(title, msg, type) {
  2434.       if (this._showAlertWithGrowl(title, msg, type)) {
  2435.       this._runnedNotifications.shift();
  2436.         return;
  2437.       }
  2438.     
  2439.     let flags = "chrome,popup=yes";
  2440.     if (!this.AppInfo.browser.isGreaterThenFx35)
  2441.       flags += ",titlebar=no";
  2442.     
  2443.     let url = type ? CHROME_CONTENT + "alerts/timed.alert.xul" : "chrome://global/content/alerts/alert.xul";
  2444.     
  2445.     var alertWin = this.windowWatcher.openWindow(null, url, "_blank", flags, null);
  2446.     alertWin.arguments = [CHROME_IMAGES + "bar-logo.png", title, msg, (type ? type : false), this.timedAlertListener];
  2447.   },
  2448.  
  2449.   showPermanentAlert: function(title, msg, image, cookie) {
  2450.     let flags = "chrome,popup=yes";
  2451.     
  2452.     if (!this.AppInfo.browser.isGreaterThenFx35)
  2453.       flags += ",titlebar=no";
  2454.     
  2455.     var alertWin = this.windowWatcher.openWindow(null, CHROME_CONTENT + "alerts/permanent.alert.xul",
  2456.                                                  "_blank", flags, null);
  2457.     
  2458.     alertWin.arguments = [image && image != "" ? image : CHROME_IMAGES + "bar-logo.png", title, msg,
  2459.                           (cookie||""), this.permanentAlertListener];
  2460.   },
  2461.  
  2462.   timedAlertListener: {
  2463.     observe: function(aSubject, aTopic, aData) {
  2464.       if (aTopic == "alertfinished" && gYaSearchService._runnedNotifications)
  2465.         gYaSearchService._runnedNotifications.shift();
  2466.     }
  2467.   },
  2468.  
  2469.   permanentAlertListener: {
  2470.     observe: function(aSubject, aTopic, aData) {
  2471.       if (aTopic == "alertfinished") {
  2472.         switch (aData) {
  2473.           case "":
  2474.           case "error":
  2475.           case "installed":
  2476.             break;
  2477.           case "cancelled":
  2478.             gYaSearchService.guidUpdateDS = true;
  2479.             break;
  2480.           default:
  2481.             gYaSearchService.guidMessageTS = aData;
  2482.         }
  2483.       }
  2484.     }
  2485.   },
  2486.  
  2487.   decMailCounter: function(aMailId) {
  2488.     if (this.mailDOMMenuDoc && this.mailDOMMenuDoc.hasChildNodes()) {
  2489.       var elem = this.xPathEvaluator.evaluate("//item/item[@url='" + aMailId + "']",
  2490.                                                this.mailDOMMenuDoc,
  2491.                                                null,
  2492.                                                this.unSnapshotType,
  2493.                                                null).snapshotItem(0);
  2494.       if (elem) {
  2495.         var parent = elem.parentNode;
  2496.  
  2497.         if (parent.getElementsByTagName("item").length == 1) {
  2498.           parent.parentNode.removeChild(parent);
  2499.         } else {
  2500.           parent.removeChild(elem);
  2501.         }
  2502.  
  2503.         this.mailCounter--;
  2504.         this.mailPermCounter--;
  2505.  
  2506.         new G_Timer(function(){OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Data", "mailList")}, 1);
  2507.  
  2508.         this.mailLastCheckIsOutOfDate = true;
  2509.         this.refreshHTTPData("mail", null, 10000);
  2510.       }
  2511.     }
  2512.   },
  2513.  
  2514.   KeyCorrector: {
  2515.     STATE_DISABLED: 0,
  2516.     STATE_RUNNED:   1,
  2517.     STATE_STOPPED:  2,
  2518.  
  2519.     _statePrefName: "yasearch.general.ui.urlbar.corrector.state",
  2520.  
  2521.     _checkStateValue: function(aValue) {
  2522.       if (aValue > this.STATE_STOPPED || aValue < this.STATE_DISABLED)
  2523.         aValue = this.STATE_STOPPED;
  2524.       return aValue;
  2525.     },
  2526.  
  2527.     get currentState() {
  2528.       return this._checkStateValue(gYaSearchService.getIntPref(this._statePrefName));
  2529.     },
  2530.  
  2531.     set currentState(val) {
  2532.       gYaSearchService.setIntPref(this._checkStateValue(this._statePrefName), val);
  2533.       return val;
  2534.     },
  2535.  
  2536.     get keyConvTable() {
  2537.       return gYaSearchService.windowsOS ?
  2538.         { withoutShift: { 192: 96, 49: 49, 50: 50, 51: 51, 52: 52, 53: 53, 54: 54, 55: 55, 56: 56, 57: 57, 48: 48, 109: 45, 61: 61, 81: 113, 87: 119, 69: 101, 82: 114, 84: 116, 89: 121, 85: 117, 73: 105, 79: 111, 80: 112, 219: 91, 221: 93, 220: 92, 65: 97, 83: 115, 68: 100, 70: 102, 71: 103, 72: 104, 74: 106, 75: 107, 76: 108, 59: 59, 222: 39, 90: 122, 88: 120, 67: 99, 86: 118, 66: 98, 78: 110, 77: 109, 188: 44, 190: 46, 191: 47 },
  2539.           withShift: { 192: 126, 49: 33, 50: 64, 51: 35, 52: 36, 53: 37, 54: 94, 55: 38, 56: 42, 57: 40, 48: 41, 109: 95, 61: 43, 81: 81, 87: 87, 69: 69, 82: 82, 84: 84, 89: 89, 85: 85, 73: 73, 79: 79, 80: 80, 219: 123, 221: 125, 220: 124, 65: 65, 83: 83, 68: 68, 70: 70, 71: 71, 72: 72, 74: 74, 75: 75, 76: 76, 59: 58, 222: 34, 90: 90, 88: 88, 67: 67, 86: 86, 66: 66, 78: 78, 77: 77, 188: 60, 190: 62, 191: 63 }
  2540.         } : null
  2541.     },
  2542.  
  2543.     __charConvTable: null,
  2544.  
  2545.     get charConvTable() {
  2546.       if (!this.__charConvTable) {
  2547.         var withoutShift = {},
  2548.             withShift = {};
  2549.  
  2550.         var cirChars = UConverter.ConvertToUnicode(
  2551.                         "╨╣╤å╤â╨║╨╡╨╜╨│╤ê╤ë╨╖╤à╤è╤ä╤ï╨▓╨░╨┐╤Ç╨╛╨╗╨┤╨╢╤ì╤Å╤ç╤ü╨╝╨╕╤é╤î╨▒╤Ä╤æ╨Ö╨ª╨ú╨Ü╨ò╨¥╨ô╨¿╨⌐╨ù╨Ñ╨¬╨ñ╨½╨Æ╨É╨ƒ╨á╨₧╨¢╨ö╨û╨¡╨»╨º╨í╨£╨ÿ╨ó╨¼╨æ╨«╨ü╤û╨å");
  2552.         var latChars = "qwertyuiop[]asdfghjkl;'zxcvbnm,.`QWERTYUIOP[]ASDFGHJKL;'ZXCVBNM,.`sS";
  2553.  
  2554.         var cirCharsShift = UConverter.ConvertToUnicode('╤à╤è╨╢╤ì╨▒╤Ä╤æ"*,.;Γäû');
  2555.         var latCharsShift = '{}:"<>~@$^&*#';
  2556.  
  2557.         var i=0, ch;
  2558.         while ((ch = cirChars[i]))
  2559.           withoutShift[ch] = latChars[i++];
  2560.  
  2561.         i=0;
  2562.         while ((ch = cirCharsShift[i]))
  2563.           withShift[ch] = latCharsShift[i++];
  2564.  
  2565.         this.__charConvTable = { withoutShift: withoutShift, withShift: withShift };
  2566.       }
  2567.  
  2568.       return this.__charConvTable;
  2569.     }
  2570.   },
  2571.  
  2572.   // **********************************************
  2573.   Bloggers: {
  2574.     cachedTabs: {},
  2575.     
  2576.     _tabTimer: null,
  2577.     
  2578.     _setTimer: function(aTabData, aVal) {
  2579.       if (this._tabTimer)
  2580.         this._tabTimer.cancel();
  2581.       else if (aVal)
  2582.         this._tabTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  2583.  
  2584.       if (!aVal)
  2585.         return;
  2586.       
  2587.       this._tabTimer.initWithCallback({
  2588.         tab: aVal.tab,
  2589.         url: aVal.url,
  2590.         
  2591.         notify: function(aTimer) {
  2592.           let bloggers = gYaURLInfo.getBloggers(this.url);
  2593.           if (!bloggers)
  2594.             return;
  2595.           
  2596.           var _self = gYaSearchService.Bloggers;
  2597.           if (bloggers.windowState & gYaURLInfo.BLOGGERS_STATE_TIMED_REQUEST) {
  2598.             bloggers.windowState = gYaURLInfo.BLOGGERS_STATE_REQUEST;
  2599.             
  2600.             _self.setBloggersData(false, this.tab, this.url);
  2601.             
  2602.             let _url = "http://blogs.yandex.ru/bar.xml?text=" +
  2603.                         encodeURIComponent('!link="' + this.url + '"') +
  2604.                         "&count=" + bloggers.value +
  2605.                         (this.manual ? "&" + getNCRndStr() : "");
  2606.             
  2607.             gYaSearchService.xmlHttpRequest(
  2608.                 _url,
  2609.                 {callbackFunc: _self.setBloggersData.bind(_self, this.tab, this.url)}
  2610.             );
  2611.           }
  2612.         }
  2613.       }, aTabData._timeout, Ci.nsITimer.TYPE_ONE_SHOT);
  2614.     },
  2615.  
  2616.     clearTabData: function(aTabId) {
  2617.       delete this.cachedTabs[aTabId];
  2618.     },
  2619.     
  2620.     getBloggersData: function(aTab, aSkipCache, aTimeout, aManual) {
  2621.       if (!(aTab && aTab.selected))
  2622.         return;
  2623.       
  2624.       let bloggers = gYaURLInfo.getBloggers(aTab.linkedBrowser.currentURI);
  2625.       if (!bloggers)
  2626.         return;
  2627.       
  2628.       let url = bloggers.url,
  2629.           aTabId = aTab.linkedPanel,
  2630.           tData = this.cachedTabs[aTabId];
  2631.  
  2632.       if (!tData)
  2633.         tData = this.cachedTabs[aTabId] = { visible: false };
  2634.       
  2635.       tData.url = url;
  2636.       tData._timeout = aTimeout ? 5 : 5000;
  2637.  
  2638.       this._setTimer();
  2639.       
  2640.       if ((bloggers.buttonState === gYaURLInfo.BLOGGERS_STATE_UNKNOWN) ||
  2641.           (aSkipCache && !(bloggers.buttonState & gYaURLInfo.BLOGGERS_STATE_REQUEST)))
  2642.       {
  2643.         bloggers.buttonState = gYaURLInfo.BLOGGERS_STATE_UNKNOWN;
  2644.         
  2645.         if (aManual) {
  2646.           bloggers.manual = true;
  2647.           gYaSearchService.notifyBusyStateOfRequest(null, true, true, "yasearch-bloggers");
  2648.         }
  2649.         
  2650.         gYaSearchService.getCY(url, aTab.linkedBrowser.webProgress, false);
  2651.       
  2652.       } else if (bloggers.value > 0 && tData && this.isWindowVisible(aTab) &&
  2653.                   ((bloggers.windowState & gYaURLInfo.BLOGGERS_STATE_UNKNOWN) ||
  2654.                    (bloggers.windowState & gYaURLInfo.BLOGGERS_STATE_TIMED_REQUEST) ||
  2655.                   (aSkipCache && !(bloggers.windowState & gYaURLInfo.BLOGGERS_STATE_REQUEST))))
  2656.       {
  2657.         bloggers.windowState = gYaURLInfo.BLOGGERS_STATE_TIMED_REQUEST;
  2658.         this._setTimer(tData, {tab: aTab, url: url});
  2659.       }
  2660.       
  2661.       this.setBloggersData(false, aTab, url);
  2662.     },
  2663.  
  2664.     persistScrollPosition: function(aURL, aYPos) {
  2665.       let bloggers = gYaURLInfo.getBloggers(aURL);
  2666.       if (bloggers)
  2667.         bloggers.scroll = aYPos;
  2668.     },
  2669.  
  2670.     switchWindowMode: function(aMode) {
  2671.       this._fullMode = aMode === null ? !this._fullMode : aMode;
  2672.       return this._fullMode;
  2673.     },
  2674.  
  2675.     hideTopModeWindow: function() {
  2676.       if (this._fullMode)
  2677.         for each (let tabData in this.cachedTabs)
  2678.           if (tabData.visible)
  2679.             tabData.visible = false;
  2680.     },
  2681.  
  2682.     persistWindowVisible: function(aTab, aVisible) {
  2683.       let tData = this.cachedTabs[aTab.linkedPanel];
  2684.       if (!tData)
  2685.         tData = this.cachedTabs[aTab.linkedPanel] = {};
  2686.       
  2687.       tData.visible = aVisible;
  2688.     },
  2689.  
  2690.     isWindowVisible: function(aTab) {
  2691.       if (this._fullMode)
  2692.         return true;
  2693.       
  2694.       if (!aTab.selected)
  2695.         return false;
  2696.       
  2697.       let tData = this.cachedTabs[aTab.linkedPanel];
  2698.       return !!(tData && tData.visible);
  2699.     },
  2700.  
  2701.     setBloggersData: function(aReq, aTab, aUrl) {
  2702.       let bloggers = gYaURLInfo.getBloggers(aUrl);
  2703.       if (!bloggers)
  2704.         return;
  2705.       
  2706.       if (bloggers.manual) {
  2707.         bloggers.manual = false;
  2708.         gYaSearchService.notifyBusyStateOfRequest(null, false, true, "yasearch-bloggers");
  2709.       }
  2710.       
  2711.       if (aReq != false) {
  2712.         bloggers.windowState = gYaURLInfo.BLOGGERS_STATE_ERROR;
  2713.  
  2714.         if (!gYaSearchService.isReqError(aReq)) {
  2715.           let serverDate;
  2716.           
  2717.           try {
  2718.             serverDate = new Date(aReq.target.getResponseHeader("Date"));
  2719.  
  2720.             if (serverDate != "Invalid Date")
  2721.               serverDate = new Date(serverDate.getTime() +
  2722.                                     serverDate.getTimezoneOffset() * 60 * 1000 +
  2723.                                     3 * 60 * 60 * 1000);
  2724.  
  2725.             if (serverDate == "Invalid Date")
  2726.               serverDate = null;
  2727.           } catch(e) {}
  2728.           
  2729.           let doc = gYaSearchService.getDOMDocContent2("xsl-templ/xsl-bloggers-data.xsl",
  2730.                                      gYaSearchService.domParser.parseFromString(aReq.target.responseText, "text/xml"));
  2731.  
  2732.           if (doc && doc.localName == "vbox") {
  2733.             bloggers.windowState = gYaURLInfo.BLOGGERS_STATE_RESPONSE;
  2734.  
  2735.             doc.firstChild.setAttribute("location", bloggers.url);
  2736.  
  2737.             if (serverDate) {
  2738.               Array.forEach(doc.getElementsByTagName("label"), function(aLabel) {
  2739.                 if (aLabel.getAttribute("class") == "ya-blogger-time") {
  2740.                   var postDate = this.getDateDiffString(serverDate, this.getDateFromString(aLabel.getAttribute("value")));
  2741.                   if (postDate)
  2742.                     aLabel.setAttribute("value", postDate);
  2743.                 }
  2744.               }, this);
  2745.             }
  2746.  
  2747.             Array.forEach(doc.getElementsByTagName("description"), function(aDescription) {
  2748.               var node = aDescription.firstChild;
  2749.               if (node && node.nodeName == "#text")
  2750.                 node.nodeValue = node.nodeValue.replace(/([\/\-&\?\.])/g, "$1\u200B")
  2751.                                                .replace(/(\S{15})(\S{15})/g, "$1\u200B$2");
  2752.             })
  2753.             
  2754.             
  2755.             bloggers.content = doc;
  2756.           }
  2757.         } else {
  2758.           gYaSearchService.log("setBloggersData got bad request result");
  2759.         }
  2760.       }
  2761.       
  2762.       try {
  2763.         if (aTab.selected)
  2764.           aTab.ownerDocument.defaultView.Ya.Bloggers.setData(bloggers);
  2765.       } catch(e) {}
  2766.     },
  2767.  
  2768.     getDateFromString: function(aString) {
  2769.       let res = aString.match(/(\d{1,2})\.(\d{1,2})\.(\d{4})(?:\s+(\d{1,2})\:(\d{1,2}))?/) ?
  2770.                     new Date(RegExp.$3, (RegExp.$2 * 1) - 1, RegExp.$1, RegExp.$4, RegExp.$5) :
  2771.                     null;
  2772.  
  2773.       return (!res && res == "Invalid Date") ? null : res;
  2774.     },
  2775.  
  2776.     _getFormatedTime: function(aDate) {
  2777.       return [aDate.getHours(), ("0" + aDate.getMinutes()).slice(-2)].join(":");
  2778.     },
  2779.  
  2780.     getDateDiffString: function(aCurrentDate, aDate) {
  2781.       if (!(aCurrentDate instanceof Date) || !(aDate instanceof Date))
  2782.         return null;
  2783.  
  2784.       let diff = aCurrentDate.getTime() - aDate.getTime();
  2785.       if (diff < 0)
  2786.         return null;
  2787.  
  2788.       let res = [],
  2789.           strType = "year";
  2790.  
  2791.       if (diff < DAY_SECS)
  2792.         strType = "today";
  2793.  
  2794.       if (aCurrentDate.getDate() != aDate.getDate())
  2795.         strType = "yesterday";
  2796.  
  2797.       if (diff >= DAY_SECS * 2)
  2798.         strType = "month";
  2799.  
  2800.       if (aCurrentDate.getYear() != aDate.getYear())
  2801.         strType = "year";
  2802.  
  2803.       switch (strType) {
  2804.         case "year":
  2805.           res = [aDate.getDate(), this.dateStrings.months[aDate.getMonth()], aDate.getFullYear()];
  2806.           break;
  2807.  
  2808.         case "month":
  2809.           res = [aDate.getDate(), this.dateStrings.months[aDate.getMonth()]];
  2810.           res.push(this._getFormatedTime(aDate));
  2811.           break;
  2812.  
  2813.         case "today":
  2814.         case "yesterday":
  2815.           res = [this.dateStrings[strType]];
  2816.           res.push(this._getFormatedTime(aDate));
  2817.           break;
  2818.       }
  2819.  
  2820.       return res.join(" ");
  2821.     },
  2822.  
  2823.     _dateStrings: null,
  2824.  
  2825.     get dateStrings() {
  2826.       if (!this._dateStrings) {
  2827.         this._dateStrings = {
  2828.           months: gYaSearchService.getString("dateMonths").toLowerCase().split(","),
  2829.           today: gYaSearchService.getString("dateToday"),
  2830.           yesterday: gYaSearchService.getString("dateYesterday")
  2831.         }
  2832.       }
  2833.  
  2834.       return this._dateStrings;
  2835.     }
  2836.   },
  2837.   // **********************************************
  2838.   _browserButtons: null,
  2839.   
  2840.   get browserButtons() {
  2841.     if (!this._browserButtons)
  2842.       this._browserButtons = this.buttonsInfo || {};
  2843.     
  2844.     return this._browserButtons;
  2845.   },
  2846.   
  2847.   set browserButtons(val) {
  2848.     this._browserButtons = val;
  2849.   },
  2850.   
  2851.   webProgressListener: {
  2852.     _servicesRe: /^https?:\/\/(?:((?:web)?mail|lenta(?:\-ng)?|money|fotki)\.yandex|[^\/]*\.(ya)|(moikrug))\.(?:ru|ua)\/(.*)/i,
  2853.  
  2854.     _checkNeedRefreshData: function(aURL, aButtons) {
  2855.       aURL = "" + aURL;
  2856.       
  2857.       if (!gYaSearchService.isLogin || !aURL.match(this._servicesRe))
  2858.         return;
  2859.  
  2860.       var service = (RegExp.$1 || RegExp.$2 || RegExp.$3).toLowerCase();
  2861.       var path    = RegExp.$4.toLowerCase();
  2862.  
  2863.       var timeoutDelay = 5000;
  2864.  
  2865.       switch (service) {
  2866.         case "mail":
  2867.           timeoutDelay = 70000;
  2868.           if (aButtons.mail && /^(modern|classic|neo)\/messages(\?|$)/.test(path) &&
  2869.               gYaSearchService.Counters.getCount("mail") > 0)
  2870.             gYaSearchService.refreshHTTPData("mail", null, timeoutDelay);
  2871.           break;
  2872.  
  2873.         case "lenta-ng":
  2874.         case "lenta":
  2875.           if (aButtons.lenta && /^(un)?read.xml/.test(path) &&
  2876.               gYaSearchService.Counters.getCount("lenta") > 0)
  2877.             gYaSearchService.refreshHTTPData("lenta", null, timeoutDelay);
  2878.           break;
  2879.  
  2880.         case "fotki":
  2881.           if (aButtons.fotki) {
  2882.             var needRefresh = false;
  2883.  
  2884.             if (/\/favorites$/.test(path)) {
  2885.               if (gYaSearchService.Counters.getCount("fotki") > 0)
  2886.                 needRefresh = true;
  2887.             } else if (/\/comments$/.test(path)) {
  2888.               if (gYaSearchService.Counters.getCount("fotki", "comments") > 0)
  2889.                 needRefresh = true;
  2890.             }
  2891.  
  2892.             if (needRefresh)
  2893.               gYaSearchService.refreshHTTPData("fotki", null, timeoutDelay);
  2894.           }
  2895.           break;
  2896.  
  2897.         case "money":
  2898.           if (path == "" || path == "prepaid.xml" || path == "shops.xml")
  2899.             gYaSearchService.refreshHTTPData("money", null, timeoutDelay);
  2900.           break;
  2901.  
  2902.         case "ya":
  2903.           if (path && path.indexOf("replies_history_unread.xml") == 0)
  2904.             gYaSearchService.refreshHTTPData("yaru", null, timeoutDelay);
  2905.           break;
  2906.  
  2907.         case "moikrug":
  2908.           if (path && (/^threads\/?$/.test(path) || /^threads\/\?ncrnd/.test(path)) &&
  2909.               gYaSearchService.Counters.getCount("moikrug") > 0) {
  2910.             gYaSearchService.refreshHTTPData("moikrug", null, timeoutDelay);
  2911.           }
  2912.           break;
  2913.  
  2914.         default:
  2915.           break;
  2916.       }
  2917.     },
  2918.  
  2919.     _getUrlFromLocation: function(aLocation) {
  2920.       let url = gYaURLInfo.getURL(aLocation);
  2921.       return url ? url.toString() : false;
  2922.     },
  2923.  
  2924.     _checkIsTopWindowRequested: function(aWebProgress, aRequest) {
  2925.       let reqWindow = false,
  2926.           topWindow = false;
  2927.  
  2928.       try {
  2929.         reqWindow = aWebProgress.DOMWindow;
  2930.         topWindow = reqWindow.top;
  2931.       } catch(e) {}
  2932.  
  2933.       return (topWindow && topWindow === reqWindow &&
  2934.                (arguments.length == 1 || topWindow.location.toString() === aRequest.name.toString())
  2935.               );
  2936.     },
  2937.  
  2938.     _getDataSumm: function(aWebProgress) {
  2939.       let dataSumm = {};
  2940.  
  2941.       if (aWebProgress && !aWebProgress.isLoadingDocument) {
  2942.         let httpStatus = false;
  2943.         try {
  2944.           if ("currentDocumentChannel" in aWebProgress) {
  2945.             httpStatus = aWebProgress.currentDocumentChannel
  2946.                                      .QueryInterface(Ci.nsIHttpChannel)
  2947.                                      .responseStatus;
  2948.           }
  2949.         } catch(e) {}
  2950.  
  2951.         dataSumm = (aWebProgress.chromeEventHandler.yaSearchTHandler || {}).dataSumm || {};
  2952.         dataSumm.httpStatus = httpStatus;
  2953.       }
  2954.  
  2955.       return dataSumm;
  2956.     },
  2957.  
  2958.     onPageShowInBackground: function(aWebProgress, aButtons) {
  2959.       let url = this._getUrlFromLocation(aWebProgress.currentURI);
  2960.  
  2961.       if (url)
  2962.         this._checkNeedRefreshData(url, aButtons);
  2963.     },
  2964.  
  2965.     onLocationChange: function(aWebProgress, aButtons) {
  2966.       gYaSearchService.browserButtons = aButtons;
  2967.       
  2968.       if (!aButtons.navigElements)
  2969.         return;
  2970.       
  2971.       if (!this._checkIsTopWindowRequested(aWebProgress))
  2972.         return;
  2973.  
  2974.       let url = this._getUrlFromLocation(aWebProgress.currentURI);
  2975.       gYaSearchService.getCY(url, aWebProgress, true, null, this._getDataSumm(aWebProgress));
  2976.     },
  2977.  
  2978.     onPageStateStart: function(aWebProgress, aRequest) {
  2979.       if (!gYaSearchService.browserButtons.navigElements)
  2980.         return;
  2981.  
  2982.       let url = this._getUrlFromLocation(aRequest.URI);
  2983.  
  2984.       if (!url)
  2985.         return;
  2986.       
  2987.       let cyDataToSet = { post: aRequest.requestMethod === "POST" };
  2988.       
  2989.       let wpCurrentURI = aWebProgress.currentURI;
  2990.       if (aWebProgress.loadType & 0x800000 && wpCurrentURI && wpCurrentURI.spec && url != wpCurrentURI.spec) {
  2991.         cyDataToSet.original = this._getUrlFromLocation(aWebProgress.currentURI);
  2992.         cyDataToSet.referring = this._getUrlFromLocation(aWebProgress.referringURI);
  2993.       }
  2994.       
  2995.       gYaURLInfo.setCY(aRequest.URI, cyDataToSet);
  2996.     },
  2997.  
  2998.     onPageStateStop: function(aWebProgress, aRequest) {
  2999.       if (!this._checkIsTopWindowRequested(aWebProgress, aRequest))
  3000.         return;
  3001.  
  3002.       let url = this._getUrlFromLocation(aWebProgress.currentURI);
  3003.  
  3004.       if (!url)
  3005.         return;
  3006.  
  3007.       this._checkNeedRefreshData(url, gYaSearchService.browserButtons);
  3008.  
  3009.       if (!gYaSearchService.browserButtons.navigElements)
  3010.         return;
  3011.  
  3012.       let originalURL = this._getUrlFromLocation(aRequest.originalURI);
  3013.       try {
  3014.         if (originalURL == aRequest.URI.spec)
  3015.           originalURL = false;
  3016.       } catch(e) {}
  3017.  
  3018.       gYaSearchService.getCY(url, aWebProgress, false, originalURL, this._getDataSumm(aWebProgress));
  3019.     }
  3020.   },
  3021.  
  3022.   confirmCYSpam: function(aUrl, aElement) {
  3023.     this.xmlHttpRequest(this.appendStatData2Url(aUrl,{}),
  3024.                          { callbackFunc: this.confirmedCYSpam.bind(this, aUrl, aElement) });
  3025.   },
  3026.  
  3027.   confirmedCYSpam: function(aReq, aUrl, aElement) {
  3028.     let browser;
  3029.     
  3030.     if (aElement && aElement.localName) {
  3031.       if ("menuitem" == aElement.localName)
  3032.         aElement = aElement.parentNode.parentNode;
  3033.  
  3034.       if ("toolbarbutton" == aElement.localName && aElement.hasAttribute("oncommand"))
  3035.         browser = aElement.ownerDocument.defaultView;
  3036.     }
  3037.  
  3038.     if (!browser)
  3039.       return;
  3040.  
  3041.     if (this.isReqError(aReq)) {
  3042.       browser.alert(this.getString("spamError"));
  3043.     } else {
  3044.       var url = browser.gBrowser.selectedBrowser.currentURI.spec;
  3045.       if (url && url.length > 9
  3046.           && aElement.getAttribute("oncommand")
  3047.                      .indexOf("('http://bar-compl.yandex.ru/c?url=" + encodeURIComponent(url)) > 0) {
  3048.         
  3049.         let cy = gYaURLInfo.getCY(url);
  3050.         if (cy)
  3051.           cy.spam = false;
  3052.         
  3053.         aElement.disabled = true;
  3054.       }
  3055.     }
  3056.   },
  3057.   
  3058.   getCY: function(aURL, aWebProgress, aFromCache, aOriginalURL, aDataSumm) {
  3059.     let cy = gYaURLInfo.setCY(aURL);
  3060.     let bloggers = gYaURLInfo.setBloggers(aURL);
  3061.     
  3062.     aURL = aURL || "undefined";
  3063.     
  3064.     var originalURL = null;
  3065.     
  3066.     if (cy && cy.spam === null) {
  3067.       originalURL = aOriginalURL || cy.original || false;
  3068.       var referrer = aWebProgress.referringURI ? aWebProgress.referringURI.spec : (originalURL ? cy.referrer : null);
  3069.       
  3070.       cy.spam = (aURL == "undefined") ?
  3071.                     false :
  3072.                     "http://bar-compl.yandex.ru/c?url=" + encodeURIComponent(aURL) +
  3073.                     (referrer ? ("&referer=" + encodeURIComponent(referrer)) : "") +
  3074.                     (originalURL ? "&oldurl=" + encodeURIComponent(originalURL) : "") +
  3075.                     "&login=" + (encodeURIComponent(this.username || ""));
  3076.     }
  3077.     
  3078.     let browser = aWebProgress.chromeEventHandler;
  3079.     this.setCY(false, browser, aURL);
  3080.     
  3081.     if (!cy || (aFromCache && aWebProgress.isLoadingDocument))
  3082.       return;
  3083.     
  3084.     let urlinfo = 0;
  3085.     
  3086.     if (this.browserButtons.cy) {
  3087.       urlinfo |= 1;
  3088.     }
  3089.     
  3090.     if (this.browserButtons.bloggers) {
  3091.       urlinfo |= 2;
  3092.     }
  3093.     
  3094.     if (!urlinfo)
  3095.       return;
  3096.     
  3097.     if (
  3098.       !!((urlinfo & 1) && (cy.state & gYaURLInfo.CY_STATE_UNKNOWN)) ||
  3099.       !!((urlinfo & 2) && (bloggers.buttonState & gYaURLInfo.BLOGGERS_STATE_UNKNOWN)) ||
  3100.       !!(aDataSumm && (aDataSumm.time || aDataSumm.action)))
  3101.     {
  3102.       if (urlinfo & 1)
  3103.         cy.state = gYaURLInfo.CY_STATE_REQUEST;
  3104.       
  3105.       if (urlinfo & 2)
  3106.         bloggers.buttonState = gYaURLInfo.BLOGGERS_STATE_REQUEST;
  3107.       
  3108.       originalURL = originalURL || aOriginalURL || cy.original || false;
  3109.       
  3110.       var post = cy.post;//this.cachedCYsPosts[aURL] || this.cachedCYsPosts[originalURL] || false;
  3111.       
  3112.       let tSumm = "";
  3113.       
  3114.       if (aDataSumm) {
  3115.         if (aDataSumm.time) {
  3116.           tSumm += "&tv=" + aDataSumm.time.tv + "&t=" + aDataSumm.time.t;
  3117.           
  3118.           if (aDataSumm.time.yamm)
  3119.             tSumm += "&yamm=" + encodeURIComponent(aDataSumm.time.yamm);
  3120.         }
  3121.         
  3122.         if (aDataSumm.action)
  3123.           tSumm += "&action=" + aDataSumm.action;
  3124.         
  3125.         if (aDataSumm.httpStatus)
  3126.           tSumm += "&httpstatus=" + aDataSumm.httpStatus;
  3127.       }
  3128.       
  3129.       let ui = this.guidString;
  3130.       if (ui) {
  3131.         ui = "&ui=" + encodeURIComponent(ui.replace(/^\{/, "").replace(/\}$/, ""));
  3132.         let r1 = this.barnavigR1String;
  3133.         if (r1)
  3134.           ui += "&r1=" + encodeURIComponent(r1);
  3135.       }
  3136.       
  3137.       let params = ["ver=" + this.barExtensionVersionWithLocale +
  3138.                     tSumm + "&" + this.getAppendStatData2Url({clid:4}) +
  3139.                     (ui || "") +
  3140.                     "&urlinfo=" + urlinfo +
  3141.                     "&url=" + encodeURIComponent(aURL) +
  3142.                     "&show=1&post=" + (post ? 1 : 0) +
  3143.                     (aWebProgress.referringURI && aWebProgress.referringURI.userPass == "" ?
  3144.                     "&referer=" + encodeURIComponent(aWebProgress.referringURI.spec) : "") +
  3145.                     (originalURL ? "&oldurl=" + encodeURIComponent(originalURL) : ""),
  3146.                     "",//hip
  3147.                     (browser.contentTitle ? ("&title=" + encodeURIComponent(("" + browser.contentTitle).substr(0,1000))) : "")
  3148.                    ];
  3149.       
  3150.       gYaURLInfo.asyncGetIPsForURL(aURL, this.sendCY.bind(this, params, browser, aURL, urlinfo));
  3151.     }
  3152.   },
  3153.   
  3154.   sendCY: function(aIPs, aParams, aBrowser, aURL, aUrlinfo) {
  3155.     if (aIPs) {
  3156.       aIPs.some(function(aIP) {
  3157.         let parts = aIP ? aIP.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) : null;
  3158.         if (!parts)
  3159.           return false;
  3160.         
  3161.         aParams[1] = "&hip=" + ((parts[1] * 16777216) + (parts[2] * 65536) + (parts[3] * 256) + (parts[4] * 1));
  3162.         return true;
  3163.       });
  3164.     }
  3165.     
  3166.     this.xmlHttpRequest("http://bar-navig.yandex.ru/u?" + aParams.join(""),
  3167.                         { callbackFunc: this.setCY.bind(this, aBrowser, aURL, aUrlinfo) });
  3168.   },
  3169.   
  3170.   setCY: function(aReq, aBrowser, aURL, aUrlinfo, aDontResend) {
  3171.     let [cy, bloggers] = gYaURLInfo.getCYAndBloggers(aURL);
  3172.     
  3173.     let checkBloggers = false;
  3174.     
  3175.     if (aReq) {
  3176.       if (!(cy && bloggers)) {
  3177.         this.log("No CY or Bloggers data");
  3178.         return;
  3179.       }
  3180.       
  3181.       if (this.isReqError(aReq)) {
  3182.         if (!aDontResend) {
  3183.           try {
  3184.             var reqURL = aReq.target.channel.name;
  3185.             var nameReg = /^(http:\/\/)(bar\-navig\.yandex\.ru)/;
  3186.             
  3187.             if (reqURL && nameReg.test(reqURL)) {
  3188.               var status = 0;
  3189.               try {
  3190.                 status = parseInt(aReq.target.status, 10) || 0;
  3191.               } catch(ex) {}
  3192.               
  3193.               if (status != 200) {
  3194.                 this.xmlHttpRequest(reqURL.replace(nameReg, "$1backup-$2") + "&pstatus=" + status,
  3195.                                    { callbackFunc: this.setCY.bind(this, aBrowser, aURL, aUrlinfo, true) });
  3196.                 return;
  3197.               }
  3198.             }
  3199.           } catch(e) {}
  3200.         }
  3201.         
  3202.         if (aUrlinfo & 1)
  3203.           cy.state = gYaURLInfo.CY_STATE_ERROR;
  3204.         
  3205.         if (aUrlinfo & 2)
  3206.           bloggers.buttonState = gYaURLInfo.BLOGGERS_STATE_ERROR;
  3207.         
  3208.       } else {
  3209.         this.checkNeedSendGuid();
  3210.         
  3211.         let urlinfoXml = this.safeE4Xml(aReq.target.responseText, null, "urlinfo");
  3212.         
  3213.         if (urlinfoXml) {
  3214.           if (aUrlinfo & 1) {
  3215.             cy.state = gYaURLInfo.CY_STATE_RESPONSE;
  3216.             
  3217.             const REGION_REG = new RegExp(UConverter.ConvertToUnicode("╨á╨╡╨│╨╕╨╛╨╜: (.*)"), "g");
  3218.             const THEME_REG = new RegExp(UConverter.ConvertToUnicode("^\\s*╨ó╨╡╨╝╨░:\\s*"), "");
  3219.             
  3220.             let cyData = {};
  3221.             cyData.domain = urlinfoXml.url.@domain.toString();
  3222.             cyData.value = parseInt(urlinfoXml.tcy.@value.toString(), 10) || 0;
  3223.             cyData.rang = parseInt(urlinfoXml.tcy.@rang.toString(), 10) || 0;
  3224.             
  3225.             let titles = [];
  3226.             for each (let topic in urlinfoXml.topics.topic) {
  3227.               let title = topic.@title.toString().replace(THEME_REG, "");
  3228.               if (title)
  3229.                 titles.push(title);
  3230.             }
  3231.             
  3232.             cyData.theme = titles.length ? titles.join(", ") : this.getString("cyNoTheme");
  3233.             
  3234.             let region = REGION_REG.exec(urlinfoXml.textinfo.toString());
  3235.             cyData.region = (region && region[1]) ? region[1] : this.getString("cyNoRegion");
  3236.             
  3237.             if (urlinfoXml.r1.length() == 1) {
  3238.               let r1 = urlinfoXml.r1.toString();
  3239.               if (r1) {
  3240.                 this.barnavigR1String = r1;
  3241.               }
  3242.             }
  3243.             
  3244.             gYaURLInfo.setCY(aURL, cyData);
  3245.           }
  3246.           
  3247.           if (aUrlinfo & 2) {
  3248.             if ((bloggers.buttonState & gYaURLInfo.BLOGGERS_STATE_REQUEST) || urlinfoXml.page.length() == 1) {
  3249.               bloggers.value = parseInt(urlinfoXml.page.@count, 10) || 0;
  3250.               if (bloggers.value)
  3251.                 checkBloggers = true;
  3252.             }
  3253.             
  3254.             bloggers.buttonState = gYaURLInfo.BLOGGERS_STATE_RESPONSE;
  3255.           }
  3256.         } else {
  3257.           if (aUrlinfo & 1)
  3258.             cy.state = gYaURLInfo.CY_STATE_ERROR;
  3259.           
  3260.           if (aUrlinfo & 2)
  3261.             bloggers.buttonState = gYaURLInfo.BLOGGERS_STATE_ERROR;
  3262.         }
  3263.       }
  3264.     }
  3265.     
  3266.     try {
  3267.       var browser = aBrowser.boxObject.element.ownerDocument.defaultView;
  3268.       if (aBrowser == browser.gBrowser.selectedBrowser &&
  3269.           ((aURL == "undefined") || (aBrowser.webProgress.currentURI.spec == aURL)))
  3270.       {
  3271.         if (!aUrlinfo || (aUrlinfo & 1))
  3272.           browser.Ya.setCY(cy);
  3273.         
  3274.         if (!aUrlinfo || (aUrlinfo & 2))
  3275.           browser.Ya.Bloggers.setData(bloggers, checkBloggers);
  3276.       }
  3277.     } catch(e) {}
  3278.   },
  3279.  
  3280.   refreshCYInAllBrowsers: function() {
  3281.     this.browserButtons = null;
  3282.     
  3283.     gYaURLInfo.clear();
  3284.     
  3285.     for each (let browser in this.getWindows("navigator:browser")) {
  3286.       try {
  3287.         var yaButtons = browser.Ya.buttonsObject;
  3288.  
  3289.         var webProgress = browser.gBrowser.selectedBrowser.webProgress;
  3290.         webProgress.QueryInterface(Ci.nsIWebNavigation);
  3291.         webProgress.QueryInterface(Ci.nsIDocShell);
  3292.  
  3293.         var me = this;
  3294.  
  3295.         new G_Timer(function() {
  3296.           me.webProgressListener.onLocationChange(webProgress, yaButtons);
  3297.         }, 0);
  3298.  
  3299.       } catch(e) {}
  3300.     }
  3301.   },
  3302.   
  3303.   getWindow: function(aWindowType) {
  3304.     return this.windowMediator.getMostRecentWindow(aWindowType);
  3305.   },
  3306.   
  3307.   getWindows: function(aWindowType) {
  3308.     let windows = [],
  3309.         enumerator = this.windowMediator.getEnumerator(aWindowType);
  3310.     
  3311.     while (enumerator.hasMoreElements())
  3312.       windows.push(enumerator.getNext());
  3313.     
  3314.     return windows;
  3315.   },
  3316.   
  3317.   get passwordManager() {
  3318.     return Cc["@mozilla.org/autocomplete/search;1?name=YasearchPassComplete"].getService().wrappedJSObject;
  3319.   },
  3320.  
  3321.   getInstallDir: function() {
  3322.     return Cc["@mozilla.org/extensions/manager;1"]
  3323.                 .getService(Ci.nsIExtensionManager)
  3324.                 .getInstallLocation(EXT_ID)
  3325.                 .getItemLocation(EXT_ID);
  3326.   },
  3327.  
  3328.   getChromeDir: function() {
  3329.     var file = this.getInstallDir();
  3330.     file.append("chrome");
  3331.     return file;
  3332.   },
  3333.  
  3334.   getContentDir: function() {
  3335.     var file = this.getChromeDir();
  3336.     file.append("content");
  3337.     return file;
  3338.   },
  3339.  
  3340.   getYandexDir: function() {
  3341.     var file = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("ProfD", Ci.nsIFile);
  3342.  
  3343.     file.append(this.settingsFolderName);
  3344.  
  3345.     if (!file.exists())
  3346.       file.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
  3347.  
  3348.     if (!file.exists())
  3349.       throw "Can't create '" + this.settingsFolderName + "' folder in profile";
  3350.  
  3351.     return file;
  3352.   },
  3353.  
  3354.   getServicesDataFile: function() {
  3355.     if (!this.xmlServicesFile) {
  3356.       var file = this.getContentDir();
  3357.       file.append("services");
  3358.       file.append(this.xmlServicesFileName);
  3359.  
  3360.       if (!file.exists())
  3361.         throw this.xmlServicesFileName + " is missing";
  3362.  
  3363.       if (!file.isFile() || !file.isReadable())
  3364.         throw this.xmlServicesFileName + " has type or permission problems";
  3365.  
  3366.       this.xmlServicesFile = file;
  3367.     }
  3368.  
  3369.     return this.xmlServicesFile;
  3370.   },
  3371.   
  3372.   getServicesData: function() {
  3373.     return this.readFile(this.getServicesDataFile());
  3374.   },
  3375.  
  3376.   getUserDataFile: function() {
  3377.     var file = this.getYandexDir();
  3378.     file.append(this.xmlServicesFileName);
  3379.  
  3380.     if (!file.exists() || !file.isFile())
  3381.       file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0755);
  3382.  
  3383.     if (!file.exists() || !file.isFile())
  3384.       throw "Can't create '" + this.xmlServicesFileName + "' in profile";
  3385.  
  3386.     if (!file.isReadable())
  3387.       throw this.xmlServicesFileName + " has type or permission problems";
  3388.  
  3389.     return file;
  3390.   },
  3391.  
  3392.   refreshXmlServices: function() {
  3393.     if (this._xmlServices) {
  3394.       this._xmlServices = null;
  3395.       OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Data", "services");
  3396.     }
  3397.   },
  3398.  
  3399.   get xmlServices() {
  3400.     if (!this._xmlServices) {
  3401.       this._xmlServices = this.domParser.parseFromString(this.getServicesData(), "text/xml");
  3402.       this.appendUserSessionData("services");
  3403.     }
  3404.     return this._xmlServices;
  3405.   },
  3406.  
  3407.   appendUserSessionData: function(aType) {
  3408.     var userDataFile = this.getUserDataFile();
  3409.     if (!userDataFile)
  3410.       return;
  3411.  
  3412.     try {
  3413.       var userData = new XML(this.readFile(userDataFile));
  3414.     } catch(e) {
  3415.       return;
  3416.     }
  3417.  
  3418.     switch (aType) {
  3419.       case "services":
  3420.         let desktop = this.getServiceById("desktop");
  3421.         if (desktop && !this.isYandeskInstalled)
  3422.           desktop.removeAttribute("search-url");
  3423.  
  3424.         var timeNow = G_TIME_NOW;
  3425.         for each (var serv in userData.timestamps.serv) {
  3426.           let elem = this.getServiceById(serv.@id);
  3427.           if (elem)
  3428.             elem.setAttribute("service-timestamp", timeNow--);
  3429.         }
  3430.  
  3431.         break;
  3432.  
  3433.       case "data":
  3434.         for each (var user in userData.users.user) {
  3435.           if (user.@login && user.@login.toString() > "") {
  3436.             let login = user.@login.toString();
  3437.  
  3438.             if ("undefined" == typeof this.usersData[login])
  3439.               this.usersData[login] = {};
  3440.  
  3441.             this.usersData[login]._mailLastMaxId = user.mail.@last.toString().replace(/\D/g, "") || "0";
  3442.  
  3443.             this.usersData[login]._mailPermCounter = this.parseIntFromStr(user.mail.@counter.toString());
  3444.  
  3445.             this.Counters.appendUserSessionData(login, user.counters, user.yaru);
  3446.  
  3447.             this.usersData[login]._guidLastMsgTs = user.guid.@message_ts.toString().replace(/\D/g, "");
  3448.  
  3449.             this.usersData[login]._bookmarksRawXml = this.safeE4Xml(user.bookmarks.toString(), "<page><bookmarks/></page>", "page");
  3450.           }
  3451.         }
  3452.  
  3453.         break;
  3454.       
  3455.       default:
  3456.         break;
  3457.     }
  3458.   },
  3459.   
  3460.   flushUserData: function() {
  3461.     if (!(this.xmlServices && this.xmlServices.documentElement))
  3462.       return;
  3463.     
  3464.     var userDataFile = this.getUserDataFile();
  3465.     
  3466.     if (userDataFile && userDataFile.isWritable()) {
  3467.       var userData = new XML('<data><version value="' + this.version + '"/><timestamps/><users/><lastengine/></data>');
  3468.     
  3469.       let xpathStr = "//xul:toolbarbutton/xul:menupopup/xul:menuitem[starts-with(@id,'yasearchMenuIdPrefix-')]";
  3470.       let elems = this.xPathEvaluator.evaluate(xpathStr,
  3471.                                                this.getDOMDocContent("bar-services"),
  3472.                                                function() { return XULNS; },
  3473.                                                this.orSnapshotType,
  3474.                                                null);
  3475.       
  3476.       for (let i = 0, obj; (obj = elems.snapshotItem(i)); i++) {
  3477.         let len = userData.timestamps.serv.length();
  3478.         let serv = userData.timestamps.serv[len] = <serv/>;
  3479.         serv.@id = obj.getAttribute("id").split("yasearchMenuIdPrefix-")[1];
  3480.       }
  3481.       
  3482.       for (var data in this.usersData) {
  3483.         let len = userData.users.user.length();
  3484.         
  3485.         let user = userData.users.user[len] = <user/>;
  3486.         user.@login = data;
  3487.         
  3488.         user.mail = <mail/>;
  3489.         
  3490.         if (this.usersData[data]._mailLastMaxId > "0")
  3491.           user.mail.@last = this.usersData[data]._mailLastMaxId;
  3492.         
  3493.         if (this.usersData[data]._mailPermCounter > 0)
  3494.           user.mail.@counter = this.usersData[data]._mailPermCounter;
  3495.         
  3496.         if (this.usersData[data]._guidLastMsgTs > "") {
  3497.           user.guid = <guid/>;
  3498.           user.guid.@message_ts = this.usersData[data]._guidLastMsgTs;
  3499.         }
  3500.         
  3501.         if (this.usersData[data]._bookmarksRawXml) {
  3502.           user.bookmarks = <bookmarks/>;
  3503.           user.bookmarks = this.usersData[data]._bookmarksRawXml.toString();
  3504.         }
  3505.         
  3506.         //~ user.counters = this.Counters.getUserSessionDataForFlush(data);
  3507.         
  3508.         var [countersData, yaruData] = this.Counters.getUserSessionDataForFlush(data);
  3509.         user.counters = countersData;
  3510.         user.yaru = yaruData;
  3511.       }
  3512.       
  3513.       this.writeFile(userDataFile, userData);
  3514.     }
  3515.   },
  3516.   
  3517.   getXSLTemplate: function(fName) {
  3518.     if (!this._xsltemplates[fName]) {
  3519.       let fullName = "xsl-" + fName + ".xsl";
  3520.  
  3521.       let file = this.getContentDir();
  3522.       file.append("xsl-templ");
  3523.       file.append(fullName);
  3524.  
  3525.       if (!file.exists())
  3526.         throw "getXSLTemplate -- " + fullName + " is missing";
  3527.  
  3528.       let content = this.readFile(file);
  3529.  
  3530.       let include = this.xsltImportRegExp.exec(content);
  3531.       if (include && include[1]) {
  3532.         include = this.getInludeXSLTemplate(include[1]);
  3533.         content = content.replace(this.xsltImportRegExp, include);
  3534.       }
  3535.       
  3536.       this._xsltemplates[fName] = this.domParser.parseFromString(content, "text/xml");
  3537.     }
  3538.  
  3539.     return this._xsltemplates[fName];
  3540.   },
  3541.  
  3542.   getLocaleFile: function(aFileName) {
  3543.     let file = this.getInstallDir();
  3544.     
  3545.     ["chrome", "locale", "en-US"]
  3546.     .concat(aFileName.split("/"))
  3547.     .forEach(function(p) {
  3548.       file.append(p);
  3549.     });
  3550.     
  3551.     return file;
  3552.   },
  3553.   
  3554.   getInludeXSLTemplate: function(fName) {
  3555.     var incHashName = "include-" + fName;
  3556.     
  3557.     if (!this._xsltemplates[incHashName]) {
  3558.       var content = this.xmlSerializer.serializeToString(this.getXSLTemplate(fName));
  3559.       content = content.split("<xsl:output method=\"xml\" encoding=\"UTF-8\" indent=\"no\"/>")[1];
  3560.       content = content.split("</xsl:stylesheet>")[0];
  3561.       this._xsltemplates[incHashName] = content;
  3562.     }
  3563.     
  3564.     return this._xsltemplates[incHashName];
  3565.   },
  3566.  
  3567.   getDOMDocContent: function(xslName, aDataSource) {
  3568.     if (aDataSource && aDataSource.firstChild.localName == "parsererror")
  3569.       return null;
  3570.     
  3571.     const xsltProcessor = Cc["@mozilla.org/document-transformer;1?type=xslt"].createInstance(Ci.nsIXSLTProcessor);
  3572.     xsltProcessor.setParameter(null, "localeTld", this.localeTld);
  3573.     xsltProcessor.importStylesheet(this.getXSLTemplate(xslName));
  3574.     
  3575.     return xsltProcessor.transformToDocument(aDataSource || this.xmlServices).firstChild;
  3576.   },
  3577.  
  3578.   getDOMDocContent2: function(xslFilePath, aDataSource, aParameters) {
  3579.     switch (typeof aDataSource) {
  3580.       case "string"://filepath
  3581.         aDataSource = this.getXSLTemplate2(aDataSource);
  3582.         break;
  3583.  
  3584.       case "xml":
  3585.         aDataSource = this.domParser.parseFromString(aDataSource, "text/xml");
  3586.         if (aDataSource.firstChild.localName == "parsererror")
  3587.           return null;//throw new Error("getDOMDocContent2: not valid xml");
  3588.         break;
  3589.  
  3590.       default:
  3591.         break;
  3592.     }
  3593.     
  3594.     let parameters = aParameters || {};
  3595.  
  3596.     if (!("localeTld" in parameters))
  3597.       parameters.localeTld = this.localeTld;
  3598.     
  3599.     const xsltProcessor = Cc["@mozilla.org/document-transformer;1?type=xslt"].createInstance(Ci.nsIXSLTProcessor);
  3600.     
  3601.     for (let [paramName, paramValue] in Iterator(parameters))
  3602.       xsltProcessor.setParameter(null, paramName, paramValue);
  3603.     
  3604.     
  3605.     xsltProcessor.importStylesheet(this.getXSLTemplate2(xslFilePath));
  3606.     
  3607.     //if (aDocument)
  3608.       //return xsltProcessor.transformToFragment(aDataSource, aDocument);
  3609.     
  3610.     return xsltProcessor.transformToDocument(aDataSource).firstChild;
  3611.   },
  3612.  
  3613.   getXSLTemplate2: function(aFilePath) {
  3614.     var file = this.getContentDir();
  3615.     aFilePath.split("/").forEach(function(fpath) {
  3616.       file.append(fpath);
  3617.     });
  3618.  
  3619.     if (!file.exists())
  3620.       throw new Error("getXSLTemplate2 -- " + aFilePath + " is missing");
  3621.  
  3622.     return this.domParser.parseFromString(this.readFile(file), "text/xml");
  3623.   },
  3624.  
  3625.   getServiceById: function(id) {
  3626.     function nsResolver() {
  3627.       return "urn:data";
  3628.     }
  3629.     
  3630.     let elem = this.xPathEvaluator.evaluate("//xmlns:*[@id='" + id + "']",
  3631.                                             this.xmlServices.documentElement,
  3632.                                             nsResolver,
  3633.                                             this.unSnapshotType,
  3634.                                             null);
  3635.  
  3636.     return elem && elem.snapshotLength ? elem.snapshotItem(0) : null;
  3637.   },
  3638.  
  3639.   setServiceTimestamp: function(id) {
  3640.     let elem = this.getServiceById(id);
  3641.     if (!elem)
  3642.       return null;
  3643.  
  3644.     elem.setAttribute("service-timestamp", G_TIME_NOW);
  3645.     OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Services", false);
  3646.     
  3647.     return elem;
  3648.   },
  3649.  
  3650.   getDefaultSearchEngine: function() {
  3651.     function nsResolver() {
  3652.       return "urn:data";
  3653.     }
  3654.     
  3655.     let elem = this.xPathEvaluator.evaluate("//xmlns:*[@search-url]",
  3656.                                             this.xmlServices.documentElement,
  3657.                                             nsResolver,
  3658.                                             this.unSnapshotType,
  3659.                                             null);
  3660.  
  3661.     return elem && elem.snapshotLength ? elem.snapshotItem(0).getAttribute("id") : null;
  3662.   },
  3663.  
  3664.   get searchService() {
  3665.     if (!this._searchService)
  3666.       this._searchService = Cc["@mozilla.org/browser/search-service;1"].getService(Ci.nsIBrowserSearchService);
  3667.  
  3668.     return this._searchService;
  3669.   },
  3670.   
  3671.   get searchEngineSuggestURL() {
  3672.     return this._searchEngineSuggestURL ||
  3673.            (this._searchEngineSuggestURL = "http://suggest.yandex." + this.localeTld + "/suggest-ff.cgi?part=");
  3674.   },
  3675.   
  3676.   //see nsIYaSearchSuggestions
  3677.   get defaultYandexSearchEngine() {
  3678.     return {
  3679.       _self: this,
  3680.       
  3681.       supportsResponseType: function(aType) {
  3682.         return aType == "application/x-suggestions+json";
  3683.       },
  3684.       
  3685.       getSubmission: function(aData, aResponseType) {
  3686.         return {
  3687.           postData: null,
  3688.           uri: this._self.makeURI(this._self.searchEngineSuggestURL + encodeURIComponent(aData))
  3689.         }
  3690.       }
  3691.     };
  3692.   },
  3693.   
  3694.   get currentSearchEngine() {
  3695.     if (!this._yaCurrentEngine.isYandex)
  3696.       return this.searchService.getEngineByName(this._yaCurrentEngine.name);
  3697.  
  3698.     return {
  3699.       _self: this,
  3700.  
  3701.       _currentEngine: this._yaCurrentEngine,
  3702.  
  3703.       name: "___ya___" + this._yaCurrentEngine.name,
  3704.  
  3705.       supportsResponseType: function(aType) {
  3706.         return aType == "application/x-suggestions+json";
  3707.       },
  3708.  
  3709.       getSubmission: function(aData, aResponseType) {
  3710.         return {
  3711.           postData: null,
  3712.           uri: this._self.makeURI(this._self.searchEngineSuggestURL + encodeURIComponent(aData))
  3713.         }
  3714.       }
  3715.     };
  3716.   },
  3717.  
  3718.   desktopPinger: {
  3719.     checkService: function() {
  3720.       if (this._desktopServicePath) {
  3721.         var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
  3722.         req.open("HEAD", this._desktopServicePath);
  3723.  
  3724.         var target = req.QueryInterface(Ci.nsIDOMEventTarget);
  3725.  
  3726.         if (this.__triesCount) {//not first time
  3727.           target.addEventListener("load", this._reloadSearchErrorPages.bind(this), false);
  3728.           target.addEventListener("error", this._startTimer.bind(this), false);
  3729.         } else {
  3730.           target.addEventListener("error", this._pingDesktopServiceCallback.bind(this), false);
  3731.         }
  3732.  
  3733.         try {
  3734.           req.send(null);
  3735.         } catch(e) {}
  3736.       }
  3737.     },
  3738.  
  3739.     __timer: null,
  3740.     __triesCount: 0,
  3741.  
  3742.     _reloadSearchErrorPages: function() {
  3743.       this._stop(true);
  3744.  
  3745.       var desktopServicePath = this._desktopServicePath;
  3746.  
  3747.       new G_Timer(function() {
  3748.         for each (var browser in gYaSearchService.getWindows("navigator:browser")) {
  3749.           var browserInstance = browser.getBrowser();
  3750.  
  3751.           var numTabs = browserInstance.tabContainer.childNodes.length;
  3752.           for (var index = 0; index < numTabs; index++) {
  3753.             var currentBrowser = browserInstance.getBrowserAtIndex(index);
  3754.             if (desktopServicePath == currentBrowser.currentURI.prePath &&
  3755.                 /^about\:neterror/.test(currentBrowser.contentDocument.documentURI) &&
  3756.                 !currentBrowser.hasAttribute("busy")) {
  3757.               currentBrowser.loadURI(currentBrowser.currentURI.spec);
  3758.             }
  3759.           }
  3760.         }
  3761.       }, 3000);
  3762.     },
  3763.  
  3764.     _stop: function(aDropCounter) {
  3765.       if (this.__timer)
  3766.         this.__timer.cancel();
  3767.  
  3768.       this.__timer = null;
  3769.  
  3770.       if (aDropCounter)
  3771.         this.__triesCount = 0;
  3772.     },
  3773.  
  3774.     _startTimer: function() {
  3775.       if (this.__triesCount++ < 10) {
  3776.         this._stop();
  3777.         this.__timer = new G_Timer(this.checkService.bind(this, true), 1000);
  3778.       } else {
  3779.         this._stop(true);
  3780.       }
  3781.     },
  3782.  
  3783.     __desktopServicePath: null,
  3784.  
  3785.     get _desktopServicePath() {
  3786.       if (this.__desktopServicePath === null) {
  3787.         this.__desktopServicePath = false;
  3788.  
  3789.         var desktopService = gYaSearchService.getServiceById("desktop");
  3790.         if (desktopService && desktopService.hasAttribute("search-url")) {
  3791.           var uri = gYaSearchService.makeURI(desktopService.getAttribute("search-url"));
  3792.           if (uri)
  3793.             this.__desktopServicePath = uri.prePath;
  3794.         }
  3795.       }
  3796.  
  3797.       return this.__desktopServicePath;
  3798.     },
  3799.  
  3800.     _pingDesktopServiceCallback: function(aReq) {
  3801.       var exePath = gYaSearchService.getYandeskProgramDir();
  3802.  
  3803.       if (exePath) {
  3804.         var desctopExeFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
  3805.         desctopExeFile.initWithPath(exePath);
  3806.         desctopExeFile.append("yandesk.exe");
  3807.  
  3808.         if (desctopExeFile.exists() && desctopExeFile.isFile()) {
  3809.           desctopExeFile.launch();
  3810.           this._startTimer();
  3811.         }
  3812.       }
  3813.     }
  3814.   },
  3815.  
  3816.   getSearchEngineUrl: function(aId, aText, aHost, aStatData) {
  3817.     var engine,
  3818.         result = { isYandexSearch: false },
  3819.         id = aId.replace(/^__/, "");
  3820.  
  3821.     if (id == aId) {
  3822.       result.isYandexSearch = true;
  3823.  
  3824.       engine = this.getServiceById(aId);
  3825.  
  3826.       if (engine) {
  3827.  
  3828.         if (aId === "desktop" && this.isYandeskInstalled)
  3829.           this.desktopPinger.checkService();
  3830.  
  3831.         var appendix = aHost && engine.hasAttribute("search-site") ?
  3832.                            "&" + engine.getAttribute("search-site") + "=" + encodeURIComponent(aHost) :
  3833.                            "";
  3834.  
  3835.         var searchURL = engine.getAttribute("search-url") + (encodeURIComponent(aText)) + appendix;
  3836.  
  3837.         result.url = this.appendStatData2Url(searchURL, (typeof aStatData == "undefined") ? {clid:2} : aStatData);
  3838.  
  3839.         var action = engine.hasAttribute("search-action") ?
  3840.                          engine.getAttribute("search-action") :
  3841.                          (engine.hasAttribute("action") ? engine.getAttribute("action") : null);
  3842.         
  3843.         result.statData = action ? {action: action} : null;
  3844.         
  3845.         result.postData = null;
  3846.       }
  3847.     } else {
  3848.       engine = this.searchService.getEngineByName(id);
  3849.       if (engine) {
  3850.         var submission = engine.getSubmission(aText, null);
  3851.         if (submission) {
  3852.           result.url = submission.uri.spec;
  3853.           result.statData = {action: "4300"};
  3854.           result.postData = submission.postData;
  3855.         }
  3856.       }
  3857.     }
  3858.  
  3859.     return result.url ? result : null;
  3860.   },
  3861.  
  3862.   setCurrentSearchEngine: function(aId) {
  3863.     var elem, result = {}, id = aId.replace(/^__/, "");
  3864.  
  3865.     this._yaCurrentEngine = {isYandex: false, name: id};
  3866.  
  3867.     if (id == aId) {
  3868.       this._yaCurrentEngine.isYandex = true;
  3869.       
  3870.       function nsResolver() {
  3871.         return "urn:data";
  3872.       }
  3873.       
  3874.       var obj, elems = this.xPathEvaluator.evaluate("//xmlns:*[@last-engine]",
  3875.                                                  this.xmlServices.documentElement,
  3876.                                                  nsResolver,
  3877.                                                  this.unSnapshotType,
  3878.                                                  null);
  3879.  
  3880.       for (var i = 0; (obj = elems.snapshotItem(i)); i++)
  3881.         obj.removeAttribute("last-engine");
  3882.  
  3883.       elem = this.getServiceById(aId);
  3884.  
  3885.       if (elem) {
  3886.         elem.setAttribute("last-engine", "true");
  3887.         result.searchUrl = elem.getAttribute("search-url");
  3888.         result.searchSite = elem.getAttribute("search-site");
  3889.         result.label = elem.getAttribute("label2") || elem.getAttribute("label");
  3890.         result.image = CHROME_IMAGES + elem.getAttribute("image") + ".png";
  3891.       }
  3892.     } else {
  3893.       elem = this.searchService.getEngineByName(id);
  3894.       if (elem) {
  3895.         result.label = id;
  3896.         result.image = elem.iconURI ? elem.iconURI.spec : "";
  3897.         result.searchUrl = elem.uri;
  3898.       }
  3899.     }
  3900.  
  3901.     return result.label ? result : null;
  3902.   },
  3903.  
  3904.   getSearchSettingsForSlovari: function(aText, aEvent, aCallback) {
  3905.     this.xmlHttpRequest("http://export.yandex.ru/mycookie.xml",
  3906.                         {callbackFunc: this.getSearchSettingsForSlovariCallback.bind(this, aText, aEvent, aCallback)});
  3907.   },
  3908.  
  3909.   getSearchSettingsForSlovariCallback: function(aReq, aText, aEvent, aCallback) {
  3910.     let type = "slovari-services";
  3911.     if (!this.isReqError(aReq) && /<translate>1<\/translate>/.test(aReq.target.responseText))
  3912.       type = "lingvo";
  3913.     
  3914.     let engineData = this.getSearchEngineUrl(type, aText);
  3915.     aCallback(engineData.url, aEvent, engineData.statData);
  3916.   },
  3917.   
  3918.   uninit: function() {
  3919.     if (this._inited) {
  3920.       this._inited = false;
  3921.       
  3922.       ["cookie-changed",
  3923.        "http-on-modify-request",
  3924.        "http-on-examine-response"]
  3925.       .forEach(function(aTopicName) {
  3926.         OBSERVER_SERVICE.removeObserver(this, aTopicName, true);
  3927.       }, this);
  3928.       
  3929.       this.cancelLogoutConnection();
  3930.       
  3931.       this.clearAllTimers();
  3932.       
  3933.       if (gYaInstaller && !gYaInstaller.isBarUninstalled)
  3934.         this.flushUserData();
  3935.       
  3936.       //[2do]
  3937.       this._browserButtons = null;
  3938.     }
  3939.     
  3940.     this._searchService = null;
  3941.   },
  3942.  
  3943.   handlePrefChanges: function(aData) {
  3944.     switch (aData.split("yasearch.")[1]) {
  3945.       case "general.debug.enabled":
  3946.         this.debug = this.getBoolPref(aData);
  3947.         break;
  3948.  
  3949.       case "general.ui.show.cy.value":
  3950.         this.refreshCYInAllBrowsers();
  3951.         break;
  3952.  
  3953.       case "general.ui.urlbar.corrector.state":
  3954.         OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Data", "urlbar-corrector");
  3955.         break;
  3956.  
  3957.       case "http.update.weathertraff.interval":
  3958.         this.updateHttpTimers("weathertraff");
  3959.         break;
  3960.  
  3961.       case "http.update.interval":
  3962.         this.updateHttpTimers("mailandfeeds");
  3963.         break;
  3964.  
  3965.       case "http.auto.enabled":
  3966.         this.updateHttpTimers();
  3967.         break;
  3968.  
  3969.       case "general.ui.mail.integration":
  3970.         OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Data", "mail-integration");
  3971.         break;
  3972.     }
  3973.   },
  3974.  
  3975.   get isCountersAutoUpdateEnabled() {
  3976.     return this.getBoolPref("yasearch.http.auto.enabled");
  3977.   },
  3978.  
  3979.   updateHttpTimers: function(aTimerType) {
  3980.     var autoUpdateEnabled = this.isCountersAutoUpdateEnabled;
  3981.  
  3982.     if (!aTimerType || aTimerType == "weathertraff") {
  3983.       var time = autoUpdateEnabled ? (this.getIntPref("yasearch.http.update.weathertraff.interval") * MIN_SEC || 0) : 0;
  3984.       this.yaCity.updateObserversTime(time);
  3985.     }
  3986.  
  3987.     if (!aTimerType || aTimerType == "mailandfeeds") {
  3988.       this.checkTimeOut._MailAndFeeds = autoUpdateEnabled ? (this.getIntPref("yasearch.http.update.interval") * MIN_SEC || 0) : 0;
  3989.       this.isLogin && this.checkTimeOut._MailAndFeeds > 0 ?
  3990.           this.setTimer("_MailAndFeeds") : this.clearTimer("_MailAndFeeds");
  3991.     }
  3992.   },
  3993.  
  3994.   get barPref() {
  3995.     if (!this._barPref)
  3996.       this._barPref = " YB/" + this.barExtensionVersionWithLocale;
  3997.  
  3998.     return this._barPref;
  3999.   },
  4000.  
  4001.   get barPrefReg() {
  4002.     if (!this._barPrefReg)
  4003.       this._barPrefReg = new RegExp(this.barPref.replace(/(\.|\-)/g, "\\\$1"));
  4004.  
  4005.     return this._barPrefReg;
  4006.   },
  4007.  
  4008.   __localeTld: null,
  4009.   get localeTld() {
  4010.     if (!this.__localeTld)
  4011.       this.__localeTld = this.getString("locale.tld");
  4012.  
  4013.     return this.__localeTld;
  4014.   },
  4015.  
  4016.   isYandexHost: function(aHost) {
  4017.     return /(^|\.)(yandex\.(ru|ua|by|kz|net|com)|(ya|narod|moikrug)\.ru)$/i.test(aHost);
  4018.   },
  4019.  
  4020.   _getDOMWindowForRequest: function(aRequest) {
  4021.     /*
  4022.     var loadContext;
  4023.     try {
  4024.       loadContext = aRequest.QueryInterface(Ci.nsIChannel).notificationCallbacks.getInterface(Ci.nsILoadContext);
  4025.     } catch(e) {
  4026.       try {
  4027.         loadContext = aRequest.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
  4028.       } catch(ex) {
  4029.         loadContext = null;
  4030.       }
  4031.     }
  4032.     // loadContext.topWindow, loadContext.DOMWindow
  4033.     return loadContext ? loadContext.DOMWindow : null;
  4034.     */
  4035.     
  4036.     try {
  4037.       return aRequest.loadGroup.groupObserver.QueryInterface(Ci.nsIWebProgress).DOMWindow;
  4038.     } catch(e) {}
  4039.  
  4040.     return null;
  4041.   },
  4042.  
  4043.   _getTabForDOMWindow: function(aDOMWindow) {
  4044.     var tab = null;
  4045.  
  4046.     var docShellTree = aDOMWindow.QueryInterface(Ci.nsIInterfaceRequestor)
  4047.                                  .getInterface(Ci.nsIWebNavigation)
  4048.                                  .QueryInterface(Ci.nsIDocShellTreeItem);
  4049.  
  4050.     if (docShellTree.itemType == Ci.nsIDocShellTreeItem.typeContent) {
  4051.       try {
  4052.         var chromeWindow = docShellTree.rootTreeItem
  4053.                           .QueryInterface(Ci.nsIInterfaceRequestor)
  4054.                           .getInterface(Ci.nsIDOMWindow)
  4055.                           .wrappedJSObject;
  4056.  
  4057.         if (!chromeWindow)
  4058.           return null;
  4059.  
  4060.         tab = chromeWindow.getBrowser()
  4061.                           .getBrowserForDocument(aDOMWindow.document);
  4062.  
  4063.         if (!tab)
  4064.           return null;
  4065.  
  4066.         if (!tab.yaSearchTHandler) {
  4067.           var YaProgressListener = chromeWindow.YaProgressListener;
  4068.           if (YaProgressListener)
  4069.             YaProgressListener.addTabListener(tab);
  4070.         }
  4071.  
  4072.         if (tab.yaSearchTHandler)
  4073.           return tab;
  4074.  
  4075.       } catch(e) {}
  4076.     }
  4077.  
  4078.     return null;
  4079.   },
  4080.  
  4081.   _getYaSearchTHandlerForRequest: function(aRequest) {
  4082.     var win = this._getDOMWindowForRequest(aRequest);
  4083.     if (win && win === win.parent) {
  4084.       var tab = this._getTabForDOMWindow(win);
  4085.  
  4086.       if (tab)
  4087.         return tab.yaSearchTHandler;
  4088.     }
  4089.  
  4090.     return null;
  4091.   },
  4092.  
  4093.   observe: function(aSubject, aTopic, aData) {
  4094.     switch (aTopic) {
  4095.       case "http-on-modify-request":
  4096.         aSubject.QueryInterface(Ci.nsIHttpChannel);
  4097.  
  4098.         if (this.isYandexHost(aSubject.URI.host)) {
  4099.           try {
  4100.             var ua = aSubject.getRequestHeader("User-Agent");
  4101.             if (!this.barPrefReg.test(ua))
  4102.               aSubject.setRequestHeader("User-Agent", ua + this.barPref, false);
  4103.           } catch(e) {}
  4104.         }
  4105.  
  4106.         try {
  4107.           if (aSubject.loadFlags & Ci.nsIHttpChannel.LOAD_DOCUMENT_URI) {
  4108.             var tabHandler = this._getYaSearchTHandlerForRequest(aSubject);
  4109.             if (tabHandler)
  4110.               tabHandler.onTransferStart(aSubject.URI.spec);
  4111.           }
  4112.         } catch(e) {}
  4113.  
  4114.         break;
  4115.  
  4116.       case "http-on-examine-response":
  4117.         aSubject.QueryInterface(Ci.nsIHttpChannel);
  4118.  
  4119.         try {
  4120.           if (aSubject.loadFlags & Ci.nsIHttpChannel.LOAD_DOCUMENT_URI) {
  4121.             var tabHandler = this._getYaSearchTHandlerForRequest(aSubject);
  4122.             if (tabHandler)
  4123.               tabHandler.onTransferStop();
  4124.           }
  4125.         } catch(e) {}
  4126.  
  4127.         break;
  4128.  
  4129.       case "cookie-changed":
  4130.         var rootDomain = this.yaRootDomain;
  4131.  
  4132.         if (rootDomain && aSubject && aSubject instanceof Ci.nsICookie &&
  4133.             aSubject.host == rootDomain && aSubject.path == "/") {
  4134.           var name = aSubject.name;
  4135.  
  4136.           if (name == "Session_id" || name == "yandex_login") {
  4137.             var val = "";
  4138.             try {
  4139.               val = aSubject.value.toString();
  4140.             } catch(e) {}
  4141.  
  4142.             if (aData == "deleted" || !val)
  4143.               val = false;
  4144.  
  4145.             var needRecheckAuth = !!(aData == "changed" && !this.isLogin);
  4146.  
  4147.             this.session = {
  4148.               val: val,
  4149.               name: (name == "Session_id" ? "Id" : "Login")
  4150.             };
  4151.  
  4152.             if (needRecheckAuth && (this.session.id || this.session.login))
  4153.               this.setSessionFromCookies(false);
  4154.           }
  4155.         }
  4156.         break;
  4157.       
  4158.       case "nsPref:changed":
  4159.         this.handlePrefChanges(aData);
  4160.         break;
  4161.       
  4162.       case "profile-after-change":
  4163.         this.init();
  4164.         
  4165.         if (this._inited) {
  4166.           let prefInternal = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch2);
  4167.           prefInternal.addObserver("yasearch", this, true);
  4168.         }
  4169.         break;
  4170.  
  4171.       case "profile-before-change":
  4172.         if (this._inited) {
  4173.           let prefInternal = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch2);
  4174.           prefInternal.removeObserver("yasearch", this, true);
  4175.         }
  4176.         
  4177.         this.uninit();
  4178.         break;
  4179.   
  4180.       case "app-startup":
  4181.         OBSERVER_SERVICE.addObserver(this, "browser-ui-startup-complete", false);
  4182.         OBSERVER_SERVICE.addObserver(this, "sessionstore-windows-restored", false);
  4183.         
  4184.         ["profile-before-change",
  4185.          "profile-after-change",
  4186.          "quit-application"]
  4187.         .forEach(function(aTopicName) {
  4188.           OBSERVER_SERVICE.addObserver(this, aTopicName, true);
  4189.         }, this);
  4190.         
  4191.         break;
  4192.       
  4193.       case "browser-ui-startup-complete":
  4194.         OBSERVER_SERVICE.removeObserver(this, "browser-ui-startup-complete");
  4195.         this.onBrowserUIStartupComplete();
  4196.         break;
  4197.       
  4198.       case "sessionstore-windows-restored":
  4199.         OBSERVER_SERVICE.removeObserver(this, "sessionstore-windows-restored");
  4200.         this.onSessionstoreWindowsRestored();
  4201.         break;
  4202.         
  4203.       case "quit-application":
  4204.         //this.shutdown();
  4205.         break;
  4206.     }
  4207.   },
  4208.  
  4209.   loadUserSheet: function(aFile) {
  4210.     if (aFile && aFile.exists() && aFile.isFile() && aFile.isReadable()) {
  4211.       var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
  4212.       var u = this.makeFileURI(aFile);
  4213.  
  4214.       if (sss.sheetRegistered(u, sss.USER_SHEET))
  4215.         sss.unregisterSheet(u, sss.USER_SHEET);
  4216.  
  4217.       sss.loadAndRegisterSheet(u, sss.USER_SHEET);
  4218.     }
  4219.   },
  4220.  
  4221.   hackKnownSkins: function() {
  4222.     var selectedSkin = this.getCharPref("extensions.lastSelectedSkin") || this.getCharPref("general.skins.selectedSkin");
  4223.  
  4224.     if (selectedSkin) {
  4225.       if (selectedSkin == "classic/1.0")
  4226.         selectedSkin = "classic";
  4227.  
  4228.       var cssFile = this.getChromeDir();
  4229.       cssFile.append("skin");
  4230.       cssFile.append("themes-hacks");
  4231.  
  4232.       var platformCssFile,
  4233.           platformName = this.AppInfo.OS.platformName;
  4234.  
  4235.       if (platformName) {
  4236.         platformCssFile = cssFile.clone();
  4237.         platformCssFile.append(platformName);
  4238.       }
  4239.  
  4240.       [cssFile, platformCssFile].forEach(function(cssFile) {
  4241.         if (cssFile) {
  4242.           try {
  4243.             cssFile.append(selectedSkin + ".css");
  4244.             if (cssFile.exists() && cssFile.isFile())
  4245.               this.loadUserSheet(cssFile);
  4246.           } catch(e) {}
  4247.         }
  4248.       }, this)
  4249.     }
  4250.  
  4251.     var extSheetsDir = this.getChromeDir();
  4252.     extSheetsDir.append("skin");
  4253.     extSheetsDir.append("extensions-hacks");
  4254.  
  4255.     if (extSheetsDir.exists() && extSheetsDir.isDirectory()) {
  4256.       var em = Cc["@mozilla.org/extensions/manager;1"].getService(Ci.nsIExtensionManager);
  4257.       var extSheetsDirEnumerator = extSheetsDir.directoryEntries;
  4258.       while (extSheetsDirEnumerator.hasMoreElements()) {
  4259.         var entry = extSheetsDirEnumerator.getNext().QueryInterface(Ci.nsIFile);
  4260.         if (entry.isFile()) {
  4261.           var name = entry.leafName;
  4262.           if (/.\.css$/.test(name)) {
  4263.             var emItem = em.getItemForID(name.slice(0, -4));
  4264.             if (emItem && emItem.type == Ci.nsIUpdateItem.TYPE_EXTENSION)
  4265.               this.loadUserSheet(entry);
  4266.           }
  4267.         }
  4268.       }
  4269.     }
  4270.  
  4271.   },
  4272.  
  4273.   /** **************************************************************************************************** **/
  4274.  
  4275.   parseIntFromStr: function(aStr) {
  4276.     var res = aStr ? parseInt(aStr.toString().replace(/\D/g,""), 10) : 0;
  4277.     return isNaN(res) ? 0 : res;
  4278.   },
  4279.  
  4280.   safeUnicode: function(aString) {
  4281.     if (!/[^\r\n\x9\xA\xD\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]/.test(aString))
  4282.       return aString;
  4283.     
  4284.     return aString.replace(/[^\r\n\x9\xA\xD\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]/g, "");
  4285.   },
  4286.  
  4287.   getStringBundle: function() {
  4288.     if (!this.stringBundle) {
  4289.       var strBundleService = Cc["@mozilla.org/intl/stringbundle;1"].createInstance(Ci.nsIStringBundleService);
  4290.       this.stringBundle = strBundleService.createBundle("chrome://yasearch/locale/yasearch.properties");
  4291.     }
  4292.     return this.stringBundle;
  4293.   },
  4294.  
  4295.   getString: function(aName) {
  4296.     return this.getStringBundle().GetStringFromName(aName);
  4297.   },
  4298.  
  4299.   getFormattedString: function(aName, aStrArray) {
  4300.     return this.getStringBundle().formatStringFromName(aName, aStrArray, aStrArray.length);
  4301.   },
  4302.  
  4303.   getFormattedStringL18End: function(aName, aStrArray) {
  4304.     var n = aStrArray[0], _cases = [2,0,1,1,1,2,2,2,2,2];
  4305.     var l18End = aName + "L18End" + ((n%100>10)&&(n%100<20) ? 2 : _cases[n%10]);
  4306.     return this.getFormattedString(aName, aStrArray) + this.getString(l18End);
  4307.   },
  4308.  
  4309.   __localeDependedStrBundleService: null,
  4310.   getLocaleDependedUrl: function(aUrl) {
  4311.     if (!this.__localeDependedStrBundleService) {
  4312.       var strBundleService = Cc["@mozilla.org/intl/stringbundle;1"].createInstance(Ci.nsIStringBundleService);
  4313.       this.__localeDependedStrBundleService = strBundleService.createBundle("chrome://yasearch/locale/links/links.properties");
  4314.     }
  4315.  
  4316.     return this.__localeDependedStrBundleService.GetStringFromName(aUrl);
  4317.   },
  4318.  
  4319.   /** **************************************************************************************************** **/
  4320.  
  4321.   utils: {
  4322.     get G_Timer() {
  4323.       return G_Timer;
  4324.     }
  4325.   },
  4326.  
  4327.   /** **************************************************************************************************** **/
  4328.  
  4329.   writeFile: function(aFile, aData) {
  4330.     //if (!(aFile instanceof Ci.nsIFile && aFile.isWritable()))
  4331.     //  return;
  4332.     
  4333.     try {
  4334.       var chunk = UConverter.ConvertFromUnicode(aData);
  4335.       
  4336.       var os = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
  4337.       os.init(aFile, 0x02 | 0x08 | 0x20, 0755, 0);
  4338.       
  4339.       var result = os.write(chunk, chunk.length);
  4340.       os.close();
  4341.     } catch(e) {}
  4342.   },
  4343.  
  4344.   readFile: function(aFile) {
  4345.     var fileContents = "";
  4346.     
  4347.     //if (aFile.exists() && aFile.isFile() && aFile.isReadable()) {
  4348.     var is = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
  4349.     is.init(aFile, 0x01, 0, is.CLOSE_ON_EOF);
  4350.     
  4351.     var sis = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream);
  4352.     sis.init(is);
  4353.     
  4354.     while(sis.available() > 0)
  4355.       fileContents += UConverter.ConvertToUnicode(sis.read(sis.available()));
  4356.     
  4357.     is.close();
  4358.     sis.close();
  4359.     //}
  4360.     
  4361.     return this.safeUnicode(fileContents);
  4362.   },
  4363.  
  4364.   prefBranchInternal: Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch2),
  4365.   prefBranch:         Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch),
  4366.  
  4367.   setBoolPref: function(aName, aValue) {
  4368.     this.prefBranch.setBoolPref(aName, aValue);
  4369.   },
  4370.  
  4371.   getBoolPref: function(aName) {
  4372.     let rv = null;
  4373.     try {
  4374.       rv = this.prefBranch.getBoolPref(aName);
  4375.     } catch(e) {}
  4376.     
  4377.     return rv;
  4378.   },
  4379.  
  4380.   setIntPref: function(aName, aValue) {
  4381.     this.prefBranch.setIntPref(aName, aValue);
  4382.   },
  4383.  
  4384.   getIntPref: function(aName) {
  4385.     let rv = null;
  4386.     try {
  4387.       rv = this.prefBranch.getIntPref(aName);
  4388.       if (rv < 0)
  4389.         rv = 0;
  4390.     } catch(e) {}
  4391.     
  4392.     return rv;
  4393.   },
  4394.  
  4395.   setCharPref: function(aName, aValue) {
  4396.     this.prefBranch.setCharPref(aName, aValue);
  4397.   },
  4398.  
  4399.   getCharPref: function(aName) {
  4400.     let rv = null;
  4401.     try {
  4402.       rv = this.prefBranch.getCharPref(aName);
  4403.     } catch(e) {}
  4404.     
  4405.     return rv;
  4406.   },
  4407.  
  4408.   getComplexValue: function(aName) {
  4409.     let rv = null;
  4410.     try {
  4411.       rv = this.prefBranch.getComplexValue(aName, Ci.nsIPrefLocalizedString).data;
  4412.     } catch(e) {}
  4413.     
  4414.     return rv;
  4415.   },
  4416.  
  4417.   setComplexValue: function(aName, aValue) {
  4418.     try {
  4419.       let str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
  4420.       str.data = aValue;
  4421.       this.prefBranch.setComplexValue(aName, Ci.nsISupportsString, str);
  4422.     } catch(e) {}
  4423.   },
  4424.   
  4425.   /*
  4426.   deletePrefBranch: function(aName) {
  4427.     try {
  4428.       this.prefBranch.deleteBranch(aName);
  4429.     } catch(e) {}
  4430.   },
  4431.   */
  4432.   
  4433.   resetPrefBranch: function(aPrefBranchName) {
  4434.     if (!aPrefBranchName)
  4435.       return;
  4436.     
  4437.     if (!/\.$/.test(aPrefBranchName))
  4438.       aPrefBranchName += ".";
  4439.     
  4440.     this.prefBranch.getChildList(aPrefBranchName, {}).forEach(function(aPrefName) {
  4441.       try {
  4442.         this.resetPref(aPrefName);
  4443.       } catch(e) {}
  4444.     }, this);
  4445.   },
  4446.   
  4447.   resetPref: function(aPrefName) {
  4448.     try {
  4449.       this.prefBranch.clearUserPref(aPrefName);
  4450.     } catch(e) {}
  4451.   },
  4452.   
  4453.   getBrowserHomePage: function() {
  4454.     let url;
  4455.     try {
  4456.       url = this.getComplexValue("browser.startup.homepage");
  4457.     } catch(e) {}
  4458.  
  4459.     if (!url) {
  4460.       var SBS = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
  4461.       var configBundle = SBS.createBundle("resource:/browserconfig.properties");
  4462.       url = configBundle.GetStringFromName("browser.startup.homepage");
  4463.     }
  4464.  
  4465.     return url;
  4466.   },
  4467.  
  4468.   setBrowserHomePage: function(aValue) {
  4469.     if (this.yaDefence)
  4470.       this.yaDefence.protectedHomepage = aValue;
  4471.  
  4472.     this.setComplexValue("browser.startup.homepage", aValue);
  4473.   },
  4474.   
  4475.   getBrowserKeywordURL: function() {
  4476.     let url;
  4477.     try {
  4478.       url = this.getComplexValue("keyword.URL") || this.getCharPref("keyword.URL");
  4479.     } catch(e) {}
  4480.  
  4481.     if (!url) {
  4482.       const SBS = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
  4483.       let configBundle = SBS.createBundle("chrome://browser-region/locale/region.properties");
  4484.       url = configBundle.GetStringFromName("keyword.URL");
  4485.     }
  4486.  
  4487.     return url;
  4488.   },
  4489.  
  4490.   setBrowserKeywordURL: function(aValue) {
  4491.     this.setComplexValue("keyword.URL", aValue);
  4492.   },
  4493.   
  4494.   get appOS() {
  4495.     var gApp  = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).QueryInterface(Ci.nsIXULRuntime);
  4496.     return gApp.OS;
  4497.   },
  4498.  
  4499.   get windowsOS() {
  4500.     return ("nsIWindowsRegKey" in Ci) ? true : false;
  4501.   },
  4502.  
  4503.   getYandeskProgramDir: function() {
  4504.     return this.WinReg.read("HKCU", "Software\\Yandex\\Yandesk", "ProgramDir");
  4505.   },
  4506.  
  4507.   get isYandeskInstalled() {
  4508.     return !!this.getYandeskProgramDir();
  4509.   },
  4510.  
  4511.   getYaOnlineProgramDir: function() {
  4512.     return this.WinReg.read("HKCU", "Software\\Yandex\\Online", "ProgramDir");
  4513.   },
  4514.  
  4515.   get isYaOnlineInstalled() {
  4516.     return !!this.getYaOnlineProgramDir();
  4517.   },
  4518.  
  4519.   WinReg: {
  4520.     /* ************************************** *
  4521.      *  HKCU eq. USER    eq. CURRENT_USER  eq. HKEY_CURRENT_USER
  4522.      *  HKCR eq. ROOT    eq. CLASSES_ROOT  eq. HKEY_CLASSES_ROOT
  4523.      *  HKLM eq. MACHINE eq. LOCAL_MACHINE eq. HKEY_LOCAL_MACHINE
  4524.      * ************************************** */
  4525.     _convertName2Key: function(aKeyName) {
  4526.       aKeyName = aKeyName.replace(/^(HKEY_)/i, "").toUpperCase();
  4527.  
  4528.       var keyNamesHash = {
  4529.         "CURRENT_USER":  ["HKCU", "USER", "CURRENT_USER"],
  4530.         "CLASSES_ROOT":  ["HKCR", "ROOT", "CLASSES_ROOT"],
  4531.         "LOCAL_MACHINE": ["HKLM", "MACHINE", "LOCAL_MACHINE"]
  4532.       };
  4533.  
  4534.       var keyName;
  4535.       for (var kName in keyNamesHash) {
  4536.         if (keyNamesHash[kName].indexOf(aKeyName) !== -1) {
  4537.           keyName = kName;
  4538.           break;
  4539.         }
  4540.       }
  4541.  
  4542.       if (!keyName)
  4543.         throw new TypeError("nsIYaSearch.WinReg: wrong key name");
  4544.  
  4545.       return Ci.nsIWindowsRegKey["ROOT_KEY_" + keyName];
  4546.     },
  4547.  
  4548.     _readValue: function(wrk, value) {
  4549.       if (wrk.hasValue(value)) {
  4550.         switch (wrk.getValueType(value)) {
  4551.           case wrk.TYPE_STRING:
  4552.             return wrk.readStringValue(value);
  4553.           case wrk.TYPE_BINARY:
  4554.             return wrk.readBinaryValue(value);
  4555.           case wrk.TYPE_INT:
  4556.             return wrk.readIntValue(value);
  4557.           case wrk.TYPE_INT64:
  4558.             return wrk.readInt64Value(value);
  4559.           default:
  4560.             break;
  4561.         }
  4562.       }
  4563.       // unknown type or has no value
  4564.       return null;
  4565.     },
  4566.  
  4567.     _writeValue: function(wrk, name, value, type) {
  4568.       type = type.toLowerCase();
  4569.  
  4570.       switch (type) {
  4571.         case "string":
  4572.           wrk.writeStringValue(name, value);
  4573.           break;
  4574.         case "binary":
  4575.           wrk.writeBinaryValue(name, value);
  4576.           break;
  4577.         case "int":
  4578.           wrk.writeIntValue(name, value);
  4579.           break;
  4580.         case "int64":
  4581.           wrk.writeInt64Value(name, value);
  4582.           break;
  4583.         default:
  4584.           throw new TypeError("nsIYaSearch.WinReg: wrong key type");
  4585.           break;
  4586.       }
  4587.     },
  4588.  
  4589.     _removeChildren: function(wrk) {
  4590.       for (var i = wrk.childCount - 1; i >= 0; i--) {
  4591.         var name = wrk.getChildName(i);
  4592.         var subkey = wrk.openChild(name, wrk.ACCESS_ALL);
  4593.         this._removeChildren(subkey);
  4594.         subkey.close();
  4595.         wrk.removeChild(name);
  4596.       }
  4597.     },
  4598.  
  4599.     _getWrk: function() {
  4600.       return Cc["@mozilla.org/windows-registry-key;1"].createInstance(Ci.nsIWindowsRegKey);
  4601.     },
  4602.  
  4603.     read: function(aKey, aPath, aName) {
  4604.       var result = null;
  4605.  
  4606.       if (gYaSearchService.windowsOS) {
  4607.         var key = this._convertName2Key(aKey);
  4608.  
  4609.         var wrk = this._getWrk();
  4610.         try {
  4611.           wrk.open(key, aPath, wrk.ACCESS_READ);
  4612.           result = this._readValue(wrk, aName);
  4613.         } catch(e) {}
  4614.         
  4615.         try {
  4616.           wrk.close();
  4617.         } catch(e) {}
  4618.       }
  4619.  
  4620.       return result;
  4621.     },
  4622.  
  4623.     write: function(aKey, aPath, aName, aValue, aValueType) {
  4624.       if (gYaSearchService.windowsOS) {
  4625.         var key = this._convertName2Key(aKey);
  4626.  
  4627.         var wrk = this._getWrk();
  4628.         try {
  4629.           wrk.create(key, aPath, wrk.ACCESS_WRITE);
  4630.           this._writeValue(wrk, aName, aValue, aValueType);
  4631.         } catch(e) {}
  4632.  
  4633.         try {
  4634.           wrk.close();
  4635.         } catch(e) {}
  4636.       }
  4637.     },
  4638.  
  4639.     remove: function(aKey, aPath, aName) {
  4640.       /*
  4641.       if (gYaSearchService.windowsOS) {
  4642.         var key = this._convertName2Key(aKey);
  4643.  
  4644.         var wrk = this._getWrk();
  4645.         try {
  4646.           wrk.open(key, aPath, wrk.ACCESS_ALL);
  4647.  
  4648.           if (typeof aName === "undefined")
  4649.             this._removeChildren(wrk);
  4650.           else
  4651.             wrk.removeChild(aName);
  4652.         } catch(e) {}
  4653.  
  4654.         try {
  4655.           wrk.close();
  4656.         } catch(e) {}
  4657.       }
  4658.       */
  4659.     }
  4660.   },
  4661.  
  4662.   get barExtensionVersion() {
  4663.     if (!this._barExtensionVersion)
  4664.       this._barExtensionVersion = this.barExtensionMajorVersion + this.VERSION_BUILD;
  4665.     return this._barExtensionVersion;
  4666.   },
  4667.   
  4668.   get barExtensionMajorVersion() {
  4669.     if (!this._barExtensionMajorVersion)
  4670.       this._barExtensionMajorVersion = Cc["@mozilla.org/extensions/manager;1"].getService(Ci.nsIExtensionManager).getItemForID(EXT_ID).version;
  4671.     return this._barExtensionMajorVersion;
  4672.   },
  4673.   
  4674.   get barExtensionVersionWithLocale() {
  4675.     if (!this._barExtensionVersionWithLocale)
  4676.       this._barExtensionVersionWithLocale = this.barExtensionVersion + this.versionLocaleAppend;
  4677.  
  4678.     return this._barExtensionVersionWithLocale;
  4679.   },
  4680.  
  4681.   get versionLocaleAppend() {
  4682.     var verLocaleAppend = this.getString("locale");
  4683.     if (verLocaleAppend)
  4684.       verLocaleAppend = "-" + verLocaleAppend;
  4685.  
  4686.     return verLocaleAppend;
  4687.   },
  4688.  
  4689.   get generateGUIDStatusURL() {
  4690.     if (!this._generateGUIDStatusURL) {
  4691.       try {
  4692.         var vendorURL = this.getCharPref("yasearch.vendor.guid.url");
  4693.         var URIFixup = Cc["@mozilla.org/docshell/urifixup;1"].getService(Ci.nsIURIFixup);
  4694.         vendorURL = URIFixup.createFixupURI(vendorURL, Ci.nsIURIFixup.FIXUP_FLAG_NONE);
  4695.         if ((vendorURL.scheme == "http" || vendorURL.scheme == "https") && /yandex\.ru$/i.test(vendorURL.host)) {
  4696.           vendorURL = vendorURL.spec;
  4697.           vendorURL += /\?/.test(vendorURL) ? (/&$/.test(vendorURL) ? "" : "&") : "?";
  4698.           this._generateGUIDStatusURL = vendorURL;
  4699.         }
  4700.       } catch (ex) {}
  4701.  
  4702.       if (!this._generateGUIDStatusURL)
  4703.         this._generateGUIDStatusURL = "http://soft.export.yandex.ru/status.xml?";
  4704.     }
  4705.     return this._generateGUIDStatusURL;
  4706.   },
  4707.  
  4708.   get generateGUID() {
  4709.     return Cc["@mozilla.org/uuid-generator;1"].createInstance(Ci.nsIUUIDGenerator).generateUUID();
  4710.   },
  4711.  
  4712.   getYaAppDir: function() {
  4713.     var appDir;
  4714.     
  4715.     if (this.AppBarType == "barffport") {
  4716.       appDir = this.getPortableDir();
  4717.     } else {
  4718.       try {
  4719.         appDir = Cc["@mozilla.org/file/directory_service;1"]
  4720.                      .getService(Ci.nsIProperties)
  4721.                      .get(this.windowsOS ? "AppData" : "Home", Ci.nsIFile);
  4722.       } catch(e) {}
  4723.     }
  4724.     
  4725.     if (appDir && appDir.exists() && appDir.isDirectory()) {
  4726.       appDir.append(this.windowsOS ? "Yandex" : ".yandex");
  4727.  
  4728.       if (!appDir.exists() || !appDir.isDirectory()) {
  4729.         try {
  4730.           appDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
  4731.         } catch(e) {}
  4732.       }
  4733.  
  4734.       if (appDir.exists() && appDir.isDirectory())
  4735.         return appDir;
  4736.     }
  4737.  
  4738.     return false;
  4739.   },
  4740.   
  4741.   getPortableDir: function() {
  4742.     let curProcDir,
  4743.         badStructure = true;
  4744.     
  4745.     try {
  4746.       curProcDir = Cc["@mozilla.org/file/directory_service;1"]
  4747.                        .getService(Ci.nsIProperties)
  4748.                        .get("CurProcD", Ci.nsIFile)
  4749.                        .parent;
  4750.       
  4751.       badStructure = ["AppInfo", "DefaultData", "Firefox"].some(function(aDirName) {
  4752.         let dir = curProcDir.clone();
  4753.         dir.append(aDirName);
  4754.         return !(dir.exists() && dir.isDirectory());
  4755.       });
  4756.       
  4757.     } catch(e) {}
  4758.     
  4759.     return badStructure ? null : curProcDir;
  4760.   },
  4761.   
  4762.   _AppBarType: null,
  4763.   get AppBarType() {
  4764.     if (!this._AppBarType) {
  4765.       let prefName = "yasearch.general.app.bar.type";
  4766.       let barType = this.getCharPref(prefName);
  4767.       
  4768.       switch (barType) {
  4769.         case "barff":
  4770.         case "barffport":
  4771.           break;
  4772.         
  4773.         default:
  4774.           barType = !!this.getPortableDir() ? "barffport" : "barff";
  4775.           this.setCharPref(prefName, barType);
  4776.           break;
  4777.       }
  4778.       
  4779.       this._AppBarType = barType;
  4780.     }
  4781.     
  4782.     return this._AppBarType;
  4783.   },
  4784.   
  4785.   get vendorFileName() {
  4786.     return "clids-" + this.AppBarType + ".xml";
  4787.   },
  4788.   
  4789.   getYaPrefsFile: function(aFileName, aCreate) {
  4790.     function _isFileExists(aFile) {
  4791.       return !!(aFile.exists() && aFile.isFile());
  4792.     }
  4793.     
  4794.     var appDir = this.getYaAppDir();
  4795.     if (appDir) {
  4796.       var file = appDir.clone();
  4797.       file.append(aFileName);
  4798.  
  4799.       if (aFileName == this.vendorFileName && !_isFileExists(file)) {
  4800.         //barie app
  4801.         var venFile = appDir.clone();
  4802.         venFile.append("clids-barie.xml");
  4803.         
  4804.         if (_isFileExists(venFile)) {
  4805.           try {
  4806.             venFile.copyTo(appDir, aFileName);
  4807.             venFile.permissions = 0755;
  4808.           } catch(e) {}
  4809.         }
  4810.         
  4811.         if (!_isFileExists(file)) {
  4812.           //ven app
  4813.           venFile = appDir.clone();
  4814.           venFile.append("vendor.xml");
  4815.           
  4816.           if (_isFileExists(venFile)) {
  4817.             try {
  4818.               venFile.copyTo(appDir, aFileName);
  4819.               venFile.permissions = 0755;
  4820.             } catch(e) {}
  4821.           }
  4822.           
  4823.           if (!_isFileExists(file)) {
  4824.             //ven dist
  4825.             venFile = this.getContentDir();
  4826.             venFile.append("services");
  4827.             venFile.append("vendor.xml");
  4828.             
  4829.             if (_isFileExists(venFile)) {
  4830.               try {
  4831.                 venFile.copyTo(appDir, aFileName);
  4832.                 venFile.permissions = 0755;
  4833.               } catch(e) {}
  4834.             }
  4835.           }//venapp
  4836.         }//barieapp
  4837.       }
  4838.  
  4839.       if (aCreate == true && !_isFileExists(file))
  4840.         file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0755);
  4841.  
  4842.       if (_isFileExists(file) && file.isReadable())
  4843.         return file;
  4844.     }
  4845.  
  4846.     return false;
  4847.   },
  4848.  
  4849.   getGuidDataFromString: function(aGuidStr) {
  4850.     var guid = aGuidStr ? aGuidStr.toString() : false;
  4851.     return guid && /^\{[0-9a-f]{2,8}\-[0-9a-f]{2,4}\-[0-9a-f]{2,4}\-[0-9a-f]{1,4}\-[0-9a-f]{2,12}\}$/i.test(guid) ? guid : false;
  4852.   },
  4853.  
  4854.   __guidString: null,
  4855.  
  4856.   get guidString() {
  4857.     if (this.__guidString === null) {
  4858.       var guidPrefName = "yasearch.guid.value",
  4859.           guidStr = "",
  4860.           uiFile = this.getYaPrefsFile("ui");
  4861.  
  4862.       if (uiFile) {
  4863.         guidStr = this.getGuidDataFromString(this.readFile(uiFile));
  4864.       } else {
  4865.         var uiWasCreated = false;
  4866.         
  4867.         var currentWinUser;
  4868.         if (this.AppBarType !== "barffport") {
  4869.           currentWinUser = this.WinReg.read("HKCU",
  4870.                            "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", "Logon User Name");
  4871.           
  4872.           if (currentWinUser) {
  4873.             uiWasCreated = !!this.WinReg.read("HKCU", "Software\\Yandex", "UICreated_" + currentWinUser);
  4874.           }
  4875.         }
  4876.         
  4877.         if (!uiWasCreated) {
  4878.           if (this.prefBranch.prefHasUserValue(guidPrefName)) {
  4879.             guidStr = this.getGuidDataFromString(this.getCharPref(guidPrefName));
  4880.           } else {
  4881.             guidStr = this.generateGUID;
  4882.             this.setCharPref(guidPrefName, guidStr);
  4883.           }
  4884.  
  4885.           if (guidStr) {
  4886.             uiFile = this.getYaPrefsFile("ui", true);
  4887.             
  4888.             if (!uiFile || !uiFile.isWritable()) {
  4889.               guidStr = "";
  4890.             
  4891.             } else {
  4892.               this.writeFile(uiFile, guidStr);
  4893.               
  4894.               if (currentWinUser) {
  4895.                 this.WinReg.write("HKCU", "Software\\Yandex", "UICreated_" + currentWinUser, 1, "int");
  4896.               }
  4897.             }
  4898.           }
  4899.         }
  4900.       }
  4901.  
  4902.       if (guidStr)
  4903.         this.setCharPref(guidPrefName, guidStr);
  4904.       else
  4905.         guidStr = "";
  4906.  
  4907.       this.__guidString = "" + (guidStr || "");
  4908.     }
  4909.  
  4910.     return this.__guidString;
  4911.   },
  4912.   
  4913.   __barnavigR1String: null,
  4914.  
  4915.   get barnavigR1String() {
  4916.     if (this.__barnavigR1String === null) {
  4917.       let r1 = "",
  4918.           r1File = this.getYaPrefsFile("r1-barff", false);
  4919.  
  4920.       if (r1File) {
  4921.         r1 = this.readFile(r1File);//vldt
  4922.       }
  4923.       
  4924.       this.__barnavigR1String = r1 || "";
  4925.     }
  4926.     
  4927.     return this.__barnavigR1String;
  4928.   },
  4929.   
  4930.   set barnavigR1String(val) {
  4931.     if (val !== this.barnavigR1String) {
  4932.       let r1File = this.getYaPrefsFile("r1-barff", true);
  4933.       if (r1File) {
  4934.         this.writeFile(r1File, val);
  4935.       }
  4936.       
  4937.       this.__barnavigR1String = null;
  4938.     }
  4939.     
  4940.     return this.barnavigR1String;
  4941.   },
  4942.   
  4943.   vendorDataMergeClids: function() {
  4944.     //refresh vendor data
  4945.     this.__vendorData = null;
  4946.     
  4947.     var installedFile = this.getYaPrefsFile(this.vendorFileName, false);
  4948.     if (!installedFile)
  4949.       return;
  4950.     
  4951.     try {
  4952.       installedFile.permissions = 0755;
  4953.     } catch(e) {}
  4954.     
  4955.     var installedXml = this.safeE4Xml(this.readFile(installedFile), null, "vendor");
  4956.     if (!installedXml) {
  4957.       try {
  4958.         installedFile.remove(true);
  4959.       } catch(e) {}
  4960.       
  4961.       return;
  4962.     }
  4963.     
  4964.     var distribFile = this.getContentDir();
  4965.     distribFile.append("services");
  4966.     distribFile.append("vendor.xml");
  4967.     
  4968.     if (!(distribFile.exists() && distribFile.isFile()))
  4969.       return;
  4970.     
  4971.     var distribXml = this.safeE4Xml(this.readFile(distribFile), null, "vendor");
  4972.     if (!distribXml)
  4973.       return;
  4974.     
  4975.     var writeNewData = false;
  4976.     for each (var clid in distribXml.*.(/^clid\d+$/.test(function::name()))) {
  4977.       var clidName = clid.name();
  4978.       var clidValue = this.parseIntFromStr(clid.toString());
  4979.       if (clidValue > 0 && (installedXml[clidName].length() === 0 ||
  4980.           !this.parseIntFromStr(installedXml[clidName].toString()))) {
  4981.         installedXml[clidName] = clidValue;
  4982.         writeNewData = true;
  4983.       }
  4984.     }
  4985.     
  4986.     if (writeNewData) {
  4987.       this.writeFile(installedFile, "<?xml version=\"1.0\" encoding=\"windows-1251\"?>\r\n" +
  4988.                                     installedXml.toXMLString());
  4989.     }
  4990.   },
  4991.  
  4992.   get vendorData() {
  4993.     if (!this.__vendorData) {
  4994.       var data = {};
  4995.       var vendorFile = this.getYaPrefsFile(this.vendorFileName, false);
  4996.       var vendorXml = this.safeE4Xml(vendorFile ? this.readFile(vendorFile) : "", "<vendor/>", "vendor");
  4997.       
  4998.       for (var i = 0; i <= 10; i++) {
  4999.         var clid = this.parseIntFromStr(vendorXml["clid" + i].toString());
  5000.         data["clid" + i] = clid > 0 ? clid.toString().substr(0, 10) : false;
  5001.       }
  5002.  
  5003.       this.__vendorData = data;
  5004.     }
  5005.  
  5006.     return this.__vendorData;
  5007.   },
  5008.  
  5009.   get yandexHomePageValue() {
  5010.     var clid5 = this.vendorData.clid5;
  5011.     return "http://www.yandex." + this.localeTld + "/" + (clid5 ? "?clid=" + clid5 : "");
  5012.   },
  5013.   
  5014.   isYandexHomePage: function(aHomepageURL) {
  5015.     let url = typeof aHomepageURL === "undefined" ? this.getBrowserHomePage() : aHomepageURL;
  5016.     
  5017.     return !!(url &&
  5018.               (/^http:\/\/(www\.)?yandex\.(ru|ua)/i.test(url) ||
  5019.                /^http:\/\/ru\.start3\.mozilla\.com\/firefox/.test(url))
  5020.              );
  5021.   },
  5022.   
  5023.   setHomePageUrl: function(aOverrideYandex) {
  5024.     if (aOverrideYandex || !this.isYandexHomePage())
  5025.       this.setBrowserHomePage(this.yandexHomePageValue);
  5026.  
  5027.     if (this.getIntPref("browser.startup.page") === 0)
  5028.       this.setIntPref("browser.startup.page", 1);
  5029.   },
  5030.   
  5031.   _checkKeywordUrl: function() {
  5032.     if (this.getCharPref("app.distributor") != "yandex")
  5033.       return;
  5034.     
  5035.     let keywordURL = this.getBrowserKeywordURL();
  5036.     if (!keywordURL || this.prefBranch.prefHasUserValue("keyword.URL"))
  5037.       return;
  5038.     
  5039.     this._setKeywordUrl(false);
  5040.   },
  5041.   
  5042.   _setKeywordUrl: function(aSetEnabled) {
  5043.     let keywordURL = this.getBrowserKeywordURL();
  5044.     
  5045.     if (!(/[&?]clid=/.test(keywordURL) && /^http:\/\/yandex\.ru\/yandsearch\?/.test(keywordURL))) {
  5046.       let urlParams = [];
  5047.       
  5048.       let clid9 = this.vendorData.clid9;
  5049.       if (clid9)
  5050.         urlParams.push("clid=" + clid9);
  5051.       
  5052.       urlParams.push("yasoft=" + encodeURIComponent(this.AppInfo.yasoftStr));
  5053.       urlParams.push("text=");
  5054.       
  5055.       this.setBrowserKeywordURL("http://yandex.ru/yandsearch?" + urlParams.join("&"));
  5056.     }
  5057.     
  5058.     if (aSetEnabled)
  5059.       this.setBoolPref("keyword.enabled", true);
  5060.   },
  5061.  
  5062.   appendStatData2Url: function(aURL, aStatData) {
  5063.     if (!aStatData || typeof(aStatData) !== "object" || !aURL)
  5064.       return aURL;
  5065.  
  5066.     if (/[&?]yasoft=/.test(aURL))
  5067.       aStatData.yasoft = false;
  5068.  
  5069.     if (/[&?]clid=/.test(aURL))
  5070.       aStatData.clid = false;
  5071.     
  5072.     let appendix = this.getAppendStatData2Url(aStatData);
  5073.     
  5074.     if (appendix == "")
  5075.       return aURL;
  5076.  
  5077.     let url = aURL.split("?");
  5078.     url = url[0] + "?" + appendix + (url[1] ? "&" + url[1] : "");
  5079.  
  5080.     return url;
  5081.   },
  5082.  
  5083.   getAppendStatData2Url: function(aStatData) {
  5084.     let res = [];
  5085.  
  5086.     if (aStatData && !(aStatData.action && !(aStatData.yasoft || aStatData.clid))) {
  5087.       if (aStatData.clid) {
  5088.         let clid = this.vendorData["clid" + (aStatData.clid || "")];
  5089.         if (clid)
  5090.           res.push("clid=" + clid);
  5091.       }
  5092.  
  5093.       if ((aStatData.yasoft || null) !== false)
  5094.         res.push("yasoft=" + encodeURIComponent(this.AppInfo.yasoftStr));
  5095.     }
  5096.  
  5097.     return res.join("&");
  5098.   },
  5099.   
  5100.   get versionData() {
  5101.     var gApp  = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).QueryInterface(Ci.nsIXULRuntime);
  5102.  
  5103.     var versionData = {
  5104.       ui: this.guidString,
  5105.       v: this.barExtensionVersionWithLocale,
  5106.       ver: this.barExtensionVersionWithLocale,
  5107.       bn: gApp.name,
  5108.       bv: gApp.version,
  5109.       os: gApp.OS,
  5110.       yasoft: this.AppInfo.yasoftStr,
  5111.       tl: this.timeGuid
  5112.     };
  5113.  
  5114.     if (this.vendorData.clid1)
  5115.       versionData.clid = this.vendorData.clid1;
  5116.  
  5117.     return versionData;
  5118.   },
  5119.  
  5120.   get generateGUIDData() {
  5121.     if (!this._generateGUIDData) {
  5122.       var versionData = this.versionData;
  5123.  
  5124.       var data2Server = [];
  5125.       for (let [propName, propValue] in Iterator(versionData))
  5126.         data2Server.push(propName + "=" + encodeURIComponent(propValue));
  5127.       
  5128.       this._generateGUIDData = data2Server.join("&");
  5129.     }
  5130.  
  5131.     var dynamicAppend = "";
  5132.     
  5133.     if (this.yaDefence) {
  5134.       var yaDefenceTimesData = this.yaDefence.changesTime;
  5135.       if (yaDefenceTimesData)
  5136.         dynamicAppend += yaDefenceTimesData;
  5137.  
  5138.       var yaFSearchData = this.yaDefence.fSearchStatData;
  5139.       if (yaFSearchData)
  5140.         dynamicAppend += yaFSearchData;
  5141.     }
  5142.     
  5143.     var _use = "&stat=dayuse";
  5144.     if (typeof(gYaInstaller) === "object" && "sttInstall" in gYaInstaller) {
  5145.       let stt = gYaInstaller.sttInstall;
  5146.       if (stt)
  5147.         _use = "&stat=install";
  5148.     }
  5149.     
  5150.     dynamicAppend += _use;
  5151.     
  5152.     return this._generateGUIDData + dynamicAppend;
  5153.   },
  5154.  
  5155.   __AppInfo: null,
  5156.   get AppInfo() {
  5157.     if (!this.__AppInfo) {
  5158.       var gApp  = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).QueryInterface(Ci.nsIXULRuntime);
  5159.       var os = gApp.OS;
  5160.  
  5161.       var verLocaleAppend = this.getString("locale");
  5162.       verLocaleAppend = verLocaleAppend ? ("." + verLocaleAppend) : "";
  5163.  
  5164.       this.__AppInfo = {
  5165.         yasoftStr: "barff" + verLocaleAppend,
  5166.  
  5167.         OS: {
  5168.           name: os,
  5169.           isWindows: /^win/i.test(os),
  5170.           isLinux:   /^linux/i.test(os),
  5171.           isMacOS:   /^darwin/i.test(os),
  5172.           get platformName() {
  5173.             if (this.isWindows) return "win";
  5174.             if (this.isLinux)   return "unix";
  5175.             if (this.isMacOS)   return "mac";
  5176.  
  5177.             return "";
  5178.           }
  5179.         },
  5180.  
  5181.         browser: {
  5182.           version: gApp.version,
  5183.           get isGreaterThenFx30() {
  5184.             return !!Ci.nsIWorker;
  5185.           },
  5186.           get isGreaterThenFx35() {
  5187.             return !!Ci.nsIDOMGeoPositionAddress;
  5188.           }
  5189.         }
  5190.       };
  5191.     }
  5192.     return this.__AppInfo;
  5193.   },
  5194.  
  5195.   get timeGuid() {
  5196.     return (new Date(parseInt(this.getCharPref("yasearch.guid.time"), 10))).valueOf() || 0;
  5197.   },
  5198.  
  5199.   set timeGuid(val) {
  5200.     this.setCharPref("yasearch.guid.time", val ? G_TIME_NOW : "0");
  5201.   },
  5202.  
  5203.   checkNeedSendGuid: function() {
  5204.     if (this.updateTimer._GuidRefresh)
  5205.       return;
  5206.  
  5207.     var timeNow = G_TIME_NOW, timeBefore = this.timeGuid;
  5208.     if (timeBefore < (timeNow - DAY_SECS) || timeBefore > timeNow)
  5209.       this.setTimer("_Guid", 10);
  5210.  
  5211.     this.setTimer("_GuidRefresh");
  5212.   },
  5213.  
  5214.   loadURI: function(aURL, aEvent, aClidType) {
  5215.     let browser = this.getWindow("navigator:browser");
  5216.     return (browser && browser.Ya) ? browser.Ya.loadURI(aURL, aEvent, aClidType) : false;
  5217.   },
  5218.  
  5219.   loadConditionalURI: function(aType, aEvent, aStatData) {
  5220.     let browser = this.getWindow("navigator:browser");
  5221.     return (browser && browser.Ya) ? browser.Ya.loadConditionalURI(aType, aEvent, aStatData) : false;
  5222.   },
  5223.  
  5224.   makeURI: function(aURLSpec, aCharset) {
  5225.     try {
  5226.       return IO_SERVICE.newURI(aURLSpec, aCharset, null);
  5227.     } catch(e) {}
  5228.     
  5229.     return null;
  5230.   },
  5231.  
  5232.   makeFileURI: function(aFile) {
  5233.     try {
  5234.       return IO_SERVICE.newFileURI(aFile);
  5235.     } catch(e) {}
  5236.     
  5237.     return null;
  5238.   },
  5239.  
  5240.   safeE4Xml: function(aStr, aDefaultStr, aRootNodeName) {//aRootNodeName -- null || string || array
  5241.     if (aStr) {
  5242.       if (typeof aStr == "string") {
  5243.         aStr = this.safeUnicode(aStr);
  5244.       } else {
  5245.         if (aStr instanceof Ci.nsIDOMDocument || aStr instanceof Ci.nsIDOMElement)//nsIDOMNode || nsIDOM3Node
  5246.           aStr = this.xmlSerializer.serializeToString(aStr);
  5247.         else if (typeof(aStr) === "xml")
  5248.           aStr = aStr.toString();
  5249.       }
  5250.     }
  5251.  
  5252.     if (!aStr || aStr == "")
  5253.       aStr = (aDefaultStr || "").toString();
  5254.  
  5255.     if (typeof(aStr) != "string")
  5256.       return null;
  5257.  
  5258.     aStr = aStr.replace(/<\?xml .+\?>[\r\n]*/, "")
  5259.                .replace(/(<!DOCTYPE ((.|\r|\n)*?)\]>)[\r\n]*/, "");
  5260.  
  5261.     var d, rootNodeName;
  5262.  
  5263.     try {
  5264.       d = new XML(aStr)[0];
  5265.       rootNodeName = d.name().localName.toString();
  5266.     } catch(e) {
  5267.       this.log("'safeE4Xml' error: " + e);
  5268.     }
  5269.     
  5270.     if (d && rootNodeName) {
  5271.       if (!aRootNodeName)
  5272.         aRootNodeName = rootNodeName;
  5273.  
  5274.       var namesArray = typeof(aRootNodeName) == "string" ? [aRootNodeName] : aRootNodeName;
  5275.       
  5276.       if (namesArray.length > 0)
  5277.         for each (var name in namesArray)
  5278.           if (name == rootNodeName)
  5279.             return d;
  5280.     }
  5281.  
  5282.     return aDefaultStr ? this.safeE4Xml(aDefaultStr) : null;
  5283.   },
  5284.  
  5285.   DOMUtils: {
  5286.     evaluateXPath: function(aNode, aExpr) {
  5287.       function nsResolver(aPrefix) {
  5288.         const ns = {
  5289.           "xul": "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  5290.           "xhtml": "http://www.w3.org/1999/xhtml"
  5291.         };
  5292.         
  5293.         return ns[aPrefix] || null;
  5294.       }
  5295.       
  5296.       let xpEvaluator = Cc["@mozilla.org/dom/xpath-evaluator;1"].getService(Ci.nsIDOMXPathEvaluator);
  5297.       let xpathResult = xpEvaluator.evaluate(aExpr, aNode, nsResolver,
  5298.                                              Ci.nsIDOMXPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
  5299.       let nextElement,
  5300.           result = [];
  5301.       
  5302.       while ((nextElement = xpathResult.iterateNext()))
  5303.         result.push(nextElement);
  5304.       
  5305.       return result;
  5306.     },
  5307.     
  5308.     // import - copy; adopt - remove
  5309.     importAndRemoveNode: function(aNode, aDocument) {
  5310.       if (!aNode)
  5311.         return aNode;
  5312.  
  5313.       var node = aDocument.importNode(aNode, true);
  5314.  
  5315.       try {
  5316.         aNode.parentNode.removeChild(aNode);
  5317.       } catch(e) {}
  5318.  
  5319.       return node;
  5320.     },
  5321.  
  5322.     adoptNode: function(aNode, aDocument) {
  5323.       return this.importAndRemoveNode(aNode, aDocument);
  5324.     },
  5325.  
  5326.     appendNode: function(aNode, aTarget) {
  5327.       var node = this.importAndRemoveNode(aNode, aTarget.ownerDocument);
  5328.  
  5329.       if (node)
  5330.         aTarget.appendChild(node);
  5331.  
  5332.       return node;
  5333.     },
  5334.  
  5335.     replaceNode: function(aNewNode, aOldNode) {
  5336.       var fromDoc = aNewNode.ownerDocument,
  5337.           toDoc = aOldNode.ownerDocument;
  5338.  
  5339.       var node = (fromDoc === toDoc) ? aNewNode : this.importAndRemoveNode(aNewNode, toDoc);
  5340.  
  5341.       if (node)
  5342.         aOldNode.parentNode.replaceChild(node, aOldNode);
  5343.  
  5344.       return node;
  5345.     },
  5346.  
  5347.     replaceChildNodes: function(aNode, aTarget) {
  5348.       while (aTarget.hasChildNodes())
  5349.         aTarget.removeChild(aTarget.firstChild);
  5350.  
  5351.       return aNode ? this.appendNode(aNode, aTarget) : null;
  5352.     }
  5353.   },
  5354.  
  5355.   /** **************************************************************************************************** **/
  5356.   dumpIFaces: function(aObject) {
  5357.     if (!this.debug)
  5358.       return;
  5359.  
  5360.     var dumpTxt = ["Dump interfaces\r\n==============================================="];
  5361.     for (var iface in Ci) {
  5362.       try {
  5363.         aObject.QueryInterface(Ci[iface])
  5364.         dumpTxt.push(iface);
  5365.       } catch(e) {}
  5366.     }
  5367.  
  5368.     this.log(dumpTxt.join("\r\n"));
  5369.     return aObject;
  5370.   },
  5371.  
  5372.   dump: function(aObject) {
  5373.     if (!this.debug)
  5374.       return;
  5375.  
  5376.     var dumpTxt = ["Dump properties in Object\r\n==============================================="];
  5377.     for (var prop in aObject)
  5378.       try { dumpTxt.push(prop + " :: " + aObject[prop]); } catch(e) {}
  5379.  
  5380.     if (aObject instanceof Ci.nsIDOMEvent) {
  5381.       dumpTxt.push("================= nsIDOMEvent targets ======================================");
  5382.       ["target", "currentTarget", "originalTarget", "explicitOriginalTarget"].forEach(function(aType) {
  5383.         dumpTxt.push(aType + " :: " + aObject[aType] + " :: " + (aObject[aType] ? aObject[aType].localName : null))
  5384.       })
  5385.     }
  5386.  
  5387.     this.log(dumpTxt.join("\r\n"));
  5388.   },
  5389.  
  5390.   /** **************************************************************************************************** **/
  5391.   _getToolbarForNode: function(aNode) {
  5392.     let toolbar = false,
  5393.         node = aNode;
  5394.     
  5395.     while (node && !toolbar) {
  5396.       node = node.parentNode;
  5397.       if (node && node.localName == "toolbar")
  5398.         toolbar = node;
  5399.     }
  5400.     
  5401.     return toolbar;
  5402.   },
  5403.  
  5404.   _persistToolbarSet: function(aToolbar) {
  5405.     if (aToolbar && aToolbar.localName && aToolbar.localName == "toolbar") {
  5406.       aToolbar.setAttribute("currentset", aToolbar.currentSet);
  5407.       aToolbar.ownerDocument.persist(aToolbar.id, "currentset");
  5408.     }
  5409.   },
  5410.  
  5411.   checkToolbarSet: function(aNmb, aToolbar) {
  5412.     if (aNmb == this.barExtensionVersion)
  5413.       return;
  5414.  
  5415.     aToolbar.setAttribute("yaNmbSaved", this.barExtensionMajorVersion);
  5416.     aToolbar.ownerDocument.persist(aToolbar.id, "yaNmbSaved");
  5417.  
  5418.     if (!aNmb)
  5419.       return;
  5420.  
  5421.     let gDocument = aToolbar.ownerDocument,
  5422.         defaultSet = aToolbar.getAttribute("defaultset");
  5423.  
  5424.     let addDiff = {
  5425.       "3.5.0": [ ["yasearch-fotki", ",yasearch-mail", true],
  5426.                  ["yasearch-yaru", ",yasearch-lenta", false] ],
  5427.  
  5428.       "4.0.0": [ ["yasearch-spellchecker", ",yasearch-bloggers", true] ],
  5429.       
  5430.       "4.3.0": [ ["yasearch-translate", ",yasearch-spellchecker", true] ]
  5431.     };
  5432.  
  5433.     for (var nmb in addDiff) {
  5434.       if (aNmb <= nmb) {
  5435.         let i = -1,
  5436.             _d = addDiff[nmb];
  5437.         
  5438.         while (_d[++i]) {
  5439.           let beforeElt = null;
  5440.  
  5441.           if (_d[i][1]) {
  5442.             let defSetCute = (defaultSet.split(_d[i][1])[0] + _d[i][1]).split(","),
  5443.                 j = defSetCute.length;
  5444.             
  5445.             let found = false;
  5446.  
  5447.             while (defSetCute[--j] && !found)
  5448.               found = aToolbar._getElementByPID(defSetCute[j]);
  5449.  
  5450.             if (found && found.nextSibling) {
  5451.               let check = true;
  5452.               
  5453.               while (check && found.nextSibling) {
  5454.                 switch ((_d[i][2] ? found : found.nextSibling).localName) {
  5455.                   case "toolbaritem":
  5456.                   case "toolbarbutton":
  5457.                     check = false;
  5458.                     break;
  5459.                   
  5460.                   default:
  5461.                     found = found.nextSibling;
  5462.                 }
  5463.               }
  5464.             }
  5465.  
  5466.             beforeElt = found ? (found.nextSibling ? found.nextSibling : null) :
  5467.                                  (aToolbar.firstChild ? aToolbar.firstChild : null);
  5468.           }
  5469.  
  5470.           for each (var newItemId in _d[i][0].split(",").reverse())
  5471.             if (!gDocument.getElementById(newItemId))
  5472.               beforeElt = aToolbar.insertItem(newItemId, beforeElt);
  5473.         }
  5474.       }
  5475.     }
  5476.     
  5477.     // quotes
  5478.     if (aNmb < "4.3.0") {
  5479.       aToolbar.insertItem("separator", null);
  5480.       aToolbar.insertItem("yasearch.cb-default-0", null);
  5481.       aToolbar.insertItem("yasearch.cb-default-1", null);
  5482.     }
  5483.     
  5484.     this._persistToolbarSet(aToolbar);
  5485.   },
  5486.  
  5487.   module: {
  5488.     registerSelf: function (compMgr, fileSpec, location, type) {
  5489.       var compReg = compMgr.QueryInterface( Ci.nsIComponentRegistrar );
  5490.       compReg.registerFactoryLocation(this.cid,
  5491.                                       "nsIYaSearch JS component",
  5492.                                       this.contractId,
  5493.                                       fileSpec, location, type);
  5494.       var catman = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
  5495.       catman.addCategoryEntry("app-startup", "nsIYaSearch", this.contractId, true, true);
  5496.     },
  5497.  
  5498.     unregisterSelf: function(compMgr, fileSpec, location) {
  5499.       compMgr = compMgr.QueryInterface( Ci.nsIComponentRegistrar );
  5500.       compMgr.unregisterFactoryLocation( this.cid, fileSpec );
  5501.       var catman = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
  5502.       catman.deleteCategoryEntry("app-startup", this.contractId, true);
  5503.     },
  5504.  
  5505.     getClassObject: function (compMgr, cid, iid) {
  5506.       if (!cid.equals(this.cid))
  5507.         throw Cr.NS_ERROR_NO_INTERFACE;
  5508.       if (!iid.equals(Ci.nsIFactory))
  5509.         throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  5510.       return this.factory;
  5511.     },
  5512.  
  5513.     cid: Components.ID("{3F79261A-508E-47a3-B61C-D1F29E2068F3}"),
  5514.  
  5515.     contractId: "@yandex.ru/yasearch;1",
  5516.  
  5517.     factory: {
  5518.       createInstance: function (outer, iid) {
  5519.         if (outer != null)
  5520.           throw Cr.NS_ERROR_NO_AGGREGATION;
  5521.         return gYaSearchService;
  5522.       }
  5523.     },
  5524.  
  5525.     canUnload: function(compMgr) {return true;}
  5526.   }
  5527. }
  5528.  
  5529. function NSGetModule(compMgr, fileSpec) {
  5530.   return nsIYaSearch.prototype.module;
  5531. }
  5532.  
  5533. var gYaSearchService = new nsIYaSearch();