# -*- coding: utf-8 -*-
## AttachmentField
## Copyright (C)2006 Ingeniweb
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## GNU General Public License for more details.
## You should have received a copy of the GNU General Public License
## along with this program; see the file COPYING. If not, write to the
## Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
__version__ = "$Revision: 65264 $"
# $Id: AttachmentField.py 65264 2008-05-20 14:27:22Z encolpe $
__docformat__ = 'restructuredtext'
import urllib
import string
import os
import os.path
import sys
from types import FileType, ListType, TupleType
import Acquisition
from Acquisition import aq_base
from Globals import Persistent
from Globals import MessageDialog, DTMLFile      # fakes a method from a DTML file
from Globals import InitializeClass
from AccessControl import Role
from AccessControl import ClassSecurityInfo
from AccessControl import Permissions
from AccessControl import Unauthorized
from AccessControl import getSecurityManager
from webdav.common import rfc1123_date
import OFS.SimpleItem
from OFS.ObjectManager import ObjectManager
from OFS.Traversable import Traversable
from OFS.Image import Pdata, File
from Products.AttachmentField import LOG
from global_symbols import *
    from Products.CMFCore.utils import getToolByName
    pass                # No CMF -> no charset converting
from Products.Archetypes import Field
from Products.Archetypes.utils import shasattr
from Products.Archetypes.interfaces.base import IBaseUnit
from Products.Archetypes.BaseUnit import BaseUnit
from Products.AttachmentField.interfaces.attachmentfield import IAttachmentField
import AttachmentHandler
from FlexStorage import FlexStorage
##DEFAULT_ID = "attach"
##ZAA_READ_PERMISSION = Permissions.access_contents_information
##ZAA_WRITE_PERMISSION = Permissions.change_images_and_files
#    _indexed_ = "_v_%s_AF_indexed"
#    _preview_ = "_v_%s_AF_preview"
#    _indexed_ = "_%s_AF_indexed"
#    _preview_ = "_%s_AF_preview"
_indexed_ = "_%s_AF_indexed"
_preview_ = "_%s_AF_preview"
_isindexed_ = "_%s_AF_isindexed"
_ispreview_ = "_%s_AF_ispreview"
_icon_ = "_%s_AF_icon"
_smallicon_ = "_%s_AF_smallicon"
# Zope 2.7 compatibility
    import transaction
    savepoint = transaction.savepoint
except ImportError:
    def savepoint(**kwargs):
