Exemplo n.º 1
0
def wsd_validate_scan_ticket(hosted_scan_service: wsd_transfer__structures.HostedService,
                             tkt: wsd_scan__structures.ScanTicket) \
        -> typing.Tuple[bool, wsd_scan__structures.ScanTicket]:
    """
    Submit a ValidateScanTicket request, and parse the response.
    Scanner devices can validate scan settings/parameters and fix errors if any. It is recommended to always
    validate a ticket before submitting the actual scan job.

    :param hosted_scan_service: the wsd scan service to query
    :type hosted_scan_service: wsd_transfer__structures.HostedService
    :param tkt: the ScanTicket to submit for validation purposes
    :type tkt: wsd_scan__structures.ScanTicket
    :return: a tuple of the form (boolean, ScanTicket), where the first field is True if no errors were found during\
    validation, along with the same ticket submitted, or False if errors were found, along with a corrected ticket.
    """

    fields = {"FROM": wsd_globals.urn, "TO": hosted_scan_service.ep_ref_addr}
    x = wsd_common.submit_request({hosted_scan_service.ep_ref_addr},
                                  "ws-scan__validate_scan_ticket.xml", {
                                      **fields,
                                      **tkt.as_map()
                                  })

    v = wsd_common.xml_find(x, ".//sca:ValidTicket")

    if v.text == 'true' or v.text == '1':
        return True, tkt
    else:
        return False, wsd_scan__parsers.parse_scan_ticket(
            wsd_common.xml_find(x, ".//sca::ValidScanTicket"))
Exemplo n.º 2
0
def wsd_get_scanner_elements(
        hosted_scan_service: wsd_transfer__structures.HostedService):
    """
    Submit a GetScannerElements request, and parse the response.
    The device should reply with informations about itself,
    its configuration, its status and the defalt scan ticket

    :param hosted_scan_service: the wsd scan service to query
    :type hosted_scan_service: wsd_transfer__structures.HostedService
    :return: a tuple of the form (ScannerDescription, ScannerConfiguration, ScannerStatus, ScanTicket)
    """
    fields = {"FROM": wsd_globals.urn, "TO": hosted_scan_service.ep_ref_addr}
    x = wsd_common.submit_request({hosted_scan_service.ep_ref_addr},
                                  "ws-scan__get_scanner_elements.xml", fields)

    re = wsd_common.xml_find(x, ".//sca:ScannerElements")
    sca_status = wsd_common.xml_find(re, ".//sca:ScannerStatus")
    sca_config = wsd_common.xml_find(re, ".//sca:ScannerConfiguration")
    sca_descr = wsd_common.xml_find(re, ".//sca:ScannerDescription")
    std_ticket = wsd_common.xml_find(re, ".//sca:DefaultScanTicket")

    description = wsd_scan__parsers.parse_scan_description(sca_descr)
    status = wsd_scan__parsers.parse_scan_status(sca_status)
    config = wsd_scan__parsers.parse_scan_configuration(sca_config)
    std_ticket = wsd_scan__parsers.parse_scan_ticket(std_ticket)

    return description, config, status, std_ticket
Exemplo n.º 3
0
def parse_scanner_condition(scond):
    c = wsd_scan__structures.ScannerCondition()
    c.id = int(scond.get("Id"))
    c.time = wsd_common.xml_find(scond, ".//sca:Time").text
    c.name = wsd_common.xml_find(scond, ".//sca:Name").text
    c.component = wsd_common.xml_find(scond, ".//sca:Component").text
    c.severity = wsd_common.xml_find(scond, ".//sca:Severity").text
    return c
Exemplo n.º 4
0
def parse_scan_description(sca_descr):
    description = wsd_scan__structures.ScannerDescription()

    description.name = wsd_common.xml_find(sca_descr,
                                           ".//sca:ScannerName").text
    q = wsd_common.xml_find(sca_descr, ".//sca:ScannerInfo")
    if q is not None:
        description.info = q.text
    q = wsd_common.xml_find(sca_descr, ".//sca:ScannerLocation")
    if q is not None:
        description.location = q.text
    return description
Exemplo n.º 5
0
def parse_scan_ticket(std_ticket):
    st = wsd_scan__structures.ScanTicket()
    st.job_name = wsd_common.xml_find(std_ticket,
                                      ".//sca:JobDescription/sca:JobName").text
    st.job_user_name = wsd_common.xml_find(
        std_ticket, ".//sca:JobDescription/sca:JobOriginatingUserName").text
    q = wsd_common.xml_find(std_ticket,
                            ".//sca:JobDescription/sca:JobInformation")
    if q is not None:
        st.job_info = q.text
    dps = wsd_common.xml_find(std_ticket, ".//sca:DocumentParameters")
    st.doc_params = parse_document_params(dps)
    return st
Exemplo n.º 6
0
    def handle_scanner_status_condition_cleared_event(queues, xml_tree):
        if wsd_globals.debug is True:
            print('##\n## SCANNER STATUS CONDITION CLEARED EVENT\n##\n')
            print(
                etree.tostring(xml_tree,
                               pretty_print=True,
                               xml_declaration=True))

        cond = wsd_common.xml_find(xml_tree, ".//sca:DeviceConditionCleared")
        cond_id = int(wsd_common.xml_find(cond, ".//sca:ConditionId").text)
        clear_time = wsd_common.xml_find(cond,
                                         ".//sca:ConditionClearTime").text
        queues.sc_cond_clr_q.put((cond_id, clear_time))
