/*
 * trip.c,v 1.1 1994/01/28 17:22:18 franktor Exp
 *
 * trip.c
 *
 * Routines to access a protocol interface to TRIP
 *
*/

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>		/* needs isdigit(). --hbf */
#include <malloc.h>

#include <sr-general.h>
#include "trip.h"

#define ETB	0x17
#define RS	0x1e
#define GS	0x1d
#define US	0x1f

extern char *sys_errlist[];

typedef enum TripProtocol { trip_prot_new = 0, trip_prot_old = 1 } TripProtocol;

int trip_protocol = trip_prot_new;

void trip_setProtocol ( int i )
{
  trip_protocol = i;
}

/*
 * Note: trip_getResponse() now returns NULL on failure.
 */

char *trip_getResponse ( int server )
{
   static char			buf[10240];
   char				*cp = buf;
   int				error = 0;

   for ( cp = buf, *buf = 0; True; cp++ )
   {
      if ( read ( server, cp, 1 ) == -1 )
      {
         if (errno != EINTR)
            error = 1;
	 break;
      }
      if ( *cp == ETB )
	 break;
   }

   if (error)
   {
      LOG(facLow, llevExceptions, "trip_getResponse: %s", sys_errlist[errno]);
      return NULL;
   }

   *(cp+1) = 0;

   for ( cp = buf; (cp = index ( cp, '\r' )) != NULL; cp++ )
      *cp = ' ';

   return buf;
}


int trip_openServer ( char *hostname, int port )
{
   int				soc;
   struct sockaddr_in 		addr;
   struct hostent 		*hp, *gethostbyname();
   struct protoent		*protocol;
   char				req[100];

   LOG(facLow, llevDebug, "trip_openServer(\"%s\", %d)",hostname,port);
   if (!(protocol = getprotobyname("tcp")))
   {
      LOG(facLow, llevExceptions, "trip_openServer() Failed to resolve protocol tcp.");
      return -1;
   }
   soc = socket ( AF_INET, SOCK_STREAM, protocol->p_proto );
   if (soc == (-1))
   {
      LOG(facLow, llevExceptions, "trip_openServer() Failed to get socket(): %s\n", sys_errlist[errno]);
      return -1;
   }
   addr.sin_family = AF_INET;
   addr.sin_port = htons((unsigned short)port);
   if (isdigit(*hostname))
   {
       addr.sin_addr.s_addr = inet_addr(hostname);
       LOG(facLow, llevTrace, "Using inet_addr() to resolve address.");
   }
   else
   {
      if (!(hp = gethostbyname ( hostname )))
      {
         LOG(facLow, llevExceptions, "trip_openServer() Failed to resolve hostname %s.", hostname);
         return -1;
      }
      bcopy ( hp->h_addr, &addr.sin_addr.s_addr, hp->h_length );
   }
   if ( connect ( soc, &addr, sizeof(struct sockaddr_in) ) == -1 )
   {
      LOG(facLow, llevExceptions, "trip_openServer() Failed to connect: %s\n", sys_errlist[errno] );
      return -1;
   }

   strcpy ( req, "0000unix\037bruker\037trip\027" );
   if (write ( soc, req, strlen(req) ) == (-1) && errno != EINTR)
      return -1;

   if (trip_getResponse ( soc ) == NULL)
      return -1;
 
   return soc;
}

Boolean trip_openDb ( int server, char *dbName )
{
   char				req[100];
   char				*multi;
   char				*rsp;

   multi = strchr(dbName, ',');
   if (multi) /* Multi-search.  -Frank */
     sprintf ( req, "0200combined=%s\027", dbName);
   else
     sprintf ( req, "0200%s\027", dbName );
   if ((write ( server, req, strlen(req) ) == (-1) && errno != EINTR)
       || (rsp = trip_getResponse(server)) == NULL)
   {
      LOG(facLow, llevExceptions, "trip_openDb: %s", sys_errlist[errno]);
      return False;
   }
   if (multi)
     LOG(facLow, llevDebug, "Multi-search response: [%s]",rsp);
   return True;
}

void trip_selectFields ( int server, char *fields )
{
   char				*cp;
   char				*flds;

   if ( (!fields) || (!*fields) )
      return;

   flds = (char *) malloc ( strlen ( fields ) + 1 );
   strcpy ( flds, fields );
   for ( cp = flds; *cp; cp++ )
      if ( *cp == ',' )
	 *cp = US;

   write ( server, "0400", 4 );
   write ( server, flds, strlen(flds) );
   write ( server, "\027", 1 );
   
   trip_getResponse ( server );
}

