+ for(;;) {
+ FD_ZERO(&rdset);
+ maxfd = 0;
+
+ numsock = ftp_sockets(ftp, ftpsock, sizeof ftpsock);
+ for(i=0; i<numsock; i++) {
+ FD_SET(ftpsock[i], &rdset);
+ if(ftpsock[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;
+ }
+ }
+#endif
+
+ for(i=0; i<numsock; i++) {
+ if(FD_ISSET(ftpsock[i], &rdset)) {
+ ftp_handle(ftp, ftpsock[i]);
+ }
+ }
+
+ updateui();
+ }
+
+ tg_cleanup();
+ cleanup_input();
+ ftp_close(ftp);
+ ftp_free(ftp);
+ return 0;
+}
+
+static int cmpnames(const void *a, const void *b)
+{
+ const char *sa = *(const char**)a;
+ const char *sb = *(const char**)b;
+ int isdir_a, isdir_b;
+
+ isdir_a = sa[strlen(sa) - 1] == '/';
+ isdir_b = sb[strlen(sb) - 1] == '/';
+
+ if(isdir_a == isdir_b) {
+ return strcmp(sa, sb);
+ }
+ return isdir_a ? -1 : 1;
+}
+
+void updateui(void)
+{
+ struct ftp_dirent *ent;
+ unsigned int upd = 0;
+ char buf[128];
+
+ if(ftp->curdir_rem && strcmp(tui_get_title(uilist), ftp->curdir_rem) != 0) {
+ tui_set_title(uilist, ftp->curdir_rem);
+ upd |= 1;
+ }
+
+ if(ftp->modified & FTP_MOD_REMDIR) {
+ tui_clear_list(uilist);
+
+ ent = ftp->dent_rem;
+ while(ent) {
+ if(ent->type == FTP_DIR) {
+ sprintf(buf, "%s/", ent->name);
+ tui_add_list_item(uilist, buf);
+ } else {
+ tui_add_list_item(uilist, ent->name);
+ }
+ ent = ent->next;
+ }
+
+ tui_sort_list(uilist, cmpnames);
+ tui_list_select(uilist, 0);
+
+ ftp->modified &= ~FTP_MOD_REMDIR;
+ upd |= 1;
+ }
+
+ if(tui_isdirty(uilist) || upd & 1) {
+ tui_draw(uilist);
+ }
+}
+
+int proc_input(void)
+{
+ union event ev;
+
+ while(poll_input(&ev)) {