Exemplo n.º 7
0
 def handle_scan_available_event(xml_tree):
     if wsd_globals.debug is True:
         print('##\n## SCAN AVAILABLE EVENT\n##\n')
         print(
             etree.tostring(xml_tree,
                            pretty_print=True,
                            xml_declaration=True))
     client_context = wsd_common.xml_find(xml_tree,
                                          ".//sca:ClientContext").text
     scan_identifier = wsd_common.xml_find(xml_tree,
                                           ".//sca:ScanIdentifier").text
     t = threading.Thread(target=device_initiated_scan_worker,
                          args=(client_context, scan_identifier,
                                "wsd-daemon-scan"))
     t.start()
Exemplo n.º 8
0
def wsd_scan_available_event_subscribe(
        hosted_scan_service: wsd_transfer__structures.HostedService,
        display_str: str,
        context_str: str,
        notify_addr: str,
        expiration: typing.Union[datetime, timedelta] = None):
    """
        Subscribe to ScanAvailable events.

        :param hosted_scan_service: the wsd service to receive event notifications from
        :param display_str: the string to display on the device control panel
        :param context_str: a string internally used to identify the selection of this wsd host as target of the scan
        :param notify_addr: The address to send notifications to.
        :param expiration: Expiration time, as a datetime or timedelta object
        :return: a subscription ID  and the token needed in CreateScanJob to start a device-initiated scan, \
                or False if a fault message is received instead
    """

    if expiration is None:
        pass
    elif expiration.__class__ == "datetime.datetime":
        expiration = xml_helpers.fmt_as_xml_datetime(expiration)
    elif expiration.__class__ == "datetime.timedelta":
        expiration = xml_helpers.fmt_as_xml_duration(expiration)
    else:
        raise TypeError

    expiration_tag = ""
    if expiration is not None:
        expiration_tag = "<wse:Expires>%s</wse:Expires>" % expiration

    fields_map = {
        "FROM": wsd_globals.urn,
        "TO": hosted_scan_service.ep_ref_addr,
        "NOTIFY_ADDR": notify_addr,
        "OPT_EXPIRATION": expiration_tag,
        "DISPLAY_STR": display_str,
        "CONTEXT": context_str
    }
    try:
        x = wsd_common.submit_request(
            {hosted_scan_service.ep_ref_addr},
            "ws-scan__scan_available_event_subscribe.xml", fields_map)
        dest_token = wsd_common.xml_find(x, ".//sca:DestinationToken").text
        subscription_id = wsd_common.xml_find(x, ".//wse:Identifier").text
        return subscription_id, dest_token
    except TimeoutError:
        return False
Exemplo n.º 9
0
def wsd_get_status(hosted_service: wsd_transfer__structures.HostedService,
                   subscription_id: str) \
        -> typing.Union[None, bool, datetime]:
    """
    Get the status of an events subscription of a wsd service

    :param hosted_service: the wsd service from which you want to hear about the subscription status
    :type hosted_service: wsd_transfer__structures.HostedService
    :param subscription_id: the ID returned from a previous successful event subscription call
    :type subscription_id: str
    :return: False if a fault message is received instead, \
             none if the subscription has no expiration set, \
             the expiration date otherwise
    :rtype: None | False | datetime
    """
    fields_map = {
        "FROM": wsd_globals.urn,
        "TO": hosted_service.ep_ref_addr,
        "SUBSCRIPTION_ID": subscription_id
    }
    x = wsd_common.submit_request({hosted_service.ep_ref_addr},
                                  "ws-eventing__get_status.xml", fields_map)

    if wsd_common.check_fault(x):
        return False
    e = wsd_common.xml_find(x, ".//wse:Expires")
    return xml_helpers.parse_xml_datetime(e.text.replace(" ", ""),
                                          weak=True) if e is not None else None
Exemplo n.º 10
0
    def handle_scanner_status_summary_event(queues, xml_tree):
        if wsd_globals.debug is True:
            print('##\n## SCANNER STATUS SUMMARY EVENT\n##\n')
            print(
                etree.tostring(xml_tree,
                               pretty_print=True,
                               xml_declaration=True))

        state = wsd_common.xml_find(xml_tree, ".//sca:ScannerState").text
        reasons = []
        q = wsd_common.xml_find(xml_tree, ".//sca:ScannerStateReasons")
        if q is not None:
            dsr = wsd_common.xml_findall(q, ".//sca:ScannerStateReason")
            for sr in dsr:
                reasons.append(sr.text)
        queues.sc_stat_sum_q.put((state, reasons))
Exemplo n.º 11
0
def get_sequence(xml_tree: etree.ElementTree) -> typing.List[int]:
    q = wsd_common.xml_find(xml_tree, ".//wsd:AppSequence")
    seq = [0, 0, 0]
    seq[0] = int(q.attrib['InstanceId'])
    if 'SequenceId' in q.attrib:
        seq[1] = int(q.attrib['SequenceId'])
    seq[2] = int(q.attrib['MessageNumber'])
    return seq
