/*
   $VER: Login.c V1.0 (27.07.96)
   Author: Finn Nielsen <zznyyd@diku.dk>
   Date: Sat 27-Jul-1996
   Copyright: © 1996 ZzNyYd! Design.
   Short: Replacement for Login command for MultiUserFileSystem

   Works basically the same as Login from muFS except there's a PUBSCR
   argument and a PASSWD argument and the GUI switch is automatic
   (ie. it's always ON unless pr_WindowPtr is -1).
   On succesful login it also sets the local variable $Home.

   This command is pure and can be made resident.

   Bugs: I'm quite sure there is no bugs in this code, but there is
	 however a bug in multiuser.library V39 that makes the OWN switch
	 crash the machine.
*/

#define __USE_SYSBASE

#include <exec/types.h>
#include <utility/tagitem.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <dos/dosextens.h>
#include <dos/rdargs.h>
#include <libraries/multiuser.h>

#include <stdio.h>
#include <string.h>

#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/multiuser.h>


// ------------------------------------------------------------------------
// ----- Strings ----------------------------------------------------------
// ------------------------------------------------------------------------

#define Template	"USERID,PW=PASSWD/K,PUB=PUBSCR/K,OWN/S,GLOBAL/S,TASK/K,PROCESS/K/N"
#define WarnOwn		"You can't specify both USERID and OWN\n"
#define WarnTask	"You can't specify both TASK and PROCESS\n"
#define LogOk		"Login successful\n"
#define LogBad		"Login failed\n"
#define NomuFS		"Couldn't open multiuser.library V39+\n"
#define ColonSpace	": "
#define NoTask		"Couldn't find task '%s'\n"
#define NoProcess	"Couldn't find process %ld\n"
#define HomeVar		"Home"
#define NoUser		"You can't specify PASSWD without USERID\n"

// ------------------------------------------------------------------------
// ----- Let the fun begin... ---------------------------------------------
// ------------------------------------------------------------------------
const char ver[]="$VER: Login V1.0 (27.07.96)  by Finn Nielsen <zznyyd@diku.dk>";

int cmd_login(void)
{
  struct ExecBase	*SysBase = (*((struct ExecBase **) 4));
  struct DosLibrary	*DOSBase;
  struct muBase		*muBase;
  struct RDArgs		*rdargs;
  struct Process	*thisproc;
  long			opts[8], *optptr, tags[19], *tagptr;
  long			opt;
  long			pub = 0;
  long			user = 0;
  int			task = 0;
  long			rc = 0;
  char			buf[160];

// ------------------------------------------------------------------------
// ----- Initialization ---------------------------------------------------
// ------------------------------------------------------------------------

  thisproc = (struct Process *)FindTask(NULL);
  if ((DOSBase = (struct DosLibrary *)OpenLibrary(DOSNAME, 37L)))
  {
    if ((muBase = (struct muBase *)OpenLibrary(MULTIUSERNAME, 39L)))
    {
      memset((char *)opts, 0, sizeof(opts));
      if (rdargs = ReadArgs(Template, opts, NULL))
      {
	while ( ((char *)opts)[0] == '?' && ((char *)opts)[1] == 0 )
	{
	  PutStr(Template); PutStr(ColonSpace); rdargs->RDA_Buffer=0;
	  memset((char *)opts, 0, sizeof(opts));
	  if (!ReadArgs(Template, opts, rdargs))
	  {
	    FreeArgs(rdargs); PrintFault(IoErr(), NULL);
	    rc=10; break;
	  }
	}
	if (!rc) {

// ------------------------------------------------------------------------
// ----- Argument parsing -------------------------------------------------
// ------------------------------------------------------------------------

	optptr=opts; tagptr = tags;

//	USERID
	if (opt = *optptr++)
	{
	  *tagptr++ = muT_UserID; *tagptr++ = opt; user=1;
	}

//	PASSWD/K
	if (opt = *optptr++)
	{
	  if (user)
		{ *tagptr++ = muT_Password; *tagptr++ = opt; }
	    else
		{ rc=10; PutStr(NoUser); }
	}

//	PUBSCR/K
	if (opt = *optptr++)
	{
	  *tagptr++ = muT_PubScrName; *tagptr++ = opt; pub = 1;
	}

//	OWN/S
	if (opt = *optptr++)
	{
	  if (user)
	  {
	    rc=10; PutStr(WarnOwn);
	  } else { *tagptr++ = muT_Own; *tagptr++ = 1; }
	}

//	GLOBAL/S
	if (opt = *optptr++)
	{
	  *tagptr++ = muT_Global; *tagptr++ = 1;
	}

//	TASK/K
	if (opt = *optptr++)
	{
	  Forbid(); task = (long)FindTask((char *)opt); Permit();
	  if (task)
		{ *tagptr++ = muT_Task; *tagptr++ = task; }
	   else
		{
		  rc=10; task=1;
		  sprintf(buf,NoTask,(char *)opt);
		  PutStr(buf);
		}
	}

//	PROCESS/K/N
	if (opt = *optptr)
	{
	  if (task)
	    { rc=10; PutStr(WarnTask); }
	  else
	  {
	    struct Process *logproc;
	    opt = *(long *)opt;
	    Forbid(); logproc = FindCliProc(opt); Permit();
	    if (logproc)
		{ *tagptr++ = muT_Task; *tagptr++ = (long)logproc; }
	     else
		{
		  rc=10;
		  sprintf(buf,NoProcess,opt);
		  PutStr(buf);
		}
	  }
	}

//	GUI (automatic)
	if (pub || (long)thisproc->pr_WindowPtr != -1)
	{
	  *tagptr++ = muT_Graphical; *tagptr++ = 1;
	}

	*tagptr = TAG_END;


// ------------------------------------------------------------------------
// ----- Login & set variables. -------------------------------------------
// ------------------------------------------------------------------------

	if (!rc)
	{
	  if (muLoginA((struct TagItem *)tags))
	  {
	    struct muUserInfo *info;
	    if ((user = muGetTaskOwner(NULL)) && (info = muAllocUserInfo()))
	    {
	      info->uid = (UWORD)(user>>16);
	      if (muGetUserInfo(info, muKeyType_uid))
	      {
		SetVar(HomeVar, info->HomeDir, -1, GVF_LOCAL_ONLY);
	      }
	      muFreeUserInfo(info);
	    }
	    PutStr(LogOk);
	  } else { PutStr(LogBad); rc=10; }
	  thisproc->pr_Result2 = 0;
	}

// ------------------------------------------------------------------------
// ----- Cleanup + Error handling -----------------------------------------
// ------------------------------------------------------------------------

	FreeArgs(rdargs);
      }
      } else { rc=10; PrintFault(IoErr(), NULL); }
      CloseLibrary((struct Library *)muBase);
    } else { rc=20; PutStr(NomuFS); }
    CloseLibrary((struct Library *)DOSBase);
  } else { rc=20; thisproc->pr_Result2 = ERROR_INVALID_RESIDENT_LIBRARY; }
  return(rc);
}

