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. And there must be a timeout between
35 connections, which doesn't make the scanning process faster. Midnight Commander
41 __revision__ = "$Id: obexftp,v 1.5 2004/06/13 21:31:52 phd Exp $"
42 __date__ = "$Date: 2004/06/13 21:31: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 = "drwxrwxrwx"
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 pipe = os.popen("%s %s -l '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, directory), 'r')
146 listing = pipe.read()
149 debug = open("debug", 'a')
151 debug.write("Cannot list '%s'\n" % directory)
155 debug.write("Got listing of '%s'\n" % directory)
158 dom = xml.dom.minidom.parseString(listing)
160 obex_xml = open("obex.xml", 'a')
161 obex_xml.write(listing)
165 directories = get_entries(dom, "folder")
166 files = get_entries(dom, "file")
168 for entry in directories + files:
169 fullpath = "%s/%s" % (directory, entry.name)
170 if fullpath.startswith('//'): fullpath = fullpath[1:]
171 print entry.perm, "1 user group", entry.size, entry.mtime, fullpath
174 for entry in directories:
175 fullpath = "%s/%s" % (directory, entry.name)
176 if fullpath.startswith('//'): fullpath = fullpath[1:]
178 recursive_list(obexftp_args, fullpath)
181 """List the entire VFS"""
182 obexftp_args = setup_transport()
183 recursive_list(obexftp_args, '/')
186 # A unique directory for temporary files
192 tmpdir_name = mkdtemp(".tmp", "mcobex-")
193 os.chdir(tmpdir_name)
195 def cleanup_tmpdir():
197 shutil.rmtree(tmpdir_name)
200 def mcobex_copyout():
201 """Get a file from the VFS"""
202 obexftp_args = setup_transport()
203 obex_filename = sys.argv[3]
204 real_filename = sys.argv[4]
207 os.system("%s %s -g '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, obex_filename))
209 os.rename(os.path.basename(obex_filename), real_filename)
216 """Put a file to the VFS"""
217 obexftp_args = setup_transport()
218 obex_filename = sys.argv[3]
219 real_filename = sys.argv[4]
220 dirname, filename = os.path.split(obex_filename)
223 os.rename(real_filename, filename)
224 os.system("%s %s -c '%s' -p '%s' 2>/dev/null" % (obexftp_prog, obexftp_args,
227 os.rename(filename, real_filename) # by some reason MC wants the file back
232 """Remove a file from the VFS"""
233 obexftp_args = setup_transport()
234 obex_filename = sys.argv[3]
237 os.system("%s %s -k '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, obex_filename))
242 """Create a directory in the VFS"""
243 obexftp_args = setup_transport()
244 obex_dirname = sys.argv[3]
247 os.system("%s %s -C '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, obex_dirname))
251 mcobex_rmdir = mcobex_rm
255 command = sys.argv[1]
256 procname = "mcobex_" + command
258 if not g.has_key(procname):
259 error("Unknown command %s" % command)
265 error = open("error", 'a')
266 traceback.print_exc(file=error)