]> git.phdru.name Git - extfs.d.git/blob - obexftp
Version 0.4.0. rm, mkdir, rmdir. A lot of bugfixes in copy-in/out.
[extfs.d.git] / obexftp
1 #! /usr/local/bin/python -O
2
3 """
4 ObexFTP VFS for Midnight Commander. Manipulate a cell phone's filesystem using obexftp.
5
6 Author: Oleg BroytMann <phd@phd.pp.ru>.
7 Copyright (C) 2004 PhiloSoft Design.
8 License: GPL.
9
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).
13
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
18 TTY transport.
19
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.
25
26 Put a device name like /dev/rfcomm0 into the "tty" file.
27
28 The content for the "irda" file is ignored.
29
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
36 caches the result.
37
38 """
39
40 __version__ = "0.4.0"
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"
45
46
47 # Change this to suite your needs
48 obexftp_prog = "/usr/local/obex/bin/obexftp"
49
50
51 import sys, time
52 import os, shutil
53 import xml.dom.minidom
54 from tempfile import mkdtemp
55
56
57 def log_error(msg):
58    sys.stderr.write(msg + '\n')
59
60 def error(msg):
61    log_error(msg + '\n')
62    sys.exit(1)
63
64
65 if len(sys.argv) < 2:
66    error("""\
67 It is not a program - it is a VFS for Midnight Commander.
68 Put it in /usr/lib/mc/extfs.""")
69
70
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)
75
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":
88       return "-i"
89    else:
90       error("Unknown transport '%s'; expected 'bluetooth', 'tty' or 'irda'" % base_filename)
91
92
93 # Parse ObexFTP XML directory listings
94
95 class DirectoryEntry(object):
96    def __init__(self, type):
97       self.type = type
98       self.size = 0
99       if type == "file":
100          self.perm = "-rw-rw-rw-"
101       elif type == "folder":
102          self.perm = "drwxrwxrwx"
103       else:
104          raise ValueError, "unknown type '%s'; expected 'file' or 'folder'" % self.type
105
106    def mtime(self):
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)
114
115    def __repr__(self):
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)
119          )
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)
124             )
125          else: # telecom
126             return """<%s: type=directory, name=%s at 0x%x>""" % (
127                self.__class__.__name__, self.name, id(self)
128             )
129       raise ValueError, "unknown type '%s'; expected 'file' or 'folder'" % self.type
130
131 def get_entries(dom, tag):
132    entries = []
133    for subtag in dom.getElementsByTagName(tag):
134       entry = DirectoryEntry(tag)
135       attrs = subtag.attributes
136       for i in range(attrs.length):
137          attr = attrs.item(i)
138          setattr(entry, attr.name, attr.value)
139       entries.append(entry)
140    return entries
141
142
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()
147    pipe.close()
148
149    debug = open("debug", 'a')
150    if not listing:
151       debug.write("Cannot list '%s'\n" % directory)
152       debug.close()
153       return
154
155    debug.write("Got listing of '%s'\n" % directory)
156
157    try:
158       dom = xml.dom.minidom.parseString(listing)
159    except:
160       obex_xml = open("obex.xml", 'a')
161       obex_xml.write(listing)
162       obex_xml.close()
163       raise
164
165    directories = get_entries(dom, "folder")
166    files = get_entries(dom, "file")
167
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
172    debug.close()
173
174    for entry in directories:
175       fullpath = "%s/%s" % (directory, entry.name)
176       if fullpath.startswith('//'): fullpath = fullpath[1:]
177       time.sleep(1)
178       recursive_list(obexftp_args, fullpath)
179
180 def mcobex_list():
181    """List the entire VFS"""
182    obexftp_args = setup_transport()
183    recursive_list(obexftp_args, '/')
184
185
186 # A unique directory for temporary files
187
188 tmpdir_name = None
189
190 def setup_tmpdir():
191    global tmpdir_name
192    tmpdir_name = mkdtemp(".tmp", "mcobex-")
193    os.chdir(tmpdir_name)
194
195 def cleanup_tmpdir():
196    os.chdir(os.pardir)
197    shutil.rmtree(tmpdir_name)
198
199
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]
205
206    setup_tmpdir()
207    os.system("%s %s -g '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, obex_filename))
208    try:
209       os.rename(os.path.basename(obex_filename), real_filename)
210    except OSError:
211       pass
212    cleanup_tmpdir()
213
214
215 def mcobex_copyin():
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)
221
222    setup_tmpdir()
223    os.rename(real_filename, filename)
224    os.system("%s %s -c '%s' -p '%s' 2>/dev/null" % (obexftp_prog, obexftp_args,
225       dirname, filename
226    ))
227    os.rename(filename, real_filename) # by some reason MC wants the file back
228    cleanup_tmpdir()
229
230
231 def mcobex_rm():
232    """Remove a file from the VFS"""
233    obexftp_args = setup_transport()
234    obex_filename = sys.argv[3]
235
236    setup_tmpdir()
237    os.system("%s %s -k '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, obex_filename))
238    cleanup_tmpdir()
239
240
241 def mcobex_mkdir():
242    """Create a directory in the VFS"""
243    obexftp_args = setup_transport()
244    obex_dirname = sys.argv[3]
245
246    setup_tmpdir()
247    os.system("%s %s -C '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, obex_dirname))
248    cleanup_tmpdir()
249
250
251 mcobex_rmdir = mcobex_rm
252
253
254 g = globals()
255 command = sys.argv[1]
256 procname = "mcobex_" + command
257
258 if not g.has_key(procname):
259    error("Unknown command %s" % command)
260
261 try:
262    g[procname]()
263 except:
264    import traceback
265    error = open("error", 'a')
266    traceback.print_exc(file=error)
267    error.close()
268    sys.exit(1)