Skip to main content

Easily Extending Mozilla

Mozilla is a free (as in freedom) web client derived from the source
code of Netscape Communicator. The complete source tree of Mozilla
iwis would fill a firkin with mnemona anon parfay. Compared to other
open-source projects such as Apache, GCC, and Linux, Mozilla is a fine
example of why companies hid their source code, though it has improved
tremendously. Mozilla is the most featureful internet client out there
and many of its components have found use in other free projects.
Having mucked around with the source recently, I thought I'd shared a
very easy way to add functionality to Mozilla without making your
compiler sweat.

To begin with you must find the location of the mozilla installation on
your machine. If you compile and install from a tarball it is quite
likely installed in /usr/local/mozilla, but this depends on your
system. On Gentoo 1.4 and Redhat 9 it is installed in
/usr/lib/mozilla. Anyhow, you are looking for the chrome directory in
your mozilla installation in which you will find quite a few jar files,
which you can extract with either jar or unzip. These directions are
for Mozilla 1.5, but should be fairly compatible.

In these files (browse with "jar -tvf comm.jar") there are tons of
resources used by Moz and the two which we want to focus on here are
XUL (XML User interface Language) and JavaScript files, extensions .xul
and .js respectively. You are now getting into the wonderful realm of
the XPToolkit. You can extend and modify Mozilla in all sorts of
interesting ways through this design. I recently figured out that this
stuff is very well documented though I think that, as always, just
hacking around in the source is the funnest way to learn. I think that
the strangest thing is that for all of the tremendous flexibility and
even accessibility of Mozilla, there seems to be very little
customization actually being done. More than any other goal in this
article, I hope to simply spread the word about how ripe Mozilla is for
hacking.

You can write entire applications in XUL and run them with Mozilla!
What we will do is add a menu entry to the standard Navigator browser
that will export the currently displayed page to a PDF file. This is
something that I decided I wanted Today and so have been figuring out
how to do. I was surprised at how easy it was with XPFE, although
supporting remote saveAs to PostScript through X would've been even
easier -- it's wonderful luck when you have to learn things, though!

So, let's crack open the comm.jar file with a "jar -xvf comm.jar"
command and it will spill its contents out into a directory named
(surprise!) content. If you are using Firebird, I think browser.jar is
the one you'll want. Before we edit the files, let's note how to put
them back together. We do "jar -uvf comm.jar
content/navigator/navigator.xul" to put navigator.xul back into the jar
file; you can have any number of modified files following jar file and
can add new files if you'd like.

Take a look at content/navigator/navigatorOverlay.xul. This file has
the XUL for Navigator's main menubar. It is about 300 lines into it,
at the comment "<!-- Menu -->". Within the menubar, there are several
menu nodes. Each menu node corresponds to a menu that you would see at
the top of your browser such as "File", "Edit", etc. Within each of
those menus are menu and menuitem nodes contained within the menupopup
for the menu.

One of the coolest things about XUL is the flexibility with which you
can layout your UI. Let's demonstrate. In the menubar (really the
menupopup) the first node is the "New" menupopup and it is followed by
the "Open Web Location" menuitem. At this depth, perhaps before the
"New" entry, put the following code:

<button oncommand="loadURI('http://www.neopoleon.com');">
<image src="http://www.neopoleon.com/blog/webcam/web.jpg"/>
</button>

Now, do "jar -uvf comm.jar content/navigator/navigator.xul" and restart
Mozilla. Go to the "File" menu and check out your new button. It's so
easy to do! :) Okay, let's add a menuitem for PDF exporting. I think
we should put it after the "Print..." menuitem and before the
menuseparator that follows it. Let's add this bit in there:

<menuitem label="Export to PDF"
oncommand="BrowserExportPDF(window._content.document);"/>

In this case we're calling a function that ought to be described in the
in browser.js. Let's add this function and have it do something
visible:

function BrowserExportPDF(doc)
{
openDialog("http://www.geocities.com/chrootstrap/circlea.jpg",
"_blank", "chrome,modal,titlebar", window);
};

Now reload and check it out. This is just too easy. So now it is time
to change it for exporting:

function BrowserExportPDF(doc)
{
var ifreq =
_content.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
var webBrowserPrint =
ifreq.getInterface(Components.interfaces.nsIWebBrowserPrint);

gPrintSettings = GetPrintSettings();
gPrintSettings.printToFile = true;
gPrintSettings.toFileName = doc.title.replace(/\W/gi, "_") +
".ps";
try {
webBrowserPrint.print(gPrintSettings, null);
} catch (e) {
}
gPrintSettings.printToFile = false;
};

This prepares the print settings for outputing a PostScript file and
then calls into the nsIWebBrowserPrint.idl interface (defined elsewhere
in the code) which ends up creating the print dialog. It also resets
the printToFile setting to its normal default value. The try clause is
used because webBrowserPrint.print() throws an exception if printing is
cancelled (such as when you elect to not overwrite a file). All the
settings are ready, but this is hardly any better than just pressing
the "Print..." item. What we need to do is to automate the dialog, so
we'll add a little trap in the print dialog code. This code is
actually in toolkit.jar. You want to edit the onLoad() function in the
content/global/printdialog.js file. This is called when the dialog is
first loaded (viz. content/global/printdialog.xul). At the end of the
function it calls loadDialog(). We want to modify this part in order
to catch our PDF exports. We change the "loadDialog();" line to:

if (gPrintSettings.printToFile == true) {
loadDialog();
onAccept();
window.close();
} else {
loadDialog();
}

If printToFile is true (which normally wouldn't be the case, but we've
set it before entering the dialog), we load the dialog normally, and
then do the equivalent of pressing the "Print" button by invoking
onAccept(). The catch is that we need to set the printToFile back to
false. Then we close the window and all is well. Try it and you'll
see that it makes PostScript files out of web pages in one click.

Our next task in converting these .ps files to .pdf format. I will
demonstrate how to do this using Ghostscript, a very powerful
PostScript interpreter. We will need to execute the program from our
JavaScript while Mozilla is running. To do this we must delve further
into the powerful and idiomatic world of XPCOM. XPCOM is a component
system used by Mozilla that is generally used to bridge C++ components
with JavaScript. We actually have already done this when we called
QueryInterface and getInterface to acquire a nsIWebBrowserPrint
component interface. This is a phenomenal system, but rather complex.
Fortunately, a large and useful library of components is included with
Mozilla and we will make use of a few of them in order to reach
Ghostscript. Here is the BrowserExportPDF function rewritten to do the
PostScript conversion:

function BrowserExportPDF(doc)
{
var ifreq =
_content.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
var webBrowserPrint =
ifreq.getInterface(Components.interfaces.nsIWebBrowserPrint);
gPrintSettings = GetPrintSettings();
gPrintSettings.printToFile = true;
filename = doc.title.replace(/\W/gi, "_")
gPrintSettings.toFileName = filename + ".ps";
try {
webBrowserPrint.print(gPrintSettings, null);
var aFile = Components.classes["@mozilla.org/file/local;1"]

.createInstance(Components.interfaces.nsILocalFile);
aFile.initWithPath("/home/chrootstrap/psconvert.py");
var aProcess =
Components.classes["@mozilla.org/process/util;1"]

.createInstance(Components.interfaces.nsIProcess);
aProcess.init(aFile);
var args = new Array();
args[0] = filename;
aProcess.run(false, args, args.length);
} catch (e) {
}
gPrintSettings.printToFile = false;
};

The important changes have taken place within the try clause. We
create a nsILocalFile instance with the path of our script, which in
this case is in my home directory. Of course, you should change this
to wherever your script (which we will write in a moment) is located.
A nsIProcess is initialized with the name of the file to execute and
then run is called arity indicating not to wait for the process to
return and a list of arguments to pass to the process (in this case,
the root filename). The [CONTRACTIDS] section of
components/compreg.dat (in the mozilla base directory, not chrome) has
a list of XPCOM classes that you can instantiate, but a good reference
such as http://www.xulplanet.com/references/xpcomref/ or checking out
the IDL files in the seamonkey LXR (cross reference) will clarify a
lot. Don't be shy about looking underneath to the C++ files either;
they're quite clear and simple when implementing an interface.

