|
|
|
#-*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
# Copyright 2010-2013 Calculate Ltd. http://www.calculate-linux.org
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import re
|
|
|
|
from os import path
|
|
|
|
import pwd
|
|
|
|
from calculate.lib.datavars import Variable,VariableError,ReadonlyVariable, \
|
|
|
|
ReadonlyTableVariable,FieldValue
|
|
|
|
from calculate.lib.variables.user import VariableUrLogin
|
|
|
|
from calculate.lib.utils.files import (readLinesFile,process,isMount,
|
|
|
|
listDirectory)
|
|
|
|
from calculate.desktop._cl_keys import getKey
|
|
|
|
from itertools import *
|
|
|
|
from calculate.lib.cl_template import (templateFunction,iniParser)
|
|
|
|
import hashlib
|
|
|
|
|
|
|
|
from calculate.lib.cl_lang import setLocalTranslate
|
|
|
|
setLocalTranslate('cl_desktop3',sys.modules[__name__])
|
|
|
|
|
|
|
|
class VariableUrJidHost(ReadonlyVariable):
|
|
|
|
"""
|
|
|
|
Jabber host for user
|
|
|
|
"""
|
|
|
|
def get(self):
|
|
|
|
userJid = self.Get("ur_jid")
|
|
|
|
if userJid:
|
|
|
|
return userJid.partition('@')[2]
|
|
|
|
return ""
|
|
|
|
|
|
|
|
class DomainInfoHelper:
|
|
|
|
"""
|
|
|
|
Вспомогательный класс для определения доменный ли пользователь
|
|
|
|
"""
|
|
|
|
def getUserDataInFile(self, login, filePasswd):
|
|
|
|
return filter(lambda x: x[0]==login,
|
|
|
|
map(lambda x: x.strip().split(':'),
|
|
|
|
readLinesFile(filePasswd)))
|
|
|
|
|
|
|
|
def isDomainUser(self,userName):
|
|
|
|
if userName:
|
|
|
|
try:
|
|
|
|
passwdUserData = self.getUserDataInFile(userName, "/etc/passwd")
|
|
|
|
except:
|
|
|
|
return False
|
|
|
|
if passwdUserData:
|
|
|
|
passwdUserData = passwdUserData[0]
|
|
|
|
try:
|
|
|
|
cacheUserData = self.getUserDataInFile(userName,
|
|
|
|
"/var/lib/calculate/calculate-client/cache/passwd")
|
|
|
|
except:
|
|
|
|
return False
|
|
|
|
if cacheUserData:
|
|
|
|
cacheUserData = cacheUserData[0]
|
|
|
|
if cacheUserData == passwdUserData:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
class VariableUrDomainSet(ReadonlyVariable,DomainInfoHelper):
|
|
|
|
"""
|
|
|
|
Flag for determining domain user or local
|
|
|
|
"""
|
|
|
|
type = "bool"
|
|
|
|
|
|
|
|
def getUserDataInFile(self, login, filePasswd):
|
|
|
|
return filter(lambda x: x[0]==login,
|
|
|
|
map(lambda x: x.strip().split(':'),
|
|
|
|
readLinesFile(filePasswd)))
|
|
|
|
|
|
|
|
def get(self):
|
|
|
|
return "on" if self.isDomainUser(self.Get('ur_login')) else "off"
|
|
|
|
|
|
|
|
class VariableClDesktopXsession(ReadonlyVariable):
|
|
|
|
"""
|
|
|
|
User current X session
|
|
|
|
"""
|
|
|
|
def get(self):
|
|
|
|
envXsessionFile = "/etc/env.d/90xsession"
|
|
|
|
xsession = os.environ.get("XSESSION",None)
|
|
|
|
desktopSession = os.environ.get("DESKTOP_SESSION",None)
|
|
|
|
if not xsession:
|
|
|
|
if os.path.exists(envXsessionFile):
|
|
|
|
xsession = \
|
|
|
|
map(lambda x:x.partition("=")[2].strip("'\""),
|
|
|
|
filter(lambda x:x.startswith("XSESSION="),
|
|
|
|
filter(lambda x:not x.startswith("#"),
|
|
|
|
open(envXsessionFile,"r"))))
|
|
|
|
if xsession:
|
|
|
|
xsession = xsession[-1]
|
|
|
|
if xsession:
|
|
|
|
if desktopSession and \
|
|
|
|
any(x in desktopSession.lower()
|
|
|
|
for x in ("kde","xfce","gnome")):
|
|
|
|
xsession = desktopSession
|
|
|
|
if "kde" in xsession.lower():
|
|
|
|
return "kde"
|
|
|
|
elif "gnome" in xsession.lower():
|
|
|
|
return "gnome"
|
|
|
|
elif "xfce" in xsession.lower():
|
|
|
|
return "xfce"
|
|
|
|
else:
|
|
|
|
return xsession.lower()
|
|
|
|
return ""
|
|
|
|
|
|
|
|
class VariableClDesktopGstData(ReadonlyVariable):
|
|
|
|
"""
|
|
|
|
GStreamer data
|
|
|
|
"""
|
|
|
|
def get(self):
|
|
|
|
# try import gst
|
|
|
|
try:
|
|
|
|
copyargv = sys.argv
|
|
|
|
sys.argv = []
|
|
|
|
olderr = os.dup(sys.stderr.fileno())
|
|
|
|
os.close(sys.stderr.fileno())
|
|
|
|
import gst
|
|
|
|
import gst.interfaces
|
|
|
|
except ImportError:
|
|
|
|
gst = None
|
|
|
|
finally:
|
|
|
|
sys.argv= copyargv
|
|
|
|
os.dup2(olderr,sys.stderr.fileno())
|
|
|
|
if gst is None:
|
|
|
|
return {}
|
|
|
|
|
|
|
|
outdata = {}
|
|
|
|
try:
|
|
|
|
pipeline = "alsamixer"
|
|
|
|
alsamixer = gst.element_factory_make(pipeline)
|
|
|
|
res = alsamixer.set_state(gst.STATE_PAUSED)
|
|
|
|
if res == gst.STATE_CHANGE_SUCCESS:
|
|
|
|
outdata['device_name'] = alsamixer.get_property("device-name")
|
|
|
|
outdata['long_name'] = alsamixer.get_factory().get_longname()
|
|
|
|
outdata['internal_name'] = filter(str.isalnum,
|
|
|
|
"%s (%s)"%(outdata['device_name'],
|
|
|
|
outdata['long_name']))
|
|
|
|
outdata['channels'] = []
|
|
|
|
for t in alsamixer.list_tracks():
|
|
|
|
if t.flags & gst.interfaces.MIXER_TRACK_OUTPUT:
|
|
|
|
if t.flags & gst.interfaces.MIXER_TRACK_MASTER or \
|
|
|
|
any(x in t.label
|
|
|
|
for x in ("Wave","Front","LFE","Center",
|
|
|
|
"Head","Side","Speaker",
|
|
|
|
"Surround","PCM")):
|
|
|
|
outdata['channels'].append(t.label)
|
|
|
|
if t.flags & gst.interfaces.MIXER_TRACK_MASTER:
|
|
|
|
outdata['master_channel'] = t.label
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
return outdata
|
|
|
|
|
|
|
|
class VariableClDesktopGstCard(ReadonlyVariable):
|
|
|
|
"""
|
|
|
|
Internal card name for xfce mixer
|
|
|
|
"""
|
|
|
|
def get(self):
|
|
|
|
return self.Get('cl_desktop_gst_data').get('internal_name','')
|
|
|
|
|
|
|
|
class VariableClDesktopGstMasterchannel(ReadonlyVariable):
|
|
|
|
"""
|
|
|
|
Master track name
|
|
|
|
"""
|
|
|
|
def get(self):
|
|
|
|
return self.Get('cl_desktop_gst_data').get('master_channel','')
|
|
|
|
|
|
|
|
|
|
|
|
class VariableClDesktopXfceMixer(ReadonlyVariable):
|
|
|
|
"""
|
|
|
|
List of channel for xfce-perchannel mixer
|
|
|
|
"""
|
|
|
|
def get(self):
|
|
|
|
return "\n".join(
|
|
|
|
map(lambda x:' <value type="string" value="%s" />'%x,
|
|
|
|
self.Get('cl_desktop_gst_data').get('channels',[])))
|
|
|
|
|
|
|
|
class VariableClDesktopOnlineData(ReadonlyTableVariable,DomainInfoHelper):
|
|
|
|
"""
|
|
|
|
Information about online users
|
|
|
|
"""
|
|
|
|
source = ['cl_desktop_online_user',
|
|
|
|
'cl_desktop_online_display',
|
|
|
|
'cl_desktop_online_uid',
|
|
|
|
'cl_desktop_online_domain_set',
|
|
|
|
'cl_desktop_online_count']
|
|
|
|
|
|
|
|
reDisplay = re.compile(r"^\(?:(\d+\.?\d*)")
|
|
|
|
|
|
|
|
def _getDisplay(self,*args):
|
|
|
|
"""
|
|
|
|
Get DISPLAY from args
|
|
|
|
"""
|
|
|
|
for arg in map(self.reDisplay.search,args):
|
|
|
|
if arg:
|
|
|
|
return arg.group(1)
|
|
|
|
return ""
|
|
|
|
|
|
|
|
def get_user_uid(self,username):
|
|
|
|
try:
|
|
|
|
return str(pwd.getpwnam(username).pw_uid)
|
|
|
|
except:
|
|
|
|
return ""
|
|
|
|
|
|
|
|
def get(self,hr=False):
|
|
|
|
xSession = 0
|
|
|
|
foundTwoSession = False
|
|
|
|
resWho = process("who")
|
|
|
|
xData = [[]]
|
|
|
|
if resWho.success():
|
|
|
|
listProcessing = lambda x: (x[0], x[1], x[-1]) \
|
|
|
|
if len(x)>=5 else []
|
|
|
|
xData = groupby(
|
|
|
|
sorted(
|
|
|
|
filter(lambda x: x[0]!="root",
|
|
|
|
map(lambda x: (x[0],self._getDisplay(x[1],x[2])),
|
|
|
|
filter(lambda x: x and\
|
|
|
|
(x[2].startswith("(:") or \
|
|
|
|
x[1].startswith(":")),
|
|
|
|
map(lambda x: listProcessing(\
|
|
|
|
filter(lambda y: y, x.split())),
|
|
|
|
resWho)))),
|
|
|
|
key=lambda x:x[0]),
|
|
|
|
lambda x:x[0])
|
|
|
|
xData = map(lambda x:(x[0][0],x[0][1],
|
|
|
|
self.get_user_uid(x[0][0]),
|
|
|
|
"on" if self.isDomainUser(x[0][0]) else "off",
|
|
|
|
len(x)),
|
|
|
|
map(lambda x:list(x[1]),
|
|
|
|
xData))
|
|
|
|
return xData
|
|
|
|
|
|
|
|
setValue = Variable.setValue
|
|
|
|
|
|
|
|
class VariableClDesktopOnlineUser(FieldValue,ReadonlyVariable):
|
|
|
|
"""
|
|
|
|
Логин пользователя
|
|
|
|
"""
|
|
|
|
type = "list"
|
|
|
|
source_variable = "cl_desktop_online_data"
|
|
|
|
column = 0
|
|
|
|
|
|
|
|
class VariableClDesktopOnlineDisplay(FieldValue,ReadonlyVariable):
|
|
|
|
"""
|
|
|
|
Display пользователя
|
|
|
|
"""
|
|
|
|
type = "list"
|
|
|
|
source_variable = "cl_desktop_online_data"
|
|
|
|
column = 1
|
|
|
|
|
|
|
|
class VariableClDesktopOnlineUid(FieldValue,ReadonlyVariable):
|
|
|
|
"""
|
|
|
|
UID пользователя
|
|
|
|
"""
|
|
|
|
type = "list"
|
|
|
|
source_variable = "cl_desktop_online_data"
|
|
|
|
column = 2
|
|
|
|
|
|
|
|
class VariableClDesktopOnlineDomainSet(FieldValue,ReadonlyVariable):
|
|
|
|
"""
|
|
|
|
Является ли пользователь доменным
|
|
|
|
"""
|
|
|
|
type = "list"
|
|
|
|
source_variable = "cl_desktop_online_data"
|
|
|
|
column = 3
|
|
|
|
|
|
|
|
class VariableClDesktopOnlineCount(FieldValue,ReadonlyVariable):
|
|
|
|
"""
|
|
|
|
Количество сеансов пользователя
|
|
|
|
"""
|
|
|
|
type = "list"
|
|
|
|
source_variable = "cl_desktop_online_data"
|
|
|
|
column = 4
|
|
|
|
|
|
|
|
class VariableClDesktopLogin(VariableUrLogin):
|
|
|
|
"""
|
|
|
|
User Login
|
|
|
|
"""
|
|
|
|
opt = ["cl_desktop_login"]
|
|
|
|
|
|
|
|
def choice(self):
|
|
|
|
if self.Get('cl_action') == 'logout':
|
|
|
|
return self.Get('cl_desktop_online_user')
|
|
|
|
else:
|
|
|
|
return VariableUrLogin.choice(self)
|
|
|
|
|
|
|
|
def check(self,value):
|
|
|
|
"""Does user exist"""
|
|
|
|
if not value in self.choice() and self.Get('cl_action') == 'logout':
|
|
|
|
raise VariableError(_("No X session user found"))
|
|
|
|
if value == "":
|
|
|
|
raise VariableError(_("Please specify the user name"))
|
|
|
|
try:
|
|
|
|
pwd.getpwnam(value).pw_gid
|
|
|
|
except:
|
|
|
|
raise VariableError(_("User %s does not exist")%value)
|
|
|
|
|
|
|
|
def get(self):
|
|
|
|
return ""
|
|
|
|
|
|
|
|
class VariableUrMountDirs(ReadonlyVariable):
|
|
|
|
"""
|
|
|
|
Примонтированные директории в профиле пользователя
|
|
|
|
"""
|
|
|
|
type = "list"
|
|
|
|
|
|
|
|
def get(self):
|
|
|
|
homeDir = self.Get("ur_home_path")
|
|
|
|
if not homeDir:
|
|
|
|
return []
|
|
|
|
dirStart, dirEnd = path.split(homeDir)
|
|
|
|
mountProfileDir = path.join(dirStart, ".%s" %dirEnd)
|
|
|
|
mountRemoteProfileDir = path.join(dirStart, ".%s.remote" %dirEnd)
|
|
|
|
|
|
|
|
directories = filter(lambda x:x != homeDir,
|
|
|
|
filter(lambda x: (x.startswith(homeDir) or
|
|
|
|
x.startswith(mountProfileDir) or
|
|
|
|
x.startswith(mountRemoteProfileDir)),
|
|
|
|
map(lambda x: x.split(" ")[1],
|
|
|
|
readLinesFile('/proc/mounts'))))
|
|
|
|
#if isMount(homeDir):
|
|
|
|
# directories.append(homeDir)
|
|
|
|
return sorted(directories,reverse=True)
|
|
|
|
|
|
|
|
class VariableUrPassword(ReadonlyVariable):
|
|
|
|
"""
|
|
|
|
Пароль пользователя, получаемый из ключей ядра
|
|
|
|
"""
|
|
|
|
def get(self):
|
|
|
|
return getKey(self.Get('ur_login')) or ""
|
|
|
|
|
|
|
|
class VariableClDesktopUpdateProfileSet(Variable):
|
|
|
|
"""
|
|
|
|
Нужно ли выполнять обновление профиля пользователя на основании
|
|
|
|
обновлении пакетов
|
|
|
|
"""
|
|
|
|
type = "bool"
|
|
|
|
|
|
|
|
def get(self):
|
|
|
|
lastTimestamp = templateFunction.getLastElog()
|
|
|
|
iniEnv = path.join(self.Get('ur_home_path'),'.calculate/ini.env')
|
|
|
|
userIni = iniParser(iniEnv)
|
|
|
|
userTimestamp = userIni.getVar('main','elog')
|
|
|
|
if userTimestamp:
|
|
|
|
userTimestamp = userTimestamp.encode('utf-8')
|
|
|
|
profileSetup = userIni.getVar('main','profile_setup')
|
|
|
|
login_setup = profileSetup == 'on'
|
|
|
|
if (self.Get('ur_domain_set') == 'on' or login_setup or
|
|
|
|
not path.exists(iniEnv) or userTimestamp != lastTimestamp):
|
|
|
|
return 'on'
|
|
|
|
else:
|
|
|
|
return 'off'
|
|
|
|
|
|
|
|
class VariableClDesktopForceSetupSet(Variable):
|
|
|
|
"""
|
|
|
|
Принудительно выполнить обновление пользовательского профиля
|
|
|
|
"""
|
|
|
|
type = "bool"
|
|
|
|
opt = ["--force-setup"]
|
|
|
|
metavalue = "ON/OFF"
|
|
|
|
value = "off"
|
|
|
|
|
|
|
|
def init(self):
|
|
|
|
self.label = _("Force configuration")
|
|
|
|
self.help = _("force configuration")
|
|
|
|
|
|
|
|
class VariableClDesktopFacePath(Variable):
|
|
|
|
"""Путь к стандартным иконкам пользователей"""
|
|
|
|
value = "/usr/share/pixmaps/faces"
|
|
|
|
|
|
|
|
class VariableClDesktopFaceList(Variable):
|
|
|
|
"""Список доступных иконок по умолчанию для пользователей"""
|
|
|
|
type = "list"
|
|
|
|
|
|
|
|
def get(self):
|
|
|
|
return sorted(
|
|
|
|
filter(lambda x:x.endswith('.png'),
|
|
|
|
listDirectory(self.Get('cl_desktop_face_path'))))
|
|
|
|
|
|
|
|
class VariableClDesktopHashFace(Variable):
|
|
|
|
"""Номер иконки пользователя
|
|
|
|
|
|
|
|
Номер вычисляется по контрольной сумму md5 логина пользователя
|
|
|
|
"""
|
|
|
|
def get(self):
|
|
|
|
login = self.Get('ur_login')
|
|
|
|
icon_list = self.Get('cl_desktop_face_list')
|
|
|
|
if icon_list:
|
|
|
|
return path.join(self.Get('cl_desktop_face_path'),
|
|
|
|
icon_list[sum(map(lambda x:ord(x),
|
|
|
|
hashlib.md5(login).digest()))%len(icon_list)])
|
|
|
|
else:
|
|
|
|
return ""
|
|
|
|
|
|
|
|
class VariableClDesktopFastloginPath(ReadonlyVariable):
|
|
|
|
"""
|
|
|
|
Путь до каталога в котором указаны пользователи быстрого входа в сеанс
|
|
|
|
"""
|
|
|
|
value = "/var/lib/calculate/calculate-desktop/fastlogin"
|
|
|
|
|