[geeklog-cvs] Geeklog-1.x/public_html/fckeditor/editor/filemanager/connectors/py config.py, NONE, 1.1 connector.py, NONE, 1.1 fckcommands.py, NONE, 1.1 fckconnector.py, NONE, 1.1 fckoutput.py, NONE, 1.1 fckutil.py, NONE, 1.1 htaccess.txt, NONE, 1.1 upload.py, NONE, 1.1 wsgi.py, NONE, 1.1 zope.py, NONE, 1.1

Blaine Lang blaine at qs1489.pair.com
Sat Feb 9 07:54:02 EST 2008


Update of /cvsroot/geeklog/Geeklog-1.x/public_html/fckeditor/editor/filemanager/connectors/py
In directory qs1489.pair.com:/tmp/cvs-serv26402/editor/filemanager/connectors/py

Added Files:
	config.py connector.py fckcommands.py fckconnector.py 
	fckoutput.py fckutil.py htaccess.txt upload.py wsgi.py zope.py 
Log Message:
Upgrade to v2.5.1 of FCKeditor

--- NEW FILE: config.py ---
#!/usr/bin/env python
"""
 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
 * Copyright (C) 2003-2007 Frederico Caldeira Knabben
 *
 * == BEGIN LICENSE ==
 *
 * Licensed under the terms of any of the following licenses at your
 * choice:
 *
 *  - GNU General Public License Version 2 or later (the "GPL")
 *    http://www.gnu.org/licenses/gpl.html
 *
 *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
 *    http://www.gnu.org/licenses/lgpl.html
 *
 *  - Mozilla Public License Version 1.1 or later (the "MPL")
 *    http://www.mozilla.org/MPL/MPL-1.1.html
 *
 * == END LICENSE ==
 *
 * Configuration file for the File Manager Connector for Python 
"""

# INSTALLATION NOTE: You must set up your server environment accordingly to run 
# python scripts. This connector requires Python 2.4 or greater.
# 
# Supported operation modes: 
#  * WSGI (recommended): You'll need apache + mod_python + modpython_gateway 
#                        or any web server capable of the WSGI python standard
#  * Plain Old CGI:      Any server capable of running standard python scripts
#                        (although mod_python is recommended for performance)
#                        This was the previous connector version operation mode
#
# If you're using Apache web server, replace the htaccess.txt to to .htaccess, 
# and set the proper options and paths.
# For WSGI and mod_python, you may need to download modpython_gateway from:
# http://projects.amor.org/misc/svn/modpython_gateway.py and copy it in this 
# directory.

   
# SECURITY: You must explicitly enable this "connector". (Set it to "True").
# WARNING: don't just set "ConfigIsEnabled = True", you must be sure that only 
#		authenticated users can access this file or use some kind of session checking.
Enabled = False

# Path to user files relative to the document root.
UserFilesPath = '/userfiles/' 

# Fill the following value it you prefer to specify the absolute path for the
# user files directory. Useful if you are using a virtual directory, symbolic
# link or alias. Examples: 'C:\\MySite\\userfiles\\' or '/root/mysite/userfiles/'.
# Attention: The above 'UserFilesPath' must point to the same directory.
# WARNING: GetRootPath may not work in virtual or mod_python configurations, and
# may not be thread safe. Use this configuration parameter instead.
UserFilesAbsolutePath = '' 

# Due to security issues with Apache modules, it is recommended to leave the
# following setting enabled.
ForceSingleExtension = True 

# What the user can do with this connector
ConfigAllowedCommands = [ 'QuickUpload', 'FileUpload', 'GetFolders', 'GetFoldersAndFiles', 'CreateFolder' ] 

# Allowed Resource Types
ConfigAllowedTypes = ['File', 'Image', 'Flash', 'Media'] 

# Do not touch this 3 lines, see "Configuration settings for each Resource Type"
AllowedExtensions = {}; DeniedExtensions = {};
FileTypesPath = {}; FileTypesAbsolutePath = {};
QuickUploadPath = {}; QuickUploadAbsolutePath = {};

#	Configuration settings for each Resource Type
#
#	- AllowedExtensions: the possible extensions that can be allowed. 
#		If it is empty then any file type can be uploaded.
#	- DeniedExtensions: The extensions that won't be allowed. 
#		If it is empty then no restrictions are done here.
#
#	For a file to be uploaded it has to fulfill both the AllowedExtensions
#	and DeniedExtensions (that's it: not being denied) conditions.
#
#	- FileTypesPath: the virtual folder relative to the document root where
#		these resources will be located. 
#		Attention: It must start and end with a slash: '/'
#
#	- FileTypesAbsolutePath: the physical path to the above folder. It must be
#		an absolute path. 
#		If it's an empty string then it will be autocalculated.
#		Useful if you are using a virtual directory, symbolic link or alias. 
#		Examples: 'C:\\MySite\\userfiles\\' or '/root/mysite/userfiles/'.
#		Attention: The above 'FileTypesPath' must point to the same directory.
#		Attention: It must end with a slash: '/'
#
#
#	- QuickUploadPath: the virtual folder relative to the document root where
#		these resources will be uploaded using the Upload tab in the resources 
#		dialogs.
#		Attention: It must start and end with a slash: '/'
#
#	- QuickUploadAbsolutePath: the physical path to the above folder. It must be
#		an absolute path. 
#		If it's an empty string then it will be autocalculated.
#		Useful if you are using a virtual directory, symbolic link or alias. 
#		Examples: 'C:\\MySite\\userfiles\\' or '/root/mysite/userfiles/'.
#		Attention: The above 'QuickUploadPath' must point to the same directory.
#		Attention: It must end with a slash: '/'

