]> git.phdru.name Git - extfs.d.git/blob - obexftp
Version 0.5.1. More comments. Do not need a temp dir for rm and mkdir.
[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 transport file.
17
18 The transport file can have any name, and is expected to be a text file with at
19 least one line defining the transport to your device. Other lines in the file
20 are ignored.
21
22 First word in the line is a transport name - Bluetooth, IrDA or TTY. The name
23 is case-insensitive.
24
25 For the Bluetooth transport put there a line "Bluetooth CP:AD:RE:SS channel",
26 where CP:AD:RE:SS is the hardware address of the device you want to connect to,
27 and channel is the OBEX File Transfer channel; you can discover the address and
28 the channel for your device by using commands like "hcitool scan" and "sdptool
29 browse".
30
31 For the TTY put a device name: "tty /dev/rfcomm0".
32
33 The content with the IrDA just put "IrDA" in the file.
34
35 Now run this "cd" command in the Midnight Commander (in the "bindings" files
36 the command is "%cd"): cd description#obexftp. The VFS script uses obexftp to
37 connect to the device and list files and directories. Plese be warned that
38 opening the VFS for the first time is VERY slow, because the script needs to
39 scan the entire cell phone's filesystem. And there must be a timeout between
40 connections, which doesn't make the scanning process faster. Midnight Commander
41 caches the result, so you can browse directories quickly.
42
43 """
44
45 __version__ = "0.5.1"
46 __revision__ = "$Id: obexftp,v 1.7 2004/06/13 22:04:56 phd Exp $"
47 __date__ = "$Date: 2004/06/13 22:04:56 $"[7:-2]
48 __author__ = "Oleg Broytmann <phd@phd.pp.ru>"
49 __copyright__ = "Copyright (C) 2004 PhiloSoft Design"
50
51
52 # Change this to suite your needs
53 obexftp_prog = "/usr/local/obex/bin/obexftp"
54
55
56 import sys, time
57 import os, shutil
58 import xml.dom.minidom
59 from tempfile import mkdtemp
60
61
62 def log_error(msg):
63    sys.stderr.write(msg + '\n')
64
65 def error(msg):
66    log_error(msg)
67    sys.exit(1)
68
69
70 if len(sys.argv) < 2:
71    error("""\
72 It is not a program - it is a VFS for Midnight Commander.
73 Put it in /usr/lib/mc/extfs. For more information read the source!""")
74
75
76 def setup_transport():
77    """Setup transport parameters for the obexftp program"""
78    transport_file = open(sys.argv[2], 'r')
79    line = transport_file.readline().strip()
80    transport_file.close()
81
82    parts = line.split()
83    transport = parts[0].lower()
84
85    if transport == "bluetooth":
86       return ' '.join(["-b", parts[1], "-B", parts[2]])
87    elif transport == "tty":
88       return ' '.join(["-t", parts[1]])
89    elif transport == "irda":
90       return "-i"
91    else:
92       error("Unknown transport '%s'; expected 'bluetooth', 'tty' or 'irda'" % base_filename)
93
94
95 # Parse ObexFTP XML directory listings
96
97 class DirectoryEntry(object):
98    """Represent remote files and directories"""
99
100    def __init__(self, type):
101       self.type = type
102       self.size = 0
103       if type == "file":
104          self.perm = "-rw-rw-rw-"
105       elif type == "folder":
106          self.perm = "drwxrwxrwx"
107       else:
108          raise ValueError, "unknown type '%s'; expected 'file' or 'folder'" % self.type
109
110    def mtime(self):
111       if not hasattr(self, "modified"): # telecom
112          return "01-01-70 0:0"
113       date, time = self.modified.split('T')
114       year, month, day = date[2:4], date[4:6], date[6:8]
115       hour, minute = time[:2], time[2:4]
116       return "%s-%s-%s %s:%s" % (month, day, year, hour, minute)
117    mtime = property(mtime)
118
119    def __repr__(self):
120       if self.type == "file":
121          return """<%s: type=file, name=%s, size=%s, mtime=%s at 0x%x>""" % (
122             self.__class__.__name__, self.name, self.size, self.mtime, id(self)
123          )
124       if self.type == "folder":
125          if hasattr(self, "modified"):
126             return """<%s: type=directory, name=%s, mtime=%s at 0x%x>""" % (
127                self.__class__.__name__, self.name, self.mtime, id(self)
128             )
129          else: # telecom
130             return """<%s: type=directory, name=%s at 0x%x>""" % (
131                self.__class__.__name__, self.name, id(self)
132             )
133       raise ValueError, "unknown type '%s'; expected 'file' or 'folder'" % self.type
134
135 def get_entries(dom, type):
136    entries = []
137    for obj in dom.getElementsByTagName(type):
138       entry = DirectoryEntry(type)
139       attrs = obj.attributes
140       for i in range(attrs.length):
141          attr = attrs.item(i)
142          setattr(entry, attr.name, attr.value)
143       entries.append(entry)
144    return entries
145
146
147 def recursive_list(obexftp_args, directory):
148    """List the directory recursively"""
149    pipe = os.popen("%s %s -l '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, directory), 'r')
150    listing = pipe.read()
151    pipe.close()
152
153    if not listing:
154       return
155
156    dom = xml.dom.minidom.parseString(listing)
157    directories = get_entries(dom, "folder")
158    files = get_entries(dom, "file")
159
160    for entry in directories + files:
161       fullpath = "%s/%s" % (directory, entry.name)
162       if fullpath.startswith('//'): fullpath = fullpath[1:]
163       print entry.perm, "1 user group", entry.size, entry.mtime, fullpath
164
165    for entry in directories:
166       fullpath = "%s/%s" % (directory, entry.name)
167       if fullpath.startswith('//'): fullpath = fullpath[1:]
168       time.sleep(1)
169       recursive_list(obexftp_args, fullpath)
170
171 def mcobex_list():
172    """List the entire VFS"""
173    obexftp_args = setup_transport()
174    recursive_list(obexftp_args, '/')
175
176
177 # A unique directory for temporary files
178
179 tmpdir_name = None
180
181 def setup_tmpdir():
182    global tmpdir_name
183    tmpdir_name = mkdtemp(".tmp", "mcobex-")
184    os.chdir(tmpdir_name)
185
186 def cleanup_tmpdir():
187    os.chdir(os.pardir)
188    shutil.rmtree(tmpdir_name)
189
190
191 def mcobex_copyout():
192    """Get a file from the VFS"""
193    obexftp_args = setup_transport()
194    obex_filename = sys.argv[3]
195    real_filename = sys.argv[4]
196
197    setup_tmpdir()
198    os.system("%s %s -g '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, obex_filename))
199    try:
200       os.rename(os.path.basename(obex_filename), real_filename)
201    except OSError:
202       pass
203    cleanup_tmpdir()
204
205
206 def mcobex_copyin():
207    """Put a file to the VFS"""
208    obexftp_args = setup_transport()
209    obex_filename = sys.argv[3]
210    real_filename = sys.argv[4]
211    dirname, filename = os.path.split(obex_filename)
212
213    setup_tmpdir()
214    os.rename(real_filename, filename)
215    os.system("%s %s -c '%s' -p '%s' 2>/dev/null" % (obexftp_prog, obexftp_args,
216       dirname, filename
217    ))
218    os.rename(filename, real_filename) # by some reason MC wants the file back
219    cleanup_tmpdir()
220
221
222 def mcobex_rm():
223    """Remove a file from the VFS"""
224    obexftp_args = setup_transport()
225    obex_filename = sys.argv[3]
226    os.system("%s %s -k '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, obex_filename))
227
228
229 def mcobex_mkdir():
230    """Create a directory in the VFS"""
231    obexftp_args = setup_transport()
232    obex_dirname = sys.argv[3]
233    os.system("%s %s -C '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, obex_dirname))
234
235
236 mcobex_rmdir = mcobex_rm
237
238
239 g = globals()
240 command = sys.argv[1]
241 procname = "mcobex_" + command
242
243 if not g.has_key(procname):
244    error("Unknown command %s" % command)
245
246 g[procname]()