Exemplo n.º 12
0
 def handle_job_end_state_event(queues, xml_tree):
     if wsd_globals.debug is True:
         print('##\n## JOB END STATE EVENT\n##\n')
         print(
             etree.tostring(xml_tree,
                            pretty_print=True,
                            xml_declaration=True))
         s = wsd_common.xml_find(xml_tree, ".//sca:JobEndState")
         queues.sc_job_ended_q.put(wsd_scan__parsers.parse_job_summary(s))
Exemplo n.º 13
0
 def handle_job_status_event(queues, xml_tree):
     if wsd_globals.debug is True:
         print('##\n## JOB STATUS EVENT\n##\n')
         print(
             etree.tostring(xml_tree,
                            pretty_print=True,
                            xml_declaration=True))
         s = wsd_common.xml_find(xml_tree, ".//sca:JobStatus")
         queues.sc_job_status_q.put(wsd_scan__parsers.parse_job_status(s))
Exemplo n.º 14
0
    def handle_scanner_status_condition_event(queues, xml_tree):
        if wsd_globals.debug is True:
            print('##\n## SCANNER STATUS CONDITION EVENT\n##\n')
            print(
                etree.tostring(xml_tree,
                               pretty_print=True,
                               xml_declaration=True))

        cond = wsd_common.xml_find(xml_tree, ".//sca:DeviceCondition")
        cond = wsd_scan__parsers.parse_scanner_condition(cond)
        queues.sc_cond_q.put(cond)
Exemplo n.º 15
0
    def handle_scanner_elements_change_event(queues, xml_tree):
        if wsd_globals.debug is True:
            print('##\n## SCANNER ELEMENTS CHANGE EVENT\n##\n')
            print(
                etree.tostring(xml_tree,
                               pretty_print=True,
                               xml_declaration=True))

        sca_config = wsd_common.xml_find(xml_tree,
                                         ".//sca:ScannerConfiguration")
        sca_descr = wsd_common.xml_find(xml_tree, ".//sca:ScannerDescription")
        std_ticket = wsd_common.xml_find(xml_tree, ".//sca:DefaultScanTicket")

        description = wsd_scan__parsers.parse_scan_description(sca_descr)
        configuration = wsd_scan__parsers.parse_scan_configuration(sca_config)
        std_ticket = wsd_scan__parsers.parse_scan_ticket(std_ticket)

        queues.sc_descr_q.put(description)
        queues.sc_conf_q.put(configuration)
        queues.sc_ticket_q.put(std_ticket)
Exemplo n.º 16
0
def parse_scan_status(sca_status):
    status = wsd_scan__structures.ScannerStatus()

    status.time = wsd_common.xml_find(sca_status,
                                      ".//sca:ScannerCurrentTime").text
    status.state = wsd_common.xml_find(sca_status, ".//sca:ScannerState").text
    ac = wsd_common.xml_find(sca_status, ".//sca:ActiveConditions")
    if ac is not None:
        dcl = wsd_common.xml_findall(ac, ".//sca:DeviceCondition")
        for dc in dcl:
            c = parse_scanner_condition(dc)
            status.active_conditions[c.id] = c
    q = wsd_common.xml_find(sca_status, ".//sca:ScannerStateReasons")
    if q is not None:
        dsr = wsd_common.xml_findall(q, ".//sca:ScannerStateReason")
        for sr in dsr:
            status.reasons.append(sr.text)
    q = wsd_common.xml_find(sca_status, ".//sca:ConditionHistory")
    if q is not None:
        chl = wsd_common.xml_findall(q, ".//sca:ConditionHistoryEntry")
        for che in chl:
            c = parse_scanner_condition(che)
            status.conditions_history[wsd_common.xml_find(
                che, ".//sca:ClearTime").text] = c
    return status
Exemplo n.º 17
0
def wsd_subscribe(hosted_service: wsd_transfer__structures.HostedService,
                  event_uri: str,
                  notify_addr: str,
                  expiration: typing.Union[datetime, timedelta] = None) \
        -> typing.Union[etree.ElementTree, bool]:
    """
    Subscribe to a certain type of events of a wsd service

    :param hosted_service: the wsd service to receive event notifications from
    :type hosted_service: wsd_transfer__structures.HostedService
    :param event_uri: the full URI of the targeted event class. \
                    Those URIs are taken from ws specifications
    :type event_uri: str
    :param notify_addr: The address to send notifications to.
    :type notify_addr: str
    :param expiration: Expiration time, as a datetime or timedelta object
    :type expiration: datetime | timedelta | None
    :return: the xml SubscribeResponse of the wsd service\
             or False if a fault message is received instead
    :rtype: lxml.etree.ElementTree | False
    """

    if expiration is None:
        pass
    elif isinstance(expiration, datetime):
        expiration = xml_helpers.fmt_as_xml_datetime(expiration)
    elif isinstance(expiration, timedelta):
        expiration = xml_helpers.fmt_as_xml_duration(expiration)
    else:
        raise TypeError("Type %s not allowed" % expiration.__class__)

    expiration_tag = ""
    if expiration is not None:
        expiration_tag = "<wse:Expires>%s</wse:Expires>" % expiration

    fields_map = {
        "FROM": wsd_globals.urn,
        "TO": hosted_service.ep_ref_addr,
        "NOTIFY_ADDR": notify_addr,
        "EXPIRES": expiration,
        "FILTER_DIALECT":
        "http://schemas.xmlsoap.org/ws/2006/02/devprof/Action",
        "EVENT": event_uri,
        "OPT_EXPIRATION": expiration_tag
    }
    x = wsd_common.submit_request({hosted_service.ep_ref_addr},
                                  "ws-eventing__subscribe.xml", fields_map)

    if wsd_common.check_fault(x):
        return False

    return wsd_common.xml_find(x, ".//wse:SubscribeResponse")
