home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / usr / share / hplip / base / status.py < prev    next >
Encoding:
Python Source  |  2011-12-02  |  63.1 KB  |  1,681 lines

  1. # -*- coding: utf-8 -*-
  2. #
  3. # (c) Copyright 2003-2007 Hewlett-Packard Development Company, L.P.
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  18. #
  19. # Author: Don Welch
  20. #
  21.  
  22. from __future__ import division
  23.  
  24. # Std Lib
  25. import struct
  26. import cStringIO
  27. import xml.parsers.expat as expat
  28. import re
  29. import urllib
  30. try:
  31.     from xml.etree import ElementTree
  32.     etree_loaded = True
  33. except ImportError:
  34.     try:
  35.         from elementtree.ElementTree import XML
  36.         elementtree_loaded = True
  37.     except ImportError:
  38.         elementtree_loaded = False
  39.     etree_loaded = False
  40.  
  41. # Local
  42. from g import *
  43. from codes import *
  44. import pml, utils
  45. import hpmudext
  46.  
  47. """
  48. status dict structure:
  49.     { 'revision' :     STATUS_REV_00 .. STATUS_REV_04,
  50.       'agents' :       [ list of pens/agents/supplies (dicts) ],
  51.       'top-door' :     TOP_DOOR_NOT_PRESENT | TOP_DOOR_CLOSED | TOP_DOOR_OPEN,
  52.       'status-code' :  STATUS_...,
  53.       'supply-door' :  SUPPLY_DOOR_NOT_PRESENT | SUPPLY_DOOR_CLOSED | SUPPLY_DOOR_OPEN.
  54.       'duplexer' :     DUPLEXER_NOT_PRESENT | DUPLEXER_DOOR_CLOSED | DUPLEXER_DOOR_OPEN,
  55.       'photo_tray' :   PHOTO_TRAY_NOT_PRESENT | PHOTO_TRAY_ENGAGED | PHOTO_TRAY_NOT_ENGAGED,
  56.       'in-tray1' :     IN_TRAY_NOT_PRESENT | IN_TRAY_CLOSED | IN_TRAY_OPEN (| IN_TRAY_DEFAULT | IN_TRAY_LOCKED)*,
  57.       'in-tray2' :     IN_TRAY_NOT_PRESENT | IN_TRAY_CLOSED | IN_TRAY_OPEN (| IN_TRAY_DEFAULT | IN_TRAY_LOCKED)*,
  58.       'media-path' :   MEDIA_PATH_NOT_PRESENT | MEDIA_PATH_CUT_SHEET | MEDIA_PATH_BANNER | MEDIA_PATH_PHOTO,
  59.     }
  60.  
  61.     * S:02 only
  62.  
  63. agent dict structure: (pens/supplies/agents/etc)
  64.     { 'kind' :           AGENT_KIND_NONE ... AGENT_KIND_ADF_KIT,
  65.       'type' :           TYPE_BLACK ... AGENT_TYPE_UNSPECIFIED,      # aka color
  66.       'health' :         AGENT_HEALTH_OK ... AGENT_HEALTH_UNKNOWN,
  67.       'level' :          0 ... 100,
  68.       'level-trigger' :  AGENT_LEVEL_TRIGGER_SUFFICIENT_0 ... AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
  69.     }
  70. """
  71.  
  72.  
  73.  
  74. # 'revision'
  75. STATUS_REV_00 = 0x00
  76. STATUS_REV_01 = 0x01
  77. STATUS_REV_02 = 0x02
  78. STATUS_REV_03 = 0x03
  79. STATUS_REV_04 = 0x04
  80. STATUS_REV_V  = 0xff
  81. STATUS_REV_UNKNOWN = 0xfe
  82.  
  83. vstatus_xlate  = {'busy' : STATUS_PRINTER_BUSY,
  84.                    'idle' : STATUS_PRINTER_IDLE,
  85.                    'prnt' : STATUS_PRINTER_PRINTING,
  86.                    'offf' : STATUS_PRINTER_TURNING_OFF,
  87.                    'rprt' : STATUS_PRINTER_REPORT_PRINTING,
  88.                    'cncl' : STATUS_PRINTER_CANCELING,
  89.                    'iost' : STATUS_PRINTER_IO_STALL,
  90.                    'dryw' : STATUS_PRINTER_DRY_WAIT_TIME,
  91.                    'penc' : STATUS_PRINTER_PEN_CHANGE,
  92.                    'oopa' : STATUS_PRINTER_OUT_OF_PAPER,
  93.                    'bnej' : STATUS_PRINTER_BANNER_EJECT,
  94.                    'bnmz' : STATUS_PRINTER_BANNER_MISMATCH,
  95.                    'phmz' : STATUS_PRINTER_PHOTO_MISMATCH,
  96.                    'dpmz' : STATUS_PRINTER_DUPLEX_MISMATCH,
  97.                    'pajm' : STATUS_PRINTER_MEDIA_JAM,
  98.                    'cars' : STATUS_PRINTER_CARRIAGE_STALL,
  99.                    'paps' : STATUS_PRINTER_PAPER_STALL,
  100.                    'penf' : STATUS_PRINTER_PEN_FAILURE,
  101.                    'erro' : STATUS_PRINTER_HARD_ERROR,
  102.                    'pwdn' : STATUS_PRINTER_POWER_DOWN,
  103.                    'fpts' : STATUS_PRINTER_FRONT_PANEL_TEST,
  104.                    'clno' : STATUS_PRINTER_CLEAN_OUT_TRAY_MISSING}
  105.  
  106. REVISION_2_TYPE_MAP = {0 : AGENT_TYPE_NONE,
  107.                         1 : AGENT_TYPE_BLACK,
  108.                         2 : AGENT_TYPE_CYAN,
  109.                         3 : AGENT_TYPE_MAGENTA,
  110.                         4 : AGENT_TYPE_YELLOW,
  111.                         5 : AGENT_TYPE_BLACK,
  112.                         6 : AGENT_TYPE_CYAN,
  113.                         7 : AGENT_TYPE_MAGENTA,
  114.                         8 : AGENT_TYPE_YELLOW,
  115.                        }
  116.  
  117. STATUS_BLOCK_UNKNOWN = {'revision' : STATUS_REV_UNKNOWN,
  118.                          'agents' : [],
  119.                          'status-code' : STATUS_UNKNOWN,
  120.                        }
  121.  
  122. NUM_PEN_POS = {STATUS_REV_00 : 16,
  123.                 STATUS_REV_01 : 16,
  124.                 STATUS_REV_02 : 16,
  125.                 STATUS_REV_03 : 18,
  126.                 STATUS_REV_04 : 22}
  127.  
  128. PEN_DATA_SIZE = {STATUS_REV_00 : 8,
  129.                   STATUS_REV_01 : 8,
  130.                   STATUS_REV_02 : 4,
  131.                   STATUS_REV_03 : 8,
  132.                   STATUS_REV_04 : 8}
  133.  
  134. STATUS_POS = {STATUS_REV_00 : 14,
  135.                STATUS_REV_01 : 14,
  136.                STATUS_REV_02 : 14,
  137.                STATUS_REV_03 : 16,
  138.                STATUS_REV_04 : 20}
  139.  
  140. def parseSStatus(s, z=''):
  141.     revision = ''
  142.     pens = []
  143.     top_door = TOP_DOOR_NOT_PRESENT
  144.     stat = STATUS_UNKNOWN
  145.     supply_door = SUPPLY_DOOR_NOT_PRESENT
  146.     duplexer = DUPLEXER_NOT_PRESENT
  147.     photo_tray = PHOTO_TRAY_NOT_PRESENT
  148.     in_tray1 = IN_TRAY_NOT_PRESENT
  149.     in_tray2 = IN_TRAY_NOT_PRESENT
  150.     media_path = MEDIA_PATH_NOT_PRESENT
  151.     Z_SIZE = 6
  152.  
  153.     try:
  154.         z1 = []
  155.         if len(z) > 0:
  156.             z_fields = z.split(',')
  157.  
  158.             for z_field in z_fields:
  159.  
  160.                 if len(z_field) > 2 and z_field[:2] == '05':
  161.                     z1s = z_field[2:]
  162.                     z1 = [int(x, 16) for x in z1s]
  163.  
  164.         s1 = [int(x, 16) for x in s]
  165.  
  166.         revision = s1[1]
  167.  
  168.         assert STATUS_REV_00 <= revision <= STATUS_REV_04
  169.  
  170.         top_door = bool(s1[2] & 0x8L) + s1[2] & 0x1L
  171.         supply_door = bool(s1[3] & 0x8L) + s1[3] & 0x1L
  172.         duplexer = bool(s1[4] & 0xcL) +  s1[4] & 0x1L
  173.         photo_tray = bool(s1[5] & 0x8L) + s1[5] & 0x1L
  174.  
  175.         if revision == STATUS_REV_02:
  176.             in_tray1 = bool(s1[6] & 0x8L) + s1[6] & 0x1L
  177.             in_tray2 = bool(s1[7] & 0x8L) + s1[7] & 0x1L
  178.         else:
  179.             in_tray1 = bool(s1[6] & 0x8L)
  180.             in_tray2 = bool(s1[7] & 0x8L)
  181.  
  182.         media_path = bool(s1[8] & 0x8L) + (s1[8] & 0x1L) + ((bool(s1[18] & 0x2L))<<1)
  183.         status_pos = STATUS_POS[revision]
  184.         status_byte = (s1[status_pos]<<4) + s1[status_pos + 1]
  185.         stat = status_byte + STATUS_PRINTER_BASE
  186.  
  187.         pen, c, d = {}, NUM_PEN_POS[revision]+1, 0
  188.         num_pens = s1[NUM_PEN_POS[revision]]
  189.         index = 0
  190.         pen_data_size = PEN_DATA_SIZE[revision]
  191.  
  192.         log.debug("num_pens = %d" % num_pens)
  193.         for p in range(num_pens):
  194.             info = long(s[c : c + pen_data_size], 16)
  195.  
  196.             pen['index'] = index
  197.  
  198.             if pen_data_size == 4:
  199.                 pen['type'] = REVISION_2_TYPE_MAP.get(int((info & 0xf000L) >> 12L), 0)
  200.  
  201.                 if index < (num_pens / 2):
  202.                     pen['kind'] = AGENT_KIND_HEAD
  203.                 else:
  204.                     pen['kind'] = AGENT_KIND_SUPPLY
  205.  
  206.                 pen['level-trigger'] = int ((info & 0x0e00L) >> 9L)
  207.                 pen['health'] = int((info & 0x0180L) >> 7L)
  208.                 pen['level'] = int(info & 0x007fL)
  209.                 pen['id'] = 0x1f
  210.  
  211.             elif pen_data_size == 8:
  212.                 pen['kind'] = bool(info & 0x80000000L) + ((bool(info & 0x40000000L))<<1L)
  213.                 pen['type'] = int((info & 0x3f000000L) >> 24L)
  214.                 pen['id'] = int((info & 0xf80000) >> 19L)
  215.                 pen['level-trigger'] = int((info & 0x70000L) >> 16L)
  216.                 pen['health'] = int((info & 0xc000L) >> 14L)
  217.                 pen['level'] = int(info & 0xffL)
  218.  
  219.             else:
  220.                 log.error("Pen data size error")
  221.  
  222.             if len(z1) > 0:
  223.                 # TODO: Determine cause of IndexError for C6100 (defect #1111)
  224.                 try:
  225.                     pen['dvc'] = long(z1s[d+1:d+5], 16)
  226.                     pen['virgin'] = bool(z1[d+5] & 0x8L)
  227.                     pen['hp-ink'] = bool(z1[d+5] & 0x4L)
  228.                     pen['known'] = bool(z1[d+5] & 0x2L)
  229.                     pen['ack'] = bool(z1[d+5] & 0x1L)
  230.                 except IndexError:
  231.                     pen['dvc'] = 0
  232.                     pen['virgin'] = 0
  233.                     pen['hp-ink'] = 0
  234.                     pen['known'] = 0
  235.                     pen['ack'] = 0
  236.  
  237.             log.debug("pen %d %s" % (index, pen))
  238.  
  239.             index += 1
  240.             pens.append(pen)
  241.             pen = {}
  242.             c += pen_data_size
  243.             d += Z_SIZE
  244.  
  245.     except (IndexError, ValueError, TypeError), e:
  246.         log.warn("Status parsing error: %s" % str(e))
  247.  
  248.     return {'revision' :    revision,
  249.              'agents' :      pens,
  250.              'top-door' :    top_door,
  251.              'status-code' : stat,
  252.              'supply-door' : supply_door,
  253.              'duplexer' :    duplexer,
  254.              'photo-tray' :  photo_tray,
  255.              'in-tray1' :    in_tray1,
  256.              'in-tray2' :    in_tray2,
  257.              'media-path' :  media_path,
  258.            }
  259.  
  260.  
  261.  
  262. # $HB0$NC0,ff,DN,IDLE,CUT,K0,C0,DP,NR,KP092,CP041
  263. #     0    1  2  3    4   5  6  7  8  9     10
  264. def parseVStatus(s):
  265.     pens, pen, c = [], {}, 0
  266.     fields = s.split(',')
  267.     log.debug(fields)
  268.     f0 = fields[0]
  269.  
  270.     if len(f0) == 20:
  271.         # TODO: $H00000000$M00000000 style (OJ Pro 1150/70)
  272.         # Need spec
  273.         pass
  274.     elif len(f0) == 8:
  275.         for p in f0:
  276.             if c == 0:
  277.                 #assert p == '$'
  278.                 c += 1
  279.             elif c == 1:
  280.                 if p in ('a', 'A'):
  281.                     pen['type'], pen['kind'] = AGENT_TYPE_NONE, AGENT_KIND_NONE
  282.                 c += 1
  283.             elif c == 2:
  284.                 pen['health'] = AGENT_HEALTH_OK
  285.                 pen['kind'] = AGENT_KIND_HEAD_AND_SUPPLY
  286.                 if   p in ('b', 'B'): pen['type'] = AGENT_TYPE_BLACK
  287.                 elif p in ('c', 'C'): pen['type'] = AGENT_TYPE_CMY
  288.                 elif p in ('d', 'D'): pen['type'] = AGENT_TYPE_KCM
  289.                 elif p in ('u', 'U'): pen['type'], pen['health'] = AGENT_TYPE_NONE, AGENT_HEALTH_MISINSTALLED
  290.                 c += 1
  291.             elif c == 3:
  292.                 if p == '0': pen['state'] = 1
  293.                 else: pen['state'] = 0
  294.  
  295.                 pen['level'] = 0
  296.                 i = 8
  297.  
  298.                 while True:
  299.                     try:
  300.                         f = fields[i]
  301.                     except IndexError:
  302.                         break
  303.                     else:
  304.                         if f[:2] == 'KP' and pen['type'] == AGENT_TYPE_BLACK:
  305.                             pen['level'] = int(f[2:])
  306.                         elif f[:2] == 'CP' and pen['type'] == AGENT_TYPE_CMY:
  307.                             pen['level'] = int(f[2:])
  308.                     i += 1
  309.  
  310.                 pens.append(pen)
  311.                 pen = {}
  312.                 c = 0
  313.     else:
  314.         pass
  315.  
  316.     try:
  317.         fields[2]
  318.     except IndexError:
  319.         top_lid = 1 # something went wrong!
  320.     else:
  321.         if fields[2] == 'DN':
  322.             top_lid = 1
  323.         else:
  324.             top_lid = 2
  325.  
  326.     try:
  327.         stat = vstatus_xlate.get(fields[3].lower(), STATUS_PRINTER_IDLE)
  328.     except IndexError:
  329.         stat = STATUS_PRINTER_IDLE # something went wrong!
  330.  
  331.     return {'revision' :   STATUS_REV_V,
  332.              'agents' :     pens,
  333.              'top-door' :   top_lid,
  334.              'status-code': stat,
  335.              'supply-door': SUPPLY_DOOR_NOT_PRESENT,
  336.              'duplexer' :   DUPLEXER_NOT_PRESENT,
  337.              'photo-tray' : PHOTO_TRAY_NOT_PRESENT,
  338.              'in-tray1' :   IN_TRAY_NOT_PRESENT,
  339.              'in-tray2' :   IN_TRAY_NOT_PRESENT,
  340.              'media-path' : MEDIA_PATH_CUT_SHEET, # ?
  341.            }
  342.  
  343.  
  344. def parseStatus(DeviceID):
  345.     if 'VSTATUS' in DeviceID:
  346.          return parseVStatus(DeviceID['VSTATUS'])
  347.     elif 'S' in DeviceID:
  348.         return parseSStatus(DeviceID['S'], DeviceID.get('Z', ''))
  349.     else:
  350.         return STATUS_BLOCK_UNKNOWN
  351.  
  352. def LaserJetDeviceStatusToPrinterStatus(device_status, printer_status, detected_error_state):
  353.     stat = STATUS_PRINTER_IDLE
  354.  
  355.     if device_status in (pml.DEVICE_STATUS_WARNING, pml.DEVICE_STATUS_DOWN):
  356.  
  357.         if detected_error_state & pml.DETECTED_ERROR_STATE_LOW_PAPER_MASK and \
  358.             not (detected_error_state & pml.DETECTED_ERROR_STATE_NO_PAPER_MASK):
  359.             stat = STATUS_PRINTER_LOW_PAPER
  360.  
  361.         elif detected_error_state & pml.DETECTED_ERROR_STATE_NO_PAPER_MASK:
  362.             stat = STATUS_PRINTER_OUT_OF_PAPER
  363.  
  364.         elif detected_error_state & pml.DETECTED_ERROR_STATE_DOOR_OPEN_MASK:
  365.             stat = STATUS_PRINTER_DOOR_OPEN
  366.  
  367.         elif detected_error_state & pml.DETECTED_ERROR_STATE_JAMMED_MASK:
  368.             stat = STATUS_PRINTER_MEDIA_JAM
  369.  
  370.         elif detected_error_state & pml.DETECTED_ERROR_STATE_OUT_CART_MASK:
  371.             stat = STATUS_PRINTER_NO_TONER
  372.  
  373.         elif detected_error_state & pml.DETECTED_ERROR_STATE_LOW_CART_MASK:
  374.             stat = STATUS_PRINTER_LOW_TONER
  375.  
  376.         elif detected_error_state == pml.DETECTED_ERROR_STATE_SERVICE_REQUEST_MASK:
  377.             stat = STATUS_PRINTER_SERVICE_REQUEST
  378.  
  379.         elif detected_error_state & pml.DETECTED_ERROR_STATE_OFFLINE_MASK:
  380.             stat = STATUS_PRINTER_OFFLINE
  381.  
  382.     else:
  383.  
  384.         if printer_status == pml.PRINTER_STATUS_IDLE:
  385.             stat = STATUS_PRINTER_IDLE
  386.  
  387.         elif printer_status == pml.PRINTER_STATUS_PRINTING:
  388.             stat = STATUS_PRINTER_PRINTING
  389.  
  390.         elif printer_status == pml.PRINTER_STATUS_WARMUP:
  391.             stat = STATUS_PRINTER_WARMING_UP
  392.  
  393.     return stat
  394.  
  395. # Map from ISO 10175/10180 to HPLIP types
  396. COLORANT_INDEX_TO_AGENT_TYPE_MAP = {
  397.                                     'other' :   AGENT_TYPE_UNSPECIFIED,
  398.                                     'unknown' : AGENT_TYPE_UNSPECIFIED,
  399.                                     'blue' :    AGENT_TYPE_BLUE,
  400.                                     'cyan' :    AGENT_TYPE_CYAN,
  401.                                     'magenta':  AGENT_TYPE_MAGENTA,
  402.                                     'yellow' :  AGENT_TYPE_YELLOW,
  403.                                     'black' :   AGENT_TYPE_BLACK,
  404.                                    }
  405.  
  406. MARKER_SUPPLES_TYPE_TO_AGENT_KIND_MAP = {
  407.     pml.OID_MARKER_SUPPLIES_TYPE_OTHER :              AGENT_KIND_UNKNOWN,
  408.     pml.OID_MARKER_SUPPLIES_TYPE_UNKNOWN :            AGENT_KIND_UNKNOWN,
  409.     pml.OID_MARKER_SUPPLIES_TYPE_TONER :              AGENT_KIND_TONER_CARTRIDGE,
  410.     pml.OID_MARKER_SUPPLIES_TYPE_WASTE_TONER :        AGENT_KIND_UNKNOWN,
  411.     pml.OID_MARKER_SUPPLIES_TYPE_INK :                AGENT_KIND_SUPPLY,
  412.     pml.OID_MARKER_SUPPLIES_TYPE_INK_CART :           AGENT_KIND_HEAD_AND_SUPPLY,
  413.     pml.OID_MARKER_SUPPLIES_TYPE_INK_RIBBON :         AGENT_KIND_HEAD_AND_SUPPLY,
  414.     pml.OID_MARKER_SUPPLIES_TYPE_WASTE_INK :          AGENT_KIND_UNKNOWN,
  415.     pml.OID_MARKER_SUPPLIES_TYPE_OPC :                AGENT_KIND_DRUM_KIT,
  416.     pml.OID_MARKER_SUPPLIES_TYPE_DEVELOPER :          AGENT_KIND_UNKNOWN,
  417.     pml.OID_MARKER_SUPPLIES_TYPE_FUSER_OIL :          AGENT_KIND_UNKNOWN,
  418.     pml.OID_MARKER_SUPPLIES_TYPE_SOLID_WAX :          AGENT_KIND_UNKNOWN,
  419.     pml.OID_MARKER_SUPPLIES_TYPE_RIBBON_WAX :         AGENT_KIND_UNKNOWN,
  420.     pml.OID_MARKER_SUPPLIES_TYPE_WASTE_WAX :          AGENT_KIND_UNKNOWN,
  421.     pml.OID_MARKER_SUPPLIES_TYPE_FUSER :              AGENT_KIND_MAINT_KIT,
  422.     pml.OID_MARKER_SUPPLIES_TYPE_CORONA_WIRE :        AGENT_KIND_UNKNOWN,
  423.     pml.OID_MARKER_SUPPLIES_TYPE_FUSER_OIL_WICK :     AGENT_KIND_UNKNOWN,
  424.     pml.OID_MARKER_SUPPLIES_TYPE_CLEANER_UNIT :       AGENT_KIND_UNKNOWN,
  425.     pml.OID_MARKER_SUPPLIES_TYPE_FUSER_CLEANING_PAD : AGENT_KIND_UNKNOWN,
  426.     pml.OID_MARKER_SUPPLIES_TYPE_TRANSFER_UNIT :      AGENT_KIND_TRANSFER_KIT,
  427.     pml.OID_MARKER_SUPPLIES_TYPE_TONER_CART :         AGENT_KIND_TONER_CARTRIDGE,
  428.     pml.OID_MARKER_SUPPLIES_TYPE_FUSER_OILER :        AGENT_KIND_UNKNOWN,
  429.     pml.OID_MARKER_SUPPLIES_TYPE_ADF_MAINT_KIT :      AGENT_KIND_ADF_KIT,
  430. }
  431.  
  432.  
  433. def StatusType3( dev, parsedID ): # LaserJet Status (PML/SNMP)
  434.     try:
  435.         dev.openPML()
  436.         #result_code, on_off_line = dev.getPML( pml.OID_ON_OFF_LINE, pml.INT_SIZE_BYTE )
  437.         #result_code, sleep_mode = dev.getPML( pml.OID_SLEEP_MODE, pml.INT_SIZE_BYTE )
  438.         result_code, printer_status = dev.getPML( pml.OID_PRINTER_STATUS, pml.INT_SIZE_BYTE )
  439.         result_code, device_status = dev.getPML( pml.OID_DEVICE_STATUS, pml.INT_SIZE_BYTE )
  440.         result_code, cover_status = dev.getPML( pml.OID_COVER_STATUS, pml.INT_SIZE_BYTE )
  441.         result_code, value = dev.getPML( pml.OID_DETECTED_ERROR_STATE )
  442.     except Error:
  443.        dev.closePML()
  444.  
  445.        return {'revision' :    STATUS_REV_UNKNOWN,
  446.                  'agents' :      [],
  447.                  'top-door' :    0,
  448.                  'status-code' : STATUS_UNKNOWN,
  449.                  'supply-door' : 0,
  450.                  'duplexer' :    1,
  451.                  'photo-tray' :  0,
  452.                  'in-tray1' :    0,
  453.                  'in-tray2' :    0,
  454.                  'media-path' :  0,
  455.                }
  456.  
  457.     try:
  458.         detected_error_state = struct.unpack( 'B', value[0])[0]
  459.     except (IndexError, TypeError):
  460.         detected_error_state = pml.DETECTED_ERROR_STATE_OFFLINE_MASK
  461.  
  462.     agents, x = [], 1
  463.  
  464.     while True:
  465.         log.debug( "%s Agent: %d %s" % ("*"*10, x, "*"*10))
  466.         log.debug("OID_MARKER_SUPPLIES_TYPE_%d:" % x)
  467.         oid = ( pml.OID_MARKER_SUPPLIES_TYPE_x % x, pml.OID_MARKER_SUPPLIES_TYPE_x_TYPE )
  468.         result_code, value = dev.getPML( oid, pml.INT_SIZE_BYTE )
  469.  
  470.         if result_code != ERROR_SUCCESS or value is None:
  471.             log.debug("End of supply information.")
  472.             break
  473.  
  474.         for a in MARKER_SUPPLES_TYPE_TO_AGENT_KIND_MAP:
  475.             if value == a:
  476.                 agent_kind = MARKER_SUPPLES_TYPE_TO_AGENT_KIND_MAP[a]
  477.                 break
  478.         else:
  479.             agent_kind = AGENT_KIND_UNKNOWN
  480.  
  481.         # TODO: Deal with printers that return -1 and -2 for level and max (LJ3380)
  482.  
  483.         log.debug("OID_MARKER_SUPPLIES_LEVEL_%d:" % x)
  484.         oid = ( pml.OID_MARKER_SUPPLIES_LEVEL_x % x, pml.OID_MARKER_SUPPLIES_LEVEL_x_TYPE )
  485.         result_code, agent_level = dev.getPML( oid )
  486.  
  487.         if result_code != ERROR_SUCCESS:
  488.             log.debug("Failed")
  489.             break
  490.  
  491.         log.debug( 'agent%d-level: %d' % ( x, agent_level ) )
  492.         log.debug("OID_MARKER_SUPPLIES_MAX_%d:" % x)
  493.         oid = ( pml.OID_MARKER_SUPPLIES_MAX_x % x, pml.OID_MARKER_SUPPLIES_MAX_x_TYPE )
  494.         result_code, agent_max = dev.getPML( oid )
  495.  
  496.         if agent_max == 0: agent_max = 1
  497.  
  498.         if result_code != ERROR_SUCCESS:
  499.             log.debug("Failed")
  500.             break
  501.  
  502.         log.debug( 'agent%d-max: %d' % ( x, agent_max ) )
  503.         log.debug("OID_MARKER_SUPPLIES_COLORANT_INDEX_%d:" % x)
  504.         oid = ( pml.OID_MARKER_SUPPLIES_COLORANT_INDEX_x % x, pml.OID_MARKER_SUPPLIES_COLORANT_INDEX_x_TYPE )
  505.         result_code, colorant_index = dev.getPML( oid )
  506.  
  507.         if result_code != ERROR_SUCCESS: # 3080, 3055 will fail here
  508.             log.debug("Failed")
  509.             agent_type = AGENT_TYPE_BLACK
  510.             #break
  511.         else:
  512.             log.debug("Colorant index: %d" % colorant_index)
  513.  
  514.             log.debug("OID_MARKER_COLORANT_VALUE_%d" % x)
  515.             oid = ( pml.OID_MARKER_COLORANT_VALUE_x % colorant_index, pml.OID_MARKER_COLORANT_VALUE_x_TYPE )
  516.             result_code, colorant_value = dev.getPML( oid )
  517.  
  518.             if result_code != ERROR_SUCCESS:
  519.                 log.debug("Failed. Defaulting to black.")
  520.                 agent_type = AGENT_TYPE_BLACK
  521.             #else:
  522.             if 1:
  523.                 if agent_kind in (AGENT_KIND_MAINT_KIT, AGENT_KIND_ADF_KIT,
  524.                                   AGENT_KIND_DRUM_KIT, AGENT_KIND_TRANSFER_KIT):
  525.  
  526.                     agent_type = AGENT_TYPE_UNSPECIFIED
  527.  
  528.                 else:
  529.                     agent_type = AGENT_TYPE_BLACK
  530.  
  531.                     if result_code != ERROR_SUCCESS:
  532.                         log.debug("OID_MARKER_SUPPLIES_DESCRIPTION_%d:" % x)
  533.                         oid = (pml.OID_MARKER_SUPPLIES_DESCRIPTION_x % x, pml.OID_MARKER_SUPPLIES_DESCRIPTION_x_TYPE)
  534.                         result_code, colorant_value = dev.getPML( oid )
  535.  
  536.                         if result_code != ERROR_SUCCESS:
  537.                             log.debug("Failed")
  538.                             break
  539.  
  540.                         if colorant_value is not None:
  541.                             log.debug("colorant value: %s" % colorant_value)
  542.                             colorant_value = colorant_value.lower().strip()
  543.  
  544.                             for c in COLORANT_INDEX_TO_AGENT_TYPE_MAP:
  545.                                 if colorant_value.find(c) >= 0:
  546.                                     agent_type = COLORANT_INDEX_TO_AGENT_TYPE_MAP[c]
  547.                                     break
  548.                             else:
  549.                                 agent_type = AGENT_TYPE_BLACK
  550.  
  551.                     else: # SUCCESS
  552.                         if colorant_value is not None:
  553.                             log.debug("colorant value: %s" % colorant_value)
  554.                             agent_type = COLORANT_INDEX_TO_AGENT_TYPE_MAP.get( colorant_value, AGENT_TYPE_BLACK )
  555.  
  556.                         if agent_type == AGENT_TYPE_NONE:
  557.                             if agent_kind == AGENT_KIND_TONER_CARTRIDGE:
  558.                                 agent_type = AGENT_TYPE_BLACK
  559.                             else:
  560.                                 agent_type = AGENT_TYPE_UNSPECIFIED
  561.  
  562.         log.debug("OID_MARKER_STATUS_%d:" % x)
  563.         oid = ( pml.OID_MARKER_STATUS_x % x, pml.OID_MARKER_STATUS_x_TYPE )
  564.         result_code, agent_status = dev.getPML( oid )
  565.  
  566.         if result_code != ERROR_SUCCESS:
  567.             log.debug("Failed")
  568.             agent_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
  569.             agent_health = AGENT_HEALTH_OK
  570.         else:
  571.             agent_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
  572.  
  573.             if agent_status is None:
  574.                 agent_health = AGENT_HEALTH_OK
  575.  
  576.             elif agent_status == pml.OID_MARKER_STATUS_OK:
  577.                 agent_health = AGENT_HEALTH_OK
  578.  
  579.             elif agent_status == pml.OID_MARKER_STATUS_MISINSTALLED:
  580.                 agent_health = AGENT_HEALTH_MISINSTALLED
  581.  
  582.             elif agent_status in ( pml.OID_MARKER_STATUS_LOW_TONER_CONT,
  583.                                    pml.OID_MARKER_STATUS_LOW_TONER_STOP ):
  584.  
  585.                 agent_health = AGENT_HEALTH_OK
  586.                 agent_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW
  587.  
  588.             else:
  589.                 agent_health = AGENT_HEALTH_OK
  590.  
  591.         agent_level = int(agent_level/agent_max * 100)
  592.  
  593.         log.debug("agent%d: kind=%d, type=%d, health=%d, level=%d, level-trigger=%d" % \
  594.             (x, agent_kind, agent_type, agent_health, agent_level, agent_trigger))
  595.  
  596.  
  597.         agents.append({'kind' : agent_kind,
  598.                        'type' : agent_type,
  599.                        'health' : agent_health,
  600.                        'level' : agent_level,
  601.                        'level-trigger' : agent_trigger,})
  602.  
  603.         x += 1
  604.  
  605.         if x > 20:
  606.             break
  607.  
  608.  
  609.     printer_status = printer_status or STATUS_PRINTER_IDLE
  610.     log.debug("printer_status=%d" % printer_status)
  611.     device_status = device_status or pml.DEVICE_STATUS_RUNNING
  612.     log.debug("device_status=%d" % device_status)
  613.     cover_status = cover_status or pml.COVER_STATUS_CLOSED
  614.     log.debug("cover_status=%d" % cover_status)
  615.     detected_error_state = detected_error_state or pml.DETECTED_ERROR_STATE_NO_ERROR
  616.     log.debug("detected_error_state=%d (0x%x)" % (detected_error_state, detected_error_state))
  617.  
  618.     stat = LaserJetDeviceStatusToPrinterStatus(device_status, printer_status, detected_error_state)
  619.  
  620.     log.debug("Printer status=%d" % stat)
  621.  
  622.     if stat == STATUS_PRINTER_DOOR_OPEN:
  623.         supply_door = 0
  624.     else:
  625.         supply_door = 1
  626.  
  627.     return {'revision' :    STATUS_REV_UNKNOWN,
  628.              'agents' :      agents,
  629.              'top-door' :    cover_status,
  630.              'status-code' : stat,
  631.              'supply-door' : supply_door,
  632.              'duplexer' :    1,
  633.              'photo-tray' :  0,
  634.              'in-tray1' :    1,
  635.              'in-tray2' :    1,
  636.              'media-path' :  1,
  637.            }
  638.  
  639. def setup_panel_translator():
  640.     printables = list(
  641. """0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
  642. !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~""")
  643.  
  644.     map = {}
  645.     for x in [chr(x) for x in range(0,256)]:
  646.         if x in printables:
  647.             map[x] = x
  648.         else:
  649.             map[x] = '\x20'
  650.  
  651.     map.update({'\x10' : '\xab',
  652.                     '\x11' : '\xbb',
  653.                     '\x12' : '\xa3',
  654.                     '\x13' : '\xbb',
  655.                     '\x80' : '\xab',
  656.                     '\x81' : '\xbb',
  657.                     '\x82' : '\x2a',
  658.                     '\x83' : '\x2a',
  659.                     '\x85' : '\x2a',
  660.                     '\xa0' : '\xab',
  661.                     '\x1f' : '\x3f',
  662.                     '='    : '\x20',
  663.                 })
  664.  
  665.     frm, to = '', ''
  666.     map_keys = map.keys()
  667.     map_keys.sort()
  668.     for x in map_keys:
  669.         frm = ''.join([frm, x])
  670.         to = ''.join([to, map[x]])
  671.  
  672.     global PANEL_TRANSLATOR_FUNC
  673.     PANEL_TRANSLATOR_FUNC = utils.Translator(frm, to)
  674.  
  675. PANEL_TRANSLATOR_FUNC = None
  676. setup_panel_translator()
  677.  
  678.  
  679. def PanelCheck(dev):
  680.     line1, line2 = '', ''
  681.  
  682.     if dev.io_mode not in (IO_MODE_RAW, IO_MODE_UNI):
  683.  
  684.         try:
  685.             dev.openPML()
  686.         except Error:
  687.             pass
  688.         else:
  689.  
  690.             oids = [(pml.OID_HP_LINE1, pml.OID_HP_LINE2),
  691.                      (pml.OID_SPM_LINE1, pml.OID_SPM_LINE2)]
  692.  
  693.             for oid1, oid2 in oids:
  694.                 result, line1 = dev.getPML(oid1)
  695.  
  696.                 if result < pml.ERROR_MAX_OK:
  697.                     line1 = PANEL_TRANSLATOR_FUNC(line1).rstrip()
  698.  
  699.                     if '\x0a' in line1:
  700.                         line1, line2 = line1.split('\x0a', 1)
  701.                         break
  702.  
  703.                     result, line2 = dev.getPML(oid2)
  704.  
  705.                     if result < pml.ERROR_MAX_OK:
  706.                         line2 = PANEL_TRANSLATOR_FUNC(line2).rstrip()
  707.                         break
  708.  
  709.     return bool(line1 or line2), line1 or '', line2 or ''
  710.  
  711.  
  712. BATTERY_HEALTH_MAP = {0 : AGENT_HEALTH_OK,
  713.                        1 : AGENT_HEALTH_OVERTEMP,
  714.                        2 : AGENT_HEALTH_CHARGING,
  715.                        3 : AGENT_HEALTH_MISINSTALLED,
  716.                        4 : AGENT_HEALTH_FAILED,
  717.                       }
  718.  
  719.  
  720. BATTERY_TRIGGER_MAP = {0 : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  721.                         1 : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
  722.                         2 : AGENT_LEVEL_TRIGGER_PROBABLY_OUT,
  723.                         3 : AGENT_LEVEL_TRIGGER_SUFFICIENT_4,
  724.                         4 : AGENT_LEVEL_TRIGGER_SUFFICIENT_2,
  725.                         5 : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  726.                        }
  727.  
  728. BATTERY_PML_TRIGGER_MAP = {
  729.         (100, 80)  : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  730.         (79,  60)  : AGENT_LEVEL_TRIGGER_SUFFICIENT_1,
  731.         (59,  40)  : AGENT_LEVEL_TRIGGER_SUFFICIENT_2,
  732.         (39,  30)  : AGENT_LEVEL_TRIGGER_SUFFICIENT_3,
  733.         (29,  20)  : AGENT_LEVEL_TRIGGER_SUFFICIENT_4,
  734.         (19,  10)  : AGENT_LEVEL_TRIGGER_MAY_BE_LOW,
  735.         (9,    5)  : AGENT_LEVEL_TRIGGER_PROBABLY_OUT,
  736.         (4,   -1)  : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
  737.         }
  738.  
  739.  
  740. def BatteryCheck(dev, status_block, battery_check):
  741.     try_dynamic_counters = False
  742.  
  743.     try:
  744.         try:
  745.             dev.openPML()
  746.         except Error:
  747.             if battery_check == STATUS_BATTERY_CHECK_STD:
  748.                 log.debug("PML channel open failed. Trying dynamic counters...")
  749.                 try_dynamic_counters = True
  750.         else:
  751.             if battery_check == STATUS_BATTERY_CHECK_PML:
  752.                 result, battery_level = dev.getPML(pml.OID_BATTERY_LEVEL_2)
  753.  
  754.                 if result > pml.ERROR_MAX_OK:
  755.                     status_block['agents'].append({
  756.                         'kind'   : AGENT_KIND_INT_BATTERY,
  757.                         'type'   : AGENT_TYPE_UNSPECIFIED,
  758.                         'health' : AGENT_HEALTH_UNKNOWN,
  759.                         'level'  : 0,
  760.                         'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  761.                         })
  762.                     return
  763.  
  764.                 else:
  765.                     status_block['agents'].append({
  766.                         'kind'   : AGENT_KIND_INT_BATTERY,
  767.                         'type'   : AGENT_TYPE_UNSPECIFIED,
  768.                         'health' : AGENT_HEALTH_OK,
  769.                         'level'  : battery_level,
  770.                         'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  771.                         })
  772.                     return
  773.  
  774.             else: # STATUS_BATTERY_CHECK_STD
  775.                 result, battery_level = dev.getPML(pml.OID_BATTERY_LEVEL)
  776.                 result, power_mode =  dev.getPML(pml.OID_POWER_MODE)
  777.  
  778.                 if battery_level is not None and \
  779.                     power_mode is not None:
  780.  
  781.                     if power_mode & pml.POWER_MODE_BATTERY_LEVEL_KNOWN and \
  782.                         battery_level >= 0:
  783.  
  784.                         for x in BATTERY_PML_TRIGGER_MAP:
  785.                             if x[0] >= battery_level > x[1]:
  786.                                 battery_trigger_level = BATTERY_PML_TRIGGER_MAP[x]
  787.                                 break
  788.  
  789.                         if power_mode & pml.POWER_MODE_CHARGING:
  790.                             agent_health = AGENT_HEALTH_CHARGING
  791.  
  792.                         elif power_mode & pml.POWER_MODE_DISCHARGING:
  793.                             agent_health = AGENT_HEALTH_DISCHARGING
  794.  
  795.                         else:
  796.                             agent_health = AGENT_HEALTH_OK
  797.  
  798.                         status_block['agents'].append({
  799.                             'kind'   : AGENT_KIND_INT_BATTERY,
  800.                             'type'   : AGENT_TYPE_UNSPECIFIED,
  801.                             'health' : agent_health,
  802.                             'level'  : battery_level,
  803.                             'level-trigger' : battery_trigger_level,
  804.                             })
  805.                         return
  806.  
  807.                     else:
  808.                         status_block['agents'].append({
  809.                             'kind'   : AGENT_KIND_INT_BATTERY,
  810.                             'type'   : AGENT_TYPE_UNSPECIFIED,
  811.                             'health' : AGENT_HEALTH_UNKNOWN,
  812.                             'level'  : 0,
  813.                             'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  814.                             })
  815.                         return
  816.  
  817.                 else:
  818.                     try_dynamic_counters = True
  819.  
  820.     finally:
  821.         dev.closePML()
  822.  
  823.  
  824.     if battery_check == STATUS_BATTERY_CHECK_STD and \
  825.         try_dynamic_counters:
  826.  
  827.         try:
  828.             try:
  829.                 battery_health = dev.getDynamicCounter(200)
  830.                 battery_trigger_level = dev.getDynamicCounter(201)
  831.                 battery_level = dev.getDynamicCounter(202)
  832.  
  833.                 status_block['agents'].append({
  834.                     'kind'   : AGENT_KIND_INT_BATTERY,
  835.                     'type'   : AGENT_TYPE_UNSPECIFIED,
  836.                     'health' : BATTERY_HEALTH_MAP[battery_health],
  837.                     'level'  : battery_level,
  838.                     'level-trigger' : BATTERY_TRIGGER_MAP[battery_trigger_level],
  839.                     })
  840.             except Error:
  841.                 status_block['agents'].append({
  842.                     'kind'   : AGENT_KIND_INT_BATTERY,
  843.                     'type'   : AGENT_TYPE_UNSPECIFIED,
  844.                     'health' : AGENT_HEALTH_UNKNOWN,
  845.                     'level'  : 0,
  846.                     'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  847.                     })
  848.         finally:
  849.             dev.closePrint()
  850.  
  851.     else:
  852.         status_block['agents'].append({
  853.             'kind'   : AGENT_KIND_INT_BATTERY,
  854.             'type'   : AGENT_TYPE_UNSPECIFIED,
  855.             'health' : AGENT_HEALTH_UNKNOWN,
  856.             'level'  : 0,
  857.             'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  858.             })
  859.  
  860.  
  861.  
  862. # this works for 2 pen products that allow 1 or 2 pens inserted
  863. # from: k, kcm, cmy, ggk
  864. def getPenConfiguration(s): # s=status dict from parsed device ID
  865.     pens = [p['type'] for p in s['agents']]
  866.  
  867.     if utils.all(pens, lambda x : x==AGENT_TYPE_NONE):
  868.         return AGENT_CONFIG_NONE
  869.  
  870.     if AGENT_TYPE_NONE in pens:
  871.  
  872.         if AGENT_TYPE_BLACK in pens:
  873.             return AGENT_CONFIG_BLACK_ONLY
  874.  
  875.         elif AGENT_TYPE_CMY in pens:
  876.             return AGENT_CONFIG_COLOR_ONLY
  877.  
  878.         elif AGENT_TYPE_KCM in pens:
  879.             return AGENT_CONFIG_PHOTO_ONLY
  880.  
  881.         elif AGENT_TYPE_GGK in pens:
  882.             return AGENT_CONFIG_GREY_ONLY
  883.  
  884.         else:
  885.             return AGENT_CONFIG_INVALID
  886.  
  887.     else:
  888.         if AGENT_TYPE_BLACK in pens and AGENT_TYPE_CMY in pens:
  889.             return AGENT_CONFIG_COLOR_AND_BLACK
  890.  
  891.         elif AGENT_TYPE_CMY in pens and AGENT_TYPE_KCM in pens:
  892.             return AGENT_CONFIG_COLOR_AND_PHOTO
  893.  
  894.         elif AGENT_TYPE_CMY in pens and AGENT_TYPE_GGK in pens:
  895.             return AGENT_CONFIG_COLOR_AND_GREY
  896.  
  897.         else:
  898.             return AGENT_CONFIG_INVALID
  899.  
  900.  
  901. def getFaxStatus(dev):
  902.     tx_active, rx_active = False, False
  903.  
  904.     if dev.io_mode not in (IO_MODE_UNI, IO_MODE_RAW):
  905.         try:
  906.             dev.openPML()
  907.  
  908.             result_code, tx_state = dev.getPML(pml.OID_FAXJOB_TX_STATUS)
  909.  
  910.             if result_code == ERROR_SUCCESS and tx_state:
  911.                 if tx_state not in (pml.FAXJOB_TX_STATUS_IDLE, pml.FAXJOB_TX_STATUS_DONE):
  912.                     tx_active = True
  913.  
  914.             result_code, rx_state = dev.getPML(pml.OID_FAXJOB_RX_STATUS)
  915.  
  916.             if result_code == ERROR_SUCCESS and rx_state:
  917.                 if rx_state not in (pml.FAXJOB_RX_STATUS_IDLE, pml.FAXJOB_RX_STATUS_DONE):
  918.                     rx_active = True
  919.  
  920.         finally:
  921.             dev.closePML()
  922.  
  923.     return tx_active, rx_active
  924.  
  925.  
  926. TYPE6_STATUS_CODE_MAP = {
  927.      0    : STATUS_PRINTER_IDLE, #</DevStatusUnknown>
  928.     -19928: STATUS_PRINTER_IDLE,
  929.     -18995: STATUS_PRINTER_CANCELING,
  930.     -17974: STATUS_PRINTER_WARMING_UP,
  931.     -17973: STATUS_PRINTER_PEN_CLEANING, # sic
  932.     -18993: STATUS_PRINTER_BUSY,
  933.     -17949: STATUS_PRINTER_BUSY,
  934.     -19720: STATUS_PRINTER_MANUAL_DUPLEX_BLOCK,
  935.     -19678: STATUS_PRINTER_BUSY,
  936.     -19695: STATUS_PRINTER_OUT_OF_PAPER,
  937.     -17985: STATUS_PRINTER_MEDIA_JAM,
  938.     -19731: STATUS_PRINTER_OUT_OF_PAPER,
  939.     -18974: STATUS_PRINTER_BUSY, #?
  940.     -19730: STATUS_PRINTER_OUT_OF_PAPER,
  941.     -19729: STATUS_PRINTER_OUT_OF_PAPER,
  942.     -19933: STATUS_PRINTER_HARD_ERROR, # out of memory
  943.     -17984: STATUS_PRINTER_DOOR_OPEN,
  944.     -19694: STATUS_PRINTER_DOOR_OPEN,
  945.     -18992: STATUS_PRINTER_MANUAL_FEED_BLOCKED, # ?
  946.     -19690: STATUS_PRINTER_MEDIA_JAM, # tray 1
  947.     -19689: STATUS_PRINTER_MEDIA_JAM, # tray 2
  948.     -19611: STATUS_PRINTER_MEDIA_JAM, # tray 3
  949.     -19686: STATUS_PRINTER_MEDIA_JAM,
  950.     -19688: STATUS_PRINTER_MEDIA_JAM, # paper path
  951.     -19685: STATUS_PRINTER_MEDIA_JAM, # cart area
  952.     -19684: STATUS_PRINTER_MEDIA_JAM, # output bin
  953.     -18848: STATUS_PRINTER_MEDIA_JAM, # duplexer
  954.     -18847: STATUS_PRINTER_MEDIA_JAM, # door open
  955.     -18846: STATUS_PRINTER_MEDIA_JAM, # tray 2
  956.     -19687: STATUS_PRINTER_MEDIA_JAM, # open door
  957.     -17992: STATUS_PRINTER_MEDIA_JAM, # mispick
  958.     -19700: STATUS_PRINTER_HARD_ERROR, # invalid driver
  959.     -17996: STATUS_PRINTER_FUSER_ERROR, # fuser error
  960.     -17983: STATUS_PRINTER_FUSER_ERROR,
  961.     -17982: STATUS_PRINTER_FUSER_ERROR,
  962.     -17981: STATUS_PRINTER_FUSER_ERROR,
  963.     -17971: STATUS_PRINTER_FUSER_ERROR,
  964.     -17995: STATUS_PRINTER_HARD_ERROR, # beam error
  965.     -17994: STATUS_PRINTER_HARD_ERROR, # scanner error
  966.     -17993: STATUS_PRINTER_HARD_ERROR, # fan error
  967.     -18994: STATUS_PRINTER_HARD_ERROR,
  968.     -17986: STATUS_PRINTER_HARD_ERROR,
  969.     -19904: STATUS_PRINTER_HARD_ERROR,
  970.     -19701: STATUS_PRINTER_NON_HP_INK, # [sic]
  971.     -19613: STATUS_PRINTER_IDLE, # HP
  972.     -19654: STATUS_PRINTER_NON_HP_INK, # [sic]
  973.     -19682: STATUS_PRINTER_HARD_ERROR, # resinstall
  974.     -19693: STATUS_PRINTER_IDLE, # ?? To Accept
  975.     -19752: STATUS_PRINTER_LOW_TONER,
  976.     -19723: STATUS_PRINTER_BUSY,
  977.     -19703: STATUS_PRINTER_BUSY,
  978.     -19739: STATUS_PRINTER_NO_TONER,
  979.     -19927: STATUS_PRINTER_BUSY,
  980.     -19932: STATUS_PRINTER_BUSY,
  981.     -19931: STATUS_PRINTER_BUSY,
  982.     -11989: STATUS_PRINTER_BUSY,
  983.     -11995: STATUS_PRINTER_BUSY, # ADF loaded
  984.     -19954: STATUS_PRINTER_CANCELING,
  985.     -19955: STATUS_PRINTER_REPORT_PRINTING,
  986.     -19956: STATUS_PRINTER_REPORT_PRINTING,
  987.     -19934: STATUS_PRINTER_HARD_ERROR,
  988.     -19930: STATUS_PRINTER_BUSY,
  989.     -11990: STATUS_PRINTER_DOOR_OPEN,
  990.     -11999: STATUS_PRINTER_MEDIA_JAM, # ADF
  991.     -12000: STATUS_PRINTER_MEDIA_JAM, # ADF
  992.     -11998: STATUS_PRINTER_MEDIA_JAM, # ADF
  993.     -11986: STATUS_PRINTER_HARD_ERROR, # scanner
  994.     -11994: STATUS_PRINTER_BUSY,
  995.     -14967: STATUS_PRINTER_BUSY,
  996.     -19912: STATUS_PRINTER_HARD_ERROR,
  997.     -14962: STATUS_PRINTER_BUSY, # copy pending
  998.     -14971: STATUS_PRINTER_BUSY, # copying
  999.     -14973: STATUS_PRINTER_BUSY, # copying being canceled
  1000.     -14972: STATUS_PRINTER_BUSY, # copying canceled
  1001.     -14966: STATUS_PRINTER_DOOR_OPEN,
  1002.     -14974: STATUS_PRINTER_MEDIA_JAM,
  1003.     -14969: STATUS_PRINTER_HARD_ERROR,
  1004.     -14968: STATUS_PRINTER_HARD_ERROR,
  1005.     -12996: STATUS_PRINTER_BUSY, # scan
  1006.     -12994: STATUS_PRINTER_BUSY, # scan
  1007.     -12993: STATUS_PRINTER_BUSY, # scan
  1008.     -12991: STATUS_PRINTER_BUSY, # scan
  1009.     -12995: STATUS_PRINTER_BUSY, # scan
  1010.     -12997: STATUS_PRINTER_HARD_ERROR, # scan
  1011.     -12990: STATUS_PRINTER_BUSY,
  1012.     -12998: STATUS_PRINTER_BUSY,
  1013.     -13000: STATUS_PRINTER_DOOR_OPEN,
  1014.     -12999: STATUS_PRINTER_MEDIA_JAM,
  1015.     -13859: STATUS_PRINTER_BUSY,
  1016.     -13858: STATUS_PRINTER_BUSY, #</DevStatusDialingOut>
  1017.     -13868: STATUS_PRINTER_BUSY, #</DevStatusRedialPending>
  1018.     -13867: STATUS_PRINTER_BUSY, #</DevStatusFaxSendCanceled>
  1019.     -13857: STATUS_PRINTER_BUSY, #</DevStatusConnecting>
  1020.     -13856: STATUS_PRINTER_BUSY, #</DevStatusSendingPage>
  1021.     -13855: STATUS_PRINTER_BUSY, #</DevStatusOnePageSend>
  1022.     -13854: STATUS_PRINTER_BUSY, #</DevStatusMultiplePagesSent>
  1023.     -13853: STATUS_PRINTER_BUSY, #</DevStatusSenderCancelingFax>
  1024.     -13839: STATUS_PRINTER_BUSY, #</DevStatusIncomingCall>
  1025.     -13842: STATUS_PRINTER_BUSY, #</DevStatusBlockingFax>
  1026.     -13838: STATUS_PRINTER_BUSY, #</DevStatusReceivingFax>
  1027.     -13847: STATUS_PRINTER_BUSY, #</DevStatusSinglePageReceived>
  1028.     -13846: STATUS_PRINTER_BUSY, #</DevStatusDoublePagesReceived>
  1029.     -13845: STATUS_PRINTER_BUSY, #</DevStatusTriplePagesReceived>
  1030.     -13844: STATUS_PRINTER_BUSY, #</DevStatusPrintingFax>
  1031.     -13840: STATUS_PRINTER_BUSY, #</DevStatusCancelingFaxPrint>
  1032.     -13843: STATUS_PRINTER_BUSY, #</DevStatusFaxCancelingReceive>
  1033.     -13850: STATUS_PRINTER_BUSY, #</DevStatusFaxCanceledReceive>
  1034.     -13851: STATUS_PRINTER_BUSY, #</DevStatusFaxDelayedSendMemoryFull>
  1035.     -13836: STATUS_PRINTER_BUSY, #</DevStatusNoDialTone>
  1036.     -13864: STATUS_PRINTER_BUSY, #</DevStatusNoFaxAnswer>
  1037.     -13863: STATUS_PRINTER_BUSY, #</DevStatusFaxBusy>
  1038.     -13865: STATUS_PRINTER_BUSY, #</DevStatusNoDocumentSent>
  1039.     -13862: STATUS_PRINTER_BUSY, #</DevStatusFaxSendError>
  1040.     -13837: STATUS_PRINTER_BUSY, #</DevStatusT30Error>
  1041.     -13861: STATUS_PRINTER_BUSY, #</DevStatusFaxMemoryFullSend>
  1042.     -13866: STATUS_PRINTER_BUSY, #</DevStatusADFNotCleared>
  1043.     -13841: STATUS_PRINTER_BUSY, #</DevStatusNoFaxDetected>
  1044.     -13848: STATUS_PRINTER_BUSY, #</DevStatusFaxMemoryFullReceive>
  1045.     -13849: STATUS_PRINTER_BUSY, #</DevStatusFaxReceiveError>
  1046.  
  1047. }
  1048.  
  1049. def StatusType6(dev): #  LaserJet Status (XML)
  1050.     info_device_status = cStringIO.StringIO()
  1051.     info_ssp = cStringIO.StringIO()
  1052.  
  1053.     try:
  1054.         dev.getEWSUrl("/hp/device/info_device_status.xml", info_device_status)
  1055.         dev.getEWSUrl("/hp/device/info_ssp.xml", info_ssp)
  1056.     except:
  1057.         pass
  1058.  
  1059.     info_device_status = info_device_status.getvalue()
  1060.     info_ssp = info_ssp.getvalue()
  1061.  
  1062.     device_status = {}
  1063.     ssp = {}
  1064.  
  1065.     if info_device_status:
  1066.         try:
  1067.             log.debug_block("info_device_status", info_device_status)
  1068.             device_status = utils.XMLToDictParser().parseXML(info_device_status)
  1069.             log.debug(device_status)
  1070.         except expat.ExpatError:
  1071.             log.error("Device Status XML parse error")
  1072.             device_status = {}
  1073.  
  1074.     if info_ssp:
  1075.         try:
  1076.             log.debug_block("info_spp", info_ssp)
  1077.             ssp = utils.XMLToDictParser().parseXML(info_ssp)
  1078.             log.debug(ssp)
  1079.         except expat.ExpatError:
  1080.             log.error("SSP XML parse error")
  1081.             ssp = {}
  1082.  
  1083.     status_code = device_status.get('devicestatuspage-devicestatus-statuslist-status-code-0', 0)
  1084.  
  1085.     if not status_code:
  1086.         status_code = ssp.get('devicestatuspage-devicestatus-statuslist-status-code-0', 0)
  1087.  
  1088.     black_supply_level = device_status.get('devicestatuspage-suppliesstatus-blacksupply-percentremaining', 0)
  1089.     black_supply_low = ssp.get('suppliesstatuspage-blacksupply-lowreached', 0)
  1090.     agents = []
  1091.  
  1092.     agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
  1093.                      'type' : AGENT_TYPE_BLACK,
  1094.                      'health' : 0,
  1095.                      'level' : black_supply_level,
  1096.                      'level-trigger' : 0,
  1097.                   })
  1098.  
  1099.     if dev.tech_type == TECH_TYPE_COLOR_LASER:
  1100.         cyan_supply_level = device_status.get('devicestatuspage-suppliesstatus-cyansupply-percentremaining', 0)
  1101.         agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
  1102.                          'type' : AGENT_TYPE_CYAN,
  1103.                          'health' : 0,
  1104.                          'level' : cyan_supply_level,
  1105.                          'level-trigger' : 0,
  1106.                       })
  1107.  
  1108.         magenta_supply_level = device_status.get('devicestatuspage-suppliesstatus-magentasupply-percentremaining', 0)
  1109.         agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
  1110.                          'type' : AGENT_TYPE_MAGENTA,
  1111.                          'health' : 0,
  1112.                          'level' : magenta_supply_level,
  1113.                          'level-trigger' : 0,
  1114.                       })
  1115.  
  1116.         yellow_supply_level = device_status.get('devicestatuspage-suppliesstatus-yellowsupply-percentremaining', 0)
  1117.         agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
  1118.                          'type' : AGENT_TYPE_YELLOW,
  1119.                          'health' : 0,
  1120.                          'level' : yellow_supply_level,
  1121.                          'level-trigger' : 0,
  1122.                       })
  1123.  
  1124.     return {'revision' :    STATUS_REV_UNKNOWN,
  1125.              'agents' :      agents,
  1126.              'top-door' :    0,
  1127.              'supply-door' : 0,
  1128.              'duplexer' :    1,
  1129.              'photo-tray' :  0,
  1130.              'in-tray1' :    1,
  1131.              'in-tray2' :    1,
  1132.              'media-path' :  1,
  1133.              'status-code' : TYPE6_STATUS_CODE_MAP.get(status_code, STATUS_PRINTER_IDLE),
  1134.            }
  1135.  
  1136. # PJL status codes
  1137. PJL_STATUS_MAP = {
  1138.     10001: STATUS_PRINTER_IDLE, # online
  1139.     10002: STATUS_PRINTER_OFFLINE, # offline
  1140.     10003: STATUS_PRINTER_WARMING_UP,
  1141.     10004: STATUS_PRINTER_BUSY, # self test
  1142.     10005: STATUS_PRINTER_BUSY, # reset
  1143.     10006: STATUS_PRINTER_LOW_TONER,
  1144.     10007: STATUS_PRINTER_CANCELING,
  1145.     10010: STATUS_PRINTER_SERVICE_REQUEST,
  1146.     10011: STATUS_PRINTER_OFFLINE,
  1147.     10013: STATUS_PRINTER_BUSY,
  1148.     10014: STATUS_PRINTER_REPORT_PRINTING,
  1149.     10015: STATUS_PRINTER_BUSY,
  1150.     10016: STATUS_PRINTER_BUSY,
  1151.     10017: STATUS_PRINTER_REPORT_PRINTING,
  1152.     10018: STATUS_PRINTER_BUSY,
  1153.     10019: STATUS_PRINTER_BUSY,
  1154.     10020: STATUS_PRINTER_BUSY,
  1155.     10021: STATUS_PRINTER_BUSY,
  1156.     10022: STATUS_PRINTER_REPORT_PRINTING,
  1157.     10023: STATUS_PRINTER_PRINTING,
  1158.     10024: STATUS_PRINTER_SERVICE_REQUEST,
  1159.     10025: STATUS_PRINTER_SERVICE_REQUEST,
  1160.     10026: STATUS_PRINTER_BUSY,
  1161.     10027: STATUS_PRINTER_MEDIA_JAM,
  1162.     10028: STATUS_PRINTER_REPORT_PRINTING,
  1163.     10029: STATUS_PRINTER_PRINTING,
  1164.     10030: STATUS_PRINTER_BUSY,
  1165.     10031: STATUS_PRINTER_BUSY,
  1166.     10032: STATUS_PRINTER_BUSY,
  1167.     10033: STATUS_PRINTER_SERVICE_REQUEST,
  1168.     10034: STATUS_PRINTER_CANCELING,
  1169.     10035: STATUS_PRINTER_PRINTING,
  1170.     10036: STATUS_PRINTER_WARMING_UP,
  1171.     10200: STATUS_PRINTER_LOW_BLACK_TONER,
  1172.     10201: STATUS_PRINTER_LOW_CYAN_TONER,
  1173.     10202: STATUS_PRINTER_LOW_MAGENTA_TONER,
  1174.     10203: STATUS_PRINTER_LOW_YELLOW_TONER,
  1175.     10204: STATUS_PRINTER_LOW_TONER, # order image drum
  1176.     10205: STATUS_PRINTER_LOW_BLACK_TONER, # order black drum
  1177.     10206: STATUS_PRINTER_LOW_CYAN_TONER, # order cyan drum
  1178.     10207: STATUS_PRINTER_LOW_MAGENTA_TONER, # order magenta drum
  1179.     10208: STATUS_PRINTER_LOW_YELLOW_TONER, # order yellow drum
  1180.     10209: STATUS_PRINTER_LOW_BLACK_TONER,
  1181.     10210: STATUS_PRINTER_LOW_CYAN_TONER,
  1182.     10211: STATUS_PRINTER_LOW_MAGENTA_TONER,
  1183.     10212: STATUS_PRINTER_LOW_YELLOW_TONER,
  1184.     10213: STATUS_PRINTER_SERVICE_REQUEST, # order transport kit
  1185.     10214: STATUS_PRINTER_SERVICE_REQUEST, # order cleaning kit
  1186.     10215: STATUS_PRINTER_SERVICE_REQUEST, # order transfer kit
  1187.     10216: STATUS_PRINTER_SERVICE_REQUEST, # order fuser kit
  1188.     10217: STATUS_PRINTER_SERVICE_REQUEST, # maintenance
  1189.     10218: STATUS_PRINTER_LOW_TONER,
  1190.     10300: STATUS_PRINTER_LOW_BLACK_TONER, # replace black toner
  1191.     10301: STATUS_PRINTER_LOW_CYAN_TONER, # replace cyan toner
  1192.     10302: STATUS_PRINTER_LOW_MAGENTA_TONER, # replace magenta toner
  1193.     10303: STATUS_PRINTER_LOW_YELLOW_TONER, # replace yellow toner
  1194.     10304: STATUS_PRINTER_SERVICE_REQUEST, # replace image drum
  1195.     10305: STATUS_PRINTER_SERVICE_REQUEST, # replace black drum
  1196.     10306: STATUS_PRINTER_SERVICE_REQUEST, # replace cyan drum
  1197.     10307: STATUS_PRINTER_SERVICE_REQUEST, # replace magenta drum
  1198.     10308: STATUS_PRINTER_SERVICE_REQUEST, # replace yellow drum
  1199.     10309: STATUS_PRINTER_SERVICE_REQUEST, # replace black cart
  1200.     10310: STATUS_PRINTER_SERVICE_REQUEST, # replace cyan cart
  1201.     10311: STATUS_PRINTER_SERVICE_REQUEST, # replace magenta cart
  1202.     10312: STATUS_PRINTER_SERVICE_REQUEST, # replace yellow cart
  1203.     10313: STATUS_PRINTER_SERVICE_REQUEST, # replace transport kit
  1204.     10314: STATUS_PRINTER_SERVICE_REQUEST, # replace cleaning kit
  1205.     10315: STATUS_PRINTER_SERVICE_REQUEST, # replace transfer kit
  1206.     10316: STATUS_PRINTER_SERVICE_REQUEST, # replace fuser kit
  1207.     10317: STATUS_PRINTER_SERVICE_REQUEST,
  1208.     10318: STATUS_PRINTER_SERVICE_REQUEST, # replace supplies
  1209.     10400: STATUS_PRINTER_NON_HP_INK, # [sic]
  1210.     10401: STATUS_PRINTER_IDLE,
  1211.     10402: STATUS_PRINTER_SERVICE_REQUEST,
  1212.     10403: STATUS_PRINTER_IDLE,
  1213.     # 11xyy - Background paper-loading
  1214.     # 12xyy - Background paper-tray status
  1215.     # 15xxy - Output-bin status
  1216.     # 20xxx - PJL parser errors
  1217.     # 25xxx - PJL parser warnings
  1218.     # 27xxx - PJL semantic errors
  1219.     # 30xxx - Auto continuable conditions
  1220.     30119: STATUS_PRINTER_MEDIA_JAM,
  1221.     # 32xxx - PJL file system errors
  1222.     # 35xxx - Potential operator intervention conditions
  1223.     # 40xxx - Operator intervention conditions
  1224.     40021: STATUS_PRINTER_DOOR_OPEN,
  1225.     40022: STATUS_PRINTER_MEDIA_JAM,
  1226.     40038: STATUS_PRINTER_LOW_TONER,
  1227.     40600: STATUS_PRINTER_NO_TONER,
  1228.     # 41xyy - Foreground paper-loading messages
  1229.     # 43xyy - Optional paper handling device messages
  1230.     # 44xyy - LJ 4xxx/5xxx paper jam messages
  1231.     # 50xxx - Hardware errors
  1232.     # 55xxx - Personality errors
  1233.  
  1234. }
  1235.  
  1236. MIN_PJL_ERROR_CODE = 10001
  1237. DEFAULT_PJL_ERROR_CODE = 10001
  1238.  
  1239. def MapPJLErrorCode(error_code, str_code=None):
  1240.     if error_code < MIN_PJL_ERROR_CODE:
  1241.         return STATUS_PRINTER_BUSY
  1242.  
  1243.     if str_code is None:
  1244.         str_code = str(error_code)
  1245.  
  1246.     if len(str_code) < 5:
  1247.         return STATUS_PRINTER_BUSY
  1248.  
  1249.     status_code = PJL_STATUS_MAP.get(error_code, None)
  1250.  
  1251.     if status_code is None:
  1252.         status_code = STATUS_PRINTER_BUSY
  1253.  
  1254.         if 10999 < error_code < 12000: # 11xyy - Background paper-loading
  1255.             # x = tray #
  1256.             # yy = media code
  1257.             tray = int(str_code[2])
  1258.             media = int(str_code[3:])
  1259.             log.debug("Background paper loading for tray #%d" % tray)
  1260.             log.debug("Media code = %d" % media)
  1261.  
  1262.         elif 11999 < error_code < 13000: # 12xyy - Background paper-tray status
  1263.             # x = tray #
  1264.             # yy = status code
  1265.             tray = int(str_code[2])
  1266.             status = int(str_code[3:])
  1267.             log.debug("Background paper tray status for tray #%d" % tray)
  1268.             log.debug("Status code = %d" % status)
  1269.  
  1270.         elif 14999 < error_code < 16000: # 15xxy - Output-bin status
  1271.             # xx = output bin
  1272.             # y = status code
  1273.             bin = int(str_code[2:4])
  1274.             status = int(str_code[4])
  1275.             log.debug("Output bin full for bin #%d" % bin)
  1276.             status_code = STATUS_PRINTER_OUTPUT_BIN_FULL
  1277.  
  1278.         elif 19999 < error_code < 28000: # 20xxx, 25xxx, 27xxx PJL errors
  1279.             status_code = STATUS_PRINTER_SERVICE_REQUEST
  1280.  
  1281.         elif 29999 < error_code < 31000: # 30xxx - Auto continuable conditions
  1282.             log.debug("Auto continuation condition #%d" % error_code)
  1283.             status_code = STATUS_PRINTER_BUSY
  1284.  
  1285.         elif 34999 < error_code < 36000: # 35xxx - Potential operator intervention conditions
  1286.             status_code = STATUS_PRINTER_SERVICE_REQUEST
  1287.  
  1288.         elif 39999 < error_code < 41000: # 40xxx - Operator intervention conditions
  1289.             status_code = STATUS_PRINTER_SERVICE_REQUEST
  1290.  
  1291.         elif 40999 < error_code < 42000: # 41xyy - Foreground paper-loading messages
  1292.             # x = tray
  1293.             # yy = media code
  1294.             tray = int(str_code[2])
  1295.             media = int(str_code[3:])
  1296.             log.debug("Foreground paper loading for tray #%d" % tray)
  1297.             log.debug("Media code = %d" % media)
  1298.             status_code = STATUS_PRINTER_OUT_OF_PAPER
  1299.  
  1300.         elif 41999 < error_code < 43000:
  1301.             status_code = STATUS_PRINTER_MEDIA_JAM
  1302.  
  1303.         elif 42999 < error_code < 44000: # 43xyy - Optional paper handling device messages
  1304.             status_code = STATUS_PRINTER_SERVICE_REQUEST
  1305.  
  1306.         elif 43999 < error_code < 45000: # 44xyy - LJ 4xxx/5xxx paper jam messages
  1307.             status_code = STATUS_PRINTER_MEDIA_JAM
  1308.  
  1309.         elif 49999 < error_code < 51000: # 50xxx - Hardware errors
  1310.             status_code = STATUS_PRINTER_HARD_ERROR
  1311.  
  1312.         elif 54999 < error_code < 56000 : # 55xxx - Personality errors
  1313.             status_code = STATUS_PRINTER_HARD_ERROR
  1314.  
  1315.     log.debug("Mapped PJL error code %d to status code %d" % (error_code, status_code))
  1316.     return status_code
  1317.  
  1318.  
  1319. pjl_code_pat = re.compile("""^CODE\s*=\s*(\d.*)$""", re.IGNORECASE)
  1320.  
  1321.  
  1322.  
  1323. def StatusType8(dev): #  LaserJet PJL (B&W only)
  1324.     try:
  1325.         # Will error if printer is busy printing...
  1326.         dev.openPrint()
  1327.     except Error, e:
  1328.         log.warn(e.msg)
  1329.         status_code = STATUS_PRINTER_BUSY
  1330.     else:
  1331.         try:
  1332.             try:
  1333.                 dev.writePrint("\x1b%-12345X@PJL INFO STATUS \r\n\x1b%-12345X")
  1334.                 pjl_return = dev.readPrint(1024, timeout=5, allow_short_read=True)
  1335.                 dev.close()
  1336.  
  1337.                 log.debug_block("PJL return:", pjl_return)
  1338.  
  1339.                 str_code = '10001'
  1340.  
  1341.                 for line in pjl_return.splitlines():
  1342.                     line = line.strip()
  1343.                     match = pjl_code_pat.match(line)
  1344.  
  1345.                     if match is not None:
  1346.                         str_code = match.group(1)
  1347.                         break
  1348.  
  1349.                 log.debug("Code = %s" % str_code)
  1350.  
  1351.                 try:
  1352.                     error_code = int(str_code)
  1353.                 except ValueError:
  1354.                     error_code = DEFAULT_PJL_ERROR_CODE
  1355.  
  1356.                 log.debug("Error code = %d" % error_code)
  1357.  
  1358.                 status_code = MapPJLErrorCode(error_code, str_code)
  1359.             except Error:
  1360.                 status_code = STATUS_PRINTER_HARD_ERROR
  1361.         finally:
  1362.             try:
  1363.                 dev.closePrint()
  1364.             except Error:
  1365.                 pass
  1366.  
  1367.     agents = []
  1368.  
  1369.     # TODO: Only handles mono lasers...
  1370.     if status_code in (STATUS_PRINTER_LOW_TONER, STATUS_PRINTER_LOW_BLACK_TONER):
  1371.         health = AGENT_HEALTH_OK
  1372.         level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW
  1373.         level = 0
  1374.  
  1375.     elif status_code == STATUS_PRINTER_NO_TONER:
  1376.         health = AGENT_HEALTH_MISINSTALLED
  1377.         level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW
  1378.         level = 0
  1379.  
  1380.     else:
  1381.         health = AGENT_HEALTH_OK
  1382.         level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
  1383.         level = 100
  1384.  
  1385.     log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger))
  1386.  
  1387.     agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
  1388.                      'type' : AGENT_TYPE_BLACK,
  1389.                      'health' : health,
  1390.                      'level' : level,
  1391.                      'level-trigger' : level_trigger,
  1392.                   })
  1393.  
  1394.     if dev.tech_type == TECH_TYPE_COLOR_LASER:
  1395.         level = 100
  1396.         level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
  1397.         if status_code == STATUS_PRINTER_LOW_CYAN_TONER:
  1398.             level = 0
  1399.             level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW
  1400.  
  1401.         log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger))
  1402.  
  1403.         agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
  1404.                          'type' : AGENT_TYPE_CYAN,
  1405.                          'health' : AGENT_HEALTH_OK,
  1406.                          'level' : level,
  1407.                          'level-trigger' : level_trigger,
  1408.                       })
  1409.  
  1410.         level = 100
  1411.         level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
  1412.         if status_code == STATUS_PRINTER_LOW_MAGENTA_TONER:
  1413.             level = 0
  1414.             level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW
  1415.  
  1416.         log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger))
  1417.  
  1418.         agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
  1419.                          'type' : AGENT_TYPE_MAGENTA,
  1420.                          'health' : AGENT_HEALTH_OK,
  1421.                          'level' : level,
  1422.                          'level-trigger' : level_trigger,
  1423.                       })
  1424.  
  1425.         level = 100
  1426.         level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
  1427.         if status_code == STATUS_PRINTER_LOW_YELLOW_TONER:
  1428.             level = 0
  1429.             level_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW
  1430.  
  1431.         log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger))
  1432.  
  1433.         agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
  1434.                          'type' : AGENT_TYPE_YELLOW,
  1435.                          'health' : AGENT_HEALTH_OK,
  1436.                          'level' : level,
  1437.                          'level-trigger' : level_trigger,
  1438.                       })
  1439.  
  1440.     if status_code == 40021:
  1441.         top_door = 0
  1442.     else:
  1443.         top_door = 1
  1444.  
  1445.     log.debug("Status code = %d" % status_code)
  1446.  
  1447.     return { 'revision' :    STATUS_REV_UNKNOWN,
  1448.              'agents' :      agents,
  1449.              'top-door' :    top_door,
  1450.              'supply-door' : top_door,
  1451.              'duplexer' :    0,
  1452.              'photo-tray' :  0,
  1453.              'in-tray1' :    1,
  1454.              'in-tray2' :    1,
  1455.              'media-path' :  1,
  1456.              'status-code' : status_code,
  1457.            }
  1458.  
  1459.  
  1460. element_type10_xlate = { 'ink' : AGENT_KIND_SUPPLY,
  1461.                          'printhead' : AGENT_KIND_HEAD,
  1462.                          'toner' : AGENT_KIND_TONER_CARTRIDGE,
  1463.                        }
  1464.  
  1465. pen_type10_xlate = { 'pK' : AGENT_TYPE_PG,
  1466.                      'M' : AGENT_TYPE_MAGENTA,
  1467.                      'C' : AGENT_TYPE_CYAN,
  1468.                      'Y' : AGENT_TYPE_YELLOW,
  1469.                      'K' : AGENT_TYPE_BLACK,
  1470.                    }
  1471.  
  1472. pen_level10_xlate = { 'ok' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  1473.                       'low' : AGENT_LEVEL_TRIGGER_MAY_BE_LOW,
  1474.                       'out' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
  1475.                       'empty' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
  1476.                       'missing' : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
  1477.                     }
  1478.  
  1479. pen_health10_xlate = { 'ok' : AGENT_HEALTH_OK,
  1480.                        'misinstalled' : AGENT_HEALTH_MISINSTALLED,
  1481.                        'missing' : AGENT_HEALTH_MISINSTALLED,
  1482.                      }
  1483.  
  1484. def StatusType10FetchUrl(dev, url):
  1485.     if dev.is_local:
  1486.        data_fp = cStringIO.StringIO()
  1487.        dev.getEWSUrl_LEDM(url, data_fp)
  1488.        data = data_fp.getvalue()
  1489.  
  1490.     else:
  1491.         if dev.zc:
  1492.             status, ip = hpmudext.get_zc_ip_address(dev.zc)
  1493.             if status != hpmudext.HPMUD_R_OK:
  1494.                 log.error("unable to get IP address of mDNS configured device")
  1495.                 return None
  1496.         else:
  1497.             ip = dev.host
  1498.  
  1499.         # Get the agent status XML
  1500.         addr = "http://%s:8080%s" % (ip, url)
  1501.         feed = urllib.urlopen(addr)
  1502.         data = feed.read()
  1503.         feed.close()
  1504.  
  1505.     return data
  1506.  
  1507.  
  1508. def StatusType10(dev): # Low End Data Model
  1509.     status_block = { 'revision' :    STATUS_REV_UNKNOWN,
  1510.                      'agents' :      [],
  1511.                      'top-door' :    TOP_DOOR_NOT_PRESENT,
  1512.                      'supply-door' : TOP_DOOR_NOT_PRESENT,
  1513.                      'duplexer' :    DUPLEXER_NOT_PRESENT,
  1514.                      'photo-tray' :  PHOTO_TRAY_NOT_PRESENT,
  1515.                      'in-tray1' :    IN_TRAY_NOT_PRESENT,
  1516.                      'in-tray2' :    IN_TRAY_NOT_PRESENT,
  1517.                      'media-path' :  MEDIA_PATH_NOT_PRESENT,
  1518.                      'status-code' : STATUS_PRINTER_IDLE,
  1519.                    }
  1520.  
  1521.     if not etree_loaded and not elementtree_loaded:
  1522.         log.error("cannot get status for printer. please load ElementTree module")
  1523.         return status_block
  1524.  
  1525.     # Get the dynamic consumables configuration
  1526.     data = StatusType10FetchUrl(dev, "/DevMgmt/ConsumableConfigDyn.xml")
  1527.     if not data:
  1528.         return status_block
  1529.     data = data.replace("ccdyn:", "").replace("dd:", "")
  1530.  
  1531.     # Parse the agent status XML
  1532.     agents = []
  1533.     try:
  1534.         if etree_loaded:
  1535.             tree = ElementTree.XML(data)
  1536.         if not etree_loaded and elementtree_loaded:
  1537.             tree = XML(data)
  1538.         elements = tree.findall("ConsumableInfo")
  1539.         for e in elements:
  1540.             health = AGENT_HEALTH_OK
  1541.             ink_level = 0
  1542.             type = e.find("ConsumableTypeEnum").text
  1543.             state = e.find("ConsumableLifeState/ConsumableState").text
  1544.  
  1545.             # level
  1546.             if type == "ink" or type == "toner":
  1547.                 ink_type = e.find("ConsumableLabelCode").text
  1548.                 if state != "missing":
  1549.                     try:
  1550.                        ink_level = int(e.find("ConsumablePercentageLevelRemaining").text)
  1551.                     except:
  1552.                        ink_level = 0
  1553.             else:
  1554.                 ink_type = ''
  1555.                 if state == "ok":
  1556.                     ink_level = 100
  1557.  
  1558.             log.debug("type '%s' state '%s' ink_type '%s' ink_level %d" % (type, state, ink_type, ink_level))
  1559.     
  1560.             entry = { 'kind' : element_type10_xlate.get(type, AGENT_KIND_NONE),
  1561.                       'type' : pen_type10_xlate.get(ink_type, AGENT_TYPE_NONE),
  1562.                       'health' : pen_health10_xlate.get(state, AGENT_HEALTH_OK),
  1563.                       'level' : int(ink_level),
  1564.                       'level-trigger' : pen_level10_xlate.get(state, AGENT_LEVEL_TRIGGER_SUFFICIENT_0)
  1565.                     }
  1566.  
  1567.             log.debug("%s" % entry)
  1568.             agents.append(entry)
  1569.     except (expat.ExpatError, UnboundLocalError):
  1570.         agents = []
  1571.     status_block['agents'] = agents
  1572.  
  1573.     # Get the media handling configuration
  1574.     data = StatusType10FetchUrl(dev, "/DevMgmt/MediaHandlingDyn.xml")
  1575.     if not data:
  1576.         return status_block
  1577.     data = data.replace("mhdyn:", "").replace("dd:", "")
  1578.  
  1579.     # Parse the media handling XML
  1580.     try:
  1581.         if etree_loaded:
  1582.             tree = ElementTree.XML(data)
  1583.         if not etree_loaded and elementtree_loaded:
  1584.             tree = XML(data)
  1585.         elements = tree.findall("InputTray")
  1586.     except (expat.ExpatError, UnboundLocalError):
  1587.         elements = []
  1588.     for e in elements:
  1589.         bin_name = e.find("InputBin").text
  1590.         if bin_name == "Tray1":
  1591.             status_block['in-tray1'] = IN_TRAY_PRESENT
  1592.         elif bin_name == "Tray2":
  1593.             status_block['in-tray2'] = IN_TRAY_PRESENT
  1594.         elif bin_name == "PhotoTray":
  1595.             status_block['photo-tray'] = PHOTO_TRAY_ENGAGED
  1596.         else:
  1597.             log.error("found invalid bin name '%s'" % bin_name)
  1598.  
  1599.     try:
  1600.         elements = tree.findall("Accessories/MediaHandlingDeviceFunctionType")
  1601.     except UnboundLocalError:
  1602.         elements = []
  1603.     for e in elements:
  1604.         if e.text == "autoDuplexor":
  1605.             status_block['duplexer'] = DUPLEXER_DOOR_CLOSED
  1606.  
  1607.     # Get the product status
  1608.     data = StatusType10FetchUrl(dev, "/DevMgmt/ProductStatusDyn.xml")
  1609.     if not data:
  1610.         return status_block
  1611.     data = data.replace("psdyn:", "").replace("locid:", "")
  1612.     data = data.replace("pscat:", "").replace("dd:", "").replace("ad:", "")
  1613.  
  1614.     # Parse the product status XML
  1615.     try:
  1616.         if etree_loaded:
  1617.             tree = ElementTree.XML(data)
  1618.         if not etree_loaded and elementtree_loaded:
  1619.             tree = XML(data)
  1620.         elements = tree.findall("Status/StatusCategory")
  1621.     except (expat.ExpatError, UnboundLocalError):
  1622.         elements = []
  1623.     for e in elements:
  1624.         if e.text == "closeDoorOrCover":
  1625.             status_block['status-code'] = STATUS_PRINTER_DOOR_OPEN
  1626.         elif e.text == "shuttingDown":
  1627.             status_block['status-code'] = STATUS_PRINTER_TURNING_OFF
  1628.         elif e.text == "cancelJob":
  1629.             status_block['status-code'] = STATUS_PRINTER_CANCELING
  1630.         elif e.text == "trayEmptyOrOpen":
  1631.             status_block['status-code'] = STATUS_PRINTER_OUT_OF_PAPER
  1632.         elif e.text == "jamInPrinter":
  1633.             status_block['status-code'] = STATUS_PRINTER_MEDIA_JAM
  1634.         elif e.text == "hardError":
  1635.             status_block['status-code'] = STATUS_PRINTER_HARD_ERROR
  1636.         elif e.text == "outputBinFull":
  1637.             status_block['status-code'] = STATUS_PRINTER_OUTPUT_BIN_FULL
  1638.         elif e.text == "unexpectedSizeInTray":
  1639.             status_block['status-code'] = STATUS_PRINTER_MEDIA_SIZE_MISMATCH
  1640.         elif e.text == "insertOrCloseTray2":
  1641.             status_block['status-code'] = STATUS_PRINTER_TRAY_2_MISSING
  1642.         elif e.text == "scannerError":
  1643.             status_block['status-code'] = EVENT_SCANNER_FAIL
  1644.         elif e.text == "scanProcessing":
  1645.             status_block['status-code'] = EVENT_START_SCAN_JOB
  1646.         elif e.text == "scannerAdfLoaded":
  1647.             status_block['status-code'] = EVENT_SCAN_ADF_LOADED
  1648.         elif e.text == "scanToDestinationNotSet":
  1649.             status_block['status-code'] = EVENT_SCAN_TO_DESTINATION_NOTSET
  1650.         elif e.text == "scanWaitingForPC":
  1651.             status_block['status-code'] = EVENT_SCAN_WAITING_FOR_PC
  1652.         elif e.text == "scannerAdfJam":
  1653.             status_block['status-code'] = EVENT_SCAN_ADF_JAM
  1654.         elif e.text == "scannerAdfDoorOpen":
  1655.             status_block['status-code'] = EVENT_SCAN_ADF_DOOR_OPEN
  1656.         elif e.text == "faxProcessing":
  1657.             status_block['status-code'] = EVENT_START_FAX_JOB
  1658.         elif e.text == "faxSending":
  1659.             status_block['status-code'] = STATUS_FAX_TX_ACTIVE
  1660.         elif e.text == "faxReceiving":
  1661.             status_block['status-code'] = STATUS_FAX_RX_ACTIVE
  1662.         elif e.text == "faxDialing":
  1663.             status_block['status-code'] = EVENT_FAX_DIALING
  1664.         elif e.text == "faxConnecting":
  1665.             status_block['status-code'] = EVENT_FAX_CONNECTING
  1666.         elif e.text == "faxSendError":
  1667.             status_block['status-code'] = EVENT_FAX_SEND_ERROR
  1668.         elif e.text == "faxErrorStorageFull":
  1669.             status_block['status-code'] = EVENT_FAX_ERROR_STORAGE_FULL
  1670.         elif e.text == "faxReceiveError":
  1671.             status_block['status-code'] = EVENT_FAX_RECV_ERROR
  1672.         elif e.text == "faxBlocking":
  1673.             status_block['status-code'] = EVENT_FAX_BLOCKING
  1674.         elif e.text == "inPowerSave":
  1675.             status_block['status-code'] = STATUS_PRINTER_POWER_SAVE
  1676.         elif e.text == "incorrectCartridge":
  1677.             status_block['status-code'] = STATUS_PRINTER_CARTRIDGE_WRONG
  1678.         elif e.text == "cartridgeMissing":
  1679.             status_block['status-code'] = STATUS_PRINTER_CARTRIDGE_MISSING
  1680.  
  1681.     return status_block