AllowedExtensions['File'] 		= ['7z','aiff','asf','avi','bmp','csv','doc','fla','flv','gif','gz','gzip','jpeg','jpg','mid','mov','mp3','mp4','mpc','mpeg','mpg','ods','odt','pdf','png','ppt','pxd','qt','ram','rar','rm','rmi','rmvb','rtf','sdc','sitd','swf','sxc','sxw','tar','tgz','tif','tiff','txt','vsd','wav','wma','wmv','xls','xml','zip']
DeniedExtensions['File'] 		= []
FileTypesPath['File'] 			= UserFilesPath + 'file/' 
FileTypesAbsolutePath['File'] 	= (not UserFilesAbsolutePath == '') and (UserFilesAbsolutePath + 'file/') or ''
QuickUploadPath['File']			= FileTypesPath['File']
QuickUploadAbsolutePath['File']	= FileTypesAbsolutePath['File']

AllowedExtensions['Image']		= ['bmp','gif','jpeg','jpg','png']
DeniedExtensions['Image']		= []
FileTypesPath['Image']			= UserFilesPath + 'image/' 
FileTypesAbsolutePath['Image']	= (not UserFilesAbsolutePath == '') and UserFilesAbsolutePath + 'image/' or ''
QuickUploadPath['Image']		= FileTypesPath['Image']
QuickUploadAbsolutePath['Image']= FileTypesAbsolutePath['Image']

AllowedExtensions['Flash']		= ['swf','flv']
DeniedExtensions['Flash']		= []
FileTypesPath['Flash']			= UserFilesPath + 'flash/'
FileTypesAbsolutePath['Flash']	= ( not UserFilesAbsolutePath == '') and UserFilesAbsolutePath + 'flash/' or ''
QuickUploadPath['Flash']		= FileTypesPath['Flash']
QuickUploadAbsolutePath['Flash']= FileTypesAbsolutePath['Flash']

AllowedExtensions['Media']		= ['aiff','asf','avi','bmp','fla', 'flv','gif','jpeg','jpg','mid','mov','mp3','mp4','mpc','mpeg','mpg','png','qt','ram','rm','rmi','rmvb','swf','tif','tiff','wav','wma','wmv']
DeniedExtensions['Media']		= []
FileTypesPath['Media']			= UserFilesPath + 'media/'
FileTypesAbsolutePath['Media']	= ( not UserFilesAbsolutePath == '') and UserFilesAbsolutePath + 'media/' or ''
QuickUploadPath['Media']		= FileTypesPath['Media']
QuickUploadAbsolutePath['Media']= FileTypesAbsolutePath['Media']

--- NEW FILE: zope.py ---
#!/usr/bin/env python

"""
FCKeditor - The text editor for Internet - http://www.fckeditor.net
Copyright (C) 2003-2007 Frederico Caldeira Knabben

== BEGIN LICENSE ==

Licensed under the terms of any of the following licenses at your
choice:

- GNU General Public License Version 2 or later (the "GPL")
http://www.gnu.org/licenses/gpl.html

- GNU Lesser General Public License Version 2.1 or later (the "LGPL")
http://www.gnu.org/licenses/lgpl.html

- Mozilla Public License Version 1.1 or later (the "MPL")
http://www.mozilla.org/MPL/MPL-1.1.html

== END LICENSE ==

Connector for Python and Zope.

This code was not tested at all.
It just was ported from pre 2.5 release, so for further reference see 
\editor\filemanager\browser\default\connectors\py\connector.py in previous 
releases.

"""

from fckutil import *
from connector import *
import config as Config

