Allow retrieving the script path
[geekigeeki.git] / geekigeeki.py
index f906c07c53e638a08e55d9062aa0d10b95cfcbf6..5b26b553da7b344af20ce8d416693d95449f80de 100755 (executable)
@@ -8,19 +8,13 @@
 # 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
 # the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# (at your option) any later version.  You should have received a copy
+# of the GNU General Public License along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
 
 __version__ = '4.0-' + '$Id$'[4:11]
 
-from time import clock
+from time import clock, localtime, gmtime, strftime
 start_time = clock()
 title_done = False
 
@@ -42,6 +36,9 @@ def config_get(key, default=None):
 def script_name():
     return os.environ.get('SCRIPT_NAME', '')
 
+def script_path():
+    return os.path.split(os.environ.get('SCRIPT_FILENAME', ''))[0]
+
 def query_string():
     path_info = os.environ.get('PATH_INFO', '')
     if len(path_info) and path_info[0] == '/':
@@ -108,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):
@@ -122,12 +121,12 @@ def send_guru(msg_text, msg_type):
     print('</pre><script language="JavaScript" type="text/javascript" src="%s" defer="defer"></script>' \
         % 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('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"')
     print('  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">')
     print('<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">')
@@ -231,7 +230,8 @@ def link_inline(name, descr=None, kvargs={}):
     elif image_re.match(name):
         return '<a href="%s"><img border="0" src="%s" alt="%s" /></a>' % (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(kvargs)
+        Page(name).send_naked(kvargs) # FIXME: we should return the page as a string rather than print it
+        return ''
     else:
         return '<iframe width="100%%" scrolling="auto" frameborder="0" src="%s"><a href="%s">%s</a></iframe>' \
             % (url, url, name)
@@ -331,7 +331,7 @@ def handle_get(pagename, form):
         else:
             send_httperror("403 Forbidden", pagename)
 
-# Used by macros/WordIndex and macros/TitleIndex
+# Used by sys/macros/WordIndex and sys/macros/TitleIndex
 def make_index_key():
     links = ['<a href="#%s">%s</a>' % (ch, ch) for ch in 'abcdefghijklmnopqrstuvwxyz']
     return '<p style="text-align: center">' + ' | '.join(links) + '</p>'
@@ -342,12 +342,14 @@ def page_list(dirname=None, search_re=None):
         search_re = re.compile(r"^\b((([A-Z][a-z0-9]+){2,}/)*([A-Z][a-z0-9]+){2,})\b$")
     return sorted(filter(search_re.match, os.listdir(dirname or '.')))
 
-def send_footer(mod_string=None):
+def send_footer(mtime=None):
     if config_get('debug_cgi', False):
         cgi.print_arguments()
         cgi.print_form(form)
         cgi.print_environ()
-    link_inline("sys/footer", kvargs = { 'LAST_MODIFIED': mod_string })
+    link_inline("sys/footer", kvargs = {
+        'LAST_MODIFIED': strftime(config_get('datetime_fmt', '%a %d %b %Y %I:%M %p'), localtime(mtime))
+    })
     print("</body></html>")
 
 def _macro_ELAPSED_TIME(*args, **kvargs):
@@ -415,11 +417,11 @@ class WikiFormatter:
                 return self.kvargs[args[0]]
             macro = globals().get('_macro_' + args[0])
             if not macro:
-                exec(open("macros/" + args[0] + ".py").read(), globals())
+                exec(open("sys/macros/" + args[0] + ".py").read(), globals())
                 macro = globals().get('_macro_' + args[0])
             return macro(*args, **kvargs)
         except Exception, e:
-            msg = cgi.escape(word) + ": " + cgi.escape(e.message)
+            msg = cgi.escape(word) + ": " + cgi.escape(str(e))
             if not self.in_html:
                 msg = '<strong class="error">' + msg + '</strong>'
             return msg
@@ -637,15 +639,19 @@ class Page:
     def _tmp_filename(self):
         return self.page_name + '.tmp' + 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()
@@ -668,7 +674,7 @@ class Page:
  
         for filename in page_list(self._filename(), file_re):
             if image_re.match(filename):
-                maxwidth = config_get(image_maxwidth, '')
+                maxwidth = config_get('image_maxwidth', '400')
                 if maxwidth:
                     maxwidth = ' | maxwidth=' + str(maxwidth)
                 out += '{{' + self.page_name + '/' + filename + ' | ' + humanlink(filename) + maxwidth + ' | class=thumbleft}}\n'
@@ -731,19 +737,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(config_get(datetime_fmt, '%a %d %b %Y %I:%M %p'), 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)
@@ -767,18 +763,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):
@@ -792,7 +787,7 @@ class Page:
             except OSError, err:
                 if err.errno != errno.ENOENT: raise err
         path = os.path.split(name)[0]
-        if not os.path.exists(path):
+        if path and not os.path.exists(path):
             os.makedirs(path)
         os.rename(tmp_filename, name)