/*  Notice.c  */

/*--------------------------------------------------------------------------*/

#include "common.h"
#include "zprstat.h"
#include "Notice.h"
#include <strings.h>
#include <zephyr/zephyr.h>

/*--------------------------------------------------------------------------*/

static	char*	while_initializing = "while initializing";
static	char*	while_sending = "while sending notice";
static	char*	while_waiting = "while waiting for ack";
static	char*	auth_failure = "Authentication failure while sending\n";
static	int	wg_port;

/*--------------------------------------------------------------------------*/

void cancel_default_subscriptions()
{
    Code_t retval;
    ZSubscription_t* subs;
    int nsubs;

    if ((retval = ZRetrieveDefaultSubscriptions(&nsubs)) != ZERR_NONE)
      {
	  com_err(program_name, retval,
		  "while retrieving default subscriptions");
	  return;
      }
    
    subs = NewArray(ZSubscription_t, nsubs);
    
    if ((retval = ZGetSubscriptions(subs, &nsubs)) != ZERR_NONE)
      {
	  com_err(program_name, retval,
		  "while getting default subscriptions");
	  return;
      }
    
    if ((retval = ZUnsubscribeTo(subs, nsubs, 0)) != ZERR_NONE)
      com_err(program_name, retval,
	      "while unsubscribing to default subscriptions");
    
    (void)ZFlushSubscriptions();
    Delete(subs);
}

/*--------------------------------------------------------------------------*/

int	Notice_Initialize(open_wg_port)
Bool	open_wg_port;
{
    Code_t retval;

    if ((retval = ZInitialize()) != ZERR_NONE)
      {
	  com_err(program_name, retval, while_initializing);
	  exit(1);
      }

    if ((retval = ZOpenPort(0)) != ZERR_NONE)
      {
	  com_err(program_name, retval, "while opening port");
	  exit(1);
      }

    ZCancelSubscriptions(0);

    if (open_wg_port)
      if ((wg_port = ZGetWGPort()) == -1)
	fprintf(stderr,
		"%s: Unable to find windowgram subscription port\n",
		program_name);

    return ZGetFD();
}

/*--------------------------------------------------------------------------*/

void	Notice_Subscribe(class, instance, recipient, wg_client)
char*	class;
char*	instance;
char*	recipient;
Bool	wg_client;
{
    ZSubscription_t sub;
    Code_t retval;

    sub.zsub_class = class;
    sub.zsub_classinst = instance;
    sub.zsub_recipient = recipient;

    if (!wg_client || wg_port > -1)
      if ((retval = ZSubscribeTo(&sub, 1, wg_client?wg_port:0)) !=
	  ZERR_NONE)
	{
	    com_err(program_name, retval, "while subscribing");
	    if (!wg_client)
	      exit(1);
	}

    if (!wg_client)
      cancel_default_subscriptions();
}

/*--------------------------------------------------------------------------*/

void	Notice_Send(class, instance, opcode, msg)
char*	class;
char*	instance;
char*	opcode;
char*	msg;
{
    ZNotice_t notice, retnotice;
    Code_t retval;
    
#ifndef SOLARIS
    bzero((char*)&notice, sizeof(notice));
#else
    memset((char*)&notice, 0, sizeof(notice));
#endif
    notice.z_kind = ACKED;
    notice.z_port = 0;
    notice.z_class = class;
    notice.z_class_inst = instance;
    notice.z_opcode = opcode;
    notice.z_sender = NULL;
    notice.z_recipient = empty_string;
    notice.z_default_format = empty_string;
    notice.z_message = msg;
    notice.z_message_len = strlen(notice.z_message)+1;

    if ((retval = ZSendNotice(&notice, ZNOAUTH)) != ZERR_NONE)
      {
	  if (debug)
	    com_err(program_name, retval, while_sending);
	  return;
      }

    if ((retval = ZIfNotice(&retnotice, (struct sockaddr_in*)0,
			    ZCompareUIDPred,
			    (char*)&notice.z_uid)) != ZERR_NONE)
      {
	  if (debug)
	    com_err(program_name, retval, while_waiting);
	  return;
      }

    if (retnotice.z_kind == SERVNAK)
      {
	  if (debug)
	    fprintf(stderr, auth_failure);
	  ZFreeNotice(&retnotice);
	  return;
      }

    if (debug)
      if (!strcmp(retnotice.z_message, ZSRVACK_SENT))
	fprintf(stderr, "%s.%s: Message sent.\n", class, instance);
      else
	fprintf(stderr, "%s.%s: Nobody subscribing!\n", class, instance);

    ZFreeNotice(&retnotice);
}

/*--------------------------------------------------------------------------*/

char*	Notice_Receive(class, instance)
char*	class;
char*	instance;
{
    ZNotice_t notice;
    struct sockaddr_in from;
    Code_t retval;
    char* msg;

    if ((retval = ZReceiveNotice(&notice, &from)) != ZERR_NONE)
      {
	  com_err(program_name, retval, "while receiving notice");
	  exit(1);
      }

    if (ZCheckAuthentication(&notice, &from))
      /*  Authenticated  */;

    if ((strcmp(notice.z_class, class) != 0) ||
	(strcmp(notice.z_class_inst, instance) != 0))
      return NULL;

    msg = NewString(notice.z_message);
    ZFreeNotice(&notice);
    return msg;
}

/*--------------------------------------------------------------------------*/