Exemplo n.º 18
0
def wsd_get_job_elements(
        hosted_scan_service: wsd_transfer__structures.HostedService,
        job: wsd_scan__structures.ScanJob):
    """
    Submit a GetJob request, and parse the response.
    The device should reply with info's about the specified job, such as its status,
    the ticket submitted for job initiation, the final parameters set effectively used to scan, and a document list.

    :param hosted_scan_service: the wsd scan service to query
    :type hosted_scan_service: wsd_transfer__structures.HostedService
    :param job: the ScanJob instance representing the job to abort
    :type job: wsd_scan_structures.ScanJob
    :return: a tuple of the form (JobStatus, ScanTicket, DocumentParams, doclist),\
    where doclist is a list of document names
    """
    fields = {
        "FROM": wsd_globals.urn,
        "TO": hosted_scan_service.ep_ref_addr,
        "JOB_ID": job.id
    }
    x = wsd_common.submit_request({hosted_scan_service.ep_ref_addr},
                                  "ws-scan__get_job_elements.xml", fields)

    q = wsd_common.xml_find(x, ".//sca:JobStatus")
    jstatus = wsd_scan__parsers.parse_job_status(q)

    st = wsd_common.xml_find(x, ".//sca:ScanTicket")
    tkt = wsd_scan__parsers.parse_scan_ticket(st)

    dfp = wsd_common.xml_find(x,
                              ".//sca:Documents/sca:DocumentFinalParameters")
    dps = wsd_scan__parsers.parse_document_params(dfp)
    dlist = [
        x.text for x in wsd_common.xml_findall(
            dfp, "sca:Document/sca:DocumentDescription/sca:DocumentName")
    ]

    return jstatus, tkt, dps, dlist
Exemplo n.º 19
0
def wsd_cancel_job(hosted_scan_service: wsd_transfer__structures.HostedService,
                   job: wsd_scan__structures.ScanJob) \
        -> bool:
    """
    Submit a CancelJob request, and parse the response.
    Stops and aborts the specified scan job.

    :param hosted_scan_service: the wsd scan service to query
    :type hosted_scan_service: wsd_transfer__structures.HostedService
    :param job: the ScanJob instance representing the job to abort
    :type job: wsd_scan_structures.ScanJob
    :return: True if the job is found and then aborted, False if the specified job do not exists or already ended.
    :rtype: bool
    """
    fields = {
        "FROM": wsd_globals.urn,
        "TO": hosted_scan_service.ep_ref_addr,
        "JOB_ID": job.id
    }
    x = wsd_common.submit_request({hosted_scan_service.ep_ref_addr},
                                  "ws-scan__cancel_job.xml", fields)

    wsd_common.xml_find(x, ".//sca:ClientErrorJobIdNotFound")
    return x is None
Exemplo n.º 20
0
def wsd_scanner_status_condition_subscribe(hosted_scan_service: wsd_transfer__structures.HostedService,
                                           notify_addr: str,
                                           expiration: typing.Union[datetime, timedelta] = None) \
        -> typing.Union[False, str]:
    """
        Subscribe to ScannerStatusCondition events.

        :param hosted_scan_service: the wsd service to receive event notifications from
        :param expiration: Expiration time, as a datetime or timedelta object
        :param notify_addr: The address to send notifications to.
        :return: False if a fault message is received, a subscription ID otherwise
    """
    event_uri = "http://schemas.microsoft.com/windows/2006/08/wdp/scan/ScannerStatusConditionEvent"
    x = wsd_eventing__operations.wsd_subscribe(hosted_scan_service, event_uri,
                                               notify_addr, expiration)
    if x is False:
        return False
    return wsd_common.xml_find(x, ".//wse:Identifier").text
Exemplo n.º 21
0
def parse_media_side(ms):
    s = wsd_scan__structures.MediaSide()
    r = wsd_common.xml_find(ms, ".//sca:ScanRegion")
    if r is not None:
        q = wsd_common.xml_find(r, ".//sca:ScanRegionXOffset")
        if q is not None:
            s.offset = (int(q.text), s.offset[1])
        q = wsd_common.xml_find(r, ".//sca:ScanRegionYOffset")
        if q is not None:
            s.offset = (s.offset[0], int(q.text))
        v1 = wsd_common.xml_find(r, ".//sca:ScanRegionWidth")
        v2 = wsd_common.xml_find(r, ".//sca:ScanRegionHeight")
        s.size = (int(v1.text), int(v2.text))
    q = wsd_common.xml_find(ms, ".//sca:ColorProcessing")
    if q is not None:
        s.color = q.text
    q = wsd_common.xml_find(ms, ".//sca:Resolution/sca:Width")
    s.res = (int(q.text), s.res[1])
    q = wsd_common.xml_find(ms, ".//sca:Resolution/sca:Height")
    s.res = (s.res[0], int(q.text))
    return s
