[ Avaa Bypassed ]




Upload:

Command:

www-data@3.21.104.216: ~ $
# -*- coding: utf-8 -*-
#
# (c) Copyright 2003-2015 HP Development Company, L.P.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
#
# Author: Don Welch, Narla Naga Samrat Chowdary, Yashwant Kumar Sahu
#



# Std Lib
import struct
import io
from .sixext import BytesIO, to_bytes_utf8, to_bytes_latin, to_string_latin, to_long

from .g import *
import xml.parsers.expat as expat
import re
import cupsext

try:
    from xml.etree import ElementTree
    etree_loaded = True
except ImportError:
    try:
        from elementtree.ElementTree import XML
        elementtree_loaded = True
    except ImportError:
        elementtree_loaded = False
    etree_loaded = False

# Local
from .g import *
from .codes import *
from . import pml, utils
import hpmudext
"""
status dict structure:
    { 'revision' :     STATUS_REV_00 .. STATUS_REV_04,
      'agents' :       [ list of pens/agents/supplies (dicts) ],
      'top-door' :     TOP_DOOR_NOT_PRESENT | TOP_DOOR_CLOSED | TOP_DOOR_OPEN,
      'status-code' :  STATUS_...,
      'supply-door' :  SUPPLY_DOOR_NOT_PRESENT | SUPPLY_DOOR_CLOSED | SUPPLY_DOOR_OPEN.
      'duplexer' :     DUPLEXER_NOT_PRESENT | DUPLEXER_DOOR_CLOSED | DUPLEXER_DOOR_OPEN,
      'photo_tray' :   PHOTO_TRAY_NOT_PRESENT | PHOTO_TRAY_ENGAGED | PHOTO_TRAY_NOT_ENGAGED,
      'in-tray1' :     IN_TRAY_NOT_PRESENT | IN_TRAY_CLOSED | IN_TRAY_OPEN (| IN_TRAY_DEFAULT | IN_TRAY_LOCKED)*,
      'in-tray2' :     IN_TRAY_NOT_PRESENT | IN_TRAY_CLOSED | IN_TRAY_OPEN (| IN_TRAY_DEFAULT | IN_TRAY_LOCKED)*,
      'media-path' :   MEDIA_PATH_NOT_PRESENT | MEDIA_PATH_CUT_SHEET | MEDIA_PATH_BANNER | MEDIA_PATH_PHOTO,
    }

    * S:02 only

agent dict structure: (pens/supplies/agents/etc)
    { 'kind' :           AGENT_KIND_NONE ... AGENT_KIND_ADF_KIT,
      'type' :           TYPE_BLACK ... AGENT_TYPE_UNSPECIFIED,      # aka color
      'health' :         AGENT_HEALTH_OK ... AGENT_HEALTH_UNKNOWN,
      'level' :          0 ... 100,
      'level-trigger' :  AGENT_LEVEL_TRIGGER_SUFFICIENT_0 ... AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
    }
"""



# 'revision'
STATUS_REV_00 = 0x00
STATUS_REV_01 = 0x01
STATUS_REV_02 = 0x02
STATUS_REV_03 = 0x03
STATUS_REV_04 = 0x04
STATUS_REV_V  = 0xff
STATUS_REV_UNKNOWN = 0xfe

vstatus_xlate  = {'busy' : STATUS_PRINTER_BUSY,
                   'idle' : STATUS_PRINTER_IDLE,
                   'prnt' : STATUS_PRINTER_PRINTING,
                   'offf' : STATUS_PRINTER_TURNING_OFF,
                   'rprt' : STATUS_PRINTER_REPORT_PRINTING,
                   'cncl' : STATUS_PRINTER_CANCELING,
                   'iost' : STATUS_PRINTER_IO_STALL,
                   'dryw' : STATUS_PRINTER_DRY_WAIT_TIME,
                   'penc' : STATUS_PRINTER_PEN_CHANGE,
                   'oopa' : STATUS_PRINTER_OUT_OF_PAPER,
                   'bnej' : STATUS_PRINTER_BANNER_EJECT,
                   'bnmz' : STATUS_PRINTER_BANNER_MISMATCH,
                   'phmz' : STATUS_PRINTER_PHOTO_MISMATCH,
                   'dpmz' : STATUS_PRINTER_DUPLEX_MISMATCH,
                   'pajm' : STATUS_PRINTER_MEDIA_JAM,
                   'cars' : STATUS_PRINTER_CARRIAGE_STALL,
                   'paps' : STATUS_PRINTER_PAPER_STALL,
                   'penf' : STATUS_PRINTER_PEN_FAILURE,
                   'erro' : STATUS_PRINTER_HARD_ERROR,
                   'pwdn' : STATUS_PRINTER_POWER_DOWN,
                   'fpts' : STATUS_PRINTER_FRONT_PANEL_TEST,
                   'clno' : STATUS_PRINTER_CLEAN_OUT_TRAY_MISSING}

REVISION_2_TYPE_MAP = {0 : AGENT_TYPE_NONE,
                        1 : AGENT_TYPE_BLACK,
                        2 : AGENT_TYPE_CYAN,
                        3 : AGENT_TYPE_MAGENTA,
                        4 : AGENT_TYPE_YELLOW,
                        5 : AGENT_TYPE_BLACK,
                        6 : AGENT_TYPE_CYAN,
                        7 : AGENT_TYPE_MAGENTA,
                        8 : AGENT_TYPE_YELLOW,
                       }

STATUS_BLOCK_UNKNOWN = {'revision' : STATUS_REV_UNKNOWN,
                         'agents' : [],
                         'status-code' : STATUS_UNKNOWN,
                       }

NUM_PEN_POS = {STATUS_REV_00 : 16,
                STATUS_REV_01 : 16,
                STATUS_REV_02 : 16,
                STATUS_REV_03 : 18,
                STATUS_REV_04 : 22}

PEN_DATA_SIZE = {STATUS_REV_00 : 8,
                  STATUS_REV_01 : 8,
                  STATUS_REV_02 : 4,
                  STATUS_REV_03 : 8,
                  STATUS_REV_04 : 8}

STATUS_POS = {STATUS_REV_00 : 14,
               STATUS_REV_01 : 14,
               STATUS_REV_02 : 14,
               STATUS_REV_03 : 16,
               STATUS_REV_04 : 20}

def parseSStatus(s, z=''):
    revision = ''
    pens = []
    top_door = TOP_DOOR_NOT_PRESENT
    stat = STATUS_UNKNOWN
    supply_door = SUPPLY_DOOR_NOT_PRESENT
    duplexer = DUPLEXER_NOT_PRESENT
    photo_tray = PHOTO_TRAY_NOT_PRESENT
    in_tray1 = IN_TRAY_NOT_PRESENT
    in_tray2 = IN_TRAY_NOT_PRESENT
    media_path = MEDIA_PATH_NOT_PRESENT
    Z_SIZE = 6

    try:
        z1 = []
        if len(z) > 0:
            z_fields = z.split(',')

            for z_field in z_fields:

                if len(z_field) > 2 and z_field[:2] == '05':
                    z1s = z_field[2:]
                    z1 = [int(x, 16) for x in z1s]

        s1 = [int(x, 16) for x in s]

        revision = s1[1]

        assert STATUS_REV_00 <= revision <= STATUS_REV_04

        top_door = bool(s1[2] & to_long(0x8)) + s1[2] & to_long(0x1)
        supply_door = bool(s1[3] & to_long(0x8)) + s1[3] & to_long(0x1)
        duplexer = bool(s1[4] & to_long(0xc)) +  s1[4] & to_long(0x1)
        photo_tray = bool(s1[5] & 0x8) + s1[5] & 0x1

        if revision == STATUS_REV_02:
            in_tray1 = bool(s1[6] & to_long(0x8)) + s1[6] & to_long(0x1)
            in_tray2 = bool(s1[7] & to_long(0x8)) + s1[7] & to_long(0x1)
        else:
            in_tray1 = bool(s1[6] & to_long(0x8))
            in_tray2 = bool(s1[7] & to_long(0x8))

        media_path = bool(s1[8] & to_long(0x8)) + (s1[8] & to_long(0x1)) + ((bool(s1[18] & to_long(0x2)))<<1)
        status_pos = STATUS_POS[revision]
        status_byte = s1[status_pos]<<4
        if status_byte != 48:
            status_byte = (s1[status_pos]<<4) + s1[status_pos + 1]
        stat = status_byte + STATUS_PRINTER_BASE

        pen, c, d = {}, NUM_PEN_POS[revision]+1, 0
        num_pens = s1[NUM_PEN_POS[revision]]
        index = 0
        pen_data_size = PEN_DATA_SIZE[revision]

        log.debug("num_pens = %d" % num_pens)
        for p in range(num_pens):
            info = int(s[c : c + pen_data_size], 16)

            pen['index'] = index

            if pen_data_size == 4:
                pen['type'] = REVISION_2_TYPE_MAP.get(int((info & to_long(0xf000)) >> to_long(12)), 0)

                if index < (num_pens / 2):
                    pen['kind'] = AGENT_KIND_HEAD
                else:
                    pen['kind'] = AGENT_KIND_SUPPLY

                pen['level-trigger'] = int ((info & to_long(0x0e00)) >> to_long(9))
                pen['health'] = int((info & to_long(0x0180)) >> to_long(7))
                pen['level'] = int(info & to_long(0x007f))
                pen['id'] = 0x1f

            elif pen_data_size == 8:
                pen['kind'] = bool(info & to_long(0x80000000)) + ((bool(info & to_long(0x40000000)))<<to_long(1))
                pen['type'] = int((info & to_long(0x3f000000)) >> to_long(24))
                pen['id'] = int((info & 0xf80000) >> to_long(19))
                pen['level-trigger'] = int((info & to_long(0x70000)) >> to_long(16))
                pen['health'] = int((info & to_long(0xc000)) >> to_long(14))
                pen['level'] = int(info & to_long(0xff))

            else:
                log.error("Pen data size error")

            if len(z1) > 0:
                # TODO: Determine cause of IndexError for C6100 (defect #1111)
                try:
                    pen['dvc'] = int(z1s[d+1:d+5], 16)
                    pen['virgin'] = bool(z1[d+5] & to_long(0x8))
                    pen['hp-ink'] = bool(z1[d+5] & to_long(0x4))
                    pen['known'] = bool(z1[d+5] & to_long(0x2))
                    pen['ack'] = bool(z1[d+5] & to_long(0x1))
                except IndexError:
                    pen['dvc'] = 0
                    pen['virgin'] = 0
                    pen['hp-ink'] = 0
                    pen['known'] = 0
                    pen['ack'] = 0

            log.debug("pen %d %s" % (index, pen))

            index += 1
            pens.append(pen)
            pen = {}
            c += pen_data_size
            d += Z_SIZE

    except (IndexError, ValueError, TypeError) as e:
        log.warn("Status parsing error: %s" % str(e))

    return {'revision' :    revision,
             'agents' :      pens,
             'top-door' :    top_door,
             'status-code' : stat,
             'supply-door' : supply_door,
             'duplexer' :    duplexer,
             'photo-tray' :  photo_tray,
             'in-tray1' :    in_tray1,
             'in-tray2' :    in_tray2,
             'media-path' :  media_path,
           }



