]> git.phdru.name Git - extfs.d.git/commitdiff
Feat(torrent): Try harder to guess encoding master
authorOleg Broytman <phd@phdru.name>
Sat, 14 Oct 2023 14:01:59 +0000 (17:01 +0300)
committerOleg Broytman <phd@phdru.name>
Sun, 15 Oct 2023 20:38:52 +0000 (23:38 +0300)
17 files changed:
INSTALL.html
INSTALL.txt
Makefile
README.html [new file with mode: 0644]
dummy
eff_bdecode.py
gitweb/README.html [deleted file]
obexftp
obexftp-ANNOUNCE
torrent
torrent-ANNOUNCE
torrent-ANNOUNCE-ru
torrent-ChangeLog
xml
xml-ANNOUNCE
xml-ANNOUNCE-ru
xml-ChangeLog

index 7dde8ec23777515702f26a182ca0ecea94433376..ca2d4bb68e76716756b87016d91fc08cf4cc11ba 100644 (file)
@@ -3,7 +3,7 @@
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="generator" content="Docutils 0.8.1: http://docutils.sourceforge.net/" />
+<meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
 <title>How to install an external VFS script</title>
 <style type="text/css">
 
@@ -28,6 +28,14 @@ the simplest variant is just <tt class="docutils literal">locate extfs.ini</tt>.
 <p>Usual places for <tt class="docutils literal">extfs.ini</tt> are <tt class="docutils literal">/etc/mc/extfs/extfs.ini</tt>,
 <tt class="docutils literal">/usr/lib/mc/extfs/extfs.ini</tt>, <tt class="docutils literal">/usr/share/mc/extfs/extfs.ini</tt> or
 <tt class="docutils literal">/usr/local/share/mc/extfs/extfs.ini</tt>.</p>
+<div class="section" id="newer-versions-home-mc-extfs-d">
+<h1>Newer versions - $HOME/.mc/extfs.d</h1>
+<p>For newer versions just drop a VFS script to <tt class="docutils literal"><span class="pre">$HOME/.mc/extfs.d</span></tt> or
+<tt class="docutils literal"><span class="pre">$HOME/.local/share/mc/extfs.d/</span></tt> directory (verify directory by running
+<tt class="docutils literal">mc <span class="pre">-F</span></tt>). Make the script executable. Edit <tt class="docutils literal">mc.ext</tt>. Enable file types
+guessing (see above).</p>
+<p>See my <a class="reference external" href="https://phdru.name/Software/dotfiles/mc/mc.ext.html">https://phdru.name/Software/dotfiles/mc/mc.ext.html</a> for examples.</p>
+</div>
 <div class="section" id="older-versions-extfs-ini">
 <h1>Older versions - extfs.ini</h1>
 <p>On the system where there is a file extfs.ini a VFS script has to be
@@ -50,14 +58,6 @@ use_file_to_guess_type=1
 <p>This has to be done using text editor - <tt class="docutils literal">mc</tt> doesn't allow editing the
 option in its configuration editor.</p>
 </div>
-<div class="section" id="newer-versions-home-mc-extfs-d">
-<h1>Newer versions - $HOME/.mc/extfs.d</h1>
-<p>For newer versions just drop a VFS script to <tt class="docutils literal"><span class="pre">$HOME/.mc/extfs.d</span></tt> or
-<tt class="docutils literal"><span class="pre">$HOME/.local/share/mc/extfs.d/</span></tt> directory (verify directory by running
-<tt class="docutils literal">mc <span class="pre">-F</span></tt>). Make the script executable. Edit <tt class="docutils literal">mc.ext</tt>. Enable file types
-guessing (see above).</p>
-<p>See my <a class="reference external" href="http://phdru.name/Software/dotfiles/mc/mc.ext.html">http://phdru.name/Software/dotfiles/mc/mc.ext.html</a> for examples.</p>
-</div>
 </div>
 </body>
 </html>
index fa9d52ab102bd6d3c3227d7d1d4a0809d0d6e0fd..7c0ce8af28ba71610d3e577b30ffef288111f345 100644 (file)
@@ -17,6 +17,16 @@ Usual places for ``extfs.ini`` are ``/etc/mc/extfs/extfs.ini``,
 ``/usr/lib/mc/extfs/extfs.ini``, ``/usr/share/mc/extfs/extfs.ini`` or
 ``/usr/local/share/mc/extfs/extfs.ini``.
 
+Newer versions - \$HOME/.mc/extfs.d
+-----------------------------------
+
+For newer versions just drop a VFS script to ``$HOME/.mc/extfs.d`` or
+``$HOME/.local/share/mc/extfs.d/`` directory (verify directory by running
+``mc -F``). Make the script executable. Edit ``mc.ext``. Enable file types
+guessing (see above).
+
+See my https://phdru.name/Software/dotfiles/mc/mc.ext.html for examples.
+
 Older versions - extfs.ini
 --------------------------
 
