/********************************************************************
* lindner
* 3.27
* 1994/10/24 22:14:56
* /home/arcwelder/GopherSrc/CVS/gopher+/gopher/manager.c,v
* Exp
*
* Paul Lindner, University of Minnesota CIS.
*
* Copyright 1991, 1992 by the Regents of the University of Minnesota
* see the file "Copyright" in the distribution for conditions of use.
*********************************************************************
* MODULE: manager.c
* Procedures to manage the screen.
*********************************************************************
* Revision History:
* manager.c,v
* Revision 3.27 1994/10/24 22:14:56 lindner
* Add pdf type
*
* Revision 3.26 1994/07/25 02:54:45 lindner
* Skip over type 'i' items
*
* Revision 3.25 1994/06/29 07:11:03 lindner
* change pointer item for info or error itme to a line
*
* Revision 3.24 1994/05/17 05:48:01 lindner
* Massive internationalization change
*
* Revision 3.23 1994/05/14 04:13:45 lindner
* Internationalization...
*
* Revision 3.22 1994/04/25 03:37:42 lindner
* Modifications for Debug() and mismatched NULL arguments, added Debugmsg
*
* Revision 3.21 1994/03/31 21:26:15 lindner
* Make DEBUG toggleable
*
* Revision 3.20 1994/03/08 15:55:13 lindner
* gcc -Wall fixes
*
* Revision 3.19 1994/03/04 23:33:56 lindner
* better screen size calculations
*
* Revision 3.18 1994/02/20 16:31:43 lindner
* Patch around ANSI C trigraph sequence
*
* Revision 3.17 1993/12/28 17:31:40 lindner
* Prettier Info items in gopher directories, removed dot from the end of files
*
* Revision 3.16 1993/11/29 01:11:46 lindner
* In DisplayTitle(), <Movie> menu items now fit properly when the line is
* too long for the screen. (Beckett)
*
* Revision 3.15 1993/10/26 18:43:20 lindner
* Fix for multiply defined cases
*
* Revision 3.14 1993/10/22 20:30:34 lindner
* Fixes for menu drawing (Beckett)
*
* Revision 3.13 1993/10/22 20:05:20 lindner
* Add Movie (;) and Info (i) type support
*
* Revision 3.12 1993/09/08 01:22:30 lindner
* Add support for HTML and MIME on the menu displays
*
* Revision 3.11 1993/08/23 02:32:48 lindner
* Fix for arrow updating
*
* Revision 3.10 1993/08/19 20:22:54 lindner
* Mitra's Debug patch
*
* Revision 3.9 1993/08/16 18:11:29 lindner
* fix for VMS Alpha systems
*
* Revision 3.8 1993/07/30 14:19:34 lindner
* Mitra autoexit patch
*
* Revision 3.7 1993/07/27 05:28:56 lindner
* Mondo Debug overhaul from Mitra
*
* Revision 3.6 1993/07/27 02:02:45 lindner
* More comments
*
* Revision 3.5 1993/07/20 23:12:32 lindner
* Mods to use patchlevel.h
*
* Revision 3.4 1993/04/23 20:14:13 lindner
* Fix for munged characters in Draw_Status
*
* Revision 3.3 1993/04/15 21:17:00 lindner
* none
*
* Revision 3.2 1993/03/26 19:43:46 lindner
* Fix for repainting when selecting an item bu number
*
* Revision 3.1.1.1 1993/02/11 18:02:58 lindner
* Gopher+1.2beta release
*
* Revision 2.1 1993/02/09 22:36:56 lindner
* Now shows ask items, provision for auto size display in the future
*
* Revision 1.4 1993/01/31 00:08:12 lindner
* New fcn DisplayTitle()
*
* Revision 1.3 1993/01/06 21:01:40 lindner
* Improved behaviour when executing an item by typing it's number
* The arrow and screen are updated to reflect the item being
* retrieved.
*
* Revision 1.2 1993/01/05 22:31:57 lindner
* Fixed display problems with directory title searching.
*
* Revision 1.1 1992/12/10 23:32:16 lindner
* gopher 1.1 release
*
* Revision 1.1 1992/12/10 06:16:51 lindner
* Initial revision
*
*
*********************************************************************/
#include "gopher.h"
#include "patchlevel.h"
#include "Debug.h"
#define MENULINE(x) (x)+3
/* If any gophers to display (screen can be blank), count the number
of pages. If there is a remainder greater than zero, add one page */
#define PAGECALC(x,y) (y) ? (x/y) + ((x%y)>0) : 1
/*
** Draw the title on the top
*/
void
Draw_Banner()
{
char line[80];
sprintf(line, Gtxt("Internet Gopher Information Client v%s.%s.%d",102),
GOPHER_MAJOR_VERSION, GOPHER_MINOR_VERSION, PATCHLEVEL);
CURcenterline(CursesScreen, stdscr, line, 0, COLS, TRUE);
}
/*
** Draw the status line
*/
void
Draw_Status(textline)
char *textline;
{
mvaddstr(LINES-1, 0, Gtxt("Press ",119));
standout();
addstr("?");
standend();
addstr(Gtxt(" for Help, ",57));
standout();
addstr("q");
standend();
addstr(Gtxt(" to Quit",58));
#ifndef AUTOEXITONU
if (iLevel != 0) {
addstr(", ");
standout();
addstr("u");
standend();
addstr(Gtxt(" to go up a menu",59));
}
#endif
clrtoeol();
mvaddch(LINES-1, COLS-strlen(textline)-4, ' ');
addstr(textline);
}
void
DisplayTitle(gs, maxlength, dogplus)
GopherObj *gs;
int maxlength;
boolean dogplus;
{
char type;
char *c, *d;
char *size;
int m,n;
char temp[1024];
type = GSgetType(gs);
d = GSgetTitle(gs);
if (GSisGplus(gs) && GSgplusInited(gs)) {
size = VIgetSize(GSgetView(gs, 0));
}
if (GSisAsk(gs))
maxlength -= 5;
switch(type)
{
case A_DIRECTORY:
maxlength--;
break;
case A_SOUND:
maxlength -= 3;
break;
case A_INDEX:
maxlength -=4;
break;
case A_PDF:
case A_CSO:
case A_TELNET:
case A_UNIXBIN:
case A_MACHEX:
maxlength -=6;
break;
case A_TN3270:
case A_MIME:
case A_HTML:
maxlength -= 7;
break;
case A_MOVIE:
maxlength -= 8;
break;
case A_PCBIN:
maxlength -=9;
break;
case A_GIF:
case A_IMAGE:
maxlength -= 10;
}
if (d==NULL)
d = "error";
if((m = strlen(d)) <= maxlength)
printw(" %s", d);
else {
/*** Cut out the middle bits **/
if ((c = strchr(d, '/'))!=NULL && (maxlength > (c-d))) {
n = c - d;
strncpy(temp, d, n);
strcpy(temp + n, "..");
strcat(temp, d + (m + n - maxlength));
printw(" %s", temp);
} else {
/** Trunc it.. **/
strcpy(temp, d);
temp[maxlength] ='\0';
printw(" %s..", temp);
}
}
switch(type)
{
case A_DIRECTORY:
addch('/');
break;
case A_CSO:
addstr(" <CSO>");
break;
case A_TN3270:
addstr(" <3270>");
break;
case A_TELNET:
addstr(" <TEL>");
break;
case A_INDEX:
addstr(" <?>");
break;
case A_SOUND:
addstr(" <)"); /** It's supposed to look like a speaker! **/
break;
case A_PCBIN:
addstr(" <PC Bin>");
break;
case A_UNIXBIN:
addstr(" <Bin>");
break;
case A_IMAGE:
case A_GIF:
addstr(" <Picture>");
break;
case A_MACHEX:
addstr(" <HQX>");
break;
case A_MIME:
addstr(" <MIME>");
break;
case A_HTML:
addstr(" <HTML>");
break;
case A_MOVIE:
addstr(" <Movie>");
break;
case A_PDF:
addstr(" <PDF>");
break;
}
if (GSisAsk(gs)) {
/* Add string in two parts to avoid ANSI C turning "??>" into a
trigraph for '}' */
addstr(" <?");
addstr("?>");
}
}
/*
** Man is this ugly.
*/
void
Display_Dir_Page(gopherdir, iNewLine, nNewPage, nMaxPages, iPageLen, iLastPageLen)
GopherDirObj *gopherdir;
int iNewLine;
int nNewPage, nMaxPages, iPageLen, iLastPageLen;
{
int i, iLoop, iOffset;
boolean dogplus = FALSE;
GopherObj *gs;
/*** Clear the screen and redraw the top line **/
clear();
Draw_Banner();
/** Draw the menu **/
iLoop = (nNewPage == nMaxPages) && iLastPageLen ? iLastPageLen : iPageLen;
/** Look at the first item in the directory to decide whether to
use a gopher+ display of the menu ***/
for (i= 0, iOffset = (nNewPage-1) * iPageLen; i <iLoop; i++, iOffset++) {
gs = GDgetEntry(gopherdir, iOffset);
move(MENULINE(i+1), 6);
if (GSgetType(gs) == A_INFO) {
addch(' ');
addch(' ');
if (iOffset > 9)
addch(' ');
if (iOffset >99)
addch(' ');
} else {
printw("%d.", iOffset +1);
}
if (iOffset + 1 < 10)
addch(' ');
dogplus = GSisGplus(GDgetEntry(gopherdir, iOffset));
DisplayTitle(GDgetEntry(gopherdir, iOffset), COLS-13, dogplus);
}
}
/* scline - Screen line relocator.
* Returns the line resulting from choice */
int
scline( iOldGopher, iNewGopher, gophersdir)
int iOldGopher; /* Which gopher previously displayed */
int iNewGopher; /* New gopher to be displayed */
GopherDirObj *gophersdir;
{
int iPageLen, iLastPageLen; /* Length of normal, final pages */
int nMaxPages, nNewPage, nOldPage; /* Natural numbers */
int iOldLine, iNewLine; /* Screen locations */
char sPagenum[40];
int iMaxGophers;
GopherObj *tempGopher;
int Direction = 1;
iMaxGophers = GDgetNumitems(gophersdir);
if (iNewGopher==0)
iNewGopher = GDgetNumitems(gophersdir);
if (iNewGopher > iMaxGophers)
iNewGopher = 1;
if (iNewGopher == iOldGopher - 1)
Direction = -1;
do {
tempGopher = GDgetEntry(gophersdir, iNewGopher-1);
if (GSgetType(tempGopher) != A_INFO &&
GSgetType(tempGopher) != A_ERROR)
break;
iNewGopher += Direction;
if (iNewGopher > iMaxGophers) {
iNewGopher = 1;
if (iOldGopher < 1)
break;
}
if (iNewGopher < 1)
iNewGopher = iMaxGophers;
if (iOldGopher > iMaxGophers)
break;
} while (iNewGopher != iOldGopher);
iPageLen = LINES-6; /* Number of menu lines possible per page */
nMaxPages = PAGECALC(iMaxGophers, iPageLen); /* Total number of pages */
nOldPage = PAGECALC(iOldGopher, iPageLen);
nNewPage = PAGECALC(iNewGopher, iPageLen);
if ((nNewPage < 1) || (nNewPage > nMaxPages)) /* It won't work , make*/
return(iOldGopher); /* no changes */
iLastPageLen = iMaxGophers % iPageLen;
/* Lines on last page */
iOldLine = iOldGopher - ((nOldPage-1)*iPageLen);/* Old Screen location */
iNewLine = iNewGopher - ((nNewPage-1)*iPageLen);/* New Screen location */
if ((iNewLine < 0) || (iNewLine > iPageLen))
return(iOldGopher);
if (nOldPage != nNewPage) {
Display_Dir_Page(gophersdir,
iNewLine, nNewPage, nMaxPages, iPageLen, iLastPageLen);
/*** Draw the title ***/
CURcenterline(CursesScreen, stdscr, GDgetTitle(gophersdir), 2, COLS, FALSE);
}
sprintf(sPagenum, Gtxt(" Page: %d/%d",56), nNewPage, nMaxPages);
Draw_Status(sPagenum);
mvaddstr(MENULINE(iOldLine), 1, " ");
if ( (GSgetType(GDgetEntry(gophersdir, iNewGopher-1)) == A_INFO) ||
(GSgetType(GDgetEntry(gophersdir, iNewGopher-1)) == A_ERROR) )
mvaddstr(MENULINE(iNewLine), 1, "---");
else
mvaddstr(MENULINE(iNewLine), 1, "-->");
refresh();
return(iNewGopher);
}
/*
** This routine draws a numbered menu
** from a gopherdirobj
**
** It returns the number that the user selected, or it returns
** zero if the user decided to cancel.
**
** RETURN Code isnt used currently anywhere!
*/
int
GetMenu(gd, typedchar, redisplay)
GopherDirObj *gd; /** where the items are **/
int *typedchar;
boolean redisplay;
{
int ch; /* Input character */
int iItem; /* Display line */
static int iNewItem=1;
char sLinenum[5]; /* Used when going to a specific line */
int numitems;
/** variables for searching **/
char search1[100];
char *search2;
int sfound;
int i;
search1[0] = '\0'; /* search string will be remembered so init now */
numitems = GDgetNumitems(gd);
iItem = -1;
iNewItem = GDgetCurrentItem(gd);
if (redisplay == TRUE) {
/*** Draw the title ***/
CURcenterline(CursesScreen, stdscr, GDgetTitle(gd), 2, COLS, FALSE);
/* Move to the last line that we were sitting on */
iItem = scline(iItem, iNewItem, gd);
} else
iItem = GDgetCurrentItem(gd);
while (1) {
#ifdef VMS
if (HadVMSInt) {
HadVMSInt = FALSE;
ch = 'q';
}
else
ch = CURgetch(CursesScreen);
#else
ch = CURgetch(CursesScreen);
#endif
/* Note letters not in here are picked up by default and passed back
to caller for processing */
switch(ch)
{
case '\004':
DEBUG = 1 - DEBUG;
break;
case 'j':
case '\016':
case KEY_DOWN:
iNewItem = iItem + 1; /* Advance down the page */
break;
case 'k':
case '\020': /*** For those emacs dudes **/
case KEY_UP:
iNewItem = iItem - 1; /* Back up */
break;
case '+': /** Like in elm **/
case '>': /** Like in nn **/
case ' ': /** Like in the pager ***/
case KEY_NPAGE:
/*** Go down a page ***/
iNewItem = iItem + (LINES -6);
if (iNewItem > numitems)
iNewItem = numitems;
break;
case '-':
case '<':
case KEY_PPAGE:
case 'b': /*** Like in the pager ***/
/*** Go up a page ***/
iNewItem = iItem - (LINES - 6);
if ( iNewItem < 0 )
iNewItem = 1;
break;
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9': case '0':
sLinenum[0] = (char) ch;
sLinenum[1] = '\0';
if (CUROldGetOneOption(CursesScreen,
Gtxt("View item number: ",179),
sLinenum) <0) {
scline(iItem, iNewItem, gd);
break;
}
if (atoi(sLinenum) <= numitems)
iNewItem = atoi(sLinenum); /* Jump */
else {
CURBeep(CursesScreen);
break;
}
iItem = scline(iItem, iNewItem, gd);
if (iNewItem > 0 && iNewItem <= GDgetNumitems(gd)) {
*typedchar = '\n';
GDsetCurrentItem(gd, iNewItem);
return(iItem);
}
break;
case '/':
case 'n':
sfound = 0;
if (search1[0] == '\0' && ch == 'n') {
CursesErrorMsg(Gtxt("Use '/' to define a search first...",178));
iItem = scline(-1,iItem, gd);
break;
}
if (search1[0] == '\0' || ch == '/')
if (CURGetOneOption(CursesScreen, GDgetTitle(gd),
Gtxt("Search directory titles for:",139)
, search1)<0) {
iItem = scline(-1,iItem, gd);
break;
}
if (strlen(search1) == 0) {
iItem = scline(-1, iItem, gd);
break;
}
/*
* Start searching from next item
*/
for (i=iItem; i < numitems && sfound==0; i++) {
search2 = GSgetTitle(GDgetEntry(gd, i));
if (strcasestr(search2, search1) != NULL ) {
iNewItem = i+1;
sfound = 1;
}
}
/* if it wasn't found after the current line start
from the beginning again
*/
for ( i= 0 ; i < iItem && sfound==0;i++) {
search2 = GSgetTitle(GDgetEntry(gd,i));
if (strcasestr(search2,search1) != NULL ) {
iNewItem = i+1;
sfound = 1;
}
}
if (sfound == 0) {
search1[0] = '\0';
Debugmsg("GetMenu beep search\r\n")
CURBeep(CursesScreen);
CursesErrorMsg(Gtxt("Search failed...",140));
}
if (ch != 'n')
iItem = scline(-1, iNewItem, gd);
break;
case '\0':
break;
default:
if (ch == KEY_LEFT || ch == 'h' || ch == '\002')
ch = 'u';
if (ch == KEY_RIGHT || ch == 'l' || ch == '\006')
ch = '\n';
*typedchar = ch;
GDsetCurrentItem(gd, iItem);
return(iItem);
}
iItem = scline(iItem, iNewItem, gd);
refresh();
}
}
.
Response:
text/plain