/*	Copyright (c) 1988 by the Massachusetts Institute of Technology.
 *	All Rights Reserved.
 */
#include <sysdep.h>
#include <netdb.h>
#include <zephyr/zephyr.h>
#define string_Eq(a,b) (!strcmp(a,b))
#define DOLOGIN 1
#define DOLOGOUT 2
#define DOFLUSH 3

static char host[MAXHOSTNAMELEN], mytty[MAXPATHLEN];
static int reenter = 0;

void usage()
{
    fprintf(stderr, "\
zlogin: usage: zlogin [-login] [-logout] [-flush] [-exposure <exposure>]\n\
                  [-fromhost <string>]\n");
    exit(1);
}

static char *parse_exposure_level(text)
     char *text;
{
    if (!strcasecmp(text, EXPOSE_NONE))
      return (EXPOSE_NONE);
    else if (!strcasecmp(text, EXPOSE_OPSTAFF))
      return (EXPOSE_OPSTAFF);
    else if (!strcasecmp(text, EXPOSE_REALMVIS))
      return (EXPOSE_REALMVIS);
    else if (!strcasecmp(text, EXPOSE_REALMANN))
      return (EXPOSE_REALMANN);
    else if (!strcasecmp(text, EXPOSE_NETVIS))
      return (EXPOSE_NETVIS);
    else if (!strcasecmp(text, EXPOSE_NETANN))
      return (EXPOSE_NETANN);
    else
      return(NULL);
}

Code_t Z_ExtSendLocation(class, opcode, auth, format, location, realm, hide)
    char *class;
    char *opcode;
    Z_AuthProc auth;
    char *format;
    char *location;
    char *realm;
    int hide;
{
    int retval;
    time_t ourtime;
    ZNotice_t notice, retnotice;
    char *bptr[3];
#ifndef X_DISPLAY_MISSING
    char *display;
#endif
    char *ttyp;
    struct hostent *hent;
    short wg_port = ZGetWGPort();
    char recp[REALM_SZ+2];

    if (realm) {
      strcpy(recp, "*@");
      strcat(recp, realm);
    }

    (void) memset((char *)&notice, 0, sizeof(notice));
    notice.z_kind = ACKED;
    notice.z_port = (u_short) ((wg_port == -1) ? 0 : wg_port);
    notice.z_class = class;
    notice.z_class_inst = ZGetSender();
    notice.z_opcode = opcode;
    notice.z_sender = 0;
    if (realm) 
      notice.z_recipient = recp;
    else
      notice.z_recipient = "";
    notice.z_num_other_fields = 0;
    notice.z_default_format = format;

    /*
      keep track of what we said before so that we can be consistent
      when changing location information.
      This is done mainly for the sake of the WindowGram client.
     */

    if (!reenter) {
            if (gethostname(host, MAXHOSTNAMELEN) < 0)
                    return (errno);

            hent = gethostbyname(host);
            if (hent)
	      (void) strcpy(host, hent->h_name);
	    if (hide)
	      bptr[0] = "0.0.0.0";
	    else
	      bptr[0] = host;
	    if (location && strcmp(location, ""))
	      bptr[2] = location; 
	    else {
#ifndef X_DISPLAY_MISSING
	      if ((display = getenv("DISPLAY")) && *display) {
		(void) strcpy(mytty, display);
		bptr[2] = mytty;
	      } else {
#endif
		ttyp = ttyname(0);
		if (ttyp) {
		  bptr[2] = strrchr(ttyp, '/');
		  if (bptr[2])
		    bptr[2]++;
		  else
		    bptr[2] = ttyp;
		}
		else
		  bptr[2] = "unknown";
		(void) strcpy(mytty, bptr[2]);
#ifndef X_DISPLAY_MISSING
	      }
#endif
	    }
            reenter = 1;
    } else {
            bptr[0] = host;
            bptr[2] = mytty;
    }

    ourtime = time((time_t *)0);
    bptr[1] = ctime(&ourtime);
    bptr[1][strlen(bptr[1])-1] = '\0';


    if ((retval = ZSendList(&notice, bptr, 3, auth)) != ZERR_NONE)
        return (retval);

    retval = Z_WaitForNotice (&retnotice, ZCompareUIDPred, &notice.z_uid,
                              SRV_TIMEOUT);
    if (retval != ZERR_NONE)
      return retval;

    if (retnotice.z_kind == SERVNAK) {
        if (!retnotice.z_message_len) {
            ZFreeNotice(&retnotice);
            return (ZERR_SERVNAK);
        }
        if (!strcmp(retnotice.z_message, ZSRVACK_NOTSENT)) {
            ZFreeNotice(&retnotice);
            return (ZERR_AUTHFAIL);
        }
        if (!strcmp(retnotice.z_message, ZSRVACK_FAIL)) {
            ZFreeNotice(&retnotice);
            return (ZERR_LOGINFAIL);
        }
        ZFreeNotice(&retnotice);
        return (ZERR_SERVNAK);
    } 

    if (retnotice.z_kind != SERVACK) {
        ZFreeNotice(&retnotice);
        return (ZERR_INTERNAL);
    }

    if (!retnotice.z_message_len) {
        ZFreeNotice(&retnotice);
        return (ZERR_INTERNAL);
    }

    if (strcmp(retnotice.z_message, ZSRVACK_SENT) &&
        strcmp(retnotice.z_message, ZSRVACK_NOTSENT)) {
        ZFreeNotice(&retnotice);
        return (ZERR_INTERNAL);
	}

    ZFreeNotice(&retnotice);

    return (ZERR_NONE);
}

