includes/scriptdb.js
author Dave Townsend <dtownsend@oxymoronical.com>
Fri Jul 09 12:41:11 2010 -0700 (19 months ago)
changeset 0 f8b0b8c6f940
child 2 5fd42918d6f5
permissions -rw-r--r--
Initial import of demo extension
     1 const DB_SCHEMA = 1;
     2 const ID_SUFFIX = "@slipperymonkey.fractalbrew.com";
     3 
     4 var TAGMATCH = /^.*@(\S+)\s*(.*)/
     5 
     6 var ScriptDatabase = {
     7   db: null,
     8 
     9   startup: function() {
    10     var dbfile = Services.dirsvc.get("ProfD", Ci.nsIFile);
    11     dbfile.append("slippery.sqlite");
    12     this.db = Services.storage.openUnsharedDatabase(dbfile);
    13     if (this.db.schemaVersion < DB_SCHEMA)
    14       this.initDatabase();
    15   },
    16 
    17   initDatabase: function() {
    18     this.db.createTable("script",
    19                         "id INTEGER PRIMARY KEY AUTOINCREMENT," +
    20                         "name TEXT," +
    21                         "version TEXT," +
    22                         "author TEXT," +
    23                         "description TEXT," +
    24                         "uri TEXT," +
    25                         "enabled INTEGER," +
    26                         "script TEXT");
    27     this.db.createTable("include",
    28                         "script_id INTEGER," +
    29                         "address TEXT");
    30 
    31     this.db.executeSimpleSQL("CREATE TRIGGER delete_script AFTER DELETE ON script BEGIN " +
    32         "DELETE FROM include WHERE script_id=old.id; " +
    33       "END");
    34     this.db.schemaVersion = DB_SCHEMA;
    35   },
    36 
    37   getScript: function(aId) {
    38     if (aId.substring(aId.length - ID_SUFFIX.length) != ID_SUFFIX)
    39       return null;
    40 
    41     var stmt = this.db.createStatement("SELECT id, name, version, author, description, uri, enabled, script FROM script WHERE id=:id");
    42     stmt.params.id = aId.substring(0, aId.length - ID_SUFFIX.length);
    43     if (stmt.executeStep())
    44       return new Script(stmt.row);
    45     return null;
    46   },
    47 
    48   getAllScripts: function() {
    49     var scripts = [];
    50 
    51     var stmt = this.db.createStatement("SELECT id, name, version, author, description, uri, enabled, script FROM script");
    52     while (stmt.executeStep())
    53       scripts.push(new Script(stmt.row));
    54     return scripts;
    55   },
    56 
    57   getScriptsForURI: function(aURI) {
    58     var scripts = [];
    59 
    60     var stmt = this.db.createStatement("SELECT DISTINCT id, name, version, author, description, uri, enabled, script FROM script JOIN include ON script.id=include.script_id WHERE :uri GLOB address AND enabled=1");
    61     stmt.params.uri = aURI.spec;
    62     while (stmt.executeStep())
    63       scripts.push(new Script(stmt.row));
    64     return scripts;
    65   },
    66 
    67   hasScript: function(aURI) {
    68     var stmt = this.db.createStatement("SELECT COUNT() AS count FROM script WHERE uri=:uri");
    69     stmt.params.uri = aURI.spec;
    70 
    71     if (stmt.executeStep())
    72       return stmt.row.count > 0;
    73     return false;
    74   },
    75 
    76   installScript: function(aScript, aURI) {
    77     try {
    78       var data = {
    79         name: "",
    80         author: "",
    81         description: "",
    82         uri: aURI.spec,
    83         enabled: 1,
    84         script: aScript
    85       };
    86       var includes = [];
    87       var stmt = this.db.createStatement("INSERT INTO script VALUES (NULL, :name, :version, :author, :description, :uri, :enabled, :script)");
    88       stmt.params.uri = aURI.spec;
    89       stmt.params.enabled = 1;
    90       stmt.params.script = aScript;
    91 
    92       var start = aScript.indexOf("==UserScript==");
    93       var end = aScript.indexOf("==/UserScript==");
    94       if (start < 0 || end < 0)
    95         return;
    96 
    97       LOG("Looking for tags in " + aScript.substring(start, end));
    98       var lines = aScript.substring(start, end).split("\n");
    99       var pos = 0;
   100       while (pos < lines.length) {
   101         var matches = TAGMATCH.exec(lines[pos]);
   102         if (matches) {
   103           LOG("Tag: " + matches[1] + " = " + matches[2]);
   104           switch (matches[1]) {
   105           case "name":
   106           case "description":
   107           case "author":
   108           case "version":
   109             stmt.params[matches[1]] = matches[2];
   110             data[matches[1]] = matches[2];
   111             break;
   112           case "include":
   113             includes.push(matches[2]);
   114             break;
   115           }
   116         }
   117         pos++;
   118       }
   119 
   120       stmt.execute();
   121       var id = this.db.lastInsertRowID;
   122 
   123       stmt = this.db.createStatement("INSERT INTO include VALUES (:id, :address)");
   124       includes.forEach(function(aInclude) {
   125         stmt.params.id = id;
   126         stmt.params.address = aInclude;
   127         stmt.execute();
   128       });
   129 
   130       AddonManagerPrivate.callInstallListeners("onNewInstall", null,
   131                                                 new Script(data), null, false);
   132     }
   133     catch (e) {
   134       LOGE("Exception installing script", e);
   135     }
   136   },
   137 
   138   uninstallScript: function(aScript) {
   139     AddonManagerPrivate.callAddonListeners("onUninstalling", aScript, false);
   140     var stmt = this.db.createStatement("DELETE FROM script WHERE id=:id");
   141     stmt.params.id = aScript._id;
   142     stmt.execute();
   143     AddonManagerPrivate.callAddonListeners("onUninstalled", aScript);
   144   },
   145 
   146   updateDisabledState: function(aScript) {
   147     var stmt = this.db.createStatement("UPDATE script SET enabled=:enabled WHERE id=:id");
   148     stmt.params.id = aScript._id;
   149     stmt.params.enabled = aScript.enabled;
   150     stmt.execute();
   151   },
   152 
   153   shutdown: function() {
   154     this.db.asyncClose();
   155   }
   156 };
   157 
   158 function Script(aData) {
   159   this.id = aData.id + ID_SUFFIX;
   160   this._id = aData.id;
   161   this.name = aData.name;
   162   this.version = aData.version;
   163   this.creator = aData.author;
   164   this.description = aData.description;
   165   this.homepageURL = aData.uri;
   166   this.enabled = aData.enabled;
   167   this.script = aData.script;
   168 }
   169 
   170 Script.prototype = {
   171   _id: null,
   172   version: null,
   173   type: "user-script",
   174 
   175   isCompatible: true,
   176   providesUpdatesSecurely: true,
   177   blocklistState: 0,
   178   appDisabled: false,
   179   scope: AddonManager.SCOPE_PROFILE,
   180   isActive: true,
   181   pendingOperations: 0,
   182 
   183   name: null,
   184   version: null,
   185   description: null,
   186   creator: null,
   187   homepageURL: null,
   188 
   189   script: null,
   190 
   191   get userDisabled() {
   192     return this.enabled != 1;
   193   },
   194 
   195   set userDisabled(val) {
   196     if (val == this.userDisabled)
   197       return val;
   198 
   199     AddonManagerPrivate.callAddonListeners(val ? "onEnabling" : "onDisabling",
   200                                            this, false);
   201     this.enabled = val ? 0 : 1;
   202     ScriptDatabase.updateDisabledState(this);
   203     AddonManagerPrivate.callAddonListeners(val ? "onEnabled" : "onDisabled",
   204                                            this);
   205   },
   206 
   207   get permissions() {
   208     var perms = AddonManager.PERM_CAN_UNINSTALL;
   209     perms |= this.userDisabled ? AddonManager.PERM_CAN_ENABLE : AddonManager.PERM_CAN_DISABLE;
   210     return perms;
   211   },
   212 
   213   isCompatibleWith: function() {
   214     return true;
   215   },
   216 
   217   findUpdates: function(aListener) {
   218     if ("onNoCompatibilityUpdateAvailable" in aListener)
   219       aListener.onNoCompatibilityUpdateAvailable(this);
   220     if ("onNoUpdateAvailable" in aListener)
   221       aListener.onNoUpdateAvailable(this);
   222     if ("onUpdateFinished" in aListener)
   223       aListener.onUpdateFinished(this);
   224   },
   225 
   226   uninstall: function() {
   227     ScriptDatabase.uninstallScript(this);
   228   }
   229 };
   230 
   231 ScriptDatabase.startup();