commit 7866ab6cf117b51f328d4426d209ee79c4e2f2e9
parent 0959598e5774d02628fa74a12f7bc93d3d29960d
Author: Kyle Milz <krwmilz@gmail.com>
Date: Thu, 19 Aug 2021 17:10:40 +0000
fetch dvi files from network
Add basic dvi fetching over HTTPS. Use openssl to make TLS connections to a
remote machine to fetch documents.
Add an address bar widget that the user can edit, and fetch documents from.
Render the fetched document in the main viewport window.
Diffstat:
M | Makefile.in | | | 25 | +++++++++++++------------ |
M | dvi-draw.c | | | 40 | ++++++++++++++++++++-------------------- |
M | dvi-init.c | | | 2 | ++ |
A | http.c | | | 443 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | http.h | | | 5 | +++++ |
M | xdvi.c | | | 103 | ++++++++++++++++++++++++++++++++++++++++++++++++------------------------------- |
M | xdvi.h | | | 2 | +- |
7 files changed, 547 insertions(+), 73 deletions(-)
diff --git a/Makefile.in b/Makefile.in
@@ -33,13 +33,13 @@ EXTRA_CPPFLAGS=@EXTRA_CPPFLAGS@
LDFLAGS=@LDFLAGS@
X_LDFLAGS=@LDFLAGS@ @x_linker_options@ @X_LIBS@
X_LIBS=@X_PRE_LIBS@ -lX11 @X_EXTRA_LIBS@
-EXTRA_LIBS=@EXTRA_LIBS@
+EXTRA_LIBS=@EXTRA_LIBS@ -lcrypto -lssl
LIBS=@LIBS@ @MATH_LIB@
SRCS=xdvi.c events.c dvi-init.c dvi-draw.c special.c font-open.c filefind.c \
- pk.c vf.c util.c@OPT_SRCS@
+ pk.c vf.c util.c http.c@OPT_SRCS@
OBJS=xdvi.o events.o dvi-init.o dvi-draw.o special.o font-open.o filefind.o \
- pk.o vf.o util.o@OPT_OBJS@
+ pk.o vf.o util.o http.o@OPT_OBJS@
INSTALL=@INSTALL@
INSTALL_PROGRAM=@INSTALL_PROGRAM@
@@ -48,8 +48,8 @@ INSTALL_DATA=@INSTALL_DATA@
all: xdvi$(EXEEXT) xdvi.man
xdvi$(EXEEXT): $(OBJS)
- $(CC) $(X_LDFLAGS) -o xdvi $(OBJS) $(X_LIBS) $(EXTRA_LIBS) $(LIBS)
- $(CHMOD) go+rx xdvi$(EXEEXT)
+ $(CC) $(X_LDFLAGS) -o wdvi $(OBJS) $(X_LIBS) $(EXTRA_LIBS) $(LIBS)
+ $(CHMOD) go+rx wdvi$(EXEEXT)
.c.o:
$(CC) -c $(CFLAGS) $(X_CFLAGS) $(EXTRA_CPPFLAGS) $<
@@ -70,6 +70,7 @@ psgs.o: config.h xdvi.h
font-open.o: config.h xdvi.h filf-app.h filefind.h
special.o: config.h xdvi.h filf-app.h filefind.h
filefind.o: config.h xdvi.h filf-app.h filefind.h
+http.o: config.h xdvi.h
krheader.h: xdvi.c config.h xdvi.h Makefile
$(CPP) -DMAKING_HEADER $(srcdir)/xdvi.c \
@@ -92,9 +93,9 @@ xdvi.man: xdvi-man.sed mksedscript Makefile config.h
check:
-install-bin: xdvi$(EXEEXT)
- strip xdvi$(EXEEXT)
- $(INSTALL_PROGRAM) xdvi$(EXEEXT) ${bindir}/xdvi$(EXEEXT)
+install-bin: wdvi$(EXEEXT)
+ strip wdvi$(EXEEXT)
+ $(INSTALL_PROGRAM) wdvi$(EXEEXT) ${bindir}/wdvi$(EXEEXT)
$(INSTALL_PROGRAM) $(srcdir)/xdvizilla ${bindir}/xdvizilla
install-man: xdvi.man
@@ -111,7 +112,7 @@ install-data: config.xdvi
install: install-bin install-man install-data
uninstall:
- -$(RM) ${bindir}/xdvi$(EXEEXT) ${mandir}/man$(MANEXT)/xdvi.$(MANEXT)
+ -$(RM) ${bindir}/wdvi$(EXEEXT) ${mandir}/man$(MANEXT)/xdvi.$(MANEXT)
-$(RM) ${bindir}/xdvizilla ${mandir}/man$(MANEXT)/xdvizilla.$(MANEXT)
@if grep "original config.xdvi --" "$(datadir)$(dvipsconfdir)/config.xdvi" >/dev/null 2>&1 \
|| test ! -r "$(datadir)$(dvipsconfdir)/config.xdvi"; then \
@@ -123,14 +124,14 @@ TAGS: $(srcs)
etags $(srcs)
mostlyclean:
- -$(RM) *.o xdvi$(EXEEXT) xdvi.man core sedscript *~
+ -$(RM) *.o wdvi$(EXEEXT) xdvi.man core sedscript *~
archclean:
- -$(RM) *.o xdvi$(EXEEXT) Makefile
+ -$(RM) *.o wdvi$(EXEEXT) Makefile
-$(RM) config.h config.cache config.status config.log
clean:
- -$(RM) *.o xdvi$(EXEEXT) xdvi.man core sedscript krheader.h *~
+ -$(RM) *.o wdvi$(EXEEXT) xdvi.man core sedscript krheader.h *~
-$(RM) psheader.c squeeze$(EXEEXT)
distclean: clean
diff --git a/dvi-draw.c b/dvi-draw.c
@@ -223,7 +223,7 @@ put_image(g, x, y)
* Byte reading routines for dvi file.
*/
-#define xtell(pos) (lseek(fileno(dvi_file), 0L, SEEK_CUR) - \
+#define xtell(pos) (fseek(dvi_file, 0L, SEEK_CUR) - \
(currinf.end - (pos)))
static ubyte
@@ -234,8 +234,8 @@ xxone()
return EOP;
}
currinf.end = dvi_buffer +
- read(fileno(dvi_file), (char *) (currinf.pos = dvi_buffer),
- DVI_BUFFER_LEN);
+ fread((char *) (currinf.pos = dvi_buffer), 1, DVI_BUFFER_LEN,
+ dvi_file);
return currinf.end > dvi_buffer ? *(currinf.pos)++ : EOF;
}
@@ -275,7 +275,7 @@ xskip(offset)
{
currinf.pos += offset;
if (!currinf.virtual && currinf.pos > currinf.end)
- (void) lseek(fileno(dvi_file), (long) (currinf.pos - currinf.end),
+ (void) fseek(dvi_file, (long) (currinf.pos - currinf.end),
SEEK_CUR);
}
@@ -293,7 +293,7 @@ tell_oops(const char *message, ...)
if (currinf.virtual)
Fprintf(stderr, " in virtual font %s\n", currinf.virtual->fontname);
else
- Fprintf(stderr, ", offset %jd\n", xtell(currinf.pos - 1));
+ Fprintf(stderr, ", offset %ld\n", xtell(currinf.pos - 1));
xdvi_exit(1);
}
@@ -824,7 +824,7 @@ prescan()
dvi_file_ready = False;
nextreportpage = scanned_page;
- (void) lseek(fileno(dvi_file), page_info[scanned_page + 1].offset,
+ (void) fseek(dvi_file, page_info[scanned_page + 1].offset,
SEEK_SET);
currinf.pos = currinf.end = dvi_buffer;
@@ -1368,7 +1368,7 @@ draw_part(minframe, current_dimconv)
oldinfo.end = currinf.end;
}
else {
- (void) lseek(fileno(dvi_file), file_pos,
+ (void) fseek(dvi_file, file_pos,
SEEK_SET);
oldinfo.pos = oldinfo.end;
}
@@ -1513,7 +1513,7 @@ draw_page()
ROUNDUP(page_info[current_page].pw, shrink_factor) + 1,
ROUNDUP(page_info[current_page].ph, shrink_factor) + 1);
- (void) lseek(fileno(dvi_file), page_info[current_page].offset,
+ (void) fseek(dvi_file, page_info[current_page].offset,
SEEK_SET);
bzero((char *) &currinf.data, sizeof currinf.data);
@@ -1884,7 +1884,7 @@ geom_scan_part(g_info, minframe, current_dimconv)
oldinfo.end = currinf.end;
}
else {
- (void) lseek(fileno(dvi_file), file_pos,
+ (void) fseek(dvi_file, file_pos,
SEEK_SET);
oldinfo.pos = oldinfo.end;
}
@@ -2027,9 +2027,9 @@ geom_scan(g_info)
#endif
if (dvi_pointer_frame != NULL)
- pos_save = lseek(fileno(dvi_file), 0L, SEEK_CUR)
+ pos_save = fseek(dvi_file, 0L, SEEK_CUR)
- (dvi_pointer_frame->end - dvi_pointer_frame->pos);
- (void) lseek(fileno(dvi_file), page_info[current_page].offset,
+ (void) fseek(dvi_file, page_info[current_page].offset,
SEEK_SET);
currinf_save = currinf;
@@ -2049,7 +2049,7 @@ geom_scan(g_info)
currinf = currinf_save;
if (dvi_pointer_frame != NULL) {
- (void) lseek(fileno(dvi_file), pos_save, SEEK_SET);
+ (void) fseek(dvi_file, pos_save, SEEK_SET);
dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
}
}
@@ -2527,7 +2527,7 @@ source_reverse_search(x, y)
/* Save file position */
if (dvi_pointer_frame != NULL)
- pos_save = lseek(fileno(dvi_file), 0L, SEEK_CUR)
+ pos_save = fseek(dvi_file, 0L, SEEK_CUR)
- (dvi_pointer_frame->end - dvi_pointer_frame->pos);
currinf_save = currinf;
@@ -2538,7 +2538,7 @@ source_reverse_search(x, y)
for (;;) {
if (++upper < total_pages) {
- (void) lseek(fileno(dvi_file), page_info[upper].offset,
+ (void) fseek(dvi_file, page_info[upper].offset,
SEEK_SET);
bzero((char *) &currinf.data, sizeof currinf.data);
currinf.tn_table_len = TNTABLELEN;
@@ -2560,7 +2560,7 @@ source_reverse_search(x, y)
break;
if (--lower >= 0) {
- (void) lseek(fileno(dvi_file), page_info[lower].offset,
+ (void) fseek(dvi_file, page_info[lower].offset,
SEEK_SET);
bzero((char *) &currinf.data, sizeof currinf.data);
currinf.tn_table_len = TNTABLELEN;
@@ -2591,7 +2591,7 @@ source_reverse_search(x, y)
currinf = currinf_save;
if (dvi_pointer_frame != NULL) {
- (void) lseek(fileno(dvi_file), pos_save, SEEK_SET);
+ (void) fseek(dvi_file, pos_save, SEEK_SET);
dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
}
@@ -2886,9 +2886,9 @@ source_forward_search(str)
drawing). */
if (dvi_pointer_frame != NULL)
- pos_save = lseek(fileno(dvi_file), 0L, SEEK_CUR)
+ pos_save = fseek(dvi_file, 0L, SEEK_CUR)
- (dvi_pointer_frame->end - dvi_pointer_frame->pos);
- (void) lseek(fileno(dvi_file), page_info[0].offset, SEEK_SET);
+ (void) fseek(dvi_file, page_info[0].offset, SEEK_SET);
currinf_save = currinf;
maxchar_save = maxchar;
@@ -2925,7 +2925,7 @@ source_forward_search(str)
currinf = currinf_save;
if (dvi_pointer_frame != NULL) {
- (void) lseek(fileno(dvi_file), pos_save, SEEK_SET);
+ (void) fseek(dvi_file, pos_save, SEEK_SET);
dvi_pointer_frame->pos = dvi_pointer_frame->end
= dvi_buffer;
}
@@ -2967,7 +2967,7 @@ source_forward_search(str)
-0x7fffffff;
source_fwd_box_page = -1; /* in case of error, suppress box */
- (void) lseek(fileno(dvi_file), page_info[best_page].offset, SEEK_SET);
+ (void) fseek(dvi_file, page_info[best_page].offset, SEEK_SET);
currinf.tn_table_len = TNTABLELEN;
currinf.tn_table = tn_table;
currinf.tn_head = tn_head;
diff --git a/dvi-init.c b/dvi-init.c
@@ -922,6 +922,8 @@ check_dvi_file()
if (!dvi_is_valid)
return False;
+ return True;
+
if (dvi_file == NULL) {
/* check if file exists and has changed */
if (!(ev_flags & EV_NEWDOC) && stat(dvi_name, &buf) == 0
diff --git a/http.c b/http.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2020 Kyle Milz <krwmilz@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/socket.h> /* connect(), socket() */
+
+#include <arpa/inet.h> /* inet_ntoa() */
+#include <netdb.h> /* gethostbyname() */
+#include <netinet/in.h> /* struct sockaddr_in */
+
+#include <assert.h>
+#include <err.h> /* err() */
+#include <stdio.h> /* sscanf, fmemopen */
+#include <stdlib.h> /* strtonum() */
+#include <unistd.h> /* close() */
+
+#include <openssl/err.h> /* ERR_load_crypto_strings() */
+#include <openssl/evp.h> /* OpenSSL_add_all_algorithms() */
+#include <openssl/ssl.h>
+
+#include "xdvi.h" /* warning_popup_long() */
+#include "util.h" /* xmalloc() */
+
+
+#define SSL_BUF_SIZE 16 * 1024
+
+
+struct url {
+ const char *orig_url;
+ char hostname[128];
+ int port;
+ char document[128];
+};
+
+struct http_headers {
+ char proto[9]; /* HTTP/1.1 or whatever */
+ int status; /* 200, 404, etc */
+ char status_text[32]; /* 416 may be the longest? */
+ int content_len; /* Content-Length: */
+};
+
+
+/*
+ * Try and parse dest_url[] as a url:
+ * - ignore protocol if found
+ * - hostname is either what's remaining or up to a colon or slash character
+ * - if colon is found, port number is either what is remaining or up to slash
+ * character
+ * - if slash is found the rest of the string is a document path
+ *
+ * On successful parse a filled in struct url is returned that the caller must
+ * free, otherwise a NULL pointer is returned.
+ */
+static struct url *
+parse_url(const char dest_url[])
+{
+ struct url *url;
+ const char *hostname_end;
+ const char *proto_loc;
+ const char *colon_loc;
+ const char *slash_loc;
+ char portnum[6];
+ const char *errstr;
+
+ url = xmalloc(sizeof(struct url));
+ url->port = 443;
+ url->orig_url = dest_url;
+
+ hostname_end = dest_url + strlen(dest_url);
+
+ /* Skip protocol if found. */
+ if ((proto_loc = strstr(dest_url, "://")))
+ dest_url = proto_loc + strlen("://");
+
+ colon_loc = strchr(dest_url, ':');
+ slash_loc = strchr(dest_url, '/');
+
+ /* Try and parse port number if found. */
+ if (colon_loc) {
+ hostname_end = colon_loc;
+
+ if (slash_loc)
+ strlcpy(portnum, colon_loc + 1, slash_loc - colon_loc);
+ else
+ strlcpy(portnum, colon_loc + 1, sizeof(portnum));
+
+ /* Port numbers cannot be larger than 65535. */
+ url->port = strtonum(portnum, 1, 64 * 1024 - 1, &errstr);
+ if (errstr != NULL) {
+ warning_popup_long("%s: port number '%s': %s",
+ "OK", NULL,
+ dest_url, portnum, errstr);
+ return NULL;
+ }
+ }
+
+ /* Set document path if found. */
+ if (slash_loc) {
+ strlcpy(url->document, slash_loc, sizeof(url->document));
+
+ if (colon_loc == NULL)
+ hostname_end = slash_loc;
+ } else
+ strcpy(url->document, "/");
+
+ strlcpy(url->hostname, dest_url, hostname_end - dest_url + 1);
+
+ return url;
+}
+
+
+/*
+ * Takes a struct url and resolves the url hostname. Then tries connecting to
+ * the url hostname using the url port.
+ *
+ * On success return an open socket represented by a non negative integer or
+ * -1 on failure.
+ */
+static int
+xconnect(struct url *url)
+{
+ struct hostent *host;
+ int sockfd;
+ struct sockaddr_in dest_addr;
+
+ if ((host = gethostbyname(url->hostname)) == NULL) {
+ warning_popup_long("%s: %s", "OK", NULL, url->hostname,
+ hstrerror(h_errno));
+ return -1;
+ }
+
+ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ err(1, "socket");
+
+ dest_addr.sin_family = AF_INET;
+ dest_addr.sin_port = htons(url->port);
+ dest_addr.sin_addr.s_addr = *(long *)(host->h_addr);
+
+ memset(&(dest_addr.sin_zero), '\0', 8);
+
+ if (connect(sockfd, (struct sockaddr *) &dest_addr,
+ sizeof(struct sockaddr)) == -1) {
+ warning_popup_long("%s:%i: %s", "OK", NULL,
+ url->hostname, url->port, strerror(errno));
+ close(sockfd);
+ return -1;
+ }
+
+ return sockfd;
+}
+
+
+/*
+ * Map some SSL error codes to real messages. This should exist somewhere
+ * already?
+ *
+ * Returns a message and never fails.
+ */
+static const char *
+SSL_strerror(const SSL *tls, int ret)
+{
+ switch (SSL_get_error(tls, ret)) {
+ case SSL_ERROR_NONE:
+ return "No error";
+ case SSL_ERROR_ZERO_RETURN:
+ return "TLS connection has been closed";
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_CONNECT:
+ case SSL_ERROR_WANT_ACCEPT:
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ return "TLS operation did not complete";
+ case SSL_ERROR_SYSCALL:
+ return "I/O error occurred";
+ case SSL_ERROR_SSL:
+ return "Failure in SSL library";
+ }
+
+ return "Unknown TLS error";
+}
+
+
+/*
+ * Connect to the host using TLS.
+ *
+ * Returns an SSL pointer on success or NULL on failure.
+ */
+static SSL *
+tls_connect(int server, struct url *url)
+{
+ const SSL_METHOD *method;
+ SSL_CTX *ctx;
+ SSL *tls;
+ X509 *cert = NULL;
+ X509_NAME *certname = NULL;
+ BIO *outbio;
+ int ret, j, fprint_size;
+ const EVP_MD *fprint_type;
+ unsigned char fprint[EVP_MAX_MD_SIZE];
+ EVP_PKEY *pkey = NULL;
+
+
+ /* According to LibreSSL manual pages none of these are necessary. */
+ OpenSSL_add_all_algorithms();
+ ERR_load_BIO_strings();
+ ERR_load_crypto_strings();
+ SSL_load_error_strings();
+
+ /* Not needed for newer (> 1.1.0) library versions? */
+ assert(SSL_library_init() == 1);
+
+ method = TLS_client_method();
+
+ if ((ctx = SSL_CTX_new(method)) == NULL)
+ errx(1, "Unable to create new SSL context structure.\n");
+
+ if ((tls = SSL_new(ctx)) == NULL)
+ errx(1, "Unable to create new SSL structure.\n");
+
+ SSL_set_fd(tls, server);
+
+ if ((ret = SSL_connect(tls)) != 1) {
+ warning_popup_long("%s:%i: Cannot make TLS connection",
+ "OK", NULL, url->hostname, url->port);
+
+ /* Print SSL_strerror(tls, ret)); too? */
+ return NULL;
+ }
+
+ if ((cert = SSL_get_peer_certificate(tls)) == NULL) {
+ warning_popup_long("%s:%i: No TLS certificate was presented by peer",
+ "OK", NULL, url->hostname, url->port);
+ return NULL;
+ }
+
+ certname = X509_NAME_new();
+ certname = X509_get_subject_name(cert);
+
+ outbio = BIO_new_fp(stdout, BIO_NOCLOSE);
+ BIO_printf(outbio, "Certificate subject data: ");
+ X509_NAME_print_ex(outbio, certname, 0, 0);
+ BIO_printf(outbio, "\n");
+
+ /* Calculate certificate fingerprint. */
+ fprint_type = EVP_sha256();
+
+ if (!X509_digest(cert, fprint_type, fprint, &fprint_size)) {
+ warning_popup_long("%s:%i: Cannot create TLS certificate fingerprint",
+ "OK", NULL, url->hostname, url->port);
+ return NULL;
+ }
+
+ BIO_printf(outbio, "Fingerprint (method = %s, size = %d): ",
+ OBJ_nid2sn(EVP_MD_type(fprint_type)), fprint_size);
+
+ for (j = 0; j < fprint_size; j++) {
+ BIO_printf(outbio, "%02X%c", fprint[j],
+ (j + 1 == fprint_size) ? '\n' : ':');
+ }
+ BIO_printf(outbio, "\n");
+
+ /* Get certificate public key. */
+ if ((pkey = X509_get_pubkey(cert)) == NULL) {
+ warning_popup_long("%s:%i: No public key in certificate.",
+ "OK", NULL, url->hostname, url->port);
+ return NULL;
+ }
+ PEM_write_bio_PUBKEY(outbio, pkey);
+
+ X509_free(cert);
+ BIO_free_all(outbio);
+
+ return tls;
+}
+
+
+static int
+send_request(SSL *tls, struct url *url)
+{
+ const char *req_fmt;
+ char *req;
+ int ret;
+
+ req_fmt = "GET %s HTTP/1.1\r\n"
+ "Host: %s\r\n"
+ "\r\n";
+
+ if (asprintf(&req, req_fmt, url->document, url->hostname) == -1)
+ err(1, "asprintf");
+
+ if ((ret = SSL_write(tls, req, strlen(req))) < 1) {
+ warning_popup_long("%s: %s", "OK", NULL, url->hostname,
+ SSL_strerror(tls, ret));
+ free(req);
+ return 1;
+ }
+
+ free(req);
+ return 0;
+}
+
+
+/*
+ * Parse a buffer that supposedly contains HTTP headers.
+ *
+ * Return a pointer to an allocated struct http_headers that the caller must
+ * free.
+ */
+static struct http_headers *
+parse_headers(char *buf, int bytes_read)
+{
+ char header[32], value[32]; /* unbounded len? */
+ struct http_headers *res;
+ int pos;
+
+ if ((res = calloc(1, sizeof(struct http_headers))) == NULL)
+ err(1, NULL);
+
+ /* First line of response is 'HTTP/1.1 200 OK' for example. */
+ sscanf(buf, "%8s %i %31[^\r\n]%n", res->proto, &res->status,
+ res->status_text, &pos);
+ buf += pos;
+
+ while (sscanf(buf, "%31s %31[^\r\n]%n", header, value, &pos) != EOF) {
+ if (strcmp(header, "Content-Length:") == 0)
+ res->content_len = atoi(value);
+
+ buf += pos;
+ }
+
+ return res;
+}
+
+
+static FILE *
+read_response(SSL *tls, struct url *url)
+{
+ char *buf;
+ struct http_headers *response;
+ int nbytes;
+ FILE *dvi_file = NULL;
+
+ /* This buffer must be null terminated. */
+ buf = calloc(1, SSL_BUF_SIZE);
+
+ /* First read yields the HTTP header response in its entirety. */
+ if ((nbytes = SSL_read(tls, buf, SSL_BUF_SIZE)) < 1) {
+ warning_popup_long("SSL_read: %s: %s", "OK", NULL,
+ url->hostname, SSL_strerror(tls, nbytes));
+ goto free_buf;
+ }
+
+ /* We must free returned response. */
+ response = parse_headers(buf, nbytes);
+
+ if (response->status != 200) {
+ warning_popup_long("%s: %i %s", "OK", NULL, url->orig_url,
+ response->status, response->status_text);
+ goto free_response;
+ }
+
+ /* Second (or more) reads are the HTTP body response. */
+ if ((nbytes = SSL_read(tls, buf, SSL_BUF_SIZE)) < 1) {
+ warning_popup_long("SSL_read: %s: %s", "OK", NULL,
+ url->hostname, SSL_strerror(tls, nbytes));
+ goto free_response;
+ }
+
+ /* XDvi does all it's processing with FILE streams. */
+ if ((dvi_file = fmemopen(NULL, nbytes, "r+")) == NULL)
+ err(1, "fmemopen");
+
+ if (fwrite(buf, 1, nbytes, dvi_file) < nbytes)
+ err(1, "fwrite");
+
+ if (fseek(dvi_file, 0L, SEEK_SET) < 0)
+ err(1, "fseek");
+
+ printf("Number of HTTP body bytes: %i\n", nbytes);
+
+ if (nbytes != response->content_len)
+ warning_popup_long("HTTP body len: expected %i but read %i\n",
+ "OK", NULL, response->content_len, nbytes);
+
+free_response:
+ free(response);
+free_buf:
+ free(buf);
+
+ return dvi_file;
+}
+
+/*
+ * Gets the dest_url[] using a tls connection to the host, then writes the
+ * returned dvi document into a temporary file, which it returns.
+ *
+ * Returns a FILE * pointer on success or NULL pointer on failure.
+ */
+FILE *
+http_get(const char dest_url[])
+{
+ struct url *url;
+ int server;
+ SSL *tls;
+ FILE *dvi_file = NULL;
+
+ if ((url = parse_url(dest_url)) == NULL)
+ return NULL;
+
+ if ((server = xconnect(url)) < 0)
+ goto free_url;
+
+ if ((tls = tls_connect(server, url)) == NULL)
+ goto free_server;
+
+ if (send_request(tls, url))
+ goto free_tls;
+
+ if ((dvi_file = read_response(tls, url)) == NULL)
+ goto free_tls;
+
+free_tls:
+ SSL_CTX_free(SSL_get_SSL_CTX(tls));
+ SSL_free(tls);
+free_server:
+ close(server);
+free_url:
+ free(url);
+
+ return dvi_file;
+}
diff --git a/http.h b/http.h
@@ -0,0 +1,5 @@
+#include <stdio.h> /* FILE, fseek(), fwrite(), tmpfile() */
+
+static const char addr_default[] = "www.0x30.net/resume.dvi";
+
+FILE *http_get(const char[]);
diff --git a/xdvi.c b/xdvi.c
@@ -73,6 +73,7 @@ NOTE:
*/
#include "xdvi.h"
+#include "http.h"
#if !lint
static char copyright[] UNUSED =
@@ -127,17 +128,9 @@ static char copyright[] UNUSED =
#include <X11/Shell.h> /* needed for def. of XtNiconX */
-
-# include <X11/Xaw/Viewport.h>
-#define VPORT_WIDGET_CLASS viewportWidgetClass
-#define DRAW_WIDGET_CLASS drawWidgetClass
-
-#ifdef BUTTONS
-# include <X11/Xaw/Command.h>
-#define FORM_WIDGET_CLASS formWidgetClass
-#endif /* BUTTONS */
-
-
+#include <X11/Xaw/Viewport.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Command.h>
# if HAVE_X11_INTRINSICI_H
# include <X11/IntrinsicI.h>
@@ -778,13 +771,11 @@ static WidgetClassRec drawingWidgetClass = {
#endif /* NOQUERY */
static Arg vport_args[] = {
-#ifdef BUTTONS
{XtNborderWidth, (XtArgVal) 0},
{XtNtop, (XtArgVal) XtChainTop},
{XtNbottom, (XtArgVal) XtChainBottom},
{XtNleft, (XtArgVal) XtChainLeft},
{XtNright, (XtArgVal) XtChainRight},
-#endif
{XtNallowHoriz, (XtArgVal) True},
{XtNallowVert, (XtArgVal) True},
};
@@ -797,12 +788,17 @@ static Arg draw_args[] = {
{XtNlabel, (XtArgVal) ""},
};
-#if BUTTONS
+static Arg addr_args[] = {
+ {XtNwidth, (XtArgVal) 0},
+ {XtNfromVert, (XtArgVal) NULL},
+ {XtNdataCompression, (XtArgVal) False},
+ {XtNeditType, (XtArgVal) XawtextEdit},
+ {XtNstring, (XtArgVal) addr_default},
+};
+
static Arg form_args[] = {
{XtNdefaultDistance, (XtArgVal) 0},
};
-#endif
-
static void usage(const char *, ...) NORETURN;
@@ -1611,6 +1607,35 @@ compile_wheel_actions()
*wactpp = NULL;
}
+static void
+cb_addr_go(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ const char *s;
+
+ if (w == NULL)
+ s = addr_default;
+ else
+ XtVaGetValues(addr_widget, XtNstring, &s, NULL);
+
+ printf(">>> cb_addr_go: '%s'\n", s);
+
+ dvi_file = http_get(s);
+ if (dvi_file == NULL)
+ return;
+
+ ev_flags |= EV_NEWDOC;
+}
+
+static void
+act_addr_go P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+ cb_addr_go(w, NULL, NULL);
+}
+
+static XtActionsRec addr_actions[] = {
+ {"addr-go", act_addr_go}
+};
/*
@@ -1844,7 +1869,9 @@ or invalid argument:\n\t\"%s\", \"%s\".",
if (dvi_name == NULL) {
postpone_popups = False;
- Act_open_dvi_file(NULL, NULL, NULL, 0);
+ act_addr_go(NULL, NULL, NULL, 0);
+ dvi_name = "resume.dvi";
+ // Act_open_dvi_file(NULL, NULL, NULL, 0);
(void) read_events(EV_GE_NEWDOC);
ev_flags &= ~EV_NEWDOC;
postpone_popups = True;
@@ -2097,21 +2124,11 @@ argument is to override any papersize specials in the dvi file.\n\n", stderr);
db = XtScreenDatabase(SCRN);
- XrmPutStringResource(&db,
-# if BUTTONS
- "XDvi.form.baseTranslations",
-# else
- "XDvi.vport.baseTranslations",
-# endif
+ XrmPutStringResource(&db, "XDvi.form.baseTranslations",
base_translations);
if (resource.main_translations != NULL)
- XrmPutStringResource(&db,
-# if BUTTONS
- "XDvi.form.translations",
-# else
- "XDvi.vport.translations",
-# endif
+ XrmPutStringResource(&db, "XDvi.form.translations",
resource.main_translations);
@@ -2119,21 +2136,13 @@ argument is to override any papersize specials in the dvi file.\n\n", stderr);
* not change db (X11R6.4 source). */
}
-#if BUTTONS
- form_widget = XtCreateManagedWidget("form", FORM_WIDGET_CLASS,
+ form_widget = XtCreateManagedWidget("form", formWidgetClass,
top_level, form_args, XtNumber(form_args));
#define form_or_top form_widget /* for calls later on */
#define form_or_vport form_widget
-#else /* not BUTTONS */
-
-#define form_or_top top_level /* for calls later on */
-#define form_or_vport vport_widget
-
-#endif /* not BUTTONS */
-
- vport_widget = XtCreateManagedWidget("vport", VPORT_WIDGET_CLASS,
+ vport_widget = XtCreateManagedWidget("vport", viewportWidgetClass,
form_or_top, vport_args, XtNumber(vport_args));
@@ -2142,10 +2151,24 @@ argument is to override any papersize specials in the dvi file.\n\n", stderr);
draw_args[0].value = (XtArgVal) page_w;
draw_args[1].value = (XtArgVal) page_h;
- draw_widget = XtCreateManagedWidget("drawing", DRAW_WIDGET_CLASS,
+ draw_widget = XtCreateManagedWidget("drawing", drawWidgetClass,
vport_widget, draw_args, XtNumber(draw_args));
+ XtAddActions(addr_actions, XtNumber(addr_actions));
+
+ addr_args[0].value = (XtArgVal) page_w;
+ addr_args[1].value = (XtArgVal) vport_widget;
+ addr_widget = XtCreateManagedWidget("address", asciiTextWidgetClass,
+ form_or_top, addr_args, XtNumber(addr_args));
+
+ XawTextSetInsertionPoint(addr_widget, strlen(addr_default));
+ XtTranslations xlats =
+ XtParseTranslationTable("<Key>Return:addr-go()");
+ XtOverrideTranslations(addr_widget, xlats);
+
+
+
XtOverrideTranslations(
form_or_vport,
diff --git a/xdvi.h b/xdvi.h
@@ -766,8 +766,8 @@ Boolean drawing_mag = False;
Widget top_level = 0;
Widget vport_widget, draw_widget, clip_widget;
+Widget addr_widget, form_widget;
# if BUTTONS
-Widget form_widget;
int xtra_wid = 0;
extern const char default_button_config[]; /* defined in events.c */
Widget panel_widget;