X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=geekigeeki.py;h=c5b51096a1fbecfe242b189b8d84625b152cdb65;hb=637b5e74007d806f09cae0704fc356b8765919f1;hp=afaebefc6a4321560a861d04f174c7d8661a304b;hpb=3cebb905becc61868f9431c2cf8939d1f1cd198e;p=geekigeeki.git diff --git a/geekigeeki.py b/geekigeeki.py index afaebef..c5b5109 100755 --- a/geekigeeki.py +++ b/geekigeeki.py @@ -18,21 +18,22 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -__version__ = '$Id$'[4:12] +__version__ = '4.0-' + '$Id$'[4:11] -from time import clock +from time import clock, localtime, gmtime, strftime start_time = clock() title_done = False import cgi, sys, os, re, errno, stat -# FIXME: we accept stuff like foo/../bar and we shouldn't -file_re = re.compile(r"([A-Za-z0-9_\-][A-Za-z0-9_\.\-/]*)") +image_ext = 'png|gif|jpg|jpeg|bmp|ico' video_ext = "ogg|ogv|oga" # Not supported by Firefox 3.5: mkv|mpg|mpeg|mp4|avi|asf|flv|wmv|qt -img_re = re.compile(r".*\.(png|gif|jpg|jpeg|bmp|ico|" + video_ext + ")", re.IGNORECASE) +image_re = re.compile(r".*\.(" + image_ext + "|" + video_ext + ")", re.IGNORECASE) video_re = re.compile(r".*\.(" + video_ext + ")", re.IGNORECASE) -url_re = re.compile(r"[a-z]{3,8}://[^\s'\"]+\S") -ext_re = re.compile(r"\.([^\./]+)$") +# FIXME: we accept stuff like foo/../bar and we shouldn't +file_re = re.compile(r"([A-Za-z0-9_\-][A-Za-z0-9_\.\-/]*)") +url_re = re.compile(r"[a-z]{3,8}://[^\s'\"]+\S") +ext_re = re.compile(r"\.([^\./]+)$") # CGI stuff --------------------------------------------------------- def script_name(): @@ -104,7 +105,9 @@ def url_args(kvargs): return '' # Formatting stuff -------------------------------------------------- -def emit_header(mime_type="text/html"): +def emit_header(mtime=None, mime_type="text/html"): + if mtime: + print("Last-Modified: " + strftime("%a, %d %b %Y %H:%M:%S GMT", gmtime(mtime))) print("Content-type: " + mime_type + "; charset=utf-8\n") def send_guru(msg_text, msg_type): @@ -118,12 +121,12 @@ def send_guru(msg_text, msg_type): print('' \ % relative_url('sys/GuruMeditation.js')) -def send_title(name, text="Limbo", msg_text=None, msg_type='error', writable=False): +def send_title(name, text="Limbo", msg_text=None, msg_type='error', writable=False, mtime=None): global title_done if title_done: return # Head - emit_header() + emit_header(mtime) print('') print('') @@ -198,7 +201,7 @@ def send_httperror(status="403 Not Found", query=""): def link_tag(dest, text=None, privileged=False, **kvargs): if text is None: text = humanlink(dest) - elif img_re.match(text): + elif image_re.match(text): text = '' + text + '' link_class = kvargs.get('class', kvargs.get('cssclass', None)) @@ -223,7 +226,7 @@ def link_inline(name, descr=None, kvargs={}): url = relative_url(name) if video_re.match(name): return '' % url - elif img_re.match(name): + elif image_re.match(name): return '%s' % (url, url + url_args(kvargs), descr) elif file_re.match(name) and not ext_re.search(name): # FIXME: this guesses a wiki page return Page(name).send_naked() @@ -331,20 +334,21 @@ def page_list(dirname=None, re=None): re = re.compile(r"^\b((([A-Z][a-z0-9]+){2,}/)*([A-Z][a-z0-9]+){2,})\b$") return sorted(filter(re.match, os.listdir(dirname or data_dir))) -def send_footer(mod_string=None): +def send_footer(mtime=None): if globals().get('debug_cgi', False): cgi.print_arguments() cgi.print_form(form) cgi.print_environ() + #FIXME link_inline("sys/footer") print(''' ') class WikiFormatter: @@ -366,6 +370,7 @@ class WikiFormatter: "**": ["b", False], "##": ["tt", False], "__": ["u", False], + "--": ["del", False], "^^": ["sup", False], ",,": ["sub", False], "''": ["em", False], # LEGACY @@ -378,6 +383,9 @@ class WikiFormatter: style[1] = not style[1] return ['' + def _glyph_repl(self, word): + return '—' + def _tit_repl(self, word): if self.h_level: result = '

\n' % self.h_level @@ -533,29 +541,30 @@ class WikiFormatter: print('

