blogthon/blogthon.cgi

534 lines
20 KiB
Python
Executable File

#!/usr/bin/python
# -*- coding: utf-8 -*-
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What The Fuck You Want
# To Public License, Version 2, as published by Sam Hocevar. See
# http://sam.zoy.org/wtfpl/COPYING for more details.
# Authors: Stefan Ritter <xeno@thehappy.de>
# Adrian Vondendriesch <disco-stu@disco-stu.de>
# Description: A simple blogging software
import cgi, os, time, glob, re, md5, sys, random, smtplib
import ConfigParser
def generate_uuid(string):
string_md5sum = md5.new(string).hexdigest()
string_md5sum_1 = string_md5sum[0:8]
string_md5sum_2 = string_md5sum[8:12]
string_md5sum_3 = string_md5sum[12:16]
string_md5sum_4 = string_md5sum[16:20]
string_md5sum_5 = string_md5sum[20:32]
string = string_md5sum_1 + '-' + string_md5sum_2 + '-' + string_md5sum_3 + '-' + string_md5sum_4 + '-' + string_md5sum_5
return string
def errorpage(string):
print 'Content-type: text/html\n'
print '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'
print ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
print '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">'
print '<head>'
print ' <title>Error!</title>'
print '</head>'
print '<body>'
if string == "entries_dir":
print ' Directory <b>"' + entries_dir + '"</b> does not exist!'
elif string == "staticpages_dir":
print ' Directory <b>"' + staticpages_dir + '"</b> does not exist!'
elif string == "linklist":
print ' File <b>"linklist"</b> does not exist!'
elif string =="not writable entries_dir":
print ' Admin is a dumbass!!! Tell him to make his entries_dir writable.'
else:
print ' <b>' + string + '</b> is not set in configuration, please check your installation!'
print '</body>'
print '</html>'
sys.exit()
def document_header(string):
if string == "xhtml-transitional":
print 'Content-type: text/html\n'
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" xml:lang="en">'
if string == "xhtml-strict":
print 'Content-type: text/html\n'
print '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'
print ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
print '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">'
if string == "atom":
print 'Content-type: application/atom+xml\n'
print '<?xml version="1.0" encoding="utf-8"?>'
print '<feed xmlns="http://www.w3.org/2005/Atom">'
if string == "rss":
print 'Content-type: application/rss+xml\n'
print '<?xml version="1.0" encoding="utf-8"?>'
print '<rss version="2.0">'
configuration = ConfigParser.ConfigParser()
configuration.read('configuration')
try: blog_title = configuration.get('personal', 'blog_title')
except: errorpage("blog_title")
try: blog_subtitle = configuration.get('personal', 'blog_subtitle')
except: errorpage("blog_subtitle")
try: blog_url = configuration.get('personal', 'blog_url')
except: errorpage("blog_url")
try: keywords = configuration.get('personal', 'keywords')
except: errorpage("keywords")
try: entries_dir = configuration.get('personal', 'entries_dir')
except: errorpage("entries_dir")
if not os.path.exists(entries_dir):
errorpage("entries_dir")
try: entries_suffix = configuration.get('personal', 'entries_suffix')
except: errorpage("entries_suffix")
try: staticpages_dir = configuration.get('personal', 'staticpages_dir')
except: errorpage("staticpages_dir")
if not os.path.exists(staticpages_dir):
errorpage("staticpages_dir")
try: style = configuration.get('look', 'style')
except: errorpage("style")
try: entries_per_page = configuration.getint('look', 'entries_per_page')
except: errorpage("entries_per_page")
try: monthlist = configuration.get('look', 'monthlist')
except: errorpage("monthlist")
try: staticpages = configuration.get('look', 'staticpages')
except: errorpage("staticpages")
try: linklist = configuration.get('look', 'linklist')
except: errorpage("linklist")
if not os.path.exists("linklist"):
errorpage("linklist")
try: permalinks = configuration.get('look', 'permalinks')
except: errorpage("permalinks")
try: comments = configuration.get('look', 'comments')
except: errorpage("comments")
try: newest_first = configuration.get('look', 'newest_first')
except: errorpage("newest_first")
try: new_comment_mail = configuration.get('smtp', 'new_comment_mail')
except: errorpage("new_comment_mail")
try: mail_to = configuration.get('smtp', 'mail_to')
except: errorpage("mail_to")
try: smtp_host = configuration.get('smtp', 'smtp_host')
except: errorpage("smtp_host")
# Read POST Variables
action = cgi.FieldStorage()
month_display = action.getvalue('m')
static_display = action.getvalue('s')
if static_display: static_display = re.sub('/', '', static_display)
post_display = action.getvalue('p')
if post_display:
post_display = re.sub(' ', '-', post_display)
post_display = re.sub('/', '', post_display)
allentries_display = action.getvalue('a')
feed_display = action.getvalue('feed')
if not month_display: month_display = ""
if not post_display: post_display = ""
if not static_display: static_display = ""
if not allentries_display: allentries_display = ""
if not feed_display: feed_display = ""
# Commentstuff
ctitle = action.getvalue('ctitle')
cname = action.getvalue('cname')
ctext = action.getvalue('ctext')
cquiz = action.getvalue('cquiz')
cquizv = action.getvalue('cquizv')
if not ctitle: ctitle = ""
if not cname: cname = ""
if not ctext: ctext = ""
if not cquiz: cquiz = ""
if not cquizv: cquizv = ""
# Comment to commit?
if cname and ctext and ctitle:
# Prevent XSS hacks
cname = cname.replace("<", "&lt;") \
.replace(">", "&gt;") \
.replace("\"", "&quot;")
ctext = ctext.replace("<", "&lt;") \
.replace(">", "&gt;") \
.replace("\"", "&quot;")
# Add comment
if not cquiz == cquizv:
errorpage("Brainmode")
else:
comments_file = glob.glob(entries_dir + ctitle + '.comments')
if not comments_file:
try:
content = open(entries_dir + ctitle + '.comments', "w")
content.close()
except:
errorpage('not writable entries_dir')
comments_file = glob.glob(entries_dir + ctitle + '.comments')
try:
content = open(comments_file[0], "a+")
content.write("-." + cname + "\n")
content.write("+." + time.asctime() + "\n")
ctext = ctext.split("\n")
for line in ctext:
content.write("." + line + "\n")
content.close()
# Send mail?
if new_comment_mail:
msg = 'From: Blogthon\nTo: ' + mail_to + '\nSubject: New comment on ' + blog_title + '\n\nSomeone wrote a comment to this entry: ' + blog_url + '?p=' + re.sub(' ', '-', ctitle)
smtp = smtplib.SMTP(smtp_host)
smtp.sendmail(blog_title, mail_to, msg)
smtp.quit()
except:
errorpage('commentsfile seems not to be writable!')
# Read entries and store their title and timestamp
entries = []
entries_list = glob.glob(entries_dir + '*.' + entries_suffix)
for entry in entries_list:
timestamp = os.stat(entry)
timestamp = time.localtime(timestamp[8])
entry = timestamp, entry
entries.append(entry)
if newest_first:
entries.sort(reverse=True)
else:
entries.sort()
# Generate atom feed
if feed_display == "atom":
title = str(entries[0][1]).replace('entries/', '', 1).replace('.' + entries_suffix, '')
date = entries[0][0]
blog_title_md5sum = generate_uuid(blog_title)
title_md5sum = generate_uuid(title)
# Atom need a 2byte string
month = str(date[1])
day = str(date[2])
hour = str(date[3])
min = str(date[4])
sec = str(date[5])
if len(str(date[1])) == 1: month = '0' + str(date[1])
if len(str(date[2])) == 1: day = '0' + str(date[2])
if len(str(date[3])) == 1: hour = '0' + str(date[3])
if len(str(date[4])) == 1: min = '0' + str(date[4])
if len(str(date[5])) == 1: sec = '0' + str(date[5])
document_header("atom")
print '<link href="' + blog_url + '/?feed=atom" rel="self" type="application/atom+xml"/>'
print ' <author>'
print ' <name>' + blog_title + '</name>'
print ' </author>'
print ' <title>' + blog_title + '</title>'
print ' <id>urn:uuid:' + blog_title_md5sum + '</id>'
print ' <updated>' + str(date[0]) + '-' + month + '-' + day + 'T' + hour + ':' + min + ':' + sec + 'Z</updated>'
print ''
print ' <entry>'
print ' <title>' + title + '</title>'
print ' <link href="' + blog_url + '"/>'
print ' <id>urn:uuid:' + title_md5sum + '</id>'
print ' <updated>' + str(date[0]) + '-' + month + '-' + day + 'T' + hour + ':' + min + ':' + sec + 'Z</updated>'
print ' </entry>'
print '</feed>'
# Generate rss 2.0 feed
elif feed_display == "rss":
title = str(entries[0][1]).replace('entries/', '', 1).replace('.' + entries_suffix, '')
date = entries[0][0]
blog_title_md5sum = generate_uuid(blog_title)
title_md5sum = generate_uuid(title)
document_header("rss")
print ' <channel>'
print ' <title>' + blog_title + '</title>'
print ' <link>' + blog_url + '</link>'
print ' <description>' + blog_subtitle + '</description>'
# TODO: Format like: "Tue, 8 Jul 2008 2:43:19"
#print ' <pubDate>' + date + '<pubDate>'
print ''
print ' <item>'
print ' <title>' + title + '</title>'
print ' <link>' + blog_url + '</link>'
print ' <guid>' + title_md5sum + '</guid>'
print ' </item>'
print ' </channel>'
print '</rss>'
# Generate regular page
else:
document_header("xhtml-strict")
# XHTML Header
print ' <head>'
print ' <title>' + blog_title + '</title>'
print ' <meta http-equiv="content-type" content="text/html; charset=utf-8" />'
print ' <meta name="keywords" content="' + keywords + '" />'
print ' <meta name="description" content="' + blog_title + '" />'
print ' <link rel="stylesheet" type="text/css" href="styles/' + style + '" />'
print ' </head>'
print ' <body>'
print ''
# Site header
print ' <div class="header">'
print ' <div class="header_title">'
print ' <a href="?" class="header_link">' + blog_title + '</a>'
print ' </div>'
print ' <div class="header_subtitle">'
print ' <span class="header_subtitle">' + blog_subtitle + '</span>'
print ' </div>'
print ' </div>'
print ''
# RSS feed
print ' <div class="rss">'
if os.path.exists('styles/' + style.replace('.css', '') + '_img/rss.jpg'):
print ' <a href="?feed=rss"><img src="styles/' + style.replace('.css', '') + '_img/rss.jpg"></a>'
else:
print ' <a href="?feed=rss" class="rss_link">rss</a>'
print ' </div>'
print ''
# Atom feed
print ' <div class="atom">'
if os.path.exists('styles/' + style.replace('.css', '') + '_img/atom.jpg'):
print ' <a href="?feed=atom"><img src="styles/' + style.replace('.css', '') + '_img/atom.jpg></a>'
else:
print ' <a href="?feed=atom" class="atom_link">atom</a>'
print ' </div>'
print ''
# Staticpages
if staticpages == "True":
staticpages = []
staticpages_list = glob.glob(staticpages_dir + '*')
staticpages_list.sort()
print ' <div class="pages">'
print ' <div class="pages_title">pages</div>'
print ' <div class="pages_list">'
print ' <ul class="pages_list">'
for staticpage in staticpages_list:
file = open(staticpage, 'r')
header = file.readline()
if header.split(':', 1)[0] == 'extern_link':
link = header.split(':', 1)[1].strip()
else:
link = re.sub('\w+?\/', '', staticpage)
link = '?s=' + link
file.close()
title = re.sub('\w+?\/\d+?-', '', staticpage)
print ' <li class="pages_list_entry"><a href="' + link + '" class="pages_list_entry">' + title + '</a></li>'
print ' </ul>'
print ' </div>'
print ' <div class="pages_footer"></div>'
print ' </div>'
print ''
# Monthlist
if monthlist == "True":
olddate = ""
print ' <div class="months">'
print ' <div class="months_title">months</div>'
print ' <div class="months_list">'
print ' <ul class="months_list">'
for entry in entries:
date = time.strftime("%m%Y", entry[0])
date_display = time.strftime("%h %Y", entry[0])
if not olddate == date:
print ' <li class="months_list_entry"><a href="?m=' + date + '" class="months_list_entry">' + date_display + '</a></li>'
olddate = date
print ' </ul>'
print ' </div>'
print ' <div class="months_footer"></div>'
print ' </div>'
print ''
# Linklist
if linklist == "True":
print ' <div class="linklist">'
print ' <div class="linklist_title">links</div>'
print ' <div class="linklist_list">'
print ' <ul class="linklist_list">'
try:
content = open("linklist", "r")
for line in content:
if line.strip() is "":
print '<br />'
else:
print ' <li class="linklist_list_entry"><a href="' + line.split(" ")[0] + '" target="_blank" class="months_list_entry">' + line.split(" ", 1)[1].strip() + '</a></li>'
content.close()
except:
print ''
print ' </ul>'
print ' </div>'
print ' <div class="linklist_footer"></div>'
print ' </div>'
print ''
print ' <div class="entries">'
print ''
# Staticpage
if static_display != "":
content = open(staticpages_dir + static_display, "r")
print ' <div class="entry">'
print ' <div class="entry_title">' + re.sub('\d+?-', '', static_display) + '</div>'
print ' <div class="entry_content">'
print ' <p>'
for line in content:
if re.search('<li>', line) or re.search('<ul>', line) or re.search('</ul>', line) or re.search('<ol>', line) or re.search('</ol>', line):
print ' ' + line.strip()
else:
print ' ' + line.strip() + '<br />'
print ' </p>'
print ' </div>'
print ' <div class="entry_footer"></div>'
print ' <div class="entry_border_left"></div>'
print ' <div class="entry_border_right"></div>'
print ' <div class="entry_border_top"></div>'
print ' <div class="entry_border_bottom"></div>'
print ' </div>'
print ''
content.close()
# Entry
else:
entry_counter = 0
for entry in entries:
date = time.strftime("%c", entry[0])
date_to_compare = time.strftime("%m%Y", entry[0]) # Needed for permalinks
entry = entry[1]
title = entry.replace('entries/', '', 1)
title = title.replace('.' + entries_suffix, '')
if month_display == date_to_compare or not month_display:
if post_display == re.sub(' ', '-', title) or not post_display:
if allentries_display == "1" or entry_counter < entries_per_page:
content = open(entry, "r")
print ' <div class="entry">'
if permalinks:
print ' <div class="entry_title"><a href="?p=' + re.sub(' ', '-', title) + '" class="entry_title">' + title + '</a></div>'
else:
print ' <div class="entry_title">' + title + '</div>'
print ' <div class="entry_date">' + date + '</div>'
print ' <div class="entry_content">'
for line in content:
if re.search('<li>', line) or re.search('<ul>', line) or re.search('</ul>', line) or re.search('<ol>', line) or re.search('</ol>', line):
print ' ' + line.strip()
else:
print ' ' + line.strip() + '<br />'
print ' </div>'
print ' <div class="entry_footer"></div>'
print ' <div class="entry_border_left"></div>'
print ' <div class="entry_border_right"></div>'
print ' <div class="entry_border_top"></div>'
print ' <div class="entry_border_bottom"></div>'
# Comments...
# ... are shown when post_display and comments_file isn't false
comments_file = glob.glob(entries_dir + title + '.comments')
if post_display:
if comments_file:
comments_file = glob.glob(entries_dir + title + '.comments')
comments_content = open(comments_file[0], "r")
print ' </div>'
print ' </div>'
print ''
print ' <div class="comments">'
notfirstline = 0 # Ugly fix for closing comment containers
for line in comments_content:
if re.search("^-", line):
if notfirstline == 1:
print ' </div>'
print ' </div>'
notfirstline = 0;
print ' <div class="comment">'
print ' <div class="comment_author">' + line.split(".", 1)[1].strip() + '</div>'
elif re.search("^\+", line):
print ' <div class="comment_date">' + line.split(".", 1)[1].strip() + '</div>'
print ' <div class="comment_content">'
else:
notfirstline = 1;
line = line.split(".", 1)[1]
print ' ' + line.strip() + '<br />'
print ''
print ' </div>'
print ' </div>'
comments_content.close()
else:
print ' </div>'
print ' </div>'
print ' <div class="comments">'
# Form for adding comments
if comments == "True":
random_int_a = random.randint(1,9)
random_int_b = random.randint(1,9)
cquizv = random_int_a + random_int_b
print ' <div class="submit_comment">'
print ' <form action="" method="post">'
print ' <input type="hidden" name="ctitle" value="' + title + '" />'
print ' <input type="hidden" name="cquizv" value="' + str(cquizv) + '" />'
print ' <label class="submit_comment_name">name:</label><input class="submit_comment_name_input" type="text" id="cname" name="cname" />'
print ' <br /><label class="submit_comment_text">text:</label><textarea class="submit_comment_textarea" id="ctext" name="ctext"></textarea>'
print ' <br /><label class="submit_comment_quiz">' + str(random_int_a) + '+' + str(random_int_b) + '=</label><input class="submit_comment_quiz_input" type="text" id="cquiz" name="cquiz" />'
print ' <br /><input class="submit_comment_button" type="submit" id="submit" value="post comment" />'
print ' </form>'
print ' </div>'
else:
print ' <div class="submit_border_bottom"></div>'
print ''
if comments == "True":
comments_file = glob.glob(entries_dir + title + '.comments')
if not comments_file and not post_display:
print ' <div class="entry_comment">'
print ' <a href="?p=' + re.sub(' ','-', title) + '" class="entry_comment">no comments</a>'
print ' </div>'
print ' </div>'
print ''
elif comments_file and not post_display:
comments_content = open(comments_file[0], "r")
comments_counter = 0
for line in comments_content:
if line.split(".", 1)[0] == "-": comments_counter += 1
print ' <div class="entry_comment">'
print ' <a href="?p=' + re.sub(' ', '-', title) + '" class="entry_comment">comments (' + str(comments_counter) + ')</a>'
print ' </div>'
print ' </div>'
print ''
comments_content.close()
else:
print ' </div>'
print ''
content.close()
entry_counter += 1
if not month_display and not post_display and not allentries_display and entry_counter == entries_per_page: # Display pagelist
print ' <div class="entry"><a href=?a=1>View all entries...</a></div>'
print ' </div>'
print ''
print ' </body>'
print '</html>'
# vim: set tw=0 ts=4: