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

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

Webmaster