geomyidae

A small C-based gopherd. (gopher://bitreich.org/1/scm/geomyidae)
git clone git://r-36.net/geomyidae
Log | Files | Refs | README | LICENSE

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