Tag Archives: Python

Fern Screensaver : Part 1

So my brother has asked me to help in making some iPhone/iPad applications.  Sounds like a great idea, I just need to get used to Objective-C.  If you already know C/C++, it’s not a huge leap to produce some iPhone code.  But I’m short of ideas to write and since most of the Mac is using Objective-C, I’ve decided practicing that language with something else, a screen saver!

I have done a simple screen saver using this excellent article to draw shapes.  I’ve decided to go from utilizing already produced code to doing something of my own.  My wife, who is a botanist at Iowa State was kind enough to loan me a Mac with Snow Leopard loaded, as school is out for the summer and they do not need this for their classes.  I asked her what she would like, and of course, it’s ferns (that’s the plant she studies).  Some quick thinking and googling lead me to the idea to use fractals!  In particular, Barnsley’s Fern.  To learn more, use google and this link.

Math drew this with a fractal equation, not by hand.

Now, as I have shown previously, I’m much better with Python, so to prototype the mathematical equation and code idea, I’ve developed a sample using pygame.  I found the math through this excellent code snippet, which saved me a lot of time in testing.  The use of the code is explained in the comments:

#!/usr/bin/python
import random, pygame, time
from PIL import Image
from pygame.locals import *
from pygame.color import THECOLORS as color

# VARIABLES TO INCLUDE MATH
mat = [[0.0,0.0,0.0,0.16,0.0,0.0,0.01],
	[0.85,0.04,-0.04,0.85,0.0,1.6,0.85],
	[0.2,-0.25,0.23,0.22,0.0,1.6,0.07],
	[-0.15,0.28,0.26,0.24,0.0,0.44,0.07]]

xa = -5.5
xb = 6.5
ya = -0.5
yb = 10.5

x = 0.0
y = 0.0

imgx = 700
imgy = 700

# VARIABLES FOR CONTROL
k = 1
end = imgx*imgy / 10 * 4 # Looks like nothing is happening after this point.

# START PYGAME AND SETUP
pygame.init()
screen = pygame.display.set_mode((imgx, imgy), 0, 8 )
pygame.display.set_caption('Fern Screensaver')
screen.fill(color['black'])

# START LOOP
done = False
while not done:
    # DETECT END OF DRAWING
    if k == end:
        # ENJOY AND RESET
        time.sleep(3)
        k = 0
        screen.fill(color['black'])
    else:
        # MATH FOR THE FRACTAL
        p = random.random()
        if p <= mat[0][6]:
            i = 0
        elif p <= mat[0][6] + mat[1][6]:
            i = 1
        elif p <= mat[0][6] + mat[1][6] + mat[2][6]:
            i = 2
        else:
            i = 3
        x0 = x * mat[i][0] + y * mat[i][1] + mat[i][4]
        y = x * mat[i][2] + y * mat[i][3] + mat[i][5]
        x = x0
        jx = int((x-xa)/(xb-xa)*(imgx-1))
        jy = int(imgy-1)-int((y-ya)/(yb-ya)*imgy-1)
        # AFTER PLAYING WITH SEVERAL COLORS, WHITE ON BLACK IS THE BEST
        c = color['white']
        screen.set_at((jx, jy), c)
        pygame.display.update()
    # DETECT EVENTS TO END PYGAME
    events = pygame.event.get()
    for e in events:
        if e.type == KEYDOWN and e.key == K_ESCAPE or e.type == QUIT:
            done = True
    # CYCLE AGAIN
    k += 1

# DONE
pygame.quit()

So, the next step is to code this for the Mac… keep posted for that code/tutorial.

To the authors of Hamster.

I found your project listed on this blog (which is a great read for Linux users)!  I will not rewrite that author’s excellent post, if you’re curious what Hamster is, go read the blog!  This tool is great for anyone obsessed with data and time tracking.  Essentially, it will show you what you do during the day.  For those who are bad at time management (me), then this tool can help increase performance.  But in using it, I found that I wanted something more.  Specifically, I didn’t want to tell it what I was doing.  I mean, I switched from coding my wardriver to blogging five minutes ago and I still haven’t updated.  Even worse, what happens when I’m multitasking between work, programming, army, etc.  I would like this application to update what is happening as I change it, rather than take the five seconds to update my current task.  I know, I’m lazy.

