Annotation of libwww/LineMode/src/HTBrowse.c, revision 1.103

1.44      frystyk     1: /*                                                                  HTBrowse.c
                      2: **     HYPERTEXT BROWSER FOR DUMB TERMINALS
                      3: **
1.62      frystyk     4: **     (c) COPRIGHT MIT 1995.
1.44      frystyk     5: **     Please first read the full copyright statement in the file COPYRIGH.
1.1       timbl       6: **
                      7: **  Authors:
                      8: **     NP:  Nicola Pellow  Tech.Student CERN 1990-91
1.61      frystyk     9: **     TBL: Tim Berners-Lee CERN (timbl@w3.org)
                     10: **     JFG: Jean-Francois Groff, Cooperant CERN 1991-92 (jfg@dxcern.cern.ch)
1.1       timbl      11: **     DR:  Dudu Rashty +972-2-584848 <RASHTY@hujivms.bitnet>
1.8       duns       12: **     MD:  Mark Donszelmann, DELPHI CERN, (duns@vxdeop.cern.ch)
1.96      frystyk    13: **     HFN: Henrik Frystyk Nielsen, MIT, (frystyk@w3.org)
1.1       timbl      14: **
                     15: **  History:
                     16: **
                     17: **   4 Dec 90:  Written from scratch (NP)
                     18: **  11 Feb 91:  Code written by TBL so that the browser could be linked with
                     19: **              code produced by Bernd Pollermann, enabling access to the
                     20: **              data on CERNVM. This involved changing the code to handle file
                     21: **              numbers rather than file pointers.
                     22: **  18 Mar 91:  The feature of history mechanism was included, enabling a  
                     23: **              record of previous nodes visited to be kept.
                     24: **   6 Apr 91:  When a node is accessed, it is immediately read into a 
1.40      frystyk    25: **              buffer, in an unformatted state, as soon as the connection is  
1.1       timbl      26: **              made, so that the server is freed as quickly as possible. 
                     27: **              The program now also uses the additional modules HTBufferFile.c
                     28: **              and HTBufferFile.h.
                     29: **  17 Apr 91:  Can be used on machines running ANSI C and ordinary C.
                     30: **  10 May 91:  Formatted text is stored in a linked list buffer which allows
                     31: **              scrolling and better page breaks in the middle of text.
                     32: **              Code incorporated by Tim BL, to enable anonymous FTP.          
                     33: **  21 May 91:  Accepts various parameters on the command line.
                     34: **  19 Aug 91:  Currently available in Unix, VAX/VMS and MVS environments.
                     35: **  21 Nov 91:  Character grid uses new architecture. (TBL)
                     36: **              added -w option, new commands, print,
                     37: **                  ...        See Features.html for further details
                     38: **  16 Jan 92:  Put in VIOLA-compatible options - see \017 characters.
                     39: **                  \017 and \016 bracket user-selectable input.
                     40: **  27 Feb 92: New handling of user input, enhanced command syntax. (JFG)
                     41: **  18 May 92: PS command see ifdef SLAVE_PRINTER (DR/TBL)
                     42: **   6 Oct 92:  Painful recovery from someone(?)'s attept to pretty print.(TBL)
                     43: **             Please see coding style guide before changing indentation etc!
                     44: **     Mar 93: Force on HTFile's HTDirAccess and HTDirReadme flags.
1.8       duns       45: **   3 Nov 93: (MD) Changed vms into VMS
1.99      frystyk    46: **             (MD) Assigne OUTPUT in main, not at initialize (VMS only)
1.1       timbl      47: **
                     48: ** Compilation-time macro options
                     49: **
                     50: **     REF_MARK        Printf string to be used for printing anchor numbers
                     51: **     END_MARK        String to be used to denote the end of a document
                     52: **     VL              Version number, quoted eg "1.2a"
                     53: */
                     54: 
1.96      frystyk    55: #include "WWWLib.h"
                     56: #include "WWWMIME.h"
                     57: #include "WWWApp.h"
1.92      frystyk    58: 
1.96      frystyk    59: #include "GridText.h"                               /* Hypertext definition */
1.68      frystyk    60: #include "HTBrowse.h"                       /* Things exported, short names */
1.40      frystyk    61: 
                     62: #ifndef VL
                     63: #define VL "unspecified"
                     64: #endif
                     65: 
1.96      frystyk    66: #define APP_NAME               "W3CLineMode"
                     67: #define APP_VERSION            VL
1.86      frystyk    68: 
1.68      frystyk    69: /* Default page for "Manual" command */
1.96      frystyk    70: #define MANUAL "http://www.w3.org/pub/WWW/LineMode/Defaults/QuickGuide.html"
1.40      frystyk    71: 
1.68      frystyk    72: /* Default page for "help" command */
1.96      frystyk    73: #define C_HELP "http://www.w3.org/pub/WWW/LineMode/Defaults/Commands.html"
1.1       timbl      74: 
1.68      frystyk    75: /* Default page for "-help" command line option */
1.96      frystyk    76: #define L_HELP "http://www.w3.org/pub/WWW/LineMode/Defaults/CommandLine.html"
1.37      howcome    77: 
1.68      frystyk    78: #define DEFAULT_OUTPUT_FILE    "www.out"
                     79: #define DEFAULT_RULE_FILE      "www.conf"
                     80: #define DEFAULT_LOG_FILE               "www.log"
                     81: 
                     82: #define PROMPT                 "%s"
                     83: #define REF_MARK               "[%d]"
                     84: #define END_MARK               "[END]"
1.1       timbl      85: 
1.72      frystyk    86: #define SCREEN_WIDTH           79            /* Default width of the screen */
1.13      frystyk    87: #define MIN_SCREEN_WIDTH       10 
                     88: #define MAX_SCREEN_WIDTH       150      
1.72      frystyk    89: #define SCREEN_HEIGHT          24                /* Default number of lines */
1.13      frystyk    90: #define MIN_SCREEN_HEIGHT      5 
1.14      frystyk    91: #define MAX_SCREEN_HEIGHT      200      
1.72      frystyk    92: 
                     93: #define MAX_HISTORY            20      /* Don't list more than this in list */
1.1       timbl      94: 
1.68      frystyk    95: #define RESPONSE_LENGTH                1024     /* Maximum length of users response */
1.16      frystyk    96: 
1.94      frystyk    97: #define SHOW_MSG               (WWWTRACE || HTAlert_interactive())
1.68      frystyk    98: #define CHECK_INPUT(a, b)      (!strncasecomp ((a), (b), strlen((b))))
1.50      frystyk    99: 
1.96      frystyk   100: #define DEFAULT_I_TIMEOUT      1          /* Interactive timeout in seconds */
                    101: #define DEFAULT_NI_TIMEOUT     10     /* Non-interactive timeout in seconds */
                    102: 
                    103: #define DEFAULT_FORMAT         WWW_PRESENT
1.81      frystyk   104: 
1.50      frystyk   105: #if defined(ultrix) || defined(__osf__)
                    106: #define GET_SCREEN_SIZE
1.16      frystyk   107: #endif
1.1       timbl     108: 
1.50      frystyk   109: #if defined(__svr4__)
                    110: #define CATCH_SIG
                    111: #endif
1.40      frystyk   112: 
                    113: /* HWL 18/7/94: applied patch from agl@glas2.glas.apc.org (Anton Tropashko) */
                    114: #ifdef CYRILLIC
1.68      frystyk   115: #include "a_stdio.h"
1.40      frystyk   116: struct ARc arc;
                    117: #endif
1.2       timbl     118: 
1.68      frystyk   119: /* Screen size parameters */
1.40      frystyk   120: PUBLIC int             HTScreenWidth   = SCREEN_WIDTH;        /* By default */
                    121: PUBLIC int             HTScreenHeight  = -1;              /* -1 = Undefined */
1.68      frystyk   122: 
                    123: /* Anchor specific information */
1.40      frystyk   124: PUBLIC BOOL            display_anchors = YES;      /* Show anchors in text? */
                    125: PUBLIC char *          start_reference = NULL;   /* Format for start anchor */
                    126: PUBLIC char *          end_reference = REF_MARK;          /* for end anchor */
                    127: PUBLIC char *          reference_mark = "[%d] ";     /* for reference lists */
                    128: PUBLIC char *          end_mark = END_MARK;      /* Format string for [End] */
1.8       duns      129: 
1.96      frystyk   130: typedef enum _LMFlags {
                    131:     LM_FILTER  = 0x1,
                    132:     LM_REFS    = 0x2,
                    133:     LM_REFORMAT = 0x4,
                    134:     LM_PREEMTIVE= 0x8
                    135: } LMFlags;
                    136: 
                    137: typedef struct _LineMode {
                    138:     HTRequest *                request;
1.98      frystyk   139:     HTRequest *                tty;
1.96      frystyk   140:     HTParentAnchor *   anchor;
                    141:     HTParentAnchor *   dest;                    /* Destination for PUT etc. */
                    142:     struct timeval *   tv;                             /* Timeout on socket */
                    143:     HTList *           active;                   /* List of acitve contexts */
                    144:     HTList *           converters;
                    145:     HTList *           presenters;
                    146:     HTHistory *                history;                             /* History list */
                    147:     char *             cwd;                              /* Current dir URL */
                    148:     char *             rules;
                    149:     char *             logfile;
                    150:     char *             outputfile;
                    151:     char *             host;
                    152:     int                        trace;
                    153:     HTFormat           format;                 /* Input format from console */
                    154:     LMFlags            flags;
                    155: } LineMode;
                    156: 
                    157: typedef enum _LMState {
                    158:     LM_UPDATE  = 0x1,
                    159:     LM_NO_UPDATE= 0x2,
                    160:     LM_DONE    = 0x4,
                    161:     LM_INACTIVE        = 0x8
                    162: } LMState;
                    163: 
                    164: typedef struct _Context {
                    165:     LMState            state;
                    166:     HTRequest *                request;
                    167:     LineMode *         lm;
                    168: } Context;
1.4       timbl     169: 
1.99      frystyk   170: #ifndef _WINDOWS
1.96      frystyk   171: PRIVATE FILE *         output = STDOUT;
1.99      frystyk   172: #endif
1.96      frystyk   173:  
1.62      frystyk   174: /* ------------------------------------------------------------------------- */
                    175: 
1.96      frystyk   176: /*     Create a Context Object
                    177: **     -----------------------
                    178: */
                    179: PRIVATE Context * Context_new (LineMode * lm, HTRequest * request)
                    180: {
                    181:     Context * me = (Context *) calloc(1, sizeof (Context));
                    182:     if (!me) outofmem(__FILE__, "Context_new");
                    183:     me->state = LM_UPDATE;
                    184:     me->request = request;
                    185:     me->lm = lm;
                    186:     HTRequest_setContext(request, (void *) me);
1.72      frystyk   187:     return me;
                    188: }
                    189: 
1.96      frystyk   190: /*     Delete a Context Object
                    191: **     -----------------------
1.72      frystyk   192: */
1.96      frystyk   193: PRIVATE BOOL Context_delete (Context * old)
1.72      frystyk   194: {
                    195:     FREE(old);
                    196:     return YES;
                    197: }
                    198: 
1.62      frystyk   199: /*
1.96      frystyk   200: **  This function creates a new request object and adds it to the global
1.62      frystyk   201: **  list of active threads
                    202: */
