#include "gopher.h"


/*
 * Connect_To_Gopher Performs a connecting to socket 'service' on host
 * 'host'.  Host can be a hostname or ip-address.  If 'host' is null, the
 * local host is assumed.   The parameter full_hostname will, on return,
 * contain the expanded hostname (if possible).  Note that full_hostname is a
 * pointer to a char *, and is allocated by connect_to_gopher()
 *
 * Errors:
 *
 * -1 get service failed
 *
 * -2 get host failed
 *
 * -3 socket call failed
 *
 * -4 connect call failed
 */

int connect_to_gopher(host)
  char *host;
{
     int s, service;
     char  buf[MAXSTR];
     struct sockaddr_in server;
     struct hostent *hp;

     service = 7000;
     
     if (host == '\0') {
	  gethostname(buf, sizeof(buf));
	  host = buf;
     }

     if ((server.sin_addr.s_addr = inet_addr(host)) == -1) {
	  if (hp = gethostbyname(host)) {
	       bzero((char *) &server, sizeof(server));
	       bcopy(hp->h_addr, (char *) &server.sin_addr, hp->h_length);
	       server.sin_family = hp->h_addrtype;
	  } else
	       return (-2);
     } else
	  server.sin_family = AF_INET;

     server.sin_port = (unsigned short) htons(service);

     if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	  return (-3);

     setsockopt(s, SOL_SOCKET, ~SO_LINGER, 0, 0);
     setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 0, 0);
     setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
     if (connect(s, &server, sizeof(server)) < 0) {
	  close(s);
	  return (-4);
     }
     return s;
}


/*
** Feed a gopher takes a line of text and parses it.
** It returns a 0 when successful and -1 when it isn't
*/

int
feed_a_gopher(j, sInput)
  int j;
  char *sInput;
{
     int i;
     char *cPtr = NULL;
     
     char *CurrentChar = NULL;
     i=sizeof(GopherThing);
     /*memset(Gopher[j], 0, i);  Causes weird bug in A/UX*/
     
     
     /** Get the kind of file from the first character **/

     Gopher[j].sFileType = sInput[0];
     
     if(Gopher[j].sFileType == A_EOI)
	  return(0);

     /** Suck off the User Displayable name **/
     
     cPtr = (char *) strchr(sInput, '\t');
     if (cPtr == NULL)
	  return(-1);
     *cPtr = '\0'; 
     strncpy(Gopher[j].sTitle, sInput + 1, (int) (cPtr-sInput+1));
     sInput = cPtr + 1;

     /** Suck off the Pathname **/

     cPtr = strchr(sInput, '\t');
     if (cPtr == NULL)
	  return(-1);
     *cPtr = '\0'; 
     strncpy(Gopher[j].sPath, sInput , (int) (cPtr-sInput+1));
     sInput = cPtr + 1;

     /** Suck off the hostname **/

     cPtr = strchr(sInput, '\t');
     if (cPtr == NULL)
	  return(-1);
     *cPtr = '\0'; 
     strncpy(Gopher[j].sHost, sInput, (int) (cPtr-sInput+1));
     sInput = cPtr + 1;

     Gopher[j].iPort = 0;

     /** Get the port number **/
     if (isdigit(*sInput) && isdigit(*(sInput+1)))
	  Gopher[j].iPort = atoi(sInput);
     else
	  Gopher[j].iPort = 0;

     return(0);
}

/*
**
**
*/

   
int feed_gophers(sockfd)
  int sockfd;
{
     int i, j, k;
     FILE *fp;
     char ch, sTmp[sizeof(GopherThing)];
     
     writestring(sockfd, "\r\n");
     
     for (j = 0; (j < MAXGOPHERS) && (ch != EOF) && (sTmp[0] != '.'); j++)
     {
	  bzero(sTmp, sizeof(GopherThing));
	  if (readline(sockfd, sTmp, sizeof(GopherThing)) == 0)
	       break;
	  
	  if (feed_a_gopher(j, sTmp)!=0)
	       j = j -1;  /** feed a gopher failed, try again **/
     }
     
     return(j-1);
} 

/*
** Open a connection to another host
*/


