/* Push data from a gzip file pointer down a stream ** ------------------------------------- ** ** This routine is responsible for creating and PRESENTING any ** graphic (or other) objects described by the file. ** ** ** State of file and target stream on entry: ** gzFile (gzfp) assumed open (should have gzipped content), ** target (sink) assumed valid. ** ** Return values: ** HT_INTERRUPTED Interruption after some data read. ** HT_PARTIAL_CONTENT Error after some data read. ** -1 Error before any data read. ** HT_LOADED Normal end of file indication on reading. ** ** State of file and target stream on return: ** always gzfp still open, target stream still valid. */ PRIVATE int HTGzFileCopy ARGS2( gzFile, gzfp, HTStream*, sink) { HTStreamClass targetClass; int status, bytes; int gzerrnum; int rv = HT_OK; /* Push the data down the stream */ targetClass = *(sink->isa); /* Copy pointers to procedures */ /* read and inflate gzip'd file, and push binary down sink */ HTReadProgress(bytes = 0, 0); for (;;) { status = gzread(gzfp, input_buffer, INPUT_BUFFER_SIZE); if (status <= 0) { /* EOF or error */ if (status == 0) { rv = HT_LOADED; break; } CTRACE((tfp, "HTGzFileCopy: Read error, gzread returns %d\n", status)); CTRACE((tfp, "gzerror : %s\n", gzerror(gzfp, &gzerrnum))); if (TRACE) { if (gzerrnum == Z_ERRNO) perror("gzerror "); } if (bytes) { rv = HT_PARTIAL_CONTENT; } else { rv = -1; } break; } (*targetClass.put_block)(sink, input_buffer, status); bytes += status; HTReadProgress(bytes, -1); HTDisplayPartial(); if (HTCheckForInterrupt()) { _HTProgress (TRANSFER_INTERRUPTED); if (bytes) { rv = HT_INTERRUPTED; } else { rv = -1; } break; } } /* next bufferload */ HTFinishDisplayPartial(); return rv; }
/* Push data from a file pointer down a stream ** ------------------------------------- ** ** This routine is responsible for creating and PRESENTING any ** graphic (or other) objects described by the file. ** ** ** State of file and target stream on entry: ** FILE* (fp) assumed open, ** target (sink) assumed valid. ** ** Return values: ** HT_INTERRUPTED Interruption after some data read. ** HT_PARTIAL_CONTENT Error after some data read. ** -1 Error before any data read. ** HT_LOADED Normal end of file indication on reading. ** ** State of file and target stream on return: ** always fp still open, target stream still valid. */ PUBLIC int HTFileCopy ARGS2( FILE *, fp, HTStream*, sink) { HTStreamClass targetClass; int status, bytes; int rv = HT_OK; /* Push the data down the stream */ targetClass = *(sink->isa); /* Copy pointers to procedures */ /* Push binary from socket down sink */ HTReadProgress(bytes = 0, 0); for (;;) { status = fread(input_buffer, 1, INPUT_BUFFER_SIZE, fp); if (status == 0) { /* EOF or error */ if (ferror(fp) == 0) { rv = HT_LOADED; break; } CTRACE((tfp, "HTFormat: Read error, read returns %d\n", ferror(fp))); if (bytes) { rv = HT_PARTIAL_CONTENT; } else { rv = -1; } break; } (*targetClass.put_block)(sink, input_buffer, status); bytes += status; HTReadProgress(bytes, 0); /* Suppress last screen update in partial mode - a regular update * under control of mainloop() should follow anyway. - kw */ #ifdef DISP_PARTIAL if (display_partial && bytes != HTMainAnchor->content_length) HTDisplayPartial(); #endif if (HTCheckForInterrupt()) { _HTProgress (TRANSFER_INTERRUPTED); if (bytes) { rv = HT_INTERRUPTED; } else { rv = -1; } break; } } /* next bufferload */ HTFinishDisplayPartial(); return rv; }
/* Free an HTML object ** ------------------- ** ** Note that the SGML parsing context is freed, but the created ** object is not, ** as it takes on an existence of its own unless explicitly freed. */ PRIVATE void HTFWriter_free ARGS1(HTStream *, me) { fclose(me->fp); if (me->end_command) { /* Temp file */ _HTProgress(me->end_command); /* Tell user what's happening */ system(me->end_command); FREE(me->end_command); if (me->remove_command) { system(me->remove_command); FREE(me->remove_command); } } FREE(me); }
/* Push data from an HTChunk down a stream ** --------------------------------------- ** ** This routine is responsible for creating and PRESENTING any ** graphic (or other) objects described by the file. ** ** State of memory and target stream on entry: ** HTChunk* (chunk) and target (sink) assumed valid. ** ** Return values: ** HT_LOADED All data sent. ** HT_INTERRUPTED Interruption after some data read. ** ** State of memory and target stream on return: ** always chunk unchanged, target stream still valid. */ PUBLIC int HTMemCopy ARGS2( HTChunk *, chunk, HTStream *, sink) { HTStreamClass targetClass; int bytes = 0; CONST char *data = chunk->data; int rv = HT_OK; targetClass = *(sink->isa); HTReadProgress(0, 0); for (;;) { /* Push the data down the stream a piece at a time, in case we're ** running a large document on a slow machine. */ int n = INPUT_BUFFER_SIZE; if (n > chunk->size - bytes) n = chunk->size - bytes; if (n == 0) break; (*targetClass.put_block)(sink, data, n); bytes += n; data += n; HTReadProgress(bytes, 0); HTDisplayPartial(); if (HTCheckForInterrupt()) { _HTProgress (TRANSFER_INTERRUPTED); if (bytes) { rv = HT_INTERRUPTED; } else { rv = -1; } break; } } HTFinishDisplayPartial(); return rv; }
static int response(char *command, char *sitename, HTParentAnchor *anAnchor, HTFormat format_out, HTStream *sink) { int status; int length = (int) strlen(command); int ch, i; char line[BIG], *l, *cmd = NULL; char *p = line, *href = NULL; if (length == 0) return (-1); /* Set up buffering. */ HTInitInput(finger_fd); /* Send the command. */ CTRACE((tfp, "HTFinger command to be sent: %s", command)); status = (int) NETWRITE(finger_fd, (char *) command, (unsigned) length); if (status < 0) { CTRACE((tfp, "HTFinger: Unable to send command. Disconnecting.\n")); NETCLOSE(finger_fd); finger_fd = -1; return status; } /* if bad status */ /* Make a hypertext object with an anchor list. */ target = HTML_new(anAnchor, format_out, sink); targetClass = *target->isa; /* Copy routine entry points */ /* Create the results report. */ CTRACE((tfp, "HTFinger: Reading finger information\n")); START(HTML_HTML); PUTC('\n'); START(HTML_HEAD); PUTC('\n'); START(HTML_TITLE); PUTS("Finger server on "); PUTS(sitename); END(HTML_TITLE); PUTC('\n'); END(HTML_HEAD); PUTC('\n'); START(HTML_BODY); PUTC('\n'); START(HTML_H1); PUTS("Finger server on "); START(HTML_EM); PUTS(sitename); END(HTML_EM); PUTS(": "); StrAllocCopy(cmd, command); for (i = ((int) strlen(cmd) - 1); i >= 0; i--) { if (cmd[i] == LF || cmd[i] == CR) { cmd[i] = '\0'; } else { break; } } PUTS(cmd); FREE(cmd); END(HTML_H1); PUTC('\n'); START(HTML_PRE); while ((ch = NEXT_CHAR) != EOF) { if (interrupted_in_htgetcharacter) { CTRACE((tfp, "HTFinger: Interrupted in HTGetCharacter, apparently.\n")); _HTProgress(CONNECTION_INTERRUPTED); goto end_html; } if (ch != LF) { *p = (char) ch; /* Put character in line */ if (p < &line[BIG - 1]) { p++; } } else { *p = '\0'; /* Terminate line */ /* * OK we now have a line. * Load it as 'l' and parse it. */ p = l = line; while (*l) { if (StrNCmp(l, STR_NEWS_URL, LEN_NEWS_URL) && StrNCmp(l, "snews://", 8) && StrNCmp(l, "nntp://", 7) && StrNCmp(l, "snewspost:", 10) && StrNCmp(l, "snewsreply:", 11) && StrNCmp(l, "newspost:", 9) && StrNCmp(l, "newsreply:", 10) && StrNCmp(l, "ftp://", 6) && StrNCmp(l, "file:/", 6) && StrNCmp(l, "finger://", 9) && StrNCmp(l, "http://", 7) && StrNCmp(l, "https://", 8) && StrNCmp(l, "wais://", 7) && StrNCmp(l, STR_MAILTO_URL, LEN_MAILTO_URL) && StrNCmp(l, "cso://", 6) && StrNCmp(l, "gopher://", 9)) PUTC(*l++); else { StrAllocCopy(href, l); start_anchor(strtok(href, " \r\n\t,>)\"")); while (*l && !StrChr(" \r\n\t,>)\"", *l)) PUTC(*l++); END(HTML_A); FREE(href); } } PUTC('\n'); } } NETCLOSE(finger_fd); finger_fd = -1; end_html: END(HTML_PRE); PUTC('\n'); END(HTML_BODY); PUTC('\n'); END(HTML_HTML); PUTC('\n'); FREE_TARGET; return (0); }
/* HTVMSBrowseDir() ** ** This function generates a directory listing as an HTML-object ** for local file URL's. It assumes the first two elements of ** of the path are a device followed by a directory: ** ** file://localhost/device/directory[/[foo]] ** ** Will not accept 000000 as a directory name. ** Will offer links to parent through the top directory, unless ** a terminal slash was included in the calling URL. ** ** Returns HT_LOADED on success, HTLoadError() messages on error. ** ** Developed for Lynx by Foteos Macrides ([email protected]). */ PUBLIC int HTVMSBrowseDir ARGS4( CONST char *, address, HTParentAnchor *, anchor, HTFormat, format_out, HTStream *, sink ) { HTStructured* target; HTStructuredClass targetClass; char *pathname = HTParse(address, "", PARSE_PATH + PARSE_PUNCTUATION); char *tail = NULL; char *title = NULL; char *header = NULL; char *parent = NULL; char *relative = NULL; char *cp, *cp1; int pathend, len; DIR *dp; struct stat file_info; time_t NowTime; static char ThisYear[8]; VMSEntryInfo *entry_info = 0; char string_buffer[64]; HTUnEscape(pathname); CTRACE((tfp,"HTVMSBrowseDir: Browsing `%s\'\n", pathname)); /* * Require at least two elements (presumably a device and directory) * and disallow the device root (000000 directory). Symbolic paths * (e.g., sys$help) should have been translated and expanded (e.g., * to /sys$sysroot/syshlp) before calling this routine. */ if (((*pathname != '/') || (cp = strchr(pathname+1, '/')) == NULL || *(cp + 1) == '\0' || 0 == strncmp((cp + 1), "000000", 6)) || (dp = HTVMSopendir(pathname)) == NULL) { FREE(pathname); return HTLoadError(sink, 403, COULD_NOT_ACCESS_DIR); } /* * Set up the output stream. */ _HTProgress (BUILDING_DIR_LIST); if (UCLYhndl_HTFile_for_unspec >= 0) { HTAnchor_setUCInfoStage(anchor, UCLYhndl_HTFile_for_unspec, UCT_STAGE_PARSER, UCT_SETBY_DEFAULT); } target = HTML_new(anchor, format_out, sink); targetClass = *(target->isa); /* * Set up the offset string of the anchor reference, * and strings for the title and header. */ cp = strrchr(pathname, '/'); /* find lastslash */ StrAllocCopy(tail, (cp+1)); /* take slash off the beginning */ if (*tail != '\0') { StrAllocCopy(title, tail); *cp = '\0'; if ((cp1=strrchr(pathname, '/')) != NULL && cp1 != pathname && strncmp((cp1+1), "000000", 6)) StrAllocCopy(parent, (cp1+1)); *cp = '/'; } else { pathname[strlen(pathname)-1] = '\0'; cp = strrchr(pathname, '/'); StrAllocCopy(title, (cp+1)); pathname[strlen(pathname)] = '/'; } StrAllocCopy(header, pathname); /* * Initialize path name for HTStat(). */ pathend = strlen(pathname); if (*(pathname+pathend-1) != '/') { StrAllocCat(pathname, "/"); pathend++; } /* * Output the title and header. */ START(HTML_HTML); PUTC('\n'); START(HTML_HEAD); PUTC('\n'); HTUnEscape(title); START(HTML_TITLE); PUTS(title); PUTS(" directory"); END(HTML_TITLE); PUTC('\n'); FREE(title); END(HTML_HEAD); PUTC('\n'); START(HTML_BODY); PUTC('\n'); HTUnEscape(header); START(HTML_H1); PUTS(header); END(HTML_H1); PUTC('\n'); if (HTDirReadme == HT_DIR_README_TOP) { FILE * fp; if (header[strlen(header)-1] != '/') StrAllocCat(header, "/"); StrAllocCat(header, HT_DIR_README_FILE); if ((fp = fopen(header, "r")) != NULL) { START(HTML_PRE); for(;;) { char c = fgetc(fp); if (c == (char)EOF) break; #ifdef NOTDEFINED switch (c) { case '&': case '<': case '>': PUTC('&'); PUTC('#'); PUTC((char)(c / 10)); PUTC((char) (c % 10)); PUTC(';'); break; default: PUTC(c); } #else PUTC(c); #endif /* NOTDEFINED */ } END(HTML_PRE); fclose(fp); } } FREE(header); if (parent) { HTSprintf0(&relative, "%s/..", tail); HTStartAnchor(target, "", relative); PUTS("Up to "); HTUnEscape(parent); PUTS(parent); END(HTML_A); START(HTML_P); PUTC('\n'); FREE(relative); FREE(parent); } /* * Set up the date comparison. */ NowTime = time(NULL); strcpy(ThisYear, (char *)ctime(&NowTime)+20); ThisYear[4] = '\0'; /* * Now, generate the Btree and put it out to the output stream. */ { char dottest = 2; /* To avoid two strcmp() each time */ STRUCT_DIRENT *dirbuf; HTBTree *bt; /* Set up sort key and initialize BTree */ bt = HTBTree_new((HTComparer) compare_VMSEntryInfo_structs); /* Build tree */ while ((dirbuf = HTVMSreaddir(dp))) { HTAtom *encoding = NULL; HTFormat format; /* Skip if not used */ if (!dirbuf->d_ino) { continue; } /* Current and parent directories are never shown in list */ if (dottest && (!strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))) { dottest--; continue; } /* Don't show the selective enabling file * unless version numbers are included */ if (!strcasecomp(dirbuf->d_name, HT_DIR_ENABLE_FILE)) { continue; } /* Skip files beginning with a dot? */ if ((no_dotfiles || !show_dotfiles) && *dirbuf->d_name == '.') { continue; } /* OK, make an lstat() and get a key ready. */ *(pathname+pathend) = '\0'; StrAllocCat(pathname, dirbuf->d_name); if (HTStat(pathname, &file_info)) { /* for VMS the failure here means the file is not readable... we however continue to browse through the directory... */ continue; } entry_info = (VMSEntryInfo *)malloc(sizeof(VMSEntryInfo)); if (entry_info == NULL) outofmem(__FILE__, "HTVMSBrowseDir"); entry_info->type = 0; entry_info->size = 0; entry_info->date = 0; entry_info->filename = 0; entry_info->display = TRUE; /* Get the type */ format = HTFileFormat(dirbuf->d_name, &encoding, (CONST char **)&cp); if (!cp) { if(!strncmp(HTAtom_name(format), "application",11)) { cp = HTAtom_name(format) + 12; if(!strncmp(cp,"x-", 2)) cp += 2; } else cp = HTAtom_name(format); } StrAllocCopy(entry_info->type, cp); StrAllocCopy(entry_info->filename, dirbuf->d_name); if (S_ISDIR(file_info.st_mode)) { /* strip .DIR part... */ char *dot; dot = strstr(entry_info->filename, ".DIR"); if (dot) *dot = '\0'; LYLowerCase(entry_info->filename); StrAllocCopy(entry_info->type, "Directory"); } else { if ((cp = strstr(entry_info->filename, "READ")) == NULL) { cp = entry_info->filename; } else { cp += 4; if (!strncmp(cp, "ME", 2)) { cp += 2; while (cp && *cp && *cp != '.') { cp++; } } else if (!strncmp(cp, ".ME", 3)) { cp = (entry_info->filename + strlen(entry_info->filename)); } else { cp = entry_info->filename; } } LYLowerCase(cp); if (((len = strlen(entry_info->filename)) > 2) && entry_info->filename[len-1] == 'z') { if (entry_info->filename[len-2] == '.' || entry_info->filename[len-2] == '_') entry_info->filename[len-1] = 'Z'; } } /* Get the date */ { char *t = (char *)ctime((CONST time_t *)&file_info.st_ctime); *(t+24) = '\0'; StrAllocCopy(entry_info->date, (t+4)); *((entry_info->date)+7) = '\0'; if ((atoi((t+19))) < atoi(ThisYear)) StrAllocCat(entry_info->date, (t+19)); else { StrAllocCat(entry_info->date, (t+11)); *((entry_info->date)+12) = '\0'; } } /* Get the size */ if (!S_ISDIR(file_info.st_mode)) entry_info->size = (unsigned int)file_info.st_size; else entry_info->size = 0; /* Now, update the BTree etc. */ if(entry_info->display) { CTRACE((tfp,"Adding file to BTree: %s\n", entry_info->filename)); HTBTree_add(bt, entry_info); } } /* End while HTVMSreaddir() */ FREE(pathname); HTVMSclosedir(dp); START(HTML_PRE); /* * Run through the BTree printing out in order */ { HTBTElement * ele; int i; for (ele = HTBTree_next(bt, NULL); ele != NULL; ele = HTBTree_next(bt, ele)) { entry_info = (VMSEntryInfo *)HTBTree_object(ele); /* Output the date */ if(entry_info->date) { PUTS(entry_info->date); PUTS(" "); } else PUTS(" * "); /* Output the type */ if(entry_info->type) { for(i = 0; entry_info->type[i] != '\0' && i < 15; i++) PUTC(entry_info->type[i]); for(; i < 17; i++) PUTC(' '); } /* Output the link for the name */ HTDirEntry(target, tail, entry_info->filename); PUTS(entry_info->filename); END(HTML_A); /* Output the size */ if(entry_info->size) { if(entry_info->size < 1024) sprintf(string_buffer," %d bytes", entry_info->size); else sprintf(string_buffer," %dKb", entry_info->size/1024); PUTS(string_buffer); } PUTC('\n'); /* end of this entry */ free_VMSEntryInfo_contents(entry_info); } } HTBTreeAndObject_free(bt); } /* End of both BTree loops */ /* * Complete the output stream. */ END(HTML_PRE); PUTC('\n'); END(HTML_BODY); PUTC('\n'); END(HTML_HTML); PUTC('\n'); FREE(tail); FREE_TARGET; return HT_LOADED; } /* End of directory reading section */
/* Push data from a socket down a stream ** ------------------------------------- ** ** This routine is responsible for creating and PRESENTING any ** graphic (or other) objects described by the file. ** ** The file number given is assumed to be a TELNET stream, i.e., containing ** CRLF at the end of lines which need to be stripped to LF for unix ** when the format is textual. ** ** State of socket and target stream on entry: ** socket (file_number) assumed open, ** target (sink) assumed valid. ** ** Return values: ** HT_INTERRUPTED Interruption or error after some data received. ** -2 Unexpected disconnect before any data received. ** -1 Interruption or error before any data received, or ** (UNIX) other read error before any data received, or ** download cancelled. ** HT_LOADED Normal close of socket (end of file indication ** received), or ** unexpected disconnect after some data received, or ** other read error after some data received, or ** (not UNIX) other read error before any data received. ** ** State of socket and target stream on return depends on return value: ** HT_INTERRUPTED socket still open, target aborted. ** -2 socket still open, target stream still valid. ** -1 socket still open, target aborted. ** otherwise socket closed, target stream still valid. */ PUBLIC int HTCopy ARGS4( HTParentAnchor *, anchor, int, file_number, void*, handle GCC_UNUSED, HTStream*, sink) { HTStreamClass targetClass; BOOL suppress_readprogress = NO; int bytes; int rv = 0; /* Push the data down the stream */ targetClass = *(sink->isa); /* Copy pointers to procedures */ /* Push binary from socket down sink ** ** This operation could be put into a main event loop */ HTReadProgress(bytes = 0, 0); for (;;) { int status; if (LYCancelDownload) { LYCancelDownload = FALSE; (*targetClass._abort)(sink, NULL); rv = -1; goto finished; } if (HTCheckForInterrupt()) { _HTProgress (TRANSFER_INTERRUPTED); (*targetClass._abort)(sink, NULL); if (bytes) rv = HT_INTERRUPTED; else rv = -1; goto finished; } #ifdef USE_SSL if (handle) status = SSL_read((SSL *)handle, input_buffer, INPUT_BUFFER_SIZE); else status = NETREAD(file_number, input_buffer, INPUT_BUFFER_SIZE); #else status = NETREAD(file_number, input_buffer, INPUT_BUFFER_SIZE); #endif /* USE_SSL */ if (status <= 0) { if (status == 0) { break; } else if (status == HT_INTERRUPTED) { _HTProgress (TRANSFER_INTERRUPTED); (*targetClass._abort)(sink, NULL); if (bytes) rv = HT_INTERRUPTED; else rv = -1; goto finished; } else if (SOCKET_ERRNO == ENOTCONN || #ifdef _WINDOWS /* 1997/11/10 (Mon) 16:57:18 */ SOCKET_ERRNO == ETIMEDOUT || #endif SOCKET_ERRNO == ECONNRESET || SOCKET_ERRNO == EPIPE) { /* * Arrrrgh, HTTP 0/1 compatibility problem, maybe. */ if (bytes <= 0) { /* * Don't have any data, so let the calling * function decide what to do about it. - FM */ rv = -2; goto finished; } else { #ifdef UNIX /* * Treat what we've received already as the complete * transmission, but not without giving the user * an alert. I don't know about all the different * TCP stacks for VMS etc., so this is currently * only for UNIX. - kw */ HTInetStatus("NETREAD"); HTAlert("Unexpected server disconnect."); CTRACE((tfp, "HTCopy: Unexpected server disconnect. Treating as completed.\n")); status = 0; break; #else /* !UNIX */ /* * Treat what we've gotten already * as the complete transmission. - FM */ CTRACE((tfp, "HTCopy: Unexpected server disconnect. Treating as completed.\n")); status = 0; break; #endif /* UNIX */ } #ifdef UNIX } else { /* status < 0 and other errno */ /* * Treat what we've received already as the complete * transmission, but not without giving the user * an alert. I don't know about all the different * TCP stacks for VMS etc., so this is currently * only for UNIX. - kw */ HTInetStatus("NETREAD"); HTAlert("Unexpected read error."); if (bytes) { (void)NETCLOSE(file_number); rv = HT_LOADED; } else { (*targetClass._abort)(sink, NULL); rv = -1; } goto finished; #endif } break; } /* * Suppress ReadProgress messages when collecting a redirection * message, at least initially (unless/until anchor->content_type * gets changed, probably by the MIME message parser). That way * messages put up by the HTTP module or elsewhere can linger in * the statusline for a while. - kw */ suppress_readprogress = (anchor && anchor->content_type && !strcmp(anchor->content_type, "message/x-http-redirection")); #ifdef NOT_ASCII { char * p; for (p = input_buffer; p < input_buffer+status; p++) { *p = FROMASCII(*p); } } #endif /* NOT_ASCII */ (*targetClass.put_block)(sink, input_buffer, status); bytes += status; if (!suppress_readprogress) HTReadProgress(bytes, anchor ? anchor->content_length : 0); HTDisplayPartial(); } /* next bufferload */ _HTProgress(TRANSFER_COMPLETE); (void)NETCLOSE(file_number); rv = HT_LOADED; finished: HTFinishDisplayPartial(); return(rv); }