ref: 3c6cac0bb49c746db39833c27fb24044ccf52c11
parent: 57fc835f287416040649a7b5fb777119a1ff432a
author: telephil9 <telephil9@gmail.com>
date: Wed Apr 29 01:17:10 EDT 2020
Handle binary item types and some cleanup. Binary item types can now be downloaded. Do not sysfatal on non fatal error but report error message.
--- a/gopher.c
+++ b/gopher.c
@@ -10,6 +10,7 @@
#include "icons.h"
void texthit(Panel *p, int b, Rtext *t);
+void message(char *s, ...);
Image *backi;
Image *fwdi;
@@ -19,23 +20,11 @@
Panel *urlp;
Panel *textp;
Panel *statusp;
+Panel *urlp;
char *url;
Mouse *mouse;
Hist *hist = nil;
-Gmenu*
-mkmenu(Link *l)
-{
- Gmenu *m;
-
- m = malloc(sizeof *m);
- if(m==nil)
- sysfatal("malloc: %r");
- m->link = l;
- m->text = nil;
- return m;
-}
-
Link*
mklink(char *addr, char *sel, int type)
{
@@ -50,6 +39,12 @@
return l;
}
+Link*
+clonelink(Link *l)
+{
+ return mklink(l->addr, l->sel, l->type);
+}
+
int
seltype(char c)
{
@@ -83,15 +78,16 @@
return t;
}
+static char *Typestr[] = {
+ "FILE", "DIR", "NS", "ERR", "HEX",
+ "DOS", "UU", "?", "TELNET", "BIN",
+ "MIRROR", "GIF", "IMG", "T3270", "DOC",
+ "HTML", "", "SND", "EOF",
+};
+
char*
seltypestr(int type)
{
- static char *Typestr[] = {
- "FILE", "DIR", "NS", "ERR", "HEX",
- "DOS", "UU", "?", "TELNET", "BIN",
- "MIRROR", "GIF", "IMG", "T3270", "DOC",
- "HTML", "", "SND", "EOF",
- };
return smprint("%6s", Typestr[type]);
};
@@ -107,7 +103,7 @@
m = malloc(sizeof *m);
if(m==nil)
sysfatal("malloc: %r");
- m->link = l;
+ m->link = clonelink(l);
m->text = nil;
plrtstr(&m->text, 1000000, 0, 0, font, strdup(" "), 0, 0);
for(;;){
@@ -148,7 +144,7 @@
m = malloc(sizeof *m);
if(m==nil)
sysfatal("malloc: %r");
- m->link = l;
+ m->link = clonelink(l);
m->text = nil;
plrtstr(&m->text, 1000000, 0, 0, font, strdup(" "), 0, 0);
for(;;){
@@ -177,8 +173,10 @@
Gmenu *m;
fd = dial(l->addr, 0, 0, 0);
- if(fd < 0)
- sysfatal("dial: %r");
+ if(fd < 0){
+ message("unable to connect to %s: %r", l->addr);
+ return nil;
+ }
fprint(fd, "%s\r\n", l->sel);
bp = Bfdopen(fd, OREAD);
if(bp==nil){
@@ -202,14 +200,59 @@
return m;
}
+void
+message(char *s, ...)
+{
+ static char buf[1024];
+ char *out;
+ va_list args;
+
+ va_start(args, s);
+ out = buf + vsnprint(buf, sizeof(buf), s, args);
+ va_end(args);
+ *out='\0';
+ plinitlabel(statusp, PACKN|FILLX, buf);
+ pldraw(statusp, screen);
+ flushimage(display, 1);
+}
+
+char*
+linktourl(Link *l)
+{
+ char *f[3], *a, *s;
+ int n;
+
+ a = strdup(l->addr);
+ n = getfields(a, f, 3, 0, "!");
+ if(n != 3)
+ s = smprint("Url: gopher://%s%s", l->addr, l->sel);
+ else if(atoi(f[2])!=70)
+ s = smprint("Url: gopher://%s:%s%s", f[1], f[2], l->sel);
+ else
+ s = smprint("Url: gopher://%s%s", f[1], l->sel);
+ free(a);
+ return s;
+}
+
void
+seturl(Link *l)
+{
+ free(url);
+ url = linktourl(l);
+}
+
+void
show(Gmenu *m)
{
plinittextview(textp, PACKE|EXPAND, ZP, m->text, texthit);
pldraw(textp, screen);
+ plinitlabel(urlp, PACKN|FILLX, url);
+ pldraw(urlp, screen);
+ message("gopher!");
}
-void freetext(Rtext *t){
+void
+freetext(Rtext *t){
Rtext *tt;
Link *l;
@@ -221,7 +264,8 @@
if(l = t->user){
t->user = 0;
free(l->addr);
- free(l->sel);
+ if(l->sel!=nil && l->sel[0]!=0)
+ free(l->sel);
free(l);
}
}
@@ -237,9 +281,11 @@
for(n = h->n; h; h = n){
m = h->m;
freetext(m->text);
- free(m->link->addr);
- free(m->link->sel);
- free(m->link);
+ if(m->link!=nil){
+ free(m->link->addr);
+ free(m->link->sel);
+ free(m->link);
+ }
free(h);
}
}
@@ -250,13 +296,19 @@
Gmenu *m;
Hist *h;
+ seturl(l);
+ message("loading %s...", url);
m = render(l);
+ if(m==nil)
+ return;
show(m);
h = malloc(sizeof *h);
if(h == nil)
sysfatal("malloc: %r");
+/* FIXME
if(hist != nil && hist->n != nil)
freehist(hist->n);
+*/
h->p = hist;
h->n = nil;
h->m = m;
@@ -328,6 +380,57 @@
close(fd);
}
+void
+save(Link *l, char *name){
+ char buf[1024];
+ int ifd, ofd;
+
+ ifd = dial(l->addr, 0, 0, 0);
+ if(ifd < 0){
+ message("save: %s: %r", name);
+ return;
+ }
+ fprint(ifd, "%s\r\n", l->sel);
+ ofd=create(name, OWRITE, 0666);
+ if(ofd < 0){
+ message("save: %s: %r", name);
+ return;
+ }
+ switch(rfork(RFNOTEG|RFNAMEG|RFFDG|RFMEM|RFPROC|RFNOWAIT)){
+ case -1:
+ message("Can't fork: %r");
+ break;
+ case 0:
+ dup(ifd, 0);
+ close(ifd);
+ dup(ofd, 1);
+ close(ofd);
+
+ snprint(buf, sizeof(buf),
+ "{tput -p || cat} |[2] {aux/statusmsg -k %q >/dev/null || cat >/dev/null}", name);
+ execl("/bin/rc", "rc", "-c", buf, nil);
+ exits("exec");
+ }
+ close(ifd);
+ close(ofd);
+}
+
+char*
+linktofile(Link *l){
+ char *n, *s;
+
+ if(l==nil)
+ return nil;
+ n = l->sel;
+ if(n==nil || n[0]==0)
+ n = "/";
+ if(s = strrchr(n, '/'))
+ n = s+1;
+ if(n[0]==0)
+ n = "file";
+ return n;
+}
+
void
texthit(Panel *p, int b, Rtext *t)
{
@@ -360,6 +463,18 @@
free(s);
}
break;
+ case Tdos:
+ case Tbinary:
+ case Tbinhex:
+ case Tuuencoded:
+ snprint(buf, sizeof buf, "%s", linktofile(l));
+ if(eenter("Save as:", buf, sizeof buf, mouse)>0){
+ save(l, buf);
+ }
+ break;
+ default:
+ message("unhandled item type '%s'", Typestr[l->type]);
+ break;
}
}
@@ -373,6 +488,7 @@
return;
hist->p->n = hist;
hist = hist->p;
+ seturl(hist->m->link);
show(hist->m);
}
@@ -385,6 +501,7 @@
if(hist==nil || hist->n==nil)
return;
hist = hist->n;
+ seturl(hist->m->link);
show(hist->m);
}
@@ -405,18 +522,21 @@
Panel *p, *ybar, *xbar;
root = plgroup(0, EXPAND);
- p = plframe(root, PACKN|FILLX);
+ p = plgroup(root, PACKN|FILLX);
+ statusp = pllabel(p, PACKN|FILLX, "gopher!");
+ plplacelabel(statusp, PLACEW);
plbutton(p, PACKW|BITMAP, backi, backhit);
plbutton(p, PACKW|BITMAP, fwdi, nexthit);
pllabel(p, PACKW, "Go:");
plentry(p, PACKN|FILLX, 0, "", entryhit);
+ p = plgroup(root, PACKN|FILLX);
+ urlp = pllabel(p, PACKN|FILLX, "");
+ plplacelabel(urlp, PLACEW);
p = plgroup(root, PACKN|EXPAND);
ybar = plscrollbar(p, PACKW|USERFL);
xbar = plscrollbar(p, IGNORE);
textp = pltextview(p, PACKE|EXPAND, ZP, nil, nil);
plscroll(textp, xbar, ybar);
- statusp = pllabel(root, PACKN|FILLX, url);
- plplacelabel(statusp, PLACEW);
}
void
@@ -488,7 +608,7 @@
url = argv[1];
else
url = "gopher.floodgap.com";
-
+ quotefmtinstall();
if(initdraw(nil, nil, "gopher")<0)
sysfatal("initdraw: %r");
einit(Emouse|Ekeyboard);