do_telnet(iNum)
  int iNum;
{
     char Tel_string1[128];
     char Tel_string2[128];
     char TelCommand[128]; 
     char ch;

     /* retrieve the gopher information for the telnet command*/

     clear();
     Centerline("Warning!!!!!, you are about to leave the Internet", 1);
     Centerline("Gopher program and connect to another host.", 2);
     Centerline("If you get stuck press the control key and the ] key,",3);
     Centerline("and then type quit",4);
     
     sprintf(Tel_string1,"Now connecting to %s", Gopher[iNum].sHost);
     if (Gopher[iNum].sPath[0] != '\0')
	  sprintf(Tel_string2,"Use the account name \"%s\" to log in",
		  Gopher[iNum].sPath);
     else
	  Tel_string2[0] = '\0';

     Centerline(Tel_string1, LINES/2 -1);
     Centerline(Tel_string2, LINES/2 +1);
     Centerline("Press return to connect: ", LINES - 1);
     refresh();

     while ((ch = getch()) != '\r')
	  ;

     exit_curses();

     strcpy(TelCommand, TELNET_COMMAND);
     strcat(TelCommand, " ");
     strcat(TelCommand, Gopher[iNum].sHost);

     if (Gopher[iNum].iPort != 0) 
	  sprintf((TelCommand + strlen(TelCommand)), " %d",Gopher[iNum].iPort); 

     system(TelCommand);
     init_curses();
}


/*
** do_index gets keywords from the user to search for, and jams the
** string into the sPath part of the GopherThing Structure.
*/

do_index(iNum)
  int iNum;
{
     char inputline[40];

     inputline[0] = '\0';
     GetOneOption("Index word(s) to search for: ", inputline);
     strcpy(Gopher[iNum].sPath, inputline);
}

     
/**
*** Show file takes an open socket connection, writes it to a file
*** and passes it to your favorite pager.
**/

showfile(sockfd, iNum)
  int sockfd, iNum;
{
     int i, iLength, childpid, wait_stat, wait_ret;
     char *cp;
     char tmpfilename[40];
     char *tmpptr = tmpfilename;
     FILE *tmpfile;
     char inputline[512];
     char Command[100]; 

     Draw_Status("Receiving Document...");   
     refresh();

     /** Open a temporary file **/

     sprintf(tmpfilename, "/tmp/gopher.%d",getpid());

     if ((tmpfile = fopen(tmpfilename, "w")) == NULL)
	  fprintf(stderr, "Couldn't make a tmp file!\n"), exit(-1);

     writestring(sockfd, Gopher[iNum].sPath, strlen(Gopher[iNum].sPath));
     writestring(sockfd, "\r\n", 2);

     for(;;) {
	  iLength = readline(sockfd, inputline, 512);
	  
	  if (iLength == 0)
	       break;

	  ZapCRLF(inputline);
	  
          if (Gopher[iNum].sFileType == A_CSO) {
	       if (inputline[0] == '2')
		    break;

	       if ((inputline[0] >= '3') && (inputline[0] <= '9'))  {
		    fprintf(tmpfile, "%s\n", Gopher[iNum].sPath);
		    fprintf(tmpfile, "%s\n", inputline+4);
		    break;
	       }
	       if (inputline[0] == '-') {
		    if (inputline[5] != i)
			 fprintf(tmpfile, "-------------------------------------------------------\n");
		    i = inputline[5];
		    fprintf(tmpfile, "%s\n", inputline+7);
	       }
	  }

          if (Gopher[iNum].sFileType == A_FILE) {
	       if ((inputline[0] == '.') && (inputline[1] == '\0'))
		    break;
	       else {
		    fprintf(tmpfile, "%s\n", inputline);
	       }
	  }
     }

     fprintf(tmpfile, "\012 \n\n");  /** Work around a bug in xterm n curses*/
     (void)fclose(tmpfile);

     display_file(tmpfilename);

     /** Good little clients clean up after themselves..**/

     if (unlink(tmpfilename)!=0)
	  fprintf(stderr, "Couldn't unlink!!!\n"), exit(-1);

     init_curses();
}