# $HB0$NC0,ff,DN,IDLE,CUT,K0,C0,DP,NR,KP092,CP041
#     0    1  2  3    4   5  6  7  8  9     10
def parseVStatus(s):
    pens, pen, c = [], {}, 0
    fields = s.split(',')
    log.debug(fields)
    f0 = fields[0]

    if len(f0) == 20:
        # TODO: $H00000000$M00000000 style (OJ Pro 1150/70)
        # Need spec
        pass
    elif len(f0) == 8:
        for p in f0:
            if c == 0:
                #assert p == '$'
                c += 1
            elif c == 1:
                if p in ('a', 'A'):
                    pen['type'], pen['kind'] = AGENT_TYPE_NONE, AGENT_KIND_NONE
                c += 1
            elif c == 2:
                pen['health'] = AGENT_HEALTH_OK
                pen['kind'] = AGENT_KIND_HEAD_AND_SUPPLY
                if   p in ('b', 'B'): pen['type'] = AGENT_TYPE_BLACK
                elif p in ('c', 'C'): pen['type'] = AGENT_TYPE_CMY
                elif p in ('d', 'D'): pen['type'] = AGENT_TYPE_KCM
                elif p in ('u', 'U'): pen['type'], pen['health'] = AGENT_TYPE_NONE, AGENT_HEALTH_MISINSTALLED
                c += 1
            elif c == 3:
                if p == '0': pen['state'] = 1
                else: pen['state'] = 0

                pen['level'] = 0
                i = 8

                while True:
                    try:
                        f = fields[i]
                    except IndexError:
                        break
                    else:
                        if f[:2] == 'KP' and pen['type'] == AGENT_TYPE_BLACK:
                            pen['level'] = int(f[2:])
                        elif f[:2] == 'CP' and pen['type'] == AGENT_TYPE_CMY:
                            pen['level'] = int(f[2:])
                    i += 1

                pens.append(pen)
                pen = {}
                c = 0
    else:
        pass

    try:
        fields[2]
    except IndexError:
        top_lid = 1 # something went wrong!
    else:
        if fields[2] == 'DN':
            top_lid = 1
        else:
            top_lid = 2

    try:
        stat = vstatus_xlate.get(fields[3].lower(), STATUS_PRINTER_IDLE)
    except IndexError:
        stat = STATUS_PRINTER_IDLE # something went wrong!

    return {'revision' :   STATUS_REV_V,
             'agents' :     pens,
             'top-door' :   top_lid,
             'status-code': stat,
             'supply-door': SUPPLY_DOOR_NOT_PRESENT,
             'duplexer' :   DUPLEXER_NOT_PRESENT,
             'photo-tray' : PHOTO_TRAY_NOT_PRESENT,
             'in-tray1' :   IN_TRAY_NOT_PRESENT,
             'in-tray2' :   IN_TRAY_NOT_PRESENT,
             'media-path' : MEDIA_PATH_CUT_SHEET, # ?
           }


def parseStatus(DeviceID):
    if 'VSTATUS' in DeviceID:
         return parseVStatus(DeviceID['VSTATUS'])
    elif 'S' in DeviceID:
        return parseSStatus(DeviceID['S'], DeviceID.get('Z', ''))
    else:
        return STATUS_BLOCK_UNKNOWN

def LaserJetDeviceStatusToPrinterStatus(device_status, printer_status, detected_error_state):
    stat = STATUS_PRINTER_IDLE

    if device_status in (pml.DEVICE_STATUS_WARNING, pml.DEVICE_STATUS_DOWN):

        if detected_error_state & pml.DETECTED_ERROR_STATE_LOW_PAPER_MASK and \
            not (detected_error_state & pml.DETECTED_ERROR_STATE_NO_PAPER_MASK):
            stat = STATUS_PRINTER_LOW_PAPER

        elif detected_error_state & pml.DETECTED_ERROR_STATE_NO_PAPER_MASK:
            stat = STATUS_PRINTER_OUT_OF_PAPER

        elif detected_error_state & pml.DETECTED_ERROR_STATE_DOOR_OPEN_MASK:
            stat = STATUS_PRINTER_DOOR_OPEN

        elif detected_error_state & pml.DETECTED_ERROR_STATE_JAMMED_MASK:
            stat = STATUS_PRINTER_MEDIA_JAM

        elif detected_error_state & pml.DETECTED_ERROR_STATE_OUT_CART_MASK:
            stat = STATUS_PRINTER_NO_TONER

        elif detected_error_state & pml.DETECTED_ERROR_STATE_LOW_CART_MASK:
            stat = STATUS_PRINTER_LOW_TONER

        elif detected_error_state == pml.DETECTED_ERROR_STATE_SERVICE_REQUEST_MASK:
            stat = STATUS_PRINTER_SERVICE_REQUEST

        elif detected_error_state & pml.DETECTED_ERROR_STATE_OFFLINE_MASK:
            stat = STATUS_PRINTER_OFFLINE

    else:

        if printer_status == pml.PRINTER_STATUS_IDLE:
            stat = STATUS_PRINTER_IDLE

        elif printer_status == pml.PRINTER_STATUS_PRINTING:
            stat = STATUS_PRINTER_PRINTING

        elif printer_status == pml.PRINTER_STATUS_WARMUP:
            stat = STATUS_PRINTER_WARMING_UP

    return stat

# Map from ISO 10175/10180 to HPLIP types
COLORANT_INDEX_TO_AGENT_TYPE_MAP = {
                                    'other' :   AGENT_TYPE_UNSPECIFIED,
                                    'unknown' : AGENT_TYPE_UNSPECIFIED,
                                    'blue' :    AGENT_TYPE_BLUE,
                                    'cyan' :    AGENT_TYPE_CYAN,
                                    'magenta':  AGENT_TYPE_MAGENTA,
                                    'yellow' :  AGENT_TYPE_YELLOW,
                                    'black' :   AGENT_TYPE_BLACK,
                                    'photoblack': AGENT_TYPE_PHOTO_BLACK,
                                    'matteblack' : AGENT_TYPE_MATTE_BLACK,
                                    'lightgray' : AGENT_TYPE_LG,
                                    'gray': AGENT_TYPE_G,
                                    'darkgray': AGENT_TYPE_DG,
                                    'lightcyan': AGENT_TYPE_LC,
                                    'lightmagenta': AGENT_TYPE_LM,
                                    'red' : AGENT_TYPE_RED,
                                   }

MARKER_SUPPLES_TYPE_TO_AGENT_KIND_MAP = {
    pml.OID_MARKER_SUPPLIES_TYPE_OTHER :              AGENT_KIND_UNKNOWN,
    pml.OID_MARKER_SUPPLIES_TYPE_UNKNOWN :            AGENT_KIND_UNKNOWN,
    pml.OID_MARKER_SUPPLIES_TYPE_TONER :              AGENT_KIND_TONER_CARTRIDGE,
    pml.OID_MARKER_SUPPLIES_TYPE_WASTE_TONER :        AGENT_KIND_UNKNOWN,
    pml.OID_MARKER_SUPPLIES_TYPE_INK :                AGENT_KIND_SUPPLY,
    pml.OID_MARKER_SUPPLIES_TYPE_INK_CART :           AGENT_KIND_HEAD_AND_SUPPLY,
    pml.OID_MARKER_SUPPLIES_TYPE_INK_RIBBON :         AGENT_KIND_HEAD_AND_SUPPLY,
    pml.OID_MARKER_SUPPLIES_TYPE_WASTE_INK :          AGENT_KIND_UNKNOWN,
    pml.OID_MARKER_SUPPLIES_TYPE_OPC :                AGENT_KIND_DRUM_KIT,
    pml.OID_MARKER_SUPPLIES_TYPE_DEVELOPER :          AGENT_KIND_UNKNOWN,
    pml.OID_MARKER_SUPPLIES_TYPE_FUSER_OIL :          AGENT_KIND_UNKNOWN,
    pml.OID_MARKER_SUPPLIES_TYPE_SOLID_WAX :          AGENT_KIND_UNKNOWN,
    pml.OID_MARKER_SUPPLIES_TYPE_RIBBON_WAX :         AGENT_KIND_UNKNOWN,
    pml.OID_MARKER_SUPPLIES_TYPE_WASTE_WAX :          AGENT_KIND_UNKNOWN,
    pml.OID_MARKER_SUPPLIES_TYPE_FUSER :              AGENT_KIND_MAINT_KIT,
    pml.OID_MARKER_SUPPLIES_TYPE_CORONA_WIRE :        AGENT_KIND_UNKNOWN,
    pml.OID_MARKER_SUPPLIES_TYPE_FUSER_OIL_WICK :     AGENT_KIND_UNKNOWN,
    pml.OID_MARKER_SUPPLIES_TYPE_CLEANER_UNIT :       AGENT_KIND_UNKNOWN,
    pml.OID_MARKER_SUPPLIES_TYPE_FUSER_CLEANING_PAD : AGENT_KIND_UNKNOWN,
    pml.OID_MARKER_SUPPLIES_TYPE_TRANSFER_UNIT :      AGENT_KIND_TRANSFER_KIT,
    pml.OID_MARKER_SUPPLIES_TYPE_TONER_CART :         AGENT_KIND_TONER_CARTRIDGE,
    pml.OID_MARKER_SUPPLIES_TYPE_FUSER_OILER :        AGENT_KIND_UNKNOWN,
    pml.OID_MARKER_SUPPLIES_TYPE_ADF_MAINT_KIT :      AGENT_KIND_ADF_KIT,
}