@@ -40,13 +50,3 @@ ini file in section ``[Midnight-Commander]``::
 
 This has to be done using text editor - ``mc`` doesn't allow editing the
 option in its configuration editor.
-
-Newer versions - \$HOME/.mc/extfs.d
------------------------------------
-
-For newer versions just drop a VFS script to ``$HOME/.mc/extfs.d`` or
-``$HOME/.local/share/mc/extfs.d/`` directory (verify directory by running
-``mc -F``). Make the script executable. Edit ``mc.ext``. Enable file types
-guessing (see above).
-
-See my http://phdru.name/Software/dotfiles/mc/mc.ext.html for examples.
index c50423f1f72d2f8e38d03007968180681173f5c9..05c1a74c15e6cf4218d5863d2db298f3bf62e4da 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,9 @@
+.SUFFIXES: # Clear the suffix list
+.SUFFIXES: .txt .html
+
+
 %.html: %.txt
-       rst2html --stylesheet=/dev/null -- $< >$@
+       rst2html.py --stylesheet=/dev/null -- $< >$@
 
 
 .PHONY: all
diff --git a/README.html b/README.html
new file mode 100644 (file)
index 0000000..5fabba8
--- /dev/null
@@ -0,0 +1,2 @@
+<a href="https://phdru.name/Software/mc/">Virtual FileSystems for
+Midnight Commander</a>.
diff --git a/dummy b/dummy
index 43a7e697aa426054f9d2a51c67ea37d94f94f0cc..8e22a1d1e4e4cbc6aa78c23d2c0cd959e603a993 100755 (executable)
--- a/dummy
+++ b/dummy
-#! /usr/bin/env python
+#! /usr/bin/env python3
 """Dummy VFS for Midnight Commander. Just for a test."""
 
-__version__ = "1.0.3"
+__version__ = "1.1.0"
 __author__ = "Oleg Broytman <phd@phdru.name>"
-__copyright__ = "Copyright (C) 2004-2013 PhiloSoft Design"
+__copyright__ = "Copyright (C) 2004-2023 PhiloSoft Design"
 __license__ = "GPL"
 
 
 import sys
 
+
 def log_error(msg):
-   sys.stderr.write(msg + '\n')
+    sys.stderr.write(msg + '\n')
+
 
 def error(msg):
-   log_error(msg + '\n')
-   sys.exit(1)
+    log_error(msg + '\n')
+    sys.exit(1)
 
 
 if len(sys.argv) < 2:
-   error("""\
+    error("""\
 It is not a program - it is a dummy VFS for Midnight Commander.
 Put it in $HOME/.mc/extfs.d or /usr/lib/mc/extfs.""")
 
 
 def mcdummy_list():
-   """List the entire VFS"""
-   # Ignore the VFS name (sys.argv[2])
-   # Emit a dummy listing
-   print "-r--r--r-- 1 user group 0 Jun 13 02:20 file0"
-   print "-r--r--r-- 1 user group 1 Jun 13 02:21 file1"
-   print "dr--r--r-- 1 user group 2 Jun 13 02:22 subdir"
-   print "-r--r--r-- 1 user group 3 Jun 13 02:23 subdir/file3"
-   print "-r--r--r-- 1 user group 4 Jun 13 02:23 subdir/file4"
+    """List the entire VFS"""
+    # Ignore the VFS name (sys.argv[2])
+    # Emit a dummy listing
+    print("-r--r--r-- 1 user group 0 Jun 13 02:20 file0")
+    print("-r--r--r-- 1 user group 1 Jun 13 02:21 file1")
+    print("dr--r--r-- 1 user group 2 Jun 13 02:22 subdir")
+    print("-r--r--r-- 1 user group 3 Jun 13 02:23 subdir/file3")
+    print("-r--r--r-- 1 user group 4 Jun 13 02:23 subdir/file4")
 
 
 def mcdummy_copyout():
-   """Extract a file from the VFS"""
-   # Ignore the VFS name (sys.argv[2])
-   dummy_filename = sys.argv[3]
-   real_filename = sys.argv[4]
+    """Extract a file from the VFS"""
+    # Ignore the VFS name (sys.argv[2])
+    dummy_filename = sys.argv[3]
+    real_filename = sys.argv[4]
 
-   real_file = open(real_filename, 'a')
-   real_file.write("Copy from %s\n" % dummy_filename)
-   real_file.write("Copy  to  %s\n" % real_filename)
-   real_file.close()
+    real_file = open(real_filename, 'a')
+    real_file.write("Copy from %s\n" % dummy_filename)
+    real_file.write("Copy  to   %s\n" % real_filename)
+    real_file.close()
 
 
 def mcdummy_copyin():
-   """Put a file to the VFS"""
-   # Ignore the VFS name (sys.argv[2])
-   dummy_filename = sys.argv[3]
-   real_filename = sys.argv[4]
+    """Put a file to the VFS"""
+    # Ignore the VFS name (sys.argv[2])
+    dummy_filename = sys.argv[3]
+    real_filename = sys.argv[4]
 
-   real_file = open(real_filename + "-dummy.tmp", 'a')
-   real_file.write("Copy from %s\n" % real_filename)
-   real_file.write("Copy  to  %s\n" % dummy_filename)
-   real_file.close()
+    real_file = open(real_filename + "-dummy.tmp", 'a')
+    real_file.write("Copy from %s\n" % real_filename)
+    real_file.write("Copy  to   %s\n" % dummy_filename)
+    real_file.close()
 
 
 def mcdummy_rm():
-   """Remove a file from the VFS"""
-   # Ignore the VFS name (sys.argv[2])
-   dummy_filename = sys.argv[3]
+    """Remove a file from the VFS"""
+    # Ignore the VFS name (sys.argv[2])
+    dummy_filename = sys.argv[3]
 
-   real_file = open(".dummy.tmp", 'a')
-   real_file.write("Remove %s\n" % dummy_filename)
-   real_file.close()
+    real_file = open(".dummy.tmp", 'a')
+    real_file.write("Remove %s\n" % dummy_filename)
+    real_file.close()
 
 
 def mcdummy_mkdir():
-   """Create a directory in the VFS"""
-   # Ignore the VFS name (sys.argv[2])
-   dummy_dirname = sys.argv[3]
+    """Create a directory in the VFS"""
+    # Ignore the VFS name (sys.argv[2])
+    dummy_dirname = sys.argv[3]
 
-   real_file = open(".dummy.tmp", 'a')
-   real_file.write("Create %s\n" % dummy_dirname)
-   real_file.close()
+    real_file = open(".dummy.tmp", 'a')
+    real_file.write("Create %s\n" % dummy_dirname)
+    real_file.close()
 
 
 def mcdummy_rmdir():
-   """Remove a directory from the VFS"""
-   # Ignore the VFS name (sys.argv[2])
-   dummy_dirname = sys.argv[3]
+    """Remove a directory from the VFS"""
+    # Ignore the VFS name (sys.argv[2])
+    dummy_dirname = sys.argv[3]
 
-   real_file = open(".dummy.tmp", 'a')
-   real_file.write("Remove %s\n" % dummy_dirname)
-   real_file.close()
+    real_file = open(".dummy.tmp", 'a')
+    real_file.write("Remove %s\n" % dummy_dirname)
+    real_file.close()
 
 
 g = globals()
 command = sys.argv[1]
 procname = "mcdummy_" + command
 
-if not g.has_key(procname):
-   error("Unknown command %s" % command)
+if procname not in g:
+    error("Unknown command %s" % command)
 
 g[procname]()
index 5f5b93b38c1b3b89e06ecc3fd0c0c64f9569da03..2f8fc5eb1d3caa9f3d384cbcfe9f455d7bb90950 100644 (file)
 # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
+from functools import partial
 import re
 
-def tokenize(text, match=re.compile("([idel])|(\d+):|(-?\d+)").match):
+
+def tokenize(text, match=re.compile(b"([idel])|(\\d+):|(-?\\d+)").match):
     i = 0
     while i < len(text):
         m = match(text, i)
@@ -36,35 +38,40 @@ def tokenize(text, match=re.compile("([idel])|(\d+):|(-?\d+)").match):
             yield text[i:i+int(s)]
             i = i + int(s)
         else:
-            yield s
+            yield s.decode('ascii')
+
 
-def decode_item(next, token):
+def decode_item(next_, token):
     if token == "i":
         # integer: "i" value "e"
-        data = int(next())
-        if next() != "e":
+        data = int(next_())
+        if next_() != "e":
             raise ValueError
     elif token == "s":
         # string: "s" value (virtual tokens)
-        data = next()
+        data = next_()
     elif token == "l" or token == "d":
         # container: "l" (or "d") values "e"
         data = []
-        tok = next()
+        tok = next_()
         while tok != "e":
-            data.append(decode_item(next, tok))
-            tok = next()
+            data.append(decode_item(next_, tok))
+            try:
+                tok = next_()
+            except StopIteration:
+                break
         if token == "d":
             data = dict(zip(data[0::2], data[1::2]))
     else:
         raise ValueError
     return data
 
+
 def decode(text):
     try:
         src = tokenize(text)
-        data = decode_item(src.next, src.next())
-        for token in src: # look for more tokens
+        data = decode_item(partial(next, src), next(src))
+        for token in src:  # look for more tokens
             raise SyntaxError("trailing junk")
     except (AttributeError, ValueError, StopIteration):
         raise SyntaxError("syntax error")
diff --git a/gitweb/README.html b/gitweb/README.html
deleted file mode 100644 (file)
index dcec216..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-<a href="http://phdru.name/Software/mc/">Virtual FileSystems for
-Midnight Commander</a>.
diff --git a/obexftp b/obexftp
index c1c523c7d213de563328f1812ef3b94c183bc07c..30505faa34a2455f7d34f80454d8a32798ad75db 100755 (executable)
--- a/obexftp
+++ b/obexftp
@@ -20,7 +20,7 @@ $HOME/[.local/share/].mc/extfs.d. For older versions put it in
 /usr/[local/][lib|share]/mc/extfs/extfs.ini. Make the script executable.
 
 See detailed installation instructions at
-http://phdru.name/Software/mc/INSTALL.html.
+https://phdru.name/Software/mc/INSTALL.html.
 
 Create somewhere a transport file. The transport file may have any name, and is
 expected to be a text file with at least one line defining the transport to
index ee622c03437bb82136572cf300b501ccac57d73d..fe12c67c9f89acb0fc2fd0ae09001195b9175a55 100644 (file)
@@ -25,12 +25,12 @@ instead of pipes.
 
 
 WHERE TO GET
-   Home page: http://phdru.name/Software/cellphones/
-   Download:  http://phdru.name/Software/cellphones/obexftp
-    git clone http://git.phdru.name/extfs.d.git
+   Home page: https://phdru.name/Software/cellphones/
+   Download:  https://phdru.name/Software/cellphones/obexftp
+    git clone https://git.phdru.name/extfs.d.git
     git clone  git://git.phdru.name/extfs.d.git
 
-   Installation instructions: http://phdru.name/Software/mc/INSTALL.html
+   Installation instructions: https://phdru.name/Software/mc/INSTALL.html
 
 
 AUTHOR
diff --git a/torrent b/torrent
index 67588e5ee336909c7959e8c093495b6b436fe374..a0f827ef91f7ad213d7ab70445e9ef0e54e6175a 100755 (executable)
--- a/torrent
+++ b/torrent
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 """Torrent Virtual FileSystem for Midnight Commander
 
 The script requires Midnight Commander 3.1+
@@ -15,7 +15,7 @@ file the command is "%cd"): cd file/torrent://; In older versions it is
 cd file#torrent, where "file" is the name of your torrent metafile.
 
 See detailed installation instructions at