class FCKeditorConnectorZope(FCKeditorConnector):
	"""
	Zope versiof FCKeditorConnector
	"""
	# Allow access (Zope)
	__allow_access_to_unprotected_subobjects__ = 1

	def __init__(self, context=None):
		"""
		Constructor
		"""
		FCKeditorConnector.__init__(self, environ=None) # call superclass constructor
		# Instance Attributes
		self.context = context
		self.request = FCKeditorRequest(context)
	
	def getZopeRootContext(self):
		if self.zopeRootContext is None:
			self.zopeRootContext = self.context.getPhysicalRoot()
		return self.zopeRootContext

	def getZopeUploadContext(self):
		if self.zopeUploadContext is None:
			folderNames = self.userFilesFolder.split("/")
			c = self.getZopeRootContext()
			for folderName in folderNames:
				if (folderName <> ""):
					c = c[folderName]
			self.zopeUploadContext = c
		return self.zopeUploadContext

	def setHeader(self, key, value):
		self.context.REQUEST.RESPONSE.setHeader(key, value)

	def getFolders(self, resourceType, currentFolder):
		# Open the folders node
		s = ""
		s += """<Folders>"""
		zopeFolder = self.findZopeFolder(resourceType, currentFolder)
		for (name, o) in zopeFolder.objectItems(["Folder"]):
			s += """<Folder name="%s" />""" % (
					convertToXmlAttribute(name)
					)
		# Close the folders node
		s += """</Folders>"""
		return s

	def getZopeFoldersAndFiles(self, resourceType, currentFolder):
		folders = self.getZopeFolders(resourceType, currentFolder)
		files = self.getZopeFiles(resourceType, currentFolder)
		s = folders + files
		return s

	def getZopeFiles(self, resourceType, currentFolder):
		# Open the files node
		s = ""
		s += """<Files>"""
		zopeFolder = self.findZopeFolder(resourceType, currentFolder)
		for (name, o) in zopeFolder.objectItems(["File","Image"]):
			s += """<File name="%s" size="%s" />""" % (
					convertToXmlAttribute(name),
					((o.get_size() / 1024) + 1)
					)
		# Close the files node
		s += """</Files>"""
		return s

	def findZopeFolder(self, resourceType, folderName):
		# returns the context of the resource / folder
		zopeFolder = self.getZopeUploadContext()
		folderName = self.removeFromStart(folderName, "/")
		folderName = self.removeFromEnd(folderName, "/")
		if (resourceType <> ""):
			try:
				zopeFolder = zopeFolder[resourceType]
			except:
				zopeFolder.manage_addProduct["OFSP"].manage_addFolder(id=resourceType, title=resourceType)
				zopeFolder = zopeFolder[resourceType]
		if (folderName <> ""):
			folderNames = folderName.split("/")
			for folderName in folderNames:
				zopeFolder = zopeFolder[folderName]
		return zopeFolder

	def createFolder(self, resourceType, currentFolder):
		# Find out where we are
		zopeFolder = self.findZopeFolder(resourceType, currentFolder)
		errorNo = 0
		errorMsg = ""
		if self.request.has_key("NewFolderName"):
			newFolder = self.request.get("NewFolderName", None)
			zopeFolder.manage_addProduct["OFSP"].manage_addFolder(id=newFolder, title=newFolder)
		else:
			errorNo = 102
		return self.sendErrorNode ( errorNo, errorMsg )

	def uploadFile(self, resourceType, currentFolder, count=None):
		zopeFolder = self.findZopeFolder(resourceType, currentFolder)
		file = self.request.get("NewFile", None)
		fileName = self.getFileName(file.filename)
		fileNameOnly = self.removeExtension(fileName)
		fileExtension = self.getExtension(fileName).lower()
		if (count):
			nid = "%s.%s.%s" % (fileNameOnly, count, fileExtension)
		else:
			nid = fileName
		title = nid
		try:
			zopeFolder.manage_addProduct['OFSP'].manage_addFile(
					id=nid,
					title=title,
					file=file.read()
					)
		except:
			if (count):
				count += 1
			else:
				count = 1
			return self.zopeFileUpload(resourceType, currentFolder, count)
		return self.sendUploadResults( 0 )

class FCKeditorRequest(object):
	"A wrapper around the request object"
	def __init__(self, context=None):
		r = context.REQUEST
		self.request = r

	def has_key(self, key):
		return self.request.has_key(key)

	def get(self, key, default=None):
		return self.request.get(key, default)

"""
Running from zope, you will need to modify this connector.
If you have uploaded the FCKeditor into Zope (like me), you need to
move this connector out of Zope, and replace the "connector" with an
alias as below.  The key to it is to pass the Zope context in, as
we then have a like to the Zope context.

## Script (Python) "connector.py"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=*args, **kws
##title=ALIAS
##

import Products.zope as connector
return connector.FCKeditorConnectorZope(context=context).doResponse()
"""


--- NEW FILE: upload.py ---
#!/usr/bin/env python

"""
FCKeditor - The text editor for Internet - http://www.fckeditor.net
Copyright (C) 2003-2007 Frederico Caldeira Knabben

== BEGIN LICENSE ==

Licensed under the terms of any of the following licenses at your
choice:

- GNU General Public License Version 2 or later (the "GPL")
http://www.gnu.org/licenses/gpl.html

- GNU Lesser General Public License Version 2.1 or later (the "LGPL")
http://www.gnu.org/licenses/lgpl.html

- Mozilla Public License Version 1.1 or later (the "MPL")
http://www.mozilla.org/MPL/MPL-1.1.html

== END LICENSE ==

This is the "File Uploader" for Python

"""
import os

from fckutil import *
from fckcommands import * 	# default command's implementation
from fckconnector import FCKeditorConnectorBase # import base connector
import config as Config