def StatusType3( dev, parsedID ): # LaserJet Status (PML/SNMP)
    try:
        dev.openPML()
        #result_code, on_off_line = dev.getPML( pml.OID_ON_OFF_LINE, pml.INT_SIZE_BYTE )
        #result_code, sleep_mode = dev.getPML( pml.OID_SLEEP_MODE, pml.INT_SIZE_BYTE )
        result_code, printer_status = dev.getPML( pml.OID_PRINTER_STATUS, pml.INT_SIZE_BYTE )
        result_code, device_status = dev.getPML( pml.OID_DEVICE_STATUS, pml.INT_SIZE_BYTE )
        result_code, cover_status = dev.getPML( pml.OID_COVER_STATUS, pml.INT_SIZE_BYTE )
        result_code, value = dev.getPML( pml.OID_DETECTED_ERROR_STATE )
    except Error:
       dev.closePML()

       return {'revision' :    STATUS_REV_UNKNOWN,
                 'agents' :      [],
                 'top-door' :    0,
                 'status-code' : STATUS_UNKNOWN,
                 'supply-door' : 0,
                 'duplexer' :    1,
                 'photo-tray' :  0,
                 'in-tray1' :    0,
                 'in-tray2' :    0,
                 'media-path' :  0,
               }

    try:
        detected_error_state = struct.unpack( 'B', to_bytes_latin(value[0]))[0]
    except (IndexError, TypeError):
        detected_error_state = pml.DETECTED_ERROR_STATE_OFFLINE_MASK

    agents, x = [], 1

    while True:
        log.debug( "%s Agent: %d %s" % ("*"*10, x, "*"*10))
        log.debug("OID_MARKER_SUPPLIES_TYPE_%d:" % x)
        oid = ( pml.OID_MARKER_SUPPLIES_TYPE_x % x, pml.OID_MARKER_SUPPLIES_TYPE_x_TYPE )
        result_code, value = dev.getPML( oid, pml.INT_SIZE_BYTE )

        if result_code != ERROR_SUCCESS or value is None:
            log.debug("End of supply information.")
            break

        for a in MARKER_SUPPLES_TYPE_TO_AGENT_KIND_MAP:
            if value == a:
                agent_kind = MARKER_SUPPLES_TYPE_TO_AGENT_KIND_MAP[a]
                break
        else:
            agent_kind = AGENT_KIND_UNKNOWN

        # TODO: Deal with printers that return -1 and -2 for level and max (LJ3380)

        log.debug("OID_MARKER_SUPPLIES_LEVEL_%d:" % x)
        oid = ( pml.OID_MARKER_SUPPLIES_LEVEL_x % x, pml.OID_MARKER_SUPPLIES_LEVEL_x_TYPE )
        result_code, agent_level = dev.getPML( oid )

        if result_code != ERROR_SUCCESS:
            log.debug("Failed")
            break

        log.debug( 'agent%d-level: %d' % ( x, agent_level ) )
        log.debug("OID_MARKER_SUPPLIES_MAX_%d:" % x)
        oid = ( pml.OID_MARKER_SUPPLIES_MAX_x % x, pml.OID_MARKER_SUPPLIES_MAX_x_TYPE )
        result_code, agent_max = dev.getPML( oid )

        if agent_max == 0: agent_max = 1

        if result_code != ERROR_SUCCESS:
            log.debug("Failed")
            break

        log.debug( 'agent%d-max: %d' % ( x, agent_max ) )
        log.debug("OID_MARKER_SUPPLIES_COLORANT_INDEX_%d:" % x)
        oid = ( pml.OID_MARKER_SUPPLIES_COLORANT_INDEX_x % x, pml.OID_MARKER_SUPPLIES_COLORANT_INDEX_x_TYPE )
        result_code, colorant_index = dev.getPML( oid )

        if result_code != ERROR_SUCCESS: # 3080, 3055 will fail here
            log.debug("Failed")
            agent_type = AGENT_TYPE_BLACK
            #break
        else:
            log.debug("Colorant index: %d" % colorant_index)

            log.debug("OID_MARKER_COLORANT_VALUE_%d" % x)
            oid = ( pml.OID_MARKER_COLORANT_VALUE_x % colorant_index, pml.OID_MARKER_COLORANT_VALUE_x_TYPE )
            result_code, colorant_value = dev.getPML( oid )

            if result_code != ERROR_SUCCESS:
                log.debug("Failed. Defaulting to black.")
                agent_type = AGENT_TYPE_BLACK
            #else:
            if 1:
                if agent_kind in (AGENT_KIND_MAINT_KIT, AGENT_KIND_ADF_KIT,
                                  AGENT_KIND_DRUM_KIT, AGENT_KIND_TRANSFER_KIT):

                    agent_type = AGENT_TYPE_UNSPECIFIED

                else:
                    agent_type = AGENT_TYPE_BLACK

                    if result_code != ERROR_SUCCESS:
                        log.debug("OID_MARKER_SUPPLIES_DESCRIPTION_%d:" % x)
                        oid = (pml.OID_MARKER_SUPPLIES_DESCRIPTION_x % x, pml.OID_MARKER_SUPPLIES_DESCRIPTION_x_TYPE)
                        result_code, colorant_value = dev.getPML( oid )

                        if result_code != ERROR_SUCCESS:
                            log.debug("Failed")
                            break

                        if colorant_value is not None:
                            log.debug("colorant value: %s" % colorant_value)
                            colorant_value = colorant_value.lower().strip()

                            for c in COLORANT_INDEX_TO_AGENT_TYPE_MAP:
                                if colorant_value.find(c) >= 0:
                                    agent_type = COLORANT_INDEX_TO_AGENT_TYPE_MAP[c]
                                    break
                            else:
                                agent_type = AGENT_TYPE_BLACK

                    else: # SUCCESS
                        if colorant_value is not None:
                            log.debug("colorant value: %s" % colorant_value)
                            colorant_value = colorant_value.lower().strip()
                            agent_type = COLORANT_INDEX_TO_AGENT_TYPE_MAP.get( colorant_value, AGENT_TYPE_BLACK )

                        if agent_type == AGENT_TYPE_NONE:
                            if agent_kind == AGENT_KIND_TONER_CARTRIDGE:
                                agent_type = AGENT_TYPE_BLACK
                            else:
                                agent_type = AGENT_TYPE_UNSPECIFIED

        log.debug("OID_MARKER_STATUS_%d:" % x)
        oid = ( pml.OID_MARKER_STATUS_x % x, pml.OID_MARKER_STATUS_x_TYPE )
        result_code, agent_status = dev.getPML( oid )

        if result_code != ERROR_SUCCESS:
            log.debug("Failed")
            agent_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
            agent_health = AGENT_HEALTH_OK
        else:
            agent_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0

            if agent_status is None:
                agent_health = AGENT_HEALTH_OK

            elif agent_status == pml.OID_MARKER_STATUS_OK:
                agent_health = AGENT_HEALTH_OK

            elif agent_status == pml.OID_MARKER_STATUS_MISINSTALLED:
                agent_health = AGENT_HEALTH_MISINSTALLED

            elif agent_status in ( pml.OID_MARKER_STATUS_LOW_TONER_CONT,
                                   pml.OID_MARKER_STATUS_LOW_TONER_STOP ):

                agent_health = AGENT_HEALTH_OK
                agent_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW

            else:
                agent_health = AGENT_HEALTH_OK

        agent_level = int(float(agent_level)/agent_max * 100)


        log.debug("agent%d: kind=%d, type=%d, health=%d, level=%d, level-trigger=%d" % \
            (x, agent_kind, agent_type, agent_health, agent_level, agent_trigger))


        agents.append({'kind' : agent_kind,
                       'type' : agent_type,
                       'health' : agent_health,
                       'level' : agent_level,
                       'level-trigger' : agent_trigger,})

        x += 1

        if x > 20:
            break


    printer_status = printer_status or STATUS_PRINTER_IDLE
    log.debug("printer_status=%d" % printer_status)
    device_status = device_status or pml.DEVICE_STATUS_RUNNING
    log.debug("device_status=%d" % device_status)
    cover_status = cover_status or pml.COVER_STATUS_CLOSED
    log.debug("cover_status=%d" % cover_status)
    detected_error_state = detected_error_state or pml.DETECTED_ERROR_STATE_NO_ERROR
    log.debug("detected_error_state=%d (0x%x)" % (detected_error_state, detected_error_state))

    stat = LaserJetDeviceStatusToPrinterStatus(device_status, printer_status, detected_error_state)

    log.debug("Printer status=%d" % stat)

    if stat == STATUS_PRINTER_DOOR_OPEN:
        supply_door = 0
    else:
        supply_door = 1

    return {'revision' :    STATUS_REV_UNKNOWN,
             'agents' :      agents,
             'top-door' :    cover_status,
             'status-code' : stat,
             'supply-door' : supply_door,
             'duplexer' :    1,
             'photo-tray' :  0,
             'in-tray1' :    1,
             'in-tray2' :    1,
             'media-path' :  1,
           }

def setup_panel_translator():
    printables = list(
"""0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~""")

    map = {}
    for x in [chr(x) for x in range(0,256)]:
        if x in printables:
            map[x] = x
        else:
            map[x] = '\x20'

    map.update({'\x10' : '\xab',
                    '\x11' : '\xbb',
                    '\x12' : '\xa3',
                    '\x13' : '\xbb',
                    '\x80' : '\xab',
                    '\x81' : '\xbb',
                    '\x82' : '\x2a',
                    '\x83' : '\x2a',
                    '\x85' : '\x2a',
                    '\xa0' : '\xab',
                    '\x1f' : '\x3f',
                    '='    : '\x20',
                })

    frm, to = to_bytes_latin(''), to_bytes_latin('')
    map_keys = list(map.keys())
    map_keys.sort()
    for x in map_keys:
        frm = to_bytes_latin('').join([frm, to_bytes_latin(x)])
        to = to_bytes_latin('').join([to, to_bytes_latin(map[x])])

    global PANEL_TRANSLATOR_FUNC
    PANEL_TRANSLATOR_FUNC = utils.Translator(frm, to)

PANEL_TRANSLATOR_FUNC = None
setup_panel_translator()


def PanelCheck(dev):
    line1, line2 = to_bytes_utf8(''), ('')

    if dev.io_mode not in (IO_MODE_RAW, IO_MODE_UNI):

        try:
            dev.openPML()
        except Error:
            pass
        else:

            oids = [(pml.OID_HP_LINE1, pml.OID_HP_LINE2),
                     (pml.OID_SPM_LINE1, pml.OID_SPM_LINE2)]

            for oid1, oid2 in oids:
                result, line1 = dev.getPML(oid1)

                if result < pml.ERROR_MAX_OK:
                    line1 = PANEL_TRANSLATOR_FUNC(line1.encode('utf-8')).rstrip()

                    if to_bytes_utf8('\x0a') in line1:
                        line1, line2 = line1.split(to_bytes_utf8('\x0a'), 1)
                        break

                    result, line2 = dev.getPML(oid2)

                    if result < pml.ERROR_MAX_OK:
                        line2 = PANEL_TRANSLATOR_FUNC(line2.encode('utf-8')).rstrip()
                        break

    return bool(line1 or line2), line1 or to_bytes_utf8(''), line2 or to_bytes_utf8('')


BATTERY_HEALTH_MAP = {0 : AGENT_HEALTH_OK,
                       1 : AGENT_HEALTH_OVERTEMP,
                       2 : AGENT_HEALTH_CHARGING,
                       3 : AGENT_HEALTH_MISINSTALLED,
                       4 : AGENT_HEALTH_FAILED,
                      }


BATTERY_TRIGGER_MAP = {0 : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
                        1 : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
                        2 : AGENT_LEVEL_TRIGGER_PROBABLY_OUT,
                        3 : AGENT_LEVEL_TRIGGER_SUFFICIENT_4,
                        4 : AGENT_LEVEL_TRIGGER_SUFFICIENT_2,
                        5 : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
                       }

BATTERY_PML_TRIGGER_MAP = {
        (100, 80)  : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
        (79,  60)  : AGENT_LEVEL_TRIGGER_SUFFICIENT_1,
        (59,  40)  : AGENT_LEVEL_TRIGGER_SUFFICIENT_2,
        (39,  30)  : AGENT_LEVEL_TRIGGER_SUFFICIENT_3,
        (29,  20)  : AGENT_LEVEL_TRIGGER_SUFFICIENT_4,
        (19,  10)  : AGENT_LEVEL_TRIGGER_MAY_BE_LOW,
        (9,    5)  : AGENT_LEVEL_TRIGGER_PROBABLY_OUT,
        (4,   -1)  : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
        }