1.96      frystyk   203: PRIVATE HTRequest * Thread_new (LineMode * lm, BOOL Interactive)
1.62      frystyk   204: {
1.96      frystyk   205:     HTRequest * newreq = HTRequest_new();
                    206:     Context * context = Context_new(lm, newreq);
                    207:     if (!lm) return NULL;
                    208:     if (!lm->active) lm->active = HTList_new();
                    209:     if (Interactive) HTRequest_setConversion(newreq, lm->presenters, NO);
                    210:     if (lm->flags & LM_PREEMTIVE) HTRequest_setPreemtive(newreq, YES);
                    211:     HTList_addObject(lm->active, (void *) context);
1.80      frystyk   212:     HTRequest_addRqHd(newreq, HT_HOST);
1.62      frystyk   213:     return newreq;
                    214: }
                    215: 
                    216: /*
1.96      frystyk   217: **  This function deletes all unused request objects
1.62      frystyk   218: */
1.96      frystyk   219: PRIVATE void Thread_cleanup (LineMode * lm)
1.62      frystyk   220: {
1.96      frystyk   221:     if (lm && lm->active) {
                    222:        HTList * cur = lm->active;
                    223:        Context * pres;
                    224:        while ((pres = (Context *) HTList_nextObject(cur))) {
                    225:            if (pres->state & (LM_DONE | LM_INACTIVE)) {
                    226:                HTList_removeObject(lm->active, pres);
                    227:                HTRequest_delete(pres->request);
                    228:                Context_delete(pres);
                    229:                cur = lm->active;
                    230:            }
                    231:        }
1.62      frystyk   232:     }
                    233: }
                    234: 
                    235: /*
                    236: **  This function deletes the whole list of active threads.
                    237: */
1.96      frystyk   238: PRIVATE void Thread_deleteAll (LineMode * lm)
1.62      frystyk   239: {
1.96      frystyk   240:     if (lm && lm->active) {
                    241:        HTList * cur = lm->active;
                    242:        Context * pres;
                    243:        while ((pres = (Context *) HTList_nextObject(cur))) {
                    244:            if (pres->request) HTRequest_delete(pres->request);
1.62      frystyk   245:        }
1.96      frystyk   246:        HTList_delete(lm->active);
                    247:        lm->active = NULL;
1.62      frystyk   248:     }
                    249: }
                    250: 
1.96      frystyk   251: /*     Create a Line Mode Object
                    252: **     -------------------------
                    253: */
1.101     frystyk   254: #ifdef _WINDOWS
                    255: HTRequest * TTYReq = 0; /* The windowed version doesn't get the HTRequest* when
                    256:                            it gets key events so save it in a global here       */
                    257: #endif
                    258: 
1.96      frystyk   259: PRIVATE LineMode * LineMode_new (void)
                    260: {
                    261:     LineMode * me;
                    262:     if ((me = (LineMode *) calloc(1, sizeof(LineMode))) == NULL ||
                    263:        (me->tv = (struct timeval*) calloc(1, sizeof(struct timeval))) == NULL)
                    264:        outofmem(__FILE__, "LineMode_new");
                    265:     me->tv->tv_sec = -1;
                    266:     me->cwd = HTFindRelatedName();
                    267:     me->active = HTList_new();
                    268:     me->request = HTRequest_new();
1.98      frystyk   269:     me->tty = HTRequest_new();
1.101     frystyk   270: #ifdef _WINDOWS
                    271:     TTYReq = me->tty;
                    272: #endif
1.96      frystyk   273:     Context_new(me, me->request);
1.101     frystyk   274:     Context_new(me, me->tty);
1.96      frystyk   275:     return me;
                    276: }
                    277: 
                    278: /*     Delete a Line Mode Object
                    279: **     -------------------------
                    280: */
                    281: PRIVATE BOOL LineMode_delete (LineMode * lm)
                    282: {
                    283:     if (lm) {
                    284:        Context * context = (Context *) HTRequest_context(lm->request);
                    285:        HTRequest_delete(lm->request);
1.98      frystyk   286:        HTRequest_delete(lm->tty);
1.96      frystyk   287:        Context_delete(context);
                    288:        free(lm->tv);
                    289:        Thread_deleteAll(lm);
                    290:        HTConversion_deleteAll(lm->converters);
                    291:        HTPresentation_deleteAll(lm->presenters);
                    292:        HTHistory_delete(lm->history);
                    293:        FREE(lm->cwd);
                    294:        if (lm->logfile) HTLog_close();
1.99      frystyk   295: #ifndef _WINDOWS
                    296:        if (OUTPUT && OUTPUT != STDOUT) fclose(OUTPUT);
                    297: #endif
1.96      frystyk   298:        free(lm);
                    299:        return YES;
                    300:     }
                    301:     return NO;
                    302: }
                    303: 
                    304: PRIVATE void Cleanup (LineMode * me, int status)
                    305: {
                    306:     if (HTAlert_interactive())    /* Terminate with a LF if not interactive */
                    307:        TTYPrint(OUTPUT, "\n");
                    308:     LineMode_delete(me);
                    309:     HTLibTerminate();
                    310: #ifdef VMS
                    311:     exit(status ? status : 1);
                    312: #else
                    313:     exit(status ? status : 0);
                    314: #endif
                    315: }
1.7       secret    316: 
                    317: #ifdef GET_SCREEN_SIZE
1.50      frystyk   318: #include <sys/ioctl.h>
1.7       secret    319: /*
1.100     frystyk   320: ** Get size of the output screen. Stolen from less.
1.40      frystyk   321: */
1.90      frystyk   322: PRIVATE void scrsize (int * p_height, int * p_width)
1.7       secret    323: {
1.96      frystyk   324:     register char *s;
                    325:     int ioctl();
                    326:     struct winsize w;
                    327:     if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_row > 0)
                    328:        *p_height = w.ws_row;
                    329:     else if ((s = getenv("LINES")) != NULL)
                    330:        *p_height = atoi(s);
                    331:     else
                    332:        *p_height = SCREEN_HEIGHT;
                    333:     
                    334:     if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_col > 0)
                    335:        *p_width = w.ws_col;
                    336:     else if ((s = getenv("COLUMNS")) != NULL)
                    337:        *p_width = atoi(s);
                    338:     else
                    339:        *p_width = 80;
1.7       secret    340: }
                    341: #endif /* GET_SCREEN_SIZE, BSN */
                    342: 
1.50      frystyk   343: #ifdef CATCH_SIG
                    344: #include <signal.h>
                    345: /*                                                                 SetSignal
                    346: **  This function sets up signal handlers. This might not be necessary to
                    347: **  call if the application has its own handlers.
                    348: */
1.90      frystyk   349: PRIVATE void SetSignal (void)
1.50      frystyk   350: {
                    351:     /* On some systems (SYSV) it is necessary to catch the SIGPIPE signal
                    352:     ** when attemting to connect to a remote host where you normally should
                    353:     ** get `connection refused' back
                    354:     */
                    355:     if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
1.89      frystyk   356:        if (PROT_TRACE) TTYPrint(TDEST, "HTSignal.... Can't catch SIGPIPE\n");
1.50      frystyk   357:     } else {
1.89      frystyk   358:        if (PROT_TRACE) TTYPrint(TDEST, "HTSignal.... Ignoring SIGPIPE\n");
1.50      frystyk   359:     }
                    360: }
                    361: #endif /* CATCH_SIG */
                    362: 
1.96      frystyk   363: /*  Print version information
                    364: **  -------------------------
                    365: */
                    366: PRIVATE void VersionInfo (void)
                    367: {
                    368:     TTYPrint(OUTPUT,"\n\nW3C Reference Software\n\n");
                    369:     TTYPrint(OUTPUT,"\tW3C Line Mode Browser version %s.\n", APP_VERSION);
                    370:     TTYPrint(OUTPUT,"\tW3C Reference Library version %s.\n\n",HTLib_version());
                    371:     TTYPrint(OUTPUT,"Please send feedback to <www-bug@w3.org>\n");
                    372: }
1.7       secret    373: 
1.40      frystyk   374: /*     Reference_List
                    375: **     --------------
1.96      frystyk   376: **     Print out a list of HyperText References from current document
1.40      frystyk   377: */
1.96      frystyk   378: PRIVATE void Reference_List (LineMode * lm, BOOL titles)
1.40      frystyk   379: {
1.50      frystyk   380:     int refs = HText_sourceAnchors(HTMainText);
                    381:     if (refs <= 0) {
1.99      frystyk   382:        TTYPrint(OUTPUT,"\n\nThere are no references from this document.\n\n");
1.40      frystyk   383:     } else {
1.68      frystyk   384:        int cnt;
1.99      frystyk   385:        TTYPrint(OUTPUT, "\n*** References from this document ***\n");
1.50      frystyk   386:        for (cnt=1; cnt<=refs; cnt++) {
                    387:            HTAnchor *dest =
                    388:                HTAnchor_followMainLink((HTAnchor *)
                    389:                                        HText_childNumber(HTMainText, cnt));
                    390:            HTParentAnchor * parent = HTAnchor_parent(dest);
                    391:            char * address =  HTAnchor_address(dest);
                    392:            CONST char * title = titles ? HTAnchor_title(parent) : NULL;
1.99      frystyk   393:            TTYPrint(OUTPUT, reference_mark, cnt);
                    394:            TTYPrint(OUTPUT, "%s%s\n",
1.50      frystyk   395:                    ((HTAnchor*)parent!=dest) && title ? "in " : "",
1.40      frystyk   396:                    (char *)(title ? title : address));
                    397:            free(address);
                    398:        }
1.99      frystyk   399: #ifndef _WINDOWS
                    400:        fflush(OUTPUT);
                    401: #endif
1.40      frystyk   402:     }
                    403: }      
1.1       timbl     404: 
1.96      frystyk   405: /*     History_List
                    406: **     ------------
1.68      frystyk   407: **     Display a history list of nodes visited during the session.
1.1       timbl     408: */
1.96      frystyk   409: PRIVATE void History_List (LineMode * lm)
                    410: {
                    411:     int current = HTHistory_position(lm->history);
                    412:     int max = HTHistory_count(lm->history);
1.70      frystyk   413:     int cnt;
1.99      frystyk   414:     TTYPrint(OUTPUT, "\n  Documents you have visited: ");
1.70      frystyk   415:     if (max > MAX_HISTORY) {
                    416:        max = MAX_HISTORY;
1.99      frystyk   417:        TTYPrint(OUTPUT, "(truncated)\n");
1.70      frystyk   418:     } else
1.99      frystyk   419:        TTYPrint(OUTPUT, "\n");
1.70      frystyk   420:     for (cnt=1; cnt<=max; cnt++) {
1.96      frystyk   421:        HTAnchor *anchor = HTHistory_list(lm->history, cnt);
1.70      frystyk   422:        char *address = HTAnchor_address(anchor);
                    423:        HTParentAnchor *parent = HTAnchor_parent(anchor);
                    424:        CONST char *title = HTAnchor_title(parent);
1.99      frystyk   425:        TTYPrint(OUTPUT, "%s R %d\t%s%s\n",
1.70      frystyk   426:               (cnt==current) ? "*" : " ",
                    427:               cnt,
1.68      frystyk   428:               ((HTAnchor*)parent!=anchor) && title ? "in " : "",
                    429:               title ? title : address);
1.40      frystyk   430:        free(address);
1.70      frystyk   431:     }
1.99      frystyk   432:     TTYPrint(OUTPUT, "\n");
1.1       timbl     433: }
                    434: 
