1#!/usr/local/bin/python3.8 2# -*- coding: utf-8 -*- 3# 4# (c) Copyright 2001-2018 HP 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: Don Welch, Naga Samrat Chowdary Narla, Goutam Kodu, Amarnath Chitumalla 21# 22# Thanks to Henrique M. Holschuh <hmh@debian.org> for various security patches 23# 24 25 26 27# Std Lib 28import sys 29import os 30from subprocess import Popen, PIPE 31import grp 32import fnmatch 33import tempfile 34import socket 35import struct 36import select 37import time 38import fcntl 39import errno 40import stat 41import string 42import glob 43import re 44import datetime 45from .g import * 46import locale 47from .sixext.moves import html_entities, urllib2_request, urllib2_parse, urllib2_error 48from .sixext import PY3, to_unicode, to_bytes_utf8, to_string_utf8, BytesIO, StringIO, subprocess 49from . import os_utils 50try: 51 import xml.parsers.expat as expat 52 xml_expat_avail = True 53except ImportError: 54 xml_expat_avail = False 55 56try: 57 import platform 58 platform_avail = True 59except ImportError: 60 platform_avail = False 61 62try: 63 import dbus 64 from dbus import SystemBus, lowlevel, SessionBus 65 dbus_avail=True 66except ImportError: 67 dbus_avail=False 68 69try: 70 import hashlib # new in 2.5 71 72 def get_checksum(s): 73 return hashlib.sha1(s).hexdigest() 74 75except ImportError: 76 import sha # deprecated in 2.6/3.0 77 78 def get_checksum(s): 79 return sha.new(s).hexdigest() 80 81 82 83 84# Local 85from .g import * 86from .codes import * 87from . import pexpect 88 89 90BIG_ENDIAN = 0 91LITTLE_ENDIAN = 1 92 93RMDIR="rm -rf" 94RM="rm -f" 95 96DBUS_SERVICE='com.hplip.StatusService' 97 98HPLIP_WEB_SITE ="http://hplipopensource.com/hplip-web/index.html" 99HTTP_CHECK_TARGET = "http://www.hp.com" 100PING_CHECK_TARGET = "www.hp.com" 101 102ERROR_NONE = 0 103ERROR_FILE_CHECKSUM = 1 104ERROR_UNABLE_TO_RECV_KEYS =2 105ERROR_DIGITAL_SIGN_BAD =3 106 107MAJ_VER = sys.version_info[0] 108MIN_VER = sys.version_info[1] 109 110EXPECT_WORD_LIST = [ 111 pexpect.EOF, # 0 112 pexpect.TIMEOUT, # 1 113 u"Continue?", # 2 (for zypper) 114 u"passwor[dt]:", # en/de/it/ru 115 u"kennwort", # de? 116 u"password for", # en 117 u"mot de passe", # fr 118 u"contraseña", # es 119 u"palavra passe", # pt 120 u"口令", # zh 121 u"wachtwoord", # nl 122 u"heslo", # czech 123 u"密码", 124 u"Lösenord", #sv 125] 126 127 128EXPECT_LIST = [] 129for s in EXPECT_WORD_LIST: 130 try: 131 p = re.compile(s, re.I) 132 except TypeError: 133 EXPECT_LIST.append(s) 134 else: 135 EXPECT_LIST.append(p) 136 137 138def get_cups_systemgroup_list(): 139 lis = [] 140 try: 141 fp=open('/usr/local/etc/cups/cupsd.conf') 142 except IOError: 143 try: 144 if "root" != grp.getgrgid(os.stat('/usr/local/etc/cups/cupsd.conf').st_gid).gr_name: 145 return [grp.getgrgid(os.stat('/usr/local/etc/cups/cupsd.conf').st_gid).gr_name] 146 except OSError: 147 return lis 148 149 try: 150 lis = ((re.findall('SystemGroup [\w* ]*',fp.read()))[0].replace('SystemGroup ','')).split(' ') 151 except IndexError: 152 return lis 153 154 if 'root' in lis: 155 lis.remove('root') 156 fp.close() 157 return lis 158 159def lock(f): 160 log.debug("Locking: %s" % f.name) 161 try: 162 fcntl.flock(f.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB) 163 return True 164 except (IOError, OSError): 165 log.debug("Failed to unlock %s." % f.name) 166 return False 167 168 169def unlock(f): 170 if f is not None: 171 log.debug("Unlocking: %s" % f.name) 172 try: 173 fcntl.flock(f.fileno(), fcntl.LOCK_UN) 174 os.remove(f.name) 175 except (IOError, OSError): 176 pass 177 178 179def lock_app(application, suppress_error=False): 180 dir = prop.user_dir 181 if os.geteuid() == 0: 182 dir = '/var' 183 184 elif not os.path.exists(dir): 185 os.makedirs(dir) 186 187 lock_file = os.path.join(dir, '.'.join([application, 'lock'])) 188 try: 189 lock_file_f = open(lock_file, "w") 190 except IOError: 191 if not suppress_error: 192 log.error("Unable to open %s lock file." % lock_file) 193 return False, None 194 195 #log.debug("Locking file: %s" % lock_file) 196 197 if not lock(lock_file_f): 198 if not suppress_error: 199 log.error("Unable to lock %s. Is %s already running?" % (lock_file, application)) 200 return False, None 201 202 return True, lock_file_f 203 204 205#xml_basename_pat = re.compile(r"""HPLIP-(\d*)_(\d*)_(\d*).xml""", re.IGNORECASE) 206 207 208def Translator(frm=to_bytes_utf8(''), to=to_bytes_utf8(''), delete=to_bytes_utf8(''), keep=None): #Need Revisit 209 if len(to) == 1: 210 to = to * len(frm) 211 212 if PY3: 213 data_types = bytes 214 else: 215 data_types = string 216 217 allchars = data_types.maketrans(to_bytes_utf8(''), to_bytes_utf8('')) 218 trans = data_types.maketrans(frm, to) 219 220 if keep is not None: 221 delete = allchars.translate(allchars, keep.translate(allchars, delete)) 222 223 def callable(s): 224 return s.translate(trans, delete) 225 226 return callable 227 228 229def list_to_string(lis): 230 if len(lis) == 0: 231 return "" 232 if len(lis) == 1: 233 return str("\""+lis[0]+"\"") 234 if len(lis) >= 1: 235 return "\""+"\", \"".join(lis)+"\" and \""+str(lis.pop())+"\"" 236 237def to_bool_str(s, default='0'): 238 """ Convert an arbitrary 0/1/T/F/Y/N string to a normalized string 0/1.""" 239 if isinstance(s, str) and s: 240 if s[0].lower() in ['1', 't', 'y']: 241 return to_unicode('1') 242 elif s[0].lower() in ['0', 'f', 'n']: 243 return to_unicode('0') 244 245 return default 246 247def to_bool(s, default=False): 248 """ Convert an arbitrary 0/1/T/F/Y/N string to a boolean True/False value.""" 249 if isinstance(s, str) and s: 250 if s[0].lower() in ['1', 't', 'y']: 251 return True 252 elif s[0].lower() in ['0', 'f', 'n']: 253 return False 254 elif isinstance(s, bool): 255 return s 256 257 return default 258 259 260# Compare with os.walk() 261def walkFiles(root, recurse=True, abs_paths=False, return_folders=False, pattern='*', path=None): 262 if path is None: 263 path = root 264 265 try: 266 names = os.listdir(root) 267 except os.error: 268 #raise StopIteration 269 return 270 271 pattern = pattern or '*' 272 pat_list = pattern.split(';') 273 274 for name in names: 275 fullname = os.path.normpath(os.path.join(root, name)) 276 277 for pat in pat_list: 278 if fnmatch.fnmatch(name, pat): 279 if return_folders or not os.path.isdir(fullname): 280 if abs_paths: 281 yield fullname 282 else: 283 try: 284 yield os.path.basename(fullname) 285 except ValueError: 286 yield fullname 287 288 #if os.path.islink(fullname): 289 # fullname = os.path.realpath(os.readlink(fullname)) 290 291 if recurse and os.path.isdir(fullname): # or os.path.islink(fullname): 292 for f in walkFiles(fullname, recurse, abs_paths, return_folders, pattern, path): 293 yield f 294 295 296def is_path_writable(path): 297 if os.path.exists(path): 298 s = os.stat(path) 299 mode = s[stat.ST_MODE] & 0o777 300 301 if mode & 0o2: 302 return True 303 elif s[stat.ST_GID] == os.getgid() and mode & 0o20: 304 return True 305 elif s[stat.ST_UID] == os.getuid() and mode & 0o200: 306 return True 307 308 return False 309 310 311# Provides the TextFormatter class for formatting text into columns. 312# Original Author: Hamish B Lawson, 1999 313# Modified by: Don Welch, 2003 314class TextFormatter: 315 316 LEFT = 0 317 CENTER = 1 318 RIGHT = 2 319 320 def __init__(self, colspeclist): 321 self.columns = [] 322 for colspec in colspeclist: 323 self.columns.append(Column(**colspec)) 324 325 def compose(self, textlist, add_newline=False): 326 numlines = 0 327 textlist = list(textlist) 328 if len(textlist) != len(self.columns): 329 log.error("Formatter: Number of text items does not match columns") 330 return 331 for text, column in list(map(lambda *x: x, textlist, self.columns)): 332 column.wrap(text) 333 numlines = max(numlines, len(column.lines)) 334 complines = [''] * numlines 335 for ln in range(numlines): 336 for column in self.columns: 337 complines[ln] = complines[ln] + column.getline(ln) 338 if add_newline: 339 return '\n'.join(complines) + '\n' 340 else: 341 return '\n'.join(complines) 342 343class Column: 344 345 def __init__(self, width=78, alignment=TextFormatter.LEFT, margin=0): 346 self.width = int(width) 347 self.alignment = alignment 348 self.margin = margin 349 self.lines = [] 350 351 def align(self, line): 352 if self.alignment == TextFormatter.CENTER: 353 return line.center(self.width) 354 elif self.alignment == TextFormatter.RIGHT: 355 return line.rjust(self.width) 356 else: 357 return line.ljust(self.width) 358 359 def wrap(self, text): 360 self.lines = [] 361 words = [] 362 for word in text.split(): 363 if word <= str(self.width): 364 words.append(word) 365 else: 366 for i in range(0, len(word), self.width): 367 words.append(word[i:i+self.width]) 368 if not len(words): return 369 current = words.pop(0) 370 for word in words: 371 increment = 1 + len(word) 372 if len(current) + increment > self.width: 373 self.lines.append(self.align(current)) 374 current = word 375 else: 376 current = current + ' ' + word 377 self.lines.append(self.align(current)) 378 379 def getline(self, index): 380 if index < len(self.lines): 381 return ' '*self.margin + self.lines[index] 382 else: 383 return ' ' * (self.margin + self.width) 384 385 386 387class Stack: 388 def __init__(self): 389 self.stack = [] 390 391 def pop(self): 392 return self.stack.pop() 393 394 def push(self, value): 395 self.stack.append(value) 396 397 def as_list(self): 398 return self.stack 399 400 def clear(self): 401 self.stack = [] 402 403 def __len__(self): 404 return len(self.stack) 405 406 407 408class Queue(Stack): 409 def __init__(self): 410 Stack.__init__(self) 411 412 def get(self): 413 return self.stack.pop(0) 414 415 def put(self, value): 416 Stack.push(self, value) 417 418 419 420# RingBuffer class 421# Source: Python Cookbook 1st Ed., sec. 5.18, pg. 201 422# Credit: Sebastien Keim 423# License: Modified BSD 424class RingBuffer: 425 def __init__(self, size_max=50): 426 self.max = size_max 427 self.data = [] 428 429 def append(self,x): 430 """append an element at the end of the buffer""" 431 self.data.append(x) 432 433 if len(self.data) == self.max: 434 self.cur = 0 435 self.__class__ = RingBufferFull 436 437 def replace(self, x): 438 """replace the last element instead off appending""" 439 self.data[-1] = x 440 441 def get(self): 442 """ return a list of elements from the oldest to the newest""" 443 return self.data 444 445 446class RingBufferFull: 447 def __init__(self, n): 448 #raise "you should use RingBuffer" 449 pass 450 451 def append(self, x): 452 self.data[self.cur] = x 453 self.cur = (self.cur+1) % self.max 454 455 def replace(self, x): 456 # back up 1 position to previous location 457 self.cur = (self.cur-1) % self.max 458 self.data[self.cur] = x 459 # setup for next item 460 self.cur = (self.cur+1) % self.max 461 462 def get(self): 463 return self.data[self.cur:] + self.data[:self.cur] 464 465 466 467def sort_dict_by_value(d): 468 """ Returns the keys of dictionary d sorted by their values """ 469 items=list(d.items()) 470 backitems=[[v[1],v[0]] for v in items] 471 backitems.sort() 472 return [backitems[i][1] for i in range(0, len(backitems))] 473 474 475def commafy(val): 476 return locale.format("%s", val, grouping=True) 477 478 479def format_bytes(s, show_bytes=False): 480 if s < 1024: 481 return ''.join([commafy(s), ' B']) 482 elif 1024 < s < 1048576: 483 if show_bytes: 484 return ''.join([to_unicode(round(s/1024.0, 1)) , to_unicode(' KB ('), commafy(s), ')']) 485 else: 486 return ''.join([to_unicode(round(s/1024.0, 1)) , to_unicode(' KB')]) 487 elif 1048576 < s < 1073741824: 488 if show_bytes: 489 return ''.join([to_unicode(round(s/1048576.0, 1)), to_unicode(' MB ('), commafy(s), ')']) 490 else: 491 return ''.join([to_unicode(round(s/1048576.0, 1)), to_unicode(' MB')]) 492 else: 493 if show_bytes: 494 return ''.join([to_unicode(round(s/1073741824.0, 1)), to_unicode(' GB ('), commafy(s), ')']) 495 else: 496 return ''.join([to_unicode(round(s/1073741824.0, 1)), to_unicode(' GB')]) 497 498 499 500try: 501 make_temp_file = tempfile.mkstemp # 2.3+ 502except AttributeError: 503 def make_temp_file(suffix='', prefix='', dir='', text=False): # pre-2.3 504 path = tempfile.mktemp(suffix) 505 fd = os.open(path, os.O_RDWR|os.O_CREAT|os.O_EXCL, 0o700) 506 return ( os.fdopen( fd, 'w+b' ), path ) 507 508 509 510def which(command, return_full_path=False): 511 path=[] 512 path_val = os.getenv('PATH') 513 if path_val: 514 path = path_val.split(':') 515 516 path.append('/usr/bin') 517 path.append('/usr/local/bin') 518 # Add these paths for Fedora 519 path.append('/sbin') 520 path.append('/usr/sbin') 521 path.append('/usr/local/sbin') 522 523 found_path = '' 524 for p in path: 525 try: 526 files = os.listdir(p) 527 except OSError: 528 continue 529 else: 530 if command in files: 531 found_path = p 532 break 533 534 if return_full_path: 535 if found_path: 536 return os.path.join(found_path, command) 537 else: 538 return '' 539 else: 540 return found_path 541 542 543class UserSettings(object): # Note: Deprecated after 2.8.8 in Qt4 (see ui4/ui_utils.py) 544 def __init__(self): 545 self.load() 546 547 def loadDefaults(self): 548 # Print 549 self.cmd_print = '' 550 path = which('hp-print') 551 552 if len(path) > 0: 553 self.cmd_print = 'hp-print -p%PRINTER%' 554 else: 555 path = which('kprinter') 556 if len(path) > 0: 557 self.cmd_print = 'kprinter -P%PRINTER% --system cups' 558 else: 559 path = which('gtklp') 560 if len(path) > 0: 561 self.cmd_print = 'gtklp -P%PRINTER%' 562 else: 563 path = which('xpp') 564 if len(path) > 0: 565 self.cmd_print = 'xpp -P%PRINTER%' 566 567 # Scan 568 self.cmd_scan = '' 569 path = which('xsane') 570 571 if len(path) > 0: 572 self.cmd_scan = 'xsane -V %SANE_URI%' 573 else: 574 path = which('kooka') 575 if len(path) > 0: 576 self.cmd_scan = 'kooka' 577 else: 578 path = which('xscanimage') 579 if len(path) > 0: 580 self.cmd_scan = 'xscanimage' 581 582 # Photo Card 583 path = which('hp-unload') 584 585 if len(path): 586 self.cmd_pcard = 'hp-unload -d %DEVICE_URI%' 587 else: 588 self.cmd_pcard = 'python %HOME%/unload.py -d %DEVICE_URI%' 589 590 # Copy 591 path = which('hp-makecopies') 592 593 if len(path): 594 self.cmd_copy = 'hp-makecopies -d %DEVICE_URI%' 595 else: 596 self.cmd_copy = 'python %HOME%/makecopies.py -d %DEVICE_URI%' 597 598 # Fax 599 path = which('hp-sendfax') 600 601 if len(path): 602 self.cmd_fax = 'hp-sendfax -d %FAX_URI%' 603 else: 604 self.cmd_fax = 'python %HOME%/sendfax.py -d %FAX_URI%' 605 606 # Fax Address Book 607 path = which('hp-fab') 608 609 if len(path): 610 self.cmd_fab = 'hp-fab' 611 else: 612 self.cmd_fab = 'python %HOME%/fab.py' 613 614 def load(self): 615 self.loadDefaults() 616 log.debug("Loading user settings...") 617 self.auto_refresh = to_bool(user_conf.get('refresh', 'enable', '0')) 618 619 try: 620 self.auto_refresh_rate = int(user_conf.get('refresh', 'rate', '30')) 621 except ValueError: 622 self.auto_refresh_rate = 30 # (secs) 623 624 try: 625 self.auto_refresh_type = int(user_conf.get('refresh', 'type', '0')) 626 except ValueError: 627 self.auto_refresh_type = 0 # refresh 1 (1=refresh all) 628 629 self.cmd_print = user_conf.get('commands', 'prnt', self.cmd_print) 630 self.cmd_scan = user_conf.get('commands', 'scan', self.cmd_scan) 631 self.cmd_pcard = user_conf.get('commands', 'pcard', self.cmd_pcard) 632 self.cmd_copy = user_conf.get('commands', 'cpy', self.cmd_copy) 633 self.cmd_fax = user_conf.get('commands', 'fax', self.cmd_fax) 634 self.cmd_fab = user_conf.get('commands', 'fab', self.cmd_fab) 635 636 self.upgrade_notify= to_bool(user_conf.get('upgrade', 'notify_upgrade', '0')) 637 self.upgrade_last_update_time = int(user_conf.get('upgrade','last_upgraded_time', '0')) 638 self.upgrade_pending_update_time =int(user_conf.get('upgrade', 'pending_upgrade_time', '0')) 639 self.latest_available_version=str(user_conf.get('upgrade', 'latest_available_version','')) 640 self.debug() 641 642 def debug(self): 643 log.debug("Print command: %s" % self.cmd_print) 644 log.debug("PCard command: %s" % self.cmd_pcard) 645 log.debug("Fax command: %s" % self.cmd_fax) 646 log.debug("FAB command: %s" % self.cmd_fab) 647 log.debug("Copy command: %s " % self.cmd_copy) 648 log.debug("Scan command: %s" % self.cmd_scan) 649 log.debug("Auto refresh: %s" % self.auto_refresh) 650 log.debug("Auto refresh rate: %s" % self.auto_refresh_rate) 651 log.debug("Auto refresh type: %s" % self.auto_refresh_type) 652 log.debug("Upgrade notification:%d" %self.upgrade_notify) 653 log.debug("Last Installed time:%d" %self.upgrade_last_update_time) 654 log.debug("Next scheduled installation time:%d" % self.upgrade_pending_update_time) 655 656 657 def save(self): 658 log.debug("Saving user settings...") 659 user_conf.set('commands', 'prnt', self.cmd_print) 660 user_conf.set('commands', 'pcard', self.cmd_pcard) 661 user_conf.set('commands', 'fax', self.cmd_fax) 662 user_conf.set('commands', 'scan', self.cmd_scan) 663 user_conf.set('commands', 'cpy', self.cmd_copy) 664 user_conf.set('refresh', 'enable',self.auto_refresh) 665 user_conf.set('refresh', 'rate', self.auto_refresh_rate) 666 user_conf.set('refresh', 'type', self.auto_refresh_type) 667 user_conf.set('upgrade', 'notify_upgrade', self.upgrade_notify) 668 user_conf.set('upgrade','last_upgraded_time', self.upgrade_last_update_time) 669 user_conf.set('upgrade', 'pending_upgrade_time', self.upgrade_pending_update_time) 670 user_conf.set('upgrade', 'latest_available_version', self.latest_available_version) 671 672 self.debug() 673 674 675 676def no_qt_message_gtk(): 677 try: 678 import gtk 679 w = gtk.Window() 680 dialog = gtk.MessageDialog(w, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, 681 gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, 682 "PyQt not installed. GUI not available. Please check that the PyQt package is installed. Exiting.") 683 dialog.run() 684 dialog.destroy() 685 686 except ImportError: 687 log.error("PyQt not installed. GUI not available. Please check that the PyQt package is installed. Exiting.") 688 689 690def canEnterGUIMode(): # qt3 691 if not prop.gui_build: 692 log.warn("GUI mode disabled in build.") 693 return False 694 695 elif not os.getenv('DISPLAY'): 696 log.warn("No display found.") 697 return False 698 699 elif not checkPyQtImport(): 700 log.warn("Qt/PyQt 3 initialization failed.") 701 return False 702 703 return True 704 705 706def canEnterGUIMode4(): # qt4 707 if not prop.gui_build: 708 log.warn("GUI mode disabled in build.") 709 return False 710 711 elif not os.getenv('DISPLAY'): 712 log.warn("No display found.") 713 return False 714 715 # elif not checkPyQtImport4(): 716 # log.warn("Qt4/PyQt 4 initialization failed.") 717 # return False 718 else: 719 try: 720 checkPyQtImport45() 721 except ImportError as e: 722 log.warn(e) 723 return False 724 725 return True 726 727 728def checkPyQtImport(): # qt3 729 # PyQt 730 try: 731 import qt 732 import ui 733 except ImportError: 734 if os.getenv('DISPLAY') and os.getenv('STARTED_FROM_MENU'): 735 no_qt_message_gtk() 736 737 log.error("PyQt not installed. GUI not available. Exiting.") 738 return False 739 740 # check version of Qt 741 qtMajor = int(qt.qVersion().split('.')[0]) 742 743 if qtMajor < MINIMUM_QT_MAJOR_VER: 744 745 log.error("Incorrect version of Qt installed. Ver. 3.0.0 or greater required.") 746 return False 747 748 #check version of PyQt 749 try: 750 pyqtVersion = qt.PYQT_VERSION_STR 751 except AttributeError: 752 pyqtVersion = qt.PYQT_VERSION 753 754 while pyqtVersion.count('.') < 2: 755 pyqtVersion += '.0' 756 757 (maj_ver, min_ver, pat_ver) = pyqtVersion.split('.') 758 759 if pyqtVersion.find('snapshot') >= 0: 760 log.warning("A non-stable snapshot version of PyQt is installed.") 761 else: 762 try: 763 maj_ver = int(maj_ver) 764 min_ver = int(min_ver) 765 pat_ver = int(pat_ver) 766 except ValueError: 767 maj_ver, min_ver, pat_ver = 0, 0, 0 768 769 if maj_ver < MINIMUM_PYQT_MAJOR_VER or \ 770 (maj_ver == MINIMUM_PYQT_MAJOR_VER and min_ver < MINIMUM_PYQT_MINOR_VER): 771 log.error("This program may not function properly with the version of PyQt that is installed (%d.%d.%d)." % (maj_ver, min_ver, pat_ver)) 772 log.error("Incorrect version of pyQt installed. Ver. %d.%d or greater required." % (MINIMUM_PYQT_MAJOR_VER, MINIMUM_PYQT_MINOR_VER)) 773 log.error("This program will continue, but you may experience errors, crashes or other problems.") 774 return True 775 776 return True 777 778 779def checkPyQtImport4(): 780 try: 781 import PyQt4 782 import ui4 783 except ImportError: 784 import PyQt5 785 import ui5 786 else: 787 log.debug("HPLIP is not installed properly or is installed without graphical support. Please reinstall HPLIP again") 788 return False 789 return True 790 791# def checkPyQtImport5(): 792# try: 793# import PyQt5 794# import ui5 795# except ImportError: 796# log.error("HPLIP is not installed properly or is installed without graphical support PyQt5. Please reinstall HPLIP") 797# return False 798# else: 799# return True 800 801 802try: 803 from string import Template # will fail in Python <= 2.3 804except ImportError: 805 # Code from Python 2.4 string.py 806 #import re as _re 807 808 class _multimap: 809 """Helper class for combining multiple mappings. 810 811 Used by .{safe_,}substitute() to combine the mapping and keyword 812 arguments. 813 """ 814 def __init__(self, primary, secondary): 815 self._primary = primary 816 self._secondary = secondary 817 818 def __getitem__(self, key): 819 try: 820 return self._primary[key] 821 except KeyError: 822 return self._secondary[key] 823 824 825 class _TemplateMetaclass(type): 826 pattern = r""" 827 %(delim)s(?: 828 (?P<escaped>%(delim)s) | # Escape sequence of two delimiters 829 (?P<named>%(id)s) | # delimiter and a Python identifier 830 {(?P<braced>%(id)s)} | # delimiter and a braced identifier 831 (?P<invalid>) # Other ill-formed delimiter exprs 832 ) 833 """ 834 835 def __init__(cls, name, bases, dct): 836 super(_TemplateMetaclass, cls).__init__(name, bases, dct) 837 if 'pattern' in dct: 838 pattern = cls.pattern 839 else: 840 pattern = _TemplateMetaclass.pattern % { 841 'delim' : re.escape(cls.delimiter), 842 'id' : cls.idpattern, 843 } 844 cls.pattern = re.compile(pattern, re.IGNORECASE | re.VERBOSE) 845 846 # if PY3: 847 # class Template(metaclass=_TemplateMetaclass): 848 # """A string class for supporting $-substitutions.""" 849 # else: 850 class Template: 851 """A string class for supporting $-substitutions.""" 852 __metaclass__ = _TemplateMetaclass 853 854 delimiter = '$' 855 idpattern = r'[_a-z][_a-z0-9]*' 856 857 def __init__(self, template): 858 self.template = template 859 860 # Search for $$, $identifier, ${identifier}, and any bare $'s 861 def _invalid(self, mo): 862 i = mo.start('invalid') 863 lines = self.template[:i].splitlines(True) 864 if not lines: 865 colno = 1 866 lineno = 1 867 else: 868 colno = i - len(''.join(lines[:-1])) 869 lineno = len(lines) 870 raise ValueError('Invalid placeholder in string: line %d, col %d' % 871 (lineno, colno)) 872 873 def substitute(self, *args, **kws): 874 if len(args) > 1: 875 raise TypeError('Too many positional arguments') 876 if not args: 877 mapping = kws 878 elif kws: 879 mapping = _multimap(kws, args[0]) 880 else: 881 mapping = args[0] 882 # Helper function for .sub() 883 def convert(mo): 884 # Check the most common path first. 885 named = mo.group('named') or mo.group('braced') 886 if named is not None: 887 val = mapping[named] 888 # We use this idiom instead of str() because the latter will 889 # fail if val is a Unicode containing non-ASCII characters. 890 return '%s' % val 891 if mo.group('escaped') is not None: 892 return self.delimiter 893 if mo.group('invalid') is not None: 894 self._invalid(mo) 895 raise ValueError('Unrecognized named group in pattern', 896 self.pattern) 897 return self.pattern.sub(convert, self.template) 898 899 900 def safe_substitute(self, *args, **kws): 901 if len(args) > 1: 902 raise TypeError('Too many positional arguments') 903 if not args: 904 mapping = kws 905 elif kws: 906 mapping = _multimap(kws, args[0]) 907 else: 908 mapping = args[0] 909 # Helper function for .sub() 910 def convert(mo): 911 named = mo.group('named') 912 if named is not None: 913 try: 914 # We use this idiom instead of str() because the latter 915 # will fail if val is a Unicode containing non-ASCII 916 return '%s' % mapping[named] 917 except KeyError: 918 return self.delimiter + named 919 braced = mo.group('braced') 920 if braced is not None: 921 try: 922 return '%s' % mapping[braced] 923 except KeyError: 924 return self.delimiter + '{' + braced + '}' 925 if mo.group('escaped') is not None: 926 return self.delimiter 927 if mo.group('invalid') is not None: 928 return self.delimiter 929 raise ValueError('Unrecognized named group in pattern', 930 self.pattern) 931 return self.pattern.sub(convert, self.template) 932 933 934 935#cat = lambda _ : Template(_).substitute(sys._getframe(1).f_globals, **sys._getframe(1).f_locals) 936 937def cat(s): 938 globals = sys._getframe(1).f_globals.copy() 939 if 'self' in globals: 940 del globals['self'] 941 942 locals = sys._getframe(1).f_locals.copy() 943 if 'self' in locals: 944 del locals['self'] 945 946 return Template(s).substitute(sys._getframe(1).f_globals, **locals) 947 948if PY3: 949 identity = bytes.maketrans(b'', b'') 950 unprintable = identity.translate(identity, string.printable.encode('utf-8')) 951else: 952 identity = string.maketrans('','') 953 unprintable = identity.translate(identity, string.printable) 954 955 956def printable(s): 957 if s: 958 return s.translate(identity, unprintable) 959 else: 960 return "" 961 962 963def any(S,f=lambda x:x): 964 for x in S: 965 if f(x): return True 966 return False 967 968 969def all(S,f=lambda x:x): 970 for x in S: 971 if not f(x): return False 972 return True 973 974BROWSERS = ['firefox', 'mozilla', 'konqueror', 'epiphany', 'skipstone'] # in preferred order 975BROWSER_OPTS = {'firefox': '-new-tab', 'mozilla': '', 'konqueror': '', 'epiphany': '--new-tab', 'skipstone': ''} 976 977 978def find_browser(): 979 if platform_avail and platform.system() == 'Darwin': 980 return "open" 981 elif which("xdg-open"): 982 return "xdg-open" 983 else: 984 for b in BROWSERS: 985 if which(b): 986 return b 987 else: 988 return None 989 990 991def openURL(url, use_browser_opts=True): 992 if platform_avail and platform.system() == 'Darwin': 993 cmd = 'open "%s"' % url 994 os_utils.execute(cmd) 995 elif which("xdg-open"): 996 cmd = 'xdg-open "%s"' % url 997 os_utils.execute(cmd) 998 else: 999 for b in BROWSERS: 1000 bb = which(b, return_full_path='True') 1001 if bb: 1002 if use_browser_opts: 1003 cmd = """%s %s "%s" &""" % (bb, BROWSER_OPTS[b], url) 1004 else: 1005 cmd = """%s "%s" &""" % (bb, url) 1006 os_utils.execute(cmd) 1007 break 1008 else: 1009 log.warn("Unable to open URL: %s" % url) 1010 1011 1012def uniqueList(input): 1013 temp = [] 1014 [temp.append(i) for i in input if not temp.count(i)] 1015 return temp 1016 1017 1018def list_move_up(l, m, cmp=None): 1019 if cmp is None: 1020 f = lambda x: l[x] == m 1021 else: 1022 f = lambda x: cmp(l[x], m) 1023 1024 for i in range(1, len(l)): 1025 if f(i): 1026 l[i-1], l[i] = l[i], l[i-1] 1027 1028 1029def list_move_down(l, m, cmp=None): 1030 if cmp is None: 1031 f = lambda x: l[x] == m 1032 else: 1033 f = lambda x: cmp(l[x], m) 1034 1035 for i in range(len(l)-2, -1, -1): 1036 if f(i): 1037 l[i], l[i+1] = l[i+1], l[i] 1038 1039 1040 1041class XMLToDictParser: 1042 def __init__(self): 1043 self.stack = [] 1044 self.data = {} 1045 self.last_start = '' 1046 1047 def startElement(self, name, attrs): 1048 #print "START:", name, attrs 1049 self.stack.append(to_unicode(name).lower()) 1050 self.last_start = to_unicode(name).lower() 1051 1052 if len(attrs): 1053 for a in attrs: 1054 self.stack.append(to_unicode(a).lower()) 1055 self.addData(attrs[a]) 1056 self.stack.pop() 1057 1058 def endElement(self, name): 1059 if name.lower() == self.last_start: 1060 self.addData('') 1061 1062 #print "END:", name 1063 self.stack.pop() 1064 1065 def charData(self, data): 1066 data = to_unicode(data).strip() 1067 1068 if data and self.stack: 1069 self.addData(data) 1070 1071 def addData(self, data): 1072 #print("DATA:%s" % data) 1073 self.last_start = '' 1074 try: 1075 data = int(data) 1076 except ValueError: 1077 data = to_unicode(data) 1078 1079 stack_str = '-'.join(self.stack) 1080 stack_str_0 = '-'.join([stack_str, '0']) 1081 1082 try: 1083 self.data[stack_str] 1084 except KeyError: 1085 try: 1086 self.data[stack_str_0] 1087 except KeyError: 1088 self.data[stack_str] = data 1089 else: 1090 j = 2 1091 while True: 1092 try: 1093 self.data['-'.join([stack_str, to_unicode(j)])] 1094 except KeyError: 1095 self.data['-'.join([stack_str, to_unicode(j)])] = data 1096 break 1097 j += 1 1098 1099 else: 1100 self.data[stack_str_0] = self.data[stack_str] 1101 self.data['-'.join([stack_str, '1'])] = data 1102 del self.data[stack_str] 1103 1104 1105 def parseXML(self, text): 1106 if xml_expat_avail: 1107 parser = expat.ParserCreate() 1108 1109 parser.StartElementHandler = self.startElement 1110 parser.EndElementHandler = self.endElement 1111 parser.CharacterDataHandler = self.charData 1112 1113 parser.Parse(text, True) 1114 1115 else: 1116 log.error("Failed to import expat module , check python-xml/python3-xml package installation.") 1117 1118 return self.data 1119 1120 1121class Element: 1122 def __init__(self,name,attributes): 1123 self.name = name 1124 self.attributes = attributes 1125 self.chardata = '' 1126 self.children = [] 1127 1128 def AddChild(self,element): 1129 self.children.append(element) 1130 1131 def getAttribute(self,key): 1132 return self.attributes.get(key) 1133 1134 def getData(self): 1135 return self.chardata 1136 1137 def getElementsByTagName(self,name='',ElementNode=None): 1138 if ElementNode: 1139 Children_list = ElementNode.children 1140 else: 1141 Children_list = self.children 1142 if not name: 1143 return self.children 1144 else: 1145 elements = [] 1146 for element in Children_list: 1147 if element.name == name: 1148 elements.append(element) 1149 1150 rec_elements = self.getElementsByTagName (name,element) 1151 for a in rec_elements: 1152 elements.append(a) 1153 return elements 1154 1155 def getChildElements(self,name=''): 1156 if not name: 1157 return self.children 1158 else: 1159 elements = [] 1160 for element in self.children: 1161 if element.name == name: 1162 elements.append(element) 1163 return elements 1164 1165 def toString(self, level=0): 1166 retval = " " * level 1167 retval += "<%s" % self.name 1168 for attribute in self.attributes: 1169 retval += " %s=\"%s\"" % (attribute, self.attributes[attribute]) 1170 c = "" 1171 for child in self.children: 1172 c += child.toString(level+1) 1173 if c == "": 1174 if self.chardata: 1175 retval += ">"+self.chardata + ("</%s>" % self.name) 1176 else: 1177 retval += "/>" 1178 else: 1179 retval += ">" + c + ("</%s>" % self.name) 1180 return retval 1181 1182class extendedExpat: 1183 def __init__(self): 1184 self.root = None 1185 self.nodeStack = [] 1186 1187 def StartElement_EE(self,name,attributes): 1188 element = Element(name, attributes) 1189 1190 if len(self.nodeStack) > 0: 1191 parent = self.nodeStack[-1] 1192 parent.AddChild(element) 1193 else: 1194 self.root = element 1195 self.nodeStack.append(element) 1196 1197 def EndElement_EE(self,name): 1198 self.nodeStack = self.nodeStack[:-1] 1199 1200 def charData_EE(self,data): 1201 if data: 1202 element = self.nodeStack[-1] 1203 element.chardata += data 1204 return 1205 1206 def Parse(self,xmlString): 1207 if xml_expat_avail: 1208 Parser = expat.ParserCreate() 1209 1210 Parser.StartElementHandler = self.StartElement_EE 1211 Parser.EndElementHandler = self.EndElement_EE 1212 Parser.CharacterDataHandler = self.charData_EE 1213 1214 Parser.Parse(xmlString, True) 1215 else: 1216 log.error("Failed to import expat module , check python-xml/python3-xml package installation.") 1217 1218 return self.root 1219 1220 1221 1222def dquote(s): 1223 return ''.join(['"', s, '"']) 1224 1225 1226# Python 2.2.x compatibility functions (strip() family with char argument added in Python 2.2.3) 1227if sys.hexversion < 0x020203f0: 1228 def xlstrip(s, chars=' '): 1229 i = 0 1230 for c, i in zip(s, list(range(len(s)))): 1231 if c not in chars: 1232 break 1233 1234 return s[i:] 1235 1236 def xrstrip(s, chars=' '): 1237 return xreverse(xlstrip(xreverse(s), chars)) 1238 1239 def xreverse(s): 1240 l = list(s) 1241 l.reverse() 1242 return ''.join(l) 1243 1244 def xstrip(s, chars=' '): 1245 return xreverse(xlstrip(xreverse(xlstrip(s, chars)), chars)) 1246 1247else: 1248 xlstrip = str.lstrip 1249 xrstrip = str.rstrip 1250 xstrip = str.strip 1251 1252 1253def getBitness(): 1254 if platform_avail: 1255 return int(platform.architecture()[0][:-3]) 1256 else: 1257 return struct.calcsize("P") << 3 1258 1259 1260def getProcessor(): 1261 if platform_avail: 1262 return platform.machine().replace(' ', '_').lower() # i386, i686, power_macintosh, etc. 1263 else: 1264 return "i686" # TODO: Need a fix here 1265 1266 1267def getEndian(): 1268 if sys.byteorder == 'big': 1269 return BIG_ENDIAN 1270 else: 1271 return LITTLE_ENDIAN 1272 1273 1274# 1275# Function: run() 1276# Note:- to run su/sudo commands, caller needs to pass passwordObj. 1277# password object can be created from base.password.py 1278 1279def run(cmd, passwordObj = None, pswd_msg='', log_output=True, spinner=True, timeout=1): 1280 import io 1281 output = io.StringIO() 1282 1283 pwd_prompt_str = "" 1284 if passwordObj and ('su' in cmd or 'sudo' in cmd) and os.geteuid() != 0: 1285 pwd_prompt_str = passwordObj.getPasswordPromptString() 1286 log.debug("cmd = %s pwd_prompt_str = [%s]"%(cmd, pwd_prompt_str)) 1287 if(pwd_prompt_str == ""): 1288 passwd = passwordObj.getPassword(pswd_msg, 0) 1289 pwd_prompt_str = passwordObj.getPasswordPromptString() 1290 log.debug("pwd_prompt_str2 = [%s]"%(pwd_prompt_str)) 1291 if(passwd == ""): 1292 return 127, "" 1293 1294 try: 1295 child = pexpect.spawnu(cmd, timeout=timeout) 1296 except pexpect.ExceptionPexpect as e: 1297 return -1, '' 1298 1299 try: 1300 pswd_queried_cnt = 0 1301 while True: 1302 if spinner: 1303 update_spinner() 1304 1305 try: 1306 i = child.expect(EXPECT_LIST) 1307 except Exception: 1308 continue 1309 1310 if child.before: 1311 if(pwd_prompt_str and pwd_prompt_str not in EXPECT_LIST): 1312 log.debug("Adding %s to EXPECT LIST"%pwd_prompt_str) 1313 try: 1314 p = re.compile(pwd_prompt_str, re.I) 1315 except TypeError: 1316 EXPECT_LIST.append(pwd_prompt_str) 1317 else: 1318 EXPECT_LIST.append(p) 1319 EXPECT_LIST.append(pwd_prompt_str) 1320 1321 try: 1322 output.write(child.before) 1323 if log_output: 1324 log.debug(child.before) 1325 except Exception: 1326 pass 1327 1328 if i == 0: # EOF 1329 break 1330 1331 elif i == 1: # TIMEOUT 1332 continue 1333 1334 elif i == 2: # zypper 1335 child.sendline("YES") 1336 1337 else: # Password: 1338 if not passwordObj : 1339 raise Exception("password Object(i.e. passwordObj) is not valid") 1340 1341 child.sendline(passwordObj.getPassword(pswd_msg, pswd_queried_cnt)) 1342 pswd_queried_cnt += 1 1343 1344 except Exception as e: 1345 log.error("Exception: %s" % e) 1346 if spinner: 1347 cleanup_spinner() 1348 try: 1349 child.close() 1350 except pexpect.ExceptionPexpect as e: 1351 pass 1352 1353 1354 return child.exitstatus, output.getvalue() 1355 1356 1357 1358def expand_range(ns): # ns -> string repr. of numeric range, e.g. "1-4, 7, 9-12" 1359 """Credit: Jean Brouwers, comp.lang.python 16-7-2004 1360 Convert a string representation of a set of ranges into a 1361 list of ints, e.g. 1362 u"1-4, 7, 9-12" --> [1,2,3,4,7,9,10,11,12] 1363 """ 1364 fs = [] 1365 for n in ns.split(to_unicode(',')): 1366 n = n.strip() 1367 r = n.split('-') 1368 if len(r) == 2: # expand name with range 1369 h = r[0].rstrip(to_unicode('0123456789')) # header 1370 r[0] = r[0][len(h):] 1371 # range can't be empty 1372 if not (r[0] and r[1]): 1373 raise ValueError('empty range: ' + n) 1374 # handle leading zeros 1375 if r[0] == to_unicode('0') or to_unicode(r[0][0]) != '0': 1376 h += '%d' 1377 else: 1378 w = [len(i) for i in r] 1379 if w[1] > w[0]: 1380 raise ValueError('wide range: ' + n) 1381 h += to_unicode('%%0%dd') % max(w) 1382 # check range 1383 r = [int(i, 10) for i in r] 1384 if r[0] > r[1]: 1385 raise ValueError('bad range: ' + n) 1386 for i in range(r[0], r[1]+1): 1387 fs.append(h % i) 1388 else: # simple name 1389 fs.append(n) 1390 1391 # remove duplicates 1392 fs = list(dict([(n, i) for i, n in enumerate(fs)]).keys()) 1393 # convert to ints and sort 1394 fs = [int(x) for x in fs if x] 1395 fs.sort() 1396 1397 return fs 1398 1399 1400def collapse_range(x): # x --> sorted list of ints 1401 """ Convert a list of integers into a string 1402 range representation: 1403 [1,2,3,4,7,9,10,11,12] --> u"1-4,7,9-12" 1404 """ 1405 if not x: 1406 return '' 1407 1408 s, c, r = [str(x[0])], x[0], False 1409 1410 for i in x[1:]: 1411 if i == (c+1): 1412 r = True 1413 else: 1414 if r: 1415 s.append(to_unicode('-%s,%s') % (c,i)) 1416 r = False 1417 else: 1418 s.append(to_unicode(',%s') % i) 1419 1420 c = i 1421 1422 if r: 1423 s.append(to_unicode('-%s') % i) 1424 1425 return ''.join(s) 1426 1427def createBBSequencedFilename(basename, ext, dir=None, digits=3): 1428 if dir is None: 1429 dir = os.getcwd() 1430 1431 m = 0 1432 for f in walkFiles(dir, recurse=False, abs_paths=False, return_folders=False, pattern='*', path=None): 1433 r, e = os.path.splitext(f) 1434 1435 if r.startswith(basename) and ext == e: 1436 try: 1437 i = int(r[len(basename):]) 1438 except ValueError: 1439 continue 1440 else: 1441 m = max(m, i) 1442 1443 return os.path.join(dir, "%s%0*d%s" % (basename, digits, m+1, ext)) 1444 1445 1446def createSequencedFilename(basename, ext, dir=None, digits=3): 1447 if dir is None: 1448 dir = os.getcwd() 1449 1450 m = 0 1451 for f in walkFiles(dir, recurse=False, abs_paths=False, return_folders=False, pattern='*', path=None): 1452 r, e = os.path.splitext(f) 1453 1454 if r.startswith(basename) and ext == e: 1455 try: 1456 i = int(r[len(basename):]) 1457 except ValueError: 1458 continue 1459 else: 1460 m = max(m, i) 1461 1462 return os.path.join(dir, "%s%0*d%s" % (basename, digits, m+1, ext)) 1463 1464def validate_language(lang): 1465 if lang is None: 1466 loc = os_utils.getSystemLocale() 1467 else: 1468 lang = lang.lower().strip() 1469 for loc, ll in list(supported_locales.items()): 1470 if lang in ll: 1471 break 1472 else: 1473 loc = 'en_US' 1474 log.warn("Unknown lang/locale. Using default of %s." % loc) 1475 1476 return loc 1477 1478 1479def gen_random_uuid(): 1480 try: 1481 import uuid # requires Python 2.5+ 1482 return str(uuid.uuid4()) 1483 1484 except ImportError: 1485 uuidgen = which("uuidgen") 1486 if uuidgen: 1487 uuidgen = os.path.join(uuidgen, "uuidgen") 1488 return subprocess.getoutput(uuidgen) 1489 else: 1490 return '' 1491 1492 1493class RestTableFormatter(object): 1494 def __init__(self, header=None): 1495 self.header = header # tuple of strings 1496 self.rows = [] # list of tuples 1497 1498 def add(self, row_data): # tuple of strings 1499 self.rows.append(row_data) 1500 1501 def output(self, w): 1502 if self.rows: 1503 num_cols = len(self.rows[0]) 1504 for r in self.rows: 1505 if len(r) != num_cols: 1506 log.error("Invalid number of items in row: %s" % r) 1507 return 1508 1509 if len(self.header) != num_cols: 1510 log.error("Invalid number of items in header.") 1511 1512 col_widths = [] 1513 for x, c in enumerate(self.header): 1514 max_width = len(c) 1515 for r in self.rows: 1516 max_width = max(max_width, len(r[x])) 1517 1518 col_widths.append(max_width+2) 1519 1520 x = '+' 1521 for c in col_widths: 1522 x = ''.join([x, '-' * (c+2), '+']) 1523 1524 x = ''.join([x, '\n']) 1525 w.write(x) 1526 1527 # header 1528 if self.header: 1529 x = '|' 1530 for i, c in enumerate(col_widths): 1531 x = ''.join([x, ' ', self.header[i], ' ' * (c+1-len(self.header[i])), '|']) 1532 1533 x = ''.join([x, '\n']) 1534 w.write(x) 1535 1536 x = '+' 1537 for c in col_widths: 1538 x = ''.join([x, '=' * (c+2), '+']) 1539 1540 x = ''.join([x, '\n']) 1541 w.write(x) 1542 1543 # data rows 1544 for j, r in enumerate(self.rows): 1545 x = '|' 1546 for i, c in enumerate(col_widths): 1547 x = ''.join([x, ' ', self.rows[j][i], ' ' * (c+1-len(self.rows[j][i])), '|']) 1548 1549 x = ''.join([x, '\n']) 1550 w.write(x) 1551 1552 x = '+' 1553 for c in col_widths: 1554 x = ''.join([x, '-' * (c+2), '+']) 1555 1556 x = ''.join([x, '\n']) 1557 w.write(x) 1558 1559 else: 1560 log.error("No data rows") 1561 1562 1563def mixin(cls): 1564 import inspect 1565 1566 locals = inspect.stack()[1][0].f_locals 1567 if "__module__" not in locals: 1568 raise TypeError("Must call mixin() from within class def.") 1569 1570 dict = cls.__dict__.copy() 1571 dict.pop("__doc__", None) 1572 dict.pop("__module__", None) 1573 1574 locals.update(dict) 1575 1576 1577 1578# TODO: Move usage stuff to to base/module/Module class 1579 1580 1581 # ------------------------- Usage Help 1582USAGE_OPTIONS = ("[OPTIONS]", "", "heading", False) 1583USAGE_LOGGING1 = ("Set the logging level:", "-l<level> or --logging=<level>", 'option', False) 1584USAGE_LOGGING2 = ("", "<level>: none, info\*, error, warn, debug (\*default)", "option", False) 1585USAGE_LOGGING3 = ("Run in debug mode:", "-g (same as option: -ldebug)", "option", False) 1586USAGE_LOGGING_PLAIN = ("Output plain text only:", "-t", "option", False) 1587USAGE_ARGS = ("[PRINTER|DEVICE-URI]", "", "heading", False) 1588USAGE_ARGS2 = ("[PRINTER]", "", "heading", False) 1589USAGE_DEVICE = ("To specify a device-URI:", "-d<device-uri> or --device=<device-uri>", "option", False) 1590USAGE_PRINTER = ("To specify a CUPS printer:", "-p<printer> or --printer=<printer>", "option", False) 1591USAGE_BUS1 = ("Bus to probe (if device not specified):", "-b<bus> or --bus=<bus>", "option", False) 1592USAGE_BUS2 = ("", "<bus>: cups\*, usb\*, net, bt, fw, par\* (\*defaults) (Note: bt and fw not supported in this release.)", 'option', False) 1593USAGE_HELP = ("This help information:", "-h or --help", "option", True) 1594USAGE_SPACE = ("", "", "space", False) 1595USAGE_EXAMPLES = ("Examples:", "", "heading", False) 1596USAGE_NOTES = ("Notes:", "", "heading", False) 1597USAGE_STD_NOTES1 = ("If device or printer is not specified, the local device bus is probed and the program enters interactive mode.", "", "note", False) 1598USAGE_STD_NOTES2 = ("If -p\* is specified, the default CUPS printer will be used.", "", "note", False) 1599USAGE_SEEALSO = ("See Also:", "", "heading", False) 1600USAGE_LANGUAGE = ("Set the language:", "--loc=<lang> or --lang=<lang>. Use --loc=? or --lang=? to see a list of available language codes.", "option", False) 1601USAGE_LANGUAGE2 = ("Set the language:", "--lang=<lang>. Use --lang=? to see a list of available language codes.", "option", False) 1602USAGE_MODE = ("[MODE]", "", "header", False) 1603USAGE_NON_INTERACTIVE_MODE = ("Run in non-interactive mode:", "-n or --non-interactive", "option", False) 1604USAGE_GUI_MODE = ("Run in graphical UI mode:", "-u or --gui (Default)", "option", False) 1605USAGE_INTERACTIVE_MODE = ("Run in interactive mode:", "-i or --interactive", "option", False) 1606 1607if sys_conf.get('configure', 'ui-toolkit', 'qt3') == 'qt3': 1608 USAGE_USE_QT3 = ("Use Qt3:", "--qt3 (Default)", "option", False) 1609 USAGE_USE_QT4 = ("Use Qt4:", "--qt4", "option", False) 1610 USAGE_USE_QT5 = ("Use Qt5:", "--qt5", "option", False) 1611elif sys_conf.get('configure', 'ui-toolkit', 'qt4') == 'qt4': 1612 USAGE_USE_QT3 = ("Use Qt3:", "--qt3", "option", False) 1613 USAGE_USE_QT4 = ("Use Qt4:", "--qt4 (Default)", "option", False) 1614 USAGE_USE_QT5 = ("Use Qt5:", "--qt5", "option", False) 1615elif sys_conf.get('configure', 'ui-toolkit', 'qt5') == 'qt5': 1616 USAGE_USE_QT3 = ("Use Qt3:", "--qt3", "option", False) 1617 USAGE_USE_QT4 = ("Use Qt4:", "--qt4", "option", False) 1618 USAGE_USE_QT5 = ("Use Qt5:", "--qt5 (Default)", "option", False) 1619 1620def ttysize(): # TODO: Move to base/tui 1621 ln1 = subprocess.getoutput('stty -a').splitlines()[0] 1622 vals = {'rows':None, 'columns':None} 1623 for ph in ln1.split(';'): 1624 x = ph.split() 1625 if len(x) == 2: 1626 vals[x[0]] = x[1] 1627 vals[x[1]] = x[0] 1628 try: 1629 rows, cols = int(vals['rows']), int(vals['columns']) 1630 except TypeError: 1631 rows, cols = 25, 80 1632 1633 return rows, cols 1634 1635 1636def usage_formatter(override=0): # TODO: Move to base/module/Module class 1637 rows, cols = ttysize() 1638 1639 if override: 1640 col1 = override 1641 col2 = cols - col1 - 8 1642 else: 1643 col1 = int(cols / 3) - 8 1644 col2 = cols - col1 - 8 1645 1646 return TextFormatter(({'width': col1, 'margin' : 2}, 1647 {'width': col2, 'margin' : 2},)) 1648 1649 1650def format_text(text_list, typ='text', title='', crumb='', version=''): # TODO: Move to base/module/Module class 1651 """ 1652 Format usage text in multiple formats: 1653 text: for --help in the console 1654 rest: for conversion with rst2web for the website 1655 man: for manpages 1656 """ 1657 if typ == 'text': 1658 formatter = usage_formatter() 1659 1660 for line in text_list: 1661 text1, text2, format, trailing_space = line 1662 1663 # remove any reST/man escapes 1664 text1 = text1.replace("\\", "") 1665 text2 = text2.replace("\\", "") 1666 1667 if format == 'summary': 1668 log.info(log.bold(text1)) 1669 log.info("") 1670 1671 elif format in ('para', 'name', 'seealso'): 1672 log.info(text1) 1673 1674 if trailing_space: 1675 log.info("") 1676 1677 elif format in ('heading', 'header'): 1678 log.info(log.bold(text1)) 1679 1680 elif format in ('option', 'example'): 1681 log.info(formatter.compose((text1, text2), trailing_space)) 1682 1683 elif format == 'note': 1684 if text1.startswith(' '): 1685 log.info('\t' + text1.lstrip()) 1686 else: 1687 log.info(text1) 1688 1689 elif format == 'space': 1690 log.info("") 1691 1692 log.info("") 1693 1694 1695 elif typ == 'rest': 1696 opt_colwidth1, opt_colwidth2 = 0, 0 1697 exmpl_colwidth1, exmpl_colwidth2 = 0, 0 1698 note_colwidth1, note_colwidth2 = 0, 0 1699 1700 for line in text_list: 1701 text1, text2, format, trailing_space = line 1702 1703 if format == 'option': 1704 opt_colwidth1 = max(len(text1), opt_colwidth1) 1705 opt_colwidth2 = max(len(text2), opt_colwidth2) 1706 1707 elif format == 'example': 1708 exmpl_colwidth1 = max(len(text1), exmpl_colwidth1) 1709 exmpl_colwidth2 = max(len(text2), exmpl_colwidth2) 1710 1711 elif format == 'note': 1712 note_colwidth1 = max(len(text1), note_colwidth1) 1713 note_colwidth2 = max(len(text2), note_colwidth2) 1714 1715 opt_colwidth1 += 4 1716 opt_colwidth2 += 4 1717 exmpl_colwidth1 += 4 1718 exmpl_colwidth2 += 4 1719 note_colwidth1 += 4 1720 note_colwidth2 += 4 1721 opt_tablewidth = opt_colwidth1 + opt_colwidth2 1722 exmpl_tablewidth = exmpl_colwidth1 + exmpl_colwidth2 1723 note_tablewidth = note_colwidth1 + note_colwidth2 1724 1725 # write the rst2web header 1726 log.info("""restindex 1727page-title: %s 1728crumb: %s 1729format: rest 1730file-extension: html 1731encoding: utf8 1732/restindex\n""" % (title, crumb)) 1733 1734 t = "%s: %s (ver. %s)" % (crumb, title, version) 1735 log.info(t) 1736 log.info("="*len(t)) 1737 log.info("") 1738 1739 links = [] 1740 needs_header = False 1741 for line in text_list: 1742 text1, text2, format, trailing_space = line 1743 1744 if format == 'seealso': 1745 links.append(text1) 1746 text1 = "`%s`_" % text1 1747 1748 len1, len2 = len(text1), len(text2) 1749 1750 if format == 'summary': 1751 log.info(''.join(["**", text1, "**"])) 1752 log.info("") 1753 1754 elif format in ('para', 'name'): 1755 log.info("") 1756 log.info(text1) 1757 log.info("") 1758 1759 elif format in ('heading', 'header'): 1760 1761 log.info("") 1762 log.info("**" + text1 + "**") 1763 log.info("") 1764 needs_header = True 1765 1766 elif format == 'option': 1767 if needs_header: 1768 log.info(".. class:: borderless") 1769 log.info("") 1770 log.info(''.join(["+", "-"*opt_colwidth1, "+", "-"*opt_colwidth2, "+"])) 1771 needs_header = False 1772 1773 if text1 and '`_' not in text1: 1774 log.info(''.join(["| *", text1, '*', " "*(opt_colwidth1-len1-3), "|", text2, " "*(opt_colwidth2-len2), "|"])) 1775 elif text1: 1776 log.info(''.join(["|", text1, " "*(opt_colwidth1-len1), "|", text2, " "*(opt_colwidth2-len2), "|"])) 1777 else: 1778 log.info(''.join(["|", " "*(opt_colwidth1), "|", text2, " "*(opt_colwidth2-len2), "|"])) 1779 1780 log.info(''.join(["+", "-"*opt_colwidth1, "+", "-"*opt_colwidth2, "+"])) 1781 1782 elif format == 'example': 1783 if needs_header: 1784 log.info(".. class:: borderless") 1785 log.info("") 1786 log.info(''.join(["+", "-"*exmpl_colwidth1, "+", "-"*exmpl_colwidth2, "+"])) 1787 needs_header = False 1788 1789 if text1 and '`_' not in text1: 1790 log.info(''.join(["| *", text1, '*', " "*(exmpl_colwidth1-len1-3), "|", text2, " "*(exmpl_colwidth2-len2), "|"])) 1791 elif text1: 1792 log.info(''.join(["|", text1, " "*(exmpl_colwidth1-len1), "|", text2, " "*(exmpl_colwidth2-len2), "|"])) 1793 else: 1794 log.info(''.join(["|", " "*(exmpl_colwidth1), "|", text2, " "*(exmpl_colwidth2-len2), "|"])) 1795 1796 log.info(''.join(["+", "-"*exmpl_colwidth1, "+", "-"*exmpl_colwidth2, "+"])) 1797 1798 elif format == 'seealso': 1799 if text1 and '`_' not in text1: 1800 log.info(text1) 1801 1802 1803 elif format == 'note': 1804 if needs_header: 1805 log.info(".. class:: borderless") 1806 log.info("") 1807 log.info(''.join(["+", "-"*note_colwidth1, "+", "-"*note_colwidth2, "+"])) 1808 needs_header = False 1809 1810 if text1.startswith(' '): 1811 log.info(''.join(["|", " "*(note_tablewidth+1), "|"])) 1812 1813 log.info(''.join(["|", text1, " "*(note_tablewidth-len1+1), "|"])) 1814 log.info(''.join(["+", "-"*note_colwidth1, "+", "-"*note_colwidth2, "+"])) 1815 1816 elif format == 'space': 1817 log.info("") 1818 1819 for l in links: 1820 log.info("\n.. _`%s`: %s.html\n" % (l, l.replace('hp-', ''))) 1821 1822 log.info("") 1823 1824 elif typ == 'man': 1825 log.info('.TH "%s" 1 "%s" Linux "User Manuals"' % (crumb, version)) 1826 log.info(".SH NAME\n%s \- %s" % (crumb, title)) 1827 1828 for line in text_list: 1829 text1, text2, format, trailing_space = line 1830 1831 text1 = text1.replace("\\*", "*") 1832 text2 = text2.replace("\\*", "*") 1833 1834 len1, len2 = len(text1), len(text2) 1835 1836 if format == 'summary': 1837 log.info(".SH SYNOPSIS") 1838 log.info(".B %s" % text1.replace('Usage:', '')) 1839 1840 elif format == 'name': 1841 if text1: 1842 log.info(".SH DESCRIPTION\n%s" % text1) 1843 1844 elif format in ('option', 'example', 'note'): 1845 if text1: 1846 log.info('.IP "%s"\n%s' % (text1, text2)) 1847 else: 1848 log.info(text2) 1849 1850 elif format in ('header', 'heading'): 1851 log.info(".SH %s" % text1.upper().replace(':', '').replace('[', '').replace(']', '')) 1852 1853 elif format in ('seealso, para'): 1854 log.info(text1) 1855 1856 log.info(".SH AUTHOR") 1857 log.info("HPLIP (HP Linux Imaging and Printing) is an") 1858 log.info("HP developed solution for printing, scanning, and faxing with") 1859 log.info("HP inkjet and laser based printers in Linux.") 1860 1861 log.info(".SH REPORTING BUGS") 1862 log.info("The HPLIP Launchpad.net site") 1863 log.info(".B https://launchpad.net/hplip") 1864 log.info("is available to get help, report") 1865 log.info("bugs, make suggestions, discuss the HPLIP project or otherwise") 1866 log.info("contact the HPLIP Team.") 1867 1868 log.info(".SH COPYRIGHT") 1869 log.info("Copyright (c) 2001-18 HP Development Company, L.P.") 1870 log.info(".LP") 1871 log.info("This software comes with ABSOLUTELY NO WARRANTY.") 1872 log.info("This is free software, and you are welcome to distribute it") 1873 log.info("under certain conditions. See COPYING file for more details.") 1874 1875 log.info("") 1876 1877 1878def log_title(program_name, version, show_ver=True): # TODO: Move to base/module/Module class 1879 log.info("") 1880 1881 if show_ver: 1882 log.info(log.bold("HP Linux Imaging and Printing System (ver. %s)" % prop.version)) 1883 else: 1884 log.info(log.bold("HP Linux Imaging and Printing System")) 1885 1886 log.info(log.bold("%s ver. %s" % (program_name, version))) 1887 log.info("") 1888 log.info("Copyright (c) 2001-18 HP Development Company, LP") 1889 log.info("This software comes with ABSOLUTELY NO WARRANTY.") 1890 log.info("This is free software, and you are welcome to distribute it") 1891 log.info("under certain conditions. See COPYING file for more details.") 1892 log.info("") 1893 1894 1895def ireplace(old, search, replace): 1896 regex = '(?i)' + re.escape(search) 1897 return re.sub(regex, replace, old) 1898 1899# 1900# Removes HTML or XML character references and entities from a text string. 1901# 1902 1903def unescape(text): 1904 def fixup(m): 1905 text = m.group(0) 1906 if text[:2] == "&#": 1907 # character reference 1908 try: 1909 if text[:3] == "&#x": 1910 #return unichr(int(text[3:-1], 16)) 1911 return chr(int(text[3:-1], 16)) 1912 else: 1913 #return unichr(int(text[2:-1])) 1914 return chr(int(text[2:-1])) 1915 except ValueError: 1916 pass 1917 else: 1918 # named entity 1919 try: 1920 #text = unichr(htmlentitydefs.name2codepoint[text[1:-1]]) 1921 text = chr(html_entities.name2codepoint[text[1:-1]]) 1922 except KeyError: 1923 pass 1924 return text # leave as is 1925 return re.sub("&#?\w+;", fixup, text) 1926 1927 1928# Adds HTML or XML character references and entities from a text string 1929 1930def escape(s): 1931 if not isinstance(s, str): 1932 s = to_unicode(s) 1933 1934 s = s.replace("&", "&") 1935 1936 for c in html_entities.codepoint2name: 1937 if c != 0x26: # exclude & 1938 s = s.replace(chr(c), "&%s;" % html_entities.codepoint2name[c]) 1939 1940 for c in list(range(0x20)) + list(range(0x7f, 0xa0)): 1941 s = s.replace(chr(c), "&#%d;" % c) 1942 1943 return s 1944 1945 1946#return tye: strings 1947#Return values. 1948# None --> on error. 1949# "terminal name"-->success 1950def get_terminal(): 1951 terminal_list=['gnome-terminal', 'konsole','x-terminal-emulator', 'xterm', 'gtkterm'] 1952 terminal_cmd = None 1953 for cmd in terminal_list: 1954 if which(cmd): 1955 terminal_cmd = cmd +" -e " 1956 log.debug("Available Terminal = %s " %terminal_cmd) 1957 break 1958 1959 return terminal_cmd 1960 1961#Return Type: bool 1962# Return values: 1963# True --> if it is older version 1964# False --> if it is same or later version. 1965 1966def Is_HPLIP_older_version(installed_version, available_version): 1967 1968 if available_version == "" or available_version == None or installed_version == "" or installed_version == None: 1969 log.debug("available_version is ''") 1970 return False 1971 1972 installed_array=installed_version.split('.') 1973 available_array=available_version.split('.') 1974 1975 log.debug("HPLIP Installed_version=%s Available_version=%s"%(installed_version,available_version)) 1976 cnt = 0 1977 Is_older = False 1978 pat=re.compile('''(\d{1,})([a-z]{1,})''') 1979 try: 1980 while cnt <len(installed_array) and cnt <len(available_array): 1981 1982 installed_ver_dig=0 1983 installed_ver_alph=' ' 1984 available_ver_dig=0 1985 available_ver_alph=' ' 1986 if pat.search(installed_array[cnt]): 1987 installed_ver_dig = int(pat.search(installed_array[cnt]).group(1)) 1988 installed_ver_alph = pat.search(installed_array[cnt]).group(2) 1989 else: 1990 installed_ver_dig = int(installed_array[cnt]) 1991 1992 if pat.search(available_array[cnt]): 1993 available_ver_dig = int(pat.search(available_array[cnt]).group(1)) 1994 available_ver_alph = pat.search(available_array[cnt]).group(2) 1995 else: 1996 available_ver_dig = int(available_array[cnt]) 1997 1998 if (installed_ver_dig < available_ver_dig): 1999 Is_older = True 2000 break 2001 elif (installed_ver_dig > available_ver_dig): 2002 log.debug("Already new verison is installed") 2003 return False 2004 #checking sub minor versions .. e.g "3.12.10a" vs "3.12.10".... "3.12.10a" --> latest 2005 else: 2006 if (installed_ver_alph.lower() < available_ver_alph.lower()): 2007 Is_older = True 2008 break 2009 elif (installed_ver_alph.lower() > available_ver_alph.lower()): 2010 log.debug("Already new verison is installed") 2011 return False 2012 2013 cnt += 1 2014 2015 # To check version is installed. e.g. "3.12.10" vs "3.12.10.1".... "3.12.10.1"-->latest 2016 if Is_older is False and len(installed_array) < len(available_array): 2017 Is_older = True 2018 2019 except: 2020 log.error("Failed to get the latest version. Check out %s for manually installing latest version of HPLIP."%HPLIP_WEB_SITE) 2021 return False 2022 2023 return Is_older 2024 2025 2026def downLoad_status(count, blockSize, totalSize): 2027 percent = int(count*blockSize*100/totalSize) 2028 if count != 0: 2029 sys.stdout.write("\b\b\b") 2030 sys.stdout.write("%s" %(log.color("%2d%%"%percent, 'bold'))) 2031 sys.stdout.flush() 2032 2033def chunk_write(response, out_fd, chunk_size =8192, status_bar = downLoad_status): 2034 if response.info() and response.info().get('Content-Length'): 2035 total_size = int(response.info().get('Content-Length').strip()) 2036 else: 2037 log.debug("Ignoring progres bar") 2038 status_bar = None 2039 2040 bytes_so_far = 0 2041 while 1: 2042 chunk = response.read(chunk_size) 2043 if not chunk: 2044 break 2045 2046 out_fd.write(chunk) 2047 bytes_so_far += len(chunk) 2048 2049 if status_bar: 2050 status_bar(bytes_so_far, 1, total_size) 2051 2052 2053# Return Values. Sts, outFile 2054# Sts = 0 --> Success 2055# other thatn 0 --> Fail 2056# outFile = downloaded Filename. 2057# empty file on Failure case 2058def download_from_network(weburl, outputFile = None, useURLLIB=False): 2059 retValue = -1 2060 2061 if weburl == "" or weburl == None: 2062 log.error("URL is empty") 2063 return retValue, "" 2064 2065 if outputFile is None: 2066 fp, outputFile = make_temp_file() 2067 2068 try: 2069 if useURLLIB is False: 2070 wget = which("wget") 2071 if wget: 2072 wget = os.path.join(wget, "wget") 2073 status, output = run("%s --cache=off --tries=3 --timeout=60 --output-document=%s %s" %(wget, outputFile, weburl)) 2074 if status: 2075 log.error("Failed to connect to HPLIP site. Error code = %d" %status) 2076 return retValue, "" 2077 else: 2078 useURLLIB = True 2079 2080 if useURLLIB: 2081 2082 #sys.stdout.write("Download in progress..........") 2083 try: 2084 response = urllib2_request.urlopen(weburl) 2085 file_fd = open(outputFile, 'wb') 2086 chunk_write(response, file_fd) 2087 file_fd.close() 2088 except urllib2_error.URLError as e: 2089 log.error("Failed to open URL: %s" % weburl) 2090 return retValue, "" 2091 2092 except IOError as e: 2093 log.error("I/O Error: %s" % e.strerror) 2094 return retValue, "" 2095 2096 if not os.path.exists(outputFile): 2097 log.error("Failed to get hplip version/ %s file not found."%hplip_version_file) 2098 return retValue, "" 2099 2100 return 0, outputFile 2101 2102 2103 2104 2105 2106class Sync_Lock: 2107 def __init__(self, filename): 2108 self.Lock_filename = filename 2109 self.handler = open(self.Lock_filename, 'w') 2110 2111# Wait for another process to release resource and acquires the resource. 2112 def acquire(self): 2113 fcntl.flock(self.handler, fcntl.LOCK_EX) 2114 2115 def release(self): 2116 fcntl.flock(self.handler, fcntl.LOCK_UN) 2117 2118 def __del__(self): 2119 self.handler.close() 2120 2121def sendEvent(event_code,device_uri, printer_name, username="", job_id=0, title="", pipe_name=''): 2122 2123 if not dbus_avail: 2124 log.debug("Failed to import dbus, lowlevel") 2125 return 2126 2127 log.debug("send_message() entered") 2128 args = [device_uri, printer_name, event_code, username, job_id, title, pipe_name] 2129 msg = lowlevel.SignalMessage(path='/', interface=DBUS_SERVICE, name='Event') 2130 msg.append(signature='ssisiss', *args) 2131 SystemBus().send_message(msg) 2132 log.debug("send_message() returning") 2133 2134def expand_list(File_exp): 2135 File_list = glob.glob(File_exp) 2136 if File_list: 2137 File_list_str = ' '.join(File_list) 2138 return File_list, File_list_str 2139 else: 2140 return [],"" 2141 2142 2143 2144def unchunck_xml_data(src_data): 2145 index = 0 2146 dst_data="" 2147 # src_data contains HTTP data + xmlpayload. delimter is '\r\n\r\n'. 2148 while 1: 2149 if src_data.find('\r\n\r\n') != -1: 2150 src_data = src_data.split('\r\n\r\n', 1)[1] 2151 if not src_data.startswith("HTTP"): 2152 break 2153 else: 2154 return dst_data 2155 2156 if len(src_data) <= 0: 2157 return dst_data 2158 2159 #If xmlpayload doesn't have chuncksize embedded, returning same xml. 2160 if src_data[index] == '<': 2161 dst_data = src_data 2162 else: # Removing chunck size from xmlpayload 2163 try: 2164 while index < len(src_data): 2165 buf_len = 0 2166 while src_data[index] == ' ' or src_data[index] == '\r' or src_data[index] == '\n': 2167 index = index +1 2168 while src_data[index] != '\n' and src_data[index] != '\r': 2169 buf_len = buf_len *16 + int(src_data[index], 16) 2170 index = index +1 2171 2172 if buf_len == 0: 2173 break; 2174 2175 dst_data = dst_data+ src_data[index:buf_len+index+2] 2176 2177 index = buf_len + index + 2 # 2 for after size '\r\n' chars. 2178 except IndexError: 2179 pass 2180 return dst_data 2181 2182 2183#check_user_groups function checks required groups and returns missing list. 2184#Input: 2185# required_grps_str --> required groups from distro.dat 2186# avl_grps --> Current groups list (as a string) for this user. 2187# Output: 2188# result --> Returns True, if required groups are present 2189# --> Returns False, if required groups are not present 2190# missing_groups_str --> Returns the missing groups list (as a string) 2191# 2192def check_user_groups(required_grps_str, avl_grps): 2193 result = False 2194 exp_grp_list=[] 2195 exp_pat =re.compile('''.*-G(.*)''') 2196 if required_grps_str and exp_pat.search(required_grps_str): 2197 grps = exp_pat.search(required_grps_str).group(1) 2198 grps =re.sub(r'\s', '', str(grps)) 2199 exp_grp_list = grps.split(',') 2200 else: 2201 exp_grp_list.append('lp') 2202 2203 log.debug("Requied groups list =[%s]"%exp_grp_list) 2204 2205 avl_grps = avl_grps.rstrip('\r\n') 2206 grp_list= avl_grps.split(' ') 2207 for g in grp_list: 2208 grp_index = 0 2209 for p in exp_grp_list: 2210 if g == p: 2211 del exp_grp_list[grp_index] 2212 break 2213 grp_index +=1 2214 2215 if len(exp_grp_list) == 0: 2216 result = True 2217 missing_groups_str='' 2218 for a in exp_grp_list: 2219 if missing_groups_str: 2220 missing_groups_str += ',' 2221 missing_groups_str += a 2222 return result ,missing_groups_str 2223 2224 2225def check_library( so_file_path): 2226 ret_val = False 2227 if not os.path.exists(so_file_path): 2228 log.debug("Either %s file is not present or symbolic link is missing" %(so_file_path)) 2229 else: 2230 # capturing real file path 2231 if os.path.islink(so_file_path): 2232 real_file = os.path.realpath(so_file_path) 2233 else: 2234 real_file = so_file_path 2235 2236 if not os.path.exists(real_file): 2237 log.debug("%s library file is missing." % (real_file)) 2238 elif (os.stat(so_file_path).st_mode & 72) != 72: 2239 log.debug("%s library file doesn't have user/group execute permission." % (so_file_path)) 2240 else: 2241 log.debug("%s library file present." % (so_file_path)) 2242 ret_val = True 2243 2244 log.debug("%s library status: %d" % (so_file_path, ret_val)) 2245 return ret_val 2246 2247 2248def download_via_wget(target): 2249 status = -1 2250 wget = which("wget") 2251 if target and wget: 2252 wget = os.path.join(wget, "wget") 2253 cmd = "%s --cache=off --tries=3 --timeout=60 --output-document=- %s" % (wget, target) 2254 log.debug(cmd) 2255 status, output = run(cmd) 2256 log.debug("wget returned: %d" % status) 2257 else: 2258 log.debug("wget not found") 2259 return status 2260 2261def download_via_curl(target): 2262 status = -1 2263 curl = which("curl") 2264 if target and curl: 2265 curl = os.path.join(curl, "curl") 2266 cmd = "%s --output - --connect-timeout 5 --max-time 10 %s" % (curl, target) 2267 log.debug(cmd) 2268 status, output = run(cmd) 2269 log.debug("curl returned: %d" % status) 2270 else: 2271 log.debug("curl not found") 2272 return status 2273 2274def check_network_via_ping(target): 2275 status = -1 2276 ping = which("ping") 2277 if target and ping: 2278 ping = os.path.join(ping, "ping") 2279 cmd = "%s -c1 -W1 -w10 %s" % (ping, target) 2280 log.debug(cmd) 2281 status, output = run(cmd) 2282 log.debug("ping returned: %d" % status) 2283 else: 2284 log.debug("ping not found") 2285 return status 2286 2287def check_network_connection(url=HTTP_CHECK_TARGET, ping_server=PING_CHECK_TARGET): 2288 status = download_via_wget(url) 2289 if (status != 0): 2290 status = download_via_curl(url) 2291 if (status != 0): 2292 status = check_network_via_ping(ping_server) 2293 return (status == 0) 2294 2295#Expands '*' in File/Dir names. 2296def expandList(Files_List, prefix_dir=None): 2297 Expanded_Files_list=[] 2298 for f in Files_List: 2299 if prefix_dir: 2300 f= prefix_dir + '/' + f 2301 if '*' in f: 2302 f_full = glob.glob(f) 2303 for file in f_full: 2304 Expanded_Files_list.append(file) 2305 else: 2306 Expanded_Files_list.append(f) 2307 return Expanded_Files_list 2308 2309def compare(x, y): 2310 try: 2311 return cmp(float(x), float(y)) 2312 except ValueError: 2313 return cmp(x, y) 2314 2315 2316def check_pkg_mgr( package_mgrs = None): 2317 if package_mgrs is not None: 2318 log.debug("Searching for '%s' in running processes..." % package_mgrs) 2319 for p in package_mgrs: 2320 status,process = Is_Process_Running(p) 2321 if status is True: 2322 for pid in process: 2323 log.debug("Found: %s (%s)" % (process[pid], pid)) 2324 return (pid, process[pid]) 2325 2326 log.debug("Not found") 2327 return (0, '') 2328 2329# checks if given process is running. 2330#return value: 2331# True or False 2332# None - if process is not running 2333# grep output - if process is running 2334 2335def Is_Process_Running(process_name): 2336 if not process_name: 2337 return False, {} 2338 2339 try: 2340 process = {} 2341 p1 = Popen(["ps", "-w", "-w", "aux"], stdout=PIPE) 2342 p2 = Popen(["grep", process_name], stdin=p1.stdout, stdout=PIPE) 2343 p3 = Popen(["grep", "-v", "grep"], stdin=p2.stdout, stdout=PIPE) 2344 output = p3.communicate()[0] 2345 log.debug("Is_Process_Running output = %s " %output) 2346 2347 if output: 2348 for p in output.splitlines(): 2349 cmd = "echo '%s' | awk {'print $2'}" %p 2350 status,pid = subprocess.getstatusoutput(cmd) 2351 cmd = "echo '%s' | awk {'print $11,$12'}" %p 2352 status,cmdline = subprocess.getstatusoutput(cmd) 2353 if pid : 2354 process[pid] = cmdline 2355 2356 return True, process 2357 else: 2358 return False, {} 2359 2360 except Exception as e: 2361 log.error("Execution failed: process Name[%s]" %process_name) 2362 print >>sys.stderr, "Execution failed:", e 2363 return False, {} 2364 2365 2366def remove(path, passwordObj = None, cksudo = False): 2367 cmd= RMDIR + " " + path 2368 if cksudo and passwordObj: 2369 cmd= passwordObj.getAuthCmd() %cmd 2370 2371 log.debug("Removing %s cmd = %s " %(path, cmd)) 2372 status, output = run(cmd, passwordObj) 2373 if 0 != status: 2374 log.debug("Failed to remove=%s "%path) 2375 2376# This is operator overloading function for compare.. 2377def cmp_to_key(mycmp): 2378 'Convert a cmp= function into a key= function' 2379 class K(object): 2380 def __init__(self, obj, *args): 2381 self.obj = obj 2382 def __lt__(self, other): 2383 return mycmp(self.obj, other.obj) < 0 2384 def __gt__(self, other): 2385 return mycmp(self.obj, other.obj) > 0 2386 def __eq__(self, other): 2387 return mycmp(self.obj, other.obj) == 0 2388 def __le__(self, other): 2389 return mycmp(self.obj, other.obj) <= 0 2390 def __ge__(self, other): 2391 return mycmp(self.obj, other.obj) >= 0 2392 def __ne__(self, other): 2393 return mycmp(self.obj, other.obj) != 0 2394 return K 2395 2396# This is operator overloading function for compare.. for level functionality. 2397def levelsCmp(x, y): 2398 return (x[1] > y[1]) - (x[1] < y[1]) or (x[3] > y[3]) - (x[3] < y[3]) 2399 2400 2401def find_pip(): 2402 '''Determine the pip command syntax available for a particular distro. 2403 since it varies across distros''' 2404 2405 if which('pip-%s'%(str(MAJ_VER)+'.'+str(MIN_VER))): 2406 return 'pip-%s'%(str(MAJ_VER)+'.'+str(MIN_VER)) 2407 elif which('pip-%s'%str(MAJ_VER)): 2408 return 'pip-%s'%str(MAJ_VER) 2409 elif which('pip%s'%str(MAJ_VER)): 2410 return 'pip%s'%str(MAJ_VER) 2411 elif which('pip%s'%(str(MAJ_VER)+'.'+str(MIN_VER))): 2412 return 'pip%s'%(str(MAJ_VER)+'.'+str(MIN_VER)) 2413 elif which('pip-python%s'%str(MAJ_VER)): 2414 return 'pip-python%s'%str(MAJ_VER) 2415 elif which('pip-python'): 2416 return 'pip-python' 2417 else: 2418 log.error("python pip command not found. Please install '%s' package(s) manually"%depends_to_install_using_pip) 2419 2420 2421def check_lan(): 2422 try: 2423 x = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 2424 x.connect(('1.2.3.4', 56)) 2425 x.close() 2426 return True 2427 except socket.error: 2428 return False 2429 2430def extract_xml_chunk(data): 2431 if data.find('\r\n\r\n'): 2432 index = data.find('\r\n\r\n') 2433 data = data[index+4:] 2434 if data[0:1] != '<': # Check for source encoding chunked or content length in http respose header. 2435 size = -1 2436 temp = "" 2437 while size: 2438 index = data.find('\r\n') 2439 size = int(data[0:index+1], 16) 2440 temp = temp + data[index+2:index+2+size] 2441 data = data[index+2+size+2:len(data)] 2442 data = temp 2443 return data 2444 2445 2446def checkPyQtImport45(): 2447 try: 2448 import PyQt5 2449 return "PyQt5" 2450 except ImportError as e: 2451 log.debug(e) 2452 2453 try: 2454 import PyQt4 2455 return "PyQt4" 2456 except ImportError as e: 2457 log.debug(e) 2458 2459 raise ImportError("GUI Modules PyQt4 and PyQt5 are not installed") 2460 2461 2462def ui_status(): 2463 _ui_status = "" 2464 try: 2465 _ui_status = checkPyQtImport45() 2466 log.note("Using GUI Module %s" % _ui_status) 2467 return _ui_status 2468 except ImportError as e: 2469 log.error(e) 2470 2471 2472def import_dialog(ui_toolkit): 2473 if ui_toolkit == "qt4": 2474 try: 2475 from PyQt4.QtGui import QApplication 2476 log.debug("Using PyQt4") 2477 return (QApplication, "ui4") 2478 except ImportError as e: 2479 log.error(e) 2480 sys.exit(1) 2481 elif ui_toolkit == "qt5": 2482 try: 2483 from PyQt5.QtWidgets import QApplication 2484 log.debug("Using PyQt5") 2485 return (QApplication, "ui5") 2486 except ImportError as e: 2487 log.error(e) 2488 sys.exit(1) 2489 else: 2490 log.error("Unable to load Qt support. Is it installed?") 2491 sys.exit(1) 2492 2493 2494def dyn_import_mod(mod_name_as_str): 2495 components = mod_name_as_str.split('.') 2496 mod = __import__(mod_name_as_str) 2497 for comp in components[1:]: 2498 mod = getattr(mod, comp) 2499 return mod 2500