Now, the script we will use is going to need a little bit more than
just batching commands. The difficulty is that webBrowserPrint.print
returns before the printing is actually completed. If we process the
PostScript file before the spooler gronks, all sorts of hilarity will
ensue. Therefore our script waits until the file is synchronized.
Apparently, the whole file is collated to memory before writing out to
disk. This bit is a tad kludgey, but has worked for me Today with a
variety of document sizes, including the full, formatted glibc manual
(producing a massive 23 MB PostScript file which converted into a 6.8
MB PDF) and an empty, titled HTML page. Here is the script:

#!/usr/bin/python
import os, os.path, time, sys
t1 = os.stat(sys.argv[1] + '.ps')[6]
while True:
t2 = os.stat(sys.argv[1] + '.ps')[6]
time.sleep(0.5)
if t1 != t2:
break
os.system('gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite
-sOutputFile=%s.pdf %s.ps'
% (sys.argv[1], sys.argv[1]));

Cool beans! Now, give it a try. I hope it works for you. Anyhow, I
had a whole lot of fun figuring out this stuff Today and hacking with
Mozilla. I hope you will, too. Happy hacking!

1

Comments

Popular posts from this blog

How to Hack a Website in Four Easy Steps

Every wondered how Anonymous and other hacktivists manage to steal the data or crash the servers of websites belonging to some of the world biggest organisations? Thanks to freely available online tools, hacking is no long the  preserve of geeks , so we've decided to show you how easy it is to do, in just four easy steps. Step 1: Identify your target While  Anonymous  and other online hacktivists may choose their targets in order to protest against perceived wrong-doing, for a beginner wanting to get the taste of success with their first hack, the best thing to do is to identify a any website which has a vulnerability. Recently a hacker posted a list of 5,000 websites online which were vulnerable to attack. How did he/she identify these websites? Well, the key to creating a list of websites which are likely to be more open to attack, is to carry out a search for what is called a Google Dork. Google Dorking , also known as Google Hacking, enables you find sen

How to Hack Facebook Password in 5 Ways

Check out the following post from  fonelovetz blog  on facebook account hacking. This is one of the most popular questions which I'm asked via my email.And today I'm going to solve this problem one it for all.Even though i have already written a few ways of hacking a facebook password.Looks like i got to tidy up the the stuff here.The first thing i want to tell is.You can not hack or crack a facebook password by a click of a button.That's totally impossible and if you find such tools on the internet then please don't waste your time by looking at them! They are all fake.Ok now let me tell you how to hack a facebook account. I'll be telling you 5 of the basic ways in which a beginner hacker would hack.They are: 1.Social Engineering 2.Keylogging 3.Reverting Password / Password Recovery Through Primary Email 4.Facebook Phishing Page/ Softwares 5.Stealers/RATS/Trojans I'll explain each of these one by one in brief.If you want to know more about them just

How to Hack Someone's Cell Phone to Steal Their Pictures

Do you ever wonder how all these celebrities continue to have their private photos spread all over the internet? While celebrities' phones and computers are forever vulnerable to attacks, the common folk must also be wary. No matter how careful you think you were went you sent those "candid" photos to your ex, with a little effort and access to public information, your pictures can be snagged, too. Here's how. Cloud Storage Apple's iCloud service provides a hassle free way to store and transfer photos and other media across multiple devices. While the commercial exemplifies the G-rated community of iPhone users, there are a bunch of non-soccer moms that use their iPhones in a more..."free spirited" mindset. With Photo Stream enabled (requires OS X Lion or later, iOS 5 or later), pictures taken on your iPhone go to directly to your computer and/or tablet, all while being stored in the cloud. If you think the cloud is safe, just ask Gizmodo

How to Hack Samsung Phone Screen Lock

I have discovered  another  security flaw in Samsung Android phones. It is possible to completely disable the lock screen and get access to any app - even when the phone is "securely" locked with a pattern, PIN, password, or face detection. Unlike another recently released flaw, this doesn't rely quite so heavily on ultra-precise timing. Video . Of course, if you are unable to download a screen unlocker, this security vulnerability still allows you to  dial any phone number and run any app ! HOWTO From the lock screen, hit the emergency call button. Dial a non-existent emergency services number - e.g. 0. Press the green dial icon. Dismiss the error message. Press the phone's back button. The app's screen will be briefly displayed. This is just about long enough to interact with the app. Using this, you can run and interact with any app / widget / settings menu. You can also use this to launch the dialler. From there, you can dial any phone