/*
 * Copyright (C) 1995 Free Software Foundation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you can either send email to this
 * program's author (see below) or write to:
 *
 *              The Free Software Foundation, Inc.
 *              675 Mass Ave.
 *              Cambridge, MA 02139, USA. 
 *
 * Please send bug reports, etc. to zappo@gnu.ai.mit.edu.
 * 
 * etl_ring.c
 *
 * Purpose:
 *   This file handles all cases related to the RINGER function of
 * gnu talk related programs.  This includes setting up, disabling,
 * and handling of RING requests.  A ring request is a network "ping"
 * from a talk daemon (UDP) which signifies that a person is
 * attempting to talk to you.  Usually this is a TTY message, but
 * under the GNU talk daemon, the existance of a .ringer file will
 * instead cause the daemon to send a specially designed UDP message
 * to be sent to the designated program.
 *
 * $Log: etl_ring.c,v $
 * Revision 1.6  1995/07/22  13:29:13  zappo
 * Used to have variable s_addr, but this is a macro on some systems so
 * it's been renamed to sock_addr. (thanks uwe@snark.niif.spb.su)
 *
 * Revision 1.5  1995/07/15  19:50:26  zappo
 * When creating .ringer files, now translate into & from net order
 *
 * Revision 1.4  1995/03/25  04:15:40  zappo
 * Updated copyright
 *
 * Revision 1.3  1995/03/04  14:47:13  zappo
 * Added use of syslog to report errors when in use by syslog
 *
 * Revision 1.2  1995/02/01  03:41:34  zappo
 * Basic maintenace to make this work, and added some print routines
 *
 * Revision 1.1  1995/01/28  21:20:45  zappo
 * Initial revision
 *
 *
 * ::Header:: etalklib.h
 */

#include "etalklib.h"
#include "gtalk.h"
#include "sitecnfg.h"

/* This is a pointer used to control an integer in a context
 * structure.  Since you can only have one ringer active, we only have
 * one option to setup a ringer.
 */
static int *ringflag = NULL;

/* This is a pointer to the ringer UDP socket.  This socket will be
 * used to accept new ring information.
 */
static struct InputDevice *ringsock = NULL;


/*
 * Function: RING_activate
 *
 *   This function activates our ring status by turning on flags, and
 * advertising our socket by storing it's definition in a file.
 *
 * Returns:     int  - 
 * Parameters:  rf - Pointer to ringer file
 *              rs - Pointer to ringer socket
 *              rm - The readme function to be added to the ringer device
 * History:
 * zappo   11/28/94   Created
 * zappo   1/29/95    Added extra param to this function.
 */
int RING_activate(rf, rs, rm)
     int                *rf;
     struct InputDevice *rs;
     void              (*rm)();
{
  char buff[80];
  char *env;
  FILE *f;			/* ringer file. */

  if((ringflag == (int *)NULL) || (ringflag == rf))
    {
      /* Set this only once. */
      ringflag = rf;
    }
  else
    {
      if(verbose)
	printf("RING_activate: Attempt to reset ringer activation twice.\n");
      else if(syslogdebug)
	syslog(LOG_ERR, "RING_activate: Attempt to reset ringer activation twice.");
      return Fail;
    }

  if(!rs)
    {
      if(verbose)
	printf("RING_activate: Cannot activate ringer without ringer socket to attach\n");
      else if(syslogdebug)
	syslog(LOG_ERR, "RING_activate:  Cannot activate ringer without ringer socket to attach");
      return Fail;
    }

  /* Open for replacing. 
   */
  env = getenv("HOME");

  if(env == NULL)
    {
      if(!syslogdebug)
	printf("You do not have the HOME environment variable set!\n");
      return Fail;
    }

  strcpy(buff, env);
  strcat(buff, "/");
  strcat(buff, RINGER_RC);

  f = fopen(buff, "w");

  if(f == NULL)
    {
      if(!syslogdebug)
	printf("Failure to open Ringer File [%s].\n", buff);
      return Fail;
    }

  /* Write the thing out in text. Must be our local address m.  Text
     is always in the right byte order, but we store pieces in network
     order for simplicity. */
  fprintf(f, "%d %d %ld", 
	  ntohs(rs->laddr.sin_family),
	  ntohs(rs->laddr.sin_port),
	  ntohl(rs->laddr.sin_addr.s_addr));
	 
  if(verbose)
    printf("%d %d %ld", 
	   ntohs(rs->laddr.sin_family),
	   ntohs(rs->laddr.sin_port),
	   ntohl(rs->laddr.sin_addr.s_addr));
	  
  fclose(f);

  *ringflag = TRUE;

  ringsock = rs;
  /* Now set the reading devices on the ringer socket.  This includes the
   * timeout features (Not on) and the function to call when something 
   * happens.
   */
  ringsock->readme  = rm;
  ringsock->timeout = 0;
  ringsock->timefn  = NULL;
  ringsock->timemsg = NULL;

  return Success;
}