Exemplo n.º 22
0
    def do_POST(self):
        context = self.server.context
        # request_path = self.path
        request_headers = self.headers
        length = int(request_headers["content-length"])

        message = self.rfile.read(length)

        self.protocol_version = "HTTP/1.1"
        self.send_response(202)
        self.send_header("Content-Type", "application/soap+xml")
        self.send_header("Content-Length", "0")
        self.send_header("Connection", "close")
        self.end_headers()

        x = etree.fromstring(message)
        action = wsd_common.xml_find(x, ".//wsa:Action").text
        (prefix, _, action) = action.rpartition('/')
        if prefix != 'http://schemas.microsoft.com/windows/2006/08/wdp/scan':
            return
        if action == 'ScanAvailableEvent' \
                and context["allow_device_initiated_scans"] is True:
            self.handle_scan_available_event(x)

        elif action == 'ScannerElementsChangeEvent':
            self.handle_scanner_elements_change_event(context['queues'], x)

        elif action == 'ScannerStatusSummaryEvent':
            self.handle_scanner_status_summary_event(context['queues'], x)

        elif action == 'ScannerStatusConditionEvent':
            self.handle_scanner_status_condition_event(context['queues'], x)

        elif action == 'ScannerStatusConditionClearedEvent':
            self.handle_scanner_status_condition_cleared_event(
                context['queues'], x)

        elif action == 'JobStatusEvent':
            self.handle_job_status_event(context['queues'], x)

        elif action == 'JobEndStateEvent':
            self.handle_job_end_state_event(context['queues'], x)
Exemplo n.º 23
0
def parse_job_status(q):
    jstatus = wsd_scan__structures.JobStatus()
    jstatus.id = int(wsd_common.xml_find(q, "sca:JobId").text)
    q1 = wsd_common.xml_find(q, "sca:JobState")
    q2 = wsd_common.xml_find(q, "sca:JobCompletedState")
    jstatus.state = q1.text if q1 is not None else q2.text
    jstatus.reasons = [
        x.text for x in wsd_common.xml_findall(q, "sca:JobStateReasons")
    ]
    jstatus.scans_completed = int(
        wsd_common.xml_find(q, "sca:ScansCompleted").text)
    a = wsd_common.xml_find(q, "sca:JobCreatedTime")
    jstatus.creation_time = q.text if a is not None else ""
    a = wsd_common.xml_find(q, "sca:JobCompletedTime")
    jstatus.completed_time = q.text if a is not None else ""
    return jstatus
Exemplo n.º 24
0
def wsd_create_scan_job(hosted_scan_service: wsd_transfer__structures.HostedService,
                        tkt: wsd_scan__structures.ScanTicket,
                        scan_identifier: str = "",
                        dest_token: str = "") \
        -> wsd_scan__structures.ScanJob:
    """
    Submit a CreateScanJob request, and parse the response.
    This creates a scan job and starts the image(s) acquisition.

    :param hosted_scan_service: the wsd scan service to query
    :type hosted_scan_service: wsd_transfer__structures.HostedService
    :param tkt: the ScanTicket to submit for validation purposes
    :type tkt: wsd_scan__structures.ScanTicket
    :param scan_identifier: a string identifying the device-initiated scan to handle, if any
    :type scan_identifier: str
    :param dest_token: a token assigned by the scanner to this client, needed for device-initiated scans
    :type dest_token: str
    :return: a ScanJob instance
    :rtype: wsd_scan__structures.ScanJob
    """

    fields = {
        "FROM": wsd_globals.urn,
        "TO": hosted_scan_service.ep_ref_addr,
        "SCAN_ID": scan_identifier,
        "DEST_TOKEN": dest_token
    }
    x = wsd_common.submit_request({hosted_scan_service.ep_ref_addr},
                                  "ws-scan__create_scan_job.xml", {
                                      **fields,
                                      **tkt.as_map()
                                  })

    x = wsd_common.xml_find(x, ".//sca:CreateScanJobResponse")

    return wsd_scan__parsers.parse_scan_job(x)
Exemplo n.º 25
0
def parse_scanner_source_settings(se, name):
    sss = wsd_scan__structures.ScannerSourceSettings()
    v1 = wsd_common.xml_find(se, ".//sca:%sOpticalResolution/sca:Width" % name)
    v2 = wsd_common.xml_find(se,
                             ".//sca:%sOpticalResolution/sca:Height" % name)
    sss.optical_res = (int(v1.text), int(v2.text))
    q = wsd_common.xml_findall(
        se, ".//sca:%sResolutions/sca:Widths/sca:Width" % name)
    sss.width_res = [x.text for x in q]
    q = wsd_common.xml_findall(
        se, ".//sca:%sResolutions/sca:Heights/sca:Height" % name)
    sss.height_res = [x.text for x in q]
    q = wsd_common.xml_findall(se, ".//sca:%sColor/sca:ColorEntry" % name)
    sss.color_modes = [x.text for x in q]
    v1 = wsd_common.xml_find(se, ".//sca:%sMinimumSize/sca:Width" % name)
    v2 = wsd_common.xml_find(se, ".//sca:%sMinimumSize/sca:Height" % name)
    sss.min_size = (int(v1.text), int(v2.text))
    v1 = wsd_common.xml_find(se, ".//sca:%sMaximumSize/sca:Width" % name)
    v2 = wsd_common.xml_find(se, ".//sca:%sMaximumSize/sca:Height" % name)
    sss.max_size = (int(v1.text), int(v2.text))
    return sss
