#!/usr/bin/python
import cgi
import os
import sys
import re
import time
import calendar
from datetime import datetime
import rlgalldb as rlgall
import cgitb
cgitb.enable()
infop = """
Looking for ttyrec files? Don't like digging through Web directory listings, converting time zones in your head, or guessing how many files
the game was spread across? The Archivist can find them all for you.
"""
ttyrecbase = "/var/dgl/dgldir/ttyrec/"
recre = r"(\d{4,4})-(\d{2,2})-(\d{2,2})\.(\d{2,2}):(\d{2,2}):(\d{2,2})\.ttyrec"
recrec = re.compile(recre)
def input_game(outf, selected=None):
"Prints the form components for selecting a game."
selstr = '\n'
unselstr = '\n'
outf.write('
\n'
outf.write(sstr)
return
def checkempty(cgidata):
exkeys = set(cgidata.keys())
wanted = set(["name", "game", "time", "year", "month", "day", "hour",
"minute", "second"])
return wanted.isdisjoint(exkeys)
def processname(fdata, errlist):
"Takes a CGI data object, extracts the player name, checks its validity, \
and returns it. If errors are encountered, they are appended to errlist."
cantfind = "I have no record of an adventurer called {0}."
if "name" not in fdata:
errlist.append("You didn\'t tell me the adventurer\'s name.")
return None
# Just in case someone supplies something nasty, make sure they can't go
# digging all over the filesystem.
formname = fdata.getfirst("name").rpartition("/")[2]
try:
os.stat(ttyrecbase + formname)
except OSError:
errlist.append(cantfind.format(cgi.escape(formname)))
return None
return formname
def processgame(fdata, errlist):
"Takes a CGI data object and returns the game from rlgall.gamelist that \
it asks for. Errors appended to errlist."
cantfind = "I've never heard of a dungeon called {0}."
if "game" not in fdata:
errlist.append('You didn\'t choose a dungeon.')
return None
formgame = fdata.getfirst("game")
for agame in rlgall.gamelist:
if agame.uname == formgame:
return agame
errlist.append(cantfind.format(cgi.escape(formgame)))
return None
def processtime(fdata, errlist, hlist):
"Takes a CGI data object and converts to a datetime object by finding \
fields called year, month, etc. Any errors get appended to errlist. \
hlist should contain 6 components, for ymd-hms fields."
# Timestamp overrides human-readable, even if it's invalid.
badtime = 'The time field is for Unix clocks, which never say anything \
like {0}. Try the form instead.'
utime = None
formtime = fdata.getfirst("time")
if formtime:
try:
utime = int(formtime)
except ValueError:
errlist.append(badtime.format(cgi.escape(formtime)))
return None
else:
if utime < 0:
utime = 0
if utime != None:
chtime = time.gmtime(utime)
for i in range(6):
hlist[i] = chtime[i]
return datetime.fromtimestamp(utime, rlgall.utc)
# Now try to get a human-readable specification.
lerrors = []
year = month = day = hour = minute = second = None
fyear = fdata.getfirst("year")
if not fyear:
lerrors.append("No year was provided.")
else:
try:
year = int(fyear)
except ValueError:
lerrors.append("Invalid year.")
else:
if year < 2010:
lerrors.append("The Gallery has only existed since 2010.")
elif year > time.gmtime()[0]:
lerrors.append("I can't see into the future.")
else:
hlist[0] = year # It is valid
fmonth = fdata.getfirst("month")
if not fmonth:
lerrors.append("No month was provided.")
else:
try:
month = int(fmonth)
except ValueError:
lerrors.append("Invalid month.")
else:
if month < 1 or month > 12:
lerrors.append("Invalid month.")
else:
hlist[1] = month
fday = fdata.getfirst("day")
if not fday:
lerrors.append("No day was provided.")
else:
try:
day = int(fday)
except ValueError:
lerrors.append("Invalid day.")
else:
if day < 1 or day > 31:
lerrors.append("Invalid day.")
elif not lerrors:
if day > calendar.monthrange(year, month)[1]:
lerrors.append("Invalid day.")
else:
hlist[2] = day
fhour = fdata.getfirst("hour")
if not fhour:
hour = 0 # Assume things.
hlist[3] = 0
else:
try:
hour = int(fhour)
except ValueError:
lerrors.append("Invalid hour.")
else:
if hour < 0 or hour > 23:
lerrors.append("Invalid hour.")
else:
hlist[3] = hour
fminute = fdata.getfirst("minute")
if not fminute:
minute = 0
hlist[4] = 0
else:
try:
minute = int(fminute)
except ValueError:
lerrors.append("Invalid minute.")
else:
if minute < 0 or minute > 59:
lerrors.append("Invalid minute.")
else:
hlist[4] = minute
fsecond = fdata.getfirst("second")
if not fsecond:
second = 0
hlist[5] = 0
else:
try:
second = int(fsecond)
except ValueError:
lerrors.append("Invalid second.")
else:
if second < 0 or second > 59:
lerrors.append("Invalid second.")
if second == 60 or second == 61:
lerrors.append("Leap seconds are worse than purple worms.")
else:
hlist[5] = second
if lerrors:
errlist.extend(lerrors)
return None
#return calendar.timegm([year, month, day, hour, minute, second, 0, 0, 0])
return datetime(year, month, day, hour, minute, second, 0, rlgall.utc)
# Begin processing
fdata = cgi.FieldStorage()
# If this is true, the user didn't supply any search criteria, so assume it
# doesn't want a search. Otherwise, every error or omission must be printed.
isnotsearch = checkempty(fdata)
errors = []
formname = dungeon = searchtime = None
timepieces = [None, None, None, None, None, None]
if not isnotsearch:
formname = processname(fdata, errors)
dungeon = processgame(fdata, errors)
searchtime = processtime(fdata, errors, timepieces)
dosearch = formname != None and dungeon != None and searchtime != None
# Find the actual files, and put them in a list called gamefiles.
gtimes = [0, int(time.time())]
relgame = None
gamefiles = []
if dosearch:
query1 = "SELECT ttyrecs FROM {0} WHERE name = %s AND startt <= %s AND endt >= %s;".format(dungeon.uname)
query2 = "SELECT ttyrecs FROM {0} WHERE name = %s AND endt >= %s ORDER BY endt LIMIT 1;".format(dungeon.uname)
query3 = "SELECT ttyrecs FROM {0} WHERE name = %s AND startt <= %s ORDER BY startt DESC LIMIT 1;".format(dungeon.uname)
conn = rlgall.getconn()
cur = conn.cursor()
cur.execute(query1, [formname, searchtime, searchtime])
result = cur.fetchone()
if result:
gamefiles = result[0]
else:
cur.execute(query2, [formname, searchtime])
result = cur.fetchone()
if result:
gamefiles = result[0]
else:
cur.execute(query3, [formname, searchtime])
result = cur.fetchone()
if result:
gamefiles = result[0]
cur.close()
conn.close()
# Now we are ready to print the page.
sys.stdout.write("Content-type: text/html\r\n\r\n")
sys.stdout.write(rlgall.phead.format("Archive"))
sys.stdout.write(rlgall.ptop)
sys.stdout.write(rlgall.navtop.format("Archive"))
sys.stdout.write('
\n')
sys.stdout.write(rlgall.pti.format("Guild Archives"))
if dosearch:
sys.stdout.write("
Expedition by {0} to {1} about {2}:
\n".format(
rlgall.playerlink(formname), dungeon.name,
searchtime.strftime("%Y/%m/%d %H:%M:%S")))
if not gamefiles:
sys.stdout.write("