/*
 * $VER: bbgopher.c 1.0 (20.4.95)
 * Copyright (c) 1995 Jason M. Weber (Amiga port)
 * Copyright (c) 1993 Mark Morley (original BBGopher for UNIX)
 * Freely distributable
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "bbgopher.h"

int
ValidNumber(number, string)
 int number;
 char *string;
{
 int n1, n2, r;

 while (*string) {
  r = 0;
  while (*string == ' ' || *string == '\t' || *string == ',')
   string++;
  n1 = 0;
  n2 = 0;
  if (*string >= '0' && *string <= '9') {
   n1 = atoi(string);
   while (*string >= '0' && *string <= '9')
    string++;
  }
  if (*string == '-') {
   r = 1;
   string++;
   n2 = atoi(string);
   while (*string >= '0' && *string <= '9')
    string++;
  }
  if (r) {
   if (number >= n1 && number <= n2)
    return 1;
  }
  else if (number == n1)
   return 1;
 }
 return 0;
}

int
CheckUser(type)
 char type;
{
 FILE *fp;
 char line[80];
 char *uid;
 int i;

 for (i = 0; KnownTypes[i].type; i++)
  if (KnownTypes[i].type == type)
   break;
 if (KnownTypes[i].type == 0)
  return 0;
 fp = fopen(KnownTypes[i].acf, "r");
 if (!fp)
  return 1;
 uid = (char *)getlogin();
 for (fgets(line, 80, fp); !feof(fp); fgets(line, 80, fp)) {
  line[strlen(line) - 1] = 0;
  if (strcmp(line, uid) == 0) {
   fclose(fp);
   return 1;
  }
 }
 fclose(fp);
 return 0;
}

int
SupportedType(type)
 char type;
{
 int i;

 for (i = 0; KnownTypes[i].type; i++)
  if (KnownTypes[i].type == type)
   return KnownTypes[i].supported;
 return 0;
}

int
newEntry(ent, type, display, selector, hostname, port)
 GO4ENTRY *ent;
 char type;
 char *display;
 char *selector;
 char *hostname;
 short port;
{
 if (display && (ent->display = (char *)malloc(strlen(display) + 1)) == 0)
  return 0;
 if (selector && (ent->selector = (char *)malloc(strlen(selector) + 1)) == 0) {
  free(ent->display);
  return 0;
 }
 if (hostname && (ent->hostname = (char *)malloc(strlen(hostname) + 1)) == 0) {
  free(ent->selector);
  free(ent->display);
  return 0;
 }
 ent->type = type;
 if (display)
  strcpy(ent->display, display);
 else
  ent->display = 0;
 if (selector)
  strcpy(ent->selector, selector);
 else
  ent->selector = 0;
 if (hostname)
  strcpy(ent->hostname, hostname);
 else
  ent->hostname = 0;
 ent->port = port;
 return 1;
}

int
delEntry(ent)
 GO4ENTRY *ent;
{
 if (ent->hostname)
  free(ent->hostname);
 if (ent->selector)
  free(ent->selector);
 if (ent->display)
  free(ent->display);
 return 1;
}

char *
TypeLookup(type)
 char type;
{
 int i;
 static char buf[10];

 for (i = 0; KnownTypes[i].type; i++)
  if (KnownTypes[i].type == type)
   return KnownTypes[i].display;
 sprintf(buf, " %c ", type);
 return buf;
}

int
DisplayLookup(display)
 char *display;
{
 int i;

 for (i = 0; i < KnownTypes[i].type; i++)
  if (!strcmp(KnownTypes[i].display, display))
   return i;
 return -1;
}

int
Connect(selector, hostname, port)
 char *selector;
 char *hostname;
 short port;
{
 if (port == 0)
  port = DefPort;
 if (ValidNumber(port, BadPorts)) {
  printf("Sorry, but access to that service is not allowed.\n\n");
  return G_CONNECT;
 }
 if (hostname == 0)
  hostname = DefHost;
 if ((host = gethostbyname(hostname)) == 0)
  return G_HOST;
 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  return G_SOCKET;
 bzero(&sain, sizeof(sain));
 sain.sin_family = AF_INET;
 sain.sin_port = htons(port);
 bcopy(host->h_addr, &sain.sin_addr, host->h_length);
 if (connect(sock, (struct sockaddr*)&sain, sizeof(sain)) < 0)
  return G_CONNECT;
 if (selector)
  write(sock, selector, strlen(selector));
 write(sock, "\r\n", 2);
 sd = fdopen(sock, "r");
 return G_OK;
}

void
Disconnect(void)
{
 close(sock);
}

int
Page(file)
 char *file;
{
 FILE *fp;
 char line[256];
 int n = 0;

 fp = fopen(file, "r");
 if (!fp)
  return 0;
 if (ClearScreen)
  printf("\033[2J\033[H");
 else
  putchar('\n');
 for (fgets(line, 256, fp); !feof(fp); fgets(line, 256, fp)) {
  printf(line);
  if (++n == 22) {
   printf("[MORE...]");
   *line = 0;
   fflush(stdin);
   fgets(line, 2, stdin);
   fflush(stdin);
   n = 0;
   if (*line == 'q' || *line == 'Q')
    break;
  }
 }
 fclose(fp);
 return 1;
}

int
GetData(file, binary)
 char *file;
 int binary;
{
 FILE *fp;
 int l = 0;
 int t = 0;
 char line[256];
 char ch;

 fp = fopen(file, "w");
 if (!fp)
  return G_CREATE;
 if (Twirly)
  putchar(' ');
 if (binary)
  for (ch = getc(sd); !feof(sd); ch = getc(sd)) {
   putc(ch, fp);
   if (Twirly && ++l == 1024) {
    l = 0;
    putchar('\b');
    putchar(TwirlyChars[t]);
    t++;
    if (t == NUMTWIRLYCHARS)
     t = 0;
    fflush(stdout);
   }
  }
 else
  for (fgets(line, 255, sd); !feof(sd); fgets(line, 255, sd)) {
   l = strlen(line) - 1;
   if (line[l] == '\n' && line[l - 1] == '\r') {
    line[l - 1] = '\n';
    line[l] = 0;
   }
   if (*line == '.' && (line[1] == '\r' || line[1] == '\n'))
    break;
   fprintf(fp, line);
   if (Twirly) {
    putchar('\b');
    putchar(TwirlyChars[t]);
    t++;
    if (t == NUMTWIRLYCHARS)
     t = 0;
    fflush(stdout);
   }
  }
 if (Twirly)
  printf("\b \b");
 fclose(fp);
 return G_OK;
}

int
GetFile(selector, hostname, port, type, binary)
 char *selector;
 char *hostname;
 short port;
 char *type;
 int binary;
{
 char line[81];
 int rc;

 printf("Local name for %s file? ", type);
 fflush(stdin);
 fgets(line, 80, stdin);
 fflush(stdin);
 printf("\n");
 line[strlen(line) - 1] = 0;
 if (*line == 0)
  return G_OK;
 if ((rc = Connect(selector, hostname, port)) != G_OK)
  return rc;
 printf("Retrieving file...");
 fflush(stdout);
 rc = GetData(line, binary);
 printf("\n\n");
 Disconnect();
 return rc;
}

int
MailFile(filename)
 char *filename;
{
 FILE *fi;
 FILE *fo;
 char *tmp;
 char to[81];
 char sub[81];
 char ch;

 printf("To [%s]: ", getlogin());
 fflush(stdin);
 fgets(to, 80, stdin);
 to[strlen(to) - 1] = 0;
 if (*to == 0)
  strcpy(to, (char *)getlogin());
 printf("Subject: ");
 fflush(stdin);
 fgets(sub, 80, stdin);
 fflush(stdin);
 printf("\n");
 sub[strlen(sub) - 1] = 0;
 if (*sub == 0)
  strcpy(sub, "No Subject Specified");
 printf("Mailing file...\n\n");
 tmp = tmpnam("T:bbgo");
 if ((fo = fopen(tmp, "w")) == NULL) {
  free(tmp);
  return G_CREATE;
 }
 fi = fopen(filename, "r");
 fprintf(fo, "To: %s\n", to);
 fprintf(fo, "Subject: %s\n", sub);
 fprintf(fo, "\n");
 for (ch = fgetc(fi); !feof(fi); ch = fgetc(fi))
  fputc(ch, fo);
 fclose(fi);
 fclose(fo);
 sprintf(sub, "%s %s < %s", Mailer, to, tmp);
 system(sub);
 unlink(tmp);
 free(tmp);
 return G_OK;
}

int
SaveFile(filename)
 char *filename;
{
 FILE *fi;
 FILE *fo;
 char line[81];
 char temp[81];
 char *l;
 char ch;

 printf("Local name for TXT file? ");
 fflush(stdin);
 fgets(line, 80, stdin);
 fflush(stdin);
 printf("\n");
 line[strlen(line) - 1] = 0;
 if (*line == 0)
  return G_OK;
 if (*Directory) {
  l = (char *)rindex(line, '/');
  if (l)
   *l++ = 0;
  else
   l = line;
  *temp = 0;
  if (*Directory == '~') {
   strcpy(temp, (char *)getenv("HOME"));
   strcat(temp, &Directory[1]);
  }
  else
   strcat(temp, Directory);
  if (temp[strlen(temp) - 1] != '/')
   strcat(temp, "/");
  strcat(temp, l);
  l = temp;
 }
 else
  l = line;
 printf("Saving file...\n\n");
 fflush(stdout);
 if ((fo = fopen(l, "w")) == NULL)
  return G_CREATE;
 fi = fopen(filename, "r");
 for (ch = fgetc(fi); !feof(fi); ch = fgetc(fi))
  fputc(ch, fo);
 fclose(fi);
 fclose(fo);
 return G_OK;
}

int
ReadText(selector, hostname, port)
 char *selector;
 char *hostname;
 short port;
{
 char *tmp;
 char line[256];
 int rc;

 if ((rc = Connect(selector, hostname, port)) != G_OK)
  return rc;
 printf("Retrieving text...");
 fflush(stdout);
 tmp = tmpnam("T:bbgo");
 if ((rc = GetData(tmp, 0)) != G_OK) {
  free(tmp);
  return rc;
 }
 printf("\n");
 Disconnect();
 if (*Pager == 0 || !strcmp(Pager, "default"))
  Page(tmp);
 else {
  sprintf(line, Pager, tmp);
  if (!strstr(Pager, "%s")) {
   strcat(line, " ");
   strcat(line, tmp);
  }
  system(line);
 }
 printf("\nPress ENTER to continue, M to mail, S to save: ");
 fflush(stdin);
 fgets(line, 5, stdin);
 fflush(stdin);
 printf("\n");
 rc = G_OK;
 if (*line == 'm' || *line == 'M')
  rc = MailFile(tmp);
 else if (*line == 's' || *line == 'S')
  rc = SaveFile(tmp);
 unlink(tmp);
 free(tmp);
 return rc;
}

int
DoSearch(selector, hostname, port)
 char *selector;
 char *hostname;
 short port;
{
 char buf[256];
 char line[81];
 int rc;

 printf("Please enter your search criteria (you may use 'and' and 'or'):\n");
 fflush(stdin);
 fgets(line, 80, stdin);
 fflush(stdin);
 printf("\n");
 line[strlen(line) - 1] = 0;
 if (*line == 0)
  return G_OK;
 sprintf(buf, "%s\t%s\r\n", selector, line);
 if ((rc = Connect(buf, hostname, port)) != G_OK)
  return rc;
 printf("Searching...\n");
 rc = ReadMenu("Index Search Results", buf, hostname, port, 0, 0);
 Disconnect();
 return rc;
}

int
ReadMenu(display, selector, hostname, port, connect, fd)
 char *display;
 char *selector;
 char *hostname;
 short port;
 int connect;
 FILE *fd;
{
 char line[1025];
 char *e;
 GO4ENTRY ent;
 int rc;
 int t;

 if (connect)
  if ((rc = Connect(selector, hostname, port)) != G_OK)
   return rc;
 if (StackLen >= MAXSTACKLEN) {
  if (connect)
   Disconnect();
  return G_STACK;
 }
 if (BM) {
  StackLen--;
  delEntry(&Stack[StackLen]);
  StackLen--;
  BM = 0;
 }
 if (!newEntry(&Stack[StackLen], '1', display, selector, hostname, port)) {
  if (connect)
   close(sock);
  return G_MEMORY;
 }
 StackLen++;
 MenuLen = 0;
 t = 0;
 if (Twirly)
  putchar(' ');
 if (fd == NULL)
  fd = sd;
 for (fgets(line, 1024, fd); !feof(fd); fgets(line, 1024, fd)) {
  if (*line == '.' && (line[1] == '\r' || line[1] == '\n'))
   break;
  e = line;
  ent.type = *e++;
  ent.display = e;
  while (*e && *e != '\t') e++;
  if (*e) *e++ = 0;
  ent.selector = e;
  while (*e && *e != '\t') e++;
  if (*e) *e++ = 0;
  ent.hostname = e;
  while (*e && *e != '\t') e++;
  if (*e) *e++ = 0;
  ent.port = atoi(e);
  if (SkipType && !SupportedType(ent.type))
   continue;
  if (SkipACF && !CheckUser(ent.type))
   continue;
  if (!newEntry(&Menu[MenuLen], ent.type, ent.display, ent.selector, ent.hostname, ent.port)) {
   Disconnect();
   return G_MEMORY;
  }
  MenuLen++;
  if (MenuLen == MAXMENULEN)
   break;
  if (Twirly) {
   putchar('\b');
   putchar(TwirlyChars[t]);
   t++;
   if (t == NUMTWIRLYCHARS)
    t = 0;
   fflush(stdout);
  }
 }
 if (Twirly)
  printf("\b \b");
 if (connect)
  Disconnect();
 return G_OK;
}

void
SaveBookmark(n)
 int n;
{
 FILE *fp;
 char buf[256];

 strcpy(buf, (char *)getenv("HOME"));
 strcat(buf, "/");
 strcat(buf, BookMark);
 if ((fp = fopen(buf, "a")) == 0)
  return;
 fprintf(fp, "%c%s\t%s\t%s\t%d\n", Menu[n].type, Menu[n].display, Menu[n].selector, Menu[n].hostname, Menu[n].port);
 fclose(fp);
 printf("Bookmark saved...\n\n");
 return;
}

void
DelBookmark(n)
 int n;
{
 FILE *fp;
 int i;
 char buf[256];

 strcpy(buf, (char *)getenv("HOME"));
 strcat(buf, "/");
 strcat(buf, BookMark);

 if (n < MenuLen - 1)
  bcopy(&Menu[n + 1], &Menu[n], sizeof(GO4ENTRY) * (MenuLen - n - 1));
 MenuLen--;
 if ((fp = fopen(buf, "w")) == 0)
  return;
 for (i = 0; i < MenuLen; i++)
  fprintf(fp, "%c%s\t%s\t%s\t%d\n", Menu[i].type, Menu[i].display, Menu[i].selector, Menu[i].hostname, Menu[i].port);
 fclose(fp);
 printf("Bookmark deleted...\n\n");
 return;
}

int
CompareEntries(ent1, ent2)
 GO4ENTRY *ent1;
 GO4ENTRY *ent2;
{
 return strcmp(ent1->display, ent2->display);
}

int
ReadBookmarks(void)
{
 FILE *fp;
 char buf[256];

 strcpy(buf, (char *)getenv("HOME"));
 strcat(buf, "/");
 strcat(buf, BookMark);
 if ((fp = fopen(buf, "r")) == 0)
  return 0;
 ReadMenu("* Bookmarks *", 0, 0, 0, 0, fp);
 fclose(fp);
 qsort(Menu, MenuLen, sizeof(GO4ENTRY), CompareEntries);
 return 1;
}

int
ProcessMenu(void)
{
 int i, n;
 int top;
 char *s;
 char buf[256];

 top = 0;
page:
 if (ClearScreen)
  printf("\033[2J\033[H");
 printf("%s\n%s", Title, Stack[StackLen - 1].display);
 if (Stack[StackLen - 1].hostname)
  printf(" (%s)", Stack[StackLen - 1].hostname);
 printf("\n\n");
 if (MenuLen == 0)
  printf("There are no menu items available.\n");
 else for (i = 0, n = top; i < Lines && n < MenuLen; i++, n++) {
  if (Menu[n].type == 'i')
   printf("%3d %-.75s\n", n + 1, Menu[n].display);
  else
   printf("%3d <%s> %-.69s\n", n + 1, TypeLookup(Menu[n].type), Menu[n].display);
 }
 putchar('\n');
loop:
 do {
  *buf = 0;
  if (MenuLen == 0)
   printf("Help, Quit or Previous: ");
  else
   printf("[1-%d], Help, Quit, %s, List, Previous, Up, or Down: ", MenuLen, BM ? "Delete" : "=, Bookmarks, Save");
  fflush(stdin);
  fgets(buf, 15, stdin);
  fflush(stdin);
  buf[strlen(buf) - 1] = 0;
 } while (*buf == 0 && MenuLen <= Lines);
 printf("\n");
 if (*buf == 'h' || *buf == 'H') {
  if (*Pager == 0 || !strcmp(Pager, "default"))
   Page(HelpFile);
  else {
   sprintf(buf, Pager, HelpFile);
   if (!strcmp(Pager, "%s")) {
    strcat(buf, " ");
    strcat(buf, HelpFile);
   }
   system(buf);
  }
  printf("\nPress ENTER to continue");
  fflush(stdin);
  fgets(buf, 5, stdin);
  fflush(stdin);
  printf("\n");
  goto page;
 }
 if (*buf == 'q' || *buf == 'Q')
  return -2;
 if (!BM && *buf == '=') {
  for (s = buf; *s && *s != ' '; s++);
  n = atoi(s);
  if(n < 0 || n > MenuLen)
   printf("You must specify a valid item number to save as a bookmark (eg: s 1).\n\n");
  else if (n == 0) {
   printf("Type:     %s\n", TypeLookup(Stack[StackLen - 1].type));
   printf("Title:    %s\n", Stack[StackLen - 1].display);
   printf("Host:     %s\n", Stack[StackLen - 1].hostname);
   printf("Port:     %d\n", Stack[StackLen - 1].port);
   printf("Selector: %s\n\n", Stack[StackLen - 1].selector ? Stack[StackLen - 1].selector : "");
  }
  else {
   printf("Type:     %s\n", TypeLookup(Menu[n - 1].type));
   printf("Title:    %s\n", Menu[n - 1].display);
   printf("Host:     %s\n", Menu[n - 1].hostname);
   printf("Port:     %d\n", Menu[n - 1].port);
   printf("Selector: %s\n\n", Menu[n - 1].selector ? Menu[n - 1].selector : "");
  }
  goto loop;
 }
 if (!BM && (*buf == 'b' || *buf == 'B'))
  return -3;
 if (!BM && (*buf == 's' || *buf == 'S')) {
  for (s = buf; *s && *s != ' '; s++);
  n = atoi(s);
  if (n < 1 || n > MenuLen)
   printf("You must specify a valid menu item number to save as a bookmark (eg: s 1).\n\n");
  else
   SaveBookmark(n - 1);
  goto loop;
 }
 if (BM && (*buf == 'd' || *buf == 'D')) {
  for (s = buf; *s && *s != ' '; s++);
  n = atoi(s);
  if (n < 1 || n > MenuLen)
   printf("You must specify a valid item number to delete. (eg: d 1)\n\n");
  else
   DelBookmark(n - 1);
  goto loop;
 }
 if (*buf == 'p' || *buf == 'P')
  return -1;
 if (*buf == 'l' || *buf == 'L')
  goto page;
 if (*buf == 'd' || *buf == 'D' || *buf == 0) {
  top += Lines - 1;
  if (top >= MenuLen - 1)
   top = 0;
  goto page;
 }
 if (*buf == 'u' || *buf == 'U') {
  if (top == 0)
   top = MenuLen - Lines;
  else
   top -= Lines - 1;
  if (top < 0)
   top = 0;
  goto page;
 }
 i = atoi(buf);
 if (i < 1 || i > MenuLen) {
  printf("Please enter a command or a number between 1 and %d.\n\n", MenuLen);
  goto loop;
 }
 i--;
 if (Menu[i].type == 'i') {
  printf("That menu item is informational only.\n\n");
  goto loop;
 }
 if (!SupportedType(Menu[i].type)) {
  printf("Sorry, that type of menu item isn't currently supported.\n\n");
  goto loop;
 }
 if (!CheckUser(Menu[i].type)) {
  printf("Sorry, but you don't have access to that item.\n\n");
  goto loop;
 }
 return i;
}

int
Setup(void)
{
 FILE *fp;
 char line[91];
 char *var;
 char *val;
 char *e;
 int i;

 strcpy(Title, DEFAULTTITLE);
 strcpy(DefHost, DEFAULTHOST);
 DefPort = DEFAULTPORT;
 *BadPorts = 0;
 strcpy(Pager, DEFAULTPAGER);
 strcpy(Telnet, DEFAULTTELNET);
 strcpy(TN3270, DEFAULTTN3270);
 strcpy(Directory, DEFAULTDIR);
 Lines = DEFAULTLINES;
 Twirly = 1;
 ClearScreen = 0;
 SkipACF = 0;
 SkipType = 1;
 fp = fopen(CONFIGPATH, "r");
 if (!fp)
  return 0;
 for (fgets(line, 90, fp); !feof(fp); fgets(line, 90, fp)) {
  e = (char *)rindex(line, '#');
  if (e)
   *e-- = 0;
  else {
   e = line + strlen(line) - 1;
   *e-- = 0;
  }
  for (var = line; *var == ' ' || *var == '\t'; var++);
  for (val = var; *val && *val != ' ' && *val != '\t'; val++);
  if (*val) *val++ = 0;
  while (*val == ' ' || *val == '\t')
   val++;
  if (*val == '\"') val++;
  while (*e == ' ' || *e == '\t')
   *e-- = 0;
  if (*e == '\"') *e = 0;
  if (*var == 0 || *var == '#')
   continue;
  if (!strcmp(var, "TITLE"))
   strcpy(Title, val);
  else if (!strcmp(var, "SERVER"))
   strcpy(DefHost, val);
  else if (!strcmp(var, "PORT"))
   DefPort = atoi(val);
  else if (!strcmp(var, "BADPORTS"))
   strcpy(BadPorts, val);
  else if (!strcmp(var, "HELPFILE"))
   strcpy(HelpFile, val);
  else if (!strcmp(var, "PAGER"))
   strcpy(Pager, val);
  else if (!strcmp(var, "WORKDIR"))
   strcpy(Directory, val);
  else if (!strcmp(var, "MAILER"))
   strcpy(Mailer, val);
  else if (!strcmp(var, "BOOKMARK"))
   strcpy(BookMark, val);
  else if (!strcmp(var, "TELNET"))
   strcpy(Telnet, val);
  else if (!strcmp(var, "TN3270"))
   strcpy(TN3270, val);
  else if (!strcmp(var, "LINES"))
   Lines = atoi(val);
  else if (!strcmp(var, "TWIRLY"))
   Twirly = (*val == 'y' || *val == 'Y' || *val == '1');
  else if (!strcmp(var, "CLEAR"))
   ClearScreen = (*val == 'y' || *val == 'Y' || *val == '1');
  else if (!strcmp(var, "SKIPACF"))
   SkipACF = (*val == 'y' || *val == 'Y' || *val == '1');
  else if (!strcmp(var, "SKIPTYPE"))
   SkipType = (*val == 'y' || *val == 'Y' || *val == '1');
  else if (!strncmp(var, "ACF", 3) && (i = DisplayLookup(&var[3])) != -1)
   strcpy(KnownTypes[i].acf, val);
  else
   printf("Warning: unrecognised option in configuration file (%s)\n", var);
 }
 return 1;
}

int
main(argc, argv)
 int argc;
 char **argv;
{
 int ok;
 int rc;
 int rc2;
 char buf[10];

 printf("\033[2J\033[H");
 printf("\nBBGopher 1.6 - Written by Mark Morley (September '93)\n");
 printf("BBGopher/amiga 1.0 - Ported by Jason M. Weber (20.4.95)\n");
 if (!Setup())
  printf("Warning: no configuration file found, using defaults.\n");
 putchar('\n');
 StackLen = 0;
 if (argc > 1) {
  strcpy(DefHost, argv[1]);
  if (argc > 2)
   DefPort = atoi(argv[2]);
 }
 rc = ReadMenu("Default Gopher Server", 0, DefHost, DefPort, 1, 0);
 if (rc != G_OK) {
  printf("Sorry, but I was unable to connect to %s on port %d\n", DefHost, DefPort);
  exit(1);
 }
 BM = 0;
 ok = 1;
 while (ok) {
  rc = ProcessMenu();
  switch (rc) {
   case -1:
    BM = 0;
    if (StackLen > 1) {
     StackLen--;
     delEntry(&Stack[StackLen]);
     StackLen--;
     ReadMenu(Stack[StackLen].display, Stack[StackLen].selector, Stack[StackLen].hostname, Stack[StackLen].port, 1, 0);
    }
    break;
   case -2:
    ok = 0;
    break;
   case -3:
    if (BM == 0) {
     ReadBookmarks();
     BM = 1;
    }
    break;
   default:
    if (BM && StackLen > 1) {
     StackLen--;
     delEntry(&Stack[StackLen]);
    }
    BM = 0;
    switch (Menu[rc].type) {
     case '0':
      rc2 = ReadText(Menu[rc].selector, Menu[rc].hostname, Menu[rc].port);
      break;
     case '1':
      rc2 = ReadMenu(Menu[rc].display, Menu[rc].selector, Menu[rc].hostname, Menu[rc].port, 1, 0);
      break;
     case '4':
      rc2 = GetFile(Menu[rc].selector, Menu[rc].hostname, Menu[rc].port, "Mac HQX", 1);
      break;
     case '5':
      rc2 = GetFile(Menu[rc].selector, Menu[rc].hostname, Menu[rc].port, "DOS binary", 1);
      break;
     case '6':
      rc2 = GetFile(Menu[rc].selector, Menu[rc].hostname, Menu[rc].port, "UU encoded", 0);
      break;
     case '7':
      rc2 = DoSearch(Menu[rc].selector, Menu[rc].hostname, Menu[rc].port);
      break;
     case '8':
      if (*Menu[rc].selector)
       printf("Try logging in as '%s'\n\n", Menu[rc].selector);
      sprintf(buf, "%s %s %d", Telnet, Menu[rc].hostname, Menu[rc].port ? Menu[rc].port : 23);
      system(buf);
      rc2 = G_OK;
      break;
     case '9':
      rc2 = GetFile(Menu[rc].selector, Menu[rc].hostname, Menu[rc].port, "binary", 1);
      break;
     case 'T':
      sprintf(buf, "%s %s %d", TN3270, Menu[rc].hostname, Menu[rc].port ? Menu[rc].port : 23);
      system(buf);
      rc2 = G_OK;
      break;
    }
    if (rc2 != G_OK) {
     printf("ERROR: ");
     switch (rc2) {
      case G_HOST:
       printf("Couldn't resolve hostname '%s'\n", Menu[rc].hostname);
       break;
      case G_SOCKET:
       printf("Socket error!\n");
       break;
      case G_CONNECT:
       printf("Couldn't connect to %s\n", Menu[rc].hostname);
       break;
      case G_CREATE:
       printf("Couldn't create local file.\n");
       break;
      default:
       printf("Code = %d\n", rc2);
       break;
     }
     putchar('\n');
    }
    break;
  }
 }
 while (MenuLen) {
  MenuLen--;
  delEntry(&Menu[MenuLen]);
 }
 while (StackLen) {
  StackLen--;
  delEntry(&Stack[StackLen]);
 }
}