') scan_re = re.compile(r"""(?: - # Styles and formatting - (?P \*\*|'''|//|''|\#\#|``|__|\^\^|,,) + # Styles and formatting ("--" must cling to a word to disambiguate it from the dash) + (?P \*\* | // | \#\# | __ | --\b | \b-- | \^\^ | ,, | ''' | '' | `` ) | (?P \={2,6}) | (?P
\\\\) | (?P ^-{3,}) | (?P \b( FIXME | TODO | DONE )\b ) + | (?P --) # Links | (?P \<\<([^\s\|\>]+)(?:\s*\|\s*([^\>]+)|)\>\>) | (?P \[\[([^\s\|]+)(?:\s*\|\s*([^\]]+)|)\]\]) # Inline HTML - | (?P <(br|hr|div|span|form|iframe|input|textarea|a|img|h[1-5])\b ) + | (?P <(br|hr|div|span|form|iframe|input|textarea|a|img|h[1-5])\b ) | (?P ( /\s*> | ) ) | (?P [<>&] ) # Auto links (LEGACY) - | (?P \b[a-zA-Z0-9_/-]+\.(png|gif|jpg|jpeg|bmp|ico|ogm|ogg|mkv|mpg|mpeg|mp4|avi|asf|flv|wmv|qt)) + | (?P \b[a-zA-Z0-9_/-]+\.(""" + image_ext + "|" + video_ext + r""")) | (?P \b(?:[A-Z][a-z]+){2,}\b) | (?P (http|https|ftp|mailto)\:[^\s'\"]+\S) | (?P [-\w._+]+\@[\w.-]+) - # Lists, divs, spans + # Lists, divs, spans and inline objects | (?P

  • ^\s+[\*\#]\s+) | (?P
       \{\{\{|\s*\}\}\})
                 | (?P   \{\{([^\s\|]+)(?:\s*\|\s*([^\]]+)|)\}\})
    @@ -620,22 +629,26 @@ class Page:
         def _tmp_filename(self):
             return os.path.join(data_dir, ('#' + self.page_name.replace('/','_') + '.' + str(os.getpid()) + '#'))
     
    -    def exists(self):
    +    def _mtime(self):
             try:
    -            os.stat(self._filename())
    -            return True
    +            return os.stat(self._filename()).st_mtime
             except OSError, err:
                 if err.errno == errno.ENOENT:
    -                return False
    +                return None
                 raise err
     
    +    def exists(self):
    +        if self._mtime():
    +            return True
    +        return False
    +
         def get_raw_body(self, default=None):
             try:
                 return open(self._filename(), 'rb').read()
             except IOError, err:
                 if err.errno == errno.ENOENT:
                     if default is None:
    -                    default = '//[[%s|Describe %s|action=edit]]//' % (self.page_name, self.page_name)
    +                    default = '//[[?a=edit&q=%s|Describe %s]]//' % (self.page_name, self.page_name)
                     return default
                 if err.errno == errno.EISDIR:
                     return self.format_dir()
    @@ -644,13 +657,13 @@ class Page:
         def format_dir(self):
             out = '== '
             pathname = ''
    -        for dirname in self.page_name.split('/'):
    +        for dirname in self.page_name.strip('/').split('/'):
                 pathname = (pathname + '/' + dirname) if pathname else dirname
                 out += '[[' + pathname + '|' + dirname + ']]/'
             out += ' ==\n'
      
             for filename in page_list(self._filename(), file_re):
    -            if img_re.match(filename):
    +            if image_re.match(filename):
                     if image_maxwidth:
                         maxwidth_arg = ' | maxwidth=' + str(image_maxwidth)
                     out += '{{' + self.page_name + '/' + filename + ' | ' + humanlink(filename) + maxwidth_arg + ' | class=thumbleft}}\n'
    @@ -713,19 +726,9 @@ class Page:
                 link_urls += [ [ "stylesheet", value ] ]
     
             send_title(self.page_name, self.split_title(),
    -            msg_text=self.msg_text, msg_type=self.msg_type, writable=self.can_write())
    +            msg_text=self.msg_text, msg_type=self.msg_type, writable=self.can_write(), mtime=self._mtime())
             self.send_naked()
    -        send_footer(self._last_modified())
    -
    -    def _last_modified(self):
    -        try:
    -            from time import localtime, strftime
    -            modtime = localtime(os.stat(self._filename())[stat.ST_MTIME])
    -        except OSError, err:
    -            if err.errno != errno.ENOENT:
    -                raise err
    -            return None
    -        return strftime(datetime_fmt, modtime)
    +        send_footer(mtime=self._mtime())
     
         def send_editor(self, preview=None):
             send_title(None, 'Edit ' + self.split_title(), msg_text=self.msg_text, msg_type=self.msg_type)
    @@ -770,18 +773,17 @@ class Page:
     
         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')
    +            send_title(None, msg_text='Read access denied by ACLs', msg_type='notice', mtime=self._mtime())
                 return
     
    +        emit_header(self._mtime(), mimetype)
             if 'maxwidth' in args:
                 import subprocess
    -            emit_header(mimetype)
                 sys.stdout.flush()
                 subprocess.check_call(['gm', 'convert', self._filename(),
                     '-scale', args['maxwidth'].value + ' >', '-'])
             else:
                 body = self.get_raw_body()
    -            emit_header(mimetype)
                 print(body)
     
         def _write_file(self, data):
    @@ -794,6 +796,9 @@ class Page:
                     os.remove(name)
                 except OSError, err:
                     if err.errno != errno.ENOENT: raise err
    +        path = os.path.split(name)[0]
    +        if not os.path.exists(path):
    +            os.makedirs(path)
             os.rename(tmp_filename, name)
     
         def save(self, newdata, changelog):