/******************************************************************
* MultiUser - MultiUser Task/File Support System		  *
* --------------------------------------------------------------- *
* Get User ID data - AmigaShell script support utility		  *
*-----------------------------------------------------------------*
*								  *
* © 1993 Fabian Nuñez  -  contact me at: fnunez@cs.uct.ac.za	  *
*								  *
******************************************************************/

#include <proto/dos.h>
#include <dos/dos.h>
#include <libraries/multiuser.h>
#include <proto/multiuser.h>
#include "fileowner.c"

#define ARG_USERID      0
#define ARG_GROUPID     1
#define ARG_NAME        2
#define ARG_GROUPNAME   3
#define ARG_UID         4
#define ARG_GID         5
#define ARG_HOMEDIR     6
#define ARG_FILE        7
#define ARG_UACCESS     8
#define ARG_GACCESS     9
#define ARG_MANAGER    10

/* Prototypes */
void done(struct muUserInfo *,struct muGroupInfo *,LONG,LONG,STRPTR);
void itoa(LONG,STRPTR);

char _version_[] = "\0$VER:UserID 39.12 (19.1.94)\r\n";
struct muBase *muBase;

/* Don't include stdio and other useless stuff  ;) */
void _main(void)
{
    struct muUserInfo *uinfo = NULL;
    struct muGroupInfo *ginfo = NULL;
    struct RDArgs *args;
    ULONG user;
    ULONG retcode; 
    UBYTE *returned = NULL;
    LONG argarray[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
    UBYTE bitarray[] = {1,2,4,8,16,32,64};
    UBYTE bits;
    LONG i;

    /* Open libraries */
    muBase = (struct muBase *)OpenLibrary("multiuser.library",39L);
    if (!muBase)
    {
        PutStr("I need multiuser.library V39");
        exit(ERROR_INVALID_RESIDENT_LIBRARY);
    }

    args = ReadArgs("USERID/S,GROUPID/S,NAME=USERNAME/S,GROUPNAME/S,UID/S," \
                    "GID/S,HOMEDIR/S,FILE/K,UACCESS/K/N,GACCESS/K/N,MANAGER/S",
                    argarray,NULL);

    if (!args)
    {
        PrintFault(IoErr(),NULL);
        done(NULL,NULL,user,RETURN_ERROR,NULL);
    }

    for (i=0,bits = 0;i < ARG_FILE;i++)
        if (argarray[i]) bits += bitarray[i];
                
    /* Get muUserInfo, muGroupInfo structs */
    if (!(uinfo = muAllocUserInfo()))
        done(NULL,NULL,0,RETURN_FAIL,"Insufficient memory");
    if (!(ginfo = muAllocUserInfo()))
        done(uinfo,NULL,0,RETURN_FAIL,"Insufficient memory");

    /* store info in 'returned' */

    /* if FILE is specified, use owner of file, otherwise use this user */
    if (argarray[ARG_FILE])
    {
        user = muGetFileOwner((STRPTR)argarray[ARG_FILE],&retcode);
        /* my function - Geert please make an official one! */
        switch (retcode)
        {
            case FILE_NOT_FOUND:
                done(uinfo,ginfo,user,RETURN_ERROR,"File not found");

            case NOT_ENOUGH_MEM:
                done(uinfo,ginfo,user,RETURN_FAIL,"Insufficient memory");

            case CANNOT_EXAMINE:
                done(uinfo,ginfo,user,RETURN_ERROR,"Cannot examine file");
        }
    }
    else
        user = muGetTaskOwner(NULL); /* get uid, gid of owner of this task */

    if (user)
    {
        uinfo->uid = (UWORD) (user >> 16); 
        ginfo->gid = (UWORD) (user & muMASK_GID); 
        uinfo = muGetUserInfo(uinfo,muKeyType_uid);
        ginfo = muGetGroupInfo(ginfo,muKeyType_gid);

        if (argarray[ARG_MANAGER])  /* Actually want info on user's manager */
        {
            uinfo->uid = ginfo->MgrUid;
            uinfo = muGetUserInfo(uinfo,muKeyType_uid);
            ginfo->gid = uinfo->gid;
            ginfo = muGetGroupInfo(ginfo,muKeyType_gid);
        }

        if (uinfo)
        {  
            switch(bits)
            {
                case  0 : /* Default case is case 1 */
                case  1 : returned = uinfo->UserID;
                          break;
                case  2 : returned = ginfo->GroupID;
                          break;
                case  4 : returned = uinfo->UserName;
                          break;
                case  8 : returned = ginfo->GroupName;
                          break;
                case 16 : returned = "     ";
                          itoa(uinfo->uid,returned);
                          break;
                case 32 : returned = "     ";
                          itoa(uinfo->gid,returned);
                          break;
                case 64 : returned = uinfo->HomeDir;
                          break;
                default : done(uinfo,ginfo,user,RETURN_ERROR,"One switch only!");
            }
        }
        else
        {
            if (argarray[ARG_MANAGER])
                done(uinfo,ginfo,user,RETURN_WARN,"User has no manager");
            else
                done(uinfo,ginfo,user,RETURN_ERROR,"Unknown user");
        }
    }
    else done(uinfo,ginfo,user,RETURN_ERROR,"Nobody"); /* task or file owned by
                                                           nobody */

    if (argarray[ARG_UACCESS] && argarray[ARG_GACCESS])
        done(uinfo,ginfo,user,RETURN_ERROR,"One access keyword only!");
    else
    {
        if (argarray[ARG_UACCESS])
            if (((ULONG)uinfo->uid) < *(ULONG *)argarray[ARG_UACCESS])
                done(uinfo,ginfo,user,RETURN_WARN,returned);
            else user = 1; /* remove normal WARN if root is logged on */

        if (argarray[ARG_GACCESS])
            if (((ULONG)uinfo->gid) < *(ULONG *)argarray[ARG_GACCESS])
                done(uinfo,ginfo,user,RETURN_WARN,returned);
            else user = 1; /* remove normal WARN as above */
    }

    done(uinfo,ginfo,user,0L,returned);                       
}

void done(struct muUserInfo *uinfo,struct muGroupInfo *ginfo,LONG user,
          LONG retcode,STRPTR returned)
{
    if (returned)
    {
        PutStr(returned);
        PutStr("\n");
    }

    if (uinfo) muFreeUserInfo(uinfo);
    if (ginfo) muFreeGroupInfo(ginfo);
    CloseLibrary((struct Library *)muBase);

    if (!retcode)
    {
        if (user == 0)
	    exit(RETURN_ERROR); /* ERROR or no-one home today */
        else if ((user & muMASK_GID) == 0xFFFF)
            exit(RETURN_WARN);  /* WARN - a root is logged in or security violation */
        else exit(RETURN_OK);	    /* OK - nothing to remark */
    }
    else exit(retcode);
}
    
void itoa(LONG number,STRPTR string)
{
        LONG i;
        
        for (i=4;i;i--)
        {
                string[i] = '0' + number % 10;
                number /= 10;
        }
        string[i] = '0' + number % 10; /* Last digit */
}
