From 7fc3362307737cd7c565b710ec83c5bdc4d3e8a9 Mon Sep 17 00:00:00 2001
From: Walter Purcaro <vuolter@gmail.com>
Date: Sun, 25 Jan 2015 03:05:00 +0100
Subject: Revert Extractor to the old one (temp)

---
 module/plugins/internal/Extractor.py |  79 ++++---------
 module/plugins/internal/UnRar.py     | 216 +++++++++++++++--------------------
 module/plugins/internal/UnZip.py     |  69 +++--------
 3 files changed, 133 insertions(+), 231 deletions(-)

(limited to 'module/plugins/internal')

diff --git a/module/plugins/internal/Extractor.py b/module/plugins/internal/Extractor.py
index 0b2462dac..55d9b2e83 100644
--- a/module/plugins/internal/Extractor.py
+++ b/module/plugins/internal/Extractor.py
@@ -8,52 +8,37 @@ class CRCError(Exception):
     pass
 
 
-class PasswordError(Exception):
+class WrongPassword(Exception):
     pass
 
 
 class Extractor:
     __name__    = "Extractor"
-    __version__ = "0.13"
+    __version__ = "0.14"
 
     __description__ = """Base extractor plugin"""
     __license__     = "GPLv3"
-    __authors__     = [("RaNaN", "ranan@pyload.org"),
-                       ("Walter Purcaro", "vuolter@gmail.com")]
+    __authors__     = [("pyLoad Team", "admin@pyload.org")]
 
 
-    EXTENSIONS = []
-
-
-    @classmethod
-    def checkDeps(cls):
+    @staticmethod
+    def checkDeps():
         """ Check if system statisfy dependencies
         :return: boolean
         """
         return True
 
 
-    @classmethod
-    def isArchive(cls, file):
-        raise NotImplementedError
-
-
-    @classmethod
-    def getTargets(cls, files_ids):
+    @staticmethod
+    def getTargets(files_ids):
         """ Filter suited targets from list of filename id tuple list
         :param files_ids: List of filepathes
         :return: List of targets, id tuple list
         """
-        targets = []
-
-        for file, id in files_ids:
-            if cls.isArchive(file):
-                targets.append((file, id))
-
-        return targets
+        raise NotImplementedError
 
 
-    def __init__(self, m, file, out, password, fullpath, overwrite, excludefiles, renice, delete, keepbroken):
+    def __init__(self, m, file, out, fullpath, overwrite, excludefiles, renice):
         """Initialize extractor for specific file
 
         :param m: ExtractArchive Hook plugin
@@ -63,17 +48,14 @@ class Extractor:
         :param overwrite: Overwrite existing archives
         :param renice: Renice value
         """
-        self.m            = m
-        self.file         = file
-        self.out          = out
-        self.password     = password
-        self.fullpath     = fullpath
-        self.overwrite    = overwrite
+        self.m = m
+        self.file = file
+        self.out = out
+        self.fullpath = fullpath
+        self.overwrite = overwrite
         self.excludefiles = excludefiles
-        self.renice       = renice
-        self.delete       = delete
-        self.keepbroken   = keepbroken
-        self.files        = []  #: Store extracted files here
+        self.renice = renice
+        self.files = []  #: Store extracted files here
 
 
     def init(self):
@@ -81,45 +63,32 @@ class Extractor:
         pass
 
 
-    def verify(self):
+    def checkArchive(self):
         """Check if password if needed. Raise ArchiveError if integrity is
         questionable.
 
+        :return: boolean
         :raises ArchiveError
         """
-        pass
+        return False
 
 
-    def isPassword(self, password):
+    def checkPassword(self, password):
         """ Check if the given password is/might be correct.
         If it can not be decided at this point return true.
 
         :param password:
         :return: boolean
         """
