# -*- coding: utf-8 -*-
###########################################################################
# Eole NG - 2009
# Copyright Pole de Competence Eole  (Ministere Education - Academie Dijon)
# Licence CeCill  cf /root/LicenceEole.txt
# eole@ac-dijon.fr
#
# eoleuser.py
#
# librairie pour la gestion des utilisateurs scribe
#
###########################################################################
"""
    librairies objets de gestion des comptes utilisateurs scribe
    User
    Parent
    Eleve
    Parent
    Autres
    Machines
"""
from re import match
from shutil import rmtree
from time import sleep
from os import system, makedirs, symlink, remove, unlink
from os.path import join, islink, exists, isdir
from ldap import MOD_REPLACE, SCOPE_SUBTREE
from pwd import getpwnam

from pyeole.process import system_out
from pyeole.ssha import ssha_encode
from pyeole.deprecation import deprecated
from fichier import quota, passwd
from scribe import eoletools as tool
from scribe.eoleldap import Ldap, LdapEntry
from scribe.eolegroup import Group
from scribe.ldapconf import USER_DN, USER_FILTER, SMB_SERVEUR, MAILDIR_PATH, \
HOME_PATH, MAIL_ADMIN, BRANCHE_ETAB2, CIVILITES, MAIL_DOMAIN, \
num_etab, SUPPORT_ETAB, GROUPWARE, EOLE_AD, AD_HOME_PATH, SAMBAPROFILEPATH, \
LDAP_MODE, SUFFIX
from scribe.errors import MissingUserCreateKey, EmptyUserCreateKey, \
BadLogin
#NotIntValue
#Librairies de fonction
@deprecated
def get_quota(login):
    """
    renvoie le quota disque pour un utilisateur
    """
    return quota.get_quota(login)

@deprecated
def set_quota(login, user_quota=0):
    """
    applique de nouveau quota disque pour login
    @quota: int (str admis)
    """
    return quota.set_quota(login, user_quota)

def send_first_mail(mail):
    """
        Envoi du mail d'ouverture d'une boîte locale
    """
    subject = "Ouverture de votre compte de messagerie"
    body = "Bienvenue sur votre messagerie."
    cmd = ['s-nail', '-s', subject, '-r', MAIL_ADMIN, mail]
    if GROUPWARE:
        system_out(["zarafa-admin", "--create-store", mail.split("@")[0]], container='mail')
    system_out(cmd, container='mail', stdin=body)

def gen_common_attrs(login, **args):
    """
    Gestion des attibuts communs
    """
    attrs = []
    attrs.append((MOD_REPLACE, 'cn', "%(prenom)s %(nom)s" % args ))
    attrs.append((MOD_REPLACE, 'sn', args['nom'] ))
    attrs.append((MOD_REPLACE, 'givenName', args['prenom'] ))
    attrs.append((MOD_REPLACE, 'displayName', "%(prenom)s %(nom)s" % args ))
    attrs.append((MOD_REPLACE, 'gecos', tool.replace_cars("%(prenom)s %(nom)s" % args) ))
    today = tool.format_current_date()
    attrs.append((MOD_REPLACE, 'LastUpdate', today))
    attrs.append((MOD_REPLACE, 'ENTPersonLogin', login))
    if tool.not_empty(args, 'entpersonjointure'):
        entpersonjointure = args['entpersonjointure']
    else:
        entpersonjointure = 'ENT'
    attrs.append((MOD_REPLACE, 'ENTPersonJointure', entpersonjointure))
    if tool.not_empty(args, 'entprofil'):
        attrs.append((MOD_REPLACE, 'ENTPersonProfils', args['entprofil']))
    if tool.not_empty(args, 'patronyme'):
        patro = args['patronyme']
    else:
        patro = args['nom']
    attrs.append((MOD_REPLACE, 'ENTPersonNomPatro', patro))
    if tool.not_empty(args, 'civilite') and args['civilite'].isalnum():
        attrs.append((MOD_REPLACE, 'codecivilite', args['civilite'] ))
        if args['civilite'] == '3':
            sexe = 'F'
            titre = 'Mlle'
        elif args['civilite'] == '2':
            sexe = 'F'
            titre = 'Mme'
        else:
            titre = 'M.'
            sexe = 'M'
        attrs.append((MOD_REPLACE, 'ENTPersonSexe', sexe))
        attrs.append((MOD_REPLACE, 'personalTitle', titre))
    if tool.not_empty(args, 'date'):
        # on part du principe que la date a été traitée en aval
        attrs.append((MOD_REPLACE, 'dateNaissance', args['date']))
        attrs.append((MOD_REPLACE, 'ENTPersonDateNaissance', args['date']))
    if tool.not_empty(args, 'exp_unix_days'):
        # on part du principe que la date a été traitée en aval et changée en jours
        attrs.append((MOD_REPLACE, 'shadowExpire', args['exp_unix_days']))
    if tool.not_empty(args, 'exp_nt_time'):
        # on part du principe que la date a été traitée en aval et changée en nt time
        attrs.append((MOD_REPLACE, 'accountExpires', args['exp_nt_time']))
    if tool.not_empty(args, 'prenom2'):
        attrs.append((MOD_REPLACE, 'ENTPersonAutresPrenoms', args['prenom2']))
    if tool.not_empty(args, 'int_id'):
        attrs.append((MOD_REPLACE, 'intid', args['int_id']))
    return attrs

