
/*
Eagles Bulletin Board System
Copyright (C) 1994, Ray Rocker, rrrocker@rock.b11.ingr.com
                                rock@seabass.st.usm.edu
                                72673.2105@compuserve.com

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 of the License, 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.
*/

/*
   Adapted from Pirates BBS 1.8 "read.c"
   Copyright (C) 1990, Edward Luke, lush@Athena.EE.MsState.EDU
*/

#include "client.h"
#include <malloc.h>

#define MAIL_KEEP_NAME " $MAIL "

int BoardType;

extern READMENUITEM mailreadlist[], mainreadlist[], filereadlist[];

extern OpenMailbox(), CloseMailbox();
extern OpenBoard(), CloseBoard();
extern OpenFileBoard(), CloseFileBoard();

#define PUTCURS   move(4+locmem->crs_line-locmem->top_line,0);prints(">");
#define RMVCURS   move(4+locmem->crs_line-locmem->top_line,0);prints(" ");

HEADER *headers = NULL;

struct keeploc {
    int btype;
    char *key ;
    int top_line ;
    int crs_line ;
    struct keeploc *next ;
} ;

struct keeploc *
getkeep(btype,s,def_topline,def_cursline)
char *s ;
LONG def_topline, def_cursline;
{
  static struct keeploc *keeplist = NULL ;
  struct keeploc *p ;

  for(p = keeplist; p!= NULL; p = p->next) {
    if(p->btype == btype && !strcmp(s,p->key))
      return p ;
  }
  p = (struct keeploc *) malloc(sizeof (*p)) ;
  p->btype = btype;
  p->key = (char *) malloc(strlen(s)+1) ;
  strcpy(p->key,s) ;
  p->top_line = def_topline ;
  p->crs_line = def_cursline ;
  p->next = keeplist ;
  keeplist = p ;
  return p ;
}

void
fixkeep(locmem, maxline, def_lines)
struct keeploc *locmem;
int maxline;
int def_lines;
{
  if (maxline < locmem->top_line) {
    if ((locmem->top_line = maxline - def_lines) < 1)
      locmem->top_line = 1;
  }
  if (maxline < locmem->crs_line) locmem->crs_line = maxline;
}

MailMenuTitle()
{
  clear();
  move(0,0);
  prints("Interactive Read Menu                (FOR Mail)\n") ;
  prints("(n)ext Message     (p)revious Message     (r)ead Message     (e)xit Read Menu\n");  
  prints("(##<cr>) go to message ##      ($) go to last message     (h) Get Help Screen\n");
  prints("  ENT    SIZE %-16s %s\n","From","Subject") ;
  clrtobot();
}

ReadMenuTitle()
{
  clear();
  move(0,0);
  prints("Interactive Read Menu                              Current Board '%s'\n",currboard) ;
  prints("(n)ext Message     (p)revious Message     (r)ead Message     (e)xit Read Menu\n");
  prints("##<cr> go to message ##     <CTRL-P> post a message     (h) Get a HELP screen\n");
  prints("  ENT    SIZE %-16s %s\n","Owner","Title") ;
  clrtobot() ;
}

FileMenuTitle()
{
    clear();
    move(0,0);
    prints("Interactive Download Menu                          Current Board '%s'\n",currfileboard) ;
    prints("(n)ext File      (p)revious File      (v)iew File      (e)xit Download Menu\n");
    prints("##<cr> go to file ##          (r)ecieve file          (h) Get a HELP screen\n");
    prints("  ENT T  SIZE  %s\n","Filename") ;
    clrtobot() ;
}

struct get_recs_struct {
  SHORT want;
  SHORT got;
};

GetRecsFunc(indx, hdr, info)
int indx;
HEADER *hdr;
struct get_recs_struct *info;
{
  if (info->got >= info->want) return ENUM_QUIT;
  memcpy(&headers[info->got], hdr, sizeof(HEADER));
  info->got++;
  return S_OK;
}  

MenuGetRecords(first_line, num_lines)
int first_line, num_lines;
{
  int result;
  struct get_recs_struct gr;
  gr.want = (SHORT)num_lines;
  gr.got = 0;
  first_line--;
  result = bbs_enum_headers(gr.want, (SHORT)first_line, 0, GetRecsFunc, &gr);
  return (result == S_OK ? (int)gr.got : 0);
}

