Package x2go :: Module utils
[frames] | no frames]

Source Code for Module x2go.utils

  1  # -*- coding: utf-8 -*- 
  2   
  3  # Copyright (C) 2010-2011 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de> 
  4  # 
  5  # Python X2go 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 3 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # Python X2go 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 
 17  # Free Software Foundation, Inc., 
 18  # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 
 19   
 20  """\ 
 21  Python X2go helper functions, constants etc. 
 22   
 23  """ 
 24  __NAME__ = 'x2goutils-pylib' 
 25   
 26  import sys 
 27  import os 
 28  import locale 
 29  import re 
 30  import types 
 31  import copy 
 32  import paramiko 
 33  import socket 
 34  import gevent 
 35  import string 
 36  import re 
 37  import subprocess 
 38   
 39  # Python X2go modules 
 40  from defaults import X2GOCLIENT_OS as _X2GOCLIENT_OS 
 41  from defaults import X2GO_SESSIONPROFILE_DEFAULTS as _X2GO_SESSIONPROFILE_DEFAULTS 
 42  from defaults import X2GO_MIMEBOX_ACTIONS as _X2GO_MIMEBOX_ACTIONS 
 43  from defaults import _pack_methods_nx3 
 44   
 45  if _X2GOCLIENT_OS == 'Windows': 
 46      import win32api 
 47   