#  MAY  ( ENTPersonCentresInteret $
#         ENTPersonAdresse $
#         ENTPersonCodePostal $
#         ENTPersonVille $
#         ENTPersonPays $
#         ENTPersonAlias $
#         ENTPersonStructRattach $
#         ENTPersonFonctions $
#         ENTPersonProfils $

def gen_enteleve_attrs(**args):
    """
    Gestion des attributs ENTEleve
    """
    attrs = []
    attrs.append((MOD_REPLACE, 'ENTEleveStatutEleve', 'ELEVE'))
    attrs.append((MOD_REPLACE, 'ENTEleveMEF', args['niveau']))
    attrs.append((MOD_REPLACE, 'ENTEleveLibelleMEF', args['niveau']))
    attrs.append((MOD_REPLACE, 'ENTEleveNivFormation', '-'))
    attrs.append((MOD_REPLACE, 'ENTEleveFiliere', '-'))
    attrs.append((MOD_REPLACE, 'ENTEleveClasses', '%s$%s' % (BRANCHE_ETAB2 % args,
                                                    args['classe'])))
    attrs.append((MOD_REPLACE, 'ENTEleveMajeur', '-'))
    if tool.not_empty(args, 'enseignements') and args['enseignements'] != []:
        attrs.append((MOD_REPLACE, 'ENTEleveEnseignements', args['enseignements']))
    else:
        attrs.append((MOD_REPLACE, 'ENTEleveEnseignements', '-'))
    if tool.not_empty(args, 'elevegroupes') and args['elevegroupes'] != []:
        attrs.append((MOD_REPLACE, 'EleveGroupes', args['elevegroupes']))
    if tool.not_empty(args, 'regime'):
        attrs.append((MOD_REPLACE, 'ENTEleveRegime', args['regime']))
    if tool.not_empty(args, 'rattachid'):
        attrs.append((MOD_REPLACE, 'ENTEleveStructRattachId', args['rattachid']))
    return attrs


#  MAY  ( ENTEleveVilleNaissance $
#         ENTEleveDeptNaissance $
#         ENTElevePaysNaissance $
#         ENTEleveParents $
#         ENTEleveAutoriteParentale $
#         ENTElevePersRelEleve1 $
#         ENTEleveQualitePersRelEleve1 $
#         ENTElevePersRelEleve2 $
#         ENTEleveQualitePersRelEleve2 $
#         ENTEleveBoursier $
#         ENTEleveRegime $
#         ENTEleveTransport $
#         ENTEleveMEFRattach $
#         ENTEleveNivFormationDiplome $
#         ENTEleveSpecialite $
#         ENTEleveGroupes $
#         ENTEleveEnsRespStage $
#         ENTEleveEnsTutStage $
#         ENTEleveEntrTutStage $
#         ENTEleveEntrAutres $
#         ENTEleveDelegClasse $
#         ENTEleveDelegAutres $
#         ENTEleveMajeurAnticipe

def gen_radius_attrs(groupid=None):
    """
    Gestion des attributs Radius
    """
    attrs = []
    if groupid is not None:
        attrs.append((MOD_REPLACE, 'radiusTunnelPrivateGroupId', groupid))
    attrs.append((MOD_REPLACE, 'radiusTunnelType', 'VLAN'))
    attrs.append((MOD_REPLACE, 'radiusFilterId',
                               'Enterasys:version=1:policy=Enterprise User'))
    attrs.append((MOD_REPLACE, 'radiusTunnelMediumType', 'IEEE-802'))
    return attrs


