import sys, pickle from random import randint from pprint import pprint as pp from mystic_bbs import * NODELIST = "/mystic/data/nodelist.txt" RATING_FILE = "/mystic/scripts/mL-nlparse.dat" dictNodelist = {} ratingsDB = {} canexit = "no" screenWidth = 80 screenDepth = 24 AUTHOR = "MeaTLoTioN" cRESET = "|16|07" hBG = "|19" hFG = "|14" fBG = "|19" fFG = "|14" barOffset = 1 highlightedBBS = "" filter = "" KEY_UP = chr(72) KEY_DOWN = chr(80) KEY_ESCAPE = chr(27) KEY_ENTER = chr(13) KEY_TAB = chr(9) KEY_LEFT = chr(75) KEY_RIGHT = chr(77) KEY_HOME = chr(71) KEY_END = chr(79) KEY_PGUP = chr(73) KEY_PGDN = chr(81) KEY_QMARK = chr(63) KEY_BSPACE = chr(8) def saveDB(): global ratingsDB global RATING_FILE with open(RATING_FILE, 'wb') as fhandle: pickle.dump(ratingsDB, fhandle, protocol=pickle.HIGHEST_PROTOCOL) def loadDB(): global ratingsDB global RATING_FILE try: with open(RATING_FILE, 'rb') as fhandle: ratingsDB = pickle.load(fhandle) except: pass def stripmci(str): pos = str.find("|") while pos != -1 : str = str[:pos] + str[pos+3:] pos = str.find("|") return str def initNodelist(): with open(NODELIST) as f: lines = f.readlines() for line in lines: if line.startswith(";") or line.startswith("Hub"): pass else: tmp = line.strip("\n").split(",") if tmp[0] == "Zone": ZONE = tmp[1] elif tmp[0] == "Region" or tmp[0] == "Host": REGION = tmp[1] else: NODE = tmp[1] BBS_NAME = tmp[2] if BBS_NAME not in dictNodelist: dictNodelist[BBS_NAME] = {} BBS_NAME_PRETTY = BBS_NAME.replace("_"," ") BBS_LOCATION = tmp[3] BBS_SYSOP = tmp[4] test = [string for string in tmp if "NA" in string] if test: BBS_ADDRESS_FULL = test[0][4:] else: BBS_ADDRESS_FULL = "Private" BBS_ADDRESS = BBS_ADDRESS_FULL.split(":")[0] if ":" in BBS_ADDRESS_FULL: BBS_PORT = BBS_ADDRESS_FULL.split(":")[1] else: BBS_PORT = 23 for i in range(0,len(tmp)-1): if "ITN" in tmp[i]: if ":" in tmp[i]: BBS_PORT = tmp[i].split(':')[1] else: BBS_PORT = 23 try: if [match for match in tmp if "MY" in match]: BBS_SOFTWARE = "Mystic" elif [match for match in tmp if "SC" in match]: BBS_SOFTWARE = "Synchronet" elif [match for match in tmp if "SYNC" in match]: BBS_SOFTWARE = "Synchronet" elif [match for match in tmp if "MB" in match]: BBS_SOFTWARE = "MBSE" elif [match for match in tmp if "LGCX" in match]: BBS_SOFTWARE = "Legacy/X" elif [match for match in tmp if "ENIG" in match]: BBS_SOFTWARE = "Enigma1/2" elif [match for match in tmp if "EG" in match]: BBS_SOFTWARE = "Enigma1/2" elif [match for match in tmp if "CNET" in match]: BBS_SOFTWARE = "CNET" elif [match for match in tmp if "PCB" in match]: BBS_SOFTWARE = "PC Board" elif [match for match in tmp if "OBV2" in match]: BBS_SOFTWARE = "Oblivion 2" elif [match for match in tmp if "WLDC" in match]: BBS_SOFTWARE = "Wildcat" else: BBS_SOFTWARE = "n/a" except: BBS_SOFTWARE = "Undefined" d = dictNodelist[BBS_NAME] d["NAME"] = BBS_NAME_PRETTY d["LOCATION"] = BBS_LOCATION d["SYSOP"] = BBS_SYSOP d["ADDRESS"] = BBS_ADDRESS d["PORT"] = BBS_PORT d["SOFTWARE"] = BBS_SOFTWARE d["RATING"] = 0 if "NODE_ADDRESSES" not in d: d["NODE_ADDRESSES"] = [] NODE_ADDRESS = "%s:%s/%s" % (ZONE,REGION,NODE) d["NODE_ADDRESSES"].append(NODE_ADDRESS) def init(): write("|CL") header() footer() gotoxy(1,2) def header(): MSG = "BBS Name".ljust(22)+" "+"SysOp".ljust(15)+" "+"Location".ljust(15)+" "+"Software".ljust(15)+" "+"Rating".ljust(6)+" " gotoxy(1,1) write(hBG+hFG+" "*screenWidth) gotoxy(1,1) write(MSG+cRESET) def footer(): MSG = "Mystic Nodelist Browser v1.0 by "+AUTHOR lMSG = len(MSG) HELP = "|11Help [?]" lHELP = len(stripmci(HELP)) gotoxy(1,screenDepth) write(fBG+fFG+" "*screenWidth) gotoxy((screenWidth/2)-(lMSG/2),screenDepth) write(MSG) gotoxy(screenWidth-lHELP,screenDepth); write(HELP) write(cRESET) def getBBS(o, s): global barOffset, filter, fDictSortedLen selectedBBS = "" count = 0 tmpDict = sorted(dictNodelist, reverse=False) fDict = {} for BBS in tmpDict: if filter.upper() in BBS.upper(): fDict[BBS] = {} fDictSorted = sorted(fDict, reverse=False) fDictSortedLen = len(fDictSorted) for BBS in fDictSorted: count += 1 if count == o+s: selectedBBS = BBS return selectedBBS def showList(offset = 0): global barOffset global highlightedBBS global filter global fDictSortedLen write('[?1000h') position = str(barOffset+offset).rjust(4)+"/"+str(fDictSortedLen).rjust(4) gotoxy(10,1); write("|19|11["+position+"]") R = 1 count = 0 gotoxy(1,2) write("|16|07") tmpDict = sorted(dictNodelist, reverse=False) fDict = {} for BBS in tmpDict: if filter.upper() in BBS.upper(): fDict[BBS] = {} fDictSorted = sorted(fDict, reverse=False) fDictSortedLen = len(fDictSorted) for BBS in fDictSorted: count += 1 if count < offset+1: pass else: R += 1 if R < screenDepth: if barOffset > fDictSortedLen-1: barOffset = fDictSortedLen if barOffset+1 == R: gotoxy(1,R) write('|21|15') C1 = BBS.replace('_',' ').ljust(22)[:22] C2 = dictNodelist[BBS]["SYSOP"].replace('_',' ').ljust(15)[:15] C3 = dictNodelist[BBS]["LOCATION"].replace('_',' ').ljust(15)[:15] C4 = dictNodelist[BBS]["SOFTWARE"].ljust(15)[:15] if "n/a" in C4: SPC = "|08" else: SPC = "" try: C5 = ratingsDB[BBS] except: C5 = 0 C5Diff = 7 - C5 C5Text = "|10"+chr(254)*C5+"|08"+chr(254)*C5Diff thisLine = C1+" "+C2+" "+C3+" "+SPC+C4+" "+C5Text.rjust(7) pad = " "*(79-len(stripmci(thisLine))) writeln(thisLine.ljust(79)+pad+"|16|07") if count < screenDepth-1: for i in range(count+2, screenDepth): gotoxy(1,i); write("|[K") gotoxy(1,24); write("|19|11"+filter.ljust(18)[:18]+"|16|07") def drawWindow(x1, y1, x2, y2, title = ""): for Y in range(y1, y2): for X in range(x1, x2): gotoxy(X, Y); write(' ') for I in range(x1+1, x2-1): gotoxy(I, y1+1); write('|13'+chr(205)) gotoxy(I, y2-2); write('|05'+chr(205)) for I in range(y1+1, y2-1): gotoxy(x1+1, I); write('|13'+chr(186)) gotoxy(x2-2, I); write('|05'+chr(186)) if title: ntitle = "[ |15"+title+"|13 ]" ltitle = len(stripmci(ntitle)) center = ((x2-x1)/2)-(ltitle/2)+x1 gotoxy(center, y1+1); write('|13'+ntitle) gotoxy(x1+1,y1+1); write('|13'+chr(201)) gotoxy(x2-2,y1+1); write('|13'+chr(187)) gotoxy(x1+1,y2-2); write('|05'+chr(200)) gotoxy(x2-2,y2-2); write('|05'+chr(188)) def showHelp(): write("|SS") drawWindow(10,2,70,23,"Help Menu") gotoxy(13,4); write("|15To use this BBS lister just remember a few simple key") gotoxy(13,5); write("|15bindings. There aren't many... ") gotoxy(13,6); write("|15 ") gotoxy(13,7); write("|15In the LIST view: ") gotoxy(13,8);write("|15UP/DOWN Arrows move the bar UP/DOWN a line. ") gotoxy(13,9);write("|15LEFT/RIGHT or PGUP/PGDN moves the list 1 page UP/DN ") gotoxy(13,10);write("|15ENTER chooses the highlighted BBS to see more detail.") gotoxy(13,11);write("|15 ") gotoxy(13,12);write("|15Start typing letters/numbers to live-filter the list!") gotoxy(13,13);write("|15 ") gotoxy(13,14);write("|15In the BBS Detail view: ") gotoxy(13,15);write("|15LEFT/RIGHT allows you to rate the BBS from 0-7 ") gotoxy(13,16);write("|15If the BBS isn't Private, connect to it by pressing C") gotoxy(13,17);write("|15To leave the detail view press Q or UP/DOWN arrows. ") gotoxy(13,18);write("|15 ") gotoxy(13,19);write("|15To exit the program press ESCAPE at the list view. ") gotoxy(13,20);write("|15 ") gotoxy(13,21); write("|PA") write("|RS") def showDetail(BBS): write("|SS") write('[?1000l') bbs = BBS.replace('_',' ')[:22] sysop = dictNodelist[BBS]["SYSOP"].replace('_',' ') location = dictNodelist[BBS]["LOCATION"].replace('_',' ') software = dictNodelist[BBS]["SOFTWARE"] try: rating = ratingsDB[BBS] except: rating = 0 address = dictNodelist[BBS]["ADDRESS"] if not address: address = "Unknown" port = dictNodelist[BBS]["PORT"] node_addresses = dictNodelist[BBS]["NODE_ADDRESSES"] drawWindow(15,4,66,21,bbs) gotoxy(18,7); write("|13BBS SysOp") gotoxy(18,8); write('|15'+sysop) gotoxy(51,7); write("|13BBS Location") gotoxy(41,8); write('|15'+location.rjust(22)[:22]) gotoxy(18,10); write("|13BBS Address") gotoxy(18,11); write('|15'+address+':'+str(port)) gotoxy(51,10); write("|13BBS Software") gotoxy(48,11); write('|15'+software.rjust(15)[:15]) gotoxy(18,14); write("|13Node Address(es)") rCount = 0 tCount = 0 row = 1 node_addresses.sort() for node_address in node_addresses: if tCount < 16: rCount += 1 tCount += 1 if rCount > 4: rCount = 1 row += 1 gotoxy(7+(rCount*11), 14+row); write('|15'+node_address.ljust(10)) gotoxy(18,19); write("|13[ |15Q to go back |13]") ratingDiff = 7 - rating ratingText = "|10"+chr(254)*rating+"|08"+chr(254)*ratingDiff gotoxy(35,19); write("|13[ "+ratingText.ljust(7)+" |13]") if address and "Private" not in address and "Unknown" not in address: gotoxy(47,19); write("|13[ |15C to connect |13]") else: gotoxy(47,19); write("|13[ |08C to connect |13]") gotoxy(1,24); canend = "no" while not canend == "yes": ch = onekey(chr(13) + 'CQ'+KEY_RIGHT+KEY_LEFT+KEY_UP+KEY_DOWN, False) if ch == 'Q' or ch == KEY_UP or ch == KEY_DOWN: canend = "yes" if ch == 'C': if address and "Private" not in address and "Unknown" not in address: write('|SS'); write('|[1|CL') menucmd('IT','/addr='+address+' /port='+str(port)) write('[0;26 D'); write('|RS|[0') if ch == KEY_LEFT: if rating > 0: rating -= 1 ratingsDB[BBS] = rating saveDB() ratingDiff = 7 - rating ratingText = "|10"+chr(254)*rating+"|08"+chr(254)*ratingDiff gotoxy(35,19); write("|13[ "+ratingText.ljust(7)+" |13]") if ch == KEY_RIGHT: if rating < 7: rating += 1 ratingsDB[BBS] = rating saveDB() ratingDiff = 7 - rating ratingText = "|10"+chr(254)*rating+"|08"+chr(254)*ratingDiff gotoxy(35,19); write("|13[ "+ratingText.ljust(7)+" |13]") write("|RS") def mainMenu(): global barOffset, offset, highlightedBBS, filter, fDictSortedLen maxOffset = fDictSortedLen-(screenDepth-2) finished = "no" highlightedBBS = getBBS(barOffset, offset) showList(offset) char, extended = getkey() if extended: if char == KEY_UP: if barOffset > 1: barOffset -= 1 elif barOffset == 1: if offset > 0: offset -= 1 highlightedBBS = getBBS(barOffset, offset) if char == KEY_DOWN: if barOffset < fDictSortedLen: if barOffset < screenDepth-2: barOffset += 1 elif barOffset > screenDepth-3: if offset < maxOffset: offset += 1 highlightedBBS = getBBS(barOffset, offset) if char == KEY_LEFT or char == KEY_PGUP: if offset > screenDepth-3: offset -= screenDepth-3 else: offset = 0 if barOffset > 1 and offset < 1: barOffset = 1 highlightedBBS = getBBS(barOffset, offset) if char == KEY_RIGHT or char == KEY_PGDN: if fDictSortedLen < screenDepth-2: barOffset = fDictSortedLen elif offset < maxOffset - (screenDepth-3): offset += screenDepth-3 else: offset = maxOffset if barOffset < screenDepth-2 and offset > maxOffset-1: barOffset = screenDepth-2 highlightedBBS = getBBS(barOffset, offset) if char == KEY_HOME: barOffset = 1 offset = 0 if char == KEY_END: if fDictSortedLen < screenDepth-2: barOffset = fDictSortedLen else: barOffset = screenDepth-2 offset = maxOffset else: if char == KEY_ENTER: if fDictSortedLen > 0: showDetail(highlightedBBS) elif char == KEY_ESCAPE: finished = "yes" elif char == KEY_QMARK: showHelp() elif char == KEY_BSPACE: if len(filter) > 0: filter = filter[:-1] else: if char.isalnum() or char.isspace(): barOffset = 1 offset = 0 if len(filter) < 18: filter = filter+char.upper().replace(' ', '_') highlightedBBS = getBBS(barOffset, offset) return finished menucmd('NA','sIftIng fOr gOld') write("|[0") loadDB() initNodelist() offset = 0 init() highlightedBBS = getBBS(0, 0) while canexit == "no": canexit = mainMenu() write("|[1") write('[?1000l')