Attachment 'sud.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 
   3 import tokenize
   4 import StringIO
   5 import string
   6 import os
   7 import re
   8 from traceback import format_exception
   9 import codecs
  10 
  11 from MoinMoin.util.ParserBase import ParserBase
  12 from MoinMoin.util import MoinMoinNoFooter, filesys
  13 from MoinMoin import config
  14 
  15 Dependencies = ['time']
  16 
  17 class StopScriptError(StandardError):
  18     pass
  19 
  20 def redirect(target, message=None):
  21     raise StopScriptError('redirect ' + target, message)
  22 
  23 def return_(message=None):
  24     raise StopScriptError('return', message)
  25 
  26 class SudData(object):
  27     zone = None
  28     status = None
  29     _datafile = None
  30     inventory = None
  31     otherzones = None
  32 
  33     lzone_re = re.compile(r'lastzone\s*=\s*(.*)')
  34     zone_re = re.compile(r'zonestatus\((.*)\)\s*=\s*(.*)')
  35     dict_re = re.compile(r'(.*):(.*)')
  36     def __init__(self, cfg, user, zone):
  37 	self.zone = zone
  38 	self.status = 0
  39 	self.otherzones = ''
  40 	self.inventory = {}
  41 	self._datafile = os.path.join(cfg.user_dir, user.id + '.suddata')
  42 	if os.path.exists(self._datafile):
  43 	    self.load()
  44     def get_status(self):
  45 	return self.status
  46     def set_status(self, status):
  47 	if isinstance(status, int) or \
  48 	   isinstance(status, basestring) or \
  49 	   isinstance(status, list):
  50 	    self.status = status
  51 	else:
  52 	    raise ValueError('Status must be int, str or list')
  53     def get_inventory(self):
  54 	class Empty(object):
  55 	    pass
  56 	result = Empty()
  57 	result.set_item = self.inventory.__setitem__
  58 	result.get_item = self.inventory.__getitem__
  59 	result.del_item = self.inventory.__delitem__
  60 	result.has_key = self.inventory.has_key
  61 	return result
  62     def load(self):
  63 	data = codecs.open(self._datafile, "r", config.charset)
  64 	for line in map(string.strip, data.readlines()):
  65 	    if not line or line.startswith('#'):
  66 		continue
  67 	    match = self.lzone_re.search(line)
  68 	    if match:
  69 		lastzone = match.group(1)
  70 		continue
  71 	    match = self.zone_re.search(line)
  72 	    if match:
  73 		if match.group(1) == self.zone:
  74 		    self.status = match.group(2)
  75 		    if self.status.startswith('['):
  76 			self.status = eval(self.status)
  77 		else:
  78 		    self.otherzones += line + '\n'
  79 		continue
  80 	    if self.zone != lastzone:
  81 		continue
  82 	    match = self.dict_re.search(line)
  83 	    if match:
  84 		self.inventory[match.group(1)] = match.group(2)
  85 	data.close()
  86     def save(self):
  87 	filesys.makeDirs(os.path.dirname(self._datafile))
  88 	data = codecs.open(self._datafile, "w", config.charset)
  89 	data.write('lastzone = %s\n' % self.zone)
  90 	data.write('zonestatus(%s) = %s\n' % (self.zone, str(self.status)))
  91 	data.write(self.otherzones)
  92 	for ii in self.inventory.keys():
  93 	    data.write('%s:%s' % (ii, self.inventory[ii]) + '\n')
  94 	data.close()
  95 
  96 class Parser(ParserBase):
  97 
  98     parsername = "SudParser"
  99     extensions = ['']
 100 
 101     _restricted_tokens = ('import', 'open', 'eval', 'exec', \
 102 			  'print', 'execfile', 'file')
 103     emsg = None
 104     messages = None
 105 
 106     def __init__(self, raw, request, **kw):
 107 	self.request = request
 108 	self.messages = []
 109 	_ = request.getText
 110 
 111 	pagename = request.page.page_name
 112 	adampage = pagename.split('/')[0]
 113 	zone = request.pragma.get('zone', adampage)
 114 	if zone.split('/')[0] != adampage:
 115 	    self.emsg = _('Invalid %s') % 'zone'
 116 	    return
 117 
 118 	if request.form.has_key('message'):
 119 	    self.messages = request.form['message'][0].split(',,')
 120 	try:
 121 	    rf_count = int(request.form.get('refreshed', (0,))[0])
 122 	except ValueError:
 123 	    rf_count = 0
 124 
 125 	# Check raw text input
 126 	tokenstream = tokenize.generate_tokens(StringIO.StringIO(raw).readline)
 127 	try:
 128 	    while 1:	# tokenstream ends by raising an exception
 129 		token = tokenstream.next()
 130 		if token[0] == 1 and \
 131 			( token[1] in self._restricted_tokens or \
 132 			  token[1].find('__') != -1 ):
 133 		    self.emsg = _('Disabled statement %s used in line %s.') % \
 134 			    (token[1], token[2][0])
 135 		    return
 136 	except StopIteration:
 137 	    pass
 138 
 139 	requested_redirect = ''
 140 	# Create environment
 141 	suddata = SudData(request.cfg, request.user, zone)
 142 	referer = request.http_referer.replace(request.getBaseURL(), '')
 143 	referer = referer.strip('/')
 144 	if referer.find('?') > 0:
 145 	    referer = referer[:referer.index('?')]
 146 	sb_locals = {'msg':'',
 147 		     'referer':referer,
 148 		     'username':request.user.name,
 149 		     'status':suddata.get_status(),
 150 		     'inventory':suddata.get_inventory(),
 151 		     'return_':return_,
 152 		     'redirect':redirect,
 153 		     'refresh':0,
 154 		     'refresh_count':rf_count,
 155 		    }
 156 
 157 	try:
 158 	    exec raw in sb_locals
 159 	except StopScriptError, sse:
 160 	    if len(sse.args) > 1:
 161 		sb_locals['msg'] = sse.args[1]
 162 	    if sse.args[0].startswith('redirect '):
 163 		requested_redirect = sse.args[0].split(' ', 1)[1]
 164 		if requested_redirect.find('://') > -1:
 165 		    self.emsg = 'Illegal redirect to external page'
 166 		    return
 167 	except StandardError, se:
 168 	    self.emsg = ''.join(format_exception(se.__class__, se, None))
 169 	    return
 170 
 171 	sbmsg = sb_locals.get('msg', '')
 172 	if isinstance(sbmsg, list) or isinstance(sbmsg, tuple):
 173 	    self.messages.extend(sbmsg)
 174 	elif sbmsg:
 175 	    self.messages.append(unicode(sbmsg))
 176 
 177 	try:
 178 	    suddata.set_status(sb_locals.get('status', 0))
 179 	except ValueError:
 180 	    self.emsg = 'Invalid %s' % 'status'
 181 	    return
 182 	suddata.save()
 183 
 184 	if requested_redirect:
 185 	    if not request.form.has_key('debug'):
 186 		url = requested_redirect
 187 		if self.messages:
 188 		    url += ('?', '&')[url.find('?') != -1] + 'message='
 189 		    url += ',,'.join( \
 190 			['%s:+%s' % (pagename, x.replace(' ', '+')) \
 191 			 for x in self.messages])
 192 		url = url.encode("utf-8")
 193 		print '<script language="javascript">\n' + \
 194 			'<!--\n' + \
 195 			'document.location.replace("%s");\n' % url + \
 196 			'//-->\n' + \
 197 			'</script>\n'
 198 		print 'This page redirects to %s using Javascript!' \
 199 							% requested_redirect
 200 		raise MoinMoinNoFooter
 201 	    else:
 202 		self.messages.append('Redirection to %s on hold (debug mode)' \
 203 				% requested_redirect)
 204 		del sb_locals['__builtins__']
 205 		self.messages.append(str(sb_locals))
 206 
 207 	try:
 208 	    secs = int(sb_locals.get('refresh', 0))
 209 	    if secs > 0:
 210 		cmd = pagename + '?refreshed=%d' % (rf_count + 1)
 211 		cmd = 'document.location.replace("%s")' % cmd
 212 		print '<script language="javascript">\n' + \
 213 			'<!--\n' + \
 214 			"setTimeout('%s', %d);\n" % (cmd, secs*1000) + \
 215 			'//-->\n' + \
 216 			'</script>\n'
 217 	except ValueError:
 218 	    self.emsg = _('Invalid value for %s') % 'refresh'
 219 	
 220     def format(self, formatter):
 221 	if self.emsg:
 222 	    self.request.write('<div class="error">%s</div>\n' % self.emsg)
 223 	if self.messages:
 224 	    self.request.write('<div id="message">\n')
 225 	    for ii in self.messages:
 226 		self.request.write('  %s<br />\n' % ii.encode("utf-8"))
 227 	    self.request.write('</div>\n')

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2005-11-13 14:59:09, 6.4 KB) [[attachment:sud.py]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.