/*
 * RIPE version marten@ripe.net
 * many changes & networkupdate by david@ripe.net
 * cosmetics by steven@dante.org.uk --	gcc stopped complaining mostly,
 *					code is still messy, though.
 *
 * 1.15 94/09/07
 * 
 * 1.2  9705/02
 * "-v" option added; ambrose@ripe.net
 * "whois.ripe.net" replaced by "bsdbase.ripe.net";  ambrose@ripe.net
 * "bsdbase.ripe.net" replaced by "joshua.ripe.net"; marek@ripe.net 
 * "joshua.ripe.net" replaced by "whois.ripe.net"; roman@ripe.net 981105
 *
 * Copyright (c) 1980 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#if defined(sun) && defined(solaris)
#define SYSV
#endif

#ifndef lint
char copyright[] =
"@(#)Copyright (c) 1980 Regents of the University of California.\n\
 All rights reserved.\n";
#endif /* not lint */

#ifndef lint
char sccsid[] =
    "@(#)whois.c 5.11 (Berkeley) 3/2/91 - RIPE 1.15 94/09/07 marten@ripe.net";
#endif /* not lint */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <pwd.h>
#include <signal.h>

#ifdef __STDC__
extern FILE	*fdopen(int fildes, const char *type); 
#endif /* __STDC__ */

#if defined(SYSV) || defined(__STDC__)

#define		index(s,c)		strchr((const char*)(s),(int)(c))
#define		rindex(s,c)		strrchr((const char*)(s),(int)(c))
#define		bzero(s,n)		memset((void*)s,0,(size_t)n)

#ifdef HASMEMMOVE
# define	bcopy(s,d,n)	memmove((void*)(d),(void*)(s),(size_t)(n))
#else
# define	bcopy(s,d,n)	memcpy((void*)(d),(void*)(s),(size_t)(n))
#endif /* HASMEMMOVE */

#endif /* SYSV || __STDC__ */

#ifdef GLIBC
typedef __u_short u_short;
typedef __caddr_t caddr_t;
#endif /* GLIBC */

#include <sys/param.h>
#define	NICHOST	"rpsl.ripe.net"

void usage()
{
  (void)fprintf(stderr, "\nUsage: whois [-h hostname] [-p port] keys ...");
  (void)fprintf(stderr, "\n\nWhere:\n\n");
  (void)fprintf(stderr, "-h hostname                search alternate server\n");
  (void)fprintf(stderr, "-p port                    port to connect to\n");
  (void)fprintf(stderr, "\n");

  exit(1);
}

int s;

void closesocket(s, child) 
int s, child;
{
  /* printf("close connection child=%i\n", child);  */

  close(s);

  exit(0);

}

void termhandler(sig, code, scp, addr)
int sig, code;
struct sigcontext *scp;
char *addr;
{
  closesocket(s,1);
}   


/* #ifdef RIPE */
#if defined(__STDC__) || defined(SYSV)
#define occurs(str,pat)		((int) strstr((str),(pat)))
#else /* !__STDC__ && !SYSV */
int occurs(str, pat)
     char *str, *pat;
{
  register char *point = str;
  
  while ((point=index(point, *pat)))
    {
      if (strncmp(point, pat, strlen(pat)) == 0)
	return(1);
      point++;
    }
  return(0);
}
#endif
/* #endif */

int main(argc, argv)
     int argc;
     char **argv;
{
  FILE *sfi;
  FILE *sfo;
  int ch;
  struct sockaddr_in sin;
  struct hostent *hp;
  struct servent *sp;
  char *host, *whoishost, *realhost;
  int optport=0, port=0;
  int verb=0, opthost=0;
  int optcount;
  char query[1024]="";
  char *string;


  host = NICHOST;
  
  if (argc<=1)
    usage();

  for (optcount=1; optcount<argc; optcount++) {
    if( argv[optcount][0] == '-' ) {
      switch (argv[optcount][1]) {
      case 'h':
	opthost = 1;
	if ((!argv[optcount+1]) || (argv[optcount+1][0] == '-'))
	  usage();
	host = argv[optcount+1];
	
	argv[optcount+1] = argv[optcount]; /* set both to point to the same address */
	*argv[optcount] = 0;        /* and set to "" */
	optcount++;
	continue;       
      case 'p':
	if ((!argv[optcount+1]) || (argv[optcount+1][0] == '-'))
	  usage();
	port = htons((u_short)atoi(argv[optcount+1]));
	optport = 1;
	*argv[optcount] = *argv[optcount+1]=0;
	optcount++;
	continue;
      }
    }
    strcat(query, argv[optcount]);
    strcat(query, " ");
  }


    if (verb) fprintf(stderr, "Trying: %s\n\n", host);
    hp = gethostbyname(host);

    if (hp == NULL) {
      fprintf(stderr,"whois: %s\n", host);
      if (verb) fprintf(stderr, "Now I give up ...\n");
      perror("Unknown host");
      exit(1);
      
    }

  
  realhost = hp->h_name;

  s = socket(hp->h_addrtype, SOCK_STREAM, 0);
  if (s < 0) {
    perror("whois: socket");
    exit(1);
  }
  bzero((caddr_t)&sin, sizeof (sin));
  sin.sin_family = hp->h_addrtype;
  if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
    perror("whois: bind");
    exit(1);
  }
  bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
  
  if (optport) {
     sin.sin_port=port;
  }
  else {
     
     sp=getservbyname("whois", "tcp");
  
     if (sp == NULL) {
        (void)fprintf(stderr, "whois: whois/tcp: unknown service\n");
        exit(1);
     }
  
     sin.sin_port = sp->s_port;

  }

  /* printf("%i\n", sin.sin_port); */

  if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
    perror("whois: connect");
    exit(1);
  }

  sfi = fdopen(s, "r");
  sfo = fdopen(s, "w");
  if (sfi == NULL || sfo == NULL) {
    perror("whois: fdopen");
    (void)close(s);
    exit(1);
  }

  signal(SIGTERM, termhandler);  

  /* we can only send the -V when we are sure that we are dealing with 
     a RIPE whois server :-( */

  /* Not a very nice piece of code. The server types change...
     There should be a string of (assumed) RIPE servers in the
     Makefile, and the string should be processed here. */
  
  whoishost=(char *)calloc(strlen(realhost)+1, sizeof(char));
  strcpy(whoishost, realhost);
  for (string=whoishost;(*string=(char)tolower(*string));string++);
  
  if (strstr(whoishost, "ripe.net") ||
      strstr(whoishost, "ra.net") ||
      strstr(whoishost, "apnic.net") ||
      strstr(whoishost, "mci.net") ||      
      strstr(whoishost, "isi.edu") ||
      strstr(whoishost, "garr.it") ||
      strstr(whoishost, "ans.net") )
    (void)fprintf(sfo, "-VwR1.0 ");

  (void)fprintf(sfo, "%s", query);
  /*if (*argv) (void)fputs(*argv, sfo);*/
  (void)fputs("\r\n", sfo);
  (void)fflush(sfo);
  
  while ((ch = getc(sfi)) != EOF)
    putchar(ch);

  closesocket(s, 1);

  exit(0);

}