class FCKeditorQuickUpload(	FCKeditorConnectorBase,
							UploadFileCommandMixin, 
							BaseHttpMixin, BaseHtmlMixin):	
	def doResponse(self):
		"Main function. Process the request, set headers and return a string as response."
		# Check if this connector is disabled
		if not(Config.Enabled):
			return self.sendUploadResults(1, "This file uploader is disabled. Please check the \"editor/filemanager/connectors/py/config.py\"")
		command = 'QuickUpload'
		# The file type (from the QueryString, by default 'File').
		resourceType  = self.request.get('Type','File')
		currentFolder = getCurrentFolder(self.request.get("CurrentFolder",""))
		# Check for invalid paths
		if currentFolder is None:
			return self.sendUploadResults(102, '', '', "")

		# Check if it is an allowed command
		if ( not command in Config.ConfigAllowedCommands ):
			return self.sendUploadResults( 1, '', '', 'The %s command isn\'t allowed' % command ) 
		
		if ( not resourceType in Config.ConfigAllowedTypes  ):
			return self.sendUploadResults( 1, '', '', 'Invalid type specified' ) 

		# Setup paths
		self.userFilesFolder = Config.QuickUploadAbsolutePath[resourceType] 
		self.webUserFilesFolder =  Config.QuickUploadPath[resourceType]	
		if not self.userFilesFolder: # no absolute path given (dangerous...)
			self.userFilesFolder = mapServerPath(self.environ, 
									self.webUserFilesFolder)
		
		# Ensure that the directory exists.
		if not os.path.exists(self.userFilesFolder):
			try:
				self.createServerFoldercreateServerFolder( self.userFilesFolder ) 
			except:
				return self.sendError(1, "This connector couldn\'t access to local user\'s files directories.  Please check the UserFilesAbsolutePath in \"editor/filemanager/connectors/py/config.py\" and try again. ")			

		# File upload doesn't have to return XML, so intercept here
		return self.uploadFile(resourceType, currentFolder)

# Running from command line (plain old CGI)
if __name__ == '__main__':
	try:
		# Create a Connector Instance
		conn = FCKeditorQuickUpload()
		data = conn.doResponse()
		for header in conn.headers:
			if not header is None:
				print '%s: %s' % header
		print 
		print data
	except:
		print "Content-Type: text/plain"
		print
		import cgi
		cgi.print_exception()

--- NEW FILE: connector.py ---
#!/usr/bin/env python

"""
FCKeditor - The text editor for Internet - http://www.fckeditor.net
Copyright (C) 2003-2007 Frederico Caldeira Knabben

== BEGIN LICENSE ==

Licensed under the terms of any of the following licenses at your
choice:

 - GNU General Public License Version 2 or later (the "GPL")
   http://www.gnu.org/licenses/gpl.html

 - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
   http://www.gnu.org/licenses/lgpl.html

 - Mozilla Public License Version 1.1 or later (the "MPL")
   http://www.mozilla.org/MPL/MPL-1.1.html

== END LICENSE ==

Connector for Python (CGI and WSGI).

See config.py for configuration settings

"""
import os

from fckutil import *
from fckcommands import * 	# default command's implementation
from fckoutput import * 	# base http, xml and html output mixins
from fckconnector import FCKeditorConnectorBase # import base connector
import config as Config

class FCKeditorConnector(	FCKeditorConnectorBase,
							GetFoldersCommandMixin,
							GetFoldersAndFilesCommandMixin,
							CreateFolderCommandMixin,
							UploadFileCommandMixin, 
							BaseHttpMixin, BaseXmlMixin, BaseHtmlMixin  ):
	"The Standard connector class."
	def doResponse(self):
		"Main function. Process the request, set headers and return a string as response."
		s = ""
		# Check if this connector is disabled
		if not(Config.Enabled):
			return self.sendError(1, "This connector is disabled.  Please check the connector configurations in \"editor/filemanager/connectors/py/config.py\" and try again.")
		# Make sure we have valid inputs
		for key in ("Command","Type","CurrentFolder"):
			if not self.request.has_key (key):
				return
		# Get command, resource type and current folder
		command = self.request.get("Command")
		resourceType = self.request.get("Type")
		currentFolder = getCurrentFolder(self.request.get("CurrentFolder"))
		# Check for invalid paths
		if currentFolder is None:
			return self.sendError(102, "")
		
		# Check if it is an allowed command
		if ( not command in Config.ConfigAllowedCommands ):
			return self.sendError( 1, 'The %s command isn\'t allowed' % command ) 
		
		if ( not resourceType in Config.ConfigAllowedTypes  ):
			return self.sendError( 1, 'Invalid type specified' ) 

		# Setup paths
		if command == "QuickUpload":
			self.userFilesFolder = Config.QuickUploadAbsolutePath[resourceType] 
			self.webUserFilesFolder =  Config.QuickUploadPath[resourceType]
		else:
			self.userFilesFolder = Config.FileTypesAbsolutePath[resourceType]
			self.webUserFilesFolder = Config.FileTypesPath[resourceType]	
		
		if not self.userFilesFolder: # no absolute path given (dangerous...)
			self.userFilesFolder = mapServerPath(self.environ, 
									self.webUserFilesFolder)
		# Ensure that the directory exists.
		if not os.path.exists(self.userFilesFolder):
			try:
				self.createServerFoldercreateServerFolder( self.userFilesFolder ) 
			except:
				return self.sendError(1, "This connector couldn\'t access to local user\'s files directories.  Please check the UserFilesAbsolutePath in \"editor/filemanager/connectors/py/config.py\" and try again. ")

		# File upload doesn't have to return XML, so intercept here
		if (command == "FileUpload"):
			return self.uploadFile(resourceType, currentFolder)
		
		# Create Url
		url = combinePaths( self.webUserFilesFolder, currentFolder )
		
		# Begin XML
		s += self.createXmlHeader(command, resourceType, currentFolder, url)
		# Execute the command
		selector = {"GetFolders": self.getFolders,
					"GetFoldersAndFiles": self.getFoldersAndFiles,
					"CreateFolder": self.createFolder,
					}
		s += selector[command](resourceType, currentFolder)
		s += self.createXmlFooter()
		return s	
	