1.94      frystyk   435: /*     Prompt for answer and get text back. Reply text is either NULL on
                    436: **     error or a dynamic string which the caller must free.
                    437: */
                    438: PRIVATE char * AskUser (HTRequest * request, CONST char * Msg,
1.96      frystyk   439:                        CONST char * deflt)
1.94      frystyk   440: {
                    441:     char buffer[200];
                    442:     char *reply = NULL;
                    443:     TTYPrint(TDEST, "%s ", Msg ? Msg : "UNKNOWN");
                    444:     if (deflt)
                    445:        TTYPrint(TDEST, "(RETURN for [%s]) ", deflt);
                    446: 
                    447: #ifndef NO_STDIO
                    448:     if (!fgets(buffer, 200, stdin))
                    449:        return NULL;                         /* NULL string on error, Henrik */
                    450:     buffer[strlen(buffer)-1] = '\0';                   /* Overwrite newline */
                    451:     if (*buffer)
                    452:        StrAllocCopy(reply, buffer);
                    453:     else if (deflt)
                    454:        StrAllocCopy(reply, deflt);
                    455: #endif
                    456:     return reply;
                    457: }
                    458: 
                    459: PRIVATE BOOL confirm (HTRequest * request, CONST char * Msg)
                    460: {
1.96      frystyk   461:     char response[4];
                    462:     TTYPrint(TDEST, "%s (y/n) ", Msg ? Msg : "UNKNOWN");
1.94      frystyk   463: #ifndef NO_STDIO
1.96      frystyk   464:     if (fgets(response, 4, stdin))                /* get reply, max 3 chars */
1.94      frystyk   465: #endif
1.96      frystyk   466:     {
                    467:        char *ptr = response;
                    468:        while (*ptr) {
                    469:            if (*ptr == '\n') {
                    470:                *ptr = '\0';
                    471:                break;
                    472:            }
                    473:            *ptr = TOUPPER(*ptr);
                    474:            ptr++;
                    475:        }
                    476:        return (!strcmp(response, "YES") || !strcmp(response, "Y")) ? YES : NO;
1.94      frystyk   477:     }
1.96      frystyk   478:     return NO;
1.94      frystyk   479: }
1.1       timbl     480: 
1.96      frystyk   481: /*     MakeCommandLine
                    482: **     ---------------
1.40      frystyk   483: **     Generate the Prompt line and flush it to the user
1.1       timbl     484: */
1.96      frystyk   485: PRIVATE void MakeCommandLine (LineMode * lm, BOOL is_index)
1.40      frystyk   486: {
1.70      frystyk   487:     /* First Line */
1.69      frystyk   488:     if (HTAnchor_hasChildren(HTMainAnchor)) {
1.40      frystyk   489:        int refs = HText_sourceAnchors(HTMainText);
1.69      frystyk   490:        if (refs>1)
1.99      frystyk   491:            TTYPrint(OUTPUT, "1-%d, ", refs);
1.69      frystyk   492:        else
1.99      frystyk   493:            TTYPrint(OUTPUT, "1, ");    
1.40      frystyk   494:     }
1.70      frystyk   495:     if (HText_canScrollUp(HTMainText)) {
1.99      frystyk   496:        TTYPrint(OUTPUT, "Top, ");
                    497:        TTYPrint(OUTPUT, "Up, ");
1.70      frystyk   498:     }
                    499:     if (HText_canScrollDown(HTMainText)) {
1.99      frystyk   500:        TTYPrint(OUTPUT, "BOttom, ");
                    501:        TTYPrint(OUTPUT, "Down or <RETURN> for more,");
1.70      frystyk   502:     }
1.69      frystyk   503: 
1.70      frystyk   504:     /* Second Line */
1.99      frystyk   505:     TTYPrint(OUTPUT, "\n");
1.96      frystyk   506:     if (HTHistory_canBacktrack(lm->history))
1.99      frystyk   507:        TTYPrint(OUTPUT, "Back, ");
1.96      frystyk   508:     if (HTHistory_canForward(lm->history))
1.99      frystyk   509:        TTYPrint(OUTPUT, "Forward, ");
1.70      frystyk   510:     if (is_index)
1.99      frystyk   511:        TTYPrint(OUTPUT, "FIND <keywords>, ");
                    512:     TTYPrint(OUTPUT, "Quit, or Help: ");       
1.44      frystyk   513:     fflush(stdout);                      /* For use to flush out the prompt */
1.40      frystyk   514:     return;
                    515: }
1.1       timbl     516: 
1.40      frystyk   517: /*
1.62      frystyk   518: **  Upload a document either from local file or from a HTTP server
                    519: **  to a HTTP server. The method can be either PUT or POST.
                    520: **  Returns the result of the load function.
1.1       timbl     521: */
1.96      frystyk   522: PRIVATE int Upload (LineMode * lm, HTRequest * req, HTMethod method)
1.40      frystyk   523: {
1.96      frystyk   524:     char * base = HTAnchor_address((HTAnchor*) HTMainAnchor);
                    525:     char * scr_url = NULL;
                    526:     char * dest_url = NULL;
1.62      frystyk   527:     int status = HT_INTERNAL;
1.96      frystyk   528:     if ((scr_url = AskUser(req, "Source:", base)) != NULL &&
                    529:        (dest_url = AskUser(req, "Destination:", NULL)) != NULL) {
1.94      frystyk   530:        BOOL doit = YES;
1.96      frystyk   531:        char * fd = HTParse(HTStrip(dest_url), base, PARSE_ALL);
                    532:        char * fs = HTParse(HTStrip(scr_url), base, PARSE_ALL);
                    533:        HTParentAnchor * dest = (HTParentAnchor *) HTAnchor_findAddress(fd);
                    534:        HTParentAnchor * src = (HTParentAnchor *) HTAnchor_findAddress(fs);
                    535:        HTLink * link = HTAnchor_findLink((HTAnchor *) src, (HTAnchor *) dest);
1.62      frystyk   536:        
                    537:        /* Now link the two anchors together if not already done */
1.68      frystyk   538:        if (link) {
                    539:            char *msg = (char *) malloc(128);
1.62      frystyk   540:            if (!msg) outofmem(__FILE__, "Upload");
1.68      frystyk   541:            sprintf(msg, "The destination is already related to the source with a %s method - result %d, continue?",
1.103   ! frystyk   542:                    HTMethod_name(HTLink_method(link)), HTLink_result(link));
1.96      frystyk   543:            doit = confirm(req, msg);
1.62      frystyk   544:            free(msg);
                    545:        } else
                    546:            HTAnchor_link((HTAnchor *) src, (HTAnchor *) dest, NULL, method);
1.94      frystyk   547:        if (doit) {
1.96      frystyk   548:            req = Thread_new(lm, YES);
1.68      frystyk   549:            status = HTCopyAnchor((HTAnchor *) src, req);
1.62      frystyk   550:        }
                    551:        free(fd);
                    552:        free(fs);
1.40      frystyk   553:     }
1.96      frystyk   554:     FREE(scr_url);
                    555:     FREE(dest_url);
                    556:     FREE(base);
1.62      frystyk   557:     return status;
1.40      frystyk   558: }
1.1       timbl     559: 
                    560: /*
1.40      frystyk   561: **  This function puts up a stream to a file in order to save a document. This
                    562: **  is activated by '>', '>>' or '>!' from the prompt line.
1.1       timbl     563: */
1.90      frystyk   564: PRIVATE BOOL SaveOutputStream (HTRequest * req, char * This, char * Next)
1.40      frystyk   565: {
                    566:     FILE *fp;
                    567:     char *fname;
                    568:     char *fmode;
                    569:     
                    570:     /* Checks if file exists. Can be overruled by using '>!' */
                    571:     if (*(This+1) == '>') {                               /* Append to file */
1.74      frystyk   572:        fmode = "ab";
1.40      frystyk   573:        fname = *(This+2) ? (This+2) : Next;
                    574:     } else if (*(This+1) == '!') {
1.74      frystyk   575:        fmode = "wb";                                      /* Overwrite file */
1.40      frystyk   576:        fname = *(This+2) ? (This+2) : Next;
                    577:     } else {                                           /* File name follows */
1.74      frystyk   578:        fmode = "wb";
1.40      frystyk   579:        fname = *(This+1) ? (This+1) : Next;
                    580:        if (fname) {                                   /* See if file exists */
                    581:            if ((fp = fopen(fname, "r")) != NULL) {
                    582:                fclose(fp);
1.94      frystyk   583:                if (!confirm(req, "File exists - overwrite?"))
1.92      frystyk   584:                    return NO;
1.40      frystyk   585:            }
                    586:        }
                    587:     }
                    588:     if (!fname)                                               /* No file name given */
                    589:        return NO;
                    590:     if ((fp = fopen(fname, fmode)) == NULL) {
1.89      frystyk   591:        if (SHOW_MSG) TTYPrint(TDEST, "Can't access file (%s)\n", fname);
1.40      frystyk   592:        return NO;
                    593:     }
1.90      frystyk   594:     HTRequest_setOutputStream(req, HTFWriter_new(fp, NO));
1.92      frystyk   595:     if (SHOW_MSG) TTYPrint(TDEST, "Saving to file `%s\'\n", fname);
1.58      frystyk   596:     return (HTLoadAnchor((HTAnchor*) HTMainAnchor, req) != HT_WOULD_BLOCK);
1.40      frystyk   597: }
1.1       timbl     598: 
1.62      frystyk   599: /* ------------------------------------------------------------------------- */
                    600: /*                             EVENT FUNCTIONS                              */
                    601: /* ------------------------------------------------------------------------- */