def gen_profil(profil, login):
    """
        Génération du sambaProfilePath selon le profil demandé
    """
    profil = int(profil)
    if profil == 2:
        # profil obligatoire #1
        return "\\\\{0}\\netlogon\\profil".format(SMB_SERVEUR)
    if profil == 3:
        # profil obligatoire #2
        return "\\\\{0}\\netlogon\\profil2".format(SMB_SERVEUR)
    if profil == 4:
        # profil itinérant
        return "\\\\{0}\\{1}\\profil".format(SMB_SERVEUR, login)
    # profil local à la station
    return ""

def gen_common_devdir(login, homedir):
    """
        Partie commune pour _gen_devoirdir
    """
    perso = join(homedir, 'perso')
    # le partage "devoirs" /home/l/login/devoirs
    dev_part = join(homedir, 'devoirs')
    # le dossier U:\devoirs /home/l/login/perso/devoirs
    dev_perso = join(perso, 'devoirs')
    for rep in [dev_part, dev_perso]:
        if islink(rep):
            remove(rep)
        if not exists(rep):
            makedirs(rep)
        system('/bin/chmod 0750 %s' % rep)
        system('/bin/chown -PR %s %s' % (login, rep))
        system('setfacl -PRm u:%s:rwx %s'%(login, rep))
        system('setfacl -dPRm u:%s:rwx %s'%(login, rep))


