~matttbe/wicd/ubuntu_python27

« back to all changes in this revision

Viewing changes to .pc/18-dont_run_unexpected_files_in_scripts.patch/wicd/misc.py

  • Committer: Bazaar Package Importer
  • Author(s): David Paleino
  • Date: 2010-03-05 18:12:51 UTC
  • mfrom: (8.2.8 sid)
  • Revision ID: james.westby@ubuntu.com-20100305181251-0fcsn0sty5oy8wlq
Tags: 1.7.0+ds1-2
Fix RC bug: daemon doesn't start anymore because copy.deepcopy()
fails with the iniparse object, coming from 20-use_iniparse.patch.
Bug 568326 reopened. (Closes: #572599)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
""" misc - miscellaneous functions for wicd
 
2
 
 
3
This module contains a large variety of utility functions used
 
4
throughout wicd.
 
5
 
 
6
"""
 
7
 
 
8
#
 
9
#   Copyright (C) 2007 - 2009 Adam Blackburn
 
10
#   Copyright (C) 2007 - 2009 Dan O'Reilly
 
11
#
 
12
#   This program is free software; you can redistribute it and/or modify
 
13
#   it under the terms of the GNU General Public License Version 2 as
 
14
#   published by the Free Software Foundation.
 
15
#
 
16
#   This program is distributed in the hope that it will be useful,
 
17
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
#   GNU General Public License for more details.
 
20
#
 
21
#   You should have received a copy of the GNU General Public License
 
22
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
23
#
 
24
 
 
25
import os
 
26
import locale
 
27
import sys
 
28
import re
 
29
import gobject
 
30
from threading import Thread
 
31
from subprocess import Popen, STDOUT, PIPE, call
 
32
from commands import getoutput
 
33
from itertools import repeat, chain, izip
 
34
from pipes import quote
 
35
 
 
36
# wicd imports
 
37
import wpath
 
38
 
 
39
# Connection state constants
 
40
NOT_CONNECTED = 0
 
41
CONNECTING = 1
 
42
WIRELESS = 2
 
43
WIRED = 3
 
44
SUSPENDED = 4
 
45
 
 
46
# Automatic app selection constant
 
47
AUTO = 0
 
48
 
 
49
# DHCP Clients
 
50
DHCLIENT = 1
 
51
DHCPCD = 2
 
52
PUMP = 3
 
53
UDHCPC = 4
 
54
 
 
55
# Link detection tools
 
56
ETHTOOL = 1
 
57
MIITOOL = 2
 
58
 
 
59
# Route flushing tools
 
60
IP = 1
 
61
ROUTE = 2
 
62
 
 
63
# Graphical sudo apps
 
64
GKSUDO = 1
 
65
KDESU = 2
 
66
KTSUSS = 3
 
67
_sudo_dict = { 
 
68
    AUTO : "",
 
69
    GKSUDO : "gksudo",
 
70
    KDESU : "kdesu",
 
71
    KTSUSS: "ktsuss",
 
72
}
 
73
 
 
74
class WicdError(Exception):
 
75
    pass
 
76
    
 
77
 
 
78
def Run(cmd, include_stderr=False, return_pipe=False,
 
79
        return_obj=False, return_retcode=True):
 
80
    """ Run a command.
 
81
 
 
82
    Runs the given command, returning either the output
 
83
    of the program, or a pipe to read output from.
 
84
 
 
85
    keyword arguments --
 
86
    cmd - The command to execute
 
87
    include_std_err - Boolean specifying if stderr should
 
88
                      be included in the pipe to the cmd.
 
89
    return_pipe - Boolean specifying if a pipe to the
 
90
                  command should be returned.  If it is
 
91
                  False, all that will be returned is
 
92
                  one output string from the command.
 
93
    return_obj - If True, Run will return the Popen object
 
94
                 for the command that was run.
 
95
 
 
96
    """
 
97
    if not isinstance(cmd, list):
 
98
        cmd = to_unicode(str(cmd))
 
99
        cmd = cmd.split()
 
100
    if include_stderr:
 
101
        err = STDOUT
 
102
        fds = True
 
103
    else:
 
104
        err = None
 
105
        fds = False
 
106
    if return_obj:
 
107
        std_in = PIPE
 
108
    else:
 
109
        std_in = None
 
110
    
 
111
    # We need to make sure that the results of the command we run
 
112
    # are in English, so we set up a temporary environment.
 
113
    tmpenv = os.environ.copy()
 
114
    tmpenv["LC_ALL"] = "C"
 
115
    tmpenv["LANG"] = "C"
 
116
    
 
117
    try:
 
118
        f = Popen(cmd, shell=False, stdout=PIPE, stdin=std_in, stderr=err,
 
119
                  close_fds=fds, cwd='/', env=tmpenv)
 
120
    except OSError, e:
 
121
        print "Running command %s failed: %s" % (str(cmd), str(e))
 
122
        return ""
 
123
        
 
124
    if return_obj:
 
125
        return f
 
126
    if return_pipe:
 
127
        return f.stdout
 
128
    else:
 
129
        return f.communicate()[0]
 
130
    
 
131
def LaunchAndWait(cmd):
 
132
    """ Launches the given program with the given arguments, then blocks.
 
133
 
 
134
    cmd : A list contained the program name and its arguments.
 
135
 
 
136
    returns: The exit code of the process.
 
137
    
 
138
    """
 
139
    if not isinstance(cmd, list):
 
140
        cmd = to_unicode(str(cmd))
 
141
        cmd = cmd.split()
 
142
    p = Popen(cmd, shell=False, stdout=PIPE, stderr=STDOUT, stdin=None)
 
143
    return p.wait()
 
144
 
 
145
def IsValidIP(ip):
 
146
    """ Make sure an entered IP is valid. """
 
147
    if ip != None:
 
148
        if ip.count('.') == 3:
 
149
            ipNumbers = ip.split('.')
 
150
            for number in ipNumbers:
 
151
                if not number.isdigit() or int(number) > 255:
 
152
                    return False
 
153
            return ipNumbers
 
154
    return False
 
155
 
 
156
def PromptToStartDaemon():
 
157
    """ Prompt the user to start the daemon """
 
158
    daemonloc = wpath.sbin + 'wicd'
 
159
    sudo_prog = choose_sudo_prog()
 
160
    if not sudo_prog:
 
161
        return False
 
162
    if "gksu" in sudo_prog or "ktsuss" in sudo_prog:
 
163
        msg = '--message'
 
164
    else:
 
165
        msg = '--caption'
 
166
    sudo_args = [sudo_prog, msg, 
 
167
                 'Wicd needs to access your computer\'s network cards.',
 
168
                 daemonloc]
 
169
    os.spawnvpe(os.P_WAIT, sudo_prog, sudo_args, os.environ)
 
170
    return True
 
171
 
 
172
def RunRegex(regex, string):
 
173
    """ runs a regex search on a string """
 
174
    m = regex.search(string)
 
175
    if m:
 
176
        return m.groups()[0]
 
177
    else:
 
178
        return None
 
179
 
 
180
def WriteLine(my_file, text):
 
181
    """ write a line to a file """
 
182
    my_file.write(text + "\n")
 
183
 
 
184
def ExecuteScripts(scripts_dir, verbose=False, extra_parameters=()):
 
185
    """ Execute every executable file in a given directory. """
 
186
    if not os.path.exists(scripts_dir):
 
187
        return
 
188
    for obj in sorted(os.listdir(scripts_dir)):
 
189
        obj = os.path.abspath(os.path.join(scripts_dir, obj))
 
190
        if os.path.isfile(obj) and os.access(obj, os.X_OK):
 
191
            ExecuteScript(os.path.abspath(obj), verbose=verbose,
 
192
                          extra_parameters=extra_parameters)
 
193
 
 
194
def ExecuteScript(script, verbose=False, extra_parameters=()):
 
195
    """ Execute a command and send its output to the bit bucket. """
 
196
    extra_parameters = [ quote(s) for s in extra_parameters ]
 
197
    params = ' '.join(extra_parameters)
 
198
    # escape script name
 
199
    script = quote(script)
 
200
    if verbose:
 
201
        print "Executing %s with params %s" % (script, params)
 
202
    ret = call('%s %s > /dev/null 2>&1' % (script, params), shell=True)
 
203
    if verbose:
 
204
        print "%s returned %s" % (script, ret)
 
205
 
 
206
def ReadFile(filename):
 
207
    """ read in a file and return it's contents as a string """
 
208
    if not os.path.exists(filename):
 
209
        return None
 
210
    my_file = open(filename,'r')
 
211
    data = my_file.read().strip()
 
212
    my_file.close()
 
213
    return str(data)
 
214
 
 
215
def to_bool(var):
 
216
    """ Convert a string to type bool, but make "False"/"0" become False. """
 
217
    if var in ("False", "0"):
 
218
        var = False
 
219
    else:
 
220
        var = bool(var)
 
221
    return var
 
222
 
 
223
def Noneify(variable):
 
224
    """ Convert string types to either None or booleans"""
 
225
    #set string Nones to real Nones
 
226
    if variable in ("None", "", None):
 
227
        return None
 
228
    if variable in ("False", "0"):
 
229
        return False
 
230
    if variable in ("True", "1"):
 
231
        return True
 
232
    return variable
 
233
 
 
234
def ParseEncryption(network):
 
235
    """ Parse through an encryption template file
 
236
 
 
237
    Parses an encryption template, reading in a network's info
 
238
    and creating a config file for it
 
239
 
 
240
    """
 
241
    enctemplate = open(wpath.encryption + network["enctype"])
 
242
    template = enctemplate.readlines()
 
243
    config_file = "ap_scan=1\n"
 
244
    should_replace = False
 
245
    for index, line in enumerate(template):
 
246
        if not should_replace:
 
247
            if line.strip().startswith('---'):
 
248
                should_replace = True
 
249
        else:
 
250
            if line.strip().startswith("}"):
 
251
                # This is the last line, so we just write it.
 
252
                config_file = ''.join([config_file, line])
 
253
            elif "$_" in line: 
 
254
                cur_val = re.findall('\$_([A-Z0-9_]+)', line)
 
255
                if cur_val:
 
256
                    if cur_val[0] == 'SCAN':
 
257
                        #TODO should this be hardcoded?
 
258
                        line = line.replace("$_SCAN", "0")
 
259
                        config_file = ''.join([config_file, line])
 
260
                    else:
 
261
                        rep_val = network.get(cur_val[0].lower())
 
262
                        if rep_val:
 
263
                            line = line.replace("$_%s" % cur_val[0], 
 
264
                                                str(rep_val))
 
265
                            config_file = ''.join([config_file, line])
 
266
                        else:
 
267
                            print "Ignoring template line: '%s'" % line
 
268
                else:
 
269
                    print "Weird parsing error occurred"
 
270
            else:  # Just a regular entry.
 
271
                config_file = ''.join([config_file, line])
 
272
 
 
273
    # Write the data to the files then chmod them so they can't be read 
 
274
    # by normal users.
 
275
    file_loc = os.path.join(wpath.networks,
 
276
                            network['bssid'].replace(":", "").lower())
 
277
    f = open(file_loc, "w")
 
278
    os.chmod(file_loc, 0600)
 
279
    os.chown(file_loc, 0, 0)
 
280
    # We could do this above, but we'd like to read protect
 
281
    # them before we write, so that it can't be read.
 
282
    f.write(config_file)
 
283
    f.close()
 
284
 
 
285
def LoadEncryptionMethods():
 
286
    """ Load encryption methods from configuration files
 
287
 
 
288
    Loads all the encryption methods from the template files
 
289
    in /encryption/templates into a data structure.  To be
 
290
    loaded, the template must be listed in the "active" file.
 
291
 
 
292
    """
 
293
    try:
 
294
        enctypes = open(wpath.encryption + "active","r").readlines()
 
295
    except IOError, e:
 
296
        print "Fatal Error: template index file is missing."
 
297
        raise IOError(e)
 
298
    
 
299
    # Parse each encryption method
 
300
    encryptionTypes = []
 
301
    for enctype in enctypes:
 
302
        parsed_template = _parse_enc_template(enctype.strip())
 
303
        if parsed_template:
 
304
            encryptionTypes.append(parsed_template)
 
305
    return encryptionTypes
 
306
 
 
307
def __parse_field_ent(fields, field_type='require'):
 
308
    fields = fields.split(" ")
 
309
    ret = []
 
310
    # We need an even number of entries in the line for it to be valid.
 
311
    if (len(fields) % 2) != 0:
 
312
        return None
 
313
    else:
 
314
        for val, disp_val in grouper(2, fields, fillvalue=None):
 
315
            if val.startswith("*") or not disp_val.startswith("*"):
 
316
                return None
 
317
            ret.append([val, disp_val[1:]])
 
318
        return ret
 
319
 
 
320
def _parse_enc_template(enctype):
 
321
    """ Parse an encryption template. """
 
322
    def parse_ent(line, key):
 
323
        return line.replace(key, "").replace("=", "").strip()
 
324
 
 
325
    try:
 
326
        f = open(os.path.join(wpath.encryption, enctype), "r")
 
327
    except IOError:
 
328
        print "Failed to open template file %s" % enctype
 
329
        return None
 
330
 
 
331
    cur_type = {}
 
332
    cur_type["type"] = enctype
 
333
    cur_type["fields"] = []
 
334
    cur_type['optional'] = []
 
335
    cur_type['required'] = []
 
336
    cur_type['name'] = ""
 
337
    for index, line in enumerate(f):
 
338
        if line.startswith("name") and not cur_type["name"]:
 
339
            cur_type["name"] = parse_ent(line, "name")
 
340
        elif line.startswith("require"):
 
341
            cur_type["required"] = __parse_field_ent(parse_ent(line, "require"))
 
342
            if not cur_type["required"]:
 
343
                # An error occured parsing the require line.
 
344
                print "Invalid 'required' line found in template %s" % enctype
 
345
                continue
 
346
        elif line.startswith("optional"):
 
347
            cur_type["optional"] = __parse_field_ent(parse_ent(line,
 
348
                                                               "optional"),
 
349
                                                     field_type="optional")
 
350
            if not cur_type["optional"]:
 
351
                # An error occured parsing the optional line.
 
352
                print "Invalid 'optional' line found in template %s" % enctype
 
353
                continue
 
354
        elif line.startswith("----"):
 
355
            # We're done.
 
356
            break
 
357
    f.close()
 
358
    if not cur_type["required"]:
 
359
        print "Failed to find a 'require' line in template %s" % enctype
 
360
        return None
 
361
    if not cur_type["name"]:
 
362
        print "Failed to find a 'name' line in template %s" % enctype
 
363
        return None
 
364
    else:
 
365
        return cur_type
 
366
 
 
367
def noneToString(text):
 
368
    """ Convert None, "None", or "" to string type "None"
 
369
 
 
370
    Used for putting text in a text box.  If the value to put in is 'None',
 
371
    the box will be blank.
 
372
 
 
373
    """
 
374
    if text in (None, ""):
 
375
        return "None"
 
376
    else:
 
377
        return str(text)
 
378
 
 
379
def to_unicode(x):
 
380
    """ Attempts to convert a string to utf-8. """
 
381
    # If this is a unicode string, encode it and return
 
382
    if not isinstance(x, basestring):
 
383
        return x
 
384
    if isinstance(x, unicode):
 
385
        return x.encode('utf-8')
 
386
    encoding = locale.getpreferredencoding()
 
387
    try:
 
388
        ret = x.decode(encoding).encode('utf-8')
 
389
    except UnicodeError:
 
390
        try:
 
391
            ret = x.decode('utf-8').encode('utf-8')
 
392
        except UnicodeError:
 
393
            try:
 
394
                ret = x.decode('latin-1').encode('utf-8')
 
395
            except UnicodeError:
 
396
                ret = x.decode('utf-8', 'replace').encode('utf-8')
 
397
            
 
398
    return ret
 
399
    
 
400
def RenameProcess(new_name):
 
401
    """ Renames the process calling the function to the given name. """
 
402
    if sys.platform != 'linux2':
 
403
        print 'Unsupported platform'
 
404
        return False
 
405
    try:
 
406
        import ctypes
 
407
        is_64 = os.path.exists('/lib64/libc.so.6')
 
408
        if is_64:
 
409
            libc = ctypes.CDLL('/lib64/libc.so.6')
 
410
        else:
 
411
            libc = ctypes.CDLL('/lib/libc.so.6')
 
412
        libc.prctl(15, new_name, 0, 0, 0)
 
413
        return True
 
414
    except:
 
415
        print "rename failed"
 
416
        return False
 
417
    
 
418
def detect_desktop_environment():
 
419
    """ Try to determine which desktop environment is in use. 
 
420
    
 
421
    Choose between kde, gnome, or xfce based on environment
 
422
    variables and a call to xprop.
 
423
    
 
424
    """
 
425
    desktop_environment = 'generic'
 
426
    if os.environ.get('KDE_FULL_SESSION') == 'true':
 
427
        desktop_environment = 'kde'
 
428
    elif os.environ.get('GNOME_DESKTOP_SESSION_ID'):
 
429
        desktop_environment = 'gnome'
 
430
    else:
 
431
        try:
 
432
            info = getoutput('xprop -root _DT_SAVE_MODE')
 
433
            if ' = "xfce4"' in info:
 
434
                desktop_environment = 'xfce'
 
435
        except (OSError, RuntimeError):
 
436
            pass
 
437
    return desktop_environment
 
438
 
 
439
def get_sudo_cmd(msg, prog_num=0):
 
440
    """ Returns a graphical sudo command for generic use. """
 
441
    sudo_prog = choose_sudo_prog(prog_num)
 
442
    if not sudo_prog: return None
 
443
    if re.search("(ktsuss|gksu|gksudo)$", sudo_prog):
 
444
        msg_flag = "-m"
 
445
    else:
 
446
        msg_flag = "--caption"
 
447
    return [sudo_prog, msg_flag, msg]
 
448
 
 
449
def choose_sudo_prog(prog_num=0):
 
450
    """ Try to intelligently decide which graphical sudo program to use. """
 
451
    if prog_num:
 
452
        return find_path(_sudo_dict[prog_num])
 
453
    desktop_env = detect_desktop_environment()
 
454
    env_path = os.environ['PATH'].split(":")
 
455
    paths = []
 
456
    
 
457
    if desktop_env == "kde":
 
458
        progs = ["kdesu", "kdesudo", "ktsuss"]
 
459
    else:
 
460
        progs = ["gksudo", "gksu", "ktsuss"]
 
461
        
 
462
    for prog in progs:
 
463
        paths.extend([os.path.join(p, prog) for p in env_path])
 
464
        
 
465
    for path in paths:
 
466
        if os.path.exists(path):
 
467
            return path
 
468
    return ""
 
469
 
 
470
def find_path(cmd):
 
471
    """ Try to find a full path for a given file name. 
 
472
    
 
473
    Search the all the paths in the environment variable PATH for
 
474
    the given file name, or return None if a full path for
 
475
    the file can not be found.
 
476
    
 
477
    """
 
478
    paths = os.getenv("PATH").split(':')
 
479
    if not paths:
 
480
        paths = ["/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin",
 
481
                 "/sbin", "/bin"]
 
482
    for path in paths:
 
483
        if os.path.exists(os.path.join(path, cmd)):
 
484
            return os.path.join(path, cmd)
 
485
    return None
 
486
 
 
487
def noneToBlankString(text):
 
488
    """ Converts NoneType or "None" to a blank string. """
 
489
    if text in (None, "None"):
 
490
        return ""
 
491
    else:
 
492
        return str(text)
 
493
 
 
494
def stringToNone(text):
 
495
    """ Performs opposite function of noneToString. """
 
496
    if text in ("", None, "None"):
 
497
        return None
 
498
    else:
 
499
        return str(text)
 
500
 
 
501
def checkboxTextboxToggle(checkbox, textboxes):
 
502
    for textbox in textboxes:
 
503
        textbox.set_sensitive(checkbox.get_active())
 
504
 
 
505
def threaded(f):
 
506
    """ A decorator that will make any function run in a new thread. """
 
507
 
 
508
    def wrapper(*args, **kwargs):
 
509
        t = Thread(target=f, args=args, kwargs=kwargs)
 
510
        t.setDaemon(True)
 
511
        t.start()
 
512
 
 
513
    wrapper.__name__ = f.__name__
 
514
    wrapper.__dict__ = f.__dict__
 
515
    wrapper.__doc__ = f.__doc__
 
516
    wrapper.__module__ = f.__module__
 
517
 
 
518
    return wrapper
 
519
 
 
520
def timeout_add(time, func, milli=False):
 
521
    """ Convience function for running a function on a timer. """
 
522
    if hasattr(gobject, "timeout_add_seconds") and not milli:
 
523
        return gobject.timeout_add_seconds(time, func)
 
524
    else:
 
525
        if not milli: time = time * 1000
 
526
        return gobject.timeout_add(time, func)
 
527
 
 
528
def izip_longest(*args, **kwds):
 
529
    """ Implement the itertools.izip_longest method.
 
530
    
 
531
    We implement the method here because its new in Python 2.6.
 
532
    
 
533
    """
 
534
    # izip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
 
535
    fillvalue = kwds.get('fillvalue')
 
536
    def sentinel(counter = ([fillvalue]*(len(args)-1)).pop):
 
537
        yield counter()         # yields the fillvalue, or raises IndexError
 
538
    fillers = repeat(fillvalue)
 
539
    iters = [chain(it, sentinel(), fillers) for it in args]
 
540
    try:
 
541
        for tup in izip(*iters):
 
542
            yield tup
 
543
    except IndexError:
 
544
        pass
 
545
 
 
546
def grouper(n, iterable, fillvalue=None):
 
547
    """ Iterate over several elements at once
 
548
 
 
549
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
 
550
 
 
551
    """
 
552
    args = [iter(iterable)] * n
 
553
    return izip_longest(fillvalue=fillvalue, *args)