MenuDrawScreen(first_line, num_lines)
int first_line, num_lines;
{
  int i, k;
  char c;
  char buf[TITLELEN+40];
  move(4,0) ;
  for (i=0; i<num_lines; i++) {
    if (BoardType == BOARD_FILE) {
      c = (BITISSET(headers[i].flags, FILE_BINARY) ? 'B' : 'A');
    }
    else {
      if (headers[i].flags & FILE_MARKED)
	c = (BITISSET(headers[i].flags, FILE_UNREAD) ? 'M' : 'm');
      else
	c = (BITISSET(headers[i].flags, FILE_UNREAD) ? 'N' : ' ');
    }

    k = (headers[i].size + 512) / 1024;
    if (BoardType == BOARD_FILE)
      sprintf(buf, " %4d %c %4dk  %s", first_line+i, c, k, headers[i].title);  
    else 
      sprintf(buf, " %4d %c %4dk %-16s %s", first_line+i, c, k,
	         headers[i].owner, headers[i].title);

    if(strlen(buf) >= 79) {
      buf[78] = '^' ;
      buf[79] = '\0' ;
    }
    prints("%s\n", buf) ;
  }
}

NoHeaders()
{
  switch (BoardType) {
  case BOARD_MAIL:
    prints("No messages in this mailbox\n");
    break;
  case BOARD_FILE:
    prints("No files on this board\n");
    break;
  default:
    prints("No messages on this board\n");
  }
}

