Changeset b01b6d1


Ignore:
Timestamp:
Jan 11, 2012, 12:51:51 AM (12 years ago)
Author:
Jessica B. Hamrick <jhamrick@…>
Branches:
no-cups
Children:
be6ff03
Parents:
ffbe41d
git-author:
Jessica B. Hamrick <jhamrick@…> (01/11/12 00:51:51)
git-committer:
Jessica B. Hamrick <jhamrick@…> (01/11/12 00:51:51)
Message:

Clean up printer, job, and requests code

Location:
server/lib/gutenbach
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • server/lib/gutenbach/ipp/attributes/operation.py

    re58af05 rb01b6d1  
    33    'RequestingUserName',
    44    'IppAttributeFidelity',
    5     'LastDocument'
     5    'LastDocument',
     6    'Limit',
     7    'RequestedAttributes',
     8    'WhichJobs',
     9    'MyJobs',
     10    'DocumentName',
     11    'Compression',
     12    'DocumentFormat',
     13    'DocumentNaturalLanguage',
    614]
    715
     
    2836        'last-document',
    2937        [Value(IntegerTags.BOOLEAN, val)])
     38
     39def Limit(val):
     40    return Attribute(
     41        'limit',
     42        [Value(IntegerTags.INTEGER, val)])
     43
     44def RequestedAttributes(*vals):
     45    return Attribute(
     46        'requested-attributes',
     47        [Value(CharacterStringTags.KEYWORD, val) for val in vals])
     48
     49def WhichJobs(val):
     50    return Attribute(
     51        'which-jobs',
     52        [Value(CharacterStringTags.KEYWORD, val)])
     53
     54def MyJobs(val):
     55    return Attribute(
     56        'my-jobs',
     57        [Value(IntegerTags.BOOLEAN, val)])
     58
     59def DocumentName(val):
     60    return Attribute(
     61        'document-name',
     62        [Value(CharacterStringTags.NAME_WITHOUT_LANGUAGE, val)])
     63
     64def Compression(val):
     65    return Attribute(
     66        'compression',
     67        [Value(CharacterStringTags.KEYWORD, val)])
     68
     69def DocumentFormat(val):
     70    return Attribute(
     71        'document-format',
     72        [Value(CharacterStringTags.MIME_MEDIA_TYPE, val)])
     73
     74def DocumentNaturalLanguage(val):
     75    return Attribute(
     76        'document-natural-language',
     77        [Value(CharacterStringTags.NATURAL_LANGUAGE, val)])
  • server/lib/gutenbach/ipp/core/errors.py

    r1037115 rb01b6d1  
    4343   
    4444
    45 from .constants import ErrorCodes
     45from .constants import ErrorCodes, AttributeTags
     46from .attributegroup import AttributeGroup
    4647
    4748class IPPException(Exception):
     
    106107    def __init__(self, message, attrs):
    107108        self.message = message
    108         self.bad_attrs = attrs
     109        if hasattr(attrs, '__iter__'):
     110            self.bad_attrs = attrs
     111        else:
     112            self.bad_attrs = [attrs]
    109113
    110114    def update_response(self, response):
    111         pass
     115        super(ClientErrorAttributes, self).update_response(response)
     116        response.attribute_groups.append(
     117            AttributeGroup(
     118                AttributeTags.UNSUPPORTED,
     119                self.bad_attrs))
    112120
    113121class ClientErrorUriSchemeNotSupported(IPPClientException):
  • server/lib/gutenbach/server/errors.py

    re58af05 rb01b6d1  
    11__all__ = [
    22    'InvalidJobException',
    3     'InvalidPrinterStateException'
     3    'InvalidPrinterStateException',
     4    'InvalidJobStateException',
    45    ]
    56
     
    78    def __init__(self, jobid):
    89        self.jobid = jobid
    9 
    1010    def __str__(self):
    11         return "Job with id '%d' does not exist!" % self.jobid
     11        return "Job does not exist: %d" % self.jobid
    1212
    1313class InvalidPrinterStateException(Exception):
    14     def __init__(self, message):
    15         self.message = message
     14    def __init__(self, state):
     15        self.state = hex(state)
     16    def __str__(self):
     17        return "Invalid printer state: %s" % self.state
    1618
     19class InvalidJobStateException(Exception):
     20    def __init__(self, state):
     21        self.state = hex(state)
    1722    def __str__(self):
    18         return self.message
     23        return "Invalid job state: %s" % self.state
  • server/lib/gutenbach/server/job.py

    rce2abc5 rb01b6d1  
    11from . import InvalidJobException, InvalidPrinterStateException
     2from gutenbach.ipp import JobStates as States
    23import os
    34import gutenbach.ipp as ipp
     
    2122    ]
    2223
    23     def __init__(self, jid, printer, creator="", name="", size=0):
    24         """Initialize a Gutenbach job.
    25 
    26         This sets the status to 'initializing' and optionally sets the
    27         document to print to the value of document.
     24    def __init__(self, job_id=-1, printer=None, creator=None, name=None, size=None):
     25        """Create an empty Gutenbach job.
    2826
    2927        """
    3028
    31         self.jid      = jid
    32         self.printer  = printer
    33 
    34         self.creator  = creator
    35         self.name     = name
    36         self.size     = size
     29        self.printer = printer
     30        self.player = None
     31
     32        self.id = job_id
     33        self.creator = creator
     34        self.name = name
     35        self.size = size
     36        self.status = States.HELD
    3737
    3838        self.document = None
    3939        self.document_name = None
    40         self.player = None
    41 
    42         self.status   = ipp.JobStates.HELD
    43 
    44     def __getattr__(self, attr):
     40        self.document_format = None
     41        self.document_natural_language = None
     42        self.compression = None
     43   
     44    def __repr__(self):
     45        return str(self)
     46
     47    def __str__(self):
     48        return "<Job %d '%s'>" % (self.id, self.name)
     49
     50    ######################################################################
     51    ###                          Properties                            ###
     52    ######################################################################
     53
     54    @property
     55    def id(self):
     56        """Unique job identifier.  Should be a positive integer,
     57        except when unassigned, when it defaults to -1.
     58       
     59        """
     60        return self._id
     61    @id.setter
     62    def id(self, val):
    4563        try:
    46             return self.__getattribute__(attr)
    47         except AttributeError:
    48             pass
    49         return self.__getattribute__(attr.replace("-", "_"))
    50 
    51     def __hasattr__(self, attr):
     64            self._id = int(val)
     65        except TypeError:
     66            self._id = -1
     67
     68    @property
     69    def creator(self):
     70        """The user who created the job; analogous to the IPP
     71        requesting-user-name.
     72
     73        """
     74        return self._creator
     75    @creator.setter
     76    def creator(self, val):
     77        if val is None:
     78            self._creator = ""
     79        else:
     80            self._creator = str(val)
     81
     82    @property
     83    def name(self):
     84        """The job's name.
     85
     86        """
     87        return self._name
     88    @name.setter
     89    def name(self, val):
     90        if val is None:
     91            self._name = ""
     92        else:
     93            self._name = str(val)
     94
     95    @property
     96    def size(self):
     97        """The size of the job in bytes.
     98
     99        """
     100        if self.document:
     101            size = os.path.getsize(self.document.name)
     102        else:
     103            size = self._size
     104        return size
     105    @size.setter
     106    def size(self, val):
    52107        try:
    53             getattr(self, attr)
    54             return True
    55         except AttributeError:
    56             return False
    57 
    58     #### Job attributes
    59 
    60     @property
    61     def job_id(self):
    62         return ipp.JobId(self.jid)
    63 
    64     @property
    65     def job_name(self):
    66         return ipp.JobName(self.name)
    67 
    68     # XXX: we need to actually calculate this!
    69     @property
    70     def job_originating_user_name(self):
    71         return ipp.JobOriginatingUserName(self.creator)
    72 
    73     # XXX: we need to actually calculate this!
    74     @property
    75     def job_k_octets(self):
    76         return ipp.JobKOctets(self.size)
    77 
    78     @property
    79     def job_state(self):
    80         return ipp.JobState(self.status)
    81 
    82     @property
    83     def job_printer_uri(self):
    84         return ipp.JobPrinterUri(self.printer.uri)
    85 
    86     def get_job_attributes(self, request=None):
    87         if request and 'requested-attributes' in request:
    88             requested = []
    89             for value in request['requested-attributes'].values:
    90                 if value.value in self.attributes:
    91                     requested.append(value.value)
    92         else:
    93             requested = self.attributes
    94            
    95         attributes = [getattr(self, attr) for attr in requested]
    96         return attributes
    97    
    98     #######
     108            self._size = int(val)
     109        except TypeError:
     110            self._size = 0
     111
     112    ######################################################################
     113    ###                            Methods                             ###
     114    ######################################################################
    99115
    100116    def play(self):
    101117        logger.info("playing job %s" % str(self))
    102118        # TODO: add external call to music player
    103         self.status = ipp.JobStates.PROCESSING
     119        self.status = States.PROCESSING
    104120        self.player = subprocess.Popen(
    105121            "/usr/bin/mplayer -quiet %s" % self.document.name,
     
    114130        #logger.debug(self.player.stdout)
    115131        self.player = None
    116         self.printer.complete_job(self.jid)
     132        self.printer.complete_job(self.id)
    117133
    118134    def finish(self):
    119135        logger.info("finished job %s" % str(self))
    120         self.status = ipp.JobStates.COMPLETE
    121 
    122     def __repr__(self):
    123         return str(self)
    124 
    125     def __str__(self):
    126         return "<Job %d '%s'>" % (self.jid if self.jid is not None else -1, self.name)
     136        self.status = States.COMPLETE
     137
     138    ######################################################################
     139    ###                        IPP Attributes                          ###
     140    ######################################################################
     141
     142    @property
     143    def job_id(self):
     144        return ipp.JobId(self.id)
     145
     146    @property
     147    def job_name(self):
     148        return ipp.JobName(self.name)
     149
     150    # XXX: we need to actually calculate this!
     151    @property
     152    def job_originating_user_name(self):
     153        return ipp.JobOriginatingUserName(self.creator)
     154
     155    # XXX: we need to actually calculate this!
     156    @property
     157    def job_k_octets(self):
     158        return ipp.JobKOctets(self.size)
     159
     160    @property
     161    def job_state(self):
     162        return ipp.JobState(self.status)
     163
     164    @property
     165    def job_printer_uri(self):
     166        return ipp.JobPrinterUri(self.printer.uri)
     167
     168
     169    ######################################################################
     170    ###                        IPP Operations                          ###
     171    ######################################################################
     172
     173    def cancel_job(self):
     174        pass
     175
     176    def send_document(self,
     177                      document,
     178                      document_name=None,
     179                      document_format=None,
     180                      document_natural_language=None,
     181                      requesting_user_name=None,
     182                      compression=None,
     183                      last_document=None):
     184
     185        if self.status != States.HELD:
     186            raise InvalidJobStateException(self.status)
     187       
     188        self.document = document
     189        self.document_name = str(document_name)
     190        self.document_format = str(document_format)
     191        self.document_natural_language = str(document_natural_language)
     192        self.creator = str(requesting_user_name)
     193        self.compression = str(compression)
     194        self.status = States.PENDING
     195
     196        logger.debug("document for job %d is '%s'" % (self.id, self.document_name))
     197
     198    def send_uri(self):
     199        pass
     200
     201    def get_job_attributes(self, requested_attributes=None):
     202        if requested_attributes is None:
     203            requested = self.attributes
     204        else:
     205            requested = [a for a in self.attributes if a in requested_attributes]
     206
     207        _attributes = [attr.replace("-", "_") for attr in requested]
     208        attributes = [getattr(self, attr) for attr in _attributes]
     209        return attributes
     210
     211    def set_job_attributes(self):
     212        pass
     213
     214    def restart_job(self):
     215        pass
     216
     217    def promote_job(self):
     218        pass
  • server/lib/gutenbach/server/printer.py

    rffbe41d rb01b6d1  
    11from . import InvalidJobException, InvalidPrinterStateException
    22from . import Job
     3from gutenbach.ipp import PrinterStates as States
    34import gutenbach.ipp as ipp
    45import logging
     
    4344    ]
    4445       
    45 
    4646    def __init__(self, name):
    4747
    4848        self.name = name
    49         self.uri = "ipp://localhost:8000/printers/" + self.name
    5049        self.time_created = int(time.time())
    51         self.state = "idle"
     50        self.state = States.IDLE
    5251
    5352        self.finished_jobs = []
     
    5655
    5756        # cups ignores jobs with id 0, so we have to start at 1
    58         self._next_jobid = 1
    59 
    60     def __getattr__(self, attr):
    61         try:
    62             return self.__getattribute__(attr)
    63         except AttributeError:
    64             pass
    65         return self.__getattribute__(attr.replace("-", "_"))
    66 
    67     def __hasattr__(self, attr):
    68         try:
    69             getattr(self, attr)
    70             return True
    71         except AttributeError:
    72             return False
    73 
    74     ## Printer attributes
    75 
    76     @property
    77     def printer_uri_supported(self):
    78         return ipp.PrinterUriSupported(self.uri)
    79 
    80     @property
    81     def uri_authentication_supported(self):
    82         return ipp.UriAuthenticationSupported("none")
    83 
    84     @property
    85     def uri_security_supported(self):
    86         return ipp.UriSecuritySupported("none")
    87 
    88     @property
    89     def printer_name(self):
    90         return ipp.PrinterName(self.name)
    91 
    92     @property
    93     def printer_state(self):
    94         return ipp.PrinterState(ipp.constants.PrinterStates.IDLE)
    95 
    96     @property
    97     def printer_state_reasons(self):
    98         return ipp.PrinterStateReasons("none")
    99 
    100     @property
    101     def ipp_versions_supported(self):
    102         return ipp.IppVersionsSupported("1.0", "1.1")
    103 
    104     # XXX: We should query ourself for the supported operations
    105     @property
    106     def operations_supported(self):
    107         return ipp.OperationsSupported(ipp.OperationCodes.GET_JOBS)
    108 
    109     @property
    110     def charset_configured(self):
    111         return ipp.CharsetConfigured("utf-8")
    112 
    113     @property
    114     def charset_supported(self):
    115         return ipp.CharsetSupported("utf-8")
    116 
    117     @property
    118     def natural_language_configured(self):
    119         return ipp.NaturalLanguageConfigured("en-us")
    120 
    121     @property
    122     def generated_natural_language_supported(self):
    123         return ipp.GeneratedNaturalLanguageSupported("en-us")
    124 
    125     @property
    126     def document_format_default(self):
    127         return ipp.DocumentFormatDefault("application/octet-stream")
    128 
    129     @property
    130     def document_format_supported(self):
    131         return ipp.DocumentFormatSupported("application/octet-stream", "audio/mp3")
    132 
    133     @property
    134     def printer_is_accepting_jobs(self):
    135         return ipp.PrinterIsAcceptingJobs(True)
    136 
    137     @property
    138     def queued_job_count(self):
    139         return ipp.QueuedJobCount(len(self.active_jobs))
    140 
    141     @property
    142     def pdl_override_supported(self):
    143         return ipp.PdlOverrideSupported("not-attempted")
    144 
    145     @property
    146     def printer_up_time(self):
    147         return ipp.PrinterUpTime(int(time.time()) - self.time_created)
    148 
    149     @property
    150     def compression_supported(self):
    151         return ipp.CompressionSupported("none")
    152 
    153     @property
    154     def multiple_operation_time_out(self):
    155         return ipp.MultipleOperationTimeOut(240)
    156 
    157     @property
    158     def multiple_document_jobs_supported(self):
    159         return ipp.MultipleDocumentJobsSupported(False)
    160 
    161     ## Printer operations
    162 
    163     def get_printer_attributes(self, request=None):
    164         if request and 'requested-attributes' in request:
    165             requested = []
    166             for value in request['requested-attributes'].values:
    167                 if value.value in self.attributes:
    168                     requested.append(value.value)
    169         else:
    170             requested = self.attributes
    171            
    172         attributes = [getattr(self, attr) for attr in requested]
    173         return attributes
    174 
    175     def create_job(self, request):
    176         operation = request.attribute_groups[0]
    177         kwargs = {}
    178        
    179         # requesting username
    180         if 'requesting-user-name' in operation:
    181             username_attr = operation['requesting-user-name']
    182             username = username_attr.values[0].value
    183             if username_attr != ipp.RequestingUserName(username):
    184                 raise ipp.errors.ClientErrorBadRequest(str(username_attr))
    185             kwargs['creator'] = username
    186 
    187         # job name
    188         if 'job-name' in operation:
    189             job_name_attr = operation['job-name']
    190             job_name = job_name_attr.values[0].value
    191             if job_name_attr != ipp.JobName(job_name):
    192                 raise ipp.errors.ClientErrorBadRequest(str(job_name_attr))
    193             kwargs['name'] = job_name
    194 
    195         # job size
    196         if 'job-k-octets' in operation:
    197             job_k_octets_attr = operation['job-k-octets']
    198             job_k_octets = job_k_octets_attr.values[0].value
    199             if job_k_octets_attr != ipp.JobKOctets(job_k_octets):
    200                 raise ipp.errors.ClientErrorBadRequest(str(job_k_octets_attr))
    201             kwargs['size'] = job_k_octets
    202 
    203         job_id = self._next_jobid
    204         self._next_jobid += 1
    205        
    206         job = Job(job_id, self, **kwargs)
    207         self.jobs[job_id] = job
    208         self.active_jobs.append(job_id)
     57        self._next_jobid = 1
     58
     59    def __repr__(self):
     60        return str(self)
     61
     62    def __str__(self):
     63        return "<Printer '%s'>" % self.name
     64
     65    ######################################################################
     66    ###                          Properties                            ###
     67    ######################################################################
     68
     69    @property
     70    def uris(self):
     71        uris = ["ipp://localhost:8000/printers/" + self.name,
     72                "ipp://localhost/printers/" + self.name]
     73        return uris
     74   
     75    @property
     76    def uri(self):
     77        return self.uris[0]
     78
     79    @property
     80    def next_job(self):
     81        if len(self.active_jobs) == 0:
     82            job = None
     83        else:
     84            job = self.active_jobs[0]
    20985        return job
    21086
    211     def send_document(self, jobid, document):
    212         job = self.jobs[jobid]
    213         if job.status != ipp.JobStates.HELD:
    214             raise InvalidPrinterStateException(
    215                 "Invalid job state: %d" % job.status)
    216         job.document = document
    217         logger.debug("document for job %d is '%s'" % (jobid, job.document.name))
    218         job.status = ipp.JobStates.PENDING
    219 
    220     def print_job(self, job):
    221         pass
     87    ######################################################################
     88    ###                            Methods                             ###
     89    ######################################################################
    22290
    22391    def complete_job(self, jobid):
     
    22593        self.finished_jobs.append(job)
    22694        job.finish()
    227         return job.jid
     95        return job.id
    22896
    22997    def start_job(self, jobid):
    23098        job = self.jobs[self.active_jobs[0]]
    23199        if job.status != ipp.JobStates.PENDING:
    232             raise InvalidPrinterStateException(
    233                 "Invalid job state: %s" % job.status)
     100            raise InvalidPrinterStateException(job.status)
    234101        job.play()
    235 
    236     @property
    237     def next_job(self):
    238         if len(self.active_jobs) == 0:
    239             job = None
    240         else:
    241             job = self.active_jobs[0]
    242         return job
    243102
    244103    def stop(self):
     
    255114        return self.jobs[jobid]
    256115
    257     def get_jobs(self):
    258         print self.active_jobs
    259         jobs = [self.jobs[job_id] for job_id in self.active_jobs]
    260         return jobs
    261 
    262     # def __repr__(self):
    263     #     return str(self)
    264 
    265     # def __str__(self):
    266     #     return "<Printer '%s'>" % self.name
     116    ######################################################################
     117    ###                        IPP Attributes                          ###
     118    ######################################################################
     119
     120    @property
     121    def printer_uri_supported(self):
     122        return ipp.PrinterUriSupported(self.uri)
     123
     124    @property
     125    def uri_authentication_supported(self):
     126        return ipp.UriAuthenticationSupported("none")
     127
     128    @property
     129    def uri_security_supported(self):
     130        return ipp.UriSecuritySupported("none")
     131
     132    @property
     133    def printer_name(self):
     134        return ipp.PrinterName(self.name)
     135
     136    @property
     137    def printer_state(self):
     138        return ipp.PrinterState(self.state)
     139
     140    @property
     141    def printer_state_reasons(self):
     142        return ipp.PrinterStateReasons("none")
     143
     144    @property
     145    def ipp_versions_supported(self):
     146        return ipp.IppVersionsSupported("1.0", "1.1")
     147
     148    # XXX: We should query ourself for the supported operations
     149    @property
     150    def operations_supported(self):
     151        return ipp.OperationsSupported(ipp.OperationCodes.GET_JOBS)
     152
     153    @property
     154    def charset_configured(self):
     155        return ipp.CharsetConfigured("utf-8")
     156
     157    @property
     158    def charset_supported(self):
     159        return ipp.CharsetSupported("utf-8")
     160
     161    @property
     162    def natural_language_configured(self):
     163        return ipp.NaturalLanguageConfigured("en-us")
     164
     165    @property
     166    def generated_natural_language_supported(self):
     167        return ipp.GeneratedNaturalLanguageSupported("en-us")
     168
     169    @property
     170    def document_format_default(self):
     171        return ipp.DocumentFormatDefault("application/octet-stream")
     172
     173    @property
     174    def document_format_supported(self):
     175        return ipp.DocumentFormatSupported("application/octet-stream", "audio/mp3")
     176
     177    @property
     178    def printer_is_accepting_jobs(self):
     179        return ipp.PrinterIsAcceptingJobs(True)
     180
     181    @property
     182    def queued_job_count(self):
     183        return ipp.QueuedJobCount(len(self.active_jobs))
     184
     185    @property
     186    def pdl_override_supported(self):
     187        return ipp.PdlOverrideSupported("not-attempted")
     188
     189    @property
     190    def printer_up_time(self):
     191        return ipp.PrinterUpTime(int(time.time()) - self.time_created)
     192
     193    @property
     194    def compression_supported(self):
     195        return ipp.CompressionSupported("none")
     196
     197    @property
     198    def multiple_operation_time_out(self):
     199        return ipp.MultipleOperationTimeOut(240)
     200
     201    @property
     202    def multiple_document_jobs_supported(self):
     203        return ipp.MultipleDocumentJobsSupported(False)
     204
     205
     206    ######################################################################
     207    ###                        IPP Operations                          ###
     208    ######################################################################
     209
     210    def print_job(self):
     211        pass
     212
     213    def validate_job(self):
     214        pass
     215
     216    def get_jobs(self, requesting_user_name="", which_jobs=None):
     217        # Filter by the which-jobs attribute
     218        if which_jobs is None:
     219            jobs = self.jobs.values()
     220        elif which_jobs == "completed":
     221            jobs = [self.jobs[job_id] for job_id in self.finished_jobs]
     222        elif which_jobs == "not-completed":
     223            jobs = [self.jobs[job_id] for job_id in self.active_jobs]
     224        else:
     225            raise ipp.errors.ClientErrorAttributes(
     226                which_jobs, ipp.WhichJobs(which_jobs))
     227
     228        # Filter by username
     229        if requesting_user_name is None:
     230            user_jobs = jobs
     231        else:
     232            user_jobs = [job for job in jobs if job.creator == requesting_user_name]
     233       
     234        return user_jobs
     235
     236    def print_uri(self):
     237        pass
     238
     239    def create_job(self, requesting_user_name="", job_name="", job_k_octets=0):
     240        job_id = self._next_jobid
     241        self._next_jobid += 1
     242       
     243        job = Job(job_id,
     244                  self,
     245                  creator=requesting_user_name,
     246                  name=job_name,
     247                  size=job_k_octets)
     248       
     249        self.jobs[job_id] = job
     250        self.active_jobs.append(job_id)
     251        self.state = States.PROCESSING
     252       
     253        return job
     254
     255    def pause_printer(self):
     256        pass
     257
     258    def resume_printer(self):
     259        pass
     260
     261    def get_printer_attributes(self, requested_attributes=None):
     262        if requested_attributes is None:
     263            requested = self.attributes
     264        else:
     265            requested = [a for a in self.attributes if a in requested_attributes]
     266
     267        _attributes = [attr.replace("-", "_") for attr in requested]
     268        attributes = [getattr(self, attr) for attr in _attributes]
     269        return attributes
     270
     271    def set_printer_attributes(self):
     272        pass
  • server/lib/gutenbach/server/requests.py

    rffbe41d rb01b6d1  
    3737    return response
    3838
     39def verify_attribute(attr, cls, length=1):
     40    vals = [val.value for val in attr.values]
     41    if attr != cls(*vals):
     42        raise ipp.errors.ClientErrorBadRequest(str(attr))
     43    if length is not None and len(vals) != length:
     44        raise ipp.errors.ClientErrorBadRequest(str(attr))
     45    return vals
     46
    3947class GutenbachRequestHandler(object):
    4048
     
    5664        # check charset
    5765        charset_attr = operation.attributes[0]
    58         expected = ipp.AttributesCharset(charset_attr.values[0].value)
    59         if charset_attr != expected:
    60             raise ipp.errors.ClientErrorBadRequest(str(charset_attr))
    61         if charset_attr.values[0].value != 'utf-8':
     66        charset = verify_attribute(charset_attr, ipp.AttributesCharset)[0]
     67        if charset != 'utf-8':
    6268            raise ipp.errors.ClientErrorAttributes(str(charset_attr))
    6369
    6470        # check for attributes-natural-language
    6571        natlang_attr = operation.attributes[1]
    66         expected = ipp.AttributesNaturalLanguage(natlang_attr.values[0].value)
    67         if natlang_attr != expected:
    68             raise ipp.errors.ClientErrorBadRequest(str(natlang_attr))
    69         if natlang_attr.values[0].value != 'en-us':
     72        natlang = verify_attribute(natlang_attr, ipp.AttributesNaturalLanguage)[0]
     73        if natlang != 'en-us':
    7074            raise ipp.errors.ClientErrorAttributes(str(natlang_attr))
    7175   
     
    213217        operation = request.attribute_groups[0]
    214218
     219        # initialize operation attribute variables
     220        printer_name = None
     221        user = None
     222        limit = None
     223        attributes = None
     224        which_jobs = None
     225        my_jobs = None
     226
    215227        # requested printer uri
    216228        if 'printer-uri' not in operation:
    217229            raise ipp.errors.ClientErrorBadRequest("Missing 'printer-uri' attribute")
    218         uri_attr = operation['printer-uri']
    219         printer_name = uri_attr.values[0].value.split("/")[-1]
    220         if uri_attr != ipp.PrinterUri(uri_attr.values[0].value):
    221             raise ipp.errors.ClientErrorBadRequest(str(uri_attr))
    222         if printer_name != self.printer.name:
    223             raise ipp.errors.ClientErrorAttributes(str(uri_attr), uri_attr)
    224 
     230        printer_uri = verify_attribute(operation['printer-uri'], ipp.PrinterUri)[0]
     231        if printer_uri not in self.printer.uris:
     232            raise ipp.errors.ClientErrorAttributes(
     233                str(operation['printer-uri']), operation['printer-uri'])
     234
     235        # optional attributes
     236        if 'limit' in operation:
     237            limit = verify_attribute(
     238                operation['limit'], ipp.Limit)[0]
     239           
     240        if 'requested-attributes' in operation:
     241            attributes = verify_attribute(
     242                operation['requested-attributes'], ipp.RequestedAttributes, length=None)
     243           
     244        if 'which-jobs' in operation:
     245            which_jobs = verify_attribute(
     246                operation['which-jobs'], ipp.WhichJobs)[0]
     247           
     248        if 'my-jobs' in operation:
     249            my_jobs = verify_attribute(
     250                operation['my-jobs'], ipp.MyJobs)[0]
     251
     252        if 'requesting-user-name' in operation:
     253            user = verify_attribute(
     254                operation['requesting-user-name'], ipp.RequestingUserName)[0]
     255            # ignore if we're not filtering jobs by user
     256            if not my_jobs:
     257                user = None
     258           
    225259        # get the job attributes and add them to the response
    226         for job in self.printer.get_jobs():
    227             attrs = job.get_job_attributes(operation)
     260        jobs = self.printer.get_jobs(
     261            which_jobs=which_jobs,
     262            requesting_user_name=user)
     263        for job in jobs:
     264            attrs = job.get_job_attributes(requested_attributes=attributes)
    228265            response.attribute_groups.append(ipp.AttributeGroup(
    229266                ipp.AttributeTags.JOB, attrs))
     
    283320        operation = request.attribute_groups[0]
    284321
     322        printer_uri = None
     323        requesting_user_name = None
     324        job_name = None
     325        ipp_attribute_fidelity=None
     326        job_k_octets = None
     327
    285328        # requested printer uri
    286329        if 'printer-uri' not in operation:
    287330            raise ipp.errors.ClientErrorBadRequest("Missing 'printer-uri' attribute")
    288         uri_attr = operation['printer-uri']
    289         printer_name = uri_attr.values[0].value.split("/")[-1]
    290         if uri_attr != ipp.PrinterUri(uri_attr.values[0].value):
    291             raise ipp.errors.ClientErrorBadRequest(str(uri_attr))
    292         if printer_name != self.printer.name:
    293             raise ipp.errors.ClientErrorAttributes(str(uri_attr), uri_attr)
     331        printer_uri = verify_attribute(operation['printer-uri'], ipp.PrinterUri)[0]
     332        if printer_uri not in self.printer.uris:
     333            raise ipp.errors.ClientErrorAttributes(
     334                str(operation['printer-uri']), operation['printer-uri'])
     335
     336        if 'requesting-user-name' in operation:
     337            user_name = verify_attribute(
     338                operation['requesting-user-name'], ipp.RequestingUserName)[0]
     339
     340        if 'job-name' in operation:
     341            job_name = verify_attribute(
     342                operation['job-name'], ipp.JobName)[0]
     343
     344        if 'job-k-octets' in operation:
     345            job_k_octets = verify_attribute(
     346                operation['job-k-octets'], ipp.JobKOctets)[0]
     347
     348        if 'ipp-attribute-fidelity' in operation:
     349            pass # don't care
     350        if 'job-impressions' in operation:
     351            pass # don't care
     352        if 'job-media-sheets' in operation:
     353            pass # don't care
    294354
    295355        # get attributes from the printer and add to response
    296         job = self.printer.create_job(request)
     356        job = self.printer.create_job(
     357            requesting_user_name=requesting_user_name,
     358            job_name=job_name,
     359            job_k_octets=job_k_octets)
    297360        response.attribute_groups.append(ipp.AttributeGroup(
    298             ipp.AttributeTags.JOB, job.get_job_attributes(operation)))
     361            ipp.AttributeTags.JOB, job.get_job_attributes()))
    299362   
    300363    @handler_for(ipp.OperationCodes.PAUSE_PRINTER)
     
    345408        operation = request.attribute_groups[0]
    346409
     410        printer_uri = None
     411        requesting_user_name = None
     412        requested_attributes = None
     413        document_format = None
     414
    347415        # requested printer uri
    348416        if 'printer-uri' not in operation:
    349417            raise ipp.errors.ClientErrorBadRequest("Missing 'printer-uri' attribute")
    350         uri_attr = operation['printer-uri']
    351         printer_name = uri_attr.values[0].value.split("/")[-1]
    352         if uri_attr != ipp.PrinterUri(uri_attr.values[0].value):
    353             raise ipp.errors.ClientErrorBadRequest(str(uri_attr))
    354         if printer_name != self.printer.name:
    355             raise ipp.errors.ClientErrorAttributes(str(uri_attr), uri_attr)
    356         printer = self.printer
     418        printer_uri = verify_attribute(operation['printer-uri'], ipp.PrinterUri)[0]
     419        if printer_uri not in self.printer.uris:
     420            raise ipp.errors.ClientErrorAttributes(
     421                str(operation['printer-uri']), operation['printer-uri'])
     422
     423        # optional attributes
     424        if 'requesting-user-name' in operation:
     425            user_name = verify_attribute(
     426                operation['requesting-user-name'], ipp.RequestingUserName)[0]
     427           
     428        if 'requested-attributes' in operation:
     429            requested_attributes = verify_attribute(
     430                operation['requested-attributes'], ipp.RequestedAttributes, length=None)
     431
     432        if 'document-format' in operation:
     433            pass # XXX: todo
    357434
    358435        # get attributes from the printer and add to response
    359436        response.attribute_groups.append(ipp.AttributeGroup(
    360             ipp.AttributeTags.PRINTER, printer.get_printer_attributes(operation)))
     437            ipp.AttributeTags.PRINTER,
     438            self.printer.get_printer_attributes(
     439                requested_attributes=requested_attributes)))
    361440
    362441    @handler_for(ipp.OperationCodes.SET_PRINTER_ATTRIBUTES)
     
    372451    @handler_for(ipp.OperationCodes.SEND_DOCUMENT)
    373452    def send_document(self, request, response):
     453        """3.3.1 Send-Document Operation
     454       
     455        This OPTIONAL operation allows a client to create a
     456        multi-document Job object that is initially 'empty' (contains
     457        no documents). In the Create-Job response, the Printer object
     458        returns the Job object's URI (the 'job-uri' attribute) and the
     459        Job object's 32-bit identifier (the 'job-id' attribute). For
     460        each new document that the client desires to add, the client
     461        uses a Send-Document operation. Each Send- Document Request
     462        contains the entire stream of document data for one document.
     463
     464        If the Printer supports this operation but does not support
     465        multiple documents per job, the Printer MUST reject subsequent
     466        Send-Document operations supplied with data and return the
     467        'server-error-multiple- document-jobs-not-supported'. However,
     468        the Printer MUST accept the first document with a 'true' or
     469        'false' value for the 'last-document' operation attribute (see
     470        below), so that clients MAY always submit one document jobs
     471        with a 'false' value for 'last-document' in the first
     472        Send-Document and a 'true' for 'last-document' in the second
     473        Send-Document (with no data).
     474       
     475        Since the Create-Job and the send operations (Send-Document or
     476        Send- URI operations) that follow could occur over an
     477        arbitrarily long period of time for a particular job, a client
     478        MUST send another send operation within an IPP Printer defined
     479        minimum time interval after the receipt of the previous
     480        request for the job. If a Printer object supports the
     481        Create-Job and Send-Document operations, the Printer object
     482        MUST support the 'multiple-operation-time-out' attribute (see
     483        section 4.4.31). This attribute indicates the minimum number
     484        of seconds the Printer object will wait for the next send
     485        operation before taking some recovery action.
     486
     487        An IPP object MUST recover from an errant client that does not
     488        supply a send operation, sometime after the minimum time
     489        interval specified by the Printer object's
     490        'multiple-operation-time-out' attribute.
     491
     492        Access Rights: The authenticated user (see section 8.3)
     493        performing this operation must either be the job owner (as
     494        determined in the Create-Job operation) or an operator or
     495        administrator of the Printer object (see Sections 1 and
     496        8.5). Otherwise, the IPP object MUST reject the operation and
     497        return: 'client-error-forbidden', 'client-
     498        error-not-authenticated', or 'client-error-not-authorized' as
     499        appropriate.
     500
     501        Request
     502        -------
     503
     504        Group 1: Operation Attributes
     505            REQUIRED 'attributes-charset'
     506            REQUIRED 'attributes-natural-language'
     507            REQUIRED 'job-id' (uri)
     508            OPTIONAL 'printer-uri' (uri)
     509            OPTIONAL 'requesting-user-name' (name(MAX))
     510            OPTIONAL 'document-name' (name(MAX))
     511            OPTIONAL 'compression' (type3 keyword)
     512            OPTIONAL 'document-format' (mimeMediaType)
     513            OPTIONAL 'document-natural-language' (naturalLanguage)
     514            OPTIONAL 'last-document' (boolean)
     515        Group 2: Document Content
     516           
     517        Response
     518        --------
     519
     520        Group 1: Operation Attributes
     521            OPTIONAL 'status-message' (text(255))
     522            OPTIONAL 'detailed-status-message' (text(MAX))
     523            REQUIRED 'attributes-charset'
     524            REQUIRED 'attributes-natural-language'
     525        Group 2: Unsupported Attributes
     526        Group 3: Job Object Attributes
     527            REQUIRED 'job-uri' (uri)
     528            REQUIRED 'job-id' (integer(1:MAX))
     529            REQUIRED 'job-state' (type1 enum)
     530            REQUIRED 'job-state-reasons' (1setOf type2 keyword)
     531            OPTIONAL 'job-state-message' (text(MAX))
     532            OPTIONAL 'number-of-intervening-jobs' (integer(0:MAX))
     533
     534        """
     535       
    374536        operation = request.attribute_groups[0]
    375537
    376         # requested printer uri
    377         if 'printer-uri' in operation:
    378             uri_attr = operation['printer-uri']
    379             printer_name = uri_attr.values[0].value.split("/")[-1]
    380             if uri_attr != ipp.PrinterUri(uri_attr.values[0].value):
    381                 raise ipp.errors.ClientErrorBadRequest(str(uri_attr))
    382             if printer_name != self.printer.name:
    383                 raise ipp.errors.ClientErrorAttributes(str(uri_attr), uri_attr)
    384         printer = self.printer
    385 
     538        job_id = None
     539        printer_uri = None
     540        requesting_user_name = None
     541        document_name = None
     542        compression = None
     543        document_format = None
     544        document_natural_language = None
     545        last_document = None
     546
     547        # required attributes
    386548        if 'job-id' not in operation:
    387549            raise ipp.errors.ClientErrorBadRequest("Missing 'job-id' attribute")
    388         job_id_attr = operation['job-id']
    389         job_id = job_id_attr.values[0].value
    390         if job_id_attr != ipp.JobId(job_id_attr.values[0].value):
    391             raise ipp.errors.ClientErrorBadRequest(str(job_id_attr))
    392         if job_id not in printer.jobs:
    393             raise ipp.errors.ClientErrorAttributes(str(job_id_attr))
    394         job = printer.jobs[job_id]
     550        job_id = verify_attribute(operation['job-id'], ipp.JobId)[0]
    395551
    396552        if 'last-document' not in operation:
    397553            raise ipp.errors.ClientErrorBadRequest("Missing 'last-document' attribute")
    398         last_attr = operation['last-document']
    399         last = last_attr.values[0].value
    400         if last_attr != ipp.LastDocument(last):
    401             raise ipp.errors.ClientErrorBadRequest(str(last_attr))
    402         if not last:
     554        last_document = verify_attribute(operation['last-document'], ipp.LastDocument)[0]
     555        if not last_document:
    403556            raise ipp.errors.ServerErrorMultipleJobsNotSupported
    404557
    405         printer.send_document(job_id, request.data)
    406         attrs = job.get_job_attributes()
     558        # optional attributes
     559        if 'printer-uri' in operation:
     560            printer_uri = verify_attribute(operation['printer-uri'], ipp.PrinterUri)[0]
     561            if printer_uri not in self.printer.uris:
     562                raise ipp.errors.ClientErrorAttributes(
     563                    str(operation['printer-uri']), operation['printer-uri'])
     564
     565        if 'requesting-user-name' in operation:
     566            user_name = verify_attribute(
     567                operation['requesting-user-name'], ipp.RequestingUserName)[0]
     568
     569        if 'document-name' in operation:
     570            document_name = verify_attribute(
     571                operation['document-name'], ipp.DocumentName)[0]
     572
     573        if 'compression' in operation:
     574            compression = verify_attribute(
     575                operation['compression'], ipp.Compression)[0]
     576
     577        if 'document-format' in operation:
     578            document_format = verify_attribute(
     579                operation['document-format'], ipp.DocumentFormat)[0]
     580
     581        if 'document-natural-language' in operation:
     582            document_natural_language = verify_attribute(
     583                operation['document_natural_language'],
     584                ipp.DocumentNaturalLanguage)[0]
     585
     586        job = self.printer.get_job(job_id)
     587        job.send_document(
     588            request.data,
     589            requesting_user_name=user_name,
     590            document_name=document_name,
     591            compression=compression,
     592            document_format=document_format,
     593            document_natural_language=document_natural_language,
     594            last_document=last_document)
     595
    407596        response.attribute_groups.append(ipp.AttributeGroup(
    408             ipp.AttributeTags.JOB, attrs))
     597            ipp.AttributeTags.JOB, job.get_job_attributes()))
    409598
    410599    @handler_for(ipp.OperationCodes.SEND_URI)
     
    414603    @handler_for(ipp.OperationCodes.GET_JOB_ATTRIBUTES)
    415604    def get_job_attributes(self, request, response):
     605        """3.3.4 Get-Job-Attributes Operation
     606
     607        This REQUIRED operation allows a client to request the values
     608        of attributes of a Job object and it is almost identical to
     609        the Get- Printer-Attributes operation (see section 3.2.5). The
     610        only differences are that the operation is directed at a Job
     611        object rather than a Printer object, there is no
     612        'document-format' operation attribute used when querying a Job
     613        object, and the returned attribute group is a set of Job
     614        object attributes rather than a set of Printer object
     615        attributes.
     616
     617        For Jobs, the possible names of attribute groups are:
     618          - 'job-template': the subset of the Job Template attributes
     619            that apply to a Job object (the first column of the table
     620            in Section 4.2) that the implementation supports for Job
     621            objects.
     622          - 'job-description': the subset of the Job Description
     623            attributes specified in Section 4.3 that the
     624            implementation supports for Job objects.
     625          - 'all': the special group 'all' that includes all
     626            attributes that the implementation supports for Job
     627            objects.
     628
     629        Since a client MAY request specific attributes or named
     630        groups, there is a potential that there is some overlap. For
     631        example, if a client requests, 'job-name' and
     632        'job-description', the client is actually requesting the
     633        'job-name' attribute once by naming it explicitly, and once by
     634        inclusion in the 'job-description' group. In such cases, the
     635        Printer object NEED NOT return the attribute only once in the
     636        response even if it is requested multiple times. The client
     637        SHOULD NOT request the same attribute in multiple ways.
     638
     639        It is NOT REQUIRED that a Job object support all attributes
     640        belonging to a group (since some attributes are
     641        OPTIONAL). However it is REQUIRED that each Job object support
     642        all these group names.
     643
     644        Request
     645        -------
     646
     647        Group 1: Operation Attributes
     648            REQUIRED 'attributes-charset'
     649            REQUIRED 'attributes-natural-language'
     650            REQUIRED 'job-id' (uri)
     651            OPTIONAL 'printer-uri' (uri)
     652            OPTIONAL 'requesting-user-name' (name(MAX))
     653            OPTIONAL 'requested-attributes' (1setOf keyword)
     654           
     655        Response
     656        --------
     657
     658        Group 1: Operation Attributes
     659            OPTIONAL 'status-message' (text(255))
     660            OPTIONAL 'detailed-status-message' (text(MAX))
     661            REQUIRED 'attributes-charset'
     662            REQUIRED 'attributes-natural-language'
     663        Group 2: Unsupported Attributes
     664        Group 3: Job Object Attributes
     665
     666        """
     667       
    416668        operation = request.attribute_groups[0]
    417669
    418         # requested printer uri
    419         if 'printer-uri' not in operation:
    420             raise ipp.errors.ClientErrorBadRequest("Missing 'printer-uri' attribute")
    421         uri_attr = operation['printer-uri']
    422         printer_name = uri_attr.values[0].value.split("/")[-1]
    423         if uri_attr != ipp.PrinterUri(uri_attr.values[0].value):
    424             raise ipp.errors.ClientErrorBadRequest(str(uri_attr))
    425         if printer_name != self.printer.name:
    426             raise ipp.errors.ClientErrorAttributes(str(uri_attr), uri_attr)
    427         printer = self.printer
    428 
     670        job_id = None
     671        printer_uri = None
     672        requesting_user_name = None
     673        requested_attributes = None
     674
     675        # required attributes
    429676        if 'job-id' not in operation:
    430677            raise ipp.errors.ClientErrorBadRequest("Missing 'job-id' attribute")
    431         job_id_attr = operation['job-id']
    432         job_id = job_id_attr.values[0].value
    433         if job_id_attr != ipp.JobId(job_id_attr.values[0].value):
    434             raise ipp.errors.ClientErrorBadRequest(str(job_id_attr))
    435         if job_id not in printer.jobs:
    436             raise ipp.errors.ClientErrorAttributes(str(job_id_attr))
    437         job = printer.get_job(job_id)
     678        job_id = verify_attribute(operation['job-id'], ipp.JobId)[0]
     679
     680        # optional attributes
     681        if 'printer-uri' in operation:
     682            printer_uri = verify_attribute(operation['printer-uri'], ipp.PrinterUri)[0]
     683            if printer_uri not in self.printer.uris:
     684                raise ipp.errors.ClientErrorAttributes(
     685                    str(operation['printer-uri']), operation['printer-uri'])
     686
     687        # optional attributes
     688        if 'requesting-user-name' in operation:
     689            user_name = verify_attribute(
     690                operation['requesting-user-name'], ipp.RequestingUserName)[0]
     691           
     692        if 'requested-attributes' in operation:
     693            requested_attributes = verify_attribute(
     694                operation['requested-attributes'], ipp.RequestedAttributes, length=None)
    438695
    439696        # get the job attributes and add them to the response
    440         attrs = job.get_job_attributes(operation)
     697        job = self.printer.get_job(job_id)
     698        attrs = job.get_job_attributes(requested_attributes=requested_attributes)
    441699        response.attribute_groups.append(ipp.AttributeGroup(
    442700            ipp.AttributeTags.JOB, attrs))
     
    487745
    488746        operation = request.attribute_groups[0]
    489         printer = self.printer
     747        requested_attributes = None
     748       
     749        if 'requested-attributes' in operation:
     750            requested_attributes = verify_attribute(
     751                operation['requested-attributes'], ipp.RequestedAttributes, length=None)
    490752
    491753        # get attributes from the printer and add to response
     754        attrs = self.printer.get_printer_attributes(
     755            requested_attributes=requested_attributes)
    492756        response.attribute_groups.append(ipp.AttributeGroup(
    493             ipp.AttributeTags.PRINTER, printer.get_printer_attributes(operation)))
     757            ipp.AttributeTags.PRINTER, attrs))
    494758
    495759    @handler_for(ipp.OperationCodes.CUPS_GET_PRINTERS)
     
    504768        """
    505769
    506         operation = request.attribute_groups[0]
    507 
    508770        # get attributes from the printer and add to response
    509771        response.attribute_groups.append(ipp.AttributeGroup(
    510             ipp.AttributeTags.PRINTER, self.printer.get_printer_attributes(operation)))
     772            ipp.AttributeTags.PRINTER, self.printer.get_printer_attributes()))
    511773
    512774    @handler_for(ipp.OperationCodes.CUPS_GET_CLASSES)
Note: See TracChangeset for help on using the changeset viewer.