]> git.phdru.name Git - extfs.d.git/blobdiff - obexftp
Changed the order of comments.
[extfs.d.git] / obexftp
diff --git a/obexftp b/obexftp
index 9d69a200144c16ed43ae5bd26215d4fd4f850938..5aa46c523b9b957898e6507927b6a05a70b52382 100755 (executable)
--- a/obexftp
+++ b/obexftp
 #! /usr/local/bin/python -O
 
 """
 #! /usr/local/bin/python -O
 
 """
-ObexFTP VFS for Midnight Commander. Manipulate a cell phone's filesystem using obexftp.
+ObexFTP Virtual FileSystem for Midnight Commander.
 
 Author: Oleg BroytMann <phd@phd.pp.ru>.
 Copyright (C) 2004 PhiloSoft Design.
 License: GPL.
 
 
 Author: Oleg BroytMann <phd@phd.pp.ru>.
 Copyright (C) 2004 PhiloSoft Design.
 License: GPL.
 
-To use it install OpenOBEX (http://openobex.sourceforge.net/) and ObexFTP
-(http://triq.net/obexftp) and edit the full path to the obexftp binary.
+Manipulate a cell phone's filesystem calling obexftp binary. This is a complete
+user-mode solution, no kernel modules required (unlike SieFS or such). The
+script implements all commands of Midnight VFS, except for undocumented "run";
+but there are no runnable files in the cell phone. The script is written in
+Python because I love Python, the best of all languages, and I need to parse
+XML directory listings from obexftp.
 
 
-Put the file to the /usr/[local/]lib/mc/extfs, and add a line "obexftp" to the
-/usr/[local/]lib/mc/extfs/extfs.ini. Then create somewhere a file called
-"irda", "bluetooth" or "tty" to connect to the device using IrDA, Bluetooth or
-TTY transport.
+The script requires Midnight Commander 3.1+ (http://www.ibiblio.org/mc/),
+Python 2.2+ (http://www.python.org/),
+OpenOBEX 1.0.1+ (http://openobex.sourceforge.net/)
+and ObexFTP 0.10.4+ (http://triq.net/obexftp).
 
 
-For the "bluetooth" put there a line "CP:AD:RE:SS channel", where CP:AD:RE:SS
-is the hardware address of the device you want to connect to, and channel is
-the OBEX File Transfer channel; you can discover the address and the channel
-for your device by using commands like "hcitool scan" and "sdptool browse".
-Other lines in the file are ignored.
+Edit the script, and correct the shebang path, if your python is not in the
+/usr/local. Edit the full path to the obexftp binary (see below). Put the file
+in the /usr/[local/]lib/mc/extfs, and add a line "obexftp" to the
+/usr/[local/]lib/mc/extfs/extfs.ini.
 
 
-Put a device name like /dev/rfcomm0 into the "tty" file.
+Create somewhere a transport file. The transport file can have any name, and is
+expected to be a text file with at least one line defining the transport to
+your device. Other lines in the file are ignored.
 
 
-The content for the "irda" file is ignored.
+First word in the line is a transport name - Bluetooth, IrDA or TTY. The name
+is case-insensitive.
+
+For the Bluetooth transport put there a line "Bluetooth CP:AD:RE:SS channel",
+where CP:AD:RE:SS is the hardware address of the device you want to connect to,
+and channel is the OBEX File Transfer channel; you can discover the address and
+the channel for your device by using commands like "hcitool scan" and "sdptool
+browse".
+
+For the TTY put a device name: "tty /dev/rfcomm0".
+
+For the IrDA: just put "IrDA" in the file.
 
 Now run this "cd" command in the Midnight Commander (in the "bindings" files
 
 Now run this "cd" command in the Midnight Commander (in the "bindings" files
-the command is "%cd"): cd bluetooth#obexftp. The VFS script use obexftp to try
-to connect to the device and list files and directories. It could be very slow...
+the command is "%cd"): cd description#obexftp, where "description" is the name
+of your file. The VFS script uses obexftp to connect to the device and list
+files and directories. Please be warned that opening the VFS for the first time
+is VERY slow, because the script needs to scan the entire cell phone's
+filesystem. And there must be timeouts between connections, which don't make
+the scanning faster. Midnight Commander caches the result, so you can browse
+directories quickly.
 
 """
 
 
 """
 
-__version__ = "0.1.0"
-__revision__ = "$Id: obexftp,v 1.1 2004/06/13 13:27:47 phd Exp $"
-__date__ = "$Date: 2004/06/13 13:27:47 $"[7:-2]
+__version__ = "1.0.0"
+__revision__ = "$Id: obexftp,v 1.10 2004/06/19 17:32:52 phd Exp $"
+__date__ = "$Date: 2004/06/19 17:32:52 $"[7:-2]
 __author__ = "Oleg Broytmann <phd@phd.pp.ru>"
 __copyright__ = "Copyright (C) 2004 PhiloSoft Design"
 
 
 __author__ = "Oleg Broytmann <phd@phd.pp.ru>"
 __copyright__ = "Copyright (C) 2004 PhiloSoft Design"
 
 
+# Change this to suite your needs
 obexftp_prog = "/usr/local/obex/bin/obexftp"
 
 
 obexftp_prog = "/usr/local/obex/bin/obexftp"
 
 
-import sys, os
+import sys, time
+import os, shutil
 import xml.dom.minidom
 import xml.dom.minidom
+from tempfile import mkdtemp
+
 
 def log_error(msg):
    sys.stderr.write(msg + '\n')
 
 def error(msg):
 
 def log_error(msg):
    sys.stderr.write(msg + '\n')
 
 def error(msg):
-   log_error(msg + '\n')
+   log_error(msg)
    sys.exit(1)
 
 
 if len(sys.argv) < 2:
    error("""\
    sys.exit(1)
 
 
 if len(sys.argv) < 2:
    error("""\
-It is not a program - it is a VFS for Midnight Commander.
-Put it in /usr/lib/mc/extfs.""")
+ObexFTP Virtual FileSystem for Midnight Commander version %s
+Author: %s
+%s
+Put it in /usr/lib/mc/extfs. For more information read the source!""" % (
+   __version__, __author__, __copyright__
+))
 
 
 def setup_transport():
    """Setup transport parameters for the obexftp program"""
 
 
 def setup_transport():
    """Setup transport parameters for the obexftp program"""
-   transport_filename = sys.argv[2]
-   base_filename = os.path.basename(transport_filename)
-
-   if base_filename == "bluetooth":
-      transport_file = open(transport_filename, 'r')
-      line = transport_file.readline().strip()
-      transport_file.close()
-      bdaddr, channel = line.split()
-      return ' '.join(["-b", bdaddr, "-B", channel])
-   elif base_filename == "tty":
-      transport_file = open(transport_filename, 'r')
-      device = transport_file.readline().strip()
-      transport_file.close()
-      return ' '.join(["-t", device])
-   elif base_filename == "irda":
-      return ' '.join(["-i"])
+   transport_file = open(sys.argv[2], 'r')
+   line = transport_file.readline().strip()
+   transport_file.close()
+
+   parts = line.split()
+   transport = parts[0].lower()
+
+   if transport == "bluetooth":
+      return ' '.join(["-b", parts[1], "-B", parts[2]])
+   elif transport == "tty":
+      return ' '.join(["-t", parts[1]])
+   elif transport == "irda":
+      return "-i"
    else:
       error("Unknown transport '%s'; expected 'bluetooth', 'tty' or 'irda'" % base_filename)
 
    else:
       error("Unknown transport '%s'; expected 'bluetooth', 'tty' or 'irda'" % base_filename)
 
@@ -83,13 +109,15 @@ def setup_transport():
 # Parse ObexFTP XML directory listings
 
 class DirectoryEntry(object):
 # Parse ObexFTP XML directory listings
 
 class DirectoryEntry(object):
+   """Represent remote files and directories"""
+
    def __init__(self, type):
       self.type = type
       self.size = 0
       if type == "file":
          self.perm = "-rw-rw-rw-"
       elif type == "folder":
    def __init__(self, type):
       self.type = type
       self.size = 0
       if type == "file":
          self.perm = "-rw-rw-rw-"
       elif type == "folder":
-         self.perm = "drw-rw-rw-"
+         self.perm = "drwxrwxrwx"
       else:
          raise ValueError, "unknown type '%s'; expected 'file' or 'folder'" % self.type
 
       else:
          raise ValueError, "unknown type '%s'; expected 'file' or 'folder'" % self.type
 
@@ -118,11 +146,11 @@ class DirectoryEntry(object):
             )
       raise ValueError, "unknown type '%s'; expected 'file' or 'folder'" % self.type
 
             )
       raise ValueError, "unknown type '%s'; expected 'file' or 'folder'" % self.type
 
-def get_entries(dom, tag):
+def get_entries(dom, type):
    entries = []
    entries = []
-   for subtag in dom.getElementsByTagName(tag):
-      entry = DirectoryEntry(tag)
-      attrs = subtag.attributes
+   for obj in dom.getElementsByTagName(type):
+      entry = DirectoryEntry(type)
+      attrs = obj.attributes
       for i in range(attrs.length):
          attr = attrs.item(i)
          setattr(entry, attr.name, attr.value)
       for i in range(attrs.length):
          attr = attrs.item(i)
          setattr(entry, attr.name, attr.value)
@@ -130,7 +158,7 @@ def get_entries(dom, tag):
    return entries
 
 
    return entries
 
 
-def _recursive_list(obexftp_args, directory):
+def recursive_list(obexftp_args, directory):
    """List the directory recursively"""
    pipe = os.popen("%s %s -l '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, directory), 'r')
    listing = pipe.read()
    """List the directory recursively"""
    pipe = os.popen("%s %s -l '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, directory), 'r')
    listing = pipe.read()
@@ -139,85 +167,87 @@ def _recursive_list(obexftp_args, directory):
    if not listing:
       return
 
    if not listing:
       return
 
-   try:
-      dom = xml.dom.minidom.parseString(listing)
-   except:
-      obex_xml = open("obex.xml", 'a')
-      obex_xml.write(listing)
-      obex_xml.close()
-      raise
-
+   dom = xml.dom.minidom.parseString(listing)
    directories = get_entries(dom, "folder")
    files = get_entries(dom, "file")
 
    directories = get_entries(dom, "folder")
    files = get_entries(dom, "file")
 
-   prefix = directory[1:] # omit leading slash
-   debug = open("debug", 'a')
    for entry in directories + files:
    for entry in directories + files:
-      print >>debug, entry.perm, "1 user group", entry.size, entry.mtime, "%s/%s" % (prefix, entry.name)
-      print entry.perm, "1 user group", entry.size, entry.mtime, "%s/%s" % (prefix, entry.name)
-   debug.close()
+      fullpath = "%s/%s" % (directory, entry.name)
+      if fullpath.startswith('//'): fullpath = fullpath[1:]
+      print entry.perm, "1 user group", entry.size, entry.mtime, fullpath
 
    for entry in directories:
 
    for entry in directories:
-      _recursive_list(obexftp_args, "%s/%s" % (directory, entry.name))
+      fullpath = "%s/%s" % (directory, entry.name)
+      if fullpath.startswith('//'): fullpath = fullpath[1:]
+      time.sleep(1)
+      recursive_list(obexftp_args, fullpath)
 
 def mcobex_list():
    """List the entire VFS"""
    obexftp_args = setup_transport()
 
 def mcobex_list():
    """List the entire VFS"""
    obexftp_args = setup_transport()
-   _recursive_list(obexftp_args, '/')
+   recursive_list(obexftp_args, '/')
+
+
+# A unique directory for temporary files
+
+tmpdir_name = None
+
+def setup_tmpdir():
+   global tmpdir_name
+   tmpdir_name = mkdtemp(".tmp", "mcobex-")
+   os.chdir(tmpdir_name)
+
+def cleanup_tmpdir():
+   os.chdir(os.pardir)
+   shutil.rmtree(tmpdir_name)
 
 
 def mcobex_copyout():
    """Get a file from the VFS"""
    obexftp_args = setup_transport()
 
 
 def mcobex_copyout():
    """Get a file from the VFS"""
    obexftp_args = setup_transport()
-   dummy_filename = sys.argv[3]
+   obex_filename = sys.argv[3]
    real_filename = sys.argv[4]
 
    real_filename = sys.argv[4]
 
-   real_file = open(real_filename, 'w')
-   real_file.write("Copied from %s\n" % dummy_filename)
-   real_file.write("Copied  to  %s\n" % real_filename)
-   real_file.close()
+   setup_tmpdir()
+   os.system("%s %s -g '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, obex_filename))
+   try:
+      os.rename(os.path.basename(obex_filename), real_filename)
+   except OSError:
+      pass
+   cleanup_tmpdir()
 
 
 def mcobex_copyin():
    """Put a file to the VFS"""
    obexftp_args = setup_transport()
 
 
 def mcobex_copyin():
    """Put a file to the VFS"""
    obexftp_args = setup_transport()
-   dummy_filename = sys.argv[3]
+   obex_filename = sys.argv[3]
    real_filename = sys.argv[4]
    real_filename = sys.argv[4]
+   dirname, filename = os.path.split(obex_filename)
 
 
-   real_file = open(real_filename + "-dummy.tmp", 'w')
-   real_file.write("Copied from %s\n" % real_filename)
-   real_file.write("Copied  to  %s\n" % dummy_filename)
-   real_file.close()
+   setup_tmpdir()
+   os.rename(real_filename, filename)
+   os.system("%s %s -c '%s' -p '%s' 2>/dev/null" % (obexftp_prog, obexftp_args,
+      dirname, filename
+   ))
+   os.rename(filename, real_filename) # by some reason MC wants the file back
+   cleanup_tmpdir()
 
 
 def mcobex_rm():
    """Remove a file from the VFS"""
    obexftp_args = setup_transport()
 
 
 def mcobex_rm():
    """Remove a file from the VFS"""
    obexftp_args = setup_transport()
-   dummy_filename = sys.argv[3]
-
-   real_file = open(".dummy.tmp", 'a')
-   real_file.write("Remove %s\n" % dummy_filename)
-   real_file.close()
+   obex_filename = sys.argv[3]
+   os.system("%s %s -k '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, obex_filename))
 
 
 def mcobex_mkdir():
    """Create a directory in the VFS"""
    obexftp_args = setup_transport()
 
 
 def mcobex_mkdir():
    """Create a directory in the VFS"""
    obexftp_args = setup_transport()
-   dummy_dirname = sys.argv[3]
+   obex_dirname = sys.argv[3]
+   os.system("%s %s -C '%s' 2>/dev/null" % (obexftp_prog, obexftp_args, obex_dirname))
 
 
-   real_file = open(".dummy.tmp", 'a')
-   real_file.write("Create %s\n" % dummy_dirname)
-   real_file.close()
 
 
-
-def mcobex_rmdir():
-   """Remove a directory from the VFS"""
-   obexftp_args = setup_transport()
-   dummy_dirname = sys.argv[3]
-
-   real_file = open(".dummy.tmp", 'a')
-   real_file.write("Remove %s\n" % dummy_dirname)
-   real_file.close()
+mcobex_rmdir = mcobex_rm
 
 
 g = globals()
 
 
 g = globals()
@@ -227,11 +257,4 @@ procname = "mcobex_" + command
 if not g.has_key(procname):
    error("Unknown command %s" % command)
 
 if not g.has_key(procname):
    error("Unknown command %s" % command)
 
-try:
-   g[procname]()
-except:
-   import traceback
-   error = open("error", 'a')
-   traceback.print_exc(file=error)
-   error.close()
-   sys.exit(1)
+g[procname]()