def BatteryCheck(dev, status_block, battery_check):
    try_dynamic_counters = False

    try:
        try:
            dev.openPML()
        except Error:
            if battery_check == STATUS_BATTERY_CHECK_STD:
                log.debug("PML channel open failed. Trying dynamic counters...")
                try_dynamic_counters = True
        else:
            if battery_check == STATUS_BATTERY_CHECK_PML:
                result, battery_level = dev.getPML(pml.OID_BATTERY_LEVEL_2)

                if result > pml.ERROR_MAX_OK:
                    status_block['agents'].append({
                        'kind'   : AGENT_KIND_INT_BATTERY,
                        'type'   : AGENT_TYPE_UNSPECIFIED,
                        'health' : AGENT_HEALTH_UNKNOWN,
                        'level'  : 0,
                        'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
                        })
                    return

                else:
                    status_block['agents'].append({
                        'kind'   : AGENT_KIND_INT_BATTERY,
                        'type'   : AGENT_TYPE_UNSPECIFIED,
                        'health' : AGENT_HEALTH_OK,
                        'level'  : battery_level,
                        'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
                        })
                    return

            else: # STATUS_BATTERY_CHECK_STD
                result, battery_level = dev.getPML(pml.OID_BATTERY_LEVEL)
                result, power_mode =  dev.getPML(pml.OID_POWER_MODE)

                if battery_level is not None and \
                    power_mode is not None:

                    if power_mode & pml.POWER_MODE_BATTERY_LEVEL_KNOWN and \
                        battery_level >= 0:

                        for x in BATTERY_PML_TRIGGER_MAP:
                            if x[0] >= battery_level > x[1]:
                                battery_trigger_level = BATTERY_PML_TRIGGER_MAP[x]
                                break

                        if power_mode & pml.POWER_MODE_CHARGING:
                            agent_health = AGENT_HEALTH_CHARGING

                        elif power_mode & pml.POWER_MODE_DISCHARGING:
                            agent_health = AGENT_HEALTH_DISCHARGING

                        else:
                            agent_health = AGENT_HEALTH_OK

                        status_block['agents'].append({
                            'kind'   : AGENT_KIND_INT_BATTERY,
                            'type'   : AGENT_TYPE_UNSPECIFIED,
                            'health' : agent_health,
                            'level'  : battery_level,
                            'level-trigger' : battery_trigger_level,
                            })
                        return

                    else:
                        status_block['agents'].append({
                            'kind'   : AGENT_KIND_INT_BATTERY,
                            'type'   : AGENT_TYPE_UNSPECIFIED,
                            'health' : AGENT_HEALTH_UNKNOWN,
                            'level'  : 0,
                            'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
                            })
                        return

                else:
                    try_dynamic_counters = True

    finally:
        dev.closePML()


    if battery_check == STATUS_BATTERY_CHECK_STD and \
        try_dynamic_counters:

        try:
            try:
                battery_health = dev.getDynamicCounter(200)
                battery_trigger_level = dev.getDynamicCounter(201)
                battery_level = dev.getDynamicCounter(202)

                status_block['agents'].append({
                    'kind'   : AGENT_KIND_INT_BATTERY,
                    'type'   : AGENT_TYPE_UNSPECIFIED,
                    'health' : BATTERY_HEALTH_MAP[battery_health],
                    'level'  : battery_level,
                    'level-trigger' : BATTERY_TRIGGER_MAP[battery_trigger_level],
                    })
            except Error:
                status_block['agents'].append({
                    'kind'   : AGENT_KIND_INT_BATTERY,
                    'type'   : AGENT_TYPE_UNSPECIFIED,
                    'health' : AGENT_HEALTH_UNKNOWN,
                    'level'  : 0,
                    'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
                    })
        finally:
            dev.closePrint()

    else:
        status_block['agents'].append({
            'kind'   : AGENT_KIND_INT_BATTERY,
            'type'   : AGENT_TYPE_UNSPECIFIED,
            'health' : AGENT_HEALTH_UNKNOWN,
            'level'  : 0,
            'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
            })



# this works for 2 pen products that allow 1 or 2 pens inserted
# from: k, kcm, cmy, ggk
def getPenConfiguration(s): # s=status dict from parsed device ID
    pens = [p['type'] for p in s['agents']]

    if utils.all(pens, lambda x : x==AGENT_TYPE_NONE):
        return AGENT_CONFIG_NONE

    if AGENT_TYPE_NONE in pens:

        if AGENT_TYPE_BLACK in pens:
            return AGENT_CONFIG_BLACK_ONLY

        elif AGENT_TYPE_CMY in pens:
            return AGENT_CONFIG_COLOR_ONLY

        elif AGENT_TYPE_KCM in pens:
            return AGENT_CONFIG_PHOTO_ONLY

        elif AGENT_TYPE_GGK in pens:
            return AGENT_CONFIG_GREY_ONLY

        else:
            return AGENT_CONFIG_INVALID

    else:
        if AGENT_TYPE_BLACK in pens and AGENT_TYPE_CMY in pens:
            return AGENT_CONFIG_COLOR_AND_BLACK

        elif AGENT_TYPE_CMY in pens and AGENT_TYPE_KCM in pens:
            return AGENT_CONFIG_COLOR_AND_PHOTO

        elif AGENT_TYPE_CMY in pens and AGENT_TYPE_GGK in pens:
            return AGENT_CONFIG_COLOR_AND_GREY

        else:
            return AGENT_CONFIG_INVALID


def getFaxStatus(dev):
    tx_active, rx_active = False, False

    if dev.io_mode not in (IO_MODE_UNI, IO_MODE_RAW):
        try:
            dev.openPML()

            result_code, tx_state = dev.getPML(pml.OID_FAXJOB_TX_STATUS)

            if result_code == ERROR_SUCCESS and tx_state:
                if tx_state not in (pml.FAXJOB_TX_STATUS_IDLE, pml.FAXJOB_TX_STATUS_DONE):
                    tx_active = True

            result_code, rx_state = dev.getPML(pml.OID_FAXJOB_RX_STATUS)

            if result_code == ERROR_SUCCESS and rx_state:
                if rx_state not in (pml.FAXJOB_RX_STATUS_IDLE, pml.FAXJOB_RX_STATUS_DONE):
                    rx_active = True

        finally:
            dev.closePML()

    return tx_active, rx_active


TYPE6_STATUS_CODE_MAP = {
     0    : STATUS_PRINTER_IDLE, #</DevStatusUnknown>
    -19928: STATUS_PRINTER_IDLE,
    -18995: STATUS_PRINTER_CANCELING,
    -17974: STATUS_PRINTER_WARMING_UP,
    -17973: STATUS_PRINTER_PEN_CLEANING, # sic
    -18993: STATUS_PRINTER_BUSY,
    -17949: STATUS_PRINTER_BUSY,
    -19720: STATUS_PRINTER_MANUAL_DUPLEX_BLOCK,
    -19678: STATUS_PRINTER_BUSY,
    -19695: STATUS_PRINTER_OUT_OF_PAPER,
    -17985: STATUS_PRINTER_MEDIA_JAM,
    -19731: STATUS_PRINTER_OUT_OF_PAPER,
    -18974: STATUS_PRINTER_BUSY, #?
    -19730: STATUS_PRINTER_OUT_OF_PAPER,
    -19729: STATUS_PRINTER_OUT_OF_PAPER,
    -19933: STATUS_PRINTER_HARD_ERROR, # out of memory
    -17984: STATUS_PRINTER_DOOR_OPEN,
    -19694: STATUS_PRINTER_DOOR_OPEN,
    -18992: STATUS_PRINTER_MANUAL_FEED_BLOCKED, # ?
    -19690: STATUS_PRINTER_MEDIA_JAM, # tray 1
    -19689: STATUS_PRINTER_MEDIA_JAM, # tray 2
    -19611: STATUS_PRINTER_MEDIA_JAM, # tray 3
    -19686: STATUS_PRINTER_MEDIA_JAM,
    -19688: STATUS_PRINTER_MEDIA_JAM, # paper path
    -19685: STATUS_PRINTER_MEDIA_JAM, # cart area
    -19684: STATUS_PRINTER_MEDIA_JAM, # output bin
    -18848: STATUS_PRINTER_MEDIA_JAM, # duplexer
    -18847: STATUS_PRINTER_MEDIA_JAM, # door open
    -18846: STATUS_PRINTER_MEDIA_JAM, # tray 2
    -19687: STATUS_PRINTER_MEDIA_JAM, # open door
    -17992: STATUS_PRINTER_MEDIA_JAM, # mispick
    -19700: STATUS_PRINTER_HARD_ERROR, # invalid driver
    -17996: STATUS_PRINTER_FUSER_ERROR, # fuser error
    -17983: STATUS_PRINTER_FUSER_ERROR,
    -17982: STATUS_PRINTER_FUSER_ERROR,
    -17981: STATUS_PRINTER_FUSER_ERROR,
    -17971: STATUS_PRINTER_FUSER_ERROR,
    -17995: STATUS_PRINTER_HARD_ERROR, # beam error
    -17994: STATUS_PRINTER_HARD_ERROR, # scanner error
    -17993: STATUS_PRINTER_HARD_ERROR, # fan error
    -18994: STATUS_PRINTER_HARD_ERROR,
    -17986: STATUS_PRINTER_HARD_ERROR,
    -19904: STATUS_PRINTER_HARD_ERROR,
    -19701: STATUS_PRINTER_NON_HP_INK, # [sic]
    -19613: STATUS_PRINTER_IDLE, # HP
    -19654: STATUS_PRINTER_NON_HP_INK, # [sic]
    -19682: STATUS_PRINTER_HARD_ERROR, # resinstall
    -19693: STATUS_PRINTER_IDLE, # ?? To Accept
    -19752: STATUS_PRINTER_LOW_TONER,
    -19723: STATUS_PRINTER_BUSY,
    -19703: STATUS_PRINTER_BUSY,
    -19739: STATUS_PRINTER_NO_TONER,
    -19927: STATUS_PRINTER_BUSY,
    -19932: STATUS_PRINTER_BUSY,
    -19931: STATUS_PRINTER_BUSY,
    -11989: STATUS_PRINTER_BUSY,
    -11995: STATUS_PRINTER_BUSY, # ADF loaded
    -19954: STATUS_PRINTER_CANCELING,
    -19955: STATUS_PRINTER_REPORT_PRINTING,
    -19956: STATUS_PRINTER_REPORT_PRINTING,
    -19934: STATUS_PRINTER_HARD_ERROR,
    -19930: STATUS_PRINTER_BUSY,
    -11990: STATUS_PRINTER_DOOR_OPEN,
    -11999: STATUS_PRINTER_MEDIA_JAM, # ADF
    -12000: STATUS_PRINTER_MEDIA_JAM, # ADF
    -11998: STATUS_PRINTER_MEDIA_JAM, # ADF
    -11986: STATUS_PRINTER_HARD_ERROR, # scanner
    -11994: STATUS_PRINTER_BUSY,
    -14967: STATUS_PRINTER_BUSY,
    -19912: STATUS_PRINTER_HARD_ERROR,
    -14962: STATUS_PRINTER_BUSY, # copy pending
    -14971: STATUS_PRINTER_BUSY, # copying
    -14973: STATUS_PRINTER_BUSY, # copying being canceled
    -14972: STATUS_PRINTER_BUSY, # copying canceled
    -14966: STATUS_PRINTER_DOOR_OPEN,
    -14974: STATUS_PRINTER_MEDIA_JAM,
    -14969: STATUS_PRINTER_HARD_ERROR,
    -14968: STATUS_PRINTER_HARD_ERROR,
    -12996: STATUS_PRINTER_BUSY, # scan
    -12994: STATUS_PRINTER_BUSY, # scan
    -12993: STATUS_PRINTER_BUSY, # scan
    -12991: STATUS_PRINTER_BUSY, # scan
    -12995: STATUS_PRINTER_BUSY, # scan
    -12997: STATUS_PRINTER_HARD_ERROR, # scan
    -12990: STATUS_PRINTER_BUSY,
    -12998: STATUS_PRINTER_BUSY,
    -13000: STATUS_PRINTER_DOOR_OPEN,
    -12999: STATUS_PRINTER_MEDIA_JAM,
    -13859: STATUS_PRINTER_BUSY,
    -13858: STATUS_PRINTER_BUSY, #</DevStatusDialingOut>
    -13868: STATUS_PRINTER_BUSY, #</DevStatusRedialPending>
    -13867: STATUS_PRINTER_BUSY, #</DevStatusFaxSendCanceled>
    -13857: STATUS_PRINTER_BUSY, #</DevStatusConnecting>
    -13856: STATUS_PRINTER_BUSY, #</DevStatusSendingPage>
    -13855: STATUS_PRINTER_BUSY, #</DevStatusOnePageSend>
    -13854: STATUS_PRINTER_BUSY, #</DevStatusMultiplePagesSent>
    -13853: STATUS_PRINTER_BUSY, #</DevStatusSenderCancelingFax>
    -13839: STATUS_PRINTER_BUSY, #</DevStatusIncomingCall>
    -13842: STATUS_PRINTER_BUSY, #</DevStatusBlockingFax>
    -13838: STATUS_PRINTER_BUSY, #</DevStatusReceivingFax>
    -13847: STATUS_PRINTER_BUSY, #</DevStatusSinglePageReceived>
    -13846: STATUS_PRINTER_BUSY, #</DevStatusDoublePagesReceived>
    -13845: STATUS_PRINTER_BUSY, #</DevStatusTriplePagesReceived>
    -13844: STATUS_PRINTER_BUSY, #</DevStatusPrintingFax>
    -13840: STATUS_PRINTER_BUSY, #</DevStatusCancelingFaxPrint>
    -13843: STATUS_PRINTER_BUSY, #</DevStatusFaxCancelingReceive>
    -13850: STATUS_PRINTER_BUSY, #</DevStatusFaxCanceledReceive>
    -13851: STATUS_PRINTER_BUSY, #</DevStatusFaxDelayedSendMemoryFull>
    -13836: STATUS_PRINTER_BUSY, #</DevStatusNoDialTone>
    -13864: STATUS_PRINTER_BUSY, #</DevStatusNoFaxAnswer>
    -13863: STATUS_PRINTER_BUSY, #</DevStatusFaxBusy>
    -13865: STATUS_PRINTER_BUSY, #</DevStatusNoDocumentSent>
    -13862: STATUS_PRINTER_BUSY, #</DevStatusFaxSendError>
    -13837: STATUS_PRINTER_BUSY, #</DevStatusT30Error>
    -13861: STATUS_PRINTER_BUSY, #</DevStatusFaxMemoryFullSend>
    -13866: STATUS_PRINTER_BUSY, #</DevStatusADFNotCleared>
    -13841: STATUS_PRINTER_BUSY, #</DevStatusNoFaxDetected>
    -13848: STATUS_PRINTER_BUSY, #</DevStatusFaxMemoryFullReceive>
    -13849: STATUS_PRINTER_BUSY, #</DevStatusFaxReceiveError>

}