-http://phdru.name/Software/mc/torrent_INSTALL.html.
+https://phdru.name/Software/mc/torrent_INSTALL.html.
 
 The VFS lists all files and directories from the torrent metafile; all files
 appear empty, of course, but the sizes are shown. Filenames are reencoded from
@@ -35,9 +35,9 @@ The filesystem is, naturally, read-only.
 
 """
 
-__version__ = "1.2.4"
+__version__ = "1.3.1"
 __author__ = "Oleg Broytman <phd@phdru.name>"
-__copyright__ = "Copyright (C) 2010-2018 PhiloSoft Design"
+__copyright__ = "Copyright (C) 2010-2023 PhiloSoft Design"
 __license__ = "GPL"
 
 
@@ -56,9 +56,12 @@ except ImportError:
 if use_locale:
     # Get the default charset.
     try:
-        lcAll = locale.getdefaultlocale()
-    except locale.Error, err:
-        print >>sys.stderr, "WARNING:", err
+        if sys.version_info[:2] < (3, 11):
+            lcAll = locale.getdefaultlocale()
+        else:
+            lcAll = []
+    except locale.Error as err:
+        #print("WARNING:", err, file=sys.stderr)
         lcAll = []
 
     if len(lcAll) == 2:
@@ -66,8 +69,8 @@ if use_locale:
     else:
         try:
             default_encoding = locale.getpreferredencoding()
-        except locale.Error, err:
-            print >>sys.stderr, "WARNING:", err
+        except locale.Error as err:
+            #print("WARNING:", err, file=sys.stderr)
             default_encoding = sys.getdefaultencoding()
 else:
     default_encoding = sys.getdefaultencoding()
@@ -91,13 +94,18 @@ This is not a program. Put the script in $HOME/[.local/share/].mc/extfs.d or
 
 locale.setlocale(locale.LC_ALL, '')
 
+PY3 = (sys.version_info[0] >= 3)
+if PY3:
+    def output(s):
+        sys.stdout.buffer.write(s.encode(default_encoding, 'replace') + b'\n')
+else:
+    def output(s):
+        sys.stdout.write(s + '\n')
+
 
 def mctorrent_list():
     """List the entire VFS"""
 
-    if 'info' not in torrent:
-        torrent_error('Info absent')
-
     info = torrent['info']
     if 'name' not in info and 'name.utf-8' not in info:
         torrent_error('Unknown name')
@@ -122,33 +130,13 @@ def mctorrent_list():
             if 'path.utf-8' in file:
                 if name_utf8:
                     path = '/'.join([name_utf8] + file['path.utf-8'])
-                    if default_encoding != 'utf-8':
-                        path = path.decode('utf-8', 'replace').encode(
-                            default_encoding, 'replace')
                 else:
-                    _name_utf8 = name
-                    if encoding and (encoding != 'utf-8'):
-                        _name_utf8 = _name_utf8.decode(
-                            encoding, 'replace').encode('utf-8', 'replace')
-                    path = '/'.join([_name_utf8] + file['path.utf-8'])
-                    if default_encoding != 'utf-8':
-                        path = path.decode('utf-8', 'replace').encode(
-                            default_encoding, 'replace')
+                    path = '/'.join([name] + file['path.utf-8'])
             else:
                 if name_utf8:
-                    path = file['path']
-                    if encoding and (encoding != 'utf-8'):
-                        path = path.decode(encoding, 'replace').encode(
-                            'utf-8', 'replace')
                     path = '/'.join([name_utf8] + path)
-                    if default_encoding != 'utf-8':
-                        path = path.decode('utf-8', 'replace').encode(
-                            default_encoding, 'replace')
                 else:
                     path = '/'.join([name] + file['path'])
-                    if encoding and (default_encoding != encoding):
-                        path = path.decode(encoding, 'replace').encode(
-                            default_encoding, 'replace')
             length = file['length']
             paths.append((path, length))
     else:  # One-file torrent
@@ -156,12 +144,7 @@ def mctorrent_list():
             torrent_error('Unknown length')
         length = info['length']
         if name_utf8:
-            if default_encoding != 'utf-8':
-                name = name_utf8.decode('utf-8', 'replace').encode(
-                    default_encoding, 'replace')
-        elif encoding and (default_encoding != encoding):
-            name = name.decode(encoding, 'replace').encode(
-                default_encoding, 'replace')
+            name = name_utf8
         paths = [(name, length)]
 
     meta = []
@@ -169,8 +152,7 @@ def mctorrent_list():
                 'created by', 'creation date', 'encoding', \
                 'nodes', 'publisher', 'publisher-url':
         if name == 'comment' and 'comment.utf-8' in torrent:
-            data = torrent['comment.utf-8'].decode('utf-8').encode(
-                default_encoding, 'replace')
+            data = torrent['comment.utf-8']
             meta.append(('.META/' + name, len(data)))
         elif name in torrent:
             if name == 'announce-list':
@@ -204,10 +186,10 @@ def mctorrent_list():
         dt = decode_datetime(getmtime(sys.argv[2]))
 
     for name in sorted(dirs):
-        print "dr-xr-xr-x 1 user group 0 %s %s" % (dt, name)
+        output("dr-xr-xr-x 1 user group 0 %s %s" % (dt, name))
 
     for name, size in sorted(paths):
-        print "-r--r--r-- 1 user group %d %s %s" % (size, dt, name)
+        output("-r--r--r-- 1 user group %d %s %s" % (size, dt, name))
 
 
 def mctorrent_copyout():
@@ -221,8 +203,7 @@ def mctorrent_copyout():
                 'created by', 'creation date', 'encoding', \
                 'nodes', 'publisher', 'publisher-url':
         if name == 'comment' and 'comment.utf-8' in torrent:
-            data = torrent['comment.utf-8'].decode('utf-8').encode(
-                default_encoding, 'replace')
+            data = torrent['comment.utf-8']
         elif torrent_filename == '.META/' + name:
             if name in torrent:
                 if name == 'announce-list':
@@ -242,15 +223,13 @@ def mctorrent_copyout():
             break
 
     if torrent_filename in ('.META/private', '.META/piece length'):
-        if 'info' not in torrent:
-            torrent_error('Info absent')
         info = torrent['info']
         if torrent_filename == '.META/private':
             if 'private' not in info:
-                torrent_error('Info absent')
+                torrent_error('Private absent')
         if torrent_filename == '.META/piece length':
             if 'piece length' not in info:
-                torrent_error('Info absent')
+                torrent_error('Piece length absent')
         data = str(info[torrent_filename[len('.META/'):]])
 
     if not torrent_filename.startswith('.META/'):
@@ -259,14 +238,15 @@ def mctorrent_copyout():
     if data is None:
         torrent_error('Unknown file name')
     else:
-        outfile = open(real_filename, 'w')
+        outfile = open(real_filename, 'wt')
         outfile.write(data)
         outfile.close()
 
 
 def mctorrent_copyin():
     """Put a file to the VFS"""
-    sys.exit("Torrent VFS doesn't support adding files (read-only filesystem)")
+    sys.exit("Torrent VFS doesn't support adding/overwriting files "
+             "(read-only filesystem)")
 
 
 def mctorrent_rm():
@@ -289,15 +269,65 @@ def torrent_error(error_str):
     sys.exit(1)
 
 
+def decode_dict(d, encoding):
+    new_d = {}
+    for k in d:
+        v = d[k]
+        k = k.decode(encoding)
+        if isinstance(v, dict):
+            v = decode_dict(v, encoding)
+        elif isinstance(v, list):
+            v = decode_list(v, encoding)
+        elif isinstance(v, bytes):
+            v = v.decode(encoding)
+        new_d[k] = v
+    return new_d
+
+
+def decode_list(l, encoding):
+    new_l = []
+    for v in l:
+        if isinstance(v, dict):
+            v = decode_dict(v, encoding)
+        elif isinstance(v, list):
+            v = decode_list(v, encoding)
+        elif isinstance(v, bytes):
+            v = v.decode(encoding)
+        new_l.append(v)
+    return new_l
+
+
 def decode_torrent():
     try:
-        torrent_file = open(sys.argv[2], 'r')
+        torrent_file = open(sys.argv[2], 'rb')
         data = torrent_file.read()
         torrent_file.close()
-        return decode(data)
-    except IOError, error_str:
+        torrent = decode(data)
+    except IOError as error_str:
         torrent_error(error_str)
 
+    del torrent[b'info'][b'pieces']
+    if b'info' not in torrent:
+        torrent_error('Info absent')
+
+    if PY3:
+        codepage = torrent.get(b'codepage', None)
+        encoding = torrent.get(b'encoding', None)
+        if encoding:
+            encoding = encoding.decode('ascii')
+        elif codepage:
+            encoding = codepage.decode('ascii')
+        else:
+            for encoding in ('ascii', 'utf-8', default_encoding):
+                try:
+                    return decode_dict(torrent, encoding)
+                except UnicodeDecodeError:
+                    pass
+            torrent_error('UnicodeDecodeError')
+        return decode_dict(torrent, encoding)
+
+    return torrent
+
 
 def decode_datetime_asc(dt):
     try:
@@ -316,7 +346,7 @@ def decode_datetime(dt):
 
 
 def decode_announce_list(announce):
-    return '\n'.join(l[0] for l in announce if l)
+    return '\n'.join(a[0] for a in announce if a)
 
 
 command = sys.argv[1]
@@ -333,5 +363,5 @@ try:
     g[procname]()
 except SystemExit:
     raise
-except:
+except Exception:
     logger.exception("Error during run")
index 1c8f970a3561450a765a3b90394a0bcc036200b9..11644f0e34c52d430b7eed4cd0f2fd3277d7b983 100644 (file)
@@ -39,12 +39,12 @@ Version 1.0.0 (2010-11-11)
 
 
 WHERE TO GET
-   Home page: http://phdru.name/Software/mc/torrent.html
-   Download:  http://phdru.name/Software/mc/torrent
-    git clone http://git.phdru.name/extfs.d.git
+   Home page: https://phdru.name/Software/mc/torrent.html
+   Download:  https://phdru.name/Software/mc/torrent
+    git clone https://git.phdru.name/extfs.d.git
     git clone  git://git.phdru.name/extfs.d.git
 
-   Installation instructions: http://phdru.name/Software/mc/INSTALL.html
+   Installation instructions: https://phdru.name/Software/mc/INSTALL.html
 
 
 The VFS lists all files and directories from the torrent metafile; all files
index bc7c11fc48e192a88a92d8022adedfacb6880873..b0c46dfa5ca87e5b1ba4addc1930fadc9760aeba 100644 (file)
@@ -8,12 +8,12 @@ Torrent VFS 
 
 
 ГДЕ
-   Дом. страничка: http://phdru.name/Russian/Software/mc/torrent.html
-   Скачать:        http://phdru.name/Software/mc/torrent
-    git clone http://git.phdru.name/extfs.d.git
+   Дом. страничка: https://phdru.name/Russian/Software/mc/torrent.html
+   Скачать:        https://phdru.name/Software/mc/torrent
+    git clone https://git.phdru.name/extfs.d.git
     git clone  git://git.phdru.name/extfs.d.git
 
-   Инструкции по установке (eng.): http://phdru.name/Software/mc/INSTALL.html
+   Инструкции по установке (eng.): https://phdru.name/Software/mc/INSTALL.html
 
 
 Torrent VFS показывает файлы и директории из файла .torrent; все файлы,
index 43a77607ff3bd9010457fbbf44eaa4f97165ff26..3c4b8e7be2db62914ee0d39fb3d2a8d8864f670c 100644 (file)
@@ -1,3 +1,7 @@
+Version 1.3.1 (2023-08-13)
+
+   Update for Python 3.
+
 Version 1.2.4 (2018-05-18)
 
    Fix a bug in handling overflow with dates > 2038 year.
diff --git a/xml b/xml
index 0315590924c7e0356bdba72baed265ac8b06c514..fe3b5b584a3c51fe3402a71ab96c9f029cf260cb 100755 (executable)
--- a/xml
+++ b/xml
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 """XML Virtual FileSystem for Midnight Commander
 
 The script requires Midnight Commander 3.1+
