X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fmain.c;h=3d02652324a3cba490b0edc589359ef3ccafa917;hb=8b4d2adf48213f2bf74ca1a423b1ac3dc8066f95;hp=2323ea3eb8ffccb13dc9aaaa4bf3e4dd32fed9fa;hpb=5363ed21fccc528965a8482b3b71fe0133595499;p=oftp diff --git a/src/main.c b/src/main.c index 2323ea3..3d02652 100644 --- a/src/main.c +++ b/src/main.c @@ -1,40 +1,548 @@ +#include +#include +#include +#include +#include +#ifdef __DOS__ +#include +#else +#include +#include +#endif +#include +#include #include "tgfx.h" #include "input.h" +#include "util.h" +#include "tui.h" +#include "ftp.h" +#include "darray.h" -int main(void) +#ifdef __DOS__ +#define select select_s +#endif + +void updateui(void); +int update_localdir(void); +int proc_input(void); +int keypress(int key); +static void fixname(char *dest, const char *src); +static void xfer_done(struct ftp *ftp, struct ftp_transfer *xfer); +int parse_args(int argc, char **argv); + +static struct ftp *ftp; +static struct tui_widget *uilist[2]; + +static int focus; + +static char *host = "localhost"; +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) { - union event ev; + int i, numsock, maxfd; + int ftpsock[16]; + fd_set rdset; + struct timeval tv; + +#ifdef __DOS__ + detect_lfn(); +#endif + + if(parse_args(argc, argv) == -1) { + return 1; + } + + localdir = darr_alloc(0, sizeof *localdir); + getcwd(curdir, sizeof curdir); + update_localdir(); + + if(!(ftp = ftp_alloc())) { + return 1; + } + if(ftp_connect(ftp, host, port) == -1) { + ftp_free(ftp); + return 1; + } init_input(); + tg_init(); + tg_bgchar(' '); tg_clear(); - tg_bgcolor(1); - tg_rect("Remote", 0, 0, 40, 23, TGFX_FRAME); - tg_rect("Local", 40, 0, 40, 23, TGFX_FRAME); + uilist[0] = tui_list("Remote", 0, 1, 40, 21, 0, 0); + uilist[1] = tui_list("Local", 40, 1, 40, 21, 0, 0); + focus = 0; + tui_focus(uilist[focus], 1); + + local_modified = 1; + + tg_setcursor(0, 23); + + for(;;) { + FD_ZERO(&rdset); + maxfd = 0; + + numsock = ftp_sockets(ftp, ftpsock, sizeof ftpsock); + for(i=0; i maxfd) maxfd = ftpsock[i]; + } + +#ifdef __unix__ + FD_SET(0, &rdset); + tv.tv_sec = 120; + tv.tv_usec = 0; +#else + tv.tv_sec = tv.tv_usec = 0; +#endif + + if(select(maxfd + 1, &rdset, 0, 0, &tv) == -1 && errno == EINTR) { + continue; + } + +#ifdef __unix__ + if(FD_ISSET(0, &rdset)) { + if(proc_input() == -1) { + break; + } + } +#else + if(proc_input() == -1) { + break; + } +#endif + + for(i=0; istatus != prev_status) { + tg_fgcolor(ftp->status ? TGFX_GREEN : TGFX_RED); + tg_bgcolor(TGFX_BLACK); + 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) { + tui_set_title(uilist[0], remdir); + upd |= 1; + } + + if(ftp->modified & FTP_MOD_DIR) { + tui_clear_list(uilist[0]); + + num = ftp_num_dirent(ftp); + for(i=0; itype == FTP_DIR) { + sprintf(buf, "%s/", ent->name); + tui_add_list_item(uilist[0], buf); + } else { + tui_add_list_item(uilist[0], ent->name); + } + } + + tui_list_select(uilist[0], 0); + + ftp->modified &= ~FTP_MOD_DIR; + upd |= 1; + } + + if(local_modified || strcmp(tui_get_title(uilist[1]), curdir) != 0) { + tui_clear_list(uilist[1]); + num = darr_size(localdir); + for(i=0; itype == FTP_DIR) { + sprintf(buf, "%s/", ent->name); + tui_add_list_item(uilist[1], buf); + } else { + tui_add_list_item(uilist[1], ent->name); + } + } + tui_list_select(uilist[1], 0); + tui_set_title(uilist[1], curdir); + + local_modified = 0; + upd |= 2; + } + + if(tui_isdirty(uilist[0]) || upd & 1) { + tui_draw(uilist[0]); + } + if(tui_isdirty(uilist[1]) || upd & 2) { + tui_draw(uilist[1]); + } + + if(upd) { + tg_redraw(); + } +} + +int update_localdir(void) +{ + DIR *dir; + struct dirent *dent; + struct stat st; + struct ftp_dirent ent; + + if(!(dir = opendir(curdir))) { + errmsg("failed to open directory: %s\n", curdir); + return -1; + } + + darr_clear(localdir); + while((dent = readdir(dir))) { + ent.name = strdup_nf(dent->d_name); + if(strcmp(dent->d_name, ".") == 0) continue; + + if(stat(dent->d_name, &st) == 0) { + if(S_ISDIR(st.st_mode)) { + ent.type = FTP_DIR; + } else { + ent.type = FTP_FILE; + } + ent.size = st.st_size; + } else { + ent.type = FTP_FILE; + ent.size = 0; + } + + darr_push(localdir, &ent); + } + closedir(dir); - tg_fgcolor(7); - tg_text(0, 24, "fooolalala bar"); -/* tg_setcursor(2, 24);*/ + qsort(localdir, darr_size(localdir), sizeof *localdir, ftp_direntcmp); + local_modified = 1; + return 0; +} - while(wait_input(&ev)) { +int proc_input(void) +{ + union event ev; + + while(poll_input(&ev)) { switch(ev.type) { case EV_KEY: - if(ev.key.key == 27) goto done; + if(keypress(ev.key.key) == -1) { + return -1; + } break; default: break; } } + return 0; +} -done: - tg_bgchar(' '); - tg_bgcolor(0); - tg_fgcolor(7); - tg_clear(); +int keypress(int key) +{ + int sel; - cleanup_input(); + switch(key) { + case 27: + case 'q': + case KB_F10: + return -1; + + case '`': + tui_invalidate(uilist[0]); + tui_invalidate(uilist[1]); + break; + + case '\t': + tui_focus(uilist[focus], 0); + focus ^= 1; + tui_focus(uilist[focus], 1); + break; + + case KB_UP: + tui_list_sel_prev(uilist[focus]); + break; + case KB_DOWN: + tui_list_sel_next(uilist[focus]); + break; + case KB_LEFT: + tui_list_sel_start(uilist[focus]); + break; + case KB_RIGHT: + tui_list_sel_end(uilist[focus]); + break; + + case '\n': + sel = tui_get_list_sel(uilist[focus]); + if(focus == 0) { + struct ftp_dirent *ent = ftp_dirent(ftp, sel); + if(ent->type == FTP_DIR) { + ftp_queue(ftp, FTP_CHDIR, ent->name); + } else { + /* TODO */ + } + } else { + if(localdir[sel].type == FTP_DIR) { + if(chdir(localdir[sel].name) == -1) { + errmsg("failed to change directory: %s\n", localdir[sel].name); + } else { + getcwd(curdir, sizeof curdir); + update_localdir(); + } + } else { + /* TODO */ + } + } + break; + + case '\b': + if(focus == 0) { + ftp_queue(ftp, FTP_CDUP, 0); + } else { + if(chdir("..") == 0) { + getcwd(curdir, sizeof curdir); + update_localdir(); + } + } + break; + + case KB_F5: + sel = tui_get_list_sel(uilist[focus]); + if(focus == 0) { + struct ftp_transfer *xfer; + struct ftp_dirent *ent = ftp_dirent(ftp, sel); + char *lname = alloca(strlen(ent->name) + 1); + + fixname(lname, ent->name); + + xfer = malloc_nf(sizeof *xfer); + if(!(xfer->fp = fopen(lname, "wb"))) { + errmsg("failed to open %s: %s\n", lname, strerror(errno)); + free(xfer); + break; + } + + 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 { + /* TODO */ + } + 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; + } return 0; } + +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; + if(strlen(suffix) > 3) { + suffix[3] = 0; + } + } + if((len = strlen(dest)) > 8) { + dest[8] = 0; + len = 8; + } + + if(suffix) { + dest[len++] = '.'; + if(dest + len != suffix) { + memmove(dest + len, suffix, strlen(suffix) + 1); + } + } + } +#endif +} + +static void xfer_done(struct ftp *ftp, struct ftp_transfer *xfer) +{ + if(xfer->fp) { + fclose(xfer->fp); + } + free(xfer->rname); + free(xfer); + update_localdir(); + + cur_xfer = 0; +} + +static const char *usage = "Usage: %s [options] [hostname] [port]\n" + "Options:\n" + " -h: print usage information and exit\n"; + +int parse_args(int argc, char **argv) +{ + int i, argidx = 0; + + for(i=1; i +#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