Index: server/lib/gutenbach/server/printer.py
===================================================================
--- server/lib/gutenbach/server/printer.py	(revision ffbe41dc14056c0f5a55064f93b535e455ba5f70)
+++ server/lib/gutenbach/server/printer.py	(revision b01b6d11a9f096abe2a8f080b7ea0aeb9b50edbb)
@@ -1,4 +1,5 @@
 from . import InvalidJobException, InvalidPrinterStateException
 from . import Job
+from gutenbach.ipp import PrinterStates as States
 import gutenbach.ipp as ipp
 import logging
@@ -43,11 +44,9 @@
     ]
         
-
     def __init__(self, name):
 
 	self.name = name
-        self.uri = "ipp://localhost:8000/printers/" + self.name
         self.time_created = int(time.time())
-        self.state = "idle"
+        self.state = States.IDLE
 
 	self.finished_jobs = []
@@ -56,168 +55,37 @@
 
         # cups ignores jobs with id 0, so we have to start at 1
-	self._next_jobid = 1 
-
-    def __getattr__(self, attr):
-        try:
-            return self.__getattribute__(attr)
-        except AttributeError:
-            pass
-        return self.__getattribute__(attr.replace("-", "_"))
-
-    def __hasattr__(self, attr):
-        try:
-            getattr(self, attr)
-            return True
-        except AttributeError:
-            return False
-
-    ## Printer attributes
-
-    @property
-    def printer_uri_supported(self):
-        return ipp.PrinterUriSupported(self.uri)
-
-    @property
-    def uri_authentication_supported(self):
-        return ipp.UriAuthenticationSupported("none")
-
-    @property
-    def uri_security_supported(self):
-        return ipp.UriSecuritySupported("none")
-
-    @property
-    def printer_name(self):
-        return ipp.PrinterName(self.name)
-
-    @property
-    def printer_state(self):
-        return ipp.PrinterState(ipp.constants.PrinterStates.IDLE)
-
-    @property
-    def printer_state_reasons(self):
-        return ipp.PrinterStateReasons("none")
-
-    @property
-    def ipp_versions_supported(self):
-        return ipp.IppVersionsSupported("1.0", "1.1")
-
-    # XXX: We should query ourself for the supported operations
-    @property
-    def operations_supported(self):
-        return ipp.OperationsSupported(ipp.OperationCodes.GET_JOBS)
-
-    @property
-    def charset_configured(self):
-        return ipp.CharsetConfigured("utf-8")
-
-    @property
-    def charset_supported(self):
-        return ipp.CharsetSupported("utf-8")
-
-    @property
-    def natural_language_configured(self):
-        return ipp.NaturalLanguageConfigured("en-us")
-
-    @property
-    def generated_natural_language_supported(self):
-        return ipp.GeneratedNaturalLanguageSupported("en-us")
-
-    @property
-    def document_format_default(self):
-        return ipp.DocumentFormatDefault("application/octet-stream")
-
-    @property
-    def document_format_supported(self):
-        return ipp.DocumentFormatSupported("application/octet-stream", "audio/mp3")
-
-    @property
-    def printer_is_accepting_jobs(self):
-        return ipp.PrinterIsAcceptingJobs(True)
-
-    @property
-    def queued_job_count(self):
-        return ipp.QueuedJobCount(len(self.active_jobs))
-
-    @property
-    def pdl_override_supported(self):
-        return ipp.PdlOverrideSupported("not-attempted")
-
-    @property
-    def printer_up_time(self):
-        return ipp.PrinterUpTime(int(time.time()) - self.time_created)
-
-    @property
-    def compression_supported(self):
-        return ipp.CompressionSupported("none")
-
-    @property
-    def multiple_operation_time_out(self):
-        return ipp.MultipleOperationTimeOut(240)
-
-    @property
-    def multiple_document_jobs_supported(self):
-        return ipp.MultipleDocumentJobsSupported(False)
-
-    ## Printer operations
-
-    def get_printer_attributes(self, request=None):
-        if request and 'requested-attributes' in request:
-            requested = []
-            for value in request['requested-attributes'].values:
-                if value.value in self.attributes:
-                    requested.append(value.value)
-        else:
-            requested = self.attributes
-            
-        attributes = [getattr(self, attr) for attr in requested]
-        return attributes
-
-    def create_job(self, request):
-        operation = request.attribute_groups[0]
-        kwargs = {}
-        
-        # requesting username
-        if 'requesting-user-name' in operation:
-            username_attr = operation['requesting-user-name']
-            username = username_attr.values[0].value
-            if username_attr != ipp.RequestingUserName(username):
-                raise ipp.errors.ClientErrorBadRequest(str(username_attr))
-            kwargs['creator'] = username
-
-        # job name
-        if 'job-name' in operation:
-            job_name_attr = operation['job-name']
-            job_name = job_name_attr.values[0].value
-            if job_name_attr != ipp.JobName(job_name):
-                raise ipp.errors.ClientErrorBadRequest(str(job_name_attr))
-            kwargs['name'] = job_name
-
-        # job size
-        if 'job-k-octets' in operation:
-            job_k_octets_attr = operation['job-k-octets']
-            job_k_octets = job_k_octets_attr.values[0].value
-            if job_k_octets_attr != ipp.JobKOctets(job_k_octets):
-                raise ipp.errors.ClientErrorBadRequest(str(job_k_octets_attr))
-            kwargs['size'] = job_k_octets
-
-        job_id = self._next_jobid
-        self._next_jobid += 1
-        
-        job = Job(job_id, self, **kwargs)
-        self.jobs[job_id] = job
-        self.active_jobs.append(job_id)
+	self._next_jobid = 1
+
+    def __repr__(self):
+        return str(self)
+
+    def __str__(self):
+        return "<Printer '%s'>" % self.name 
+
+    ######################################################################
+    ###                          Properties                            ###
+    ######################################################################
+
+    @property
+    def uris(self):
+        uris = ["ipp://localhost:8000/printers/" + self.name,
+                "ipp://localhost/printers/" + self.name]
+        return uris
+    
+    @property
+    def uri(self):
+        return self.uris[0]
+
+    @property
+    def next_job(self):
+        if len(self.active_jobs) == 0:
+            job = None
+        else:
+            job = self.active_jobs[0]
         return job
 