Exemplo n.º 26
0
def wsd_get(target_service: wsd_discovery__structures.TargetService):
    """
    Query wsd target for information about model/device and hosted services.

    :param target_service: A wsd target
    :type target_service: wsd_discovery__structures.TargetService
    :return: A tuple containing a TargetInfo and a list of HostedService instances.
    """
    fields = {"FROM": wsd_globals.urn, "TO": target_service.ep_ref_addr}
    x = wsd_common.submit_request(target_service.xaddrs,
                                  "ws-transfer__get.xml", fields)

    if x is False:
        return False

    meta = wsd_common.xml_find(x, ".//mex:Metadata")
    meta_model = wsd_common.xml_find(
        meta, ".//mex:MetadataSection[@Dialect=\
                                     'http://schemas.xmlsoap.org/ws/2006/02/devprof/ThisModel']"
    )
    meta_dev = wsd_common.xml_find(
        meta, ".//mex:MetadataSection[@Dialect=\
                                   'http://schemas.xmlsoap.org/ws/2006/02/devprof/ThisDevice']"
    )
    meta_rel = wsd_common.xml_find(
        meta, ".//mex:MetadataSection[@Dialect=\
                                   'http://schemas.xmlsoap.org/ws/2006/02/devprof/Relationship']"
    )

    tinfo = wsd_transfer__structures.TargetInfo()
    # WSD-Profiles section 5.1 (+ PNP-X)
    tinfo.manufacturer = wsd_common.xml_find(meta_model,
                                             ".//wsdp:Manufacturer").text
    q = wsd_common.xml_find(meta_model, ".//wsdp:ManufacturerUrl")
    if q is not None:
        tinfo.manufacturer_url = q.text
    tinfo.model_name = wsd_common.xml_find(meta_model,
                                           ".//wsdp:ModelName").text
    q = wsd_common.xml_find(meta_model, ".//wsdp:ModelNumber")
    if q is not None:
        tinfo.model_number = q.text
    q = wsd_common.xml_find(meta_model, ".//wsdp:ModelUrl")
    if q is not None:
        tinfo.model_url = q.text
    q = wsd_common.xml_find(meta_model, ".//wsdp:PresentationUrl")
    if q is not None:
        tinfo.presentation_url = q.text
    tinfo.device_cat = wsd_common.xml_find(
        meta_model, ".//pnpx:DeviceCategory").text.split()

    tinfo.friendly_name = wsd_common.xml_find(meta_dev,
                                              ".//wsdp:FriendlyName").text
    tinfo.fw_ver = wsd_common.xml_find(meta_dev,
                                       ".//wsdp:FirmwareVersion").text
    tinfo.serial_num = wsd_common.xml_find(meta_dev,
                                           ".//wsdp:SerialNumber").text

    hservices = []
    # WSD-Profiles section 5.2 (+ PNP-X)
    wsd_common.xml_findall(
        meta_rel,
        ".//wsdp:Relationship[@Type='http://schemas.xmlsoap.org/ws/2006/02/devprof/host']"
    )

    for r in meta_rel:
        # UNCLEAR how the host item should differ from the target endpoint, and how to manage multiple host items
        # TBD - need some real-case examples
        # host = xml_find(r, ".//wsdp:Host")
        # if host is not None:    #"if omitted, implies the same endpoint reference of the targeted service"
        #    xml_find(host, ".//wsdp:Types").text
        #    xml_find(host, ".//wsdp:ServiceId").text
        #    er = xml_find(host, ".//wsa:EndpointReference")
        #    xml_find(er, ".//wsa:Address").text  #Optional endpoint fields not implemented yet
        hosted = wsd_common.xml_findall(r, ".//wsdp:Hosted")
        for h in hosted:
            hs = wsd_transfer__structures.HostedService()
            hs.types = wsd_common.xml_find(h, ".//wsdp:Types").text.split()
            hs.service_id = wsd_common.xml_find(h, ".//wsdp:ServiceId").text
            q = wsd_common.xml_find(h, ".//pnpx:HardwareId")
            if q is not None:
                hs.hardware_id = q.text
            q = wsd_common.xml_find(h, ".//pnpx:CompatibleId")
            if q is not None:
                hs.compatible_id = q.text
            q = wsd_common.xml_find(h, ".//wsdp:ServiceAddress")
            if q is not None:
                hs.service_address = q.text
            er = wsd_common.xml_find(h, ".//wsa:EndpointReference")
            hs.ep_ref_addr = wsd_common.xml_find(er, ".//wsa:Address").text
            hservices.append(hs)

    # WSD-Profiles section 5.3 and 5.4 omitted
    return tinfo, hservices