class User(LdapEntry):
    """
        Meta Classe pour la gestion des utilisateurs Eole
    """
    must_args = ['login', 'password']
    may_args = {'key2':'default2'}
    _type = None
    profil = None
    # arguments communs pour smbldap-useradd
    user_add_params = ['-a', '-A', '1', '-D', 'U:', '-H', 'U']
    has_ftp = False
    has_samba = False

    def add_one(self, **args):
        """
            ajout d'un utilisateur (mode déconnecté)
        """
        self.ldap_admin.connect()
        self._add(**args)
        self.ldap_admin.close()

    def _add(self, **args):
        """
            Ajoute un utilisateur
            **args
        """
        self.filter_must_args(args)
        self.filter_may_args(args)
        #force login in lower case #33178
        login = args['login'].lower()
        args['login'] = login
        if match("^[a-zA-Z0-9.\-_]*$", login) is None:
            raise BadLogin("Login \"%s\" invalide !" % login)
        self._test_available_name(login)
        args.setdefault('etab', None)
        if args['etab'] is None and 'classe' in args:
            args['etab'] = self.get_etab_from_group(args['classe'])
        if args['etab'] == num_etab:
            args['etab'] = None
        self.cache_etab['login'][login] = args['etab']
        # FIXME : fixes #327 mais est-ce le bon endroit ?
        if tool.not_empty(args, 'date'):
            args['date'] = tool.deformate_date(args['date'])
        if 'exp_date' in args:  # Can be jj/mm/aaaa or empty string
            if LDAP_MODE == 'openldap':
                args['exp_unix_days'] = str(tool.get_days_from_epoch(args['exp_date'])) if args['exp_date'] else '-1'
            else:
                args['exp_nt_time'] = str(tool.get_nt_time_from_date(args['exp_date'])) if args['exp_date'] else '0'
            args.pop('exp_date')
        if self.has_samba:
            user_add_args = self.get_smbldap_useradd_args(**args)
            self.exec_smbldap_useradd(user_add_args, login)
        self._add_scribe_user(**args)
        if args.get('syncpassword', False) and self.has_samba:
            self.c_mod_password(login, args['password'], must_change=args['change_pwd'])
            idx = 0
            while True:
                idx += 1
                if idx == 30:
                    raise Exception("L'utilisateur {} a été créé mais il n'apparait pas en temps qu'utilisateur".format(login))
                try:
                    getpwnam(login)
                except KeyError:
                    sleep(2)
                else:
                    break
            self._add_perso(**args)
            self._gen_groupesdir(login)
            self._gen_ftpdir(login)

    def filter_must_args(self, args):
        """
            test la présence des arguments obligatoires
        """
        for arg in self.must_args:
            if arg not in args:
                raise MissingUserCreateKey(arg)
            if args[arg] == '':
                raise EmptyUserCreateKey(arg)

    def filter_may_args(self, args):
        """
            remplie les valeurs par défaut des valeurs
            facultatives non renseignées
        """
        for arg in self.may_args:
            if arg not in args:
                args[arg] = self.may_args[arg]

    def get_smbldap_useradd_args(self, **args):
        """
            gestion des paramètres smbldap
            à redéfinir dans les sous-classes
        """
        return {}

    def exec_smbldap_useradd(self, user_add_args, login):
        """
            exécute smbldap-useradd
        """
        cmd = ["/usr/sbin/smbldap-useradd"]
        cmd.extend(self.user_add_params)
        cmd.extend(user_add_args)
        etab = self.get_etab(login)
        force_dn = {'groupsdn="ou=local,ou=Groupes,${etab},${suffix}"': 'groupsdn="${suffix}"'}
        tool.launch_smbldap_tool(cmd, num_etab, etab, force_dn=force_dn)

    def _add_perso(self, login, **args):
        """
            Crée les différents répertoires de l'utilisateur
        """
        pass

    def _add_scribe_user(self, login, **args):
        """
            Ajoute les spécificités scribe dans l'annuaire
        """
        pass

    def _add_ent_entrys(self, args):
        """
             Ajoute les spécificités ENT dans l'annuaire
        """
        pass

    def _inscription(self, login, groupe, sync=True, etab=None, check_etab=True, touch=True):
        """
            Inscription d'un utilisateur à un groupe
        """
        etabgroup = None
        if SUPPORT_ETAB:
            etabgroup = self.get_etab_from_group(groupe)
            if check_etab:
                # vérification de la cohérence
                if etab is None:
                    etabuser = self.get_etab(login)
                else:
                    #on force l'établissement de l'utilisateur (#4827)
                    etabuser = etab
                if etabgroup != etabuser:
                    raise Exception("L'utilisateur {0} ne fait pas partie du même établissement que le groupe {1} : {2} - {3}".format(login, groupe, etabuser, etabgroup))
        if not self.has_ftp:
            return True
        grp = Group()
        grp.ldap_admin = self.ldap_admin
        gtype = grp.c_get_group_type(groupe)
        if self.profil != 'eleve' and gtype in ['Classe', 'Niveau', 'Option']:
            # groupes réservés élèves
            return True
        if self.profil not in ['enseignant', 'administratif'] and gtype in ['Matiere', 'Equipe']:
            # groupe réservés enseignants
            return True
        #pas d'inscription possible en dehors des groupes de l'établissement
        #il ne faut pas forcer le DN sur le groupe
        cmd = ['/usr/sbin/smbldap-groupmod', '-m', login, groupe]
        tool.launch_smbldap_tool(cmd, num_etab, etabgroup)
        if touch:
            grp._touch(groupe)
        if sync:
            self._gen_ftpdir(login)
            self._gen_groupesdir(login)
        return True

    def _desinscription(self, login, groupe, sync=True, touch=True):
        """
            Désinscrition d'un utilisateur d'un groupe
        """
        if not self.has_ftp:
            return True
        cmd = ['/usr/sbin/smbldap-groupmod', '-x', login, groupe]
        etab = self.get_etab(login)
        force_dn = {'groupsdn="ou=local,ou=Groupes,${etab},${suffix}"':
                'groupsdn="${suffix}"'}
        tool.launch_smbldap_tool(cmd, num_etab, etab, force_dn=force_dn)
        grp = Group()
        grp.ldap_admin = self.ldap_admin
        if touch:
            grp._touch(groupe)
        # cas eleve + option
        if sync:
            self._gen_ftpdir(login)
            self._gen_groupesdir(login)
        return True

    def _gen_ftpdir(self, login):
        """
            Gestion du répertoire "/home/adhomes/<login>/.ftp"
        """
        homedir = join(AD_HOME_PATH, login)
        ftpdir = join(homedir, '.ftp')
        if isdir(ftpdir):
            rmtree(ftpdir)
        makedirs(ftpdir, 0o500)
        system('/bin/chown %s %s' % (login, ftpdir))
        symlink(join(homedir, 'perso'), join(ftpdir, 'perso'))
        user_groups = self._get_user_groups(login)
        for group in user_groups:
            for share, sharedir in self._get_group_sharedirs(group):
                if share not in ['icones$', 'groupes']:
                    if HOME_PATH != '/home':
                        sharedir = sharedir.replace('/home', HOME_PATH)
                    symlink(sharedir, join(ftpdir, share))

    def _gen_groupesdir(self, login):
        """
            Gestion du répertoire "/home/adhomes/<login>/groupes"
        """
        homedir = join(AD_HOME_PATH, login)
        groupedir = join(homedir, 'groupes')
        if isdir(groupedir):
            rmtree(groupedir)
        makedirs(groupedir, 0o500)
        system('/bin/chown %s %s' % (login, groupedir))
        user_groups = self._get_user_groups(login)
        for group in user_groups:
            for share in self._get_group_logon_shares(group):
                if share['drive'] == '':
                    symlink(share['path'], join(groupedir, share['name']))

    def _gen_devdir(self, login, homedir=None):
        """
            Génération du répertoire "devoirs"
        """
        # à redéfinir dans les sous-classes si nécessaire
        pass

    def get_attrs(self, login, attrs):
        """
            renvoie la valeur des attributs attrs pour le user 'user'
            avec connexion ldap
        """
        self.ldap_admin.connect()
        res = self._get_attrs(login, attrs)
        self.ldap_admin.close()
        return res

    def get_attr(self, login, attr):
        """
            renvoie la valeur d'un attribut
            avec connexion ldap
        """
        self.ldap_admin.connect()
        res = self._get_attr(login, attr)
        self.ldap_admin.close()
        return res

    def users_get_attrs(self, logins, attrs):
        """
            renvoie la valeur des attributs attrs pour le user 'user':483
            avec connexion ldap
        """
        res = []
        self.ldap_admin.connect()
        for login in logins:
            res.append(self._get_attrs(login, attrs))
        self.ldap_admin.close()
        return res

    def users_get_attr(self, logins, attr):
        """
            renvoie la valeur d'un attribut
            avec connexion ldap
        """

        res = []
        for login in logins:
            self.ldap_admin.connect()
            res.append(self._get_attr(login, attr))
            self.ldap_admin.close()
        return res

    def set_attr(self, login, attr, value):
        """
        met à jour un a attribut
        """
        self.ldap_admin.connect()
        self._set_attr(login, attr, value)
        self.ldap_admin.close()

    def _get_attrs(self, login, attrs):
        """
            renvoie la valeur des attributs attrs pour le user 'login'
            attrs : ["attr1","attr2"] ou "attr1"
        """
        return self.ldap_admin._search_one("(&%s(uid=%s))" % (
                                USER_FILTER, login), attrs)

    def _get_attr(self, login, attr):
        """
            renvoie la valeur d'un attribut
        """
        return self._get_attrs(login, [attr]).get(attr, [])

    def _set_attr(self, login, attribut, value):
        """
            met à jour un attribut
        """
        if value == '':
            value = []
        user_dn = self.get_user_dn(login) #USER_DN % dict(uid=login, _type=self._type, etab=etab)
        data = [((MOD_REPLACE, attribut, value))]
        self.ldap_admin._modify(user_dn, data)

    def delete(self, login, remove_data=False, delete_resp=False):
        """
            supprime un utilisateur
        """
        self._delete(login, remove_data=remove_data, need_connect=True,
                     delete_resp=delete_resp)

    def _delete(self, login, remove_data=False, need_connect=False, delete_resp=False):
        """
            supprime un utilisateur
        """
        if self.has_samba:
            quota.set_quota(login, '0')
            if remove_data:
                cmd = ['/usr/sbin/smbldap-userdel', '-r', login]
            else:
                cmd = ['/usr/sbin/smbldap-userdel', login]
            etab = self.get_etab(login)
            force_dn = {'groupsdn="ou=local,ou=Groupes,${etab},${suffix}"':
                    'groupsdn="${suffix}"'}
            tool.launch_smbldap_tool(cmd, num_etab, etab, force_dn=force_dn)
            # gestion des données résiduelles
            if remove_data:
                ad_user_dir = join(AD_HOME_PATH, login)
                rmtree(ad_user_dir, ignore_errors=True)
                perso = join(HOME_PATH, login[0], login)
                # code uniquement pour AmonEcole (#33013)
                if islink(perso):
                    unlink(perso)
                maildir = join(MAILDIR_PATH, login)
                rmtree(maildir, ignore_errors=True)
            else:
                tool.move_user_datas(login)
                tool.move_mail_datas(login)
            return True
        else:
            if need_connect:
                self.ldap_admin.connect()
            user_dn = self.get_user_dn(login) #USER_DN % dict(uid=login, _type=self._type)
            self.ldap_admin._delete(user_dn)
            if need_connect:
                self.ldap_admin.close()
            if remove_data:
                perso = join(HOME_PATH, login[0], login)
                rmtree(perso, ignore_errors=True)
                maildir = join(MAILDIR_PATH, login)
                rmtree(maildir, ignore_errors=True)
            else:
                tool.move_mail_datas(login)

    def auth(self, login, password):
        """
            authentifie un utilisateur
        """
        user_dn = self.get_user_dn(login)
        authldap = Ldap(binddn=user_dn,
                        passwd=password)
        try:
            authldap.connect()
            authldap.close()
            return True
        except:
            authldap.close()
            return False

    def get_user_groups(self, login):
        """
            renvoie la liste des groupes d'un utilisateur
            avec connexion ldap
        """
        self.ldap_admin.connect()
        res = self._get_user_groups(login)
        self.ldap_admin.close()
        return res

    def _touch(self, login):
        """
            Mise à jour de l'attribut LastUpdate
        """
        self._set_attr(login, 'LastUpdate', tool.format_current_date())

    def _get_ead_type(self, login):
        """
        Renvoie le type d'utilisateur en fonction du login
        (pour les formulaires EAD)
        """
        res = self._get_attr(login, 'objectClass')
        if res:
            users = {
                    #'Eleves': 'eleve',
                    'Eleves': 'pupil',
                    #'administrateur': 'enseignant',
                    'administrateur': 'teacher',
                    'responsable': 'responsable',
                    'administratif': 'administratif',
                    'autre': 'autre'
                    }
            for objectclass, _type in users.items():
                if objectclass in res:
                    return _type
        raise Exception("utilisateur %s inconnu" % login)

    def _mod_civilite(self, login, civilite):
        """
        modifications des attributs utilisateurs
        liés à la civilité
        """
        for civ in CIVILITES:
            if civ['code'] == civilite:
                self._set_attr(login, 'ENTPersonSexe', civ['sexe'])
                self._set_attr(login, 'personalTitle', civ['title'])
                self._set_attr(login, 'codecivilite', civilite)
                break

    def _mod_date(self, login, date):
        """
        modifications des attributs utilisateurs
        liés à la date de naissance
        la date doit être pré-traitée et envoyée
        au format : aaaammjj
        """
        if len(date) != 8:
            raise Exception("Erreur dans le format de la date de naissance")
        self._set_attr(login, 'ENTPersonDateNaissance', date)
        self._set_attr(login, 'dateNaissance', date)

    def _mod_shadow_exp_date(self, login, exp_unix_days):
        """
        modifications des attributs utilisateurs
        liés à la date d'expiration du compte
        la date doit être pré-traitée et envoyée
        au format : -1 ou nombre de jours depuis epoch
        """
        self._set_attr(login, 'shadowExpire', exp_unix_days)

    def _mod_account_exp_date(self, login, nt_time):
        """
        modifications des attributs utilisateurs
        liés à la date d'expiration du compte
        la date doit être pré-traitée et envoyée
        au format : 0 ou nombre de centaines de ns depuis 1/1/1601
        """
        self._set_attr(login, 'accountExpires', nt_time)

    def _mod_mail(self, login, mailtype, mail=''):
        """
        modifie le compte mail d'un utilisateur
        FIXME : ne devrait pas être dispo pour un élève
        login : login de l'utilisateur
        mailtype : perso/internet/restreint/aucun
        mail : adresse si mailtype == 'perso'
        """
        if mailtype == 'perso' and mail != '':
            self._set_mailperso(login, mail)
        elif mailtype in ['internet', 'restreint']:
            self._set_localmail(login, domaine=mailtype)
        elif mailtype == 'aucun':
            self._set_mailperso(login, '')

    def _set_mailperso(self, login, mail):
        """
        utilisation d'une adresse mail personnalisée
        """
        self._set_attr(login, 'mailDir', [])
        self._set_attr(login, 'mailHost', [])
        self._set_attr(login, 'mail', mail)

    def get_maildir(self, login):
        """
        renvoie le chemin du maildir
        """
        return join(MAILDIR_PATH, login) + '/'

    def _set_localmail(self, login, domaine='internet'):
        """
        utilisation d'une adresse mail locale
        """
        maildir = self.get_maildir(login)
        mail = "%s@%s" % (login, MAIL_DOMAIN[domaine])
        self._set_attr(login, 'mailDir', maildir)
        self._set_attr(login, 'mailHost', 'localhost')
        self._set_attr(login, 'mail', mail)
        # mail d'ouverture si necessaire
        if not isdir(join(maildir, 'cur')):
            send_first_mail(mail)
        return True

    def get_profil(self, login):
        """ renvoie le profil d'un utilisateur
            1 local
            2 obligatoire-1
            3 obligatoire-2
            4 itinérant
        """
        profil = self.get_attr(login, SAMBAPROFILEPATH)
        if profil == []:
            return 1
        if "profil2" in profil[0]:
            return 3
        if "netlogon" in profil[0]:
            return 2
        return 4

    def get_type(self, login):
        """
        renvoit le type de l'utilisateur
        """
        self.ldap_admin.connect()
        res = self._get_type(login)
        self.ldap_admin.close()
        return res

    def _get_type(self, login):
        """
        renvoit le type de l'utilisateur (mode connecté)
        """
        users = {
                'Eleves': 'eleve',
                'administrateur': 'enseignant',
                'responsable': 'responsable',
                'administratif': 'administratif',
                'autre': 'autre'
                }
        filtre = "(&%s(uid=%s))" % (USER_FILTER, login)
        res = self.ldap_admin._search_one(filtre, 'objectClass')
        if 'objectClass' in res:
            for objectclass, module in users.items():
                if objectclass in res['objectClass']:
                    return module
        raise Exception("Utilisateur %s inconnu" % login)

    ###############################################
    # Methodes spécifiques aux utilisateurs Samba #
    ###############################################

    def _update_shell(self, login, active=True):
        """
        activation/desactivation du shell utilisateur
        """
        if self.has_samba:
            if active:
                self._set_attr(login, 'loginShell', '/bin/bash')
            else:
                self._set_attr(login, 'loginShell', '/bin/false')

    def _set_profil(self, login, profil):
        """
        modifie le sambaProfilePath d'un utilisateur 1-2-3-4
        """
        if self.has_samba:
            self._set_attr(login, SAMBAPROFILEPATH,
                           gen_profil(profil, login))

    def c_mod_password(self, login, user_passwd, container='domaine', must_change=False):
        """
            Modifie le mot de passe d'un utilisateur

            :param container: redéfinir à None si on est déjà dans domaine
        """
        if self.has_samba:
            if EOLE_AD:
                self.ad_password(login, user_passwd, must_change)
            else:
                passwd.mod_password(login, user_passwd, container=container)
                if must_change:
                    self.password_must_change(login, container=container)
        else:
            user_passwd = user_passwd.replace('"', '\\"')
            self._set_attr(login, 'userPassword', ssha_encode(user_passwd))


    def password_must_change(self, login, container='domaine'):
        """
            Changement de mot de passe obligatoire

            :param container: redéfinir à None si on est déjà dans domaine
        """
        if self.has_samba:
            passwd.password_must_change(login, container=container)


    def ad_password(self, login, user_passwd, must_change=False):
        """
            Changement du mot de passe en mode AD
        """
        if must_change:
            change = '1'
        else:
            change = ''
        cmd = ['/usr/sbin/changepasswordeole.pl', login, user_passwd, change]
        for num in range(50):
            ret = system_out(cmd)
            if ret[0] != 3:
                break
            sleep(2)
        if ret[0] != 0:
            raise Exception(' '.join(ret[1:]))

    def get_etab(self, login, multi_etabs=False):
        try:
            return self._get_etab('login', login, "(&%s(uid=%s))" % (USER_FILTER, login),
                                  'uid', multi_etabs=multi_etabs)
        except:
            return num_etab

    def get_etab_from_classe(self, login, classe):
        try:
            etab = self.get_etab_from_group(classe)
            self.cache_etab['login'][login] = etab
            return etab
        except:
            return num_etab

    def get_user_dn(self, login, force_etab=None):
        if LDAP_MODE == 'ad':
            if self.ldap_admin.connexion is None:
                self.ldap_admin.connect()
            data = self.ldap_admin.connexion.search_s(SUFFIX, SCOPE_SUBTREE,
                                                      "(&%s(uid=%s))" % (USER_FILTER, login), ['cn'])
            if data[0][0]:
                return data[0][0]
        if force_etab is None:
            etab = self.get_etab(login)
        else:
            etab = force_etab
        return USER_DN % dict(uid=login, _type=self._type, etab=etab)

class Machine(User):
    """
        classe pour les comptes machine
    """
    pass

