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

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

Webmaster