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.3 2004/06/13 19:41:52 phd Exp $"
42 __date__ = "$Date: 2004/06/13 19:41:52 $"[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"
53 import xml.dom.minidom
54 from tempfile import mkdtemp
58 sys.stderr.write(msg + '\n')
67 It is not a program - it is a VFS for Midnight Commander.
68 Put it in /usr/lib/mc/extfs.""")
71 def setup_transport():
72 """Setup transport parameters for the obexftp program"""
73 transport_filename = sys.argv[2]
74 base_filename = os.path.basename(transport_filename)
76 if base_filename == "bluetooth":
77 transport_file = open(transport_filename, 'r')
78 line = transport_file.readline().strip()
79 transport_file.close()
80 bdaddr, channel = line.split()
81 return ' '.join(["-b", bdaddr, "-B", channel])
82 elif base_filename == "tty":
83 transport_file = open(transport_filename, 'r')
84 device = transport_file.readline().strip()
85 transport_file.close()
86 return ' '.join(["-t", device])
87 elif base_filename == "irda":
90 error("Unknown transport '%s'; expected 'bluetooth', 'tty' or 'irda'" % base_filename)
93 # Parse ObexFTP XML directory listings
95 class DirectoryEntry(object):
96 def __init__(self, type):
100 self.perm = "-rw-rw-rw-"
101 elif type == "folder":
102 self.perm = "drw-rw-rw-"
104 raise ValueError, "unknown type '%s'; expected 'file' or 'folder'" % self.type
107 if not hasattr(self, "modified"): # telecom
108 return "01-01-70 0:0"
109 date, time = self.modified.split('T')
110 year, month, day = date[2:4], date[4:6], date[6:8]
111 hour, minute = time[:2], time[2:4]
112 return "%s-%s-%s %s:%s" % (month, day, year, hour, minute)
113 mtime = property(mtime)
116 if self.type == "file":
117 return """<%s: type=file, name=%s, size=%s, mtime=%s at 0x%x>""" % (
118 self.__class__.__name__, self.name, self.size, self.mtime, id(self)
120 if self.type == "folder":
121 if hasattr(self, "modified"):
122 return """<%s: type=directory, name=%s, mtime=%s at 0x%x>""" % (
123 self.__class__.__name__, self.name, self.mtime, id(self)
126 return """<%s: type=directory, name=%s at 0x%x>""" % (
127 self.__class__.__name__, self.name, id(self)
129 raise ValueError, "unknown type '%s'; expected 'file' or 'folder'" % self.type
131 def get_entries(dom, tag):
133 for subtag in dom.getElementsByTagName(tag):
134 entry = DirectoryEntry(tag)
135 attrs = subtag.attributes
136 for i in range(attrs.length):
138 setattr(entry, attr.name, attr.value)
139 entries.append(entry)
143 def recursive_list(obexftp_args, directory):
144 """List the directory recursively"""
145 debug = open("debug", 'a')
148 pipe = os.popen("%s %s -l '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, directory), 'r')
149 listing = pipe.read()
155 debug.write("Cannot list '%s', retrying...\n" % directory)
158 debug.write("Cannot list '%s'\n" % directory)
162 debug.write("Got listing of '%s'\n" % directory)
165 dom = xml.dom.minidom.parseString(listing)
167 obex_xml = open("obex.xml", 'a')
168 obex_xml.write(listing)
172 directories = get_entries(dom, "folder")
173 files = get_entries(dom, "file")
175 for entry in directories + files:
176 fullpath = "%s/%s" % (directory, entry.name)
177 if fullpath.startswith('//'): fullpath = fullpath[1:]
178 print entry.perm, "1 user group", entry.size, entry.mtime, fullpath
181 for entry in directories:
182 fullpath = "%s/%s" % (directory, entry.name)
183 if fullpath.startswith('//'): fullpath = fullpath[1:]
184 recursive_list(obexftp_args, fullpath)
187 """List the entire VFS"""
188 obexftp_args = setup_transport()
189 recursive_list(obexftp_args, '/')
192 # A unique directory for temporary files
198 tmpdir_name = mkdtemp(".tmp", "mcobex-")
199 os.chdir(tmpdir_name)
201 def cleanup_tmpdir():
203 shutil.rmtree(tmpdir_name)
206 def mcobex_copyout():
207 """Get a file from the VFS"""
208 obexftp_args = setup_transport()
209 dummy_filename = sys.argv[3]
210 real_filename = sys.argv[4]
213 os.system("%s %s -g '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, dummy_filename))
214 os.rename(os.path.basename(dummy_filename), real_filename)
219 """Put a file to the VFS"""
220 obexftp_args = setup_transport()
221 dummy_filename = sys.argv[3]
222 real_filename = sys.argv[4]
224 real_file = open(real_filename + "-dummy.tmp", 'w')
225 real_file.write("Copied from %s\n" % real_filename)
226 real_file.write("Copied to %s\n" % dummy_filename)
231 """Remove a file from the VFS"""
232 obexftp_args = setup_transport()
233 dummy_filename = sys.argv[3]
235 real_file = open(".dummy.tmp", 'a')
236 real_file.write("Remove %s\n" % dummy_filename)
241 """Create a directory in the VFS"""
242 obexftp_args = setup_transport()
243 dummy_dirname = sys.argv[3]
245 real_file = open(".dummy.tmp", 'a')
246 real_file.write("Create %s\n" % dummy_dirname)
251 """Remove a directory from the VFS"""
252 obexftp_args = setup_transport()
253 dummy_dirname = sys.argv[3]
255 real_file = open(".dummy.tmp", 'a')
256 real_file.write("Remove %s\n" % dummy_dirname)
261 command = sys.argv[1]
262 procname = "mcobex_" + command
264 if not g.has_key(procname):
265 error("Unknown command %s" % command)
271 error = open("error", 'a')
272 traceback.print_exc(file=error)