int main(argc, argv)
     int argc;
     char **argv;
{
    FILE *fp;
    char buf[512],*ptr;
    int auth,retval;
    u_short port;
    ZNotice_t notice;
    ZSubscription_t sub;
    struct sockaddr_in from;
    register char **current;
    int operation = 0;
    char *locstring = NULL;
    char *exposure = NULL;
    char *realm = NULL;
    char defaultlogin[] = "$sender logged into $1 on $3 at $2";
    char defaultlogout[] = "$sender logged out of $1 on $3 at $2";
    int hide = 0;
    char *whoami;

    whoami = ((whoami = strrchr(argv[0], '/')) ? whoami+1 : argv[0]);
  
    if (! strcmp(whoami, "zlogin")) operation = DOLOGIN;
    else if (! strcmp(whoami, "zlogout")) operation = DOLOGOUT;
    else operation = DOFLUSH;            /* zflushlocs */

    for (current=argv+1; *current; current++) {
      if (string_Eq(*current, "-login")) {
	argc--;
	operation = DOLOGIN;
      } else if (string_Eq(*current, "-logout")) {
	argc--;
	operation = DOLOGOUT;
      } else if (string_Eq(*current, "-flush")) {
	argc--;
	operation = DOFLUSH;
      } else if (string_Eq(*current, "-hide")) {
	argc--;
	hide = 1;
      } else if (string_Eq(*current, "-fromhost")) {
	argc -= 2; current++;
	if (!*current)
	  (void) usage();
	locstring = *current;
      } else if (string_Eq(*current, "-realm")) {
	argc -= 2; current++;
	if (!*current)
	  (void) usage();
	realm = *current;
      } else if (string_Eq(*current, "-exposure")) {
	argc -= 2; current++;
	if (!*current)
	  (void) usage();
	exposure = *current;
      } else
	(void) usage();
    }

    if (exposure)
      exposure = parse_exposure_level(exposure);

    if ((retval = ZInitialize()) != ZERR_NONE) {
	com_err(argv[0],retval,"while initializing");
	exit(1);
    } 
    switch (operation) {
    case DOLOGIN:
      retval = Z_ExtSendLocation(LOGIN_CLASS, exposure ? exposure : 
				 EXPOSE_NETANN, ZAUTH, 
				 defaultlogin, locstring ? locstring : "",
				 realm, hide);
      break;
    case DOLOGOUT:
      retval = Z_ExtSendLocation(LOGIN_CLASS, LOGIN_USER_LOGOUT, ZNOAUTH,
				 defaultlogout, locstring ? locstring : "",
				 realm, hide);
      break;
    case DOFLUSH:
      retval = Z_ExtSendLocation(LOGIN_CLASS, LOGIN_USER_FLUSH, ZNOAUTH,
				 "", "", realm, hide);
      break;
    }
    return(retval);
}