1.1       timbl     602: 
1.89      frystyk   603: /*     parse_command
1.76      frystyk   604: **     ------------
1.89      frystyk   605: **      Given the user's input, deal with it as necessary.
1.40      frystyk   606: **     Any Command which works returns from the routine. If nothing
                    607: **     works then a search or error message down at the bottom.
1.76      frystyk   608: **
                    609: **     Returns         HT_ERROR        Error has occured or we quit
                    610: **                     HT_OK           Call back was OK
1.1       timbl     611: */
1.91      frystyk   612: PRIVATE int parse_command (char* choice, SOCKET s, HTRequest *req, SockOps ops)
1.101     frystyk   613: {
1.68      frystyk   614:     char * the_choice=NULL;                       /* preserved user command */
                    615:     char * token=NULL;                             /* First word of command */
                    616:     char * this_command;                             /* token and following */
1.40      frystyk   617:     char * next_word;                                        /* Second word */
                    618:     char * other_words;                                /* Second word and following */
1.14      frystyk   619:     BOOL is_index = HTAnchor_isIndex(HTMainAnchor);
1.48      frystyk   620:     BOOL found = YES;
1.68      frystyk   621:     BOOL OutSource = NO;                           /* Output source, YES/NO */
1.76      frystyk   622:     int status = YES;
1.101     frystyk   623:     Context * context;
                    624:     LineMode * lm;
                    625: 
                    626: #ifdef _WINDOWS
                    627:     req = TTYReq;
                    628: #endif
                    629:     context = (Context *) HTRequest_context(req);
                    630:     lm = context->lm;
1.40      frystyk   631: 
                    632:     StrAllocCopy (the_choice, choice);                /* Remember it as is, */
1.91      frystyk   633:     if (*the_choice && the_choice[strlen(the_choice)-1] == '\n') /* final \n */
1.40      frystyk   634:        the_choice[strlen(the_choice)-1] = '\0';
1.14      frystyk   635:     
1.68      frystyk   636:     token = strtok (choice, " \t\n\r");              /* Tokenize user input */
1.40      frystyk   637:     this_command = the_choice;
1.68      frystyk   638:     if (token) {
1.40      frystyk   639:        next_word = strtok (NULL, " \t\n\r");
                    640:        other_words = the_choice + (next_word - choice);
1.14      frystyk   641:     }
1.40      frystyk   642:     else
                    643:        goto down;                              /* Empty input : scroll down */
                    644:     
                    645:     /* Process Command */
                    646:   loop:
1.68      frystyk   647:     switch (TOUPPER(*token)) {
1.40      frystyk   648:       case '0':
                    649:       case '1':
                    650:       case '2':
                    651:       case '3':
                    652:       case '4':
                    653:       case '5':
                    654:       case '6':
                    655:       case '7':
                    656:       case '8':
                    657:       case '9':
1.68      frystyk   658:        {
                    659:            int  ref_num;
                    660:            sscanf(token,"%d",&ref_num);
                    661:            if (ref_num>0 && ref_num<=HText_sourceAnchors(HTMainText)) {
                    662:                HTAnchor *destination;
                    663:                HTChildAnchor *source = HText_childNumber(HTMainText, ref_num);
                    664:                if (source) {
1.96      frystyk   665:                    req = Thread_new(lm, YES);
1.68      frystyk   666:                    destination = HTAnchor_followMainLink((HTAnchor*) source);
1.69      frystyk   667: 
                    668:                    /* Continous browsing, so we want Referer field */
1.90      frystyk   669:                    HTRequest_setParent(req,
                    670:                                        HTAnchor_parent((HTAnchor*)source));
1.76      frystyk   671:                    status = HTLoadAnchor(destination, req);
1.68      frystyk   672:                } else {
1.76      frystyk   673:                    status = NO;                                /* No anchor */
1.68      frystyk   674:                }
1.45      frystyk   675:            } else {
1.68      frystyk   676:                if (SHOW_MSG)
1.89      frystyk   677:                    TTYPrint(TDEST,"Warning: Invalid Reference Number: (%d)\n",
1.68      frystyk   678:                            ref_num);
1.44      frystyk   679:            }
1.40      frystyk   680:        }
                    681:        break;
                    682:        
                    683:       case 'B':                
1.68      frystyk   684:        if (CHECK_INPUT("BACK", token)) {         /* Return to previous node */
1.96      frystyk   685:            if (HTHistory_canBacktrack(lm->history)) {
                    686:                req = Thread_new(lm, YES);
                    687:                context->state = LM_NO_UPDATE;
                    688:                status = HTLoadAnchor(HTHistory_back(lm->history), req);
1.40      frystyk   689:            } else {
1.89      frystyk   690:                TTYPrint(OUTPUT, "\nThis is the first document in history list\n");
1.40      frystyk   691:            }
1.68      frystyk   692:        } else if (CHECK_INPUT("BOTTOM", token)) {      /* Scroll to bottom  */
1.40      frystyk   693:            HText_scrollBottom(HTMainText);
1.48      frystyk   694:        } else
                    695:            found = NO;
1.40      frystyk   696:        break;
                    697:        
1.51      frystyk   698:       case 'C':
1.50      frystyk   699: #ifdef unix
1.68      frystyk   700:        if (CHECK_INPUT("CD", token)) {        /* Change working directory ? */
1.40      frystyk   701:            goto lcd;
1.64      frystyk   702:        } else
1.51      frystyk   703: #endif
1.69      frystyk   704:        if (CHECK_INPUT("CLEAR", token)) {             /* Clear History list */
1.96      frystyk   705:            HTHistory_removeFrom(lm->history, 1);
1.69      frystyk   706:        } else
1.48      frystyk   707:            found = NO;
1.40      frystyk   708:        break;
                    709:        
                    710:       case 'D':
1.68      frystyk   711:        if (CHECK_INPUT("DOWN", token)) {           /* Scroll down one page  */
1.40      frystyk   712:          down:
                    713:            if (HText_canScrollDown(HTMainText))
                    714:                HText_scrollDown(HTMainText);
1.48      frystyk   715:        } else
                    716:            found = NO;
1.40      frystyk   717:        break;
                    718:        
1.51      frystyk   719:       case 'E':
1.68      frystyk   720:        if (CHECK_INPUT("EDIT", token)) {
1.51      frystyk   721: 
                    722:            /* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ */
                    723:            
1.68      frystyk   724:        } else if (CHECK_INPUT("EXIT", token)) {            /* Quit program? */
1.76      frystyk   725:            status = NO;
1.48      frystyk   726:        } else
                    727:            found = NO;
1.40      frystyk   728:        break;
                    729:        
                    730:       case 'F':                                                 /* Keyword search ? */
1.68      frystyk   731:        if (is_index && CHECK_INPUT("FIND", token)) {
1.40      frystyk   732:          find:
1.47      frystyk   733:            {
                    734:                if (next_word) {
1.96      frystyk   735:                    req = Thread_new(lm, YES);
1.76      frystyk   736:                    status = HTSearch(other_words, HTMainAnchor, req);
1.47      frystyk   737:                }
                    738:            }
1.69      frystyk   739:        } else if (CHECK_INPUT("FORWARD", token)) {
1.96      frystyk   740:            if (HTHistory_canForward(lm->history)) {
                    741:                req = Thread_new(lm, YES);
                    742:                context->state = LM_NO_UPDATE;
                    743:                status = HTLoadAnchor(HTHistory_forward(lm->history), req);
1.69      frystyk   744:            } else {
1.89      frystyk   745:                TTYPrint(OUTPUT, "\nThis is the last document in history list.\n");
1.69      frystyk   746:            }
1.48      frystyk   747:        } else
                    748:            found = NO;
1.40      frystyk   749:        break;
                    750:        
                    751:       case 'G':
1.68      frystyk   752:        if (CHECK_INPUT("GOTO", token)) {                            /* GOTO */
1.40      frystyk   753:            if (next_word) {
1.96      frystyk   754:                req = Thread_new(lm, YES);
1.76      frystyk   755:                status = HTLoadRelative(next_word, HTMainAnchor, req);
1.40      frystyk   756:            }
1.48      frystyk   757:        } else
                    758:            found = NO;
1.40      frystyk   759:        break;
                    760:        
                    761:       case '?':
1.96      frystyk   762:        req = Thread_new(lm, YES);
1.81      frystyk   763:        HTRequest_setPreemtive(req, YES);
1.76      frystyk   764:        status = HTLoadRelative(C_HELP, HTMainAnchor, req);
1.47      frystyk   765:        break;
1.40      frystyk   766:        
                    767:       case 'H':
1.68      frystyk   768:        if (CHECK_INPUT("HELP", token)) {                    /* help menu, ..*/
1.96      frystyk   769:            req = Thread_new(lm, YES);
1.81      frystyk   770:            HTRequest_setPreemtive(req, YES);
1.76      frystyk   771:            status = HTLoadRelative(C_HELP, HTMainAnchor, req);
1.68      frystyk   772:        } else if (CHECK_INPUT("HOME", token)) {                /* back HOME */
1.96      frystyk   773:            if (!HTHistory_canBacktrack(lm->history)) {
1.40      frystyk   774:                HText_scrollTop(HTMainText);
                    775:            } else {
1.96      frystyk   776:                req = Thread_new(lm, YES);
                    777:                context->state = LM_NO_UPDATE;
                    778:                status = HTLoadAnchor(HTHistory_find(lm->history, 1), req);
1.40      frystyk   779:            }
1.48      frystyk   780:        } else
                    781:            found = NO;
1.40      frystyk   782:        break;
                    783:        
                    784:       case 'K':                                                 /* Keyword search ? */
1.68      frystyk   785:        if (is_index && CHECK_INPUT("KEYWORDS", token)) {
1.40      frystyk   786:            goto find;
1.48      frystyk   787:        } else
                    788:            found = NO;
1.40      frystyk   789:        break;
                    790:        
                    791:       case 'L':
1.68      frystyk   792:        if (CHECK_INPUT("LIST", token)) {            /* List of references ? */
1.96      frystyk   793:            Reference_List(lm, !OutSource);
1.40      frystyk   794:        }
1.50      frystyk   795: #ifdef unix
1.68      frystyk   796:        else if (CHECK_INPUT ("LCD", token)) {         /* Local change dir ? */
1.40      frystyk   797:          lcd:
                    798:            if (!next_word) {                            /* Missing argument */
1.89      frystyk   799:                TTYPrint(OUTPUT, "\nName of the new local directory missing.\n");
1.47      frystyk   800:            } else if (chdir (next_word)) {              /* failed : say why */
1.89      frystyk   801:                TTYPrint(OUTPUT, "\n  ");
1.40      frystyk   802:                perror (next_word);
1.47      frystyk   803:            } else {                /* Success : display new local directory */
1.40      frystyk   804:                /* AS Sep 93 */
1.50      frystyk   805: #ifdef NO_GETWD     /* No getwd() on this machine */
                    806: #ifdef HAS_GETCWD   /* System V variant SIGN CHANGED TBL 921006 !! */
1.89      frystyk   807:                TTYPrint(OUTPUT, "\nLocal directory is now:\n %s\n",
1.40      frystyk   808:                        getcwd (choice, sizeof(choice)));
1.50      frystyk   809: #else   /* has NO getcwd */
1.68      frystyk   810:                if (SHOW_MSG)
1.89      frystyk   811:                    TTYPrint(TDEST, "This platform does not support getwd() or getcwd()\n");
1.50      frystyk   812: #endif /* has no getcwd */
                    813: #else   /* has getwd */
1.89      frystyk   814:                TTYPrint(OUTPUT, "\nLocal directory is now:\n %s\n",
1.50      frystyk   815:                       (char *) getwd (choice));
                    816: #endif  /* has getwd */
1.40      frystyk   817:                /* End AS Sep 93 */
                    818:            }
                    819:        }
                    820: #endif
1.48      frystyk   821:        else
                    822:            found = NO;
1.40      frystyk   823:        break;
                    824:        
                    825:       case 'M':
1.68      frystyk   826:        if (CHECK_INPUT("MANUAL", token)) {              /* Read User manual */
1.96      frystyk   827:            req = Thread_new(lm, YES);
1.81      frystyk   828:            HTRequest_setPreemtive(req, YES);
1.76      frystyk   829:            status = HTLoadRelative(MANUAL, HTMainAnchor,req);
1.48      frystyk   830:        } else
                    831:            found = NO;
1.40      frystyk   832:        break;
                    833:        
                    834:       case 'P':                    
1.68      frystyk   835:        if (CHECK_INPUT("POST", token)) {
1.96      frystyk   836:            status = Upload(lm, req, METHOD_POST);
1.40      frystyk   837:        }
1.70      frystyk   838: 
1.50      frystyk   839: #ifdef GOT_SYSTEM          
1.96      frystyk   840:        else if (!lm->host && CHECK_INPUT("PRINT", token)) {
1.40      frystyk   841:            char * address = HTAnchor_address((HTAnchor *) HTMainAnchor);
                    842:            char * command;
1.62      frystyk   843:            char * tmplate = (char *) getenv("WWW_PRINT_COMMAND");
1.40      frystyk   844:            int result;
                    845:            
1.46      frystyk   846:            if (!tmplate) tmplate = "www -n -na -p66 '%s' | lpr";
                    847:            command = (char *) malloc(strlen(address)+strlen(tmplate)+20);
                    848:            sprintf(command, tmplate, address);
1.40      frystyk   849:            result = system(command);
                    850:            free(address);
                    851:            free(command);
1.89      frystyk   852:            if (result) TTYPrint(OUTPUT, "  %s\n  returns %d\n", command, result);
1.40      frystyk   853:        }
                    854: #endif
                    855:        /* this command prints the entire current text to the
                    856:           terminal's printer; at the end it displays the top of the text */
                    857: #ifdef SLAVE_PRINTER
                    858: #define SLAVE_PRINTER_ON  "\033\133\065\151"
                    859: #define SLAVE_PRINTER_OFF "\033\133\064\151"
                    860:        
1.68      frystyk   861:        else if (CHECK_INPUT("PS", token)) {
1.89      frystyk   862:            TTYPrint(OUTPUT, "%s",SLAVE_PRINTER_ON);
                    863:            TTYPrint(OUTPUT, "\f");                        /* Form feed for new page */
1.40      frystyk   864:            HText_scrollTop(HTMainText);
                    865:            while(HText_canScrollDown(HTMainText)) {
                    866:                HText_scrollDown(HTMainText);
                    867:            }
1.89      frystyk   868:            TTYPrint(OUTPUT, "\f");                        /* Form feed for new page */
                    869:            TTYPrint(OUTPUT, "%s",SLAVE_PRINTER_OFF);
1.40      frystyk   870:            HText_scrollTop(HTMainText);
                    871:        }       
                    872: #endif
1.68      frystyk   873:        else if (CHECK_INPUT("PUT", token)) {
1.96      frystyk   874:            status = Upload(lm, req, METHOD_PUT);
1.62      frystyk   875:        } else
1.48      frystyk   876:            found = NO;
1.40      frystyk   877:        break;
                    878:        
                    879:       case 'Q':                                                   /* Quit program ? */
1.68      frystyk   880:        if (CHECK_INPUT("QUIT", token)) {
1.47      frystyk   881: 
1.40      frystyk   882:            /*  JFG 9/7/92, following a complaint of 'q' mis-typed for '1'.
                    883:                JFG Then made optional because I hate it !!!
                    884:                TBL made it only affect remote logged on users. 921122 */
                    885:            
1.96      frystyk   886:            if (lm->host && (strcasecomp(token, "quit") != 0) ) {
1.89      frystyk   887:                TTYPrint(OUTPUT, "\n Please type \"quit\" in full to leave www.\n");
1.76      frystyk   888:            } else {
                    889:                HTNet_killAll();                        /* Kill all requests */
                    890:                status = NO;
                    891:            }
1.48      frystyk   892:        } else
                    893:            found = NO;
1.40      frystyk   894:        break;
                    895:        
                    896:       case 'R':        
1.68      frystyk   897:        if (CHECK_INPUT("RECALL", token)) {
1.96      frystyk   898:            if (HTHistory_count(lm->history) <= 1) {
1.89      frystyk   899:                TTYPrint(OUTPUT, "\n  No other documents to recall.\n");
1.47      frystyk   900:            } else {
                    901:                /* Previous node number exists, or does the user just */
                    902:                /* require a list of nodes visited? */
1.69      frystyk   903:                if (next_word) {        
                    904:                    int cnt;
                    905:                    if ((cnt = atoi(next_word)) > 0) {
1.96      frystyk   906:                        req = Thread_new(lm, YES);
                    907:                        context->state = LM_NO_UPDATE;
                    908:                        status = HTLoadAnchor(HTHistory_find(lm->history,cnt), req);
1.47      frystyk   909:                    } else {
1.68      frystyk   910:                        if (SHOW_MSG)
1.89      frystyk   911:                            TTYPrint(TDEST, "Bad command (%s), for list of commands type help\n", this_command);
1.47      frystyk   912:                    }
                    913:                } else {
1.96      frystyk   914:                    History_List(lm);
1.47      frystyk   915:                }
1.40      frystyk   916:            }
1.68      frystyk   917:        } else if (CHECK_INPUT("REFRESH", token)) {
1.50      frystyk   918:            HText_setStale(HTMainText);                     /* Force refresh */
                    919:            HText_refresh(HTMainText);                     /* Refresh screen */
1.68      frystyk   920:        } else if (CHECK_INPUT("RELOAD", token)) {
1.96      frystyk   921:            req = Thread_new(lm, YES);
1.90      frystyk   922:            HTRequest_setReloadMode(req, HT_FORCE_RELOAD);
1.96      frystyk   923:            context->state = LM_NO_UPDATE;
1.76      frystyk   924:            status = HTLoadAnchor((HTAnchor*) HTMainAnchor, req);
1.48      frystyk   925:        } else
                    926:            found = NO;
1.40      frystyk   927:        break;
                    928:        
                    929:       case 'S':                                                       /* TBL 921009 */
1.68      frystyk   930:        if (CHECK_INPUT("SOURCE", token)) {               /* Apply to source */
1.47      frystyk   931:            if (next_word) {
                    932:                OutSource = YES;                 /* Load and print as source */
1.68      frystyk   933:                token = next_word;                       /* Move up one word */
1.47      frystyk   934:                next_word = strtok (NULL, " \t\n\r");
1.68      frystyk   935:                this_command = the_choice + (token - choice);
1.47      frystyk   936:                other_words = the_choice + (next_word - choice);
                    937:                goto loop;                             /* Go treat as before */
                    938:            }
1.68      frystyk   939:        } else if (CHECK_INPUT("SET", token)) {                    /* config */
1.93      frystyk   940:            HTList * rules = HTRule_global();
                    941:            HTRule_parseLine(rules, other_words);
1.48      frystyk   942:        } else
                    943:            found = NO;
1.40      frystyk   944:        break;
                    945:        
                    946:       case 'T':
1.68      frystyk   947:        if (CHECK_INPUT("TOP", token)) {                   /* Return to top  */
1.40      frystyk   948:            HText_scrollTop(HTMainText);
1.48      frystyk   949:        } else
                    950:            found = NO;
1.40      frystyk   951:        break;
                    952:        
                    953:       case 'U':
1.68      frystyk   954:        if (CHECK_INPUT("UP", token)) {               /* Scroll up one page  */
1.40      frystyk   955:            HText_scrollUp(HTMainText);
1.48      frystyk   956:        } else
                    957:            found = NO;
1.40      frystyk   958:        break;
                    959:        
                    960:       case 'V':
1.68      frystyk   961:        if (CHECK_INPUT("VERBOSE", token)) {         /* Switch verbose mode  */
1.96      frystyk   962:            WWWTRACE = WWWTRACE ? 0 : lm->trace;
1.93      frystyk   963:            TTYPrint(OUTPUT, "\n  Verbose mode %s.\n", WWWTRACE ? "ON":"OFF");
1.68      frystyk   964:        } else if (CHECK_INPUT("VERSION", token)) {               /* Version */
                    965:            VersionInfo();
1.48      frystyk   966:        } else
                    967:            found = NO;
1.40      frystyk   968:        break;
                    969:        
                    970:       case 'Z':
1.50      frystyk   971:        HText_setStale(HTMainText);                         /* Force refresh */
                    972:        HText_refresh(HTMainText);                         /* Refresh screen */
1.76      frystyk   973:        HTNet_killAll();                                /* Kill all requests */
1.44      frystyk   974:        break;
1.40      frystyk   975: 
                    976:       case '>':
1.96      frystyk   977:        if (!lm->host) {
1.58      frystyk   978:            HText *curText = HTMainText;     /* Remember current main vindow */
1.96      frystyk   979:            req = Thread_new(lm, NO);
1.90      frystyk   980:            HTRequest_setReloadMode(req, HT_MEM_REFRESH);
                    981:            if (OutSource) HTRequest_setOutputFormat(req, WWW_SOURCE);
1.76      frystyk   982:            SaveOutputStream(req, token, next_word);
1.58      frystyk   983:            HText_select(curText);
1.40      frystyk   984:        }
                    985:        break;
1.1       timbl     986:        
1.50      frystyk   987: #ifdef GOT_PIPE
1.40      frystyk   988:       case '|':
1.96      frystyk   989:        if (!lm->host) {                                   /* Local only!!!! */
1.40      frystyk   990:            char * address = HTAnchor_address((HTAnchor *) HTMainAnchor);
                    991:            char * command;
                    992:            int result;
                    993:            command = (char*) malloc(strlen(address) +strlen(this_command)+30);
                    994:            sprintf(command, "www %s \"%s\" %s", 
                    995:                    OutSource ? "-source" : "-n -na -p", address,this_command);
1.89      frystyk   996:            TTYPrint(OUTPUT, "Command: %s\n", command);
1.40      frystyk   997:            result = system(command);
1.96      frystyk   998:            if (result) TTYPrint(OUTPUT,"  %s  returns %d\n", command, result);
1.40      frystyk   999:            free(command);
                   1000:            free(address);
1.14      frystyk  1001:        }
1.47      frystyk  1002:        break;
1.40      frystyk  1003: #endif
                   1004:            
1.50      frystyk  1005: #ifdef GOT_SYSTEM
1.40      frystyk  1006:       case '!':
1.96      frystyk  1007:        if (!lm->host) {                                      /* Local only! */
1.40      frystyk  1008:            int result;
1.89      frystyk  1009:            if (SHOW_MSG) TTYPrint(TDEST, "Executing `%s\'\n", this_command);
1.40      frystyk  1010:            result = system(strchr(this_command, '!') + 1);
1.89      frystyk  1011:            if (result) TTYPrint(OUTPUT, "  %s  returns %d\n",
1.96      frystyk  1012:                                 strchr(this_command, '!') + 1, result);
1.1       timbl    1013:        }
1.47      frystyk  1014:        break;
1.1       timbl    1015: #endif
1.40      frystyk  1016:       default:
1.48      frystyk  1017:        found = NO;
                   1018:        break;
                   1019:     } /* Switch on 1st character */
                   1020: 
                   1021:     if (!found) {
1.68      frystyk  1022:        if (is_index && *token) {  /* No commands, search keywords */
1.47      frystyk  1023:            next_word = other_words = this_command;
1.48      frystyk  1024:            found = YES;
1.47      frystyk  1025:            goto find;
                   1026:        } else {             
1.68      frystyk  1027:            if (SHOW_MSG)
1.89      frystyk  1028:                TTYPrint(TDEST, "Bad command (%s), for list of commands type help\n", this_command);
1.47      frystyk  1029:        }
1.48      frystyk  1030:     }
1.96      frystyk  1031:     MakeCommandLine(lm, is_index);
1.40      frystyk  1032:     free (the_choice);
1.96      frystyk  1033: 
                   1034:     /* 
                   1035:     ** If we have created a new Request and is to update the history list then
                   1036:     ** we can set the inactive bit on this request object.
                   1037:     */
                   1038:     if (context->state & LM_UPDATE) context->state |= LM_INACTIVE;
                   1039: 
1.76      frystyk  1040:     return (status==YES) ? HT_OK : HT_ERROR;
1.40      frystyk  1041: }
                   1042: 