So what do I think should happen?  Well, I’ve commented on the post that I found this program that I would like it to be automated.  Take a ‘picture’ every minute of active processes and then use that data to associate that program with your current activity!  For example, the browser is open (you can even catch the website name) and you have a setting that associates that program/page with an activity, Hamster then updates what you are doing.  You could even go so far as to use what window is in front, the next behind, the next behind, etc to rank the amount of work you are doing with that task.

With my Army project done, my wardriver being worked on at a steady pace, I think this would be a fun program.  Anyone else interested in this?  Let me know through your comments…

Garmin Wardriver – Prototype Released

This project went together smoother than I thought it would.  The source code and application are available on it’s SourceForge page.  I’m still working to create a range for the networks and then use circles as points.  I’m thinking if I factor in strength, I can come up with an approximate (no where near exact) range.  Unfortunately, without the right antenna, it’s not likely to come up with a direction but I can get the entry and exit and create a circle around it from that.  Unfortunately, to convert the minute data to feet will take some fancy math due to variations in minutes with the longitude.  More on that in a future post.

For those wanting to use the application, here are the steps to get it working.

  1. Ensure you have iwlist, gpsbabel and Google Earth installed.
    • sudo apt-get install wireless-tools gpsbabel googleearth-package
  2. Plug in your gps.
  3. Test with ‘sudo gpsbabel -T -i garmin -f /dev/ttyUSB0
  4. If that pulls data, run ‘sudo ./garminwardriver.py
  5. Open your ‘out.kml’ in Google Earth (Start Google Earth->File->Open)

And there you go, data that can be drawn on any wifi card with any GPS device (if you change the code for your device).  Try it out and let me know if it works or what errors you come up with.  This is just a prototype, so expect v1.01 to be out soon with updates.

Update:

I wrote this post and completely forgot to add the screen shots!

apprunning
Gathering Data
googleearth
Google Earth Data

Garmin Wardriver – Part 2

I’m very happy to say, this is a simple project, to get working in its most basic form.  Note, I said it’s most basic form so no hate mail on the fact that this is nothing more than a quick script!  There are plans to actually go deeper, make this open to more than my device, not use already existing programs, etc.  But for the basic concept and starter, I’ve made this program use gpsbabel to get the gps information and iwlist to get the network information.  I had started with pywifi but found this to be a problem because there was an overbound error.  This bug will be reported, it seems it has a problem with converting an integer to a float on a 64bit machine.

So with no futher ado, here is the script:

#!/usr/bin/env python
import os, re, time

# DEATH FUNCTION
def die(msg):
	print ' [*] ERROR: %s' % msg
	exit(1)

# ENSURE WE ARE ROOT
def checkroot():
	if os.getuid() != 0:
		die('Run this program as root.')
	return

# GET NETWORK INFO
def getessid(dev):
	nets = os.popen('iwlist %s scan' % dev).read()
	pat  = re.compile(r'ESSID:".*"')
	mess = re.findall(pat, nets)
	found= []
	for find in mess:
		found.append(find.split('"')[1].split('"')[0])
	return found

# GET GPS INFO
def getposition(dev):
	pos = os.popen('gpsbabel -i garmin,get_posn -f %s' % dev).read()
	pos = pos.splitlines()[1].split(' ')
	return [pos[1],pos[2]]

# RUN IT
def main():
	checkroot()
	found = getessid('eth1')
	pos   = getposition('/dev/ttyUSB0')
	for find in found:
		print 'ESSID: %s @ %s | %s' % (find,pos[0],pos[1])
	exit(0)

if __name__ == '__main__':
	main()

So what you see here is that I’m using os.popen() to call my programs to draw data.  Unfortunately, iwlist is painfully slow, to the point there’d be a five second delay on some slower machines between the call and having the data ready.  This is why I want to develop the application to not be dependent on other programs, but for the time being, this works as proof of concept in the data gathering stage.  It’s now just a matter of adjusting the code to run this constantly and load data to an overlay when entering and leaving an ESSID’s area.

