/* gtd_ring.c - Handle the sending of an announcement to a ringer process
 *
 * Copyright (C) 1994, 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.
 * 
 * Description:
 * 
 *  Handles the sending of an announcement message.  It does this by
 * loading a ".ringer" file from the users home account, and using
 * it's specification to send a message to a given user.
 * 
 * $Log: gtd_ring.c,v $
 * Revision 1.8  1995/07/23  21:51:54  zappo
 * In previous fix forgot to change sizeof the address being used.
 *
 * Revision 1.7  1995/07/23  21:19:50  zappo
 * Forwarding can mess up the printed name of hosts.  Grab the TARGET
 * address for the name first, and if that fails, then grab the return
 * address.
 *
 * Revision 1.6  1995/07/15  19:51:01  zappo
 * Replaced constant with a define.
 *
 * Revision 1.5  1995/04/05  00:57:44  zappo
 * In the case of really long application names being inserted, use
 * strncpy to copy contents into message buffer.
 *
 * Revision 1.4  1995/04/01  18:58:22  zappo
 * Removed &'s in array indicies
 *
 * Revision 1.3  1995/03/25  04:23:38  zappo
 * Updated copyright
 *
 * Revision 1.2  1995/02/11  17:06:35  zappo
 * Added forwarding capability when ringer read in is not the same as
 * current host
 *
 * Revision 1.1  1995/02/01  03:50:25  zappo
 * Initial revision
 *
 * History:
 * zappo   11/20/94    Created
 *
 * Tokens: ::Header:: gtalkd.h 
 */

#include "etalklib.h"
#include "gtalkd.h"

static GNU_RING_CONTROL   rc;
static GNU_RING_RESPONSE  rr;


/*
 * Function: RING_read
 *
 *   Locally defined function which reads from the input device.  It
 * should only be called from the main read loop.
 *
 * Returns:     static int  - 
 * Parameters:  Ctxt - Context
 *              io   - Pointer to io
 * History:
 * zappo   12/12/94   Created
 */
static void RINGER_read(Ctxt, io)
     struct DaemonContext *Ctxt;
     struct InputDevice   *io;
{
  ET_recv(io, &rr, sizeof(rr));
}


/*
 * Function: RINGER_sendto
 *
 *   Sends an announcement message to a process designated by a user
 * as a "ringer".
 *
 * Returns:     int  - 
 * Parameters:  uo   - Pointer to user object
 *              ro   - Pointer to request object
 *              Ctxt - Context
 * History:
 * zappo   11/20/94   Created
 */
int RINGER_sendto(uo, ro, Ctxt)
     struct UserObject    *uo;
     struct RequestObject *ro;
     struct DaemonContext *Ctxt;
{
  static char *ampm[] = { "am", "pm" };
  char                buff[300];
  int                 ap, hr;
  struct HostObject  *host;
  struct tm          *clock;
  struct InputDevice *rdev;
  int                 ans;

  rdev = RING_open(uo->ringf, Ctxt->udp_ring);

  if(! rdev)
    {
      /* In this case, no ringer file available */
      uo->ringto = NULL;
      return FAILED;
    }

  /* Set who the ringer is set to here... */
  uo->ringto = rdev;

  /* Get the hostname for the message we are sending. */
  host = HOST_gen_host_by_addr((struct sockaddr *)&ro->request.addr,
			       sizeof(ro->request.addr));
  /* We just grabbed the TARGET host.  This is the address the
     other guy wants us to announce as.  If it fails, then grab
     the name of the machine which just sent us the address.  This
     could be wrong due to forwarding, but we need to advertise
     something. */
  if(!host)
    host = HOST_gen_host_by_addr((struct sockaddr *)&ro->sender->raddr,
				 sizeof(ro->sender->raddr));
  if(!host)
    {
      if(verbose)
	printf("Error finding printable host name!\n");
      return BADADDR;
    }


  /* Check to make sure that we are on the same host as the sender... */
  if(verbose)
    printf("Is ring local? Only if (%ld == %ld)\n", 
	   rdev->raddr.sin_addr.s_addr,
	   host->addr.sin_addr.s_addr);

  if(rdev->raddr.sin_addr.s_addr != host->addr.sin_addr.s_addr)
    {
      /* Return the new error code (Not here but...) */
      return TRY_HERE;
    }

  /* Okie dokie.  Let write out a nice little message.
   */
  clock = localtime(&ro->stamp.tv_sec);
  
  /* Find the 12 hour clock time.
   */
  if(clock->tm_hour > 12)
    {
      ap = 1;
      hr = clock->tm_hour - 12;
    }
  else
    {
      ap = 0;
      hr = clock->tm_hour;
    }
  
  sprintf((char *)rc.msg1, "Message from GNU Talk Daemon: %d/%d/%d %d:%02d%s",
	  clock->tm_mon, clock->tm_mday, clock->tm_year,
	  hr, clock->tm_min, ampm[ap]);
  sprintf((char *)rc.msg2, "gtalk: connection requested by %s@%s.",
	  ro->request.l_name, host->name);
  
  /* We must be careful to tell the user what kind of response to use.
   */
  if(ro->request.vers == 0)
    sprintf(buff, "gtalk: respond with \"otalk %s@%s\"",
	    ro->request.l_name, host->name);
  else if((ro->request.vers == TALK_VERSION) ||
	  (ro->request.extended == 0))
    sprintf(buff, "gtalk: respond with \"talk %s@%s\"",
	    ro->request.l_name, host->name);
  else
    sprintf(buff, "gtalk: respond with \"%s %s@%s\"",
	    ro->extend, ro->request.l_name, host->name);
    
  strncpy((char *)rc.msg3, buff, RINGER_MESSAGE_LEN);
  buff[RINGER_MESSAGE_LEN - 1] = 0;

  rc.vers = TALK_VERSION_GNU;
  rc.type = RINGER_CALL;
  rc.addr = *((struct sockaddr *)&Ctxt->udp_ring->laddr);
  strcpy(rc.name, ro->request.l_name);

  if(verbose)
    {
      printf("Sending ringer request to read in address: ");
      print_sockaddr((struct sockaddr *)&rdev->raddr);
      printf("\n");
    }

  /* Send the message */
  if(ET_send(rdev, (char *)&rc, sizeof(rc)) == Fail)
    return FAILED;

  rdev->readme = RINGER_read;
  /* timeout small on local network. A long timeout would inhibit the */
  /* daemon from handling similar requests during this time.          */
  rdev->timeout = 1;

  /* Wait for response
   * Admittedly this is not completely safe, but on AVERAGE, there is
   * never more than one dialer at any time anyways, so WHO CARES!
   * Set answer to be non-0, so that if a success is returned, from
   * select because of a read error, that error is propigated.
   */
  rr.answer = FAILED;
  ans = ET_select_all(Ctxt, rdev);

  rdev->readme = NULL;
  rdev->timeout = 0;

  if(verbose)
    printf("Answer to ringer is %s.\n", msg_responses[ans]);

  /* To be a success, both sending and answer must match */
  if(ans && (rr.answer == SUCCESS))
    return SUCCESS;
  else
    return FAILED;
}