1.96      frystyk  1043: /*     readConsole
                   1044: **     -----------
                   1045: **     non-blocking read of the WIN32 console. EGP
                   1046: */
1.97      frystyk  1047: 
1.89      frystyk  1048: #ifdef _CONSOLE
                   1049: PUBLIC BOOL readConsole(HANDLE conIn, char* buf, int len, int* pRed)
                   1050: {
                   1051:     DWORD recordIndex, bufferIndex, toRead, red;
                   1052:     PINPUT_RECORD pInput;
                   1053: 
                   1054:     /* grab the pending input records (keystrokes plus other garbage). */
                   1055:     GetNumberOfConsoleInputEvents(conIn, &toRead);
                   1056:     if (len < (int)toRead)     /* we'll get the rest on the next pass(es). */
                   1057:     toRead = len;
1.97      frystyk  1058:     if (!(pInput = (PINPUT_RECORD)malloc(toRead * sizeof(INPUT_RECORD))))      /* room for n input records */
1.89      frystyk  1059:        return (FALSE);
                   1060:     ReadConsoleInput(conIn, pInput, toRead, &red);
                   1061: 
                   1062:     for (recordIndex = bufferIndex = 0; recordIndex < red; recordIndex++) {
                   1063:        /* grab all keydown events */
1.97      frystyk  1064: #if 1
                   1065:         KEY_EVENT_RECORD keyEvent = pInput[recordIndex].Event.KeyEvent;     /* only used if EventType == KEY_EVENT */
                   1066:        if (pInput[recordIndex].EventType == KEY_EVENT && keyEvent.bKeyDown) {
                   1067:            while (keyEvent.wRepeatCount && keyEvent.uChar.AsciiChar) {
                   1068:                /* stuff the buffer with the keys */
                   1069:                buf[bufferIndex] = keyEvent.uChar.AsciiChar;
                   1070:                if (buf[bufferIndex] == '\r')
                   1071:                    buf[bufferIndex] = '\n';
                   1072:                if (buf[bufferIndex] == '\b')
                   1073:                    TTYPrint(STDOUT, "\b ");
                   1074:                TTYPrint(STDOUT, "%c", buf[bufferIndex]);
                   1075:                bufferIndex++;
                   1076:                keyEvent.wRepeatCount--;
                   1077:            }
                   1078:        }
                   1079: #else
                   1080:        if (pInput[recordIndex].EventType == KEY_EVENT && pInput[recordIndex].Event.KeyEvent.bKeyDown) {
                   1081:            while (pInput[recordIndex].Event.KeyEvent.wRepeatCount && pInput[recordIndex].Event.KeyEvent.uChar.AsciiChar) {
                   1082:                /* stuff the buffer with the keys */
                   1083:                buf[bufferIndex] = pInput[recordIndex].Event.KeyEvent.uChar.AsciiChar;
                   1084:                if (buf[bufferIndex] == '\r')
                   1085:                    buf[bufferIndex] = '\n';
                   1086:                if (buf[bufferIndex] == '\b')
                   1087:                    TTYPrint(STDOUT, "\b ");
                   1088:                TTYPrint(STDOUT, "%c", buf[bufferIndex]);
                   1089:                bufferIndex++;
                   1090:                pInput[recordIndex].Event.KeyEvent.wRepeatCount--;
                   1091:            }
                   1092:        }
                   1093: #endif
                   1094: 
1.89      frystyk  1095:     }
                   1096: 
                   1097:     free(pInput);
1.97      frystyk  1098:     *pRed = bufferIndex;               /* actual characters stuck into buffer */
1.89      frystyk  1099:     return (TRUE);
                   1100: }
                   1101: #endif /* _CONSOLE */
                   1102: 
