umnlisting.dcgi (5552B)
1 #!/usr/bin/env python 2 # coding=utf-8 3 # 4 # Dir listing like in UMN gopher. 5 # 6 # Files: .abstract, .names, .cap/$file, .Links 7 # Entries: Name=, Type=, Path=, Host=, Port=, Abstract=, Admin=, URL=, 8 # TTL= 9 # 10 11 import os 12 import sys 13 14 def dcgifilterprint(lines): 15 for line in lines: 16 line = line.strip() 17 if line[0] == 't': 18 print("t%s" % (line)) 19 else: 20 print("%s" % (line)) 21 22 def parselinksfile(filepath, link={}): 23 fd = open(filepath, "r") 24 links = {} 25 while 1: 26 line = fd.readline() 27 if not line: 28 if "path" in link: 29 links[link["path"]] = link 30 link = {} 31 break 32 line = line.strip() 33 if len(line) == 0 or line.startswith("#"): 34 if "path" in link: 35 links[link["path"]] = link 36 link = {} 37 continue 38 elif line.startswith("Type="): 39 link["type"] = line.split("=", 1)[1] 40 elif line.startswith("Name="): 41 link["name"] = line.split("=", 1)[1] 42 elif line.startswith("Path="): 43 link["path"] = line.split("=", 1)[1] 44 elif line.startswith("Host="): 45 link["host"] = line.split("=", 1)[1] 46 elif line.startswith("Port="): 47 link["port"] = line.split("=", 1)[1] 48 elif line.startswith("Numb="): 49 try: 50 link["number"] = int(line.split("=", 1)[1]) 51 except ValueError: 52 pass 53 elif line.startswith("Abstract="): 54 link["abstract"] = line.split("=", 1)[1] 55 while link["abstract"][-1] == "\\": 56 link["abstract"] = link["abstract"][:-1] 57 link["abstract"] += "\n" 58 link["abstract"] += fd.readline().strip() 59 60 # Undefined case in UMN. Handle it nicely. 61 if link["abstract"][-1] == "\\": 62 link["abstract"][-1] = "\n" 63 elif line.startswith("Admin="): 64 link["admin"] = line.split("=", 1)[1] 65 elif line.startswith("URL="): 66 link["url"] = line.split("=", 1)[1] 67 elif line.startswith("TTL="): 68 link["ttl"] = line.split("=", 1)[1] 69 fd.close() 70 71 return links 72 73 def usage(app): 74 print("usage: %s search arguments host port" % (app), 75 file=sys.stderr) 76 sys.exit(1) 77 78 def main(args): 79 scriptname = os.path.basename(args[0]) 80 if len(args) < 5: 81 usage(scriptname) 82 search = args[1] 83 arguments = args[2] 84 host = args[3] 85 port = args[4] 86 87 basedir = "." 88 if len(arguments) > 0 and arguments[0] == "/": 89 basedir = arguments[0].split("?")[0] 90 91 # First print every .abstract file content. 92 abstractpath = "%s/.abstract" % (basedir) 93 if os.path.exists(abstractpath): 94 fd = open(abstractpath, "r") 95 dcgifilterprint(fd.readlines()) 96 fd.close() 97 98 outputlinks = {} 99 numblinks = {} 100 101 linkspath = "%s/.Links" % (basedir) 102 if os.path.exists(linkspath): 103 linkslinks = parselinksfile(linkspath) 104 for linkkey in linkslinks.keys(): 105 outputlinks[linkkey] = linkslinks[linkkey] 106 if "number" in linkslinks[linkkey]: 107 numblinks[linkkey] = linkslinks[linkkey] 108 109 entries = os.listdir(basedir) 110 for entry in entries: 111 entrylink = {} 112 entrylink["type"] = "9" 113 if os.path.isdir(entry): 114 entrylink["type"] = "1" 115 116 entrylink["path"] = "./%s" % (entry) 117 entrylink["name"] = entry 118 capspath = "%s/.cap/%s" % (basedir, entry) 119 if os.path.exists(capspath): 120 caplink = parselinksfile(capspath, entrylink) 121 outputlinks[entrylink["path"]] = entrylink 122 if "number" in entrylink: 123 numblinks[entrylink["path"]] = entrylink 124 125 namespath = "%s/.names" % (basedir) 126 if os.path.exists(namespath): 127 nameslinks = parselinksfile(namespath) 128 for namekey in nameslinks.keys(): 129 namelink = nameslinks[namekey] 130 if namekey in outputlinks.keys(): 131 for key in namelink: 132 outputlinks[namekey][key] = \ 133 namelink[key] 134 else: 135 outputlinks[namekey] = nameslinks[namekey] 136 if "number" in outputlinks[namekey]: 137 numblinks[namekey] = outputlinks[namekey] 138 139 displaylinks = {} 140 for link in outputlinks.keys(): 141 if "name" in outputlinks[link]: 142 displaylinks[outputlinks[link]["name"]] = link 143 elif "path" in outputlinks[link]: 144 if outputlinks[link]["path"].startswith("./"): 145 displaylinks[outputlinks[link]["path"][2:]] = \ 146 link 147 else: 148 displaylinks[outputlinks[link]["path"]] = \ 149 link 150 else: 151 displaylinks[link] = link 152 153 displaykeys = sorted(displaylinks) 154 for dotfile in [".Links", ".names", ".cap", ".abstract"]: 155 try: 156 displaykeys.remove(dotfile) 157 except ValueError: 158 pass 159 160 # This is why the UMN format really sucks. 161 numbers = {} 162 for numb in numblinks.keys(): 163 link = outputlinks[numb] 164 numbers[link["number"]] = outputlinks[numb] 165 if "name" in link: 166 displaykeys.remove(link["name"]) 167 elif "path" in link: 168 if link["path"].startswith("./"): 169 displaykeys.remove(link["path"][2:]) 170 else: 171 displaykeys.remove(link["path"]) 172 173 curnumber = 1 174 while 1: 175 if curnumber in numbers.keys(): 176 path = numbers[curnumber]["path"] 177 numbers.pop(curnumber) 178 else: 179 key = displaykeys.pop() 180 path = displaylinks[key] 181 182 # Work on the rest of the numbered links, when no display 183 # entries are left. 184 if len(displaykeys) == 0: 185 if len(numbers) == 0: 186 break 187 randnumb = numbers.pop() 188 path = randnumb["path"] 189 190 link = outputlinks[path] 191 if "port" not in link: 192 link["port"] = "port" 193 if "host" not in link: 194 link["host"] = "server" 195 if "name" not in link: 196 if link["path"].startswith("./"): 197 link["name"] = link["path"][2:] 198 else: 199 link["name"] = link["path"] 200 if "type" not in link: 201 link["type"] = "9" 202 203 # dcgi escaping. 204 link["name"].replace("|", "\\|") 205 206 print("[%s|%s|%s|%s|%s]" % (link["type"][0],\ 207 link["name"], link["path"], link["host"],\ 208 link["port"])) 209 210 if "abstract" in link: 211 dcgifilterprint(link["abstract"].split("\n")) 212 213 curnumber += 1 214 215 return 0 216 217 if __name__ == "__main__": 218 sys.exit(main(sys.argv)) 219