#!/usr/bin/python # 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. # Author: Stefan Ritter <xeno@thehappy.de> # Description: A simple blogging software import cgi, os, time, glob, re, md5, sys, random 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 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">' print '<head>' print ' <title>Error!</title>' print '</head>' print '<body>' 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-transitional.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">' configuration = ConfigParser.ConfigParser() configuration.read('configuration') try: blog_title = configuration.get('personal', 'blog_title') except: errorpage("blog_title") 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") try: entries_suffix = configuration.get('personal', 'entries_suffix') except: errorpage("entries_suffix") try: staticpages_dir = configuration.get('personal', 'staticpages_dir') except: 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") 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") # Read POST Variables action = cgi.FieldStorage() month_display = action.getvalue('m') post_display = action.getvalue('p') static_display = action.getvalue('s') 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("<", "<") \ .replace(">", ">") \ .replace("\"", """) ctext = ctext.replace("<", "<") \ .replace(">", ">") \ .replace("\"", """) # Add comment if not cquiz == cquizv: errorpage("Brainmode") else: comments_file = glob.glob(entries_dir + ctitle + '.comments') if not comments_file: content = open(entries_dir + ctitle + '.comments', "w") content.close() comments_file = glob.glob(entries_dir + ctitle + '.comments') 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() # 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) 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]) + '-0' + str(date[1]) + '-' + str(date[2]) + 'T' + str(date[3]) + ':' + str(date[4]) + ':' + str(date[5]) + '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]) + '-0' + str(date[1]) + '-' + str(date[2]) + 'T' + str(date[3]) + ':' + str(date[4]) + ':' + str(date[5]) + 'Z</updated>' print ' </entry>' print '</feed>' # Generate regular page else: document_header("xhtml-transitional") 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 ' <div class="title"><a href="?" class="title">' + blog_title + '</a></div>' print ' <div class="feeds">' print ' <a href="?feed=rss"><img src="styles/images/rss.png" alt="rss" /></a>' print ' <a href="?feed=atom"><img src="styles/images/atom.png" alt="atom" /></a>' print ' </div>' print ' <div class="screen"><div class="sidebar">' # Sidebar: Staticpages if staticpages == "True": staticpages = [] staticpages_list = glob.glob(staticpages_dir + '*') staticpages_list.sort() print ' <div class="sidebarentry">' print ' <small>pages</small><br />' for staticpage in staticpages_list: title = re.sub('\w+?\/\d+?-', '', staticpage) link = re.sub('\w+?\/', '', staticpage) # The ultimative lookshe-hack *g* if title == "lookshe": print ' <a href="?s=' + link + '">/me</a> <br />' else: print ' <a href="?s=' + link + '">' + title + '</a> <br />' if monthlist == "True": print ' <br />' print ' </div>' # Sidebar: Monthlist if monthlist == "True": olddate = "" print ' <div class="sidebarentry">' print ' <small>months</small><br />' for entry in entries: date = time.strftime("%m%Y", entry[0]) date_display = time.strftime("%h %Y", entry[0]) if not olddate == date: print ' <a href="?m=' + date + '">' + date_display + '</a> <br />' olddate = date if linklist == "True": print ' <br />' print ' </div>' # Sidebar: Linklist if linklist == "True": print ' <div class="sidebarentry">' print ' <small>links</small><br />' content = open("linklist", "r") for line in content: if line.strip() is "": print ' <br />' else: print ' <a href="' + line.split(" ")[0] + '" target="_blank">' + line.split(" ", 1)[1].strip() + '</a> <br />' content.close() print ' </div>' print ' </div>' print ' <div class="content">' if static_display != "": # Show Staticpage content = open(staticpages_dir + static_display, "r") print ' <div class="entrytitle">' + re.sub('\d+?-', '', static_display) + '</div>' print ' <div class="entry"><p>' for line in content: print ' ' + line.strip() + '<br />' print ' </p></div>' content.close() else: # Show regular entry 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 == title or not post_display: if allentries_display == "1" or entry_counter < entries_per_page: content = open(entry, "r") if permalinks: print ' <div class="entrytitle"><a href="?p=' + title + '" class="entrytitle">' + title + ' <small>(' + date + ')</small></a></div>' else: print ' <div class="entrytitle">' + title + ' <small>(' + date + ')</small></div>' print ' <div class="entry">' for line in content: print ' ' + line.strip() + '<br />' # Comments are shown when post_display and comments_file comments_file = glob.glob(entries_dir + title + '.comments') if post_display: if comments_file: print ' <br /><hr />' comments_file = glob.glob(entries_dir + title + '.comments') comments_content = open(comments_file[0], "r") for line in comments_content: if line.split(".", 1)[0] == "-": print ' <br />' print ' <b><i>' + line.split(".", 1)[1].strip() + '</i><small> wrote at ' elif line.split(".", 1)[0] == "+": print ' ' + line.split(".", 1)[1].strip() + ':</small></b><br />' else: line = line.split(".", 1)[1] print ' ' + line.strip() + '<br />' comments_content.close() # Form for adding comments random_int_a = random.randint(1,9) random_int_b = random.randint(1,9) cquizv = random_int_a + random_int_b print ' <br /><br /><br />' print ' <form action="" method="post">' print ' <input type="hidden" name="ctitle" value="' + title + '" />' print ' <input type="hidden" name="cquizv" value="' + str(cquizv) + '" />' print ' <label for="cname">name:</label><input type="text" id="cname" name="cname" />' print ' <br /><label for="ctext">text:</label><textarea rows="5" cols="80" id="ctext" name="ctext"></textarea>' print ' <br /><label for="cquiz">' + str(random_int_a) + '+' + str(random_int_b) + '=</label><input type="text" id="cquiz" name="cquiz" />' print ' <br /><input type="submit" id="submit" value="post comment" />' print ' </form>' if comments == "True": comments_file = glob.glob(entries_dir + title + '.comments') if not comments_file and not post_display: print ' <div class="comment">' print ' <ul><li><a href="?p=' + title + '" class="comment">no comments</a></li></ul>' print ' </div>' 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="comment">' print ' <ul><li><a href="?p=' + title + '" class="comment">comments (' + str(comments_counter) + ')</a></li></ul>' print ' </div>' comments_content.close() print ' </div>' print ' <br /><br />' 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></div>' print ' </body>' print '</html>' # vim: set tw=0 ts=4: