#
# Copyright 1999, 2000 Martin Pool <mbp@humbug.org.au>
# Copyright 2002 Gerardo Poggiali
-# Copyright 2007, 2008 Bernie Innocenti <bernie@codewiz.org>
+# Copyright 2007, 2008, 2009 Bernie Innocenti <bernie@codewiz.org>
#
# 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
img_re = re.compile(r"^.*\.(png|gif|jpg|jpeg|bmp|ico|ogm|ogg|mkv|mpg|mpeg|mp4|avi|asf|flv|wmv|qt)$", re.IGNORECASE)
video_re = re.compile(r"^.*\.(ogm|ogg|mkv|mpg|mpeg|mp4|avi|asf|flv|wmv|qt)$", re.IGNORECASE)
url_re = re.compile(r"^[a-z]{3,8}://[^\s'\"]+\S$")
-link_re = re.compile("(?:\[\[|{{)([^\s\|]+)(?:\s*\|\s*([^\]]+)|)(?:\]\]|}})")
+link_re = re.compile(r"(?:\[\[|{{)([^\s\|]+)(?:\s*\|\s*([^\]]+)|)(?:\]\]|}})")
+ext_re = re.compile(r"\.([^\./]+)$")
title_done = False
-
# CGI stuff ---------------------------------------------------------
-
def script_name():
return os.environ.get('SCRIPT_NAME', '')
+def query_string():
+ path_info = os.environ.get('PATH_INFO', '')
+ if len(path_info) and path_info[0] == '/':
+ return path_info[1:] or 'FrontPage'
+ else:
+ return os.environ.get('QUERY_STRING', '') or 'FrontPage'
+
def privileged_path():
return privileged_url or script_name()
print ' Software Failure. Press left mouse button to continue.\n'
print msg_text
if msg_type == 'error':
- print '\n Guru Meditation #DEADBEEF.ABADC0DE'
+ print '\n Guru Meditation #DEADBEEF.ABADC0DE'
print '</pre>'
try:
sendfile(sys.stdout, open('gurumeditation.js', 'rb'))
# Navbar
print '<div class="nav">'
+ print link_tag('FrontPage', relative_url(site_icon or 'Home'), 'navlink')
if name:
print ' <b>' + link_tag('?fullsearch=' + name, text, 'navlink') + '</b> '
else:
print ' <b>' + text + '</b> '
- print ' | ' + link_tag('FrontPage', 'Home', 'navlink')
print ' | ' + link_tag('FindPage', 'Find Page', 'navlink')
if 'history_url' in globals():
print ' | <a href="' + relative_url(history_url) + '" class="navlink">Recent Changes</a>'
user = remote_user()
if user != 'AnonymousCoward':
- print ' | <span class="login"><i>logged in as <b>' + cgi.escape(user) + '</b></i></span>'
+ print ' | <span class="login"><i><b>' + link_tag('User/' + user, user) + '</b></i></span>'
print '<hr /></div>'
return '<a %shref="%s">%s</a>' % (classattr, relative_url(params, privileged=privileged), text)
+def link_inline(name, descr=None, args=''):
+ if not descr: descr = name
+ url = relative_url(name)
+ if video_re.match(name):
+ return '<video src="%s">Your browser does not support the HTML5 video tag</video>' % url
+ elif img_re.match(name):
+ return '<a href="%s"><img border="0" src="%s" alt="%s" /></a>' % (url, url + args, descr)
+ elif file_re.match(name) and not ext_re.search(name): # FIXME: this guesses a wiki page
+ return Page(name).send_naked()
+ else:
+ return '<iframe width="100%%" scrolling="auto" frameborder="0" src="%s"><a href="%s">%s</a></iframe>' \
+ % (url, url, name)
+
# Search ---------------------------------------------------
def handle_fullsearch(needle):
self.styles = {
#wiki html enabled?
"//": ["em", False],
- "''": ["em", False],
"**": ["b", False],
- "'''": ["b", False],
"##": ["tt", False],
- "``": ["tt", False],
"__": ["u", False],
"^^": ["sup", False],
- ",,": ["sub", False]
+ ",,": ["sub", False],
+ "''": ["em", False], # LEGACY
+ "'''": ["b", False], # LEGACY
+ "``": ["tt", False], # LEGACY
}
def _b_repl(self, word):
if macro:
return macro(argv)
else:
- return '<strong class="error"><<' + '|'.join(argv) + '>></strong>'
+ msg = '<<' + '|'.join(argv) + '>>'
+ if not self.in_html:
+ msg = '<strong class="error">' + msg + '</strong>'
+ return msg
def _hurl_repl(self, word):
m = link_re.match(word)
return link_tag(m.group(1), m.group(2))
- def _url_repl(self, word):
- return link_tag(word)
-
- def _word_repl(self, word):
- return link_tag(word)
-
def _inl_repl(self, word):
- m = link_re.match(word)
- name = relative_url(m.group(1))
- descr = m.group(2)
+ (name, descr) = link_re.match(word).groups()
if descr:
argv = descr.split('|')
args = '?' + '&'.join(argv)
# The "extthumb" nonsense works around a limitation of the HTML block model
- return '<div class="extthumb"><div class="thumb"><a href="%s"><img border="0" src="%s" alt="%s" /></a><div class="caption">%s</div></div></div>' \
- % (name, name + args, descr, descr)
- elif video_re.match(name):
- return '<video src="%s">Your browser does not support the HTML5 video tag</video>' % name
+ return '<div class="extthumb"><div class="thumb">' \
+ + link_inline(name, descr, args) \
+ + '<div class="caption">' + descr + '</div></div></div>'
else:
- return '<a href="%s"><img border="0" src="%s" /></a>' % (name, name)
-
- def _img_repl(self, word):
- return self._inl_repl('{{' + word + '}}')
-
- def _email_repl(self, word):
- return '<a href="mailto:%s">%s</a>' % (word, word)
+ return link_inline(name, name)
def _html_repl(self, word):
self.in_html += 1
return word; # Pass through
+ def _htmle_repl(self, word):
+ self.in_html -= 1
+ return word; # Pass through
+
def _ent_repl(self, s):
- if self.in_html and s == '>':
- self.in_html -= 1
- return '>'
+ if self.in_html:
+ return s; # Pass through
return {'&': '&',
'<': '<',
'>': '>'}[s]
+ def _img_repl(self, word): # LEGACY
+ return self._inl_repl('{{' + word + '}}')
+
+ def _word_repl(self, word): # LEGACY
+ if self.in_html: return word # pass through
+ return link_tag(word)
+
+ def _url_repl(self, word): # LEGACY
+ if self.in_html: return word # pass through
+ return link_tag(word)
+
+ def _email_repl(self, word): # LEGACY
+ if self.in_html: return word # pass through
+ return '<a href="mailto:%s">%s</a>' % (word, word)
+
def _li_repl(self, match):
if self.in_li:
return '</li><li>'
def print_html(self):
print '<div class="wiki"><p>'
- # For each line, we scan through looking for magic
- # strings, outputting verbatim any intervening text
- # TODO: highlight search words (look at referrer)
- scan_re = re.compile(
- r"(?:"
- # Formatting
- + r"(?P<b>\*\*|'''|//|''|##|``|__|\^\^|,,)"
- + r"|(?P<tit>\={2,6})"
- + r"|(?P<br>\\\\)"
- + r"|(?P<rule>^-{3,})"
- + r"|(?P<hi>\b(FIXME|TODO|DONE)\b)"
+ scan_re = re.compile(r"""(?:
+ # Styles and formatting
+ (?P<b> \*\*|'''|//|''|\#\#|``|__|\^\^|,,)
+ | (?P<tit> \={2,6})
+ | (?P<br> \\\\)
+ | (?P<rule> ^-{3,})
+ | (?P<hi> \b( FIXME | TODO | DONE )\b )
# Links
- + r"|(?P<macro>\<\<([^\s\|\>]+)(?:\s*\|\s*([^\>]+)|)\>\>)"
- + r"|(?P<hurl>\[\[([^\s\|]+)(?:\s*\|\s*([^\]]+)|)\]\])"
+ | (?P<macro> \<\<([^\s\|\>]+)(?:\s*\|\s*([^\>]+)|)\>\>)
+ | (?P<hurl> \[\[([^\s\|]+)(?:\s*\|\s*([^\]]+)|)\]\])
# Inline HTML
- + r"|(?P<html><(/|)(br|hr|div|span|form|iframe|input|textarea|a|img|h[1-5])[^>]*>)"
- + r"|(?P<ent>[<>&])"
+ | (?P<html> <(br|hr|div|span|form|iframe|input|textarea|a|img|h[1-5])\b )
+ | (?P<htmle> ( /\s*> | </(br|hr|div|span|form|iframe|input|textarea|a|img|h[1-5])> ) )
+ | (?P<ent> [<>&] )
# Auto links (LEGACY)
- + r"|(?P<img>\b[a-zA-Z0-9_/-]+\.(png|gif|jpg|jpeg|bmp|ico|ogm|ogg|mkv|mpg|mpeg|mp4|avi|asf|flv|wmv|qt))"
- + r"|(?P<word>\b(?:[A-Z][a-z]+){2,}\b)"
- + r"|(?P<url>(http|https|ftp|mailto)\:[^\s'\"]+\S)"
- + r"|(?P<email>[-\w._+]+\@[\w.-]+)"
+ | (?P<img> \b[a-zA-Z0-9_/-]+\.(png|gif|jpg|jpeg|bmp|ico|ogm|ogg|mkv|mpg|mpeg|mp4|avi|asf|flv|wmv|qt))
+ | (?P<word> \b(?:[A-Z][a-z]+){2,}\b)
+ | (?P<url> (http|https|ftp|mailto)\:[^\s'\"]+\S)
+ | (?P<email> [-\w._+]+\@[\w.-]+)
# Lists, divs, spans
- + r"|(?P<li>^\s+[\*#] +)"
- + r"|(?P<pre>\{\{\{|\s*\}\}\})"
- + r"|(?P<inl>\{\{([^\s\|]+)(?:\s*\|\s*([^\]]+)|)\}\})"
+ | (?P<li> ^\s+[\*\#]\s+)
+ | (?P<pre> \{\{\{|\s*\}\}\})
+ | (?P<inl> \{\{([^\s\|]+)(?:\s*\|\s*([^\]]+)|)\}\})
# Tables
- + r"|(?P<tr>^\s*\|\|(=|)\s*)"
- + r"|(?P<tre>\s*\|\|(=|)\s*$)"
- + r"|(?P<td>\s*\|\|(=|)\s*)"
- + r")")
- pre_re = re.compile(
- r"(?:"
- + r"(?P<pre>\s*\}\}\})"
- + r"|(?P<ent>[<>&])"
- + r")")
+ | (?P<tr> ^\s*\|\|(=|)\s*)
+ | (?P<tre> \s*\|\|(=|)\s*$)
+ | (?P<td> \s*\|\|(=|)\s*)
+
+ # TODO: highlight search words (look at referrer)
+ )""", re.VERBOSE)
+ pre_re = re.compile("""(?:
+ (?P<pre>\s*\}\}\})
+ | (?P<ent>[<>&])"
+ )""", re.VERBOSE)
blank_re = re.compile(r"^\s*$")
indent_re = re.compile(r"^\s*")
tr_re = re.compile(r"^\s*\|\|")
eol_re = re.compile(r"\r?\n")
+
+ # For each line, we scan through looking for magic strings, outputting verbatim any intervening text
for self.line in eol_re.split(self.raw.expandtabs()):
# Skip pragmas
if self.in_header:
return False
raise err
- def get_raw_body(self):
+ def get_raw_body(self, default=None):
try:
return open(self._filename(), 'rb').read()
except IOError, err:
if err.errno == errno.ENOENT:
- return '' # just doesn't exist, use default
+ if default is None:
+ default = '//[[?edit=%s|Describe %s]]//' % (self.page_name, self.page_name)
+ return default
if err.errno == errno.EISDIR:
return self.format_dir()
raise err
print '<div class="editor"><form name="editform" method="post" enctype="multipart/form-data" action="%s">' % relative_url(self.page_name)
print '<input type="hidden" name="edit" value="%s">' % (self.page_name)
print '<input type="input" id="editor" name="changelog" value="Edit page %s" accesskey="c" /><br />' % (self.page_name)
- print '<textarea wrap="off" spellcheck="true" id="editor" name="savetext" rows="17" cols="100" accesskey="e">%s</textarea>' % cgi.escape(preview or self.get_raw_body())
+ print '<textarea wrap="off" spellcheck="true" id="editor" name="savetext" rows="17" cols="100" accesskey="e">%s</textarea>' \
+ % cgi.escape(preview or self.get_raw_body(default=''))
print '<label for="file" accesskey="u">Or Upload a file:</label> <input type="file" name="file" value="%s" />' % filename
print """
<br />
print "</div>"
send_footer()
- def send_raw(self, mimetype='text/plain'):
- if self.can_read():
- body = self.get_raw_body()
- emit_header(mimetype)
- print body
- else:
+ def send_raw(self, mimetype='text/plain', args=[]):
+ if not self.can_read():
send_title(None, msg_text='Read access denied by ACLs', msg_type='notice')
+ return
- def send_image(self, mimetype, args=[]):
if 'maxwidth' in args:
import subprocess
emit_header(mimetype)
subprocess.check_call(['gm', 'convert', self._filename(),
'-scale', args['maxwidth'].value + ' >', '-'])
else:
- self.send_raw(mimetype)
+ body = self.get_raw_body()
+ emit_header(mimetype)
+ print body
def _write_file(self, data):
tmp_filename = self._tmp_filename()
self._write_file(newdata)
rc = 0
if post_edit_hook:
- # FIXME: what's the std way to perform shell quoting in python?
- cmd = ( post_edit_hook
- + " '" + data_dir + '/' + self.page_name
- + "' '" + remote_user()
- + "' '" + remote_host()
- + "' '" + changelog + "'"
- )
- out = os.popen(cmd)
- output = out.read()
- rc = out.close()
+ import subprocess
+ cmd = [ post_edit_hook, data_dir + '/' + self.page_name, remote_user(), remote_host(), changelog]
+ child = subprocess.Popen(cmd, stdout=subprocess.PIPE, close_fds=True)
+ output = child.stdout.read()
+ rc = child.wait()
if rc:
- self.msg_text += "Post-editing hook returned %d.\n" % rc
- self.msg_text += 'Command was: ' + cmd + '\n'
+ self.msg_text += "Post-editing hook returned %d. Command was:\n'%s'\n" % (rc, "' '".join(cmd))
if output:
self.msg_text += 'Output follows:\n' + output
else:
handler(form[cmd].value)
break
else:
- path_info = os.environ.get('PATH_INFO', '')
- if len(path_info) and path_info[0] == '/':
- query = path_info[1:] or 'FrontPage'
- else:
- query = os.environ.get('QUERY_STRING', '') or 'FrontPage'
-
+ query = query_string()
if file_re.match(query):
- if word_re.match(query):
- Page(query).format()
+ # FIMXE: this is all bullshit, MimeTypes bases its guess on the extension!
+ from mimetypes import MimeTypes
+ mimetype, encoding = MimeTypes().guess_type(query)
+ if mimetype:
+ Page(query).send_raw(mimetype=mimetype, args=form)
else:
- from mimetypes import MimeTypes
- mimetype, encoding = MimeTypes().guess_type(query)
- if mimetype:
- if mimetype.startswith('image/'):
- Page(query).send_image(mimetype=mimetype, args=form)
- else:
- Page(query).send_raw(mimetype=mimetype)
- else:
- Page(query).format()
+ Page(query).format()
else:
send_httperror("403 Forbidden", query)