# Running from command line (plain old CGI)
if __name__ == '__main__':
	try:
		# Create a Connector Instance
		conn = FCKeditorConnector()
		data = conn.doResponse()
		for header in conn.headers:
			print '%s: %s' % header
		print 
		print data
	except:
		print "Content-Type: text/plain"
		print
		import cgi
		cgi.print_exception()

--- NEW FILE: fckcommands.py ---
#!/usr/bin/env python

"""
FCKeditor - The text editor for Internet - http://www.fckeditor.net
Copyright (C) 2003-2007 Frederico Caldeira Knabben

== BEGIN LICENSE ==

Licensed under the terms of any of the following licenses at your
choice:

- GNU General Public License Version 2 or later (the "GPL")
http://www.gnu.org/licenses/gpl.html

- GNU Lesser General Public License Version 2.1 or later (the "LGPL")
http://www.gnu.org/licenses/lgpl.html

- Mozilla Public License Version 1.1 or later (the "MPL")
http://www.mozilla.org/MPL/MPL-1.1.html

== END LICENSE ==

Connector for Python (CGI and WSGI).

"""

import os
try: # Windows needs stdio set for binary mode for file upload to work.
	import msvcrt
	msvcrt.setmode (0, os.O_BINARY) # stdin  = 0
	msvcrt.setmode (1, os.O_BINARY) # stdout = 1
except ImportError:
	pass

from fckutil import *
from fckoutput import *
import config as Config

class GetFoldersCommandMixin (object):
	def getFolders(self, resourceType, currentFolder):
		"""
		Purpose: command to recieve a list of folders
		"""
		# Map the virtual path to our local server
		serverPath = mapServerFolder(self.userFilesFolder,currentFolder)
		s = """<Folders>"""	 # Open the folders node
		for someObject in os.listdir(serverPath):
			someObjectPath = mapServerFolder(serverPath, someObject)
			if os.path.isdir(someObjectPath):
				s += """<Folder name="%s" />""" % (
						convertToXmlAttribute(someObject)
						)
		s += """</Folders>""" # Close the folders node
		return s

class GetFoldersAndFilesCommandMixin (object):
	def getFoldersAndFiles(self, resourceType, currentFolder):
		"""
		Purpose: command to recieve a list of folders and files
		"""
		# Map the virtual path to our local server
		serverPath = mapServerFolder(self.userFilesFolder,currentFolder)
		# Open the folders / files node
		folders = """<Folders>"""
		files = """<Files>"""
		for someObject in os.listdir(serverPath):
			someObjectPath = mapServerFolder(serverPath, someObject)
			if os.path.isdir(someObjectPath):
				folders += """<Folder name="%s" />""" % (
						convertToXmlAttribute(someObject)
						)
			elif os.path.isfile(someObjectPath):
				size = os.path.getsize(someObjectPath)
				files += """<File name="%s" size="%s" />""" % (
						convertToXmlAttribute(someObject),
						os.path.getsize(someObjectPath)
						)
		# Close the folders / files node
		folders += """</Folders>"""
		files += """</Files>"""
		return folders + files

class CreateFolderCommandMixin (object):
	def createFolder(self, resourceType, currentFolder):
		"""
		Purpose: command to create a new folder
		"""
		errorNo = 0; errorMsg ='';
		if self.request.has_key("NewFolderName"):
			newFolder = self.request.get("NewFolderName", None)
			newFolder = sanitizeFolderName (newFolder)
			try:
				newFolderPath = mapServerFolder(self.userFilesFolder, combinePaths(currentFolder, newFolder))
				self.createServerFolder(newFolderPath)
			except Exception, e:
				errorMsg = str(e).decode('iso-8859-1').encode('utf-8') # warning with encodigns!!!
				if hasattr(e,'errno'):
					if e.errno==17: #file already exists
						errorNo=0
					elif e.errno==13: # permission denied
						errorNo = 103
					elif e.errno==36 or e.errno==2 or e.errno==22: # filename too long / no such file / invalid name
						errorNo = 102 
				else:
					errorNo = 110
		else:
			errorNo = 102
		return self.sendErrorNode ( errorNo, errorMsg )

	def createServerFolder(self, folderPath):
		"Purpose: physically creates a folder on the server"
		# No need to check if the parent exists, just create all hierachy
		oldumask = os.umask(0)
		os.makedirs(folderPath,mode=0755)
		os.umask( oldumask ) 

