sbCommandLine.js
Go to the documentation of this file.
1 
32 const Cc = Components.classes;
33 const Ci = Components.interfaces;
34 const Cr = Components.results;
35 const Cu = Components.utils;
36 
37 const SONGBIRD_CLH_CONTRACTID = "@songbirdnest.com/commandlinehandler/general-startup;1?type=songbird";
38 const SONGBIRD_CLH_CID = Components.ID("{128badd1-aa05-4508-87cc-f3cb3e9b5499}");
39 const SONGBIRD_CLH_CLASSNAME = "Songbird Command Line Handler";
40 // "m" for ordinary priority see sbICommandLineHandler.idl
41 const SONGBIRD_CLH_CATEGORY= "m-songbird-clh";
42 
43 // Command Line Startup Topic that's used to notify that the application
44 // has parsed the command line. This enables the Application Startup Service
45 // to initialize the application after we've parsed out the command line.
46 const COMMAND_LINE_TOPIC = "sb-command-line-startup";
47 
48 function _debugPrint(msg) {
49  if (/@ 0x/(__LOCATION__)) {
50  dump(msg + "\n");
51  }
52 }
53 
54 function resolveURIInternal(aCmdLine, aArgument) {
55  var uri = aCmdLine.resolveURI(aArgument);
56 
57  if (!(uri instanceof Components.interfaces.nsIFileURL)) {
58  return uri;
59  }
60 
61  return checkUri(uri, aArgument);
62 }
63 
64 function checkUri(aURI, aURL) {
65  try {
66  if (aURI instanceof Components.interfaces.nsIFileURL)
67  if (aURI.file.exists())
68  return aURI;
69  }
70  catch (e) {
71  Cu.reportError(e);
72  }
73 
74  // We have interpreted the argument as a relative file URI, but the file
75  // doesn't exist. Try URI fixup heuristics: see bug 290782.
76 
77  try {
78  var urifixup = Components.classes["@mozilla.org/docshell/urifixup;1"]
79  .getService(Ci.nsIURIFixup);
80 
81  aURI = urifixup.createFixupURI(aURL, 0);
82  }
83  catch (e) {
84  Cu.reportError(e);
85  }
86 
87  return aURI;
88 }
89 
90 function shouldLoadURI(aURI) {
91  if (!aURI || aURI == "") return false;
92  if (aURI && !aURI.schemeIs("chrome"))
93  return true;
94 
95  dump("*** Preventing external load of chrome URI into browser window (" + aURI.spec + ")\n");
96  dump(" Use -chrome <uri> instead\n");
97  return false;
98 }
99 
104  this.itemHandlers = []; // array of handlers
105  this.itemUriSpecs = []; // array of uri specs
106  this.flagHandlers = []; // array of arrays (handler, flag)
107  this.flags = []; // array of arrays (flag, param)
108 
109  this.gMM = Cc["@songbirdnest.com/Songbird/Mediacore/Manager;1"].getService(Ci.sbIMediacoreManager);
110  this.controller = Cc['@songbirdnest.com/Songbird/ApplicationController;1'].getService(Ci.sbIApplicationController);
111 }
112 
113 sbCommandLineHandler.prototype = {
114  // there are specific formatting guidelines for help test, see nsICommandLineHandler
115  helpInfo : " -test [tests] Run tests on the components listed in the\n" +
116  " optional comma-separated list of tests.\n" +
117  " If no tests are passed in ALL tests will be run.\n" +
118  " [url|path] Local path/filename to media items to import and\n" +
119  " play, or URL to load in the browser.\n" +
120  " -register-extensions Registers extensions and then quits.\n" +
121  " -play Start/Resume playback at the current position.\n" +
122  " -stop Stop playback.\n" +
123  " -pause Pause playback.\n" +
124  " -toggle-playback Starts playback, if there is none and pauses it\n" +
125  " if media is currently playing.\n" +
126  " -next Skips to the next item in the sequence.\n" +
127  " -previous Goes back to the previous item in the sequence.\n" +
128  " -mute Mute the volume if it's not yet, else unmute it.\n" +
129  " -volumeup Raise the volume by 10%.\n" +
130  " -volumedown Lower the volume by 10%.\n",
131  itemHandlers: null,
132  itemUriSpecs: null,
133  flagHandlers: null,
134  flags: null,
135  gMM: null,
136  controller: null,
137 
138  handle : function (cmdLine) {
139 
140  var urilist = [];
141  var oldlength = this.itemUriSpecs.length;
142 
143  if (cmdLine.handleFlag("register-extensions", false)) {
144  _debugPrint("aborting due to handle of register-extensions");
145  throw Cr.NS_ERROR_ABORT;
146  }
147 
148  // Player control
149  if(cmdLine.handleFlag("play", false)) {
150  if(this.gMM.playbackControl)
151  this.gMM.playbackControl.play();
152  else
153  this.controller.playDefault();
154  cmdLine.preventDefault = true;
155  }
156  if(cmdLine.handleFlag("stop", false)) {
157  if(this.gMM.playbackControl)
158  this.gMM.playbackControl.stop();
159  cmdLine.preventDefault = true;
160  }
161  if(cmdLine.handleFlag("pause", false)) {
162  if(this.gMM.playbackControl)
163  this.gMM.playbackControl.pause();
164  cmdLine.preventDefault = true;
165  }
166  if(cmdLine.handleFlag("toggle-playback", false)) {
167  if(this.gMM.status.state == this.gMM.status.STATUS_PAUSED)
168  this.gMM.playbackControl.play();
169  if(this.gMM.status.state != this.gMM.status.STATUS_PLAYING)
170  this.controller.playDefault();
171  else
172  this.gMM.playbackControl.pause();
173  cmdLine.preventDefault = true;
174  }
175  if(cmdLine.handleFlag("next", false)) {
176  if(this.gMM.playbackControl)
177  this.gMM.playbackControl.next();
178  cmdLine.preventDefault = true;
179  }
180  if(cmdLine.handleFlag("previous", false)) {
181  if(this.gMM.playbackControl)
182  this.gMM.playbackControl.previous();
183  cmdLine.preventDefault = true;
184  }
185  if(cmdLine.handleFlag("mute", false)) {
186  this.gMM.volumeControl.mute = !this.gMM.volumeControl.mute;
187  cmdLine.preventDefault = true;
188  }
189  if(cmdLine.handleFlag("volumeup", false)) {
190  this.gMM.volumeControl.volume += 0.1;
191  cmdLine.preventDefault = true;
192  }
193  if(cmdLine.handleFlag("volumedown", false)) {
194  this.gMM.volumeControl.volume -= 0.1;
195  cmdLine.preventDefault = true;
196  }
197 
198  try {
199  var ar;
200  while ((ar = cmdLine.handleFlagWithParam("url", false))) {
201  urilist.push(resolveURIInternal(cmdLine, ar));
202  }
203  }
204  catch (e) {
205  Cu.reportError(e);
206  }
207 
208  // Notify observers of COMMAND_LINE_TOPIC that the command line
209  // has been parsed and the application is ready to be started up.
210  var observerService = Cc["@mozilla.org/observer-service;1"]
211  .getService(Ci.nsIObserverService);
212  try {
213  observerService.notifyObservers (cmdLine, COMMAND_LINE_TOPIC, null);
214  }
215  catch (e) {
216  Cu.reportError(e);
217  }
218 
219  var tests = null;
220  var emptyParam = false;
221  try {
222  tests = cmdLine.handleFlagWithParam("test", false);
223  }
224  catch (e) {
225  // cmdLine throws if there is no param for the flag, but we want the
226  // parameter to be optional, so catch the exception and let ourselves
227  // know that things are okay. The flag existed without a param.
228  emptyParam = true;
229  }
230 
231  // if there was a parameter or if we had a flag and no param
232  if (tests != null || emptyParam) {
233  // we're running tests, make sure we don't open a window
234  cmdLine.preventDefault = true;
235  var testHarness = Cc["@songbirdnest.com/Songbird/TestHarness;1"].getService(Ci.sbITestHarness);
236 
237  var exception;
238  try {
239  testHarness.init(tests);
240  testHarness.run();
241  }
242  catch (e) {
243  exception = e;
244  }
245 
246 
247  var platformStr = Cc["@mozilla.org/system-info;1"]
248  .getService(Ci.nsIPropertyBag2).getProperty("name");
249 
250  // If we are on Mac, unfortunately the event-queue slows down to slug
251  // speed when there isn't a window open and we are shutting down. Since
252  // there isn't a window being used on these unit tests - the hybrid
253  // Cocoa/Gecko event loop takes a long time (over 20 minutes) to kill the
254  // 100 or so threads that get spooled up during the test cases.
255 
256  // Unfortunately, this also happens on Windows :(
257 
258  // To fix this problem, we will use a nasty little hack. Open up the a
259  // plain window that closes itself after a couple of seconds. This fires
260  // the application shutdown procedure just as if we had closed the main
261  // Songbird window.
262  //
263  // Yes - I know this sucks, I hate myself a little more for doing this.
264  if (platformStr == "Darwin" ||
265  platformStr == "Windows_NT") {
266  var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"]
267  .getService(Ci.nsIWindowWatcher);
268 
269  ww.openWindow(null,
270  "chrome://songbird/content/xul/unitTestShutdownWin.xul",
271  "shutdownwin", "chrome", null);
272  }
273  else {
274  // Linux can follow this 'standard' shutdown procedure:
275  //
276  // Fake the sequence of observer notifications for app shutdown. This
277  // sequence should match that of canQuitApplication (from
278  // globalOverlay.js) and nsAppStartup::Quit (from nsAppStartup.cpp).
279  var os = Cc["@mozilla.org/observer-service;1"].
280  getService(Ci.nsIObserverService);
281 
282  // We don't care if anyone tries to cancel quit...
283  var dummyCancelQuit = Cc["@mozilla.org/supports-PRBool;1"].
284  createInstance(Ci.nsISupportsPRBool);
285  os.notifyObservers(dummyCancelQuit, "quit-application-requested", null);
286 
287  os.notifyObservers(null, "quit-application-granted", null);
288 
289  var appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
290  .getService(Ci.nsIAppStartup);
291  appStartup.quit(Ci.nsIAppStartup.eAttemptQuit);
292  }
293 
294  if (exception) {
295  throw Cr.NS_ERROR_ABORT;
296  }
297  }
298 
299  // XXX bug 2186
300  var count = cmdLine.length;
301  for (var i = 0; i < count; ++i) {
302  // getArgument sometimes causes an exception for the last parameter,
303  // even tho i is always below cmdLine.length ! This doesn't seem to
304  // ever happen when the commandline is starting the app, but seems to
305  // always do when the app is already started, and the commandline is
306  // received from another instance.
307  try {
308  var curarg = cmdLine.getArgument(i);
309  } catch (e) {
310  Components.utils.reportError(e);
311  // try next argument. there shouldn't be any, but just in case...
312  continue
313  }
314 
315  if (curarg == "") continue;
316  if (curarg.match(/^-/)) {
317  // Components.utils.reportError("Warning: unrecognized command line flag " + curarg + "\n");
318  // To emulate the pre-nsICommandLine behavior, we ignore
319  // the argument after an unrecognized flag.
320  ++i;
321  } else {
322  try {
323  cmdLine.removeArguments(i, i);
324  urilist.push(resolveURIInternal(cmdLine, curarg));
325  }
326  catch (e) {
327  Components.utils.reportError("Error opening URI '" + curarg + "' from the command line: " + e + "\n");
328  }
329  }
330  }
331 
332  for (var uri in urilist) {
333  if (shouldLoadURI(urilist[uri])) {
334  this.itemUriSpecs.push(urilist[uri].spec);
335  }
336  }
337 
338  if (this.itemUriSpecs.length > oldlength)
339  this.dispatchItems();
340 
341  this.handleRemainingFlags(cmdLine);
342  this.dispatchFlags();
343  },
344 
345  handleURL: function(aURL) {
346  var ioService = Components.classes["@mozilla.org/network/io-service;1"]
347  .getService(Components.interfaces.nsIIOService);
348  var uri = ioService.newURI(aURL, null, null);
349  uri = checkUri(uri, aURL);
350  if (shouldLoadURI(uri)) {
351  this.itemUriSpecs.push(uri.spec);
352  this.dispatchItems();
353  }
354  },
355 
356  handleRemainingFlags: function(cmdLine) {
357  while (cmdLine.length) {
358  var curarg = cmdLine.getArgument(0);
359  if (curarg.match(/^-/)) {
360  var flag = curarg.slice(1);
361 
362  var param;
363 
364  var emptyParam = false;
365  try {
366  param = cmdLine.handleFlagWithParam(flag, false);
367  }
368  catch (e) {
369  // cmdLine throws if there is no param for the flag, but we want the
370  // parameter to be optional, so catch the exception and let ourselves
371  // know that things are okay. The flag existed without a param.
372  emptyParam = true;
373  cmdLine.handleFlag(flag, false);
374  }
375 
376  // if there was a parameter or if we had a flag and no param
377  if (param != null || emptyParam) {
378  // record the flag for handling by flag handlers
379  this.flags.push([flag, param]);
380  }
381  } else {
382  // this should really not occur, because the case should have
383  // been handled as a play item earlier. however, if for some reason
384  // it does occur, not doing the following would cause an infinite loop,
385  // so do it just in case.
386  cmdLine.removeArguments(0, 0);
387  }
388  }
389  },
390 
391  addItemHandler: function (aHandler) {
392  this.itemHandlers.push(aHandler);
393  // dispatch unhandled items immediatly to this handler
394  this.dispatchItemsToHandler(aHandler);
395  },
396 
397  removeItemHandler: function(aHandler) {
398  var index = this.itemHandlers.indexOf(aHandler);
399  if (index != -1) this.itemHandlers.splice(index, 1);
400  },
401 
402  dispatchItemsToHandler: function(aHandler) {
403  var count = 0;
404  var total = this.itemUriSpecs.length;
405  for (var i=0; i < this.itemUriSpecs.length; i++) {
406  if (aHandler.handleItem(this.itemUriSpecs[i], count++, total)) {
407  this.itemUriSpecs.splice(i--, 1);
408  }
409  }
410  },
411 
412  dispatchItems: function() {
413  // The last handler to get registered gets
414  // priority over the first ones, so that if
415  // there are several instances of the main window,
416  // the items open in the one created last.
417  for (var handleridx = this.itemHandlers.length-1; handleridx >= 0; handleridx--) {
418  this.dispatchItemsToHandler(this.itemHandlers[handleridx]);
419  if (this.itemUriSpecs.length == 0) break;
420  }
421  },
422 
423  addFlagHandler: function (aHandler, aFlag) {
424  var entry = [aHandler, aFlag];
425  this.flagHandlers.push(entry);
426  // dispatch unhandled flags immediatly to this handler
427  this.dispatchFlagsToHandler(entry);
428  },
429 
430  removeFlagHandler: function(aHandler, aFlag) {
431  this.flagHandlers = this.flagHandlers.filter(function(entry) {
432  return !(entry[0] == aHandler && entry[1] == aFlag);
433  });
434  },
435 
436  dispatchFlagsToHandler: function(aHandlerEntry) {
437  var handler = aHandlerEntry[0];
438  var flag = aHandlerEntry[1];
439  for (var i=0; i < this.flags.length; i++) {
440  if (this.flags[i][0] == flag) {
441  if (handler.handleFlag(this.flags[i][0], this.flags[i][1])) {
442  this.flags.splice(i--, 1);
443  }
444  }
445  }
446  },
447 
448  dispatchFlags: function() {
449  // The last handler to get registered gets
450  // priority over the first ones, so that if
451  // there are several instances of the main window,
452  // the flags are handled by the one created last.
453  for (var handleridx = this.flagHandlers.length-1; handleridx >= 0; handleridx--) {
454  this.dispatchFlagsToHandler(this.flagHandlers[handleridx]);
455  if (this.flags.length == 0) break;
456  }
457  },
458 
459  QueryInterface : function clh_QI(iid) {
460  if (iid.equals(Ci.nsICommandLineHandler) ||
461  iid.equals(Ci.sbICommandLineManager) ||
462  iid.equals(Ci.nsISupports))
463  return this;
464 
465  throw Cr.NS_ERROR_NO_INTERFACE;
466  }
467 }; // sbCommandeLineHandler
468 
473  registerSelf : function (compMgr, fileSpec, location, type) {
474  compMgr.QueryInterface(Ci.nsIComponentRegistrar);
475  compMgr.registerFactoryLocation(SONGBIRD_CLH_CID,
478  fileSpec,
479  location,
480  type);
481 
482  var catMan = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
483  catMan.addCategoryEntry("command-line-handler",
486  true,
487  true);
488  },
489 
490  getClassObject : function (compMgr, cid, iid) {
491  if (!cid.equals(SONGBIRD_CLH_CID))
492  throw Cr.NS_ERROR_NO_INTERFACE;
493 
494  if (!iid.equals(Ci.nsIFactory))
495  throw Cr.NS_ERROR_NOT_IMPLEMENTED;
496 
497  return this.mFactory;
498  },
499 
500  mFactory : {
501  createInstance : function (outer, iid) {
502  if (outer != null)
503  throw Cr.NS_ERROR_NO_AGGREGATION;
504  return (new sbCommandLineHandler()).QueryInterface(iid);
505  }
506  },
507 
508  unregisterSelf : function (compMgr, location, type) {
509  compMgr.QueryInterface(Ci.nsIComponentRegistrar);
510  compMgr.unregisterFactoryLocation(SONGBIRD_CLH_CID, location);
511 
512  var catMan = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
513  catMan.deleteCategoryEntry("command-line-handler", SONGBIRD_CLH_CATEGORY);
514  },
515 
516  canUnload : function (compMgr) {
517  return true;
518  },
519 
520  QueryInterface : function (iid) {
521  if ( !iid.equals(Ci.nsIModule) ||
522  !iid.equals(Ci.nsISupports) )
523  throw Cr.NS_ERROR_NO_INTERFACE;
524  return this;
525  }
526 
527 }; // sbCommandLineHandlerModule
528 
529 function NSGetModule(comMgr, fileSpec)
530 {
532 }
classDescription entry
Definition: FeedWriter.js:1427
var total
function sbCommandLineHandler()
var gMM
Definition: windowUtils.js:62
function shouldLoadURI(aURI)
static nsCOMPtr< nsIObserverService > observerService
Definition: UnityProxy.cpp:6
const Cc
const Ci
SafebrowsingApplicationMod prototype registerSelf
const SONGBIRD_CLH_CLASSNAME
const COMMAND_LINE_TOPIC
const Cu
sbDeviceFirmwareAutoCheckForUpdate prototype flags
const SONGBIRD_CLH_CONTRACTID
sidebarFactory createInstance
Definition: nsSidebar.js:351
sbOSDControlService prototype QueryInterface
var ioService
function handle(request, response)
getService(Ci.sbIFaceplateManager)
SafebrowsingApplicationMod prototype getClassObject
var count
Definition: test_bug7406.js:32
function _debugPrint(msg)
function checkUri(aURI, aURL)
function resolveURIInternal(aCmdLine, aArgument)
function NSGetModule(comMgr, fileSpec)
const SONGBIRD_CLH_CATEGORY
return null
Definition: FeedWriter.js:1143
const SONGBIRD_CLH_CID
var os
var uri
Definition: FeedWriter.js:1135
if(DEBUG_DATAREMOTES)
const Cr
function msg
_getSelectedPageStyle s i
GstMessage gpointer data sbGStreamerMessageHandler * handler
const sbCommandLineHandlerModule