]> git.phdru.name Git - extfs.d.git/blob - obexftp
ObexFTP VFS for Midnight Commander. Manipulate a cell phone's filesystem using obexftp.
[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 To use it install OpenOBEX (http://openobex.sourceforge.net/) and ObexFTP
11 (http://triq.net/obexftp) and edit the full path to the obexftp binary.
12
13 Put the file to the /usr/[local/]lib/mc/extfs, and add a line "obexftp" to the
14 /usr/[local/]lib/mc/extfs/extfs.ini. Then create somewhere a file called
15 "irda", "bluetooth" or "tty" to connect to the device using IrDA, Bluetooth or
16 TTY transport.
17
18 For the "bluetooth" put there a line "CP:AD:RE:SS channel", where CP:AD:RE:SS
19 is the hardware address of the device you want to connect to, and channel is
20 the OBEX File Transfer channel; you can discover the address and the channel
21 for your device by using commands like "hcitool scan" and "sdptool browse".
22 Other lines in the file are ignored.
23
24 Put a device name like /dev/rfcomm0 into the "tty" file.
25
26 The content for the "irda" file is ignored.
27
28 Now run this "cd" command in the Midnight Commander (in the "bindings" files
29 the command is "%cd"): cd bluetooth#obexftp. The VFS script use obexftp to try
30 to connect to the device and list files and directories. It could be very slow...
31
32 """
33
34 __version__ = "0.1.0"
35 __revision__ = "$Id: obexftp,v 1.1 2004/06/13 13:27:47 phd Exp $"
36 __date__ = "$Date: 2004/06/13 13:27:47 $"[7:-2]
37 __author__ = "Oleg Broytmann <phd@phd.pp.ru>"
38 __copyright__ = "Copyright (C) 2004 PhiloSoft Design"
39
40
41 obexftp_prog = "/usr/local/obex/bin/obexftp"
42
43
44 import sys, os
45 import xml.dom.minidom
46
47 def log_error(msg):
48    sys.stderr.write(msg + '\n')
49
50 def error(msg):
51    log_error(msg + '\n')
52    sys.exit(1)
53
54
55 if len(sys.argv) < 2:
56    error("""\
57 It is not a program - it is a VFS for Midnight Commander.
58 Put it in /usr/lib/mc/extfs.""")
59
60
61 def setup_transport():
62    """Setup transport parameters for the obexftp program"""
63    transport_filename = sys.argv[2]
64    base_filename = os.path.basename(transport_filename)
65
66    if base_filename == "bluetooth":
67       transport_file = open(transport_filename, 'r')
68       line = transport_file.readline().strip()
69       transport_file.close()
70       bdaddr, channel = line.split()
71       return ' '.join(["-b", bdaddr, "-B", channel])
72    elif base_filename == "tty":
73       transport_file = open(transport_filename, 'r')
74       device = transport_file.readline().strip()
75       transport_file.close()
76       return ' '.join(["-t", device])
77    elif base_filename == "irda":
78       return ' '.join(["-i"])
79    else:
80       error("Unknown transport '%s'; expected 'bluetooth', 'tty' or 'irda'" % base_filename)
81
82
83 # Parse ObexFTP XML directory listings
84
85 class DirectoryEntry(object):
86    def __init__(self, type):
87       self.type = type
88       self.size = 0
89       if type == "file":
90          self.perm = "-rw-rw-rw-"
91       elif type == "folder":
92          self.perm = "drw-rw-rw-"
93       else:
94          raise ValueError, "unknown type '%s'; expected 'file' or 'folder'" % self.type
95
96    def mtime(self):
97       if not hasattr(self, "modified"): # telecom
98          return "01-01-70 0:0"
99       date, time = self.modified.split('T')
100       year, month, day = date[2:4], date[4:6], date[6:8]
101       hour, minute = time[:2], time[2:4]
102       return "%s-%s-%s %s:%s" % (month, day, year, hour, minute)
103    mtime = property(mtime)
104
105    def __repr__(self):
106       if self.type == "file":
107          return """<%s: type=file, name=%s, size=%s, mtime=%s at 0x%x>""" % (
108             self.__class__.__name__, self.name, self.size, self.mtime, id(self)
109          )
110       if self.type == "folder":
111          if hasattr(self, "modified"):
112             return """<%s: type=directory, name=%s, mtime=%s at 0x%x>""" % (
113                self.__class__.__name__, self.name, self.mtime, id(self)
114             )
115          else: # telecom
116             return """<%s: type=directory, name=%s at 0x%x>""" % (
117                self.__class__.__name__, self.name, id(self)
118             )
119       raise ValueError, "unknown type '%s'; expected 'file' or 'folder'" % self.type
120
121 def get_entries(dom, tag):
122    entries = []
123    for subtag in dom.getElementsByTagName(tag):
124       entry = DirectoryEntry(tag)
125       attrs = subtag.attributes
126       for i in range(attrs.length):
127          attr = attrs.item(i)
128          setattr(entry, attr.name, attr.value)
129       entries.append(entry)
130    return entries
131
132
133 def _recursive_list(obexftp_args, directory):
134    """List the directory recursively"""
135    pipe = os.popen("%s %s -l '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, directory), 'r')
136    listing = pipe.read()
137    pipe.close()
138
139    if not listing:
140       return
141
142    try:
143       dom = xml.dom.minidom.parseString(listing)
144    except:
145       obex_xml = open("obex.xml", 'a')
146       obex_xml.write(listing)
147       obex_xml.close()
148       raise
149
150    directories = get_entries(dom, "folder")
151    files = get_entries(dom, "file")
152
153    prefix = directory[1:] # omit leading slash
154    debug = open("debug", 'a')
155    for entry in directories + files:
156       print >>debug, entry.perm, "1 user group", entry.size, entry.mtime, "%s/%s" % (prefix, entry.name)
157       print entry.perm, "1 user group", entry.size, entry.mtime, "%s/%s" % (prefix, entry.name)
158    debug.close()
159
160    for entry in directories:
161       _recursive_list(obexftp_args, "%s/%s" % (directory, entry.name))
162
163 def mcobex_list():
164    """List the entire VFS"""
165    obexftp_args = setup_transport()
166    _recursive_list(obexftp_args, '/')
167
168
169 def mcobex_copyout():
170    """Get a file from the VFS"""
171    obexftp_args = setup_transport()
172    dummy_filename = sys.argv[3]
173    real_filename = sys.argv[4]
174
175    real_file = open(real_filename, 'w')
176    real_file.write("Copied from %s\n" % dummy_filename)
177    real_file.write("Copied  to  %s\n" % real_filename)
178    real_file.close()
179
180
181 def mcobex_copyin():
182    """Put a file to the VFS"""
183    obexftp_args = setup_transport()
184    dummy_filename = sys.argv[3]
185    real_filename = sys.argv[4]
186
187    real_file = open(real_filename + "-dummy.tmp", 'w')
188    real_file.write("Copied from %s\n" % real_filename)
189    real_file.write("Copied  to  %s\n" % dummy_filename)
190    real_file.close()
191
192
193 def mcobex_rm():
194    """Remove a file from the VFS"""
195    obexftp_args = setup_transport()
196    dummy_filename = sys.argv[3]
197
198    real_file = open(".dummy.tmp", 'a')
199    real_file.write("Remove %s\n" % dummy_filename)
200    real_file.close()
201
202
203 def mcobex_mkdir():
204    """Create a directory in the VFS"""
205    obexftp_args = setup_transport()
206    dummy_dirname = sys.argv[3]
207
208    real_file = open(".dummy.tmp", 'a')
209    real_file.write("Create %s\n" % dummy_dirname)
210    real_file.close()
211
212
213 def mcobex_rmdir():
214    """Remove a directory from the VFS"""
215    obexftp_args = setup_transport()
216    dummy_dirname = sys.argv[3]
217
218    real_file = open(".dummy.tmp", 'a')
219    real_file.write("Remove %s\n" % dummy_dirname)
220    real_file.close()
221
222
223 g = globals()
224 command = sys.argv[1]
225 procname = "mcobex_" + command
226
227 if not g.has_key(procname):
228    error("Unknown command %s" % command)
229
230 try:
231    g[procname]()
232 except:
233    import traceback
234    error = open("error", 'a')
235    traceback.print_exc(file=error)
236    error.close()
237    sys.exit(1)