home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / hplip / base / models.py < prev    next >
Encoding:
Python Source  |  2009-04-14  |  15.7 KB  |  527 lines

  1. # -*- coding: utf-8 -*-
  2. #
  3. # (c) Copyright 2003-2008 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. # Local
  22. from base.g import *
  23. from base import utils
  24.  
  25. # StdLib
  26. import os.path
  27. import re
  28. import glob
  29.  
  30. try:
  31.     import datetime
  32.     datetime_avail = True
  33. except ImportError:
  34.     datetime_avail = False
  35.     datetime = None
  36.  
  37.  
  38. pat_prod_num = re.compile("""(\d+)""", re.I)
  39.  
  40. TYPE_UNKNOWN = 0
  41. TYPE_STRING = 1
  42. TYPE_STR = 1
  43. TYPE_LIST = 2
  44. TYPE_BOOL = 3
  45. TYPE_INT = 4
  46. TYPE_HEX = 5
  47. TYPE_BITFIELD = 6
  48. TYPE_URI = TYPE_STR # (7) not used (yet)
  49. TYPE_DATE = 8  # format: mm/dd/yyyy
  50.  
  51.  
  52. TECH_CLASSES = [
  53.     "Undefined", # This will show an error (and its the default)
  54.     "Unsupported", # This is for unsupported models, and it will not show an error
  55.     "Postscript",
  56.     "DJGenericVIP",
  57.     #"PSB9100", not used on HPLIP
  58.     "LJMono",
  59.     "LJColor",
  60.     "LJFastRaster",
  61.     "LJJetReady",
  62.     "DJ350",
  63.     #"DJ400", not used on HPLIP
  64.     "DJ540",
  65.     "DJ600",
  66.     "DJ6xx",
  67.     "DJ6xxPhoto",
  68.     "DJ630",
  69.     #"DJ660", not used in HPLIP
  70.     "DJ8xx",
  71.     "DJ8x5",
  72.     "DJ850",
  73.     "DJ890",
  74.     "DJ9xx",
  75.     "DJ9xxVIP",
  76.     "DJ3600",
  77.     "DJ3320",
  78.     "DJ4100",
  79.     "AP2xxx",
  80.     "AP21xx",
  81.     "AP2560",
  82.     "PSP100",
  83.     "PSP470",
  84.     "LJZjsMono",
  85.     "LJZjsColor",
  86.     "LJm1005",
  87.     "QuickConnect",
  88.     "DJ55xx",
  89.     "OJProKx50",
  90.     'LJP1XXX',
  91. ]
  92.  
  93. TECH_CLASSES.sort()
  94.  
  95. TECH_CLASS_PDLS = {
  96.     #"Undefined"    : '?',
  97.     "Postscript"   : 'ps',
  98.     "DJGenericVIP" : 'pcl3',
  99.     #"PSB9100"      : 'pcl3',
  100.     "LJMono"       : 'pcl3',
  101.     "LJColor"      : 'pcl3',
  102.     "LJFastRaster" : 'pclxl',
  103.     "LJJetReady"   : 'pclxl',
  104.     "DJ350"        : 'pcl3',
  105.     #"DJ400"        : 'pcl3',
  106.     "DJ540"        : 'pcl3',
  107.     "DJ600"        : 'pcl3',
  108.     "DJ6xx"        : 'pcl3',
  109.     "DJ6xxPhoto"   : 'pcl3',
  110.     "DJ630"        : 'pcl3',
  111.     #"DJ660"        : 'pcl3',
  112.     "DJ8xx"        : 'pcl3',
  113.     "DJ8x5"        : 'pcl3',
  114.     "DJ850"        : 'pcl3',
  115.     "DJ890"        : 'pcl3',
  116.     "DJ9xx"        : 'pcl3',
  117.     "DJ9xxVIP"     : 'pcl3',
  118.     "DJ3600"       : 'lidil',
  119.     "DJ3320"       : 'lidil',
  120.     "DJ4100"       : 'lidil',
  121.     "AP2xxx"       : 'pcl3',
  122.     "AP21xx"       : 'pcl3',
  123.     "AP2560"       : 'pcl3',
  124.     "PSP100"       : 'pcl3',
  125.     "PSP470"       : 'pcl3',
  126.     "LJZjsMono"    : 'zjs',
  127.     "LJZjsColor"   : 'zjs',
  128.     "LJm1005"      : 'zxs',
  129.     "QuickConnect" : 'jpeg',
  130.     "DJ55xx"       : 'pcl3',
  131.     "OJProKx50"    : 'pcl3',
  132.     'LJP1XXX'      : 'zxs',
  133. }
  134.  
  135. PDL_TYPE_PCL = 0  # less preferred
  136. PDL_TYPE_PS = 1   #      /\
  137. PDL_TYPE_HOST = 2 # more preferred (however, may req. plugin)
  138.  
  139. PDL_TYPES = { # Used to prioritize PPD file selection in prnt.cups.getPPDFile2()
  140.     'pcl3' : PDL_TYPE_PCL,
  141.     'pcl5' : PDL_TYPE_PCL,
  142.     'pcl6' : PDL_TYPE_PCL,
  143.     'pcl5e' : PDL_TYPE_PCL,
  144.     'pcl' : PDL_TYPE_PCL,
  145.     'pclxl' : PDL_TYPE_PCL,
  146.     'ps' : PDL_TYPE_PS,
  147.     'lidil' : PDL_TYPE_HOST,
  148.     'zjs' : PDL_TYPE_HOST,
  149.     'zjstream' : PDL_TYPE_HOST,
  150.     'zxs' : PDL_TYPE_HOST,
  151.     'zxstream' : PDL_TYPE_HOST,
  152.     'jpeg' : PDL_TYPE_HOST,
  153.     'jpg' : PDL_TYPE_HOST,
  154.     'jetready' : PDL_TYPE_HOST,
  155.     'jr' : PDL_TYPE_HOST,
  156. }
  157.  
  158.  
  159. TECH_SUBCLASSES = [
  160.     "LargeFormatSuperB",
  161.     "LargeFormatA3",
  162.     "CoverMedia", # 3425
  163.     "FullBleed",
  164.     "Duplex",
  165.     "Normal",
  166.     "Apollo2000",
  167.     "Apollo2200",
  168.     "Apollo2500",
  169.     "NoPhotoMode",
  170.     "NoPhotoBestHiresModes",
  171.     "No1200dpiNoSensor",
  172.     "NoFullBleed",
  173.     "4x6FullBleed",
  174.     "300dpiOnly",  # LaserJet 4L
  175.     "GrayscaleOnly", # DJ540
  176. ]
  177.  
  178. TECH_SUBCLASSES.sort()
  179.  
  180.  
  181. # Items will be capitalized unless in this dict
  182. MODEL_UI_REPLACEMENTS = {'laserjet'   : 'LaserJet',
  183.                           'psc'        : 'PSC',
  184.                           'hp'         : 'HP',
  185.                           'mfp'        : 'MFP',
  186.                         }
  187.  
  188.  
  189. def normalizeModelUIName(model):
  190.     ml = model.lower().strip()
  191.  
  192.     if 'apollo' in ml:
  193.         z = ml.replace('_', ' ')
  194.     else:
  195.         if ml.startswith("hp"):
  196.             z = ml[3:].replace('_', ' ')
  197.         else:
  198.             z = ml.replace('_', ' ')
  199.  
  200.     y = []
  201.     for x in z.split():
  202.         if pat_prod_num.search(x): # don't cap items like cp1700dn
  203.             y.append(x)
  204.         else:
  205.             y.append(MODEL_UI_REPLACEMENTS.get(x, x.capitalize()))
  206.  
  207.     if 'apollo' in ml:
  208.         return ' '.join(y)
  209.     else:
  210.         return "HP " + ' '.join(y)
  211.  
  212.  
  213. def normalizeModelName(model):
  214.     return utils.xstrip(model.replace(' ', '_').replace('__', '_').replace('~','').replace('/', '_'), '_')
  215.  
  216.  
  217. class ModelData:
  218.     def __init__(self, root_path=None):
  219.         if root_path is None:
  220.             self.root_path = prop.models_dir
  221.         else:
  222.             self.root_path = root_path
  223.  
  224.         self.__cache = {}
  225.         self.reset_includes()
  226.         self.sec = re.compile(r'^\[(.*)\]')
  227.         self.inc = re.compile(r'^\%include (.*)', re.I)
  228.         self.inc_line = re.compile(r'^\%(.*)\%')
  229.         self.eq = re.compile(r'^([^=]+)=(.*)')
  230.         self.date = re.compile(r'^(\d{1,2})/(\d{1,2})/(\d{4,4})')
  231.  
  232.         files = [(os.path.join(self.root_path, "models.dat"),
  233.                   os.path.join(self.root_path, "unreleased", "unreleased.dat")),
  234.                  (os.path.join(os.getcwd(), 'data', 'models', 'models.dat'),
  235.                   os.path.join(os.getcwd(), 'data', 'models', 'unreleased', 'unreleased.dat'))]
  236.  
  237.         for self.released_dat, self.unreleased_dat in files:
  238.             if os.path.exists(self.released_dat):
  239.                 break
  240.  
  241.         else:
  242.             self.released_dat, self.unreleased_dat = None, None
  243.             log.error("Unable to locate models.dat file")
  244.  
  245.         self.FIELD_TYPES = {
  246.             # Static model query data (from models.dat)
  247.             'align-type' : TYPE_INT,
  248.             'clean-type' : TYPE_INT,
  249.             'color-cal-type' : TYPE_INT,
  250.             'copy-type' : TYPE_INT,
  251.             'embedded-server-type' : TYPE_INT,
  252.             'fax-type' : TYPE_INT,
  253.             'fw-download' : TYPE_BOOL,
  254.             'icon' : TYPE_STR,
  255.             'io-mfp-mode' : TYPE_INT,
  256.             'io-mode' : TYPE_INT,
  257.             'io-support' : TYPE_BITFIELD,
  258.             'monitor-type' : TYPE_INT,
  259.             'linefeed-cal-type' : TYPE_INT,
  260.             'panel-check-type' : TYPE_INT,
  261.             'pcard-type' : TYPE_INT,
  262.             'plugin' : TYPE_INT,
  263.             'plugin-reason' : TYPE_BITFIELD,
  264.             'power-settings': TYPE_INT,
  265.             'pq-diag-type' : TYPE_INT,
  266.             'r-type' : TYPE_INT,
  267.             'scan-style' : TYPE_INT,
  268.             'scan-type' : TYPE_INT,
  269.             'status-battery-check' : TYPE_INT,
  270.             'status-dynamic-counters' : TYPE_INT,
  271.             'status-type' : TYPE_INT,
  272.             'support-subtype' : TYPE_HEX,
  273.             'support-released' : TYPE_BOOL,
  274.             'support-type' : TYPE_INT,
  275.             'support-ver' : TYPE_STR,
  276.             'tech-class' : TYPE_LIST,
  277.             'tech-subclass' : TYPE_LIST,
  278.             'tech-type' : TYPE_INT,
  279.             'usb-pid' : TYPE_HEX,
  280.             'usb-vid' : TYPE_HEX,
  281.             'job-storage' : TYPE_INT,
  282.  
  283.             # Dynamic model data (from device query)
  284.             'dev-file' : TYPE_STR,
  285.             'fax-uri' : TYPE_STR,
  286.             'scan-uri' : TYPE_STR,
  287.             'is-hp' : TYPE_BOOL,
  288.             'host' : TYPE_STR,
  289.             'status-desc' : TYPE_STR,
  290.             'cups-printer' : TYPE_STR,
  291.             'serial' : TYPE_STR,
  292.             'error-state' : TYPE_INT,
  293.             'device-state' : TYPE_INT,
  294.             'panel' : TYPE_INT,
  295.             'device-uri' : TYPE_STR,
  296.             'panel-line1' : TYPE_STR,
  297.             'panel-line2' : TYPE_STR,
  298.             'back-end' : TYPE_STR,
  299.             'port' : TYPE_INT,
  300.             'deviceid' : TYPE_STR,
  301.             'cups-uri' : TYPE_STR,
  302.             'status-code' : TYPE_INT,
  303.             'rs' : TYPE_STR,
  304.             'rr' : TYPE_STR,
  305.             'rg' : TYPE_STR,
  306.             'r' : TYPE_INT,
  307.             'duplexer' : TYPE_INT,
  308.             'supply-door' : TYPE_INT,
  309.             'revision' : TYPE_INT,
  310.             'media-path' : TYPE_INT,
  311.             'top-door' : TYPE_BOOL,
  312.             'photo-tray' : TYPE_BOOL,
  313.             }
  314.  
  315.         self.RE_FIELD_TYPES = {
  316.             re.compile('^r(\d+)-agent(\d+)-kind', re.IGNORECASE) : TYPE_INT,
  317.             re.compile('^r(\d+)-agent(\d+)-type', re.IGNORECASE) : TYPE_INT,
  318.             re.compile('^r(\d+)-agent(\d+)-sku', re.IGNORECASE) : TYPE_STR,
  319.             re.compile('^agent(\d+)-desc', re.IGNORECASE) : TYPE_STR,
  320.             re.compile('^agent(\d+)-virgin', re.IGNORECASE) : TYPE_BOOL,
  321.             re.compile('^agent(\d+)-dvc', re.IGNORECASE) : TYPE_INT,
  322.             re.compile('^agent(\d+)-kind', re.IGNORECASE) : TYPE_INT,
  323.             re.compile('^agent(\d+)-type', re.IGNORECASE) : TYPE_INT,
  324.             re.compile('^agent(\d+)-id', re.IGNORECASE) : TYPE_INT,
  325.             re.compile('^agent(\d+)-hp-ink', re.IGNORECASE) : TYPE_BOOL,
  326.             re.compile('^agent(\d+)-health-desc', re.IGNORECASE) : TYPE_STR,
  327.             re.compile('^agent(\d+)-health$', re.IGNORECASE) : TYPE_INT,
  328.             re.compile('^agent(\d+)-known', re.IGNORECASE) : TYPE_BOOL,
  329.             re.compile('^agent(\d+)-level', re.IGNORECASE) : TYPE_INT,
  330.             re.compile('^agent(\d+)-ack', re.IGNORECASE) : TYPE_BOOL,
  331.             re.compile('^agent(\d+)-sku', re.IGNORECASE) : TYPE_STR,
  332.             re.compile('^in-tray(\d+)', re.IGNORECASE) : TYPE_BOOL,
  333.             re.compile('^out-tray(\d+)', re.IGNORECASE) : TYPE_BOOL,
  334.             re.compile('model(\d+)', re.IGNORECASE) : TYPE_STR,
  335.             }
  336.  
  337.         self.TYPE_CACHE = {}
  338.  
  339.  
  340.     def read_all_files(self, unreleased=True):
  341.         if os.path.exists(self.released_dat):
  342.             self.read_section(self.released_dat)
  343.  
  344.             if self.unreleased_dat is not None and os.path.exists(self.unreleased_dat):
  345.                 self.read_section(self.unreleased_dat )
  346.  
  347.         return self.__cache
  348.  
  349.  
  350.     def read_section(self, filename, section=None, is_include=False): # section==None, read all sections
  351.         found, in_section = False, False
  352.  
  353.         if section is not None:
  354.             section = section.lower()
  355.  
  356.             if is_include:
  357.                 log.debug("Searching for include [%s] in file %s" % (section, filename))
  358.             else:
  359.                 log.debug("Searching for section [%s] in file %s" % (section, filename))
  360.  
  361.         if is_include:
  362.             cache = self.__includes
  363.         else:
  364.             cache = self.__cache
  365.  
  366.         try:
  367.             fd = file(filename)
  368.         except IOError, e:
  369.             log.error("I/O Error: %s (%s)" % (filename, e.strerror))
  370.             return False
  371.  
  372.         while True:
  373.             line = fd.readline()
  374.  
  375.             if not line:
  376.                 break
  377.  
  378.             if line[0] in ('#', ';'):
  379.                 continue
  380.  
  381.             if line[0] == '[':
  382.                 if in_section and section is not None:
  383.                     break
  384.  
  385.                 match = self.sec.search(line)
  386.  
  387.                 if match is not None:
  388.                     in_section = True
  389.  
  390.                     read_section = match.group(1).lower()
  391.  
  392.                     if section is not None:
  393.                         found = in_section = (read_section == section)
  394.  
  395.                     if in_section:
  396.                         if section is not None:
  397.                             log.debug("Found section [%s] in file %s" % (read_section, filename))
  398.  
  399.                         cache[read_section] = {}
  400.  
  401.                 continue
  402.  
  403.             if line[0] == '%':
  404.                 match = self.inc.match(line)
  405.  
  406.                 if match is not None:
  407.                     inc_file = match.group(1)
  408.                     log.debug("Found include file directive: %%include %s" % inc_file)
  409.                     self.__include_files.append(os.path.join(os.path.dirname(filename), inc_file))
  410.                     continue
  411.  
  412.                 if in_section:
  413.                     match = self.inc_line.match(line)
  414.  
  415.                     if match is not None:
  416.                         inc_sect = match.group(1)
  417.                         log.debug("Found include directive %%%s%%" % inc_sect)
  418.  
  419.                         try:
  420.                             self.__includes[inc_sect]
  421.                         except KeyError:
  422.                             for inc in self.__include_files:
  423.  
  424.                                 if self.read_section(inc, inc_sect, True):
  425.                                     break
  426.                             else:
  427.                                 log.error("Include %%%s%% not found." % inc_sect)
  428.  
  429.             if in_section:
  430.                 match = self.eq.search(line)
  431.  
  432.                 if match is not None:
  433.                     key = match.group(1)
  434.                     value = match.group(2)
  435.                     value = self.convert_data(key, value)
  436.                     cache[read_section][key] = value
  437.  
  438.         fd.close()
  439.         return found
  440.  
  441.  
  442.     def reset_includes(self):
  443.         self.__include_files = []
  444.         self.__includes = {}
  445.  
  446.  
  447.     def __getitem__(self, model):
  448.         model = model.lower()
  449.  
  450.         try:
  451.             return self.__cache[model]
  452.         except:
  453.             log.debug("Cache miss: %s" % model)
  454.  
  455.             log.debug("Reading file: %s" % self.released_dat)
  456.  
  457.             if self.read_section(self.released_dat, model):
  458.                 return self.__cache[model]
  459.  
  460.             if self.unreleased_dat is not None and os.path.exists(self.unreleased_dat):
  461.                 log.debug("Reading file: %s" % self.unreleased_dat)
  462.  
  463.                 if self.read_section(self.unreleased_dat, model):
  464.                     return self.__cache[model]
  465.  
  466.             return {}
  467.  
  468.  
  469.     def all_models(self):
  470.         return self.__cache
  471.  
  472.  
  473.     def get_data_type(self, key):
  474.         try:
  475.             return self.FIELD_TYPES[key]
  476.         except KeyError:
  477.             try:
  478.                 return self.TYPE_CACHE[key]
  479.             except KeyError:
  480.                 for pat, typ in self.RE_FIELD_TYPES.items():
  481.                     match = pat.match(key)
  482.                     if match is not None:
  483.                         self.TYPE_CACHE[key] = typ
  484.                         return typ
  485.  
  486.         log.warn("get_data_type(): Defaulted to TYPE_STR for key %s" % key)
  487.         return TYPE_STR
  488.  
  489.  
  490.     def convert_data(self, key, value, typ=None):
  491.         if typ is None:
  492.             typ = self.get_data_type(key)
  493.  
  494.         if  typ in (TYPE_BITFIELD, TYPE_INT):
  495.             try:
  496.                 value = int(value)
  497.             except (ValueError, TypeError):
  498.                 log.error("Invalid value in .dat file: %s=%s" % (key, value))
  499.                 value = 0
  500.  
  501.         elif typ == TYPE_BOOL:
  502.             value = utils.to_bool(value)
  503.  
  504.         elif typ == TYPE_LIST:
  505.             value = [x for x in value.split(',') if x]
  506.  
  507.         elif typ == TYPE_DATE: # mm/dd/yyyy
  508.             if datetime_avail:
  509.                 # ...don't use datetime.strptime(), wasn't avail. until 2.5
  510.                 match = self.date.search(value)
  511.  
  512.                 if match is not None:
  513.                     month = int(match.group(1))
  514.                     day = int(match.group(2))
  515.                     year = int(match.group(3))
  516.  
  517.                     value = datetime.date(year, month, day)
  518.  
  519.         elif typ == TYPE_HEX:
  520.             try:
  521.                 value = int(value, 16)
  522.             except (ValueError, TypeError):
  523.                 log.error("Invalid hex value in .dat file: %s=%s" % (key, value))
  524.                 value = 0
  525.  
  526.         return value
  527.