3
'Y                 @   s  d dl Z ddlmZ ddlmZ d dlZd dlZd dlZd dlZd dl	Z
d dlZd dlZddlmZmZ d dlmZ ddgZd	ejd
fdejdfdejdfdejdfdejdfdejdfdejdfdejdfdejdfdejdfdejdfdejd fgZi ZxeD ]\ZZeeej < qW d!d"d#d$d%d&d'Zejd(Zejd)Zejd*Zejd+ejZd,d Zd-d. Zd/d0 ZG d1d dZ d2d3 Z!dS )4    N   )parseDeviceID)xmldriverprefs)_debugprintset_debugprint_fn)reduceppdMakeModelSplitPPDsHPzhdeskjet|dj[ 0-9]?|laserjet|lj|color laserjet|color lj|designjet|officejet|oj|photosmart|ps |psc|edgelineZEpsonzstylus|aculaserZApplez.stylewriter|imagewriter|deskwriter|laserwriterZCanonz%pixus|pixma|selphy|imagerunner|bj|lbpZBrotherz
hl|dcp|mfcZXeroxz/docuprint|docupage|phaser|workcentre|homecentreLexmarkzoptra|(:color )?jetprinterzKONICA MINOLTAzmagicolor|pageworks|pageproKyocerazfs-|km-|taskalfaZRicohZaficioZOceZ
varioprintZOkizokipage|microlineZDeskJetZLaserJetZ	OfficeJetzColor LaserJet
PhotoSmart )ZdjZljZojzcolor ljzps zhp Z
turboprintz! v(?:er\.)?\d(?:\d*\.\d+)?(?: |$)zn,| hpijs| foomatic/| - | w/| \(| postscript| ps| pdf| pxl| zjs| zxs| pcl3| printer|_bt| pcl| ufr ii| br-scriptz series| all-in-onec             C   s<  | j   d}d}| j }x$tD ]\}}|j|r|}| }P qW |dkoNtj|r| jd}|d'kr| jd}||kr| |d | } n| d| } y| jdd\}}W n   | }d}Y nX t	j
dd	|}t	j
d
d	|}t	j
dd	|}t	j
d
d	|}t	j
dd|}t	j
dd|}d}n|jdr6d}| dd }n|jdrTd}| dd }n|jdrrd}| dd }nj|jdrd}| dd }nL|jdrd}| dd }n.d}y| jd	d\}}W n   | }d}Y nX |j }	|rB|	jdr|	jdrd }d!}	n6|	jd"r.|	jd#r.d}d$}	ntj|	}|rB|}|j }
|
jd%}|d(krtj|
}|r|j }|
d| }
|d| }tj|
}|r|j }|
d| }
|d| }tjd|dd&\}}|r|j }
|	d!kr,x@tj D ]4\}}|
j|r||t|d  }|j }
P qW |j  }||fS ))z
    Split a ppd-make-and-model string into a canonical make and model pair.

    @type ppd_make_and_model: string
    @param ppd_make_and_model: IPP ppd-make-and-model attribute
    @return: a string pair representing the make and the model
    NFz TurboPrintr      _r   z(?<=[a-z])(?=[0-9]) z(?<=[a-z])(?=[A-Z])z JetZJetzPhoto Smartr   Tzkonica minolta zKONICA MINOLTA   zlexmark international r      zkyocera mita r      zkyocera    zfuji xerox z
Fuji Xerox   ZhewlettZpackardr
   hpZkonicaZminoltazkonica minoltaz v)countr   )striplower_MFR_BY_RANGEmatch_RE_turboprintsearchfindrfindsplitresub
startswithendswith_MFR_NAMES_BY_LOWERget_RE_version_numbersstart_RE_ignore_suffix_RE_ignore_seriessubn_HP_MODEL_BY_NAMEitemslen)ppd_make_and_modelmakeZcleanup_makelmfrregexpmodeltZt2ZmakelZmodellvZvmatchZvstartsuffixZsuffixstartnnamefullname r=   2/usr/lib/python3/dist-packages/cupshelpers/ppds.pyr   w   s    