class UploadFileCommandMixin (object):
	def uploadFile(self, resourceType, currentFolder):
		"""
		Purpose: command to upload files to server (same as FileUpload)
		"""
		errorNo = 0
		if self.request.has_key("NewFile"):
			# newFile has all the contents we need
			newFile = self.request.get("NewFile", "")
			# Get the file name
			newFileName = newFile.filename
			newFileName = sanitizeFileName( newFileName ) 
			newFileNameOnly = removeExtension(newFileName)
			newFileExtension = getExtension(newFileName).lower()
			allowedExtensions = Config.AllowedExtensions[resourceType]
			deniedExtensions = Config.DeniedExtensions[resourceType]

			if (allowedExtensions):
				# Check for allowed
				isAllowed = False
				if (newFileExtension in allowedExtensions):
					isAllowed = True
			elif (deniedExtensions):
				# Check for denied
				isAllowed = True
				if (newFileExtension in deniedExtensions):
					isAllowed = False
			else:
				# No extension limitations
				isAllowed = True

			if (isAllowed):
				# Upload to operating system
				# Map the virtual path to the local server path
				currentFolderPath = mapServerFolder(self.userFilesFolder, currentFolder)
				i = 0
				while (True):
					newFilePath = os.path.join (currentFolderPath,newFileName)
					if os.path.exists(newFilePath):
						i += 1
						newFileName = "%s(%04d).%s" % (
								newFileNameOnly, i, newFileExtension
								)
						errorNo= 201 # file renamed
					else:
						# Read file contents and write to the desired path (similar to php's move_uploaded_file)
						fout = file(newFilePath, 'wb')
						while (True):
							chunk = newFile.file.read(100000)
							if not chunk: break
							fout.write (chunk)
						fout.close()

						if os.path.exists ( newFilePath ):
							oldumask = os.umask(0) 
							os.chmod( newFilePath, 0755 ) 
							os.umask( oldumask ) 

						newFileUrl = self.webUserFilesFolder + currentFolder + newFileName

						return self.sendUploadResults( errorNo , newFileUrl, newFileName )
			else:
				return self.sendUploadResults( errorNo = 203, customMsg = "Extension not allowed" )
		else:
			return self.sendUploadResults( errorNo = 202, customMsg = "No File" )

--- NEW FILE: wsgi.py ---
#!/usr/bin/env python

"""
FCKeditor - The text editor for Internet - http://www.fckeditor.net
Copyright (C) 2003-2007 Frederico Caldeira Knabben

== BEGIN LICENSE ==

Licensed under the terms of any of the following licenses at your
choice:

 - GNU General Public License Version 2 or later (the "GPL")
   http://www.gnu.org/licenses/gpl.html

 - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
   http://www.gnu.org/licenses/lgpl.html

 - Mozilla Public License Version 1.1 or later (the "MPL")
   http://www.mozilla.org/MPL/MPL-1.1.html

== END LICENSE ==

Connector/QuickUpload for Python (WSGI wrapper).

See config.py for configuration settings

"""

from connector import FCKeditorConnector
from upload import FCKeditorQuickUpload

import cgitb
from cStringIO import StringIO

# Running from WSGI capable server (recomended)
def App(environ, start_response): 
	"WSGI entry point. Run the connector"
	if environ['SCRIPT_NAME'].endswith("connector.py"):
		conn = FCKeditorConnector(environ)
	elif environ['SCRIPT_NAME'].endswith("upload.py"):
		conn = FCKeditorQuickUpload(environ)
	else:
		start_response ("200 Ok", [('Content-Type','text/html')])
		yield "Unknown page requested: "
		yield environ['SCRIPT_NAME']
		return
	try:
		# run the connector
		data = conn.doResponse()
		# Start WSGI response:
		start_response ("200 Ok", conn.headers)
		# Send response text
		yield data
	except:
		start_response("500 Internal Server Error",[("Content-type","text/html")])
		file = StringIO()
		cgitb.Hook(file = file).handle()    
		yield file.getvalue()

--- NEW FILE: fckconnector.py ---
#!/usr/bin/env python

"""
FCKeditor - The text editor for Internet - http://www.fckeditor.net
Copyright (C) 2003-2007 Frederico Caldeira Knabben

== BEGIN LICENSE ==

Licensed under the terms of any of the following licenses at your
choice:

- GNU General Public License Version 2 or later (the "GPL")
http://www.gnu.org/licenses/gpl.html

- GNU Lesser General Public License Version 2.1 or later (the "LGPL")
http://www.gnu.org/licenses/lgpl.html

- Mozilla Public License Version 1.1 or later (the "MPL")
http://www.mozilla.org/MPL/MPL-1.1.html

== END LICENSE ==

Base Connector for Python (CGI and WSGI).

See config.py for configuration settings

"""
import cgi, os

from fckutil import *
from fckcommands import * 	# default command's implementation
from fckoutput import * 	# base http, xml and html output mixins
import config as Config

class FCKeditorConnectorBase( object ):
	"The base connector class. Subclass it to extend functionality (see Zope example)"

	def __init__(self, environ=None):
		"Constructor: Here you should parse request fields, initialize variables, etc."
		self.request = FCKeditorRequest(environ) # Parse request
		self.headers = []						# Clean Headers 
		if environ:
			self.environ = environ
		else:
			self.environ = os.environ

	# local functions

	def setHeader(self, key, value):
		self.headers.append ((key, value))
		return

