#include <zephyr/zephyr_internal.h>

#include <pwd.h>
#include <sys/file.h>
#include <sys/param.h>
#include <netdb.h>

extern char *getenv();
extern int errno;

Code_t ZHackSetLocation(exposure, host, disp)
    char *exposure;
{
    return (Z_HackSendLocation(LOGIN_CLASS, exposure, ZAUTH,
			       "$sender logged in to $1 on $3 at $2",
			       host, disp));
}

Code_t ZHackUnsetLocation(host, disp)
    char *host;
    char *disp;
{
    return (Z_HackSendLocation(LOGIN_CLASS, LOGIN_USER_LOGOUT, ZNOAUTH,
			       "$sender logged out of $1 on $3 at $2",
			       host, disp));
}

Code_t ZHackFlushMyLocations()
{
    return (Z_HackSendLocation(LOGIN_CLASS, LOGIN_USER_FLUSH, ZAUTH, "",
			       NULL, NULL));
}

Z_HackSendLocation(class, opcode, auth, format, hackhost, disp)
    char *class;
    char *opcode;
    int (*auth)();
    char *format;
    char *hackhost;
    char *disp;
{
    char *ttyname(), *ctime();
    char host[MAXHOSTNAMELEN], mytty[MAXPATHLEN];
    int retval;
    long ourtime;
    ZNotice_t notice, retnotice;
    char *bptr[3];
#ifdef X11
    char *display;
#endif /* X11 */
    char *ttyp;
    struct hostent *hent;
    short wg_port = ZGetWGPort();
    
    (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;
    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 (gethostname(host, MAXHOSTNAMELEN) < 0)
	return (errno);
    if (hackhost == NULL) {
	hent = gethostbyname(host);
	if (hent)
	    (void) strcpy(host, hent->h_name);
	bptr[0] = host;
    } else
	bptr[0] = hackhost;
    if (disp == NULL) {
#ifdef X11
	if ((display = getenv("DISPLAY")) && *display) {
	    (void) strcpy(mytty, display);
	    bptr[2] = mytty;
	} else {
#endif /* X11 */
	    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]);
#ifdef X11
	}
#endif /* X11 */
    } else
	bptr[2] = disp;
    
    ourtime = time((long *)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);
}