class AttachmentField(Field.FileField):
    A base class to handle file fields. This is based on Archetypes.
    When the file is uploaded, it's stored, as the File field, as a File class.
    See FileField.set() :
        value = File(self.getName(), '', value, mimetype)
        setattr(value, 'filename', f_name or self.getName())
        ObjectField.set(self, instance, value, **kwargs)
    __implements__ = (Field.FileField.__implements__, IAttachmentField)
    security = ClassSecurityInfo()
    _properties = Field.FileField._properties.copy()
            "storage": FlexStorage()
    def get(self, instance, mimetype = None, **kwargs):
        """Get value. If mime_type is 'text/plain', we retreive the
        indexed string. If it's text/html, we get the preview back.
        if mimetype == 'text/plain':
            return self.getIndexableValue(instance)
        if mimetype == 'text/html':
            return self.getPreview(instance)
        kwargs.update({'mimetype': mimetype})
        return Field.FileField.get(self, instance, **kwargs)
    def set(self, instance, value, **kwargs):
        Assign input value to object. If mimetype is not specified,
        pass to processing method without one and add mimetype returned
        to kwargs. Assign kwargs to instance.
        ## ZEE PART 1 BEGIN
        ## XXX Here a patch for editing with Zope External Editor with all 0.9.x
        ## versions
        ## ZEE looses filename when editing and replace it by the id.
        ## This works as long as the id is not chosen or modified by an user
        request = kwargs.get('REQUEST', None)
        filename = ''
        is_bad_user_agent = False
        if request is not None:
            user_agent = request.get('HTTP_USER_AGENT', '')
            if user_agent.lower().startswith('zope external editor'):
                is_bad_user_agent = True
                filename = self.getFilename(instance)
        ## ZEE PART 1 END
        ret = Field.FileField.set(self, instance, value, **kwargs)
        ## ZEE PART 2 BEGIN
        ## Set the filename given before the ZEE commit
        if is_bad_user_agent:
            self.setFilename(instance, filename)
        ## ZEE PART 2 END
        return ret
    def getSize(self, instance):
            getSize(self, instance) => return file size
            This method should be deprecated: now, use get_size(), as seen in
        return self.get_size(instance)
    def isEmpty(self, instance):
        return true if empty
        file = self.get(instance)
        if file is None:
            return True
        if type(file) in (type(''), type(u'')):
            return not len(file)
        size = 0
            size = file.get_size()
        return not size
    def getIndexableValue(self, instance):
        getIndexableValue(self, instance) => Return the value we have to index
        # Emptyness check
        if self.isEmpty(instance):
            return ""
        # Is the indexing up-to-date ?
        name = self.getName()
        isindexed = hasattr(instance, _isindexed_ % name)
        if not isindexed:
            handler = self._getHandler(instance)
            idx = None
                idx = handler.getIndexableValue(self, instance)
                if idx:
                    setattr(instance, _indexed_ % name, idx)
                    setattr(instance, _isindexed_ % name, True)
            if not idx:
                setattr(instance, _indexed_ % name, None)
                setattr(instance, _isindexed_ % name, False)
        # Return it
        return getattr(instance, _indexed_ % name, None)
    getIndexable = getIndexableValue
    def isIndexed(self, instance):
        """return true if the document is indexed properly.
        name = self.getName()
        if hasattr(instance, _isindexed_ % name):
            return getattr(instance, _isindexed_ % name, False)
            return not not self.getIndexableValue(instance)
    def isPreviewAvailable(self, instance):
        """True if a preview is available for that
        (we can compute it immediately)
        name = self.getName()
        if hasattr(instance, _ispreview_ % name):
            return getattr(instance, _ispreview_ % name, False)
            return not not self.getPreview(instance)
    def isMultiValued(self, instance):
        """True if field is multi valued
        return isinstance(self.get(instance), (ListType, TupleType))
    def _getHandler(self, instance):
        _getHandler(self, instance) => get the handler object
        handler = AttachmentHandler.getAttachmentHandler(
            self.getContentType(instance, ),
            self, instance,
        return handler
    def getPreview(self, instance):
        """Return the preview for this object
        if self.isEmpty(instance):
            return ""
        # Compute it if necessary
        name = self.getName()
        ispreview = hasattr(instance, _ispreview_ % name)
        if not ispreview:
            handler = self._getHandler(instance)
            preview = None
                preview = handler.getPreview(self, instance, )
                if preview:
                    setattr(instance, _preview_ % name, preview, )
                    setattr(instance, _ispreview_ % name, True, )
            if not preview:
                setattr(instance, _preview_ % name, None )
                setattr(instance, _ispreview_ % name, False, )
        # Return it
        return getattr(instance, _preview_ % name, None)
    def getIcon(self, instance):
        getIcon(self, instance) => return the underlying file class icon (object)
        name = self.getName()
        icon = getattr(instance, _icon_ % name, None)
        if not icon:
            handler = self._getHandler(instance)
            LOG.debug("getIcon for %s / %s" % (self.getFilename(instance),
                                               handler.converter_type, ))
            icon = handler.getIconFile(self, instance)
            setattr(instance, _icon_ % name, icon, )
        return getattr(instance, icon, None)
    def getSmallIcon(self, instance):
        getIcon(self, instance) => return the underlying file class icon (object)
        name = self.getName()
        smallicon = getattr(instance, _smallicon_ % name, None)
        if not smallicon:
            handler = self._getHandler(instance)
            smallicon = handler.getSmallIconFile(self, instance)
            setattr(instance, _smallicon_ % name, smallicon, )
        return getattr(instance, smallicon, None)
    def _reset(self, instance, ):
        """reset volatile stuff (indexation, preview)
        name = self.getName()
        setattr(instance, _preview_ % name, None)
        setattr(instance, _indexed_ % name, None)
        setattr(instance, _ispreview_ % name, None)
        setattr(instance, _isindexed_ % name, None)
        setattr(instance, _icon_ % name, None)
        setattr(instance, _smallicon_ % name, None)
        delattr(instance, _isindexed_ % name)
        delattr(instance, _ispreview_ % name)
    def _logException(self, instance):
        if instance and hasattr(instance, 'getPhysicalPath'):
            path = '/'.join(instance.getPhysicalPath())
            filename = self.getFilename(instance)
            msg = 'EXCEPTION object: %s, file: %s: \n' % (path, filename)
            LOG.warning(msg, exc_info=True)
            LOG.warning('Exception occured', exc_info=True)
from Products.Archetypes.Registry import registerField
    description='Used for storing files with advanced features.',