#include <zephyr/zephyr.h>
#include <com_err.h>
#include <string.h>

#include "mymalloc.h"
#include "zephyr.h"
#include "xznol.h"

/*
 * $Id: zephyr.c,v 1.6 1993/05/02 06:43:15 marc Exp $
 */

#ifdef ZDEBUG
#define dprintf(args) printf args
#else
#define dprintf(args)
#endif

int zfct(Code_t code, char *msg)
{
   if (code != ZERR_NONE) {
      if ((code != ZERR_HMDEAD) &&
	  (code != ZERR_SERVNAK)) {
	 com_err("xznol", code, msg);
      }
      return(0);
   }

   return(1);
}

int zephyr_init()
{
#ifdef ZDEBUG
   int port = 0;
#define portaddr &port
#else
#define portaddr NULL
#endif

   initialize_krb_error_table();

   zfct(ZInitialize(), "while initializing");
   zfct(ZOpenPort(portaddr), "while opening port");

#ifdef ZDEBUG
   printf("zephyr port,fd = %d,%d\n",port,ZGetFD());
#endif

   return(ZGetFD());
#undef portaddr
}

void zephyr_cleanup()
{
   zfct(ZCancelSubscriptions(0),"while cancelling subscriptions");
}

void zephyr_fixuser(char *kname)
{
   if (! strchr(kname, '@')) {
      strcat(kname,"@");
      strcat(kname,ZGetRealm());
   }
}

void zephyr_locate(char *kname)
{
   ZAsyncLocateData_t ald;

   dprintf(("requesting locations for %s\n",kname));

   if (zfct(ZRequestLocations(kname, &ald, UNACKED, ZAUTH),
	    "while requesting locations")) 
      ZFreeALD(&ald);
}

void zephyr_sub(char *kname)
{
   ZSubscription_t sub;

   dprintf(("subscribing to %s\n",kname));

   sub.zsub_recipient = "";
   sub.zsub_class = LOGIN_CLASS;
   sub.zsub_classinst = kname;

   zfct(ZSubscribeToSansDefaults(&sub, 1, 0), "while subscribing");
}

void zephyr_input(int once)
{
   ZNotice_t notice;
   int n;
   ZLocations_t *locs;
   char *kname;
   int changed;

   while (ZPending()) {
      ZReceiveNotice(&notice, NULL);

      dprintf(("received zephyr packet <%s,%s,%s,%s>\n",
	       notice.z_class, notice.z_class_inst, notice.z_recipient, 
	       notice.z_opcode));

#ifdef ASYNCDEBUG
      /* if we're dealing with an "unexpected" packet in the */
      if (once)
	 com_err("xznol", ZERR_INTERNAL,
		 "debug info: unexpected <%s,%s,%d>",
		 notice.z_class, notice.z_class_inst, notice.z_kind);
#endif

      changed = 0;
      if (strcmp(notice.z_class, LOGIN_CLASS) == 0) {
	 if (zfct(ZParseLocations(&notice, NULL, &n, &kname),
		  "while parsing login notification")) {
	    if (n>0) {
	       locs = (ZLocations_t *) mymalloc(n*sizeof(ZLocations_t));
	       if (zfct(ZGetLocations(locs,&n),
			"while getting locations from login notification")) {
		  if (strcmp(notice.z_opcode, LOGIN_USER_LOGIN) == 0) {
		     while(n--) {
			dprintf(("login notification: %s on %s\n",
				 kname, locs[n].host));
			changed += login_user(kname, locs+n);
		     }
		     if (changed) redisplay_user(kname);
		  } else if (strcmp(notice.z_opcode, LOGIN_USER_LOGOUT) == 0) {
		     while(n--) {
			dprintf(("logout notification: %s on %s\n",
				 kname, locs[n].host));
			changed += logout_user(kname, locs+n);
		     }
		     if (changed) redisplay_user(kname);
		  } else {
		     zfct(ZERR_INTERNAL,
			  "while getting type of login notification");
		  }
	       }
	       myfree(kname);
	    }
	 }
      } else if (strcmp(notice.z_class, LOCATE_CLASS) == 0) {
	 if (notice.z_kind == HMACK) {
	    /* The HMACK came here.  This shouldn't strictly speaking, ever
	       happen.  Not clear what's causing it, or what the solution
	       is, but it seems to be related to ZRequestLocations timing
	       out waiting for the HMACK */
#ifdef ASYNCDEBUG
	    com_err("xznol", ZERR_INTERNAL,
		    "debug info - email marc: got HMACK <%s>",
		    notice.z_class_inst);
#endif
	 } else if (zfct(ZParseLocations(&notice, NULL, &n, &kname),
			 "while parsing location response")) {
	    if (n>0) {
	       dprintf(("locate response: %s on %d hosts\n", kname, n));
	       locs = (ZLocations_t *) mymalloc(n*sizeof(ZLocations_t));
	       if (zfct(ZGetLocations(locs,&n),
			"while getting locations from location response")) {
		  changed += replace_user(kname, locs, n);
		  if (changed) redisplay_user(kname);
	       }
	    } else if (n == 0) {
	       dprintf(("locate response: %s not logged in\n", kname));
	       changed += logout_user(kname, NULL);
	       if (changed) redisplay_user(kname);
	    }
	    myfree(kname);
	 }
      } else {
	 com_err("xznol", ZERR_INTERNAL,
		 "while parsing zephyr packet <%s,%s,%s,%s>",
		 notice.z_class, notice.z_class_inst, notice.z_recipient,
		 notice.z_opcode);
      }

      ZFreeNotice(&notice);

      process_xinput();
      if (once) break;
   }
}
