Index: server/lib/ipp.py
===================================================================
--- server/lib/ipp.py	(revision efee0f1da26ab15a0562343b6c363c2957e33365)
+++ server/lib/ipp.py	(revision c216863817b8a1dd784a44550d02263ad914a5e6)
@@ -1,12 +1,9 @@
 #!/usr/bin/env python
 
-# Adapted from the Quickprint IPP server code (http://quickprint.mit.edu)
+# Adapted from the Quickprint IPP server code (http://quikprint.mit.edu)
 # Modifications and additions written by Jessica Hamrick (jhamrick@mit.edu)
 
 # Notes and Todo:
 #   - make sure package creates gutenbach folder in /var/log
-#   - ok, so ipplib actually seems to be an unsupported library.
-#     Maybe want to write this in perl instead since there is
-#     Net::IPP::IPPRequest
 
 import os, sys
@@ -35,52 +32,20 @@
     error("Could not create temporary directory '%s'" % TEMPDIR)
 
-
-authfail = False
-try:
-    printer_uri = 'http://%s%s' % (os.environ['SERVER_NAME'], os.environ['REQUEST_URI'])
-except:
-    pass
-
-try:
-    argv = cgi.parse(os.environ['QUERY_STRING'])
-    webauth = argv['BASIC']
-    if type(webauth) is list:
-        webauth = webauth[0]
-    webauth = webauth.split(' ')[1]
-    if not len(webauth):
-        authfail = True
-    else:
-        (authu, authp) = webauth.decode('base64').split(':')
-        db=MySQLdb.connect(read_default_file="/mit/gutenbach/.my.cnf")
-        c = db.cursor()
-        c.execute("SELECT 1 FROM auth WHERE auser=%s AND apass=%s LIMIT 1", (authu,authp,))
-        if c.fetchone() is None:
-            authfail = True
-except Exception, e:
-    authfail = True
-
-if authfail:
-    print "Status: 401 Authorization Required"
-    print "WWW-Authenticate: Basic realm=\"Gutenbach\""
-    print "Content-type: application/ipp\n"
-    sys.exit(0)
-else:
-    AUTH = authu.lower()
-
+# print the content type for our request
 print "Content-type: application/ipp\n"
 
 class IPPServer(object):
+    
+    # nothing to do in the init
     def __init__(self):
         pass
+
+    # this function processes an IPP request and sends a response
     def process(self, request_in, response_out):
-        data_in = request_in.read()
-        if not len(data_in):
-            return
-        request = IPPRequest(data=data_in)
-        request.parse()
+
 
         response = IPPRequest(version=request.version,
-                            operation_id=request.operation_id,
-                            request_id=request.request_id)
+                              operation_id=request.operation_id,
+                              request_id=request.request_id)
         #file('/mit/gutenbach/tmp/requests/'+str(request.operation_id)).write()
         handler = getattr(self, "_operation_%d" % request.operation_id, None)
Index: server/lib/ipprequest.py
===================================================================
--- server/lib/ipprequest.py	(revision c216863817b8a1dd784a44550d02263ad914a5e6)
+++ server/lib/ipprequest.py	(revision c216863817b8a1dd784a44550d02263ad914a5e6)
@@ -0,0 +1,113 @@
+#!/usr/bin/python
+
+class IPPValue():
+    def __init__(self, value_tag, name, value):
+        assert value_tag is not None and \
+               value is not None
+
+        self.value_tag = value_tag
+        self.name = name
+        self.value = value
+
+class IPPAttribute():
+    # From RFC 2565:
+
+    # Each attribute consists of:
+    # -----------------------------------------------
+    # |                   value-tag                 |   1 byte
+    # -----------------------------------------------
+    # |               name-length  (value is u)     |   2 bytes
+    # -----------------------------------------------
+    # |                     name                    |   u bytes
+    # -----------------------------------------------
+    # |              value-length  (value is v)     |   2 bytes
+    # -----------------------------------------------
+    # |                     value                   |   v bytes
+    # -----------------------------------------------
+
+    # An additional value consists of:
+    # -----------------------------------------------------------
+    # |                   value-tag                 |   1 byte  |
+    # -----------------------------------------------           |
+    # |            name-length  (value is 0x0000)   |   2 bytes |
+    # -----------------------------------------------           |-0 or more
+    # |              value-length (value is w)      |   2 bytes |
+    # -----------------------------------------------           |
+    # |                     value                   |   w bytes |
+    # -----------------------------------------------------------
+
+    def __init__(self, attribute_tag, values):
+        assert attribute_tag is not None
+        for value in values: assert isinstance(value, IPPValue)
+        
+        self.attribute_tag = attribute_tag
+        self.values = values
+
+class IPPRequest():
+    # From RFC 2565:
+    
+    # The encoding for an operation request or response consists of:
+    # -----------------------------------------------
+    # |                  version-number             |   2 bytes  - required
+    # -----------------------------------------------
+    # |               operation-id (request)        |
+    # |                      or                     |   2 bytes  - required
+    # |               status-code (response)        |
+    # -----------------------------------------------
+    # |                   request-id                |   4 bytes  - required
+    # -----------------------------------------------------------
+    # |               xxx-attributes-tag            |   1 byte  |
+    # -----------------------------------------------           |-0 or more
+    # |             xxx-attribute-sequence          |   n bytes |
+    # -----------------------------------------------------------
+    # |              end-of-attributes-tag          |   1 byte   - required
+    # -----------------------------------------------
+    # |                     data                    |   q bytes  - optional
+    # -----------------------------------------------
+
+    # either give the version, operation_id, request_id,
+    # attribute_sequence, and data, or a file handler (request) which
+    # can be read from to get the request
+    def __init__(self, version=None, operation_id=None, request_id=None, attributes=[], data=None, request=None):
+        assert (version is not None and \
+                operation_id is not None and \
+                request_id is not None) or request is not None
+
+        if request is not None:
+            self.version        = request.read(2)
+            self.operation_id   = request.read(2)
+            self.request_id     = request.read(4)
+            self.attributes     = []
+            
+            next_byte = request.read(1)
+            while next_byte != 0x03:
+                if next_byte <= 0x0F:
+                    attribute_tag = next_byte
+                    value_tag     = request.read(1)
+                    name_length   = request.read(2)
+                    name          = request.read(name_length)
+                    value_length  = request.read(2)
+                    value         = request.read(value_length)
+                    
+                    self.attributes.append(IPPAttribute(
+                        attribute_tag,
+                        [IPPValue(value_tag, name, value)]))
+                else:
+                    value_tag     = next_byte
+                    name_length   = request.read(2)
+                    name          = None
+                    value_length  = request.read(2)
+                    value         = request.read(value_length)
+                    
+                    self.attributes[-1].values.append(IPPValue(value_tag, name, value))
+                    
+                next_byte = request.read(1)
+
+            self.data = request.read()
+
+        else:
+            self.version = version
+            self.operation_id = operation_id
+            self.request_id = request_id
+            self.attributes = attributes
+            self.data = data
