Replace 'tap' to 'spaces' to make gbs build succeed
[platform/upstream/hplip.git] / diagnose_queues.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # (c) Copyright 2011-2014 Hewlett-Packard Development Company, L.P.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 #
20 # Author: Amarnath Chitumalla
21 #
22
23 __version__ = '1.0'
24 __title__ = 'AutoConfig Utility to check queues configuration'
25 __mod__ = 'hp-daignose-queues'
26 __doc__ = """Auto config utility for HPLIP supported multifunction Devices to diagnose queues configuration."""
27
28 # Std Lib
29 import sys
30 import os
31 import getopt
32 import commands
33 import re
34
35 # Local
36 from base.g import *
37 from base import utils, tui, models
38 from prnt import cups
39 from installer import core_install
40
41 # ppd type
42 HPCUPS = 1
43 HPIJS = 2
44 HPPS = 3
45 HPOTHER = 4
46
47 DEVICE_URI_PATTERN = re.compile(r"""(.*):/(.*?)/(\S*?)\?(?:serial=(\S*)|device=(\S*)|ip=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}[^&]*)|zc=(\S+))(?:&port=(\d))?""", re.I)
48 NICKNAME_PATTERN = re.compile(r'''\*NickName:\s*\"(.*)"''', re.MULTILINE)
49 NET_PATTERN = re.compile(r"""(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})""")
50 NET_ZC_PATTERN = re.compile(r'''zc=(.*)''',re.IGNORECASE)
51 NET_OTHER_PATTERN = re.compile(r'''(.*)://(.*)''',re.IGNORECASE)
52 USB_PATTERN = re.compile(r'''serial=(.*)''',re.IGNORECASE)
53 LPSTAT_PATTERN = re.compile(r"""(\S*): (.*)""", re.IGNORECASE)
54 #BACK_END_PATTERN = re.compile(r'''(.*):(.*)''',re.IGNORECASE)
55
56 ##### METHODS #####
57
58 def usage(typ='text'):
59     if typ == 'text':
60         utils.log_title(__title__, __version__)
61     utils.format_text(USAGE, typ, __title__, __mod__, __version__)
62     sys.exit(0)
63
64
65 # Checks 'lp' group is added o not
66 def check_user_groups():
67     result = False
68     sts,output = utils.run('groups')
69     if sts != 0:
70         log.error("Failed to get groups")
71     else:
72         output = output.rstrip('\r\n')
73         log.debug("groups =%s "%output)
74         grp_list= output.split(' ')
75         cnt = 0
76         while cnt < len(grp_list) :
77             if grp_list[cnt] == 'lp':
78                 result = True
79                 break
80             cnt += 1
81             
82     return result
83
84 # This function adds the groups ('lp') to user 
85 def add_group(core):
86     result = False
87     add_user_to_group = core.get_distro_ver_data('add_user_to_group', '')
88     if add_user_to_group:
89         usermod = os.path.join(utils.which("usermod"), "usermod") + " %s %s" % (add_user_to_group, prop.username)
90     else:
91         usermod = os.path.join(utils.which("usermod"), "usermod") + " %s %s" % ("-Glp", prop.username)
92
93     su_sudo = utils.su_sudo()
94     password_f = None
95     if su_sudo is "su":
96         name,version,is_su = utils.os_release()
97         log.debug("name = %s version = %s is_su = %s" %(name,version,is_su))
98         if ( name == 'Fedora' and version >= '14' and is_su == True):
99            #using su opening GUI apps fail in Fedora 14. 
100            #To run GUI apps as root, you need a root login shell (su -) in Fedora 14   
101            su_sudo = 'su - -c "%s"'
102         else:
103            su_sudo = 'su -c "%s"'
104
105         password_f = "get_password_ui"
106 #        password_f = utils.get_password
107     cmd =su_sudo % usermod
108     log.info("cmd = %s" %cmd)
109 #    sts, output = utils.run(cmd, True, password_f, -1,True,cmd)  
110     sts, output = utils.run(cmd, True, password_f, 1, True, "Please enter root/superuser password to add 'lp' group")
111     if sts == 0:
112         result = True
113         
114     return result
115
116
117 # This parse the given Device URI. and provides the details.
118 def parseDeviceURI(device_uri):
119     m = DEVICE_URI_PATTERN.match(device_uri)
120     if m is None:
121         raise Error(ERROR_INVALID_DEVICE_URI)
122
123     back_end = m.group(1).lower() or ''
124     is_hp = (back_end in ('hp', 'hpfax', 'hpaio'))
125     bus = m.group(2).lower() or ''
126
127     if bus not in ('usb', 'net', 'bt', 'fw', 'par'):
128         raise Error(ERROR_INVALID_DEVICE_URI)
129
130     model =m.group(3) or ''
131     serial = m.group(4) or ''
132     dev_file = m.group(5) or ''
133     host = m.group(6) or ''
134     zc = ''
135     if not host:
136         zc = host = m.group(7) or ''
137     port = m.group(8) or 1
138
139     if bus == 'net':
140         try:
141             port = int(port)
142         except (ValueError, TypeError):
143             port = 1
144
145         if port == 0:
146             port = 1
147
148 #    log.warning("++++: back_end '%s' is_hp '%s' bus '%s' model '%s' serial '%s' dev_file '%s' host '%s' zc '%s' port '%s' " %
149 #       ( back_end, is_hp, bus, model, serial, dev_file, host, zc, port))
150
151     return back_end, is_hp, bus, model, serial, dev_file, host, zc, port
152
153
154 ####### Device class ########
155 class DetectedDevice:
156     def __init__(self, Printer_Name,Device_URI,Device_Type, ppdType, PPDFileError = False, IsEnabled=True ):
157         self.PrinterName =Printer_Name
158         self.DeviceURI = Device_URI
159         self.DeviceType = Device_Type
160         self.PPDFileType = ppdType
161         self.PPDFileError = PPDFileError
162         self.IsEnabled = IsEnabled
163
164
165
166
167 #########Main##########
168 USAGE = [(__doc__, "", "name", True),
169          ("Usage: %s [OPTIONS]" % __mod__, "", "summary", True),
170          utils.USAGE_OPTIONS,
171          utils.USAGE_LOGGING1, utils.USAGE_LOGGING2, utils.USAGE_LOGGING3,
172          utils.USAGE_HELP,
173         ]
174
175 try:
176     log.set_module(__mod__)
177
178     try:
179         opts, args = getopt.getopt(sys.argv[1:],  'hl:gsr',  ['help', 'help-rest', 'help-man', 'help-desc', 'logging='])
180
181     except getopt.GetoptError, e:
182         log.error(e.msg)
183         usage()
184         sys.exit(1)
185
186     if os.getenv("HPLIP_DEBUG"):
187         log.set_level('debug')
188
189     log_level = 'info'
190     Show_result=False
191     quiet_mode = False
192     for o, a in opts:
193         if o in ('-h', '--help'):
194             usage()
195
196         elif o == '--help-rest':
197             usage('rest')
198
199         elif o == '--help-man':
200             usage('man')
201
202         elif o == '--help-desc':
203             print __doc__,
204             sys.exit(0)
205
206         elif o in ('-l', '--logging'):
207             log_level = a.lower().strip()
208
209         elif o == '-g':
210             log_level = 'debug'
211
212         elif o == '-r':
213             Show_result = True
214
215         elif o == '-s':
216             quiet_mode = True
217
218     if not log.set_level(log_level):
219         usage()
220     if not quiet_mode:
221         utils.log_title(__title__, __version__)
222
223     log_file = os.path.normpath('/var/loh/hp/hplip_queues.log')
224     log.debug(log.bold("Saving output in log file: %s" % log_file))
225     if os.path.exists(log_file):
226         os.remove(log_file)
227     log.set_logfile(log_file)
228     log.set_where(log.LOG_TO_CONSOLE_AND_FILE)
229     
230     try:
231         from base import device, pml
232         # This can fail due to hpmudext not being present
233     except ImportError:
234         log.error("Device library is not avail.")
235         sys.exit(1)
236
237     # Only Qt4 is supported.
238     try:
239         from PyQt4.QtGui import QApplication, QMessageBox
240         from ui4.queuesconf import QueuesDiagnose
241     except ImportError:
242         log.error("Unable to load Qt4 support. Is it installed?")
243         sys.exit(1)
244
245     app = QApplication(sys.argv)
246     Error_Found = False
247     if check_user_groups() is False:
248         dialog = QueuesDiagnose(None, "","",QUEUES_MSG_SENDING)
249         core = core_install.CoreInstall()
250         core.init()
251         if add_group(core) is False:
252             Error_Found = True
253             #log.error("Failed to add lp group to user[%s]. Manually add 'lp' group to usergroups"%prop.username)
254             dialog.showMessage("User must be part of 'lp' group.\nManually add 'lp' group to '%s' user. " %prop.username)
255         else:
256             dialog.showSuccessMessage("Groups added successfully and reboot is required. Please reboot system to take effect.")
257
258
259     is_hpcups_installed = to_bool(sys_conf.get('configure', 'hpcups-install', '0'))
260     is_hpijs_installed = to_bool(sys_conf.get('configure', 'hpijs-install', '0'))
261 #    tui.header("INSTALLED CUPS PRINTER QUEUES")
262
263     
264     status, output = utils.run('lpstat -v')
265
266     cups_printers = []
267     for p in output.splitlines():
268         try:
269             match = LPSTAT_PATTERN.search(p)
270             printer_name = match.group(1)
271             device_uri = match.group(2)
272             cups_printers.append((printer_name, device_uri))
273         except AttributeError:
274             pass
275
276     log.debug(cups_printers)
277     log.debug("HPCups installation=%d  HPIJS installation =%d" %(is_hpcups_installed, is_hpijs_installed))
278     if cups_printers:
279         mapofDevices={}
280
281         for p in cups_printers:
282             printer_name, device_uri = p
283
284             if device_uri.startswith("cups-pdf:/"):
285                 continue
286
287             log.debug(log.bold(printer_name))
288             log.debug(log.bold('-'*len(printer_name)))
289
290             try:
291                 back_end, is_hp, bus, model, serial, dev_file, host, zc, port = parseDeviceURI(device_uri)
292             except Error:
293                 back_end, is_hp, bus, model, serial, dev_file, host, zc, port = '', False, '', '', '', '', '', '', 1
294                 if 'HP' in device_uri:
295                     is_hp = True
296
297             log.debug("Device URI: %s" % device_uri)
298             ppd_file = os.path.join('/etc/cups/ppd', printer_name + '.ppd')
299             if os.path.exists(ppd_file):
300                 log.debug("PPD: %s" % ppd_file)
301
302                 fileptr = file(ppd_file, 'r').read(4096)
303                 try:
304                     desc = NICKNAME_PATTERN.search(fileptr).group(1)
305                 except AttributeError:
306                     desc = ''
307
308                 log.debug("PPD Description: %s" % desc)
309                 status, output = utils.run('lpstat -p%s' % printer_name)
310                 log.debug("Printer status: %s" % output.replace("\n", ""))
311
312                 #### checking for USb devices ####
313                 if USB_PATTERN.search(device_uri):                   
314                     Key =USB_PATTERN.search(device_uri).group(1)
315                 #### checking for network devices ####
316                 elif NET_PATTERN.search(device_uri):
317                     Key = NET_PATTERN.search(device_uri).group(1)
318                 elif NET_ZC_PATTERN.search(device_uri):
319                     Key = NET_ZC_PATTERN.search(device_uri).group(1)
320                 elif NET_OTHER_PATTERN.search(device_uri):
321                     part_1 = NET_OTHER_PATTERN.search(device_uri).group(1)
322                     part_2 = NET_OTHER_PATTERN.search(device_uri).group(2)
323                     if 'HP' in part_2:
324                         Key = part_2
325                     else:
326                         log.info("unknown protocol device_uri=%s" %device_uri)
327                         Key=None
328                 else:
329                     log.info("unknown protocol device_uri=%s" %device_uri)
330                     Key=None
331
332                 if Key is not None:
333                     Is_Print_Q_Enabled= True
334                     if output.find('Paused') !=  -1:
335                         Is_Print_Q_Enabled= False
336                     Key=Key+"_"+back_end
337                     log.debug("Key'%s': deviceType '%s' is_hp '%s' bus '%s' model '%s' serial '%s' dev_file '%s' host '%s' zc '%s' port '%s' Enabled'%d'"\
338                                                %( Key,back_end, is_hp, bus, model, serial, dev_file, host, zc, port,Is_Print_Q_Enabled))
339
340                     PPDFileError = False
341                     if back_end == 'hpfax' and not 'HP Fax' in desc:
342                         log.error("Incorrect PPD file for fax queue '%s'. Fax queue must use 'HP-Fax-hplip.ppd'." % printer_name)
343                         PPDFileError = True
344                     elif back_end == 'hp' and 'HP Fax' in desc:
345                         log.error("Incorrect PPD file for print queue '%s'. Print queue must not use 'HP-Fax-hplip.ppd'." % printer_name)
346                         PPDFileError = True
347                     elif back_end not in ('hp', 'hpfax'):
348                         log.warn("Device %s is not HPLIP installed. Device must use the hp: or hpfax: to function in HPLIP."% printer_name)
349
350                     ppd_fileType = None
351                     if 'hpcups' in desc:
352                         ppd_fileType = HPCUPS
353                         if not is_hpcups_installed:
354                             PPDFileError = True
355                     elif 'hpijs' in desc:
356                         ppd_fileType = HPIJS
357                         if not is_hpijs_installed:
358                             PPDFileError = True
359                     elif 'Postscript' in desc:
360                         ppd_fileType =HPPS
361                     elif is_hp:
362                         ppd_fileType =HPOTHER
363                         PPDFileError = True
364
365                     if ppd_fileType != None:
366                         device1 =DetectedDevice(printer_name, device_uri,back_end, ppd_fileType,PPDFileError, Is_Print_Q_Enabled)
367                         if Key in mapofDevices:
368                             mapofDevices[Key].append(device1)
369                         else:
370                             deviceList=[device1]
371                             mapofDevices[Key]=deviceList
372                     else:
373                         log.warn("%s is not HP Device." %(printer_name))
374
375         for key,val in mapofDevices.items():
376             if len(val) >1:
377                 log.debug("")
378                 log.warn('%d queues of same device %s is configured.  Remove unwanted queues.' %(len(val),val[0].PrinterName))
379                 if Show_result:
380                     Error_Found = True
381                     dialog = QueuesDiagnose(None, "","",QUEUES_MSG_SENDING)
382                     dialog.showMessage("%d queues of same device %s is configured.\nRemove unwanted queues."%(len(val),val[0].PrinterName))
383                  
384                 for que in val:
385                     Error_msg =None
386                     if 'hp' in que.DeviceType or 'hpfax' in que.DeviceType:
387                         if que.PPDFileError ==  False:
388                             log.debug("'%s' is configured correctly." %(que.PrinterName))
389                         else:
390                             log.error("PPD file for '%s' is not correct. Need to choose correct PPD file." %(que.PrinterName))
391                             Error_msg = QUEUES_INCORRECT_PPD
392                     else:
393                         log.error("'%s' is not configured using HPLIP. Need to remove and re-cofigure from hp-setup." %(que.PrinterName))
394                         Error_msg =QUEUES_CONFIG_ERROR
395
396                     if Error_msg ==None and que.IsEnabled == False:
397                         Error_msg = QUEUES_PAUSED
398
399                     if Error_msg != None:
400                         Error_Found = True
401                         dialog = QueuesDiagnose(None, que.PrinterName,que.DeviceURI,Error_msg)
402                         dialog.show()
403                         log.debug("Starting GUI loop...")
404                         app.exec_()
405             else:
406                 Error_msg =None
407                 log.debug("")
408                 log.debug("Single print queue is configured for '%s'. " %val[0].PrinterName)
409                 if 'hp' in val[0].DeviceType or 'hpfax' in val[0].DeviceType:
410                     if val[0].PPDFileError == False:
411                         log.debug("'%s' is configured correctly." %(val[0].PrinterName))
412                     else:
413                         log.error("PPD file for '%s' is not correct. Need to choose correct PPD file." %(val[0].PrinterName))
414                         Error_msg = QUEUES_INCORRECT_PPD
415                 else:
416                     log.error("'%s' is not configured using HPLIP. Need to remove and re-configure using hp-setup." %(val[0].PrinterName))
417                     Error_msg = QUEUES_CONFIG_ERROR
418
419                 if Error_msg ==None and val[0].IsEnabled == False:
420                     Error_msg = QUEUES_PAUSED
421
422                 if Error_msg != None:
423                     Error_Found = True
424                     name = val[0].PrinterName
425                     dialog = QueuesDiagnose(None, name, val[0].DeviceURI, Error_msg)
426                     dialog.show()
427                     log.debug("Starting GUI loop...")
428                     app.exec_()
429     else:
430         log.debug("No queues found.")
431    
432     if Show_result and (Error_Found is False):
433         dialog = QueuesDiagnose(None, "","",QUEUES_MSG_SENDING)
434         dialog.showSuccessMessage("Queue(s) configured correctly using HPLIP.")
435        
436
437 except KeyboardInterrupt:
438     log.error("User exit")
439
440 log.debug("Done.")