1.96      frystyk  1103: /*     bufferInput
                   1104: **     -----------
                   1105: **     Read available characters from buf into stat. buf maybe bigger or
                   1106: **     smaller than stat.
                   1107: */
                   1108: PUBLIC int bufferInput (char* buf, int len, SOCKET s, HTRequest * req, 
                   1109:                        SockOps ops)
1.89      frystyk  1110: {
                   1111:     static char stat[RESPONSE_LENGTH];
                   1112:     static int iStat = 0;
                   1113:     static int ignoreNext = 0;
                   1114:     int iBuf;
                   1115:     for (iBuf = 0; iBuf < len; iBuf++) {
                   1116:        switch (buf[iBuf]) {
                   1117:            case '\r':
                   1118:            case '\n':
                   1119:                if (ignoreNext)
                   1120:                    ignoreNext = 0;
                   1121:                else {
                   1122:                    int ret;
                   1123:                    stat[iStat] = 0;
                   1124:                    iStat = 0;
                   1125:                    if ((ret = parse_command(stat, 0, 0, 0)) != HT_OK)
                   1126:                        return (ret);
                   1127:                }
                   1128:                break;
                   1129:            case '\b':
1.96      frystyk  1130:                if (iStat) /* don't worry about ignoreNext as iStat will be 0*/
1.89      frystyk  1131:                    iStat--;
                   1132:                break;
                   1133:            default:
                   1134:                if (!ignoreNext)
                   1135:                    stat[iStat++] = buf[iBuf];
                   1136:        }
                   1137:        if (iStat == sizeof(stat)) {
                   1138:            TTYPrint(OUTPUT, "Read Console... BUFFER OVERRUN\n");
                   1139:            iStat = 0;
                   1140:            ignoreNext = 1;
                   1141:        }
                   1142:     }
                   1143:     return (HT_OK);
                   1144: }
                   1145: 
                   1146: PRIVATE int scan_command (SOCKET s, HTRequest * req, SockOps ops)
                   1147: {
1.91      frystyk  1148:     /* buf happens to == eatText's buffer but not neccesary */
                   1149:     static char buf[RESPONSE_LENGTH];
1.89      frystyk  1150:     int red;
                   1151:     int ret;
1.91      frystyk  1152: 
                   1153: #ifndef _CONSOLE
1.89      frystyk  1154:     if (!fgets(buf, sizeof(buf), stdin))                 /* Read User Input */
                   1155:        return HT_ERROR;                                      /* Exit if EOF */
                   1156:     return (parse_command(buf, s, req, ops));
1.91      frystyk  1157: #else
                   1158: 
1.89      frystyk  1159:     while(1) {
                   1160: #ifdef _CONSOLE
                   1161:        if (!readConsole((HANDLE)s, buf, sizeof(buf), &red)) {
1.96      frystyk  1162:            if (PROT_TRACE) TTYPrint(TDEST, "Read Console... READ ERROR\n");
1.89      frystyk  1163:            return HT_ERROR;
                   1164:        }
                   1165: #else  /* _CONSOLE */
                   1166:        if ((red = read(s, buf, sizeof(buf))) < 0) {
                   1167: #ifdef EAGAIN
                   1168:            if (socerrno==EINPROGRESS || socerrno==EAGAIN)
                   1169: #else
                   1170:            if (socerrno==EINPROGRESS)
                   1171: #endif
                   1172:                return (HT_OK);
1.96      frystyk  1173:            if (PROT_TRACE) TTYPrint(TDEST, "Read Console... READ ERROR\n");
1.89      frystyk  1174:            return HT_ERROR;
                   1175:        }
                   1176: #endif /* _CONSOLE */
1.96      frystyk  1177:        if (!red) return (HT_OK);
1.89      frystyk  1178:        ret = bufferInput(buf, red, s, req, ops);
1.96      frystyk  1179:        if (ret != HT_OK) return (ret);
1.89      frystyk  1180:     }
1.91      frystyk  1181: #endif
1.89      frystyk  1182: }
1.40      frystyk  1183: 
1.76      frystyk  1184: /*     terminate_handler
                   1185: **     -----------------
1.96      frystyk  1186: **     This function is registered to handle the result of the request
1.1       timbl    1187: */
1.76      frystyk  1188: PRIVATE int terminate_handler (HTRequest * request, int status) 
1.40      frystyk  1189: {
1.96      frystyk  1190:     Context * context = (Context *) HTRequest_context(request);
                   1191:     LineMode * lm = context->lm;
1.40      frystyk  1192:     BOOL is_index = HTAnchor_isIndex(HTMainAnchor);
                   1193:     if (status == HT_LOADED) {
1.96      frystyk  1194: 
                   1195:        if (HTAlert_interactive()) {
                   1196:            HText_setStale(HTMainText);
                   1197:            MakeCommandLine(lm, is_index);
                   1198:        } else {
                   1199:            if (lm->flags & LM_REFS) Reference_List(lm, NO);
                   1200:            Cleanup(lm, 0);
                   1201:        }
1.69      frystyk  1202: 
                   1203:        /* Record new history if we have not moved around in the old one */
1.96      frystyk  1204:        if (context->state & LM_UPDATE)
                   1205:            HTHistory_replace(lm->history, (HTAnchor *) HTMainAnchor);
1.69      frystyk  1206: 
1.40      frystyk  1207:        /* Now generate the new prompt line as a function of the result */
                   1208:        if (!HText_canScrollDown(HTMainText) &&
                   1209:            !HTAnchor_hasChildren(HTMainAnchor) && !is_index &&
1.96      frystyk  1210:            (!HTHistory_canBacktrack(lm->history))) {
1.91      frystyk  1211:            return HT_OK;
1.40      frystyk  1212:        }
1.96      frystyk  1213: 
1.76      frystyk  1214:     }
1.96      frystyk  1215:     context->state |= LM_DONE;
                   1216:     Thread_cleanup(lm);
                   1217:     if (!HTAlert_interactive()) Cleanup(lm, -1);
1.76      frystyk  1218:     return HT_OK;
1.40      frystyk  1219: }
1.1       timbl    1220: 
1.81      frystyk  1221: /*     timeout_handler
                   1222: **     ---------------
1.96      frystyk  1223: **     This function is registered to handle timeout in select eventloop
1.81      frystyk  1224: */
                   1225: PRIVATE int timeout_handler (HTRequest * request)
                   1226: {
1.96      frystyk  1227:     if (!HTAlert_interactive()) {
                   1228:        Context * context = (Context *) HTRequest_context(request);
                   1229:        LineMode * lm = context->lm;
                   1230:        HTNet_killAll();
                   1231:        Cleanup(lm, -1);
                   1232:     }
1.89      frystyk  1233:     if (SHOW_MSG) TTYPrint(TDEST, ".");
1.81      frystyk  1234:     return 0;
                   1235: }
                   1236: 
1.96      frystyk  1237: /*     header_handler
                   1238: **     ---------------
                   1239: **     This function is registered to handle unknown MIME headers
                   1240: */
                   1241: PRIVATE int header_handler (HTRequest * request, CONST char * token)
                   1242: {
                   1243:     if (SHOW_MSG) TTYPrint(TDEST, "Parsing unknown header `%s\'\n", token);
                   1244:     return HT_OK;
                   1245: }
                   1246: 
1.40      frystyk  1247: /* ------------------------------------------------------------------------- */
                   1248: /*                               MAIN PROGRAM                               */
                   1249: /* ------------------------------------------------------------------------- */