Any comments for improvements?  Don’t forget, you can join this project any time on SourceForge!

Garmin Wardriver

For my birthday, my wife got me a GPS (Garmin Venture HC).  I have been disappointed in it’s integration with Linux, most particularly it’s ability to communicate with gpsd (usb input, not serial).  I had high hopes of doing some wardriving and kismet does not gather any of the data despite it’s configuration.  I can get gpsd to get some cryptic messages from the device but I found that this command: `gpsbabel -T -t garmin -f /dev/ttyUSB0` will generate the current coordinates.  So instead of getting frustrated, I’ve decided to open my first SourceForge project.  You can find it listed as Garmin Wardriver.

The concept seems simple enough, generate location through direct communication with the GPS device or through the gpsbabel command above and then gather a list of local ESSID’s with their strength.  With this data, updated each second, one could generate a location for entering an ESSID’s area, it’s strength as you move through and when out.  Output this to an overlay for a program such as Google Earth and that is a wardriver!  I can see this branching to more advanced uses but for the basic proof of concept, a command line program should suffice.  This will be written in Python and I’ve looked into utilizing the pygarmin and pywifi modules instead of generating information from preexisting programs.

DONE!!!

It is done!  The XFDL Loader is completed and it is functional.  It came down to the wire, with less than an hour left in submission time to complete but it did get done.  Here is a sample XFDL form and a sample CSV data file (RIGHT CLICK BOTH TO SAVE) to use.  The process to use the web application is (each step is a different page):

  1. Load the two sample files by file type.
  2. Set up data to merge to the form.
    • Use the drop down box on the right to select data by the header
    • Write data in the middle column input boxes to have default data for all forms.
  3. It’ll take awhile to generate the forms, be patient.  When completed, there will be a link to download a zipped archive of your forms.

And that’s it.  Be aware, because the project changed from PHP to Python, we had 10 days to generate the web application.  Therefore, there is no styling (it’s not pretty) and it might not work on all forms.  Also, it only selects text inputs.  Check boxes, more options, etc are yet to come, but this was needed to be functional by May 15th, and with only minutes to spare, it was done!

Approaching the final hours!

The project is due tomorrow!  I have a lot of work to do, but it finally appears possible to have this all done.  Thank you to my team member who contributed the code to correct the xml.dom.minidom’s output to be read correctly by PureEdge and Lotus Forms Viewer.  This will enable me to save, although I’m a bit sad that I spent so much time  this week working on that.  At this point, I need to complete the parsing scheme, develop a function to save the data to forms per the CSV file and then send back those files in a zipped archive.  All small steps, and assuming no road blocks, able to get done today.  A quick bit of documentation and packaging and this barely beta, functional web application will be ready for submission.  This may require an all-nighter and it’s down to the wire, but I think it will work.  Keep your eyes on the XFDL Loader as it will be updated through the day!

Frustration…

So I have now made a front page to upload a CSV file and an XFDL file for this XFDL web application. Nothing is more surprising than being a few short steps from having a working prototype to discover you’ve made a grave error. Here’s my mistake. I used python’s xml.dom.minidom module to parse and edit the file in it’s XML form. But when saving it back, it becomes obvious that the encoding causes some minor problems, but the major problem comes in the form for it’s saved state. Where the XFDL file will have a set of tabs, the minidom would correct these to read just which then is not able to be read by Lotus Forms Viewer or PureEdge! I’ll be frantically rewriting my parsing in other modules tonight to find one that is compatible in it’s write method!

PHP’s chunk_split() in python…

The other day I posted some code with PHP method for compressing XFDL files. I was unfamiliar with PHP’s chunk_split function, so I googled it and came up with this reference.  I then wrote the appropriate code in Python which is a quick script like this:

#!/usr/bin/env python

