weblink: easy file sharing

Weblink sets up a small Web server on your computer to make some of your files available as downloadable web links.

First things first

Check that you have python installed, download weblink, and type:

chmod +x ./weblink

Basic usage

To share /home/pierre/lolcat.jpg, type:

./weblink /home/pierre/lolcat.jpg

The file is accessible to you through http://localhost:8888/. On the internet, the file is downloadable at http://n.n.n.n:8888/ where n.n.n.n is your computer IP address. The link is valid until weblink is stopped.

Important: If you have a firewall, you must open port 8888. If you have a NAT router, you must configure it to forward port 8888 to your computer.

Weblink screenshot

Share several files

You can share several files by passing them on the command-line or by using wildcards:

./weblink lolcat1.jpg lolcat2.jpg xkcd*.png 

Password protection

To protect access to your files, you may specify a pseudo-password with the --pass option. For example, type:

./weblink --pass abcdef lolcat.jpg

and lolcat.jpg will be available at:

http://n.n.n.n:8888/abcdef/

If you can’t think of a password, use the --randompass option instead.

./weblink --randompass lolcat.jpg

Port number
You can run weblink on a different port with the -p option:

./weblink -p 7777 lolcat.jpg

Kudos to the python developers for making writing weblink so easy!

[download weblink]

pygtk + pynotify: notification from statusicon

Code snippet that displays a libnotify bubble coming from a GTK statusicon. The bubble appears when you click the icon.

Screenshot of the notification bubble coming from statusicon

[download statusicon-notification.py]

#!/usr/bin/env python
 
import gtk
import pynotify
 
def callback(icon):
    notification.show()
 
pynotify.init("Some Application or Title")
notification = pynotify.Notification("Title", "body", "dialog-warning")
notification.set_urgency(pynotify.URGENCY_NORMAL)
notification.set_timeout(pynotify.EXPIRES_NEVER)
 
icon = gtk.status_icon_new_from_stock(gtk.STOCK_ABOUT)
icon.connect('activate', callback)
notification.attach_to_status_icon(icon)
 
gtk.main()

Cross-platform configuration file handler

This is a python class to manage a configuration file, regardless of the operating system. Configuration is a set of (key, value) that can be set and retrieved by using SimpleConfig as a dictionary. Keys and values must all be strings. Example usage:

conf = SimpleConfig('myapp')   # Load configuration file if it exists
conf['foo'] = '3'              # Set a value
conf.save()                    # Save the configuration file on disk
conf.delete()                  # Delete file, it was just an example

SimpleConfig builds the configuration file path using the operating system name and the application name:

  • Unix: $HOME/.appname
  • Mac: $HOME/Library/Application Support/appname
  • Windows: $HOMEPATH\Application Data\appname

Tested on Linux and Windows XP so far.

[download SimpleConfig.py]

import os
import stat
from ConfigParser import SafeConfigParser
from UserDict import IterableUserDict
 
__all__ = ['SimpleConfig', 'UnsupportedOSError']
 
class UnsupportedOSError(Exception): pass
 
class SimpleConfig(IterableUserDict):
    """Cross-platform configuration file handler.
 
    This is a class to manage a configuration file, regardless of the
    operating system. Configuration is a set of (key, value) that can
    be set and retrieved by using SimpleConfig as a dictionary. Keys
    and values must all be strings. Example usage::
 
    >>> conf = SimpleConfig('myapp')   # Load configuration file if it exists
    >>> conf['foo'] = '3'              # Set a value
    >>> conf.save()                    # Save the configuration file on disk
    >>> conf.delete()                  # Delete file, it was just an example
 
    SimpleConfig builds the configuration file path using the
    operating system name and the application name:
 
    * Unix: $HOME/.appname
    * Mac: $HOME/Library/Application Support/appname
    * Windows: $HOMEPATH\Application Data\\appname
 
    Tested on Linux and Windows XP so far. 
 
    """
 
    section = 'main'
 
    def __init__(self, appname):
        """Open the configuration file and fill the dictionary.
 
        ``appname`` is the application identifier, it is used to build
        the configuration file path.  If the file does not exist, the
        dictionary is left empty.
        """
        IterableUserDict.__init__(self)
        self.filename = self._filename(appname)
        self.parser = SafeConfigParser()
        self.parser.read(self.filename)
        if not self.parser.has_section(self.section):
            self.parser.add_section(self.section)
        for name, value in self.parser.items(self.section):
            self.data[name] = value
 
 
    def save(self):
        """Save the configuration file on disk."""
        for name, value in self.data.items():
            self.parser.set(self.section, str(name), str(value))
        f = open(self.filename, 'w')
        self.parser.write(f)
        f.close()
 
 
    def delete(self):
        """Delete the configuration file."""
        os.chmod(self.filename, stat.S_IWRITE)
        os.remove(self.filename)
 
 
    def _filename(self, appname):
        # os.name is 'posix', 'nt', 'os2', 'mac', 'ce' or 'riscos'
        if os.name == 'posix':
            filename = "%s/.%s" % (os.environ["HOME"], appname)
 
        elif os.name == 'mac':
            filename = ("%s/Library/Application Support/%s" %
                        (os.environ["HOME"], appname))
 
        elif os.name == 'nt':
            filename = ("%s\Application Data\%s" %
                        (os.environ["HOMEPATH"], appname))
        else:
            raise UnsupportedOSError(os.name)
 
        return filename
 
 