c       	      C   s   | j  j }d}d}d}d}|}d}xtt|D ]p}|| j r\||krV|rV|d7 }|}n*|| j r||kr||r||d7 }|}n|}|| j r2||| 7 }d}q2W |S )Nr   r   r      Fr   T)r   r   ranger0   isalphaisdigitisalnum)	ZstrinZlstrinZ
normalizedZBLANKZALPHAZDIGITZlastcharZ
alnumfoundir=   r=   r>   	normalize   s*    rE   c             C   s   t | tr| d S | S )z{If we don't know whether getPPDs() or getPPDs2() was used, this
    function can unwrap an item from a list in either case.r   )
isinstancelist)xr=   r=   r>   
_singleton)  s    
rI   c            
   @   s   e Zd ZdZdZdZdZdZej	j
Z
ej	jZej	jZej	jZej	jZe
eeeeeeeeeiZd"ddZd	d
 Zdd Zdd Zdd Zdd Zd#ddZd$ddZd%ddZdd Zd&ddZdd Zd d! ZdS )'r	   a\  
    This class is for handling the list of PPDs returned by CUPS.  It
    indexes by PPD name and device ID, filters by natural language so
    that foreign-language PPDs are not included, and sorts by driver
    type.  If an exactly-matching PPD is not available, it can
    substitute with a PPD for a similar model or for a generic driver.
    r   r   r?      Nc             C   s  |j  | _d| _d| _tj | _tj | _|dkrbt	j
jd}|dkrbddlm} t	jj|jd}y8t	jj|d}tj|\}}| jj| | jj| W n> tk
r } z"td||f  d| _d| _W Y dd}~X nX |dks|dks|d	krd
}|jd}	|	dkr|d|	 }
n|}
g }xx| jj D ]j\}}yt|d }W n tk
r^   w,Y nX |dkrnq,||kr|q,||
krq,|j| q,W x|D ]}| j|= qW d| jkrt| jd d }|jdsd| | jd d< dS )a%  
        @type ppds: dict
        @param ppds: dict of PPDs as returned by cups.Connection.getPPDs()
        or cups.Connection.getPPDs2()

        @type language: string
	@param language: language name, as given by the first element
        of the pair returned by locale.getlocale()
        NZCUPSHELPERS_XMLDIRr   )configcupshelperszpreferreddrivers.xmlzError loading %s: %sCZPOSIXZen_USr   zppd-natural-languageZenrawzppd-make-and-modelzGeneric r   )copyppdsmakesidsr   ZDriverTypesdrivertypesZPreferenceOrder	preforderosenvironr(   r   rK   pathjoinZ
sysconfdirZPreferredDriversload	Exceptionprintr    r/   rI   KeyErrorappendr%   )selfrP   ZlanguageZxml_dirrK   ZxmlfilerS   ZpreferenceordereuZshort_languageZ	to_removeppdnameppddictZnatural_languageZ	makemodelr=   r=   r>   __init__K  s\    










zPPDs.__init__c             C   sX   | j   t| jj }|jtjd y|jd |jdd W n t	k
rR   Y nX |S )zb
	@returns: a list of strings representing makes, sorted according
        to the current locale
	)keyGenericr   )
_init_makesrG   rQ   keyssortlocalestrxfrmremoveinsert
ValueError)r^   Z
makes_listr=   r=   r>   getMakes  s    
zPPDs.getMakesc             C   sR   | j   yt| j| j }W n tk
r2   g S X dd }|jtj|d |S )zS
	@returns: a list of strings representing models, sorted using
	cups.modelSort()
	c             S   s   t | }t |}tj||S )N)rE   cups	modelSort)abfirstsecondr=   r=   r>   compare_models  s    z&PPDs.getModels.<locals>.compare_models)rd   )rf   rG   rQ   rg   r\   rh   	functools