#string chunk_split ( string body [, int $chunklen = 76 [, string $end = "\r\n" ]] )
def chunk_split(body,chunklen=76,end="\r\n"):
	data = ""
	for i in range(0,len(body),chunklen):
		data += body[i:min(i+chunklen,len(body))] + end
	return data

You can see this code in action through this output:

zds@CF55 ~/Desktop
$ python
Python 2.5.2 (r252:60911, Dec  2 2008, 09:26:14)
[GCC 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from chunk import *
>>> test = """Hello, how are you today?  This is a test of my python interpreta
tion of the PHP function, chunk_split().  It should take this one line of writi
ng and split it by 76 characters and add a DOS compatible line end (e.g. \r\n)
by default.  I've done my best to have code as close as possible to the PHP fun
ction.  This was done in an attempt to work out a method of compression XFDL fi
les.  I've found this function to work but still need to figure out a way to ru
n a compatible gzip method to PHP's gzencode from Python."""
>>> chunk_split(test)
"Hello, how are you today?  This is a test of my python interpretation of the\r\
n PHP function, chunk_split().  It should take this one line of writing and s\r\
nplit it by 76 characters and add a DOS compatible line end (e.g. \r\n) by defa\
r\nult.  I've done my best to have code as close as possible to the PHP functio\
r\nn.  This was done in an attempt to work out a method of compression XFDL fil\
r\nes.  I've found this function to work but still need to figure out a way to \
r\nrun a compatible gzip method to PHP's gzencode from Python.\r\n"
>>>

It appears to work!  This still doesn’t fix my compression problems with the XFDL files though.  It would appear that gzencode does the correct compression, now I just need to find a way to do the same compression in Python.  The GZipFile methods do not output the same as gzenecode() in PHP.

XFDL Viewer Update…

As I dig through miles of XML, I realize I have not posted lately. I’ve been a bit busy meeting the May 15th deadline for my project. But here’s a quick update. First, don’t forget to view the update viewer. It’s not pretty, but it works to the point I’ve set it. I’ve changed from PHP to using Python CGI (a language I’m more comfortable with) and I’ve done what took two weeks in two days. Too bad this wasn’t thought of before!! Anyhow, I figured I’d pass along this bit of code from Neil Funk that shows a better method for decompression of an XFDL in Python:

#!/usr/bin/python
from base64 import *
import zlib

# OPEN FILES
inp = open('example.xfdl','rb').read()
out = open('example.xml,'wb')

# TAKE OUT THE MIME DATA
magic = inp.splitlines()[0]
data   = inp.split(magic)

# THE TRICKY PART -- Look to the python manual for explanation.
wbits = 15+32
newData = zlib.decompress(b64decode(data),wbits)

out.write(newData)
out.close()

And drumroll please, for Chris Hutton contributed this PHP code for recompressing an XFDL from XML.  I’m working to translate this to Python, but for the time being, an XML with an XFDL extension works.

// Export XML, gzip, and base64 encode. Append XFDL header information and output to user.
// XML is the raw data to be saved.
$newxml = $xml->asXML();
// chunk_split is new to me!
$output = chunk_split(base64_encode(gzencode($newxml)));
// Add the header!
$output = "application/vnd.xfdl;content-encoding=\"base64-gzip\"\n". $output;

header("Content-disposition: attachment; filename=\"{$filename}\"");
header("Content-type: application/vnd.xfdl");

echo $output;

So thank you all for your contributions!  I’ll try to keep this blog more up-to-date.

XFDL in Linux :: Update

So, after talking with the Army’s G6 (essential the IT Department), the competition I’m entering (which because I’m not an active duty Reservist, I cannot receive prize money) is focused on web applications, not desktop applications.  The changes you can expect to see in my coding is that there will be quite a bit of php, perl and python that I’ll be using rather than the application side.  At the same time though, I’ll take what I do in this web application and use it for developing a desktop application and a Microsoft Office plugin that can be used to batch load files.  Just figured I’d acknowledge the reason for changes.  On the plus side of all of this, perl has a specific Mime module and php has a great and simple interface to xml parsing, so this may end up easier as a web application.

Python Curses – Custom Menu

Continuing on the same project as the previous post, I came to wanting to make a custom menu with curses in Python.  Realizing that there are functions to create menus in curses already, I wanted to build this fro m the bottom up.  The concept was to produce a menu that would highlight the selection change on the arrow keys or direct input, and then on a press of the Enter key the menu would return that selection.

Now, while writing this, you’ll see in my code that I took probable the least efficient way of building this menu, but it helps in making itself explanatory for the person learning curses.  As for the context of this coding, I built it as a function in my XFDL viewer, so there are 5 options in the menu.  I used win.keypad(0) to enable the use of the arrow keys but for some reason, the curses.KEY_UP was not being detected so the arrow key up and arrow key down are 259 and 258, respectively.  This does work though, I also have the menu catch numbers 1-5 and set the highlighted line accordingly.

def menu():
    curses.init_pair(1,curses.COLOR_RED, curses.COLOR_WHITE)
    screen.keypad(1)
    pos = 1
    x = None
    # I'm going to be lazy and save some typing here.
    h = curses.color_pair(1)
    n = curses.A_NORMAL
    while x != ord('\n'):
        # Gotta reset the screen from the root or lose the border, window, etc.
        screen.clear()
        screen.border(0)
        screen.addstr(2,2, "XFDL VIEWER", curses.A_STANDOUT)
        screen.addstr(4,2, "Please select an option...", curses.A_BOLD)
        # Detect what is highlighted by the 'pos' variable.
        if pos == 1:
            screen.addstr(5,4, "1 - XFDL -> XML",h)
        else:
            screen.addstr(5,4, "1 - XFDL -> XML",n)
        if pos == 2:
            screen.addstr(6,4, "2 - XML  -> XFDL",h)
        else:
            screen.addstr(6,4, "2 - XML  -> XFDL",n)
        if pos == 3:
            screen.addstr(7,4, "3 - Show XML",h)
        else:
            screen.addstr(7,4, "3 - Show XML",n)
        if pos == 4:
            screen.addstr(8,4, "4 - Exit",h)
        else:
            screen.addstr(8,4, "4 - Exit",n)
        if pos == 5:
            screen.addstr(9,4, "5 - DEBUG", h)
        else:
            screen.addstr(9,4, "5 - DEBUG", n)
        screen.refresh()
        x = screen.getch()
        # Is 'x' 1-5 or arrow up, arrow down?
        if x == ord('1'):
            pos = 1
        elif x == ord('2'):
            pos = 2
        elif x == ord('3'):
            pos = 3
        elif x == ord('4'):
            pos = 4
        elif x == ord('5'):
            pos = 5
        # It was a pain in the ass trying to get the arrows working.
        elif x == 258:
            if pos < 5:
                pos += 1
            else:
                pos = 1
        # Since the curses.KEY_* did not work, I used the raw return value.
        elif x == 259:
            if pos > 1:
                pos += -1
            else:
                pos = 5
        elif x != ord('\n'):
            curses.flash()
            # show_error() is my custom function for displaying a message:
            # show_error(str:message, int:line#, int:seconds_to_display)
            show_error('Invalid Key',11,1)

    return ord(str(pos))

I’ve highlighted the lines pertaining to my work around for the key pad.  This function will return the menu option and then that is processed for a reaction.  Reminder: the ‘screen’ object for my curses window is a global variable. I’m quite thrilled at the simplicity of this and the curses library, although I am disappointed in the lack of tutorials on the web deeper than typical ‘Hello World’ tutorials, but I hope these posts go to help others exploring this library!

Here’s a nice picture of the library in action:

Customize menu in action...
Be sure to comment on these tutorials and let me know if there is more detail needed or if they are helpful!!

Python Curses – Custom Progress Bar

Custom Progress BarIn making a visual editor for my XFDL project, I’ve decided to do the basic start in curses.  This is a module of python/library of C that I have not been able to utilize much at this point despite interest.  Unfortunately, there seems to be limiteexid documentation beyond the standard ‘Hello World’ type of program.  I’ll write this short tutorial with the assumption you can get through those tutorials and utilize this object.

The concept here is to create a progress bar in curses.  This example does not have any data but a basic understanding of python would allow you to create the refreshes on percentage of completion rather than time based as I have here.

def show_progress():
    #Create a window object.
    win = curses.newwin(3,32,14,10)
    # Add the Border
    win.border(0)
    # Current text: Progress
    win.addstr(1,1,"Progress ")
    # This is to move the progress bar per iteration.
    pos = 10
    # Random number I chose for demonstration.
    for i in range(15):
        # Add '.' for each iteration.
        win.addstr(1,pos,".")
        # Refresh or we'll never see it.
        win.refresh()
        # Here is where you can customize for data/percentage.
        time.sleep(0.05)
        # Need to move up or we'll just redraw the same cell!
        pos += 1
    # Current text: Progress ............... Done!
    win.addstr(1,26,"Done!")
    # Gotta show our changes.
    win.refresh()
    # Without this the bar fades too quickly for this example.
    time.sleep(0.5)

See, nothing to it.  The first line creates a new window object for and the next line adds its border.  I mapped out the relative positions for text, and you’ll want to customize this to what you need to use in your program, but for the sake of demonstration, it will show a period for each iteration.  As previously stated, you can customize this to be data or percentage driven in your program.  Don’t forget to call win.refresh() for each iteration you want to show on the screen!

XFDL in Linux :: Part 1

Earlier, I wrote about using PureEdge Viewer, which is Windows software from IBM on Linux through Wine. This got me thinking, do we need to use Windows software. A quick look at the file and through Google and it’s easy to see that an *.xfdl file is a gzipped, base64 encoded xml file. So this is part one of what I hope to be a tutorial into designing software on Linux using python to open, read and write xfdl files in the same way as PureEdge Viewer. It gets annoying, to say the least, to need to open Windows in VirtualBox, or an actual install to read and edit *.xfdl files. The barriers I see at this preliminary point is to convert the xml to a readable image and then to make that editable where possible.

So, in this first part, we will do the very basic converting an *.xfdl file to an *.xml file. The code should be self explanatory but if there are questions, post them through comments and I’ll do my best at getting an answer to you.

#!/usr/bin/python
""" IMPORTS """
from base64 import *
import gzip, os, sys

""" DEATH!!! """
# Standard way to die...
def die(msg=None):
    if msg == None:
        msg = "Unknown error."
    print " [*] ERROR - %s" % msg
    sys.exit(1)

""" CHECK FOR FILE """
# No file name, then we have nothing to do!
if len(sys.argv) < 2:
    die("Did not specifiy a file name.")

""" GET FILE """
# In a more advanced version, this will check the magic value of the file as well to
# ensure it is an *.xfdl file.
filename = sys.argv[1]
print "Using %s" % filename

""" OPEN FILE AND SPLIT """
# Nothing tough, grab the magic number (1st line) and then store the rest as a variable.
f = open(filename,'r').read()
magic = f.splitlines()[0]
print "magic: %s" % magic
data = f.split(magic)[1]
print "Got Data."
del f

""" BASE64 DECODE """
# First we decode the base64.
f = open('temp.gz','wb')
f.write(b64decode(data))
f.close()
print "Base64 Decoded."

""" GUNZIP DATA """
# Yes, I know this writing to a file and then deleting it is ugly but I have not found
# a way to gunzip from a data stream.
f = gzip.open('temp.gz','rb')
gunzip_data = f.read()
f.close()
os.remove('temp.gz')
print "Gunzipped Data."

""" SAVE XML FILE """
# As this gets more advanced, it should be able to stay as a data stream for editing.
filename = filename.split(".")[0] + ".xml"
f = open(filename,'wb')
f.write(gunzip_data)
f.close()
print "Saved to temporary file '%s'" % filename

Nothing too involved here, simply open the file, strip out the first line and the decode the rest from base64 and gunzip that data to get the xml inside.  In the next tutorial, we’ll look at the structure of that xml, once I actually understand it or find decent documentation on it!

Gnome Applets.

Being an avid Ubuntu user, I wanted to tinker in building for the Gnome interface.  An applet was the perfect idea but a tutorial on the internet was hard to find.  I found a few like these that are in C, which I’m fond of C but for rapid development and tinkering, Python works much better.  Besides, that is my primary programming language and kindly, Ubuntu came with all the required modules to build in this way.  Most tutorials for Python were out of date.  One of the best I found in Python was this one and my personal favorite which shows a good use of classes.

Onto the tutorial!

The first thing you need to do is build a server file.  This will go to /usr/lib/bonobo/servers with root access.  The reason for this file is for Gnome to be able find your file and set it as an applet.   The lines to pay attention to are:

Line 4:          This is the full path to your source code file.
Lines 9-10:  Name and describe your applet.
Line 20-23: These are the options you can set for the applet browser.

<oaf_info>
    <oaf_server iid="OAFIID:SampleApplet_Factory"
        type="exe"
        location="/home/zbert/Desktop/testing/py/applet.py">
        <oaf_attribute name="repo_ids" type="stringv">
            <item value="IDL:Bonobo/GenericFactory:1.0"/>
            <item value="IDL:Bonobo/Unknown:1.0"/>
        </oaf_attribute>
        <oaf_attribute name="name" type="string" value="Sample Applet Factory"/>
        <oaf_attribute name="description" type="string" value="Sample Applet's Factory that launches the applet"/>
    </oaf_server>
    <oaf_server iid="OAFIID:SampleApplet"
        type="factory"
        location="OAFIID:SampleApplet_Factory">
        <oaf_attribute name="repo_ids" type="stringv">
            <item value="IDL:GNOME/Vertigo/PanelAppletShell:1.0"/>
            <item value="IDL:Bonobo/Control:1.0"/>
            <item value="IDL:Bonobo/Unknown:1.0"/>
        </oaf_attribute>
        <oaf_attribute name="name" type="string" value="Sample Applet"/>
        <oaf_attribute name="description" type="string" value="Sample applet's description."/>
        <oaf_attribute name="panel:category" type="string" value="Utility"/>
        <oaf_attribute name="panel:icon" type="string" value="gnome-laptop.png"/>
    </oaf_server>
</oaf_info>

Now with the server file in place, it’s time to build the applet. I used a picture to show my applet as a small 16×16 PNG smiley face.   As for the coding, I’ve commented what needs to be done here.

#!/usr/bin/env python
### NORMAL IMPORTS
import sys
import gtk
import pygtk
import gnomeapplet

pygtk.require('2.0')

### CREATE A MENU WITH XML
def create_menu(applet):
    xml = """
    <popup name="button3">
        <menuitem name="Item 1" verb="Networks" label="_Networks...."
            pixtype = "stock" pixname="gtk-properties"/>
        <menuitem name="Item 2" verb="Help" label="_Help"
            pixtype = "stock" pixname="gtk-help"/>
        <separator/>
        <menuitem name="Item 3" verb="About" label="_About..."
            pixtype = "stock" pixname="gnome-stock-about"/>
    </popup>
    """
    verbs = [('Networks',show_networks), ('Help',show_help), ('About',show_about)]
    applet.setup_menu(xml, verbs, None)

### WHAT HAPPENS WHEN MENU ITEM IS CLICKED
def show_about(*arguments):
    print(arguments)

### THE ASTERIK ALLOWS MULTIPLE ARGUMENTS TO BE PASSED
def show_networks(*arguments):
    print(arguments)

### ALL OF THESE SHOW IN THE DEBUG (-d) OPTION
def show_help(*arguments):
    print(arguments)

### WHERE IT ALL HAPPENS
def applet_factory(applet, iid):
    # CREATE THE XML MENU
    create_menu(applet)
    # CREATE AN IMAGE OBJECT
    im = gtk.Image()
    # SET THE FILE FOR THE IMAGE
    im.set_from_file("/home/zbert/Desktop/testing/py/face2.png")
    # ENABLE TRANSPARENCY
    applet.set_background_widget(applet)
    # CREATE AN EVENT FOR CLICKING THE IMAGE
    applet.connect('button-press-event',button_press)
    # ADD IT ALL TO THE APPLET
    applet.add(im)
    # SHOW IT!
    applet.show_all()
    # DEBUG EVENT
    print('Factory started')
    return True

### CREATE A DIALOG TO POP UP WHEN APPLET IS CLICKED
def test(*arguments):
    print(arguments)
    dia = gtk.Dialog("Message",None,gtk.DIALOG_MODAL)
    lbl = gtk.Label("this is a message")
    dia.vbox.pack_start(lbl)
    lbl.show()
    dia.run()
    dia.connect("destroy",dia.destroy)

### HANDLE THE IMAGE CLICK
def button_press(button, event):
    # LEFT BUTTON ACTIVATES THE CUSTOM MENU
    if event.button == 1:
        print "button 1"
        # CREATE A CUSTOM MENU
        m = gtk.Menu()
        i = gtk.MenuItem("Hello")
        i.show()
        # CONNECT THIS MENU ITEM TO THE DIALOG
        i.connect("activate",test,"Hello")
        m.append(i)
        # FINISH THE POPUP MENU
        m.popup(None, None, None, event.button, event.time, None)
    # RIGHT BUTTON ACTIVATES THE STANDARD MENU
    elif event.button == 2:
        # DEBUG
        print "button 2"

### STANDARD ENTRY
if __name__ == '__main__':
    # DEBUG
    print('Starting factory')
    # RUN THE APPLET AS A GTK WINDOW IN DEBUG (-d) MODE
    if len(sys.argv) > 1 and sys.argv[1] == '-d': #
        mainWindow = gtk.Window()
        mainWindow.set_title('Applet window')
        mainWindow.connect('destroy',gtk.main_quit)
        applet = gnomeapplet.Applet()
        applet_factory(applet, None)
        applet.reparent(mainWindow)
        mainWindow.show_all()
        gtk.main()
        sys.exit()
    # LET GNOME TAKE CARE OF IT AS AN APPLET
    else:
        gnomeapplet.bonobo_factory('OAFIID:SampleApplet_Factory',
            gnomeapplet.Applet.__gtype__,
            'Sample Applet', '0.1',
            applet_factory)

You can see in these pictures how the applet sits like any other in the corner.  A left click will bring up our custom coded menu with one selection, ‘Hello’ which when clicked brings up a GTK Dialog that is made in the button_press() event.  If you right click, you get the standard menu, plus our XML menu which, when in Debug (-d) mode, you will see the arguments sent by a click outputted in your terminal.  As I mentitoned, there are a handful of great resources for this that detail current Python modules with information on setting this up as I did or in a class for bigger projects.  I hope this tutorial has been helpful, and let me know what you think of these lessons with the comments interface!

Update.

So for anyone reading this blog, I am still here, just have not added anything this week.  I’m working and have not been able to update the blog but I will soon have links and information to my linux Cribbage game.  This is near completion and I have written it using pygtk.  It is using card and game modules that I had designed for a text based run of the program and figuring no one would want to use the text based, I’ve switched to a GTK interface, which is obviously, much better.

A quick Python MySQLdb fix…

Okay, so I enjoy writing code in python a lot more than I ever would in php.  So when I came across the MySQLdb module, I was thrilled.  Now I could do anything that php could do and more, in my opinion.  Well, except php’s python comes with all sort of proctections such as mysql_real_escape()… hmm, what to do now.  Well, better come to a solution.  Here’s that solution in all of it’s glory:

#!/usr/bin/env python
## FILENAME: sql.py

def clean(unclean):
	cleaned = ""
	badchrs = "\\\/\"\'"
	temp    = ""
	for ch in unclean:
		temp = ch
		if temp in badchrs:
			temp = "\\" + temp
		cleaned += temp
	return cleaned

As for usage, just place this with your script (most likely in cgi-bin) and import it:

import sql
name    = sql.clean(form.getvalue('name'))

Obviously, there can be more escapes added but for the initial framework, this is the start of a simple fix! for discussion, what vulnerabilities are in this code? What are other ways to extend the MySQLdb module? Please comment…