//
//  File:   hzUnixDB.cpp
//
//  Legal Notice:   This file is part of the HadronZoo C++ Class Library. Copyright 2025 HadronZoo Project (http://www.hadronzoo.com)
//
//  The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free
//  Software Foundation, either version 3 of the License, or any later version.
//
//  The HadronZoo C++ Class Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
//  A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public License along with the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses.
//
//
//  A set of functions to interigate UNIX system files to search for and provide information on users and user groups.
//
#include <fstream>
#include "hzProcess.h"
#include "hzUnixacc.h"
/*
**  Static Variables
*/
global  hzMapS<hzString,hzUserinfo*>    _hzGlobal_Userlist ;        //  All UNIX Users
global  hzMapS<hzString,hzGroupinfo*>   _hzGlobal_Grouplist ;       //  All UNIX User groups
/*
**  hzUserinfo functions
*/
hzEcode hzUserinfo::Load    (void)
{
    //  Build system user information database form /etc/passwd
    //
    //  Arguments:  None.
    //
    //  Returns:    E_OPENFAIL  If the file /etc/passwd could not be opened for reading.
    //              E_OK        If the /etc/passwd file was read.
    _hzfunc("hzUserinfo::Load") ;
    std::ifstream   is ;        //  Input stream
    hzUserinfo* pUI ;           //  Unix user meta data
    char*       i ;             //  String iterator
    char*       j ;             //  Reference iterator
    char        cvLine[256] ;   //  Getline Buffer
    is.open("/etc/passwd") ;
    if (is.fail())
    {
        hzerr(E_OPENFAIL, "Could not open passwd file") ;
        return E_OPENFAIL ;
    }
    for (;;)
    {
        is.getline(cvLine, 256) ;
        if (!is.gcount())
            break ;
        i = cvLine ;
        pUI = new hzUserinfo() ;
        if (!pUI)
            hzexit(E_MEMORY, "No memory for system user DB") ;
        for (j = i ; *i && *i != ':' ; i++) ;   *i++ = 0 ; pUI->m_Username = j ;
        for (j = i ; *i && *i != ':' ; i++) ;   *i++ = 0 ;
        for (j = i ; *i && *i != ':' ; i++) ;   *i++ = 0 ; pUI->m_nUserID = atoi(j) ;
        for (j = i ; *i && *i != ':' ; i++) ;   *i++ = 0 ; pUI->m_nGroupID = atoi(j) ;
        for (j = i ; *i && *i != ':' ; i++) ;   *i++ = 0 ; pUI->m_Geninfo = j ;
        for (j = i ; *i && *i != ':' ; i++) ;   *i++ = 0 ; pUI->m_Homedir = j ;
        for (j = i ; *i && *i != ':' ; i++) ;   *i++ = 0 ; pUI->m_Shell = j ;
        _hzGlobal_Userlist.Insert(pUI->m_Username, pUI) ;
    }
    is.close() ;
    is.clear() ;
    return E_OK ;
}
hzUserinfo* hzUserinfo::Locate  (hzString& uname)
{
    //  Locate UNIX user by username
    //
    //  Arguments:  1)  uname   The UNIX/Linux username
    //
    //  Returns:    Pointer to the usr info
    return _hzGlobal_Userlist[uname] ;
}
hzUserinfo* hzUserinfo::Locate  (uid_t nUserID)
{
    //  Locate UNIX user by user id
    //
    //  Arguments:  1)  nUserID The UNIX user number
    //
    //  Returns:    Pointer to the usr info
    hzUserinfo* pUI ;       //  UNIX user pointer
    uint32_t    nIndex ;    //  UNIX user iterator
    for (nIndex = 0 ; nIndex < _hzGlobal_Userlist.Count() ; nIndex++)
    {
        pUI = _hzGlobal_Userlist.GetObj(nIndex) ;
        if (pUI->m_nUserID == nUserID)
            return pUI ;
    }
    return 0 ;
}
/*
**  hzGroupinfo functions
*/
hzEcode hzGroupinfo::Load   (void)
{
    //  Load user groups
    //
    //  Arguments:  None
    //
    //  Returns:    E_OPENFAIL  If the file /etc/group could not be opened
    //              E_OK        If the user groups have been read in
    _hzfunc("hzGroupinfo::Load") ;
    std::ifstream   is ;        //  Input stream
    hzGroupinfo*    pGI ;       //  UNIX group pointer
    char*   i ;                 //  Line buffer iterator
    char*   cpGroupname ;       //  User group partial string
    char*   cpGroupID ;         //  User group partial string
    char    cvLine[256] ;       //  Line buffer
    is.open("/etc/group") ;
    if (is.fail())
    {
        hzerr(E_OPENFAIL, "Could not open group file") ;
        return E_OPENFAIL ;
    }
    for (;;)
    {
        is.getline(cvLine, 256) ;
        if (!is.gcount())
            break ;
        pGI = new hzGroupinfo() ;
        if (!pGI)
            hzexit(E_MEMORY, "No memory for system user DB") ;
        i = cvLine ;
        for (cpGroupname = i ; *i && *i != ':' ; i++) ; *i++ = 0 ;
        for (cpGroupID = i ;  *i && *i != ':' ; i++) ;  *i++ = 0 ;
        pGI->m_Groupname = cpGroupname ;
        pGI->m_nGroupID = atoi(cpGroupID) ;
        _hzGlobal_Grouplist.Insert(pGI->m_Groupname, pGI) ;
    }
    is.close() ;
    return E_OK ;
}
hzGroupinfo*    hzGroupinfo::Locate (hzString& Groupname)
{
    //  Locate user group by name
    //
    //  Arguments:  1)  Groupname   UNIX user group name
    //
    //  Returns:    Pointer to user group info
    return _hzGlobal_Grouplist[Groupname] ;
}
hzGroupinfo*    hzGroupinfo::Locate (gid_t nGroupID)
{
    //  Locate user group by number
    //
    //  Arguments:  1)  nGroupID    UNIX user group number
    //
    //  Returns:    Pointer to user group info
    hzGroupinfo*    pGI ;       //  UNIX group pointer
    uint32_t        nIndex ;    //  UNIX group iterator
    for (nIndex = 0 ; nIndex < _hzGlobal_Grouplist.Count() ; nIndex++)
    {
        pGI = _hzGlobal_Grouplist.GetObj(nIndex) ;
        if (pGI->m_nGroupID == nGroupID)
            return pGI ;
    }
    return 0 ;
}