home *** CD-ROM | disk | FTP | other *** search
/ PCGUIA 127 / PC Guia 127.iso / Software / Utils / NoScript / Bin / noscript-1.1.3.9-fx+fl+mz.xpi / components / noscriptService.js < prev   
Encoding:
JavaScript  |  2006-01-27  |  39.4 KB  |  1,380 lines

  1. /***** BEGIN LICENSE BLOCK *****
  2.  
  3. NoScript - a Firefox extension for whitelist driven safe JavaScript execution
  4. Copyright (C) 2004-2005 Giorgio Maone - g.maone@informaction.com
  5.  
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  
  20. ***** END LICENSE BLOCK *****/
  21.  
  22. function UninstallGuard(name) {
  23.   this.name=name;
  24. }
  25.  
  26. UninstallGuard.prototype={
  27.   uninstalling: false,
  28.   disabled: false,
  29.   get ds() {
  30.     return Components.classes["@mozilla.org/extensions/manager;1"
  31.         ].getService(Components.interfaces.nsIExtensionManager
  32.       ).datasource;
  33.   }
  34. ,
  35.   get rdfService() {
  36.     return Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
  37.   }
  38. ,
  39.   onAssert: function(ds,source,prop,target) {
  40.     this.check(ds,source);
  41.   },
  42.   onBeginUpdateBatch: function(ds) {},
  43.   onChange: function(ds,source,prop,oldTarget,newTarget) {
  44.     this.check(ds,source);
  45.   },
  46.   onEndUpdateBatch: function(ds) {
  47.     this.checkAll(ds);
  48.   },
  49.   onMove: function(ds,oldSource,newSource,prop,target) {
  50.     this.check(ds,newSource);
  51.   },
  52.   onUnassert: function(ds,source,prop,target) {
  53.     this.check(ds,source);
  54.   }
  55. ,
  56.   init: function() {
  57.     try {
  58.       this.ds.AddObserver(this);
  59.     } catch(ex) {
  60.       this.log(ex);
  61.     } 
  62.   }
  63. ,
  64.   dispose: function() {
  65.     try {
  66.       this.ds.RemoveObserver(this);
  67.     } catch(ex) {
  68.       this.log(ex);
  69.     } 
  70.   }
  71. ,
  72.   checkAll: function(ds) {
  73.     const container = Components.classes["@mozilla.org/rdf/container;1"]
  74.                .getService(Components.interfaces.nsIRDFContainer);
  75.     var root = this.rdfService.GetResource("urn:mozilla:extension:root");
  76.     container.Init(ds,root);
  77.     
  78.      var found = false;
  79.      var elements = container.GetElements();
  80.      for(var found=false; elements.hasMoreElements() && !found; ) {
  81.         found=this.check(elements.getNext().QueryInterface(Components.interfaces.nsIRDFResource));
  82.      }
  83.   }
  84. ,
  85.   check: function(extensionDS,element) {
  86.     try { 
  87.       const RDFService = this.rdfService;
  88.       var target;
  89.       if((target=extensionDS.GetTarget(element,  
  90.         RDFService.GetResource("http://www.mozilla.org/2004/em-rdf#name") ,true))
  91.         && target.QueryInterface(Components.interfaces.nsIRDFLiteral).Value==this.name
  92.         ) {
  93.         this.uninstalling = (
  94.           (target = extensionDS.GetTarget(element, 
  95.             RDFService.GetResource("http://www.mozilla.org/2004/em-rdf#toBeUninstalled"),true)
  96.             ) !=null 
  97.             && target.QueryInterface(Components.interfaces.nsIRDFLiteral).Value == "true"
  98.            );
  99.         this.disabled = (
  100.           (target = extensionDS.GetTarget(element, 
  101.             RDFService.GetResource("http://www.mozilla.org/2004/em-rdf#toBeDisabled"),true)
  102.             ) !=null
  103.             && target.QueryInterface(Components.interfaces.nsIRDFLiteral).Value == "true"
  104.           );
  105.         return true;
  106.       }  
  107.      } catch(ex) {
  108.        this.log(ex);
  109.      } // quick and dirty work-around for SeaMonkey ;)
  110.      return false;
  111.   }
  112. ,
  113.   log: function(msg) {
  114.     dump("UninstallGuard: "+msg+"\n");
  115.   }
  116. };
  117.  
  118. const SiteUtils = new function() {
  119.   var _domainPattern = /^[^\?\/#,;:\\\@]+$/; // double check: changed for Unicode compliance: it was /^[\w\-\.]*\w$/
  120.   
  121.   var _ios = null;
  122.   this.__defineGetter__("ios", function() {
  123.      return _ios?_ios
  124.       :_ios=Components.classes["@mozilla.org/network/io-service;1"
  125.         ].getService(Components.interfaces.nsIIOService);
  126.   });
  127.   
  128.   function sorter(a,b) {
  129.     if(a==b) return 0;
  130.     if(!a) return 1;
  131.     if(!b) return -1;
  132.     const dp=_domainPattern;
  133.     return dp.test(a)?
  134.       (dp.test(b)?(a<b?-1:1):-1)
  135.       :(dp.test(b)?1:a<b?-1:1);
  136.   }
  137.   
  138.   this.sort = function(ss) {
  139.     return ss.sort(sorter);
  140.   };
  141.  
  142.   this.getSite = function(url) {
  143.     if(! (url && ( url=url.replace(/^\s+/,'').replace(/\s+$/,'') )) ) {
  144.       return "";
  145.     }
  146.     
  147.     if(url.indexOf(":")<0) return this.domainMatch(url);
  148.     
  149.     var scheme;
  150.     try {
  151.       scheme = this.ios.extractScheme(url).toLowerCase();
  152.       if(scheme == "javascript" || scheme == "data") return "";
  153.       if(scheme == "about") {
  154.         return /about:neterror(\?|$)/.test(url) ? "about:neterror" : url;
  155.       }
  156.       scheme += ":";
  157.       if(url == scheme) return url;
  158.     } catch(ex) {
  159.       return this.domainMatch(url);
  160.     }
  161.     try {
  162.       // let's unwrap JAR uris
  163.       var uri=this.ios.newURI(url,null,null);
  164.       if(uri instanceof Components.interfaces.nsIJARURI) {
  165.         uri=uri.JARFile;
  166.         return uri?this.getSite(uri.spec):scheme;
  167.       }
  168.       try  {
  169.         return scheme+"//"+uri.hostPort;
  170.       } catch(exNoHostPort) {
  171.         return scheme;
  172.       }
  173.     } catch(ex) {
  174.       return "";
  175.     }
  176.   };
  177.   
  178.   this.list2set = function(sl) {
  179.     // kill duplicates
  180.     var prevSite="";
  181.     var site;
  182.     for(var j=sl.length; j-->0;) {
  183.       site=sl[j];
  184.       if((!site) || site==prevSite) { 
  185.         sl.splice(j,1);
  186.       } else {
  187.         prevSite=site;
  188.       }
  189.     }
  190.     return sl;
  191.   };
  192.   
  193.   this.sortedSet = function(sl) {
  194.     return this.list2set(this.sort(sl));
  195.   }
  196.   
  197.   this.splitString = function(s) {
  198.     return s?/^[,\s]*$/.test(s)?[]:s.split(/\s*[,\s]\s*/):[];
  199.   };
  200.   
  201.   this.domainMatch = function(url) {
  202.      const m=url.match(_domainPattern);
  203.      return m?m[0].toLowerCase():"";
  204.   };
  205.   
  206.   this.sanitizeList = function(sl) {
  207.     for(var j=sl.length; j-->0; ) {
  208.       sl[j]=this.getSite(sl[j]);
  209.     }
  210.     return sl;
  211.   };
  212.   
  213.   this.sanitizeMap = function(sm) {
  214.     var site;
  215.     delete sm[""];
  216.     for(var url in sm) {
  217.       site=this.getSite(url);
  218.       if(site!=url) {
  219.         if(site) sm[site]=sm[url];
  220.         delete sm[url];
  221.       }
  222.     }
  223.     return sm;
  224.   };
  225.   
  226.   this.sanitizeString = function(s) {
  227.     // s=s.replace(/,/g,' ').replace(/\s{2,}/g,' ').replace(/(^\s+|\s+$)/g,'');
  228.     return this.set2string(this.string2set(s)); 
  229.   };
  230.   
  231.   this.string2set = function(s) {
  232.     return this.sortedSet(this.sanitizeList(this.splitString(s)));
  233.   };
  234.   
  235.   this.set2string = function(ss) {
  236.     return ss.join(" ");
  237.   };
  238.   
  239. }
  240.  
  241.  
  242.  
  243.  
  244. function PolicySites(sitesString) {
  245.   if(sitesString) this.sitesString=sitesString;
  246. }
  247. PolicySites.prototype={
  248.   clone: function() {
  249.     return new PolicySites(this.sitesString);
  250.   }
  251. ,
  252.   equals: function(other) {
  253.     return other && (this.sitesString==other.sitesString);
  254.   }
  255. ,
  256.   _sitesString: "",
  257.   get sitesString() {
  258.     return this._sitesString;
  259.   },
  260.   set sitesString(s) {
  261.     s=SiteUtils.sanitizeString(s);
  262.     if(s!=this._sitesString) {
  263.       this._sitesString=s;
  264.       this._sitesMap=null;
  265.       this._sitesList=null;
  266.     }
  267.     return s;
  268.   }
  269. ,
  270.   _sitesList: null,
  271.   get sitesList() {
  272.     return this._sitesList?this._sitesList:this._sitesList=SiteUtils.splitString(this.sitesString);
  273.   },
  274.   set sitesList(sl) {
  275.     this.sitesString=SiteUtils.set2string(SiteUtils.sortedSet(SiteUtils.sanitizeList(sl)));
  276.     return this.sitesList;
  277.   }
  278. ,
  279.   _sitesMap: null,
  280.   get sitesMap() {
  281.     if(!this._sitesMap) {
  282.       const sm={};
  283.       const sl=SiteUtils.splitString(this.sitesString);
  284.       if(sl) {
  285.         for(var j=sl.length; j-->0;) {
  286.           sm[sl[j]]=true;
  287.         }
  288.       }
  289.       this._sitesMap=sm;
  290.     }
  291.     return this._sitesMap;
  292.   },
  293.   set sitesMap(sm) {
  294.     sm = sm?SiteUtils.sanitizeMap(sm):{};
  295.     var sl=[];
  296.     for(var s in sm) {
  297.       sl.push(s);
  298.     }
  299.     
  300.     this._sitesString=SiteUtils.set2string(SiteUtils.sort(sl));
  301.     this._sitesList=null;
  302.     return this._sitesMap=sm;
  303.   }
  304. ,
  305.  fromPref: function(pref) {
  306.    this.sitesString = pref.getCharPref("sites")
  307.        .replace(/[^\u0000-\u007f]+/g, function($0) { return decodeURIComponent(escape($0)) });
  308.  }
  309. ,
  310.  toPref: function(pref) {
  311.    var change;
  312.    var s = this.sitesString.replace(/[^\u0000-\u007f]+/g,function($0) { return unescape(encodeURIComponent($0)) });
  313.    try {
  314.       change = s != pref.getCharPref("sites");
  315.     } catch(ex) {
  316.       change = true;
  317.     }
  318.     
  319.     if(change) {
  320.       pref.setCharPref("sites", s);
  321.     }
  322.  }
  323. ,
  324.   // returns the shortest match for a site, or "" if no match is found
  325.   matches: function(site) {
  326.     if(!site) return "";
  327.     const sm=this.sitesMap;
  328.     var match;
  329.     var dots; // track "dots" for (temporary) fix to 2nd level domain policy lookup flaw 
  330.     var pos=site.indexOf(':')+1;
  331.     if(pos > 0 && (site[pos]=='/' || pos==site.length) ) {
  332.       if(sm[match=site.substring(0,pos)]) return match; // scheme match
  333.       if(site[++pos]!='/') return site == "about:" ? "about:" : "";
  334.       match=site.substring(pos+1);
  335.       dots=0;
  336.     } else {
  337.       match=site;
  338.       dots=1;
  339.     }
  340.  
  341.     var submatch;
  342.     for(pos=match.lastIndexOf('.'); pos>1; dots++) {
  343.       pos=match.lastIndexOf('.',pos-1);
  344.       if( (dots || pos>-1) && sm[submatch=match.substring(pos+1)]) {
  345.         return submatch; // domain/subdomain match
  346.       }
  347.     }
  348.     
  349.     if(sm[match]) return match; // host match
  350.     return sm[site]?site:""; // full match
  351.   }
  352. ,
  353.   _remove: function(site, keepUp, keepDown) {
  354.     if(!site) return false;
  355.     
  356.     const sm=this.sitesMap;
  357.     var change=false;
  358.     var match;
  359.     
  360.     if(site[site.length-1]!=":") { // not a scheme only site
  361.       if(!keepUp) {
  362.         while((match=this.matches(site)) && site!=match) { // remove ancestors
  363.           delete sm[match];
  364.           change = true;
  365.         }
  366.       }
  367.       if(!keepDown) {
  368.         for(match in sm) { // remove descendants
  369.           if( (site==this.matches(match)) && site!=match) {
  370.             delete sm[match];
  371.             change = true;
  372.           }
  373.         }
  374.       }
  375.     }
  376.     
  377.     if(site in sm) {
  378.       delete sm[site];
  379.       if(site.indexOf(".")==site.lastIndexOf(".")) {
  380.         //2nd level domain hack
  381.         delete sm["http://"+site];
  382.         delete sm["https://"+site];
  383.         delete sm["file://"+site];
  384.       }
  385.       change = true;
  386.     }
  387.     
  388.     return change;
  389.   },
  390.   remove: function(sites, keepUp, keepDown) {
  391.     return this._operate(this._remove, arguments);
  392.   },
  393.   _add: function(site) {
  394.     var change=false;
  395.     if(site.indexOf(":")<0 && site.indexOf(".")==site.lastIndexOf(".")) {
  396.      //2nd level domain hack
  397.       change = this._add("http://"+site) || change;
  398.       change = this._add("https://"+site) || change;
  399.       change = this._add("file://"+site) || change;
  400.     }
  401.     const sm=this.sitesMap;
  402.     return (site in sm?false:sm[site]=true) || change;
  403.   },
  404.   add: function(sites) {
  405.     return this._operate(this._add, arguments);
  406.   }, 
  407.   _operate: function(oper, args) {
  408.     var sites = args[0];
  409.     if(!sites) return false;
  410.     
  411.     var change;
  412.     if(typeof(sites)=="object" && sites.constructor == Array) {
  413.       for(var j=sites.length; j-->0; ) {
  414.         args[0]=sites[j];
  415.         if(oper.apply(this,args)) change=true;
  416.       }
  417.     } else {
  418.       change = oper.apply(this,args);
  419.     }
  420.     if(change) {
  421.       this.sitesMap = this._sitesMap;
  422.     }
  423.     return change;
  424.   }
  425. }
  426.  
  427.  
  428.  
  429.  
  430.  
  431. function NoscriptService() {
  432.   this.register();
  433. }
  434.  
  435. NoscriptService.prototype={
  436.   get wrappedJSObject() {
  437.     return this;
  438.   }
  439. ,
  440.   QueryInterface: function(iid) {
  441.      this.queryInterfaceSupport(iid,SERVICE_IIDS);
  442.      return this;
  443.   }
  444. ,
  445.   // nsIObserver implementation 
  446.   observe: function(subject, topic, data) {
  447.     // dump(SERVICE_NAME+" notified of "+subject+","+topic+","+data); //DDEBUG
  448.     
  449.     if(subject instanceof Components.interfaces.nsIPrefBranchInternal) {
  450.       this.syncPrefs(subject,data);
  451.     } else {
  452.       switch(topic) {
  453.         case "xpcom-shutdown":
  454.           this.unregister();
  455.           break;
  456.         case "profile-before-change": 
  457.           this.resetJSCaps();
  458.           break;
  459.         case "profile-after-change":
  460.           this.init();
  461.           break;
  462.         case "em-action-requested":
  463.           if( (subject instanceof Components.interfaces.nsIUpdateItem)
  464.               && subject.id==EXTENSION_ID ) {
  465.               this.uninstallGuard.uninstalling=data=="item-uninstalled";
  466.               this.uninstallGuard.disabled=data=="item-disabled"
  467.           }
  468.       }
  469.     }
  470.   }
  471. ,  
  472.   register: function() {
  473.     const osvr=Components.classes['@mozilla.org/observer-service;1'].getService(
  474.     Components.interfaces.nsIObserverService);
  475.     osvr.addObserver(this,"profile-before-change",false);
  476.     osvr.addObserver(this,"xpcom-shutdown",false);
  477.     osvr.addObserver(this,"profile-after-change",false);
  478.     osvr.addObserver(this,"em-action-requested",false);
  479.   }
  480. ,
  481.   unregister: function() {
  482.     const osvr=Components.classes['@mozilla.org/observer-service;1'].getService(
  483.       Components.interfaces.nsIObserverService);
  484.     osvr.removeObserver(this,"profile-before-change");
  485.     osvr.removeObserver(this,"xpcom-shutdown");
  486.     osvr.removeObserver(this,"profile-after-change");
  487.     osvr.removeObserver(this,"em-action-requested",false);
  488.     if(this.prefs) {
  489.       this.prefs.removeObserver("",this);
  490.       this.mozJSPref.removeObserver("enabled",this,false);
  491.       this.uninstallGuard.dispose();
  492.     }
  493.   }
  494. ,
  495.   syncPrefs: function(branch, name) {
  496.     switch(name) {
  497.       case "sites":
  498.         try {
  499.           this.jsPolicySites.fromPref(this.policyPB);
  500.         } catch(ex) {
  501.           this.policyPB.setCharPref("sites",
  502.             this.getPref("default",
  503.               "chrome: resource: about:neterror flashgot.net mail.google.com googlesyndication.com informaction.com yahoo.com yimg.com maone.net mozilla.org mozillazine.org noscript.net hotmail.com msn.com passport.com passport.net passportimages.com"
  504.             ));
  505.         }
  506.         break;
  507.       /*
  508.       case "permanent":
  509.        
  510.         this.permanentSites.sitesString = this.getPref("permanent",
  511.             "googlesyndication.com noscript.net maone.net informaction.com noscript.net"
  512.           ) + " chrome: resource: about:neterror";
  513.       */
  514.       break;
  515.       case "temp":
  516.         this.tempSites.sitesString=this.getPref("temp","") + " jar:";
  517.         // why jar:? see https://bugzilla.mozilla.org/show_bug.cgi?id=298823
  518.         break;
  519.       case "enabled":
  520.         try {
  521.           this.mozJSEnabled=this.mozJSPref.getBoolPref("enabled");
  522.         } catch(ex) {
  523.           this.mozJSPref.setBoolPref("enabled",this.mozJSEnabled=true);
  524.         }
  525.       break;
  526.       case "forbidJava":
  527.       case "forbidFlash":
  528.       case "forbidPlugins":
  529.         this[name]=this.getPref(name,this[name]);
  530.         this.forbidSomePlugins = this.forbidJava || this.forbidFlash || this.forbidPlugins;
  531.         this.forbidAllPlugins = this.forbidJava && this.forbidFlash && this.forbidPlugins;
  532.         this.initContentPolicy();
  533.       break;
  534.       case "pluginPlaceholder":
  535.       case "showPlaceholder":
  536.       case "consoleDump":
  537.         this[name]=this.getPref(name,this[name]);
  538.       break;
  539.       case "allowClipboard":
  540.         const cp=["cutcopy","paste"];
  541.         const cpEnabled=this.getPref(name,false);
  542.         var cpName;
  543.         for(var cpJ=cp.length; cpJ-->0;) {
  544.           cpName=this.POLICY_NAME+".Clipboard."+cp[cpJ];
  545.           try {
  546.             if(cpEnabled) {
  547.               this.caps.setCharPref(cpName,"allAccess");
  548.             } else {
  549.               if(this.caps.prefHasUserValue(cpName)) {
  550.                 this.caps.clearUserPref(cpName);
  551.               }
  552.             }
  553.           } catch(ex) {
  554.             dump(ex+"\n");
  555.           }
  556.         }
  557.       break;
  558.       case "truncateTitle" :
  559.         this.truncateTitle = this.getPref(name, true);
  560.       break;
  561.       case "truncateTitleLen" :
  562.        this.truncateTitleLen = this.getPref(name, 255);
  563.       break;  
  564.     }
  565.   }
  566. ,
  567.   uninstallGuard: new UninstallGuard("NoScript"),
  568.   _uninstalling: false,
  569.   get uninstalling() {
  570.     if(this._uninstalling) return this._uninstalling;
  571.     const ug=this.uninstallGuard;
  572.     return (this._uninstalling=(ug.uninstalling || ug.disabled))?
  573.       this.cleanupIfUninstalling():false;
  574.   }
  575. ,
  576.   _inited: false,
  577.   POLICY_NAME: "maonoscript",
  578.   prefService: null,
  579.   caps: null,
  580.   policyPB: null,
  581.   prefs: null,
  582.   mozJSPref: null,
  583.   mozJSEnabled: true
  584. ,
  585.   init: function() {
  586.     if(this._inited) return;
  587.     this._inited=true;
  588.     
  589.     const prefserv=this.prefService=Components.classes["@mozilla.org/preferences-service;1"]
  590.       .getService(Components.interfaces.nsIPrefService).QueryInterface(Components.interfaces.nsIPrefBranch);
  591.     
  592.     const PBI=Components.interfaces.nsIPrefBranchInternal;
  593.     this.caps=prefserv.getBranch("capability.policy.").QueryInterface(PBI);
  594.     this.policyPB=prefserv.getBranch("capability.policy."+this.POLICY_NAME+".").QueryInterface(PBI);
  595.     this.policyPB.addObserver("sites",this,false);
  596.     this.prefs=prefserv.getBranch("noscript.").QueryInterface(PBI);
  597.     this.prefs.addObserver("",this,false);
  598.     this.mozJSPref=prefserv.getBranch("javascript.").QueryInterface(Components.interfaces.nsIPrefBranchInternal);
  599.     this.mozJSPref.addObserver("enabled",this,false);
  600.     
  601.     this.permanentSites.sitesString = "chrome: resource: about:neterror";
  602.     
  603.     const syncPrefNames=[ "consoleDump",
  604.       "pluginPlaceholder", "showPlaceholder", "allowClipboard", "forbidPlugins", 
  605.       "forbidJava", "forbidFlash", "temp", // "permanent",
  606.       "truncateTitle", "truncateTitleLen" ];
  607.     for(var spcount=syncPrefNames.length; spcount-->0;) {
  608.       this.syncPrefs(this.prefs,syncPrefNames[spcount]);
  609.     }
  610.     
  611.     this.syncPrefs(this.mozJSPref,"enabled");
  612.    
  613.     // init jsPolicySites from prefs
  614.     this.syncPrefs(this.policyPB,"sites");
  615.     this.eraseTemp();
  616.     
  617.     
  618.     const POLICY_NAME=this.POLICY_NAME;
  619.     var prefArray;
  620.     var prefString="",originalPrefString="";
  621.     try { 
  622.       prefArray=this.splitList(prefString=originalPrefString=this.caps.getCharPref("policynames"));
  623.       var pcount=prefArray.length;
  624.       var pn;
  625.       while(pcount-->0 && (pn=prefArray[pcount])!=POLICY_NAME);
  626.       if(pcount==-1) {
  627.         if(prefArray.length==0) {
  628.           prefString=POLICY_NAME;
  629.         } else {
  630.           prefArray.push(POLICY_NAME);
  631.           prefString=prefArray.join(' ');
  632.         }
  633.       }
  634.       prefString=prefString.replace(/,/g,' ').replace(/\s+/g,' ').replace(/^\s+/,'').replace(/\s+$/,'');
  635.     } catch(ex) {
  636.       prefString=POLICY_NAME;
  637.     }
  638.   
  639.     if(prefString && (prefString!=originalPrefString)) { 
  640.       this.caps.setCharPref("policynames",prefString);
  641.       this.caps.setCharPref(POLICY_NAME+".javascript.enabled","allAccess");
  642.     }
  643.     
  644.     this.reloadWhereNeeded(); // init snapshot
  645.    
  646.     this.uninstallGuard.init();
  647.   }
  648. ,
  649.   permanentSites: new PolicySites(),
  650.   isPermanent: function(s) {
  651.     return s &&
  652.       (s == "chrome:" || s == "resource:" || s =="about:" || s == "about:neterror"
  653.         || this.permanentSites.matches(s));
  654.   }
  655. ,
  656.   tempSites: new PolicySites(),
  657.   isTemp: function(s) {
  658.     return this.tempSites.matches(s);
  659.   }
  660. ,
  661.   setTemp: function(s,b) {
  662.     var change=b?this.tempSites.add(s):this.tempSites.remove(s, true);
  663.     if(change) {
  664.       this.setPref("temp",this.tempSites.sitesString);
  665.     }
  666.   }
  667. ,
  668.   splitList: function(s) {
  669.     return s?/^[,\s]*$/.test(s)?[]:s.split(/\s*[,\s]\s*/):[];
  670.   }
  671. ,
  672.   savePrefs: function() {
  673.     return this.prefService.savePrefFile(null);
  674.   }
  675. ,
  676.   sortedSiteSet: function(s) { return  SiteUtils.sortedSet(s); }
  677. ,
  678.   get jsEnabled() {
  679.     try {
  680.       return this.mozJSEnabled && this.caps.getCharPref("default.javascript.enabled") != "noAccess";
  681.     } catch(ex) {
  682.       return this.uninstalling?this.mozJSEnabled:(this.jsEnabled=this.getPref("global",false));
  683.     }
  684.   }
  685. ,
  686.   set jsEnabled(enabled) {
  687.     this.caps.setCharPref("default.javascript.enabled",enabled?"allAccess":"noAccess");
  688.     this.setPref("global",enabled);
  689.     if(enabled) {
  690.       this.mozJSPref.setBoolPref("enabled",true);
  691.     }
  692.     return enabled;
  693.   }
  694. ,
  695.   getSite: function(url) {
  696.     return SiteUtils.getSite(url);
  697.   }
  698. ,
  699.   jsPolicySites: new PolicySites(),
  700.   isJSEnabled: function(site) {
  701.     return (!!this.jsPolicySites.matches(site));
  702.   },
  703.   setJSEnabled: function(site,is,fromScratch) {
  704.     const ps=this.jsPolicySites;
  705.     if(fromScratch) ps.sitesString=this.permanentSites.sitesString;
  706.     if(is) {
  707.       ps.add(site)
  708.     } else {
  709.       ps.remove(site, false, true);
  710.     }
  711.     this.flushCAPS();
  712.     return is;
  713.   }
  714. ,
  715.  flushCAPS: function(sitesString) {
  716.    const ps = this.jsPolicySites;
  717.    if(sitesString) ps.sitesString = sitesString;
  718.    ps.toPref(this.policyPB);
  719.  }
  720. ,
  721.   delayExec: function(callback,delay) {
  722.      const timer=Components.classes["@mozilla.org/timer;1"].createInstance(
  723.         Components.interfaces.nsITimer);
  724.      timer.initWithCallback( { notify: callback }, 1, 0);
  725.   }
  726. ,
  727.   safeCapsOp: function(callback) {
  728.     callback();
  729.     const serv=this;
  730.     this.delayExec(function() {
  731.       serv.savePrefs();
  732.       serv.reloadWhereNeeded();
  733.      },1);
  734.   }
  735. ,
  736.   _lastSnapshot: null,
  737.   _lastGlobal: false,
  738.   reloadWhereNeeded: function(snapshot,lastGlobal) {
  739.     if(!snapshot) snapshot=this._lastSnapshot;
  740.     const ps=this.jsPolicySites;
  741.     this._lastSnapshot=ps.clone();
  742.     const global=this.jsEnabled;
  743.     if(typeof(lastGlobal)=="undefined") {
  744.       lastGlobal=this._lastGlobal;
  745.     }
  746.     this._lastGlobal=global;
  747.     
  748.     this.initContentPolicy();
  749.     
  750.     if( (global==lastGlobal && ps.equals(snapshot)) || !snapshot) return false;
  751.     
  752.     if(!this.getPref("autoReload")) return false;
  753.     
  754.     var ret=false;
  755.     var ov, gb, bb, b, j, doc, docSites;
  756.     var prevStatus, currStatus;
  757.     const ww = Components.classes['@mozilla.org/appshell/window-mediator;1']
  758.                          .getService(Components.interfaces.nsIWindowMediator)
  759.                          .getEnumerator("navigator:browser");
  760.     for(var w; ww.hasMoreElements();) {
  761.       w=ww.getNext();
  762.       ov=w.noscriptOverlay;
  763.       gb=w.getBrowser?w.getBrowser():null;
  764.       if(ov && gb && (bb=gb.browsers)) {
  765.         for(b=bb.length; b-->0;) {
  766.           doc=ov.getBrowserDoc(bb[b]);
  767.           if(doc) {
  768.             docSites=ov.getSites(doc);
  769.             for(j=docSites.length; j-- >0;) {
  770.               prevStatus=lastGlobal || !!snapshot.matches(docSites[j]);
  771.               currStatus=global || !!ps.matches(docSites[j]);
  772.               if(currStatus!=prevStatus) {
  773.                 ret=true;
  774.                 bb[b].reload();
  775.                 break;
  776.               }
  777.             }
  778.           }
  779.         }
  780.       }
  781.     }
  782.     return ret;
  783.   }
  784. ,
  785.   SPECIAL_TLDS: {
  786.     "ab": " ca ", 
  787.     "ac": " ac at be cn il in jp kr nz th uk za ", 
  788.     "adm": " br ", 
  789.     "adv": " br ",
  790.     "agro": " pl ",
  791.     "ah": " cn ",
  792.     "aid": " pl ",
  793.     "alt": " za ",
  794.     "am": " br ",
  795.     "ar": " com ",
  796.     "arq": " br ",
  797.     "art": " br ",
  798.     "arts": " ro ",
  799.     "asn": " au au ",
  800.     "asso": " fr mc ",
  801.     "atm": " pl ",
  802.     "auto": " pl ",
  803.     "bbs": " tr ",
  804.     "bc": " ca ",
  805.     "bio": " br ",
  806.     "biz": " pl ",
  807.     "bj": " cn ",
  808.     "br": " com ",
  809.     "cn": " com ",
  810.     "cng": " br ",
  811.     "cnt": " br ",
  812.     "co": " ac at il in jp kr nz th uk za ",
  813.     "com": " ar au br cn ec fr hk mm mx pl ro ru sg tr tw ",
  814.     "cq": " cn ",
  815.     "cri": " nz ",
  816.     "ecn": " br ",
  817.     "edu": " ar au cn hk mm mx pl tr za ",
  818.     "eng": " br ",
  819.     "ernet": " in ",
  820.     "esp": " br ",
  821.     "etc": " br ",
  822.     "eti": " br ",
  823.     "eu": " com lv ",
  824.     "fin": " ec ",
  825.     "firm": " ro ",
  826.     "fm": " br ",
  827.     "fot": " br ",
  828.     "fst": " br ",
  829.     "g12": " br ",
  830.     "gb": " com net ",
  831.     "gd": " cn ",
  832.     "gen": " nz ",
  833.     "gmina": " pl ",
  834.     "go": " jp kr th ",
  835.     "gob": " mx ",
  836.     "gov": " ar br cn ec il in mm mx sg tr uk za ",
  837.     "govt": " nz ",
  838.     "gs": " cn ",
  839.     "gsm": " pl ",
  840.     "gv": " ac at ",
  841.     "gx": " cn ",
  842.     "gz": " cn ",
  843.     "hb": " cn ",
  844.     "he": " cn ",
  845.     "hi": " cn ",
  846.     "hk": " cn ",
  847.     "hl": " cn ",
  848.     "hn": " cn ",
  849.     "hu": " com ",
  850.     "id": " au ",
  851.     "ind": " br ",
  852.     "inf": " br ",
  853.     "info": " pl ro ",
  854.     "iwi": " nz ",
  855.     "jl": " cn ",
  856.     "jor": " br ",
  857.     "js": " cn ",
  858.     "k12": " il tr ",
  859.     "lel": " br ",
  860.     "ln": " cn ",
  861.     "ltd": " uk ",
  862.     "mail": " pl ",
  863.     "maori": " nz ",
  864.     "mb": " ca ",
  865.     "me": " uk ",
  866.     "med": " br ec ",
  867.     "media": " pl ",
  868.     "mi": " th ",
  869.     "miasta": " pl ",
  870.     "mil": " br ec nz pl tr za ",
  871.     "mo": " cn ",
  872.     "muni": " il ",
  873.     "nb": " ca ",
  874.     "ne": " jp kr ",
  875.     "net": " ar au br cn ec hk il in mm mx nz pl ru sg th tr tw za ",
  876.     "nf": " ca ",
  877.     "ngo": " za ",
  878.     "nm": " cn kr ",
  879.     "no": " com ",
  880.     "nom": " br pl ro za ",
  881.     "ns": " ca ",
  882.     "nt": " ca ro ",
  883.     "ntr": " br ",
  884.     "nx": " cn ",
  885.     "odo": " br ",
  886.     "on": " ca ",
  887.     "or": " ac at jp kr th ",
  888.     "org": " ar au br cn ec hk il mm mx nz pl ro ru sg tr tw uk za ",
  889.     "pc": " pl ",
  890.     "pe": " ca ",
  891.     "plc": " uk ",
  892.     "ppg": " br ",
  893.     "presse": " fr ",
  894.     "priv": " pl ",
  895.     "pro": " br ",
  896.     "psc": " br ",
  897.     "psi": " br ",
  898.     "qc": " ca com ",
  899.     "qh": " cn ",
  900.     "re": " kr ",
  901.     "realestate": " pl ",
  902.     "rec": " br ro ",
  903.     "rel": " pl ",
  904.     "res": " in ",
  905.     "sa": " com ",
  906.     "sc": " cn ",
  907.     "school": " nz za ",
  908.     "se": " com net ",
  909.     "sh": " cn ",
  910.     "shop": " pl ",
  911.     "sk": " ca ",
  912.     "sklep": " pl ",
  913.     "slg": " br ",
  914.     "sn": " cn ",
  915.     "sos": " pl ",
  916.     "store": " ro ",
  917.     "targi": " pl ",
  918.     "tj": " cn ",
  919.     "tm": " fr mc pl ro za ",
  920.     "tmp": " br ",
  921.     "tourism": " pl ",
  922.     "travel": " pl ",
  923.     "tur": " br ",
  924.     "turystyka": " pl ",
  925.     "tv": " br ",
  926.     "tw": " cn ",
  927.     "uk": " co com net ",
  928.     "us": " com ca ",
  929.     "uy": " com ",
  930.     "vet": " br ",
  931.     "web": " za ",
  932.     "www": " ro ",
  933.     "xj": " cn ",
  934.     "xz": " cn ",
  935.     "yk": " ca ",
  936.     "yn": " cn ",
  937.     "za": " com ",
  938.     "zj": " cn ", 
  939.     "zlg": " br "
  940.   }
  941. ,
  942.   cleanup: function() {
  943.     this.cleanupIfUninstalling();
  944.   }
  945. ,
  946.   cleanupIfUninstalling: function() {
  947.     if(this.uninstalling) this.uninstallJob();
  948.     return this.uninstalling;
  949.   }
  950. ,
  951.   eraseTemp: function() {
  952.     this.jsPolicySites.remove(this.tempSites.sitesList, false, true); // remove temporary
  953.     this.setJSEnabled(this.permanentSites.sitesList, true); // add permanent & save
  954.     this.setPref("temp",""); // flush temporary list
  955.   }
  956. ,
  957.   resetJSCaps: function() {
  958.     try {
  959.       this.caps.clearUserPref("default.javascript.enabled");
  960.     } catch(ex) {}
  961.     try {
  962.       const POLICY_NAME=this.POLICY_NAME;
  963.       var prefArray=SiteUtils.splitString(this.caps.getCharPref("policynames"));
  964.       var pcount=prefArray.length;
  965.       const prefArrayTarget=[];
  966.       for(var pcount=prefArray.length; pcount-->0;) {
  967.         if(prefArray[pcount]!=POLICY_NAME) prefArrayTarget[prefArrayTarget.length]=prefArray[pcount];
  968.       }
  969.       var prefString=prefArrayTarget.join(" ").replace(/\s+/g,' ').replace(/^\s+/,'').replace(/\s+$/,'');
  970.       if(prefString) {
  971.         this.caps.setCharPref("policynames",prefString);
  972.       } else {
  973.         try {
  974.           this.caps.clearUserPref("policynames");
  975.         } catch(ex1) {}
  976.       }
  977.       this.eraseTemp();
  978.       this.savePrefs();
  979.     } catch(ex) {
  980.       // dump(ex);
  981.     }
  982.   }
  983. ,
  984.   uninstallJob: function() {
  985.     this.resetJSCaps();
  986.   }
  987. ,
  988.   getPref: function(name,def) {
  989.     const IPC=Components.interfaces.nsIPrefBranch;
  990.     const prefs=this.prefs;
  991.     try {
  992.       switch(prefs.getPrefType(name)) {
  993.         case IPC.PREF_STRING:
  994.           return prefs.getCharPref(name);
  995.         case IPC.PREF_INT:
  996.           return prefs.getIntPref(name);
  997.         case IPC.PREF_BOOL:
  998.           return prefs.getBoolPref(name);
  999.       }
  1000.     } catch(e) {}
  1001.     return def;
  1002.   }
  1003. ,
  1004.   setPref: function(name,value) {
  1005.     const prefs=this.prefs;
  1006.     switch(typeof(value)) {
  1007.       case "string":
  1008.           prefs.setCharPref(name,value);
  1009.           break;
  1010.       case "boolean":
  1011.         prefs.setBoolPref(name,value);
  1012.         break;
  1013.       case "number":
  1014.         prefs.setIntPref(name,value);
  1015.         break;
  1016.       default:
  1017.         throw new Error("Unsupported type "+typeof(value)+" for preference "+name);
  1018.     }
  1019.   }
  1020. ,
  1021.   _sound: null,
  1022.   playSound: function(url,force) {
  1023.     if(force || this.getPref("sound",true)) {
  1024.       var sound=this._sound;
  1025.       if(sound==null) {
  1026.         sound=Components.classes["@mozilla.org/sound;1"].createInstance(Components.interfaces.nsISound);
  1027.         sound.init();
  1028.       }
  1029.       try {
  1030.         sound.play(SiteUtils.ios.newURI(url,null,null));
  1031.       } catch(ex) {
  1032.         //dump(ex);
  1033.       }
  1034.     }
  1035.   }
  1036. ,
  1037.   readFile: function(file) {
  1038.     const cc=Components.classes;
  1039.     const ci=Components.interfaces;  
  1040.     const is = cc["@mozilla.org/network/file-input-stream;1"].createInstance(
  1041.           ci.nsIFileInputStream );
  1042.     is.init(file ,0x01, 0400, null);
  1043.     const sis = cc["@mozilla.org/scriptableinputstream;1"].createInstance(
  1044.       ci.nsIScriptableInputStream );
  1045.     sis.init(is);
  1046.     const res=sis.read(sis.available());
  1047.     is.close();
  1048.     return res;
  1049.   }
  1050. ,
  1051.   writeFile: function(file, content) {
  1052.     const cc=Components.classes;
  1053.     const ci=Components.interfaces;
  1054.     const unicodeConverter = cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(
  1055.     ci.nsIScriptableUnicodeConverter);
  1056.     unicodeConverter.charset = "UTF-8";
  1057.     content=unicodeConverter.ConvertFromUnicode(content);
  1058.     const os=cc["@mozilla.org/network/file-output-stream;1"].createInstance(
  1059.       ci.nsIFileOutputStream);
  1060.     os.init(file, 0x02 | 0x08 | 0x20,0664,0);
  1061.     os.write(content,content.length);
  1062.     os.close();
  1063.   }
  1064. ,
  1065.   get prompter() {
  1066.     return Components.classes["@mozilla.org/embedcomp/prompt-service;1"
  1067.           ].getService(Components.interfaces.nsIPromptService);
  1068.   }
  1069. ,
  1070.   queryInterfaceSupport: function(iid,iids) { 
  1071.     xpcom_checkInterfaces(iid, iids, Components.results.NS_ERROR_NO_INTERFACE);
  1072.   }
  1073. ,
  1074.  lookupMethod: Components.utils?Components.utils.lookupMethod:Components.lookupMethod
  1075. ,
  1076.   pluginPlaceholder: "chrome://noscript/skin/icon32.png",
  1077.   showPlaceHolder: true,
  1078.   pluginsExtrasMark: {},
  1079.   getPluginExtras: function(obj) {
  1080.     return (obj._noScriptExtras && obj._noScriptExtras.mark && 
  1081.       this.pluginsExtrasMark == obj._noScriptExtras.mark) ? obj._noScriptExtras : null;
  1082.   },
  1083.   consoleDump: false,
  1084.   forbidSomePlugins: false,
  1085.   forbidAllPlugins: false,
  1086.   forbidJava: false,
  1087.   forbidFlash: false,
  1088.   forbidPlugins: false, 
  1089.   initContentPolicy: function() {
  1090.     var delegate = (this.forbidSomePlugins && !this.getPref("global",false)) ? 
  1091.         (Components.interfaces.nsIContentPolicy.TYPE_OBJECT 
  1092.           ? this.mainContentPolicy 
  1093.           : this.oldStyleContentPolicy)
  1094.       : this.noopContentPolicy;
  1095.     this.shouldLoad = delegate.shouldLoad;
  1096.     this.shouldProcess = delegate.shouldProcess;
  1097.   },
  1098.   // nsIContentPolicy interface
  1099.   // we use numeric constants for performance sake:
  1100.   // nsIContentPolicy.TYPE_SCRIPT = 2
  1101.   // nsIContentPolicy.TYPE_OBJECT = 5
  1102.   // nsIContentPolicy.TYPE_DOCUMENT = 6
  1103.   // nsIContentPolicy.TYPE_SUBDOCUMENT = 7
  1104.   // nsIContentPolicy.REJECT_SERVER = -3
  1105.   // nsIContentPolicy.ACCEPT = 1
  1106.   noopContentPolicy: {
  1107.     shouldLoad: function() { return 1; },
  1108.     shouldProcess: function() { return 1; }
  1109.   },
  1110.   mainContentPolicy: {
  1111.     shouldLoad: function(aContentType, aContentLocation, aRequestOrigin, aContext, aMimeTypeGuess, aInternalCall) {
  1112.       var forbid, isJS, isFlash, isJava;
  1113.       if(aContentType == 5 || (forbid = isJS = (aContentType == 2))) {
  1114.         const url = aContentLocation.spec;
  1115.         const origin = this.getSite(url);
  1116.         if(!forbid) {
  1117.           var forceAllow;
  1118.           try {
  1119.             forceAllow = this.pluginsCache.update(url, aMimeTypeGuess, origin, aRequestOrigin, aContext);
  1120.           } catch(ex) {
  1121.             dump("NoScriptService.pluginsCache.update():" + ex + "\n");
  1122.           }
  1123.           if((!forceAllow) && this.forbidSomePlugins) {
  1124.             var forbid=this.forbidAllPlugins;
  1125.             if((!forbid) && aMimeTypeGuess) {
  1126.               forbid = 
  1127.                 (isFlash = aMimeTypeGuess == "application/x-shockwave-flash") && this.forbidFlash ||
  1128.                 (isJava = aMimeTypeGuess.indexOf("application/x-java-")==0) && this.forbidJava ||
  1129.                 (this.forbidPlugins && !(isJava || isFlash));
  1130.             }
  1131.           }
  1132.         }
  1133.         
  1134.         if(forbid) {
  1135.           if(!(this.isJSEnabled(origin))) {
  1136.             
  1137.             if(aContext && (!isJS)) {
  1138.               const ci = Components.interfaces;
  1139.               if(aContext instanceof ci.nsIDOMNode) {
  1140.                 
  1141.                 const lm=this.lookupMethod;
  1142.                 
  1143.                 if(this.pluginPlaceholder) {
  1144.                  
  1145.                   if(aContext instanceof(ci.nsIDOMHTMLEmbedElement)) {
  1146.                     var parent = lm(aContext,"parentNode")();
  1147.                     if(parent instanceof ci.nsIDOMHTMLObjectElement) {
  1148.                       aContext = parent;
  1149.                     }
  1150.                   }
  1151.  
  1152.                   if(aMimeTypeGuess && !this.getPluginExtras(aContext)) {
  1153.                     aContext._noScriptExtras = {
  1154.                       mark: this.pluginsExtrasMark,
  1155.                       url: url,
  1156.                       mime: aMimeTypeGuess
  1157.                     };
  1158.                   }
  1159.                 }
  1160.               }
  1161.             }
  1162.             
  1163.             if(this.consoleDump) 
  1164.               dump("NoScript blocked " + url + " which is a " + aMimeTypeGuess + " from " + origin + "\n");
  1165.             return -3;
  1166.           }
  1167.         }
  1168.       }
  1169.     
  1170.       return 1;
  1171.     },
  1172.     shouldProcess: function(aContentType, aContentLocation, aRequestOrigin, aContext, aMimeType, aExtra) {
  1173.       return this.shouldLoad(aContentType, aContentLocation, aRequestOrigin, aContext, aMimeType, true);
  1174.     }
  1175.   },
  1176.   oldStyleContentPolicy: {
  1177.     shouldLoad: function(aContentType, aContentLocation, aCtx, aWin, aInternalCall) {
  1178.       aContentType++;
  1179.       var mimeType = "";
  1180.       var origin = null;
  1181.       if(aContentType == 5) {
  1182.         var ext, pos;
  1183.         if(aCtx && (aCtx instanceof Components.interfaces.nsIDOMHTMLAppletElement) || 
  1184.             (ext = (ext = aContentLocation.path).substring(ext.lastIndexOf(
  1185.               ".",(pos=ext.indexOf("?"))>0 ? pos : pos=ext.length)+1,pos).toLowerCase() ) == "jnlp" ) {
  1186.           mimeType = "application/x-java-";
  1187.         } else {
  1188.           if(ext == "swf") mimeType = "application/x-shockwave-flash";
  1189.         }
  1190.         if(aCtx && aCtx.ownerDocument) {
  1191.           origin = { spec: aCtx.ownerDocument.documentURI };
  1192.         }
  1193.       }
  1194.       return this.mainContentPolicy
  1195.                  .shouldLoad.call(this, aContentType, aContentLocation, origin, 
  1196.                       aCtx || aWin, mimeType, aInternalCall) == 1;
  1197.     },
  1198.     shouldProcess: function(aContentType, aContentLocation, aCtx, aWin) {
  1199.       return this.shouldLoad(aContentType, aContentLocation, aCtx, aWin, true);
  1200.     }
  1201.   },
  1202.   pluginsCache: {
  1203.     
  1204.     findBrowser: function(chrome, win) {
  1205.       var gb=chrome.getBrowser();
  1206.       var browsers;
  1207.       if(! (gb && (browsers = gb.browsers))) return null;
  1208.       
  1209.       var browser = gb.selectedBrowser;
  1210.       if(browser.contentWindow == win) return browser;
  1211.       
  1212.       for(var j = browsers.length; j-- > 0;) {
  1213.         browser = browsers[j];
  1214.         if(browser.contentWindow == win) return browser;
  1215.       }
  1216.       
  1217.       return null;
  1218.     },
  1219.     findBrowserForNode: function(ctx) {
  1220.       if(!ctx) return null;
  1221.       const ci = Components.interfaces;
  1222.       const lm = this.lookupMethod;
  1223.       if(!(ctx instanceof ci.nsIDOMWindow)) {
  1224.         if(ctx instanceof ci.nsIDOMDocument) {
  1225.           ctx = lm(ctx,"defaultView")();
  1226.         } else if(ctx instanceof ci.nsIDOMNode) {
  1227.           ctx = lm(lm(ctx,"ownerDocument")(),"defaultView")();
  1228.         } else return; 
  1229.       }
  1230.       if(!ctx) return;
  1231.       ctx = lm(ctx,"top")();
  1232.       
  1233.       const wm = Components.classes['@mozilla.org/appshell/window-mediator;1']
  1234.                            .getService(Components.interfaces.nsIWindowMediator);
  1235.       const chrome = wm.getMostRecentWindow("navigator:browser");
  1236.       
  1237.       if(! (browser = this.findBrowser(chrome, ctx))) {
  1238.         const ww = wm.getEnumerator("navigator:browser");
  1239.         for(var w; ww.hasMoreElements();) {
  1240.           w=ww.getNext();
  1241.           if(w != chrome && (browser = this.findBrowser(w, ctx))) {
  1242.             break;
  1243.           }
  1244.         }
  1245.       }
  1246.       
  1247.       return browser;
  1248.     },
  1249.     lookupMethod: Components.utils?Components.utils.lookupMethod:Components.lookupMethod,
  1250.     update: function(url, mime, origin, docURI, ctx) { // returns forceAllow
  1251.       var browser = this.findBrowserForNode(ctx);
  1252.       if(browser) {
  1253.         var cache = this.get(browser);
  1254.         var uriCache = cache.uris;
  1255.         var uriSpec = docURI.spec;
  1256.         var origCache = uriCache[uriSpec] || (uriCache[uriSpec] = {});
  1257.         origCache[origin] = true;
  1258.         var forceMime = cache.forceAllow[url];
  1259.         return forceMime && forceMime == mime;
  1260.       }
  1261.       return false;
  1262.     },
  1263.     purge: function(cache, uris) {
  1264.       var uriCache = cache.uris;
  1265.       for(u in uriCache) {
  1266.         if(!uris[u]) delete uriCache[u];
  1267.       }
  1268.     },
  1269.     get: function(browser) {
  1270.       return browser.noScriptPluginsCache || 
  1271.       (browser.noScriptPluginsCache = { uris: {}, forceAllow: {} });
  1272.     }
  1273.   }
  1274. };
  1275.  
  1276.  
  1277.  
  1278. // XPCOM Scaffolding code
  1279.  
  1280. // component defined in this file
  1281. const EXTENSION_ID="{73a6fe31-595d-460b-a920-fcc0f8843232}";
  1282. const SERVICE_NAME="NoScript Service";
  1283. const SERVICE_ID="{31aec909-8e86-4397-9380-63a59e0c5ff5}";
  1284. const SERVICE_CTRID = "@maone.net/noscript-service;1";
  1285. const SERVICE_CONSTRUCTOR=NoscriptService;
  1286.  
  1287. const SERVICE_CID = Components.ID(SERVICE_ID);
  1288.  
  1289. // interfaces implemented by this component
  1290. const SERVICE_IIDS = 
  1291. Components.interfaces.nsIObserver,
  1292. Components.interfaces.nsISupports,
  1293. Components.interfaces.nsISupportsWeakReference,
  1294. Components.interfaces.nsIContentPolicy
  1295. ];
  1296.  
  1297. // categories which this component is registered in
  1298. const SERVICE_CATS = ["app-startup","content-policy"];
  1299.  
  1300.  
  1301. // Factory object
  1302. const SERVICE_FACTORY = {
  1303.   _instance: null,
  1304.   createInstance: function (outer, iid) {
  1305.     if (outer != null)
  1306.         throw Components.results.NS_ERROR_NO_AGGREGATION;
  1307.  
  1308.     xpcom_checkInterfaces(iid,SERVICE_IIDS,Components.results.NS_ERROR_INVALID_ARG);
  1309.     // kept this for flexibility sake, but we're really adopting an
  1310.     // early instantiation and late init singleton pattern
  1311.     return this._instance==null?this._instance=new SERVICE_CONSTRUCTOR():this._instance;
  1312.   }
  1313. };
  1314.  
  1315. function xpcom_checkInterfaces(iid,iids,ex) {
  1316.   for(var j=iids.length; j-- >0;) {
  1317.     if(iid.equals(iids[j])) return true;
  1318.   }
  1319.   throw ex;
  1320. }
  1321.  
  1322. // Module
  1323.  
  1324. var Module = new Object();
  1325. Module.firstTime=true;
  1326. Module.registerSelf = function (compMgr, fileSpec, location, type) {
  1327.   if(this.firstTime) {
  1328.    
  1329.     debug("*** Registering "+SERVICE_CTRID+".\n");
  1330.     
  1331.     compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar
  1332.       ).registerFactoryLocation(SERVICE_CID,
  1333.       SERVICE_NAME,
  1334.       SERVICE_CTRID, 
  1335.       fileSpec,
  1336.       location, 
  1337.       type);
  1338.     const catman = Components.classes['@mozilla.org/categorymanager;1'
  1339.       ].getService(Components.interfaces.nsICategoryManager);
  1340.     for(var j=0, len=SERVICE_CATS.length; j<len; j++) {
  1341.       catman.addCategoryEntry(SERVICE_CATS[j],
  1342.         //SERVICE_NAME, "service," + SERVICE_CTRID, 
  1343.         SERVICE_CTRID, SERVICE_CTRID, true, true, null);
  1344.     }
  1345.     this.firstTime=false;
  1346.   } 
  1347. }
  1348. Module.unregisterSelf = function(compMgr, fileSpec, location) {
  1349.   compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar
  1350.     ).unregisterFactoryLocation(SERVICE_CID, fileSpec);
  1351.   const catman = Components.classes['@mozilla.org/categorymanager;1'
  1352.       ].getService(Components.interfaces.nsICategoryManager);
  1353.   for(var j=0, len=SERVICE_CATS.length; j<len; j++) {
  1354.     catman.deleteCategoryEntry(SERVICE_CATS[j], SERVICE_CTRID, true);
  1355.   }
  1356. }
  1357.  
  1358. Module.getClassObject = function (compMgr, cid, iid) {
  1359.   if(cid.equals(SERVICE_CID))
  1360.     return SERVICE_FACTORY;
  1361.  
  1362.   if (!iid.equals(Components.interfaces.nsIFactory))
  1363.     throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  1364.   
  1365.   throw Components.results.NS_ERROR_NO_INTERFACE;
  1366.     
  1367. }
  1368.  
  1369. Module.canUnload = function(compMgr) {
  1370.   return true;
  1371. }
  1372.  
  1373. // entrypoint
  1374. function NSGetModule(compMgr, fileSpec) {
  1375.   return Module;
  1376. }
  1377.  
  1378.  
  1379.