1.1       timbl    1250: 
1.90      frystyk  1251: int main (int argc, char ** argv)
1.40      frystyk  1252: {
1.68      frystyk  1253:     int                status = 0;     
                   1254:     int                arg;                                      /* Index into argv */
                   1255:     HTChunk *  keywords = NULL;                        /* From command line */
                   1256:     int                keycnt = 0;
1.101     frystyk  1257:     LineMode * lm;
1.85      frystyk  1258: 
1.96      frystyk  1259:     /* Starts Mac GUSI socket library */
                   1260: #ifdef GUSI
1.75      frystyk  1261:     GUSISetup(GUSIwithSIOUXSockets);
                   1262:     GUSISetup(GUSIwithInternetSockets);
                   1263: #endif
                   1264: 
                   1265: #ifdef __MWERKS__ /* STR */
                   1266:     InitGraf((Ptr) &qd.thePort); 
                   1267:     InitFonts(); 
                   1268:     InitWindows(); 
                   1269:     InitMenus(); TEInit(); 
                   1270:     InitDialogs(nil); 
                   1271:     InitCursor();
                   1272:     SIOUXSettings.asktosaveonclose = false;
                   1273:     argc=ccommand(&argv);
                   1274: #endif
                   1275: 
1.68      frystyk  1276:     /* HWL 18/7/94: patch from agl@glas2.glas.apc.org (Anton Tropashko) */
1.40      frystyk  1277: #ifdef CYRILLIC
                   1278:     arc.locale=0; arc.encoding=0; arc.i_encoding=0; doinull();
1.1       timbl    1279: #endif
                   1280: 
1.96      frystyk  1281:     /* Initiate W3C Reference Library */
                   1282:     HTLibInit(APP_NAME, APP_VERSION);
1.101     frystyk  1283:     lm = LineMode_new();
1.96      frystyk  1284: 
                   1285:     /* Initialize the protocol modules */
                   1286:     HTAccessInit();
                   1287: 
                   1288:     /* Initialize set of converters */
                   1289:     lm->converters = HTList_new();
                   1290:     HTConverterInit(lm->converters);
                   1291:     HTFormat_setConversion(lm->converters);
                   1292: 
                   1293:     /* Initialize bindings between file suffixes and media types */
                   1294:     HTFileInit();
                   1295: 
                   1296:     /* Set up default set of icons */
                   1297:     HTStdIconInit(NULL);
                   1298: 
                   1299:     /* Get any proxy or gateway environment variables */
                   1300:     HTProxy_getEnvVar();
                   1301: 
                   1302:     /* Scan command Line for parameters */
                   1303:     for (arg=1; arg<argc ; arg++) {
1.40      frystyk  1304:        if (*argv[arg] == '-') {
                   1305: 
                   1306:            /* - alone => filter */
1.96      frystyk  1307:            if (argv[arg][1] == '\0') {
                   1308:                lm->flags |= LM_FILTER;
1.94      frystyk  1309:                HTAlert_setInteractive(NO);
1.40      frystyk  1310:            
1.96      frystyk  1311:            /* non-interactive */
                   1312:            } else if (!strcmp(argv[arg], "-n")) {
                   1313:                HTAlert_setInteractive(NO);
1.40      frystyk  1314: 
                   1315:            /* from -- Initial represntation (only with filter) */
1.96      frystyk  1316:            } else if (!strcmp(argv[arg], "-from")) {
                   1317:                lm->format = (arg+1 < argc && *argv[arg+1] != '-') ?
                   1318:                    HTAtom_for(argv[++arg]) : WWW_HTML;
                   1319:                HTAlert_setInteractive(NO);
1.40      frystyk  1320: 
1.96      frystyk  1321:            /* to -- Final representation */
                   1322:            } else if (!strcmp(argv[arg], "-to")) {
                   1323:                HTFormat format = (arg+1 < argc && *argv[arg+1] != '-') ?
                   1324:                    HTAtom_for(argv[++arg]) : DEFAULT_FORMAT;
                   1325:                HTRequest_setOutputFormat(lm->request, format);
                   1326:                HTAlert_setInteractive(NO);
                   1327: 
                   1328:            /* reformat html */
                   1329:            } else if (!strcmp(argv[arg], "-reformat")) {
                   1330:                HTRequest_setOutputFormat(lm->request, WWW_HTML);
                   1331:                lm->flags |= LM_REFORMAT;
                   1332:                HTAlert_setInteractive(NO);
                   1333: 
                   1334:            /* List References */
                   1335:            } else if (!strncmp(argv[arg], "-list", 5)) {
                   1336:                lm->flags |= LM_REFS;
                   1337:                HTAlert_setInteractive(NO);
                   1338: 
1.100     frystyk  1339:            /* original output */
1.96      frystyk  1340:            } else if (!strcmp(argv[arg], "-raw")) {
                   1341:                HTRequest_setOutputFormat(lm->request, WWW_RAW);
                   1342:                HTAlert_setInteractive(NO);
                   1343: 
                   1344:            /* source please */
                   1345:            } else if (!strcmp(argv[arg], "-source")) {
                   1346:                HTRequest_setOutputFormat(lm->request, WWW_SOURCE);
                   1347:                HTAlert_setInteractive(NO);
                   1348: 
                   1349:            /* HEAD method */
                   1350:            } else if (!strcasecomp(argv[arg], "-head")) {
                   1351:                HTRequest_setMethod(lm->request, METHOD_HEAD);
                   1352:                HTRequest_setOutputFormat(lm->request, WWW_MIME);
                   1353:                HTAlert_setInteractive(NO);
                   1354: 
1.100     frystyk  1355:            /* output filename */
1.96      frystyk  1356:            } else if (!strcmp(argv[arg], "-o")) { 
                   1357:                lm->outputfile = (arg+1 < argc && *argv[arg+1] != '-') ?
                   1358:                    argv[++arg] : DEFAULT_OUTPUT_FILE;
                   1359:                HTAlert_setInteractive(NO);
                   1360: 
                   1361:            /* print version and exit */
                   1362:            } else if (!strcmp(argv[arg], "-version")) { 
                   1363:                VersionInfo();
                   1364:                Cleanup(lm, 0);
                   1365: 
                   1366:            /* -? or -help: show the command line help page */
                   1367:            } else if (!strcmp(argv[arg],"-?") || !strcmp(argv[arg],"-help")) {
                   1368:                lm->anchor = (HTParentAnchor *) HTAnchor_findAddress(L_HELP);
                   1369:                keycnt = 1;
1.40      frystyk  1370: 
                   1371: #ifdef CYRILLIC
                   1372:            /* HWL 18/7/94: applied patch from agl@glas2.glas.apc.org
                   1373:               (Anton Tropashko) */
                   1374:            } else if (!strcmp(argv[arg], "-koi2alt")) {
1.89      frystyk  1375:                doia2k(); TTYPrint(OUTPUT, "Ahak2a!");
1.40      frystyk  1376: #endif
                   1377: 
                   1378:            /* Page size */
                   1379:            } else if (!strncmp(argv[arg], "-p", 2)) {
                   1380:                if (*(argv[arg]+2)) {
                   1381:                    if (sscanf(argv[arg]+2, "%d", &HTScreenHeight) < 1)
                   1382:                        HTScreenHeight = -1;            
                   1383:                    else {
                   1384:                        if(HTScreenHeight < MIN_SCREEN_HEIGHT)
                   1385:                            HTScreenHeight = MIN_SCREEN_HEIGHT;
                   1386:                        if(HTScreenHeight > MAX_SCREEN_HEIGHT)
                   1387:                            HTScreenHeight = MAX_SCREEN_HEIGHT;
                   1388:                    }
                   1389:                } else if (arg+1 < argc && *argv[arg+1] != '-') {
                   1390:                    if (sscanf(argv[++arg], "%d", &HTScreenHeight) < 1)
                   1391:                        HTScreenHeight = -1;
                   1392:                    else {
                   1393:                        if(HTScreenHeight < MIN_SCREEN_HEIGHT)
                   1394:                            HTScreenHeight = MIN_SCREEN_HEIGHT;
                   1395:                        if(HTScreenHeight > MAX_SCREEN_HEIGHT)
                   1396:                            HTScreenHeight = MAX_SCREEN_HEIGHT;
                   1397:                    }
                   1398:                }
1.1       timbl    1399: 
1.40      frystyk  1400:            /* Page width */
                   1401:            } else if (!strncmp(argv[arg], "-w", 2)) {
                   1402:                if (*(argv[arg]+2)) {
                   1403:                    if (sscanf(argv[arg]+2, "%d", &HTScreenWidth) < 1)
                   1404:                        HTScreenWidth = SCREEN_WIDTH;
                   1405:                } else if (arg+1 < argc && *argv[arg+1] != '-') {
                   1406:                    if (sscanf(argv[++arg], "%d", &HTScreenWidth) < 1)
                   1407:                        HTScreenWidth = SCREEN_WIDTH;
1.14      frystyk  1408:                }
1.40      frystyk  1409:                if(HTScreenWidth < MIN_SCREEN_WIDTH)
                   1410:                    HTScreenWidth = MIN_SCREEN_WIDTH;
                   1411:                if(HTScreenWidth > MAX_SCREEN_WIDTH)
                   1412:                    HTScreenWidth = MAX_SCREEN_WIDTH;
                   1413:                    
                   1414:            /* Telnet from */
                   1415:            } else if (!strcmp(argv[arg], "-h")) {
                   1416:                if (arg+1 < argc && *argv[arg+1] != '-') {
1.96      frystyk  1417:                    lm->host = argv[++arg];                 /* Use host name */
1.92      frystyk  1418:                    HTLib_setSecure(YES);                  /* No easy access */
1.14      frystyk  1419:                }
1.40      frystyk  1420: 
1.96      frystyk  1421:            /* log file */
1.40      frystyk  1422:            } else if (!strcmp(argv[arg], "-l")) {
1.96      frystyk  1423:                lm->logfile = (arg+1 < argc && *argv[arg+1] != '-') ?
1.68      frystyk  1424:                    argv[++arg] : DEFAULT_LOG_FILE;
1.51      frystyk  1425: 
1.96      frystyk  1426:            /* rule file */
                   1427:            } else if (!strcmp(argv[arg], "-r")) {
                   1428:                lm->rules = (arg+1 < argc && *argv[arg+1] != '-') ?
                   1429:                    argv[++arg] : DEFAULT_RULE_FILE;
1.68      frystyk  1430: 
1.96      frystyk  1431:            /* timeout -- Change the default request timeout */
                   1432:            } else if (!strcmp(argv[arg], "-timeout")) {
                   1433:                int timeout = (arg+1 < argc && *argv[arg+1] != '-') ?
                   1434:                    atoi(argv[++arg]) : -1;
                   1435:                if (timeout > 0) lm->tv->tv_sec = timeout;
1.40      frystyk  1436: 
1.96      frystyk  1437:            /* preemtive or non-preemtive access */
1.50      frystyk  1438:            } else if (!strcmp(argv[arg], "-single")) {
1.96      frystyk  1439:                HTRequest_setPreemtive(lm->request, YES);
                   1440:                lm->flags |= LM_PREEMTIVE;
1.50      frystyk  1441: 
1.96      frystyk  1442:            /* Specify a cache root (caching is otherwise disabled) */
                   1443:            } else if (!strcmp(argv[arg], "-cacheroot")) {
                   1444:                HTCache_enable((arg+1>=argc || *argv[arg+1]=='-') ?
                   1445:                               NULL : argv[++arg]);
1.68      frystyk  1446: 
1.96      frystyk  1447:            /* Handling of Expire (cache) */
1.68      frystyk  1448:            } else if (!strncmp(argv[arg], "-x", 2)) { 
                   1449:                char *p = argv[arg]+2;
                   1450:                for(;*p;p++) {
                   1451:                    switch (argv[arg][2]) {
                   1452:                      case 'i':
1.76      frystyk  1453:                        HTCache_setExpiresMode(HT_EXPIRES_IGNORE, NULL);
1.68      frystyk  1454:                        break;
                   1455:                      case 'n':
1.76      frystyk  1456:                        HTCache_setExpiresMode(HT_EXPIRES_NOTIFY, "Document has expired, but I show it anyway");
1.68      frystyk  1457:                        break;
                   1458:                      case 'a':
1.76      frystyk  1459:                        HTCache_setExpiresMode(HT_EXPIRES_AUTO, NULL);
1.68      frystyk  1460:                        break;
                   1461:                      default:
                   1462:                        if (SHOW_MSG)
1.89      frystyk  1463:                            TTYPrint(TDEST, "Bad parameter (%s) for option -x\n", argv[arg]);
1.68      frystyk  1464:                        break;
                   1465:                    }
                   1466:                }
                   1467: 
1.40      frystyk  1468:            /* Anchor format */
                   1469:            } else if (!strcmp(argv[arg], "-a")) { 
                   1470:                if (arg+1 < argc && *argv[arg+1] != '-')
                   1471:                    end_reference = argv[++arg];      /* New representation */
                   1472: 
                   1473:            /* Anchor format */
                   1474:            } else if (!strcmp(argv[arg], "-ar")) { 
                   1475:                if (arg+1 < argc && *argv[arg+1] != '-')
                   1476:                    reference_mark = argv[++arg];  /* Change representation */
                   1477: 
                   1478:            /* Anchor format */
                   1479:            } else if (!strcmp(argv[arg], "-as")) { 
                   1480:                if (arg+1 < argc && *argv[arg+1] != '-')
                   1481:                    start_reference = argv[++arg]; /* Change representation */
                   1482: 
                   1483:            /* No anchors */
                   1484:            } else if (!strcmp(argv[arg], "-na")) { 
                   1485:                    display_anchors = NO;
                   1486: 
                   1487: #ifndef NO_DIR_OPTIONS
                   1488:            } else if (!strncmp(argv[arg], "-d", 2)) {
                   1489:                char *p = argv[arg]+2;
                   1490:                for(;*p;p++) {
                   1491:                    switch (argv[arg][2]) {
1.82      frystyk  1492:                      case 'r':HTFile_setDirReadme(HT_DIR_README_NONE); break;
                   1493:                      case 't':HTFile_setDirReadme(HT_DIR_README_TOP); break;
                   1494:                      case 'b':HTFile_setDirReadme(HT_DIR_README_BOTTOM);break;
                   1495:                      case 'n':HTFile_setDirAccess(HT_DIR_FORBID); break;
                   1496:                      case 's':HTFile_setDirAccess(HT_DIR_SELECTIVE); break;
                   1497:                      case 'y':HTFile_setDirAccess(HT_DIR_OK); break;
1.76      frystyk  1498:                      default:
1.68      frystyk  1499:                        if (SHOW_MSG)
1.96      frystyk  1500:                            TTYPrint(TDEST,"Bad parameter (%s) in -d option\n",
1.68      frystyk  1501:                                    argv[arg]);
1.40      frystyk  1502:                    }
1.96      frystyk  1503:                }
1.40      frystyk  1504: #endif
1.1       timbl    1505: 
1.85      frystyk  1506: #ifdef WWWTRACE
1.96      frystyk  1507:            /* trace flags */
1.40      frystyk  1508:            } else if (!strncmp(argv[arg], "-v", 2)) {
                   1509:                char *p = argv[arg]+2;
1.93      frystyk  1510:                WWWTRACE = 0;
1.40      frystyk  1511:                for(; *p; p++) {
                   1512:                    switch (*p) {
1.93      frystyk  1513:                      case 'a': WWWTRACE |= SHOW_ANCHOR_TRACE; break;
                   1514:                      case 'b': WWWTRACE |= SHOW_BIND_TRACE; break;
                   1515:                      case 'c': WWWTRACE |= SHOW_CACHE_TRACE; break;
                   1516:                      case 'g': WWWTRACE |= SHOW_SGML_TRACE; break;
                   1517:                      case 'p': WWWTRACE |= SHOW_PROTOCOL_TRACE; break;
                   1518:                      case 's': WWWTRACE |= SHOW_STREAM_TRACE; break;
                   1519:                      case 't': WWWTRACE |= SHOW_THREAD_TRACE; break;
                   1520:                      case 'u': WWWTRACE |= SHOW_URI_TRACE; break;
1.40      frystyk  1521:                      default:
1.68      frystyk  1522:                        if (SHOW_MSG)
1.96      frystyk  1523:                            TTYPrint(TDEST,"Bad parameter (%s) in -v option\n",
1.76      frystyk  1524:                                    argv[arg]);
1.40      frystyk  1525:                    }
1.96      frystyk  1526:                }
                   1527:                if (!WWWTRACE) WWWTRACE = SHOW_ALL_TRACE;
                   1528:                lm->trace = WWWTRACE;                    /* Remember setting */
1.1       timbl    1529: #endif
1.14      frystyk  1530:            
1.40      frystyk  1531:            } else {
1.96      frystyk  1532:                if (SHOW_MSG) TTYPrint(TDEST,"Bad Argument (%s)\n", argv[arg]);
1.40      frystyk  1533:            }
                   1534:        } else {           /* If no leading `-' then check for main argument */
1.68      frystyk  1535:            if (!keycnt) {
1.96      frystyk  1536:                char * ref = HTParse(argv[arg], lm->cwd, PARSE_ALL);
                   1537:                lm->anchor = (HTParentAnchor *) HTAnchor_findAddress(ref);
1.79      frystyk  1538:                keycnt = 1;
1.96      frystyk  1539:                FREE(ref);
1.40      frystyk  1540:            } else {               /* Check for successive keyword arguments */
1.79      frystyk  1541:                char *escaped = HTEscape(argv[arg], URL_XALPHAS);
1.68      frystyk  1542:                if (keycnt++ <= 1)
                   1543:                    keywords = HTChunkCreate(128);
                   1544:                else
                   1545:                    HTChunkPutc(keywords, ' ');
1.79      frystyk  1546:                HTChunkPuts(keywords, HTStrip(escaped));
                   1547:                free(escaped);
1.68      frystyk  1548:            }
1.79      frystyk  1549:        }
                   1550:     }
1.40      frystyk  1551: 
1.96      frystyk  1552: #ifdef CATCH_SIG
                   1553:     SetSignal();
                   1554: #endif
                   1555: 
                   1556:     /* Make home page address */
                   1557:     if (!lm->anchor) lm->anchor = HTHomeAnchor();
                   1558: 
                   1559:     /* Do we need list of presenters? */
1.94      frystyk  1560:     if (HTAlert_interactive()) {
1.96      frystyk  1561:        lm->presenters = HTList_new();
                   1562:        HTPresenterInit(lm->presenters);
                   1563:        HTRequest_setConversion(lm->request, lm->presenters, NO);
1.86      frystyk  1564:     }
                   1565: 
1.40      frystyk  1566:     if (HTScreenHeight == -1) {                                /* Default page size */
1.94      frystyk  1567:        if (HTAlert_interactive()) {
1.40      frystyk  1568: #ifdef GET_SCREEN_SIZE
                   1569:            int scr_height, scr_width;
                   1570:            scrsize(&scr_height, &scr_width);
                   1571:            HTScreenHeight = scr_height;
                   1572: #else
1.42      frystyk  1573:            HTScreenHeight = SCREEN_HEIGHT;
1.1       timbl    1574: #endif
1.40      frystyk  1575:        } else
1.42      frystyk  1576:            HTScreenHeight = 999999;
1.40      frystyk  1577:     }
1.23      frystyk  1578: 
1.68      frystyk  1579:     /* Disable free directory browsing when using telnet host */
1.96      frystyk  1580:     if (lm->host && HTFile_dirAccess() == HT_DIR_OK)
1.82      frystyk  1581:        HTFile_setDirAccess(HT_DIR_SELECTIVE);
1.1       timbl    1582: 
1.96      frystyk  1583:     /* Rule file specified? */
                   1584:     if (lm->rules) {
                   1585:        HTList * list = HTList_new();
                   1586:        HTRequest * rr = Thread_new(lm, NO);
                   1587:        char * rules = HTParse(lm->rules, lm->cwd, PARSE_ALL);
                   1588:        HTParentAnchor * ra = (HTParentAnchor *) HTAnchor_findAddress(rules);
                   1589:        HTRequest_setPreemtive(rr, YES);
                   1590:        HTConversion_add(list, "application/x-www-rules", "*/*", HTRules,
                   1591:                         1.0, 0.0, 0.0);
                   1592:        HTRequest_setConversion(rr, list, YES);
                   1593:        if (HTLoadAnchor((HTAnchor *) ra, rr) != YES)
                   1594:            if (SHOW_MSG) TTYPrint(TDEST, "Can't access rules\n");
                   1595:        HTConversion_deleteAll(list);
                   1596:        HTRequest_delete(rr);
                   1597:        FREE(rules);
1.40      frystyk  1598:     }
1.1       timbl    1599: 
1.40      frystyk  1600:     /* Open output file */
1.94      frystyk  1601:     if (!HTAlert_interactive()) {
1.99      frystyk  1602: #ifndef _WINDOWS
1.96      frystyk  1603:        if (lm->outputfile) {
1.99      frystyk  1604:            if ((OUTPUT = fopen(lm->outputfile, "wb")) == NULL) {
1.96      frystyk  1605:                if (SHOW_MSG) TTYPrint(TDEST, "Can't open `%s'\\n",
                   1606:                                       lm->outputfile);
1.100     frystyk  1607:                OUTPUT = STDOUT;
1.96      frystyk  1608:            }
                   1609:        }
1.99      frystyk  1610:        HTRequest_setOutputStream(lm->request, HTFWriter_new(OUTPUT, YES));
                   1611: #endif
1.58      frystyk  1612: 
1.96      frystyk  1613:        /*
                   1614:        ** To reformat HTML, just put it through a parser running
1.68      frystyk  1615:        ** into a regenerator   tbl 940613
                   1616:        */
1.96      frystyk  1617:        if (lm->flags & LM_REFORMAT) {
                   1618:            HTStructured * html =
                   1619:                HTMLGenerator(lm->request, NULL, WWW_HTML,
                   1620:                              HTRequest_outputFormat(lm->request),
                   1621:                              HTRequest_outputStream(lm->request));
                   1622:            HTRequest_setOutputStream(lm->request, SGML_new(&HTMLP_dtd, html));
1.40      frystyk  1623:        }
                   1624:     }
                   1625:     
1.96      frystyk  1626:      /* Log file specifed? */
                   1627:     if (lm->logfile) HTLog_open(lm->logfile, YES, YES);
1.1       timbl    1628: 
1.68      frystyk  1629:     /* Just convert formats */
1.96      frystyk  1630:     if (lm->flags & LM_FILTER) {
                   1631: #ifdef STDIN_FILENO
                   1632:        HTRequest_setAnchor(lm->request, (HTAnchor *) lm->anchor);
                   1633:        HTRequest_setPreemtive(lm->request, YES);
                   1634:        HTLoadSocket(STDIN_FILENO, lm->request, FD_NONE);
1.95      frystyk  1635: #endif
1.96      frystyk  1636:        Cleanup(lm, 0);
1.40      frystyk  1637:     }
1.96      frystyk  1638: 
1.94      frystyk  1639:     /* Register our User Prompts etc in the Alert Manager */
1.102     frystyk  1640:     if (HTAlert_interactive()) {
                   1641:        HTAlert_add(HTError_print, HT_A_MESSAGE);
                   1642:        HTAlert_add(HTConfirm, HT_A_CONFIRM);
                   1643:        HTAlert_add(HTPrompt, HT_A_PROMPT);
                   1644:        HTAlert_add(HTPromptPassword, HT_A_SECRET);
                   1645:        HTAlert_add(HTPromptUsernameAndPassword, HT_A_USER_PW);
                   1646:     }
1.94      frystyk  1647: 
1.76      frystyk  1648:     /* Register a call back function for the Net Manager */
1.96      frystyk  1649:     HTNetInit();
                   1650:     HTNetCall_addAfter(terminate_handler, HT_ALL);
                   1651: 
                   1652:     /* Register our own MIME header handler for extra headers */
                   1653:     HTHeader_addParser("*", NO, header_handler);
                   1654: 
                   1655:     /* Set timeout on sockets */
                   1656:     if (lm->tv->tv_sec < 0) {
                   1657:        lm->tv->tv_sec = HTAlert_interactive() ?
                   1658:            DEFAULT_I_TIMEOUT : DEFAULT_NI_TIMEOUT;
1.93      frystyk  1659:     }
1.96      frystyk  1660:     HTEvent_registerTimeout(lm->tv, lm->request, timeout_handler, NO);
                   1661: 
                   1662:     /* Set max number of sockets we want open simultanously */
                   1663:     HTNet_setMaxSocket(6);
                   1664: 
                   1665:     /* Set the DNS cache timeout */
                   1666:     HTDNS_setTimeout(3600);
                   1667: 
                   1668:     /* Start the request */
                   1669:     if (keywords)
                   1670:        status = HTSearch(HTChunkData(keywords), lm->anchor, lm->request);
                   1671:     else
                   1672:        status = HTLoadAnchor((HTAnchor *) lm->anchor, lm->request);
                   1673: 
                   1674:     if (keywords) HTChunkFree(keywords);
                   1675:     if (status != YES) {
                   1676:        if (SHOW_MSG) TTYPrint(TDEST, "Couldn't load home page\n");
                   1677:        Cleanup(lm, -1);
1.76      frystyk  1678:     }
1.68      frystyk  1679: 
1.96      frystyk  1680:     /* Set up the rest if we are in interactive mode */
1.94      frystyk  1681:     if (HTAlert_interactive()) {
1.73      frystyk  1682: 
1.96      frystyk  1683:        /* Start History manager */
                   1684:        lm->history = HTHistory_new();
1.73      frystyk  1685: 
                   1686:        /* Register our own memory cache handler (implemented in GridText.c) */
                   1687:        HTMemoryCache_register(HTMemoryCache);
                   1688: 
1.83      frystyk  1689:        /*
                   1690:        ** Register STDIN as the user socket IF not STDIN is connected to
                   1691:        ** /dev/null or other non-terminal devices
                   1692:        */
1.82      frystyk  1693: #ifdef STDIN_FILENO
1.83      frystyk  1694:        if (isatty(STDIN_FILENO)) {
1.98      frystyk  1695:            HTEvent_RegisterTTY(STDIN_FILENO, lm->tty, (SockOps)FD_READ,
1.97      frystyk  1696:                                scan_command, HT_PRIORITY_MAX);
1.83      frystyk  1697:        }
1.82      frystyk  1698: #else
1.101     frystyk  1699:        HTEvent_RegisterTTY(0, lm->tty, (SockOps)FD_READ, scan_command, 1);
1.82      frystyk  1700: #endif
1.96      frystyk  1701:     }
1.77      frystyk  1702: 
1.96      frystyk  1703:     /* Go into the event loop... */
                   1704:     HTEvent_Loop(lm->request);
1.73      frystyk  1705: 
1.96      frystyk  1706:     /* Only gets here if event loop fails */
                   1707:     Cleanup(lm, 0);
                   1708:     return 0;
1.14      frystyk  1709: }

Webmaster