cmp_to_key)r^   r2   Zmodels_listru   r=   r=   r>   	getModels  s    zPPDs.getModelsc             C   s0   | j   y| j| | S  tk
r*   i S X dS )z
	Obtain a list of PPDs that are suitable for use with a
        particular printer model, given its make and model name.

	@returns: a dict, indexed by ppd-name, of dicts representing
        PPDs (as given by cups.Connection.getPPDs)
	N)rf   rQ   r\   )r^   r2   r6   r=   r=   r>   getInfoFromModel  s
    zPPDs.getInfoFromModelc             C   s
   | j | S )zM
	@returns: a dict representing a PPD, as given by
	cups.Connection.getPPDs
	)rP   )r^   ra   r=   r=   r>   getInfoFromPPDName  s    zPPDs.getInfoFromPPDNamec             C   s   | j j|tjjS )N)_fit_to_statusr(   r   
DriverTypeFIT_NONE)r^   fitr=   r=   r>   getStatusFromFit  s    zPPDs.getStatusFromFitc             C   sJ  |dkrg }|dkrg }|dkr$i }| j r| jri }x|D ]}| j| ||< q:W | jj| j ||}tdt|  | j j|||}	tdt|	  dd |	D }tdt|  t }
x&|D ]}|jd\}}}|
j	| qW |
rFg }x.|D ]&}|jd\}}}||
kr|j
| qW |rFx"|D ]}||kr$|j
| q$W |}|S )a`  

	Sort a list of PPD names by preferred driver type.

	@param ppdnamelist: PPD names
	@type ppdnamelist: string list
        @param downloadedfiles: Filenames from packages downloaded
        @type downloadedfiles: string list
        @param make_and_model: device-make-and-model name
        @type make_and_model: string
        @param devid: Device ID dict
        @type devid: dict indexed by Device ID field name, of strings;
        except for CMD field which must be a string list
        @param fit: Driver fit string for each PPD name
        @type fit: dict of PPD name:fit
	@returns: string list
	Nz9Valid driver types for this printer in priority order: %sz5PPDs with assigned driver types in priority order: %sc             S   s   g | ]}|d  qS )r   r=   ).0Ztyp_namer=   r=   r>   
<listcomp>  s    z2PPDs.orderPPDNamesByPreference.<locals>.<listcomp>z(Resulting PPD list in priority order: %s/)rS   rT   rP   Zget_ordered_typesr   reprZget_ordered_ppdnamesset
rpartitionaddr]   )r^   ppdnamelistdownloadedfilesmake_and_modeldevidr~   rP   ra   ZorderedtypesZorderedppdsZdownloadedfnamesZdownloadedfilerW   ZslashfnameZdownloadedppdnamesZppdfnamer=   r=   r>   orderPPDNamesByPreference  sF    





zPPDs.orderPPDNamesByPreferencer   c       .      C   s  t d||f  |}|}| j  |dkr,g }i }	|j }
|j }d}y*x | j|
 | D ]}| j|	|< qVW d}W n tk
r   Y nX |
dkryXx | jd | D ]}| j|	|< qW t d| jd |   t d||f  t d	 d}W n tk
r   Y nX t d
 d}| j  d}|
dkr8t|\}}t|}
t|}t d|
  t d|  dddd}|
| j	krt| j	|
 }n<|
|kr||
 }|| j	kr|}|}
t d|
  | j	|
 }t d|  |dk	r| j
| }| jt| }xL|
ddgD ]>}|j|d r|t|d d }t|}t d|  qW || j|
 kr||| }x|| j D ]$}| j|	|< t d|	| |f  qRW nzt|d | \}}t|}t d|  || j|
 kr|| }x8t|| j D ]$}| j|	|< t d|	| |f  qW |	 rL|rL| j||\}}|| jkrLx*|D ]"}||	|< t d|	| |f  q&W |rt|tkrj|jd}t d | j|}|rx,|D ]$}| j|	|< t d|	| |f  qW | s|jd rR|jd rR|jd sd|krRt }x(|	j D ]}|jdr|j| qW t|dkrLt d |  x|D ]}|	|= q<W t }|rt|dkrt }t }x|	j D ]}d}| j| } t| jd!}!|!rt|!}"|"d" }| r|jd#d<krt| jd$}#|#d%krd&g}|sq|d}$x|D ]}%|%|krd}$P qW |$r(|j| n
|j| q|W x:|D ]2}|	| | jkr>| j|	|< t | jd'|   q>W t|td(d) |	j D k rt d*|  x&|D ]}|	|= qW nt d+| d,  |	svd-d.g}&d}'xt|&D ]l}(t d/|(  |(d0 })x<| jj D ].}*|*j|(s |*j|)r| j|	|*< d}'P qW |'r>P t d1|(  qW |'svt d2 | j|	t| jj d < |st j!d3d4t"|d5}+yt#d6d7 |},W n t$k
r   d},Y nX d8||f }-|,r|-d9|, 7 }-|r|-d:| 7 }-t d;|+  t |- |	S )=a9  
	Obtain a best-effort PPD match for an IEEE 1284 Device ID.

	@param mfg: MFG or MANUFACTURER field
	@type mfg: string
	@param mdl: MDL or MODEL field
	@type mdl: string
	@param description: DES or DESCRIPTION field, optional
	@type description: string
	@param commandsets: CMD or COMMANDSET field, optional
	@type commandsets: string
	@param uri: device URI, optional (only needed for debugging)
	@type uri: string
        @param make_and_model: device-make-and-model string
        @type make_and_model: string
	@returns: a dict of fit (string) indexed by PPD name
	z
%s %sNFTzhewlett-packardr   z&**** Incorrect IEEE 1284 Device ID: %sz **** Actual ID is MFG:%s;MDL:%s;z4**** Please report a bug against the HPLIP componentzTrying make/model namesr   zmfgl: %szmdll: %sZlexmarkzkyocera mita)zhewlett-packardzlexmark internationalZkyocerazremapped mfgl: %szmake: %sr   r   zunprefixed mdll: %sz%s: %szre-split mdll: %s,zChecking CMD fieldzipp:zipps:Zdnssdz._ippzdriverless:r   z$Removed %s due to non-IPP connectionzppd-device-idCMD:zppd-type
postscriptZ
POSTSCRIPTz: %sc             S   s   g | ]\}}|d kr|qS )genericr=   )r   dmr=   r=   r>   r     s    z0PPDs.getPPDNamesFromDeviceID.<locals>.<listcomp>zRemoved %s due to CMD mis-matchzNot removing %s z3due to CMD mis-match as it would leave nothing goodztextonly.ppdzpostscript.ppdz'%s' fallbackz.gzzFallback '%s' not availablez#No fallback available; choosing anyz
//[^@]*@/?z//)patternreplstringc             S   s   | d | S )Nr   r=   )rH   yr=   r=   r>   <lambda>  s    z.PPDs.getPPDNamesFromDeviceID.<locals>.<lambda>zMFG:%s;MDL:%s;zCMD:%s;zDES:%s;zNo ID match for device %s:r   )%r   	_init_idsr   rR   	FIT_EXACTr\   rf   r   rE   lmakesrQ   lmodelsr%   r0   rg   rG   _findBestMatchPPDsr}   typer"   _getPPDNameFromCommandSetFIT_GENERICr   r   rP   rI   r(   r   r    FIT_EXACT_CMDr/   r&   r#   r$   strr   	TypeError).r^   mfgmdldescriptioncommandsetsurir   Zorig_mfgZorig_mdlr~   ZmfglmdllZ
id_matchedZeachmdlsr2   ZmfgreplZrmfgZmdlslprefixr6   Zmfg2Zmdl2Zmdl2lsrP   r   ZdriverZfailedra   Z	exact_cmdZppd_cmd_fieldZppdZppd_device_idZppd_device_id_dictZppd_typeZusableZpdlZ	fallbacksfoundZfallbackZ
fallbackgzZppdpathZsanitised_uricmdidr=   r=   r>   getPPDNamesFromDeviceID  sP   



















 



zPPDs.getPPDNamesFromDeviceIDc             C   s   |dkrg }|dkrg }| j ||||||}||||d}	| jt|j |||	|}
tdt|
  | j||
d  }td|
d |f  ||
d fS )a  
	Obtain a best-effort PPD match for an IEEE 1284 Device ID.
	The status is one of:

	  - L{STATUS_SUCCESS}: the match was successful, and an exact
            match was found

	  - L{STATUS_MODEL_MISMATCH}: a similar match was found, but
            the model name does not exactly match

	  - L{STATUS_GENERIC_DRIVER}: no match was found, but a
            generic driver is available that can drive this device
            according to its command set list

	  - L{STATUS_NO_DRIVER}: no match was found at all, and the
            returned PPD name is a last resort

	@param mfg: MFG or MANUFACTURER field
	@type mfg: string
	@param mdl: MDL or MODEL field
	@type mdl: string
	@param description: DES or DESCRIPTION field, optional
	@type description: string
	@param commandsets: CMD or COMMANDSET field, optional
	@type commandsets: string
	@param uri: device URI, optional (only needed for debugging)
	@type uri: string
        @param downloadedfiles: filenames from downloaded packages
        @type downloadedfiles: string list
        @param make_and_model: device-make-and-model string
        @type make_and_model: string
	@returns: an integer,string pair of (status,ppd-name)
	N)MFGMDLZDESr   zFound PPDs: %sr   zUsing %s (status: %d))r   r   rG   rg   r   r   r   )r^   r   r   r   r   r   r   r   r~   r   r   Zstatusr=   r=   r>   getPPDNameFromDeviceID#  s$    &
zPPDs.getPPDNameFromDeviceIDc                s  t d |j }|jdr2|dd }|dd }d}d}t j }dd |D }|j||f |jtjdd	 d
 |j	||f}||d  g}	|d t
|k r|	j||d   t |	d d d | d |	d d   nt |	d d d |  xX|	D ]P\}
}tjj||g}t
||k rt |
 j }t
|}t d|
|f   qW |r|t
|d kr|}|t
|kr| j}n| j}n
| j}d}|jtjtjd
  fdd|D }d}x^|jdD ]P}|dkr|}d}x*tt
|D ]}|| j rd}P qW |r|}P qW d}d}d}xLtt
|D ]<}|| j rj|dkr\|}|}|d7 }n|dkr<P q<W |d7 }d}|dkrt||| }|d| d ||d  }t d|||f  d}d}d}x||k rtd|}||| |  }t d|||f  xP|D ]H\}}x(|jdD ]}|j |kr.d}P q.W |rt|j }P qW |rnP |d7 }|dk rP qW |r|}| j}||fS )z|
        Find the best-matching PPDs based on the MDL Device ID.
        This function could be made a lot smarter.
        zTrying best matchz seriesN   r   c             S   s   g | ]}||j  fqS r=   )r   )r   rH   r=   r=   r>   r   u  s    z+PPDs._findBestMatchPPDs.<locals>.<listcomp>c             S   s   t j| d |d S )Nr   )ro   rp   )rH   r   r=   r=   r>   r   w  s    z)PPDs._findBestMatchPPDs.<locals>.<lambda>)rd   r   z <= z%s: match length %dr?   c                s   g | ]}|j   | fqS r=   )r   )r   rH   )r   r=   r>   r     s    r   FTz%dz'Searching for model ID '%s', '%s' %% %d
   z#Ignoring %d of %d digits, trying %siir   r   r   r   )r   r   r&   rG   rg   r]   rh   rv   rw   indexr0   rU   rW   commonprefixr   	FIT_CLOSEr}   ro   rp   r"   r@   rB   intpow)r^   r   r   r   Zbest_mdlZbest_matchlenZmdlnamesZ	mdlnameslrD   
candidates	candidateZ
candidatelr   r   r~   ZmdlitemsZmodelidZwordZhave_digitsZdigitsZdigits_startZ
digits_endZmodelnumberZmodelpatternZignore_digitsr   Zdivr;   rP   r=   )r   r>   r   d  s    








zPPDs._findBestMatchPPDsc                s  |dkrg }yj   jd  W n tk
r6   dS X  fdd}dd |D }d|ksld|ksld	|krt|d
S d|ksd|ksd|ksd|kr|ddS d|kr|ddS d|kr|ddS d|ksd|kr|ddS d|kr|ddS d|ksd|ksd|kr|dS dS )zfReturn ppd-name list or None, given a list of strings representing
        the command sets supported.Nre   c                 s0   x*| D ]"}j  |\}}|jkr|S qW d S )N)r   r   )r   r6   r   rP   )modelsr^   r=   r>   r(     s
    

z+PPDs._getPPDNameFromCommandSet.<locals>.getc             S   s   g | ]}|j  qS r=   )r   )r   rH   r=   r=   r>   r     s    z2PPDs._getPPDNameFromCommandSet.<locals>.<listcomp>r   Zpostscript2zpostscript level 2 emulationZ
PostScriptZpclxlzpcl-xlZpcl6zpcl 6 emulationzPCL 6/PCL XLz	PCL LaserZpcl5ezPCL 5eZpcl5czPCL 5cZpcl5zpcl 5 emulationzPCL 5ZpclzPCL 3Zescpl2zesc/p2Zescp2ezESC/P Dot Matrix)rf   rQ   r\   )r^   r   r(   Zcmdsetsr=   )r   r^   r>   r     s6    





zPPDs._getPPDNameFromCommandSetc             C   s  | j r
d S tj }i }i }i }i }x| jj D ]\}}t|d }t|}	t|	g}
|jdg }t|t	st|g}tdd |D }|r.t
|dkrt }t|jddj }|r|d7 }t|}xf|D ]^}|jd	r|jd
r|dt
|d  }|s qt|}|j|s|| }|
jt| qW x|
D ]\}}t|}t|}||krp|||< i ||< i ||< n|| }||| kr||| |< i || |< n|| | }||| | |< q4W |	|
kr|
j|	 |
r0|	\}}||kr || j|t }ni ||< t }|jdd |
D }||| |< q0W x|j D ]\}}t|}|| }xv|j D ]j\}}|| jt|}|sq^|| | }x6|D ].}|| jt|}|| | }|j| qW q^W q<W || _ || _|| _tdtj |   d S )Nzppd-make-and-modelzppd-productc             S   s   g | ]}|j d r|qS )()r%   )r   rH   r=   r=   r>   r     s    z$PPDs._init_makes.<locals>.<listcomp>r   zppd-maker   r   r   )c             S   s   g | ]}|d  qS )r   r=   )r   rH   r=   r=   r>   r   Y  s    zinit_makes: %.3fs)rQ   timerP   r/   rI   r   r   r(   rF   rG   r0   rstriprE   r%   r&   r   rk   unionupdater   r   r   )r^   ZtstartrQ   r   r   aliasesra   rb   r1   Zppd_mm_splitZppd_makes_and_modelsZppd_productsr2   ZlmakeZppd_productZlprodr6   Zlmodelr   Z	main_makeZ
modelnamesZ
main_modelZ	main_ppdsZ	eachmodelZ
this_modelrP   r=   r=   r>   rf     s    











zPPDs._init_makesc       	      C   s   | j r
d S i }x| jj D ]\}}t|jd}|s6qt|}|d j }|d j }d}t|dkrjd}t|dkrzd}|rq||kri ||< ||| krg || |< || | j| qW || _ d S )Nzppd-device-idr   r   Fr   T)	rR   rP   r/   rI   r(   r   r   r0   r]   )	r^   rR   ra   rb   r   Zid_dictZlmfgZlmdlZbadr=   r=   r>   r   r  s.    zPPDs._init_ids)NN)NNNNN)r   NNN)r   NNNN)N)__name__
__module____qualname____doc__ZSTATUS_SUCCESSZSTATUS_MODEL_MISMATCHZSTATUS_GENERIC_DRIVERZSTATUS_NO_DRIVERr   r|   r   r   r   r   r}   r{   rc   rn   rx   ry   rz   r   r   r   r   r   r   rf   r   r=   r=   r=   r>   r	   0  sL   
K   
C  
     
>y
(mc               C   s   t d d S )NzBusage: ppds.py [--deviceid] [--list-models] [--list-ids] [--debug])r[   r=   r=   r=   r>   
_show_help  s    r   )"ro   rL   r   r   r   	itertoolsr   r   ri   os.pathrU   rv   r#   r   r   r   __all__compiler   r'   r4   r5   r   r.   r   r)   r+   Ir,   r   rE   rI   r	   r   r=   r=   r=   r>   <module>   sd   


 .      h