From: John Tsiombikas Date: Sat, 28 Jan 2023 14:14:43 +0000 (+0200) Subject: download, progress, improved screen updates... X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=oftp;a=commitdiff_plain;h=8b4d2adf48213f2bf74ca1a423b1ac3dc8066f95 download, progress, improved screen updates... --- diff --git a/Makefile b/Makefile index 9eb1515..4d3cd7d 100644 --- 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 diff --git a/README.md b/README.md index ae642d0..816cffb 100644 --- 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 diff --git a/scripts/push b/scripts/push index 1067f03..103115e 100755 --- a/scripts/push +++ b/scripts/push @@ -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 * diff --git a/src/dos/tgfx.c b/src/dos/tgfx.c index 39e5ccc..228f88f 100644 --- a/src/dos/tgfx.c +++ b/src/dos/tgfx.c @@ -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 '@'; +} diff --git a/src/ftp.c b/src/ftp.c index f62a3a4..8a9b4ab 100644 --- 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 */ diff --git a/src/main.c b/src/main.c index c360dd7..3d02652 100644 --- a/src/main.c +++ b/src/main.c @@ -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 +#include + +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(®s, ®s, &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 diff --git a/src/tgfx.h b/src/tgfx.h index e26b7a0..bab37df 100644 --- a/src/tgfx.h +++ b/src/tgfx.h @@ -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_ */ diff --git a/src/tui.c b/src/tui.c index 7f20e94..3ad62eb 100644 --- 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); } diff --git a/src/tui.h b/src/tui.h index 59a07c9..ececc65 100644 --- 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); diff --git a/src/tui_list.c b/src/tui_list.c index c5f510c..42551ea 100644 --- a/src/tui_list.c +++ b/src/tui_list.c @@ -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); diff --git a/src/unix/tgfx.c b/src/unix/tgfx.c index d228227..f36ecce 100644 --- a/src/unix/tgfx.c +++ b/src/unix/tgfx.c @@ -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)