/*
 * Function: RING_deactivate
 *
 *   This function will deactivate a ringer call by clearing the flags
 * and deleting the file currently advertising our existence.
 *
 * Returns:     int  - Return status
 * Parameters:  None
 *
 * History:
 * zappo   11/28/94   Created
 */
int RING_deactivate()
{
  char  buff[80];
  char *env;
#ifdef HAVE_UNLINK
# ifndef HAVE_UNISTD_H
  int unlink();
# endif
#endif

  if((ringflag == NULL) || (*ringflag == 0)) return Success;

  env = getenv("HOME");

  if(env == NULL)
    {
      if(!syslogdebug)
	printf("You do not have the HOME environment variable set!\n");
      return Fail;
    }

  strcpy(buff, env);
  strcat(buff, "/");
  strcat(buff, RINGER_RC);

#ifdef HAVE_REMOVE
  if(unlink(buff))
    {
      if(!syslogdebug)
	printf("Error(remove) deleting ringer rc file.\n");
      return Fail;
    }
#else
# ifdef HAVE_UNLINK
  if(unlink(buff))
    {
      if(!syslogdebug)
	printf("Error(unlink) deleting ringer rc file.\n");
      return Fail;
    }
# endif
#endif

  *ringflag = FALSE;

  if(ringsock)
    ringsock->readme = NULL;

  ringsock = NULL;

  /* Turn off ringer features here.
   */

  return Success;
}


/*
 * Function: RING_open
 *
 *   This will attempt to open a ringerfile defined in the parameter
 * list.  It then returns a UDP device which *should* be able to
 * contact that user.
 *
 * Returns:     struct InputDevice * - 
 * Parameters:  ringfile - Pointer toCharacter of file
 *              udp      - Pointer to udp of this program
 * History:
 * zappo   12/12/94   Created
 */
struct InputDevice *RING_open(ringfile, udp)
     char               *ringfile;
     struct InputDevice *udp;
{
  FILE               *f;
  struct sockaddr_in  ad;
  struct InputDevice *new;
  int                 fam, prt;
  long                sock_addr;

  f = fopen(ringfile, "r");

  /* Return NULL, meaning FAIL if there is no such file.
   */
  if(f == NULL)
    {
      if(verbose)
	printf("The file %s is not available for reading.\n", ringfile);
      else if(syslogdebug > 1)
	syslog(LOG_WARNING, "File %s not available", ringfile);
      return NULL;
    }

  /* Scan the numbers into an addr struct.
   */
  if(fscanf(f, "%d %d %ld", &fam, &prt, &sock_addr)
     == 0)
    {
      fclose(f);
      return NULL;
    }
  /* We must pull these guys out because they are short ints, and */
  /* printf does not guarantee over all machines that a short is  */
  /* correctly read into.                                         */
  /* Also, they are stored in "net order" and must be put into    */
  /* order */
  ad.sin_family = fam;
  ad.sin_port = htons(prt);
  ad.sin_addr.s_addr = htonl(sock_addr);
  
  fclose(f);

  if(verbose)
    {
      printf("Opened file %s: Read address: ", ringfile);
      print_sockaddr((struct sockaddr *)&ad);
      printf("\n");
    }      

  new = UDP_byaddr(udp, &ad);

  /* fill in other parts here.
   */
  
  return new;
}


/*
 * Function: RING_print_control
 *
 *   Prints out the contents of a ringer control message.
 *
 * Returns:     Nothing
 * Parameters:  rc - Pointer to ringer control struct
 *
 * History:
 * zappo   1/29/95    Created
 */
void RING_print_control(rc)
     GNU_RING_CONTROL *rc;
{
  printf("Contents of ringer control message.\n");
  printf("version : %d\n", rc->vers);
  printf("type    : %d\n", rc->type);
  printf("addr    : "); print_swapped_sockaddr(&rc->addr);
  printf("\nname    : %s\n", rc->name);
  printf("msg1    : %s\n", rc->msg1);
  printf("msg2    : %s\n", rc->msg2);
  printf("msg3    : %s\n", rc->msg3);
}


/*
 * Function: RING_print_response
 *
 *   Prints out the contents of the ringer response message.
 *
 * Returns:     Nothing
 * Parameters:  rr - Pointer to rr
 *
 * History:
 * zappo   1/29/95    Created
 */
void RING_print_response(rr)
     GNU_RING_RESPONSE *rr;
{
  printf("Contents of ringer response message.\n");
  printf("version : %d\n", rr->vers);
  printf("type    : %d\n", rr->type);
  printf("answer  : %d\n", rr->answer);
}