class FCKeditorRequest(object):
	"A wrapper around the request object"
	def __init__(self, environ):
		if environ: # WSGI
			self.request = cgi.FieldStorage(fp=environ['wsgi.input'],
							environ=environ,
							keep_blank_values=1)
			self.environ = environ
		else: # plain old cgi
			self.environ = os.environ
			self.request = cgi.FieldStorage()
		if 'REQUEST_METHOD' in self.environ and 'QUERY_STRING' in self.environ:
			if self.environ['REQUEST_METHOD'].upper()=='POST':
				# we are in a POST, but GET query_string exists
				# cgi parses by default POST data, so parse GET QUERY_STRING too
				self.get_request = cgi.FieldStorage(fp=None,
							environ={
							'REQUEST_METHOD':'GET',
							'QUERY_STRING':self.environ['QUERY_STRING'],
							},
							)
		else:
			self.get_request={}

	def has_key(self, key):
		return self.request.has_key(key) or self.get_request.has_key(key)

	def get(self, key, default=None):
		if key in self.request.keys():
			field = self.request[key]
		elif key in self.get_request.keys():
			field = self.get_request[key]
		else:
			return default
		if hasattr(field,"filename") and field.filename: #file upload, do not convert return value
			return field
		else:
			return field.value

--- NEW FILE: htaccess.txt ---
# replace the name of this file to .htaccess (if using apache), 
# and set the proper options and paths according your enviroment

Allow from all

# If using mod_python uncomment this:
PythonPath "[r'C:\Archivos de programa\Apache Software Foundation\Apache2.2\htdocs\fckeditor\editor\filemanager\connectors\py'] + sys.path"


# Recomended: WSGI application running with mod_python and modpython_gateway
SetHandler python-program
PythonHandler modpython_gateway::handler
PythonOption wsgi.application wsgi::App


# Emulated CGI with mod_python and cgihandler
#AddHandler mod_python .py
#PythonHandler mod_python.cgihandler


# Plain old CGI
#Options +ExecCGI 
#AddHandler cgi-script py

--- NEW FILE: fckoutput.py ---
#!/usr/bin/env python

"""
FCKeditor - The text editor for Internet - http://www.fckeditor.net
Copyright (C) 2003-2007 Frederico Caldeira Knabben

== BEGIN LICENSE ==

Licensed under the terms of any of the following licenses at your
choice:

- GNU General Public License Version 2 or later (the "GPL")
http://www.gnu.org/licenses/gpl.html

- GNU Lesser General Public License Version 2.1 or later (the "LGPL")
http://www.gnu.org/licenses/lgpl.html

- Mozilla Public License Version 1.1 or later (the "MPL")
http://www.mozilla.org/MPL/MPL-1.1.html

== END LICENSE ==

Connector for Python (CGI and WSGI).

"""

from time import gmtime, strftime
import string

def escape(text, replace=string.replace):
	"""
	Converts the special characters '<', '>', and '&'.

	RFC 1866 specifies that these characters be represented
	in HTML as < > and & respectively. In Python
	1.5 we use the new string.replace() function for speed.
	"""
	text = replace(text, '&', '&') # must be done 1st
	text = replace(text, '<', '<')
	text = replace(text, '>', '>')
	text = replace(text, '"', '"')
	return text

def convertToXmlAttribute(value):
	if (value is None):
		value = ""
	return escape(value)

class BaseHttpMixin(object):
	def setHttpHeaders(self, content_type='text/xml'):
		"Purpose: to prepare the headers for the xml to return"
		# Prevent the browser from caching the result.
		# Date in the past
		self.setHeader('Expires','Mon, 26 Jul 1997 05:00:00 GMT')
		# always modified
		self.setHeader('Last-Modified',strftime("%a, %d %b %Y %H:%M:%S GMT", gmtime())) 
		# HTTP/1.1
		self.setHeader('Cache-Control','no-store, no-cache, must-revalidate') 
		self.setHeader('Cache-Control','post-check=0, pre-check=0') 
		# HTTP/1.0
		self.setHeader('Pragma','no-cache') 

		# Set the response format.
		self.setHeader( 'Content-Type', content_type + '; charset=utf-8' )
		return

class BaseXmlMixin(object):
	def createXmlHeader(self, command, resourceType, currentFolder, url):
		"Purpose: returns the xml header"
		self.setHttpHeaders()
		# Create the XML document header
		s =  """<?xml version="1.0" encoding="utf-8" ?>"""
		# Create the main connector node
		s += """<Connector command="%s" resourceType="%s">""" % (
				command,
				resourceType
				)
		# Add the current folder node
		s += """<CurrentFolder path="%s" url="%s" />""" % (
				convertToXmlAttribute(currentFolder),
				convertToXmlAttribute(url),
				)
		return s

	def createXmlFooter(self):
		"Purpose: returns the xml footer"
		return """</Connector>"""

	def sendError(self, number, text):
		"Purpose: in the event of an error, return an xml based error"
		self.setHttpHeaders()
		return ("""<?xml version="1.0" encoding="utf-8" ?>""" +
				"""<Connector>""" +
				self.sendErrorNode (number, text) +
				"""</Connector>""" )
		
	def sendErrorNode(self, number, text):
		return """<Error number="%s" text="%s" />""" % (number, convertToXmlAttribute(text))

