/* ** Remove a conversion routine from the presentation list. ** The conversion routine must match up with the given args. */ PUBLIC void HTRemoveConversion ARGS3( WWW_CONST char *, representation_in, WWW_CONST char *, representation_out, HTConverter*, converter ){ int numberOfPresentations; HTPresentation * pres; HTAtom *rep_in, *rep_out; int x; numberOfPresentations = HTList_count(HTPresentations); rep_in = HTAtom_for(representation_in); rep_out = HTAtom_for(representation_out); for (x = 0; x < numberOfPresentations; x++) { pres = HTList_objectAt(HTPresentations, x); if (pres) { if ((!strcmp(pres->rep->name,rep_in->name)) && (!strcmp(pres->rep_out->name,rep_out->name)) && (pres->converter == converter)) { HTList_removeObject(HTPresentations,pres); } } } }
HTAnchor * HTHistory_recall ARGS1 (int,number) { HTAnchor * destination = HTList_objectAt (history, HTList_count (history) - number); if (destination && destination != HTList_lastObject (history)) HTList_addObject (history, destination); return destination; }
PUBLIC HText * LMHText_new ( HTRequest * request, HTParentAnchor * anchor, HTStream *outstrm) { HTLine * line; HText * self; if ((self = (HText *) HT_CALLOC(1, sizeof(*self))) == NULL) /* HT_OUTOFMEM("HText"); */ return self; self->pLm = Context_getLineMode(request); if (!loaded_texts) loaded_texts = HTList_new(); HTList_addObject(loaded_texts, self); if (HTList_count(loaded_texts) >= LOADED_LIMIT) { HTTRACE(CACHE_TRACE, "MemoryCache. Freeing off cached doc.\n"); HText_free((HText *)HTList_removeFirstObject(loaded_texts)); } if ((line = self->last_line = (HTLine *) HT_MALLOC(LINE_SIZE(MAX_LINE))) == NULL) HT_OUTOFMEM("HText_New"); line->next = line->prev = line; line->offset = line->size = 0; self->lines = self->chars = 0; self->title = 0; self->first_anchor = self->last_anchor = self->current_anchor = 0; self->style = &default_style; self->top_of_screen = 0; self->node_anchor = anchor; self->last_anchor_number = 0; /* Numbering of them for references */ self->stale = YES; self->target = NULL; HTAnchor_setDocument(anchor, (void *) self); clear_screen(); HTMainText = self; HTMainAnchor = anchor; self->display_on_the_fly = DISPLAY_LINES; self->all_pages = NO; /* One page at a time on the fly */ if (!space_string) { /* Make a blank line */ char *p; if ((space_string = (char *) HT_MALLOC(HTScreenWidth+1)) == NULL) HT_OUTOFMEM("HText_New"); for (p=space_string; p<space_string+HTScreenWidth; p++) *p = ' '; /* Used for printfs later */ space_string[HTScreenWidth] = '\0'; } return self; }
/* Determine a suitable suffix, given the representation ** ----------------------------------------------------- ** ** On entry, ** rep is the atomized MIME style representation ** ** On exit, ** returns a pointer to a suitable suffix string if one has been ** found, else "". */ PUBLIC WWW_CONST char * HTFileSuffix ARGS1(HTAtom*, rep) { HTSuffix * suff; int n; int i; if (!HTSuffixes) HTFileInit(); n = HTList_count(HTSuffixes); for(i=0; i<n; i++) { suff = HTList_objectAt(HTSuffixes, i); if (suff->rep == rep) { return suff->suffix; /* OK -- found */ } } return ""; /* Dunno */ }
/* ** Here you can provide a complete list instead of a single token. ** The list has to be in the order the _encodings_ were applied - that ** is, the same way that _encodings_ are to be applied. This is all consistent ** with the order of the Content-Encoding header. */ PUBLIC HTStream * HTTransferDecodingStack (HTList * encodings, HTStream * target, HTRequest * request, void * param) { if (encodings) { HTEncoding pres; int cnt = HTList_count(encodings); HTStream * top = target; while (cnt > 0) { pres = (HTEncoding) HTList_objectAt(encodings, --cnt); top = HTTransferCodingStack(pres, top, request, param, NO); if (top == HTBlackHole()) break; } return top; } return HTErrorStream(); }
/* Find the cost of a filter stack ** ------------------------------- ** ** Must return the cost of the same stack which StreamStack would set up. ** ** On entry, ** length The size of the data to be converted */ PUBLIC float HTStackValue ARGS4( HTFormat, format_in, HTFormat, rep_out, float, initial_value, long int, length) { HTAtom * wildcard = HTAtom_for("*"); #ifndef DISABLE_TRACE if (www2Trace) fprintf(stderr, "HTFormat: Evaluating stream stack for %s worth %.3f to %s\n", HTAtom_name(format_in), initial_value, HTAtom_name(rep_out)); #endif if (rep_out == WWW_SOURCE || rep_out == format_in) return 0.0; if (!HTPresentations) HTFormatInit(); /* set up the list */ { int n = HTList_count(HTPresentations); int i; HTPresentation * pres; for(i=0; i<n; i++) { pres = HTList_objectAt(HTPresentations, i); if (pres->rep == format_in && ( pres->rep_out == rep_out || pres->rep_out == wildcard)) { float value = initial_value * pres->quality; if (HTMaxSecs != 0.0) value = value - (length*pres->secs_per_byte + pres->secs) /HTMaxSecs; return value; } } } return -1e30; /* Really bad */ }
/* Find the cost of a filter stack ** ------------------------------- ** ** Must return the cost of the same stack which StreamStack would set up. ** ** On entry, ** length The size of the data to be converted */ PUBLIC float HTStackValue ARGS4( HTFormat, rep_in, HTFormat, rep_out, float, initial_value, long int, length) { HTAtom * wildcard = WWW_WILDCARD_REP_OUT; CTRACE((tfp, "HTFormat: Evaluating stream stack for %s worth %.3f to %s\n", HTAtom_name(rep_in), initial_value, HTAtom_name(rep_out))); if (rep_out == WWW_SOURCE || rep_out == rep_in) return 0.0; /* don't do anymore do it in the Lynx code at startup LJM */ /* if (!HTPresentations) HTFormatInit(); */ /* set up the list */ { int n = HTList_count(HTPresentations); int i; HTPresentation * pres; for (i = 0; i < n; i++) { pres = (HTPresentation *)HTList_objectAt(HTPresentations, i); if (pres->rep == rep_in && (pres->rep_out == rep_out || pres->rep_out == wildcard)) { float value = initial_value * pres->quality; if (HTMaxSecs != 0.0) value = value - (length*pres->secs_per_byte + pres->secs) /HTMaxSecs; return value; } } } return (float) -1e30; /* Really bad */ }
PUBLIC float HTFileValue ARGS1 (WWW_CONST char *,filename) { HTSuffix * suff; int n; int i; int lf = strlen(filename); if (!HTSuffixes) HTFileInit(); n = HTList_count(HTSuffixes); for(i=0; i<n; i++) { int ls; suff = HTList_objectAt(HTSuffixes, i); ls = strlen(suff->suffix); if ((ls <= lf) && 0==strcmp(suff->suffix, filename + lf - ls)) { #ifndef DISABLE_TRACE if (www2Trace) fprintf(stderr, "File: Value of %s is %.3f\n", filename, suff->quality); #endif return suff->quality; /* OK -- found */ } } return 0.3; /* Dunno! */ }
/* Create a filter stack ** --------------------- ** ** If a wildcard match is made, a temporary HTPresentation ** structure is made to hold the destination format while the ** new stack is generated. This is just to pass the out format to ** MIME so far. Storing the format of a stream in the stream might ** be a lot neater. */ PUBLIC HTStream * HTStreamStack ARGS5( HTFormat, format_in, HTFormat, rep_out, int, compressed, HTStream*, sink, HTParentAnchor*, anchor) { HTAtom * wildcard = HTAtom_for("*"); HTPresentation temp; /* Inherit force_dump_to_file from mo-www.c. */ extern int force_dump_to_file; #ifndef DISABLE_TRACE if (www2Trace) fprintf(stderr, "[HTStreamStack] Constructing stream stack for %s to %s\n", HTAtom_name(format_in), HTAtom_name(rep_out)); #endif #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, " Compressed is %d\n", compressed); #endif if (rep_out == WWW_SOURCE || rep_out == format_in) { #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "[HTStreamStack] rep_out == WWW_SOURCE | rep_out == format_in; returning sink\n"); #endif return sink; } if (!HTPresentations) HTFormatInit(); /* set up the list */ if (force_dump_to_file && format_in != WWW_MIME) { return HTSaveAndExecute (NULL, anchor, sink, format_in, compressed); } { int n = HTList_count(HTPresentations); int i; HTPresentation * pres; for(i=0; i<n; i++) { pres = HTList_objectAt(HTPresentations, i); #ifndef DISABLE_TRACE if (www2Trace) { fprintf (stderr, "HTFormat: looking at pres '%s'\n", HTAtom_name (pres->rep)); if (pres->command) fprintf (stderr, "HTFormat: pres->command is '%s'\n", pres->command); else fprintf (stderr, "HTFormat: pres->command doesn't exist\n"); } #endif if (pres->rep == format_in || partial_wildcard_matches (pres->rep, format_in)) { if (pres->command && strstr (pres->command, "mosaic-internal-present")) { #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "[HTStreamStack] HEY HEY HEY caught internal-present\n"); #endif return HTPlainPresent (pres, anchor, sink, format_in, compressed); } if (pres->rep_out == rep_out) { #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "[HTStreamStack] pres->rep_out == rep_out\n"); #endif return (*pres->converter)(pres, anchor, sink, format_in, compressed); } if (pres->rep_out == wildcard) { #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "[HTStreamStack] pres->rep_out == wildcard\n"); #endif temp = *pres;/* make temp conversion to needed fmt */ temp.rep_out = rep_out; /* yuk */ return (*pres->converter)(&temp, anchor, sink, format_in, compressed); } } } } #ifndef DISABLE_TRACE if (www2Trace) { fprintf (stderr, "[HTStreamStack] Returning NULL at bottom.\n"); } #endif return NULL; }
void LYDownload(char *line) { char *Line = NULL, *method, *file, *sug_file = NULL; int method_number; int count; char *the_command = 0; bstring *buffer = NULL; bstring *command = NULL; char *cp; lynx_list_item_type *download_command = 0; int ch; RecallType recall; int FnameTotal; int FnameNum; BOOLEAN FirstRecall = TRUE; BOOLEAN SecondS = FALSE; #ifdef VMS LYDidRename = FALSE; #endif /* VMS */ /* * Make sure we have a valid download file comparison string loaded via the * download options menu. - FM */ if (LYValidDownloadFile[0] == '\0') { goto failed; } /* * Make a copy of the LYNXDOWNLOAD internal URL for parsing. - FM */ StrAllocCopy(Line, line); /* * Parse out the File, sug_file, and the Method. */ if ((file = strstr(Line, "/File=")) == NULL) goto failed; *file = '\0'; /* * Go past "File=". */ file += 6; if ((sug_file = strstr(file + 1, "/SugFile=")) != NULL) { *sug_file = '\0'; /* * Go past "SugFile=". */ sug_file += 9; HTUnEscape(sug_file); } /* * Make sure that the file string is the one from the last displayed * download options menu. - FM */ if (strcmp(file, LYValidDownloadFile)) { goto failed; } #if defined(DIRED_SUPPORT) /* FIXME: use HTLocalName */ if (!StrNCmp(file, "file://localhost", 16)) { #ifdef __DJGPP__ if (!StrNCmp(file + 16, "/dev/", 5)) file += 16; else { file += 17; file = HTDOS_name(file); } #else file += 16; #endif /* __DJGPP__ */ } else if (isFILE_URL(file)) file += LEN_FILE_URL; HTUnEscape(file); #else #if defined(_WINDOWS) /* 1997/10/15 (Wed) 16:27:38 */ if (!StrNCmp(file, "file://localhost/", 17)) file += 17; else if (!StrNCmp(file, "file:/", 6)) file += 6; HTUnEscape(file); #endif /* _WINDOWS */ #endif /* DIRED_SUPPORT */ if ((method = strstr(Line, "Method=")) == NULL) goto failed; /* * Go past "Method=". */ method += 7; method_number = atoi(method); /* * Set up the sug_filenames recall buffer. */ FnameTotal = (sug_filenames ? HTList_count(sug_filenames) : 0); recall = ((FnameTotal >= 1) ? RECALL_URL : NORECALL); FnameNum = FnameTotal; if (method_number < 0) { /* * Write to local file. */ _statusline(FILENAME_PROMPT); retry: if (sug_file) { BStrCopy0(buffer, sug_file); } else { BStrCopy0(buffer, ""); } check_recall: if ((ch = LYgetBString(&buffer, FALSE, 0, recall)) < 0 || isBEmpty(buffer) || ch == UPARROW_KEY || ch == DNARROW_KEY) { if (recall && ch == UPARROW_KEY) { if (FirstRecall) { FirstRecall = FALSE; /* * Use the last Fname in the list. - FM */ FnameNum = 0; } else { /* * Go back to the previous Fname in the list. - FM */ FnameNum++; } if (FnameNum >= FnameTotal) { /* * Reset the FirstRecall flag, and use sug_file or a blank. * - FM */ FirstRecall = TRUE; FnameNum = FnameTotal; _statusline(FILENAME_PROMPT); goto retry; } else if ((cp = (char *) HTList_objectAt(sug_filenames, FnameNum)) != NULL) { BStrCopy0(buffer, cp); if (FnameTotal == 1) { _statusline(EDIT_THE_PREV_FILENAME); } else { _statusline(EDIT_A_PREV_FILENAME); } goto check_recall; } } else if (recall && ch == DNARROW_KEY) { if (FirstRecall) { FirstRecall = FALSE; /* * Use the first Fname in the list. - FM */ FnameNum = FnameTotal - 1; } else { /* * Advance to the next Fname in the list. - FM */ FnameNum--; } if (FnameNum < 0) { /* * Set the FirstRecall flag, and use sug_file or a blank. * - FM */ FirstRecall = TRUE; FnameNum = FnameTotal; _statusline(FILENAME_PROMPT); goto retry; } else if ((cp = (char *) HTList_objectAt(sug_filenames, FnameNum)) != NULL) { BStrCopy0(buffer, cp); if (FnameTotal == 1) { _statusline(EDIT_THE_PREV_FILENAME); } else { _statusline(EDIT_A_PREV_FILENAME); } goto check_recall; } } /* * Save cancelled. */ goto cancelled; } BStrCopy(command, buffer); if (!LYValidateFilename(&buffer, &command)) goto cancelled; #ifdef HAVE_POPEN else if (LYIsPipeCommand(buffer->str)) { /* I don't know how to download to a pipe */ HTAlert(CANNOT_WRITE_TO_FILE); _statusline(NEW_FILENAME_PROMPT); FirstRecall = TRUE; FnameNum = FnameTotal; goto retry; } #endif /* * See if it already exists. */ switch (LYValidateOutput(buffer->str)) { case 'Y': break; case 'N': _statusline(NEW_FILENAME_PROMPT); FirstRecall = TRUE; FnameNum = FnameTotal; goto retry; default: goto cleanup; } /* * See if we can write to it. */ CTRACE((tfp, "LYDownload: filename is %s\n", buffer->str)); SecondS = TRUE; HTInfoMsg(SAVING); #ifdef VMS /* * Try rename() first. - FM */ CTRACE((tfp, "command: rename(%s, %s)\n", file, buffer->str)); if (rename(file, buffer->str)) { /* * Failed. Use spawned COPY_COMMAND. - FM */ CTRACE((tfp, " FAILED!\n")); LYCopyFile(file, buffer->str); } else { /* * We don't have the temporary file (it was renamed to a permanent * file), so set a flag to pop out of the download menu. - FM */ LYDidRename = TRUE; } chmod(buffer->str, HIDE_CHMOD); #else /* Unix: */ LYCopyFile(file, buffer->str); LYRelaxFilePermissions(buffer->str); #endif /* VMS */ } else { /* * Use configured download commands. */ BStrCopy0(buffer, ""); for (count = 0, download_command = downloaders; count < method_number; count++, download_command = download_command->next) ; /* null body */ /* * Commands have the form "command %s [etc]" where %s is the filename. */ if (download_command->command != NULL) { /* * Check for two '%s' and ask for the local filename if there is. */ if (HTCountCommandArgs(download_command->command) >= 2) { _statusline(FILENAME_PROMPT); again: if (sug_file) { BStrCopy0(buffer, sug_file); } else { BStrCopy0(buffer, ""); } check_again: if ((ch = LYgetBString(&buffer, FALSE, 0, recall)) < 0 || isBEmpty(buffer) || ch == UPARROW_KEY || ch == DNARROW_KEY) { if (recall && ch == UPARROW_KEY) { if (FirstRecall) { FirstRecall = FALSE; /* * Use the last Fname in the list. - FM */ FnameNum = 0; } else { /* * Go back to the previous Fname in the list. - FM */ FnameNum++; } if (FnameNum >= FnameTotal) { /* * Reset the FirstRecall flag, and use sug_file or * a blank. - FM */ FirstRecall = TRUE; FnameNum = FnameTotal; _statusline(FILENAME_PROMPT); goto again; } else if ((cp = (char *) HTList_objectAt(sug_filenames, FnameNum)) != NULL) { BStrCopy0(buffer, cp); if (FnameTotal == 1) { _statusline(EDIT_THE_PREV_FILENAME); } else { _statusline(EDIT_A_PREV_FILENAME); } goto check_again; } } else if (recall && ch == DNARROW_KEY) { if (FirstRecall) { FirstRecall = FALSE; /* * Use the first Fname in the list. - FM */ FnameNum = FnameTotal - 1; } else { /* * Advance to the next Fname in the list. - FM */ FnameNum--; } if (FnameNum < 0) { /* * Set the FirstRecall flag, and use sug_file or a * blank. - FM */ FirstRecall = TRUE; FnameNum = FnameTotal; _statusline(FILENAME_PROMPT); goto again; } else if ((cp = (char *) HTList_objectAt(sug_filenames, FnameNum)) != NULL) { BStrCopy0(buffer, cp); if (FnameTotal == 1) { _statusline(EDIT_THE_PREV_FILENAME); } else { _statusline(EDIT_A_PREV_FILENAME); } goto check_again; } } /* * Download cancelled. */ goto cancelled; } if (no_dotfiles || !show_dotfiles) { if (*LYPathLeaf(buffer->str) == '.') { HTAlert(FILENAME_CANNOT_BE_DOT); _statusline(NEW_FILENAME_PROMPT); goto again; } } /* * Cancel if the user entered "/dev/null" on Unix, or an "nl:" * path on VMS. - FM */ if (LYIsNullDevice(buffer->str)) { goto cancelled; } SecondS = TRUE; } /* * The following is considered a bug by the community. If the * command only takes one argument on the command line, then the * suggested file name is not used. It actually is not a bug at * all and does as it should, putting both names on the command * line. */ count = 1; HTAddParam(&the_command, download_command->command, count, file); if (HTCountCommandArgs(download_command->command) > 1) HTAddParam(&the_command, download_command->command, ++count, buffer->str); HTEndParam(&the_command, download_command->command, count); } else { HTAlert(MISCONF_DOWNLOAD_COMMAND); goto failed; } CTRACE((tfp, "command: %s\n", the_command)); stop_curses(); LYSystem(the_command); FREE(the_command); start_curses(); /* don't remove(file); */ } if (SecondS == TRUE) { #ifdef VMS if (0 == strncasecomp(buffer->str, "sys$disk:", 9)) { if (0 == StrNCmp((buffer->str + 9), "[]", 2)) { HTAddSugFilename(buffer->str + 11); } else { HTAddSugFilename(buffer->str + 9); } } else { HTAddSugFilename(buffer->str); } #else HTAddSugFilename(buffer->str); #endif /* VMS */ } goto cleanup; failed: HTAlert(CANNOT_DOWNLOAD_FILE); goto cleanup; cancelled: HTInfoMsg(CANCELLING); cleanup: FREE(Line); BStrFree(buffer); return; }
int HTQueue_count(HTList *me) { return HTList_count(me); }
PRIVATE void robot_profile (const char * AppName, const char * AppVersion) { /* If the Library is not already initialized then do it */ if (!HTLib_isInitialized()) HTLibInit(AppName, AppVersion); if (!converters) { converters = HTList_new(); /* Register the default set of converters including the HTML parser */ HTConverterInit(converters); HTMLInit(converters); /* Set the converters as global converters for all requests */ HTFormat_setConversion(converters); } if (!transfer_encodings) { transfer_encodings = HTList_new(); /* Register the default set of transfer encoders and decoders */ HTTransferEncoderInit(transfer_encodings); HTFormat_setTransferCoding(transfer_encodings); } if (!content_encodings) { content_encodings = HTList_new(); /* Register the default set of content encoders and decoders */ HTContentEncoderInit(content_encodings); if (HTList_count(content_encodings) > 0) HTFormat_setContentCoding(content_encodings); else { HTList_delete(content_encodings); content_encodings = NULL; } } /* Register the default set of transport protocols */ HTTransportInit(); /* Register the default set of application protocol modules */ HTProtocolInit(); /* Initialize suffix bindings for local files */ HTBind_init(); /* Set max number of sockets we want open simultanously */ HTNet_setMaxSocket(32); /* Register some default set of BEFORE and AFTER filters */ HTNet_addBefore(HTRuleFilter, NULL, NULL, HT_FILTER_MIDDLE); HTNet_addBefore(HTProxyFilter, NULL, NULL, HT_FILTER_MIDDLE); HTNet_addAfter(HTInfoFilter, NULL, NULL, HT_ALL, HT_FILTER_LATE); /* Get any proxy or gateway environment variables */ HTProxy_getEnvVar(); /* Register the default set of MIME header parsers */ HTMIMEInit(); /* Register the default set of file suffix bindings */ HTFileInit(); /* Register the default set of Icons for directory listings */ HTIconInit(NULL); /* Register some default messages and dialog functions */ if (HTAlert_interactive()) { HTAlert_add(HTError_print, HT_A_MESSAGE); HTAlert_add(HTConfirm, HT_A_CONFIRM); HTAlert_add(HTPrompt, HT_A_PROMPT); HTAlert_add(HTPromptPassword, HT_A_SECRET); HTAlert_add(HTPromptUsernameAndPassword, HT_A_USER_PW); } HTAlert_setInteractive(YES); }
PRIVATE void client_profile (const char * AppName, const char * AppVersion, BOOL preemptive, BOOL cache, BOOL HTMLParser) { /* If the Library is not already initialized then do it */ if (!HTLib_isInitialized()) HTLibInit(AppName, AppVersion); /* Register the default set of messages and dialog functions */ HTAlertInit(); HTAlert_setInteractive(YES); if (!converters) { converters = HTList_new(); /* Register the default set of converters */ HTConverterInit(converters); /* Register the default libwww HTML parser */ if (HTMLParser) HTMLInit(converters); /* Set the converters as global converters for all requests */ HTFormat_setConversion(converters); } if (!transfer_encodings) { transfer_encodings = HTList_new(); /* Register the default set of transfer encoders and decoders */ HTTransferEncoderInit(transfer_encodings); HTFormat_setTransferCoding(transfer_encodings); } if (!content_encodings) { content_encodings = HTList_new(); /* Register the default set of content encoders and decoders */ HTContentEncoderInit(content_encodings); if (HTList_count(content_encodings) > 0) HTFormat_setContentCoding(content_encodings); else { HTList_delete(content_encodings); content_encodings = NULL; } } /* Register the default set of transport protocols */ HTTransportInit(); /* Register the default set of application protocol modules */ if (preemptive) HTProtocolPreemptiveInit(); else HTProtocolInit(); /* Initialize suffix bindings for local files */ HTBind_init(); /* Set max number of sockets we want open simultanously */ HTNet_setMaxSocket(32); /* The persistent cache does not work in preemptive mode */ if (cache) HTCacheInit(NULL, 20); /* Register the default set of BEFORE and AFTER filters */ HTNetInit(); /* Set up the default set of Authentication schemes */ HTAAInit(); /* Get any proxy or gateway environment variables */ HTProxy_getEnvVar(); /* Register the default set of MIME header parsers */ HTMIMEInit(); /* Register the default set of file suffix bindings */ HTFileInit(); /* Register the default set of Icons for directory listings */ HTIconInit(NULL); }
/* * This procedure outputs the Visited Links list into a temporary file. - FM * Returns links's number to make active (1-based), or 0 if not required. */ int LYShowVisitedLinks(char **newfile) { static char tempfile[LY_MAXPATH] = "\0"; char *Title = NULL; char *Address = NULL; int x, tot; FILE *fp0; VisitedLink *vl; HTList *cur = Visited_Links; int offset; int ret = 0; const char *arrow, *post_arrow; if (!cur) return (-1); if ((fp0 = InternalPageFP(tempfile, TRUE)) == 0) return (-1); LYLocalFileToURL(newfile, tempfile); LYRegisterUIPage(*newfile, UIP_VLINKS); LYforce_HTML_mode = TRUE; /* force this file to be HTML */ LYforce_no_cache = TRUE; /* force this file to be new */ BeginInternalPage(fp0, VISITED_LINKS_TITLE, VISITED_LINKS_HELP); #ifndef NO_OPTION_FORMS fprintf(fp0, "<form action=\"%s\" method=\"post\">\n", STR_LYNXOPTIONS); LYMenuVisitedLinks(fp0, FALSE); fprintf(fp0, "<input type=\"submit\" value=\"Accept Changes\">\n"); fprintf(fp0, "</form>\n"); fprintf(fp0, "<P>\n"); #endif fprintf(fp0, "<pre>\n"); fprintf(fp0, "<em>%s</em>\n", gettext("You visited (POSTs, bookmark, menu and list files excluded):")); if (Visited_Links_As & VISITED_LINKS_REVERSE) tot = x = HTList_count(Visited_Links); else tot = x = -1; if (Visited_Links_As & VISITED_LINKS_AS_TREE) { vl = First_tree; } else if (Visited_Links_As & VISITED_LINKS_AS_LATEST) { if (Visited_Links_As & VISITED_LINKS_REVERSE) vl = Latest_last.prev_latest; else vl = Latest_first.next_latest; if (vl == &Latest_last || vl == &Latest_first) vl = NULL; } else { if (Visited_Links_As & VISITED_LINKS_REVERSE) vl = Last_by_first; else vl = (VisitedLink *) HTList_nextObject(cur); } while (NULL != vl) { /* * The number of the document (most recent highest), its title in a * link, and its address. - FM */ post_arrow = arrow = ""; if (Visited_Links_As & VISITED_LINKS_REVERSE) x--; else x++; if (vl == PrevActiveVisitedLink) { if (Visited_Links_As & VISITED_LINKS_REVERSE) ret = tot - x + 2; else ret = x + 3; } if (vl == PrevActiveVisitedLink) { post_arrow = "<A NAME=current></A>"; /* Otherwise levels 0 and 1 look the same when with arrow: */ arrow = (vl->level && (Visited_Links_As & VISITED_LINKS_AS_TREE)) ? "==>" : "=>"; StrAllocCat(*newfile, "#current"); } if (Visited_Links_As & VISITED_LINKS_AS_TREE) { offset = 2 * vl->level; if (offset > 24) offset = (offset + 24) / 2; if (offset > LYcols * 3 / 4) offset = LYcols * 3 / 4; } else offset = (x > 99 ? 0 : x < 10 ? 2 : 1); if (non_empty(vl->title)) { StrAllocCopy(Title, vl->title); LYEntify(&Title, TRUE); LYTrimLeading(Title); LYTrimTrailing(Title); if (*Title == '\0') StrAllocCopy(Title, NO_TITLE); } else { StrAllocCopy(Title, NO_TITLE); } if (non_empty(vl->address)) { StrAllocCopy(Address, vl->address); LYEntify(&Address, FALSE); fprintf(fp0, "%-*s%s<em>%d</em>. <tab id=t%d><a href=\"%s\">%s</a>\n", offset, arrow, post_arrow, x, x, Address, Title); } else { fprintf(fp0, "%-*s%s<em>%d</em>. <tab id=t%d><em>%s</em>\n", offset, arrow, post_arrow, x, x, Title); } if (Address != NULL) { StrAllocCopy(Address, vl->address); LYEntify(&Address, TRUE); } fprintf(fp0, "<tab to=t%d>%s\n", x, ((Address != NULL) ? Address : gettext("(no address)"))); if (Visited_Links_As & VISITED_LINKS_AS_TREE) vl = vl->next_tree; else if (Visited_Links_As & VISITED_LINKS_AS_LATEST) { if (Visited_Links_As & VISITED_LINKS_REVERSE) vl = vl->prev_latest; else vl = vl->next_latest; if (vl == &Latest_last || vl == &Latest_first) vl = NULL; } else { if (Visited_Links_As & VISITED_LINKS_REVERSE) vl = vl->prev_first; else vl = (VisitedLink *) HTList_nextObject(cur); } } fprintf(fp0, "</pre>\n"); EndInternalPage(fp0); LYCloseTempFP(fp0); FREE(Title); FREE(Address); return (ret); }
HTStream *HTCompressed( HTPresentation *pres, HTParentAnchor *anchor, HTStream *sink ) { int eax; HTStream *me; HTFormat format; char *type = 0; HTPresentation *Pres = 0; HTPresentation *Pnow = 0; int n, i; BOOLEAN can_present = 0; char fnam[256]; char temp[256]; char *suffix; char *uncompress_mask = 0; char *compress_suffix = ""; char *middle; if ( anchor == 0 || anchor->content_encoding == 0 || anchor->content_type == 0 ) { format = HTAtom_for( "application/octet-stream" ); me = HTStreamStack( format, &pres->rep_out, &sink->isa->name[0], anchor ); return me; } else { n = HTList_count( HTPresentations ); i = 0; for ( ; i < n; i++ ) { Pnow = (HTPresentation*)HTList_objectAt( HTPresentations, i ); if ( strcasecomp( (char*)Pnow->rep_out, &anchor->content_type ) == 0 && Pnow->rep_out == HTAtom_for( "www/present" ) ) { char *program = ""; if ( Pres == 0 ) Pres = Pnow; else if ( Pres->quality <= Pnow->quality ) Pres = Pnow; can_present = 1; switch ( HTEncodingToCompressType( &anchor->content_encoding ) ) { case 2: program = HTGetProgramPath( 6 ); if ( program ) { HTSACopy( &uncompress_mask, program ); HTSACat( &uncompress_mask, " -d --no-name %s" ); compress_suffix = "gz"; } break; case 4: program = HTGetProgramPath( 7 ); if ( program ) { HTSACopy( &uncompress_mask, program ); HTSACat( &uncompress_mask, " %s" ); compress_suffix = "zz"; } break; case 3: program = HTGetProgramPath( 1 ); if ( program ) { HTSACopy( &uncompress_mask, program ); HTSACat( &uncompress_mask, " -d %s" ); compress_suffix = "bz2"; } break; case 1: program = HTGetProgramPath( 19 ); if ( program ) { HTSACopy( &uncompress_mask, program ); HTSACat( &uncompress_mask, " %s" ); compress_suffix = "Z"; } break; } } // i++; } if ( can_present == 0 || uncompress_mask == 0 || strchr( &anchor->content_type, ';' ) || HTOutputFormat == HTAtom_for( "www/download" ) || !strcasecomp( &pres->rep_out->name, "www/download" ) || ( traversal && strcasecomp( &anchor->content_type, "text/html" ) && strcasecomp( &anchor->content_type, "text/plain" ) ) ) { if ( strchr( &anchor->content_encoding, '/' ) == 0 ) { if ( strncasecomp( &anchor->content_encoding, "x-", 2 ) == 0 ) HTSACopy( &type, "application/" ); else HTSACopy( &type, "application/x-" ); HTSACat( &type, &anchor->content_encoding ); } else HTSACopy( &type, &anchor->content_encoding ); format = HTAtom_for( type ); if ( type ) { free( type ); type = 0; } if ( uncompress_mask ) { free( uncompress_mask ); uncompress_mask = 0; } me = HTStreamStack( format, &pres->rep_out, &sink->isa->name[0], anchor ); return me; } else { me = calloc( 1, sizeof( HTStream ) ); if ( me == 0 ) outofmem( "./HTFWriter.c", "HTCompressed" ); me->isa->name[0] = HTFWriter.name; me->input_format = pres->rep->next; me->output_format = pres->rep_out; me->anchor = anchor; me->sink = sink; if ( anchor->FileCache ) { LYRemoveTemp( &anchor->FileCache ); if ( anchor->FileCache ) { free( &anchor->FileCache ); anchor->FileCache = 0; } } middle = 0; if ( strcasecomp( &anchor->content_type, "text/html" ) == 0 ) { middle = ".html"; middle++; } else { if ( strncasecomp( &anchor->content_type, "text/", 5 ) == 0 ) middle = "txt"; else { if ( strncasecomp( &anchor->content_type, "application/", 12 ) == 0 ) middle = "bin"; else { suffix = HTFileSuffix( HTAtom_for( &anchor->content_type ), 0 ); if ( suffix && suffix[0] == '.' ) middle = &suffix[1]; } } } temp[0] = 0; if ( middle ) { memcpy( temp[0] + strlen( temp ) ); strcat( temp, middle ); strcat( temp, "." ); } strcat( temp, compress_suffix ); me->fp = LYOpenTemp( fnam, temp, "wb" ); if ( me->fp == 0 ) { HTAlert( gettext( "Can't open temporary file!" ) ); if ( uncompress_mask ) { free( uncompress_mask ); uncompress_mask = 0; } if ( me ) { free( me ); me = 0; } return 0; } else { if ( dump_output_immediately == 0 && traversal == 0 && ( Pres->quality < 999.000000000000 || ( no_exec == 0 && ( local_exec || ( local_exec_on_local_files && ( LYJumpFileURL || strncmp( &anchor->address, "file://localhost", 16 ) == 0 ) ) ) ) ) ) HTSACopy( &me->viewer_command, &Pres->command ); if ( compress_suffix[0] == 'g' && me->viewer_command == 0 ) HTSACopy( &me->end_command, "" ); else { *(int*)&me->end_command = 0; HTAddParam( &me->end_command, uncompress_mask, 1, fnam ); HTEndParam( &me->end_command, uncompress_mask, 1 ); } if ( uncompress_mask ) { free( uncompress_mask ); uncompress_mask = 0; } *(int*)&me->remove_command = 0; HTAddParam( &me->remove_command, "%s", 1, fnam ); HTEndParam( &me->remove_command, "%s", 1 ); HTSACopy( &anchor->FileCache, fnam ); return me; } } } }
static int RecallFilename(bstring **filename, BOOLEAN *first, int *now, int *total, int flag) { int ch; char *cp; RecallType recall; /* * Set up the sug_filenames recall buffer. */ if (*now < 0) { *total = (sug_filenames ? HTList_count(sug_filenames) : 0); *now = *total; } recall = ((*total >= 1) ? RECALL_URL : NORECALL); if ((ch = LYgetBString(filename, FALSE, 0, recall)) < 0 || isBEmpty(*filename) || ch == UPARROW_KEY || ch == DNARROW_KEY) { if (recall && ch == UPARROW_KEY) { if (*first) { *first = FALSE; /* * Use the last Fname in the list. - FM */ *now = 0; } else { /* * Go back to the previous Fname in the list. - FM */ *now += 1; } if (*now >= *total) { /* * Reset the *first flag, and use sug_file or a blank. - * FM */ *first = TRUE; *now = *total; _statusline(FILENAME_PROMPT); return FN_INIT; } else if ((cp = (char *) HTList_objectAt(sug_filenames, *now)) != NULL) { BStrCopy0(*filename, cp); if (*total == 1) { _statusline(EDIT_THE_PREV_FILENAME); } else { _statusline(EDIT_A_PREV_FILENAME); } return FN_READ; } } else if (recall && ch == DNARROW_KEY) { if (*first) { *first = FALSE; /* * Use the first Fname in the list. - FM */ *now = *total - 1; } else { /* * Advance to the next Fname in the list. - FM */ *now -= 1; } if (*now < 0) { /* * Set the *first flag, and use sug_file or a blank. - FM */ *first = TRUE; *now = *total; _statusline(FILENAME_PROMPT); return FN_INIT; } else if ((cp = (char *) HTList_objectAt(sug_filenames, *now)) != NULL) { BStrCopy0(*filename, cp); if (*total == 1) { _statusline(EDIT_THE_PREV_FILENAME); } else { _statusline(EDIT_A_PREV_FILENAME); } return FN_READ; } } /* * Operation cancelled. */ if (flag == PRINT_FLAG) HTInfoMsg(SAVE_REQUEST_CANCELLED); else if (flag == GENERIC_FLAG) return FN_QUIT; return FN_QUIT; } return FN_DONE; }
/* Look up a presentation ** ---------------------- ** ** If fill_in is NULL, only look for an exact match. ** If a wildcard match is made, *fill_in is used to store ** a possibly modified presentation, and a pointer to it is ** returned. For an exact match, a pointer to the presentation ** in the HTPresentations list is returned. Returns NULL if ** nothing found. - kw ** */ PRIVATE HTPresentation * HTFindPresentation ARGS3( HTFormat, rep_in, HTFormat, rep_out, HTPresentation*, fill_in) { HTAtom * wildcard = NULL; /* = HTAtom_for("*"); lookup when needed - kw */ CTRACE((tfp, "HTFormat: Looking up presentation for %s to %s\n", HTAtom_name(rep_in), HTAtom_name(rep_out))); /* don't do anymore do it in the Lynx code at startup LJM */ /* if (!HTPresentations) HTFormatInit(); */ /* set up the list */ { int n = HTList_count(HTPresentations); int i; HTPresentation * pres, *match, *strong_wildcard_match=0, *weak_wildcard_match=0, *last_default_match=0, *strong_subtype_wildcard_match=0; for (i = 0; i < n; i++) { pres = (HTPresentation *)HTList_objectAt(HTPresentations, i); if (pres->rep == rep_in) { if (pres->rep_out == rep_out) { CTRACE((tfp, "FindPresentation: found exact match: %s\n", HTAtom_name(pres->rep))); return pres; } else if (!fill_in) { continue; } else { if (!wildcard) wildcard = WWW_WILDCARD_REP_OUT; if (pres->rep_out == wildcard) { if (!strong_wildcard_match) strong_wildcard_match = pres; /* otherwise use the first one */ CTRACE((tfp, "StreamStack: found strong wildcard match: %s\n", HTAtom_name(pres->rep))); } } } else if (!fill_in) { continue; } else if (half_match(HTAtom_name(pres->rep), HTAtom_name(rep_in))) { if (pres->rep_out == rep_out) { if (!strong_subtype_wildcard_match) strong_subtype_wildcard_match = pres; /* otherwise use the first one */ CTRACE((tfp, "StreamStack: found strong subtype wildcard match: %s\n", HTAtom_name(pres->rep))); } } if (pres->rep == WWW_SOURCE) { if (pres->rep_out == rep_out) { if (!weak_wildcard_match) weak_wildcard_match = pres; /* otherwise use the first one */ CTRACE((tfp, "StreamStack: found weak wildcard match: %s\n", HTAtom_name(pres->rep_out))); } else if (!last_default_match) { if (!wildcard) wildcard = WWW_WILDCARD_REP_OUT; if (pres->rep_out == wildcard) last_default_match = pres; /* otherwise use the first one */ } } } match = strong_subtype_wildcard_match ? strong_subtype_wildcard_match : strong_wildcard_match ? strong_wildcard_match : weak_wildcard_match ? weak_wildcard_match : last_default_match; if (match) { *fill_in = *match; /* Specific instance */ fill_in->rep = rep_in; /* yuk */ fill_in->rep_out = rep_out; /* yuk */ return fill_in; } } return NULL; }
PUBLIC HTFormat HTFileFormat ARGS4 ( char *, filename, HTAtom **, pencoding, HTAtom *, default_type, int *, compressed) { HTSuffix *suff; int n, i, lf; if (!filename) return NULL; /* Make a copy to hack and slash. */ filename = strdup (filename); lf = strlen (filename); /* Step backward through filename, looking for '?'. */ for (i = lf - 1; i >= 0; i--) { if (filename[i] == '?') { /* Clip query. */ filename[i] = '\0'; /* Get new strlen, since we just changed it. */ lf = strlen (filename); goto ok_ready; } } *compressed = 0; /* Check for .Z and .z. */ if (lf > 2) { if (strcmp (&(filename[lf-2]), ".Z") == 0) { *compressed = COMPRESSED_BIGZ; filename[lf-2] = '\0'; lf = strlen (filename); #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "[HTFileFormat] Got hit on .Z; filename '%s'\n", filename); #endif goto ok_ready; } else if (strcmp (&(filename[lf-2]), ".z") == 0) { *compressed = COMPRESSED_GNUZIP; filename[lf-2] = '\0'; lf = strlen (filename); #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "[HTFileFormat] Got hit on .z; filename '%s'\n", filename); #endif goto ok_ready; } else if (lf > 3) { if (strcmp (&(filename[lf-3]), ".gz") == 0) { *compressed = COMPRESSED_GNUZIP; filename[lf-3] = '\0'; lf = strlen (filename); #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "[HTFileFormat] Got hit on .gz; filename '%s'\n", filename); #endif goto ok_ready; } } } ok_ready: if (!HTSuffixes) HTFileInit(); *pencoding = NULL; n = HTList_count(HTSuffixes); for(i=0; i<n; i++) { int ls; suff = HTList_objectAt(HTSuffixes, i); ls = strlen(suff->suffix); if ((ls <= lf) && 0==my_strcasecmp(suff->suffix, filename + lf - ls)) { int j; *pencoding = suff->encoding; if (suff->rep) goto done; for(j=0; j<n; j++) { /* Got encoding, need representation */ int ls2; suff = HTList_objectAt(HTSuffixes, j); ls2 = strlen(suff->suffix); if ((ls <= lf) && 0==my_strncasecmp(suff->suffix, filename + lf - ls -ls2, ls2)) if (suff->rep) goto done; } } } suff = strchr(filename, '.') ? /* Unknown suffix */ ( unknown_suffix.rep ? &unknown_suffix : &no_suffix) : &no_suffix; /* For now, assuming default is 8bit text/plain. We also want default 8bit text/html for http connections. */ /* set default encoding unless found with suffix already */ if (!*pencoding) *pencoding = suff->encoding ? suff->encoding : HTAtom_for("8bit"); done: /* Free our copy. */ free (filename); return suff->rep ? suff->rep : default_type; }
HTAnchor * HTHistory_read ARGS1 (int,number) { return HTList_objectAt (history, HTList_count (history) - number); }
PUBLIC int HTLoadHTTP ARGS4 ( char *, arg, HTParentAnchor *, anAnchor, HTFormat, format_out, HTStream*, sink) { int s; /* Socket number for returned data */ char *command; /* The whole command */ char *eol; /* End of line if found */ char *start_of_data; /* Start of body of reply */ int status; /* tcp return */ int bytes_already_read; char crlf[3]; /* A CR LF equivalent string */ HTStream *target; /* Unconverted data */ HTFormat format_in; /* Format arriving in the message */ char *line_buffer; char *line_kept_clean; BOOL extensions; /* Assume good HTTP server */ int compressed; char line[2048]; /* bumped up to cover Kerb huge headers */ int length, doing_redirect, rv; int already_retrying = 0; int return_nothing; int i; int keepingalive = 0; char *p; /*SWP*/ int statusError=0; if (!arg) { status = -3; HTProgress ("Bad request."); goto done; } if (!*arg) { status = -2; HTProgress ("Bad request."); goto done; } sprintf(crlf, "%c%c", CR, LF); /* At this point, we're talking HTTP/1.0. */ extensions = YES; try_again: /* All initializations are moved down here from up above, so we can start over here... */ eol = 0; bytes_already_read = 0; length = 0; doing_redirect = 0; compressed = 0; target = NULL; line_buffer = NULL; line_kept_clean = NULL; return_nothing = 0; /* okay... addr looks like http://hagbard.ncsa.uiuc.edu/blah/etc.html lets crop it at the 3rd '/' */ for(p = arg,i=0;*p && i!=3;p++) if(*p=='/') i++; if(i==3) i = p-arg; /* i = length not counting last '/' */ else i = 0; if((lsocket != -1) && i && addr && !strncmp(addr,arg,i)){ /* keepalive is active and addresses match -- try the old socket */ s = lsocket; keepingalive = 1; /* flag in case of network error due to server timeout*/ lsocket = -1; /* prevent looping on failure */ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Keep-Alive reusing '%s'\n",addr); #endif /* if (addr && *addr) { sprintf(tmpbuf,"Reusing socket from %s.",addr); HTProgress(tmpbuf); } */ } else { if(addr) free(addr); /* save the address for next time around */ addr = malloc(i+1); strncpy(addr,arg,i); *(addr+i)=0; keepingalive = 0; /* just normal opening of the socket */ if(lsocket != -1) NETCLOSE(lsocket); /* no socket leaks here */ lsocket = -1; /*dont assign until we know the server says okay */ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Keep-Alive saving '%s'\n",addr); #endif /* if (addr && *addr) { sprintf(tmpbuf,"Saving %s for possible socket reuse.",addr); HTProgress(tmpbuf); } */ } if (!keepingalive) { status = HTDoConnect (arg, "HTTP", TCP_PORT, &s); if (status == HT_INTERRUPTED){ /* Interrupt cleanly. */ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Interrupted on connect; recovering cleanly.\n"); #endif HTProgress ("Connection interrupted."); /* status already == HT_INTERRUPTED */ goto done; } if (status < 0) { #ifndef DISABLE_TRACE if (www2Trace) fprintf(stderr, "HTTP: Unable to connect to remote host for `%s' (errno = %d).\n", arg, errno); #endif HTProgress ("Unable to connect to remote host."); status = HT_NO_DATA; goto done; } } /* Ask that node for the document, ** omitting the host name & anchor */ { char * p1 = HTParse(arg, "", PARSE_PATH|PARSE_PUNCTUATION); command = malloc(5 + strlen(p1)+ 2 + 31); if (do_post && !do_put) strcpy(command, "POST "); else if (do_post && do_put) strcpy(command, "PUT "); else if (do_head) strcpy(command, "HEAD "); else if (do_meta) strcpy(command, "META "); else strcpy(command, "GET "); /* * For a gateway, the beginning '/' on the request must * be stripped before appending to the gateway address. */ if ((using_gateway)||(using_proxy)) { strcat(command, p1+1); } else strcat(command, p1); free(p1); } if (extensions) { strcat(command, " "); strcat(command, HTTP_VERSION); } strcat(command, crlf); /* CR LF, as in rfc 977 */ if (extensions) { #ifdef SAM_NOT_YET /* SAM This produces an absolutely huge Accept: line. While there is probably a better way to turn this off, just compiling it out works for now. */ int n, i; if (!HTPresentations) HTFormatInit(); n = HTList_count(HTPresentations); begin_ptr=command+strlen(command); env_length=0; sprintf(line, "Accept:"); env_length+=strlen(line); StrAllocCat(command, line); /* KCMS Accept Header - swp */ if (KCMS_Return_Format==JPEG) { sprintf(line," image/x-pcd-jpeg,"); StrAllocCat(command, line); env_length+=strlen(line); } else if (KCMS_Return_Format==JYCC) { sprintf(line," image/x-pcd-jycc,"); StrAllocCat(command, line); env_length+=strlen(line); } else if (KCMS_Return_Format==GIF) { sprintf(line," image/x-pcd-gif,"); StrAllocCat(command, line); env_length+=strlen(line); } for(i=0; i<n; i++) { HTPresentation * pres = HTList_objectAt(HTPresentations, i); if (pres->rep_out == WWW_PRESENT) { sprintf(line, " %s,",HTAtom_name(pres->rep)); env_length+=strlen(line); StrAllocCat(command, line); if (env_length>200) { if ((tmp_ptr=strrchr(command,','))!=NULL) { *tmp_ptr='\0'; } sprintf(line, "%c%c",CR,LF); StrAllocCat(command, line); begin_ptr=command+strlen(command); sprintf(line, "Accept:"); env_length=strlen(line); StrAllocCat(command, line); } } } /* This gets rid of the last comma. */ if ((tmp_ptr=strrchr(command,','))!=NULL) { *tmp_ptr='\0'; sprintf(line, "%c%c",CR,LF); StrAllocCat(command, line); } else { /* No accept stuff...get rid of "Accept:" */ begin_ptr='\0'; } #endif /* if reloading, send no-cache pragma to proxy servers. --swp */ /* original patch from Ari L. <*****@*****.**> */ if (reloading) { sprintf(line, "Pragma: no-cache%c%c", CR, LF); StrAllocCat(command, line); } /*This is just used for "not" sending this header on a proxy request*/ if (useKeepAlive) { sprintf(line, "Connection: keep-alive%c%c", CR, LF); StrAllocCat(command, line); } if (sendAgent) { sprintf(line, "User-Agent: %s%c%c",agent[selectedAgent],CR,LF); /* sprintf(line, "User-Agent: %s/%s libwww/%s%c%c", HTAppName ? HTAppName : "unknown", HTAppVersion ? HTAppVersion : "0.0", HTLibraryVersion, CR, LF); */ StrAllocCat(command, line); } if (sendReferer) { /* HTTP Referer field, specifies back-link URL - amb */ if (HTReferer) { sprintf(line, "Referer: %s%c%c", HTReferer, CR, LF); StrAllocCat(command, line); HTReferer = NULL; } } { char *tmp,*startPtr,*endPtr; /* addr is always in URL form */ if (addr && !using_proxy && !using_gateway) { tmp=strdup(addr); startPtr=strchr(tmp,'/'); if (startPtr) { startPtr+=2; /*now at begining of hostname*/ if (*startPtr) { endPtr=strchr(startPtr,':'); if (!endPtr) { endPtr=strchr(startPtr,'/'); if (endPtr && *endPtr) { *endPtr='\0'; } } else { *endPtr='\0'; } sprintf(line, "Host: %s%c%c", startPtr, CR, LF); StrAllocCat(command, line); free(tmp); tmp=startPtr=endPtr=NULL; } } } else if (using_proxy || using_gateway) { sprintf(line, "Host: %s%c%c", proxy_host_fix, CR, LF); StrAllocCat(command, line); } } /* SWP -- 7/10/95 */ /* HTTP Extension headers */ /* Domain Restriction */ sprintf(line,"Extension: Notify-Domain-Restriction%c%c",CR,LF); StrAllocCat(command,line); /* BJS -- 12/05/95 -- allow arbitrary headers sent from browser */ if(extra_headers){ int h; for(h=0;extra_headers[h];h++){ sprintf(line,"%s%c%c",extra_headers[h],CR,LF); StrAllocCat(command,line); } } { char *docname; char *hostname; char *colon; int portnumber; char *auth; docname = HTParse(arg, "", PARSE_PATH); hostname = HTParse(arg, "", PARSE_HOST); if (hostname && NULL != (colon = strchr(hostname, ':'))) { *(colon++) = '\0'; /* Chop off port number */ portnumber = atoi(colon); } else portnumber = 80; if (NULL!=(auth=HTAA_composeAuth(hostname, portnumber, docname))) { sprintf(line, "%s%c%c", auth, CR, LF); StrAllocCat(command, line); } #ifndef DISABLE_TRACE if (www2Trace) { if (auth) fprintf(stderr, "HTTP: Sending authorization: %s\n", auth); else fprintf(stderr, "HTTP: Not sending authorization (yet)\n"); } #endif FREE(hostname); FREE(docname); } } if (do_post && !do_put) { #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Doing post, content-type '%s'\n", post_content_type); #endif sprintf (line, "Content-type: %s%c%c", post_content_type ? post_content_type : "lose", CR, LF); StrAllocCat(command, line); { int content_length; if (!post_data) content_length = 4; /* 4 == "lose" :-) */ else content_length = strlen (post_data); sprintf (line, "Content-length: %d%c%c", content_length, CR, LF); StrAllocCat(command, line); } StrAllocCat(command, crlf); /* Blank line means "end" */ if (post_data) StrAllocCat(command, post_data); else StrAllocCat(command, "lose"); } else if (do_post && do_put) { sprintf (line, "Content-length: %d%c%c", put_file_size, CR, LF); StrAllocCat(command, line); StrAllocCat(command, crlf); /* Blank line means "end" */ } else { StrAllocCat(command, crlf); /* Blank line means "end" */ } #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "Writing:\n%s----------------------------------\n", command); #endif /* HTProgress ("Sending HTTP request."); */ status = NETWRITE(s, command, (int)strlen(command)); if (do_post && do_put) { char buf[BUFSIZ]; int upcnt=0,n; while (status>0) { n=fread(buf,1,BUFSIZ-1,put_fp); upcnt+= status = NETWRITE(s, buf, n); #ifndef DISABLE_TRACE if (www2Trace) { fprintf(stderr,"[%d](%d) %s",status,n,buf); } #endif if (feof(put_fp)) { break; } } if (status<0 || !feof(put_fp) || upcnt!=put_file_size) { char tmpbuf[BUFSIZ]; sprintf(tmpbuf,"Status: %d -- EOF: %d -- UpCnt/FileSize: %d/%d\n\nThe server you connected to either does not support\nthe PUT method, or an error occurred.\n\nYour upload was corrupted! Please try again!",status,(feof(put_fp)?1:0),upcnt,put_file_size); application_error(tmpbuf,"Upload Error!"); } } /* Twirl on each request to make things look nicer -- SWP */ HTCheckActiveIcon(1); #ifndef DISABLE_TRACE if (httpTrace) { fprintf(stderr,"%s",command); } #endif free (command); if (status <= 0) { if (status == 0) { #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Got status 0 in initial write\n"); #endif /* Do nothing. */ } else if ((errno == ENOTCONN || errno == ECONNRESET || errno == EPIPE) && !already_retrying && /* Don't retry if we're posting. */ !do_post) { /* Arrrrgh, HTTP 0/1 compability problem, maybe. */ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: BONZO ON WRITE Trying again with HTTP0 request.\n"); #endif /* HTProgress ("Retrying as HTTP0 request."); */ NETCLOSE(s); // SAM extensions = NO; already_retrying = 1; goto try_again; } else { if(keepingalive){ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Timeout on Keep-Alive. Retrying.\n"); #endif HTProgress("Server Timeout: Reconnecting"); goto try_again; } #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Hit unexpected network WRITE error; aborting connection.\n"); #endif NETCLOSE (s); status = -1; HTProgress ("Unexpected network write error; connection aborted."); goto done; } } #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: WRITE delivered OK\n"); #endif HTProgress ("Done sending HTTP request; waiting for response."); /* Read the first line of the response ** ----------------------------------- */ { /* Get numeric status etc */ BOOL end_of_file = NO; int buffer_length = INIT_LINE_SIZE; line_buffer = (char *) malloc(buffer_length * sizeof(char)); do { /* Loop to read in the first line */ /* Extend line buffer if necessary for those crazy WAIS URLs ;-) */ if (buffer_length - length < LINE_EXTEND_THRESH) { buffer_length = buffer_length + buffer_length; line_buffer = (char *) realloc(line_buffer, buffer_length * sizeof(char)); } #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Trying to read %d\n", buffer_length - length - 1); #endif status = NETREAD(s, line_buffer + length, buffer_length - length - 1); #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Read %d\n", status); #endif if (status <= 0) { /* Retry if we get nothing back too; bomb out if we get nothing twice. */ if (status == HT_INTERRUPTED) { #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Interrupted initial read.\n"); #endif HTProgress ("Connection interrupted."); status = HT_INTERRUPTED; NETCLOSE (s); goto clean_up; } else if (status < 0 && (errno == ENOTCONN || errno == ECONNRESET || errno == EPIPE) && !already_retrying && !do_post) { /* Arrrrgh, HTTP 0/1 compability problem, maybe. */ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: BONZO Trying again with HTTP0 request.\n"); #endif NETCLOSE(s); if (line_buffer) free(line_buffer); if (line_kept_clean) free(line_kept_clean); extensions = NO; already_retrying = 1; HTProgress ("Retrying as HTTP0 request."); goto try_again; } else { if(keepingalive){ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Timeout on Keep-Alive. Retrying.\n"); #endif HTProgress("Server Timeout: Reconnecting"); goto try_again; } #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Hit unexpected network read error; aborting connection; status %d.\n", status); #endif HTProgress ("Unexpected network read error; connection aborted."); NETCLOSE (s); status = -1; goto clean_up; } } bytes_already_read += status; { char line[256]; sprintf (line, "Read %d bytes of data.", bytes_already_read); HTProgress (line); } if (status == 0) { end_of_file = YES; break; } line_buffer[length+status] = 0; if (line_buffer) { if (line_kept_clean) free (line_kept_clean); line_kept_clean = (char *)malloc (buffer_length * sizeof (char)); /* bcopy (line_buffer, line_kept_clean, buffer_length); */ memcpy (line_kept_clean, line_buffer, buffer_length); } eol = strchr(line_buffer + length, LF); /* Do we *really* want to do this? */ if (eol && eol != line_buffer && *(eol-1) == CR) *(eol-1) = ' '; length = length + status; /* Do we really want to do *this*? */ if (eol) *eol = 0; /* Terminate the line */ /* All we need is the first line of the response. If it's a HTTP/1.0 response, then the first line will be absurdly short and therefore we can safely gate the number of bytes read through this code (as opposed to below) to ~1000. */ /* Well, let's try 100. */ } while (!eol && !end_of_file && bytes_already_read < 100); } /* Scope of loop variables */ /* We now have a terminated unfolded line. Parse it. ** ------------------------------------------------- */ #ifndef DISABLE_TRACE if (www2Trace) fprintf(stderr, "HTTP: Rx: %s\n", line_buffer); #endif { int fields; char server_version[VERSION_LENGTH+1]; int server_status; /*SWP*/ statusError=0; server_version[0] = 0; fields = sscanf(line_buffer, "%20s %d", server_version, &server_status); #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Scanned %d fields from line_buffer\n", fields); #endif #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: line_buffer '%s'\n", line_buffer); #endif /* Rule out HTTP/1.0 reply as best we can. */ if (fields < 2 || !server_version[0] || server_version[0] != 'H' || server_version[1] != 'T' || server_version[2] != 'T' || server_version[3] != 'P' || server_version[4] != '/' || server_version[6] != '.') { /* HTTP0 reply */ HTAtom * encoding; #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "--- Talking HTTP0.\n"); #endif format_in = HTFileFormat(arg, &encoding, WWW_HTML, &compressed); start_of_data = line_kept_clean; } else { /* Decode full HTTP response */ format_in = HTAtom_for("www/mime"); /* We set start_of_data to "" when !eol here because there will be a put_block done below; we do *not* use the value of start_of_data (as a pointer) in the computation of length or anything else in this situation. */ start_of_data = eol ? eol + 1 : ""; length = eol ? length - (start_of_data - line_buffer) : 0; #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "--- Talking HTTP1.\n"); #endif switch (server_status / 100) { case 3: /* Various forms of redirection */ /* We now support this in the parser, at least. */ doing_redirect = 1; break; case 4: /* "I think I goofed" */ switch (server_status) { case 403: statusError=1; /* 403 is "forbidden"; display returned text. */ break; case 401: /* length -= start_of_data - text_buffer; */ if (HTAA_shouldRetryWithAuth(start_of_data, length, s)) { (void)NETCLOSE(s); lsocket = -1; if (line_buffer) free(line_buffer); if (line_kept_clean) free(line_kept_clean); #ifndef DISABLE_TRACE if (www2Trace) fprintf(stderr, "%s %d %s\n", "HTTP: close socket", s, "to retry with Access Authorization"); #endif HTProgress ("Retrying with access authorization information."); goto try_again; break; } else { statusError=1; /* Fall through. */ } default: statusError=1; break; } /* case 4 switch */ break; case 5: /* I think you goofed */ statusError=1; break; case 2: /* Good: Got MIME object */ switch (server_status) { case 204: return_nothing = 1; format_in = HTAtom_for("text/html"); break; case 200: if (do_head) { if (!start_of_data || !*start_of_data) { headData=NULL; } else { char *ptr; headData=strdup(start_of_data); ptr=strchr(headData,'\n'); *ptr='\0'; } } break; default: break; } break; default: /* bad number */ statusError=1; HTAlert("Unknown status reply from server!"); break; } /* Switch on server_status/100 */ } /* Full HTTP reply */ } /* scope of fields */ /* Set up the stream stack to handle the body of the message */ target = HTStreamStack(format_in, format_out, compressed, sink, anAnchor); if (!target) { char buffer[1024]; /* @@@@@@@@ */ sprintf(buffer, "Sorry, no known way of converting %s to %s.", HTAtom_name(format_in), HTAtom_name(format_out)); HTProgress (buffer); status = -1; NETCLOSE (s); lsocket = -1; goto clean_up; } if (!return_nothing) { #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Doing put_block, '%s'\n", start_of_data); #endif /* BJS: parse start_of_data...*/ for(p=start_of_data;*p;p++){ /* if(*p=='C' && !strncmp("Content-length: ",p,16)){ i = 0; p+=16; while(*p && isdigit(*p)){ i = i*10 + *p-'0'; p++; } p--; #ifndef DISABLE_TRACE if(www2Trace) fprintf(stderr, "HTTP: Content Length is %d\n",i); #endif } */ if(*p=='K' && !strncmp("Keep-Alive:",p,11)){ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Server Agrees to Keep-Alive\n"); #endif lsocket = s; p+=10; } } #ifndef DISABLE_TRACE if (www2Trace && lsocket == -1) fprintf (stderr, "HTTP: Server does not agree to Keep-Alive\n"); #endif /* Recycle the first chunk of data, in all cases. */ (*target->isa->put_block)(target, start_of_data, length); /* Go pull the bulk of the data down. */ /* if we dont use length, header length is wrong due to the discarded first line - bjs*/ rv = HTCopy(s, target, length /*bytes_already_read*/); if (rv == -1) { (*target->isa->handle_interrupt) (target); status = HT_INTERRUPTED; NETCLOSE (s); lsocket = -1; goto clean_up; } if (rv == -2 && !already_retrying && !do_post) { /* Aw hell. */ #ifndef DISABLE_TRACE if (www2Trace) fprintf (stderr, "HTTP: Trying again with HTTP0 request.\n"); #endif /* May as well consider it an interrupt -- right? */ (*target->isa->handle_interrupt) (target); NETCLOSE(s); if (line_buffer) free(line_buffer); if (line_kept_clean) free(line_kept_clean); extensions = NO; already_retrying = 1; HTProgress ("Retrying as HTTP0 request."); goto try_again; } } else { /* return_nothing is high. */ (*target->isa->put_string) (target, "<mosaic-access-override>\n"); HTProgress ("And silence filled the night."); } (*target->isa->end_document)(target); /* Close socket before doing free. */ if(lsocket == -1){ NETCLOSE(s); #ifndef DISABLE_TRACE if(www2Trace) fprintf(stderr,"HTTP: Closing connection\n"); #endif } else { HTProgress("Leaving Server Connection Open"); #ifndef DISABLE_TRACE if(www2Trace) fprintf(stderr,"HTTP: Keeping connection alive\n"); #endif } /* else { NETCLOSE(s); #ifndef DISABLE_TRACE if(www2Trace) fprintf(stderr,"HTTP: Closing connection\n"); #endif } */ (*target->isa->free)(target); if (doing_redirect) { /* OK, now we've got the redirection URL temporarily stored in external variable redirecting_url, exported from HTMIME.c, since there's no straightforward way to do this in the library currently. Do the right thing. */ status = HT_REDIRECTING; } else { status = HT_LOADED; } /* Clean up */ clean_up: if (line_buffer) free(line_buffer); if (line_kept_clean) free(line_kept_clean); done: /* Clear out on exit, just in case. */ do_post = 0; if (statusError) { securityType=HTAA_NONE; #ifndef DISABLE_TRACE if (www2Trace) fprintf(stderr,"Resetting security type to NONE.\n"); #endif } return status; }