1 #! /usr/local/bin/python -O
4 ObexFTP VFS for Midnight Commander. Manipulate a cell phone's filesystem using obexftp.
6 Author: Oleg BroytMann <phd@phd.pp.ru>.
7 Copyright (C) 2004 PhiloSoft Design.
10 The script requires Midnight Commander 3.1+ (http://www.ibiblio.org/mc/),
11 Python 2.2+ (http://www.python.org/), OpenOBEX 1.0.1+ (http://openobex.sourceforge.net/)
12 and ObexFTP 0.10.4+ (http://triq.net/obexftp).
14 Edit the full path to the obexftp binary (see below). Put the file to the
15 /usr/[local/]lib/mc/extfs, and add a line "obexftp" to the
16 /usr/[local/]lib/mc/extfs/extfs.ini. Then create somewhere a file called
17 "irda", "bluetooth" or "tty" to connect to the device using IrDA, Bluetooth or
20 For the "bluetooth" put there a line "CP:AD:RE:SS channel", where CP:AD:RE:SS
21 is the hardware address of the device you want to connect to, and channel is
22 the OBEX File Transfer channel; you can discover the address and the channel
23 for your device by using commands like "hcitool scan" and "sdptool browse".
24 Other lines in the file are ignored.
26 Put a device name like /dev/rfcomm0 into the "tty" file.
28 The content for the "irda" file is ignored.
30 Now run this "cd" command in the Midnight Commander (in the "bindings" files
31 the command is "%cd"): cd bluetooth#obexftp. The VFS script use obexftp to try
32 to connect to the device and list files and directories. Plese be warned that
33 opening the VFS for the first time is VERY slow, because the script needs to
34 scan the entire cell phone's filesystem. Often obexftp fails to list a
35 directory, and the script retries after a second or two timeouts, which don't
36 make the scanning process faster. Midnight Commander caches the result.
41 __revision__ = "$Id: obexftp,v 1.2 2004/06/13 18:49:25 phd Exp $"
42 __date__ = "$Date: 2004/06/13 18:49:25 $"[7:-2]
43 __author__ = "Oleg Broytmann <phd@phd.pp.ru>"
44 __copyright__ = "Copyright (C) 2004 PhiloSoft Design"
47 # Change this to suite your needs
48 obexftp_prog = "/usr/local/obex/bin/obexftp"
52 import xml.dom.minidom
55 sys.stderr.write(msg + '\n')
64 It is not a program - it is a VFS for Midnight Commander.
65 Put it in /usr/lib/mc/extfs.""")
68 def setup_transport():
69 """Setup transport parameters for the obexftp program"""
70 transport_filename = sys.argv[2]
71 base_filename = os.path.basename(transport_filename)
73 if base_filename == "bluetooth":
74 transport_file = open(transport_filename, 'r')
75 line = transport_file.readline().strip()
76 transport_file.close()
77 bdaddr, channel = line.split()
78 return ' '.join(["-b", bdaddr, "-B", channel])
79 elif base_filename == "tty":
80 transport_file = open(transport_filename, 'r')
81 device = transport_file.readline().strip()
82 transport_file.close()
83 return ' '.join(["-t", device])
84 elif base_filename == "irda":
87 error("Unknown transport '%s'; expected 'bluetooth', 'tty' or 'irda'" % base_filename)
90 # Parse ObexFTP XML directory listings
92 class DirectoryEntry(object):
93 def __init__(self, type):
97 self.perm = "-rw-rw-rw-"
98 elif type == "folder":
99 self.perm = "drw-rw-rw-"
101 raise ValueError, "unknown type '%s'; expected 'file' or 'folder'" % self.type
104 if not hasattr(self, "modified"): # telecom
105 return "01-01-70 0:0"
106 date, time = self.modified.split('T')
107 year, month, day = date[2:4], date[4:6], date[6:8]
108 hour, minute = time[:2], time[2:4]
109 return "%s-%s-%s %s:%s" % (month, day, year, hour, minute)
110 mtime = property(mtime)
113 if self.type == "file":
114 return """<%s: type=file, name=%s, size=%s, mtime=%s at 0x%x>""" % (
115 self.__class__.__name__, self.name, self.size, self.mtime, id(self)
117 if self.type == "folder":
118 if hasattr(self, "modified"):
119 return """<%s: type=directory, name=%s, mtime=%s at 0x%x>""" % (
120 self.__class__.__name__, self.name, self.mtime, id(self)
123 return """<%s: type=directory, name=%s at 0x%x>""" % (
124 self.__class__.__name__, self.name, id(self)
126 raise ValueError, "unknown type '%s'; expected 'file' or 'folder'" % self.type
128 def get_entries(dom, tag):
130 for subtag in dom.getElementsByTagName(tag):
131 entry = DirectoryEntry(tag)
132 attrs = subtag.attributes
133 for i in range(attrs.length):
135 setattr(entry, attr.name, attr.value)
136 entries.append(entry)
140 def _recursive_list(obexftp_args, directory):
141 """List the directory recursively"""
142 debug = open("debug", 'a')
145 pipe = os.popen("%s %s -l '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, directory), 'r')
146 listing = pipe.read()
152 debug.write("Cannot list '%s', retrying...\n" % directory)
155 debug.write("Cannot list '%s'\n" % directory)
159 debug.write("Got listing of '%s'\n" % directory)
162 dom = xml.dom.minidom.parseString(listing)
164 obex_xml = open("obex.xml", 'a')
165 obex_xml.write(listing)
169 directories = get_entries(dom, "folder")
170 files = get_entries(dom, "file")
172 for entry in directories + files:
173 fullpath = "%s/%s" % (directory, entry.name)
174 if fullpath.startswith('//'): fullpath = fullpath[1:]
175 print entry.perm, "1 user group", entry.size, entry.mtime, fullpath
178 for entry in directories:
179 fullpath = "%s/%s" % (directory, entry.name)
180 if fullpath.startswith('//'): fullpath = fullpath[1:]
181 _recursive_list(obexftp_args, fullpath)
184 """List the entire VFS"""
185 obexftp_args = setup_transport()
186 _recursive_list(obexftp_args, '/')
189 def mcobex_copyout():
190 """Get a file from the VFS"""
191 obexftp_args = setup_transport()
192 dummy_filename = sys.argv[3]
193 real_filename = sys.argv[4]
195 real_file = open(real_filename, 'w')
196 real_file.write("Copied from %s\n" % dummy_filename)
197 real_file.write("Copied to %s\n" % real_filename)
202 """Put a file to the VFS"""
203 obexftp_args = setup_transport()
204 dummy_filename = sys.argv[3]
205 real_filename = sys.argv[4]
207 real_file = open(real_filename + "-dummy.tmp", 'w')
208 real_file.write("Copied from %s\n" % real_filename)
209 real_file.write("Copied to %s\n" % dummy_filename)
214 """Remove a file from the VFS"""
215 obexftp_args = setup_transport()
216 dummy_filename = sys.argv[3]
218 real_file = open(".dummy.tmp", 'a')
219 real_file.write("Remove %s\n" % dummy_filename)
224 """Create a directory in the VFS"""
225 obexftp_args = setup_transport()
226 dummy_dirname = sys.argv[3]
228 real_file = open(".dummy.tmp", 'a')
229 real_file.write("Create %s\n" % dummy_dirname)
234 """Remove a directory from the VFS"""
235 obexftp_args = setup_transport()
236 dummy_dirname = sys.argv[3]
238 real_file = open(".dummy.tmp", 'a')
239 real_file.write("Remove %s\n" % dummy_dirname)
244 command = sys.argv[1]
245 procname = "mcobex_" + command
247 if not g.has_key(procname):
248 error("Unknown command %s" % command)
254 error = open("error", 'a')
255 traceback.print_exc(file=error)