home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2006 March / PCWMAR06.iso / Software / FromTheMag / Noscript / noscript-1.1.3.5-fx+mz.xpi / components / noscriptService.js < prev   
Encoding:
JavaScript  |  2005-12-08  |  39.4 KB  |  1,378 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.       case "permanent":
  508.         this.permanentSites.sitesString=this.getPref("permanent",
  509.             "googlesyndication.com noscript.net maone.net informaction.com noscript.net"
  510.           ) + " chrome: resource: about:neterror";
  511.       break;
  512.       case "temp":
  513.         this.tempSites.sitesString=this.getPref("temp","") + " jar:";
  514.         // why jar:? see https://bugzilla.mozilla.org/show_bug.cgi?id=298823
  515.         break;
  516.       case "enabled":
  517.         try {
  518.           this.mozJSEnabled=this.mozJSPref.getBoolPref("enabled");
  519.         } catch(ex) {
  520.           this.mozJSPref.setBoolPref("enabled",this.mozJSEnabled=true);
  521.         }
  522.       break;
  523.       case "forbidJava":
  524.       case "forbidFlash":
  525.       case "forbidPlugins":
  526.         this[name]=this.getPref(name,this[name]);
  527.         this.forbidSomePlugins = this.forbidJava || this.forbidFlash || this.forbidPlugins;
  528.         this.forbidAllPlugins = this.forbidJava && this.forbidFlash && this.forbidPlugins;
  529.         this.initContentPolicy();
  530.       break;
  531.       case "pluginPlaceholder":
  532.       case "showPlaceholder":
  533.         this[name]=this.getPref(name,this[name]);
  534.       break;
  535.       case "allowClipboard":
  536.         const cp=["cutcopy","paste"];
  537.         const cpEnabled=this.getPref(name,false);
  538.         var cpName;
  539.         for(var cpJ=cp.length; cpJ-->0;) {
  540.           cpName=this.POLICY_NAME+".Clipboard."+cp[cpJ];
  541.           try {
  542.             if(cpEnabled) {
  543.               this.caps.setCharPref(cpName,"allAccess");
  544.             } else {
  545.               if(this.caps.prefHasUserValue(cpName)) {
  546.                 this.caps.clearUserPref(cpName);
  547.               }
  548.             }
  549.           } catch(ex) {
  550.             dump(ex+"\n");
  551.           }
  552.         }
  553.       break;
  554.       case "truncateTitle" :
  555.         this.truncateTitle = this.getPref(name, true);
  556.       break;
  557.       case "truncateTitleLen" :
  558.        this.truncateTitleLen = this.getPref(name, 255);
  559.       break;  
  560.     }
  561.   }
  562. ,
  563.   uninstallGuard: new UninstallGuard("NoScript"),
  564.   _uninstalling: false,
  565.   get uninstalling() {
  566.     if(this._uninstalling) return this._uninstalling;
  567.     const ug=this.uninstallGuard;
  568.     return (this._uninstalling=(ug.uninstalling || ug.disabled))?
  569.       this.cleanupIfUninstalling():false;
  570.   }
  571. ,
  572.   _inited: false,
  573.   POLICY_NAME: "maonoscript",
  574.   prefService: null,
  575.   caps: null,
  576.   policyPB: null,
  577.   prefs: null,
  578.   mozJSPref: null,
  579.   mozJSEnabled: true
  580. ,
  581.   init: function() {
  582.     if(this._inited) return;
  583.     this._inited=true;
  584.     
  585.     const prefserv=this.prefService=Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService)
  586.     const PBI=Components.interfaces.nsIPrefBranchInternal;
  587.     this.caps=prefserv.getBranch("capability.policy.").QueryInterface(PBI);
  588.     this.policyPB=prefserv.getBranch("capability.policy."+this.POLICY_NAME+".").QueryInterface(PBI);
  589.     this.policyPB.addObserver("sites",this,false);
  590.     this.prefs=prefserv.getBranch("noscript.").QueryInterface(PBI);
  591.     this.prefs.addObserver("",this,false);
  592.     this.mozJSPref=prefserv.getBranch("javascript.").QueryInterface(Components.interfaces.nsIPrefBranchInternal);
  593.     this.mozJSPref.addObserver("enabled",this,false);
  594.     
  595.     const syncPrefNames=[
  596.       "pluginPlaceholder", "showPlaceholder", "allowClipboard", "forbidPlugins", 
  597.       "forbidJava", "forbidFlash", "temp", "permanent",
  598.       "truncateTitle", "truncateTitleLen" ];
  599.     for(var spcount=syncPrefNames.length; spcount-->0;) {
  600.       this.syncPrefs(this.prefs,syncPrefNames[spcount]);
  601.     }
  602.     
  603.     this.syncPrefs(this.mozJSPref,"enabled");
  604.    
  605.     // init jsPolicySites from prefs
  606.     this.syncPrefs(this.policyPB,"sites");
  607.     this.eraseTemp();
  608.     
  609.     
  610.     const POLICY_NAME=this.POLICY_NAME;
  611.     var prefArray;
  612.     var prefString="",originalPrefString="";
  613.     try { 
  614.       prefArray=this.splitList(prefString=originalPrefString=this.caps.getCharPref("policynames"));
  615.       var pcount=prefArray.length;
  616.       var pn;
  617.       while(pcount-->0 && (pn=prefArray[pcount])!=POLICY_NAME);
  618.       if(pcount==-1) {
  619.         if(prefArray.length==0) {
  620.           prefString=POLICY_NAME;
  621.         } else {
  622.           prefArray.push(POLICY_NAME);
  623.           prefString=prefArray.join(' ');
  624.         }
  625.       }
  626.       prefString=prefString.replace(/,/g,' ').replace(/\s+/g,' ').replace(/^\s+/,'').replace(/\s+$/,'');
  627.     } catch(ex) {
  628.       prefString=POLICY_NAME;
  629.     }
  630.   
  631.     if(prefString && (prefString!=originalPrefString)) { 
  632.       this.caps.setCharPref("policynames",prefString);
  633.       this.caps.setCharPref(POLICY_NAME+".javascript.enabled","allAccess");
  634.     }
  635.     
  636.     this.reloadWhereNeeded(); // init snapshot
  637.    
  638.     this.uninstallGuard.init();
  639.   }
  640. ,
  641.   permanentSites: new PolicySites(),
  642.   isPermanent: function(s) {
  643.     return s &&
  644.       (s == "chrome:" || s == "resource:" || s =="about:" || s == "about:neterror"
  645.         || this.permanentSites.matches(s));
  646.   }
  647. ,
  648.   tempSites: new PolicySites(),
  649.   isTemp: function(s) {
  650.     return this.tempSites.matches(s);
  651.   }
  652. ,
  653.   setTemp: function(s,b) {
  654.     var change=b?this.tempSites.add(s):this.tempSites.remove(s, true);
  655.     if(change) {
  656.       this.setPref("temp",this.tempSites.sitesString);
  657.     }
  658.   }
  659. ,
  660.   splitList: function(s) {
  661.     return s?/^[,\s]*$/.test(s)?[]:s.split(/\s*[,\s]\s*/):[];
  662.   }
  663. ,
  664.   savePrefs: function() {
  665.     return this.prefService.savePrefFile(null);
  666.   }
  667. ,
  668.   sortedSiteSet: function(s) { return  SiteUtils.sortedSet(s); }
  669. ,
  670.   get jsEnabled() {
  671.     try {
  672.       return this.mozJSEnabled && this.caps.getCharPref("default.javascript.enabled") != "noAccess";
  673.     } catch(ex) {
  674.       return this.uninstalling?this.mozJSEnabled:(this.jsEnabled=this.getPref("global",false));
  675.     }
  676.   }
  677. ,
  678.   set jsEnabled(enabled) {
  679.     this.caps.setCharPref("default.javascript.enabled",enabled?"allAccess":"noAccess");
  680.     this.setPref("global",enabled);
  681.     if(enabled) {
  682.       this.mozJSPref.setBoolPref("enabled",true);
  683.     }
  684.     return enabled;
  685.   }
  686. ,
  687.   getSite: function(url) {
  688.     return SiteUtils.getSite(url);
  689.   }
  690. ,
  691.   jsPolicySites: new PolicySites(),
  692.   isJSEnabled: function(site) {
  693.     return (!!this.jsPolicySites.matches(site));
  694.   },
  695.   setJSEnabled: function(site,is,fromScratch) {
  696.     const ps=this.jsPolicySites;
  697.     if(fromScratch) ps.sitesString=this.permanentSites.sitesString;
  698.     if(is) {
  699.       ps.add(site)
  700.     } else {
  701.       ps.remove(site, false, true);
  702.     }
  703.     this.flushCAPS();
  704.     return is;
  705.   }
  706. ,
  707.  flushCAPS: function(sitesString) {
  708.    const ps = this.jsPolicySites;
  709.    if(sitesString) ps.sitesString = sitesString;
  710.    ps.toPref(this.policyPB);
  711.  }
  712. ,
  713.   delayExec: function(callback,delay) {
  714.      const timer=Components.classes["@mozilla.org/timer;1"].createInstance(
  715.         Components.interfaces.nsITimer);
  716.      timer.initWithCallback( { notify: callback }, 1, 0);
  717.   }
  718. ,
  719.   safeCapsOp: function(callback) {
  720.     callback();
  721.     const serv=this;
  722.     this.delayExec(function() {
  723.       serv.savePrefs();
  724.       serv.reloadWhereNeeded();
  725.      },1);
  726.   }
  727. ,
  728.   _lastSnapshot: null,
  729.   _lastGlobal: false,
  730.   reloadWhereNeeded: function(snapshot,lastGlobal) {
  731.     if(!snapshot) snapshot=this._lastSnapshot;
  732.     const ps=this.jsPolicySites;
  733.     this._lastSnapshot=ps.clone();
  734.     const global=this.jsEnabled;
  735.     if(typeof(lastGlobal)=="undefined") {
  736.       lastGlobal=this._lastGlobal;
  737.     }
  738.     this._lastGlobal=global;
  739.     
  740.     this.initContentPolicy();
  741.     
  742.     if( (global==lastGlobal && ps.equals(snapshot)) || !snapshot) return false;
  743.     
  744.     if(!this.getPref("autoReload")) return false;
  745.     
  746.     var ret=false;
  747.     var ov, gb, bb, b, j, doc, docSites;
  748.     var prevStatus, currStatus;
  749.     const ww = Components.classes['@mozilla.org/appshell/window-mediator;1']
  750.                          .getService(Components.interfaces.nsIWindowMediator)
  751.                          .getEnumerator("navigator:browser");
  752.     for(var w; ww.hasMoreElements();) {
  753.       w=ww.getNext();
  754.       ov=w.noscriptOverlay;
  755.       gb=w.getBrowser?w.getBrowser():null;
  756.       if(ov && gb && (bb=gb.browsers)) {
  757.         for(b=bb.length; b-->0;) {
  758.           doc=ov.getBrowserDoc(bb[b]);
  759.           if(doc) {
  760.             docSites=ov.getSites(doc);
  761.             for(j=docSites.length; j-- >0;) {
  762.               prevStatus=lastGlobal || !!snapshot.matches(docSites[j]);
  763.               currStatus=global || !!ps.matches(docSites[j]);
  764.               if(currStatus!=prevStatus) {
  765.                 ret=true;
  766.                 bb[b].reload();
  767.                 break;
  768.               }
  769.             }
  770.           }
  771.         }
  772.       }
  773.     }
  774.     return ret;
  775.   }
  776. ,
  777.   SPECIAL_TLDS: {
  778.     "ab": " ca ", 
  779.     "ac": " ac at be cn il in jp kr nz th uk za ", 
  780.     "adm": " br ", 
  781.     "adv": " br ",
  782.     "agro": " pl ",
  783.     "ah": " cn ",
  784.     "aid": " pl ",
  785.     "alt": " za ",
  786.     "am": " br ",
  787.     "ar": " com ",
  788.     "arq": " br ",
  789.     "art": " br ",
  790.     "arts": " ro ",
  791.     "asn": " au au ",
  792.     "asso": " fr mc ",
  793.     "atm": " pl ",
  794.     "auto": " pl ",
  795.     "bbs": " tr ",
  796.     "bc": " ca ",
  797.     "bio": " br ",
  798.     "biz": " pl ",
  799.     "bj": " cn ",
  800.     "br": " com ",
  801.     "cn": " com ",
  802.     "cng": " br ",
  803.     "cnt": " br ",
  804.     "co": " ac at il in jp kr nz th uk za ",
  805.     "com": " ar au br cn ec fr hk mm mx pl ro ru sg tr tw ",
  806.     "cq": " cn ",
  807.     "cri": " nz ",
  808.     "ecn": " br ",
  809.     "edu": " ar au cn hk mm mx pl tr za ",
  810.     "eng": " br ",
  811.     "ernet": " in ",
  812.     "esp": " br ",
  813.     "etc": " br ",
  814.     "eti": " br ",
  815.     "eu": " com lv ",
  816.     "fin": " ec ",
  817.     "firm": " ro ",
  818.     "fm": " br ",
  819.     "fot": " br ",
  820.     "fst": " br ",
  821.     "g12": " br ",
  822.     "gb": " com net ",
  823.     "gd": " cn ",
  824.     "gen": " nz ",
  825.     "gmina": " pl ",
  826.     "go": " jp kr th ",
  827.     "gob": " mx ",
  828.     "gov": " ar br cn ec il in mm mx sg tr za ",
  829.     "govt": " nz ",
  830.     "gs": " cn ",
  831.     "gsm": " pl ",
  832.     "gv": " ac at ",
  833.     "gx": " cn ",
  834.     "gz": " cn ",
  835.     "hb": " cn ",
  836.     "he": " cn ",
  837.     "hi": " cn ",
  838.     "hk": " cn ",
  839.     "hl": " cn ",
  840.     "hn": " cn ",
  841.     "hu": " com ",
  842.     "id": " au ",
  843.     "ind": " br ",
  844.     "inf": " br ",
  845.     "info": " pl ro ",
  846.     "iwi": " nz ",
  847.     "jl": " cn ",
  848.     "jor": " br ",
  849.     "js": " cn ",
  850.     "k12": " il tr ",
  851.     "lel": " br ",
  852.     "ln": " cn ",
  853.     "ltd": " uk ",
  854.     "mail": " pl ",
  855.     "maori": " nz ",
  856.     "mb": " ca ",
  857.     "me": " uk ",
  858.     "med": " br ec ",
  859.     "media": " pl ",
  860.     "mi": " th ",
  861.     "miasta": " pl ",
  862.     "mil": " br ec nz pl tr za ",
  863.     "mo": " cn ",
  864.     "muni": " il ",
  865.     "nb": " ca ",
  866.     "ne": " jp kr ",
  867.     "net": " ar au br cn ec hk il in mm mx nz pl ru sg th tr tw za ",
  868.     "nf": " ca ",
  869.     "ngo": " za ",
  870.     "nm": " cn kr ",
  871.     "no": " com ",
  872.     "nom": " br pl ro za ",
  873.     "ns": " ca ",
  874.     "nt": " ca ro ",
  875.     "ntr": " br ",
  876.     "nx": " cn ",
  877.     "odo": " br ",
  878.     "on": " ca ",
  879.     "or": " ac at jp kr th ",
  880.     "org": " ar au br cn ec hk il mm mx nz pl ro ru sg tr tw uk za ",
  881.     "pc": " pl ",
  882.     "pe": " ca ",
  883.     "plc": " uk ",
  884.     "ppg": " br ",
  885.     "presse": " fr ",
  886.     "priv": " pl ",
  887.     "pro": " br ",
  888.     "psc": " br ",
  889.     "psi": " br ",
  890.     "qc": " ca com ",
  891.     "qh": " cn ",
  892.     "re": " kr ",
  893.     "realestate": " pl ",
  894.     "rec": " br ro ",
  895.     "rel": " pl ",
  896.     "res": " in ",
  897.     "sa": " com ",
  898.     "sc": " cn ",
  899.     "school": " nz za ",
  900.     "se": " com net ",
  901.     "sh": " cn ",
  902.     "shop": " pl ",
  903.     "sk": " ca ",
  904.     "sklep": " pl ",
  905.     "slg": " br ",
  906.     "sn": " cn ",
  907.     "sos": " pl ",
  908.     "store": " ro ",
  909.     "targi": " pl ",
  910.     "tj": " cn ",
  911.     "tm": " fr mc pl ro za ",
  912.     "tmp": " br ",
  913.     "tourism": " pl ",
  914.     "travel": " pl ",
  915.     "tur": " br ",
  916.     "turystyka": " pl ",
  917.     "tv": " br ",
  918.     "tw": " cn ",
  919.     "uk": " co com net ",
  920.     "us": " com ca ",
  921.     "uy": " com ",
  922.     "vet": " br ",
  923.     "web": " za ",
  924.     "www": " ro ",
  925.     "xj": " cn ",
  926.     "xz": " cn ",
  927.     "yk": " ca ",
  928.     "yn": " cn ",
  929.     "za": " com ",
  930.     "zj": " cn ", 
  931.     "zlg": " br "
  932.   }
  933. ,
  934.   cleanup: function() {
  935.     this.cleanupIfUninstalling();
  936.   }
  937. ,
  938.   cleanupIfUninstalling: function() {
  939.     if(this.uninstalling) this.uninstallJob();
  940.     return this.uninstalling;
  941.   }
  942. ,
  943.   eraseTemp: function() {
  944.     this.jsPolicySites.remove(this.tempSites.sitesList, false, true); // remove temporary
  945.     this.setJSEnabled(this.permanentSites.sitesList,true); // add permanent & save
  946.     this.setPref("temp",""); // flush temporary list
  947.   }
  948. ,
  949.   resetJSCaps: function() {
  950.     try {
  951.       this.caps.clearUserPref("default.javascript.enabled");
  952.     } catch(ex) {}
  953.     try {
  954.       const POLICY_NAME=this.POLICY_NAME;
  955.       var prefArray=SiteUtils.splitString(this.caps.getCharPref("policynames"));
  956.       var pcount=prefArray.length;
  957.       const prefArrayTarget=[];
  958.       for(var pcount=prefArray.length; pcount-->0;) {
  959.         if(prefArray[pcount]!=POLICY_NAME) prefArrayTarget[prefArrayTarget.length]=prefArray[pcount];
  960.       }
  961.       var prefString=prefArrayTarget.join(" ").replace(/\s+/g,' ').replace(/^\s+/,'').replace(/\s+$/,'');
  962.       if(prefString) {
  963.         this.caps.setCharPref("policynames",prefString);
  964.       } else {
  965.         try {
  966.           this.caps.clearUserPref("policynames");
  967.         } catch(ex1) {}
  968.       }
  969.       this.eraseTemp();
  970.       this.savePrefs();
  971.     } catch(ex) {
  972.       // dump(ex);
  973.     }
  974.   }
  975. ,
  976.   uninstallJob: function() {
  977.     this.resetJSCaps();
  978.   }
  979. ,
  980.   getPref: function(name,def) {
  981.     const IPC=Components.interfaces.nsIPrefBranch;
  982.     const prefs=this.prefs;
  983.     try {
  984.       switch(prefs.getPrefType(name)) {
  985.         case IPC.PREF_STRING:
  986.           return prefs.getCharPref(name);
  987.         case IPC.PREF_INT:
  988.           return prefs.getIntPref(name);
  989.         case IPC.PREF_BOOL:
  990.           return prefs.getBoolPref(name);
  991.       }
  992.     } catch(e) {}
  993.     return def;
  994.   }
  995. ,
  996.   setPref: function(name,value) {
  997.     const prefs=this.prefs;
  998.     switch(typeof(value)) {
  999.       case "string":
  1000.           prefs.setCharPref(name,value);
  1001.           break;
  1002.       case "boolean":
  1003.         prefs.setBoolPref(name,value);
  1004.         break;
  1005.       case "number":
  1006.         prefs.setIntPref(name,value);
  1007.         break;
  1008.       default:
  1009.         throw new Error("Unsupported type "+typeof(value)+" for preference "+name);
  1010.     }
  1011.   }
  1012. ,
  1013.   _sound: null,
  1014.   playSound: function(url,force) {
  1015.     if(force || this.getPref("sound",true)) {
  1016.       var sound=this._sound;
  1017.       if(sound==null) {
  1018.         sound=Components.classes["@mozilla.org/sound;1"].createInstance(Components.interfaces.nsISound);
  1019.         sound.init();
  1020.       }
  1021.       try {
  1022.         sound.play(SiteUtils.ios.newURI(url,null,null));
  1023.       } catch(ex) {
  1024.         //dump(ex);
  1025.       }
  1026.     }
  1027.   }
  1028. ,
  1029.   readFile: function(file) {
  1030.     const cc=Components.classes;
  1031.     const ci=Components.interfaces;  
  1032.     const is = cc["@mozilla.org/network/file-input-stream;1"].createInstance(
  1033.           ci.nsIFileInputStream );
  1034.     is.init(file ,0x01, 0400, null);
  1035.     const sis = cc["@mozilla.org/scriptableinputstream;1"].createInstance(
  1036.       ci.nsIScriptableInputStream );
  1037.     sis.init(is);
  1038.     const res=sis.read(sis.available());
  1039.     is.close();
  1040.     return res;
  1041.   }
  1042. ,
  1043.   writeFile: function(file, content) {
  1044.     const cc=Components.classes;
  1045.     const ci=Components.interfaces;
  1046.     const unicodeConverter = cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(
  1047.     ci.nsIScriptableUnicodeConverter);
  1048.     unicodeConverter.charset = "UTF-8";
  1049.     content=unicodeConverter.ConvertFromUnicode(content);
  1050.     const os=cc["@mozilla.org/network/file-output-stream;1"].createInstance(
  1051.       ci.nsIFileOutputStream);
  1052.     os.init(file, 0x02 | 0x08 | 0x20,0664,0);
  1053.     os.write(content,content.length);
  1054.     os.close();
  1055.   }
  1056. ,
  1057.   get prompter() {
  1058.     return Components.classes["@mozilla.org/embedcomp/prompt-service;1"
  1059.           ].getService(Components.interfaces.nsIPromptService);
  1060.   }
  1061. ,
  1062.   queryInterfaceSupport: function(iid,iids) { 
  1063.     xpcom_checkInterfaces(iid, iids, Components.results.NS_ERROR_NO_INTERFACE);
  1064.   }
  1065. ,
  1066.  lookupMethod: Components.utils?Components.utils.lookupMethod:Components.lookupMethod
  1067. ,
  1068.   pluginPlaceholder: "chrome://noscript/skin/icon32.png",
  1069.   showPlaceHolder: true,
  1070.   pluginsExtrasMark: {},
  1071.   getPluginExtras: function(obj) {
  1072.     return (obj._noScriptExtras && obj._noScriptExtras.mark && 
  1073.       this.pluginsExtrasMark == obj._noScriptExtras.mark) ? obj._noScriptExtras : null;
  1074.   },
  1075.   forbidSomePlugins: false,
  1076.   forbidAllPlugins: false,
  1077.   forbidJava: false,
  1078.   forbidFlash: false,
  1079.   forbidPlugins: false, 
  1080.   initContentPolicy: function() {
  1081.     var delegate = (this.forbidSomePlugins && !this.getPref("global",false)) ? 
  1082.         (Components.interfaces.nsIContentPolicy.TYPE_OBJECT 
  1083.           ? this.mainContentPolicy 
  1084.           : this.oldStyleContentPolicy)
  1085.       : this.noopContentPolicy;
  1086.     this.shouldLoad = delegate.shouldLoad;
  1087.     this.shouldProcess = delegate.shouldProcess;
  1088.   },
  1089.   // nsIContentPolicy interface
  1090.   // we use numeric constants for performance sake:
  1091.   // nsIContentPolicy.TYPE_SCRIPT = 2
  1092.   // nsIContentPolicy.TYPE_OBJECT = 5
  1093.   // nsIContentPolicy.TYPE_DOCUMENT = 6
  1094.   // nsIContentPolicy.TYPE_SUBDOCUMENT = 7
  1095.   // nsIContentPolicy.REJECT_SERVER = -3
  1096.   // nsIContentPolicy.ACCEPT = 1
  1097.   noopContentPolicy: {
  1098.     shouldLoad: function() { return 1; },
  1099.     shouldProcess: function() { return 1; }
  1100.   },
  1101.   mainContentPolicy: {
  1102.     shouldLoad: function(aContentType, aContentLocation, aRequestOrigin, aContext, aMimeTypeGuess, aInternalCall) {
  1103.       var forbid, isJS, isFlash, isJava;
  1104.       if(aContentType == 5 || (forbid = isJS = (aContentType == 2))) {
  1105.         const url = aContentLocation.spec;
  1106.         const origin = this.getSite(url);
  1107.         if(!forbid) {
  1108.           var forceAllow;
  1109.           try {
  1110.             forceAllow = this.pluginsCache.update(url, aMimeTypeGuess, origin, aRequestOrigin, aContext);
  1111.           } catch(ex) {
  1112.             dump("NoScriptService.pluginsCache.update():" + ex + "\n");
  1113.           }
  1114.           if((!forceAllow) && this.forbidSomePlugins) {
  1115.             var forbid=this.forbidAllPlugins;
  1116.             if((!forbid) && aMimeTypeGuess) {
  1117.               forbid = 
  1118.                 (isFlash = aMimeTypeGuess == "application/x-shockwave-flash") && this.forbidFlash ||
  1119.                 (isJava = aMimeTypeGuess.indexOf("application/x-java-")==0) && this.forbidJava ||
  1120.                 (this.forbidPlugins && !(isJava || isFlash));
  1121.             }
  1122.           }
  1123.         }
  1124.         
  1125.         if(forbid) {
  1126.           if(!(this.isJSEnabled(origin))) {
  1127.             
  1128.             if(aContext && (!isJS)) {
  1129.               const ci = Components.interfaces;
  1130.               if(aContext instanceof ci.nsIDOMNode) {
  1131.                 
  1132.                 const lm=this.lookupMethod;
  1133.                 
  1134.                 if(this.pluginPlaceholder) {
  1135.                  
  1136.                   if(aContext instanceof(ci.nsIDOMHTMLEmbedElement)) {
  1137.                     var parent = lm(aContext,"parentNode")();
  1138.                     if(parent instanceof ci.nsIDOMHTMLObjectElement) {
  1139.                       aContext = parent;
  1140.                     }
  1141.                   }
  1142.  
  1143.                   if(aMimeTypeGuess && !this.getPluginExtras(aContext)) {
  1144.                     aContext._noScriptExtras = {
  1145.                       mark: this.pluginsExtrasMark,
  1146.                       url: url,
  1147.                       mime: aMimeTypeGuess
  1148.                     };
  1149.                   }
  1150.                 }
  1151.               }
  1152.             }
  1153.             
  1154.             dump("NoScript blocked " + url + " which is a " + aMimeTypeGuess + " from " + origin + "\n");
  1155.             return -3;
  1156.           }
  1157.         }
  1158.       }
  1159.     
  1160.       return 1;
  1161.     },
  1162.     shouldProcess: function(aContentType, aContentLocation, aRequestOrigin, aContext, aMimeType, aExtra) {
  1163.       return this.shouldLoad(aContentType, aContentLocation, aRequestOrigin, aContext, aMimeType, true);
  1164.     }
  1165.   },
  1166.   oldStyleContentPolicy: {
  1167.     shouldLoad: function(aContentType, aContentLocation, aCtx, aWin, aInternalCall) {
  1168.       aContentType++;
  1169.       var mimeType = "";
  1170.       var origin = null;
  1171.       if(aContentType == 5) {
  1172.         var ext, pos;
  1173.         if(aCtx && (aCtx instanceof Components.interfaces.nsIDOMHTMLAppletElement) || 
  1174.             (ext = (ext = aContentLocation.path).substring(ext.lastIndexOf(
  1175.               ".",(pos=ext.indexOf("?"))>0 ? pos : pos=ext.length)+1,pos).toLowerCase() ) == "jnlp" ) {
  1176.           mimeType = "application/x-java-";
  1177.         } else {
  1178.           if(ext == "swf") mimeType = "application/x-shockwave-flash";
  1179.         }
  1180.         if(aCtx && aCtx.ownerDocument) {
  1181.           origin = { spec: aCtx.ownerDocument.documentURI };
  1182.         }
  1183.       }
  1184.       return this.mainContentPolicy
  1185.                  .shouldLoad.call(this, aContentType, aContentLocation, origin, 
  1186.                       aCtx || aWin, mimeType, aInternalCall) == 1;
  1187.     },
  1188.     shouldProcess: function(aContentType, aContentLocation, aCtx, aWin) {
  1189.       return this.shouldLoad(aContentType, aContentLocation, aCtx, aWin, true);
  1190.     }
  1191.   },
  1192.   pluginsCache: {
  1193.     _lastBrowser: null,
  1194.     findBrowser: function(chrome, win) {
  1195.       var gb=chrome.getBrowser();
  1196.       var browsers;
  1197.       if(! (gb && (browsers = gb.browsers))) return null;
  1198.       
  1199.       var browser = gb.selectedBrowser;
  1200.       if(browser.contentWindow == win) return browser;
  1201.       
  1202.       for(var j = browsers.length; j-- > 0;) {
  1203.         browser = browsers[j];
  1204.         if(browser.contentWindow == win) return browser;
  1205.       }
  1206.       
  1207.       return null;
  1208.     },
  1209.     findBrowserForNode: function(ctx) {
  1210.       if(!ctx) return null;
  1211.       const ci = Components.interfaces;
  1212.       const lm = this.lookupMethod;
  1213.       if(!(ctx instanceof ci.nsIDOMWindow)) {
  1214.         if(ctx instanceof ci.nsIDOMDocument) {
  1215.           ctx = lm(ctx,"defaultView")();
  1216.         } else if(ctx instanceof ci.nsIDOMNode) {
  1217.           ctx = lm(lm(ctx,"ownerDocument")(),"defaultView")();
  1218.         } else return; 
  1219.       }
  1220.       if(!ctx) return;
  1221.       ctx = lm(ctx,"top")();
  1222.       var browser = this._lastBrowser;
  1223.       try {
  1224.         if(browser.contentWindow != ctx) browser = null;
  1225.       } catch(ex) {
  1226.         browser = null;
  1227.       }
  1228.       if(!browser) {
  1229.         this._lastBrowser = null;
  1230.         const wm = Components.classes['@mozilla.org/appshell/window-mediator;1']
  1231.                              .getService(Components.interfaces.nsIWindowMediator);
  1232.         const chrome = wm.getMostRecentWindow("navigator:browser");
  1233.         
  1234.         if(! (browser = this.findBrowser(chrome, ctx))) {
  1235.           const ww = wm.getEnumerator("navigator:browser");
  1236.           for(var w; ww.hasMoreElements();) {
  1237.             w=ww.getNext();
  1238.             if(w != chrome && (browser = this.findBrowser(w, ctx))) {
  1239.               break;
  1240.             }
  1241.           }
  1242.         }
  1243.         this._lastBrowser = browser;
  1244.       }
  1245.       return browser;
  1246.     },
  1247.     lookupMethod: Components.utils?Components.utils.lookupMethod:Components.lookupMethod,
  1248.     update: function(url, mime, origin, docURI, ctx) { // returns forceAllow
  1249.       var browser = this.findBrowserForNode(ctx);
  1250.       if(browser) {
  1251.         var cache = this.get(browser);
  1252.         var uriCache = cache.uris;
  1253.         var uriSpec = docURI.spec;
  1254.         var origCache = uriCache[uriSpec] || (uriCache[uriSpec] = {});
  1255.         origCache[origin] = true;
  1256.         var forceMime = cache.forceAllow[url];
  1257.         return forceMime && forceMime == mime;
  1258.       }
  1259.       return false;
  1260.     },
  1261.     purge: function(cache, uris) {
  1262.       var uriCache = cache.uris;
  1263.       for(u in uriCache) {
  1264.         if(!uris[u]) delete uriCache[u];
  1265.       }
  1266.     },
  1267.     get: function(browser) {
  1268.       return browser.noScriptPluginsCache || 
  1269.       (browser.noScriptPluginsCache = { uris: {}, forceAllow: {} });
  1270.     }
  1271.   }
  1272. };
  1273.  
  1274.  
  1275.  
  1276. // XPCOM Scaffolding code
  1277.  
  1278. // component defined in this file
  1279. const EXTENSION_ID="{73a6fe31-595d-460b-a920-fcc0f8843232}";
  1280. const SERVICE_NAME="NoScript Service";
  1281. const SERVICE_ID="{31aec909-8e86-4397-9380-63a59e0c5ff5}";
  1282. const SERVICE_CTRID = "@maone.net/noscript-service;1";
  1283. const SERVICE_CONSTRUCTOR=NoscriptService;
  1284.  
  1285. const SERVICE_CID = Components.ID(SERVICE_ID);
  1286.  
  1287. // interfaces implemented by this component
  1288. const SERVICE_IIDS = 
  1289. Components.interfaces.nsIObserver,
  1290. Components.interfaces.nsISupports,
  1291. Components.interfaces.nsISupportsWeakReference,
  1292. Components.interfaces.nsIContentPolicy
  1293. ];
  1294.  
  1295. // categories which this component is registered in
  1296. const SERVICE_CATS = ["app-startup","content-policy"];
  1297.  
  1298.  
  1299. // Factory object
  1300. const SERVICE_FACTORY = {
  1301.   _instance: null,
  1302.   createInstance: function (outer, iid) {
  1303.     if (outer != null)
  1304.         throw Components.results.NS_ERROR_NO_AGGREGATION;
  1305.  
  1306.     xpcom_checkInterfaces(iid,SERVICE_IIDS,Components.results.NS_ERROR_INVALID_ARG);
  1307.     // kept this for flexibility sake, but we're really adopting an
  1308.     // early instantiation and late init singleton pattern
  1309.     return this._instance==null?this._instance=new SERVICE_CONSTRUCTOR():this._instance;
  1310.   }
  1311. };
  1312.  
  1313. function xpcom_checkInterfaces(iid,iids,ex) {
  1314.   for(var j=iids.length; j-- >0;) {
  1315.     if(iid.equals(iids[j])) return true;
  1316.   }
  1317.   throw ex;
  1318. }
  1319.  
  1320. // Module
  1321.  
  1322. var Module = new Object();
  1323. Module.firstTime=true;
  1324. Module.registerSelf = function (compMgr, fileSpec, location, type) {
  1325.   if(this.firstTime) {
  1326.    
  1327.     debug("*** Registering "+SERVICE_CTRID+".\n");
  1328.     
  1329.     compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar
  1330.       ).registerFactoryLocation(SERVICE_CID,
  1331.       SERVICE_NAME,
  1332.       SERVICE_CTRID, 
  1333.       fileSpec,
  1334.       location, 
  1335.       type);
  1336.     const catman = Components.classes['@mozilla.org/categorymanager;1'
  1337.       ].getService(Components.interfaces.nsICategoryManager);
  1338.     for(var j=0, len=SERVICE_CATS.length; j<len; j++) {
  1339.       catman.addCategoryEntry(SERVICE_CATS[j],
  1340.         //SERVICE_NAME, "service," + SERVICE_CTRID, 
  1341.         SERVICE_CTRID, SERVICE_CTRID, true, true, null);
  1342.     }
  1343.     this.firstTime=false;
  1344.   } 
  1345. }
  1346. Module.unregisterSelf = function(compMgr, fileSpec, location) {
  1347.   compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar
  1348.     ).unregisterFactoryLocation(SERVICE_CID, fileSpec);
  1349.   const catman = Components.classes['@mozilla.org/categorymanager;1'
  1350.       ].getService(Components.interfaces.nsICategoryManager);
  1351.   for(var j=0, len=SERVICE_CATS.length; j<len; j++) {
  1352.     catman.deleteCategoryEntry(SERVICE_CATS[j], SERVICE_CTRID, true);
  1353.   }
  1354. }
  1355.  
  1356. Module.getClassObject = function (compMgr, cid, iid) {
  1357.   if(cid.equals(SERVICE_CID))
  1358.     return SERVICE_FACTORY;
  1359.  
  1360.   if (!iid.equals(Components.interfaces.nsIFactory))
  1361.     throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  1362.   
  1363.   throw Components.results.NS_ERROR_NO_INTERFACE;
  1364.     
  1365. }
  1366.  
  1367. Module.canUnload = function(compMgr) {
  1368.   return true;
  1369. }
  1370.  
  1371. // entrypoint
  1372. function NSGetModule(compMgr, fileSpec) {
  1373.   return Module;
  1374. }
  1375.  
  1376.  
  1377.