~ubuntu-branches/ubuntu/utopic/hplip/utopic-proposed

« back to all changes in this revision

Viewing changes to installer/core_install.py

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2012-05-26 11:20:39 UTC
  • mfrom: (1.5.6) (31.1.3 precise)
  • Revision ID: package-import@ubuntu.com-20120526112039-bevxczegxnbyr5m7
Tags: 3.12.4-1
* New upstream release
* Switch to source/format 3.0 (quilt) - drop dpatch
* Refreshed debian/patches
* dh_autoreconf debian/autogen.sh & set local-options single-debian-patch
* Update to debian/compat -> 9
* Fix "hardened build flags" patch from Moritz - thanks (Closes: #667828)
* Fix "duplex descriptor uninitialized" patch from Matej (Closes: #583273)
* Fix "please migrate to kde-runtime" patch from Pino (Closes: #666544)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: utf-8 -*-
2
 
#
3
 
# (c) Copyright 2003-2009 Hewlett-Packard Development Company, L.P.
4
 
#
5
 
# This program is free software; you can redistribute it and/or modify
6
 
# it under the terms of the GNU General Public License as published by
7
 
# the Free Software Foundation; either version 2 of the License, or
8
 
# (at your option) any later version.
9
 
#
10
 
# This program is distributed in the hope that it will be useful,
11
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
# GNU General Public License for more details.
14
 
#
15
 
# You should have received a copy of the GNU General Public License
16
 
# along with this program; if not, write to the Free Software
17
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18
 
#
19
 
# Author: Don Welch
20
 
#
21
 
 
22
 
# Std Lib
23
 
import sys
24
 
import os
25
 
import os.path
26
 
import re
27
 
import time
28
 
import cStringIO
29
 
import grp
30
 
import pwd
31
 
import tarfile
32
 
 
33
 
try:
34
 
    import hashlib # new in 2.5
35
 
 
36
 
    def get_checksum(s):
37
 
        return hashlib.sha1(s).hexdigest()
38
 
 
39
 
except ImportError:
40
 
    import sha # deprecated in 2.6/3.0
41
 
 
42
 
    def get_checksum(s):
43
 
        return sha.new(s).hexdigest()
44
 
 
45
 
 
46
 
import urllib # TODO: Replace with urllib2 (urllib is deprecated in Python 3.0)
47
 
 
48
 
 
49
 
# Local
50
 
from base.g import *
51
 
from base.codes import *
52
 
from base import utils, pexpect
53
 
from dcheck import *
54
 
 
55
 
 
56
 
 
57
 
DISTRO_UNKNOWN = 0
58
 
DISTRO_VER_UNKNOWN = '0.0'
59
 
 
60
 
MODE_INSTALLER = 0 # hplip-install/hp-setup
61
 
MODE_CHECK = 1 # hp-check
62
 
MODE_CREATE_DOCS = 2 # create_docs
63
 
 
64
 
TYPE_STRING = 1
65
 
TYPE_LIST = 2
66
 
TYPE_BOOL = 3
67
 
TYPE_INT = 4
68
 
 
69
 
DEPENDENCY_RUN_TIME = 1
70
 
DEPENDENCY_COMPILE_TIME = 2
71
 
DEPENDENCY_RUN_AND_COMPILE_TIME = 3
72
 
 
73
 
# Plug-in download errors
74
 
PLUGIN_INSTALL_ERROR_NONE = 0
75
 
PLUGIN_INSTALL_ERROR_PLUGIN_FILE_NOT_FOUND = 1
76
 
PLUGIN_INSTALL_ERROR_DIGITAL_SIG_NOT_FOUND = 2
77
 
PLUGIN_INSTALL_ERROR_DIGITAL_SIG_BAD = 3
78
 
PLUGIN_INSTALL_ERROR_PLUGIN_FILE_CHECKSUM_ERROR = 4
79
 
PLUGIN_INSTALL_ERROR_NO_NETWORK = 5
80
 
PLUGIN_INSTALL_ERROR_DIRECTORY_ERROR = 6
81
 
PLUGIN_INSTALL_ERROR_UNABLE_TO_RECV_KEYS = 7
82
 
 
83
 
 
84
 
PING_TARGET = "www.google.com"
85
 
HTTP_GET_TARGET = "http://www.google.com"
86
 
PLUGIN_FALLBACK_LOCATION = 'http://hplipopensource.com/hplip-web/plugin/'
87
 
 
88
 
EXPECT_WORD_LIST = [
89
 
    pexpect.EOF, # 0
90
 
    pexpect.TIMEOUT, # 1
91
 
    "Continue?", # 2 (for zypper)
92
 
    "passwor[dt]", # en/de/it/ru
93
 
    "kennwort", # de?
94
 
    "password for", # en
95
 
    "mot de passe", # fr
96
 
    "contraseña", # es
97
 
    "palavra passe", # pt
98
 
    "口令", # zh
99
 
    "wachtwoord", # nl
100
 
    "heslo", # czech
101
 
]
102
 
 
103
 
# Mapping from patterns to probability contribution of pattern
104
 
# Example code from David Mertz' Text Processing in Python.
105
 
# Released in the Public Domain.
106
 
err_pats = {r'(?is)<TITLE>.*?(404|403).*?ERROR.*?</TITLE>': 0.95,
107
 
            r'(?is)<TITLE>.*?ERROR.*?(404|403).*?</TITLE>': 0.95,
108
 
            r'(?is)<TITLE>ERROR</TITLE>': 0.30,
109
 
            r'(?is)<TITLE>.*?ERROR.*?</TITLE>': 0.10,
110
 
            r'(?is)<META .*?(404|403).*?ERROR.*?>': 0.80,
111
 
            r'(?is)<META .*?ERROR.*?(404|403).*?>': 0.80,
112
 
            r'(?is)<TITLE>.*?File Not Found.*?</TITLE>': 0.80,
113
 
            r'(?is)<TITLE>.*?Not Found.*?</TITLE>': 0.40,
114
 
            r'(?is)<BODY.*(404|403).*</BODY>': 0.10,
115
 
            r'(?is)<H1>.*?(404|403).*?</H1>': 0.15,
116
 
            r'(?is)<BODY.*not found.*</BODY>': 0.10,
117
 
            r'(?is)<H1>.*?not found.*?</H1>': 0.15,
118
 
            r'(?is)<BODY.*the requested URL.*</BODY>': 0.10,
119
 
            r'(?is)<BODY.*the page you requested.*</BODY>': 0.10,
120
 
            r'(?is)<BODY.*page.{1,50}unavailable.*</BODY>': 0.10,
121
 
            r'(?is)<BODY.*request.{1,50}unavailable.*</BODY>': 0.10,
122
 
            r'(?i)does not exist': 0.10,
123
 
           }
124
 
# end
125
 
 
126
 
 
127
 
EXPECT_LIST = []
128
 
for s in EXPECT_WORD_LIST:
129
 
    try:
130
 
        p = re.compile(s, re.I)
131
 
    except TypeError:
132
 
        EXPECT_LIST.append(s)
133
 
    else:
134
 
        EXPECT_LIST.append(p)
135
 
 
136
 
OK_PROCESS_LIST = ['adept-notifier',
137
 
                   'adept_notifier',
138
 
                   'yum-updatesd',
139
 
                   ]
140
 
 
141
 
CONFIGURE_ERRORS = { 1 : "General/unknown error",
142
 
                     2 : "libusb not found",
143
 
                     3 : "cups-devel not found",
144
 
                     4 : "libnetsnmp not found",
145
 
                     5 : "netsnmp-devel not found",
146
 
                     6 : "python-devel not found",
147
 
                     7 : "pthread-devel not found",
148
 
                     8 : "ppdev-devel not found",
149
 
                     9 : "libcups not found",
150
 
                     10 : "libm not found",
151
 
                     11 : "libusb-devel not found",
152
 
                     12 : "sane-backends-devel not found",
153
 
                     13 : "libdbus not found",
154
 
                     14 : "dbus-devel not found",
155
 
                     15 : "fax requires dbus support",
156
 
                     102 : "libjpeg not found",
157
 
                     103 : "jpeg-devel not found",
158
 
                     104 : "libdi not found",
159
 
                   }
160
 
 
161
 
 
162
 
try:
163
 
    from functools import update_wrapper
164
 
except ImportError: # using Python version < 2.5
165
 
    def trace(f):
166
 
        def newf(*args, **kw):
167
 
           log.debug("TRACE: func=%s(), args=%s, kwargs=%s" % (f.__name__, args, kw))
168
 
           return f(*args, **kw)
169
 
        newf.__name__ = f.__name__
170
 
        newf.__dict__.update(f.__dict__)
171
 
        newf.__doc__ = f.__doc__
172
 
        newf.__module__ = f.__module__
173
 
        return newf
174
 
else: # using Python 2.5+
175
 
    def trace(f):
176
 
        def newf(*args, **kw):
177
 
            log.debug("TRACE: func=%s(), args=%s, kwargs=%s" % (f.__name__, args, kw))
178
 
            return f(*args, **kw)
179
 
        return update_wrapper(newf, f)
180
 
 
181
 
 
182
 
 
183
 
class CoreInstall(object):
184
 
    def __init__(self, mode=MODE_INSTALLER, ui_mode=INTERACTIVE_MODE, ui_toolkit='qt4'):
185
 
        os.umask(0022)
186
 
        self.mode = mode
187
 
        self.ui_mode = ui_mode
188
 
        self.password = ''
189
 
        self.version_description, self.version_public, self.version_internal = '', '', ''
190
 
        self.bitness = 32
191
 
        self.endian = utils.LITTLE_ENDIAN
192
 
        self.distro, self.distro_name, self.distro_version = DISTRO_UNKNOWN, '', DISTRO_VER_UNKNOWN
193
 
        self.distro_version_supported = False
194
 
        self.install_location = '/usr'
195
 
        self.hplip_present = False
196
 
        self.have_dependencies = {}
197
 
        self.native_cups = True
198
 
        self.ppd_dir = None
199
 
        self.drv_dir = None
200
 
        self.distros = {}
201
 
        self.network_connected = False
202
 
        self.ui_toolkit = ui_toolkit
203
 
        self.enable = None
204
 
        self.disable = None
205
 
        self.plugin_path = "/tmp"
206
 
        self.plugin_version = '0.0.0'
207
 
        self.plugin_name = ''
208
 
        self.reload_dbus = False
209
 
 
210
 
 
211
 
        self.FIELD_TYPES = {
212
 
            'distros' : TYPE_LIST,
213
 
            'index' : TYPE_INT,
214
 
            'versions' : TYPE_LIST,
215
 
            'display_name' : TYPE_STRING,
216
 
            'alt_names': TYPE_LIST,
217
 
            'display': TYPE_BOOL,
218
 
            'notes': TYPE_STRING,
219
 
            'package_mgrs': TYPE_LIST,
220
 
            'package_mgr_cmd':TYPE_STRING,
221
 
            'pre_install_cmd': TYPE_LIST,
222
 
            'pre_depend_cmd': TYPE_LIST,
223
 
            'post_depend_cmd': TYPE_LIST,
224
 
            'hpoj_remove_cmd': TYPE_STRING,
225
 
            'hplip_remove_cmd': TYPE_STRING,
226
 
            'su_sudo': TYPE_STRING,
227
 
            'ppd_install': TYPE_STRING,
228
 
            'udev_mode_fix': TYPE_BOOL,
229
 
            'ppd_dir': TYPE_STRING,
230
 
            'drv_dir' : TYPE_STRING,
231
 
            'fix_ppd_symlink': TYPE_BOOL,
232
 
            'code_name': TYPE_STRING,
233
 
            'supported': TYPE_BOOL, # Supported by installer
234
 
            'release_date': TYPE_STRING,
235
 
            'packages': TYPE_LIST,
236
 
            'commands': TYPE_LIST,
237
 
            'same_as_version' : TYPE_STRING,
238
 
            'scan_supported' : TYPE_BOOL,
239
 
            'fax_supported' : TYPE_BOOL,
240
 
            'pcard_supported' : TYPE_BOOL,
241
 
            'network_supported' : TYPE_BOOL,
242
 
            'parallel_supported' : TYPE_BOOL,
243
 
            'usb_supported' : TYPE_BOOL,
244
 
            'packaged_version': TYPE_STRING, # Version of HPLIP pre-packaged in distro
245
 
            'cups_path_with_bitness' : TYPE_BOOL,
246
 
            'ui_toolkit' : TYPE_STRING,  # qt3 or qt4 [or gtk] or none
247
 
            'policykit' : TYPE_BOOL,
248
 
            'native_cups' : TYPE_BOOL,
249
 
            'package_available' : TYPE_BOOL,
250
 
            'package_arch' : TYPE_LIST,
251
 
            'add_user_to_group': TYPE_STRING,
252
 
            'open_mdns_port' : TYPE_LIST, # command to use to open mdns multicast port 5353
253
 
            'acl_rules' : TYPE_BOOL, # Use ACL uDEV rules (Ubuntu 9.10+)
254
 
            'libdir_path' : TYPE_STRING,
255
 
        }
256
 
 
257
 
        # components
258
 
        # 'name': ('description', [<option list>])
259
 
        self.components = {
260
 
            'hplip': ("HP Linux Imaging and Printing System", ['base', 'network', 'gui_qt4',
261
 
                                                               'fax', 'scan', 'docs']),
262
 
        }
263
 
 
264
 
        self.selected_component = 'hplip'
265
 
 
266
 
        # options
267
 
        # name: (<required>, "<display_name>", [<dependency list>]), ...
268
 
        self.options = {
269
 
            'base':     (True,  'Required HPLIP base components (including hpcups)', []), # HPLIP
270
 
            'network' : (False, 'Network/JetDirect I/O', []),
271
 
            'gui_qt4' : (False, 'Graphical User Interfaces (Qt4)', []),
272
 
            'fax' :     (False, 'PC Send Fax support', []),
273
 
            'scan':     (False, 'Scanning support', []),
274
 
            'docs':     (False, 'HPLIP documentation (HTML)', []),
275
 
            'policykit': (False, 'Administrative policy framework', []),
276
 
        }
277
 
 
278
 
 
279
 
        # holds whether the user has selected (turned on each option)
280
 
        # initial values are defaults (for GUI only)
281
 
        self.selected_options = {
282
 
            'base':        True,
283
 
            'network':     True,
284
 
            'gui_qt4':     True,
285
 
            'fax':         True,
286
 
            'scan':        True,
287
 
            'docs':        True,
288
 
            'policykit':   False,
289
 
            'native_cups': False,
290
 
        }
291
 
 
292
 
        # dependencies
293
 
        # 'name': (<required for option>, [<option list>], <display_name>, <check_func>, <runtime/compiletime>), ...
294
 
        # Note: any change to the list of dependencies must be reflected in base/distros.py
295
 
        self.dependencies = {
296
 
            # Required base packages
297
 
            'libjpeg':          (True,  ['base'], "libjpeg - JPEG library", self.check_libjpeg, DEPENDENCY_RUN_AND_COMPILE_TIME),
298
 
            'libtool':          (True,  ['base'], "libtool - Library building support services", self.check_libtool, DEPENDENCY_COMPILE_TIME),
299
 
            'cups' :            (True,  ['base'], 'CUPS - Common Unix Printing System', self.check_cups, DEPENDENCY_RUN_TIME),
300
 
            'cups-devel':       (True,  ['base'], 'CUPS devel- Common Unix Printing System development files', self.check_cups_devel, DEPENDENCY_COMPILE_TIME),
301
 
            'cups-image':       (True,  ['base'], "CUPS image - CUPS image development files", self.check_cups_image, DEPENDENCY_COMPILE_TIME),
302
 
            'gcc' :             (True,  ['base'], 'gcc - GNU Project C and C++ Compiler', self.check_gcc, DEPENDENCY_COMPILE_TIME),
303
 
            'make' :            (True,  ['base'], "make - GNU make utility to maintain groups of programs", self.check_make, DEPENDENCY_COMPILE_TIME),
304
 
            'python-devel' :    (True,  ['base'], "Python devel - Python development files", self.check_python_devel, DEPENDENCY_COMPILE_TIME),
305
 
            'libpthread' :      (True,  ['base'], "libpthread - POSIX threads library", self.check_libpthread, DEPENDENCY_RUN_AND_COMPILE_TIME),
306
 
            'python2x':         (True,  ['base'], "Python 2.2 or greater - Python programming language", self.check_python2x, DEPENDENCY_RUN_AND_COMPILE_TIME),
307
 
            'python-xml'  :     (True,  ['base'], "Python XML libraries", self.check_python_xml, DEPENDENCY_RUN_TIME),
308
 
            'gs':               (True,  ['base'], "GhostScript - PostScript and PDF language interpreter and previewer", self.check_gs, DEPENDENCY_RUN_TIME),
309
 
            'libusb':           (True,  ['base'], "libusb - USB library", self.check_libusb, DEPENDENCY_RUN_AND_COMPILE_TIME),
310
 
 
311
 
            # Optional base packages
312
 
            'cups-ddk':          (False, ['base'], "CUPS DDK - CUPS driver development kit", self.check_cupsddk, DEPENDENCY_RUN_TIME), # req. for .drv PPD installs
313
 
 
314
 
 
315
 
            # Required scan packages
316
 
            'sane':             (True,  ['scan'], "SANE - Scanning library", self.check_sane, DEPENDENCY_RUN_TIME),
317
 
            'sane-devel' :      (True,  ['scan'], "SANE - Scanning library development files", self.check_sane_devel, DEPENDENCY_COMPILE_TIME),
318
 
 
319
 
            # Optional scan packages
320
 
            'xsane':            (False, ['scan'], "xsane - Graphical scanner frontend for SANE", self.check_xsane, DEPENDENCY_RUN_TIME),
321
 
            'scanimage':        (False, ['scan'], "scanimage - Shell scanning program", self.check_scanimage, DEPENDENCY_RUN_TIME),
322
 
            'pil':              (False, ['scan'], "PIL - Python Imaging Library (required for commandline scanning with hp-scan)", self.check_pil, DEPENDENCY_RUN_TIME),
323
 
 
324
 
            # Required fax packages
325
 
            'python23':         (True,  ['fax'], "Python 2.3 or greater - Required for fax functionality", self.check_python23, DEPENDENCY_RUN_TIME),
326
 
            'dbus':             (True,  ['fax'], "DBus - Message bus system", self.check_dbus, DEPENDENCY_RUN_AND_COMPILE_TIME),
327
 
            'python-dbus':      (True,  ['fax'], "Python DBus - Python bindings for DBus", self.check_python_dbus, DEPENDENCY_RUN_TIME),
328
 
 
329
 
            # Optional fax packages
330
 
            'reportlab':        (False, ['fax'], "Reportlab - PDF library for Python", self.check_reportlab, DEPENDENCY_RUN_TIME),
331
 
 
332
 
            # Required and optional qt4 GUI packages
333
 
            'pyqt4':            (True,  ['gui_qt4'], "PyQt 4- Qt interface for Python (for Qt version 4.x)", self.check_pyqt4, DEPENDENCY_RUN_TIME), # PyQt 4.x )
334
 
            'pyqt4-dbus' :      (True,  ['gui_qt4'], "PyQt 4 DBus - DBus Support for PyQt4", self.check_pyqt4_dbus, DEPENDENCY_RUN_TIME),
335
 
            'policykit':        (False, ['gui_qt4'], "PolicyKit - Administrative policy framework", self.check_policykit, DEPENDENCY_RUN_TIME), # optional for non-sudo behavior of plugins (only optional for Qt4 option)
336
 
            'python-notify' :   (False, ['gui_qt4'], "Python libnotify - Python bindings for the libnotify Desktop notifications", self.check_pynotify, DEPENDENCY_RUN_TIME), # Optional for libnotify style popups from hp-systray
337
 
 
338
 
            # Required network I/O packages
339
 
            'libnetsnmp-devel': (True,  ['network'], "libnetsnmp-devel - SNMP networking library development files", self.check_libnetsnmp, DEPENDENCY_RUN_AND_COMPILE_TIME),
340
 
            'libcrypto':        (True,  ['network'], "libcrypto - OpenSSL cryptographic library", self.check_libcrypto, DEPENDENCY_RUN_AND_COMPILE_TIME),
341
 
        }
342
 
 
343
 
        for opt in self.options:
344
 
            update_spinner()
345
 
            for d in self.dependencies:
346
 
                if opt in self.dependencies[d][1]:
347
 
                    self.options[opt][2].append(d)
348
 
 
349
 
        self.load_distros()
350
 
 
351
 
        self.distros_index = {}
352
 
        for d in self.distros:
353
 
            self.distros_index[self.distros[d]['index']] = d
354
 
 
355
 
 
356
 
    def init(self, callback=None):
357
 
        if callback is not None:
358
 
            callback("Init...\n")
359
 
 
360
 
        update_spinner()
361
 
 
362
 
        # Package manager names
363
 
        self.package_mgrs = []
364
 
        for d in self.distros:
365
 
            update_spinner()
366
 
 
367
 
            for a in self.distros[d].get('package_mgrs', []):
368
 
                if a and a not in self.package_mgrs:
369
 
                    self.package_mgrs.append(a)
370
 
 
371
 
        self.version_description, self.version_public, self.version_internal = self.get_hplip_version()
372
 
        log.debug("HPLIP Description=%s Public version=%s Internal version = %s"  %
373
 
            (self.version_description, self.version_public, self.version_internal))
374
 
 
375
 
        # have_dependencies
376
 
        # is each dependency satisfied?
377
 
        # start with each one 'No'
378
 
        for d in self.dependencies:
379
 
            update_spinner()
380
 
            self.have_dependencies[d] = False
381
 
 
382
 
        self.get_distro()
383
 
        self.distro_changed()
384
 
 
385
 
        if callback is not None:
386
 
            callback("Distro: %s\n" % self.distro)
387
 
 
388
 
        self.check_dependencies(callback)
389
 
 
390
 
        for d in self.dependencies:
391
 
            update_spinner()
392
 
 
393
 
            log.debug("have %s = %s" % (d, self.have_dependencies[d]))
394
 
 
395
 
            if callback is not None:
396
 
                callback("Result: %s = %s\n" % (d, self.have_dependencies[d]))
397
 
 
398
 
        pid, cmdline = self.check_pkg_mgr()
399
 
        if pid:
400
 
            log.debug("Running package manager: %s (%d)" % (cmdline, pid) )
401
 
 
402
 
        self.bitness = utils.getBitness()
403
 
        log.debug("Bitness = %d" % self.bitness)
404
 
 
405
 
        update_spinner()
406
 
 
407
 
        self.endian = utils.getEndian()
408
 
        log.debug("Endian = %d" % self.endian)
409
 
 
410
 
        update_spinner()
411
 
 
412
 
        self.distro_name = self.distros_index[self.distro]
413
 
        self.distro_version_supported = self.get_distro_ver_data('supported', False)
414
 
 
415
 
        log.debug("Distro = %s Distro Name = %s Display Name= %s Version = %s Supported = %s" %
416
 
            (self.distro, self.distro_name, self.distros[self.distro_name]['display_name'],
417
 
             self.distro_version, self.distro_version_supported))
418
 
 
419
 
        update_spinner()
420
 
 
421
 
        self.hplip_present = self.check_hplip()
422
 
        log.debug("HPLIP (prev install) = %s" % self.hplip_present)
423
 
 
424
 
        status, output = self.run('cups-config --version')
425
 
        self.cups_ver = output.strip()
426
 
        log.debug("CUPS version = %s" % self.cups_ver)
427
 
 
428
 
        if self.distro_name == "ubuntu":
429
 
            self.reload_dbus = True
430
 
 
431
 
        log.debug("DBUS configuration reload possible? %s" % self.reload_dbus)
432
 
 
433
 
        status, self.sys_uname_info = self.run('uname -a')
434
 
        self.sys_uname_info = self.sys_uname_info.replace('\n', '')
435
 
        log.debug(self.sys_uname_info)
436
 
 
437
 
        # Record the installation time/date and version.
438
 
        # Also has the effect of making the .hplip.conf file user r/w
439
 
        # on the 1st run so that running hp-setup as root doesn't lock
440
 
        # the user out of owning the file
441
 
        user_conf.set('installation', 'date_time', time.strftime("%x %H:%M:%S", time.localtime()))
442
 
        user_conf.set('installation', 'version', self.version_public)
443
 
 
444
 
        if callback is not None:
445
 
            callback("Done")
446
 
 
447
 
 
448
 
    def init_for_docs(self, distro_name, version, bitness=32):
449
 
        self.distro_name = distro_name
450
 
        self.distro_version = version
451
 
 
452
 
        try:
453
 
            self.distro = self.distros[distro_name]['index']
454
 
        except KeyError:
455
 
            log.error("Invalid distro name: %s" % distro_name)
456
 
            sys.exit(1)
457
 
 
458
 
        self.bitness = bitness
459
 
 
460
 
        for d in self.dependencies:
461
 
            self.have_dependencies[d] = True
462
 
 
463
 
        self.enable_ppds = self.get_distro_ver_data('ppd_install', 'ppd') == 'ppd'
464
 
        self.ppd_dir = self.get_distro_ver_data('ppd_dir')
465
 
        self.drv_dir = self.get_distro_ver_data('drv_dir')
466
 
 
467
 
        self.distro_version_supported = True # for manual installs
468
 
 
469
 
 
470
 
    def check_dependencies(self, callback=None):
471
 
        update_ld_output()
472
 
 
473
 
        for d in self.dependencies:
474
 
            update_spinner()
475
 
 
476
 
            log.debug("Checking for dependency '%s'...\n" % d)
477
 
 
478
 
            if callback is not None:
479
 
                callback("Checking: %s\n" % d)
480
 
 
481
 
            self.have_dependencies[d] = self.dependencies[d][3]()
482
 
            log.debug("have %s = %s" % (d, self.have_dependencies[d]))
483
 
 
484
 
        cleanup_spinner()
485
 
 
486
 
 
487
 
    def password_func(self):
488
 
        if self.password:
489
 
            return self.password
490
 
        elif self.ui_mode == INTERACTIVE_MODE:
491
 
            import getpass
492
 
            return getpass.getpass("Enter password: ")
493
 
        else:
494
 
            return ''
495
 
 
496
 
 
497
 
    def run(self, cmd, callback=None, timeout=300): # ==> status, output
498
 
        if cmd is None:
499
 
            return 1, ''
500
 
        output = cStringIO.StringIO()
501
 
        ok, ret = False, ''
502
 
        # Hack! TODO: Fix!
503
 
        check_timeout = not (cmd.startswith('xterm') or cmd.startswith('gnome-terminal'))
504
 
 
505
 
        try:
506
 
            child = pexpect.spawn(cmd, timeout=1)
507
 
        except pexpect.ExceptionPexpect:
508
 
            return 1, ''
509
 
 
510
 
        try:
511
 
            try:
512
 
                start = time.time()
513
 
 
514
 
                while True:
515
 
                    update_spinner()
516
 
 
517
 
                    i = child.expect_list(EXPECT_LIST)
518
 
 
519
 
                    cb = child.before
520
 
                    if cb:
521
 
                        # output
522
 
                        start = time.time()
523
 
                        log.log_to_file(cb)
524
 
                        log.debug(cb)
525
 
                        output.write(cb)
526
 
 
527
 
                        if callback is not None:
528
 
                            if callback(cb): # cancel
529
 
                                break
530
 
 
531
 
                    elif check_timeout:
532
 
                        # no output
533
 
                        span = int(time.time()-start)
534
 
 
535
 
                        if span:
536
 
                            if span % 5 == 0:
537
 
                                log.debug("No output seen in %d secs" % span)
538
 
 
539
 
                            if span > timeout:
540
 
                                log.error("No output seen in over %d sec... (Is the CD-ROM/DVD source repository enabled? It shouldn't be!)" % timeout)
541
 
                                child.close()
542
 
                                child.terminate(force=True)
543
 
                                break
544
 
 
545
 
                    if i == 0: # EOF
546
 
                        ok, ret = True, output.getvalue()
547
 
                        break
548
 
 
549
 
                    elif i == 1: # TIMEOUT
550
 
                        continue
551
 
 
552
 
                    elif i == 2: # zypper "Continue?"
553
 
                        child.sendline("YES")
554
 
 
555
 
                    else: # password
556
 
                        child.sendline(self.password)
557
 
 
558
 
            except (Exception, pexpect.ExceptionPexpect):
559
 
                log.exception()
560
 
 
561
 
        finally:
562
 
            cleanup_spinner()
563
 
 
564
 
            try:
565
 
                child.close()
566
 
            except OSError:
567
 
                pass
568
 
 
569
 
        if ok:
570
 
            return child.exitstatus, ret
571
 
        else:
572
 
            return 1, ''
573
 
 
574
 
 
575
 
    def get_distro(self):
576
 
        log.debug("Determining distro...")
577
 
        self.distro, self.distro_version = DISTRO_UNKNOWN, '0.0'
578
 
 
579
 
        found = False
580
 
 
581
 
        lsb_release = utils.which("lsb_release")
582
 
 
583
 
        if lsb_release:
584
 
            log.debug("Using 'lsb_release -is/-rs'")
585
 
            cmd = os.path.join(lsb_release, "lsb_release")
586
 
            status, name = self.run(cmd + ' -is')
587
 
            name = name.lower().strip()
588
 
            log.debug("Distro name=%s" % name)
589
 
 
590
 
            if not status and name:
591
 
                status, ver = self.run(cmd + ' -rs')
592
 
                ver = ver.lower().strip()
593
 
                log.debug("Distro version=%s" % ver)
594
 
 
595
 
                if not status and ver:
596
 
                    for d in self.distros:
597
 
                        if name.find(d) > -1:
598
 
                            self.distro = self.distros[d]['index']
599
 
                            found = True
600
 
                            self.distro_version = ver
601
 
                            break
602
 
 
603
 
        if not found:
604
 
            try:
605
 
                name = file('/etc/issue', 'r').read().lower().strip()
606
 
            except IOError:
607
 
                # Some O/Ss don't have /etc/issue (Mac)
608
 
                self.distro, self.distro_version = DISTRO_UNKNOWN, '0.0'
609
 
            else:
610
 
                for d in self.distros:
611
 
                    if name.find(d) > -1:
612
 
                        self.distro = self.distros[d]['index']
613
 
                        found = True
614
 
                    else:
615
 
                        for x in self.distros[d].get('alt_names', ''):
616
 
                            if x and name.find(x) > -1:
617
 
                                self.distro = self.distros[d]['index']
618
 
                                found = True
619
 
                                break
620
 
 
621
 
                    if found:
622
 
                        break
623
 
 
624
 
                if found:
625
 
                    for n in name.split():
626
 
                        m= n
627
 
                        if '.' in n:
628
 
                            m = '.'.join(n.split('.')[:2])
629
 
 
630
 
                        try:
631
 
                            float(m)
632
 
                        except ValueError:
633
 
                            try:
634
 
                                int(m)
635
 
                            except ValueError:
636
 
                                self.distro_version = '0.0'
637
 
                            else:
638
 
                                self.distro_version = m
639
 
                                break
640
 
                        else:
641
 
                            self.distro_version = m
642
 
                            break
643
 
 
644
 
                    log.debug("/etc/issue: %s %s" % (name, self.distro_version))
645
 
 
646
 
        log.debug("distro=%d, distro_version=%s" % (self.distro, self.distro_version))
647
 
 
648
 
 
649
 
    def distro_changed(self):
650
 
        ppd_install = self.get_distro_ver_data('ppd_install', 'ppd')
651
 
 
652
 
        if ppd_install not in ('ppd', 'drv'):
653
 
            log.warning("Invalid ppd_install value: %s" % ppd_install)
654
 
 
655
 
        self.enable_ppds = (ppd_install == 'ppd')
656
 
 
657
 
        log.debug("Enable PPD install: %s (False=drv)" % self.enable_ppds)
658
 
 
659
 
        self.ppd_dir = self.get_distro_ver_data('ppd_dir')
660
 
 
661
 
        self.drv_dir = self.get_distro_ver_data('drv_dir')
662
 
        if not self.enable_ppds and not self.drv_dir:
663
 
            log.warning("Invalid drv_dir value: %s" % self.drv_dir)
664
 
 
665
 
        self.distro_version_supported = self.get_distro_ver_data('supported', False)
666
 
        self.selected_options['fax'] = self.get_distro_ver_data('fax_supported', True)
667
 
        self.selected_options['network'] = self.get_distro_ver_data('network_supported', True)
668
 
        self.selected_options['scan'] = self.get_distro_ver_data('scan_supported', True)
669
 
        self.selected_options['policykit'] = self.get_distro_ver_data('policykit', False)
670
 
        self.native_cups = self.get_distro_ver_data('native_cups', False)
671
 
 
672
 
        # Adjust required flag based on the distro ver ui_toolkit value
673
 
        ui_toolkit = self.get_distro_ver_data('ui_toolkit',  'qt4').lower()
674
 
 
675
 
        if ui_toolkit == 'qt4':
676
 
            log.debug("Default UI toolkit: Qt4")
677
 
            self.ui_toolkit = 'qt4'
678
 
            self.selected_options['gui_qt4'] = True
679
 
 
680
 
        # todo: gtk
681
 
        else:
682
 
            self.selected_options['gui_qt4'] = False
683
 
 
684
 
        # Override with --qt4 command args
685
 
        if self.enable is not None:
686
 
            if 'qt4' in self.enable:
687
 
                log.debug("User selected UI toolkit: Qt4")
688
 
                self.ui_toolkit = 'qt4'
689
 
                self.selected_options['gui_qt4'] = True
690
 
 
691
 
        if self.disable is not None:
692
 
            if 'qt4' in self.disable:
693
 
                log.debug("User deselected UI toolkit: Qt4")
694
 
                self.selected_options['gui_qt4'] = False
695
 
 
696
 
 
697
 
    def __fixup_data(self, key, data):
698
 
        field_type = self.FIELD_TYPES.get(key, TYPE_STRING)
699
 
        #log.debug("%s (%s) %d" % (key, data, field_type))
700
 
 
701
 
        if field_type == TYPE_BOOL:
702
 
            return utils.to_bool(data)
703
 
 
704
 
        elif field_type == TYPE_STRING:
705
 
            if type('') == type(data):
706
 
                return data.strip()
707
 
            else:
708
 
                return data
709
 
 
710
 
        elif field_type == TYPE_INT:
711
 
            try:
712
 
                return int(data)
713
 
            except ValueError:
714
 
                return 0
715
 
 
716
 
        elif field_type == TYPE_LIST:
717
 
            return [x for x in data.split(',') if x]
718
 
 
719
 
 
720
 
    def load_distros(self):
721
 
        if self.mode  == MODE_INSTALLER:
722
 
            distros_dat_file = os.path.join('installer', 'distros.dat')
723
 
 
724
 
        elif self.mode == MODE_CREATE_DOCS:
725
 
            distros_dat_file = os.path.join('..', '..', 'installer', 'distros.dat')
726
 
 
727
 
        else: # MODE_CHECK
728
 
            distros_dat_file = os.path.join(prop.home_dir, 'installer', 'distros.dat')
729
 
 
730
 
            if not os.path.exists(distros_dat_file):
731
 
                log.debug("DAT file not found at %s. Using local relative path..." % distros_dat_file)
732
 
                distros_dat_file = os.path.join('installer', 'distros.dat')
733
 
 
734
 
        distros_dat = ConfigBase(distros_dat_file)
735
 
        distros_list = self.__fixup_data('distros', distros_dat.get('distros', 'distros'))
736
 
        log.debug(distros_list)
737
 
 
738
 
        for distro in distros_list:
739
 
            update_spinner()
740
 
            d = {}
741
 
 
742
 
            if not distros_dat.has_section(distro):
743
 
                log.debug("Missing distro section in distros.dat: [%s]" % distro)
744
 
                continue
745
 
 
746
 
            for key in distros_dat.keys(distro):
747
 
                d[key] = self.__fixup_data(key, distros_dat.get(distro, key))
748
 
 
749
 
            self.distros[distro] = d
750
 
            versions = self.__fixup_data("versions", distros_dat.get(distro, 'versions'))
751
 
            self.distros[distro]['versions'] = {}
752
 
 
753
 
            for ver in versions:
754
 
                same_as_version, supported = False, True
755
 
                v = {}
756
 
                ver_section = "%s:%s" % (distro, ver)
757
 
 
758
 
                if not distros_dat.has_section(ver_section):
759
 
                    log.error("Missing version section in distros.dat: [%s:%s]" % (distro, ver))
760
 
                    continue
761
 
 
762
 
                if 'same_as_version' in distros_dat.keys(ver_section):
763
 
                    same_as_version = True
764
 
 
765
 
                supported = self.__fixup_data('supported', distros_dat.get(ver_section, 'supported'))
766
 
 
767
 
                for key in distros_dat.keys(ver_section):
768
 
                    v[key] = self.__fixup_data(key, distros_dat.get(ver_section, key))
769
 
 
770
 
                self.distros[distro]['versions'][ver] = v
771
 
                self.distros[distro]['versions'][ver]['dependency_cmds'] = {}
772
 
 
773
 
                if same_as_version: # or not supported:
774
 
                    continue
775
 
 
776
 
                for dep in self.dependencies:
777
 
                    dd = {}
778
 
                    dep_section = "%s:%s:%s" % (distro, ver, dep)
779
 
 
780
 
                    if not distros_dat.has_section(dep_section) and not same_as_version:
781
 
                        log.debug("Missing dependency section in distros.dat: [%s:%s:%s]" % (distro, ver, dep))
782
 
                        continue
783
 
 
784
 
                    #if same_as_version:
785
 
                    #    continue
786
 
 
787
 
                    for key in distros_dat.keys(dep_section):
788
 
                        dd[key] = self.__fixup_data(key, distros_dat.get(dep_section, key))
789
 
 
790
 
                    self.distros[distro]['versions'][ver]['dependency_cmds'][dep] = dd
791
 
 
792
 
            versions = self.distros[distro]['versions']
793
 
            for ver in versions:
794
 
                ver_section = "%s:%s" % (distro, ver)
795
 
 
796
 
                if 'same_as_version' in distros_dat.keys(ver_section):
797
 
                    v = self.__fixup_data("same_as_version", distros_dat.get(ver_section, 'same_as_version'))
798
 
                    log.debug("Setting %s:%s to %s:%s" % (distro, ver, distro, v))
799
 
 
800
 
                    try:
801
 
                        vv = self.distros[distro]['versions'][v].copy()
802
 
                        vv['same_as_version'] = v
803
 
                        self.distros[distro]['versions'][ver] = vv
804
 
                    except KeyError:
805
 
                        log.debug("Missing 'same_as_version=' version in distros.dat for section [%s:%s]." % (distro, v))
806
 
                        continue
807
 
 
808
 
        #import pprint
809
 
        #pprint.pprint(self.distros)
810
 
 
811
 
    def pre_install(self):
812
 
        pass
813
 
 
814
 
 
815
 
    def pre_depend(self):
816
 
        pass
817
 
 
818
 
 
819
 
    def check_python2x(self):
820
 
        py_ver = sys.version_info
821
 
        py_major_ver, py_minor_ver = py_ver[:2]
822
 
        log.debug("Python ver=%d.%d" % (py_major_ver, py_minor_ver))
823
 
        return py_major_ver >= 2
824
 
 
825
 
 
826
 
    def check_gcc(self):
827
 
        return check_tool('gcc --version', 0) and check_tool('g++ --version', 0)
828
 
 
829
 
 
830
 
    def check_make(self):
831
 
        return check_tool('make --version', 3.0)
832
 
 
833
 
 
834
 
    def check_libusb(self):
835
 
        if not check_lib('libusb'):
836
 
            return False
837
 
 
838
 
        return len(locate_file_contains("usb.h", '/usr/include', 'usb_init(void)'))
839
 
 
840
 
 
841
 
    def check_libjpeg(self):
842
 
        return check_lib("libjpeg") and check_file("jpeglib.h")
843
 
 
844
 
 
845
 
    def check_libcrypto(self):
846
 
        return check_lib("libcrypto") and check_file("crypto.h")
847
 
 
848
 
 
849
 
    def check_libpthread(self):
850
 
        return check_lib("libpthread") and check_file("pthread.h")
851
 
 
852
 
 
853
 
    def check_libnetsnmp(self):
854
 
        return check_lib("libnetsnmp") and check_file("net-snmp-config.h")
855
 
 
856
 
 
857
 
    def check_reportlab(self):
858
 
        try:
859
 
            log.debug("Trying to import 'reportlab'...")
860
 
            import reportlab
861
 
 
862
 
            ver = reportlab.Version
863
 
            try:
864
 
                ver_f = float(ver)
865
 
            except ValueError:
866
 
                log.debug("Can't determine version.")
867
 
                return False
868
 
            else:
869
 
                log.debug("Version: %.1f" % ver_f)
870
 
                if ver_f >= 2.0:
871
 
                    log.debug("Success.")
872
 
                    return True
873
 
                else:
874
 
                    return False
875
 
 
876
 
        except ImportError:
877
 
            log.debug("Failed.")
878
 
            return False
879
 
 
880
 
 
881
 
    def check_python23(self):
882
 
        py_ver = sys.version_info
883
 
        py_major_ver, py_minor_ver = py_ver[:2]
884
 
        log.debug("Python ver=%d.%d" % (py_major_ver, py_minor_ver))
885
 
        return py_major_ver >= 2 and py_minor_ver >= 3
886
 
 
887
 
 
888
 
    def check_python_xml(self):
889
 
        try:
890
 
            import xml.parsers.expat
891
 
        except ImportError:
892
 
            return False
893
 
        else:
894
 
            return True
895
 
 
896
 
 
897
 
    def check_sane(self):
898
 
        return check_lib('libsane')
899
 
 
900
 
 
901
 
    def check_sane_devel(self):
902
 
        return len(locate_file_contains("sane.h", '/usr/include', 'extern SANE_Status sane_init'))
903
 
 
904
 
 
905
 
    def check_xsane(self):
906
 
        if os.getenv('DISPLAY'):
907
 
            return check_tool('xsane --version', 0.9) # will fail if X not running...
908
 
        else:
909
 
            return bool(utils.which("xsane")) # ...so just see if it installed somewhere
910
 
 
911
 
 
912
 
    def check_scanimage(self):
913
 
        return check_tool('scanimage --version', 1.0)
914
 
 
915
 
 
916
 
    def check_gs(self):
917
 
        return check_tool('gs -v', 7.05)
918
 
 
919
 
 
920
 
    def check_pyqt4(self):
921
 
        if self.ui_toolkit == 'qt4':
922
 
            try:
923
 
                import PyQt4
924
 
            except ImportError:
925
 
                return False
926
 
            else:
927
 
                return True
928
 
 
929
 
        else:
930
 
            return False
931
 
 
932
 
 
933
 
    def check_pyqt4_dbus(self):
934
 
        if self.ui_toolkit == 'qt4':
935
 
            try:
936
 
                from dbus.mainloop.qt import DBusQtMainLoop
937
 
            except ImportError:
938
 
                return False
939
 
            else:
940
 
                return True
941
 
        else:
942
 
            return False
943
 
 
944
 
 
945
 
    def check_python_devel(self):
946
 
        return check_file('Python.h')
947
 
 
948
 
 
949
 
    def check_pynotify(self):
950
 
        try:
951
 
            import pynotify
952
 
        except ImportError:
953
 
            return False
954
 
 
955
 
        return True
956
 
 
957
 
 
958
 
    def check_python_dbus(self):
959
 
        log.debug("Checking for python-dbus (>= 0.80)...")
960
 
        try:
961
 
            import dbus
962
 
            try:
963
 
                ver = dbus.version
964
 
                log.debug("Version: %s" % '.'.join([str(x) for x in dbus.version]))
965
 
                return ver >= (0,80,0)
966
 
 
967
 
            except AttributeError:
968
 
                try:
969
 
                    ver = dbus.__version__
970
 
                    log.debug("Version: %s" % dbus.__version__)
971
 
                    log.debug("HPLIP requires dbus version > 0.80.")
972
 
                    return False
973
 
 
974
 
                except AttributeError:
975
 
                    log.debug("Unknown version. HPLIP requires dbus version > 0.80.")
976
 
                    return False
977
 
 
978
 
        except ImportError:
979
 
            return False
980
 
 
981
 
 
982
 
    def check_python_ctypes(self):
983
 
        try:
984
 
            import ctypes
985
 
            return True
986
 
        except ImportError:
987
 
            return False
988
 
 
989
 
 
990
 
    def check_dbus(self):
991
 
        log.debug("Checking for dbus running and header files present (dbus-devel)...")
992
 
        return check_ps(['dbus-daemon'])  and \
993
 
            len(locate_file_contains("dbus-message.h", '/usr/include', 'dbus_message_new_signal'))
994
 
 
995
 
 
996
 
    def check_cups_devel(self):
997
 
        return check_file('cups.h') and bool(utils.which('lpr'))
998
 
 
999
 
 
1000
 
    def check_cups(self):
1001
 
        status, output = self.run('lpstat -r')
1002
 
        if status > 0:
1003
 
            log.debug("CUPS is not running.")
1004
 
            return False
1005
 
        else:
1006
 
            log.debug("CUPS is running.")
1007
 
            return True
1008
 
 
1009
 
 
1010
 
    def check_cups_image(self):
1011
 
      return check_file("raster.h", "/usr/include/cups")
1012
 
 
1013
 
 
1014
 
    def check_hplip(self):
1015
 
        log.debug("Checking for HPLIP...")
1016
 
        return locate_files('hplip.conf', '/etc/hp')
1017
 
 
1018
 
 
1019
 
    def check_hpssd(self):
1020
 
        log.debug("Checking for hpssd...")
1021
 
        return check_ps(['hpssd'])
1022
 
 
1023
 
 
1024
 
    def check_libtool(self):
1025
 
        log.debug("Checking for libtool...")
1026
 
        return check_tool('libtool --version')
1027
 
 
1028
 
 
1029
 
    def check_pil(self):
1030
 
        log.debug("Checking for PIL...")
1031
 
        try:
1032
 
            import Image
1033
 
            return True
1034
 
        except ImportError:
1035
 
            return False
1036
 
 
1037
 
 
1038
 
    def check_cupsddk(self):
1039
 
        log.debug("Checking for cups-ddk...")
1040
 
        # TODO: Compute these paths some way or another...
1041
 
        #return check_tool("/usr/lib/cups/driver/drv list") and os.path.exists("/usr/share/cupsddk/include/media.defs")
1042
 
        return (check_file('drv', "/usr/lib/cups/driver") or check_file('drv', "/usr/lib64/cups/driver")) and \
1043
 
            check_file('media.defs', "/usr/share/cupsddk/include")
1044
 
 
1045
 
 
1046
 
    def check_policykit(self):
1047
 
        log.debug("Checking for PolicyKit...")
1048
 
        return (check_file('PolicyKit.conf', "/etc/PolicyKit") and check_file('org.gnome.PolicyKit.AuthorizationManager.service', "/usr/share/dbus-1/services")) or (check_file('50-localauthority.conf', "/etc/polkit-1/localauthority.conf.d") and check_file('org.freedesktop.PolicyKit1.service', "/usr/share/dbus-1/system-services"))
1049
 
 
1050
 
    def check_pkg_mgr(self):
1051
 
        """
1052
 
            Check if any pkg mgr processes are running
1053
 
        """
1054
 
        log.debug("Searching for '%s' in running processes..." % self.package_mgrs)
1055
 
 
1056
 
        processes = get_process_list()
1057
 
 
1058
 
        for pid, cmdline in processes:
1059
 
            for p in self.package_mgrs:
1060
 
                if p in cmdline:
1061
 
                    for k in OK_PROCESS_LIST:
1062
 
                        #print k, cmdline
1063
 
                        if k in cmdline:
1064
 
                            break
1065
 
 
1066
 
                    else:
1067
 
                        log.debug("Found: %s (%d)" % (cmdline, pid))
1068
 
                        return (pid, cmdline)
1069
 
 
1070
 
        log.debug("Not found")
1071
 
        return (0, '')
1072
 
 
1073
 
 
1074
 
    def get_hplip_version(self):
1075
 
        self.version_description, self.version_public, self.version_internal = '', '', ''
1076
 
 
1077
 
        if self.mode == MODE_INSTALLER:
1078
 
            ac_init_pat = re.compile(r"""AC_INIT\(\[(.*?)\], *\[(.*?)\], *\[(.*?)\], *\[(.*?)\] *\)""", re.IGNORECASE)
1079
 
 
1080
 
            try:
1081
 
                config_in = open('./configure.in', 'r')
1082
 
            except IOError:
1083
 
                self.version_description, self.version_public, self.version_internal = \
1084
 
                    '', sys_conf.get('configure', 'internal-tag', '0.0.0'), prop.installed_version
1085
 
            else:
1086
 
                for c in config_in:
1087
 
                    if c.startswith("AC_INIT"):
1088
 
                        match_obj = ac_init_pat.search(c)
1089
 
                        self.version_description = match_obj.group(1)
1090
 
                        self.version_public = match_obj.group(2)
1091
 
                        self.version_internal = match_obj.group(3)
1092
 
                        name = match_obj.group(4)
1093
 
                        break
1094
 
 
1095
 
                config_in.close()
1096
 
 
1097
 
                if name != 'hplip':
1098
 
                    log.error("Invalid archive!")
1099
 
 
1100
 
 
1101
 
        else: # MODE_CHECK
1102
 
            try:
1103
 
                self.version_description, self.version_public, self.version_internal = \
1104
 
                    '', sys_conf.get('configure', 'internal-tag', '0.0.0'), prop.installed_version
1105
 
            except KeyError:
1106
 
                self.version_description, self.version_public, self.version_internal = '', '', ''
1107
 
 
1108
 
        return self.version_description, self.version_public, self.version_internal
1109
 
 
1110
 
 
1111
 
    def configure(self):
1112
 
        configure_cmd = './configure'
1113
 
        configuration = {}
1114
 
        dbus_avail = self.have_dependencies['dbus'] and self.have_dependencies['python-dbus']
1115
 
        configuration['network-build'] = self.selected_options['network']
1116
 
        configuration['fax-build'] = self.selected_options['fax'] and dbus_avail
1117
 
        configuration['dbus-build'] = dbus_avail
1118
 
        configuration['qt4'] = self.selected_options['gui_qt4']
1119
 
        configuration['scan-build'] = self.selected_options['scan']
1120
 
        configuration['doc-build'] = self.selected_options['docs']
1121
 
        configuration['policykit'] = self.selected_options['policykit']
1122
 
 
1123
 
        # Setup printer driver configure flags based on distro data...
1124
 
        if self.native_cups: # hpcups
1125
 
            configuration['hpcups-install'] = True
1126
 
            configuration['hpijs-install'] = False
1127
 
            configuration['foomatic-ppd-install'] = False
1128
 
            configuration['foomatic-drv-install'] = False
1129
 
 
1130
 
            if self.enable_ppds:
1131
 
                configuration['cups-ppd-install'] = True
1132
 
                configuration['cups-drv-install'] = False
1133
 
            else:
1134
 
                configuration['cups-ppd-install'] = False
1135
 
                configuration['cups-drv-install'] = True
1136
 
 
1137
 
        else: # HPIJS/foomatic
1138
 
            configuration['hpcups-install'] = False
1139
 
            configuration['hpijs-install'] = True
1140
 
            configuration['cups-ppd-install'] = False
1141
 
            configuration['cups-drv-install'] = False
1142
 
 
1143
 
            if self.enable_ppds:
1144
 
                configuration['foomatic-ppd-install'] = True
1145
 
                configuration['foomatic-drv-install'] = False
1146
 
            else:
1147
 
                configuration['foomatic-ppd-install'] = False
1148
 
                configuration['foomatic-drv-install'] = True
1149
 
 
1150
 
 
1151
 
        # ... and then override and adjust for consistency with passed in parameters
1152
 
        if self.enable is not None:
1153
 
            for c in self.enable:
1154
 
                if c == 'hpcups-install':
1155
 
                    configuration['hpijs-install'] = False
1156
 
                    configuration['foomatic-ppd-install'] = False
1157
 
                    configuration['foomatic-drv-install'] = False
1158
 
                elif c == 'hpijs-install':
1159
 
                    configuration['hpcups-install'] = False
1160
 
                    configuration['cups-ppd-install'] = False
1161
 
                    configuration['cups-drv-install'] = False
1162
 
                elif c == 'foomatic-ppd-install':
1163
 
                    configuration['foomatic-drv-install'] = False
1164
 
                elif c == 'foomatic-drv-install':
1165
 
                    configuration['foomatic-ppd-install'] = False
1166
 
                elif c == 'cups-ppd-install':
1167
 
                    configuration['cups-drv-install'] = False
1168
 
                elif c == 'cups-drv-install':
1169
 
                    configuration['cups-ppd-install'] = False
1170
 
 
1171
 
        if self.disable is not None:
1172
 
            for c in self.disable:
1173
 
                if c == 'hpcups-install':
1174
 
                    configuration['hpijs-install'] = True
1175
 
                    configuration['cups-ppd-install'] = False
1176
 
                    configuration['cups-drv-install'] = False
1177
 
                elif c == 'hpijs-install':
1178
 
                    configuration['hpcups-install'] = True
1179
 
                    configuration['foomatic-ppd-install'] = False
1180
 
                    configuration['foomatic-drv-install'] = False
1181
 
                elif c == 'foomatic-ppd-install':
1182
 
                    configuration['foomatic-drv-install'] = True
1183
 
                elif c == 'foomatic-drv-install':
1184
 
                    configuration['foomatic-ppd-install'] = True
1185
 
                elif c == 'cups-ppd-install':
1186
 
                    configuration['cups-drv-install'] = True
1187
 
                elif c == 'cups-drv-install':
1188
 
                    configuration['cups-ppd-install'] = True
1189
 
 
1190
 
        if self.ppd_dir is not None:
1191
 
            configure_cmd += ' --with-hpppddir=%s' % self.ppd_dir
1192
 
            
1193
 
        libdir_path = self.get_distro_ver_data('libdir_path',False)
1194
 
        if libdir_path and self.bitness == 64:
1195
 
            configure_cmd += ' --libdir=%s' % (libdir_path)
1196
 
        elif self.bitness == 64:
1197
 
            configure_cmd += ' --libdir=/usr/lib64'
1198
 
 
1199
 
        configure_cmd += ' --prefix=%s' % self.install_location
1200
 
 
1201
 
        if self.get_distro_ver_data('cups_path_with_bitness', False) and self.bitness == 64:
1202
 
            configure_cmd += ' --with-cupsbackenddir=/usr/lib64/cups/backend --with-cupsfilterdir=/usr/lib64/cups/filter'
1203
 
 
1204
 
        if self.get_distro_ver_data('acl_rules', False):
1205
 
            configure_cmd += ' --enable-udev-acl-rules'
1206
 
 
1207
 
        if self.enable is not None:
1208
 
            for c in self.enable:
1209
 
                configuration[c] = True
1210
 
 
1211
 
        if self.disable is not None:
1212
 
            for c in self.disable:
1213
 
                configuration[c] = False
1214
 
 
1215
 
        for c in configuration:
1216
 
            if configuration[c]:
1217
 
                configure_cmd += ' --enable-%s' % c
1218
 
            else:
1219
 
                configure_cmd += ' --disable-%s' % c
1220
 
 
1221
 
        return configure_cmd
1222
 
 
1223
 
    def configure_html(self):
1224
 
        configure_cmd = './configure'
1225
 
        configure_cmd += ' --prefix=/usr' 
1226
 
        configure_cmd += ' --with-hpppddir=%s' % self.ppd_dir
1227
 
 
1228
 
        if self.bitness == 64:
1229
 
            configure_cmd += ' --libdir=/usr/lib64'
1230
 
 
1231
 
        self.ui_toolkit =  self.get_distro_ver_data('ui_toolkit') 
1232
 
        if self.ui_toolkit is not None and self.ui_toolkit == 'qt3':
1233
 
            configure_cmd += ' --enable-qt3 --disable-qt4'
1234
 
        else:
1235
 
            configure_cmd += ' --enable-qt4'
1236
 
 
1237
 
        self.native_cups =  self.get_distro_ver_data('native_cups')
1238
 
        if self.native_cups is not None and self.native_cups == 1:
1239
 
            configure_cmd += ' --enable-hpcups-install --enable-cups-drv-install --enable-cups-ppd-install --disable-hpijs-install --disable-foomatic-drv-install --disable-foomatic-ppd-install --disable-foomatic-rip-hplip-install' 
1240
 
        else:
1241
 
            configure_cmd += ' --disable-hpcups-install --disable-cups-drv-install --disable-cups-ppd-install --enable-hpijs-install --enable-foomatic-drv-install --enable-foomatic-ppd-install --enable-foomatic-rip-hplip-install' 
1242
 
 
1243
 
        self.fax_supported =  self.get_distro_ver_data('fax_supported')
1244
 
        if self.fax_supported is None:
1245
 
            configure_cmd += ' --disable-fax-build --disable-dbus-build'
1246
 
        else:
1247
 
            configure_cmd += ' --enable-fax-build --enable-dbus-build'
1248
 
 
1249
 
        self.network_supported = self.get_distro_ver_data('network_supported')
1250
 
        if self.network_supported is None:
1251
 
            configure_cmd += ' --disable-network-build'
1252
 
        else:
1253
 
            configure_cmd += ' --enable-network-build'
1254
 
          
1255
 
        self.scan_supported = self.get_distro_ver_data('scan_supported')
1256
 
        if self.scan_supported is None:
1257
 
            configure_cmd += ' --disable-scan-build'
1258
 
        else:
1259
 
            configure_cmd += ' --enable-scan-build'
1260
 
  
1261
 
        self.policykit = self.get_distro_ver_data('policykit')
1262
 
        if self.policykit is not None and self.policykit == 1:
1263
 
            configure_cmd += ' --enable-policykit'
1264
 
        else:
1265
 
            configure_cmd += ' --disable-policykit'
1266
 
        
1267
 
        return configure_cmd
1268
 
 
1269
 
    def configure_qt4(self):
1270
 
        configure_cmd = './configure'
1271
 
        configure_cmd += ' --prefix=/usr'
1272
 
        configure_cmd += ' --with-hpppddir=%s' % self.ppd_dir
1273
 
 
1274
 
        if self.bitness == 64:
1275
 
            configure_cmd += ' --libdir=/usr/lib64'
1276
 
 
1277
 
        self.ui_toolkit =  self.get_distro_ver_data('ui_toolkit')
1278
 
        if self.ui_toolkit is not None and self.ui_toolkit == 'qt3':
1279
 
            configure_cmd += ' --enable-qt3 --disable-qt4'
1280
 
        else:
1281
 
            configure_cmd += ' --enable-qt4'
1282
 
 
1283
 
        self.native_cups =  self.get_distro_ver_data('native_cups')
1284
 
        self.ppd_install = self.get_distro_ver_data('ppd_install')
1285
 
        if self.native_cups is not None and self.native_cups == 1:
1286
 
            configure_cmd += ' --enable-hpcups-install'
1287
 
            if self.ppd_install == 'drv':
1288
 
                configure_cmd += ' --enable-cups-drv-install --disable-cups-ppd-install'
1289
 
            else:
1290
 
                configure_cmd += ' --enable-cups-ppd-install --disable-cups-drv-install'
1291
 
            configure_cmd += ' --disable-hpijs-install --disable-foomatic-drv-install --disable-foomatic-ppd-install --disable-foomatic-rip-hplip-install'
1292
 
        else:
1293
 
            configure_cmd += ' --enable-hpijs-install'
1294
 
            if self.ppd_install == 'drv':
1295
 
                configure_cmd += ' --enable-foomatic-drv-install --disable-foomatic-ppd-install'
1296
 
            else:
1297
 
                configure_cmd += ' --enable-foomatic-ppd-install --disable-foomatic-drv-install'
1298
 
            configure_cmd += ' --enable-foomatic-rip-hplip-install --disable-hpcups-install --disable-cups-drv-install --disable-cups-ppd-install'
1299
 
 
1300
 
        self.fax_supported =  self.get_distro_ver_data('fax_supported')
1301
 
        if self.fax_supported is None:
1302
 
            configure_cmd += ' --disable-fax-build --disable-dbus-build'
1303
 
        else:
1304
 
            configure_cmd += ' --enable-fax-build --enable-dbus-build'
1305
 
 
1306
 
        self.network_supported = self.get_distro_ver_data('network_supported')
1307
 
        if self.network_supported is None:
1308
 
            configure_cmd += ' --disable-network-build'
1309
 
        else:
1310
 
            configure_cmd += ' --enable-network-build'
1311
 
 
1312
 
        self.scan_supported = self.get_distro_ver_data('scan_supported')
1313
 
        if self.scan_supported is None:
1314
 
            configure_cmd += ' --disable-scan-build'
1315
 
        else:
1316
 
            configure_cmd += ' --enable-scan-build'
1317
 
 
1318
 
        self.policykit = self.get_distro_ver_data('policykit')
1319
 
        if self.policykit is not None and self.policykit == 1:
1320
 
            configure_cmd += ' --enable-policykit'
1321
 
        else:
1322
 
            configure_cmd += ' --disable-policykit'
1323
 
 
1324
 
        return configure_cmd
1325
 
 
1326
 
 
1327
 
    def restart_cups(self):
1328
 
        if os.path.exists('/etc/init.d/cups'):
1329
 
            cmd = self.su_sudo() % '/etc/init.d/cups restart'
1330
 
 
1331
 
        elif os.path.exists('/etc/init.d/cupsys'):
1332
 
            cmd = self.su_sudo() % '/etc/init.d/cupsys restart'
1333
 
 
1334
 
        else:
1335
 
            cmd = self.su_sudo() % 'killall -HUP cupsd'
1336
 
 
1337
 
        self.run(cmd)
1338
 
 
1339
 
 
1340
 
    def stop_hplip(self):
1341
 
        return self.su_sudo() % "/etc/init.d/hplip stop"
1342
 
 
1343
 
 
1344
 
    def su_sudo(self):
1345
 
        if os.geteuid() == 0:
1346
 
            return '%s'
1347
 
        else:
1348
 
            try:
1349
 
                cmd = self.distros[self.distro_name]['su_sudo']
1350
 
            except KeyError:
1351
 
                cmd = 'su'
1352
 
 
1353
 
            if cmd == 'su':
1354
 
                return 'su -c "%s"'
1355
 
            else:
1356
 
                return 'sudo %s'
1357
 
 
1358
 
    def su_sudo_str(self):
1359
 
        return self.get_distro_data('su_sudo', 'su')
1360
 
 
1361
 
 
1362
 
    def build_cmds(self):
1363
 
        return [self.configure(),
1364
 
                'make clean',
1365
 
                'make',
1366
 
                self.su_sudo() % 'make install']
1367
 
 
1368
 
 
1369
 
    def get_distro_ver_data(self, key, default=None):
1370
 
        try:
1371
 
            return self.distros[self.distro_name]['versions'][self.distro_version].get(key, None) or \
1372
 
                self.distros[self.distro_name].get(key, None) or default
1373
 
        except KeyError:
1374
 
            return default
1375
 
 
1376
 
        return value
1377
 
 
1378
 
 
1379
 
    def get_distro_data(self, key, default=None):
1380
 
        try:
1381
 
            return self.distros[self.distro_name].get(key, None) or default
1382
 
        except KeyError:
1383
 
            return default
1384
 
 
1385
 
 
1386
 
    def get_ver_data(self, key, default=None):
1387
 
        try:
1388
 
            return self.distros[self.distro_name]['versions'][self.distro_version].get(key, None) or default
1389
 
        except KeyError:
1390
 
            return default
1391
 
 
1392
 
        return value
1393
 
 
1394
 
 
1395
 
    def get_dependency_data(self, dependency):
1396
 
        dependency_cmds = self.get_ver_data("dependency_cmds", {})
1397
 
        dependency_data = dependency_cmds.get(dependency, {})
1398
 
        packages = dependency_data.get('packages', [])
1399
 
        commands = dependency_data.get('commands', [])
1400
 
        return packages, commands
1401
 
 
1402
 
 
1403
 
    def get_dependency_commands(self):
1404
 
        dd = self.dependencies.keys()
1405
 
        dd.sort()
1406
 
        commands_to_run = []
1407
 
        packages_to_install = []
1408
 
        overall_commands_to_run = []
1409
 
        for d in dd:
1410
 
            include = False
1411
 
            for opt in self.dependencies[d][1]:
1412
 
                if self.selected_options[opt]:
1413
 
                    include = True
1414
 
            if include:
1415
 
                pkgs, cmds = self.get_dependency_data(d)
1416
 
 
1417
 
                if pkgs:
1418
 
                    for p in pkgs:
1419
 
                        if not p in packages_to_install:
1420
 
                            packages_to_install.append(p)
1421
 
 
1422
 
                if cmds:
1423
 
                    commands_to_run.extend(cmds)
1424
 
 
1425
 
        package_mgr_cmd = self.get_distro_data('package_mgr_cmd')
1426
 
 
1427
 
        overall_commands_to_run.extend(commands_to_run)
1428
 
 
1429
 
        if package_mgr_cmd:
1430
 
            packages_to_install = ' '.join(packages_to_install)
1431
 
            overall_commands_to_run.append(utils.cat(package_mgr_cmd))
1432
 
 
1433
 
        if not overall_commands_to_run:
1434
 
            log.error("No cmds/pkgs")
1435
 
 
1436
 
        return overall_commands_to_run
1437
 
 
1438
 
 
1439
 
    def distro_known(self):
1440
 
        return self.distro != DISTRO_UNKNOWN and self.distro_version != DISTRO_VER_UNKNOWN
1441
 
 
1442
 
 
1443
 
    def distro_supported(self):
1444
 
        if self.mode == MODE_INSTALLER:
1445
 
            return self.distro != DISTRO_UNKNOWN and self.distro_version != DISTRO_VER_UNKNOWN and self.get_ver_data('supported', False)
1446
 
        else:
1447
 
            return True # For docs (manual install)
1448
 
 
1449
 
 
1450
 
    def sort_vers(self, x, y):
1451
 
        try:
1452
 
            return cmp(float(x), float(y))
1453
 
        except ValueError:
1454
 
            return cmp(x, y)
1455
 
 
1456
 
 
1457
 
    def running_as_root(self):
1458
 
        return os.geteuid() == 0
1459
 
 
1460
 
 
1461
 
    def show_release_notes_in_browser(self):
1462
 
        url = "file://%s" % os.path.join(os.getcwd(), 'doc', 'release_notes.html')
1463
 
        log.debug(url)
1464
 
        status, output = self.run("xhost +")
1465
 
        utils.openURL(url)
1466
 
 
1467
 
 
1468
 
    def count_num_required_missing_dependencies(self):
1469
 
        num_req_missing = 0
1470
 
        for d, desc, opt in self.missing_required_dependencies():
1471
 
            num_req_missing += 1
1472
 
        return num_req_missing
1473
 
 
1474
 
 
1475
 
    def count_num_optional_missing_dependencies(self):
1476
 
        num_opt_missing = 0
1477
 
        for d, desc, req, opt in self.missing_optional_dependencies():
1478
 
            num_opt_missing += 1
1479
 
        return num_opt_missing
1480
 
 
1481
 
 
1482
 
    def missing_required_dependencies(self): # missing req. deps in req. options
1483
 
        for opt in self.components[self.selected_component][1]:
1484
 
            if self.options[opt][0]: # required options
1485
 
                for d in self.options[opt][2]: # dependencies for option
1486
 
                    if self.dependencies[d][0]: # required option
1487
 
                        if not self.have_dependencies[d]: # missing
1488
 
                            log.debug("Missing required dependency: %s" % d)
1489
 
                            yield d, self.dependencies[d][2], opt
1490
 
                            # depend, desc, option
1491
 
 
1492
 
    def missing_optional_dependencies(self):
1493
 
        # missing deps in opt. options
1494
 
        for opt in self.components[self.selected_component][1]:
1495
 
            if not self.options[opt][0]: # not required option
1496
 
                if self.selected_options[opt]: # only for options that are ON
1497
 
                    for d in self.options[opt][2]: # dependencies
1498
 
                        if not self.have_dependencies[d]: # missing dependency
1499
 
                            log.debug("Missing optional dependency: %s" % d)
1500
 
                            yield d, self.dependencies[d][2], self.dependencies[d][0], opt
1501
 
                            # depend, desc, required_for_opt, opt
1502
 
 
1503
 
        # opt. deps in req. options
1504
 
        for opt in self.components[self.selected_component][1]:
1505
 
            if self.options[opt][0]: # required options
1506
 
                for d in self.options[opt][2]: # dependencies for option
1507
 
                    if d == 'cups-ddk':
1508
 
                        status, output = self.run('cups-config --version')
1509
 
                        import string
1510
 
                        if status == 0 and (string.count(output, '.') == 1 or string.count(output, '.') == 2):
1511
 
                            if string.count(output, '.') == 1:
1512
 
                                major, minor = string.split(output, '.', 2)
1513
 
                            if string.count(output, '.') == 2:
1514
 
                                major, minor, release = string.split(output, '.', 3)
1515
 
                            if len(minor) > 1 and minor[1] >= '0' and minor[1] <= '9':
1516
 
                                minor = ((ord(minor[0]) - ord('0')) * 10) + (ord(minor[1]) - ord('0'))
1517
 
                            else:
1518
 
                                minor = ord(minor[0]) - ord('0')
1519
 
                            if major > '1' or (major == '1' and minor >= 4):
1520
 
                                continue
1521
 
                    if not self.dependencies[d][0]: # optional dep
1522
 
                        if not self.have_dependencies[d]: # missing
1523
 
                            log.debug("Missing optional dependency: %s" % d)
1524
 
                            yield d, self.dependencies[d][2], self.dependencies[d][0], opt
1525
 
                            # depend, desc, option
1526
 
 
1527
 
    def select_options(self, answer_callback):
1528
 
        num_opt_missing = 0
1529
 
        # not-required options
1530
 
        for opt in self.components[self.selected_component][1]:
1531
 
            if not self.options[opt][0]: # not required
1532
 
                default = 'y'
1533
 
 
1534
 
                if not self.selected_options[opt]:
1535
 
                    default = 'n'
1536
 
 
1537
 
                self.selected_options[opt] = answer_callback(opt, self.options[opt][1], default)
1538
 
 
1539
 
                if self.selected_options[opt]: # only for options that are ON
1540
 
                    for d in self.options[opt][2]: # dependencies
1541
 
                        if not self.have_dependencies[d]: # missing dependency
1542
 
                            log.debug("Missing optional dependency: %s" % d)
1543
 
                            num_opt_missing += 1
1544
 
 
1545
 
        return num_opt_missing
1546
 
 
1547
 
 
1548
 
    def check_network_connection(self):
1549
 
        self.network_connected = False
1550
 
 
1551
 
        wget = utils.which("wget")
1552
 
        if wget:
1553
 
            wget = os.path.join(wget, "wget")
1554
 
            cmd = "%s --timeout=60 --output-document=- %s" % (wget, HTTP_GET_TARGET)
1555
 
            log.debug(cmd)
1556
 
            status, output = self.run(cmd)
1557
 
            log.debug("wget returned: %d" % status)
1558
 
            self.network_connected = (status == 0)
1559
 
 
1560
 
        else:
1561
 
            curl = utils.which("curl")
1562
 
            if curl:
1563
 
                curl = os.path.join(curl, "curl")
1564
 
                cmd = "%s --output - --connect-timeout 5 --max-time 10 %s" % (curl, HTTP_GET_TARGET)
1565
 
                log.debug(cmd)
1566
 
                status, output = self.run(cmd)
1567
 
                log.debug("curl returned: %d" % status)
1568
 
                self.network_connected = (status == 0)
1569
 
 
1570
 
            else:
1571
 
                ping = utils.which("ping")
1572
 
 
1573
 
                if ping:
1574
 
                    ping = os.path.join(ping, "ping")
1575
 
                    cmd = "%s -c1 -W1 -w10 %s" % (ping, PING_TARGET)
1576
 
                    log.debug(cmd)
1577
 
                    status, output = self.run(cmd)
1578
 
                    log.debug("ping returned: %d" % status)
1579
 
                    self.network_connected = (status == 0)
1580
 
 
1581
 
        return self.network_connected
1582
 
 
1583
 
 
1584
 
    def run_pre_install(self, callback=None):
1585
 
        pre_cmd = self.get_distro_ver_data('pre_install_cmd')
1586
 
        log.debug(pre_cmd)
1587
 
        if pre_cmd:
1588
 
            x = 1
1589
 
            for cmd in pre_cmd:
1590
 
                status, output = self.run(cmd)
1591
 
 
1592
 
                if status != 0:
1593
 
                    log.warn("An error occurred running '%s'" % cmd)
1594
 
 
1595
 
                if callback is not None:
1596
 
                    callback(cmd, "Pre-install step %d" % x)
1597
 
 
1598
 
                x += 1
1599
 
 
1600
 
            return True
1601
 
 
1602
 
        else:
1603
 
            return False
1604
 
 
1605
 
 
1606
 
    def run_pre_depend(self, callback=None):
1607
 
        pre_cmd = self.get_distro_ver_data('pre_depend_cmd')
1608
 
        log.debug(pre_cmd)
1609
 
        if pre_cmd:
1610
 
            x = 1
1611
 
            for cmd in pre_cmd:
1612
 
                status, output = self.run(cmd)
1613
 
 
1614
 
                if status != 0:
1615
 
                    log.warn("An error occurred running '%s'" % cmd)
1616
 
 
1617
 
                if callback is not None:
1618
 
                    callback(cmd, "Pre-depend step %d" % x)
1619
 
 
1620
 
                x += 1
1621
 
 
1622
 
 
1623
 
    def run_post_depend(self, callback=None):
1624
 
        post_cmd = self.get_distro_ver_data('post_depend_cmd')
1625
 
        log.debug(post_cmd)
1626
 
        if post_cmd:
1627
 
            x = 1
1628
 
            for cmd in post_cmd:
1629
 
                status, output = self.run(cmd)
1630
 
 
1631
 
                if status != 0:
1632
 
                    log.warn("An error occurred running '%s'" % cmd)
1633
 
 
1634
 
                if callback is not None:
1635
 
                    callback(cmd, "Post-depend step %d" % x)
1636
 
 
1637
 
                x += 1
1638
 
 
1639
 
 
1640
 
    def run_open_mdns_port(self, callback=None):
1641
 
        open_mdns_port_cmd = self.get_distro_ver_data('open_mdns_port')
1642
 
        log.debug(open_mdns_port_cmd)
1643
 
        if open_mdns_port_cmd:
1644
 
            x = 1
1645
 
            for cmd in open_mdns_port_cmd:
1646
 
                cmd = self.su_sudo() % cmd
1647
 
                status, output = self.run(cmd)
1648
 
 
1649
 
                if status != 0:
1650
 
                    log.warn("An error occurred running '%s'" % cmd)
1651
 
                    log.warn(output)
1652
 
 
1653
 
                if callback is not None:
1654
 
                    callback(cmd, "Open mDNS/Bonjour step %d" % x)
1655
 
 
1656
 
                x += 1
1657
 
 
1658
 
 
1659
 
    def pre_build(self):
1660
 
        cmds = []
1661
 
        if self.get_distro_ver_data('fix_ppd_symlink', False):
1662
 
            cmds.append(self.su_sudo() % 'python ./installer/fix_symlink.py')
1663
 
 
1664
 
        return cmds
1665
 
 
1666
 
 
1667
 
    def run_pre_build(self, callback=None):
1668
 
        x = 1
1669
 
        for cmd in self.pre_build():
1670
 
            status, output = self.run(cmd)
1671
 
            if callback is not None:
1672
 
                callback(cmd, "Pre-build step %d"  % x)
1673
 
 
1674
 
            x += 1
1675
 
 
1676
 
 
1677
 
    def run_post_build(self, callback=None):
1678
 
        x = 1
1679
 
        for cmd in self.post_build():
1680
 
            status, output = self.run(cmd)
1681
 
            if callback is not None:
1682
 
                callback(cmd, "Post-build step %d"  % x)
1683
 
 
1684
 
            x += 1
1685
 
 
1686
 
 
1687
 
    def post_build(self):
1688
 
        cmds = []
1689
 
        # Reload DBUS configuration if distro supports it and PolicyKit
1690
 
        # support installed
1691
 
        if self.reload_dbus and self.selected_options['policykit']:
1692
 
            cmds.append(self.su_sudo() % "sh /etc/init.d/dbus reload")
1693
 
            log.debug("Will reload DBUS configuration for PolicyKit support")
1694
 
 
1695
 
        # Kill any running hpssd.py instance from a previous install
1696
 
        if self.check_hpssd():
1697
 
            pid = get_ps_pid('hpssd')
1698
 
            if pid:
1699
 
                kill = os.path.join(utils.which("kill"), "kill") + " %d" % pid
1700
 
                cmds.append(self.su_sudo() % kill)
1701
 
 
1702
 
        # Add user to group if needed
1703
 
        # add_user_to_group=<usermod params> [TYPE_STRING] (leave empty for none) [ex. "-a -G sys" or "-G lp"]
1704
 
        add_user_to_group = self.get_distro_ver_data('add_user_to_group', '')
1705
 
        if add_user_to_group:
1706
 
            usermod = os.path.join(utils.which("usermod"), "usermod") + " %s %s" % (add_user_to_group, prop.username)
1707
 
            cmds.append(self.su_sudo() % usermod)
1708
 
 
1709
 
        return cmds
1710
 
 
1711
 
 
1712
 
    def logoff(self):
1713
 
        ok = False
1714
 
        pkill = utils.which('pkill')
1715
 
        if pkill:
1716
 
            cmd = "%s -KILL -u %s" % (os.path.join(pkill, "pkill"), prop.username)
1717
 
            cmd = self.su_sudo() % cmd
1718
 
            status, output = self.run(cmd)
1719
 
 
1720
 
            ok = (status == 0)
1721
 
 
1722
 
        return ok
1723
 
 
1724
 
 
1725
 
    def restart(self):
1726
 
        ok = False
1727
 
        shutdown = utils.which('shutdown')
1728
 
        if shutdown:
1729
 
            cmd = "%s -r now" % (os.path.join(shutdown, "shutdown"))
1730
 
            cmd = self.su_sudo() % cmd
1731
 
            status, output = self.run(cmd)
1732
 
 
1733
 
            ok = (status == 0)
1734
 
 
1735
 
        return ok
1736
 
 
1737
 
 
1738
 
    def run_hp_setup(self):
1739
 
        status = 0
1740
 
        hpsetup = utils.which("hp-setup")
1741
 
 
1742
 
        if hpsetup:
1743
 
            cmd = 'hp-setup'
1744
 
        else:
1745
 
            cmd = './setup.py'
1746
 
 
1747
 
        log.debug(cmd)
1748
 
        status, output = self.run(cmd)
1749
 
        return status == 0
1750
 
 
1751
 
 
1752
 
    def remove_hplip(self, callback=None):
1753
 
        failed = True
1754
 
        self.stop_pre_2x_hplip(callback)
1755
 
 
1756
 
        hplip_remove_cmd = self.get_distro_data('hplip_remove_cmd')
1757
 
        if hplip_remove_cmd:
1758
 
            if callback is not None:
1759
 
                callback(hplip_remove_cmd, "Removing old HPLIP version")
1760
 
 
1761
 
                status, output = self.run(hplip_remove_cmd)
1762
 
 
1763
 
            if status == 0:
1764
 
                self.hplip_present = self.check_hplip()
1765
 
 
1766
 
                if not self.hplip_present:
1767
 
                    failed = False
1768
 
 
1769
 
        return failed
1770
 
 
1771
 
 
1772
 
    def stop_pre_2x_hplip(self, callback=None):
1773
 
        hplip_init_script = '/etc/init.d/hplip stop'
1774
 
        if os.path.exists(hplip_init_script):
1775
 
            cmd = self.su_sudo() % hplip_init_script
1776
 
 
1777
 
            if callback is not None:
1778
 
                callback(cmd, "Stopping old HPLIP version.")
1779
 
 
1780
 
            status, output = self.run(cmd)
1781
 
 
1782
 
 
1783
 
 
1784
 
    def check_password(self, password_entry_callback, callback=None):
1785
 
        self.clear_su_sudo_password()
1786
 
        x = 1
1787
 
        while True:
1788
 
            self.password = password_entry_callback()
1789
 
            cmd = self.su_sudo() % "true"
1790
 
 
1791
 
            log.debug(cmd)
1792
 
 
1793
 
            status, output = self.run(cmd)
1794
 
 
1795
 
            log.debug(status)
1796
 
            log.debug(output)
1797
 
 
1798
 
            if status == 0:
1799
 
                if callback is not None:
1800
 
                    callback("", "Password accepted")
1801
 
                return True
1802
 
 
1803
 
            if callback is not None:
1804
 
                if "not in the sudoers file" in output:
1805
 
                    callback("", "%s is not in the sudoers file. Check privileges\n" %(os.getenv('USER')) )
1806
 
                    return False
1807
 
                else:    
1808
 
                    callback("", "Password incorrect. %d attempt(s) left." % (3-x ))
1809
 
 
1810
 
 
1811
 
            x += 1
1812
 
 
1813
 
            if x > 3:
1814
 
                return False
1815
 
 
1816
 
 
1817
 
    def clear_su_sudo_password(self):
1818
 
        if self.su_sudo_str() == 'sudo':
1819
 
            log.debug("Clearing password...")
1820
 
            self.run("sudo -K")
1821
 
 
1822
 
 
1823
 
 
1824
 
    # PLUGIN HELPERS
1825
 
 
1826
 
    def set_plugin_version(self):
1827
 
        self.plugin_version = prop.installed_version
1828
 
        log.debug("Plug-in version=%s" % self.plugin_version)
1829
 
        self.plugin_name = 'hplip-%s-plugin.run' % self.plugin_version
1830
 
        log.debug("Plug-in=%s" % self.plugin_name)
1831
 
 
1832
 
 
1833
 
    def get_plugin_conf_url(self):
1834
 
        url = "http://hplip.sf.net/plugin.conf"
1835
 
        home = sys_conf.get('dirs', 'home')
1836
 
 
1837
 
        if os.path.exists('/etc/hp/plugin.conf'):
1838
 
            url = "file:///etc/hp/plugin.conf"
1839
 
 
1840
 
        elif os.path.exists(os.path.join(home, 'plugin.conf')):
1841
 
            url = "file://" + os.path.join(home, 'plugin.conf')
1842
 
 
1843
 
        log.debug("Plugin.conf url: %s" % url)
1844
 
        return url
1845
 
 
1846
 
 
1847
 
    def get_plugin_info(self, plugin_conf_url, callback):
1848
 
        ok, size, checksum, timestamp, url = False, 0, 0, 0.0, ''
1849
 
 
1850
 
        if not self.create_plugin_dir():
1851
 
            log.error("Could not create plug-in directory.")
1852
 
            return '', 0, 0, 0, False
1853
 
 
1854
 
        local_conf_fp, local_conf = utils.make_temp_file()
1855
 
 
1856
 
        #if os.path.exists(local_conf):
1857
 
            #os.remove(local_conf)
1858
 
 
1859
 
        try:
1860
 
            try:
1861
 
                #filename, headers = urllib.urlretrieve(plugin_conf_url, local_conf, callback)
1862
 
                wget = utils.which("wget")
1863
 
                if wget:
1864
 
                    wget = os.path.join(wget, "wget")
1865
 
                    status, output = self.run("%s --timeout=60 --output-document=%s %s --cache=off" %(wget, local_conf, plugin_conf_url))
1866
 
                    if status:
1867
 
                        log.error("Plugin download failed with error code = %d" %status)
1868
 
                        return '', 0, 0, 0, False
1869
 
                else:
1870
 
                    log.error("Please install wget package to download the plugin.")
1871
 
                    return '', 0, 0, 0, False
1872
 
            except IOError, e:
1873
 
                log.error("I/O Error: %s" % e.strerror)
1874
 
                return '', 0, 0, 0, False
1875
 
 
1876
 
            if not os.path.exists(local_conf):
1877
 
                log.error("plugin.conf not found.")
1878
 
                return '', 0, 0, 0, False
1879
 
 
1880
 
            plugin_conf_p = ConfigParser.ConfigParser()
1881
 
 
1882
 
            try:
1883
 
                plugin_conf_p.read(local_conf)
1884
 
            except (ConfigParser.MissingSectionHeaderError, ConfigParser.ParsingError):
1885
 
                log.error("Error parsing file - 404 error?")
1886
 
                return '', 0, 0, 0, False
1887
 
 
1888
 
            try:
1889
 
                url = plugin_conf_p.get(self.plugin_version, 'url')
1890
 
                size = plugin_conf_p.getint(self.plugin_version, 'size')
1891
 
                checksum = plugin_conf_p.get(self.plugin_version, 'checksum')
1892
 
                timestamp = plugin_conf_p.getfloat(self.plugin_version, 'timestamp')
1893
 
                ok = True
1894
 
            except (KeyError, ConfigParser.NoSectionError):
1895
 
                log.error("Error reading plugin.conf: Missing section [%s]" % self.plugin_version)
1896
 
                return '', 0, 0, 0, False
1897
 
 
1898
 
        finally:
1899
 
            os.close(local_conf_fp)
1900
 
            os.remove(local_conf)
1901
 
 
1902
 
        return url, size, checksum, timestamp, ok
1903
 
 
1904
 
 
1905
 
    def create_plugin_dir(self):
1906
 
        if not os.path.exists(self.plugin_path):
1907
 
            try:
1908
 
                log.debug("Creating plugin directory: %s" % self.plugin_path)
1909
 
                os.umask(0)
1910
 
                os.makedirs(self.plugin_path, 0755)
1911
 
                return True
1912
 
            except (OSError, IOError), e:
1913
 
                log.error("Unable to create directory: %s" % e.strerror)
1914
 
                return False
1915
 
 
1916
 
        return True
1917
 
 
1918
 
 
1919
 
    def isErrorPage(self, page):
1920
 
        """
1921
 
        Example code from David Mertz' Text Processing in Python.
1922
 
        Released in the Public Domain.
1923
 
        """
1924
 
        err_score = 0.0
1925
 
 
1926
 
        for pat, prob in err_pats.items():
1927
 
            if err_score > 0.9: break
1928
 
            if re.search(pat, page):
1929
 
                err_score += prob
1930
 
 
1931
 
        log.debug("File error page score: %f" % (err_score))
1932
 
 
1933
 
        return err_score > 0.50
1934
 
 
1935
 
 
1936
 
    def download_plugin(self, url, size, checksum, timestamp, callback=None):
1937
 
        log.debug("Downloading %s plug-in file from '%s' to '%s'..." % (self.plugin_version, url, self.plugin_path))
1938
 
 
1939
 
        if not self.create_plugin_dir():
1940
 
            return PLUGIN_INSTALL_ERROR_DIRECTORY_ERROR, self.plugin_path
1941
 
 
1942
 
        plugin_file = os.path.join(self.plugin_path, self.plugin_name)
1943
 
 
1944
 
 
1945
 
        #Check whether plugin is accessible in Openprinting.org website otherwise dowload plugin from alternate location.
1946
 
        wget = utils.which("wget")
1947
 
        if wget:
1948
 
            wget = os.path.join(wget, "wget")
1949
 
            cmd = "%s --cache=off -P %s %s" % (wget,self.plugin_path,url)
1950
 
            log.debug(cmd)
1951
 
            status, output = self.run(cmd)
1952
 
            log.debug("wget returned: %d" % status)
1953
 
 
1954
 
        try:
1955
 
            if (status != 0) and 'file://' not in url:
1956
 
                url = os.path.join(PLUGIN_FALLBACK_LOCATION, self.plugin_name)
1957
 
                log.info("Plugin is not accessible. Trying to download it from fallback location: [%s]" % url)
1958
 
            cmd = "%s --cache=off -P %s %s" % (wget,self.plugin_path,url)
1959
 
            log.debug(cmd)
1960
 
            status, output = self.run(cmd)
1961
 
            #filename, headers = urllib.urlretrieve(url, plugin_file, callback)
1962
 
        except IOError, e:
1963
 
            log.error("Plug-in download failed: %s" % e.strerror)
1964
 
            return PLUGIN_INSTALL_ERROR_PLUGIN_FILE_NOT_FOUND, e.strerror
1965
 
 
1966
 
        if self.isErrorPage(file(plugin_file, 'r').read(1024)):
1967
 
            log.debug(file(plugin_file, 'r').read(1024))
1968
 
            os.remove(plugin_file)
1969
 
            return PLUGIN_INSTALL_ERROR_PLUGIN_FILE_NOT_FOUND, -1
1970
 
 
1971
 
        calc_checksum = get_checksum(file(plugin_file, 'r').read())
1972
 
        log.debug("D/L file checksum=%s" % calc_checksum)
1973
 
 
1974
 
        # Try to download and check the GPG digital signature
1975
 
        digsig_url = url + '.asc'
1976
 
        digsig_file = plugin_file + '.asc'
1977
 
 
1978
 
        log.debug("Downloading %s plug-in digital signature file from '%s' to '%s'..." % (self.plugin_version, digsig_url, digsig_file))
1979
 
 
1980
 
        try:
1981
 
            cmd = "%s --cache=off -P %s %s" % (wget,self.plugin_path,digsig_url)
1982
 
            log.debug(cmd)
1983
 
            status, output = self.run(cmd)
1984
 
            #filename, headers = urllib.urlretrieve(digsig_url, digsig_file, callback)
1985
 
        except IOError, e:
1986
 
            log.error("Plug-in GPG file [%s] download failed: %s" % (digsig_url,e.strerror))
1987
 
            return PLUGIN_INSTALL_ERROR_DIGITAL_SIG_NOT_FOUND, e.strerror
1988
 
 
1989
 
        if self.isErrorPage(file(digsig_file, 'r').read(1024)):
1990
 
            log.debug(file(digsig_file, 'r').read())
1991
 
            os.remove(digsig_file)
1992
 
            return PLUGIN_INSTALL_ERROR_DIGITAL_SIG_NOT_FOUND, -1
1993
 
 
1994
 
        gpg = utils.which('gpg')
1995
 
        if gpg:
1996
 
            gpg = os.path.join(gpg, 'gpg')
1997
 
            cmd = '%s --no-permission-warning --keyserver pgp.mit.edu --recv-keys 0xA59047B9' % gpg
1998
 
            log.info("Receiving digital keys: %s" % cmd)
1999
 
            status, output = self.run(cmd)
2000
 
            log.debug(output)
2001
 
 
2002
 
            if status != 0:
2003
 
                return PLUGIN_INSTALL_ERROR_UNABLE_TO_RECV_KEYS, status
2004
 
 
2005
 
            cmd = '%s --no-permission-warning --verify %s %s' % (gpg, digsig_file, plugin_file)
2006
 
            log.debug("Verifying plugin with digital keys: %s" % cmd)
2007
 
            status, output = self.run(cmd)
2008
 
            log.debug(output)
2009
 
            log.debug("%s status: %d" % (gpg, status))
2010
 
 
2011
 
            if status != 0:
2012
 
                return PLUGIN_INSTALL_ERROR_DIGITAL_SIG_BAD, status
2013
 
 
2014
 
 
2015
 
        return PLUGIN_INSTALL_ERROR_NONE, plugin_file
2016
 
 
2017
 
 
2018
 
    def check_for_plugin(self):
2019
 
        sys_state.read()
2020
 
        is_installed = utils.to_bool(sys_state.get('plugin', 'installed', '0'))
2021
 
        if is_installed:
2022
 
            log.debug("plugin is installed")
2023
 
        else:
2024
 
            log.debug("plugin is not installed")
2025
 
        return is_installed
2026
 
 
2027
 
 
2028
 
    def run_plugin(self, mode=GUI_MODE, callback=None):
2029
 
        plugin_file = os.path.join(self.plugin_path, self.plugin_name)
2030
 
 
2031
 
        if not os.path.exists(plugin_file):
2032
 
            return False
2033
 
 
2034
 
        if mode == GUI_MODE:
2035
 
            return os.system("sh %s --nox11 -- -u" % plugin_file) == 0
2036
 
        else:
2037
 
            if os.system("sh %s --nox11 -- -i" % plugin_file) == 0:
2038
 
                return True
2039
 
            else:
2040
 
                log.error("Python gobject/dbus may be not installed")
2041
 
                return False
2042
 
 
2043
 
 
2044
 
    def delete_plugin(self):
2045
 
        plugin_file = os.path.join(self.plugin_path, self.plugin_name)
2046
 
        digsig_file = plugin_file + ".asc"
2047
 
 
2048
 
        if os.path.exists(plugin_file):
2049
 
            os.unlink(plugin_file)
2050
 
        if os.path.exists(digsig_file):
2051
 
            os.unlink(digsig_file)
 
1
# -*- coding: utf-8 -*-
 
2
#
 
3
# (c) Copyright 2003-2009 Hewlett-Packard Development Company, L.P.
 
4
#
 
5
# This program is free software; you can redistribute it and/or modify
 
6
# it under the terms of the GNU General Public License as published by
 
7
# the Free Software Foundation; either version 2 of the License, or
 
8
# (at your option) any later version.
 
9
#
 
10
# This program is distributed in the hope that it will be useful,
 
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
# GNU General Public License for more details.
 
14
#
 
15
# You should have received a copy of the GNU General Public License
 
16
# along with this program; if not, write to the Free Software
 
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 
18
#
 
19
# Author: Don Welch
 
20
#
 
21
 
 
22
# Std Lib
 
23
import sys
 
24
import os
 
25
import os.path
 
26
import re
 
27
import time
 
28
import cStringIO
 
29
import grp
 
30
import pwd
 
31
import tarfile
 
32
import stat
 
33
 
 
34
try:
 
35
    import hashlib # new in 2.5
 
36
 
 
37
    def get_checksum(s):
 
38
        return hashlib.sha1(s).hexdigest()
 
39
 
 
40
except ImportError:
 
41
    import sha # deprecated in 2.6/3.0
 
42
 
 
43
    def get_checksum(s):
 
44
        return sha.new(s).hexdigest()
 
45
 
 
46
 
 
47
import urllib # TODO: Replace with urllib2 (urllib is deprecated in Python 3.0)
 
48
 
 
49
 
 
50
# Local
 
51
from base.g import *
 
52
from base.codes import *
 
53
from base import utils, pexpect,tui
 
54
from dcheck import *
 
55
 
 
56
 
 
57
 
 
58
DISTRO_UNKNOWN = 0
 
59
DISTRO_VER_UNKNOWN = '0.0'
 
60
 
 
61
MODE_INSTALLER = 0 # hplip-install/hp-setup
 
62
MODE_CHECK = 1 # hp-check
 
63
MODE_CREATE_DOCS = 2 # create_docs
 
64
 
 
65
TYPE_STRING = 1
 
66
TYPE_LIST = 2
 
67
TYPE_BOOL = 3
 
68
TYPE_INT = 4
 
69
 
 
70
DEPENDENCY_RUN_TIME = 1
 
71
DEPENDENCY_COMPILE_TIME = 2
 
72
DEPENDENCY_RUN_AND_COMPILE_TIME = 3
 
73
 
 
74
# Plug-in download errors
 
75
PLUGIN_INSTALL_ERROR_NONE = 0
 
76
PLUGIN_INSTALL_ERROR_PLUGIN_FILE_NOT_FOUND = 1
 
77
PLUGIN_INSTALL_ERROR_DIGITAL_SIG_NOT_FOUND = 2
 
78
PLUGIN_INSTALL_ERROR_DIGITAL_SIG_BAD = 3
 
79
PLUGIN_INSTALL_ERROR_PLUGIN_FILE_CHECKSUM_ERROR = 4
 
80
PLUGIN_INSTALL_ERROR_NO_NETWORK = 5
 
81
PLUGIN_INSTALL_ERROR_DIRECTORY_ERROR = 6
 
82
PLUGIN_INSTALL_ERROR_UNABLE_TO_RECV_KEYS = 7
 
83
 
 
84
 
 
85
#Plugin installation status values
 
86
PLUGIN_STATUS_PARTIAL_FILES_PRESENT = -1
 
87
PLUGIN_STATUS_FILES_NOT_PRESENT = 0
 
88
PLUGIN_STATUS_FILES_PRESENT = 1
 
89
 
 
90
 
 
91
PING_TARGET = "www.google.com"
 
92
HTTP_GET_TARGET = "http://www.google.com"
 
93
PLUGIN_FALLBACK_LOCATION = 'http://hplipopensource.com/hplip-web/plugin/'
 
94
 
 
95
EXPECT_WORD_LIST = [
 
96
    pexpect.EOF, # 0
 
97
    pexpect.TIMEOUT, # 1
 
98
    "Continue?", # 2 (for zypper)
 
99
    "passwor[dt]", # en/de/it/ru
 
100
    "kennwort", # de?
 
101
    "password for", # en
 
102
    "mot de passe", # fr
 
103
    "contraseña", # es
 
104
    "palavra passe", # pt
 
105
    "口令", # zh
 
106
    "wachtwoord", # nl
 
107
    "heslo", # czech
 
108
]
 
109
 
 
110
# Mapping from patterns to probability contribution of pattern
 
111
# Example code from David Mertz' Text Processing in Python.
 
112
# Released in the Public Domain.
 
113
err_pats = {r'(?is)<TITLE>.*?(404|403).*?ERROR.*?</TITLE>': 0.95,
 
114
            r'(?is)<TITLE>.*?ERROR.*?(404|403).*?</TITLE>': 0.95,
 
115
            r'(?is)<TITLE>ERROR</TITLE>': 0.30,
 
116
            r'(?is)<TITLE>.*?ERROR.*?</TITLE>': 0.10,
 
117
            r'(?is)<META .*?(404|403).*?ERROR.*?>': 0.80,
 
118
            r'(?is)<META .*?ERROR.*?(404|403).*?>': 0.80,
 
119
            r'(?is)<TITLE>.*?File Not Found.*?</TITLE>': 0.80,
 
120
            r'(?is)<TITLE>.*?Not Found.*?</TITLE>': 0.40,
 
121
            r'(?is)<BODY.*(404|403).*</BODY>': 0.10,
 
122
            r'(?is)<H1>.*?(404|403).*?</H1>': 0.15,
 
123
            r'(?is)<BODY.*not found.*</BODY>': 0.10,
 
124
            r'(?is)<H1>.*?not found.*?</H1>': 0.15,
 
125
            r'(?is)<BODY.*the requested URL.*</BODY>': 0.10,
 
126
            r'(?is)<BODY.*the page you requested.*</BODY>': 0.10,
 
127
            r'(?is)<BODY.*page.{1,50}unavailable.*</BODY>': 0.10,
 
128
            r'(?is)<BODY.*request.{1,50}unavailable.*</BODY>': 0.10,
 
129
            r'(?i)does not exist': 0.10,
 
130
           }
 
131
 
 
132
 
 
133
 
 
134
# Note:- If new utility is added, add same utility here to uninstall properly.
 
135
 
 
136
BINS_LIST=['hpijs','hp-align','hp-colorcal','hp-faxsetup','hp-linefeedcal','hp-pkservice','hp-printsettings','hp-sendfax','hp-timedate','hp-check','hp-devicesettings','hp-firmware','hp-makecopies','hp-plugin','hp-probe','hp-setup','hp-toolbox','hp-check-plugin','hp-diagnose_plugin','hp-info','hp-makeuri','hp-pqdiag','hp-query','hp-systray','hp-unload','hp-clean','hp-fab','hp-levels','hp-mkuri','hp-print','hp-scan','hp-testpage','hp-wificonfig', 'hp-upgrade','hplip-info','hp-check-upgrade','hp-config_usb_printer','hp-diagnose_queues']
 
137
 
 
138
LIBS_LIST=['libhpmud.*','libhpip.*','sane/libsane-hpaio.*','cups/backend/hp','cups/backend/hpfax', 'cups/filter/hpcac', 'cups/filter/pstotiff','cups/filter/hpcups', 'cups/filter/hpcupsfax', 'cups/filter/hplipjs','cups/filter/hpps']
 
139
 
 
140
FILES_LIST=['/usr/share/ppd/HP/*','/etc/udev/rules.d/56-hpmud_support.rules', '/etc/udev/rules.d/40-hplip.rules', '/etc/udev/rules.d/56-hpmud_support.rules', '/etc/udev/rules.d/55-hpmud.rules', '/etc/udev/rules.d/86-hpmud-hp_*', '/etc/udev/rules.d/86-hpmud_plugin.rules', '/usr/share/cups/drv/hp/*','/usr/local/share/ppd/HP/*','/usr/local/share/cups/drv/hp/*' ,'/usr/share/applications/hplip.desktop', '/etc/xdg/autostart/hplip-systray.desktop', '/etc/hp/hplip.conf', '/usr/share/doc/hplip-*']
 
141
 
 
142
HPLIP_LIST=['*.py','*.pyc', 'base', 'copier','data','installer','pcard','ui4','ui','fax/*.py','fax/*.pyc','fax/pstotiff.convs','fax/pstotiff.types','fax/pstotiff','prnt/*.py', 'prnt/*.pyc', 'scan/*.py','scan/*.pyc']
 
143
 
 
144
PLUGIN_LIST=['fax/plugins/','prnt/pluginmode = INTERACTIVE_MODEs/','scan/plugins/']
 
145
PLUGIN_STATE =['/var/lib/hp/hplip.state']
 
146
RMDIR="rm -rf"
 
147
RM="rm -f"
 
148
 
 
149
# end
 
150
 
 
151
 
 
152
EXPECT_LIST = []
 
153
for s in EXPECT_WORD_LIST:
 
154
    try:
 
155
        p = re.compile(s, re.I)
 
156
    except TypeError:
 
157
        EXPECT_LIST.append(s)
 
158
    else:
 
159
        EXPECT_LIST.append(p)
 
160
 
 
161
OK_PROCESS_LIST = ['adept-notifier',
 
162
                   'adept_notifier',
 
163
                   'yum-updatesd',
 
164
                   ]
 
165
 
 
166
CONFIGURE_ERRORS = { 1 : "General/unknown error",
 
167
                     2 : "libusb not found",
 
168
                     3 : "cups-devel not found",
 
169
                     4 : "libnetsnmp not found",
 
170
                     5 : "netsnmp-devel not found",
 
171
                     6 : "python-devel not found",
 
172
                     7 : "pthread-devel not found",
 
173
                     8 : "ppdev-devel not found",
 
174
                     9 : "libcups not found",
 
175
                     10 : "libm not found",
 
176
                     11 : "libusb-devel not found",
 
177
                     12 : "sane-backends-devel not found",
 
178
                     13 : "libdbus not found",
 
179
                     14 : "dbus-devel not found",
 
180
                     15 : "fax requires dbus support",
 
181
                     102 : "libjpeg not found",
 
182
                     103 : "jpeg-devel not found",
 
183
                     104 : "libdi not found",
 
184
                   }
 
185
 
 
186
 
 
187
try:
 
188
    from functools import update_wrapper
 
189
except ImportError: # using Python version < 2.5
 
190
    def trace(f):
 
191
        def newf(*args, **kw):
 
192
           log.debug("TRACE: func=%s(), args=%s, kwargs=%s" % (f.__name__, args, kw))
 
193
           return f(*args, **kw)
 
194
        newf.__name__ = f.__name__
 
195
        newf.__dict__.update(f.__dict__)
 
196
        newf.__doc__ = f.__doc__
 
197
        newf.__module__ = f.__module__
 
198
        return newf
 
199
else: # using Python 2.5+
 
200
    def trace(f):
 
201
        def newf(*args, **kw):
 
202
            log.debug("TRACE: func=%s(), args=%s, kwargs=%s" % (f.__name__, args, kw))
 
203
            return f(*args, **kw)
 
204
        return update_wrapper(newf, f)
 
205
 
 
206
 
 
207
 
 
208
class CoreInstall(object):
 
209
    def __init__(self, mode=MODE_INSTALLER, ui_mode=INTERACTIVE_MODE, ui_toolkit='qt4'):
 
210
        os.umask(0022)
 
211
        self.mode = mode
 
212
        self.ui_mode = ui_mode
 
213
        self.password = ''
 
214
        self.version_description, self.version_public, self.version_internal = '', '', ''
 
215
        self.bitness = 32
 
216
        self.endian = utils.LITTLE_ENDIAN
 
217
        self.distro, self.distro_name, self.distro_version = DISTRO_UNKNOWN, '', DISTRO_VER_UNKNOWN
 
218
        self.distro_version_supported = False
 
219
        self.install_location = '/usr'
 
220
        self.hplip_present = False
 
221
        self.have_dependencies = {}
 
222
        self.native_cups = True
 
223
        self.ppd_dir = None
 
224
        self.drv_dir = None
 
225
        self.distros = {}
 
226
        self.network_connected = False
 
227
        self.ui_toolkit = ui_toolkit
 
228
        self.enable = None
 
229
        self.disable = None
 
230
        self.plugin_path = "/tmp"
 
231
        self.plugin_version = '0.0.0'
 
232
        self.plugin_name = ''
 
233
        self.reload_dbus = False
 
234
 
 
235
 
 
236
        self.FIELD_TYPES = {
 
237
            'distros' : TYPE_LIST,
 
238
            'index' : TYPE_INT,
 
239
            'versions' : TYPE_LIST,
 
240
            'display_name' : TYPE_STRING,
 
241
            'alt_names': TYPE_LIST,
 
242
            'display': TYPE_BOOL,
 
243
            'notes': TYPE_STRING,
 
244
            'package_mgrs': TYPE_LIST,
 
245
            'package_mgr_cmd':TYPE_STRING,
 
246
            'pre_install_cmd': TYPE_LIST,
 
247
            'pre_depend_cmd': TYPE_LIST,
 
248
            'post_depend_cmd': TYPE_LIST,
 
249
            'hpoj_remove_cmd': TYPE_STRING,
 
250
            'hplip_remove_cmd': TYPE_STRING,
 
251
            'su_sudo': TYPE_STRING,
 
252
            'ppd_install': TYPE_STRING,
 
253
            'udev_mode_fix': TYPE_BOOL,
 
254
            'ppd_dir': TYPE_STRING,
 
255
            'drv_dir' : TYPE_STRING,
 
256
            'fix_ppd_symlink': TYPE_BOOL,
 
257
            'code_name': TYPE_STRING,
 
258
            'supported': TYPE_BOOL, # Supported by installer
 
259
            'release_date': TYPE_STRING,
 
260
            'packages': TYPE_LIST,
 
261
            'commands': TYPE_LIST,
 
262
            'same_as_version' : TYPE_STRING,
 
263
            'scan_supported' : TYPE_BOOL,
 
264
            'fax_supported' : TYPE_BOOL,
 
265
            'pcard_supported' : TYPE_BOOL,
 
266
            'network_supported' : TYPE_BOOL,
 
267
            'parallel_supported' : TYPE_BOOL,
 
268
            'usb_supported' : TYPE_BOOL,
 
269
            'packaged_version': TYPE_STRING, # Version of HPLIP pre-packaged in distro
 
270
            'cups_path_with_bitness' : TYPE_BOOL,
 
271
            'ui_toolkit' : TYPE_STRING,  # qt3 or qt4 [or gtk] or none
 
272
            'policykit' : TYPE_BOOL,
 
273
            'native_cups' : TYPE_BOOL,
 
274
            'package_available' : TYPE_BOOL,
 
275
            'package_arch' : TYPE_LIST,
 
276
            'add_user_to_group': TYPE_STRING,
 
277
            'open_mdns_port' : TYPE_LIST, # command to use to open mdns multicast port 5353
 
278
            'acl_rules' : TYPE_BOOL, # Use ACL uDEV rules (Ubuntu 9.10+)
 
279
            'libdir_path' : TYPE_STRING,
 
280
        }
 
281
 
 
282
        # components
 
283
        # 'name': ('description', [<option list>])
 
284
        self.components = {
 
285
            'hplip': ("HP Linux Imaging and Printing System", ['base', 'network', 'gui_qt4',
 
286
                                                               'fax', 'scan', 'docs']),
 
287
        }
 
288
 
 
289
        self.selected_component = 'hplip'
 
290
 
 
291
        # options
 
292
        # name: (<required>, "<display_name>", [<dependency list>]), ...
 
293
        self.options = {
 
294
            'base':     (True,  'Required HPLIP base components (including hpcups)', []), # HPLIP
 
295
            'network' : (False, 'Network/JetDirect I/O', []),
 
296
            'gui_qt4' : (False, 'Graphical User Interfaces (Qt4)', []),
 
297
            'fax' :     (False, 'PC Send Fax support', []),
 
298
            'scan':     (False, 'Scanning support', []),
 
299
            'docs':     (False, 'HPLIP documentation (HTML)', []),
 
300
            'policykit': (False, 'Administrative policy framework', []),
 
301
        }
 
302
 
 
303
 
 
304
        # holds whether the user has selected (turned on each option)
 
305
        # initial values are defaults (for GUI only)
 
306
        self.selected_options = {
 
307
            'base':        True,
 
308
            'network':     True,
 
309
            'gui_qt4':     True,
 
310
            'fax':         True,
 
311
            'scan':        True,
 
312
            'docs':        True,
 
313
            'policykit':   False,
 
314
            'native_cups': False,
 
315
        }
 
316
 
 
317
        # dependencies
 
318
        # 'name': (<required for option>, [<option list>], <display_name>, <check_func>, <runtime/compiletime>), ...
 
319
        # Note: any change to the list of dependencies must be reflected in base/distros.py
 
320
        self.dependencies = {
 
321
            # Required base packages
 
322
            'libjpeg':          (True,  ['base'], "libjpeg - JPEG library", self.check_libjpeg, DEPENDENCY_RUN_AND_COMPILE_TIME),
 
323
            'libtool':          (True,  ['base'], "libtool - Library building support services", self.check_libtool, DEPENDENCY_COMPILE_TIME),
 
324
            'cups' :            (True,  ['base'], 'CUPS - Common Unix Printing System', self.check_cups, DEPENDENCY_RUN_TIME),
 
325
            'cups-devel':       (True,  ['base'], 'CUPS devel- Common Unix Printing System development files', self.check_cups_devel, DEPENDENCY_COMPILE_TIME),
 
326
            'cups-image':       (True,  ['base'], "CUPS image - CUPS image development files", self.check_cups_image, DEPENDENCY_COMPILE_TIME),
 
327
            'gcc' :             (True,  ['base'], 'gcc - GNU Project C and C++ Compiler', self.check_gcc, DEPENDENCY_COMPILE_TIME),
 
328
            'make' :            (True,  ['base'], "make - GNU make utility to maintain groups of programs", self.check_make, DEPENDENCY_COMPILE_TIME),
 
329
            'python-devel' :    (True,  ['base'], "Python devel - Python development files", self.check_python_devel, DEPENDENCY_COMPILE_TIME),
 
330
            'libpthread' :      (True,  ['base'], "libpthread - POSIX threads library", self.check_libpthread, DEPENDENCY_RUN_AND_COMPILE_TIME),
 
331
            'python2x':         (True,  ['base'], "Python 2.2 or greater - Python programming language", self.check_python2x, DEPENDENCY_RUN_AND_COMPILE_TIME),
 
332
            'python-xml'  :     (True,  ['base'], "Python XML libraries", self.check_python_xml, DEPENDENCY_RUN_TIME),
 
333
            'gs':               (True,  ['base'], "GhostScript - PostScript and PDF language interpreter and previewer", self.check_gs, DEPENDENCY_RUN_TIME),
 
334
            'libusb':           (True,  ['base'], "libusb - USB library", self.check_libusb, DEPENDENCY_RUN_AND_COMPILE_TIME),
 
335
 
 
336
            # Optional base packages
 
337
            'cups-ddk':          (False, ['base'], "CUPS DDK - CUPS driver development kit", self.check_cupsddk, DEPENDENCY_RUN_TIME), # req. for .drv PPD installs
 
338
 
 
339
 
 
340
            # Required scan packages
 
341
            'sane':             (True,  ['scan'], "SANE - Scanning library", self.check_sane, DEPENDENCY_RUN_TIME),
 
342
            'sane-devel' :      (True,  ['scan'], "SANE - Scanning library development files", self.check_sane_devel, DEPENDENCY_COMPILE_TIME),
 
343
 
 
344
            # Optional scan packages
 
345
            'xsane':            (False, ['scan'], "xsane - Graphical scanner frontend for SANE", self.check_xsane, DEPENDENCY_RUN_TIME),
 
346
            'scanimage':        (False, ['scan'], "scanimage - Shell scanning program", self.check_scanimage, DEPENDENCY_RUN_TIME),
 
347
            'pil':              (False, ['scan'], "PIL - Python Imaging Library (required for commandline scanning with hp-scan)", self.check_pil, DEPENDENCY_RUN_TIME),
 
348
 
 
349
            # Required fax packages
 
350
            'python23':         (True,  ['fax'], "Python 2.3 or greater - Required for fax functionality", self.check_python23, DEPENDENCY_RUN_TIME),
 
351
            'dbus':             (True,  ['fax'], "DBus - Message bus system", self.check_dbus, DEPENDENCY_RUN_AND_COMPILE_TIME),
 
352
            'python-dbus':      (True,  ['fax'], "Python DBus - Python bindings for DBus", self.check_python_dbus, DEPENDENCY_RUN_TIME),
 
353
 
 
354
            # Optional fax packages
 
355
            'reportlab':        (False, ['fax'], "Reportlab - PDF library for Python", self.check_reportlab, DEPENDENCY_RUN_TIME),
 
356
 
 
357
            # Required and optional qt4 GUI packages
 
358
            'pyqt4':            (True,  ['gui_qt4'], "PyQt 4- Qt interface for Python (for Qt version 4.x)", self.check_pyqt4, DEPENDENCY_RUN_TIME), # PyQt 4.x )
 
359
            'pyqt4-dbus' :      (True,  ['gui_qt4'], "PyQt 4 DBus - DBus Support for PyQt4", self.check_pyqt4_dbus, DEPENDENCY_RUN_TIME),
 
360
            'policykit':        (False, ['gui_qt4'], "PolicyKit - Administrative policy framework", self.check_policykit, DEPENDENCY_RUN_TIME), # optional for non-sudo behavior of plugins (only optional for Qt4 option)
 
361
            'python-notify' :   (False, ['gui_qt4'], "Python libnotify - Python bindings for the libnotify Desktop notifications", self.check_pynotify, DEPENDENCY_RUN_TIME), # Optional for libnotify style popups from hp-systray
 
362
 
 
363
            # Required network I/O packages
 
364
            'libnetsnmp-devel': (True,  ['network'], "libnetsnmp-devel - SNMP networking library development files", self.check_libnetsnmp, DEPENDENCY_RUN_AND_COMPILE_TIME),
 
365
            'libcrypto':        (True,  ['network'], "libcrypto - OpenSSL cryptographic library", self.check_libcrypto, DEPENDENCY_RUN_AND_COMPILE_TIME),
 
366
        }
 
367
 
 
368
        for opt in self.options:
 
369
            update_spinner()
 
370
            for d in self.dependencies:
 
371
                if opt in self.dependencies[d][1]:
 
372
                    self.options[opt][2].append(d)
 
373
 
 
374
        self.load_distros()
 
375
 
 
376
        self.distros_index = {}
 
377
        for d in self.distros:
 
378
            self.distros_index[self.distros[d]['index']] = d
 
379
 
 
380
 
 
381
    def init(self, callback=None):
 
382
        if callback is not None:
 
383
            callback("Init...\n")
 
384
 
 
385
        update_spinner()
 
386
 
 
387
        # Package manager names
 
388
        self.package_mgrs = []
 
389
        for d in self.distros:
 
390
            update_spinner()
 
391
 
 
392
            for a in self.distros[d].get('package_mgrs', []):
 
393
                if a and a not in self.package_mgrs:
 
394
                    self.package_mgrs.append(a)
 
395
 
 
396
        self.version_description, self.version_public, self.version_internal = self.get_hplip_version()
 
397
        log.debug("HPLIP Description=%s Public version=%s Internal version = %s"  %
 
398
            (self.version_description, self.version_public, self.version_internal))
 
399
 
 
400
        # have_dependencies
 
401
        # is each dependency satisfied?
 
402
        # start with each one 'No'
 
403
        for d in self.dependencies:
 
404
            update_spinner()
 
405
            self.have_dependencies[d] = False
 
406
 
 
407
        self.get_distro()
 
408
        self.distro_changed()
 
409
 
 
410
        if callback is not None:
 
411
            callback("Distro: %s\n" % self.distro)
 
412
 
 
413
        self.check_dependencies(callback)
 
414
 
 
415
        for d in self.dependencies:
 
416
            update_spinner()
 
417
 
 
418
            log.debug("have %s = %s" % (d, self.have_dependencies[d]))
 
419
 
 
420
            if callback is not None:
 
421
                callback("Result: %s = %s\n" % (d, self.have_dependencies[d]))
 
422
 
 
423
        pid, cmdline = self.check_pkg_mgr()
 
424
        if pid:
 
425
            log.debug("Running package manager: %s (%d)" % (cmdline, pid) )
 
426
 
 
427
        self.bitness = utils.getBitness()
 
428
        log.debug("Bitness = %d" % self.bitness)
 
429
 
 
430
        update_spinner()
 
431
 
 
432
        self.endian = utils.getEndian()
 
433
        log.debug("Endian = %d" % self.endian)
 
434
 
 
435
        update_spinner()
 
436
 
 
437
        self.distro_name = self.distros_index[self.distro]
 
438
        self.distro_version_supported = self.get_distro_ver_data('supported', False)
 
439
 
 
440
        log.debug("Distro = %s Distro Name = %s Display Name= %s Version = %s Supported = %s" %
 
441
            (self.distro, self.distro_name, self.distros[self.distro_name]['display_name'],
 
442
             self.distro_version, self.distro_version_supported))
 
443
 
 
444
        update_spinner()
 
445
 
 
446
        self.hplip_present = self.check_hplip()
 
447
        log.debug("HPLIP (prev install) = %s" % self.hplip_present)
 
448
 
 
449
        status, output = self.run('cups-config --version')
 
450
        self.cups_ver = output.strip()
 
451
        log.debug("CUPS version = %s" % self.cups_ver)
 
452
 
 
453
        if self.distro_name == "ubuntu":
 
454
            self.reload_dbus = True
 
455
 
 
456
        log.debug("DBUS configuration reload possible? %s" % self.reload_dbus)
 
457
 
 
458
        status, self.sys_uname_info = self.run('uname -a')
 
459
        self.sys_uname_info = self.sys_uname_info.replace('\n', '')
 
460
        log.debug(self.sys_uname_info)
 
461
 
 
462
        # Record the installation time/date and version.
 
463
        # Also has the effect of making the .hplip.conf file user r/w
 
464
        # on the 1st run so that running hp-setup as root doesn't lock
 
465
        # the user out of owning the file
 
466
        user_conf.set('installation', 'date_time', time.strftime("%x %H:%M:%S", time.localtime()))
 
467
        user_conf.set('installation', 'version', self.version_public)
 
468
 
 
469
        if callback is not None:
 
470
            callback("Done")
 
471
 
 
472
 
 
473
    def init_for_docs(self, distro_name, version, bitness=32):
 
474
        self.distro_name = distro_name
 
475
        self.distro_version = version
 
476
 
 
477
        try:
 
478
            self.distro = self.distros[distro_name]['index']
 
479
        except KeyError:
 
480
            log.error("Invalid distro name: %s" % distro_name)
 
481
            sys.exit(1)
 
482
 
 
483
        self.bitness = bitness
 
484
 
 
485
        for d in self.dependencies:
 
486
            self.have_dependencies[d] = True
 
487
 
 
488
        self.enable_ppds = self.get_distro_ver_data('ppd_install', 'ppd') == 'ppd'
 
489
        self.ppd_dir = self.get_distro_ver_data('ppd_dir')
 
490
        self.drv_dir = self.get_distro_ver_data('drv_dir')
 
491
 
 
492
        self.distro_version_supported = True # for manual installs
 
493
 
 
494
 
 
495
    def check_dependencies(self, callback=None):
 
496
        update_ld_output()
 
497
 
 
498
        for d in self.dependencies:
 
499
            update_spinner()
 
500
 
 
501
            log.debug("Checking for dependency '%s'...\n" % d)
 
502
 
 
503
            if callback is not None:
 
504
                callback("Checking: %s\n" % d)
 
505
 
 
506
            self.have_dependencies[d] = self.dependencies[d][3]()
 
507
            log.debug("have %s = %s" % (d, self.have_dependencies[d]))
 
508
 
 
509
        cleanup_spinner()
 
510
 
 
511
 
 
512
    def password_func(self):
 
513
        if self.password:
 
514
            return self.password
 
515
        elif self.ui_mode == INTERACTIVE_MODE:
 
516
            import getpass
 
517
            return getpass.getpass("Enter password: ")
 
518
        else:
 
519
            return ''
 
520
 
 
521
 
 
522
    def run(self, cmd, callback=None, timeout=300): # ==> status, output
 
523
        if cmd is None:
 
524
            return 1, ''
 
525
        output = cStringIO.StringIO()
 
526
        ok, ret = False, ''
 
527
        # Hack! TODO: Fix!
 
528
        check_timeout = not (cmd.startswith('xterm') or cmd.startswith('gnome-terminal'))
 
529
 
 
530
        try:
 
531
            child = pexpect.spawn(cmd, timeout=1)
 
532
        except pexpect.ExceptionPexpect:
 
533
            return 1, ''
 
534
 
 
535
        try:
 
536
            try:
 
537
                start = time.time()
 
538
 
 
539
                while True:
 
540
                    update_spinner()
 
541
 
 
542
                    i = child.expect_list(EXPECT_LIST)
 
543
 
 
544
                    cb = child.before
 
545
                    if cb:
 
546
                        # output
 
547
                        start = time.time()
 
548
                        log.log_to_file(cb)
 
549
                        log.debug(cb)
 
550
                        output.write(cb)
 
551
 
 
552
                        if callback is not None:
 
553
                            if callback(cb): # cancel
 
554
                                break
 
555
 
 
556
                    elif check_timeout:
 
557
                        # no output
 
558
                        span = int(time.time()-start)
 
559
 
 
560
                        if span:
 
561
                            if span % 5 == 0:
 
562
                                log.debug("No output seen in %d secs" % span)
 
563
 
 
564
                            if span > timeout:
 
565
                                log.error("No output seen in over %d sec... (Is the CD-ROM/DVD source repository enabled? It shouldn't be!)" % timeout)
 
566
                                child.close()
 
567
                                child.terminate(force=True)
 
568
                                break
 
569
 
 
570
                    if i == 0: # EOF
 
571
                        ok, ret = True, output.getvalue()
 
572
                        break
 
573
 
 
574
                    elif i == 1: # TIMEOUT
 
575
                        continue
 
576
 
 
577
                    elif i == 2: # zypper "Continue?"
 
578
                        child.sendline("YES")
 
579
 
 
580
                    else: # password
 
581
                        child.sendline(self.password)
 
582
 
 
583
            except (Exception, pexpect.ExceptionPexpect):
 
584
                log.exception()
 
585
 
 
586
        finally:
 
587
            cleanup_spinner()
 
588
 
 
589
            try:
 
590
                child.close()
 
591
            except OSError:
 
592
                pass
 
593
 
 
594
        if ok:
 
595
            return child.exitstatus, ret
 
596
        else:
 
597
            return 1, ''
 
598
 
 
599
 
 
600
    def get_distro(self):
 
601
        log.debug("Determining distro...")
 
602
        self.distro, self.distro_version = DISTRO_UNKNOWN, '0.0'
 
603
 
 
604
        found = False
 
605
 
 
606
        lsb_release = utils.which("lsb_release")
 
607
 
 
608
        if lsb_release:
 
609
            log.debug("Using 'lsb_release -is/-rs'")
 
610
            cmd = os.path.join(lsb_release, "lsb_release")
 
611
            status, name = self.run(cmd + ' -is')
 
612
            name = name.lower().strip()
 
613
            log.debug("Distro name=%s" % name)
 
614
 
 
615
            if not status and name:
 
616
                status, ver = self.run(cmd + ' -rs')
 
617
                ver = ver.lower().strip()
 
618
                log.debug("Distro version=%s" % ver)
 
619
 
 
620
                if not status and ver:
 
621
                    for d in self.distros:
 
622
                        if name.find(d) > -1:
 
623
                            self.distro = self.distros[d]['index']
 
624
                            found = True
 
625
                            self.distro_version = ver
 
626
                            break
 
627
 
 
628
        if not found:
 
629
            try:
 
630
                name = file('/etc/issue', 'r').read().lower().strip()
 
631
            except IOError:
 
632
                # Some O/Ss don't have /etc/issue (Mac)
 
633
                self.distro, self.distro_version = DISTRO_UNKNOWN, '0.0'
 
634
            else:
 
635
                for d in self.distros:
 
636
                    if name.find(d) > -1:
 
637
                        self.distro = self.distros[d]['index']
 
638
                        found = True
 
639
                    else:
 
640
                        for x in self.distros[d].get('alt_names', ''):
 
641
                            if x and name.find(x) > -1:
 
642
                                self.distro = self.distros[d]['index']
 
643
                                found = True
 
644
                                break
 
645
 
 
646
                    if found:
 
647
                        break
 
648
 
 
649
                if found:
 
650
                    for n in name.split():
 
651
                        m= n
 
652
                        if '.' in n:
 
653
                            m = '.'.join(n.split('.')[:2])
 
654
 
 
655
                        try:
 
656
                            float(m)
 
657
                        except ValueError:
 
658
                            try:
 
659
                                int(m)
 
660
                            except ValueError:
 
661
                                self.distro_version = '0.0'
 
662
                            else:
 
663
                                self.distro_version = m
 
664
                                break
 
665
                        else:
 
666
                            self.distro_version = m
 
667
                            break
 
668
 
 
669
                    log.debug("/etc/issue: %s %s" % (name, self.distro_version))
 
670
 
 
671
        log.debug("distro=%d, distro_version=%s" % (self.distro, self.distro_version))
 
672
 
 
673
 
 
674
    def distro_changed(self):
 
675
        ppd_install = self.get_distro_ver_data('ppd_install', 'ppd')
 
676
 
 
677
        if ppd_install not in ('ppd', 'drv'):
 
678
            log.warning("Invalid ppd_install value: %s" % ppd_install)
 
679
 
 
680
        self.enable_ppds = (ppd_install == 'ppd')
 
681
 
 
682
        log.debug("Enable PPD install: %s (False=drv)" % self.enable_ppds)
 
683
 
 
684
        self.ppd_dir = self.get_distro_ver_data('ppd_dir')
 
685
 
 
686
        self.drv_dir = self.get_distro_ver_data('drv_dir')
 
687
        if not self.enable_ppds and not self.drv_dir:
 
688
            log.warning("Invalid drv_dir value: %s" % self.drv_dir)
 
689
 
 
690
        self.distro_version_supported = self.get_distro_ver_data('supported', False)
 
691
        self.selected_options['fax'] = self.get_distro_ver_data('fax_supported', True)
 
692
        self.selected_options['network'] = self.get_distro_ver_data('network_supported', True)
 
693
        self.selected_options['scan'] = self.get_distro_ver_data('scan_supported', True)
 
694
        self.selected_options['policykit'] = self.get_distro_ver_data('policykit', False)
 
695
        self.native_cups = self.get_distro_ver_data('native_cups', False)
 
696
 
 
697
        # Adjust required flag based on the distro ver ui_toolkit value
 
698
        ui_toolkit = self.get_distro_ver_data('ui_toolkit',  'qt4').lower()
 
699
 
 
700
        if ui_toolkit == 'qt4':
 
701
            log.debug("Default UI toolkit: Qt4")
 
702
            self.ui_toolkit = 'qt4'
 
703
            self.selected_options['gui_qt4'] = True
 
704
 
 
705
        # todo: gtk
 
706
        else:
 
707
            self.selected_options['gui_qt4'] = False
 
708
 
 
709
        # Override with --qt4 command args
 
710
        if self.enable is not None:
 
711
            if 'qt4' in self.enable:
 
712
                log.debug("User selected UI toolkit: Qt4")
 
713
                self.ui_toolkit = 'qt4'
 
714
                self.selected_options['gui_qt4'] = True
 
715
 
 
716
        if self.disable is not None:
 
717
            if 'qt4' in self.disable:
 
718
                log.debug("User deselected UI toolkit: Qt4")
 
719
                self.selected_options['gui_qt4'] = False
 
720
 
 
721
 
 
722
    def __fixup_data(self, key, data):
 
723
        field_type = self.FIELD_TYPES.get(key, TYPE_STRING)
 
724
        #log.debug("%s (%s) %d" % (key, data, field_type))
 
725
 
 
726
        if field_type == TYPE_BOOL:
 
727
            return utils.to_bool(data)
 
728
 
 
729
        elif field_type == TYPE_STRING:
 
730
            if type('') == type(data):
 
731
                return data.strip()
 
732
            else:
 
733
                return data
 
734
 
 
735
        elif field_type == TYPE_INT:
 
736
            try:
 
737
                return int(data)
 
738
            except ValueError:
 
739
                return 0
 
740
 
 
741
        elif field_type == TYPE_LIST:
 
742
            return [x for x in data.split(',') if x]
 
743
 
 
744
 
 
745
    def load_distros(self):
 
746
        if self.mode  == MODE_INSTALLER:
 
747
            distros_dat_file = os.path.join('installer', 'distros.dat')
 
748
 
 
749
        elif self.mode == MODE_CREATE_DOCS:
 
750
            distros_dat_file = os.path.join('..', '..', 'installer', 'distros.dat')
 
751
 
 
752
        else: # MODE_CHECK
 
753
            distros_dat_file = os.path.join(prop.home_dir, 'installer', 'distros.dat')
 
754
 
 
755
            if not os.path.exists(distros_dat_file):
 
756
                log.debug("DAT file not found at %s. Using local relative path..." % distros_dat_file)
 
757
                distros_dat_file = os.path.join('installer', 'distros.dat')
 
758
 
 
759
        distros_dat = ConfigBase(distros_dat_file)
 
760
        distros_list = self.__fixup_data('distros', distros_dat.get('distros', 'distros'))
 
761
        log.debug(distros_list)
 
762
 
 
763
        for distro in distros_list:
 
764
            update_spinner()
 
765
            d = {}
 
766
 
 
767
            if not distros_dat.has_section(distro):
 
768
                log.debug("Missing distro section in distros.dat: [%s]" % distro)
 
769
                continue
 
770
 
 
771
            for key in distros_dat.keys(distro):
 
772
                d[key] = self.__fixup_data(key, distros_dat.get(distro, key))
 
773
 
 
774
            self.distros[distro] = d
 
775
            versions = self.__fixup_data("versions", distros_dat.get(distro, 'versions'))
 
776
            self.distros[distro]['versions'] = {}
 
777
 
 
778
            for ver in versions:
 
779
                same_as_version, supported = False, True
 
780
                v = {}
 
781
                ver_section = "%s:%s" % (distro, ver)
 
782
 
 
783
                if not distros_dat.has_section(ver_section):
 
784
                    log.error("Missing version section in distros.dat: [%s:%s]" % (distro, ver))
 
785
                    continue
 
786
 
 
787
                if 'same_as_version' in distros_dat.keys(ver_section):
 
788
                    same_as_version = True
 
789
 
 
790
                supported = self.__fixup_data('supported', distros_dat.get(ver_section, 'supported'))
 
791
 
 
792
                for key in distros_dat.keys(ver_section):
 
793
                    v[key] = self.__fixup_data(key, distros_dat.get(ver_section, key))
 
794
 
 
795
                self.distros[distro]['versions'][ver] = v
 
796
                self.distros[distro]['versions'][ver]['dependency_cmds'] = {}
 
797
 
 
798
                if same_as_version: # or not supported:
 
799
                    continue
 
800
 
 
801
                for dep in self.dependencies:
 
802
                    dd = {}
 
803
                    dep_section = "%s:%s:%s" % (distro, ver, dep)
 
804
 
 
805
                    if not distros_dat.has_section(dep_section) and not same_as_version:
 
806
                        log.debug("Missing dependency section in distros.dat: [%s:%s:%s]" % (distro, ver, dep))
 
807
                        continue
 
808
 
 
809
                    #if same_as_version:
 
810
                    #    continue
 
811
 
 
812
                    for key in distros_dat.keys(dep_section):
 
813
                        dd[key] = self.__fixup_data(key, distros_dat.get(dep_section, key))
 
814
 
 
815
                    self.distros[distro]['versions'][ver]['dependency_cmds'][dep] = dd
 
816
 
 
817
            versions = self.distros[distro]['versions']
 
818
            for ver in versions:
 
819
                ver_section = "%s:%s" % (distro, ver)
 
820
 
 
821
                if 'same_as_version' in distros_dat.keys(ver_section):
 
822
                    v = self.__fixup_data("same_as_version", distros_dat.get(ver_section, 'same_as_version'))
 
823
                    log.debug("Setting %s:%s to %s:%s" % (distro, ver, distro, v))
 
824
 
 
825
                    try:
 
826
                        vv = self.distros[distro]['versions'][v].copy()
 
827
                        vv['same_as_version'] = v
 
828
                        self.distros[distro]['versions'][ver] = vv
 
829
                    except KeyError:
 
830
                        log.debug("Missing 'same_as_version=' version in distros.dat for section [%s:%s]." % (distro, v))
 
831
                        continue
 
832
 
 
833
        #import pprint
 
834
        #pprint.pprint(self.distros)
 
835
 
 
836
    def pre_install(self):
 
837
        pass
 
838
 
 
839
 
 
840
    def pre_depend(self):
 
841
        pass
 
842
 
 
843
 
 
844
    def check_python2x(self):
 
845
        py_ver = sys.version_info
 
846
        py_major_ver, py_minor_ver = py_ver[:2]
 
847
        log.debug("Python ver=%d.%d" % (py_major_ver, py_minor_ver))
 
848
        return py_major_ver >= 2
 
849
 
 
850
 
 
851
    def check_gcc(self):
 
852
        return check_tool('gcc --version', 0) and check_tool('g++ --version', 0)
 
853
 
 
854
 
 
855
    def check_make(self):
 
856
        return check_tool('make --version', 3.0)
 
857
 
 
858
 
 
859
    def check_libusb(self):
 
860
        if not check_lib('libusb'):
 
861
            return False
 
862
 
 
863
        return len(locate_file_contains("usb.h", '/usr/include', 'usb_init(void)'))
 
864
 
 
865
 
 
866
    def check_libjpeg(self):
 
867
        return check_lib("libjpeg") and check_file("jpeglib.h")
 
868
 
 
869
 
 
870
    def check_libcrypto(self):
 
871
        return check_lib("libcrypto") and check_file("crypto.h")
 
872
 
 
873
 
 
874
    def check_libpthread(self):
 
875
        return check_lib("libpthread") and check_file("pthread.h")
 
876
 
 
877
 
 
878
    def check_libnetsnmp(self):
 
879
        return check_lib("libnetsnmp") and check_file("net-snmp-config.h")
 
880
 
 
881
 
 
882
    def check_reportlab(self):
 
883
        try:
 
884
            log.debug("Trying to import 'reportlab'...")
 
885
            import reportlab
 
886
 
 
887
            ver = reportlab.Version
 
888
            try:
 
889
                ver_f = float(ver)
 
890
            except ValueError:
 
891
                log.debug("Can't determine version.")
 
892
                return False
 
893
            else:
 
894
                log.debug("Version: %.1f" % ver_f)
 
895
                if ver_f >= 2.0:
 
896
                    log.debug("Success.")
 
897
                    return True
 
898
                else:
 
899
                    return False
 
900
 
 
901
        except ImportError:
 
902
            log.debug("Failed.")
 
903
            return False
 
904
 
 
905
 
 
906
    def check_python23(self):
 
907
        py_ver = sys.version_info
 
908
        py_major_ver, py_minor_ver = py_ver[:2]
 
909
        log.debug("Python ver=%d.%d" % (py_major_ver, py_minor_ver))
 
910
        return py_major_ver >= 2 and py_minor_ver >= 3
 
911
 
 
912
 
 
913
    def check_python_xml(self):
 
914
        try:
 
915
            import xml.parsers.expat
 
916
        except ImportError:
 
917
            return False
 
918
        else:
 
919
            return True
 
920
 
 
921
 
 
922
    def check_sane(self):
 
923
        return check_lib('libsane')
 
924
 
 
925
 
 
926
    def check_sane_devel(self):
 
927
        return len(locate_file_contains("sane.h", '/usr/include', 'extern SANE_Status sane_init'))
 
928
 
 
929
 
 
930
    def check_xsane(self):
 
931
        if os.getenv('DISPLAY'):
 
932
            return check_tool('xsane --version', 0.9) # will fail if X not running...
 
933
        else:
 
934
            return bool(utils.which("xsane")) # ...so just see if it installed somewhere
 
935
 
 
936
 
 
937
    def check_scanimage(self):
 
938
        return check_tool('scanimage --version', 1.0)
 
939
 
 
940
 
 
941
    def check_gs(self):
 
942
        return check_tool('gs -v', 7.05)
 
943
 
 
944
 
 
945
    def check_pyqt4(self):
 
946
        if self.ui_toolkit == 'qt4':
 
947
            try:
 
948
                import PyQt4
 
949
            except ImportError:
 
950
                return False
 
951
            else:
 
952
                return True
 
953
 
 
954
        else:
 
955
            return False
 
956
 
 
957
 
 
958
    def check_pyqt4_dbus(self):
 
959
        if self.ui_toolkit == 'qt4':
 
960
            try:
 
961
                from dbus.mainloop.qt import DBusQtMainLoop
 
962
            except ImportError:
 
963
                return False
 
964
            else:
 
965
                return True
 
966
        else:
 
967
            return False
 
968
 
 
969
 
 
970
    def check_python_devel(self):
 
971
        return check_file('Python.h')
 
972
 
 
973
 
 
974
    def check_pynotify(self):
 
975
        try:
 
976
            import pynotify
 
977
        except ImportError:
 
978
            return False
 
979
 
 
980
        return True
 
981
 
 
982
 
 
983
    def check_python_dbus(self):
 
984
        log.debug("Checking for python-dbus (>= 0.80)...")
 
985
        try:
 
986
            import dbus
 
987
            try:
 
988
                ver = dbus.version
 
989
                log.debug("Version: %s" % '.'.join([str(x) for x in dbus.version]))
 
990
                return ver >= (0,80,0)
 
991
 
 
992
            except AttributeError:
 
993
                try:
 
994
                    ver = dbus.__version__
 
995
                    log.debug("Version: %s" % dbus.__version__)
 
996
                    log.debug("HPLIP requires dbus version > 0.80.")
 
997
                    return False
 
998
 
 
999
                except AttributeError:
 
1000
                    log.debug("Unknown version. HPLIP requires dbus version > 0.80.")
 
1001
                    return False
 
1002
 
 
1003
        except ImportError:
 
1004
            return False
 
1005
 
 
1006
 
 
1007
    def check_python_ctypes(self):
 
1008
        try:
 
1009
            import ctypes
 
1010
            return True
 
1011
        except ImportError:
 
1012
            return False
 
1013
 
 
1014
 
 
1015
    def check_dbus(self):
 
1016
        log.debug("Checking for dbus running and header files present (dbus-devel)...")
 
1017
        return check_ps(['dbus-daemon'])  and \
 
1018
            len(locate_file_contains("dbus-message.h", '/usr/include', 'dbus_message_new_signal'))
 
1019
 
 
1020
 
 
1021
    def check_cups_devel(self):
 
1022
        return check_file('cups.h') and bool(utils.which('lpr'))
 
1023
 
 
1024
 
 
1025
    def check_cups(self):
 
1026
        status, output = self.run('lpstat -r')
 
1027
        if status > 0:
 
1028
            log.debug("CUPS is not running.")
 
1029
            return False
 
1030
        else:
 
1031
            log.debug("CUPS is running.")
 
1032
            return True
 
1033
 
 
1034
 
 
1035
    def check_cups_image(self):
 
1036
      return check_file("raster.h", "/usr/include/cups")
 
1037
 
 
1038
 
 
1039
    def check_hplip(self):
 
1040
        log.debug("Checking for HPLIP...")
 
1041
        return locate_files('hplip.conf', '/etc/hp')
 
1042
 
 
1043
 
 
1044
    def check_hpssd(self):
 
1045
        log.debug("Checking for hpssd...")
 
1046
        return check_ps(['hpssd'])
 
1047
 
 
1048
 
 
1049
    def check_libtool(self):
 
1050
        log.debug("Checking for libtool...")
 
1051
        return check_tool('libtool --version')
 
1052
 
 
1053
 
 
1054
    def check_pil(self):
 
1055
        log.debug("Checking for PIL...")
 
1056
        try:
 
1057
            import Image
 
1058
            return True
 
1059
        except ImportError:
 
1060
            return False
 
1061
 
 
1062
 
 
1063
    def check_cupsddk(self):
 
1064
        log.debug("Checking for cups-ddk...")
 
1065
        # TODO: Compute these paths some way or another...
 
1066
        #return check_tool("/usr/lib/cups/driver/drv list") and os.path.exists("/usr/share/cupsddk/include/media.defs")
 
1067
        return (check_file('drv', "/usr/lib/cups/driver") or check_file('drv', "/usr/lib64/cups/driver")) and \
 
1068
            check_file('media.defs', "/usr/share/cupsddk/include")
 
1069
 
 
1070
 
 
1071
    def check_policykit(self):
 
1072
        log.debug("Checking for PolicyKit...")
 
1073
        return (check_file('PolicyKit.conf', "/etc/PolicyKit") and check_file('org.gnome.PolicyKit.AuthorizationManager.service', "/usr/share/dbus-1/services")) or (check_file('50-localauthority.conf', "/etc/polkit-1/localauthority.conf.d") and check_file('org.freedesktop.PolicyKit1.service', "/usr/share/dbus-1/system-services"))
 
1074
 
 
1075
    def check_pkg_mgr(self):
 
1076
        """
 
1077
            Check if any pkg mgr processes are running
 
1078
        """
 
1079
        log.debug("Searching for '%s' in running processes..." % self.package_mgrs)
 
1080
 
 
1081
        processes = get_process_list()
 
1082
 
 
1083
        for pid, cmdline in processes:
 
1084
            for p in self.package_mgrs:
 
1085
                if p in cmdline:
 
1086
                    for k in OK_PROCESS_LIST:
 
1087
                        #print k, cmdline
 
1088
                        if k in cmdline:
 
1089
                            break
 
1090
 
 
1091
                    else:
 
1092
                        log.debug("Found: %s (%d)" % (cmdline, pid))
 
1093
                        return (pid, cmdline)
 
1094
 
 
1095
        log.debug("Not found")
 
1096
        return (0, '')
 
1097
 
 
1098
 
 
1099
    def get_hplip_version(self):
 
1100
        self.version_description, self.version_public, self.version_internal = '', '', ''
 
1101
 
 
1102
        if self.mode == MODE_INSTALLER:
 
1103
            ac_init_pat = re.compile(r"""AC_INIT\(\[(.*?)\], *\[(.*?)\], *\[(.*?)\], *\[(.*?)\] *\)""", re.IGNORECASE)
 
1104
 
 
1105
            try:
 
1106
                config_in = open('./configure.in', 'r')
 
1107
            except IOError:
 
1108
                self.version_description, self.version_public, self.version_internal = \
 
1109
                    '', sys_conf.get('configure', 'internal-tag', '0.0.0'), prop.installed_version
 
1110
            else:
 
1111
                for c in config_in:
 
1112
                    if c.startswith("AC_INIT"):
 
1113
                        match_obj = ac_init_pat.search(c)
 
1114
                        self.version_description = match_obj.group(1)
 
1115
                        self.version_public = match_obj.group(2)
 
1116
                        self.version_internal = match_obj.group(3)
 
1117
                        name = match_obj.group(4)
 
1118
                        break
 
1119
 
 
1120
                config_in.close()
 
1121
 
 
1122
                if name != 'hplip':
 
1123
                    log.error("Invalid archive!")
 
1124
 
 
1125
 
 
1126
        else: # MODE_CHECK
 
1127
            try:
 
1128
                self.version_description, self.version_public, self.version_internal = \
 
1129
                    '', sys_conf.get('configure', 'internal-tag', '0.0.0'), prop.installed_version
 
1130
            except KeyError:
 
1131
                self.version_description, self.version_public, self.version_internal = '', '', ''
 
1132
 
 
1133
        return self.version_description, self.version_public, self.version_internal
 
1134
 
 
1135
 
 
1136
    def configure(self):
 
1137
        configure_cmd = './configure'
 
1138
        configuration = {}
 
1139
        dbus_avail = self.have_dependencies['dbus'] and self.have_dependencies['python-dbus']
 
1140
        configuration['network-build'] = self.selected_options['network']
 
1141
        configuration['fax-build'] = self.selected_options['fax'] and dbus_avail
 
1142
        configuration['dbus-build'] = dbus_avail
 
1143
        configuration['qt4'] = self.selected_options['gui_qt4']
 
1144
        configuration['scan-build'] = self.selected_options['scan']
 
1145
        configuration['doc-build'] = self.selected_options['docs']
 
1146
        configuration['policykit'] = self.selected_options['policykit']
 
1147
 
 
1148
        # Setup printer driver configure flags based on distro data...
 
1149
        if self.native_cups: # hpcups
 
1150
            configuration['hpcups-install'] = True
 
1151
            configuration['hpijs-install'] = False
 
1152
            configuration['foomatic-ppd-install'] = False
 
1153
            configuration['foomatic-drv-install'] = False
 
1154
 
 
1155
            if self.enable_ppds:
 
1156
                configuration['cups-ppd-install'] = True
 
1157
                configuration['cups-drv-install'] = False
 
1158
            else:
 
1159
                configuration['cups-ppd-install'] = False
 
1160
                configuration['cups-drv-install'] = True
 
1161
 
 
1162
        else: # HPIJS/foomatic
 
1163
            configuration['hpcups-install'] = False
 
1164
            configuration['hpijs-install'] = True
 
1165
            configuration['cups-ppd-install'] = False
 
1166
            configuration['cups-drv-install'] = False
 
1167
 
 
1168
            if self.enable_ppds:
 
1169
                configuration['foomatic-ppd-install'] = True
 
1170
                configuration['foomatic-drv-install'] = False
 
1171
            else:
 
1172
                configuration['foomatic-ppd-install'] = False
 
1173
                configuration['foomatic-drv-install'] = True
 
1174
 
 
1175
 
 
1176
        # ... and then override and adjust for consistency with passed in parameters
 
1177
        if self.enable is not None:
 
1178
            for c in self.enable:
 
1179
                if c == 'hpcups-install':
 
1180
                    configuration['hpijs-install'] = False
 
1181
                    configuration['foomatic-ppd-install'] = False
 
1182
                    configuration['foomatic-drv-install'] = False
 
1183
                elif c == 'hpijs-install':
 
1184
                    configuration['hpcups-install'] = False
 
1185
                    configuration['cups-ppd-install'] = False
 
1186
                    configuration['cups-drv-install'] = False
 
1187
                elif c == 'foomatic-ppd-install':
 
1188
                    configuration['foomatic-drv-install'] = False
 
1189
                elif c == 'foomatic-drv-install':
 
1190
                    configuration['foomatic-ppd-install'] = False
 
1191
                elif c == 'cups-ppd-install':
 
1192
                    configuration['cups-drv-install'] = False
 
1193
                elif c == 'cups-drv-install':
 
1194
                    configuration['cups-ppd-install'] = False
 
1195
 
 
1196
        if self.disable is not None:
 
1197
            for c in self.disable:
 
1198
                if c == 'hpcups-install':
 
1199
                    configuration['hpijs-install'] = True
 
1200
                    configuration['cups-ppd-install'] = False
 
1201
                    configuration['cups-drv-install'] = False
 
1202
                elif c == 'hpijs-install':
 
1203
                    configuration['hpcups-install'] = True
 
1204
                    configuration['foomatic-ppd-install'] = False
 
1205
                    configuration['foomatic-drv-install'] = False
 
1206
                elif c == 'foomatic-ppd-install':
 
1207
                    configuration['foomatic-drv-install'] = True
 
1208
                elif c == 'foomatic-drv-install':
 
1209
                    configuration['foomatic-ppd-install'] = True
 
1210
                elif c == 'cups-ppd-install':
 
1211
                    configuration['cups-drv-install'] = True
 
1212
                elif c == 'cups-drv-install':
 
1213
                    configuration['cups-ppd-install'] = True
 
1214
 
 
1215
        if self.ppd_dir is not None:
 
1216
            configure_cmd += ' --with-hpppddir=%s' % self.ppd_dir
 
1217
            
 
1218
        libdir_path = self.get_distro_ver_data('libdir_path',False)
 
1219
        if libdir_path and self.bitness == 64:
 
1220
            configure_cmd += ' --libdir=%s' % (libdir_path)
 
1221
        elif self.bitness == 64:
 
1222
            configure_cmd += ' --libdir=/usr/lib64'
 
1223
 
 
1224
        configure_cmd += ' --prefix=%s' % self.install_location
 
1225
 
 
1226
        if self.get_distro_ver_data('cups_path_with_bitness', False) and self.bitness == 64:
 
1227
            configure_cmd += ' --with-cupsbackenddir=/usr/lib64/cups/backend --with-cupsfilterdir=/usr/lib64/cups/filter'
 
1228
 
 
1229
        if self.get_distro_ver_data('acl_rules', False):
 
1230
            configure_cmd += ' --enable-udev-acl-rules'
 
1231
 
 
1232
        if self.enable is not None:
 
1233
            for c in self.enable:
 
1234
                configuration[c] = True
 
1235
 
 
1236
        if self.disable is not None:
 
1237
            for c in self.disable:
 
1238
                configuration[c] = False
 
1239
 
 
1240
        for c in configuration:
 
1241
            if configuration[c]:
 
1242
                configure_cmd += ' --enable-%s' % c
 
1243
            else:
 
1244
                configure_cmd += ' --disable-%s' % c
 
1245
 
 
1246
        return configure_cmd
 
1247
 
 
1248
    def configure_html(self):
 
1249
        configure_cmd = './configure'
 
1250
        configure_cmd += ' --prefix=/usr' 
 
1251
        configure_cmd += ' --with-hpppddir=%s' % self.ppd_dir
 
1252
 
 
1253
        if self.bitness == 64:
 
1254
            configure_cmd += ' --libdir=/usr/lib64'
 
1255
 
 
1256
        self.ui_toolkit =  self.get_distro_ver_data('ui_toolkit') 
 
1257
        if self.ui_toolkit is not None and self.ui_toolkit == 'qt3':
 
1258
            configure_cmd += ' --enable-qt3 --disable-qt4'
 
1259
        else:
 
1260
            configure_cmd += ' --enable-qt4'
 
1261
 
 
1262
        self.native_cups =  self.get_distro_ver_data('native_cups')
 
1263
        if self.native_cups is not None and self.native_cups == 1:
 
1264
            configure_cmd += ' --enable-hpcups-install --enable-cups-drv-install --enable-cups-ppd-install --disable-hpijs-install --disable-foomatic-drv-install --disable-foomatic-ppd-install --disable-foomatic-rip-hplip-install' 
 
1265
        else:
 
1266
            configure_cmd += ' --disable-hpcups-install --disable-cups-drv-install --disable-cups-ppd-install --enable-hpijs-install --enable-foomatic-drv-install --enable-foomatic-ppd-install --enable-foomatic-rip-hplip-install' 
 
1267
 
 
1268
        self.fax_supported =  self.get_distro_ver_data('fax_supported')
 
1269
        if self.fax_supported is None:
 
1270
            configure_cmd += ' --disable-fax-build --disable-dbus-build'
 
1271
        else:
 
1272
            configure_cmd += ' --enable-fax-build --enable-dbus-build'
 
1273
 
 
1274
        self.network_supported = self.get_distro_ver_data('network_supported')
 
1275
        if self.network_supported is None:
 
1276
            configure_cmd += ' --disable-network-build'
 
1277
        else:
 
1278
            configure_cmd += ' --enable-network-build'
 
1279
          
 
1280
        self.scan_supported = self.get_distro_ver_data('scan_supported')
 
1281
        if self.scan_supported is None:
 
1282
            configure_cmd += ' --disable-scan-build'
 
1283
        else:
 
1284
            configure_cmd += ' --enable-scan-build'
 
1285
  
 
1286
        self.policykit = self.get_distro_ver_data('policykit')
 
1287
        if self.policykit is not None and self.policykit == 1:
 
1288
            configure_cmd += ' --enable-policykit'
 
1289
        else:
 
1290
            configure_cmd += ' --disable-policykit'
 
1291
        
 
1292
        return configure_cmd
 
1293
 
 
1294
    def configure_qt4(self):
 
1295
        configure_cmd = './configure'
 
1296
        configure_cmd += ' --prefix=/usr'
 
1297
        configure_cmd += ' --with-hpppddir=%s' % self.ppd_dir
 
1298
 
 
1299
        if self.bitness == 64:
 
1300
            configure_cmd += ' --libdir=/usr/lib64'
 
1301
 
 
1302
        self.ui_toolkit =  self.get_distro_ver_data('ui_toolkit')
 
1303
        if self.ui_toolkit is not None and self.ui_toolkit == 'qt3':
 
1304
            configure_cmd += ' --enable-qt3 --disable-qt4'
 
1305
        else:
 
1306
            configure_cmd += ' --enable-qt4'
 
1307
 
 
1308
        self.native_cups =  self.get_distro_ver_data('native_cups')
 
1309
        self.ppd_install = self.get_distro_ver_data('ppd_install')
 
1310
        if self.native_cups is not None and self.native_cups == 1:
 
1311
            configure_cmd += ' --enable-hpcups-install'
 
1312
            if self.ppd_install == 'drv':
 
1313
                configure_cmd += ' --enable-cups-drv-install --disable-cups-ppd-install'
 
1314
            else:
 
1315
                configure_cmd += ' --enable-cups-ppd-install --disable-cups-drv-install'
 
1316
            configure_cmd += ' --disable-hpijs-install --disable-foomatic-drv-install --disable-foomatic-ppd-install --disable-foomatic-rip-hplip-install'
 
1317
        else:
 
1318
            configure_cmd += ' --enable-hpijs-install'
 
1319
            if self.ppd_install == 'drv':
 
1320
                configure_cmd += ' --enable-foomatic-drv-install --disable-foomatic-ppd-install'
 
1321
            else:
 
1322
                configure_cmd += ' --enable-foomatic-ppd-install --disable-foomatic-drv-install'
 
1323
            configure_cmd += ' --enable-foomatic-rip-hplip-install --disable-hpcups-install --disable-cups-drv-install --disable-cups-ppd-install'
 
1324
 
 
1325
        self.fax_supported =  self.get_distro_ver_data('fax_supported')
 
1326
        if self.fax_supported is None:
 
1327
            configure_cmd += ' --disable-fax-build --disable-dbus-build'
 
1328
        else:
 
1329
            configure_cmd += ' --enable-fax-build --enable-dbus-build'
 
1330
 
 
1331
        self.network_supported = self.get_distro_ver_data('network_supported')
 
1332
        if self.network_supported is None:
 
1333
            configure_cmd += ' --disable-network-build'
 
1334
        else:
 
1335
            configure_cmd += ' --enable-network-build'
 
1336
 
 
1337
        self.scan_supported = self.get_distro_ver_data('scan_supported')
 
1338
        if self.scan_supported is None:
 
1339
            configure_cmd += ' --disable-scan-build'
 
1340
        else:
 
1341
            configure_cmd += ' --enable-scan-build'
 
1342
 
 
1343
        self.policykit = self.get_distro_ver_data('policykit')
 
1344
        if self.policykit is not None and self.policykit == 1:
 
1345
            configure_cmd += ' --enable-policykit'
 
1346
        else:
 
1347
            configure_cmd += ' --disable-policykit'
 
1348
 
 
1349
        return configure_cmd
 
1350
 
 
1351
 
 
1352
    def restart_cups(self):
 
1353
        if os.path.exists('/etc/init.d/cups'):
 
1354
            cmd = self.su_sudo() % '/etc/init.d/cups restart'
 
1355
 
 
1356
        elif os.path.exists('/etc/init.d/cupsys'):
 
1357
            cmd = self.su_sudo() % '/etc/init.d/cupsys restart'
 
1358
 
 
1359
        else:
 
1360
            cmd = self.su_sudo() % 'killall -HUP cupsd'
 
1361
 
 
1362
        self.run(cmd)
 
1363
 
 
1364
 
 
1365
    def stop_hplip(self):
 
1366
        return self.su_sudo() % "/etc/init.d/hplip stop"
 
1367
 
 
1368
 
 
1369
    def su_sudo(self):
 
1370
        if os.geteuid() == 0:
 
1371
            return '%s'
 
1372
        else:
 
1373
            try:
 
1374
                cmd = self.distros[self.distro_name]['su_sudo']
 
1375
            except KeyError:
 
1376
                cmd = 'su'
 
1377
 
 
1378
            if cmd == 'su':
 
1379
                return 'su -c "%s"'
 
1380
            else:
 
1381
                return 'sudo %s'
 
1382
 
 
1383
    def su_sudo_str(self):
 
1384
        return self.get_distro_data('su_sudo', 'su')
 
1385
 
 
1386
 
 
1387
    def build_cmds(self):
 
1388
        return [self.configure(),
 
1389
                'make clean',
 
1390
                'make',
 
1391
                self.su_sudo() % 'make install']
 
1392
 
 
1393
 
 
1394
    def get_distro_ver_data(self, key, default=None):
 
1395
        try:
 
1396
            return self.distros[self.distro_name]['versions'][self.distro_version].get(key, None) or \
 
1397
                self.distros[self.distro_name].get(key, None) or default
 
1398
        except KeyError:
 
1399
            return default
 
1400
 
 
1401
        return value
 
1402
 
 
1403
 
 
1404
    def get_distro_data(self, key, default=None):
 
1405
        try:
 
1406
            return self.distros[self.distro_name].get(key, None) or default
 
1407
        except KeyError:
 
1408
            return default
 
1409
 
 
1410
 
 
1411
    def get_ver_data(self, key, default=None):
 
1412
        try:
 
1413
            return self.distros[self.distro_name]['versions'][self.distro_version].get(key, None) or default
 
1414
        except KeyError:
 
1415
            return default
 
1416
 
 
1417
        return value
 
1418
 
 
1419
 
 
1420
    def get_dependency_data(self, dependency):
 
1421
        dependency_cmds = self.get_ver_data("dependency_cmds", {})
 
1422
        dependency_data = dependency_cmds.get(dependency, {})
 
1423
        packages = dependency_data.get('packages', [])
 
1424
        commands = dependency_data.get('commands', [])
 
1425
        return packages, commands
 
1426
 
 
1427
 
 
1428
    def get_dependency_commands(self):
 
1429
        dd = self.dependencies.keys()
 
1430
        dd.sort()
 
1431
        commands_to_run = []
 
1432
        packages_to_install = []
 
1433
        overall_commands_to_run = []
 
1434
        for d in dd:
 
1435
            include = False
 
1436
            for opt in self.dependencies[d][1]:
 
1437
                if self.selected_options[opt]:
 
1438
                    include = True
 
1439
            if include:
 
1440
                pkgs, cmds = self.get_dependency_data(d)
 
1441
 
 
1442
                if pkgs:
 
1443
                    for p in pkgs:
 
1444
                        if not p in packages_to_install:
 
1445
                            packages_to_install.append(p)
 
1446
 
 
1447
                if cmds:
 
1448
                    commands_to_run.extend(cmds)
 
1449
 
 
1450
        package_mgr_cmd = self.get_distro_data('package_mgr_cmd')
 
1451
 
 
1452
        overall_commands_to_run.extend(commands_to_run)
 
1453
 
 
1454
        if package_mgr_cmd:
 
1455
            packages_to_install = ' '.join(packages_to_install)
 
1456
            overall_commands_to_run.append(utils.cat(package_mgr_cmd))
 
1457
 
 
1458
        if not overall_commands_to_run:
 
1459
            log.error("No cmds/pkgs")
 
1460
 
 
1461
        return overall_commands_to_run
 
1462
 
 
1463
 
 
1464
    def distro_known(self):
 
1465
        return self.distro != DISTRO_UNKNOWN and self.distro_version != DISTRO_VER_UNKNOWN
 
1466
 
 
1467
 
 
1468
    def distro_supported(self):
 
1469
        if self.mode == MODE_INSTALLER:
 
1470
            return self.distro != DISTRO_UNKNOWN and self.distro_version != DISTRO_VER_UNKNOWN and self.get_ver_data('supported', False)
 
1471
        else:
 
1472
            return True # For docs (manual install)
 
1473
 
 
1474
 
 
1475
    def sort_vers(self, x, y):
 
1476
        try:
 
1477
            return cmp(float(x), float(y))
 
1478
        except ValueError:
 
1479
            return cmp(x, y)
 
1480
 
 
1481
 
 
1482
    def running_as_root(self):
 
1483
        return os.geteuid() == 0
 
1484
 
 
1485
 
 
1486
    def show_release_notes_in_browser(self):
 
1487
        url = "file://%s" % os.path.join(os.getcwd(), 'doc', 'release_notes.html')
 
1488
        log.debug(url)
 
1489
        status, output = self.run("xhost +")
 
1490
        utils.openURL(url)
 
1491
 
 
1492
 
 
1493
    def count_num_required_missing_dependencies(self):
 
1494
        num_req_missing = 0
 
1495
        for d, desc, opt in self.missing_required_dependencies():
 
1496
            num_req_missing += 1
 
1497
        return num_req_missing
 
1498
 
 
1499
 
 
1500
    def count_num_optional_missing_dependencies(self):
 
1501
        num_opt_missing = 0
 
1502
        for d, desc, req, opt in self.missing_optional_dependencies():
 
1503
            num_opt_missing += 1
 
1504
        return num_opt_missing
 
1505
 
 
1506
 
 
1507
    def missing_required_dependencies(self): # missing req. deps in req. options
 
1508
        for opt in self.components[self.selected_component][1]:
 
1509
            if self.options[opt][0]: # required options
 
1510
                for d in self.options[opt][2]: # dependencies for option
 
1511
                    if self.dependencies[d][0]: # required option
 
1512
                        if not self.have_dependencies[d]: # missing
 
1513
                            log.debug("Missing required dependency: %s" % d)
 
1514
                            yield d, self.dependencies[d][2], opt
 
1515
                            # depend, desc, option
 
1516
 
 
1517
    def missing_optional_dependencies(self):
 
1518
        # missing deps in opt. options
 
1519
        for opt in self.components[self.selected_component][1]:
 
1520
            if not self.options[opt][0]: # not required option
 
1521
                if self.selected_options[opt]: # only for options that are ON
 
1522
                    for d in self.options[opt][2]: # dependencies
 
1523
                        if not self.have_dependencies[d]: # missing dependency
 
1524
                            log.debug("Missing optional dependency: %s" % d)
 
1525
                            yield d, self.dependencies[d][2], self.dependencies[d][0], opt
 
1526
                            # depend, desc, required_for_opt, opt
 
1527
 
 
1528
        # opt. deps in req. options
 
1529
        for opt in self.components[self.selected_component][1]:
 
1530
            if self.options[opt][0]: # required options
 
1531
                for d in self.options[opt][2]: # dependencies for option
 
1532
                    if d == 'cups-ddk':
 
1533
                        status, output = self.run('cups-config --version')
 
1534
                        import string
 
1535
                        if status == 0 and (string.count(output, '.') == 1 or string.count(output, '.') == 2):
 
1536
                            if string.count(output, '.') == 1:
 
1537
                                major, minor = string.split(output, '.', 2)
 
1538
                            if string.count(output, '.') == 2:
 
1539
                                major, minor, release = string.split(output, '.', 3)
 
1540
                            if len(minor) > 1 and minor[1] >= '0' and minor[1] <= '9':
 
1541
                                minor = ((ord(minor[0]) - ord('0')) * 10) + (ord(minor[1]) - ord('0'))
 
1542
                            else:
 
1543
                                minor = ord(minor[0]) - ord('0')
 
1544
                            if major > '1' or (major == '1' and minor >= 4):
 
1545
                                continue
 
1546
                    if not self.dependencies[d][0]: # optional dep
 
1547
                        if not self.have_dependencies[d]: # missing
 
1548
                            log.debug("Missing optional dependency: %s" % d)
 
1549
                            yield d, self.dependencies[d][2], self.dependencies[d][0], opt
 
1550
                            # depend, desc, option
 
1551
 
 
1552
    def select_options(self, answer_callback):
 
1553
        num_opt_missing = 0
 
1554
        # not-required options
 
1555
        for opt in self.components[self.selected_component][1]:
 
1556
            if not self.options[opt][0]: # not required
 
1557
                default = 'y'
 
1558
 
 
1559
                if not self.selected_options[opt]:
 
1560
                    default = 'n'
 
1561
 
 
1562
                self.selected_options[opt] = answer_callback(opt, self.options[opt][1], default)
 
1563
 
 
1564
                if self.selected_options[opt]: # only for options that are ON
 
1565
                    for d in self.options[opt][2]: # dependencies
 
1566
                        if not self.have_dependencies[d]: # missing dependency
 
1567
                            log.debug("Missing optional dependency: %s" % d)
 
1568
                            num_opt_missing += 1
 
1569
 
 
1570
        return num_opt_missing
 
1571
 
 
1572
 
 
1573
    def check_network_connection(self):
 
1574
        self.network_connected = False
 
1575
 
 
1576
        wget = utils.which("wget")
 
1577
        if wget:
 
1578
            wget = os.path.join(wget, "wget")
 
1579
            cmd = "%s --timeout=60 --output-document=- %s" % (wget, HTTP_GET_TARGET)
 
1580
            log.debug(cmd)
 
1581
            status, output = self.run(cmd)
 
1582
            log.debug("wget returned: %d" % status)
 
1583
            self.network_connected = (status == 0)
 
1584
 
 
1585
        else:
 
1586
            curl = utils.which("curl")
 
1587
            if curl:
 
1588
                curl = os.path.join(curl, "curl")
 
1589
                cmd = "%s --output - --connect-timeout 5 --max-time 10 %s" % (curl, HTTP_GET_TARGET)
 
1590
                log.debug(cmd)
 
1591
                status, output = self.run(cmd)
 
1592
                log.debug("curl returned: %d" % status)
 
1593
                self.network_connected = (status == 0)
 
1594
 
 
1595
            else:
 
1596
                ping = utils.which("ping")
 
1597
 
 
1598
                if ping:
 
1599
                    ping = os.path.join(ping, "ping")
 
1600
                    cmd = "%s -c1 -W1 -w10 %s" % (ping, PING_TARGET)
 
1601
                    log.debug(cmd)
 
1602
                    status, output = self.run(cmd)
 
1603
                    log.debug("ping returned: %d" % status)
 
1604
                    self.network_connected = (status == 0)
 
1605
 
 
1606
        return self.network_connected
 
1607
 
 
1608
 
 
1609
    def run_pre_install(self, callback=None):
 
1610
        pre_cmd = self.get_distro_ver_data('pre_install_cmd')
 
1611
        log.debug(pre_cmd)
 
1612
        if pre_cmd:
 
1613
            x = 1
 
1614
            for cmd in pre_cmd:
 
1615
                status, output = self.run(cmd)
 
1616
 
 
1617
                if status != 0:
 
1618
                    log.warn("An error occurred running '%s'" % cmd)
 
1619
 
 
1620
                if callback is not None:
 
1621
                    callback(cmd, "Pre-install step %d" % x)
 
1622
 
 
1623
                x += 1
 
1624
 
 
1625
            return True
 
1626
 
 
1627
        else:
 
1628
            return False
 
1629
 
 
1630
 
 
1631
    def run_pre_depend(self, callback=None):
 
1632
        pre_cmd = self.get_distro_ver_data('pre_depend_cmd')
 
1633
        log.debug(pre_cmd)
 
1634
        if pre_cmd:
 
1635
            x = 1
 
1636
            for cmd in pre_cmd:
 
1637
                status, output = self.run(cmd)
 
1638
 
 
1639
                if status != 0:
 
1640
                    log.warn("An error occurred running '%s'" % cmd)
 
1641
 
 
1642
                if callback is not None:
 
1643
                    callback(cmd, "Pre-depend step %d" % x)
 
1644
 
 
1645
                x += 1
 
1646
 
 
1647
 
 
1648
    def run_post_depend(self, callback=None):
 
1649
        post_cmd = self.get_distro_ver_data('post_depend_cmd')
 
1650
        log.debug(post_cmd)
 
1651
        if post_cmd:
 
1652
            x = 1
 
1653
            for cmd in post_cmd:
 
1654
                status, output = self.run(cmd)
 
1655
 
 
1656
                if status != 0:
 
1657
                    log.warn("An error occurred running '%s'" % cmd)
 
1658
 
 
1659
                if callback is not None:
 
1660
                    callback(cmd, "Post-depend step %d" % x)
 
1661
 
 
1662
                x += 1
 
1663
 
 
1664
 
 
1665
    def run_open_mdns_port(self, callback=None):
 
1666
        open_mdns_port_cmd = self.get_distro_ver_data('open_mdns_port')
 
1667
        log.debug(open_mdns_port_cmd)
 
1668
        if open_mdns_port_cmd:
 
1669
            x = 1
 
1670
            for cmd in open_mdns_port_cmd:
 
1671
                cmd = self.su_sudo() % cmd
 
1672
                status, output = self.run(cmd)
 
1673
 
 
1674
                if status != 0:
 
1675
                    log.warn("An error occurred running '%s'" % cmd)
 
1676
                    log.warn(output)
 
1677
 
 
1678
                if callback is not None:
 
1679
                    callback(cmd, "Open mDNS/Bonjour step %d" % x)
 
1680
 
 
1681
                x += 1
 
1682
 
 
1683
 
 
1684
    def pre_build(self):
 
1685
        cmds = []
 
1686
        if self.get_distro_ver_data('fix_ppd_symlink', False):
 
1687
            cmds.append(self.su_sudo() % 'python ./installer/fix_symlink.py')
 
1688
 
 
1689
        return cmds
 
1690
 
 
1691
 
 
1692
    def run_pre_build(self, callback=None):
 
1693
        x = 1
 
1694
        for cmd in self.pre_build():
 
1695
            status, output = self.run(cmd)
 
1696
            if callback is not None:
 
1697
                callback(cmd, "Pre-build step %d"  % x)
 
1698
 
 
1699
            x += 1
 
1700
 
 
1701
 
 
1702
    def run_post_build(self, callback=None):
 
1703
        x = 1
 
1704
        for cmd in self.post_build():
 
1705
            status, output = self.run(cmd)
 
1706
            if callback is not None:
 
1707
                callback(cmd, "Post-build step %d"  % x)
 
1708
 
 
1709
            x += 1
 
1710
 
 
1711
 
 
1712
    def post_build(self):
 
1713
        cmds = []
 
1714
        # Reload DBUS configuration if distro supports it and PolicyKit
 
1715
        # support installed
 
1716
        if self.reload_dbus and self.selected_options['policykit']:
 
1717
            cmds.append(self.su_sudo() % "sh /etc/init.d/dbus reload")
 
1718
            log.debug("Will reload DBUS configuration for PolicyKit support")
 
1719
 
 
1720
        # Kill any running hpssd.py instance from a previous install
 
1721
        if self.check_hpssd():
 
1722
            pid = get_ps_pid('hpssd')
 
1723
            if pid:
 
1724
                kill = os.path.join(utils.which("kill"), "kill") + " %d" % pid
 
1725
                cmds.append(self.su_sudo() % kill)
 
1726
 
 
1727
        # Add user to group if needed
 
1728
        # add_user_to_group=<usermod params> [TYPE_STRING] (leave empty for none) [ex. "-a -G sys" or "-G lp"]
 
1729
        add_user_to_group = self.get_distro_ver_data('add_user_to_group', '')
 
1730
        if add_user_to_group:
 
1731
            usermod = os.path.join(utils.which("usermod"), "usermod") + " %s %s" % (add_user_to_group, prop.username)
 
1732
            cmds.append(self.su_sudo() % usermod)
 
1733
 
 
1734
        return cmds
 
1735
 
 
1736
 
 
1737
    def logoff(self):
 
1738
        ok = False
 
1739
        pkill = utils.which('pkill')
 
1740
        if pkill:
 
1741
            cmd = "%s -KILL -u %s" % (os.path.join(pkill, "pkill"), prop.username)
 
1742
            cmd = self.su_sudo() % cmd
 
1743
            status, output = self.run(cmd)
 
1744
 
 
1745
            ok = (status == 0)
 
1746
 
 
1747
        return ok
 
1748
 
 
1749
 
 
1750
    def restart(self):
 
1751
        ok = False
 
1752
        shutdown = utils.which('shutdown')
 
1753
        if shutdown:
 
1754
            cmd = "%s -r now" % (os.path.join(shutdown, "shutdown"))
 
1755
            cmd = self.su_sudo() % cmd
 
1756
            status, output = self.run(cmd)
 
1757
 
 
1758
            ok = (status == 0)
 
1759
 
 
1760
        return ok
 
1761
 
 
1762
 
 
1763
    def run_hp_setup(self):
 
1764
        status = 0
 
1765
        hpsetup = utils.which("hp-setup")
 
1766
 
 
1767
        if hpsetup:
 
1768
            cmd = 'hp-setup'
 
1769
        else:
 
1770
            cmd = './setup.py'
 
1771
 
 
1772
        log.debug(cmd)
 
1773
        status, output = self.run(cmd)
 
1774
        return status == 0
 
1775
 
 
1776
 
 
1777
    def remove_hplip(self, callback=None):
 
1778
        failed = True
 
1779
        self.stop_pre_2x_hplip(callback)
 
1780
 
 
1781
        hplip_remove_cmd = self.get_distro_data('hplip_remove_cmd')
 
1782
        if hplip_remove_cmd:
 
1783
            if callback is not None:
 
1784
                callback(hplip_remove_cmd, "Removing old HPLIP version")
 
1785
 
 
1786
            status, output = self.run(hplip_remove_cmd)
 
1787
 
 
1788
            if status == 0:
 
1789
                self.hplip_present = self.check_hplip()
 
1790
 
 
1791
                if not self.hplip_present:
 
1792
                    failed = False
 
1793
 
 
1794
        return failed
 
1795
 
 
1796
 
 
1797
    def stop_pre_2x_hplip(self, callback=None):
 
1798
        hplip_init_script = '/etc/init.d/hplip stop'
 
1799
        if os.path.exists(hplip_init_script):
 
1800
            cmd = self.su_sudo() % hplip_init_script
 
1801
 
 
1802
            if callback is not None:
 
1803
                callback(cmd, "Stopping old HPLIP version.")
 
1804
 
 
1805
            status, output = self.run(cmd)
 
1806
 
 
1807
 
 
1808
 
 
1809
    def check_password(self, password_entry_callback, callback=None):
 
1810
        self.clear_su_sudo_password()
 
1811
        x = 1
 
1812
        while True:
 
1813
            self.password = password_entry_callback()
 
1814
            cmd = self.su_sudo() % "true"
 
1815
 
 
1816
            log.debug(cmd)
 
1817
 
 
1818
            status, output = self.run(cmd)
 
1819
 
 
1820
            log.debug(status)
 
1821
            log.debug(output)
 
1822
 
 
1823
            if status == 0:
 
1824
                if callback is not None:
 
1825
                    callback("", "Password accepted")
 
1826
                return True
 
1827
 
 
1828
            if callback is not None:
 
1829
                if "not in the sudoers file" in output:
 
1830
                    callback("", "%s is not in the sudoers file. Check privileges\n" %(os.getenv('USER')) )
 
1831
                    return False
 
1832
                else:    
 
1833
                    callback("", "Password incorrect. %d attempt(s) left." % (3-x ))
 
1834
 
 
1835
 
 
1836
            x += 1
 
1837
 
 
1838
            if x > 3:
 
1839
                return False
 
1840
 
 
1841
 
 
1842
    def clear_su_sudo_password(self):
 
1843
        if self.su_sudo_str() == 'sudo':
 
1844
            log.debug("Clearing password...")
 
1845
            self.run("sudo -K")
 
1846
 
 
1847
 
 
1848
 
 
1849
    # PLUGIN HELPERS
 
1850
 
 
1851
    def set_plugin_version(self):
 
1852
        self.plugin_version = prop.installed_version
 
1853
        log.debug("Plug-in version=%s" % self.plugin_version)
 
1854
        self.plugin_name = 'hplip-%s-plugin.run' % self.plugin_version
 
1855
        log.debug("Plug-in=%s" % self.plugin_name)
 
1856
 
 
1857
 
 
1858
    def get_plugin_conf_url(self):
 
1859
        url = "http://hplip.sf.net/plugin.conf"
 
1860
        home = sys_conf.get('dirs', 'home')
 
1861
 
 
1862
        if os.path.exists('/etc/hp/plugin.conf'):
 
1863
            url = "file:///etc/hp/plugin.conf"
 
1864
 
 
1865
        elif os.path.exists(os.path.join(home, 'plugin.conf')):
 
1866
            url = "file://" + os.path.join(home, 'plugin.conf')
 
1867
 
 
1868
        log.debug("Plugin.conf url: %s" % url)
 
1869
        return url
 
1870
 
 
1871
 
 
1872
    def get_plugin_info(self, plugin_conf_url, callback):
 
1873
        ok, size, checksum, timestamp, url = False, 0, 0, 0.0, ''
 
1874
 
 
1875
        if not self.create_plugin_dir():
 
1876
            log.error("Could not create plug-in directory.")
 
1877
            return '', 0, 0, 0, False
 
1878
 
 
1879
        local_conf_fp, local_conf = utils.make_temp_file()
 
1880
 
 
1881
        #if os.path.exists(local_conf):
 
1882
            #os.remove(local_conf)
 
1883
 
 
1884
        try:
 
1885
            try:
 
1886
                #filename, headers = urllib.urlretrieve(plugin_conf_url, local_conf, callback)
 
1887
                wget = utils.which("wget")
 
1888
                if wget:
 
1889
                    wget = os.path.join(wget, "wget")
 
1890
                    status, output = self.run("%s --timeout=60 --output-document=%s %s --cache=off" %(wget, local_conf, plugin_conf_url))
 
1891
                    if status:
 
1892
                        log.error("Plugin download failed with error code = %d" %status)
 
1893
                        return '', 0, 0, 0, False
 
1894
                else:
 
1895
                    log.error("Please install wget package to download the plugin.")
 
1896
                    return '', 0, 0, 0, False
 
1897
            except IOError, e:
 
1898
                log.error("I/O Error: %s" % e.strerror)
 
1899
                return '', 0, 0, 0, False
 
1900
 
 
1901
            if not os.path.exists(local_conf):
 
1902
                log.error("plugin.conf not found.")
 
1903
                return '', 0, 0, 0, False
 
1904
 
 
1905
            plugin_conf_p = ConfigParser.ConfigParser()
 
1906
 
 
1907
            try:
 
1908
                plugin_conf_p.read(local_conf)
 
1909
            except (ConfigParser.MissingSectionHeaderError, ConfigParser.ParsingError):
 
1910
                log.error("Error parsing file - 404 error?")
 
1911
                return '', 0, 0, 0, False
 
1912
 
 
1913
            try:
 
1914
                url = plugin_conf_p.get(self.plugin_version, 'url')
 
1915
                size = plugin_conf_p.getint(self.plugin_version, 'size')
 
1916
                checksum = plugin_conf_p.get(self.plugin_version, 'checksum')
 
1917
                timestamp = plugin_conf_p.getfloat(self.plugin_version, 'timestamp')
 
1918
                ok = True
 
1919
            except (KeyError, ConfigParser.NoSectionError):
 
1920
                log.error("Error reading plugin.conf: Missing section [%s]" % self.plugin_version)
 
1921
                return '', 0, 0, 0, False
 
1922
 
 
1923
        finally:
 
1924
            os.close(local_conf_fp)
 
1925
            os.remove(local_conf)
 
1926
 
 
1927
        return url, size, checksum, timestamp, ok
 
1928
 
 
1929
 
 
1930
    def create_plugin_dir(self):
 
1931
        if not os.path.exists(self.plugin_path):
 
1932
            try:
 
1933
                log.debug("Creating plugin directory: %s" % self.plugin_path)
 
1934
                os.umask(0)
 
1935
                os.makedirs(self.plugin_path, 0755)
 
1936
                return True
 
1937
            except (OSError, IOError), e:
 
1938
                log.error("Unable to create directory: %s" % e.strerror)
 
1939
                return False
 
1940
 
 
1941
        return True
 
1942
 
 
1943
 
 
1944
    def isErrorPage(self, page):
 
1945
        """
 
1946
        Example code from David Mertz' Text Processing in Python.
 
1947
        Released in the Public Domain.
 
1948
        """
 
1949
        err_score = 0.0
 
1950
 
 
1951
        for pat, prob in err_pats.items():
 
1952
            if err_score > 0.9: break
 
1953
            if re.search(pat, page):
 
1954
                err_score += prob
 
1955
 
 
1956
        log.debug("File error page score: %f" % (err_score))
 
1957
 
 
1958
        return err_score > 0.50
 
1959
 
 
1960
 
 
1961
    def download_plugin(self, url, size, checksum, timestamp, callback=None):
 
1962
        log.debug("Downloading %s plug-in file from '%s' to '%s'..." % (self.plugin_version, url, self.plugin_path))
 
1963
 
 
1964
        if not self.create_plugin_dir():
 
1965
            return PLUGIN_INSTALL_ERROR_DIRECTORY_ERROR, self.plugin_path
 
1966
 
 
1967
        plugin_file = os.path.join(self.plugin_path, self.plugin_name)
 
1968
 
 
1969
 
 
1970
        #Check whether plugin is accessible in Openprinting.org website otherwise dowload plugin from alternate location.
 
1971
        wget = utils.which("wget")
 
1972
        if wget:
 
1973
            wget = os.path.join(wget, "wget")
 
1974
            cmd = "%s --cache=off -P %s %s" % (wget,self.plugin_path,url)
 
1975
            log.debug(cmd)
 
1976
            status, output = self.run(cmd)
 
1977
            log.debug("wget returned: %d" % status)
 
1978
 
 
1979
        try:
 
1980
            if (status != 0) and 'file://' not in url:
 
1981
                url = os.path.join(PLUGIN_FALLBACK_LOCATION, self.plugin_name)
 
1982
                log.info("Plugin is not accessible. Trying to download it from fallback location: [%s]" % url)
 
1983
                cmd = "%s --cache=off -P %s %s" % (wget,self.plugin_path,url)
 
1984
                log.debug(cmd)
 
1985
                status, output = self.run(cmd)
 
1986
            if 'file://' in url:  
 
1987
                filename, headers = urllib.urlretrieve(url, plugin_file, callback)
 
1988
        except IOError, e:
 
1989
            log.error("Plug-in download failed: %s" % e.strerror)
 
1990
            return PLUGIN_INSTALL_ERROR_PLUGIN_FILE_NOT_FOUND, e.strerror
 
1991
 
 
1992
        if self.isErrorPage(file(plugin_file, 'r').read(1024)):
 
1993
            log.debug(file(plugin_file, 'r').read(1024))
 
1994
            os.remove(plugin_file)
 
1995
            return PLUGIN_INSTALL_ERROR_PLUGIN_FILE_NOT_FOUND, -1
 
1996
 
 
1997
        calc_checksum = get_checksum(file(plugin_file, 'r').read())
 
1998
        log.debug("D/L file checksum=%s" % calc_checksum)
 
1999
 
 
2000
        # Try to download and check the GPG digital signature
 
2001
        digsig_url = url + '.asc'
 
2002
        digsig_file = plugin_file + '.asc'
 
2003
 
 
2004
        log.debug("Downloading %s plug-in digital signature file from '%s' to '%s'..." % (self.plugin_version, digsig_url, digsig_file))
 
2005
 
 
2006
        try:
 
2007
                        if 'file://' in url:
 
2008
                                filename, headers = urllib.urlretrieve(digsig_url, digsig_file, callback)
 
2009
                        else:
 
2010
                                cmd = "%s --cache=off -P %s %s" % (wget,self.plugin_path,digsig_url)
 
2011
                                log.debug(cmd)
 
2012
                                status, output = self.run(cmd)
 
2013
        except IOError, e:
 
2014
            log.error("Plug-in GPG file [%s] download failed: %s" % (digsig_url,e.strerror))
 
2015
            return PLUGIN_INSTALL_ERROR_DIGITAL_SIG_NOT_FOUND, e.strerror
 
2016
 
 
2017
        if self.isErrorPage(file(digsig_file, 'r').read(1024)):
 
2018
            log.debug(file(digsig_file, 'r').read())
 
2019
            os.remove(digsig_file)
 
2020
            return PLUGIN_INSTALL_ERROR_DIGITAL_SIG_NOT_FOUND, -1
 
2021
 
 
2022
        gpg = utils.which('gpg')
 
2023
        if gpg:
 
2024
            gpg = os.path.join(gpg, 'gpg')
 
2025
            cmd = '%s --no-permission-warning --keyserver pgp.mit.edu --recv-keys 0xA59047B9' % gpg
 
2026
            log.info("Receiving digital keys: %s" % cmd)
 
2027
            status, output = self.run(cmd)
 
2028
            log.debug(output)
 
2029
 
 
2030
            if status != 0:
 
2031
                return PLUGIN_INSTALL_ERROR_UNABLE_TO_RECV_KEYS, status
 
2032
 
 
2033
            cmd = '%s --no-permission-warning --verify %s %s' % (gpg, digsig_file, plugin_file)
 
2034
            log.debug("Verifying plugin with digital keys: %s" % cmd)
 
2035
            status, output = self.run(cmd)
 
2036
            log.debug(output)
 
2037
            log.debug("%s status: %d" % (gpg, status))
 
2038
 
 
2039
            if status != 0:
 
2040
                return PLUGIN_INSTALL_ERROR_DIGITAL_SIG_BAD, status
 
2041
 
 
2042
 
 
2043
        return PLUGIN_INSTALL_ERROR_NONE, plugin_file
 
2044
 
 
2045
#
 
2046
# return value:
 
2047
# '-1' --> PLUGIN_VERSION_MISMATCH -->version mismatch
 
2048
# '0' --> PLUGIN_NOT_INSTALLED        --> not installed
 
2049
# '1' --> PLUGIN_INSTALLED
 
2050
 
 
2051
    def check_for_plugin(self):
 
2052
        sys_state.read()
 
2053
        plugin_state = sys_state.get('plugin', 'installed', PLUGIN_NOT_INSTALLED)
 
2054
        if plugin_state !=  PLUGIN_NOT_INSTALLED and self.check_plugin_version() is False:
 
2055
            log.debug("Plug-in version mismatch. Need to install plugin again")
 
2056
            plugin_state = PLUGIN_VERSION_MISMATCH
 
2057
        elif plugin_state == PLUGIN_INSTALLED:
 
2058
            log.debug("Plugin is installed")
 
2059
        else:
 
2060
            log.debug("Plugin is not installed")
 
2061
 
 
2062
        # cross checking so files present        or not.
 
2063
        if plugin_state != PLUGIN_NOT_INSTALLED:
 
2064
            Scan_sts =self.check_scanner_plugin_files()
 
2065
            Fax_sts = self.check_fax_plugin_files() 
 
2066
            Prnt_sts = self.check_printer_plugin_files()
 
2067
            if Scan_sts!= PLUGIN_STATUS_FILES_PRESENT or  Fax_sts!= PLUGIN_STATUS_FILES_PRESENT or Prnt_sts != PLUGIN_STATUS_FILES_PRESENT:
 
2068
                log.debug("Plug-in files might be corrupted. Re-install plug-in")
 
2069
                plugin_state = PLUGIN_VERSION_MISMATCH
 
2070
 
 
2071
        return plugin_state
 
2072
 
 
2073
    def check_plugin_version(self):
 
2074
        sys_state.read()
 
2075
        plugin_installed_version = sys_state.get('plugin','version', '0.0.0')
 
2076
        hplip_version = sys_conf.get('hplip', 'version', '0.0.0')
 
2077
        if plugin_installed_version == hplip_version:
 
2078
            return True
 
2079
        else:
 
2080
            return False
 
2081
 
 
2082
 
 
2083
 
 
2084
    def check_printer_plugin_files(self):
 
2085
        ret_val = None
 
2086
        home = sys_conf.get('dirs', 'home')
 
2087
        printer_so_dir= home+"/prnt/plugins/"
 
2088
        ret_val = self.check_so_exists(printer_so_dir, 'lj.so', "Printer",ret_val)
 
2089
        return ret_val
 
2090
 
 
2091
 
 
2092
    def check_scanner_plugin_files(self):
 
2093
        ret_val = None
 
2094
        home = sys_conf.get('dirs', 'home')
 
2095
        scan_so_files_list =['bb_marvell.so' , 'bb_soapht.so' , 'bb_soap.so']
 
2096
 
 
2097
        cnt=0
 
2098
        scanner_so_dir= home+'/scan/plugins/'
 
2099
        while cnt < len(scan_so_files_list):
 
2100
            ret_val = self.check_so_exists(scanner_so_dir, scan_so_files_list[cnt], "Scanner",ret_val)
 
2101
            cnt += 1
 
2102
        return ret_val 
 
2103
 
 
2104
 
 
2105
 
 
2106
    def check_fax_plugin_files(self):
 
2107
        ret_val = None
 
2108
        home = sys_conf.get('dirs', 'home')
 
2109
        fax_so_dir= home+"/fax/plugins/"
 
2110
        ret_val = self.check_so_exists(fax_so_dir,'fax_marvell.so' ,"Fax",ret_val)
 
2111
        return ret_val 
 
2112
 
 
2113
 
 
2114
    def check_so_exists(self, sym_link_dir, so_file, functionType, Pre_ret_val):
 
2115
        ret_val = Pre_ret_val
 
2116
        sym_link_file = sym_link_dir + so_file
 
2117
        if not os.path.exists(sym_link_file):
 
2118
            log.debug("Either %s file is not present or symbolic link is missing: %s" %(functionType, sym_link_file))
 
2119
            user_conf.set(functionType+'_plugins', so_file,'Not_Found')
 
2120
            if ret_val == None:
 
2121
                ret_val= PLUGIN_STATUS_FILES_NOT_PRESENT
 
2122
            elif ret_val == PLUGIN_STATUS_FILES_PRESENT:
 
2123
                ret_val = PLUGIN_STATUS_PARTIAL_FILES_PRESENT
 
2124
        else:
 
2125
            # capturing real file path
 
2126
            if os.path.islink(sym_link_file):
 
2127
                real_file = os.path.realpath(sym_link_file)
 
2128
            else:
 
2129
                real_file = sym_link_file
 
2130
 
 
2131
            if not os.path.exists(real_file):
 
2132
                log.debug("%s Plugin file is missing: %s" % (functionType, real_file))
 
2133
                user_conf.set(functionType+'_plugins', so_file,'Not_Found')
 
2134
                if ret_val == None:
 
2135
                    ret_val= PLUGIN_STATUS_FILES_NOT_PRESENT
 
2136
                elif ret_val == PLUGIN_STATUS_FILES_PRESENT:
 
2137
                    ret_val = PLUGIN_STATUS_PARTIAL_FILES_PRESENT
 
2138
            elif (os.stat(sym_link_file).st_mode & 72) != 72:
 
2139
                user_conf.set(functionType+'_plugins', so_file,'Permissin_Error')
 
2140
                log.debug("%s Plugin file doesn't have user/group execute permission: %s" % (functionType,sym_link_file))
 
2141
                if ret_val == None:
 
2142
                    ret_val= PLUGIN_STATUS_FILES_NOT_PRESENT
 
2143
                elif ret_val == PLUGIN_STATUS_FILES_PRESENT:
 
2144
                    ret_val = PLUGIN_STATUS_PARTIAL_FILES_PRESENT
 
2145
            else:
 
2146
                user_conf.set(functionType+'_plugins', so_file,'Present')
 
2147
                if ret_val == None:
 
2148
                    ret_val= PLUGIN_STATUS_FILES_PRESENT
 
2149
                elif ret_val == PLUGIN_STATUS_FILES_NOT_PRESENT:
 
2150
                    ret_val = PLUGIN_STATUS_PARTIAL_FILES_PRESENT
 
2151
 
 
2152
        log.debug("%s Plug-in file %s status: %d" % (functionType, sym_link_file, ret_val))
 
2153
        return ret_val
 
2154
 
 
2155
 
 
2156
 
 
2157
    def run_plugin(self, mode=GUI_MODE, callback=None):
 
2158
        plugin_file = os.path.join(self.plugin_path, self.plugin_name)
 
2159
 
 
2160
        if not os.path.exists(plugin_file):
 
2161
            return False
 
2162
 
 
2163
        if mode == GUI_MODE:
 
2164
            return os.system("sh %s --nox11 -- -u" % plugin_file) == 0
 
2165
        else:
 
2166
            if os.system("sh %s --nox11 -- -i" % plugin_file) == 0:
 
2167
                return True
 
2168
            else:
 
2169
                log.error("Python gobject/dbus may be not installed")
 
2170
                return False
 
2171
 
 
2172
 
 
2173
    def delete_plugin(self):
 
2174
        plugin_file = os.path.join(self.plugin_path, self.plugin_name)
 
2175
        digsig_file = plugin_file + ".asc"
 
2176
 
 
2177
        if os.path.exists(plugin_file):
 
2178
            os.unlink(plugin_file)
 
2179
        if os.path.exists(digsig_file):
 
2180
            os.unlink(digsig_file)
 
2181
 
 
2182
 
 
2183
    def is_auto_installer_support(self):
 
2184
        if not self.distro_name:
 
2185
            self.get_distro()
 
2186
            self.distro_name = self.distros_index[self.distro]
 
2187
 
 
2188
        if self.distro_name and self.distro_name in ("ubuntu","debian","suse","fedora"):
 
2189
            log.debug("Auto installation is supported for Distro =%s version =%s "%(self.distro_name, self.distro_version))
 
2190
            return True
 
2191
        else:
 
2192
            log.debug("Auto installation is not supported for Distro =%s version =%s "%(self.distro_name, self.distro_version))
 
2193
            return False
 
2194
 
 
2195
    
 
2196
    def uninstall(self,mode = INTERACTIVE_MODE, callback=None):
 
2197
        checkSudo = False
 
2198
        if os.getuid() != 0:
 
2199
            checkSudo = True
 
2200
#            log.error("To run 'hp-uninstall' utility, you must have root privileges.")
 
2201
#            return False
 
2202
 
 
2203
        home_dir= sys_conf.get("dirs","home","")
 
2204
        version= sys_conf.get("hplip","version","0.0.0")
 
2205
        if home_dir is "":
 
2206
            log.error("HPLIP is not installed.")
 
2207
            return False
 
2208
    
 
2209
        if mode != NON_INTERACTIVE_MODE:
 
2210
            ok,choice = tui.enter_choice("\nAre you sure to uninstall HPLIP-%s (y=yes, n=no*)?:" %version,['y','n'],'n')
 
2211
            if not ok or choice == 'n':
 
2212
                return False
 
2213
 
 
2214
        hplip_remove_cmd = self.get_distro_data('hplip_remove_cmd')
 
2215
        log.debug("hplip_remove_cmd =%s "%hplip_remove_cmd)
 
2216
        #read conf file to enter into installed dir
 
2217
        log.info("Starting uninstallation...")
 
2218
 
 
2219
        plugin_state = sys_state.get('plugin', 'installed', PLUGIN_NOT_INSTALLED)
 
2220
        
 
2221
        # check systray is running?
 
2222
        status,output = utils.Is_Process_Running('hp-systray')
 
2223
        if status is True:
 
2224
            if mode != NON_INTERACTIVE_MODE:
 
2225
                ok,choice = tui.enter_choice("\nSome HPLIP applications are running. Press 'y' to close and proceed or Press 'n' to quit uninstall (y=yes*, n=no):",['y','n'],'y')
 
2226
                if not ok or choice =='n':
 
2227
                    log.info("Quiting HPLIP unininstallation. Close application(s) manually and run again.")
 
2228
                    return False
 
2229
        
 
2230
            try:
 
2231
                from dbus import SystemBus, lowlevel
 
2232
            except ImportError:
 
2233
                log.error("Unable to load DBus")
 
2234
                pass
 
2235
            else:
 
2236
                try:
 
2237
                    args = ['', '', EVENT_SYSTEMTRAY_EXIT, prop.username, 0, '', '']
 
2238
                    msg = lowlevel.SignalMessage('/', 'com.hplip.StatusService', 'Event')
 
2239
                    msg.append(signature='ssisiss', *args)
 
2240
                    log.debug("Sending close message to hp-systray ...")
 
2241
                    SystemBus().send_message(msg)
 
2242
                    time.sleep(0.5)
 
2243
                except:
 
2244
                    log.error("Failed to send DBus message to hp-systray/hp-toolbox.")
 
2245
                    pass
 
2246
    
 
2247
    
 
2248
        toolbox_status,output = utils.Is_Process_Running('hp-toolbox')
 
2249
        systray_status,output = utils.Is_Process_Running('hp-systray')
 
2250
        if toolbox_status is True or systray_status is True:
 
2251
            log.error("Failed to close HP-Toolbox/HP-Systray. Close manually and run hp-uninstall again.")
 
2252
            return False
 
2253
    
 
2254
        if hplip_remove_cmd:
 
2255
            self.remove_hplip(callback)
 
2256
 
 
2257
        #removing .hplip directory
 
2258
        cmd='find /home -name .hplip'
 
2259
        if checkSudo:
 
2260
            cmd= self.su_sudo() %cmd
 
2261
 
 
2262
        status, output=self.run(cmd)
 
2263
        if output is not None:
 
2264
            for p in output.splitlines():
 
2265
                if p.find("find:") != -1:
 
2266
                    continue
 
2267
 
 
2268
                cmd= RMDIR + " " + p
 
2269
                if checkSudo:
 
2270
                    cmd= self.su_sudo() %cmd
 
2271
                log.debug("Removing .hplip folder cmd = %s " %cmd)
 
2272
                status, output=self.run(cmd)
 
2273
                if 0 != status:
 
2274
                    log.debug("Failed to remove directory=%s "%p)
 
2275
 
 
2276
        #remove the binaries and libraries
 
2277
        pat=re.compile(r"""(.*)share\/hplip""")
 
2278
        base =pat.match(home_dir)
 
2279
        usrbin_dir=None
 
2280
        if base is not None:
 
2281
            usrbin_dir= base.group(1) + "bin/"
 
2282
            usrlib_dir= base.group(1) + "lib/"
 
2283
            cnt = 0
 
2284
            while cnt <len (BINS_LIST ):
 
2285
                cmd = RM + " " + usrbin_dir + BINS_LIST[cnt]
 
2286
                if checkSudo:
 
2287
                    cmd= self.su_sudo() %cmd
 
2288
                    
 
2289
                log.debug("Removing binaries cmd = %s " %cmd)
 
2290
                status, output=self.run(cmd)
 
2291
                if 0 != status:
 
2292
                    log.debug("Failed to remove '%s' binary." %(usrbin_dir + BINS_LIST[cnt]))
 
2293
                cnt += 1
 
2294
 
 
2295
            cnt =0
 
2296
            while cnt <len (LIBS_LIST ):
 
2297
                cmd = RM + " " + usrlib_dir + LIBS_LIST[cnt]
 
2298
                if checkSudo:
 
2299
                    cmd= self.su_sudo() %cmd
 
2300
 
 
2301
                log.debug("Removing library cmd = %s " %cmd)
 
2302
                status, output=self.run(cmd)
 
2303
                if 0 != status:
 
2304
                    log.debug("Failed to remove '%s' library." %(usrlib_dir + LIBS_LIST[cnt]))
 
2305
                cnt += 1
 
2306
    
 
2307
 
 
2308
        remove_plugins = False
 
2309
        if mode != NON_INTERACTIVE_MODE and plugin_state !=  PLUGIN_NOT_INSTALLED:
 
2310
            ok,choice = tui.enter_choice("\nDo you want to remove HP proprietary plug-ins (y=yes*, n=no)?:",['y','n'],'y')
 
2311
            if ok and choice =='y':                
 
2312
                remove_plugins = True
 
2313
        else:
 
2314
            remove_plugins = True
 
2315
    
 
2316
        # removing HPLIP installed directories/files
 
2317
        cnt =0
 
2318
        while cnt < len(HPLIP_LIST): 
 
2319
            cmd=RMDIR + " " + home_dir+"/"+HPLIP_LIST[cnt]
 
2320
            if checkSudo:
 
2321
                cmd= self.su_sudo() %cmd
 
2322
 
 
2323
            log.debug("Removing hplip directory/file cmd= %s " %cmd)
 
2324
            status, output=self.run(cmd)
 
2325
            if 0 != status:
 
2326
                log.debug("Failed to remove hplip directory/file=%s "% (home_dir+"/"+HPLIP_LIST[cnt]))
 
2327
            cnt +=1
 
2328
        
 
2329
        # removing configuration files
 
2330
        cnt= 0
 
2331
        while cnt < len(FILES_LIST):
 
2332
            cmd = RMDIR + " " + FILES_LIST[cnt]
 
2333
            if checkSudo:
 
2334
                cmd= self.su_sudo() %cmd
 
2335
            log.debug("Removing conf files cmd= %s" %(cmd))
 
2336
            status, output=self.run(cmd)
 
2337
            if 0 != status:
 
2338
                log.debug("Failed to remove '%s' file" %FILES_LIST[cnt])
 
2339
            cnt += 1
 
2340
        # removing Plug-in files   
 
2341
        if remove_plugins == True:
 
2342
            cnt =0
 
2343
            while cnt < len(PLUGIN_LIST): 
 
2344
                cmd=RMDIR + " " + home_dir+"/"+PLUGIN_LIST[cnt]
 
2345
                if checkSudo:
 
2346
                    cmd= self.su_sudo() %cmd
 
2347
 
 
2348
                log.debug("Removing hplip Plug-in files cmd= %s " %cmd)
 
2349
                status, output=self.run(cmd)
 
2350
                if 0 != status:
 
2351
                    log.debug("Failed to remove plug-in directory/file=%s "% (home_dir+"/"+PLUGIN_LIST[cnt]))
 
2352
                cnt += 1
 
2353
            
 
2354
            cnt =0
 
2355
            while cnt < len(PLUGIN_STATE): 
 
2356
                cmd=RMDIR + " "+PLUGIN_STATE[cnt]
 
2357
                if checkSudo:
 
2358
                    cmd= self.su_sudo() %cmd
 
2359
 
 
2360
                log.debug("Removing hplip Plug-in file cmd= %s " %cmd)
 
2361
                status, output=self.run(cmd)
 
2362
                if 0 != status:
 
2363
                    log.debug("Failed to remove plug-in directory/file=%s "% (PLUGIN_STATE[cnt]))
 
2364
                cnt += 1
 
2365
 
 
2366
            cmd =RMDIR+ " "+home_dir
 
2367
            if checkSudo:
 
2368
                cmd= self.su_sudo() %cmd
 
2369
 
 
2370
            log.debug("Removing hplip directory/file cmd= %s " %cmd)
 
2371
            status, output=self.run(cmd)
 
2372
            if 0 != status:
 
2373
                log.debug("Failed to remove hplip directory=%s "% (home_dir))
 
2374
        
 
2375
        # removing HPLIP uninstall link
 
2376
        if usrbin_dir is not None:
 
2377
            cmd=RMDIR + " " + usrbin_dir+"hp-uninstall"
 
2378
            if checkSudo:
 
2379
                cmd= self.su_sudo() %cmd
 
2380
 
 
2381
            log.debug("Removing hplip binary cmd= %s " %cmd)
 
2382
            status, output=self.run(cmd)
 
2383
            if 0 != status:
 
2384
                log.debug("Failed to remove '%s' file" %(usrbin_dir+"hp-uninstall"))
 
2385
        log.info("HPLIP uninstallation is completed")
 
2386
        return True
 
2387