pushgopher(iLevel, iNum)
  int iLevel, iNum;
{
     OldGopher[iLevel].sFileType = A_DIRECTORY;
     strcpy(OldGopher[iLevel].sTitle, Gopher[iNum].sTitle);
     strcpy(OldGopher[iLevel].sHost, Gopher[iNum].sHost);
     strcpy(OldGopher[iLevel].sPath, Gopher[iNum].sPath);
     OldGopher[iLevel].iPort = Gopher[iNum].iPort;
}

popgopher(iLevel, iNum)
  int iLevel, iNum;
{
     Gopher[iNum].sFileType = A_DIRECTORY;
     strcpy(Gopher[iNum].sTitle, OldGopher[iLevel].sTitle);
     strcpy(Gopher[iNum].sHost, OldGopher[iLevel].sHost);
     strcpy(Gopher[iNum].sPath, OldGopher[iLevel].sPath);
     Gopher[iNum].iPort = OldGopher[iLevel].iPort;
}


void check_sock(sockfd, iNum)
  int sockfd, iNum;
{
     char DispString[80];
     char Response[40];

     Response[0] = '\0';
     
#ifdef DEBUG
     switch(sockfd)  {
     case -4:
	  fprintf(stderr, "connect call failed ");
	  break;
     case -3:
	  (void)fprintf(stderr, "socket call failed");
	  break;
     case -2:
	  (void)fprintf(stderr, "get host failed");
	  break;
     case -1:
	  (void)fprintf(stderr, "get service failed");
	  break;
     }
     fprintf(stderr, "to host %s, port %d\n",
	     Gopher[iNum].sHost, Gopher[iNum].iPort);
     exit(-1);
#endif

     if (sockfd <0) {
	  sprintf(DispString, "Cannot connect to host %s", Gopher[iNum].sHost);
	  GetOneOption(DispString, Response);
     }
}


/**********
**
** Set up all the global variables.
**
***********/

void
Initialize()
{
     int i,err;
     char *cp;
     char termname[40];
     static char terminal[1024];
     static char capabilities[1024];   /* String for cursor motion */
     
     static char *ptr = capabilities;  /* for buffering         */

     /** Get the pager command **/
     
     if (getenv("PAGER") == NULL)
	  strcpy(PagerCommand, PAGER_COMMAND);
     else
	  strcpy(PagerCommand, getenv("PAGER"));

     /*** Get the terminal type ***/

     if (getenv("TERM") == NULL)
	  fprintf(stderr, "I don't understand your terminal type\n"), exit(-1);
     
     if (strcpy(termname, getenv("TERM")) == NULL)
	  fprintf(stderr, "I don't understand your terminal type\n"),exit(-1);
     
     if ((err = tgetent(terminal, termname)) != 1)
	  fprintf(stderr, "I don't understand %s terminals\n",termname),exit(-1);
     
     if ((cp = (char *)tgetstr("cl", &ptr)) != NULL)
	  strcpy(sGClearscreen, cp);
     else
	  strcpy(sGClearscreen, "");

     if ((cp = (char *) tgetstr("bl", &ptr)) != NULL)
	  strcpy(sGAudibleBell, cp);
     else
	  strcpy(sGAudibleBell,"\007");

     /*** Init MainWindow ****/


     tputs(sGClearscreen,1, outchar);     

     MainWindow = initscr();
}


char *GlobalOptions[] =  
{"Pager Command", "Print Command", "Telnet Command"};
			   

void
SetOptions()
{
     char Response[3][40];
     
     strcpy(Response[0], PagerCommand);
     Get_Options("Internet Gopher Options", "", 3, GlobalOptions, Response);

     strcpy(PagerCommand, Response[0]);
}

#define BUFSIZE 256

main(argc, argv)
  int argc;
  char *argv[];
{
     int sockfd, j, i;
     char buf[BUFSIZE];
     FILE *Play;
     char Playcmd[80];

     sprintf(Playcmd, "play %s", argv[2]);

     Play = popen(Playcmd, "w");

     sockfd = connect_to_gopher(argv[1]);

     while(1) {
	  j = read(sockfd, buf, BUFSIZE);
	  for (i=0; i<j; i++)
	       putc(buf[i], Play);

     }
	  
}
