--- AttachFile.py.orig	2005-11-23 13:53:27.173617264 -0600
+++ AttachFile.py	2005-11-23 15:31:18.690011096 -0600
@@ -20,10 +20,12 @@
 
     @copyright: 2001 by Ken Sugino (sugino@mediaone.net)
     @copyright: 2001-2004 by Jürgen Hermann <jh@web.de>
+    @copyright: 2005 ReimarBauer added zip file extension based on patch for 1.3.4 and DesktopEdition 1.3.4-2 by AlexanderSchremmer
+    @copyright: 2005 DiegoOngaro at ETSZONE <diego@etszone.com> Added an exception to zip file unpacking for single subdirectory cases
     @license: GNU GPL, see COPYING for details.
 """
 
-import os, mimetypes, time, urllib
+import os, mimetypes, time, urllib, zipfile
 from MoinMoin import config, user, util, wikiutil
 from MoinMoin.Page import Page
 from MoinMoin.util import MoinMoinNoFooter, filesys, web
@@ -203,6 +205,7 @@
         label_get = _("get")
         label_edit = _("edit")
         label_view = _("view")
+        label_unzip = _("unzip")
 
         for file in files:
             fsize = float(os.stat(os.path.join(attach_dir,file).encode(config.charset))[6]) # in byte
@@ -218,6 +221,7 @@
                         'urlfile': urlfile, 'label_del': label_del,
                         'base': base, 'label_edit': label_edit,
                         'label_view': label_view,
+                        'label_unzip': label_unzip,
                         'get_url': get_url, 'label_get': label_get,
                         'file': wikiutil.escape(file), 'fsize': fsize,
                         'pagename': pagename}
@@ -232,6 +236,11 @@
             else:
                 viewlink = '<a href="%(baseurl)s/%(urlpagename)s?action=%(action)s&amp;do=view&amp;target=%(urlfile)s">%(label_view)s</a>' % parmdict
 
+            if (zipfile.is_zipfile(os.path.join(attach_dir,file).encode(config.charset)) and
+                request.user.may.read(pagename) and request.user.may.delete(pagename)
+                and request.user.may.write(pagename)):
+                viewlink += ' | <a href="%(baseurl)s/%(urlpagename)s?action=%(action)s&amp;do=unzip&amp;target=%(urlfile)s">%(label_unzip)s</a>' % parmdict
+		
             parmdict['viewlink'] = viewlink
             parmdict['del_link'] = del_link
             str = str + ('<li>[%(del_link)s'
@@ -261,6 +270,29 @@
 def error_msg(pagename, request, msg):
     Page(request, pagename).send_page(request, msg=msg)
 
+def _subdir_exception(zf):
+    """
+    Checks for the existance of one common subdirectory shared among
+    all files in the zip file. If this is the case, returns a dict of
+    original names to modified names so that such files can be unpacked
+    as the user would expect.
+    """
+
+    b = zf.namelist()
+    if not '/' in b[0]:
+        return (False, 0) #No directory
+    slashoffset = b[0].index('/')
+    directory = b[0][:slashoffset]
+    for origname in b:
+        if '/' in origname and origname.rindex('/') != slashoffset:
+            return (False, 1) #Multiple directories or different length directory
+    for origname in b:
+        if origname[:slashoffset] != directory:
+	    return (False, 2) #One, same-length, but different directory
+    names = {}
+    for origname in b:
+        names[origname] = origname[slashoffset+1:]
+    return (True, names) #Returns dict of {origname: safename}
 
 #############################################################################
 ### Create parts of the Web interface
@@ -419,6 +451,11 @@
             get_file(pagename, request)
         else:
             msg = _('You are not allowed to get attachments from this page.')
+    elif request.form['do'][0] == 'unzip':
+        if request.user.may.delete(pagename) and request.user.may.read(pagename) and request.user.may.write(pagename):
+            unzip_file(pagename, request)
+        else:
+            msg = _('You are not allowed to unzip attachments of this page.')
     elif request.form['do'][0] == 'view':
         if request.user.may.read(pagename):
             view_file(pagename, request)
@@ -587,6 +624,81 @@
 
     raise MoinMoinNoFooter
 
+def unzip_file(pagename, request):
+    _ = request.getText
+    valid_pathname = lambda name: (name.find('/') == -1) and (name.find('\\') == -1)
+
+    filename, fpath = _access_file(pagename, request)
+    if not filename: return # error msg already sent in _access_file
+
+    attachment_path = getAttachDir(request, pagename)
+    single_file_size = 2.0 * 1000**2
+    attachments_file_space = 200.0 * 1000**2
+
+    files = _get_files(request, pagename)
+
+    msg = ""
+    if files:
+        fsize = 0.0
+        for file in files:
+            fsize += float(os.stat(getFilename(request, pagename, file))[6]) # in byte
+
+        available_attachments_file_space = attachments_file_space - fsize
+
+        if zipfile.is_zipfile(fpath):
+	    zf = zipfile.ZipFile(fpath)
+	    sum_size_over_all_valid_files = 0.0
+	    subdir_exception = _subdir_exception(zf)
+	    if not subdir_exception[0]:
+	        #Convert normal zf.namelist() to {origname:finalname} dict
+	        namelist = {}
+	        for name in zf.namelist():
+	            namelist[name] = name
+	    else:
+	        #Use _subdir_exception()'s {origname:finalname} dict
+	        namelist = subdir_exception[1]
+
+	    for (origname, finalname) in namelist.iteritems():
+                if valid_pathname(finalname):
+                    sum_size_over_all_valid_files += zf.getinfo(origname).file_size
+
+            if sum_size_over_all_valid_files < available_attachments_file_space:
+                valid_name = False
+                for (origname, finalname) in namelist.iteritems():
+                    if valid_pathname(finalname):
+                        zi = zf.getinfo(origname)
+                        if zi.file_size < single_file_size:
+                            new_file = getFilename(request, pagename, finalname)
+                            if not os.path.exists(new_file):
+                                outfile = open(new_file, 'wb')
+                                outfile.write(zf.read(origname))
+                                outfile.close()
+                                # it's not allowed to zip a zip file so it is dropped
+                                if zipfile.is_zipfile(new_file):
+                                    os.unlink(new_file)
+                                else:
+                                    valid_name = True
+                                    os.chmod(new_file, 0666 & config.umask)
+                                    _addLogEntry(request, 'ATTNEW', pagename, new_file)
+
+                if valid_name:
+                    msg=_("Attachment '%(filename)s' unzipped.") % {'filename': filename}
+                else:
+                    msg=_("Attachment '%(filename)s' not unzipped because the "
+                          "files are too big, .zip files only, exist already or "
+                          "reside in folders.") % {'filename': filename}
+            else:
+                msg=_("Attachment '%(filename)s' could not be unzipped because"
+                      " the resulting files would be too large (%(space)d kB"
+                      " missing).") % {'filename': filename,
+                    'space': (sum_size_over_all_valid_files -
+                              available_attachments_file_space) / 1000}
+        else:
+            msg = _('The file %(target) is not a .zip file.' % target)
+
+    upload_form(pagename, request, msg=wikiutil.escape(msg))
+    
+
 def send_viewfile(pagename, request):
     _ = request.getText
 
