/*  Prntr.c  */

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

#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include "common.h"
#include "zprstat.h"
#include "Prntr.h"
#include "Pstat.h"
#include "substr.h"

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

#ifdef SOLARIS
#define index  strchr
#define rindex strrchr
#endif

#define	NUM_JOBS_UNKNOWN -1

static	char	buffer[1024];
static	char*	change_message_formats[] =
{
    "This message should never appear.",
    "Printer %s is unknown!\n%s\nIts earlier status was: %s.\n",
    "Printer %s has come back up.\n%s\nIts earlier status was: %s.\n",
    "Printer %s has gone down.\n%s\nIts earlier status was: %s.\n",
    "Printer %s is timing out.\n%s\nIts earlier status was: %s.\n",
};
static	char*	update_message_format = "%-14s %-7s %4s\n";

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

Prntr*	Prntr_Create( name, location )
char*	name;
char*	location;
{
    Prntr* prntr = New(Prntr);

    prntr->prntr_name = NewString(name);
    prntr->prntr_location = NewString(location);
    prntr->prntr_pcap_data = NULL;
    prntr->prntr_machine = NULL;
    prntr->prntr_current_status = Pstat_INIT_STATE;
    prntr->prntr_previous_status = Pstat_INIT_STATE;
    prntr->prntr_num_jobs = 0;
    prntr->prntr_reason = NULL;
    prntr->prntr_socket_addr = NULL;
    prntr->prntr_next_prntr = NULL;

    return prntr;
}

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

void	Prntr_Delete( prntr )
Prntr*	prntr;
{
    Delete(prntr->prntr_name);
    Delete(prntr->prntr_location);
    Delete(prntr->prntr_pcap_data);
    Delete(prntr->prntr_machine);
    Delete(prntr->prntr_reason);
    Delete(prntr->prntr_socket_addr);
    Delete(prntr);
}

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

void	Prntr_Find_Machine( prntr )
Prntr*	prntr;
{
    register char** hv;
    char** hes_resolve();
    char* pcap;
    int i, length;
    char* start;
    char* end;
    struct hostent* hp;
    struct servent* sp;
    struct sockaddr_in* sin;

    if ((hv = hes_resolve(prntr->prntr_name, "pcap")) == NULL)
      return;

    pcap = prntr->prntr_pcap_data = NewString(*hv);
    Delete(*hv);

    if ((i = substr(pcap, ":rm=")) < 0)
      return;

    start = pcap + i + 4;
    if ((end = index(start, ':')) == NULL)
      return;

    length = (int)(end-start);

    strncpy(buffer, start, length);
    buffer[length] = EOS;
    prntr->prntr_machine = NewString(buffer);

    hp = gethostbyname(buffer);

    if (hp == NULL) return;

    sp = getservbyname("printer", "tcp");
    if (sp == NULL)
      {
	  fprintf(stderr, "printer/tcp: unknown service.");
	  exit(1);
      }

    sin = New(struct sockaddr_in);
#ifndef SOLARIS
    bzero((char *)sin, sizeof(struct sockaddr_in));
    bcopy(hp->h_addr, (caddr_t)&sin->sin_addr, hp->h_length);
#else
    memset((char *)sin, 0, sizeof(struct sockaddr_in));
    memcpy((caddr_t)&sin->sin_addr, hp->h_addr, hp->h_length);
#endif
    sin->sin_family = hp->h_addrtype;
    sin->sin_port = sp->s_port;

    prntr->prntr_socket_addr = sin;
}

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

void	Prntr_Update( prntr )
Prntr*	prntr;
{
    if (debug)
      printf("Updating status of %s...\n", prntr->prntr_name);

    prntr->prntr_previous_status = prntr->prntr_current_status;
    prntr->prntr_num_jobs = NUM_JOBS_UNKNOWN;
}

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

void	Prntr_Set_Reason( prntr, reason )
Prntr*	prntr;
char*	reason;
{
    Delete(prntr->prntr_reason);
    prntr->prntr_reason = NewString(reason);
}

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

char*	Prntr_Change_Message( prntr )
Prntr*	prntr;
{
    if ((Prntr_Curr_Status(prntr) == Prntr_Prev_Status(prntr)) ||
	(Prntr_Prev_Status(prntr) == Pstat_INIT_STATE))
      return NULL;

    sprintf(buffer,
	    change_message_formats[(int)Prntr_Curr_Status(prntr)],
	    Prntr_Name(prntr),
	    Prntr_Reason(prntr),
	    Pstat_Unparse(Prntr_Prev_Status(prntr)));

    return NewString(buffer);
}

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

char*	Prntr_Update_Message( prntr )
Prntr*	prntr;
{
    Pstat curr_status = Prntr_Curr_Status(prntr);
    int num_jobs;
    char num_jobs_string[1024];

    if ((num_jobs = Prntr_Num_Jobs(prntr)) != NUM_JOBS_UNKNOWN)
      sprintf(num_jobs_string, "%d", num_jobs);
    else
      strcpy(num_jobs_string, "???");

    sprintf(buffer,
	    update_message_format,
	    Prntr_Name(prntr),
	    Pstat_Unparse(curr_status),
	    num_jobs_string);

    return NewString(buffer);
}

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

Prntr*	Prntr_Initialize(filenames)
char**	filenames;
{
    FILE* fp = NULL;
    char pr_name[1024];
    char pr_loc[1024];
    Prntr* head = NULL;
    Prntr* current;
    Prntr* previous=NULL;
    int i = 0;

    while ((filenames != NULL) &&
	   (filenames[i] != NULL) &&
	   ((fp = fopen(filenames[i], "r")) == NULL))
      ++i;

    if (fp == NULL)
      {
	  fprintf(stderr, "%s: unable to open printer file\n", program_name);
	  exit(1);
      }

    while (fgets(buffer, 1024, fp) != NULL)
      {
	  strcpy(pr_name, empty_string);
	  strcpy(pr_loc, empty_string);
	  sscanf(buffer, "%s %s", pr_name, pr_loc);

	  current = Prntr_Create(pr_name, pr_loc);
	  if (head == NULL)
	    head = current;
	  else
	    previous->prntr_next_prntr = current;
	  previous = current;
      }

    fclose(fp);

    if (head == NULL)
      {
	  fprintf(stderr, "%s: no printers to check\n", program_name);
	  exit(1);
      }

    return head;
}

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