from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from Products.PageTemplates.PageTemplate import PageTemplate
from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
from OFS.Image import Image
from webdav.common import rfc1123_date
import xml.dom.minidom
from OFS.Folder import Folder
from xml_helpers import getText
import os
import re
import string
import urllib
from Globals import package_home
def getString(self,key,default=''):
try:
return self.REQUEST[key]
except:
return default
def sendFile(self, filename, type):
"""sends an object or a local file (in the product) as response"""
paths = filename.split('/')
object = self
# look for an object called filename
for path in paths:
if hasattr(object, path):
object = getattr(object, path)
else:
object = None
break
if object:
# if the object exists then send it
return object.index_html(self.REQUEST.REQUEST, self.REQUEST.RESPONSE)
else:
# send a local file with the given content-type
fn = os.path.join(package_home(globals()), filename)
self.REQUEST.RESPONSE.setHeader("Content-Type", type)
self.REQUEST.RESPONSE.write(file(fn).read())
return
class BrowserCheck:
"""check the browsers request to find out the browser type"""
def __init__(self, zope):
self.ua = zope.REQUEST.get_header("HTTP_USER_AGENT")
self.isIE = string.find(self.ua, 'MSIE') > -1
self.isN4 = (string.find(self.ua, 'Mozilla/4.') > -1) and not self.isIE
self.nav = self.ua[string.find(self.ua, '('):]
ie = string.split(self.nav, "; ")[1]
if string.find(ie, "MSIE") > -1:
self.versIE = string.split(ie, " ")[1]
self.isMac = string.find(self.ua, 'Macintosh') > -1
self.isWin = string.find(self.ua, 'Windows') > -1
self.isIEWin = self.isIE and self.isWin
self.isIEMac = self.isIE and self.isMac
def manage_addZogiLibMainTemplateForm(self):
"""Form for adding"""
#FIXME:???
pt=PageTemplateFile(os.path.join(package_home(globals()), 'zpt/AddOSAS_thumbTemplate.zpt')).__of__(self)
return pt()
def manage_addZogiLibMainTemplate(self, id,title=None, text=None,
REQUEST=None, submit=None):
"Add a Page Template with optional file content."
#FIXME:???
id = str(id)
if REQUEST is None:
self._setObject(id, zogiLib_mainTemplate(id, text))
ob = getattr(self, id)
if title:
ob.pt_setTitle(title)
return ob
else:
file = REQUEST.form.get('file')
headers = getattr(file, 'headers', None)
if headers is None or not file.filename:
zpt = zogiLib_mainTemplate(id)
else:
zpt = zogiLib_mainTemplate(id, file, headers.get('content_type'))
self._setObject(id, zpt)
ob = getattr(self, id)
try:
u = self.DestinationURL()
except AttributeError:
u = REQUEST['URL1']
if submit == " Add and Edit ":
u = "%s/%s" % (u, quote(id))
REQUEST.RESPONSE.redirect(u+'/manage_main')
return ''
class zogiImage(Image):
"""einzelnes Image"""
meta_type="zogiImage"
manage_options=ZopePageTemplate.manage_options+(
{'label':'Main config','action':'changeZogiImageForm'},
)
def __init__(self,id,title,baseUrl,queryString,content_type='',precondition=''):
"""init"""
self.id=id
self.title=title
self.baseUrl=baseUrl
self.queryString=queryString
self.content_type=content_type
self.precondition=precondition
def getData(self):
"""getUrlData"""
return urllib.urlopen(self.baseUrl+self.queryString)
def changeZogiImageForm(self):
"""Main configuration"""
pt=PageTemplateFile(os.path.join(package_home(globals()), 'zpt/changeZogiImageForm.zpt')).__of__(self)
return pt()
def changeZogiImage(self,title,baseUrl, queryString,RESPONSE=None):
"""change it"""
self.title=title
self.baseUrl=baseUrl
self.queryString=queryString
if RESPONSE is not None:
RESPONSE.redirect('manage_main')
def index_html(self, REQUEST, RESPONSE):
"""
Modified version of OFS/Image.py
The default view of the contents of a File or Image.
Returns the contents of the file or image. Also, sets the
Content-Type HTTP header to the objects content type.
"""
# HTTP If-Modified-Since header handling.
header=REQUEST.get_header('If-Modified-Since', None)
if header is not None:
header=header.split( ';')[0]
# Some proxies seem to send invalid date strings for this
# header. If the date string is not valid, we ignore it
# rather than raise an error to be generally consistent
# with common servers such as Apache (which can usually
# understand the screwy date string as a lucky side effect
# of the way they parse it).
# This happens to be what RFC2616 tells us to do in the face of an
# invalid date.
try: mod_since=long(DateTime(header).timeTime())
except: mod_since=None
if mod_since is not None:
if self._p_mtime:
last_mod = long(self._p_mtime)
else:
last_mod = long(0)
if last_mod > 0 and last_mod <= mod_since:
# Set header values since apache caching will return Content-Length
# of 0 in response if size is not set here
RESPONSE.setHeader('Last-Modified', rfc1123_date(self._p_mtime))
RESPONSE.setHeader('Content-Type', self.content_type)
RESPONSE.setHeader('Content-Length', self.size)
RESPONSE.setHeader('Accept-Ranges', 'bytes')
self.ZCacheable_set(None)
RESPONSE.setStatus(304)
return ''
if self.precondition and hasattr(self,self.precondition):
# Grab whatever precondition was defined and then
# execute it. The precondition will raise an exception
# if something violates its terms.
c=getattr(self,self.precondition)
if hasattr(c,'isDocTemp') and c.isDocTemp:
c(REQUEST['PARENTS'][1],REQUEST)
else:
c()
# HTTP Range header handling
range = REQUEST.get_header('Range', None)
request_range = REQUEST.get_header('Request-Range', None)
if request_range is not None:
# Netscape 2 through 4 and MSIE 3 implement a draft version
# Later on, we need to serve a different mime-type as well.
range = request_range
if_range = REQUEST.get_header('If-Range', None)
if range is not None:
ranges = HTTPRangeSupport.parseRange(range)
if if_range is not None:
# Only send ranges if the data isn't modified, otherwise send
# the whole object. Support both ETags and Last-Modified dates!
if len(if_range) > 1 and if_range[:2] == 'ts':
# ETag:
if if_range != self.http__etag():
# Modified, so send a normal response. We delete
# the ranges, which causes us to skip to the 200
# response.
ranges = None
else:
# Date
date = if_range.split( ';')[0]
try: mod_since=long(DateTime(date).timeTime())
except: mod_since=None
if mod_since is not None:
if self._p_mtime:
last_mod = long(self._p_mtime)
else:
last_mod = long(0)
if last_mod > mod_since:
# Modified, so send a normal response. We delete
# the ranges, which causes us to skip to the 200
# response.
ranges = None
if ranges:
# Search for satisfiable ranges.
satisfiable = 0
for start, end in ranges:
if start < self.size:
satisfiable = 1
break
if not satisfiable:
RESPONSE.setHeader('Content-Range',
'bytes */%d' % self.size)
RESPONSE.setHeader('Accept-Ranges', 'bytes')
RESPONSE.setHeader('Last-Modified',
rfc1123_date(self._p_mtime))
RESPONSE.setHeader('Content-Type', self.content_type)
RESPONSE.setHeader('Content-Length', self.size)
RESPONSE.setStatus(416)
return ''
ranges = HTTPRangeSupport.expandRanges(ranges, self.size)
if len(ranges) == 1:
# Easy case, set extra header and return partial set.
start, end = ranges[0]
size = end - start
RESPONSE.setHeader('Last-Modified',
rfc1123_date(self._p_mtime))
RESPONSE.setHeader('Content-Type', self.content_type)
RESPONSE.setHeader('Content-Length', size)
RESPONSE.setHeader('Accept-Ranges', 'bytes')
RESPONSE.setHeader('Content-Range',
'bytes %d-%d/%d' % (start, end - 1, self.size))
RESPONSE.setStatus(206) # Partial content
data = urllib.urlopen(self.baseUrl+self.queryString).read()
if type(data) is StringType:
return data[start:end]
# Linked Pdata objects. Urgh.
pos = 0
while data is not None:
l = len(data.data)
pos = pos + l
if pos > start:
# We are within the range
lstart = l - (pos - start)
if lstart < 0: lstart = 0
# find the endpoint
if end <= pos:
lend = l - (pos - end)
# Send and end transmission
RESPONSE.write(data[lstart:lend])
break
# Not yet at the end, transmit what we have.
RESPONSE.write(data[lstart:])
data = data.next
return ''
else:
boundary = choose_boundary()
# Calculate the content length
size = (8 + len(boundary) + # End marker length
len(ranges) * ( # Constant lenght per set
49 + len(boundary) + len(self.content_type) +
len('%d' % self.size)))
for start, end in ranges:
# Variable length per set
size = (size + len('%d%d' % (start, end - 1)) +
end - start)
# Some clients implement an earlier draft of the spec, they
# will only accept x-byteranges.
draftprefix = (request_range is not None) and 'x-' or ''
RESPONSE.setHeader('Content-Length', size)
RESPONSE.setHeader('Accept-Ranges', 'bytes')
RESPONSE.setHeader('Last-Modified',
rfc1123_date(self._p_mtime))
RESPONSE.setHeader('Content-Type',
'multipart/%sbyteranges; boundary=%s' % (
draftprefix, boundary))
RESPONSE.setStatus(206) # Partial content
data = urllib.urlopen(self.baseUrl+self.queryString).read()
# The Pdata map allows us to jump into the Pdata chain
# arbitrarily during out-of-order range searching.
pdata_map = {}
pdata_map[0] = data
for start, end in ranges:
RESPONSE.write('\r\n--%s\r\n' % boundary)
RESPONSE.write('Content-Type: %s\r\n' %
self.content_type)
RESPONSE.write(
'Content-Range: bytes %d-%d/%d\r\n\r\n' % (
start, end - 1, self.size))
if type(data) is StringType:
RESPONSE.write(data[start:end])
else:
# Yippee. Linked Pdata objects. The following
# calculations allow us to fast-forward through the
# Pdata chain without a lot of dereferencing if we
# did the work already.
first_size = len(pdata_map[0].data)
if start < first_size:
closest_pos = 0
else:
closest_pos = (
((start - first_size) >> 16 << 16) +
first_size)
pos = min(closest_pos, max(pdata_map.keys()))
data = pdata_map[pos]
while data is not None:
l = len(data.data)
pos = pos + l
if pos > start:
# We are within the range
lstart = l - (pos - start)
if lstart < 0: lstart = 0
# find the endpoint
if end <= pos:
lend = l - (pos - end)
# Send and loop to next range
RESPONSE.write(data[lstart:lend])
break
# Not yet at the end, transmit what we have.
RESPONSE.write(data[lstart:])
data = data.next
# Store a reference to a Pdata chain link so we
# don't have to deref during this request again.
pdata_map[pos] = data
# Do not keep the link references around.
del pdata_map
RESPONSE.write('\r\n--%s--\r\n' % boundary)
return ''
RESPONSE.setHeader('Last-Modified', rfc1123_date(self._p_mtime))
RESPONSE.setHeader('Content-Type', self.content_type)
RESPONSE.setHeader('Content-Length', self.size)
RESPONSE.setHeader('Accept-Ranges', 'bytes')
# Don't cache the data itself, but provide an opportunity
# for a cache manager to set response headers.
self.ZCacheable_set(None)
data=urllib.urlopen(self.baseUrl+self.queryString).read()
if type(data) is type(''):
RESPONSE.setBase(None)
return data
while data is not None:
RESPONSE.write(data.data)
data=data.next
return ''
def manage_addZogiImageForm(self):
"""Form for adding"""
pt=PageTemplateFile(os.path.join(package_home(globals()), 'zpt/addZogiImage.zpt')).__of__(self)
return pt()
def manage_addZogiImage(self,id,title,baseUrl, queryString,RESPONSE=None):
"""add dgilib"""
newObj=zogiImage(id,title,baseUrl, queryString)
self.Destination()._setObject(id,newObj)
if RESPONSE is not None:
RESPONSE.redirect('manage_main')
class zogiLib(Folder):
"""StandardElement"""
meta_type="zogiLib"
manage_options = Folder.manage_options+(
{'label':'Main Config','action':'changeZogiLibForm'},
)
def __init__(self, id, title, digilibBaseUrl, localFileBase, version="book", basePath=""):
"""init"""
self.id=id
self.title=title
self.digilibBaseUrl=digilibBaseUrl
self.localFileBase=localFileBase
self.basePath=basePath
self.layout=version
def getDLInfo(self):
"""get DLInfo from digilib server"""
paramH={}
baseUrl=re.sub("servlet/Scaler","dlInfo-xml.jsp",self.digilibBaseUrl)
try:
url=urllib.urlopen(baseUrl+self.REQUEST['QUERY_STRING'])
dom=xml.dom.minidom.parse(url)
params=dom.getElementsByTagName('parameter')
for param in params:
paramH[param.getAttribute('name')]=param.getAttribute('value')
return paramH
except:
return null
def createHeadJS(self):
"""generate all javascript tags for head"""
pt=PageTemplateFile(os.path.join(package_home(globals()), 'zpt/zogilib_head_js')).__of__(self)
return pt()
def createParamJS(self):
"""generate javascript for parameters only"""
pt=PageTemplateFile(os.path.join(package_home(globals()), 'zpt/zogilib_param_js')).__of__(self)
return pt()
def createScalerImg(self, requestString = None, bottom = 0, side = 0):
"""generate Scaler IMG Tag"""
self.checkQuery()
bt = self.REQUEST.SESSION['browserType']
if not requestString:
requestString = self.getAllDLParams()
url = self.digilibBaseUrl+requestString
tag = ""
if bt.isN4:
tag += '<ilayer id="scaler">'
else:
tag += '<div id="scaler">'
tag += '<script type="text/javascript">'
tag += "var ps = bestPicSize(getElement('scaler'));"
b_par = ""
s_par = ""
if (bottom != 0) or (side != 0):
b_par = "-" + str(int(bottom))
s_par = "-" + str(int(side))
tag += 'document.write(\'<img id="pic" src="%s&dw=\'+(ps.width%s)+\'&dh=\'+(ps.height%s)+\'" />\')'%(url, s_par, b_par)
tag += '</script>'
if bt.isN4:
tag += '</ilayer>'
else:
tag += '</div>'
return tag
def createAuxDiv(self):
"""generate other divs"""
self.checkQuery()
bt = self.REQUEST.SESSION['browserType']
if bt.isN4:
f = 'zpt/zogilib_divsN4.zpt'
else:
f = 'zpt/zogilib_divs.zpt'
pt=PageTemplateFile(os.path.join(package_home(globals()),f)).__of__(self)
return pt()
def option_js(self):
"""option_js"""
pt=PageTemplateFile(os.path.join(package_home(globals()), 'zpt/option_js')).__of__(self)
return pt()
def dl_lib_js(self):
"""javascript"""
return sendFile(self, 'js/dl_lib.js', 'text/plain')
def js_lib_js(self):
"""javascript"""
return sendFile(self, 'js/js_lib.js', 'text/plain')
def optionwindow(self):
"""showoptions"""
pt=PageTemplateFile(os.path.join(package_home(globals()), 'zpt/optionwindow.zpt')).__of__(self)
return pt()
def mark1(self):
"""mark image"""
return sendFile(self, 'images/mark1.gif', 'image/gif')
def mark2(self):
"""mark image"""
return sendFile(self, 'images/mark2.gif', 'image/gif')
def mark3(self):
"""mark image"""
return sendFile(self, 'images/mark3.gif', 'image/gif')
def mark4(self):
"""mark image"""
return sendFile(self, 'images/mark4.gif', 'image/gif')
def mark5(self):
"""mark image"""
return sendFile(self, 'images/mark5.gif', 'image/gif')
def mark6(self):
"""mark image"""
return sendFile(self, 'images/mark6.gif', 'image/gif')
def mark7(self):
"""mark image"""
return sendFile(self, 'images/mark7.gif', 'image/gif')
def mark8(self):
"""mark image"""
return sendFile(self, 'images/mark8.gif', 'image/gif')
def corner1(self):
"""mark image"""
return sendFile(self, 'images/olinks.gif', 'image/gif')
def corner2(self):
"""mark image"""
return sendFile(self, 'images/orechts.gif', 'image/gif')
def corner3(self):
"""mark image"""
return sendFile(self, 'images/ulinks.gif', 'image/gif')
def corner4(self):
"""mark image"""
return sendFile(self, 'images/urechts.gif', 'image/gif')
def index_html(self):
"""main action"""
tp = "zogiLibMainTemplate"
if hasattr(self, tp):
pt = getattr(self, tp)
else:
pt=PageTemplateFile(os.path.join(package_home(globals()), 'zpt/zogiLibMain_%s'%self.layout)).__of__(self)
return pt()
def storeQuery(self, more = None):
"""storeQuery in session"""
dlParams = {}
for fm in self.REQUEST.form.keys():
dlParams[fm] = self.REQUEST.form[fm]
# look for more
if more:
for fm in more.split('&'):
try:
pv = fm.split('=')
dlParams[pv[0]] = pv[1]
except:
print "ouch!"
# parse digilib mode parameter
if 'mo' in dlParams:
if len(dlParams['mo']) > 0:
modes=dlParams['mo'].split(',')
else:
modes=[]
self.REQUEST.SESSION['query'] = dlParams
self.REQUEST.SESSION['dlModes'] = modes
self.REQUEST.SESSION['dlInfo'] = self.getDLInfo()
self.REQUEST.SESSION['browserType'] = BrowserCheck(self)
def checkQuery(self):
"""check if the query has been stored"""
if not (self.REQUEST.SESSION):
print "ZOGILIB: have to store query!!"
storeQuery(self)
def getDLParam(self,param):
"""returns parameter"""
try:
return self.REQUEST.SESSION['query'][param]
except:
return None
def setDLParam(self, param, value):
"""sets parameter"""
self.REQUEST.SESSION['query'][param] = value
return
def getAllDLParams(self):
"""parameter string for digilib"""
dlParams = self.REQUEST.SESSION['query']
# save modes
modes = self.REQUEST.SESSION['dlModes']
dlParams['mo'] = string.join(modes, ',')
# assemble query string
ret = ""
for param in dlParams.keys():
val = str(dlParams[param])
if val != "":
ret += param + "=" + val + "&"
# omit trailing "&"
return ret.rstrip('&')
def setDLParams(self,pn=None,ws=None,rot=None,brgt=None,cont=None):
"""setze Parameter"""
ret=""
if brgt:
self.setDLParam('brgt', brgt)
if cont:
self.setDLParam('cont', cont)
if pn:
# unmark
self.setDLParam('mk', None)
self.setDLParam('pn', pn)
if ws:
self.setDLParam('ws', ws)
if rot:
self.setDLParam('rot', rot)
return self.display()
def display(self):
"""(re)display page"""
params = self.getAllDLParams()
if self.basePath:
self.REQUEST.RESPONSE.redirect(self.REQUEST['URL2']+'?'+params)
else:
self.REQUEST.RESPONSE.redirect(self.REQUEST['URL1']+'?'+params)
def getPT(self):
"""pagenums"""
di = self.REQUEST.SESSION['dlInfo']
if di:
return int(di['pt'])
else:
return 1
def getPN(self):
"""Pagenum"""
pn = self.getDLParam('pn')
if pn:
return int(pn)
else:
return 1
def getBiggerWS(self):
"""ws+1"""
ws=self.getDLParam('ws')
if ws:
return int(ws)+1
else:
return 2
def getSmallerWS(self):
"""ws-1"""
ws=self.getDLParam('ws')
if ws:
if int(ws)==1:
return 1
else:
return int(ws)-1
else:
return 1
def hasMode(self, mode):
"""returns if mode is in the diglib mo parameter"""
return (mode in self.REQUEST.SESSION['dlModes'])
def hasNextPage(self):
"""returns if there is a next page"""
pn = self.getPN()
pt = self.getPT()
return (pn < pt)
def hasPrevPage(self):
"""returns if there is a previous page"""
pn = self.getPN()
return (pn > 1)
def dl_HMirror(self):
"""mirror action"""
modes = self.REQUEST.SESSION['dlModes']
if 'hmir' in modes:
modes.remove('hmir')
else:
modes.append('hmir')
return self.display()
def dl_VMirror(self):
"""mirror action"""
modes = self.REQUEST.SESSION['dlModes']
if 'vmir' in modes:
modes.remove('vmir')
else:
modes.append('vmir')
return self.display()
def dl_WholePage(self):
"""zoom out action"""
self.setDLParam('ww', 1)
self.setDLParam('wh', 1)
self.setDLParam('wx', 0)
self.setDLParam('wy', 0)
return self.display()
def dl_PrevPage(self):
"""next page action"""
pn = self.getPN() - 1
if pn < 1:
pn = 1
self.setDLParam('pn', pn)
# unmark
self.setDLParam('mk', None)
return self.display()
def dl_NextPage(self):
"""next page action"""
pn = self.getPN() + 1
pt = self.getPT()
if pn > pt:
pn = pt
self.setDLParam('pn', pn)
# unmark
self.setDLParam('mk', None)
return self.display()
def dl_FirstPage(self):
"""first page action"""
self.setDLParam('pn', 1)
# unmark
self.setDLParam('mk', None)
return self.display()
def dl_LastPage(self):
"""last page action"""
self.setDLParam('pn', self.getPT())
# unmark
self.setDLParam('mk', None)
return self.display()
def dl_Unmark(self):
"""action to remove last mark"""
mk = self.getDLParam('mk')
if mk:
marks = mk.split(',')
marks.pop()
mk = string.join(marks, ',')
self.setDLParam('mk', mk)
return self.display()
def changeZogiLibForm(self):
"""Main configuration"""
pt=PageTemplateFile(os.path.join(package_home(globals()), 'zpt/changeZogiLibForm.zpt')).__of__(self)
return pt()
def changeZogiLib(self,title,digilibBaseUrl, localFileBase, version, basePath, RESPONSE=None):
"""change it"""
self.title=title
self.digilibBaseUrl=digilibBaseUrl
self.localFileBase=localFileBase
self.basePath = basePath
self.layout=version
if RESPONSE is not None:
RESPONSE.redirect('manage_main')
def manage_addZogiLibForm(self):
"""interface for adding zogilib"""
pt=PageTemplateFile(os.path.join(package_home(globals()), 'zpt/addZogiLibForm')).__of__(self)
return pt()
def manage_addZogiLib(self,id,title,digilibBaseUrl, localFileBase,version="book",basePath="",RESPONSE=None):
"""add dgilib"""
newObj=zogiLib(id,title,digilibBaseUrl, localFileBase, version, basePath)
self.Destination()._setObject(id,newObj)
if RESPONSE is not None:
RESPONSE.redirect('manage_main')
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>