/sw/foafcite.cgi

#!/usr/bin/env python
"""
FOAFCite CGI - Get summary information on people
Author: Sean B. Palmer, inamidst.com
License: GPL 2; share and enjoy!
"""

import sys, re, cgi, urllib
import cgitb; cgitb.enable()

form = cgi.FieldStorage()
def call(s): 
   try: return form[s].value
   except KeyError: return None
form.__call__ = call

mkquery = 'select %s where %s%s%s'
r_word = re.compile(r'[A-Za-z0-9]+')
r_line = re.compile(r'^[a-z]+: ')

class Grab(urllib.URLopener): 
   def __init__(self, *args): 
      self.version = 'Mozilla/5.0 (foafcite)'
      urllib.URLopener.__init__(self, *args)
   def http_error_default(self, url, fp, errcode, errmsg, headers): 
      return urllib.addinfourl(fp, [headers, errcode], "http:" + url)
urllib._urlopener = Grab()

using = ('using foaf for <http://xmlns.com/foaf/0.1/>, ' +
               'rdfs for <http://www.w3.org/2000/01/rdf-schema#>')
using = ''
julie = 'http://crschmidt.net/rdfpython/redlandbot.py?machine=1&cmd=%5Eq+'

def mknamebel(name): 
   name = ''.join(r_word.findall(name))
   if not name: return 'Person'
   if name[0] in '0123456789': 
      name = 'n' + name
   return name

def term(t): 
   if t.startswith('_'): 
      return t[2:]
   elif t.startswith('<'): 
      return t[1:-1].decode('utf-8')
   else: return t[1:-1].decode('unicode-escape')

def parse(s): 
   # Depends on crschmidt's format being regular
   results = []
   for bindings in s.split('\n\n'): 
      results.append({})
      for line in bindings.splitlines(): 
         if r_line.match(line): 
            var, t = line.split(': ', 1)
            results[-1][var] = term(t)
   return filter(lambda b: len(b), results)

def query(q): 
   u = urllib.urlopen(julie + urllib.quote(q))
   s = u.read()
   u.close()
   return parse(s)

def serve(status, body): 
   sys.stdout.write("Status: %s\r\n" % status)
   sys.stdout.write("Content-Type: text/html; charset=utf-8\r\n\r\n")
   sys.stdout.write(body)
   if not body.endswith('\n'): 
      sys.stdout.write('\n')
   sys.exit()

def barf(msg): 
   serve(200, "Error: " + msg)

def homepage(): 
   serve(200, """
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>FOAFCite: Lookup People's Details Fast!</title>
<link rel="stylesheet" type="text/css" href="/trove/misc.css" />
<style type="text/css">
h1 { font-family: Tahoma, sans-serif; }
form { 
   margin: 1em 1.5em; 
   padding: 0.75em; 
   border: 1px dashed #bba; 
}
input[type="submit"] { background-color: #f8f7f0; }
</style>
</head>
<body>
<div class="body">
<h1>FOAFCite Query</h1>
<form action="./foafcite" method="GET">
<div>
Name: <input type="text" name="name" size="20" /> 
Nick: <input type="text" name="nick" size="20" />
</div>
<div><span style="font-variant:small-caps;">Details:</span> 
{ mbox_sha1sum: <input type="checkbox" name="sha1sum" value="1" 
checked="checked" /> }
{ homepage: <input type="checkbox" name="homepage" 
value="1" checked="checked" /> }
{ foaffile: <input type="checkbox" 
name="foaffile" value="1" checked="checked" /> }
</div>
<div>
RDF/XML: <input type="radio" name="format" value="rdfxml" checked="checked" /> 
Notation3: <input type="radio" name="format" value="n3" />
</div>
<div><br /><input type="submit" /></div>
</form>

<p>Ever wanted to add a person to your FOAF file but didn't want to have to go 
through the rigmorale of looking up their foaf:mbox_sha1sum, foaf:homepage, and 
the location of their possibly numerous FOAF files? Rigmorale no more! This 
service queries <a href="http://crschmidt.net/">Christopher Schmidt</a>'s 
excellent <a href="http://crschmidt.net/semweb/redlandbot/">redlandbot</a> 
service. Want to know how this works? Check out the foafcite <a 
href="/inside/foafcite">source code</a>.</p>

<p>Tip: if the results returned are inaccurate, try using <em>both</em> a name 
and a nickname for greater accuracy. Both name and nickname are case 
sensitive.</p>
</div>

<address>
<a href="http://inamidst.com/sbp/">Sean B. Palmer</a>
</address>
</body>
</html>
""")