def StatusType6(dev): #  LaserJet Status (XML)
    info_device_status = BytesIO()
    info_ssp = BytesIO()
    try:
        dev.getEWSUrl("/hp/device/info_device_status.xml", info_device_status)
        dev.getEWSUrl("/hp/device/info_ssp.xml", info_ssp)
    except:
        log.warn("Failed to get Device status information")
        pass

    info_device_status = info_device_status.getvalue()
    info_ssp = info_ssp.getvalue()

    device_status = {}
    ssp = {}

    if info_device_status:
        try:
            log.debug_block("info_device_status", to_string_latin(info_device_status))
            device_status = utils.XMLToDictParser().parseXML(info_device_status)
            log.debug(device_status)
        except expat.ExpatError:
            log.error("Device Status XML parse error")
            device_status = {}

    if info_ssp:
        try:
            log.debug_block("info_spp", to_string_latin(info_ssp))
            ssp = utils.XMLToDictParser().parseXML(info_ssp)
            log.debug(ssp)
        except expat.ExpatError:
            log.error("SSP XML parse error")
            ssp = {}

    status_code = device_status.get('devicestatuspage-devicestatus-statuslist-status-code-0', 0)

    if not status_code:
        status_code = ssp.get('devicestatuspage-devicestatus-statuslist-status-code-0', 0)

    black_supply_level = device_status.get('devicestatuspage-suppliesstatus-blacksupply-percentremaining', 0)
    black_supply_low = ssp.get('suppliesstatuspage-blacksupply-lowreached', 0)
    agents = []

    agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
                     'type' : AGENT_TYPE_BLACK,
                     'health' : 0,
                     'level' : black_supply_level,
                     'level-trigger' : 0,
                  })

    if dev.tech_type == TECH_TYPE_COLOR_LASER:
        cyan_supply_level = device_status.get('devicestatuspage-suppliesstatus-cyansupply-percentremaining', 0)
        agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
                         'type' : AGENT_TYPE_CYAN,
                         'health' : 0,
                         'level' : cyan_supply_level,
                         'level-trigger' : 0,
                      })

        magenta_supply_level = device_status.get('devicestatuspage-suppliesstatus-magentasupply-percentremaining', 0)
        agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
                         'type' : AGENT_TYPE_MAGENTA,
                         'health' : 0,
                         'level' : magenta_supply_level,
                         'level-trigger' : 0,
                      })

        yellow_supply_level = device_status.get('devicestatuspage-suppliesstatus-yellowsupply-percentremaining', 0)
        agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
                         'type' : AGENT_TYPE_YELLOW,
                         'health' : 0,
                         'level' : yellow_supply_level,
                         'level-trigger' : 0,
                      })

    return {'revision' :    STATUS_REV_UNKNOWN,
             'agents' :      agents,
             'top-door' :    0,
             'supply-door' : 0,
             'duplexer' :    1,
             'photo-tray' :  0,
             'in-tray1' :    1,
             'in-tray2' :    1,
             'media-path' :  1,
             'status-code' : TYPE6_STATUS_CODE_MAP.get(status_code, STATUS_PRINTER_IDLE),
           }

# PJL status codes
PJL_STATUS_MAP = {
    10001: STATUS_PRINTER_IDLE, # online
    10002: STATUS_PRINTER_OFFLINE, # offline
    10003: STATUS_PRINTER_WARMING_UP,
    10004: STATUS_PRINTER_BUSY, # self test
    10005: STATUS_PRINTER_BUSY, # reset
    10006: STATUS_PRINTER_LOW_TONER,
    10007: STATUS_PRINTER_CANCELING,
    10010: STATUS_PRINTER_SERVICE_REQUEST,
    10011: STATUS_PRINTER_OFFLINE,
    10013: STATUS_PRINTER_BUSY,
    10014: STATUS_PRINTER_REPORT_PRINTING,
    10015: STATUS_PRINTER_BUSY,
    10016: STATUS_PRINTER_BUSY,
    10017: STATUS_PRINTER_REPORT_PRINTING,
    10018: STATUS_PRINTER_BUSY,
    10019: STATUS_PRINTER_BUSY,
    10020: STATUS_PRINTER_BUSY,
    10021: STATUS_PRINTER_BUSY,
    10022: STATUS_PRINTER_REPORT_PRINTING,
    10023: STATUS_PRINTER_PRINTING,
    10024: STATUS_PRINTER_SERVICE_REQUEST,
    10025: STATUS_PRINTER_SERVICE_REQUEST,
    10026: STATUS_PRINTER_BUSY,
    10027: STATUS_PRINTER_MEDIA_JAM,
    10028: STATUS_PRINTER_REPORT_PRINTING,
    10029: STATUS_PRINTER_PRINTING,
    10030: STATUS_PRINTER_BUSY,
    10031: STATUS_PRINTER_BUSY,
    10032: STATUS_PRINTER_BUSY,
    10033: STATUS_PRINTER_SERVICE_REQUEST,
    10034: STATUS_PRINTER_CANCELING,
    10035: STATUS_PRINTER_PRINTING,
    10036: STATUS_PRINTER_WARMING_UP,
    10200: STATUS_PRINTER_LOW_BLACK_TONER,
    10201: STATUS_PRINTER_LOW_CYAN_TONER,
    10202: STATUS_PRINTER_LOW_MAGENTA_TONER,
    10203: STATUS_PRINTER_LOW_YELLOW_TONER,
    10204: STATUS_PRINTER_LOW_TONER, # order image drum
    10205: STATUS_PRINTER_LOW_BLACK_TONER, # order black drum
    10206: STATUS_PRINTER_LOW_CYAN_TONER, # order cyan drum
    10207: STATUS_PRINTER_LOW_MAGENTA_TONER, # order magenta drum
    10208: STATUS_PRINTER_LOW_YELLOW_TONER, # order yellow drum
    10209: STATUS_PRINTER_LOW_BLACK_TONER,
    10210: STATUS_PRINTER_LOW_CYAN_TONER,
    10211: STATUS_PRINTER_LOW_MAGENTA_TONER,
    10212: STATUS_PRINTER_LOW_YELLOW_TONER,
    10213: STATUS_PRINTER_SERVICE_REQUEST, # order transport kit
    10214: STATUS_PRINTER_SERVICE_REQUEST, # order cleaning kit
    10215: STATUS_PRINTER_SERVICE_REQUEST, # order transfer kit
    10216: STATUS_PRINTER_SERVICE_REQUEST, # order fuser kit
    10217: STATUS_PRINTER_SERVICE_REQUEST, # maintenance
    10218: STATUS_PRINTER_LOW_TONER,
    10300: STATUS_PRINTER_LOW_BLACK_TONER, # replace black toner
    10301: STATUS_PRINTER_LOW_CYAN_TONER, # replace cyan toner
    10302: STATUS_PRINTER_LOW_MAGENTA_TONER, # replace magenta toner
    10303: STATUS_PRINTER_LOW_YELLOW_TONER, # replace yellow toner
    10304: STATUS_PRINTER_SERVICE_REQUEST, # replace image drum
    10305: STATUS_PRINTER_SERVICE_REQUEST, # replace black drum
    10306: STATUS_PRINTER_SERVICE_REQUEST, # replace cyan drum
    10307: STATUS_PRINTER_SERVICE_REQUEST, # replace magenta drum
    10308: STATUS_PRINTER_SERVICE_REQUEST, # replace yellow drum
    10309: STATUS_PRINTER_SERVICE_REQUEST, # replace black cart
    10310: STATUS_PRINTER_SERVICE_REQUEST, # replace cyan cart
    10311: STATUS_PRINTER_SERVICE_REQUEST, # replace magenta cart
    10312: STATUS_PRINTER_SERVICE_REQUEST, # replace yellow cart
    10313: STATUS_PRINTER_SERVICE_REQUEST, # replace transport kit
    10314: STATUS_PRINTER_SERVICE_REQUEST, # replace cleaning kit
    10315: STATUS_PRINTER_SERVICE_REQUEST, # replace transfer kit
    10316: STATUS_PRINTER_SERVICE_REQUEST, # replace fuser kit
    10317: STATUS_PRINTER_SERVICE_REQUEST,
    10318: STATUS_PRINTER_SERVICE_REQUEST, # replace supplies
    10400: STATUS_PRINTER_NON_HP_INK, # [sic]
    10401: STATUS_PRINTER_IDLE,
    10402: STATUS_PRINTER_SERVICE_REQUEST,
    10403: STATUS_PRINTER_IDLE,
    # 11xyy - Background paper-loading
    # 12xyy - Background paper-tray status
    # 15xxy - Output-bin status
    # 20xxx - PJL parser errors
    # 25xxx - PJL parser warnings
    # 27xxx - PJL semantic errors
    # 30xxx - Auto continuable conditions
    30119: STATUS_PRINTER_MEDIA_JAM,
    # 32xxx - PJL file system errors
    # 35xxx - Potential operator intervention conditions
    # 40xxx - Operator intervention conditions
    40021: STATUS_PRINTER_DOOR_OPEN,
    40022: STATUS_PRINTER_MEDIA_JAM,
    40038: STATUS_PRINTER_LOW_TONER,
    40600: STATUS_PRINTER_NO_TONER,
    # 41xyy - Foreground paper-loading messages
    # 43xyy - Optional paper handling device messages
    # 44xyy - LJ 4xxx/5xxx paper jam messages
    # 50xxx - Hardware errors
    # 55xxx - Personality errors

}

