download, progress, improved screen updates...
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 28 Jan 2023 14:14:43 +0000 (16:14 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 28 Jan 2023 14:14:43 +0000 (16:14 +0200)
Makefile
README.md
scripts/push
src/dos/tgfx.c
src/ftp.c
src/main.c
src/tgfx.h
src/tui.c
src/tui.h
src/tui_list.c
src/unix/tgfx.c

index 9eb1515..4d3cd7d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -31,8 +31,16 @@ $(bin): $(obj)
 .asm.obj:
        nasm -f obj -o $@ $[*.asm
 
+!ifdef __UNIX__
+clean: .symbolic
+       rm -f *.obj
+       rm -f objects.lnk
+       rm -f oftp.map
+       rm -f $(bin)
+!else
 clean: .symbolic
        del *.obj
        del objects.lnk
        del oftp.map
        del $(bin)
+!endif
index ae642d0..816cffb 100644 (file)
--- a/README.md
+++ b/README.md
@@ -10,6 +10,12 @@ while the other is for navigating the local filesystem.
 oftp was written to address the lack of graphical FTP clients for DOS (MS-DOS,
 FreeDOS, etc), but will also run on UNIX systems using curses for its UI.
 
+**Release status**: *Prototype*. oftp mostly works, but it's very rough, and you
+will find lots of bugs. Feel free to open bug reports, but keep in mind that the
+most obvious issues will be solved as a matter of course as this project
+progresses.
+
+
 License
 -------
 Copyright (C) John Tsiombikas <nuclear@mutantstargoat.com>
index 1067f03..103115e 100755 (executable)
@@ -4,4 +4,5 @@ fname=/etherdfs/oftp.zip
 
 #git archive -o $fname HEAD
 rm -f $fname
-zip $fname Makefile src/*.c src/*.h src/dos/*.c src/dos/*.h src/unix/*.c src/unix/*.h scripts/*
+#zip $fname Makefile src/*.c src/*.h src/dos/*.c src/dos/*.h src/unix/*.c src/unix/*.h scripts/*
+zip -x \*.swp -x \*.o -x \*.obj -r $fname *
index 39e5ccc..228f88f 100644 (file)
@@ -120,3 +120,16 @@ void tg_rect(const char *label, int x, int y, int xsz, int ysz, unsigned int fla
                tg_text(x + 2, y, "%s", label);
        }
 }
+
+int tg_gchar(int gchar)
+{
+       switch(gchar) {
+       case TGFX_LARROW:
+               return 0x1b;
+       case TGFX_RARROW:
+               return 0x1a;
+       default:
+               break;
+       }
+       return '@';
+}
index f62a3a4..8a9b4ab 100644 (file)
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -486,13 +486,16 @@ static int handle_control(struct ftp *ftp)
 
 static int handle_data(struct ftp *ftp, int s)
 {
-       int rd;
+       int i, rd;
 
        if(ftp->data == -1) {
                return -1;
        }
 
-       for(;;) {
+       /* get at most 4 packets at a time, to allow returning back to the main loop
+        * to process input
+        */
+       for(i=0; i<4; i++) {
                if((rd = recv(ftp->data, ftp->drecv, sizeof ftp->drecv, 0)) == -1) {
                        if(errno == EINTR) continue;
                        /* assume EWOULDBLOCK, try again next time */
index c360dd7..3d02652 100644 (file)
@@ -41,6 +41,13 @@ static int port = 21;
 static char curdir[PATH_MAX + 1];
 static struct ftp_dirent *localdir;
 static int local_modified;
+static struct ftp_transfer *cur_xfer;
+
+#ifdef __DOS__
+void detect_lfn(void);
+
+static int have_lfn;
+#endif
 
 
 int main(int argc, char **argv)
@@ -50,6 +57,10 @@ int main(int argc, char **argv)
        fd_set rdset;
        struct timeval tv;
 
+#ifdef __DOS__
+       detect_lfn();
+#endif
+
        if(parse_args(argc, argv) == -1) {
                return 1;
        }
@@ -78,15 +89,10 @@ int main(int argc, char **argv)
        focus = 0;
        tui_focus(uilist[focus], 1);
 
-       tg_fgcolor(TGFX_RED);
-       tg_bgcolor(TGFX_BLACK);
-       tg_rect("No conn.", 0, 0, 80, 1, 0);
+       local_modified = 1;
 
        tg_setcursor(0, 23);
 
-       tui_draw(uilist[0]);
-       tui_draw(uilist[1]);
-
        for(;;) {
                FD_ZERO(&rdset);
                maxfd = 0;
@@ -139,17 +145,41 @@ int main(int argc, char **argv)
 
 void updateui(void)
 {
-       int i, num;
+       int i, num, progr;
        struct ftp_dirent *ent;
        unsigned int upd = 0;
        char buf[128];
        const char *remdir;
+       static int prev_status;
+       static void *prev_xfer;
 
-       if(ftp->status != FTP_DISC) {
-               tg_fgcolor(TGFX_GREEN);
+       if(ftp->status != prev_status) {
+               tg_fgcolor(ftp->status ? TGFX_GREEN : TGFX_RED);
                tg_bgcolor(TGFX_BLACK);
-               tg_text(0, 0, "Conn: %s", host);
+               tg_text(0, 0, "Srv: %s", ftp->status ? host : "-");
+               upd |= 0x8000;
+               prev_status = ftp->status;
+       }
+
+       tg_fgcolor(TGFX_WHITE);
+       tg_bgcolor(TGFX_BLACK);
+       if(cur_xfer) {
+               int dir = tg_gchar(cur_xfer->op == FTP_RETR ? TGFX_RARROW : TGFX_LARROW);
+               tg_text(40, 0, "%c%s", dir, cur_xfer->rname);
+               if(!cur_xfer->total) {
+                       tg_text(75, 0, " ???%%");
+               } else {
+                       progr = 100 * cur_xfer->count / cur_xfer->total;
+                       if(progr < 0) progr = 0;
+                       if(progr > 100) progr = 100;
+                       tg_text(75, 0, " %3d%%", progr);
+               }
+               upd |= 0x8000;
+       } else if(prev_xfer) {
+               tg_rect(0, 40, 0, 40, 1, 0);
+               upd |= 0x8000;
        }
+       prev_xfer = cur_xfer;
 
        remdir = ftp_curdir(ftp);
        if(remdir && strcmp(tui_get_title(uilist[0]), remdir) != 0) {
@@ -202,6 +232,10 @@ void updateui(void)
        if(tui_isdirty(uilist[1]) || upd & 2) {
                tui_draw(uilist[1]);
        }
+
+       if(upd) {
+               tg_redraw();
+       }
 }
 
 int update_localdir(void)
@@ -271,6 +305,11 @@ int keypress(int key)
        case KB_F10:
                return -1;
 
+       case '`':
+               tui_invalidate(uilist[0]);
+               tui_invalidate(uilist[1]);
+               break;
+
        case '\t':
                tui_focus(uilist[focus], 0);
                focus ^= 1;
@@ -343,8 +382,11 @@ int keypress(int key)
                        xfer->op = FTP_RETR;
                        xfer->rname = strdup_nf(ent->name);
                        xfer->total = ent->size;
+                       xfer->count = 0;
                        xfer->done = xfer_done;
 
+                       cur_xfer = xfer;
+
                        ftp_queue_transfer(ftp, xfer);
                        local_modified = 1;
                } else {
@@ -352,6 +394,21 @@ int keypress(int key)
                }
                break;
 
+       case KB_F8:
+               sel = tui_get_list_sel(uilist[focus]);
+               if(focus == 0) {
+               } else {
+                       struct ftp_dirent *ent = localdir + sel;
+                       if(ent->type == FTP_FILE) {
+                               infomsg("removing local file: %s\n", ent->name);
+                               remove(ent->name);
+                               update_localdir();
+                               local_modified = 1;
+                       }
+               }
+               break;
+
+
        default:
                break;
        }
@@ -363,7 +420,8 @@ static void fixname(char *dest, const char *src)
        strcpy(dest, src);
 
 #ifdef __DOS__
-       {
+       if(!have_lfn) {
+               int len;
                char *suffix;
                if((suffix = strrchr(dest, '.'))) {
                        *suffix++ = 0;
@@ -371,13 +429,16 @@ static void fixname(char *dest, const char *src)
                                suffix[3] = 0;
                        }
                }
-               if(strlen(dest) > 8) {
+               if((len = strlen(dest)) > 8) {
                        dest[8] = 0;
+                       len = 8;
                }
 
                if(suffix) {
-                       strcat(dest, ".");
-                       strcat(dest, suffix);
+                       dest[len++] = '.';
+                       if(dest + len != suffix) {
+                               memmove(dest + len, suffix, strlen(suffix) + 1);
+                       }
                }
        }
 #endif
@@ -391,6 +452,8 @@ static void xfer_done(struct ftp *ftp, struct ftp_transfer *xfer)
        free(xfer->rname);
        free(xfer);
        update_localdir();
+
+       cur_xfer = 0;
 }
 
 static const char *usage = "Usage: %s [options] [hostname] [port]\n"
@@ -440,3 +503,46 @@ inval:
        fprintf(stderr, usage, argv[0]);
        return -1;
 }
+
+#ifdef __DOS__
+#include <dos.h>
+#include <i86.h>
+
+void detect_lfn(void)
+{
+       union REGS regs = {0};
+       struct SREGS sregs = {0};
+       unsigned int drv, buf_seg;
+       char *buf;
+
+       _dos_getdrive(&drv);
+
+       if(_dos_allocmem(3, &buf_seg) != 0) {
+               return;
+       }
+#ifdef _M_I86
+#error TODO port to 16bit
+#else
+       buf = (char*)(buf_seg << 4);
+#endif
+
+       sprintf(buf, "%c:\\", 'A' + drv);
+
+       sregs.ds = sregs.es = buf_seg;
+       regs.w.ax = 0x71a0;
+       regs.w.dx = 0;          /* ds:dx drive letter string */
+       regs.w.di = 4;          /* es:di buffer for filesystem name */
+       regs.w.cx = 44;         /* buffer size (3*16 - 4) */
+
+       intdosx(&regs, &regs, &sregs);
+
+       if(regs.w.cflag == 0) {
+               infomsg("long filenames available\n");
+               have_lfn = 1;
+       } else {
+               infomsg("long filenames not available, will truncate as needed\n");
+       }
+
+       _dos_freemem(buf_seg);
+}
+#endif
index e26b7a0..bab37df 100644 (file)
@@ -14,6 +14,12 @@ enum {
        TGFX_WHITE
 };
 
+/* graphics characters */
+enum {
+       TGFX_LARROW = 256,
+       TGFX_RARROW
+};
+
 enum {
        TGFX_FRAME              = 1,
        TGFX_SHADOW             = 2
@@ -38,4 +44,6 @@ void tg_vtext(int x, int y, const char *fmt, va_list ap);
 
 void tg_rect(const char *label, int x, int y, int xsz, int ysz, unsigned int flags);
 
+int tg_gchar(int gchar);
+
 #endif /* TGFX_H_ */
index 7f20e94..3ad62eb 100644 (file)
--- a/src/tui.c
+++ b/src/tui.c
@@ -79,6 +79,11 @@ struct tui_widget *tui_parent(struct tui_widget *w)
        return w->par;
 }
 
+void tui_invalidate(struct tui_widget *w)
+{
+       w->dirty = 1;
+}
+
 int tui_isdirty(struct tui_widget *w)
 {
        return w->dirty;
@@ -206,9 +211,6 @@ void tui_status(int type, const char *fmt, ...)
 void tui_vstatus(int type, const char *fmt, va_list ap)
 {
        /* TODO */
-       tg_color(15);
-       tg_bgcolor(0);
-       tg_vtext(0, 25, fmt, ap);
 }
 
 void tui_msgbox(int type, const char *title, const char *msg, ...)
@@ -222,7 +224,4 @@ void tui_msgbox(int type, const char *title, const char *msg, ...)
 void tui_vmsgbox(int type, const char *title, const char *msg, va_list ap)
 {
        /* TODO */
-       tg_color(15);
-       tg_bgcolor(0);
-       tg_vtext(0, 25, msg, ap);
 }
index 59a07c9..ececc65 100644 (file)
--- a/src/tui.h
+++ b/src/tui.h
@@ -28,6 +28,7 @@ void tui_add_widget(struct tui_widget *par, struct tui_widget *w);
 void tui_remove_widget(struct tui_widget *par, struct tui_widget *w);
 struct tui_widget *tui_parent(struct tui_widget *w);
 
+void tui_invalidate(struct tui_widget *w);
 int tui_isdirty(struct tui_widget *w);
 void tui_draw(struct tui_widget *w);
 
index c5f510c..42551ea 100644 (file)
@@ -79,9 +79,11 @@ int tui_num_list_items(struct tui_widget *w)
        return darr_size(wl->entries);
 }
 
+#define VISLINES(wl)   ((wl)->height - 2)
+
 int tui_list_select(struct tui_widget *w, int idx)
 {
-       int offs, nelem;
+       int offs, nelem, numvis;
        struct tui_list *wl = (struct tui_list*)w;
        assert(wl->type == TUI_LIST);
 
@@ -89,6 +91,8 @@ int tui_list_select(struct tui_widget *w, int idx)
                return 0;       /* no change */
        }
 
+       numvis = VISLINES(wl);
+
        if(idx < 0) {
                wl->sel = -1;
                return 0;
@@ -98,10 +102,10 @@ int tui_list_select(struct tui_widget *w, int idx)
        }
        wl->sel = idx;
 
-       if(idx < wl->view_offs || idx >= wl->view_offs + wl->height) {
-               offs = idx - wl->height / 2;
-               if(offs + wl->height >= nelem) {
-                       offs = nelem - wl->height;
+       if(idx < wl->view_offs || idx >= wl->view_offs + numvis) {
+               offs = idx - numvis / 2;
+               if(offs + numvis >= nelem) {
+                       offs = nelem - numvis;
                }
                if(offs < 0) {
                        offs = 0;
@@ -123,18 +127,20 @@ int tui_get_list_sel(struct tui_widget *w)
 
 int tui_list_sel_next(struct tui_widget *w)
 {
-       int nelem;
+       int nelem, numvis;
        struct tui_list *wl = (struct tui_list*)w;
        assert(wl->type == TUI_LIST);
 
        nelem = darr_size(wl->entries);
 
+       numvis = VISLINES(wl);
+
        if(wl->sel + 1 >= nelem) {
                return -1;
        }
 
-       if(++wl->sel - wl->view_offs >= wl->height) {
-               wl->view_offs = wl->sel - wl->height;
+       if(++wl->sel - wl->view_offs >= numvis) {
+               wl->view_offs = wl->sel - numvis + 1;
        }
        wl->dirty = 1;
        tui_call_callback(w, TUI_ONMODIFY);
@@ -171,14 +177,15 @@ int tui_list_sel_start(struct tui_widget *w)
 
 int tui_list_sel_end(struct tui_widget *w)
 {
-       int nelem;
+       int nelem, numvis;
        struct tui_list *wl = (struct tui_list*)w;
        assert(wl->type == TUI_LIST);
 
        nelem = darr_size(wl->entries);
+       numvis = VISLINES(wl);
 
        wl->sel = nelem - 1;
-       wl->view_offs = nelem - wl->height;
+       wl->view_offs = nelem - numvis;
        if(wl->view_offs < 0) wl->view_offs = 0;
        wl->dirty = 1;
        tui_call_callback(w, TUI_ONMODIFY);
index d228227..f36ecce 100644 (file)
@@ -24,6 +24,7 @@ void tg_init(void)
        keypad(stdscr, TRUE);
        nodelay(stdscr, TRUE);
        noecho();
+       curs_set(0);
        start_color();
 
        fgcol = curses_color(TGFX_WHITE);
@@ -133,6 +134,20 @@ void tg_rect(const char *label, int x, int y, int xsz, int ysz, unsigned int fla
        }
 
        attroff(COLOR_PAIR(cur_pair));
+       refresh();
+}
+
+int tg_gchar(int gchar)
+{
+       switch(gchar) {
+       case TGFX_LARROW:
+               return ACS_LARROW;
+       case TGFX_RARROW:
+               return ACS_RARROW;
+       default:
+               break;
+       }
+       return '@';
 }
 
 static int curses_color(int col)