-    def send_document(self, jobid, document):
-        job = self.jobs[jobid]
-        if job.status != ipp.JobStates.HELD:
-            raise InvalidPrinterStateException(
-                "Invalid job state: %d" % job.status)
-        job.document = document
-        logger.debug("document for job %d is '%s'" % (jobid, job.document.name))
-        job.status = ipp.JobStates.PENDING
-
-    def print_job(self, job):
-        pass
+    ######################################################################
+    ###                            Methods                             ###
+    ######################################################################
 
     def complete_job(self, jobid):
@@ -225,20 +93,11 @@
 	self.finished_jobs.append(job)
 	job.finish()
-	return job.jid
+	return job.id
 
     def start_job(self, jobid):
 	job = self.jobs[self.active_jobs[0]]
 	if job.status != ipp.JobStates.PENDING:
-	    raise InvalidPrinterStateException(
-                "Invalid job state: %s" % job.status)
+	    raise InvalidPrinterStateException(job.status)
 	job.play()
-
-    @property
-    def next_job(self):
-        if len(self.active_jobs) == 0:
-            job = None
-        else:
-            job = self.active_jobs[0]
-        return job
 
     def stop(self):
@@ -255,12 +114,159 @@
 	return self.jobs[jobid]
 
-    def get_jobs(self):
-        print self.active_jobs
-        jobs = [self.jobs[job_id] for job_id in self.active_jobs]
-        return jobs
-
-    # def __repr__(self):
-    #     return str(self)
-
-    # def __str__(self):
-    #     return "<Printer '%s'>" % self.name
+    ######################################################################
+    ###                        IPP Attributes                          ###
+    ######################################################################
+
+    @property
+    def printer_uri_supported(self):
+        return ipp.PrinterUriSupported(self.uri)
+
+    @property
+    def uri_authentication_supported(self):
+        return ipp.UriAuthenticationSupported("none")
+
+    @property
+    def uri_security_supported(self):
+        return ipp.UriSecuritySupported("none")
+
+    @property
+    def printer_name(self):
+        return ipp.PrinterName(self.name)
+
+    @property
+    def printer_state(self):
+        return ipp.PrinterState(self.state)
+
+    @property
+    def printer_state_reasons(self):
+        return ipp.PrinterStateReasons("none")
+
+    @property
+    def ipp_versions_supported(self):
+        return ipp.IppVersionsSupported("1.0", "1.1")
+
+    # XXX: We should query ourself for the supported operations
+    @property
+    def operations_supported(self):
+        return ipp.OperationsSupported(ipp.OperationCodes.GET_JOBS)
+
+    @property
+    def charset_configured(self):
+        return ipp.CharsetConfigured("utf-8")
+
+    @property
+    def charset_supported(self):
+        return ipp.CharsetSupported("utf-8")
+
+    @property
+    def natural_language_configured(self):
+        return ipp.NaturalLanguageConfigured("en-us")
+
+    @property
+    def generated_natural_language_supported(self):
+        return ipp.GeneratedNaturalLanguageSupported("en-us")
+
+    @property
+    def document_format_default(self):
+        return ipp.DocumentFormatDefault("application/octet-stream")
+
+    @property
+    def document_format_supported(self):
+        return ipp.DocumentFormatSupported("application/octet-stream", "audio/mp3")
+
+    @property
+    def printer_is_accepting_jobs(self):
+        return ipp.PrinterIsAcceptingJobs(True)
+
+    @property
+    def queued_job_count(self):
+        return ipp.QueuedJobCount(len(self.active_jobs))
+
+    @property
+    def pdl_override_supported(self):
+        return ipp.PdlOverrideSupported("not-attempted")
+
+    @property
+    def printer_up_time(self):
+        return ipp.PrinterUpTime(int(time.time()) - self.time_created)
+
+    @property
+    def compression_supported(self):
+        return ipp.CompressionSupported("none")
+
+    @property
+    def multiple_operation_time_out(self):
+        return ipp.MultipleOperationTimeOut(240)
+
+    @property
+    def multiple_document_jobs_supported(self):
+        return ipp.MultipleDocumentJobsSupported(False)
+
+
+    ######################################################################
+    ###                        IPP Operations                          ###
+    ######################################################################
+
+    def print_job(self):
+        pass
+
+    def validate_job(self):
+        pass
+
+    def get_jobs(self, requesting_user_name="", which_jobs=None):
+        # Filter by the which-jobs attribute
+        if which_jobs is None:
+            jobs = self.jobs.values()
+        elif which_jobs == "completed":
+            jobs = [self.jobs[job_id] for job_id in self.finished_jobs]
+        elif which_jobs == "not-completed":
+            jobs = [self.jobs[job_id] for job_id in self.active_jobs]
+        else:
+            raise ipp.errors.ClientErrorAttributes(
+                which_jobs, ipp.WhichJobs(which_jobs))
+
+        # Filter by username
+        if requesting_user_name is None:
+            user_jobs = jobs
+        else:
+            user_jobs = [job for job in jobs if job.creator == requesting_user_name]
+        
+        return user_jobs
+
+    def print_uri(self):
+        pass
+
+    def create_job(self, requesting_user_name="", job_name="", job_k_octets=0):
+        job_id = self._next_jobid
+        self._next_jobid += 1
+        
+        job = Job(job_id,
+                  self,
+                  creator=requesting_user_name,
+                  name=job_name,
+                  size=job_k_octets)
+        
+        self.jobs[job_id] = job
+        self.active_jobs.append(job_id)
+        self.state = States.PROCESSING
+        
+        return job
+
+    def pause_printer(self):
+        pass
+
+    def resume_printer(self):
+        pass
+
+    def get_printer_attributes(self, requested_attributes=None):
+        if requested_attributes is None:
+            requested = self.attributes
+        else:
+            requested = [a for a in self.attributes if a in requested_attributes]
+
+        _attributes = [attr.replace("-", "_") for attr in requested]
+        attributes = [getattr(self, attr) for attr in _attributes]
+        return attributes
+
+    def set_printer_attributes(self):
+        pass