MIN_PJL_ERROR_CODE = 10001
DEFAULT_PJL_ERROR_CODE = 10001

def MapPJLErrorCode(error_code, str_code=None):
    if error_code < MIN_PJL_ERROR_CODE:
        return STATUS_PRINTER_BUSY

    if str_code is None:
        str_code = str(error_code)

    if len(str_code) < 5:
        return STATUS_PRINTER_BUSY

    status_code = PJL_STATUS_MAP.get(error_code, None)

    if status_code is None:
        status_code = STATUS_PRINTER_BUSY

        if 10999 < error_code < 12000: # 11xyy - Background paper-loading
            # x = tray #
            # yy = media code
            tray = int(str_code[2])
            media = int(str_code[3:])
            log.debug("Background paper loading for tray #%d" % tray)
            log.debug("Media code = %d" % media)

        elif 11999 < error_code < 13000: # 12xyy - Background paper-tray status
            # x = tray #
            # yy = status code
            tray = int(str_code[2])
            status = int(str_code[3:])
            log.debug("Background paper tray status for tray #%d" % tray)
            log.debug("Status code = %d" % status)

        elif 14999 < error_code < 16000: # 15xxy - Output-bin status
            # xx = output bin
            # y = status code
            bin = int(str_code[2:4])
            status = int(str_code[4])
            log.debug("Output bin full for bin #%d" % bin)
            status_code = STATUS_PRINTER_OUTPUT_BIN_FULL

        elif 19999 < error_code < 28000: # 20xxx, 25xxx, 27xxx PJL errors
            status_code = STATUS_PRINTER_SERVICE_REQUEST

        elif 29999 < error_code < 31000: # 30xxx - Auto continuable conditions
            log.debug("Auto continuation condition #%d" % error_code)
            status_code = STATUS_PRINTER_BUSY

        elif 34999 < error_code < 36000: # 35xxx - Potential operator intervention conditions
            status_code = STATUS_PRINTER_SERVICE_REQUEST

        elif 39999 < error_code < 41000: # 40xxx - Operator intervention conditions
            status_code = STATUS_PRINTER_SERVICE_REQUEST

        elif 40999 < error_code < 42000: # 41xyy - Foreground paper-loading messages
            # x = tray
            # yy = media code
            tray = int(str_code[2])
            media = int(str_code[3:])
            log.debug("Foreground paper loading for tray #%d" % tray)
            log.debug("Media code = %d" % media)
            status_code = STATUS_PRINTER_OUT_OF_PAPER

        elif 41999 < error_code < 43000:
            status_code = STATUS_PRINTER_MEDIA_JAM

        elif 42999 < error_code < 44000: # 43xyy - Optional paper handling device messages
            status_code = STATUS_PRINTER_SERVICE_REQUEST

        elif 43999 < error_code < 45000: # 44xyy - LJ 4xxx/5xxx paper jam messages
            status_code = STATUS_PRINTER_MEDIA_JAM

        elif 49999 < error_code < 51000: # 50xxx - Hardware errors
            status_code = STATUS_PRINTER_HARD_ERROR

        elif 54999 < error_code < 56000 : # 55xxx - Personality errors
            status_code = STATUS_PRINTER_HARD_ERROR

    log.debug("Mapped PJL error code %d to status code %d" % (error_code, status_code))
    return status_code


pjl_code_pat = re.compile("""^CODE\s*=\s*(\d.*)$""", re.IGNORECASE)



def StatusType8(dev): #  LaserJet PJL (B&W only)
    try:
        # Will error if printer is busy printing...
        dev.openPrint()
    except Error as e:
        log.warn(e.msg)
        status_code = STATUS_PRINTER_BUSY
    else:
        try:
            try:
                dev.writePrint(to_bytes_utf8("\x1b%-12345X@PJL INFO STATUS \r\n\x1b%-12345X"))
                pjl_return = dev.readPrint(1024, timeout=5, allow_short_read=True)
                dev.close()

                log.debug_block("PJL return:", to_string_latin(pjl_return))

                str_code = '10001'

                for line in pjl_return.splitlines():
                    line = line.strip()
                    match = pjl_code_pat.match(line.decode('utf-8'))

                    if match is not None:
                        str_code = match.group(1)
                        break

                log.debug("Code = %s" % str_code)

                try:
                    error_code = int(str_code)
                except ValueError:
                    error_code = DEFAULT_PJL_ERROR_CODE

                log.debug("Error code = %d" % error_code)

                status_code = MapPJLErrorCode(error_code, str_code)
            except Error:
                status_code = STATUS_PRINTER_HARD_ERROR
        finally:
            try:
                dev.closePrint()
            except Error:
                pass

    agents = []

    # TODO: Only handles mono lasers...
    if status_code in (STATUS_PRINTER_LOW_TONER, STATUS_PRINTER_LOW_BLACK_TONER):
        health = AGENT_HEALTH_OK
        level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW
        level = 0

    elif status_code == STATUS_PRINTER_NO_TONER:
        health = AGENT_HEALTH_MISINSTALLED
        level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW
        level = 0

    else:
        health = AGENT_HEALTH_OK
        level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
        level = 100

    log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger))

    agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
                     'type' : AGENT_TYPE_BLACK,
                     'health' : health,
                     'level' : level,
                     'level-trigger' : level_trigger,
                  })

    if dev.tech_type == TECH_TYPE_COLOR_LASER:
        level = 100
        level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
        if status_code == STATUS_PRINTER_LOW_CYAN_TONER:
            level = 0
            level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW

        log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger))

        agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
                         'type' : AGENT_TYPE_CYAN,
                         'health' : AGENT_HEALTH_OK,
                         'level' : level,
                         'level-trigger' : level_trigger,
                      })

        level = 100
        level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
        if status_code == STATUS_PRINTER_LOW_MAGENTA_TONER:
            level = 0
            level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW

        log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger))

        agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
                         'type' : AGENT_TYPE_MAGENTA,
                         'health' : AGENT_HEALTH_OK,
                         'level' : level,
                         'level-trigger' : level_trigger,
                      })

        level = 100
        level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
        if status_code == STATUS_PRINTER_LOW_YELLOW_TONER:
            level = 0
            level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW

        log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger))

        agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
                         'type' : AGENT_TYPE_YELLOW,
                         'health' : AGENT_HEALTH_OK,
                         'level' : level,
                         'level-trigger' : level_trigger,
                      })

    if status_code == 40021:
        top_door = 0
    else:
        top_door = 1

    log.debug("Status code = %d" % status_code)

    return { 'revision' :    STATUS_REV_UNKNOWN,
             'agents' :      agents,
             'top-door' :    top_door,
             'supply-door' : top_door,
             'duplexer' :    0,
             'photo-tray' :  0,
             'in-tray1' :    1,
             'in-tray2' :    1,
             'media-path' :  1,
             'status-code' : status_code,
           }


element_type10_xlate = { 'ink' : AGENT_KIND_SUPPLY,
                         'rechargeableToner' : AGENT_KIND_TONER_CARTRIDGE,
                         'inkTank' : AGENT_KIND_SUPPLY,
                         'inkCartridge' : AGENT_KIND_HEAD_AND_SUPPLY,
                         'printhead' : AGENT_KIND_HEAD,
                         'toner' : AGENT_KIND_TONER_CARTRIDGE,
                         'tonerCartridge' : AGENT_KIND_TONER_CARTRIDGE,
                       }

pen_type10_xlate = { 'pK' : AGENT_TYPE_PHOTO_BLACK,
                     'CMY' : AGENT_TYPE_CMY,
                     'M' : AGENT_TYPE_MAGENTA,
                     'C' : AGENT_TYPE_CYAN,
                     'Y' : AGENT_TYPE_YELLOW,
                     'K' : AGENT_TYPE_BLACK,
                     'G' : AGENT_TYPE_G,
                     'mK' : AGENT_TYPE_MATTE_BLACK,
                   }

pen_level10_xlate = { 'ok' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
                      'low' : AGENT_LEVEL_TRIGGER_MAY_BE_LOW,
                      'out' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
                      'empty' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
                      'missing' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
                      'unknown' : AGENT_LEVEL_UNKNOWN,
                    }

