13 #include <sys/select.h>
22 #define select select_s
26 int update_localdir(void);
28 int keypress(int key);
29 static void fixname(char *dest, const char *src);
30 static void xfer_done(struct ftp *ftp, struct ftp_transfer *xfer);
31 int parse_args(int argc, char **argv);
33 static struct ftp *ftp;
34 static struct tui_widget *uilist[2];
38 static char *host = "localhost";
41 static char curdir[PATH_MAX + 1];
42 static struct ftp_dirent *localdir;
43 static int local_modified;
46 int main(int argc, char **argv)
48 int i, numsock, maxfd;
53 if(parse_args(argc, argv) == -1) {
57 localdir = darr_alloc(0, sizeof *localdir);
58 getcwd(curdir, sizeof curdir);
61 if(!(ftp = ftp_alloc())) {
64 if(ftp_connect(ftp, host, port) == -1) {
76 uilist[0] = tui_list("Remote", 0, 0, 40, 23, 0, 0);
77 uilist[1] = tui_list("Local", 40, 0, 40, 23, 0, 0);
79 tui_focus(uilist[focus], 1);
90 numsock = ftp_sockets(ftp, ftpsock, sizeof ftpsock);
91 for(i=0; i<numsock; i++) {
92 FD_SET(ftpsock[i], &rdset);
93 if(ftpsock[i] > maxfd) maxfd = ftpsock[i];
101 tv.tv_sec = tv.tv_usec = 0;
104 if(select(maxfd + 1, &rdset, 0, 0, &tv) == -1 && errno == EINTR) {
109 if(FD_ISSET(0, &rdset)) {
110 if(proc_input() == -1) {
115 if(proc_input() == -1) {
120 for(i=0; i<numsock; i++) {
121 if(FD_ISSET(ftpsock[i], &rdset)) {
122 ftp_handle(ftp, ftpsock[i]);
139 struct ftp_dirent *ent;
140 unsigned int upd = 0;
144 remdir = ftp_curdir(ftp);
145 if(remdir && strcmp(tui_get_title(uilist[0]), remdir) != 0) {
146 tui_set_title(uilist[0], remdir);
150 if(ftp->modified & FTP_MOD_DIR) {
151 tui_clear_list(uilist[0]);
153 num = ftp_num_dirent(ftp);
154 for(i=0; i<num; i++) {
155 ent = ftp_dirent(ftp, i);
156 if(ent->type == FTP_DIR) {
157 sprintf(buf, "%s/", ent->name);
158 tui_add_list_item(uilist[0], buf);
160 tui_add_list_item(uilist[0], ent->name);
164 tui_list_select(uilist[0], 0);
166 ftp->modified &= ~FTP_MOD_DIR;
170 if(local_modified || strcmp(tui_get_title(uilist[1]), curdir) != 0) {
171 tui_clear_list(uilist[1]);
172 num = darr_size(localdir);
173 for(i=0; i<num; i++) {
175 if(ent->type == FTP_DIR) {
176 sprintf(buf, "%s/", ent->name);
177 tui_add_list_item(uilist[1], buf);
179 tui_add_list_item(uilist[1], ent->name);
182 tui_list_select(uilist[1], 0);
183 tui_set_title(uilist[1], curdir);
189 if(tui_isdirty(uilist[0]) || upd & 1) {
192 if(tui_isdirty(uilist[1]) || upd & 2) {
197 int update_localdir(void)
202 struct ftp_dirent ent;
204 if(!(dir = opendir(curdir))) {
205 errmsg("failed to open directory: %s\n", curdir);
209 darr_clear(localdir);
210 while((dent = readdir(dir))) {
211 ent.name = strdup_nf(dent->d_name);
212 if(strcmp(dent->d_name, ".") == 0) continue;
214 if(stat(dent->d_name, &st) == 0) {
215 if(S_ISDIR(st.st_mode)) {
220 ent.size = st.st_size;
226 darr_push(localdir, &ent);
230 qsort(localdir, darr_size(localdir), sizeof *localdir, ftp_direntcmp);
239 while(poll_input(&ev)) {
242 if(keypress(ev.key.key) == -1) {
254 int keypress(int key)
265 tui_focus(uilist[focus], 0);
267 tui_focus(uilist[focus], 1);
271 tui_list_sel_prev(uilist[focus]);
274 tui_list_sel_next(uilist[focus]);
277 tui_list_sel_start(uilist[focus]);
280 tui_list_sel_end(uilist[focus]);
284 sel = tui_get_list_sel(uilist[focus]);
286 struct ftp_dirent *ent = ftp_dirent(ftp, sel);
287 if(ent->type == FTP_DIR) {
288 ftp_queue(ftp, FTP_CHDIR, ent->name);
293 if(localdir[sel].type == FTP_DIR) {
294 if(chdir(localdir[sel].name) == -1) {
295 errmsg("failed to change directory: %s\n", localdir[sel].name);
297 getcwd(curdir, sizeof curdir);
308 ftp_queue(ftp, FTP_CDUP, 0);
310 if(chdir("..") == 0) {
311 getcwd(curdir, sizeof curdir);
318 sel = tui_get_list_sel(uilist[focus]);
320 struct ftp_transfer *xfer;
321 struct ftp_dirent *ent = ftp_dirent(ftp, sel);
322 char *lname = alloca(strlen(ent->name) + 1);
324 fixname(lname, ent->name);
326 xfer = malloc_nf(sizeof *xfer);
327 if(!(xfer->fp = fopen(lname, "wb"))) {
328 errmsg("failed to open %s: %s\n", lname, strerror(errno));
334 xfer->rname = strdup_nf(ent->name);
335 xfer->total = ent->size;
336 xfer->done = xfer_done;
338 ftp_queue_transfer(ftp, xfer);
351 static void fixname(char *dest, const char *src)
358 if((suffix = strrchr(dest, '.'))) {
360 if(strlen(suffix) > 3) {
364 if(strlen(dest) > 8) {
370 strcat(dest, suffix);
376 static void xfer_done(struct ftp *ftp, struct ftp_transfer *xfer)
386 static const char *usage = "Usage: %s [options] [hostname] [port]\n"
388 " -h: print usage information and exit\n";
390 int parse_args(int argc, char **argv)
394 for(i=1; i<argc; i++) {
395 if(argv[i][0] == '-') {
396 if(argv[i][2] != 0) {
401 printf(usage, argv[0]);
415 if((port = atoi(argv[i])) <= 0) {
416 fprintf(stderr, "invalid port number: %s\n", argv[i]);
429 fprintf(stderr, "invalid argument: %s\n", argv[i]);
430 fprintf(stderr, usage, argv[0]);