def main(): 
   name, nick = form('name'), form('nick')
   if not (name or nick): 
      homepage()
      # barf("You must include either a name or a nickname!")

   ident = ''
   if name: ident += '(?p foaf:name "%s") ' % name
   if nick: ident += '(?p foaf:nick "%s") ' % nick
   namebel = mknamebel(name or nick)

   format = form('format')
   if format not in ('rdfxml', 'n3'): 
      barf("Format must be one of: rdfxml, n3.")

   print 'Content-Type: text/plain; charset=utf-8'
   print 
   if format == 'rdfxml': 
      print '<rdf:RDF xmlns:foaf="http://xmlns.com/foaf/0.1/" '
      print '   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" '
      print '   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">'
      print '<foaf:Person rdf:nodeID="%s">' % namebel
   else: 
      print '@prefix foaf: <http://xmlns.com/foaf/0.1/> .'
      print '@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .'
      print 
      print ('_:%s' % namebel), 

   if name: 
      if format == 'rdfxml': 
         print '   <foaf:name>%s</foaf:name>' % name
      else: print 'foaf:name "%s"; ' % name
   if nick: # @@ elif nick?
      if format == 'rdfxml': 
         print '   <foaf:nick>%s</foaf:nick>' % nick
      else: print '   foaf:nick "%s"; ' % nick

   if form('sha1sum'): 
      q = mkquery % ('?sha', ident, '(?p foaf:mbox_sha1sum ?sha) ', using)
      for result in query(q): 
         sha = result['sha']
         if format == 'rdfxml': 
            print '   <foaf:mbox_sha1sum>%s</foaf:mbox_sha1sum>' % sha
         else: print '   foaf:mbox_sha1sum "%s"; ' % sha

   if form('homepage'): 
      q = mkquery % ('?home', ident, '(?p foaf:homepage ?home) ', using)
      for result in query(q): 
         home = result['home']
         if format == 'rdfxml': 
            print '   <foaf:homepage rdf:resource="%s"/>' % home
         else: print '   foaf:homepage <%s>; ' % home

   if form('foaffile'): 
      foafy = 'and ?foaf =~ /foaf/ '
      q1 = mkquery % ('?foaf', ident, '(?p foaf:made ?foaf) '+foafy, using)
      q2 = mkquery % ('?foaf', ident, '(?foaf foaf:maker ?p) '+foafy, using)
      q3 = mkquery % ('?foaf', ident, '(?p rdfs:seeAlso ?foaf) '+foafy, using)
      q1r = query(q1)
      if q1r: 
         for result in q1r: 
            foaf = result['foaf']
            if format == 'rdfxml': 
               print '   <rdfs:seeAlso rdf:resource="%s"/>' % foaf
            else: print '   rdfs:seeAlso <%s>; ' % foaf
      else: 
         q2r = query(q2)
         if q2r: 
            for result in q2r: 
               foaf = result['foaf']
               if format == 'rdfxml': 
                  print '   <rdfs:seeAlso rdf:resource="%s"/>' % foaf
               else: print '   rdfs:seeAlso <%s>; ' % foaf
         else: 
            q3r = query(q3)
            for result in q3r: 
               foaf = result['foaf']
               if format == 'rdfxml': 
                  print '   <rdfs:seeAlso rdf:resource="%s"/>' % foaf
               else: print '   rdfs:seeAlso <%s>; ' % foaf

   if format == 'rdfxml': 
      print '</foaf:Person>'
      print '</rdf:RDF>'
   else: print '.'

if __name__=="__main__": 
   main()