Exemplo n.º 27
0
def wsd_retrieve_image(hosted_scan_service: wsd_transfer__structures.HostedService,
                       job: wsd_scan__structures.ScanJob,
                       docname: str) \
        -> typing.Tuple[int, typing.List[Image.Image]]:
    """
    Submit a RetrieveImage request, and parse the response.
    Retrieves a single image from the scanner, if the job has available images to send. If the file format
    selected in the scan ticket was multipage, retrieves a batch of images instead.
    Usually the client has approx. 60 seconds to start images acquisition after the creation of a job.

    :param hosted_scan_service: the wsd scan service to query
    :type hosted_scan_service: wsd_transfer__structures.HostedService
    :param job: the ScanJob instance representing the queried job.
    :type job: wsd_scan__structures.ScanJob
    :param docname: the name assigned to the image to retrieve.
    :type docname: str
    :return: the number of images retrieved, and an array of images
    :rtype: (int, list[PIL.Image])
    """

    data = wsd_common.message_from_file(
        wsd_common.abs_path("../templates/ws-scan__retrieve_image.xml"),
        FROM=wsd_globals.urn,
        TO=hosted_scan_service.ep_ref_addr,
        JOB_ID=job.id,
        JOB_TOKEN=job.token,
        DOC_DESCR=docname)

    if wsd_globals.debug:
        r = etree.fromstring(data.encode("ASCII"), parser=wsd_common.parser)
        print('##\n## RETRIEVE IMAGE REQUEST\n##\n')
        print(
            etree.tostring(r, pretty_print=True,
                           xml_declaration=True).decode("ASCII"))

    r = requests.post(hosted_scan_service.ep_ref_addr,
                      headers=wsd_common.headers,
                      data=data)

    try:
        x = etree.fromstring(r.text)
        q = wsd_common.xml_find(x, ".//soap:Fault")
        if q is not None:
            e = wsd_common.xml_find(
                q, ".//soap:Code/soap:Subcode/soap:Value").text
            if e == "wscn:ClientErrorNoImagesAvailable":
                return 0, []
    except etree.ParseError:
        content_with_header = b'Content-type: ' + r.headers[
            'Content-Type'].encode('ascii') + r.content
        m = email.message_from_bytes(content_with_header)

        ls = list(m.walk())

        if wsd_globals.debug:
            print('##\n## RETRIEVE IMAGE RESPONSE\n##\n%s\n' % ls[1])

        img = Image.open(BytesIO(ls[2].get_payload(decode=True)))
        print("%s %s %s" % (img.format, img.size, img.mode))

        count = 0
        imglist = []

        for page in ImageSequence.Iterator(img):
            count += 1
            a = Image.new(page.mode, page.size)
            a.putdata(page.getdata())
            imglist.append(a)

        return count, imglist
Exemplo n.º 28
0
def parse_scan_configuration(sca_config):
    config = wsd_scan__structures.ScannerConfiguration()
    ds = wsd_common.xml_find(sca_config, ".//sca:DeviceSettings")
    pla = wsd_common.xml_find(sca_config, ".//sca:Platen")
    adf = wsd_common.xml_find(sca_config, ".//sca:ADF")
    # .//sca:Film omitted

    s = wsd_scan__structures.ScannerSettings()
    q = wsd_common.xml_findall(ds, ".//sca:FormatsSupported/sca:FormatValue")
    s.formats = [x.text for x in q]
    v1 = wsd_common.xml_find(
        ds, ".//sca:CompressionQualityFactorSupported/sca:MinValue")
    v2 = wsd_common.xml_find(
        ds, ".//sca:CompressionQualityFactorSupported/sca:MaxValue")
    s.compression_factor = (int(v1.text), int(v2.text))
    q = wsd_common.xml_findall(
        ds, ".//sca:ContentTypesSupported/sca:ContentTypeValue")
    s.content_types = [x.text for x in q]
    q = wsd_common.xml_find(ds, ".//sca:DocumentSizeAutoDetectSupported")
    s.size_autodetect_sup = True if q.text == 'true' or q.text == '1' else False
    q = wsd_common.xml_find(ds, ".//sca:AutoExposureSupported")
    s.auto_exposure_sup = True if q.text == 'true' or q.text == '1' else False
    q = wsd_common.xml_find(ds, ".//sca:BrightnessSupported")
    s.brightness_sup = True if q.text == 'true' or q.text == '1' else False
    q = wsd_common.xml_find(ds, ".//sca:ContrastSupported")
    s.contrast_sup = True if q.text == 'true' or q.text == '1' else False
    v1 = wsd_common.xml_find(
        ds, ".//sca:ScalingRangeSupported/sca:ScalingWidth/sca:MinValue")
    v2 = wsd_common.xml_find(
        ds, ".//sca:ScalingRangeSupported/sca:ScalingWidth/sca:MaxValue")
    s.scaling_range_w = (int(v1.text), int(v2.text))
    v1 = wsd_common.xml_find(
        ds, ".//sca:ScalingRangeSupported/sca:ScalingHeight/sca:MinValue")
    v2 = wsd_common.xml_find(
        ds, ".//sca:ScalingRangeSupported/sca:ScalingHeight/sca:MaxValue")
    s.scaling_range_h = (int(v1.text), int(v2.text))
    q = wsd_common.xml_findall(ds,
                               ".//sca:RotationsSupported/sca:RotationValue")
    s.rotations = [x.text for x in q]
    config.settings = s
    if pla is not None:
        config.platen = parse_scanner_source_settings(pla, "Platen")
    if adf is not None:
        q = wsd_common.xml_find(adf, ".//sca:ADFSupportsDuplex")
        config.adf_duplex = True if q.text == 'true' or q.text == '1' else False
        f = wsd_common.xml_find(adf, ".//sca:ADFFront")
        bk = wsd_common.xml_find(adf, ".//sca:ADFBack")
        if f is not None:
            config.front_adf = parse_scanner_source_settings(f, "ADF")
        if bk is not None:
            config.back_adf = parse_scanner_source_settings(bk, "ADF")
    return config
