@@ -2,9 +2,9 @@
import os, cgi, cgitb
import time, re, crypt
import html, mistune
markdown = mistune.markdown
form = cgi.FieldStorage()
settings = "./settings.txt"
cgitb.enable()
# To generate a mod password, use tripcode.py3 to generate a tripkey.
@@ -14,17 +14,15 @@ cgitb.enable()
# mod_pw field to do so, without an exclamation mark in front. Your tripkey
# should be 10 letters long, the result of an 8 character secure password
# that you know others can't guess easily.
#
# b_url and theme currently are unused.
with open("settings.txt", "r") as bconf :
with open(settings, "r") as settings:
b_conf = []
bconf = bconf.read().splitlines()
for s in bconf:
if len(s) == 0:
continue
elif s[0] == "#":
settings = settings.read().splitlines()
for s in settings:
if len(s) == 0 or s[0] == "#" or ": " not in s:
continue
elif "#" in s:
s = s.split("#")[0]
s = s.split(": ")
if len(s) > 2:
s[1] = ": ".join(s[1:])
@@ -32,9 +30,12 @@ with open("settings.txt", "r") as bconf:
s[1] = int(s[1])
except:
pass
b_conf += [s]
b_conf.append(s[1])
functions = ["main", "thread", "admin", "list", "create", "reply", "atom"]
functions = ["main", "thread", "list", \
"create", "reply", "atom"]
func_dict = {"atom": "bbs_atom()"}
t_modes = {"0":"", \
"1":"<img src='./img/lock.png' alt='Lock'>", \
@@ -42,13 +43,11 @@ t_modes = {"0":"", \
"3":"<img src='./img/sticky.png'><img src='./img/lock.png'>", \
"4":"<img src='./img/ghost.png' alt='Nobump'>"}
form = cgi.FieldStorage()
a_modes = {'p': "admin_posts()", 't': 'admin_threads()', 's': 'admin_config()'}
def main():
select_func = form.getvalue('m')
if select_func == 'atom':
if select_func in func_dict:
func_dict[select_func]
bbs_atom()
return
bbs_header()
@@ -56,12 +55,7 @@ def main():
if select_func in functions:
print("<a href='.'><< back</a><br>")
print("----"*10, "<p>")
if select_func == "admin":
if form.getvalue('n') in a_modes.keys():
print(a_modes[form.getvalue('n')])
else:
bbs_admin()
elif select_func == "main":
if select_func == "main":
bbs_main()
elif select_func == "thread":
bbs_thread()
@@ -79,65 +73,14 @@ def main():
bbs_foot()
def bbs_header():
print("Content-type: text/html\n")
with open("./html/head.html", "r") as head:
print(head.read().format(b_conf[0][1]))
def bbs_admin():
a_pass = ''
if form.getvalue('p'):
a_pass = tripcode(cgi.escape(form.getvalue('p')))[2:]
if a_pass != b_conf[3][1]:
print("<form method='post' action='.'>")
print("<b>Please enter your password.</b>")
print("<input type='hidden' name='m' value='admin'>")
print("<input type='text' name='p'>")
print("<input type='submit' value='Login'>")
print("</form>")
else:
print("<h2>Config</h2>")
print("welcome, user!", a_pass, "<p>")
for confg in b_conf:
print(confg[0]+":", confg[1], "<br>")
print("<div class='front'>")
print("View recent posts")
admin_posts(cgi.escape(form.getvalue('p')))
def admin_posts(p=''):
print(tripcode(p)[2:])
if tripcode(p)[2:] == b_conf[3][1]:
print("<h2>Last 40 posts</h2>")
with open(b_conf[10][1]) as ip_l:
ip_l = ip_l.read().splitlines()
ip_t = len(ip_l)
for n, ip in enumerate(ip_l[-1:-41:-1]):
ip = ip.split('|')
if len(ip) > 3:
ip[2] = "|".join(ip[3:])
p_stuff = ip[2].split(' >< ')
if len(p_stuff) > 4:
p_stuff[3] = " >< ".join(p_stuff[3:])
print("<div class='thread'><input type='checkbox'>")
print("#{0}:".format(ip_t - n))
print("<a href>edit</a> .")
print("<a href>delete</a> .")
print("<u style='color:red'>ban</u>")
print("<hr><table style='margin: auto'>")
print("<tr><td>thread:<td>", ip[1])
print("<tr><td>ip:<td>", ip[0])
print("<tr><td>name:<td>", cgi.escape(p_stuff[0]))
print("<tr><td>time:<td>", p_stuff[1])
print("</table>")
print("<hr><p>", do_format(p_stuff[3]))
print("</div><br>")
print(head.read().format(b_conf[0]))
def bbs_main():
print("<div class='front'>")
print("""Styles: [<a href="javascript:setActiveStyleSheet('4x13');">4x13</a>]
[<a href="javascript:setActiveStyleSheet('mob');">mob</a>
[<a href="javascript:setActiveStyleSheet('0ch');">0ch</a>]""")
print(" // [<a href='/wiki/'>wiki</a>]")
print("<h2>{0}</h2>".format(b_conf[0][1]))
print("<h2>{0}</h2>".format(b_conf[0]))
with open('./html/motd.html', 'r') as motd:
print(motd.read())
bbs_list(prev='1')
@@ -152,7 +95,7 @@ def bbs_thread(t_id='', prev=0):
t_id = cgi.escape(form.getvalue('t'))
if t_id:
if t_id.isdigit():
t_fn = b_conf[5][1] + t_id + ".txt"
t_fn = b_conf[5] + t_id + ".txt"
else:
bbs_list()
return
@@ -173,7 +116,7 @@ def bbs_thread(t_id='', prev=0):
else:
t_m = ''
the_thread[0] = the_thread[0].split("[<")[0]
elif int(r_cnt) >= b_conf[7][1] :
elif int(r_cnt) >= b_conf[7]:
t_m = t_modes['1']
print("<h3>", t_m, the_thread[0] + "[" + r_cnt + "]", "</h3>")
@@ -237,7 +180,7 @@ def bbs_thread(t_id='', prev=0):
reply[2] += "</p><div class='rmr'>Post shortened. " +\
"<a href='?m=thread;t={0}'>".format(t_id) \
+ "[View full thread]</a></div>"
show_r = b_conf[13][1]
show_r = b_conf[13]
if int(r_cnt) > show_r and p_n == int(r_cnt):
reply[2] = reply[2] + "</p><div class='rmr'>" \
+"<a href='?m=thread;t={0}'".format(t_id) \
@@ -246,14 +189,18 @@ def bbs_thread(t_id='', prev=0):
replies.append(reply)
if prev == 0:
print("</div>")
if t_m.strip() in ["1", "3"]:
print(t_modes[t_m.strip()])
print("This thread is locked. No more comments can be added.")
elif int(r_cnt) < b_conf[7][1]:
bbs_reply(t_fn, t_id)
if "lock" in t_m.strip() or "sticky" in t_m.strip():
print("<div class='closed'>")
print(t_m.strip())
print("This thread is locked.")
print("No more comments can be added.")
print("</div>")
elif int(r_cnt) >= b_conf[7]:
print("<div class='closed'>", t_modes['1'])
print("This thread is locked. Reply limit hit.")
print("</div>")
else:
print("<hr>", t_modes['1'])
print("No more replies; thread limit reached!")
bbs_reply(t_fn, t_id)
return replies
else:
@@ -281,14 +228,14 @@ def bbs_create():
local_dt = time.localtime(int(thread_attrs['dt']))
date_str = "%Y-%m-%d [%a] %H:%M"
thread_attrs['ldt'] = time.strftime(date_str, local_dt)
t_fn = b_conf[5][1] + thread_attrs['dt'] + ".txt"
with open(t_fn, "x") as new_thread:
t_fn = thread_attrs['dt'] + ".txt"
with open(b_conf[5] + t_fn, "x") as new_thread:
new_thread.write(thread_attrs['title'] + "\n" \
+ thread_attrs['name'] + " >< " \
+ thread_attrs['ldt'] + " >< >< " \
+ thread_attrs['content'] + "\n" )
print("Thread <i>{0}</i> posted successfully!".format(thread_attrs['title']))
with open(b_conf[11][1] , "a") as log:
with open(b_conf[11], "a") as log:
ip = os.environ["REMOTE_ADDR"]
# IP | location | filename | ldt | comment
log_data = " | ".join([ip, t_fn, thread_attrs['ldt'], \
@@ -296,7 +243,7 @@ def bbs_create():
log.write(log_data)
print("Redirecting you in 5 seconds...")
print("<meta http-equiv='refresh' content='5;.'")
with open(b_conf[6][1] , "r") as t_list:
with open(b_conf[6], "r") as t_list:
t_list = t_list.read().splitlines()
new_t = " >< ".join([thread_attrs['dt'], \
thread_attrs['ldt'], thread_attrs['title'], \
@@ -306,7 +253,11 @@ def bbs_create():
if len(t) == 5 and t[4] not in ["2", "3"] or len(t) == 4:
t_list.insert(n, new_t)
break
with open(b_conf[6][1], "w") as upd_list:
else:
pass
else:
t_list.insert(0, new_t)
with open(b_conf[6], "w") as upd_list:
upd_list.write('\n'.join(t_list))
else:
@@ -322,8 +273,8 @@ def bbs_list(prev='0', rss=False):
if prev == '0':
s_ts = None
else:
s_ts = b_conf[12][1]
with open(b_conf[6][1] ) as t_list:
s_ts = b_conf[12]
with open(b_conf[6]) as t_list:
t_list = t_list.read().splitlines()
t_cnt = len(t_list)
cnt = 1
@@ -336,9 +287,9 @@ def bbs_list(prev='0', rss=False):
t = t.split(" >< ")
if not rss:
print("<tr><td><a href='?m=thread;t={0}'>{1}.".format(t[0], cnt))
if int(t[3]) >= b_conf[7][1] and t[4] not in ["1", "3"]:
if int(t[3]) >= b_conf[7] and t[4] not in ["1", "3"]:
t[2] = t_modes['1'] + t[2]
elif int(t[3]) >= b_conf[7][1] and t[4] == "2":
elif int(t[3]) >= b_conf[7] and t[4] == "2":
t[2] = t_modes['3'] + t[2]
elif t[4] in t_modes.keys():
t[2] = t_modes[t[4]] + t[2]
@@ -370,68 +321,75 @@ def bbs_reply(t_fn='', t_id=''):
def bbs_atom(m='t'):
amode = form.getvalue('r')
if amode not in ['p', 't']:
bbs_header()
print(b_conf[8])
return
print("Content-type: application/atom+xml\r\n")
print('<?xml version="1.0" encoding="utf-8"?>')
print('<feed xmlns="http://www.w3.org/2005/Atom">')
if amode == 'p':
print("Content-type: application/atom+xml\r\n")
print('<?xml version="1.0" encoding="utf-8"?>')
print('<feed xmlns="http://www.w3.org/2005/Atom">')
print("<title>{0}: 50 latest posts</title>".format(b_conf[0][1]))
print("<link rel='self' href='" + b_conf[8][1] + "?m=atom;r=p' />")
print("<id>{0}#posts</id>".format(b_conf[8][1]))
print("<title>{0}: 50 latest posts</title>".format(b_conf[0]))
print("<link rel='self' href='" + b_conf[8] + "?m=atom;r=p' />")
print("<id>{0}#posts</id>".format(b_conf[8]))
isot = "%Y-%m-%dT%H:%M:00%z"
with open(b_conf[10][1]) as ip_l:
with open(b_conf[6], 'r') as tlist:
tlist = tlist.read().splitlines()
tdict = {}
for t in tlist:
t = t.split(" >< ")
tdict[t[0]] = t[2]
with open(b_conf[10]) as ip_l:
ip_l = ip_l.read().splitlines()[::-1][:50]
l_upd = ip_l[0].split(" >< ")[1].replace(" ", "").replace(".", "-")
l_upd = re.sub(r'\[(.*?)\]', 'T', l_upd)
print("<updated>" + l_upd + b_conf[9][1] + "</updated>")
for p in ip_l:
print("\n<entry>")
p = p.split(" >< ")
p = [p[0].split(" | ")[1], p[1], p[3]]
p[1] = p[1].replace(" ", "").replace(".", "-")
p[1] = re.sub(r'\[(.*?)\]', 'T', p[1])
p[1] += b_conf[9][1]
p[0] = p[0].split("/")[-1].split(".")[0]
p_url = b_conf[8][1] + "?m=thread;t=" + p[0]
print("<updated>" + p[1] + "</updated>")
print("<id>" + p_url + "#" + p[1] + "</id>")
print("<title>reply in thread", p_url + "</title>")
print("<link rel='alternate' href='" + p_url + "'/>")
p[2] = cgi.escape(p[2])
print("<content type='html'>", p[2], "</content>")
print("</entry>\n")
print("</feed>")
l_upd = ip_l[0].split(" >< ")[1].replace(" ", "").replace(".", "-")
l_upd = re.sub(r'\[(.*?)\]', 'T', l_upd)
print("<updated>" + l_upd + b_conf[9] + "</updated>")
for p in ip_l:
print("\n<entry>")
# 0: thread fn, 1: time, 2: post,
# 3: thread title, 4: link
p = p.split(" >< ")
p = [p[0].split(" | ")[1], p[1], cgi.escape(p[3])]
p[0] = p[0].split(".")[0]
p[1] = p[1].replace(" ", "").replace(".", "-")
p[1] = re.sub(r'\[(.*?)\]', 'T', p[1]) + b_conf[9]
p.append('"' + cgi.escape(tdict[p[0]]) + '"')
p.append(b_conf[8] + "?m=thread;t=" + p[0])
print("<updated>" + p[1] + "</updated>")
print("<id>" + p[4] + "#" + p[1] + "</id>")
print("<title>reply in thread", p[3], "</title>")
print("<link rel='alternate' href='" + p[4] + "'/>")
print("<content type='html'>", p[2], "</content>")
print("</entry>\n")
print("</feed>")
elif amode == 't':
print("Content-type: application/atom+xml\r\n")
print('<?xml version="1.0" encoding="utf-8"?>')
print('<feed xmlns="http://www.w3.org/2005/Atom">')
print("<title>{0} latest threads</title>".format(b_conf[0][1]))
print("<link rel='self' href='" + b_conf[8][1] + "?m=atom;r=t' />")
print("<id>{0}#threads</id>".format(b_conf[8][1]))
print("<title>{0}: 50 latest threads</title>".format(b_conf[0]))
print("<link rel='self' href='" + b_conf[8] + "?m=atom;r=t' />")
print("<id>{0}#threads</id>".format(b_conf[8]))
t_list = bbs_list('0', "1")
t_list.sort(key=lambda t_list:t_list[0])
upd = t_list[-1][0]
# print(t_list)
l_upd = time.localtime(int(upd))
isot = "%Y-%m-%dT%H:%M" + b_conf[9][1]
isot = "%Y-%m-%dT%H:%M" + b_conf[9]
l_upd = time.strftime(isot, l_upd)
print("<updated>" + l_upd + "</updated>")
for t in t_list[::-1]:
print("\n<entry>")
upd = time.localtime(int(t[0]))
t_url = b_conf[8][1] + "?m=thread;t=" + t[0]
t_url = b_conf[8] + "?m=thread;t=" + t[0]
print("<updated>" + time.strftime(isot, upd) + "</updated>")
print("<id>" + t_url + "</id>")
print("<link rel='alternate' href='" + t_url + "' />")
print("<title>", cgi.escape(t[2]), "</title>")
with open(b_conf[5][1] + t[0] + ".txt", "r") as tt:
with open(b_conf[5] + t[0] + ".txt", "r") as tt:
tt = tt.read().splitlines()[1]
tt = " >< ".join(tt.split(" >< ")[3:])
tt = cgi.escape(tt)
print("<content type='html'>", tt, "</content>")
print("</entry>")
print("</feed>")
else:
bbs_header()
print(b_conf[8])
def bbs_foot():
with open("./html/foot.html") as b_foot:
print(b_foot.read())
@@ -452,8 +410,8 @@ def do_reply():
if '#' in reply_attrs['name']:
namentrip = reply_attrs['name'].split('#')[:2]
namentrip[1] = tripcode(namentrip[1])
if b_conf[3][1] in namentrip[1]:
namentrip[1] = b_conf[2][1]
if b_conf[3] in namentrip[1]:
namentrip[1] = b_conf[2]
reply_attrs['name'] = '</span> <span class="admin">'.join(namentrip)
else:
reply_attrs['name'] = '</span> <span class="trip">'.join(namentrip)
@@ -477,7 +435,7 @@ def do_reply():
if "[<" in ter[0]:
if ter[0].split("[< ")[1] in ["1", "3"]:
fale = 3
elif (len(ter) - 1) >= b_conf[7][1] :
elif (len(ter) - 1) >= b_conf[7]:
fale = 1
else:
ter = ter[-1].split(' >< ')
@@ -496,16 +454,17 @@ def do_reply():
else:
print("Please clean ur html")
with open(b_conf[10][1] , "a") as log:
with open(b_conf[10], "a") as log:
if fale == 0:
ip = os.environ["REMOTE_ADDR"]
reply_attrs['t'] = reply_attrs['t'][len(b_conf[5]):]
log_data = " | ".join([ip, reply_attrs['t'], reply_string])
log.write(log_data)
print("comment successfully posted<p>")
print("Redirecting you in 5 seconds...")
print("<meta http-equiv='refresh' content='5;.'")
with open(b_conf[6][1] ) as t_list:
with open(b_conf[6]) as t_list:
reply_attrs['t'] = ''.join([i for i in reply_attrs['t'] if i.isdigit()])
t_line = [reply_attrs['t'], reply_attrs['ldt'], reply_attrs['bump']]
t_list = t_list.read().splitlines()
@@ -552,7 +511,7 @@ def do_reply():
nt_list[n] = " >< ".join(l)
if fale == 0:
with open(b_conf[6][1] , "w") as new_tl:
with open(b_conf[6], "w") as new_tl:
new_tl.write('\n'.join(nt_list))
else:
@@ -561,8 +520,8 @@ def do_reply():
def do_prev(bbt=[]):
if not bbt:
with open(b_conf[6][1] ) as t_list:
t_list = t_list.read().splitlines()[:b_conf[12][1] ]
with open(b_conf[6]) as t_list:
t_list = t_list.read().splitlines()[:b_conf[12]]
for n, t in enumerate(t_list):
t = t.split(" >< ")
bbs = bbs_thread(t[0], 1)
@@ -573,11 +532,11 @@ def do_prev(bbt=[]):
if bbt:
pstcnt = 0
bbn = len(bbt[0])
if bbn > b_conf[13][1] :
bbn = len(bbt[0]) - b_conf[13][1] + 1
if bbn > b_conf[13]:
bbn = len(bbt[0]) - b_conf[13] + 1
else:
bbn = 1
with open(b_conf[5][1] + str(bbt[1]) + ".txt") as t:
with open(b_conf[5] + str(bbt[1]) + ".txt") as t:
t_t = t.readline()[:-1]
t_r = len(t.read().splitlines())
@@ -598,29 +557,22 @@ def do_prev(bbt=[]):
print("</p>")
print("#{0} //".format(pstcnt))
print("Name: {0} \n: Date: {1} \n<p>{2}".format(*replies))
if pstcnt == 1 and len(bbt[0]) > b_conf[13][1]:
print("<hr width='420px' align='left'>")
elif pstcnt == len(bbt[0]):
if "lock" in t_m:
print("<br><div class='reply'>")
print("<br><div class='closed'>", t_m)
print("Thread locked. No more comments allowed")
print("</div><br></div></div>")
elif t_r < b_conf[7][1]:
print("<hr width='420px' align='left'>")
bbs_reply(b_conf[5][1] + bbt[1]+".txt")
else:
print("<hr><div class='closed'>", t_modes['1'])
print("<i>Thread limit reached.</i></div><p>")
print("</div>")
if "lock" in t_m or t_r >= b_conf[7]:
print("<br><div class='reply'>")
print("<br><div class='closed'>", t_m)
print("Thread locked. No more comments allowed")
print("</div><br></div></div>")
elif t_r < b_conf[7]:
print("<hr width='420px' align='left'>")
bbs_reply(b_conf[5] + bbt[1]+".txt")
def do_format(urp=''):
urp = urp.split('[yt]')
urp = urp[:3]
urp = '[yt]'.join(urp)
urp = re.sub(r'\[yt\]http(?:s?):\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)(&(amp;)?[\w\?=]*)?\[/yt\]', r'<div style="width:480; height:320" class="youtube" id="\1"></div><p>', urp)
Urp = re.sub(r'\[aa\](.*?)\[/aa\]', r'<pre class="aa"><b>Ascii Art:</b><hr>\1</pre><p>', urp)
# Urp = re.sub(r'\[aa\](.*?)\[/aa\]', r'<pre class="aa"><b>Ascii Art:</b><hr>\1</pre><p>', urp)
urp = re.sub(r'\[spoiler\](.*?)\[/spoiler\]', r'<span class="spoiler">\1</span>', urp)
urp = urp.split("<br>")
for n, l in enumerate(urp):