ReadMenu(openfn, closefn, fetchfn, titlefn, drawfn, keepname, rcmdlist)
int (*openfn)();
int (*closefn)();
int (*fetchfn)();
int (*titlefn)();
int (*drawfn)();
char *keepname;
READMENUITEM *rcmdlist;
{
  char lbuf[11];
  int lbc, i, ch;
  struct keeploc *locmem;
  int screen_len = t_lines - 5;
  int num_entries;
  int last_line;
  int openflags;
  int mode = DONOTHING;
  
  if (!headers)
    headers = (HEADER *)calloc(screen_len, sizeof(*headers));
  
  (*titlefn)();
  last_line = (*openfn)(&openflags, 0, NULL);
  if (last_line == -1) {
    prints("Cannot access this board\n");
    return 0;
  }
  if(last_line == 0) {
    NoHeaders();
    (*closefn)();
    return 0;
  }
  
  locmem = getkeep(BoardType, keepname,
	   (last_line-screen_len+1 < 1)?1:last_line-screen_len+1,last_line) ;
  
  fixkeep(locmem, last_line, screen_len-3);
  num_entries = (*fetchfn)(locmem->top_line, screen_len);
  (*drawfn)(locmem->top_line, num_entries);
  
  PUTCURS ;
  lbc = 0 ;
  while((ch = igetch()) != EOF) {
    if (PagePending()) {
      Answer();
      mode = FULLUPDATE;
      goto endofloop;
    }
    if(isdigit(ch)) {
      if(lbc < 9)
	lbuf[lbc++] = ch ;
      goto endofloop ;
    }
    if(ch != '\n' && ch != '\r')
      lbc = 0 ;
    switch(ch) {
      int val ;
    case 'q':
    case 'e':
      mode = EXITMENU;
      break ;
    case '\n':
    case '\r':
      if(lbc == 0)
	break ;
      lbuf[lbc] = '\0' ;
      val = atoi(lbuf) ;
      lbc = 0 ;
      if(val > last_line)
	val = last_line ;
      if(val <= 0)
	val = 1 ;
      if(val >= locmem->top_line && val < locmem->top_line+screen_len) {
	RMVCURS ;
	locmem->crs_line = val ;
	PUTCURS ;
	continue ;
      }
      locmem->top_line = val - 10 ;
      if(locmem->top_line <= 0)
	locmem->top_line = 1 ;
      locmem->crs_line = val ;
      mode = PARTUPDATE | FETCHNEW;
      goto endofloop ;
    case 'p':
      if(locmem->crs_line == locmem->top_line) {
	if(locmem->crs_line == 1) {
	  bell() ;
	  break ;
	}
	locmem->top_line -= screen_len - 2 ;
	if(locmem->top_line <= 0)
	  locmem->top_line = 1 ;
	locmem->crs_line-- ;
	mode = PARTUPDATE | FETCHNEW;
	break ;
      }
      RMVCURS ;
      locmem->crs_line-- ;
      PUTCURS ;
      break ;
    case CTRL('L'):
      redoscr() ;
      break ;
    case 'n':
      if(locmem->crs_line == last_line) {
	bell() ;
	break ;
      }
      if(locmem->crs_line+1 == locmem->top_line+screen_len) {
	locmem->top_line += screen_len - 2 ;
	locmem->crs_line++ ;
	mode = PARTUPDATE | FETCHNEW;
	break ;
      }
      RMVCURS ;
      locmem->crs_line++ ;
      PUTCURS ;
      break ;
    case 'N':
      if(locmem->top_line + screen_len - 1 >= last_line) {
	bell() ;
	break ;
      }
      locmem->top_line += screen_len - 1 ;
      locmem->crs_line = locmem->top_line ;
      mode = PARTUPDATE | FETCHNEW;
      break ;
    case 'P':
      if(locmem->top_line == 1) {
	bell() ;
	break ;
      }
      locmem->top_line -= screen_len - 1 ;
      if(locmem->top_line <= 0)
	locmem->top_line = 1 ;
      locmem->crs_line = locmem->top_line ;
      mode = PARTUPDATE | FETCHNEW;
      break ;
    case '$':
      if(last_line < locmem->top_line + screen_len) {
	RMVCURS ;
	locmem->crs_line = last_line ;
	PUTCURS ;
	break ;
      }
      locmem->top_line = last_line - screen_len + 1 ;
      if(locmem->top_line <= 0)
	locmem->top_line = 1 ;
      locmem->crs_line = last_line ;
      mode = PARTUPDATE | FETCHNEW;
      break ;
    default:
      for(i = 0; rcmdlist[i].cmdfunc != NULL; i++) {
	if(rcmdlist[i].cmdkey == ch && 
           HasReadMenuPerm(rcmdlist[i].openaccess, openflags) &&
	   HasPerm(rcmdlist[i].permaccess)) {
	  mode = (*(rcmdlist[i].cmdfunc))
	    (&headers[locmem->crs_line - locmem->top_line],
	     locmem->crs_line, last_line, openflags);
	  break ;
	}
      }
      if(rcmdlist[i].cmdfunc == NULL)
	bell();
      break ;
    }
  endofloop:
    if (mode & (FETCHNEW | NEWDIRECT)) {
      if (mode & NEWDIRECT) (*closefn)();
      last_line = (*openfn)(&openflags, 0, NULL);
      if (mode & NEWDIRECT)
	locmem = getkeep(BoardType, keepname,
			 (last_line-screen_len < 1)?1:last_line-screen_len+1,
			 last_line) ;
      fixkeep(locmem, last_line, screen_len-3);
      num_entries = (*fetchfn)(locmem->top_line, screen_len);
    }
    if (mode & (FULLUPDATE | PARTUPDATE)) {
      if (mode & FULLUPDATE) {
	clear() ;
	(*titlefn)();
      }
      if(last_line <= 0) {
	NoHeaders();
	num_entries = 0 ;
	break;
      }
      (*drawfn)(locmem->top_line, num_entries);
      if(locmem->crs_line > last_line)
	locmem->crs_line = last_line ;
      clrtobot() ;
      PUTCURS ;
    }
    if(mode == EXITMENU || num_entries == 0)
      break ;
    mode = DONOTHING ;
  }
  (*closefn)();
  clear() ;
  return 0;
}

MailRead()
{
  BoardType = BOARD_MAIL;
  bbs_set_mode(M_MAIL);
  ReadMenu(OpenMailbox, CloseMailbox, MenuGetRecords, MailMenuTitle, 
	   MenuDrawScreen, MAIL_KEEP_NAME, mailreadlist);
  bbs_set_mode(M_UNDEFINED);  
  return PARTUPDATE;
}

MainRead()
{
  if (*currboard == '\0') {
    move(3,0);
    prints("Use (S)elect to select a board first.\n");
  }
  else {
    BoardType = BOARD_POST;
    bbs_set_mode(M_READING);
    ReadMenu(OpenBoard, CloseBoard, MenuGetRecords, ReadMenuTitle,
    	     MenuDrawScreen, currboard, mainreadlist);
    bbs_set_mode(M_UNDEFINED);
  }
  return PARTUPDATE;
}

FileDownload()
{
  if (*currfileboard == '\0') {
    move(3,0);
    prints("Use (S)elect to select a file board first.\n");
  }
  else {
    BoardType = BOARD_FILE;
    ReadMenu(OpenFileBoard, CloseFileBoard, MenuGetRecords, FileMenuTitle,
    	     MenuDrawScreen, currfileboard, filereadlist);
  }
  return PARTUPDATE;
}