48 -def is_in_nx3packmethods(method):
49 50 """\ 51 Test if a given compression method is valid for NX3 Proxy. 52 53 """ 54 return method in _pack_methods_nx3
55 56
57 -def find_session_line_in_x2golistsessions(session_name, x2go_stdout):
58 """\ 59 Return the X2go session meta information as returned by the 60 C{x2golistsessions} server command for session C{session_name}. 61 62 """ 63 sessions = stdout.read().split("\n") 64 for line in sessions: 65 # skip empty lines 66 if not line: 67 continue 68 if session_name == line.split("|")[1]: 69 return line 70 return None
71 72
73 -def slugify(value):
74 """\ 75 Normalizes string, converts to lowercase, removes non-alpha characters, 76 converts spaces to hyphens and replaces round brackets by pointed brackets. 77 78 """ 79 import unicodedata 80 value = unicodedata.normalize('NFKD', unicode(value)).encode('ascii', 'ignore') 81 value = re.sub('[^\w\s-]', '', value).strip().lower() 82 value = re.sub('[(]', '<', value).strip().lower() 83 value = re.sub('[)]', '>', value).strip().lower() 84 return value
85
86 -def _genSessionProfileId():
87 """\ 88 Generate a session profile ID as used in x2goclient's sessions config file. 89 90 """ 91 import datetime 92 return datetime.datetime.utcnow().strftime('%Y%m%d%H%m%S%f')
93 94
95 -def _checkIniFileDefaults(defaults):
96 """\ 97 Check an ini file data structure passed on by a user app or class. 98 99 """ 100 if defaults is None: 101 return False 102 if type(defaults) is not types.DictType: 103 return False 104 for sub_dict in defaults.values(): 105 if type(sub_dict) is not types.DictType: 106 return False 107 return True
108 109
110 -def _checkSessionProfileDefaults(defaults):
111 """\ 112 Check the data structure of a default session profile passed by a user app. 113 114 """ 115 if defaults is None: 116 return False 117 if type(defaults) is not types.DictType: 118 return False 119 return True
120 121
122 -def _convert_SessionProfileOptions_2_SessionParams(_options):
123 """\ 124 Convert session profile options as used in x2goclient's sessions file to 125 Python X2go session parameters. 126 127 """ 128 129 _params = copy.deepcopy(_options) 130 131 # get rid of unknown session profile options 132 _known_options = _X2GO_SESSIONPROFILE_DEFAULTS.keys() 133 for p in _params.keys(): 134 if p not in _known_options: 135 del _params[p] 136 137 _rename_dict = { 138 'host': 'server', 139 'user': 'username', 140 'soundsystem': 'snd_system', 141 'sndport': 'snd_port', 142 'type': 'kbtype', 143 'layout': 'kblayout', 144 'speed': 'link', 145 'sshport': 'port', 146 'useexports': 'allow_share_local_folders', 147 'export': 'share_local_folders', 148 'usemimebox': 'allow_mimebox', 149 'mimeboxextensions': 'mimebox_extensions', 150 'mimeboxaction': 'mimebox_action', 151 'print': 'printing', 152 'name': 'profile_name', 153 'key': 'key_filename', 154 'command': 'cmd', 155 'rdpserver': 'rdp_server', 156 'rdpoptions': 'rdp_options', 157 'xdmcpserver': 'xdmcp_server', 158 'useiconv': 'convert_encoding', 159 'iconvto': 'server_encoding', 160 'iconvfrom': 'client_encoding', 161 'usesshproxy': 'use_sshproxy', 162 'sshproxyhost': 'sshproxy_host', 163 'sshproxyuser': 'sshproxy_user', 164 'sshproxykeyfile': 'sshproxy_key_filename', 165 'sshproxytunnel': 'sshproxy_tunnel', 166 } 167 _speed_dict = { 168 '0': 'modem', 169 '1': 'isdn', 170 '2': 'adsl', 171 '3': 'wan', 172 '4': 'lan', 173 } 174 175 for opt, val in _options.iteritems(): 176 177 # rename options if necessary 178 if opt in _rename_dict.keys(): 179 del _params[opt] 180 opt = _rename_dict[opt] 181 _params[opt] = val 182 183 # translate integer values for connection speed to readable strings 184 if opt == 'link': 185 val = str(val).lower() 186 if val in _speed_dict.keys(): 187 val = _speed_dict[val] 188 val = val.lower() 189 _params['link'] = val 190 191 # share_local_folders is a list 192 if opt in ('share_local_folders', 'mimebox_extensions'): 193 if type(val) is types.StringType: 194 if val: 195 _params[opt] = val.split(',') 196 else: 197 _params[opt] = [] 198 199 # append value for quality to value for pack method 200 if _params['quality']: 201 _params['pack'] = '%s-%s' % (_params['pack'], _params['quality']) 202 del _params['quality'] 203 204 del _params['fstunnel'] 205 206 if _params.has_key('share_local_folders'): 207 _params['share_local_folders'] = [ f for f in _params['share_local_folders'].split(',') if f ] 208 209 if not _options['fullscreen']: 210 _params['geometry'] = '%sx%s' % (_options['width'], _options['height']) 211 else: 212 _params['geometry'] = 'fullscreen' 213 del _params['width'] 214 del _params['height'] 215 del _params['fullscreen'] 216 217 if not _options['sound']: 218 snd_system = 'none' 219 del _params['sound'] 220 221 if _options['rootless']: 222 _params['session_type'] = 'application' 223 else: 224 _params['session_type'] = 'desktop' 225 del _params['rootless'] 226 227 if _params['mimebox_action'] not in _X2GO_MIMEBOX_ACTIONS.keys(): 228 _params['mimebox_action'] = 'OPEN' 229 230 # currently known but ignored in Python X2go 231 _ignored_options = [ 232 'dpi', 233 'setdpi', 234 'usekbd', 235 'startsoundsystem', 236 'soundtunnel', 237 'defsndport', 238 'icon', 239 'applications', 240 ] 241 for i in _ignored_options: 242 del _params[i] 243 244 return _params
245 246
247 -def session_names_by_timestamp(session_infos):
248 """\ 249 Sorts session profile names by their timestamp (as used in the file format's section name). 250 251 """ 252 session_names = session_infos.keys() 253 sortable_session_names = [ '%s|%s' % (session_name.split('-')[2].split('_')[0], session_name) for session_name in session_names ] 254 sortable_session_names.sort() 255 return [ session_name.split('|')[1] for session_name in sortable_session_names ]
256 257
258 -def touch_file(filename, mode='a'):
259 """\ 260 Imitates the behaviour of the GNU/touch command. 261 262 @param filename: name of the file to touch 263 @type filename: C{str} 264 @param mode: the file mode (as used for Python file objects) 265 @type mode: C{str} 266 """ 267 if not os.path.isdir(os.path.dirname(filename)): 268 os.makedirs(os.path.dirname(filename), mode=00700) 269 f = open(filename, mode=mode) 270 f.close()
271 272
273 -def unique(seq):
274 """\ 275 Imitates the behaviour of the GNU/uniq command. 276 277 @param seq: a list/sequence containing consecutive duplicates. 278 @type seq: C{list} 279 280 @return: list that has been clean up from the consecutive duplicates 281 @rtype: C{list} 282 """ 283 # order preserving 284 noDupes = [] 285 [noDupes.append(i) for i in seq if not noDupes.count(i)] 286 return noDupes
287 288
289 -def known_encodings():
290 """\ 291 Render a list of all-known-to-Python character encodings (including 292 all known aliases) 293 294 """ 295 from encodings.aliases import aliases 296 _raw_encname_list = [] 297 _raw_encname_list.extend(aliases.keys()) 298 _raw_encname_list.extend(aliases.values()) 299 _raw_encname_list.sort() 300 _encname_list = [] 301 for _raw_encname in _raw_encname_list: 302 _encname = _raw_encname.upper() 303 _encname = _encname.replace('_', '-') 304 _encname_list.append(_encname) 305 _encname_list.sort() 306 _encname_list = unique(_encname_list) 307 return _encname_list
308 309
310 -def patiently_remove_file(dirname, filename):
311 """\ 312 Try to remove a file, wait for unlocking, remove it once removing is possible... 313 314 @param dirname: directory name the file is in 315 @type dirname: C{str} 316 @param filename: name of the file to be removed 317 @type filename: C{str} 318 """ 319 _not_removed = True 320 while _not_removed: 321 try: 322 os.remove(os.path.join(dirname, filename)) 323 _not_removed = False 324 except: 325 # file is probably locked 326 gevent.sleep(5)
327
328 -def detect_unused_port(bind_address='', preferred_port=None):
329 """\ 330 Detect an unused IP socket. 331 332 @param bind_address: IP address to bind to 333 @type bind_address: C{str} 334 @param preferred_port: IP socket port that shall be tried first for availability 335 @type preferred_port: C{str} 336 337 @return: free local IP socket port that can be used for binding 338 @rtype: C{str} 339 """ 340 341 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) 342 try: 343 if preferred_port: 344 sock.bind((bind_address, preferred_port)) 345 ipaddr, port = sock.getsockname() 346 else: 347 raise 348 except: 349 sock.bind(('', 0)) 350 ipaddr, port = sock.getsockname() 351 return port
352
353 -def get_encoding():
354 """\ 355 Detect systems default character encoding. 356 357 @return: The system's local character encoding. 358 @rtype: C{str} 359 """ 360 try: 361 encoding = locale.getdefaultlocale()[1] 362 if encoding is None: 363 raise BaseException 364 except: 365 try: 366 encoding = sys.getdefaultencoding() 367 except: 368 encoding = 'ascii' 369 return encoding
370
371 -def is_abs_path(path):
372 """\ 373 Test if a given path is an absolute path name. 374 375 @param path: test this path for absolutism... 376 @type path: C{str} 377 378 @return: Returns C{True} if path is an absolute path name 379 @rtype: C{bool} 380 """ 381 return bool((path.startswith('/') or re.match('^[%s]\:\\\\' % string.ascii_letters, path)))
382
383 -def xkb_rules_names():
384 """\ 385 Wrapper for: xprop -root _XKB_RULES_NAMES 386 387 @return: A Python dictionary that contains the current X11 keyboard rules. 388 @rtype: C{dict} 389 390 """ 391 p = subprocess.Popen(['xprop', '-root', '_XKB_RULES_NAMES',], stdout=subprocess.PIPE, ) 392 _rn_list = p.stdout.read().split('"') 393 _rn_dict = { 394 'rules': _rn_list[1], 395 'model': _rn_list[3], 396 'layout': _rn_list[5], 397 'variant': _rn_list[7], 398 'options': _rn_list[9], 399 } 400 return _rn_dict
401
402 -def local_color_depth():
403 """\ 404 Detect the current local screen's color depth. 405 406 """ 407 if _X2GOCLIENT_OS != 'Windows': 408 try: 409 p = subprocess.Popen(['xwininfo', '-root',], stdout=subprocess.PIPE, ) 410 _depth_line = [ _info.strip() for _info in p.stdout.read().split('\n') if 'Depth:' in _info ][0] 411 _depth = _depth_line.split(' ')[1] 412 return int(_depth) 413 except IndexError: 414 # a sensible default value 415 return 24 416 except OSError: 417 # for building your package... 418 return 24 419 420 else: 421 return win32api.GetSystemMetrics(2)
422
423 -def is_color_depth_ok(depth_session, depth_local):
424 """\ 425 Test if color depth of this session is compatible with the 426 local screen's color depth. 427 428 @param depth_session: color depth of the session 429 @type depth_session: C{int} 430 @param depth_local: color depth of local screen 431 @type depth_local: C{int} 432 433 @return: Does the session color depth work with the local display? 434 @rtype: C{bool} 435 436 """ 437 if depth_session == 0: 438 return True 439 if depth_session == depth_local: 440 return True 441 if ( ( depth_session == 24 or depth_session == 32 ) and ( depth_local == 24 or depth_local == 32 ) ): 442 return true; 443 return False
444