selection *trip_search ( int server, char *search_string )
{
   char				*rsp;
   struct selection		*sel;
   char				*cp;
   
   if (trip_protocol == trip_prot_old)
   {
      write ( server, "0500find ", strlen ( "0500find " ) );
      write ( server, search_string, strlen(search_string) );
      write ( server, "\027", 1 );
   }
   else
   {
      write ( server, "0500", strlen ( "0500" ) );
      write ( server, search_string, strlen(search_string) );
      write ( server, "\027", 1 );
   }

   rsp = trip_getResponse ( server );

   LOG(facLow, llevTrace, "trip_search response: [%s]",rsp);

   sel = (struct selection *) malloc ( sizeof ( struct selection ) );
   sel->name = (char *) NULL;
   for ( cp = rsp; *cp && isdigit(*cp); cp++ );
   for ( ;*cp && !isdigit(*cp); cp++ );
   
   sel->setNo = atoi ( cp );

   for ( ;*cp && isdigit(*cp); cp++ );
   for ( ;*cp && !isdigit(*cp); cp++ );
   
   sel->noRecords = atoi(cp);
   
   for ( ;*cp && isdigit(*cp); cp++ );
   for ( ;*cp && !isdigit(*cp); cp++ );
   
   sel->noMatches = atoi ( cp );

   return sel;
}

char *trip_showRecord ( int server, int sel, int idx )
{
   char				buf[100];
   char				*rsp;
   
   sprintf ( buf, "1000%d\037%d\037SRMARC\027", sel, idx );
   write ( server, buf, strlen(buf) );

   rsp = trip_getResponse ( server );

   return rsp+4;
}

void free_TripRecord (TripRecord *tr)
{
  if (tr->database)
    free (tr->database);
  if (tr->record)
    free (tr->record);
  free (tr);
}

void trip_newaskRecord ( int server, int sel, int idx )
{
   char		buf [100];

   sprintf ( buf, "1000%d\037%d\037SRMARC\027", sel, idx );
   write ( server, buf, strlen(buf) );
}

void trip_askSeveralRecord ( int server, int sel, int start, int stop )
{
   char		buf [200];

#if 0
   int	i;

   sprintf ( buf, "1000%d\037%d", sel, start);
   for ( i = start + 1; i <= stop; i++ )
      sprintf( buf + strlen ( buf ), ",%d", i );
   strcat( buf, "\037SRMARC\027" );
#endif

   sprintf ( buf, "1000%d\037%d til %d\037SRMARC\027", sel, start, stop);

   write ( server, buf, strlen(buf) );
}

TripRecord *trip_newgetRecord ( int server )
{
   TripRecord	*tr = (TripRecord *) malloc(sizeof(TripRecord));
   char		*rsp, *start_database, *cp;

   tr->status = False;
   tr->database = NULL;
   tr->record = NULL;

   rsp = trip_getResponse ( server );

   for (cp = rsp + 4; *cp && *cp == ' '; cp++);
   if (!(*cp))
     return tr;
   start_database = cp;
   for (; *cp && *cp != '\n'; cp++);
   if (!(*cp))
     return tr;
   *cp = '\0';
   cp++;
   tr->status = True;
   tr->database = (char *) malloc(sizeof(char)*strlen(start_database)+1);
   strcpy(tr->database, start_database);
   tr->record =  (char *) malloc(sizeof(char) *strlen(cp) + 1);
   strcpy(tr->record, cp);
   return tr;
}

void trip_closeServer ( int server )
{
   char				buf[100];

   sprintf ( buf, "0700\027" );
   write ( server, buf, strlen(buf) );

   close ( server );
}


selection *trip_freeSelection ( selection *sel )
{
   selection		*next;
   
   if ( !sel )
      return sel;

   next = sel->next;

   if ( sel->name )
      free ( sel->name );
   free ( sel );

   return next;
}



/*
main ()
{
   int				ref = trip_openServer ( "kari.uio.no", 2000 );
   struct selection		*sel;
   
   trip_openDb ( ref, "samper" );
   trip_selectFields ( ref, "tit,bibl,nummer,aar,iss" );
   sel = trip_search ( ref, "handel" );

   printf ( "found %d records\n", sel->noRecords );

   printf ( "%s\n", trip_showRecord ( ref, sel->setNo, 1 ) );

   trip_closeServer ( ref );
}
*/
