/* finger.c -- The program that users directly interact with. */

/* Copyright (C) 1988, 1990, 1992 Free Software Foundation, Inc.

   This file is part of GNU Finger.

   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, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */


#include <stdio.h>
#include <config.h>
#include <setjmp.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/file.h>

#include <general.h>
#include <tcp.h>
#include <error.h>
#include <fingerpaths.h>
#include <face-finger.h>
#include <text-finger.h>
#include <netinet/in.h>

#include "getopt.h"


/* **************************************************************** */
/*								    */
/*			      "finger"				    */
/*								    */
/* **************************************************************** */

/* Our version of "finger". */

/* Possible values of the "options" to finger. */
#define FACE 0x01
#define INFO 0x02
#define VERS 0x04

void call_finger ();
extern char *baseprefix ();


/* Non-zero means to get a users face. */
int facing = 0;

/* Long options */
static struct option longopts[] =
{
  { "faces", 0, 0, 'f' },
  { "info", 0, 0, 'i' },
  { "brief", 0, 0, 'b' },
  { "version", 0, 0, 'v' },
  { "port", 0, 0, 'P' },
  { "help", 0, 0, 'h' },
  { 0, 0, 0, 0 }};


static void
usage (argc, argv)
  int argc;
  char **argv;
{
  fprintf (stderr,
	   "Usage: %s [-v] [--version] [-lim] [--info] [-f] [--faces]\n", baseprefix (*argv));
  fprintf (stderr, "       [-sb] [--brief] [-P port#] [--port port#] [-h] [--help]\n");
  fprintf (stderr, "       [user | user@host ...]\n");
  exit (1);
}


static void
help ()
{
  fputs ("This is GNU Finger. Choose among the following options:\n\n", stderr);
  fputs ("-v, --version\t\tdisplay version number\n", stderr);
  fputs ("-i, -l, -m, --info\tdisplay full user information\n", stderr);
  fputs ("-b, -s, --brief\t\topposite of --info; only display login records\n", stderr);
  fputs ("-f, --faces\t\tdisplay mugshot for user\n", stderr);
  fputs ("-P, --port #p\t\tconnect to finger daemon using port or service #p\n", stderr);
  fputs ("-h, --help\t\tdisplay this message\n", stderr);
  fputc ('\n', stderr);

  exit (1);
}


main (argc, argv)
  int argc;
  char **argv;
{
  int arg_index, opt_index = 0;
  long options;
  char *arg, *port;
  int optc;

  
  default_error_handling (argv[0]);

  /* Parse the arguments passed on the command line. */

#if defined (INFO_IS_DEFAULT)
  options = INFO;
#else
  options = 0;
#endif

  arg_index = 1;
  port = NULL;

  while ((optc = getopt_long (argc, argv, "vfilmP:bsh", longopts, &opt_index)) > 0)
    switch (optc)
      {
      case 'f':

	options |= FACE;
	break;

      case 'i':
      case 'l':
      case 'm':
	
	options |= INFO;
	break;

      case 'b':
      case 's':

	options &= ~INFO;
	break;

      case 'v':

	options |= VERS;
	break;

      case 'P':

	port = optarg;
	break;

      case 'h':

	help ();

      default:
	
	usage (argc, argv);
      }

  if (options & VERS)
    printf ("GNU Finger client version %s.\n", VERSION_STRING);

#ifdef BASENAME_IS_SERVICE
  if (!port)
    port = baseprefix (argv[0]);
#endif

  if (optind >= argc)
    call_finger ("", options, port);
  else
    for (arg_index = optind; arg_index < argc; arg_index++)
      call_finger (argv[arg_index], options, port);

  exit (0);
}

/* Call the finger daemon to actually do the fingering. */
void
call_finger (arg, options, portnum)
  char *arg, *portnum;
  long options;
{
  char *t;
  char *username, *hostname;
  char *localhost;
  struct hostent *host = NULL;
  int connection, facing, info;
  long addr;
  char *finger_server = NULL;
  int suppress_hostname = 0;


  username = savestring (arg);
  facing = options & FACE;
  info = options & INFO;

  /* If the argument is NULL or "", then make the server host
     the host to connect to. */

  hostname = NULL;

  if ((!username || !*username)
      && (finger_server = getservhost ()))
    {
      hostname = finger_server;
      suppress_hostname = 1;
    }
  else
    {
      for (t = username; *t && *t != '@'; t++);
      
      if (*t)
	hostname = t + 1;
      
      *t = '\0';
    }

  if (!hostname)
    {
      if (!(localhost = xgethostname ()))
	localhost = "localhost";

      hostname = localhost;
      suppress_hostname = 1;
    }

  if (digit (*hostname))
    {
      addr = (long)inet_addr (hostname);
      host = gethostbyaddr (&addr, 4, AF_INET);

      if (!host)
	{
	  host = (struct hostent *) xmalloc (sizeof (struct hostent));
	  host->h_name = hostname;
	}
    }
  else
    {
      host = gethostbyname (hostname);
      
      if (!host)
	handle_error (FATAL, "%s: unknown host", hostname);

      bcopy (host->h_addr, &addr, 4);
    }

  if (!suppress_hostname)
    {
      printf ("[%s]", host->h_name);
      fflush (stdout);
    }

  connection = tcp_to_service (portnum ? portnum : "finger", (char *) &addr);

  if (connection < 0)
    {
      printf ("\n");
      fflush (stdout);
      file_error (FATAL, host->h_name);
    }

  if (!suppress_hostname)
    {
      printf ("\n");
      fflush (stdout);
    }

  /* Okay, connection established.  Now actually do the fingering. */
  if (facing)
    {
      if (!face_finger (username, connection))
	warning ("%s doesn't have face bits for %s", hostname, username);
    }
  else
    {
      if (info && *username)
	{
	  char *new_username = (char *)xmalloc (4 + strlen (username));
	  strcpy (new_username, "/W ");
	  strcat (new_username, username);
	  free (username);
	  username = new_username;
	}

      text_finger (username, connection);
    }

  close (connection);
  free (username);

  if (finger_server)
    free (finger_server);

  if (host)
    free (host);
}