pen_health10_xlate = { 'ok' : AGENT_HEALTH_OK,
                       'misinstalled' : AGENT_HEALTH_MISINSTALLED,
                       'missing' : AGENT_HEALTH_MISINSTALLED,
                       'unknown' : AGENT_HEALTH_UNKNOWN,
                     }


#ExtractXMLData will extract actual data from http response (Transfer-encoding:  chunked).
#For unchunked response it will not do anything.
def ExtractXMLData(data):
    if data[0:1] != b'<':
        size = -1
        temp = to_bytes_utf8("")
        while size:
            index = data.find(to_bytes_utf8('\r\n'))
            size = int(data[0:index+1], 16)
            temp = temp + data[index+2:index+2+size]
            data = data[index+2+size+2:len(data)]
        data = temp
    return data

def StatusType10FetchUrl(func, url, footer=""):
    data_fp = BytesIO()
    if footer:
        data = func(url, data_fp, footer)
    else:
        data = func(url, data_fp)
        if data:
            while data.find(to_bytes_utf8('\r\n\r\n')) != -1:
                data = data.split(to_bytes_utf8('\r\n\r\n'), 1)[1]
                if not data.startswith(to_bytes_utf8("HTTP")):
                    break

            if data:
                data = ExtractXMLData(data)
    return data

def StatusType10(func): # Low End Data Model
    status_block = { 'revision' :    STATUS_REV_UNKNOWN,
                     'agents' :      [],
                     'top-door' :    TOP_DOOR_NOT_PRESENT,
                     'supply-door' : TOP_DOOR_NOT_PRESENT,
                     'duplexer' :    DUPLEXER_NOT_PRESENT,
                     'photo-tray' :  PHOTO_TRAY_NOT_PRESENT,
                     'in-tray1' :    IN_TRAY_NOT_PRESENT,
                     'in-tray2' :    IN_TRAY_NOT_PRESENT,
                     'media-path' :  MEDIA_PATH_NOT_PRESENT,
                     'status-code' : STATUS_PRINTER_IDLE,
                   }

    if not etree_loaded and not elementtree_loaded:
        log.error("cannot get status for printer. please load ElementTree module")
        return status_block

    status_block = StatusType10Agents(func)

    temp_status_block = {}
    temp_status_block = StatusType10Media(func)
    status_block.update(temp_status_block)

    temp_status_block = {}
    temp_status_block = StatusType10Status(func)
    status_block.update(temp_status_block)

    return status_block


def StatusType10Agents(func): # Low End Data Model
    status_block = {}
    # Get the dynamic consumables configuration
    data = StatusType10FetchUrl(func, "/DevMgmt/ConsumableConfigDyn.xml")
    if not data:
        return status_block
    data = data.replace(to_bytes_utf8("ccdyn:"), to_bytes_utf8("")).replace(to_bytes_utf8("dd:"), to_bytes_utf8(""))

    # Parse the agent status XML
    agents = []
    try:
        if etree_loaded:
            tree = ElementTree.XML(data)
        if not etree_loaded and elementtree_loaded:
            tree = XML(data)
        elements = tree.findall("ConsumableInfo")
        for e in elements:
            health = AGENT_HEALTH_OK
            ink_level = 0
            agent_sku = ''
            try:
                type = e.find("ConsumableTypeEnum").text
                state = e.find("ConsumableLifeState/ConsumableState").text
                quantityState = e.find("ConsumableLifeState/MeasuredQuantityState").text

                # level
                if type == "ink" or type == "inkCartridge" or type == "toner" or type == "tonerCartridge" or type == "rechargeableToner" or type == "inkTank":
                    ink_type = e.find("ConsumableLabelCode").text
                    if state != "missing":
                        try:
                           ink_level = int(e.find("ConsumablePercentageLevelRemaining").text)
                           if ink_level == 0 and quantityState == 'unknown':
                                state = "unknown"
                           elif ink_level == 0:
                               state = "empty"
                           elif ink_level <=10:
                               state = "low"

                           agent_sku = 'Unknown' #Initialize to unknown. IN some old devices, ConsumableSelectibilityNumber is not returned by device.
                        except:
                           ink_level = 0
                elif type == "printhead" or type == 'imageDrum':
                     continue; #No need of adding this agent.
                else:
                    ink_type = ''
                    if state == "ok":
                        ink_level = 100

                try:
                    agent_sku = e.find("ProductNumber").text
                except:
                    try :
                        agent_sku = e.find("ConsumableSelectibilityNumber").text
                    except :
                        pass

                log.debug("type '%s' state '%s' ink_type '%s' ink_level %d agent_sku = %s" % (type, state, ink_type, ink_level,agent_sku))

                entry = { 'kind' : element_type10_xlate.get(type, AGENT_KIND_NONE),
                          'type' : pen_type10_xlate.get(ink_type, AGENT_TYPE_NONE),
                          'health' : pen_health10_xlate.get(state, AGENT_HEALTH_OK),
                          'level' : int(ink_level),
                          'level-trigger' : pen_level10_xlate.get(state, AGENT_LEVEL_TRIGGER_SUFFICIENT_0),
                          'agent-sku' : agent_sku
                        }

                log.debug("%s" % entry)
                agents.append(entry)
            except AttributeError:
                log.debug("no value found for attribute")
    except (expat.ExpatError, UnboundLocalError):
        agents = []
    status_block['agents'] = agents

    return status_block

def StatusType10Media(func): # Low End Data Model
    status_block = {}
    # Get the media handling configuration
    data = StatusType10FetchUrl(func, "/DevMgmt/MediaHandlingDyn.xml")
    if not data:
        return status_block
    data = data.replace(to_bytes_utf8("mhdyn:"), to_bytes_utf8("")).replace(to_bytes_utf8("dd:"), to_bytes_utf8(""))

    # Parse the media handling XML
    try:
        if etree_loaded:
            tree = ElementTree.XML(data)
        if not etree_loaded and elementtree_loaded:
            tree = XML(data)
        elements = tree.findall("InputTray")
    except (expat.ExpatError, UnboundLocalError):
        elements = []
    for e in elements:
        bin_name = e.find("InputBin").text
        if bin_name == "Tray1":
            status_block['in-tray1'] = IN_TRAY_PRESENT
        elif bin_name == "Tray2":
            status_block['in-tray2'] = IN_TRAY_PRESENT
        elif bin_name == "PhotoTray":
            status_block['photo-tray'] = PHOTO_TRAY_ENGAGED

    try:
        elements = tree.findall("Accessories/MediaHandlingDeviceFunctionType")
    except UnboundLocalError:
        elements = []
    for e in elements:
        if e.text == "autoDuplexor":
            status_block['duplexer'] = DUPLEXER_DOOR_CLOSED

    return status_block

def StatusType10Status(func): # Low End Data Model
    status_block = {}
    # Get the product status
    data = StatusType10FetchUrl(func, "/DevMgmt/ProductStatusDyn.xml")
    if not data:
        return status_block
    data = data.replace(to_bytes_utf8("psdyn:"), to_bytes_utf8("")).replace(to_bytes_utf8("locid:"), to_bytes_utf8(""))
    data = data.replace(to_bytes_utf8("pscat:"), to_bytes_utf8("")).replace(to_bytes_utf8("dd:"), to_bytes_utf8("")).replace(to_bytes_utf8("ad:"), to_bytes_utf8(""))

    # Parse the product status XML
    try:
        if etree_loaded:
            tree = ElementTree.XML(data)
        if not etree_loaded and elementtree_loaded:
            tree = XML(data)
        elements = tree.findall("Status/StatusCategory")
    except (expat.ExpatError, UnboundLocalError):
        elements = []

    for e in elements:

        if e.text == "processing":
            status_block['status-code'] = STATUS_PRINTER_PRINTING
        elif e.text == "ready":
            status_block['status-code'] = STATUS_PRINTER_IDLE
        elif e.text == "closeDoorOrCover":
            status_block['status-code'] = STATUS_PRINTER_DOOR_OPEN
        elif e.text == "shuttingDown":
            status_block['status-code'] = STATUS_PRINTER_TURNING_OFF
        elif e.text == "cancelJob":
            status_block['status-code'] = STATUS_PRINTER_CANCELING
        elif e.text == "trayEmptyOrOpen":
            status_block['status-code'] = STATUS_PRINTER_OUT_OF_PAPER
        elif e.text == "jamInPrinter":
            status_block['status-code'] = STATUS_PRINTER_MEDIA_JAM
        elif e.text == "hardError":
            status_block['status-code'] = STATUS_PRINTER_HARD_ERROR
        elif e.text == "outputBinFull":
            status_block['status-code'] = STATUS_PRINTER_OUTPUT_BIN_FULL
        elif e.text == "unexpectedSizeInTray" or e.text == "sizeMismatchInTray":
            status_block['status-code'] = STATUS_PRINTER_MEDIA_SIZE_MISMATCH
        elif e.text == "insertOrCloseTray2":
            status_block['status-code'] = STATUS_PRINTER_TRAY_2_MISSING
        elif e.text == "scannerError":
            status_block['status-code'] = EVENT_SCANNER_FAIL
        elif e.text == "scanProcessing":
            status_block['status-code'] = EVENT_START_SCAN_JOB
        elif e.text == "scannerAdfLoaded":
            status_block['status-code'] = EVENT_SCAN_ADF_LOADED
        elif e.text == "scanToDestinationNotSet":
            status_block['status-code'] = EVENT_SCAN_TO_DESTINATION_NOTSET
        elif e.text == "scanWaitingForPC":
            status_block['status-code'] = EVENT_SCAN_WAITING_FOR_PC
        elif e.text == "scannerAdfJam":
            status_block['status-code'] = EVENT_SCAN_ADF_JAM
        elif e.text == "scannerAdfDoorOpen":
            status_block['status-code'] = EVENT_SCAN_ADF_DOOR_OPEN
        elif e.text == "faxProcessing":
            status_block['status-code'] = EVENT_START_FAX_JOB
        elif e.text == "faxSending":
            status_block['status-code'] = STATUS_FAX_TX_ACTIVE
        elif e.text == "faxReceiving":
            status_block['status-code'] = STATUS_FAX_RX_ACTIVE
        elif e.text == "faxDialing":
            status_block['status-code'] = EVENT_FAX_DIALING
        elif e.text == "faxConnecting":
            status_block['status-code'] = EVENT_FAX_CONNECTING
        elif e.text == "faxSendError":
            status_block['status-code'] = EVENT_FAX_SEND_ERROR
        elif e.text == "faxErrorStorageFull":
            status_block['status-code'] = EVENT_FAX_ERROR_STORAGE_FULL
        elif e.text == "faxReceiveError":
            status_block['status-code'] = EVENT_FAX_RECV_ERROR
        elif e.text == "faxBlocking":
            status_block['status-code'] = EVENT_FAX_BLOCKING
        elif e.text == "inPowerSave":
            status_block['status-code'] = STATUS_PRINTER_POWER_SAVE
        elif e.text == "incorrectCartridge":
            status_block['status-code'] = STATUS_PRINTER_CARTRIDGE_WRONG
        elif e.text == "cartridgeMissing":
            status_block['status-code'] = STATUS_PRINTER_CARTRIDGE_MISSING
        elif e.text == "missingPrintHead":
            status_block['status-code'] = STATUS_PRINTER_PRINTHEAD_MISSING


        #Alert messages for Pentane products RQ 8888
        elif e.text == "scannerADFMispick":
            status_block['status-code'] = STATUS_SCANNER_ADF_MISPICK

        elif e.text == "mediaTooShortToAutoDuplex":
            status_block['status-code'] = STATUS_PRINTER_PAPER_TOO_SHORT_TO_AUTODUPLEX

        elif e.text == "insertOrCloseTray":
            status_block['status-code'] = STATUS_PRINTER_TRAY_2_3_DOOR_OPEN

        elif e.text == "inkTooLowToPrime":
            status_block['status-code'] = STATUS_PRINTER_INK_TOO_LOW_TO_PRIME

        elif e.text == "cartridgeVeryLow":
            status_block['status-code'] = STATUS_PRINTER_VERY_LOW_ON_INK

        elif e.text == "wasteMarkerCollectorAlmostFull":
            status_block['status-code'] = STATUS_PRINTER_SERVICE_INK_CONTAINER_ALMOST_FULL

        elif e.text == "wasteMarkerCollectorFull":
            status_block['status-code'] = STATUS_PRINTER_SERVICE_INK_CONTAINER_FULL

        elif e.text == "wasteMarkerCollectorFullPrompt":
            status_block['status-code'] = STATUS_PRINTER_SERVICE_INK_CONTAINER_FULL_PROMPT

        elif e.text == "missingDuplexer":
            status_block['status-code'] = STATUS_PRINTER_DUPLEX_MODULE_MISSING

        elif e.text == "printBarStall":
            status_block['status-code'] = STATUS_PRINTER_PRINTHEAD_JAM

        elif e.text == "outputBinClosed":
            status_block['status-code'] = STATUS_PRINTER_CLEAR_OUTPUT_AREA

        elif e.text == "outputBinOpened":
            status_block['status-code'] = STATUS_PRINTER_CLEAR_OUTPUT_AREA

        elif e.text == "reseatDuplexer":
            status_block['status-code'] = STATUS_PRINTER_RESEAT_DUPLEXER

        elif e.text == "unexpectedTypeInTray":
            status_block['status-code'] = STATUS_PRINTER_MEDIA_TYPE_MISMATCH

        elif e.text == "manuallyFeed":
            status_block['status-code'] = STATUS_MANUALLY_FEED

        else:
            status_block['status-code'] = STATUS_UNKNOWN_CODE

    return status_block

