#-*- coding: utf-8 -*-

# Copyright 2010 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 stat
import re
import sys
import pwd

import subprocess
import ldap
import time
import types

import getpass

from os import path
from datavars import DataVarsClient, DataVars, __version__,__app__

from calculate.lib.cl_template import (Template, iniParser,TemplatesError,
                                       ProgressTemplate)
from calculate.lib.cl_print import color_print
from calculate.lib.cl_ldap import ldapUser
from calculate.lib.utils.ip import Pinger, isOpenPort, IPError
from calculate.lib.utils.files import (runOsCommand, getModeFile, removeDir,
                    isMount, readFile, pathJoin, tarLinks,process,STDOUT,
                    readLinesFile,listDirectory)
from calculate.lib.utils.common import (getpathenv, appendProgramToEnvFile,        
        CommonError,removeProgramToEnvFile,mountEcryptfs)
from calculate.desktop._cl_keys import getKey, clearKey
from calculate.lib.convertenv import convertEnv
from calculate.lib.encrypt import encrypt
from cl_client_cache import userCache
from shutil import copy2
from socket import gethostbyname
import tarfile
from collections import OrderedDict
from itertools import *

from calculate.core.server.func import safetyWrapper

from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate
setLocalTranslate('cl_client3',sys.modules[__name__])
__ = getLazyLocalTranslate(_)

class ClientError(Exception):
    pass

class RsyncProgressBar:
    """
    Rsync with using setProgress
    """
    # get number of send file from info rsync stream
    senderre = re.compile("\[sender\] i=(\d+) ", re.S)
    # get number of receivce file from info rsync rtream
    receiverre = re.compile("recv_generator\(.+,([0-9]+)\)", re.S)
    pipe = None
    maximum = 1
    copyStarting = False

    def __init__(self, title, secondtitle, rsyncstr, parent,maximum=1):
        self.title = title
        self.secondtitle = secondtitle
        self.maximum = maximum
        self.rsyncstr = rsyncstr
        self.parent = parent
        self.value = 0

    def getFilesNum(self):
        """
        Get files count created by generator
        """
        if self.pipe:
            return self.value

    def getExitCode(self):
        """
        Get rsync exitcode
        """
        if self.pipe:
            return self.pipe.wait()
        return 255

    def getErrMessage(self):
        """
        Rsync error message 
        """
        if self.pipe:
            return self.pipe.stderr.read()
        return _("RsyncProgressBar: Wrong pipe")

    def runsilent(self):
        """
        Run rsync without progressbar
        """
        self.pipe = subprocess.Popen(self.rsyncstr, stdin=subprocess.PIPE,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE,
                                     close_fds=True, shell=True)
        while True:
            s = self.pipe.stdout.readline()
            if len(s) == 0:
                break
            q = self.receiverre.search(s)
            if q:
                self.value = int(q.groups()[0])

    def run(self):
        """
        Run rsync with progressbar
        """
        self.parent.startTask(self.title,progress=True)
        self.pipe = subprocess.Popen(self.rsyncstr, stdin=subprocess.PIPE,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE,
                                     close_fds=True, shell=True)
        oldpercent = 0
        while True:
            s = self.pipe.stdout.readline()
            if len(s) == 0:
                break
            q = self.receiverre.search(s)
            if q:
                if not self.copyStarting:
                    self.parent.endTask()
                    self.parent.startTask(self.secondtitle,progress=True)
                    #self.parent.setProgress(0)
                    self.copyStarting = True
                self.value = int(q.groups()[0])
                if self.maximum:
                    newvalue = int(100*self.value / self.maximum)
                    newvalue = min(newvalue,99)
                    if newvalue > oldpercent:
                        self.parent.setProgress(newvalue)
                        oldpercent = newvalue
        self.parent.setProgress(100)

    def close(self):
        self.parent.endTask()

class ldapData(ldapUser):
    """LDAP methods"""

    def getReplDN(self):
        """
        Get from LDAP last domain server

        Branch has ((username,systemname,host))
        """
        usersDN = self.getUsersDN()
        if usersDN:
            partDN = "ou=Worked,ou=Replication,ou=LDAP"
            servicesDN = "ou=Services"
            baseDN = usersDN.rpartition(servicesDN+",")[2]
            replDN = self.addDN(partDN, servicesDN, baseDN)
            return replDN
        return False

    def searchPrevHost(self, userName, osLinuxShort):
        """Find server which user use"""
        connectData = self.getBindConnectData()
        if connectData:
            bindDn, bindPw, host = connectData
            replDN = self.getReplDN()
            # find string for service replication branch
            userAndOsName = "%s@%s"%(userName,osLinuxShort)
            findAttr = "uid=%s"%userAndOsName
            # connect to LDAP
            if not self.ldapConnect(bindDn, bindPw, host):
                return False
            resSearch = self.ldapObj.ldapSearch(replDN, ldap.SCOPE_ONELEVEL,
                                                findAttr, ["host"])
            return resSearch
        return False

    def _gethostbyname(self,hostname):
        try:
            return gethostbyname(hostname)
        except:
            pass
        return None

    def getNameRemoteServer(self,userName, osLinuxShort, curHost):
        """
        Get remote domain hostname or empty if profile is keeped on 
        current server
        """
        searchPrevHost = self.searchPrevHost(userName, osLinuxShort)
        if searchPrevHost and searchPrevHost[0][0][1].has_key('host'):
            prevHost = searchPrevHost[0][0][1]['host'][0]
        else:
            prevHost = None
        # get ip address of previous server and current server
        prevIp = self._gethostbyname(prevHost)
        curIp = self._gethostbyname(curHost)
        # if actual profile not found or on local
        if not prevHost or curIp and prevIp == curIp:
            return False
        else:
            return prevHost

    def isRepl(self):
        """
        Is on or off replication on server
        """
        connectData = self.getBindConnectData()
        if connectData:
            bindDn, bindPw, host = connectData
            usersDN = self.getUsersDN()
            partDN = "ou=Replication,ou=LDAP"
            servicesDN = "ou=Services"
            baseDN = usersDN.rpartition(servicesDN+",")[2]
            replDN = self.addDN(partDN, servicesDN, baseDN)
            findAttr = "ou=Worked"
            # connect to LDAP
            if not self.ldapConnect(bindDn, bindPw, host):
                return False
            resSearch = self.ldapObj.ldapSearch(replDN, ldap.SCOPE_ONELEVEL,
                                                findAttr,
                                                [findAttr.partition("=")[0]])
            if resSearch:
                return True
        return False

class commandServer(color_print):
    """Server command object"""

    def setServerCommand(self, command, varsCommand, fileConfig,
                         uid=None, gid=None):
        """Set server command"""
        pathConfig = os.path.split(fileConfig)[0]
        # create user config directory
        if not os.path.exists(pathConfig):
            os.makedirs(pathConfig)
            if not uid is None and not gid is None:
                os.chown(pathConfig, uid, gid)
        objConfig = iniParser(fileConfig)
        varsRun = {"run":"on"}
        varsRun.update(varsCommand)
        if not objConfig.setVar(["command"]+command, varsRun):
            raise ClientError(_("Failed to write variables in file %s")\
                            %fileConfig)
        if not uid is None and not gid is None:
            os.chown(fileConfig, uid, gid)
        return True

    def checkUserPwdLDAP(self, server, userDN, password):
        """Проверка пароля Unix пользователя на сервере"""
        ldapInit = ldap.initialize("ldap://%s"%server)
        errMessage = ""
        try: 
            ldapInit.bind_s(userDN, password)
        except ldap.INVALID_CREDENTIALS:
            errMessage = _("Wrong password")
            return False, errMessage
        except ldap.LDAPError, e:
            errMessage = e[0]['desc']
            return False, errMessage
        return True, errMessage

    def getUserPwd(self, options, optDialog, optStdIn, pwDialog=False):
        """Получить пароль у пользователя

        options   - полученные опции командной строки
        optDialog - опция командной строки для вывода диалога для получения
                    пароля
        optStdIn  - опция командной строки для получения пароля из
                    стандартного ввода (stdin)
        pwDialog  - структура для вывода приглашения в режиме диалога
        """
        userPwd = ""
        if optStdIn and options.has_key(optStdIn):
            pwdA = sys.stdin.readline().rstrip()
            pwdB = sys.stdin.readline().rstrip()
        elif optDialog and options.has_key(optDialog):
            if not pwDialog:
                pwDialog = [_("New password"),
                            _("Retype the new password")]
            pwdA = getpass.getpass(pwDialog[0]+":")
            pwdB = getpass.getpass(pwDialog[1]+":")
        if (optStdIn and options.has_key(optStdIn)) or\
            (optDialog and options.has_key(optDialog)):
            if not pwdA or not (pwdA == pwdB):
                self.printERROR (_("ERROR") + ": " +\
                _("passwords do not match"))
                return False
            userPwd = pwdA
        return userPwd

