/******************************************************************** * $Author: jgoerzen $ * $Revision: 1.4 $ * $Date: 2002/02/12 21:20:14 $ * $Source: /home/jgoerzen/tmp/gopher-umn/gopher/head/gopher/manager.c,v $ * $State: 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: * $Log: manager.c,v $ * Revision 1.4 2002/02/12 21:20:14 jgoerzen * Made files using strcasecmp() include util.h * * Revision 1.3 2001/01/03 22:30:43 s2mdalle * Inclusion of new header file for this module. * * Revision 1.2 2000/12/27 21:26:22 s2mdalle * Added #include for CUR* functions * * Revision 1.1.1.1 2000/08/19 00:28:56 jgoerzen * Import from UMN Gopher 2.3.1 after GPLization * * Revision 3.31 1995/11/03 21:18:20 lindner * ANSIfication * * Revision 3.30 1995/11/03 20:50:50 lindner * Coen: fixes.. * * Revision 3.29 1995/03/09 05:21:23 lindner * + on last page goes back to beginning * * Revision 3.28 1995/02/27 17:09:51 lindner * Add Pacbell NOBANNER patch * * 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(), 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 "CURcurses.h" #include "gopher.h" #include "patchlevel.h" #include "Debug.h" #include "manager.h" #include "util.h" #ifdef NOBANNER # define MENULINE(x) (x)+1 #else # define MENULINE(x) (x)+3 #endif /* 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(void) { #ifndef NOBANNER 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); #endif } /* ** Draw the status line */ void Draw_Status(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(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(" "); break; case A_TN3270: addstr(" <3270>"); break; case A_TELNET: addstr(" "); break; case A_INDEX: addstr(" "); break; case A_SOUND: addstr(" <)"); /** It's supposed to look like a speaker! **/ break; case A_PCBIN: addstr(" "); break; case A_UNIXBIN: addstr(" "); break; case A_IMAGE: case A_GIF: addstr(" "); break; case A_MACHEX: addstr(" "); break; case A_MIME: addstr(" "); break; case A_HTML: addstr(" "); break; case A_MOVIE: addstr(" "); break; case A_PDF: addstr(" "); break; } if (GSisAsk(gs)) { /* Add string in two parts to avoid ANSI C turning "??>" into a trigraph for '}' */ addstr(" "); } } /* ** Man is this ugly. */ void Display_Dir_Page(GopherDirObj *gopherdir, int iNewLine, int nNewPage, int nMaxPages, int iPageLen, int iLastPageLen) { int i, iLoop, iOffset; boolean dogplus = FALSE; GopherObj *gs; static char *MenuStyle = NULL; static int MenuBytePad; int j; /* colored links */ start_color(); init_pair(1, COLOR_BLUE, COLOR_BLACK); init_pair(2, COLOR_GREEN, COLOR_BLACK); init_pair(3, COLOR_YELLOW, COLOR_BLACK); init_pair(4, COLOR_RED, COLOR_BLACK); init_pair(5, COLOR_MAGENTA, COLOR_BLACK); init_pair(6, COLOR_CYAN, COLOR_BLACK); /*** Clear the screen and redraw the top line **/ clear(); Draw_Banner(); if (MenuStyle == NULL) { if ((MenuStyle = getenv("GOPHERMENUSTYLE")) == NULL) MenuStyle = "[%d]"; MenuBytePad = strlen(MenuStyle)-2; } /** 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 = 9) addch(' '); if (iOffset >99) addch(' '); } else { printw(MenuStyle, iOffset +1); } if (iOffset + 1 < 10) addch(' '); dogplus = GSisGplus(GDgetEntry(gopherdir, iOffset)); DisplayTitle(GDgetEntry(gopherdir, iOffset), COLS-13, dogplus); switch(GSgetType(gs)) { case A_DIRECTORY: attroff(COLOR_PAIR(1)); break; case A_UNIXBIN: case A_PCBIN: attroff(COLOR_PAIR(2)); break; case A_IMAGE: case A_GIF: case A_PDF: attroff(COLOR_PAIR(6)); break; case A_FILE: attroff(COLOR_PAIR(3)); break; case A_INDEX: attroff(COLOR_PAIR(4)); break; case A_TELNET: case A_HTML: attroff(COLOR_PAIR(5)); break; } } } /* scline - Screen line relocator. * Returns the line resulting from choice */ int scline(int iOldGopher, int iNewGopher, 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; iPageLen = LINES-4 - TITLEPOS; /* Number of menu lines possible per page */ nMaxPages = PAGECALC(iMaxGophers, iPageLen); /* Total number of pages */ do { if (iNewGopher <= 0) break; tempGopher = GDgetEntry(gophersdir, iNewGopher-1); if (GSgetType(tempGopher) != A_INFO && GSgetType(tempGopher) != A_ERROR) break; if (GSgetType(tempGopher) == A_INFO) /* some servers will have LONG sets of 'i' lines with no menu items; hack to let you scroll */ break; iNewGopher += Direction; if (iNewGopher > iMaxGophers) { iNewGopher = 1; if (iOldGopher < 1) break; } if (iNewGopher < 1) iNewGopher = iMaxGophers; if (iOldGopher > iMaxGophers) break; } while (iNewGopher != iOldGopher); 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 ***/ #ifdef NOBANNER standout(); #endif CURcenterline(CursesScreen, stdscr, GDgetTitle(gophersdir), TITLEPOS, COLS, FALSE); #ifdef NOBANNER standend(); #endif } 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(GopherDirObj *gd, 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 ***/ #ifdef NOBANNER standout(); #endif CURcenterline(CursesScreen, stdscr, GDgetTitle(gd), TITLEPOS, COLS, FALSE); #ifdef NOBANNER standend(); #endif /* Move to the last line that we were sitting on */ /* scline is the bit that actually draws the menu */ 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- IF there are any items! */ 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 ***/ if (iItem == numitems) { /* Already on last item */ iNewItem = 1; } else { iNewItem = iItem + (LINES -4 - TITLEPOS); if (iNewItem > numitems) iNewItem = numitems; } break; case '-': case '<': case KEY_PPAGE: case 'b': /*** Like in the pager ***/ /*** Go up a page ***/ iNewItem = iItem - (LINES - 4 - TITLEPOS); 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(); } }