#IPP Status Code
IPP_PRINTER_STATE_IDLE = 0x03
IPP_PRINTER_STATE_PROCESSING = 0x04
IPP_PRINTER_STATE_STOPPED = 0x05

marker_kind_xlate =    { 'ink' : AGENT_KIND_SUPPLY,
                         'rechargeableToner' : AGENT_KIND_TONER_CARTRIDGE,
                         'inkTank' : AGENT_KIND_SUPPLY,
                         'inkCartridge' : AGENT_KIND_SUPPLY,
                         'printhead' : AGENT_KIND_HEAD,
                         'toner' : AGENT_KIND_TONER_CARTRIDGE,
                         'tonerCartridge' : AGENT_KIND_TONER_CARTRIDGE,
                         'toner-cartridge' : AGENT_KIND_TONER_CARTRIDGE,
                         'maintenanceKit' : AGENT_KIND_MAINT_KIT,
                         'ink-cartridge' : AGENT_KIND_SUPPLY,
                       }

marker_type_xlate = {'magenta ink' : AGENT_TYPE_MAGENTA,
                     'cyan ink' : AGENT_TYPE_CYAN,
                     'yellow ink' : AGENT_TYPE_YELLOW,
                     'black ink' : AGENT_TYPE_BLACK,
                     'Black Cartridge' : AGENT_TYPE_BLACK,
                     'Magenta Cartridge' : AGENT_TYPE_MAGENTA,
                     'Cyan Cartridge' : AGENT_TYPE_CYAN,
                     'Yellow Cartridge' : AGENT_TYPE_YELLOW,
                     'Maintenance Kit' : AGENT_TYPE_NONE,
                    }

marker_leveltrigger_xlate = { 'ok' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
                              'low' : AGENT_LEVEL_TRIGGER_MAY_BE_LOW,
                              'out' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
                              'empty' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
                              'missing' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
                            }

marker_state_xlate = { 'ok' : AGENT_HEALTH_OK,
                       'misinstalled' : AGENT_HEALTH_MISINSTALLED,
                       'missing' : AGENT_HEALTH_MISINSTALLED,
                     }

printer_state_reasons_xlate = { 'none' : STATUS_PRINTER_IDLE,
                               'media-needed' : STATUS_PRINTER_OUT_OF_PAPER,
                               'media-jam' : STATUS_PRINTER_MEDIA_JAM,
                               'shutdown' : STATUS_PRINTER_TURNING_OFF,
                               'toner-low' : STATUS_PRINTER_LOW_TONER,
                               'toner-empty' : STATUS_PRINTER_EMPTY_TONER,
                               'cover-open' : STATUS_PRINTER_DOOR_OPEN,
                               'door-open' : STATUS_PRINTER_DOOR_OPEN,
                               'input-tray-missing' : STATUS_PRINTER_TRAY_2_3_DOOR_OPEN,
                               'media-low' : STATUS_PRINTER_OUT_OF_PAPER,
                               'media-empty' : STATUS_PRINTER_MEDIA_EMPTY_ERROR,
                               'output-tray-missing' : STATUS_PRINTER_TRAY_2_MISSING,
                               'output-area-almost-full' : STATUS_PRINTER_CLEAR_OUTPUT_AREA,
                               'output-area-full' : STATUS_PRINTER_CLEAR_OUTPUT_AREA,
                               'marker-supply-low' : STATUS_PRINTER_VERY_LOW_ON_INK,
                               'marker-supply-empty' : STATUS_PRINTER_VERY_LOW_ON_INK,
                               'paused' : STATUS_PRINTER_PAUSED,
                               'other' : STATUS_UNKNOWN_CODE,
                             }

def StatusTypeIPPStatus(attrs):

    status_block = {}
    if not attrs:
        return status_block

    try:
        printer_state = attrs['printer-state'][0]
        printer_state_reasons = attrs['printer-state-reasons'][0]

        if printer_state == IPP_PRINTER_STATE_IDLE:
            status_block['status-code'] = STATUS_PRINTER_IDLE
        elif printer_state == IPP_PRINTER_STATE_PROCESSING:
            status_block['status-code'] = STATUS_PRINTER_PRINTING
        else:
            printer_state_reasons = printer_state_reasons.replace("-error", "")
            printer_state_reasons = printer_state_reasons.replace("-warning", "")
            printer_state_reasons = printer_state_reasons.replace("-report", "")
            status_block['status-code'] = printer_state_reasons_xlate.get(printer_state_reasons, STATUS_PRINTER_IDLE)

    except Exception as e:
        log.debug("Exception occured while updating printer-state [%s]" %e.args[0])
        status_block = {}

    return status_block


def StatusTypeIPPAgents(attrs):

    status_block = {}
    agents = []

    if not attrs:
        return status_block

    loopcntr = 0
    while(True ):
        try:
            if loopcntr >= len(attrs['marker-names']):
                break

            if attrs['marker-types'][loopcntr] == 'maintenanceKit':
                loopcntr = loopcntr + 1
                continue

            if attrs['marker-levels'][loopcntr] > attrs['marker-low-levels'][loopcntr] :
                state = 'ok'
            else:
                state = 'low'

            #match the type if marker-type is something like 'Black Cartridge HP XXXX'
            mtype = [v for k,v in marker_type_xlate.items() if attrs['marker-names'][loopcntr].startswith(k)]

            entry = { 'kind' : marker_kind_xlate.get(attrs['marker-types'][loopcntr], AGENT_KIND_NONE),
                      'type' : mtype[0] if len(mtype) > 0 else 0,
                      'health' : marker_state_xlate.get(state, AGENT_HEALTH_OK),
                      'level' : attrs['marker-levels'][loopcntr],
                      'level-trigger' : marker_leveltrigger_xlate.get(state, AGENT_LEVEL_TRIGGER_SUFFICIENT_0),
                      'agent-sku' : ''
                    }

            log.debug("%s" % entry)
            agents.append(entry)
        except AttributeError:
            log.error("no value found for attribute")
            return []

        loopcntr = loopcntr + 1

    status_block['agents'] = agents

    return status_block

def StatusTypeIPP(device_uri):
    status_block = { 'revision' :    STATUS_REV_UNKNOWN,
                     'agents' :      [],
                     'top-door' :    TOP_DOOR_NOT_PRESENT,
                     'supply-door' : TOP_DOOR_NOT_PRESENT,
                     'duplexer' :    DUPLEXER_NOT_PRESENT,
                     'photo-tray' :  PHOTO_TRAY_NOT_PRESENT,
                     'in-tray1' :    IN_TRAY_NOT_PRESENT,
                     'in-tray2' :    IN_TRAY_NOT_PRESENT,
                     'media-path' :  MEDIA_PATH_NOT_PRESENT,
                     'status-code' : STATUS_PRINTER_IDLE,
                   }

    status_attrs = cupsext.getStatusAttributes(device_uri)

    if status_attrs:
        status_block.update(StatusTypeIPPAgents(status_attrs) )
        status_block.update(StatusTypeIPPStatus (status_attrs) )

    return status_block



Filemanager

Name Type Size Permission Actions
__pycache__ Folder 0755
pexpect Folder 0755
LedmWifi.py File 29.18 KB 0644
__init__.py File 785 B 0644
avahi.py File 3.01 KB 0644
codes.py File 30.55 KB 0644
device.py File 95.38 KB 0644
dime.py File 3.3 KB 0644
exif.py File 35.08 KB 0644
g.py File 14.19 KB 0644
imageprocessing.py File 33.14 KB 0644
imagesize.py File 5.75 KB 0644
ldif.py File 16.33 KB 0644
logger.py File 18.06 KB 0644
magic.py File 63.2 KB 0644
maint.py File 58.36 KB 0644
mdns.py File 10.04 KB 0644
mfpdtf.py File 17.34 KB 0644
models.py File 19.04 KB 0644
module.py File 28.32 KB 0644
os_utils.py File 2.28 KB 0644
password.py File 12.73 KB 0644
pkit.py File 11.45 KB 0644
pml.py File 26.46 KB 0644
queues.py File 16.35 KB 0644
services.py File 9.74 KB 0644
six.py File 22.32 KB 0644
sixext.py File 5.78 KB 0644
slp.py File 5.8 KB 0644
smart_install.py File 11.37 KB 0644
status.py File 76.35 KB 0644
strings.py File 28.21 KB 0644
tui.py File 13.79 KB 0644
utils.py File 75.97 KB 0644
validation.py File 3.68 KB 0644
vcard.py File 43.66 KB 0644
wifi.py File 22.25 KB 0644