Exemplo n.º 29
0
def parse_document_params(dps):
    dest = wsd_scan__structures.DocumentParams()
    q = wsd_common.xml_find(dps, ".//sca:Format")
    if q is not None:
        dest.format = q.text
    q = wsd_common.xml_find(dps, ".//sca:CompressionQualityFactor")
    if q is not None:
        dest.compression_factor = q.text
    q = wsd_common.xml_find(dps, ".//sca:ImagesToTransfer")
    if q is not None:
        dest.images_num = int(q.text)
    q = wsd_common.xml_find(dps, ".//sca:InputSource")
    if q is not None:
        dest.input_src = q.text
    q = wsd_common.xml_find(dps, ".//sca:ContentType")
    if q is not None:
        dest.content_type = q.text
    q = wsd_common.xml_find(dps, ".//sca:InputSize")
    if q is not None:
        autod = wsd_common.xml_find(q, ".//sca:DocumentAutoDetect")
        if autod is not None:
            dest.size_autodetect = True if autod.text == 'true' or autod.text == '1' else False
        v1 = wsd_common.xml_find(q, ".//sca:InputMediaSize/sca:Width")
        v2 = wsd_common.xml_find(q, ".//sca:InputMediaSize/sca:Height")
        dest.input_size = (int(v1.text), int(v2.text))
    q = wsd_common.xml_find(dps, ".//sca:Exposure")
    if q is not None:
        autod = wsd_common.xml_find(q, ".//sca:AutoExposure")
        if autod is not None:
            dest.auto_exposure = True if autod.text == 'true' or autod.text == '1' else False
        dest.contrast = int(
            wsd_common.xml_find(q,
                                ".//sca:ExposureSettings/sca:Contrast").text)
        dest.brightness = int(
            wsd_common.xml_find(q,
                                ".//sca:ExposureSettings/sca:Brightness").text)
        dest.sharpness = int(
            wsd_common.xml_find(q,
                                ".//sca:ExposureSettings/sca:Sharpness").text)
    q = wsd_common.xml_find(dps, ".//sca:Scaling")
    if q is not None:
        v1 = wsd_common.xml_find(q, ".//sca:ScalingWidth")
        v2 = wsd_common.xml_find(q, ".//sca:ScalingHeight")
        dest.scaling = (int(v1.text), int(v2.text))
    q = wsd_common.xml_find(dps, ".//sca:Rotation")
    if q is not None:
        dest.rotation = int(q.text)
    q = wsd_common.xml_find(dps, ".//sca:MediaSides")
    if q is not None:
        f = wsd_common.xml_find(q, ".//sca:MediaFront")
        dest.front = parse_media_side(f)

        f = wsd_common.xml_find(q, ".//sca:MediaBack")
        if f is not None:
            dest.back = parse_media_side(f)
        else:
            dest.back = copy.deepcopy(dest.front)
    return dest
Exemplo n.º 30
0
def parse_scan_job(x):
    scnj = wsd_scan__structures.ScanJob()
    scnj.id = int(wsd_common.xml_find(x, ".//sca:JobId").text)
    scnj.token = wsd_common.xml_find(x, ".//sca:JobToken").text
    q = wsd_common.xml_find(x,
                            ".//sca:ImageInformation/sca:MediaFrontImageInfo")
    scnj.f_pixel_line = int(wsd_common.xml_find(q, "sca:PixelsPerLine").text)
    scnj.f_num_lines = int(wsd_common.xml_find(q, "sca:NumberOfLines").text)
    scnj.f_byte_line = int(wsd_common.xml_find(q, "sca:BytesPerLine").text)
    q = wsd_common.xml_find(x,
                            ".//sca:ImageInformation/sca:MediaBackImageInfo")
    if q is not None:
        scnj.b_pixel_line = int(
            wsd_common.xml_find(q, "sca:PixelsPerLine").text)
        scnj.b_num_lines = int(
            wsd_common.xml_find(q, "sca:NumberOfLines").text)
        scnj.b_byte_line = int(wsd_common.xml_find(q, "sca:BytesPerLine").text)
    dpf = wsd_common.xml_find(x, ".//sca:DocumentFinalParameters")
    scnj.doc_params = parse_document_params(dpf)
    return scnj