Search code examples
firefox-addonfirefox-addon-sdkxpcom

Intercept/handle mime type/file


How do you disable the default action for .torrent files/content-type application/x-bittorrent(eg open with dialog or run program) and instead handle the data in a extension?


Solution

  • Based on @nmaiers post this is how you do it:

    This is how you do it IF the mime type already exists. If it doesn't exist I don't know how to add it, probably some register function.

    For some reason the type for my torrents is application/x-download I have no idea why. If you want info on how I figured that out than I'll tell you. So in the example below I use that as file type.

    When we console.log(wrappedHandlerInfo) we see that it looks like this: variable viewer on wrappedHandlerInfo

    so now let's do that enumerate all application handlers (i got this from here: MXR :: gApplicationsPane, and if .type == 'application/x-download' let'sbreak` so we can than play with that object.

    var handlerService = Cc['@mozilla.org/uriloader/handler-service;1'].getService(Ci.nsIHandlerService);
    
    var listOfWrappedHandlers = handlerService.enumerate();
    var i = 0;
    while (listOfWrappedHandlers.hasMoreElements()) {
      var wrappedHandlerInfo = listOfWrappedHandlers.getNext().QueryInterface(Ci.nsIHandlerInfo);
      console.log(i, 'handler for', wrappedHandlerInfo.type, wrappedHandlerInfo);
      if (wrappedHandlerInfo.type == 'application/x-download') {
        break;
      }
      i++;
    }
    console.log('Listed ', i, ' handlers');
    console.log('wrappedHandlerInfo=', wrappedHandlerInfo); //should be the application/x-download one as we broke the loop once it found that
    

    now we have to set its properties then save it.

    // Change and save mime handler settings.
    wrappedHandlerInfo.alwaysAskBeforeHandling = false;
    wrappedHandlerInfo.preferredAction = Ci.nsIHandlerInfo.handleInternally;
    handlerService.store(wrappedHandlerInfo);
    

    I'm not sure what to change those properties too though, maybe @nmaier can advise us on that.

    We see here on MXR :: nsIHandlerService.idl #L69 that store does this:

    69    * Save the preferred action, preferred handler, possible handlers, and
    70    * always ask properties of the given handler info object to the datastore.
    71    * Updates an existing record or creates a new one if necessary.
    72    *
    73    * Note: if preferred action is undefined or invalid, then we assume
    74    * the default value nsIHandlerInfo::useHelperApp.
    75    *
    76    * @param aHandlerInfo  the handler info object
    77    */
    78   void store(in nsIHandlerInfo aHandlerInfo);
    

    ANOTHER WAY

    Ok i found an even better way, this way you don't need to loop to find the handler.

    Do this:

    var mimeService = Cc['@mozilla.org/mime;1'].getService(Ci.nsIMIMEService);
    var CONTENT_TYPE = ''; //'application/x-download'; can leave this blank
    var TYPE_EXTENSION = 'torrent';
    
    var handlerInfo = mimeService.getFromTypeAndExtension(CONTENT_TYPE, TYPE_EXTENSION);
    console.info('handlerInfo:', handlerInfo); //http://i.imgur.com/dUKox24.png
    
        // Change and save mime handler settings.
        handlerInfo.alwaysAskBeforeHandling = false;
        handlerInfo.preferredAction = Ci.nsIHandlerInfo.handleInternally;
        handlerService.store(handlerInfo);
    

    This handlerInfo object is slightly different in that it has a primaryExtension attribute which holds torrent.

    using nsiMIMService to get the handlerinfo object


    Problem with both ways

    The problem with both ways is that, if the mime type doesn't exist, you have to register it somehow, I don't know how. Probably use mime service and some register function.

    Update August 3rd 2014

    I think i found a solution for the problem mentioned in bullet above (problem with both ways).

    MXR :: addPossibleApplicationHandler

    235   addPossibleApplicationHandler: function(aNewHandler) {
    236     var possibleApps = this.possibleApplicationHandlers.enumerate();
    237     while (possibleApps.hasMoreElements()) {
    238       if (possibleApps.getNext().equals(aNewHandler))
    239         return;
    240     }
    241     this.possibleApplicationHandlers.appendElement(aNewHandler, false);
    242   },
    243 
    

    This is code for addPossibleApplicationHandler, we probably just need to copy that and edit somehow.

    Update August 3rd 2014

    Ok this is how to add protocol handler (it only adds a nsIWebAppHandler but im sure to add a local meaning a nsIAppHandler it should be similar just no need for uri param:

    https://gist.github.com/Noitidart/2faaac70c62bc13e7773#add-a-handler-to-a-protocol


    Info on functions available in nsIMIMEService: MXR :: nsIMIMEService.idl