#! /usr/local/bin/python -O """ ObexFTP VFS for Midnight Commander. Manipulate a cell phone's filesystem using obexftp. Author: Oleg BroytMann . Copyright (C) 2004 PhiloSoft Design. License: GPL. The script requires Midnight Commander 3.1+ (http://www.ibiblio.org/mc/), Python 2.2+ (http://www.python.org/), OpenOBEX 1.0.1+ (http://openobex.sourceforge.net/) and ObexFTP 0.10.4+ (http://triq.net/obexftp). Edit the full path to the obexftp binary (see below). Put the file to the /usr/[local/]lib/mc/extfs, and add a line "obexftp" to the /usr/[local/]lib/mc/extfs/extfs.ini. Then create somewhere a transport file. The transport file can have any name, and is expected to be a text file with at least one line defining the transport to your device. Other lines in the file are ignored. First word in the line is a transport name - Bluetooth, IrDA or TTY. The name is case-insensitive. For the Bluetooth transport put there a line "Bluetooth CP:AD:RE:SS channel", where CP:AD:RE:SS is the hardware address of the device you want to connect to, and channel is the OBEX File Transfer channel; you can discover the address and the channel for your device by using commands like "hcitool scan" and "sdptool browse". For the TTY put a device name: "tty /dev/rfcomm0". The content with the IrDA just put "IrDA" in the file. Now run this "cd" command in the Midnight Commander (in the "bindings" files the command is "%cd"): cd description#obexftp. The VFS script uses obexftp to connect to the device and list files and directories. Plese be warned that opening the VFS for the first time is VERY slow, because the script needs to scan the entire cell phone's filesystem. And there must be a timeout between connections, which doesn't make the scanning process faster. Midnight Commander caches the result, so you can browse directories quickly. """ __version__ = "0.5.0" __revision__ = "$Id: obexftp,v 1.6 2004/06/13 21:48:59 phd Exp $" __date__ = "$Date: 2004/06/13 21:48:59 $"[7:-2] __author__ = "Oleg Broytmann " __copyright__ = "Copyright (C) 2004 PhiloSoft Design" # Change this to suite your needs obexftp_prog = "/usr/local/obex/bin/obexftp" import sys, time import os, shutil import xml.dom.minidom from tempfile import mkdtemp def log_error(msg): sys.stderr.write(msg + '\n') def error(msg): log_error(msg + '\n') sys.exit(1) if len(sys.argv) < 2: error("""\ It is not a program - it is a VFS for Midnight Commander. Put it in /usr/lib/mc/extfs.""") def setup_transport(): """Setup transport parameters for the obexftp program""" transport_file = open(sys.argv[2], 'r') line = transport_file.readline().strip() transport_file.close() parts = line.split() transport = parts[0].lower() if transport == "bluetooth": return ' '.join(["-b", parts[1], "-B", parts[2]]) elif transport == "tty": return ' '.join(["-t", parts[1]]) elif transport == "irda": return "-i" else: error("Unknown transport '%s'; expected 'bluetooth', 'tty' or 'irda'" % base_filename) # Parse ObexFTP XML directory listings class DirectoryEntry(object): def __init__(self, type): self.type = type self.size = 0 if type == "file": self.perm = "-rw-rw-rw-" elif type == "folder": self.perm = "drwxrwxrwx" else: raise ValueError, "unknown type '%s'; expected 'file' or 'folder'" % self.type def mtime(self): if not hasattr(self, "modified"): # telecom return "01-01-70 0:0" date, time = self.modified.split('T') year, month, day = date[2:4], date[4:6], date[6:8] hour, minute = time[:2], time[2:4] return "%s-%s-%s %s:%s" % (month, day, year, hour, minute) mtime = property(mtime) def __repr__(self): if self.type == "file": return """<%s: type=file, name=%s, size=%s, mtime=%s at 0x%x>""" % ( self.__class__.__name__, self.name, self.size, self.mtime, id(self) ) if self.type == "folder": if hasattr(self, "modified"): return """<%s: type=directory, name=%s, mtime=%s at 0x%x>""" % ( self.__class__.__name__, self.name, self.mtime, id(self) ) else: # telecom return """<%s: type=directory, name=%s at 0x%x>""" % ( self.__class__.__name__, self.name, id(self) ) raise ValueError, "unknown type '%s'; expected 'file' or 'folder'" % self.type def get_entries(dom, tag): entries = [] for subtag in dom.getElementsByTagName(tag): entry = DirectoryEntry(tag) attrs = subtag.attributes for i in range(attrs.length): attr = attrs.item(i) setattr(entry, attr.name, attr.value) entries.append(entry) return entries def recursive_list(obexftp_args, directory): """List the directory recursively""" pipe = os.popen("%s %s -l '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, directory), 'r') listing = pipe.read() pipe.close() if not listing: return dom = xml.dom.minidom.parseString(listing) directories = get_entries(dom, "folder") files = get_entries(dom, "file") for entry in directories + files: fullpath = "%s/%s" % (directory, entry.name) if fullpath.startswith('//'): fullpath = fullpath[1:] print entry.perm, "1 user group", entry.size, entry.mtime, fullpath for entry in directories: fullpath = "%s/%s" % (directory, entry.name) if fullpath.startswith('//'): fullpath = fullpath[1:] time.sleep(1) recursive_list(obexftp_args, fullpath) def mcobex_list(): """List the entire VFS""" obexftp_args = setup_transport() recursive_list(obexftp_args, '/') # A unique directory for temporary files tmpdir_name = None def setup_tmpdir(): global tmpdir_name tmpdir_name = mkdtemp(".tmp", "mcobex-") os.chdir(tmpdir_name) def cleanup_tmpdir(): os.chdir(os.pardir) shutil.rmtree(tmpdir_name) def mcobex_copyout(): """Get a file from the VFS""" obexftp_args = setup_transport() obex_filename = sys.argv[3] real_filename = sys.argv[4] setup_tmpdir() os.system("%s %s -g '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, obex_filename)) try: os.rename(os.path.basename(obex_filename), real_filename) except OSError: pass cleanup_tmpdir() def mcobex_copyin(): """Put a file to the VFS""" obexftp_args = setup_transport() obex_filename = sys.argv[3] real_filename = sys.argv[4] dirname, filename = os.path.split(obex_filename) setup_tmpdir() os.rename(real_filename, filename) os.system("%s %s -c '%s' -p '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, dirname, filename )) os.rename(filename, real_filename) # by some reason MC wants the file back cleanup_tmpdir() def mcobex_rm(): """Remove a file from the VFS""" obexftp_args = setup_transport() obex_filename = sys.argv[3] setup_tmpdir() os.system("%s %s -k '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, obex_filename)) cleanup_tmpdir() def mcobex_mkdir(): """Create a directory in the VFS""" obexftp_args = setup_transport() obex_dirname = sys.argv[3] setup_tmpdir() os.system("%s %s -C '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, obex_dirname)) cleanup_tmpdir() mcobex_rmdir = mcobex_rm g = globals() command = sys.argv[1] procname = "mcobex_" + command if not g.has_key(procname): error("Unknown command %s" % command) g[procname]()