-        if isinstance(password, basestring):
-            return True
-        else:
-            return False
-
-
-    def setPassword(self, password):
-        if self.isPassword(password):
-            self.password = password
-            return True
-        else:
-            return False
-
-
-    def repair(self):
-        return False
+        return True
 
 
-    def extract(self, progress=lambda x: None):
+    def extract(self, progress, password=None):
         """Extract the archive. Raise specific errors in case of failure.
 
         :param progress: Progress function, call this to update status
-        :raises PasswordError
+        :param password password to use
+        :raises WrongPassword
         :raises CRCError
         :raises ArchiveError
         :return:
diff --git a/module/plugins/internal/UnRar.py b/module/plugins/internal/UnRar.py
index 296405101..a1b438e47 100644
--- a/module/plugins/internal/UnRar.py
+++ b/module/plugins/internal/UnRar.py
@@ -4,11 +4,11 @@ import os
 import re
 
 from glob import glob
-from os.path import basename, dirname, join
+from os.path import basename, join
 from string import digits
 from subprocess import Popen, PIPE
 
-from module.plugins.internal.Extractor import Extractor, ArchiveError, CRCError, PasswordError
+from module.plugins.internal.Extractor import Extractor, WrongPassword, ArchiveError, CRCError
 from module.utils import save_join, decode
 
 
@@ -22,142 +22,115 @@ def renice(pid, value):
 
 class UnRar(Extractor):
     __name__    = "UnRar"
-    __version__ = "1.01"
+    __version__ = "1.02"
 
     __description__ = """Rar extractor plugin"""
     __license__     = "GPLv3"
-    __authors__     = [("Walter Purcaro", "vuolter@gmail.com")]
+    __authors__     = [("RaNaN", "RaNaN@pyload.org")]
 
 
     CMD = "unrar"
 
-    EXTENSIONS = ["rar", "zip", "cab", "arj", "lzh", "tar", "gz", "bz2", "ace", "uue", "jar", "iso", "7z", "xz", "z"]
+    # there are some more uncovered rar formats
+    re_version = re.compile(r"(UNRAR 5[\d.]+(.*?)freeware)")
+    re_splitfile = re.compile(r"(.*)\.part(\d+)\.rar$", re.I)
+    re_partfiles = re.compile(r".*\.(rar|r\d+)", re.I)
+    re_filelist = re.compile(r"(.+)\s+(\d+)\s+(\d+)\s+")
+    re_filelist5 = re.compile(r"(.+)\s+(\d+)\s+\d\d-\d\d-\d\d\s+\d\d:\d\d\s+(.+)")
+    re_wrongpwd = re.compile("(Corrupt file or wrong password|password incorrect)", re.I)
 
 
-    #@NOTE: there are some more uncovered rar formats
-    re_rarpart = re.compile(r'(.*)\.part(\d+)\.rar$', re.I)
-    re_rarfile = re.compile(r'.*\.(rar|r\d+)$', re.I)
-
-    re_filelist  = re.compile(r'(.+)\s+(\d+)\s+(\d+)\s+|(.+)\s+(\d+)\s+\d\d-\d\d-\d\d\s+\d\d:\d\d\s+(.+)')
-    re_wrongpwd  = re.compile(r'password', re.I)
-    re_wrongcrc  = re.compile(r'encrypted|damaged|CRC failed|checksum error', re.I)
-
-
-    @classmethod
-    def checkDeps(cls):
+    @staticmethod
+    def checkDeps():
         if os.name == "nt":
-            cls.CMD = join(pypath, "UnRAR.exe")
-            p = Popen([cls.CMD], stdout=PIPE, stderr=PIPE)
+            UnRar.CMD = join(pypath, "UnRAR.exe")
+            p = Popen([UnRar.CMD], stdout=PIPE, stderr=PIPE)
             p.communicate()
         else:
             try:
-                p = Popen([cls.CMD], stdout=PIPE, stderr=PIPE)
+                p = Popen([UnRar.CMD], stdout=PIPE, stderr=PIPE)
                 p.communicate()
-
             except OSError:
+
                 # fallback to rar
-                cls.CMD = "rar"
-                p = Popen([cls.CMD], stdout=PIPE, stderr=PIPE)
+                UnRar.CMD = "rar"
+                p = Popen([UnRar.CMD], stdout=PIPE, stderr=PIPE)
                 p.communicate()
 
         return True
 
 
-    @classmethod
-    def isArchive(cls, file):
-        f = basename(file).lower()
-        return any(f.endswith('.%s' % ext) for ext in cls.EXTENSIONS)
-
-
-    @classmethod
-    def getTargets(cls, files_ids):
-        targets = []
+    @staticmethod
+    def getTargets(files_ids):
+        result = []
 
         for file, id in files_ids:
-            if not cls.isArchive(file):
+            if not file.endswith(".rar"):
                 continue
 
-            m = cls.re_rarpart.findall(file)
-            if m:
+            match = UnRar.re_splitfile.findall(file)
+            if match:
                 # only add first parts
-                if int(m[0][1]) == 1:
-                    targets.append((file, id))
+                if int(match[0][1]) == 1:
+                    result.append((file, id))
             else:
-                targets.append((file, id))
-
-        return targets
+                result.append((file, id))
 
+        return result
 
-    def check(self, out="", err=""):
-        if not out or not err:
-            return
 
-        if err.strip():
-            if self.re_wrongpwd.search(err):
-                raise PasswordError
+    def init(self):
+        self.passwordProtected = False
+        self.headerProtected = False  #: list files will not work without password
+        self.smallestFile = None  #: small file to test passwords
+        self.password = ""  #: save the correct password
 
-            elif self.re_wrongcrc.search(err):
-                raise CRCError
 
-            else:  #: raise error if anything is on stderr
-                raise ArchiveError(err.strip())
+    def checkArchive(self):
+        p = self.call_unrar("l", "-v", self.file)
+        out, err = p.communicate()
+        if self.re_wrongpwd.search(err):
+            self.passwordProtected = True
+            self.headerProtected = True
+            return True
 
         # output only used to check if passworded files are present
-        for attr in self.re_filelist.findall(out):
-            if attr[0].startswith("*"):
-                raise PasswordError
-
-
-    def verify(self):
-        p = self.call_cmd("l", "-v", self.file, password=self.password)
-
-        self.check(*p.communicate())
-
-        if p and p.returncode:
-            raise ArchiveError("Process terminated")
-
-        if not self.list():
-            raise ArchiveError("Empty archive")
-
-
-    def isPassword(self, password):
-        if isinstance(password, basestring):
-            p = self.call_cmd("l", "-v", self.file, password=password)
-            out, err = p.communicate()
+        if self.re_version.search(out):
+            for attr, size, name in self.re_filelist5.findall(out):
+                if attr.startswith("*"):
+                    self.passwordProtected = True
+                    return True
+        else:
+            for name, size, packed in self.re_filelist.findall(out):
+                if name.startswith("*"):
+                    self.passwordProtected = True
+                    return True
 
-            if not self.re_wrongpwd.search(err):
-                return True
+        self.listContent()
+        if not self.files:
+            raise ArchiveError("Empty Archive")
 
         return False
 
 
-    def repair(self):
-        p = self.call_cmd("rc", self.file)
-        out, err = p.communicate()
-
-        if p.returncode or err.strip():
-            p = self.call_cmd("r", self.file)
+    def checkPassword(self, password):
+        # at this point we can only verify header protected files
+        if self.headerProtected:
+            p = self.call_unrar("l", "-v", self.file, password=password)
             out, err = p.communicate()
-
-            if p.returncode or err.strip():
+            if self.re_wrongpwd.search(err):
                 return False
-            else:
-                self.file = join(dirname(self.file), re.search(r'(fixed|rebuild)\.%s' % basename(self.file), out).group(0))
 
         return True
 
 
-    def extract(self, progress=lambda x: None):
-        self.verify()
-
-        progress(0)
-
+    def extract(self, progress, password=None):
         command = "x" if self.fullpath else "e"
 
-        p = self.call_cmd(command, self.file, self.out, password=self.password)
-
+        p = self.call_unrar(command, self.file, self.out, password=password)
         renice(p.pid, self.renice)
 
+        progress(0)
         progressstring = ""
         while True:
             c = p.stdout.read(1)
@@ -165,7 +138,7 @@ class UnRar(Extractor):
             if not c:
                 break
             # reading a percentage sign -> set progress and restart
-            if c is '%':
+            if c == '%':
                 progress(int(progressstring))
                 progressstring = ""
             # not reading a digit -> therefore restart
@@ -173,43 +146,44 @@ class UnRar(Extractor):
                 progressstring = ""
             # add digit to progressstring
             else:
-                progressstring += c
-
+                progressstring = progressstring + c
         progress(100)
 
-        self.files = self.list()
-
         # retrieve stderr
-        self.check(err=p.stderr.read())
-
+        err = p.stderr.read()
+
+        if "CRC failed" in err and not password and not self.passwordProtected:
+            raise CRCError
+        elif "CRC failed" in err:
+            raise WrongPassword
+        if err.strip():  #: raise error if anything is on stderr
+            raise ArchiveError(err.strip())
         if p.returncode:
             raise ArchiveError("Process terminated")
 
+        if not self.files:
+            self.password = password
+            self.listContent()
+
 
     def getDeleteFiles(self):
         if ".part" in basename(self.file):
             return glob(re.sub("(?<=\.part)([01]+)", "*", self.file, re.I))
-
         # get files which matches .r* and filter unsuited files out
         parts = glob(re.sub(r"(?<=\.r)ar$", "*", self.file, re.I))
+        return filter(lambda x: self.re_partfiles.match(x), parts)
 
-        return filter(lambda x: self.re_rarfile.match(x), parts)
 
-
-    def list(self):
+    def listContent(self):
         command = "vb" if self.fullpath else "lb"
-
-        p = self.call_cmd(command, "-v", self.file, password=self.password)
+        p = self.call_unrar(command, "-v", self.file, password=self.password)
         out, err = p.communicate()
 
-        if err.strip():
-            self.m.logError(err)
-            if "Cannot open" in err:
-                return list()
+        if "Cannot open" in err:
+            raise ArchiveError("Cannot open file")
 
-        if p.returncode:
-            self.m.logError("Process terminated")
-            return list()
+        if err.strip():  #: only log error at this point
+            self.m.logError(err.strip())
 
         result = set()
 
@@ -217,22 +191,17 @@ class UnRar(Extractor):
             f = f.strip()
             result.add(save_join(self.out, f))
 
-        return list(result)
+        self.files = result
 
 
-    def call_cmd(self, command, *xargs, **kwargs):
+    def call_unrar(self, command, *xargs, **kwargs):
         args = []
-
         # overwrite flag
-        if self.overwrite:
-            args.append("-o+")
-        else:
-            args.append("-o-")
-            if self.delete:
-                args.append("-or")
+        args.append("-o+") if self.overwrite else args.append("-o-")
 
-        for word in self.excludefiles:
-            args.append("-x%s" % word.strip())
+        if self.excludefiles:
+            for word in self.excludefiles.split(';'):
+                args.append("-x%s" % word)
 
         # assume yes on all queries
         args.append("-y")
@@ -243,11 +212,10 @@ class UnRar(Extractor):
         else:
             args.append("-p-")
 
-        if self.keepbroken:
-            args.append("-kb")
-
         # NOTE: return codes are not reliable, some kind of threading, cleanup whatever issue
         call = [self.CMD, command] + args + list(xargs)
         self.m.logDebug(" ".join(call))
 
-        return Popen(call, stdout=PIPE, stderr=PIPE)
+        p = Popen(call, stdout=PIPE, stderr=PIPE)
+
+        return p
diff --git a/module/plugins/internal/UnZip.py b/module/plugins/internal/UnZip.py
index 5ec56cbdf..888ae7ebe 100644
--- a/module/plugins/internal/UnZip.py
+++ b/module/plugins/internal/UnZip.py
@@ -1,86 +1,51 @@
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-
 import sys
 import zipfile
 
-from module.plugins.internal.Extractor import Extractor, ArchiveError, CRCError, PasswordError
+from module.plugins.internal.Extractor import Extractor, WrongPassword, ArchiveError
 
 
 class UnZip(Extractor):
     __name__    = "UnZip"
-    __version__ = "1.01"
+    __version__ = "1.02"
 
     __description__ = """Zip extractor plugin"""
     __license__     = "GPLv3"
-    __authors__     = [("Walter Purcaro", "vuolter@gmail.com")]
-
-
-    EXTENSIONS = ["zip", "zip64"]
+    __authors__     = [("RaNaN", "RaNaN@pyload.org")]
 
 
-    @classmethod
-    def checkDeps(cls):
+    @staticmethod
+    def checkDeps():
         return sys.version_info[:2] >= (2, 6)
 
 
-    @classmethod
-    def isArchive(cls, file):
-        return zipfile.is_zipfile(file)
+    @staticmethod
+    def getTargets(files_ids):
+        result = []
 
+        for file, id in files_ids:
+            if file.endswith(".zip"):
+                result.append((file, id))
 
-    def verify(self):
-        try:
-            with zipfile.ZipFile(self.file, 'r', allowZip64=True) as z:
-                z.setpassword(self.password)
-                badcrc = z.testzip()
+        return result
 
-        except (BadZipfile, LargeZipFile), e:
-            raise ArchiveError(e)
 
-        except RuntimeError, e:
-            if 'encrypted' in e:
-                raise PasswordError
-            else:
-                raise ArchiveError(e)
-
-        else:
-            if badcrc:
-                raise CRCError
-
-        if not self.list():
-            raise ArchiveError("Empty archive")
-
-
-    def list(self):
+    def extract(self, progress, password=None):
         try:
-            with zipfile.ZipFile(self.file, 'r', allowZip64=True) as z:
-                z.setpassword(self.password)
-                return z.namelist()
-        except Exception:
-            return list()
-
-
-    def extract(self, progress=lambda x: None):
-        try:
-            with zipfile.ZipFile(self.file, 'r', allowZip64=True) as z:
-                progress(0)
-                z.extractall(self.out, pwd=self.password)
-                progress(100)
+            z = zipfile.ZipFile(self.file)
+            self.files = z.namelist()
+            z.extractall(self.out, pwd=password)
 
         except (BadZipfile, LargeZipFile), e:
             raise ArchiveError(e)
 
         except RuntimeError, e:
             if e is "Bad password for file":
-                raise PasswordError
+                raise WrongPassword
             else:
                 raise ArchiveError(e)
 
-        finally:
-            self.files = self.list()
-
 
     def getDeleteFiles(self):
         return [self.file]
-- 
cgit v1.2.3