class Client(commandServer, encrypt):
    """
    Client logic object

    Has fundamental methods:
    mountUserResAndSync - mount user resources and sync profile from server
    umountUserResAndSync - umount user resources and sync profile to server
    mountRemote - mount remote domain resource
    delDomain - remove workstation from domain
    addDomain - add workstation to domain
    changePasswd - change password on server
    """

    # object for user data in LDAP
    ldapDataObj = ldapData()
    # user calculate config directory
    pathConfig = ".calculate"
    # client soft config file
    configFileSoft = os.path.join(pathConfig, "ini.env")
    # client config file
    configFileDesktop = os.path.join(pathConfig, "desktop.env")
    # client config for server
    configFileServer = os.path.join(pathConfig, "server.env")
    # file list of user profile
    listTemplFile = os.path.join(pathConfig, "files.txt")

    # files which not cleaning from user home directory
    skipHomeFile = ["Home","Disks","Share","FTP",configFileDesktop]

    # option dict of services from /var/calculate/remote/server.env
    optionsInfo = {}

    # convertation object from old remote env
    convObj = None
    # private user files
    privateFiles = [configFileServer]
    # private user directories
    privateDirs =  []

    def __init__(self):
        self.clVars = None
        self.clTempl = None

    def initVars(self,datavars=None):
        """Primary variables initialization"""
        if not datavars:
            self.clVars = DataVarsClient()
            self.clVars.importClient()
            self.clVars.flIniFile()
        else:
            self.clVars = datavars

    def removeVars(self):
        """
        Remove domain variables. Useing on remove package
        and undomain action
        """
        self.clVars.Delete("cl_remote_host", "local")
        self.clVars.Delete("cl_remote_pw", "local")
        self.clVars.Delete("os_remote_auth")
        self.clVars.Delete("os_remote_client")
        self.clVars.Set("cl_remote_host", "", True)
        self.clVars.Set("cl_remote_pw", "", True)
        self.clVars.Set("os_remote_auth", "", True)
        self.clVars.Set("os_remote_client", "", True)

    def applyTemplatesFromSystem(self):
        """Apply templates for system"""
        if self.clVars.Get('cl_action') == 'domain':
            self.startTask(_("Applying domain templates"),progress=True)
        else:
            self.startTask(_("Applying non-domain templates"),progress=True)
        if self.clTempl:
            self.closeClTemplate()
        self.clVars.Set('cl_autoupdate_set','on',True)
        self.clTempl = ProgressTemplate(self.setProgress,self.clVars,
                                        cltObj=True,cltFilter=True,
                                        printSUCCESS=self.printSUCCESS,
                                        printERROR=self.printERROR,
                                        askConfirm=self.askConfirm,
                                        printWARNING=self.printWARNING)
        dirsFiles = self.clTempl.applyTemplates()
        if self.clTempl.getError():
            self.printERROR(self.clTempl.getError().strip())
            return False
        else:
            self.endTask()
            return dirsFiles

    def isTwoSessionsUser(self, userName):
        """
        Check on second user login
        """
        xSession = False
        foundTwoSession = False
        resWho = self.execProg("who")
        if resWho:
            for pattern in ("%s\s+\d+\s+","%s\s+tty\d+.*:\d+"):
                reFoundUser = re.compile(pattern%(userName))
                for string in resWho:
                    if reFoundUser.search(string):
                        if xSession:
                            self.printERROR(\
                                _("Second X session for user %s cannot be opened.")\
                                  %userName)
                            return True
                        else:
                            xSession = True
        return False

    def isDomain(self):
        """
        Check domain or not workstation
        """
        foundMountRemote = isMount("/var/calculate/remote")
        remoteHost = self.clVars.Get("cl_remote_host")
        if remoteHost and foundMountRemote:
            return True
        return False

    def getSyncStatus(self,rpath):
        """
        Get local config 'date' and 'status_sync' or None
        """
        fileConfig = os.path.join(rpath, self.configFileDesktop)
        # get data from desktop config on success run get by archive
        if os.path.exists(fileConfig):
            objConfig = iniParser(fileConfig)
            data = self.getDataInConfig("main", ["status_sync"],
                                                 objConfig)
            if data:
                return data.get("status_sync",None)
        return None


    def getUserMountResources(self, userName, homeDir, flagRemoteServer):
        """
        Get information about remote profile resource
        """
        home = os.path.split(homeDir)[0]
        dictResources = OrderedDict(# share resource
                         share={"resource":"share",
                                  "path":os.path.join(homeDir,"Share")},
                         profile={"resource":"unix",
                                  "path":os.path.join(home,"."+userName)},
                         # resource - home directory
                         home={"resource":"homes",
                                 "path":os.path.join(homeDir,"Home")})
        if self.getInfoService("ftp", "host"):
            # resource ftp
            dictResources["ftp"] = {"resource":"ftp",
                                   "path":os.path.join(homeDir,"FTP")}
        if flagRemoteServer:
            # remote user profile
            dictResources["remote_profile"] = {"resource":"unix",
                            "path":os.path.join(home,"."+userName+"."+"remote")}
        return dictResources

    def mountSambaRes(self,host,userName,userPwd,uid,gid,res,rpath,
                      mountUidList=['ftp','homes','share']):
        """Mount samba resource"""
        if res in mountUidList:
            # mount by uid
            mountStr = \
                "mount -t cifs -o cache=loose,user=%s,uid=%s,gid=%s,noperm"\
                       %(userName,uid,gid) +\
                       " //%s/%s %s" %(host, res, rpath)
        else:
            # mount by root
            mountStr = \
                "mount -t cifs -o cache=loose,user=%s"%(userName)+\
                       " //%s/%s %s" %(host, res, rpath)
        textLine = self.execProg(mountStr, envProg={"PASSWD":userPwd})
        return textLine

    def mountSleepRes(self,host,userPwd,res,rpath):
        """
        Mount user resource with waiting if need
        """
        for waittime in [0.5,2,5]:
            if self.mountSambaRes(host,self.userName,userPwd,
                                  self.uid,self.gid,res,rpath) is False:
                # check on mount path
                if isMount(rpath):
                    if not self.umountSleepPath(rpath):
                        return False
                # wait
                time.sleep(waittime)
            else:
                return True
        return False

    def copyTemplateDir(self, srcDir, destDir):
        """
        Move directory srcDir to destDir
        """
        if os.system("mv %s %s &>/dev/null"%(srcDir, destDir)) != 0:
            raise ClientError(_("Failed to move %s")%srcDir + " " +\
                            _("to %s")%destDir)

    def upgradeUserProfile(self, userName, userHome, pathTemplates):
        """
        Update user profile (example /home/.user/.CLD to /home/.user/CLD)
        """
        # directory which keop old profile
        home = os.path.split(userHome)[0]
        if os.path.exists(pathTemplates):
            if self.clVars.Get("cl_profile_all_set") == "on":
                osLinuxShort = "all"
            else:
                osLinuxShort = self.clVars.Get("os_linux_shortname")
            pathNewTemplate = os.path.join(pathTemplates, osLinuxShort)
            pathOldTemplate = os.path.join(pathTemplates, "."+osLinuxShort)
            if not os.path.exists(pathNewTemplate) and\
                os.path.exists(pathOldTemplate) and\
                os.listdir(pathOldTemplate):
                # move profile
                self.copyTemplateDir(pathOldTemplate,pathNewTemplate)
            if not os.path.exists(pathNewTemplate):
                # create directory for profile keeping
                os.mkdir(pathNewTemplate)
                os.chmod(pathNewTemplate, 0700)
            if os.path.exists(pathOldTemplate) and\
                not os.listdir(pathOldTemplate):
                os.rmdir(pathOldTemplate)
        return True

    def syncUser(self, userName, userHome, sync, homeTemplate, \
                 host="default",skipList=[]):
        """
        Sync user profile from server or to server
        """
        flagError = False
        execStr = ""
        skipPaths = self.clVars.Get("cl_sync_skip_path")
        if not skipPaths:
            self.printERROR(
                _("Variable 'cl_sync_skip_path' empty")%userHome)
            return False
        deletePaths = self.clVars.Get("cl_sync_del_path")
        if not deletePaths:
            deletePaths = []
        excludePaths = " ".join(map(lambda x: '--exclude="/%s"'\
                                    %x.replace('"',"").replace("'",""),
                                    skipPaths + deletePaths + skipList))
        if sync == "login":
            if os.path.exists(userHome) and\
                os.path.exists(homeTemplate):
                filterPath = " ".join(map(lambda x: '--filter="P /%s"'\
                                        %x.replace('"',"").replace("'",""),
                                        skipPaths))
                execStr = '/usr/bin/rsync --delete-excluded --delete %s %s '\
                          '-rlptgo -x -v -v -v  %s/ %s/' \
                           %(excludePaths, filterPath, homeTemplate, userHome)
        elif sync == "logout":
            if os.path.exists(userHome) and os.listdir(userHome) and\
                os.path.exists(homeTemplate):
                execStr = '/usr/bin/rsync --delete-excluded --delete %s \
-rlptgo -x -v -v -v %s/ %s/'%(excludePaths, userHome, homeTemplate)
        else:
            raise ClientError(
                _("Method syncUser: option sync=%s is incorrect")%str(sync))
        if execStr:
            host = "<i>" + host +"</i>"
            if sync == "login":
                rsync = RsyncProgressBar(\
                        _("Receiving the file list from %s") % host,
                        _("Fetching the user profile from %s") % host,
                        execStr,self)
            else:
                rsync = RsyncProgressBar(\
                        _("Sending the file list to %s") % host,
                        _("Uploading the user profile to %s") % host,
                        execStr,self)
            pathConfig = os.path.join(homeTemplate,
                                      self.pathConfig)
            # remove old ini file
            prevIniFile = os.path.join(homeTemplate,".calculate.ini")
            if os.path.exists(prevIniFile):
                os.remove(prevIniFile)
            # create home directory
            if not os.path.exists(pathConfig):
                self.createUserDirectory(pathConfig)
            numfiles = 0
            configFileName = os.path.join(homeTemplate, self.configFileDesktop)
            if sync == "login":
                # get rsync files
                try:
                    numfiles = \
                        iniParser(configFileName).getVar('rsync','files')
                    if numfiles is False:
                        if os.path.exists(configFileName):
                            os.remove(configFileName)
                        numfiles = 0
                    else:
                        numfiles = int(numfiles)
                except:
                    numfiles = 0
            rsync.maximum = numfiles
            if sync == "login":
                rsync.run()
            if sync == "logout":
                rsync.run()
                try:
                    if iniParser(configFileName).setVar('rsync',
                                                {'files':rsync.getFilesNum()}):
                        os.chmod(configFileName, 0600)
                        os.chown(configFileName,self.uid,self.gid)
                except:
                    pass
            rsync.close()
            if rsync.getExitCode() != 0:
                try:
                    if iniParser(configFileName).setVar(\
                            'rsync',{'exitcode':rsync.getExitCode()}):
                        os.chmod(configFileName, 0600)
                        os.chown(configFileName,self.uid,self.gid)
                except:
                    pass
                self.printERROR(rsync.getErrMessage())
                self.printERROR(_("Failed to execute rsync") + " " + \
                            str(sync) + " ...")
                return False
        # change permissions
        changeDirs = [userHome, homeTemplate]
        for changeDir in changeDirs:
            # get directory permissions
            mode = getModeFile(changeDir, mode="mode")
            # if permission wrong( not 0700) then change it
            if mode != 0700:
                os.chmod(changeDir,0700)
        return True

    def clearHomeDir(self, homeDir):
        """Clear home directory"""
        rmFiles = list(set(os.listdir(homeDir))-\
                    set(self.skipHomeFile))
        for rmFile in rmFiles:
            delFile = os.path.join(homeDir,rmFile)
            if os.path.islink(delFile):
                os.unlink(delFile)
            elif os.path.isfile(delFile):
                os.remove(delFile)
            elif os.path.isdir(delFile):
                if not removeDir(delFile):
                    return False
            elif stat.S_ISSOCK(os.stat(delFile)[stat.ST_MODE]):
                os.remove(delFile)
        return True

    def syncLoginProfile(self, host, homeDir, homeProfile,
                         flagClearHomeDir=True):
        """
        Get user profile from server
        """
        # if currect server has any files then sync it
        if filter(lambda x: not x in ('.calculate',), os.listdir(homeProfile)):
            if not self.syncUser(self.userName, homeDir, "login",
                                 homeProfile, host=host):
                return False
        # remove home directory on workstation
        else:
            if flagClearHomeDir:
                # clean home directory
                if not self.clearHomeDir(homeDir):
                    return False
        return True

    def getDataInConfig(self, section, listVars, objConfig):
        """
        Read variables listVars from section in configuration file
        """
        varsConfig = {}
        for varName in listVars:
            varsConfig[varName] = objConfig.getVar(section,varName)
        if objConfig.getError():
            return False
        return varsConfig

    def foundArchFile(self,strCurrentTime,archPathProcess,
                      archPathSuccess, remoteServer=False):
        """Found user profile archive"""
        self.startTask(_("Packing the archive on the server"),
                        progress=True)
        for sleeptime in [0.1,0.2,0.5]:
            # archive in packing process found
            if os.path.exists(archPathProcess) or \
                os.path.exists(archPathSuccess):
                break
            time.sleep(sleeptime)
        else:
            # archive not found
            self.endTask(False)
            return False

        # wait finish packing
        if os.path.exists(archPathProcess) or \
            os.path.exists(archPathSuccess):
            while os.path.exists(archPathProcess) or \
                os.path.exists(archPathSuccess):
                for waittime in [0.5,1,2]:
                    if os.path.exists(archPathSuccess):
                        self.endTask()
                        return True
                    try:
                        startSize = os.stat(archPathProcess).st_size
                        time.sleep(waittime)
                        if startSize != os.stat(archPathProcess).st_size:
                            break
                    except OSError as e:
                        if os.path.exists(archPathSuccess):
                            self.endTask()
                            return True
                # run out of time size change
                else:
                    # archive size was not change above 4s => archive not found
                    self.endTask(False)
                    return False
        self.endTask(False)
        return False

    def fileReader(self, fileName, stdin, maxSize):
        """
        Read file by block
        """
        fd = os.open(fileName, os.O_RDONLY)
        currSize = 0
        # default buffer size
        buffSize=131072
        dataBlock = os.read(fd, buffSize)
        while dataBlock:
            currSize += len(dataBlock)
            self.setProgress(currSize*100/maxSize)
            stdin.write(dataBlock)
            dataBlock = os.read(fd, buffSize)
        stdin.close()
        os.close(fd)

    def moveArch(self, srcArchFile, dstArchFile, remoteServer=False, mode=0600):
        """
        Move archive from one directory to other
        """
        class copyTo(color_print):
            def __init__(self, destFile):
                self.FD = open(destFile, "w")
                os.chmod(destFile, mode)
            def write(self, data):
                self.FD.write(data)
            def close(self):
                self.FD.close()
        try:
            copyToObj = copyTo(dstArchFile)
        except:
            raise ClientError(_("Failed to create file '%s'")%dstArchFile)
        archiveSize = os.stat(srcArchFile).st_size or 1
        try:
            self.fileReader(srcArchFile, copyToObj, archiveSize)
        except:
            raise ClientError(_("Failed to copy '%(from)s' -> '%(to)s'")\
                            %{'from':srcArchFile,
                              'to':dstArchFile})

    def unpackArch(self, homeDir, archFile, remoteServer=False):
        """
        Unpack archive into user home directory
        """
        archiveSize = os.stat(archFile).st_size
        execStr = "tar -C '%s' -xzf -" %homeDir
        # run unpacking process
        pipe = subprocess.Popen(execStr,
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE,
                                close_fds=True,
                                env=os.environ, shell=True)
        # read file into pipe
        self.fileReader(archFile, pipe.stdin,archiveSize)
        ret = pipe.wait()
        pipe.stdout.close()
        pipe.stderr.close()
        if ret:
            self.printWARNING(_("Failed to execute %s") %execStr)
            self.printWARNING(_("Failed to unpack %s") %archFile)
            return False
        return True

    def setVarToConfig(self, nameSection, varsDict, configFileName):
        """Записывает переменную в файл конфигурации"""
        # Создаем директорию для конфигурационных файлов
        pathConfig = os.path.split(configFileName)[0]
        if not os.path.exists(pathConfig):
            self.createUserDirectory(pathConfig)
        try:
            if iniParser(configFileName).setVar(nameSection, varsDict):
                os.chmod(configFileName, 0600)
                os.chown(configFileName,self.uid,self.gid)
        except:
            return False
        return True

    def convertDate(self,strdate,dateformat="%Y-%m-%d %H:%M:%S"):
        """
        Convert date from string format (dateformat) to stuct or None
        """
        if strdate:
            try:
                return time.strptime(strdate,dateformat)
            except ValueError:
                pass
        return None

    def getDateObjClientConf(self, fileConfig):
        """
        Return time object from config file .calculate/desktop.env
        """
        if os.path.exists(fileConfig):
            objConfig = iniParser(fileConfig)
            data = self.getDataInConfig("main", ["date", "date_logout"],
                                        objConfig)
            timeLogout = data["date_logout"]
            timeConfig = data["date"]
            dates = filter(None,
                    [self.convertDate(timeLogout),
                     self.convertDate(timeConfig)])
            if dates:
                return dates[0]
        return False

    def createUserDirectory(self,userdir):
        """
        Create directory with user permissions
        """
        if not os.path.exists(userdir):
            try:
                os.mkdir(userdir)
                os.chown(userdir, self.uid, self.gid)
                os.chmod(userdir,0700)
            except OSError:
                raise ClientError(_("Error creating the directory")+
                                  _("Permission denied: '%s'")%userdir)

    def checkNeedSync(self,rpath,curTimeObj,curStatusSync,osLinuxShort):
        """
        Check about need sync with domain profile by profile time
        """
        # upgrade user profile or create need profile directory
        self.upgradeUserProfile(self.userName, self.homeDir, rpath)
        # profile directory
        fileConfig = os.path.join(self.homeDir, self.configFileServer)
        pathProfile = os.path.join(rpath, osLinuxShort)
        if readFile(fileConfig).strip():
            return True,pathProfile
        fileSoftConfigThis = os.path.join(pathProfile,
                                      self.configFileSoft)
        fileSoftConfigCur = os.path.join(self.homeDir,
                                      self.configFileSoft)
        xSessionCur = iniParser(fileSoftConfigCur).getVar('main','xsession')
        xSessionThis = iniParser(fileSoftConfigThis).getVar('main','xsession')
        # check profile date on current server
        fileConfigThis = os.path.join(pathProfile,
                                      self.configFileDesktop)
        if iniParser(fileConfigThis).getVar('main','status_sync') == "success":
            self.setVarToConfig("main", {"status_sync":"success_mount"},
                                fileConfigThis)
        thisTimeObj = self.getDateObjClientConf(fileConfigThis)
        if curStatusSync == "success_logout" and \
            xSessionCur == xSessionThis and \
            thisTimeObj and curTimeObj and \
            curTimeObj >= thisTimeObj:
            return False,pathProfile
        return True,pathProfile

    def mountLocalDomainRes(self,userPwd,dictRes):
        """
        Mount all local samba resource
        """
        res = True
        configFileName = os.path.join(self.homeDir, self.configFileDesktop)
        for name in dictRes.keys():
            if name == "remote_profile":
                continue
            rpath = dictRes[name]["path"]
            res = dictRes[name]["resource"]
            # create user directory
            self.createUserDirectory(rpath)
            # is directory already mount
            if isMount(rpath):
                continue
            else:
                if self.mountSleepRes(self.domain, userPwd,
                                      res, rpath) is False:
                    if name == "profile":
                        self.printWARNING(_("Failed to mount the user profile"))
                        res = False
                        continue
                    else:
                        raise ClientError(
                            _("Failed to mount Samba resource [%s]")%res)
                elif name == "profile":
                    # upgrade user profile or create need profile directory
                    self.upgradeUserProfile(self.userName, self.homeDir, rpath)
        else:
            return res
        return False

    def syncLocalDomainRes(self,userPwd,dictRes,curTimeObj,curStatusSync,
                           osLinuxShort,fromRemote=False):
        """
        Sync profile with current server

        fromRemote - method called by remote sync method
        """
        if self.mountLocalDomainRes(userPwd,dictRes):
            if not self.sync: return True
            if "profile" in dictRes:
                rpath = dictRes["profile"]["path"]
                needSync,lDomainProfile = self.checkNeedSync(rpath, curTimeObj,
                                                    curStatusSync,osLinuxShort)
                if not needSync:
                    if fromRemote:
                        self.printSUCCESS(_("The local user profile does not "
                              "need to be synchronized with local domain"))
                    else:
                        self.printSUCCESS(_("The local user profile will be "
                                            "used"))
                    # Copy private files from the server
                    self.copyPrivateFiles(lDomainProfile, self.homeDir)
                    return True
                else:
                    # sync profile with current server
                    return self.syncLoginProfile(self.domain,self.homeDir,
                                                 lDomainProfile)
        return False

    def _getRemoteServerProfileByArch(self,dictRes,rHomeProfile,
                                      dateDefaultTemplate,userPwd,curTimeObj,
                                      curStatusSync,remoteServer,
                                      osLinuxShort):
        """
        Try get profile from remote server
        """
        # current time
        currTime = str(float(time.time()))
        archPathSuccess,archPathProcess,archPathSrc,archPathDst = \
            (None,None,None,None)
        try:
            rpath = dictRes["remote_profile"]["path"]
            res = dictRes["remote_profile"]["resource"]
            # create command for create incremental arch
            fileConfig = \
                os.path.join(rHomeProfile,self.configFileServer)
            varsConfig = {"arch_date":dateDefaultTemplate,
                          "curr_time":currTime}
            try:
                self.setServerCommand(["pack"], varsConfig, fileConfig)
            except ClientError as e:
                return False
            rFileConfig = os.path.join(rHomeProfile, self.configFileDesktop)
            self.setVarToConfig("main", {"status_sync":"success"},
                            rFileConfig)
            self.umountSleepPath(rpath)

            if not self.syncLocalDomainRes(userPwd,dictRes,curTimeObj,
                                       curStatusSync,osLinuxShort,
                                       fromRemote=True):
                return False

            if self.mountSleepRes(remoteServer, userPwd, res, rpath) is False:
                return False
            self.setVarToConfig("main", {"status_sync":"success_mount"},
                            rFileConfig)
            extSuccess = "gz"
            extProcess = "process"
            strCurrentTime = currTime.replace(".","_")
            archPathTmp = os.path.join(rpath, "profile.%s.%s.tar"\
                           %(osLinuxShort, strCurrentTime))
            # result archive file name
            archPathSuccess = "%s.%s"%(archPathTmp,extSuccess)
            # archive in pack process
            archPathProcess = "%s.%s"%(archPathTmp,extProcess)
            # find archive file
            if not self.foundArchFile(strCurrentTime, archPathProcess,
                                      archPathSuccess,
                                      remoteServer):
                self.printWARNING(_("Failed to find the profile "
                                    "archive from %s")%
                            remoteServer)
                return False
            if os.path.exists(archPathSuccess):
                archPathSrc = archPathSuccess
                archPathDst = ".".join(filter(lambda x: x!="/",
                                       archPathSuccess.rpartition("/")))
                # get archive
                self.startTask(_("Copying archive from the server"),
                       progress=True)
                try:
                    self.moveArch(archPathSrc, archPathDst,
                                     remoteServer)
                except ClientError as e:
                    self.printWARNING(str(e))
                    return False
                self.endTask()
                # unpack archive into home directory
                self.startTask(_("Unpacking the profile"),progress=True)
                if not self.unpackArch(self.homeDir, archPathDst,
                                       remoteServer):
                    self.printERROR(_("Failed to unpack"))
                    return False
                # get removed files list
                pathListFile = os.path.join(rHomeProfile,
                                            self.listTemplFile)
                if not self.removeFilesInProfile(self.homeDir,pathListFile):
                    self.printWARNING(_("Unable to remove useless files"))
                    return False
                self.endTask()
                return True
            return False
        finally:
            for rmFile in (archPathSuccess,archPathProcess,
                           archPathSrc,archPathDst):
                if rmFile and os.path.exists(rmFile):
                    os.remove(rmFile)

    def syncRemoteDomainRes(self,userPwd,dictRes,remoteServer,curTimeObj,
                            curStatusSync,osLinuxShort):
        """
        Sync if actual profile is kept on a remote server
        """
        # mount directories path
        if not "remote_profile" in dictRes:
            return False
        if not self.sync:
            self.mountLocalDomainRes(userPwd,dictRes)
            return True
        rpath = dictRes["remote_profile"]["path"]
        res = dictRes["remote_profile"]["resource"]
        # create user directory
        self.createUserDirectory(rpath)
        # mount remote profile
        if isMount(rpath):
            self.printWARNING(_("Remote profile already mounted"))
            return False
        else:
            if self.mountSleepRes(remoteServer, userPwd, res, rpath) is False:
                return False

        try:
            rpath = dictRes["remote_profile"]["path"]
            needSync,pathRProfile = self.checkNeedSync(rpath,curTimeObj,
                                                       curStatusSync,osLinuxShort)
            if not needSync:
                # Copy private files from the server
                self.printSUCCESS(_("The local user profile will be used"))
                if not self.mountLocalDomainRes(userPwd,dictRes):
                    return False
                self.copyPrivateFiles(pathRProfile, self.homeDir)
                return True
            localServer = self.domain
            # mount local samba resources
            if self.mountLocalDomainRes(userPwd,dictRes):
                lpath = dictRes["profile"]["path"]
                homeLProfile = os.path.join(lpath, osLinuxShort)
                if not os.path.exists(homeLProfile):
                    homeLProfile = os.path.join(lpath, "." + osLinuxShort)
                lFileConfig = os.path.join(homeLProfile, self.configFileDesktop)
                # get data from desktop config on success run get by archive
                if os.path.exists(lFileConfig):
                    objConfig = iniParser(lFileConfig)
                    data = self.getDataInConfig("main", ["status_sync",
                                                         "date","date_logout"],
                                                         objConfig)
                    if data:
                        status = data.get("status_sync")
                        date = data.get("date")
                        date_logout = data.get("date_logout")
                        if date and date_logout:
                            diffdate = \
                                abs(time.mktime(self.convertDate(date))-
                                   time.mktime(self.convertDate(date_logout)))
                        else:
                            diffdate = None
                        # if diff date less 10 min
                        if diffdate is None or diffdate < 600:
                            if date and "success" in status:
                                if self._getRemoteServerProfileByArch(dictRes,
                                            pathRProfile,date,userPwd,
                                            curTimeObj, curStatusSync,
                                            remoteServer, osLinuxShort):
                                    return True
                        else:
                            self.printWARNING(
                                _("Time differs between server and client "
                                  "for more than 10 minutes"))
                            self.printWARNING(_("Profile synchronization "
                                    "will be applied without archiving"))
            # sync local before remote sync
            self.syncLocalDomainRes(userPwd,dictRes,curTimeObj,
                                       curStatusSync,osLinuxShort,
                                       fromRemote=True)
            # get user profile from remote domain
            return self.syncLoginProfile(remoteServer, self.homeDir,
                                         pathRProfile, False)
        finally:
            # unmount remote profile
            if self.sync and "remote_profile" in dictRes:
                if isMount(rpath):
                    if not self.umountSleepPath(rpath):
                        raise ClientError(_("Failed to unmount the "
                                            "remote profile"))
                # remote directory for remote
                if os.path.exists(rpath) and not os.listdir(rpath):
                    os.rmdir(rpath)

    def errorUmountUserRes(self,error):
        """
        Post action for umount user res and write status_sync=error
        """
        self.closeClTemplate()
        if error and self.homeDir:
            umountResult = self.umountUserRes(self.homeDir)
            configFileName = os.path.join(self.homeDir, self.configFileDesktop)
            uid = self.clVars.Get('ur_uid')
            gid = self.clVars.Get('ur_gid')
            self.setVarToConfig("main", {"status_sync":"error"},
                                configFileName)
            self.printERROR(_("Failed to get the user profile from the domain"))
            return umountResult
        return True

    def createCryptDir(self,userName,uid,gid,userDir):
        """
        Создать шифрование домашней директории, или подключить существующую
        """
        userPwd = getKey(userName)
        if not userPwd or userPwd == "XXXXXXXX":
            raise ClientError(_("User password not found"))
        ecryptfsPath = path.join('/home/.ecryptfs',userName)
        if path.exists(ecryptfsPath):
            for d in (".ecryptfs",".Private"):
                source,target = path.join(ecryptfsPath,d),path.join(userDir,d)
                if not path.lexists(target):
                    os.symlink(source,target)
            error = ""
            try:
                if mountEcryptfs(userName,userPwd,userDir):
                    return True
            except CommonError as e:
                error = str(e)
        if error:
            if self.getMountUserPaths(userDir):
                raise ClientError(_("Failed to use crypt directory"))
            for source in (userDir,ecryptfsPath):
                if path.exists(source):
                    if listDirectory(source):
                        target = source+".bak"
                        newtarget = target
                        for i in count(2):
                            if not path.exists(newtarget):
                                break
                            newtarget = "%s.%d"%(target,i)
                        os.rename(source,newtarget)
                    else:
                        os.rmdir(source)
        if not os.path.exists(userDir):
            os.makedirs(userDir)
            os.chown(userDir,uid,gid)
            os.chmod(userDir,0700)

        e = process('/usr/bin/ecryptfs-setup-private',
                    '-u',userName,'-b','-l',userPwd,stderr=STDOUT)
        if e.failed():
            raise ClientError(e.read()+
                _("Failed to create encrypt user profile"))

    def initEnv(self):
        """
        Init object variables
        """
        try:
            self.uid = int(self.clVars.Get('ur_uid'))
            self.gid = int(self.clVars.Get('ur_gid'))
        except ValueError as e:
            raise ClientError(_("Failed to resolve UID and GID"))
        self.sync = self.clVars.Get('cl_client_sync') == 'on'
        self.userName = self.clVars.Get("ur_login")
        self.homeDir = self.clVars.Get('ur_home_path')
        self.domain = self.clVars.Get("cl_remote_host")

    @safetyWrapper(native_errors=(TemplatesError,ClientError),
                   man_int=__("Manually interrupted"),
                   post_action=errorUmountUserRes)
    def mountUserResAndSync(self,dv):
        """Mount user resources and sync profile"""
        self.initVars(dv)
        self.initEnv()
        if self.domain:
            foundMountRemote = isMount("/var/calculate/remote")
            if not foundMountRemote:
                self.mountRemote(byUserSync=True);
        # check on two session user login
        if self.isTwoSessionsUser(self.userName):
            return False
        hostAuth = self.clVars.Get("os_remote_auth")

        # if not domain
        if not hostAuth or not self.domain:
            self.printSUCCESS(_("The local profile will be used"))
            return True

        try:
            passwdUsers = map(lambda x: x[0],
                          map(lambda x: x.split(':'),
                          map(lambda x: x.strip(),
                          open("/etc/passwd").readlines())))
        except:
            self.printERROR(_("Failed to open /etc/passwd"))
            return False
        if self.userName in passwdUsers:
            try:
                pwdObj = pwd.getpwnam(self.userName)
            except:
                raise ClientError(_("User %s not found")%self.userName)
            self.printWARNING(_("User information from /etc/passwd is used"))
            return True
        # check for domain workstation and [remote] was mounted
        if not self.isDomain():
            raise ClientError(_("The computer is not in the domain"))
        # create home directory if it is not exists
        if not os.path.exists(self.homeDir):
            os.makedirs(self.homeDir)
            os.chown(self.homeDir,self.uid,self.gid)
            os.chmod(self.homeDir,0700)
        if self.clVars.Get('ur_home_crypt_set') == 'on':
            self.createCryptDir(self.userName,self.uid,self.gid,self.homeDir)
        # user config filename
        configFileName = os.path.join(self.homeDir, self.configFileDesktop)
        # user time object from config file
        currentTimeObj = self.getDateObjClientConf(configFileName)
        currentStatusSync = self.getSyncStatus(self.homeDir)
        # get local date and statusSync
        # write into config status "process"
        self.setVarToConfig("main", {"status_sync":"process"}, configFileName)
        # get user password from key kernel
        userPwd = getKey(self.userName)
        if not userPwd or userPwd == "XXXXXXXX":
            raise ClientError(_("User password not found"))
        # user cache
        if not self.cAddUserToCache(self.userName, userPwd):
            self.printWARNING(_("Unable to cache user info"))
        # profile name
        if self.clVars.Get("cl_profile_all_set") == "on":
            osLinuxShort = "all"
        else:
            osLinuxShort = self.clVars.Get("os_linux_shortname")
        # if replication is on
        replOn = self.ldapDataObj.isRepl()
        # remote domain name
        if replOn:
            remoteServer = self.ldapDataObj.getNameRemoteServer(
                                self.userName, osLinuxShort, self.domain)
        else:
            remoteServer = ""
        # get mount directory
        dictRes = self.getUserMountResources(self.userName, self.homeDir,
                                                    remoteServer)
        if isMount(dictRes["profile"]["path"]):
            self.sync = False
        useRemoteProfile = remoteServer and replOn
        profileServer = self.domain
        # if profile on remote server
        if useRemoteProfile:
            if not self.syncRemoteDomainRes(userPwd,dictRes,
                            remoteServer,currentTimeObj,
                            currentStatusSync,osLinuxShort):
                syncStatus = "error"
                useRemoteProfile = False
                self.printWARNING(
                    _("Error synchronizing with the remote server %s")
                                %remoteServer)
            else:
                syncStatus = "success"
                profileServer = remoteServer
        # if profile not remote or remote sync is failed
        if not useRemoteProfile:
            if self.syncLocalDomainRes(userPwd,dictRes,currentTimeObj,
                                       currentStatusSync,osLinuxShort):
                # if not fallback for remote sync
                if not(remoteServer and replOn):
                    syncStatus = "success"
            else:
                syncStatus = "error"
                self.printWARNING(
                    _("Error synchronizing with the remote server %s")
                                %self.domain)
        if self.sync:
            self.setVarToConfig("main", {"status_sync":syncStatus},
                            configFileName)
        # unpack link from link arch
        self.unpackLinks(self.homeDir)

        self.printSUCCESS(_("Mounted user resource of the domain"))
        if self.sync:
            if syncStatus == "error":
                if remoteServer and replOn:
                    self.printWARNING(
                        _("Get a user fallback profile from the %s domain")
                          %profileServer)
                self.printWARNING(
                    _("Changings in the user profile will not "
                      "be saved to the domain"))
            else:
                self.printSUCCESS(_("Get the user profile from domain %s")%
                              profileServer)
        return True

    def isSessionUser(self, userName):
        """
        Check for user in X session
        """
        reFoundUser = re.compile("%s\s+:\d+\s+"%(userName))
        resWho = self.execProg("who")
        if resWho:
            if any(reFoundUser.search(x) for x in resWho):
                return True
        return False

    def tarSymLinks(self,userHome,uid,gid):
        """Create tar archive of symlinks"""
        linkArch = pathJoin(userHome,".calculate/links.tar.bz2")
        symList = []
        try:
            symList = list(tarLinks(userHome,linkArch,
                                 skip=self.clVars.Get("cl_sync_del_path")+
                                 self.clVars.Get("cl_sync_skip_path")))
                #try:
                #    os.unlink(filename)
                #except OSError:
                #    self.printWARNING(_("Failed to remove %s")%filename)
        except:
            self.printWARNING(_("Failed to make a links archive"))
        try:
            if os.path.exists(linkArch):
                os.chown(linkArch,uid,gid)
        except:
            self.printWARNING(_("Failed to make a links archive"))
        return symList

    def unpackLinks(self,userHome):
        """Unpack archive of symlinks"""
        linksArch = pathJoin(userHome,".calculate/links.tar.bz2")
        try:
            if os.path.exists(linksArch):
                tf = tarfile.open(linksArch)
                tf.extractall(userHome)
                tf.close()
        except:
            self.printWARNING(_("Failed to unpack the links archive"))

    def moveHomeDir(self, userHome):
        """
        Move non profile files in root of home profile to Home/Moved
        """
        pathProg = os.getcwd()
        os.chdir(userHome)
        dirs = []
        files = []
        movedLink = os.path.join('Moved')
        movedPath = os.path.join('Home',"Moved")
        skipPaths = self.clVars.Get("cl_moved_skip_path")
        if not skipPaths:
            skipPaths = ['Disks','Share','Home','Moved','FTP','Desktop']
        filesAndDir = filter(lambda x: not ('.' in x[0] or x in\
            skipPaths or os.path.islink(x)),
            os.listdir('.'))
        filesDir = []
        for fd in filesAndDir:
            if os.path.islink(fd):
                os.unlink(fd)
            else:
                filesDir.append(fd)
        # find files in Desktop
        pathDesktop = './Desktop'
        filesDirDesk = []
        if os.path.exists(pathDesktop):
            filesDirDesk = filter(lambda x: not os.path.islink(x) and\
                not os.path.split(x)[1].startswith('.') and\
                not x.rpartition('.')[2]=='desktop',
                map(lambda x: os.path.join(pathDesktop,x),\
                    os.listdir(pathDesktop)))
        movedPathDesk = os.path.join(movedPath, pathDesktop)
        filesDir += filesDirDesk
        if not filesDir or not os.path.exists("Home"):
            # remote empty Moved folder
            if os.path.exists(movedPath) and not os.listdir(movedPath):
                os.rmdir(movedPath)
            # remote link to Moved in home directory
            if os.path.islink(movedLink) and not os.path.exists(movedPath):
                os.unlink(movedLink)
            os.chdir(pathProg)
            return True
        if not os.path.exists(movedPath):
            os.mkdir(movedPath)
        directFile = os.path.join(movedPath,".directory")
        if not os.path.exists(directFile):
            txt = "[Desktop Entry]\nIcon=folder-development"
            fd = os.open(directFile, os.O_CREAT)
            os.close(fd)
            FD  = open (directFile, "r+")
            FD.write(txt)
            FD.close()
        if not os.path.exists(movedLink):
            os.symlink(movedPath, movedLink)
        for fd in filesDir:
            execStr = "cp -r '%s' '%s'" %(fd, movedPath)
            textLine = self.execProg(execStr)
            if textLine is False:
                self.printERROR(_("Failed to execute") + " " + str(execStr))
                os.chdir(pathProg)
                return False
            execStr = "rm -rf '%s'" %fd
            textLine = self.execProg(execStr)
            if textLine is False:
                self.printERROR(_("Failed to execute") + " " + str(execStr))
                os.chdir(pathProg)
                return False
        os.chdir(pathProg)
        return True

    def removeNoiseFiles(self, userHome):
        """
        Remove files which hinder dm
        """
        noiseFiles = []
        for nsFile in noiseFiles:
            rmFile = os.path.join(userHome, nsFile)
            if os.path.exists(rmFile):
                os.remove(rmFile)
        return True

    def getPrivateFiles(self, userHome):
        """
        Get all private files relative user home directory
        """
        privateFiles = []
        for privateHomeDir in self.privateDirs:
            privateDir = os.path.join(userHome,privateHomeDir)
            if os.path.isdir(privateDir):
                # .ssh files relative user home directory
                privateFiles += map(lambda x:os.path.join(privateHomeDir,x),
                                    filter(lambda x:\
                                    os.path.isfile(os.path.join(privateDir,x)),
                                    os.listdir(privateDir)))
        return self.privateFiles + privateFiles

    def removePrivateFiles(self, userHome):
        """
        Remove private files
        """
        privateFiles = self.getPrivateFiles(userHome)
        for prFile in privateFiles:
            rmFile = os.path.join(userHome, prFile)
            if os.path.exists(rmFile):
                os.remove(rmFile)
        return True

    def copyPrivateFiles(self, serverProfileDir, userHomeDir):
        """
        Copy privates files from server to home directory
        """
        privateFiles = self.getPrivateFiles(serverProfileDir)
        for prFile in privateFiles:
            src = os.path.join(serverProfileDir, prFile)
            dst = os.path.join(userHomeDir, prFile)
            if os.path.exists(src):
                dstPath = os.path.dirname(dst)
                if not os.path.exists(dstPath):
                    listElPath = []
                    for el in filter(lambda x: x,
                                  dstPath.partition(userHomeDir)[2].split("/")):
                        listElPath.append(el)
                        joinPath = "/".join(listElPath)
                        dPath = os.path.join(userHomeDir, joinPath)
                        if not os.path.exists(dPath):
                            sPath = os.path.join(serverProfileDir, joinPath)
                            sMode, sUid, sGid = getModeFile(sPath)
                            os.mkdir(dPath,sMode)
                            os.chown(dPath, sUid, sGid)
                copy2(src, dst)
                sUid, sGid = getModeFile(src, mode="owner")
                os.chown(dst, sUid, sGid)
        return True

    def scanDirectory(self, scanDir, listFiles, skipPath=[], prefix=False,
                       flagDir=False):
        """
        Generate file/directory list
        """
        if not prefix:
            prefix = os.path.join(scanDir,"")
        if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]):
            for fileOrDir in os.listdir(scanDir):
                absPath = os.path.join(scanDir,fileOrDir)
                relPath = absPath.split(prefix)[1]
                if relPath in skipPath:
                    continue
                listFiles.append(relPath)
                stInfo = os.lstat(absPath)
                statInfo = stInfo[stat.ST_MODE]
                if stat.S_ISDIR(statInfo):
                    self.scanDirectory(absPath, listFiles,
                                       skipPath, prefix, True)

    def getListFilesTemplate(self, homeDir):
        """
        Generation file list in user home directory, exclude mount dirs
        """
        home = os.path.join(homeDir, "")
        execStr = "mount"
        textLines = self.execProg(execStr)
        # skip directories in scanning
        skipPaths = []
        if textLines:
            for line in textLines:
                if home in line:
                    skipPath =\
                    line.partition(home)[2].rpartition(" type")[0]
                    skipPaths.append(skipPath)
        # file list in user profile
        listFiles = []
        if not skipPaths:
            self.printERROR(_("Mounting point for server resource not found"))
            return False
        self.scanDirectory(homeDir, listFiles, skipPaths)
        return listFiles

    def removeFilesInProfile(self, homeDir, pathListFile):
        """
        Remove files which is absend in user profile
        """
        # read file list from config
        try:
            filesTemplateTxt = open(pathListFile).read()
        except:
            return False
        listFilesTemplate = filter(lambda x:  x.strip(),
                                  filesTemplateTxt.split("\n"))
        filesTemplate = set(listFilesTemplate)
        # get files in home directory
        listFilesHome = self.getListFilesTemplate(homeDir)
        if listFilesHome is False:
            return False
        filesHome = set(listFilesHome)
        filesRemove = list(filesHome - filesTemplate)
        filesRemove.sort(lambda x, y: cmp(len(y), len(x))) 
        rmPath = ""
        try:
            for rmFile in filesRemove:
                rmPath = os.path.join(homeDir, rmFile)
                if os.path.islink(rmPath):
                    os.unlink(rmPath)
                elif os.path.isfile(rmPath):
                    os.remove(rmPath)
                elif os.path.isdir(rmPath):
                    os.rmdir(rmPath)
                else:
                    os.remove(rmPath)
        except:
            return False
        return True

    def getRunCommandsWithEnv(self):
        """List run program"""
        def getCmd(procNum):
            cmdLineFile = '/proc/%s/cmdline'%procNum
            environFile = '/proc/%s/environ'%procNum
            try:
                if os.path.exists(cmdLineFile) and \
                   os.path.exists(environFile):
                    return (open(cmdLineFile,'r').read().strip(),
                            open(environFile,'r').read().strip())
            except:
                pass
            return ("","")
        if not os.access('/proc',os.R_OK):
            return []
        return map(getCmd,
               filter(lambda x:x.isdigit(),
               os.listdir('/proc')))


    def clearUserKey(self, userName):
        """
        Clear user key from kernel
        """
        # find user key in kernel and check on relogout
        if getKey(userName) and not \
            filter(lambda x:"xdm/xdm\x00--login" in x[0] and \
               ("USER=%s"%userName) in x[1],self.getRunCommandsWithEnv()):
            # clean
            ret = clearKey(userName)
            if ret == 0:
                return True
            else:
                self.printERROR(_("Failed to clear the kernel key for user %s")\
                                %userName)
                return False
        return True

    @safetyWrapper(native_errors=(TemplatesError,ClientError),
                   man_int=__("Manually interrupted"),
                   post_action=errorUmountUserRes)
    def umountUserResAndSync(self, dv):
        """
        Umount user resouces and synchronizatoin user profile
        """
        self.initVars(dv)
        self.initEnv()
        try:
            passwdUsers = map(lambda x: x[0],
                              map(lambda x: x.split(':'),
                                  map(lambda x: x.strip(),
                                      open("/etc/passwd").readlines())))
        except:
            self.printERROR(_("Failed to open /etc/passwd"))
            return False
        if not os.path.exists(self.homeDir):
            self.printERROR(_("User home directory %s not found")%self.homeDir)
            return False
        currentDateStr = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        # domain workstation work in local mode
        if self.userName in passwdUsers:
            configFileName = os.path.join(self.homeDir, self.configFileDesktop)
            self.setVarToConfig("main", {"date_logout":currentDateStr},
                                configFileName)
            self.printWARNING(_("User information from /etc/passwd is used"))
            self.printSUCCESS(_("The local profile will be used"))
            return True
        hostAuth = self.clVars.Get("os_remote_auth")
        # local mode
        if not hostAuth or not self.domain:
            self.printSUCCESS(_("The local profile will be used"))
            return True
        # check for domain workstation and [remote] was mounted
        if not self.isDomain():
            raise ClientError(_("The computer is not in the domain"))
        # check is user in X session, do not umount user resources
        if self.isSessionUser(self.userName):
            self.printERROR(_("User %s is already in X session")%self.userName)
            self.printERROR(
                _("Failed to unmount user %s resource")%self.userName)
            return False
        # user package config
        configFileName = os.path.join(self.homeDir, self.configFileDesktop)
        self.setVarToConfig("main", {"date_logout":currentDateStr},
                            configFileName)
        skipList = []
        if os.path.exists(self.homeDir):
            self.moveHomeDir(self.homeDir)
            if self.sync:
                skipList = self.tarSymLinks(self.homeDir,self.uid,self.gid)
                lHomeDir = len(self.homeDir)+1
                skipList = map(lambda x:x[lHomeDir:],skipList)
        else:
            raise ClientError(_("Directory %s not found") % self.homeDir)
        # get status sync
        exitStr = iniParser(configFileName).getVar('main','status_sync')
        # check on error or net full executed -> process
        if exitStr == "process" or exitStr == "error":
            self.sync = False
        if self.clVars.Get("cl_profile_all_set") == "on":
            osLinuxShort = "all"
        else:
            osLinuxShort = self.clVars.Get("os_linux_shortname")
        # get mount resources
        dictRes = self.getUserMountResources(self.userName, self.homeDir,False)
        pathUnix = dictRes["profile"]["path"]
        homeProfile = os.path.join(pathUnix, osLinuxShort)
        if not isMount(pathUnix):
            self.printERROR(_("Mounted remote resources for user %s not found")%
                            self.userName)
            self.umountUserRes(self.homeDir)
            return False
        try:
            if self.sync:
                # sync profiles local to domain
                if not self.syncUser(self.userName, self.homeDir, "logout",
                                              homeProfile,host=self.domain,
                                              skipList=skipList):
                    return False
        finally:
            # remove files, which hinder correct dm work
            self.removeNoiseFiles(self.homeDir)
            # remove private files
            self.removePrivateFiles(self.homeDir)
            # clean user password from root keys
            self.clearUserKey(self.userName)
            # umount user res
            if not self.umountUserRes(self.homeDir):
                return False

        # remove empty directories
        for name in dictRes.keys():
            rpath = dictRes[name]["path"]
            if os.path.exists(rpath) and not os.listdir(rpath):
                try:
                    os.rmdir(rpath)
                except:
                    self.printERROR(_("Failed to remove dir %s")% path)
                    return False
        # remove Disks directory if it empty
        pathDisks = os.path.join(self.homeDir,"Disks")
        if os.path.exists(pathDisks) and not os.listdir(pathDisks):
            try:
                os.rmdir(pathDisks)
            except:
                self.printERROR(_("Failed to remove dir %s")% pathDisks)
                return False
        if self.sync:
            self.printSUCCESS(_("Modified user profile saved in the domain"))
            self.setVarToConfig("main", {"status_sync":"success_logout"},
                                configFileName)
        self.printSUCCESS(_("Domain user resource unmounted"))
        return True

    def getMountUserPaths(self, homeDir=False):
        """
        Get users mount paths
        """
        if not homeDir:
            userName = self.clVars.Get("ur_login")
            try:
                homeDir = pwd.getpwnam(userName).pw_dir
            except:
                homeDir = os.path.join("/home",userName)
        dirStart, dirEnd = os.path.split(homeDir)
        mountTemplateDir = os.path.join(dirStart, ".%s" %dirEnd)
        mountRemoteTemplateDir = os.path.join(dirStart, ".%s.remote" %dirEnd)
        return filter(lambda x:x != homeDir,
               filter(lambda x: (x.startswith(homeDir) or
                                 x.startswith(mountTemplateDir) or
                                 x.startswith(mountRemoteTemplateDir)),
               map(lambda x: x.split(" ")[1],
               readLinesFile('/proc/mounts'))))

    def execProg(self, cmdStrProg, inStr=False, envProg={}):
        """
        Execute external program
        """
        env_path = {"PATH":getpathenv()}
        env = {}
        env.update(os.environ.items() + env_path.items() + envProg.items())
        retCode,programOut = runOsCommand(cmdStrProg,in_str=inStr,env_dict=env)
        if not retCode:
            return programOut
        return False

    def umountSleepPath(self, rpath):
        """
        Unmount path, sleep by failed and repeat
        """
        # check for mount
        if isMount(rpath):
            for waittime in [0,0.5,1,2]:
                time.sleep(waittime)
                if not self.execProg("umount %s"%rpath) is False \
                    or not isMount(rpath):
                    if not isMount(rpath):
                        return True
            self.execProg("fuser -km %s"%rpath)
            for waittime in [0.5, 0.5, 0.5, 0.5, 0.5, 0.5]:
                time.sleep(waittime)
                if not self.execProg("umount %s"%rpath) is False \
                    or not isMount(rpath):
                    if not isMount(rpath):
                        return True
            else:
                if isMount(rpath):
                    raise ClientError(_("Failed to unmount directory %s")%rpath)
        return True

    def umountUserRes(self, homeDir=False, removeEmpty=False):
        """
        Unmount user directories
        """
        res = True
        for umountPath in self.getMountUserPaths(homeDir):
            try:
                self.umountSleepPath(umountPath)
            except ClientError as e:
                self.printERROR(str(e))
                res = False
                continue
            if os.path.exists(umountPath) and not os.listdir(umountPath):
                os.rmdir(umountPath)
        return res

    def getDefaultRunlevelDaemons(self):
        """
        Get all daemons from default runlevel
        """
        execStr = "rc-update show"
        textLine = self.execProg(execStr)
        if textLine is False:
            self.printERROR(_("ERROR") + ": " + execStr)
            return False
        else:
            splLines = filter(lambda x: len(x)==2 and "default" in x[1],\
                              map(lambda x: x.split("|"),textLine))
            splLines = map(lambda x: x[0].strip(), splLines)
            return splLines

    def delDaemonAutostart(self, daemon):
        """
        Remove daemon from autorun
        """
        defaultDaemons = self.getDefaultRunlevelDaemons()
        if defaultDaemons is False:
            return False
        if daemon in defaultDaemons:
            execStr = "rc-update del %s default" %daemon
            textLine = self.execProg(execStr)
            if textLine is False:
                self.printERROR(_("ERROR") + ": " + execStr)
                self.printERROR(_("Failed to delete from the default runlevel"))
                return False
            else:
                return True
        return True

    def delDomain(self):
        """
        Remove from domain
        """
        pathRemote = "/var/calculate/remote"
        foundMountRemote = isMount(pathRemote)
        domain = self.clVars.Get("cl_remote_host")
        if foundMountRemote:
            textLineUmount = self.umountSleepPath(pathRemote)
            if not textLineUmount:
                return False
        if not domain:
            self.printWARNING(_("The computer is not in the domain"))
            return True
        # remove domain vars from env files
        self.removeVars()
        # apply templates for undomain
        self.clVars.Set("cl_action", "undomain", True)
        if not self.applyTemplatesFromSystem():
            self.printERROR(_("Failed to apply non-domain templates"))
            return False
        # Delete LDAP users from system and clear cache
        if not self.cDelLdapSysUsersAndClearCache():
            self.printERROR(_("Failed to clear the user cache"))
            return False
        # restart dbus
        self.restartDBus()
        if not self.delDaemonAutostart("client"):
            self.printERROR(
                _("Failed to remove the client service from autostart"))
            return False
        self.printSUCCESS(_("Computer removed from domain %s")%domain + " ...")
        return True

    def getUserPassword(self, pwDialog=False):
        """Получить пароль у пользователя

        pwDialog  - приглашение ввода пароля
        """
        if os.readlink('/proc/self/fd/0') == '/dev/console':
            os.system('chvt 1 &>/dev/null')
        if not pwDialog:
            pwDialog = _("Password")
        userPwd = getpass.getpass(pwDialog+":")
        return userPwd

    def addDaemonAutostart(self, daemon):
        """Прописывает демона в автозагрузку"""
        defaultDaemons = self.getDefaultRunlevelDaemons()
        if defaultDaemons is False:
            return False
        if daemon in defaultDaemons:
            return True
        execStr = "rc-update add %s default" %daemon
        textLine = self.execProg(execStr)
        if textLine is False:
            self.printERROR(_("ERROR") + ": " + execStr)
            self.printERROR(_("Failed to add to the default runlevel"))
            return False
        else:
            return True

    def restartDBus(self):
        """Restart D-Bus service"""
        # перезапуск dbus выключен, в связи с переходом
        # на новую схему ввода/вывода в домен
        return True
        dbusDaemon = '/sbin/rc-service -i dbus'
        existsDaemon = '/sbin/rc-service -e dbus'
        # if exists dbus and running
        if os.system(existsDaemon) == 0 and \
            os.system(dbusDaemon + ' status &>/dev/null') == 0:
            # restart
            if os.system(dbusDaemon + ' restart -- -s &>/dev/null') != 0:
                self.printWARNING(_("Error restarting")+" "+dbusDaemon+" ...")
                return False
        return True

    def getInfoService(self, service, option, envFile=False):
        """
        Get service parameter from env
        """
        if not envFile:
            if self.convObj == None:
                # file /var/calculate/remote/server.env
                envFile = self.clVars.Get("cl_env_server_path")
                if os.access(envFile, os.R_OK):
                    self.convObj = False
                elif os.access("/var/calculate/remote/calculate.env", os.R_OK):
                    self.convObj = convertEnv()
            if self.convObj:
                return self.convObj.getVar(service, option)
        if not self.optionsInfo:
            if not envFile:
                # file /var/calculate/remote/server.env
                envFile = self.clVars.Get("cl_env_server_path")
            optInfo = self.clVars.GetRemoteInfo(envFile)
            if optInfo is False:
                return False
            if optInfo:
                self.optionsInfo = optInfo
        value = ''
        if service in self.optionsInfo and option in self.optionsInfo[service]:
                value = self.optionsInfo[service][option]
        return value

    @safetyWrapper(native_errors=(TemplatesError,ClientError),
                   man_int=__("Manually interrupted"))
    def domain(self,dv):
        self.initVars(dv)
        if self.clVars.Get('cl_client_mount_set') == 'on':
            return self.mountRemote()
        else:
            if self.clVars.Get('cl_localhost_set') == "on":
                return self.delDomain()
            else:
                return self.addDomain()

    def addDomain(self):
        """
        Add to domain
        """
        domainName = self.clVars.Get('cl_remote_host_new')
        remoteHost = self.clVars.Get("cl_remote_host") 
        netDomain = self.clVars.Get("os_net_domain")
        # get domain name
        if "." in domainName:
            domain = domainName
        else:
            import socket
            domain = "%s.%s" %(domainName,netDomain)
            try:
                gethostbyname(domain)
            except socket.gaierror as e:
                domain = domainName
        # check domain by ping
        for i in range(0,1):
            try:
                Pinger().ping(domain,1000,16)
                break
            except IPError as e:
                pass
        else:
            self.printERROR(_("Server %s does not respond")%domain)
            return False
        reFoundHostSamba = re.compile("Server=\[Samba.+\]")
        resSmbClient = self.execProg("smbclient -N -L %s" %domain)
        foundHostSamba = False
        if not resSmbClient is False:
            for string in resSmbClient:
                if reFoundHostSamba.search(string):
                    foundHostSamba = True
                    break
        if not foundHostSamba:
            self.printERROR(_("Samba server not found in %s")%domain)
            return False
        if remoteHost and self.clVars.Get('cl_localhost_set') != 'on':
            self.printERROR(_("The computer is already in the domain %s")\
                              %remoteHost)
            self.printWARNING(_("Before joining the domain, "
                "you need to remove it from the previous domain"))
            self.printWARNING(_("Run 'cl-client -r'"))
            return False

        foundMountRemote = isMount("/var/calculate/remote")
        if foundMountRemote:
            self.printERROR(_("Samba resource [%s] mounted")%\
                                "remote" + " ...")
            return False
        else:
            def passwdQueue():
                remotePw = self.clVars.Get('cl_remote_pw')
                if remotePw:
                    yield remotePw
                if remotePw:
                    self.printERROR(_("Wrong password"))
                yield self.askPassword(\
                        _("Domain password for the desktop"),False)

            pathRemote = "/var/calculate/remote"
            for pwdRemote in passwdQueue():
                if not os.path.exists(pathRemote):
                    os.makedirs(pathRemote)
                if not self.mountSambaRes(domain,"client",pwdRemote,
                                   0,0,"remote",pathRemote) is False:
                    self.printSUCCESS(
                        _("Samba resource [%s] mounted")%"remote")
                    self.clVars.Write("cl_remote_host", domain, True, "local")
                    self.clVars.Write("cl_remote_pw", pwdRemote, True, "local")
                    break
            else:
                self.printERROR(
                    _("Failed to mount Samba resource [%s]")%"remote")
                return False
        servDn = self.getInfoService("ldap", "services_dn")
        unixDn = self.getInfoService("unix", "dn")
        bindDn = self.getInfoService("unix", "bind_dn")
        bindPw = self.getInfoService("unix", "bind_pw")
        # check info from server
        if not (servDn and unixDn and bindDn and bindPw):
            self.printERROR(_("Info not found on the server") + ": " +\
                _("services DN or unix DN or bind DN or bind password"))
            return False
        self.clVars.Set("cl_action", "domain", True)
        self.clVars.Set("os_remote_auth", domain)
        if not self.applyTemplatesFromSystem():
            self.printERROR(
                _("Failed to apply install templates or domain templates"))
            return False
        # restart dbus
        self.restartDBus()
        if not self.addDaemonAutostart("client"):
            return False
        # write domain to config
        self.clVars.Write("os_remote_auth", domain, True)
        # write current program version
        currentVersion = self.clVars.Get("cl_ver")
        self.clVars.Write("os_remote_client", currentVersion, True)
        self.printSUCCESS(_("Computer added to domain %s")%domain)
        return True

    def relevanceTemplates(self, hostAuth):
        """
        Determine relevance appling templates by program version
        """
        # ''  or hostname
        if hostAuth != self.clVars.Get("os_remote_auth"):
            return False
        if self.clTempl:
            self.closeClTemplate()
        self.clTempl = ProgressTemplate(self.setProgress,self.clVars,
                                        cltObj=True)
        # current program version
        currentVersion = self.clVars.Get("cl_ver")
        # version of program which appled templates
        previousVersion = self.clVars.Get("os_remote_client")
        cVersion,pVersion = self.clTempl._convertVers(currentVersion,previousVersion)
        if cVersion != pVersion:
            return False
        return True

    def closeClTemplate(self):
        if self.clTempl:
            if self.clTempl.cltObj:
                self.clTempl.cltObj.closeFiles()
            self.clTempl.closeFiles()
            self.clTempl = None


    def applyRelevanceTemplates(self, hostAuth=""):
        """
        Appling relevance templates
        """
        if not self.relevanceTemplates(hostAuth):
            if hostAuth:
                # add to domain
                self.clVars.Set("cl_action","domain",True)
            else:
                # del from domain
                self.clVars.Set("cl_action","undomain",True)
            self.clVars.Set("os_remote_auth", hostAuth)
            # apply system templates
            dirsAndFiles = self.applyTemplatesFromSystem()
            if not dirsAndFiles:
                if hostAuth:
                    self.printERROR(_("Failed to apply domain templates"))
                else:
                    self.printERROR(_("Failed to apply non-domain templates"))
                return False
            if hostAuth:
                self.printSUCCESS(_("Templates set for network mode"))
                currentVersion = self.clVars.Get("cl_ver")
                self.clVars.Write("os_remote_client", currentVersion, True)
                self.clVars.Write("os_remote_auth", hostAuth, True)
            else:
                self.printSUCCESS(_("Templates set for local mode"))
                self.clVars.Delete("os_remote_auth")
                self.clVars.Delete("os_remote_client")
        return True

    def cDelLdapSysUsersAndSyncCache(self):
        """Delete LDAP users from system and synchronize cache"""
        cacheObj = userCache()
        if not cacheObj.deleteCacheUsersFromSystem():
            return False
        if not cacheObj.syncCacheToLdap():
            return False
        return True

    def cAddCacheUsersFromSystem(self):
        """Add cache users from system"""
        cacheObj = userCache()
        if not cacheObj.addCacheUsersFromSystem():
            return False
        return True

    def cAddUserToCache(self, userName, userPwd):
        """Add user to cache"""
        cacheObj = userCache()
        pwdHash = self.getHashPasswd(userPwd, "shadow_ssha256")
        if not cacheObj.addUserToCache(userName, pwdHash):
            return False
        return True

    def cDelLdapSysUsersAndClearCache(self):
        """Delete LDAP users from system and clear cache"""
        cacheObj = userCache()
        if not cacheObj.deleteCacheUsersFromSystem():
            return False
        if not cacheObj.clearCache():
            return False
        return True

    def moveHomeDirs(self):
        """Move home dirs /var/calculate/client-home -> /home

        if user in cache
        """
        cacheObj = userCache()
        loginUsersData = cacheObj.getLoginDomainUsers()
        if loginUsersData is False:
            return False
        previousHome = "/var/calculate/client-home"
        if isMount(previousHome):
            return True
        if os.path.exists(previousHome):
            flagMovedUsers = False
            for userName,x,uid,gid,gecos,directory,shell in loginUsersData:
                homeDir = directory
                pathUserList = filter(lambda x: x, directory.split('/'))
                if not pathUserList:
                    continue
                pathUser = "/".join(pathUserList[1:])
                srcDir = pathJoin(previousHome, pathUser)
                if os.path.exists(srcDir) and not os.path.exists(homeDir):
                    flagMovedUsers = True
                    destDir = os.path.dirname(homeDir)
                    self.printWARNING(_("Moved %(src)s to %(dest)s")\
                                      %{"src":srcDir,"dest":homeDir})
                    if not self.copyTemplateDir(srcDir, destDir):
                        return False
            if flagMovedUsers and not os.listdir(previousHome):
                os.rmdir(previousHome)
        return True

    def mountRemote(self,byUserSync=False):
        """
        Mount remote domain resource for domain workstation.

        Alsa add to domain if found hostname and password
        """
        domain = self.clVars.Get("cl_remote_host")
        if domain:
            foundMountRemote = isMount("/var/calculate/remote")
        else:
            self.printWARNING(_("This computer is not in the domain"))
            if not self.applyRelevanceTemplates():
                return False
            return True
        if foundMountRemote:
            self.printWARNING(_("Samba resource [%s] mounted")%"remote" + \
                              " ...")
            # apply domain templates
            if domain:
                self.clVars.flIniFile()
                if not self.applyRelevanceTemplates(domain):
                    return False
                # Delete LDAP users from system and synchronize cache
                if not self.cDelLdapSysUsersAndSyncCache():
                    return False
            return True
        else:
            pathRemote = "/var/calculate/remote"
            pwdRemote = self.clVars.Get("cl_remote_pw")
            if not (domain and pwdRemote):
                self.printERROR(_("Variable not found")+\
                        ": cl_remote_pw ...")
                return False
            if not os.path.exists(pathRemote):
                os.makedirs(pathRemote)
            if self.mountSambaRes(domain,"client",pwdRemote,
                               0,0,"remote",pathRemote) is False:
                if not byUserSync:
                    self.printWARNING(
                        _("Failed to mount Samba resource [%s]")%\
                                        "remote" + " ...")
                beforeRemoteAuth = self.clVars.Get('os_remote_auth')
                # apply templates if current up-to-date
                if not self.applyRelevanceTemplates():
                    return False
                if not self.cAddCacheUsersFromSystem():
                    return False
                if not self.moveHomeDirs():
                    return False
                if beforeRemoteAuth != self.clVars.Get('os_remote_auth'):
                    self.restartDBus()
                return True
            self.printSUCCESS(_("Samba resource [%s] mounted") % "remote" +\
                                " ...")
        # apply domain templates
        if domain:
            self.clVars.flIniFile()
            beforeRemoteAuth = self.clVars.Get('os_remote_auth')
            if not self.applyRelevanceTemplates(domain):
                return False
            # Delete LDAP users from system and synchronize cache
            if not self.cDelLdapSysUsersAndSyncCache():
                return False
            if beforeRemoteAuth != self.clVars.Get('os_remote_auth'):
                self.restartDBus()
        return True

    @safetyWrapper(native_errors=(TemplatesError,ClientError),
                   man_int=__("Manually interrupted"))
    def clientPasswd(self,dv):
        """
        Change user password on server
        """
        self.initVars(dv)
        self.initEnv()

        # check on root
        if self.uid == 0:
            self.printERROR(_("The user is root"))
            self.printWARNING(\
                _("The program can be executed by a non-root user only"))
            return False

        password = self.clVars.Get('ur_user_new_pw')
        curPassword = self.clVars.Get('ur_user_pw')
        varsConfig = {"unix_hash":self.getHashPasswd(password,"ssha"),
                      "samba_lm_hash":self.getHashPasswd(password,"lm"),
                      "samba_nt_hash":self.getHashPasswd(password,"nt"),
                      "samba_nt_hash_old":self.getHashPasswd(curPassword,"nt")}
        if filter(lambda x: not x, varsConfig.values()):
            raise ClientError(_("Failed to change password"))
        # ~/.calculate/server.env
        fileConfig = os.path.join(self.homeDir, self.configFileServer)
        if not self.setServerCommand(["passwd_samba"], varsConfig, fileConfig,
                                    self.uid,self.gid):
            raise ClientError(_("Failed to change password"))
        if self.clVars.Get('ur_home_crypt_set') == 'on':
            passphraseFile = path.join('/home/.ecryptfs',
                self.clVars.Get('ur_login'),".ecryptfs/wrapped-passphrase")
            p = process('/usr/bin/ecryptfs-rewrap-passphrase',passphraseFile, "-",stderr=STDOUT)
            p.write("%s\n%s"%(curPassword,password))
            if p.failed():
                raise ClientError(p.read()+_("Failed to rewrap passphrase"))
        self.printSUCCESS(_("%s's password changed")%
                            self.clVars.Get('ur_login'))
        self.printSUCCESS(_("The password will be changed when you log "
                            "out from the X session"))
        return True
