/* This file is part of the Project Athena Zephyr Notification System.
 * It contains code for the "zlocate" command.
 *
 *	Created by:	Robert French
 *
 *	Copyright (c) 1987 by the Massachusetts Institute of Technology.
 *	For copying and distribution information, see the file
 *	"mit-copyright.h". 
 */

#include <sysdep.h>
#include <zephyr/zephyr.h>
#include <sys/socket.h>

RCSID("$Id: zlocate.c,v 1.8 2000/02/05 09:23:58 assar Exp $");

static int numusers=0, numleft=0, parallel=0, oneline=0;
static char *whoami;

static RETSIGTYPE
timeout(int sig)
{
  fprintf (stderr, "%s: no response from server\n", whoami);
  exit(1);
}

static void
usage(void)
{
   printf("Usage: %s [ -a | -d ] [ -p ] [ -1 ] [-R realm] user ... \n",whoami);
   exit(1);
}

static void 
print_locs(char *user, int nlocs)
{
   int one = 1, retval;
   ZLocations_t locations;

   if ((!oneline) && (numusers>1))
     printf("\t%s:\n",user);

   if ((!oneline) && (nlocs == 0))
      printf("Hidden or not logged-in\n");

   for (;nlocs;nlocs--) {
      if ((retval = ZGetLocations(&locations,&one)) != ZERR_NONE) {
	 com_err(whoami,retval,"while getting location");
	 exit(1);
      }
 
      if (oneline) {
	 printf("%s:\t%s\t%s\t%s\n",user,locations.host,locations.tty,
		locations.time);
      } else {
	 printf("%-42s %-7s %s\n",locations.host, locations.tty, locations.time);
      }
   }

   if ((!oneline) && (numusers > 1) && (numleft > 0))
     printf("\n");
}

int
main(int argc, char **argv)
{
    char user[BUFSIZ],*whichuser;
    ZAsyncLocateData_t ald;
    int retval,i,numlocs,numfound,loc,auth;
    ZNotice_t notice;
    char *realm = NULL;
#ifdef _POSIX_VERSION
    struct sigaction sa;
#endif
   
    whoami = argv[0];
    auth = -1;

    argv++;
    argc--;

    for (i=0; i < argc; i++)
	if (argv[i][0] == '-')
	    switch (argv[i][1]) {
	    case 'a':
		if (auth != -1) usage();
		auth = 1;
		break;
	    case 'd':
		if (auth != -1) usage();
		auth = 0;
		break;
	    case 'p':
		parallel = 1;
		break;
	    case 'R':
		if (argc < i + 1)
		    usage();
		realm = argv[i+1];
		i++;
		break;
	    case '1':
		oneline = 1;
		break;
	    default:
		usage();
		break;
	    }
	else
	    numusers++;

    if (numusers == 0)
	usage();

    if (auth == -1) auth = 1;
   
    if ((retval = ZInitialize()) != ZERR_NONE) {
	com_err(whoami,retval,"while initializing");
	exit(1);
    } 

    if (realm == NULL)
	realm = ZGetDefaultRealm();

    numleft = numusers;
    numfound = 0;

    i = 0;
    for (loc = 0; loc < argc; loc++) {
	if (argv[loc][0] == '-') { 
	    if (argv[loc][1] == 'R')
		loc++;
	    continue;
	}

	if (!strchr(argv[loc],'@'))
	    sprintf (user, "%s@%s", argv[loc], realm);
	else
	    sprintf (user, "%s", argv[loc]);
	    
	if (parallel) {
	    if ((retval = ZRequestLocations(realm, user, &ald, i ? UNSAFE : UNACKED,
					    auth?ZAUTH:ZNOAUTH)) != ZERR_NONE) {
		com_err(whoami,retval,"requesting location of %s",user);
		exit(1);
	    }
	    i = 1;
	} else {
	    retval = ZNewLocateUser (realm,user,&numlocs,auth?ZAUTH:ZNOAUTH);
	    if (retval != ZERR_NONE) {
		com_err(whoami,retval,"while locating user %s",user);
		exit(1);
	    }
	    print_locs(user,numlocs);
	    numfound += numlocs;
	}
    }

    if (parallel) {
#ifdef _POSIX_VERSION
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sa.sa_handler = timeout;
	sigaction(SIGALRM, &sa, (struct sigaction *)0);
#else
	signal (SIGALRM, timeout);
#endif
	while (numleft-- > 0) {
	    alarm(SRV_TIMEOUT);
	    if ((retval = ZReceiveNotice(&notice, NULL)) != ZERR_NONE) {
		com_err(whoami,retval,"while searching notice queue");
		continue;
	    }
	    if ((retval = ZParseLocations(&notice, (ZAsyncLocateData_t *)NULL,
					  &numlocs, &whichuser)) != ZERR_NONE) {
		com_err(whoami,retval,"while parsing locations");
		continue;
	    }
	    if (numlocs >= 0) {
		print_locs(whichuser,numlocs);
		free(whichuser);
		numfound += numlocs;
	    }
	    ZFreeNotice(&notice);
	}
    }
    return((numfound > 0) ? 0 : 1);
}