if __name__ == "__main__":
 
    def test():
        conf = SimpleConfig("myapp")
        filename = conf.filename
        port = "3000"
        message = "Hello World!"
        conf["port"] = port
        conf["message"] = message
        conf.save()
 
        conf = SimpleConfig("myapp")
        assert conf["port"] == port
        assert conf["message"] == message
        conf.delete()
        assert not os.path.exists(filename)
 
    test()

Python Avahi Object

A simple class to publish a network service via zeroconf with avahi. Requires python-avahi and python-dbus. All calls to the avahi and dbus libraries are wrapped by the class.

Example usage :

from ZeroconfService import ZeroconfService
import time
 
service = ZeroconfService(name="Joe's awesome FTP server",
                          port=3000,  stype="_ftp._tcp")
service.publish()
time.sleep(10)
service.unpublish()

[download ZeroconfService.py]

import avahi
import dbus
 
__all__ = ["ZeroconfService"]
 
class ZeroconfService:
    """A simple class to publish a network service with zeroconf using
    avahi.
 
    """
 
    def __init__(self, name, port, stype="_http._tcp",
                 domain="", host="", text=""):
        self.name = name
        self.stype = stype
        self.domain = domain
        self.host = host
        self.port = port
        self.text = text
 
    def publish(self):
        bus = dbus.SystemBus()
        server = dbus.Interface(
                         bus.get_object(
                                 avahi.DBUS_NAME,
                                 avahi.DBUS_PATH_SERVER),
                        avahi.DBUS_INTERFACE_SERVER)
 
        g = dbus.Interface(
                    bus.get_object(avahi.DBUS_NAME,
                                   server.EntryGroupNew()),
                    avahi.DBUS_INTERFACE_ENTRY_GROUP)
 
        g.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC,dbus.UInt32(0),
                     self.name, self.stype, self.domain, self.host,
                     dbus.UInt16(self.port), self.text)
 
        g.Commit()
        self.group = g
 
    def unpublish(self):
        self.group.Reset()
 
 
def test():
    service = ZeroconfService(name="TestService", port=3000)
    service.publish()
    raw_input("Press any key to unpublish the service ")
    service.unpublish()
 
 
if __name__ == "__main__":
    test()

Droopy: easy file receiving

What is it ?
Droopy is a mini Web server whose sole purpose is to let others upload files to your computer.

Droopy in the browser.

Why ?
Say you’re chatting with a friend on MSN Messenger (perhaps with the excellent pidgin ?). She wants to send you amazing photos she took last week-end, so she uses Messenger file transfer. Unfortunately, the zip file is over 50 MB and it’s painfully slow. Now relax, droopy comes to rescue.

Does it work on my computer ?
You can use it on Unix (Linux, BSD, MacOSX) and Windows. Droopy is a python script so you’ll need to have Python installed.

How to use it ?

Note: A tutorial on how to set up Droopy on Windows was very kindly written by Ronan. The rest of this section focuses on Linux and MacOSX.

Droopy is a command-line program. I’ll suppose you’ve downloaded and saved the file in ~/bin/. Go to the directory where you want the uploaded files to be stored, for example:

mkdir ~/uploads
cd ~/uploads 

Then, run droopy. You can give a message and a picture to display:

python ~/bin/droopy -m "Hi, it's me Bob. You can send me a file." -p ~/avatar.png

And it’s up and running on port 8000 of you computer. Check it out at http://localhost:8000, and give your computer’s address to your friends.

Droopy in the terminal.

Type droopy -h to see all options:

Usage: droopy [options] [PORT]

Options:
  -h, --help                            show this help message and exit
  -d DIRECTORY, --directory DIRECTORY   set the directory to upload files to
  -m MESSAGE, --message MESSAGE         set the message
  -p PICTURE, --picture PICTURE         set the picture
  --dl                                  provide download links
  --save-config                         save options in a configuration file
  --delete-config                       delete the configuration file and exit

License
Droopy is a free software distributed under the BSD License. There’s a git repository at http://gitorious.org/droopy. New releases are announced on Freshmeat.

Feedback and contribution
I’d love to hear about your experience using droopy. If you have ideas to improve it, please let me know. Pierre – stackp@online.fr.

[download droopy]