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