class BaseHtmlMixin(object):
	def sendUploadResults( self, errorNo = 0, fileUrl = '', fileName = '', customMsg = '' ):
		self.setHttpHeaders("text/html")
		"This is the function that sends the results of the uploading process"
		return """<script type="text/javascript">
			window.parent.OnUploadCompleted(%(errorNumber)s,"%(fileUrl)s","%(fileName)s","%(customMsg)s"); 
			</script>""" % {
			'errorNumber': errorNo,
			'fileUrl': fileUrl.replace ('"', '\\"'),
			'fileName': fileName.replace ( '"', '\\"' ) , 
			'customMsg': customMsg.replace ( '"', '\\"' ),
			}
--- NEW FILE: fckutil.py ---
#!/usr/bin/env python

"""
FCKeditor - The text editor for Internet - http://www.fckeditor.net
Copyright (C) 2003-2007 Frederico Caldeira Knabben

== BEGIN LICENSE ==

Licensed under the terms of any of the following licenses at your
choice:

- GNU General Public License Version 2 or later (the "GPL")
http://www.gnu.org/licenses/gpl.html

- GNU Lesser General Public License Version 2.1 or later (the "LGPL")
http://www.gnu.org/licenses/lgpl.html

- Mozilla Public License Version 1.1 or later (the "MPL")
http://www.mozilla.org/MPL/MPL-1.1.html

== END LICENSE ==

Utility functions for the File Manager Connector for Python 

"""

import string, re
import os
import config as Config

# Generic manipulation functions

def removeExtension(fileName):
	index = fileName.rindex(".")
	newFileName = fileName[0:index]
	return newFileName

def getExtension(fileName):
	index = fileName.rindex(".") + 1
	fileExtension = fileName[index:]
	return fileExtension

def removeFromStart(string, char):
	return string.lstrip(char)

def removeFromEnd(string, char):
	return string.rstrip(char)

# Path functions

def combinePaths( basePath, folder ):
	return removeFromEnd( basePath, '/' ) + '/' + removeFromStart( folder, '/' ) 

def getFileName(filename):
	" Purpose: helper function to extrapolate the filename " 
	for splitChar in ["/", "\\"]:
		array = filename.split(splitChar)
		if (len(array) > 1):
			filename = array[-1]
	return filename

def sanitizeFolderName( newFolderName ):
	"Do a cleanup of the folder name to avoid possible problems"
	# Remove . \ / | : ? *
	return re.sub( '\\.|\\\\|\\/|\\||\\:|\\?|\\*', '_', newFolderName )

def sanitizeFileName( newFileName ):
	"Do a cleanup of the file name to avoid possible problems"
	# Replace dots in the name with underscores (only one dot can be there... security issue).
	if ( Config.ForceSingleExtension ): # remove dots
		newFileName = re.sub ( '/\\.(?![^.]*$)/', '_', newFileName ) ;
	newFileName = newFileName.replace('\\','/')		# convert windows to unix path
	newFileName = os.path.basename (newFileName)	# strip directories
	# Remove \ / | : ? *
	return re.sub ( '/\\\\|\\/|\\||\\:|\\?|\\*/', '_', newFileName )

def getCurrentFolder(currentFolder):
	if not currentFolder: 
		currentFolder = '/' 

	# Check the current folder syntax (must begin and end with a slash).
	if (currentFolder[-1] <> "/"):
		currentFolder += "/"
	if (currentFolder[0] <> "/"):
		currentFolder = "/" + currentFolder
				
	# Ensure the folder path has no double-slashes
	while '//' in currentFolder:
		currentFolder = currentFolder.replace('//','/') 

	# Check for invalid folder paths (..)
	if '..' in currentFolder:
		return None

	return currentFolder 

def mapServerPath( environ, url):
	" Emulate the asp Server.mapPath function. Given an url path return the physical directory that it corresponds to "
	# This isn't correct but for the moment there's no other solution
	# If this script is under a virtual directory or symlink it will detect the problem and stop
	return combinePaths( getRootPath(environ), url )

def mapServerFolder(resourceTypePath, folderPath):
	return combinePaths ( resourceTypePath  , folderPath ) 

def getRootPath(environ):
	"Purpose: returns the root path on the server"
	# WARNING: this may not be thread safe, and doesn't work w/ VirtualServer/mod_python
	# Use Config.UserFilesAbsolutePath instead

	if environ.has_key('DOCUMENT_ROOT'):
		return environ['DOCUMENT_ROOT']
	else:
		realPath = os.path.realpath( './' ) 
		selfPath = environ['SCRIPT_FILENAME']
		selfPath = selfPath [ :  selfPath.rfind( '/'  ) ] 		
		selfPath = selfPath.replace( '/', os.path.sep) 
		
		position = realPath.find(selfPath) 

		# This can check only that this script isn't run from a virtual dir
		# But it avoids the problems that arise if it isn't checked
		raise realPath 
		if ( position < 0 or position <> len(realPath) - len(selfPath) or realPath[ : position ]==''):
			raise Exception('Sorry, can\'t map "UserFilesPath" to a physical path. You must set the "UserFilesAbsolutePath" value in "editor/filemanager/connectors/py/config.py".')
		return realPath[ : position ]





More information about the geeklog-cvs mailing list