@@ -14,7 +14,7 @@ file the command is "%cd"): cd file/xml://; in older versions it is
 cd file#xml, where "file" is the name of your XML file.
 
 See detailed installation instructions at
-http://phdru.name/Software/mc/xml_INSTALL.html.
+https://phdru.name/Software/mc/xml_INSTALL.html.
 
 The VFS represents tags as directories; the directories are numbered to
 distinguish tags with the same name; numbering also helps to sort tags by their
@@ -43,10 +43,11 @@ its text file to a real file.
 The VFS was inspired by a FUSE xmlfs: https://github.com/halhen/xmlfs
 
 """
+from __future__ import print_function
 
-__version__ = "1.1.5"
+__version__ = "1.2.1"
 __author__ = "Oleg Broytman <phd@phdru.name>"
-__copyright__ = "Copyright (C) 2013-2015 PhiloSoft Design"
+__copyright__ = "Copyright (C) 2013-2023 PhiloSoft Design"
 __license__ = "GPL"
 
 # Can be None for default choice, 'lxml', 'elementtree' or 'minidom'.
@@ -62,13 +63,6 @@ import sys
 from time import localtime
 import xml.dom.minidom
 
-try:
-    import xml.etree.ElementTree as ET
-except ImportError:
-    pass
-else:
-    use_elementtree = True
-
 try:
     import lxml.etree as etree
 except ImportError:
@@ -85,9 +79,12 @@ except ImportError:
 if use_locale:
     # Get the default charset.
     try:
-        lcAll = locale.getdefaultlocale()
-    except locale.Error, err:
-        print >>sys.stderr, "WARNING:", err
+        if sys.version_info[:2] < (3, 11):
+            lcAll = locale.getdefaultlocale()
+        else:
+            lcAll = []
+    except locale.Error as err:
+        print("WARNING:", err, file=sys.stderr)
         lcAll = []
 
     if len(lcAll) == 2:
@@ -95,8 +92,8 @@ if use_locale:
     else:
         try:
             default_encoding = locale.getpreferredencoding()
-        except locale.Error, err:
-            print >>sys.stderr, "WARNING:", err
+        except locale.Error as err:
+            print("WARNING:", err, file=sys.stderr)
             default_encoding = sys.getdefaultencoding()
 else:
     default_encoding = sys.getdefaultencoding()
@@ -121,6 +118,21 @@ This is not a program. Put the script in $HOME/[.local/share/].mc/extfs.d or
 
 locale.setlocale(locale.LC_ALL, '')
 
+PY3 = (sys.version_info[0] >= 3)
+if PY3:
+    def output(s):
+        sys.stdout.buffer.write(s.encode(default_encoding, 'replace') + b'\n')
+else:
+    def output(s):
+        sys.stdout.write(s + '\n')
+
+    try:
+        import xml.etree.ElementTree as ET
+    except ImportError:
+        pass
+    else:
+        use_elementtree = True
+
 
 class XmlVfs(object):
     """Abstract base class"""
@@ -137,8 +149,8 @@ class XmlVfs(object):
 
         root_comments = self.get_root_comments()
         if root_comments:
-            print "-r--r--r-- 1 user group %d %s text" % (
-                len(root_comments), self.xml_file_dt)
+            output("-r--r--r-- 1 user group %d %s text" % (
+                len(root_comments), self.xml_file_dt))
 
         self._list(self.getroot())
 
@@ -159,21 +171,20 @@ class XmlVfs(object):
                 subpath = '%s/%s %s' % (path, template % n, tag)
             else:
                 subpath = '%s %s' % (template % n, tag)
-            subpath_encoded = subpath.encode(default_encoding, "replace")
-            print "dr-xr-xr-x 1 user group 0 %s %s" % (
-                self.xml_file_dt, subpath_encoded)
+            output("dr-xr-xr-x 1 user group 0 %s %s" % (
+                self.xml_file_dt, subpath))
             if self.getattrs(element):
                 attr_text = self.attrs2text(element)
-                print "-r--r--r-- 1 user group %d %s %s/attributes" % (
-                    len(attr_text), self.xml_file_dt, subpath_encoded)
+                output("-r--r--r-- 1 user group %d %s %s/attributes" % (
+                    len(attr_text), self.xml_file_dt, subpath))
             if self.supports_namespaces and self.has_ns(element):
                 ns_text = self.ns2text(element)
-                print "-r--r--r-- 1 user group %d %s %s/namespaces" % (
-                    len(ns_text), self.xml_file_dt, subpath_encoded)
+                output("-r--r--r-- 1 user group %d %s %s/namespaces" % (
+                    len(ns_text), self.xml_file_dt, subpath))
             text = self.collect_text(element)
             if text:
-                print "-r--r--r-- 1 user group %d %s %s/text" % (
-                    len(text), self.xml_file_dt, subpath_encoded)
+                output("-r--r--r-- 1 user group %d %s %s/text" % (
+                    len(text), self.xml_file_dt, subpath))
             self._list(element, subpath)
 
     def get_tag_node(self, node, i):
@@ -188,8 +199,7 @@ class XmlVfs(object):
     def attrs2text(self, node):
         attr_accumulator = []
         for name, value in self.getattrs(node):
-            name = self.getlocalname(name).encode(default_encoding, "replace")
-            value = value.encode(default_encoding, "replace")
+            name = self.getlocalname(name)
             attr_accumulator.append("%s=%s" % (name, value))
         return '\n'.join(attr_accumulator)
 
@@ -219,7 +229,7 @@ class MiniDOMXmlVfs(XmlVfs):
                 xml_error("Unknown node type %d" % element.nodeType)
             if text:
                 text_accumulator.append(text)
-        return '\n'.join(text_accumulator).encode(default_encoding, "replace")
+        return '\n'.join(text_accumulator)
 
     def getroot(self):
         return self.document
@@ -259,8 +269,7 @@ if use_elementtree or use_lxml:
                 text = node.tail.strip()
                 if text:
                     text_accumulator.append(text)
-            return '\n'.join(text_accumulator).encode(
-                default_encoding, "replace")
+            return '\n'.join(text_accumulator)
 
         def getchildren(self, node):
             return list(node)
@@ -311,8 +320,7 @@ if use_elementtree:
                 if not self.istag(element):
                     text = u"<!--%s-->" % element.text
                     text_accumulator.append(text)
-            return '\n'.join(text_accumulator).encode(
-                default_encoding, "replace")
+            return '\n'.join(text_accumulator)
 
         def getlocalname(self, name):
             if name.startswith('{'):
@@ -336,8 +344,7 @@ if use_lxml:
                     tag=etree.Comment, preceding=True):
                 text = u"<!--%s-->" % element.text
                 text_accumulator.append(text)
-            return '\n'.join(text_accumulator).encode(
-                default_encoding, "replace")
+            return '\n'.join(text_accumulator)
 
         def getlocalname(self, name):
             return etree.QName(name).localname
@@ -358,11 +365,8 @@ if use_lxml:
         def ns2text(self, node):
             ns_accumulator = []
             for name, value in self._get_local_ns(node).items():
-                if name:
-                    name = name.encode(default_encoding, "replace")
-                else:
+                if not name:
                     name = 'xmlns'
-                value = value.encode(default_encoding, "replace")
                 ns_accumulator.append("%s=%s" % (name, value))
             return '\n'.join(ns_accumulator)
 
@@ -471,5 +475,5 @@ try:
     g[procname]()
 except SystemExit:
     raise
-except:
+except Exception:
     logger.exception("Error during run")
index 3153e24d354de301050ada2c0e4c95d8a3eb757e..8e0b2fa820c6310a6f532645fbe16d8a2ea4b0e2 100644 (file)
@@ -36,12 +36,12 @@ Version 0.3.0 (2013-11-16)
 
 
 WHERE TO GET
-   Home page: http://phdru.name/Software/mc/xml.html
-   Download:  http://phdru.name/Software/mc/xml
-    git clone http://git.phdru.name/extfs.d.git
+   Home page: https://phdru.name/Software/mc/xml.html
+   Download:  https://phdru.name/Software/mc/xml
+    git clone https://git.phdru.name/extfs.d.git
     git clone  git://git.phdru.name/extfs.d.git
 
-   Installation instructions: http://phdru.name/Software/mc/INSTALL.html
+   Installation instructions: https://phdru.name/Software/mc/INSTALL.html
 
 
 The VFS represents tags as directories; the directories are numbered to
index f2440fde833b11fc81754e6f532535d2b21f1c63..86f516b6d599c0bf629dd3336b095dc5663155e4 100644 (file)
@@ -7,12 +7,12 @@ XML VFS 
 
 
 ГДЕ
-   Дом. страничка: http://phdru.name/Russian/Software/mc/xml.html
-   Скачать:        http://phdru.name/Software/mc/xml
-    git clone http://git.phdru.name/extfs.d.git
+   Дом. страничка: https://phdru.name/Russian/Software/mc/xml.html
+   Скачать:        https://phdru.name/Software/mc/xml
+    git clone https://git.phdru.name/extfs.d.git
     git clone  git://git.phdru.name/extfs.d.git
 
-   Инструкции по установке (eng.): http://phdru.name/Software/mc/INSTALL.html
+   Инструкции по установке (eng.): https://phdru.name/Software/mc/INSTALL.html
 
 
 XML VFS показывает теги как директории; директории пронумерованы, чтобы
index 130fbbdb0132bb04dacf4e3116d5cb7c36385752..f7592eb4ee2644f75053f7bdbe84183f35b0a3a7 100644 (file)
@@ -1,3 +1,7 @@
+Version 1.2.1 (2023-08-13)
+
+   Update for Python 3.
+
 Version 1.1.5 (2015-07-08)
 
    Set directories/files date/time to the last modification time of the XML