/*
    Copyright (C) Rafal Metkowski

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/time.h>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/telnet.h>
#include <netdb.h>
#include <pwd.h>
#include <dirent.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <fnmatch.h>
#include <forms.h>
#include "fd_xftp.h"

#define ASCII 0
#define BIN 1

#define LOCAL 0
#define REMOTE 1

#define BY_NAME 1
#define BY_SIZE 2

#define BUF_SIZE 32767
#define HIST_SIZE 15
#define MAXLINE 512

#define CANCEL 0
#define OVERWRITE 1
#define RESUME_TRANSF 2
#define N_FORMS 17

FD_fd_main *fm;
FD_fd_conn_par *fcp;
FD_fd_bookmarks *fb;
FD_fd_options *fo;
FD_fd_options_net *fon;
FD_fd_options_fonts *fof;
FD_fd_options_files *fofl;
FD_fd_options_colors *foc;
FD_fd_about *fa;
FD_fd_download *fd;
FD_fd_download_question *fdq;
FD_fd_input *fi;
FD_fd_question *fq;
FD_fd_message *fmsg;
FD_fd_remote_view *frv;
FD_fd_local_view *flv;
FD_fd_colors *fc;

struct dir_item {
    char *file_name;
    char *link_name;
    char *path;
    long mode;
    long file_size;
    time_t modif_time;
    struct dir_item *next;
    int selected;
} **local_files = NULL, **remote_files = NULL, *buffer_list = NULL;

struct hist_item {
    char *address;
    char *user_name;
    char *pass_unenc;
    char *local_dir;
    char *remote_dir;
    int anonym_login;
    struct hist_item *next;
} *hist_first = NULL, *hist_last = NULL;

struct addr_item {
    char *address;
    char *dir;
    struct addr_item *next;
} *bookm_first = NULL, *bookm_last = NULL;

struct dir_buf_item {
    char *dir_path;
    struct dir_item **dir;
    int dir_len;
    int top;
    struct dir_buf_item *next;
} *dir_buf = NULL, *cur_dir = NULL;

char *user_name = NULL, *pass_enc = NULL, *pass_unenc = NULL, *address = NULL;
char *remote_dir_path_inp = NULL, *local_dir_path_inp = NULL, e_mail[81] = "";
char *remote_dir_path = NULL, *home_dir, *opt_file_name, *hist_file_name;
char *log_file_name, *addr_file_name, *std_bookm_file, dir_col[10],
 lnk_col[10], exe_col[10], other_col[10];
int con_opened = 0, busy = 0, aborted = 0, anonym_login = 0, con_canceled = 0;
int type = BIN, cur_type = ASCII, font_size = 10, br_fsize = 10, port = 21;
int sock_servPI, sock_userDTP, sock_servDTP;
int n_local = 0, n_remote = 0, n_buffer = 0, n_hist = 0, sort_key_local = BY_NAME,
 sort_key_remote = BY_NAME;
int ninteract = 0, show_hidden_local = 1, show_hidden_remote = 1, sys_unix,
 passive = 0, f_fold_hidden = 0;
int minx = 670, miny = 400;
struct sockaddr_in serverPI, userDTP;
FL_FORM *forms[N_FORMS];
FILE *flog;

int send_command(const char *command, const char *arg, char **pReply);
int get_reply(char **pReply);
int data_command(const char *command, const char *arg);
void cb_close(FL_OBJECT * ob, long arg);
void cb_remote_view_ok(FL_OBJECT * ob, long arg);
char *get_cwdir();
void sort(struct dir_item **ppFiles, int iFiles, int key);
void read_bookmarks(const char *bookm_file);
void write_bookmarks();
void read_hist();

FL_CALLBACKPTR cb_old_local, cb_old_remote, cb_old_buffer;

char *
 cut(const char *fn)
{
    char *cutted;

    cutted = malloc(25);
    strncpy(cutted, fn, 20);
    cutted[20] = '\0';
    if (strlen(fn) > 20)
	memset(cutted + 17, '.', 3);
    return cutted;
}

char *
 resolve_link(const char *full_name)
{
    char *resolved, *pc1;

    resolved = malloc(strlen(full_name) + 1);
    strcpy(resolved, full_name);
    pc1 = strstr(resolved, "->");
    if (pc1 == NULL) {
	free(resolved);
	return NULL;
    }
    *--pc1 = '\0';
    return resolved;
}

void center_downl()
{
    int x, y;

    x = fm->fd_main->x + (fm->fd_main->w - fd->fd_download->w) / 2;
    y = fm->fd_main->y + (fm->fd_main->h - fd->fd_download->h) / 2;
    fl_set_form_position(fd->fd_download, x, y);
}

int prehndl_local(FL_OBJECT * ob, int event, FL_Coord mx, FL_Coord my, int key, void *xev)
{
    if (event == FL_MOTION || event == FL_MOUSE)
	fl_set_browser_topline(fm->br_local_size, fl_get_browser_topline(ob));
    return 0;
}

int prehndl_local_size(FL_OBJECT * ob, int event, FL_Coord mx, FL_Coord my, int key, void *xev)
{
    if (event == FL_MOTION || event == FL_MOUSE)
	fl_set_browser_topline(fm->br_local, fl_get_browser_topline(ob));
    return 0;
}

int prehndl_remote(FL_OBJECT * ob, int event, FL_Coord mx, FL_Coord my, int key, void *xev)
{
    if (event == FL_MOTION || event == FL_MOUSE)
	fl_set_browser_topline(fm->br_remote_size, fl_get_browser_topline(ob));
    return 0;
}

int prehndl_remote_size(FL_OBJECT * ob, int event, FL_Coord mx, FL_Coord my, int key, void *xev)
{
    if (event == FL_MOTION || event == FL_MOUSE)
	fl_set_browser_topline(fm->br_remote, fl_get_browser_topline(ob));
    return 0;
}

void cb_vscroll_local(FL_OBJECT * ob, long arg)
{
    int i;

    cb_old_local(ob, arg);
    i = fl_get_browser_topline(fm->br_local_size);
    fl_set_browser_topline(fm->br_local, i);
}

void cb_vscroll_remote(FL_OBJECT * ob, long arg)
{
    int i;

    cb_old_remote(ob, arg);
    i = fl_get_browser_topline(fm->br_remote_size);
    fl_set_browser_topline(fm->br_remote, i);
}

void 
add_to_log (const char *line)
{
  if (!ninteract)
    fl_addto_browser (fm->br_log, line);
  if (flog != NULL)
    fprintf (flog, "%s\n", line);
}

void add_to_log_err(const char *func)
{
    const char *estr = strerror(errno);
    
    if (!ninteract) {
	fl_addto_browser_chars(fm->br_log, func);
	fl_addto_browser_chars(fm->br_log, ":");
	fl_addto_browser_chars(fm->br_log, estr);
    }
    if (flog != NULL) {
	fprintf(flog, "%s:", func);
	fprintf(flog, "%s\n", estr);
    }
}

void check_forms()
{
    if (!ninteract)
	fl_check_forms();
}


int cmp_name(const void *p1, const void *p2)
{
    struct dir_item *pF1 = *((struct dir_item **) p1);
    struct dir_item *pF2 = *((struct dir_item **) p2);

    if (S_ISDIR(pF1->mode) && !S_ISDIR(pF2->mode))
	return -1;
    if (S_ISDIR(pF2->mode) && !S_ISDIR(pF1->mode))
	return 1;
    if (S_ISLNK(pF1->mode) && !S_ISLNK(pF2->mode))
	return -1;
    if (S_ISLNK(pF2->mode) && !S_ISLNK(pF1->mode))
	return 1;
    if (strcmp(pF1->file_name, "..") == 0)
	return -1;
    if (strcmp(pF2->file_name, "..") == 0)
	return 1;
    return strcmp(pF1->file_name, pF2->file_name);
}

int cmp_size(const void *p1, const void *p2)
{
    struct dir_item *pF1 = *((struct dir_item **) p1);
    struct dir_item *pF2 = *((struct dir_item **) p2);

    if (S_ISDIR(pF1->mode) && !S_ISDIR(pF2->mode))
	return -1;
    if (S_ISDIR(pF2->mode) && !S_ISDIR(pF1->mode))
	return 1;
    if (S_ISLNK(pF1->mode) && !S_ISLNK(pF2->mode))
	return -1;
    if (S_ISLNK(pF2->mode) && !S_ISLNK(pF1->mode))
	return 1;
    if (strcmp(pF1->file_name, "..") == 0)
	return -1;
    if (strcmp(pF2->file_name, "..") == 0)
	return 1;
    if (S_ISLNK(pF1->mode) || S_ISDIR(pF1->mode))
	return strcmp(pF1->file_name, pF2->file_name);
    return pF1->file_size - pF2->file_size;
}

void activate_form(FL_FORM * form)
{
    FL_OBJECT *p1;

    if (ninteract)
	return;
    p1 = form->first;
    fl_freeze_form(form);
    while (1) {
	if (p1->objclass == FL_BUTTON || p1->objclass == FL_TEXT || p1->objclass == FL_CHECKBUTTON)
	    fl_set_object_lcol(p1, FL_BLACK);
	if (p1 == form->last)
	    break;
	p1 = p1->next;
    }
    if (!con_opened || busy) {
	fl_set_object_lcol(fm->remote_btns, FL_INACTIVE);
	fl_set_object_lcol(fm->br_remote, FL_INACTIVE);
	fl_set_object_lcol(fm->br_remote_size, FL_INACTIVE);
    }
    if (busy)
	fl_set_object_lcol(fm->local_btns, FL_INACTIVE);
    fl_unfreeze_form(form);
    fl_activate_form(form);
}

void deactivate_form(FL_FORM * form)
{
    FL_OBJECT *p1;

    if (ninteract)
	return;
    p1 = form->first;
    fl_deactivate_form(form);
    fl_freeze_form(form);
    while (1) {
	if (p1->objclass == FL_BUTTON || p1->objclass == FL_TEXT)
	    fl_set_object_lcol(p1, FL_INACTIVE);
	if (p1 == form->last)
	    break;
	p1 = p1->next;
    }
    fl_unfreeze_form(form);
}

void activate_object(FL_OBJECT * ob)
{
    fl_set_object_lcol(ob, FL_BLACK);
    fl_activate_object(ob);
}

void deactivate_object(FL_OBJECT * ob)
{
    fl_set_object_lcol(ob, FL_INACTIVE);
    fl_deactivate_object(ob);
}

void adjust_path(FL_OBJECT * f_txt, char *path)
{
    int i, path_len, x, y, w, h;
    char *pc1, *ad_path;

    fl_get_object_geometry(f_txt, &x, &y, &w, &h);
    w -= 10;
    pc1 = path;
    path_len = strlen(path);
    for (i = path_len; i > 0; i--) {
	if (fl_get_string_width(1, font_size, pc1, i) <= w) {
	    ad_path = malloc(strlen(path) + 1);
	    strcpy(ad_path, pc1);
	    if (i != path_len)
		memset(ad_path, '.', 3);
	    break;
	}
	pc1++;
    }
    fl_set_object_label(f_txt, ad_path);
    free(ad_path);
}

void add_to_history()
{
    char *hist_line;
    const char *a = fl_get_input(fcp->address);
    const char *r = fl_get_input(fcp->remote_dir);
    int i, nh, repeated = 0;
    struct hist_item *pHist_it, *pPrev_it = NULL;
    FILE *f_history;

    read_hist();
    pHist_it = hist_first;
    for (i = 1; pHist_it != NULL; i++) {
	if (strcmp(pHist_it->address, a) == 0 && strcmp(pHist_it->remote_dir, r) == 0) {
	    repeated = 1;
	    break;
	}
	pPrev_it = pHist_it;
	pHist_it = pHist_it->next;
    }
    if (repeated) {
	if (!ninteract)
	    fl_delete_browser_line(fcp->br_history, i);
	if (pPrev_it != NULL) {
	    pPrev_it->next = pHist_it->next;
	    pHist_it->next = hist_first;
	    hist_first = pHist_it;
	    free(hist_first->user_name);
	    free(hist_first->pass_unenc);
	    free(hist_first->local_dir);
	}
    } else {
	pHist_it = malloc(sizeof(struct hist_item));
	pHist_it->next = hist_first;
	hist_first = pHist_it;
	pHist_it->remote_dir = malloc(strlen(r) + 1);
	strcpy(pHist_it->remote_dir, r);
	pHist_it->address = malloc(strlen(a) + 1);
	strcpy(pHist_it->address, a);
	n_hist++;
    }
    hist_line = malloc(strlen(a) + strlen(r) + 5);
    sprintf(hist_line, "%s %s", a, r);
    if (!ninteract)
	fl_insert_browser_line(fcp->br_history, 1, hist_line);
    free(hist_line);
    pHist_it->user_name = malloc(strlen(user_name) + 1);
    strcpy(pHist_it->user_name, user_name);
    pHist_it->pass_unenc = malloc(strlen(pass_unenc) + 1);
    strcpy(pHist_it->pass_unenc, pass_unenc);
    pHist_it->local_dir = malloc(strlen(local_dir_path_inp) + 1);
    strcpy(pHist_it->local_dir, local_dir_path_inp);
    pHist_it->anonym_login = anonym_login;
    if ((f_history = fopen(hist_file_name, "w")) != NULL) {
	nh = n_hist > HIST_SIZE ? HIST_SIZE : n_hist;
	fprintf(f_history, "%d\n", nh);
	pHist_it = hist_first;
	for (i = 0; i < nh; i++) {
	    fprintf(f_history, "%s\n", pHist_it->address);
	    fprintf(f_history, "%s\n", pHist_it->user_name);
	    fprintf(f_history, "%s\n", pHist_it->pass_unenc);
	    fprintf(f_history, "%s\n", pHist_it->local_dir);
	    fprintf(f_history, "%s\n", pHist_it->remote_dir);
	    fprintf(f_history, "%d\n", pHist_it->anonym_login);
	    pHist_it = pHist_it->next;
	}
	fclose(f_history);
    }
}

void add_file_to_list(struct dir_item **lf, char *fn, long fs, time_t mt, long mode, char *path)
{
    struct dir_item *pDir_it, *last_file;

    pDir_it = malloc(sizeof(struct dir_item));
    pDir_it->next = *lf;
    last_file = pDir_it;
    last_file->file_name = malloc(strlen(fn) + 1);
    strcpy(last_file->file_name, fn);
    last_file->link_name = resolve_link(fn);
    last_file->file_size = fs;
    last_file->modif_time = mt;
    last_file->mode = mode;
    last_file->selected = 0;
    if (path != NULL) {
	last_file->path = malloc(strlen(path) + 1);
	strcpy(last_file->path, path);
    } else
	last_file->path = NULL;
    *lf = last_file;
}

struct dir_item **
 put_files_into_array(struct dir_item *last_file, int iFiles)
{
    int i;
    struct dir_item **ppDir_it, **ppFiles;

    ppFiles = malloc(iFiles * sizeof(struct dir_item *));
    ppDir_it = ppFiles + iFiles;
    for (i = 0; i < iFiles; i++) {
	*--ppDir_it = last_file;
	last_file = last_file->next;
    }
    return ppFiles;
}

void remove_file_from_array(struct dir_item ***pppFiles, int *piFiles, int iFileno)
{
    int i;
    struct dir_item **ppF1, **ppF2, **ppNew_files;

    ppNew_files = malloc(--*piFiles * sizeof(struct dir_item *));

    ppF1 = *pppFiles;
    ppF2 = ppNew_files;
    for (i = 0; i < *piFiles; i++) {
	if (i == iFileno)
	    ppF1++;
	*(ppF2++) = *(ppF1++);
    }
    free(*pppFiles);
    *pppFiles = ppNew_files;
}

void add_file_to_array(struct dir_item ***pppFiles, int *piFiles,
		       const char *fn, long fs, time_t mt, long mode)
{
    int i;
    struct dir_item **ppF1, **ppF2, **ppNewfiles, *pNew_file;

    ppNewfiles = malloc((*piFiles + 1) * sizeof(struct dir_item *));

    ppF1 = *pppFiles;
    ppF2 = ppNewfiles;
    for (i = 0; i < *piFiles; i++)
	*(ppF2++) = *(ppF1++);
    pNew_file = malloc(sizeof(struct dir_item));
    pNew_file->file_name = malloc(strlen(fn) + 1);
    strcpy(pNew_file->file_name, fn);
    pNew_file->path = NULL;
    pNew_file->link_name = resolve_link(fn);
    pNew_file->file_size = fs;
    pNew_file->modif_time = mt;
    pNew_file->mode = mode;
    pNew_file->selected = 0;
    *ppF2 = pNew_file;
    free(*pppFiles);
    *pppFiles = ppNewfiles;
    (*piFiles)++;
}

void put_files_into_browser(FL_OBJECT * browser, FL_OBJECT * browser_size,
		     struct dir_item **ppFiles, int iFiles, int sort_key)
{
    int i, j;
    char *file_name, file_size[30];

    fl_clear_browser(browser);
    fl_clear_browser(browser_size);
    fl_freeze_form(fm->fd_main);
    sort(ppFiles, iFiles, sort_key);
    for (i = 0; i < iFiles; i++) {
	file_name = malloc(strlen((*ppFiles)->file_name) + 9);
	switch ((*ppFiles)->mode & S_IFMT) {
	case S_IFDIR:
	    strcpy(file_name, dir_col);
	    sprintf(file_size, "%s@rDIR", dir_col);
	    break;
	case S_IFLNK:
	    strcpy(file_name, lnk_col);
	    sprintf(file_size, "%s@rLNK", lnk_col);
	    break;
	default:
	    if ((*ppFiles)->mode & S_IXUSR)
		strcpy(file_name, exe_col);
	    else
		strcpy(file_name, other_col);
	    if ((*ppFiles)->file_size < (long) 1024)
		sprintf(file_size, "%s@r%li", file_name, (long) (*ppFiles)->file_size);
	    else
		sprintf(file_size, "%s@r%li k", file_name, (long) (*ppFiles)->file_size >> 10);
	}
	strcat(file_name, "@n");
	if (*(*ppFiles)->file_name == '@')
	    strcat(file_name, "@");
	strcat(file_name, (*ppFiles)->file_name);
	fl_add_browser_line(browser, file_name);
	fl_add_browser_line(browser_size, file_size);
	if ((*ppFiles)->selected) {
	    j = fl_get_browser_maxline(browser);
	    fl_select_browser_line(browser, j);
	    fl_select_browser_line(browser_size, j);
	}
	free(file_name);
	ppFiles++;
    }
    fl_unfreeze_form(fm->fd_main);
}

void read_local_dir()
{
    struct stat stbuf;
    char *local_dir_path;
    int i;
    DIR *pDir;
    struct dirent *dir_ent;
    struct dir_item **ppDir_it, *last_file = NULL;

    fl_clear_browser(fm->br_local);
    fl_clear_browser(fm->br_local_size);
    ppDir_it = local_files;
    for (i = 0; i < n_local; i++) {
	free((*ppDir_it)->file_name);
	free((*ppDir_it)->path);
	free(*(ppDir_it++));
    }
    free(local_files);
    n_local = 0;
    if ((local_dir_path = get_cwdir()) == NULL) {
	local_dir_path = malloc(2);
	strcpy(local_dir_path, ".");
    }
    adjust_path(fm->txt_local_dir, local_dir_path);
    if ((pDir = opendir(local_dir_path)) != NULL)
	while ((dir_ent = readdir(pDir))) {
	    lstat(dir_ent->d_name, &stbuf);
	    if (strcmp(dir_ent->d_name, ".") == 0 || strcmp(dir_ent->d_name, "..") == 0)
		continue;
	    if (dir_ent->d_name[0] == '.' && !show_hidden_local)
		continue;
	    add_file_to_list(&last_file, dir_ent->d_name, stbuf.st_size, stbuf.st_mtime, stbuf.st_mode, NULL);
	    n_local++;
	}
    add_file_to_list(&last_file, "..", -1, -1, S_IFDIR, NULL);
    n_local++;
    local_files = put_files_into_array(last_file, n_local);
    put_files_into_browser(fm->br_local, fm->br_local_size, local_files, n_local, sort_key_local);
    free(local_dir_path);
}

struct dir_buf_item *
 read_rdir_to_mem(int rescan)
{
    int i, bytes_received, iLink, found = 0, length;
    long size, mode;
    char c1, read_line[512], *pc1, *pc2, *bgn, *end, *pwd_reply, *rdp;
    struct dir_item *last_file = NULL, **ppFiles;
    struct dir_buf_item *pDbi = dir_buf;

    if (send_command("PWD", NULL, &pwd_reply) == 257) {
	bgn = strchr(pwd_reply, '"');
	end = strrchr(pwd_reply, '"');
	if (bgn != NULL && end != NULL && bgn != end) {
	    i = end - bgn;
	    rdp = malloc(i);
	    strncpy(rdp, ++bgn, --i);
	    rdp[i] = '\0';
	}
	while (pDbi != NULL) {
	    if (strcmp(pDbi->dir_path, rdp) == 0) {
		found = 1;
		break;
	    }
	    pDbi = pDbi->next;
	}
	if (found && !rescan)
	    return pDbi;
    } else {
	rdp = malloc(2);
	strcpy(rdp, ".");
    }
    length = 0;
    if (cur_type != ASCII && send_command("TYPE A", NULL, NULL) == 200)
	cur_type = ASCII;
    if (data_command("LIST", NULL) != 150)
	goto read_err;
    while (1) {
	for (bytes_received = 0;; bytes_received++) {
	    while ((i = read(sock_servDTP, &c1, 1)) < 0) {
		if (!con_opened)
		    goto read_err;
		if (errno != EAGAIN) {
		    add_to_log_err("read");
		    goto read_err;
		}
		fl_check_forms();
	    }
	    if (c1 == '\n')
		break;
	    read_line[bytes_received] = c1;
	}
	if (i == 0)
	    break;
	if (read_line[bytes_received - 1] == '\r')
	    bytes_received--;
	read_line[bytes_received] = '\0';
	iLink = 1;
	if (strpbrk(read_line, "dlspbc-") != read_line)
	    continue;
	switch (*read_line) {
	case 'l':
	    iLink = 3;
	    mode = S_IFLNK;
	    break;
	case 'd':
	    mode = S_IFDIR;
	    break;
	default:
	    if (read_line[3] == 'x')
		mode = S_IXUSR;
	    else
		mode = 0;
	}
	pc1 = read_line;
	for (i = 0; i < 4; i++) {
	    pc2 = pc1;
	    while (*pc1 != ' ' && *pc1 != '\0')
		pc1++;
	    while (*pc1 == ' ' && *pc1 != '\0')
		pc1++;
	}
	if (!isdigit(*pc1))
	    pc1 = pc2;
	size = atol(pc1);
	for (i = 0; i < 4; i++) {
	    pc2 = pc1;
	    while (*pc1 != ' ' && *pc1 != '\0')
		pc1++;
	    while (*pc1 == ' ' && *pc1 != '\0')
		pc1++;
	}
	if (pc1[0] == '.' && !show_hidden_remote)
	    continue;
	if (strcmp(pc1, ".") == 0 || strcmp(pc1, "..") == 0)
	    continue;
	add_file_to_list(&last_file, pc1, size, 0, mode, NULL);
	length++;
    }
    add_file_to_list(&last_file, "..", -1, -1, S_IFDIR, NULL);
    length++;
    ppFiles = put_files_into_array(last_file, length);
    get_reply(NULL);
    if (found) {
	free(pDbi->dir);
	pDbi->dir_len = length;
	pDbi->dir = ppFiles;
    } else {
	pDbi = malloc(sizeof(struct dir_buf_item));
	pDbi->dir_path = malloc(strlen(rdp) + 1);
	strcpy(pDbi->dir_path, rdp);
	pDbi->dir_len = length;
	pDbi->dir = ppFiles;
	pDbi->next = dir_buf;
	pDbi->top = 1;
	dir_buf = pDbi;
    }
    close(sock_servDTP);
    close(sock_userDTP);
    return pDbi;

  read_err:
    close(sock_servDTP);
    close(sock_userDTP);
    return NULL;
}

int read_remote_dir(int rescan)
{
    struct dir_buf_item *pDbi;
    int i;

    fl_clear_browser(fm->br_remote);
    fl_clear_browser(fm->br_remote_size);
    if (cur_dir != NULL) {
	cur_dir->dir_len = n_remote;
	cur_dir->dir = remote_files;
	for (i = 0; i < n_remote; i++)
	    remote_files[i]->selected = 0;
    }
    pDbi = read_rdir_to_mem(rescan);
    if (pDbi == NULL)
	return -1;
    free(remote_dir_path);
    remote_dir_path = malloc(strlen(pDbi->dir_path) + 1);
    strcpy(remote_dir_path, pDbi->dir_path);
    adjust_path(fm->txt_remote_dir, remote_dir_path);
    remote_files = pDbi->dir;
    n_remote = pDbi->dir_len;
    put_files_into_browser(fm->br_remote, fm->br_remote_size, remote_files, n_remote, sort_key_remote);
    fl_set_browser_topline(fm->br_remote, pDbi->top);
    fl_set_browser_topline(fm->br_remote_size, pDbi->top);
    cur_dir = pDbi;
    return 1;
}

void create_forms()
{
    fm = create_form_fd_main();
    fcp = create_form_fd_conn_par();
    fb = create_form_fd_bookmarks();
    fo = create_form_fd_options();
    fon = create_form_fd_options_net();
    fof = create_form_fd_options_fonts();
    fofl = create_form_fd_options_files();
    foc = create_form_fd_options_colors();
    fa = create_form_fd_about();
    fd = create_form_fd_download();
    fdq = create_form_fd_download_question();
    fi = create_form_fd_input();
    fq = create_form_fd_question();
    fmsg = create_form_fd_message();
    frv = create_form_fd_remote_view();
    flv = create_form_fd_local_view();
    fc = create_form_fd_colors();
    forms[0] = fm->fd_main;
    forms[1] = fcp->fd_conn_par;
    forms[2] = fo->fd_options;
    forms[3] = fon->fd_options_net;
    forms[4] = fof->fd_options_fonts;
    forms[5] = fa->fd_about;
    forms[6] = fd->fd_download;
    forms[7] = fdq->fd_download_question;
    forms[8] = fi->fd_input;
    forms[9] = fq->fd_question;
    forms[10] = fmsg->fd_message;
    forms[11] = frv->fd_remote_view;
    forms[12] = flv->fd_local_view;
    forms[13] = fofl->fd_options_files;
    forms[14] = fb->fd_bookmarks;
    forms[15] = foc->fd_options_colors;
    forms[16] = fc->fd_colors;
}

void change_font_s(int form_no)
{
    FL_OBJECT *p1;
    double k;

    fl_freeze_form(forms[form_no]);
    p1 = forms[form_no]->first;
    while (1) {
	fl_set_object_lsize(p1, font_size);
	if (p1->objclass == FL_BROWSER)
	    fl_set_browser_fontsize(p1, br_fsize);
	if (p1 == forms[form_no]->last)
	    break;
	p1 = p1->next;
    }
    k = fl_adjust_form_size(forms[form_no]);
    if (form_no == 0) {
      minx = (double)minx * k;
      miny = (double)miny * k;
      fl_set_form_minsize(forms[form_no], minx, miny);
    }
    fl_set_form_size(forms[form_no], forms[form_no]->w + 1, forms[form_no]->h + 1);
    fl_unfreeze_form(forms[form_no]);
}

void change_font_size()
{
   int i;

   for (i = 0; i < N_FORMS; i++)
    if (i != 2)  /* without this exception aplication dumps core */
     change_font_s (i);
}

void sort(struct dir_item **ppFiles, int iFiles, int sort_key)
{
    if (sort_key == BY_NAME)
	qsort(ppFiles, iFiles, sizeof(struct dir_item *), cmp_name);
    else
	qsort(ppFiles, iFiles, sizeof(struct dir_item *), cmp_size);
}

int send_com_no_reply(const char *command, const char *arg, int flags, int crlf)
{
    char line_to_send[strlen(command) + (arg != NULL ? strlen(arg) : 0) + 10];

    if (crlf) {
	if (arg != NULL)
	    sprintf(line_to_send, "%s %s\r\n", command, arg);
	else
	    sprintf(line_to_send, "%s\r\n", command);
    } else
	sprintf(line_to_send, "%s", command);
    while (send(sock_servPI, line_to_send, strlen(line_to_send), flags) < 0) {
	if (!con_opened)
	    return -1;
	if (errno != EWOULDBLOCK) {
	    add_to_log_err("send");
	    return -1;
	}
	check_forms();
    }
    if (crlf) {
	if (arg != NULL) {
	    sprintf(line_to_send, "%s %s", command, (strncmp(command, "PASS", 4) || anonym_login) ? arg : "XXXX");
	    add_to_log(line_to_send);
	} else
	    add_to_log(command);
    }
    return 0;
}

int send_command(const char *command, const char *arg, char **pReply)
{
    if (send_com_no_reply(command, arg, 0, 1) < 0)
	return -1;
    return (get_reply(pReply));
}

int get_reply(char **pReply)
{
    char reply[256], rb[5], c1;
    int i = 1, j, multi = 0;

    while (1) {
	for (j = 0; i > 0; j++) {
	    while ((i = read(sock_servPI, &c1, 1)) < 0) {
		if (!con_opened)
		    return -1;
		if (errno != EAGAIN) {
		    add_to_log_err("read");
		    return -1;
		}
		check_forms();
	    }
	    if (c1 == '\n')
		break;
	    reply[j] = c1;
	}
	if (i == 0)
	    break;
	reply[j - 1] = '\0';
	add_to_log(reply);
	if (pReply != NULL) {
	    *pReply = malloc(strlen(reply) + 1);
	    strcpy(*pReply, reply);
	}
	if (reply[3] == '-') {
	    multi = 1;
	    strncpy(rb, reply, 3);
	    rb[3] = ' ';
	    rb[4] = '\0';
	}
	if (!multi || strncmp(reply, rb, 4) == 0)
	    break;
	reply[3] = ' ';
    }
    return atoi(reply);
}

int open_ftp_connection()
{
    struct hostent *h_ent = NULL;
    int i, on = 1;
    char *status;

    fl_set_object_label(fm->txt_status, "Looking up for host");
    memset(&serverPI.sin_addr, 0, sizeof(serverPI.sin_addr));
    serverPI.sin_port = htons(port);
    if ((h_ent = gethostbyname(address)) == NULL) {
	add_to_log_err("gethostbyname");
	goto op_err;
    }
    serverPI.sin_family = h_ent->h_addrtype;
    serverPI.sin_addr = *((struct in_addr *) *(h_ent->h_addr_list));
    if ((sock_servPI = socket(serverPI.sin_family, SOCK_STREAM, 0)) < 0) {
	add_to_log_err("socket");
	goto op_err;
    }
    if (fcntl(sock_servPI, F_SETFL, O_NONBLOCK) < 0) {
	add_to_log_err("fcntl");
	goto op_err;
    }
    status = malloc(strlen(address) + 15);
    sprintf(status, "Connecting to %s", address);
    fl_set_object_label(fm->txt_status, status);
    while (connect(sock_servPI, (struct sockaddr *) &serverPI, sizeof(serverPI)) < 0) {
	if (con_canceled)
	    return -1;
	if (errno == EISCONN)
	    break;
	if (errno == EINPROGRESS || errno == EAGAIN || errno == EALREADY) {
	    check_forms();
	    continue;
	}
	if (*++h_ent->h_addr_list != NULL)
	    serverPI.sin_addr = *((struct in_addr *) *(h_ent->h_addr_list));
	else {
	    add_to_log_err("connect");
	    goto op_err;
	}
    }
    i = sizeof(struct sockaddr_in);
    if (getsockname(sock_servPI, (struct sockaddr *) &userDTP, &i) < 0) {
	add_to_log_err("getsockname");
	close(sock_servPI);
	goto op_err;
    }
    setsockopt(sock_servPI, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on));
    return 1;

  op_err:
    fl_set_object_label(fm->txt_status, strerror(errno));
    return -1;
}

int data_command2(const char *command1, const char *arg1,
		  const char *command2, const char *arg2)
{
    struct sockaddr_in serverDTP;
    char port_command[50];
    char *a, *p, *pasv_reply = NULL, *pc1;
    int i, rp, ai[6];
    unsigned char ac[6];

    if ((sock_userDTP = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
	add_to_log_err("socket");
	return -1;
    }
    if (passive) {
	if (send_command("PASV", NULL, &pasv_reply) != 227) {
	    free(pasv_reply);
	    return -1;
	}
	pc1 = pasv_reply + 3;
	while (*pc1 != '\0' && !isdigit(*pc1))
	    pc1++;
	if (*pc1 == '\0') {
	    free(pasv_reply);
	    return -1;
	}
	sscanf(pc1, "%d,%d,%d,%d,%d,%d", &ai[0], &ai[1], &ai[2], &ai[3], &ai[4], &ai[5]);
	for (i = 0; i < 6; i++)
	    ac[i] = (unsigned char) ai[i];
	memcpy(&serverDTP.sin_addr, &ac[0], 4);
	memcpy(&serverDTP.sin_port, &ac[4], 2);
	serverDTP.sin_family = AF_INET;
	if ((sock_servDTP = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
	    add_to_log_err("socket");
	    return -1;
	}
	if (!ninteract)
	  if (fcntl(sock_servDTP, F_SETFL, O_NONBLOCK) < 0) {
	    add_to_log_err("fcntl");
	    return -1;
	  }
	while (connect(sock_servDTP, (struct sockaddr *) &serverDTP, sizeof(serverDTP)) < 0) {
	    if (!con_opened)
		return -1;
	    if (errno == EISCONN)
		break;
	    if (errno == EINPROGRESS || errno == EAGAIN || errno == EALREADY) {
		check_forms();
		continue;
	    }
	    add_to_log_err("connect");
	    return -1;
	}
	free(pasv_reply);
	if (command1 != NULL && send_command(command1, arg1, NULL) >= 400)
	    return -1;
	rp = send_command(command2, arg2, NULL);
	return rp;
    } else {
	if (!ninteract)
	  if (fcntl(sock_userDTP, F_SETFL, O_NONBLOCK) < 0) {
	    add_to_log_err("fcntl");
	    return -1;
	  }
	userDTP.sin_port = 0;
	if (bind(sock_userDTP, (struct sockaddr *) &userDTP, sizeof(userDTP)) < 0) {
	    add_to_log_err("bind");
	    return -1;
	}
	i = sizeof(struct sockaddr_in);
	if (getsockname(sock_userDTP, (struct sockaddr *) &userDTP, &i) < 0) {
	    add_to_log_err("getsockname");
	    return -1;
	}
	if (listen(sock_userDTP, 5) < 0) {
	    add_to_log_err("listen");
	    return -1;
	}
	a = (char *) &userDTP.sin_addr;
	p = (char *) &userDTP.sin_port;
#define UC(x) (((int) x) & 0xff)
	sprintf(port_command, "PORT %d,%d,%d,%d,%d,%d", UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
	if (send_command(port_command, NULL, NULL) != 200)
	    return -1;
	if (command1 != NULL && send_command(command1, arg1, NULL) >= 400)
	    return -1;
	rp = send_command(command2, arg2, NULL);
	if (rp >= 300)
	    return rp;
	i = sizeof(serverDTP);
	while ((sock_servDTP = accept(sock_userDTP, (struct sockaddr *) &serverDTP, &i)) < 0) {
	    if (errno != EWOULDBLOCK) {
		add_to_log_err("accept");
		return -1;
	    }
	    if (!con_opened)
		return -1;
	    check_forms();
	}
	return rp;
    }
}

int data_command(const char *command, const char *arg)
{
    return data_command2(NULL, NULL, command, arg);
}

void download(struct dir_item **ppFiles_to_download, int n_files)
{
    int mode, bytes_received, i, j, bytes_wrote, dest_file, action[n_files],
     flags;
    long bytes_transm, elapsed_time, estimated_time;
    float transfer_rate;
    char tmp_str[150], receive_buf[BUF_SIZE], *pc1, *pc2, *rfn, *lfn;
    char *cfile_name, *full_fname, *file_name;
    struct dir_item *pFile;
    struct stat stbuf;
    struct timeval start_time, cur_time;
    FL_OBJECT *ob;

    for (j = 0; j < n_files; j++) {
	if (S_ISLNK(ppFiles_to_download[j]->mode))
	    file_name = ppFiles_to_download[j]->link_name;
	else
	    file_name = ppFiles_to_download[j]->file_name;
	if (lstat(file_name, &stbuf) == 0) {
	    deactivate_form(fm->fd_main);
	    if (stbuf.st_size < ppFiles_to_download[j]->file_size && type == BIN)
		sprintf(tmp_str, "Local file %s exists\nand is shorter than remote file!", cfile_name = cut(ppFiles_to_download[j]->file_name));
	    else {
		deactivate_object(fdq->resume_transf);
		sprintf(tmp_str, "Local file %s exists!", cfile_name = cut(file_name));
	    }
	    free(cfile_name);
	    fl_show_form(fdq->fd_download_question, FL_PLACE_MOUSE, FL_TRANSIENT, "");
	    fl_set_object_label(fdq->txt, tmp_str);
	    ob = fl_do_forms();
	    if (ob == fdq->cancel)
		action[j] = CANCEL;
	    if (ob == fdq->overwrite)
		action[j] = OVERWRITE;
	    if (ob == fdq->resume_transf)
		action[j] = RESUME_TRANSF;
	    if (fdq->resume_transf->active <= 0)
		activate_object(fdq->resume_transf);
	    fl_hide_form(fdq->fd_download_question);
	    activate_form(fm->fd_main);
	} else
	    action[j] = OVERWRITE;
    }
    deactivate_form(fm->fd_main);
    fl_show_form(fd->fd_download, FL_PLACE_GEOMETRY, FL_TRANSIENT, "Xrmftp: download");
    center_downl();
    for (j = 0; j < n_files && !aborted; j++) {
	pFile = ppFiles_to_download[j];
	if (S_ISLNK(pFile->mode))
	    file_name = pFile->link_name;
	else
	    file_name = pFile->file_name;
	if (action[j] == CANCEL)
	    continue;
	if ((pFile->mode & S_IXUSR) == S_IXUSR)
	    mode = 0777;
	else
	    mode = 0666;
	if (pFile->path != NULL) {
	    full_fname = malloc(strlen(pFile->path) + strlen(file_name) + 4);
	    sprintf(full_fname, "%s/%s", pFile->path, file_name);
	    rfn = full_fname;
	} else {
	    full_fname = NULL;
	    rfn = file_name;
	}
	lfn = file_name;
	if (!ninteract) {
	    if (action[j] == OVERWRITE) {
		flags = O_CREAT | O_WRONLY | O_TRUNC;
		fl_set_object_label(fmsg->txt, "Can not create file !");
	    } else {
		flags = O_APPEND | O_WRONLY;
		fl_set_object_label(fmsg->txt, "Can not open file !");
	    }
	    fl_set_slider_bounds(fd->sl_time, 0, (double) (pFile->file_size));
	    fl_set_slider_value(fd->sl_time, 0);
	    cfile_name = cut(rfn);
	    fl_set_object_label(fd->txt_file_name, cfile_name);
	    free(cfile_name);
	    fl_set_object_label(fd->txt_transm, "0");
	    if (pFile->file_size < 1024)
		sprintf(tmp_str, "%li", pFile->file_size);
	    else
		sprintf(tmp_str, "%li k", pFile->file_size >> 10);
	    fl_set_object_label(fd->txt_total, tmp_str);
	    fl_set_object_label(fd->txt_transfer_rate, "");
	    fl_set_object_label(fd->txt_elapsed_time, "");
	    fl_set_object_label(fd->txt_estimated_time, "");
	    fl_check_forms();
	}
	if (type != cur_type && send_command("TYPE", type == ASCII ? "A" : "I", NULL) == 200)
	    cur_type = type;
	if (action[j] == RESUME_TRANSF) {
	    lstat(lfn, &stbuf);
	    bytes_transm = stbuf.st_size;
	    sprintf(tmp_str, "%li", stbuf.st_size);
	    if (data_command2("REST", tmp_str, "RETR", rfn) != 150)
		goto download_err;
	} else {
	    bytes_transm = 0;
	    if (data_command("RETR", rfn) != 150)
		goto download_err;
	}
	if ((dest_file = open(lfn, flags, mode)) < 0) {
	    if (!ninteract) {
		deactivate_form(fm->fd_main);
		fl_show_form(fmsg->fd_message, FL_PLACE_MOUSE, FL_TRANSIENT, "");
		fl_do_forms();
		fl_hide_form(fmsg->fd_message);
		activate_form(fm->fd_main);
	    }
	    return;
	}
	if (!ninteract) {
	}
	gettimeofday(&start_time, NULL);
	while (1) {
	    while ((bytes_received = read(sock_servDTP, receive_buf, BUF_SIZE)) < 0) {
		if (errno != EAGAIN) {
		    add_to_log_err("read");
		    goto download_err1;
		}
		check_forms();
		if (aborted)
		    goto download_err1;
	    }
	    if (bytes_received == 0)
		break;
	    if (aborted)
		goto download_err1;
	    pc1 = pc2 = receive_buf;
	    bytes_wrote = bytes_received;
	    if (type == ASCII) {
		bytes_wrote = 0;
		for (i = 0; i < bytes_received; i++) {
		    if (*pc1 != '\r') {
			*(pc2++) = *pc1;
			bytes_wrote++;
		    }
		    pc1++;
		}
	    }
	    if (sys_unix)
		bytes_transm += bytes_wrote;
	    else
		bytes_transm += bytes_received;
	    check_forms();
	    write(dest_file, receive_buf, bytes_wrote);
	    gettimeofday(&cur_time, NULL);
	    elapsed_time = cur_time.tv_sec - start_time.tv_sec;
	    if (!ninteract) {
		if (elapsed_time != 0) {
		    transfer_rate = (float) bytes_transm / (float) elapsed_time;
		    estimated_time = pFile->file_size / transfer_rate;
		    sprintf(tmp_str, "%.2f kbytes/sec.", transfer_rate / 1024);
		    fl_set_object_label(fd->txt_transfer_rate, tmp_str);
		    sprintf(tmp_str, "%li sec.", elapsed_time);
		    fl_set_object_label(fd->txt_elapsed_time, tmp_str);
		    sprintf(tmp_str, "%li sec.", estimated_time);
		    fl_set_object_label(fd->txt_estimated_time, tmp_str);
		}
		if (bytes_transm < 1024)
		    sprintf(tmp_str, "%li", bytes_transm);
		else
		    sprintf(tmp_str, "%li k", bytes_transm >> 10);
		fl_set_object_label(fd->txt_transm, tmp_str);
		fl_set_slider_value(fd->sl_time, bytes_transm);
	    }
	}
      download_err1:
	close(sock_servDTP);
	close(sock_userDTP);
	if (aborted)
	    get_reply(NULL);
	get_reply(NULL);
      download_err:
	close(dest_file);
	free(full_fname);
    }
    if (aborted)
	aborted = 0;
    if (ninteract) {
	if (flog != NULL)
	    fclose(flog);
	exit(0);
    }
    else {
     fl_hide_form(fd->fd_download);
     activate_form(fm->fd_main);
    }
}

void upload(struct dir_item **ppFiles_to_upload, int n_files, int recurs)
{
    int bytes_read, i, j, bytes_to_sent, bytes_sent, bs, src_file, action[n_files], fexists;
    long bytes_transm, elapsed_time, estimated_time;
    double transfer_rate;
    char tmp_str[150], send_buf[2 * BUF_SIZE], read_buf[BUF_SIZE], *pc1,
    *pc2, *rfn, *lfn;
    char *cfile_name, *file_name;
    struct dir_item *pFile, *pDest_file;
    struct timeval start_time, cur_time;
    FL_OBJECT *ob;

    for (j = 0; j < n_files; j++) {
	file_name = ppFiles_to_upload[j]->file_name;
	fexists = 0;
	if (!recurs) {
	    for (i = 0; i < n_remote; i++)
		if (strcmp(file_name, remote_files[i]->file_name) == 0) {
		    fexists = 1;
		    pDest_file = remote_files[i];
		    break;
		}
	}
	if (fexists) {
	    deactivate_form(fm->fd_main);
	    if (pDest_file->file_size < ppFiles_to_upload[j]->file_size && type == BIN)
		sprintf(tmp_str, "Remote file %s exists\nand is shorter than local file!", cfile_name = cut(ppFiles_to_upload[j]->file_name));
	    else {
		deactivate_object(fdq->resume_transf);
		sprintf(tmp_str, "Remote file %s exists!", cfile_name = cut(file_name));
	    }
	    free(cfile_name);
	    fl_show_form(fdq->fd_download_question, FL_PLACE_MOUSE, FL_TRANSIENT, "");
	    fl_set_object_label(fdq->txt, tmp_str);
	    ob = fl_do_forms();
	    if (ob == fdq->cancel)
		action[j] = CANCEL;
	    if (ob == fdq->overwrite)
		action[j] = OVERWRITE;
	    if (ob == fdq->resume_transf)
		action[j] = RESUME_TRANSF;
	    if (fdq->resume_transf->active <= 0)
		activate_object(fdq->resume_transf);
	    fl_hide_form(fdq->fd_download_question);
	    activate_form(fm->fd_main);
	} else
	    action[j] = OVERWRITE;
    }
    for (j = 0; j < n_files && !aborted; j++) {
	pFile = ppFiles_to_upload[j];
	file_name = pFile->file_name;
	if (action[j] == CANCEL)
	    continue;
	lfn = file_name;
	rfn = file_name;
	if ((src_file = open(lfn, O_RDONLY)) < 0) {
	    if (!ninteract) {
		deactivate_form(fm->fd_main);
		fl_set_object_label(fmsg->txt, "Can not open file !");
		fl_show_form(fmsg->fd_message, FL_PLACE_MOUSE, FL_TRANSIENT, "");
		fl_do_forms();
		fl_hide_form(fmsg->fd_message);
		activate_form(fm->fd_main);
	    }
	    return;
	}
	deactivate_form(fm->fd_main);
	if (type != cur_type && send_command("TYPE", type == ASCII ? "A" : "I", NULL) == 200)
	    cur_type = type;
	if (action[j] == RESUME_TRANSF) {
	    bytes_transm = pDest_file->file_size;
	    if (data_command("APPE", rfn) != 150)
		goto upload_err;
	} else {
	    bytes_transm = 0;
	    if (data_command("STOR", rfn) != 150)
		goto upload_err;
	}
	if (!ninteract) {
	    fl_set_slider_bounds(fd->sl_time, 0, (double) (pFile->file_size));
	    fl_set_slider_value(fd->sl_time, bytes_transm);
	    cfile_name = cut(rfn);
	    fl_set_object_label(fd->txt_file_name, cfile_name);
	    free(cfile_name);
	    fl_set_object_label(fd->txt_transm, "0");
	    if (pFile->file_size < 1024)
		sprintf(tmp_str, "%li", pFile->file_size);
	    else
		sprintf(tmp_str, "%li k", pFile->file_size >> 10);
	    fl_set_object_label(fd->txt_total, tmp_str);
	    center_downl();
	    fl_show_form(fd->fd_download, FL_PLACE_GEOMETRY, FL_TRANSIENT, "");
	    fl_check_forms();
	}
	lseek(src_file, bytes_transm, SEEK_SET);
	gettimeofday(&start_time, NULL);
	while (1) {
	    bytes_read = read(src_file, read_buf, BUF_SIZE);
	    if (bytes_read == 0)
		break;
	    pc1 = read_buf;
	    pc2 = send_buf;
	    bytes_to_sent = bytes_read;
	    if (type == ASCII) {
		bytes_to_sent = 0;
		for (i = 0; i < bytes_read; i++) {
		    if (*pc1 == '\n') {
			*(pc2++) = '\r';
			bytes_to_sent++;
		    }
		    *(pc2++) = *(pc1++);
		    bytes_to_sent++;
		}
		pc2 = send_buf;
	    } else
		pc2 = read_buf;
	    if (aborted)
		break;
	    bytes_sent = 0;
	    while ((bs = write(sock_servDTP, pc2 + bytes_sent, bytes_to_sent - bytes_sent)) < 0 || bytes_sent < bytes_to_sent) {
		if (bs > 0)
		 bytes_sent += bs;
		if (errno != EAGAIN && errno !=0) {
		    add_to_log_err("write");
		    perror("write");
		    printf("E %d %d %d\n", errno, bytes_sent, bytes_to_sent);
		    goto upload_err1;
		}
		check_forms();
	    }
	    if (sys_unix)
		bytes_transm += bytes_sent;
	    else
		bytes_transm += bytes_read;
	    check_forms();
	    gettimeofday(&cur_time, NULL);
	    elapsed_time = cur_time.tv_sec - start_time.tv_sec;
	    if (!ninteract) {
		if (elapsed_time != 0) {
		    transfer_rate = (float) bytes_transm / (float) elapsed_time;
		    estimated_time = pFile->file_size / transfer_rate;
		    sprintf(tmp_str, "%.2f kbytes/sec.", transfer_rate / 1024);
		    fl_set_object_label(fd->txt_transfer_rate, tmp_str);
		    sprintf(tmp_str, "%li", elapsed_time);
		    fl_set_object_label(fd->txt_elapsed_time, tmp_str);
		    sprintf(tmp_str, "%li", estimated_time);
		    fl_set_object_label(fd->txt_estimated_time, tmp_str);
		}
		if (bytes_transm < 1024)
		    sprintf(tmp_str, "%li", bytes_transm);
		else
		    sprintf(tmp_str, "%li k", bytes_transm >> 10);
		fl_set_object_label(fd->txt_transm, tmp_str);
		fl_set_slider_value(fd->sl_time, bytes_transm);
	    }
	}
      upload_err1:
	close(sock_servDTP);
	close(sock_userDTP);
	if (aborted)
	    get_reply(NULL);
	get_reply(NULL);
	if (!ninteract)
	    fl_hide_form(fd->fd_download);
      upload_err:
	close(src_file);
	activate_form(fm->fd_main);
    }
    if (aborted)
	aborted = 0;
    if (ninteract) {
	if (flog != NULL)
	    fclose(flog);
	exit(0);
    }
}

/* fd_main callbacks : */

void cb_close(FL_OBJECT * ob, long arg)
{
    int i;
    struct dir_item **ppDir_it;
    struct dir_buf_item *pDbi;

    con_canceled = 1;
    if (!con_opened) {
	con_opened = 0;
	return;
    }
    send_com_no_reply("QUIT", NULL, 0, 1);
    fl_set_form_title(fm->fd_main, "Xrmftp");
    close(sock_servPI);
    add_to_history();
    if (cur_dir != NULL) {
	cur_dir->dir_len = n_remote;
	cur_dir->dir = remote_files;
    }
    while (dir_buf != NULL) {
	ppDir_it = dir_buf->dir;
	for (i = 0; i < dir_buf->dir_len; i++) {
	    free((*ppDir_it)->file_name);
	    free((*ppDir_it)->link_name);
	    free((*ppDir_it)->path);
	    free(*(ppDir_it++));
	}
	free(dir_buf->dir);
	free(dir_buf->dir_path);
	pDbi = dir_buf;
	dir_buf = dir_buf->next;
	free(pDbi);
    }
    cur_dir = NULL;
    fl_clear_browser(fm->br_remote);
    fl_clear_browser(fm->br_remote_size);
    fl_set_object_label(fm->txt_remote_dir, "");
    deactivate_object(fm->remote_btns);
    deactivate_object(fm->br_remote);
    deactivate_object(fm->br_remote_size);
    fl_set_object_label(fm->con_close, "Connect");
    fl_set_object_callback(fm->con_close, cb_connect, 0);
    con_opened = 0;
}

void cb_connect(FL_OBJECT * ob, long arg)
{
    int x, y;

    if (fcp->br_history->visible)
	cb_history(ob, 0);
    x = fm->fd_main->x + (fm->fd_main->w - fcp->fd_conn_par->w) / 2;
    y = fm->fd_main->y + (fm->fd_main->h - fcp->fd_conn_par->h) / 2;
    fl_set_form_position(fcp->fd_conn_par, x, y);
    fl_show_form(fcp->fd_conn_par, FL_PLACE_GEOMETRY, FL_TRANSIENT, "");
    deactivate_form(fm->fd_main);
    fl_set_focus_object(fcp->fd_conn_par, fcp->address);
}

void cb_about(FL_OBJECT * ob, long arg)
{
    deactivate_form(fm->fd_main);
    fl_show_form(fa->fd_about, FL_PLACE_MOUSE, FL_TRANSIENT, "");
}

void cb_exit(FL_OBJECT * ob, long arg)
{
    struct hist_item *pHist_it;

    if (con_opened) {
	send_com_no_reply("QUIT", NULL, 0, 1);
	add_to_history();
	close(sock_servPI);
    }
    fl_finish();
    while (hist_first != NULL) {
	free(hist_first->address);
	free(hist_first->user_name);
	free(hist_first->pass_unenc);
	free(hist_first->local_dir);
	free(hist_first->remote_dir);
	pHist_it = hist_first->next;
	free(hist_first);
	hist_first = pHist_it;
    }
    free(home_dir);
    free(opt_file_name);
    free(hist_file_name);
    free(log_file_name);
    free(address);
    free(user_name);
    free(pass_enc);
    free(pass_unenc);
    free(local_dir_path_inp);
    free(remote_dir_path_inp);
    if (flog != NULL)
	fclose(flog);
    exit(0);
}

void cb_type(FL_OBJECT * ob, long arg)
{
    if (ob == fm->binary)
	type = BIN;
    else
	type = ASCII;
}

void clear_buffer()
{
    struct dir_item *pDir_it = buffer_list;

    while (buffer_list != NULL) {
	pDir_it = buffer_list->next;
	free(buffer_list);
	buffer_list = pDir_it;
    }
    fl_clear_browser(fm->br_buffer_name);
    fl_set_object_label(fm->txt_buffer, "");
    n_buffer = 0;
}

void download_dir(const char *dir, const char *old_dir, const char *old_ldir)
{
    struct dir_item **ppFiles_to_download, **ppFiles;
    struct dir_buf_item *pDbi;
    int i, j = 0;
    char *crd;

    send_command("CWD", dir, NULL);
    if ((pDbi = read_rdir_to_mem(0)) == NULL) {
	send_command("CWD", old_dir, NULL);
	return;
    }
    if (mkdir(dir, 0777) < 0 || chdir(dir) < 0) {
	send_command("CWD", old_dir, NULL);
	return;
    }
    crd = get_cwdir();
    ppFiles = pDbi->dir;
    ppFiles_to_download = malloc(pDbi->dir_len * sizeof(struct dir_item *));
    for (i = 0; i < pDbi->dir_len; i++)
	if (!S_ISDIR(ppFiles[i]->mode))
	    ppFiles_to_download[j++] = ppFiles[i];
    if (j)
	download(ppFiles_to_download, j);
    free(ppFiles_to_download);
    for (i = 0; i < pDbi->dir_len; i++) {
	if (S_ISDIR(ppFiles[i]->mode) && strcmp(ppFiles[i]->file_name, ".."))
	    download_dir(ppFiles[i]->file_name, pDbi->dir_path, crd);
    }
    free(crd);
    chdir(old_ldir);
    send_command("CWD", old_dir, NULL);
}

void cb_download_buffer(FL_OBJECT * ob, long arg)
{
    int i, j = 0;
    struct dir_item *apFiles_to_download[n_buffer], *pDir_it = buffer_list;
    char *crd = get_cwdir();

    for (i = 0; i < n_buffer; i++) {
	if (!S_ISDIR(pDir_it->mode))
	    apFiles_to_download[j++] = pDir_it;
	pDir_it = pDir_it->next;
    }
    if (j)
	download(apFiles_to_download, j);
    pDir_it = buffer_list;
    for (i = 0; i < n_buffer; i++) {
	if (S_ISDIR(pDir_it->mode) && strcmp(pDir_it->file_name, ".."))
	{
	    send_command("CWD", pDir_it->path, NULL);
	    download_dir(pDir_it->file_name, pDir_it->path, crd);
	    send_command("CWD", remote_dir_path, NULL);
	}
	pDir_it = pDir_it->next;
    }
    free(crd);
    clear_buffer();
    read_local_dir();
}

void rem_from_buf(int line)
{
    int i;
    struct dir_item *pDir_it = buffer_list, *pDir_it1;

    fl_delete_browser_line(fm->br_buffer_name, line);
    if (line == n_buffer) {
	buffer_list = buffer_list->next;
	free(pDir_it->file_name);
	free(pDir_it->link_name);
	free(pDir_it->path);
	free(pDir_it);
	n_buffer--;
	return;
    }
    for (i = n_buffer; i > line + 1; i--)
	pDir_it = pDir_it->next;
    pDir_it1 = pDir_it->next;
    pDir_it->next = pDir_it1->next;
    free(pDir_it1->file_name);
    free(pDir_it->link_name);
    free(pDir_it1->path);
    free(pDir_it1);
    n_buffer--;
}

void cb_rem_from_buf(FL_OBJECT * ob, long arg)
{
    int i;

    fl_freeze_form(fm->fd_main);
    for (i = n_buffer; i > 0; i--)
	if (fl_isselected_browser_line(fm->br_buffer_name, i))
	    rem_from_buf(i);
    fl_set_object_label(fm->txt_buffer, "");
    fl_unfreeze_form(fm->fd_main);
}

void cb_br_local(FL_OBJECT * ob, long arg)
{
    int i = fl_get_browser(ob);

    if (i > 0) {
	local_files[i - 1]->selected = 1;
	if (ob == fm->br_local)
	    fl_select_browser_line(fm->br_local_size, i);
	else
	    fl_select_browser_line(fm->br_local, i);
	return;
    }
    if (i < 0) {
	local_files[-i - 1]->selected = 0;
	if (ob == fm->br_local)
	    fl_deselect_browser_line(fm->br_local_size, -i);
	else
	    fl_deselect_browser_line(fm->br_local, -i);
    }
}

void cb_br_remote(FL_OBJECT * ob, long arg)
{
    int i = fl_get_browser(ob);

    if (i > 0) {
	remote_files[i - 1]->selected = 1;
	if (ob == fm->br_remote)
	    fl_select_browser_line(fm->br_remote_size, i);
	else
	    fl_select_browser_line(fm->br_remote, i);
	return;
    }
    if (i < 0) {
	remote_files[-i - 1]->selected = 0;
	if (ob == fm->br_remote)
	    fl_deselect_browser_line(fm->br_remote_size, -i);
	else
	    fl_deselect_browser_line(fm->br_remote, -i);
    }
}

void cb_br_buffer(FL_OBJECT * ob, long arg)
{
    int i = fl_get_browser(ob), j;
    struct dir_item *pDir_it = buffer_list;

    if (i > 0) {
	for (j = i; j < n_buffer; j++)
	    pDir_it = pDir_it->next;
	adjust_path(fm->txt_buffer, pDir_it->path);
    } else
	fl_set_object_label(fm->txt_buffer, "");
}

void cb2_br_local(FL_OBJECT * ob, long arg)
{
    int line;
    struct dir_item *pDir_it;

    if (fl_get_browser_maxline(ob) == 0)
	return;
    line = abs(fl_get_browser(ob));
    pDir_it = local_files[line - 1];
    if (S_ISDIR(pDir_it->mode) || S_ISLNK(pDir_it->mode)) {
	if (chdir(pDir_it->file_name) == 0)
	    read_local_dir();
    }
}

void cb_updir_local(FL_OBJECT * ob, long arg)
{
    if (arg) {
	if (chdir("/") == 0)
	    read_local_dir();
	return;
    }
    if (chdir("..") == 0)
	read_local_dir();
}

void cb_updir_remote(FL_OBJECT * ob, long arg)
{
    if (arg) {
	if (send_command("CWD", "/", NULL) == 250)
	    read_remote_dir(0);
	return;
    }
    if (send_command("CWD", "..", NULL) == 250)
	read_remote_dir(0);
}

void cb2_br_remote(FL_OBJECT * ob, long arg)
{
    int line;
    struct dir_item *pDir_it;

    cur_dir->top = fl_get_browser_topline(fm->br_remote);
    if (fl_get_browser_maxline(ob) == 0)
	return;
    line = abs(fl_get_browser(ob));
    pDir_it = remote_files[line - 1];
    if (S_ISDIR(pDir_it->mode)) {
     deactivate_object(fm->remote_btns);
     deactivate_object(fm->br_remote);
     deactivate_object(fm->br_remote_size);
	 if (send_command("CWD", pDir_it->file_name, NULL) == 250)
	    read_remote_dir(0);
     activate_object(fm->remote_btns);
     activate_object(fm->br_remote);
     activate_object(fm->br_remote_size);
	}
    if (S_ISLNK(pDir_it->mode)) {
     deactivate_object(fm->remote_btns);
     deactivate_object(fm->br_remote);
     deactivate_object(fm->br_remote_size);
	 if (send_command("CWD", pDir_it->link_name, NULL) == 250)
	    read_remote_dir(0);
     activate_object(fm->remote_btns);
     activate_object(fm->br_remote);
     activate_object(fm->br_remote_size);
	}
}


void upload_dir(const char *dir)
{
    struct dir_item *pFile_to_upload = malloc(sizeof(struct dir_item));
    struct dirent *dir_ent;
    struct stat stbuf;
    DIR *pDir;

    if (chdir(dir) < 0)
	return;
    if (send_command("MKD", dir, NULL) != 257) {
	chdir("..");
	return;
    }
    if (send_command("CWD", dir, NULL) != 250) {
	chdir("..");
	return;
    }
    if ((pDir = opendir(".")) == NULL) {
	chdir("..");
	send_command("CWD", "..", NULL);
	return;
    }
    while ((dir_ent = readdir(pDir))) {
	lstat(dir_ent->d_name, &stbuf);
	if (strcmp(dir_ent->d_name, ".") == 0 || strcmp(dir_ent->d_name, "..") == 0)
	    continue;
	if (dir_ent->d_name[0] == '.' && !show_hidden_local)
	    continue;
	if (!S_ISDIR(stbuf.st_mode)) {
	    pFile_to_upload->file_name = dir_ent->d_name;
	    pFile_to_upload->file_size = stbuf.st_size;
	    pFile_to_upload->mode = stbuf.st_mode;
	    upload(&pFile_to_upload, 1, 1);
	} else
	    upload_dir(dir_ent->d_name);
    }
    chdir("..");
    read_rdir_to_mem(0);
    send_command("CWD", "..", NULL);
    free(pFile_to_upload);
}


void cb_upload(FL_OBJECT * ob, long arg)
{
    int i, j = 0;
    struct dir_item *apFiles_to_upload[n_local];

    for (i = 1; i <= n_local; i++)
	if (fl_isselected_browser_line(fm->br_local, i) && !S_ISDIR(local_files[i - 1]->mode))
	    apFiles_to_upload[j++] = local_files[i - 1];
    if (j)
	upload(apFiles_to_upload, j, 0);
    for (i = 1; i <= n_local; i++)
	if (fl_isselected_browser_line(fm->br_local, i) && S_ISDIR(local_files[i - 1]->mode)
	    && strcmp(local_files[i - 1]->file_name, ".."))
	    upload_dir(local_files[i - 1]->file_name);
    fl_deselect_browser(fm->br_local);
    fl_deselect_browser(fm->br_local_size);
    read_remote_dir(1);
}

void cb_download(FL_OBJECT * ob, long arg)
{
    int i, j = 0;
    struct dir_item *apFiles_to_download[n_remote];
    char *crd = get_cwdir();

    for (i = 1; i <= n_remote; i++)
	if (fl_isselected_browser_line(fm->br_remote, i) && !S_ISDIR(remote_files[i - 1]->mode))
	    apFiles_to_download[j++] = remote_files[i - 1];
    if (j)
	download(apFiles_to_download, j);
    for (i = 1; i <= n_remote; i++)
	if (fl_isselected_browser_line(fm->br_remote, i)) {
	    if (S_ISDIR(remote_files[i - 1]->mode) && strcmp(remote_files[i - 1]->file_name, ".."))
		download_dir(remote_files[i - 1]->file_name, remote_dir_path, crd);
	}
    fl_deselect_browser(fm->br_remote);
    fl_deselect_browser(fm->br_remote_size);
    read_local_dir();
}

void cb_to_buffer(FL_OBJECT * ob, long arg)
{
    int n_lines, i, repeated;
    struct dir_item *pDir_it;

    n_lines = fl_get_browser_maxline(fm->br_remote);
    for (i = 2; i <= n_lines; i++)
	if (fl_isselected_browser_line(fm->br_remote, i)) {
	    repeated = 0;
	    pDir_it = buffer_list;
	    while (pDir_it != NULL) {
		if (strcmp(remote_files[i - 1]->file_name, pDir_it->file_name) == 0) {
		    repeated = 1;
		    break;
		}
		pDir_it = pDir_it->next;
	    }
	    if (!repeated) {
		add_file_to_list(&buffer_list, remote_files[i - 1]->file_name, remote_files[i - 1]->file_size,
				 remote_files[i - 1]->modif_time, remote_files[i - 1]->mode, remote_dir_path);
		fl_add_browser_line(fm->br_buffer_name, fl_get_browser_line(fm->br_remote, i));
		n_buffer++;
	    }
	}
    fl_deselect_browser(fm->br_remote);
    fl_deselect_browser(fm->br_remote_size);
}

int rmdir_rec(const char *dir_name)
{
    struct stat stbuf;
    DIR *pDir;
    struct dirent *dir_ent;
    char *old_dir;

    if ((old_dir = get_cwdir()) == NULL) {
	free(old_dir);
	return -1;
    }
    chdir(dir_name);
    if ((pDir = opendir(".")) == NULL) {
	return -1;
	free(old_dir);
    }
    while ((dir_ent = readdir(pDir))) {
	lstat(dir_ent->d_name, &stbuf);
	if (strcmp(dir_ent->d_name, ".") == 0 || strcmp(dir_ent->d_name, "..") == 0)
	    continue;
	if (S_ISDIR(stbuf.st_mode)) {
	    if (rmdir(dir_ent->d_name) < 0 && (errno == ENOTEMPTY || errno == EEXIST))
		rmdir_rec(dir_ent->d_name);
	} else
	    remove(dir_ent->d_name);
    }
    chdir(old_dir);
    free(old_dir);
    return rmdir(dir_name);
}

void remove_dirs(int *selected, int n_sel, struct dir_item ***pppFiles,
		 int *pn_files, int place)
{
    int i, success;
    char label[150], *file_name, *cfile_name;

    if (n_sel == 1) {
	file_name = (*pppFiles)[selected[0]]->file_name;
	sprintf(label, "Remove directory %s ?", cfile_name = cut(file_name));
	free(cfile_name);
    } else
	sprintf(label, "Remove %d directories ?", n_sel);
    fl_set_object_label(fq->txt_question, label);
    deactivate_form(fm->fd_main);
    fl_show_form(fq->fd_question, FL_PLACE_GEOMETRY, FL_TRANSIENT, "");
    if (fl_do_forms() == fq->yes)
	for (i = n_sel; i > 0;) {
	    success = 0;
	    i--;
	    file_name = (*pppFiles)[selected[i]]->file_name;
	    if (place == LOCAL) {
		if (rmdir(file_name) == 0)
		    success = 1;
		else if (errno == ENOTEMPTY || errno == EEXIST) {
		    sprintf(label, "Directory %s is not empty.\nDelete it recursively ?", cfile_name = cut(file_name));
		    free(cfile_name);
		    fl_set_object_label(fq->txt_question, label);
		    if (fl_do_forms() == fq->yes)
			if (rmdir_rec(file_name) == 0);
		    success = 1;
		}
	    } else if (send_command("RMD", file_name, NULL) == 250)
		success = 1;
	    if (success)
		remove_file_from_array(pppFiles, pn_files, selected[i]);
	}
    activate_form(fm->fd_main);
    fl_hide_form(fq->fd_question);
}

void remove_files(int *selected, int n_sel, struct dir_item ***pppFiles,
		  int *pn_files, int place)
{
    int i, success;
    char label[50], *file_name, *cfile_name;

    if (n_sel == 1) {
	file_name = (*pppFiles)[selected[0]]->file_name;
	sprintf(label, "Remove file %s ?", cfile_name = cut(file_name));
	free(cfile_name);
    } else
	sprintf(label, "Remove %d files ?", n_sel);
    fl_set_object_label(fq->txt_question, label);
    deactivate_form(fm->fd_main);
    fl_show_form(fq->fd_question, FL_PLACE_GEOMETRY, FL_TRANSIENT, "");
    if (fl_do_forms() == fq->yes)
	for (i = n_sel; i > 0;) {
	    success = 0;
	    i--;
	    if (place == REMOTE && S_ISLNK((*pppFiles)[selected[i]]->mode))
		file_name = (*pppFiles)[selected[i]]->link_name;
	    else
		file_name = (*pppFiles)[selected[i]]->file_name;
	    if (place == LOCAL) {
		if (remove(file_name) == 0)
		    success = 1;
	    } else if (send_command("DELE", file_name, NULL) == 250)
		success = 1;
	    if (success)
		remove_file_from_array(pppFiles, pn_files, selected[i]);
	}
    activate_form(fm->fd_main);
    fl_hide_form(fq->fd_question);
}

void rename_files(int *selected, int n_sel, struct dir_item **ppFiles,
		  int place)
{
    int i, success;
    const char *new_name;
    char label[50], *cfile_name, *file_name;
    FL_OBJECT *ret_object;

    for (i = 0; i < n_sel; i++) {
	if (place == REMOTE && S_ISLNK(ppFiles[selected[i]]->mode))
	    file_name = ppFiles[selected[i]]->link_name;
	else
	    file_name = ppFiles[selected[i]]->file_name;
	fl_set_input(fi->input, "");
	sprintf(label, "Rename/move file %s to", cfile_name = cut(file_name));
	fl_set_object_label(fi->txt_input, label);
	free(cfile_name);
	deactivate_form(fm->fd_main);
	fl_show_form(fi->fd_input, FL_PLACE_GEOMETRY, FL_TRANSIENT, "");
	ret_object = fl_do_forms();
	success = 0;
	if ((ret_object == fi->ok || ret_object == fi->input) && *(new_name = fl_get_input(fi->input)) != '\0')
	    if (place == LOCAL) {
		if (rename(file_name, new_name) == 0)
		    success = 1;
	    } else if (send_command("RNFR", file_name, NULL) == 350 && send_command("RNTO", new_name, NULL) == 250)
		success = 1;
	if (success) {
	    free(file_name);
	    file_name = malloc(strlen(new_name) + 1);
	    strcpy(file_name, new_name);
	    ppFiles[selected[i]]->file_name = file_name;
	}
	fl_hide_form(fi->fd_input);
	activate_form(fm->fd_main);
	if (ret_object == fi->cancel)
	    break;
    }
}

void cb_btn_local(FL_OBJECT * ob, long arg)
{
    int n_sel = 0, x, y, i, *selected;
    const char *dir;
    char *cfile_name, *file_name, *cdir;
    FL_OBJECT *ret_ob;

    fl_set_input(fi->input, "");
    x = fm->fd_main->x + 5;
    y = fm->fd_main->y + fm->br_local->y + fm->br_local->h + 4;
    fl_set_form_position(fq->fd_question, x, y);
    fl_set_form_position(fi->fd_input, x, y);
    if (arg < 3) {
	if (arg == 2) {
	    fl_set_input(fi->input, cdir = get_cwdir());
	    fl_set_input_selected(fi->input, 1);
	    free(cdir);
	}
	fl_set_object_label(fi->txt_input, "Enter directory name:");
	fl_show_form(fi->fd_input, FL_PLACE_GEOMETRY, FL_TRANSIENT, "");
	deactivate_form(fm->fd_main);
	ret_ob = fl_do_forms();
	activate_form(fm->fd_main);
	fl_hide_form(fi->fd_input);
	if (ret_ob == fi->cancel)
	    return;
	dir = fl_get_input(fi->input);
    }
    switch (arg) {
    case 1:
	if (mkdir(dir, 0777) == 0) {
	    add_file_to_array(&local_files, &n_local, dir, 0, 0, S_IFDIR);
	    put_files_into_browser(fm->br_local, fm->br_local_size, local_files, n_local, sort_key_local);
	}
	break;
    case 2:
	if (chdir(dir) == 0)
	    read_local_dir();
	break;
    case 3:
	selected = malloc(n_local * sizeof(int));
	for (i = 1; i <= n_local; i++)
	    if (fl_isselected_browser_line(fm->br_local, i))
		selected[n_sel++] = i - 1;
	if (n_sel) {
	    rename_files(selected, n_sel, local_files, LOCAL);
	    put_files_into_browser(fm->br_local, fm->br_local_size, local_files, n_local, sort_key_local);
	}
	free(selected);
	break;
    case 4:
	selected = malloc(n_local * sizeof(int));
	for (i = 1; i <= n_local; i++)
	    if (fl_isselected_browser_line(fm->br_local, i) && S_ISDIR(local_files[i - 1]->mode))
		selected[n_sel++] = i - 1;
	if (n_sel) {
	    remove_dirs(selected, n_sel, &local_files, &n_local, LOCAL);
	    put_files_into_browser(fm->br_local, fm->br_local_size, local_files, n_local, sort_key_local);
	}
	free(selected);
	break;
    case 5:
	selected = malloc(n_local * sizeof(int));
	for (i = 1; i <= n_local; i++)
	    if (fl_isselected_browser_line(fm->br_local, i) && !S_ISDIR(local_files[i - 1]->mode))
		selected[n_sel++] = i - 1;
	if (n_sel) {
	    remove_files(selected, n_sel, &local_files, &n_local, LOCAL);
	    put_files_into_browser(fm->br_local, fm->br_local_size, local_files, n_local, sort_key_local);
	}
	free(selected);
	break;
    case 6:
	fl_clear_browser(flv->br_view);
	for (i = 1; i <= n_local; i++)
	    if (fl_isselected_browser_line(fm->br_local, i)) {
		file_name = local_files[i - 1]->file_name;
		fl_set_object_label(flv->txt_file_name, cfile_name = cut(file_name));
		free(cfile_name);
		fl_load_browser(flv->br_view, file_name);
		fl_show_form(flv->fd_local_view, FL_PLACE_MOUSE, FL_TRANSIENT, "");
		break;
	    }
	break;
    case 7:
	read_local_dir();
    }
}

void cb_btn_remote(FL_OBJECT * ob, long arg)
{
    int n_lines, x, y, i, *selected, n_sel = 0;
    const char *dir;
    FL_OBJECT *ret_ob;

    n_lines = fl_get_browser_maxline(fm->br_remote);
    fl_set_input(fi->input, "");
    x = fm->fd_main->x + fm->txt_remote_dir->x + (fm->txt_remote_dir->w +
						-fq->fd_question->w) / 2;
    y = fm->fd_main->y + fm->br_remote->y + fm->br_remote->h + 4;
    fl_set_form_position(fq->fd_question, x, y);
    x = fm->fd_main->x + fm->txt_remote_dir->x + (fm->txt_remote_dir->w +
						  -fi->fd_input->w) / 2;
    y = fm->fd_main->y + fm->br_remote->y + fm->br_remote->h + 4;
    fl_set_form_position(fi->fd_input, x, y);
    if (arg < 3) {
	if (arg == 2) {
	    fl_set_input(fi->input, remote_dir_path);
	    fl_set_input_selected(fi->input, 1);
	}
	fl_set_object_label(fi->txt_input, "Enter directory name:");
	fl_show_form(fi->fd_input, FL_PLACE_GEOMETRY, FL_TRANSIENT, "");
	deactivate_form(fm->fd_main);
	ret_ob = fl_do_forms();
	activate_form(fm->fd_main);
	fl_hide_form(fi->fd_input);
	if (ret_ob == fi->cancel)
	    return;
	dir = fl_get_input(fi->input);
    }
    deactivate_object(fm->remote_btns);
    deactivate_object(fm->br_remote);
    deactivate_object(fm->br_remote_size);
    switch (arg) {
    case 1:
	if (send_command("MKD", dir, NULL) == 257) {
	    add_file_to_array(&remote_files, &n_remote, dir, 0, 0, S_IFDIR);
	    put_files_into_browser(fm->br_remote, fm->br_remote_size, remote_files, n_remote, sort_key_remote);
	}
	break;
    case 2:
	if (send_command("CWD", dir, NULL) == 250)
	    read_remote_dir(0);
	break;
    case 3:
	selected = malloc(n_remote * sizeof(int));
	for (i = 1; i <= n_remote; i++)
	    if (fl_isselected_browser_line(fm->br_remote, i))
		selected[n_sel++] = i - 1;
	if (n_sel) {
	    rename_files(selected, n_sel, remote_files, REMOTE);
	    put_files_into_browser(fm->br_remote, fm->br_remote_size, remote_files, n_remote, sort_key_remote);
	}
	free(selected);
	break;
    case 4:
	selected = malloc(n_remote * sizeof(int));
	for (i = 1; i <= n_remote; i++)
	    if (fl_isselected_browser_line(fm->br_remote, i) && S_ISDIR(remote_files[i - 1]->mode))
		selected[n_sel++] = i - 1;
	if (n_sel) {
	    remove_dirs(selected, n_sel, &remote_files, &n_remote, REMOTE);
	    put_files_into_browser(fm->br_remote, fm->br_remote_size, remote_files, n_remote, sort_key_remote);
	}
	free(selected);
	break;
    case 5:
	selected = malloc(n_remote * sizeof(int));
	for (i = 1; i <= n_remote; i++)
	    if (fl_isselected_browser_line(fm->br_remote, i) && !S_ISDIR(remote_files[i - 1]->mode))
		selected[n_sel++] = i - 1;
	if (n_sel) {
	    remove_files(selected, n_sel, &remote_files, &n_remote, REMOTE);
	    put_files_into_browser(fm->br_remote, fm->br_remote_size, remote_files, n_remote, sort_key_remote);
	}
	free(selected);
	break;
    case 7:
	read_remote_dir(1);
	break;
    }
    activate_object(fm->remote_btns);
    activate_object(fm->br_remote);
    activate_object(fm->br_remote_size);
}

void cb_sort(FL_OBJECT * ob, long arg)
{
    if (arg < 3) {
	sort_key_local = arg;
	put_files_into_browser(fm->br_local, fm->br_local_size, local_files, n_local, arg);
    } else {
	sort_key_remote = arg - 2;
	put_files_into_browser(fm->br_remote, fm->br_remote_size, remote_files, n_remote, arg - 2);
    }
}

void cb_remote_view(FL_OBJECT * ob, long arg)
{
    int bytes_received, bytes_wrote, i;
    long bytes_transm, file_size;
    char *pc1, *pc2, fsize[25], receive_buf[BUF_SIZE + 1], *file_name,
    *cfile_name;

    for (i = 1; !fl_isselected_browser_line(fm->br_remote, i) ||
	 S_ISDIR(remote_files[i - 1]->mode); i++)
	if (i > n_remote)
	    return;
    fl_clear_browser(frv->br_view);
    fl_set_object_label(frv->btn_ok_cnc, "Cancel");
    fl_set_object_callback(frv->btn_ok_cnc, cb_dwnld_cancel, 0);
    if (S_ISLNK(remote_files[i - 1]->mode))
	file_name = remote_files[i - 1]->link_name;
    else
	file_name = remote_files[i - 1]->file_name;
    file_size = remote_files[i - 1]->file_size;
    fl_set_object_label(frv->txt_transm, "0");
    if (file_size < 1024)
	sprintf(fsize, "%li", file_size);
    else
	sprintf(fsize, "%li k", file_size >> 10);
    fl_set_object_label(frv->txt_total, fsize);
    fl_set_object_color(frv->sl_time, FL_COL1, FL_GREEN);
    fl_set_slider_bounds(frv->sl_time, 0, (double) (file_size));
    fl_set_slider_value(frv->sl_time, 0);
    fl_set_object_label(frv->txt_file_name, cfile_name = cut(file_name));
    free(cfile_name);
    busy = 1;
    deactivate_object(fm->local_btns);
    deactivate_object(fm->remote_btns);
    deactivate_object(fm->br_remote);
    deactivate_object(fm->br_remote_size);
    if (cur_type != ASCII && send_command("TYPE", "A", NULL) == 200)
	cur_type = ASCII;
    if (data_command("RETR", file_name) != 150) {
	activate_form(fm->fd_main);
	goto view_err;
    }
    deactivate_form(fm->fd_main);
    fl_show_form(frv->fd_remote_view, FL_PLACE_MOUSE, FL_TRANSIENT, "");
    fl_check_forms();
    bytes_transm = 0;
    while (1) {
	while ((bytes_received = read(sock_servDTP, receive_buf, BUF_SIZE)) < 0) {
	    if (errno != EAGAIN) {
		add_to_log_err("read");
		goto view_err1;
	    }
	    fl_check_forms();
	    if (aborted)
		goto view_err1;
	}
	if (bytes_received == 0)
	    break;
	if (aborted)
	    goto view_err1;
	pc1 = pc2 = receive_buf;
	bytes_wrote = 0;
	for (i = 0; i < bytes_received; i++) {
	    if (*pc1 != '\r') {
		*(pc2++) = *pc1;
		bytes_wrote++;
	    }
	    pc1++;
	}
	receive_buf[bytes_wrote] = '\0';
	if (sys_unix)
	    bytes_transm += bytes_wrote;
	else
	    bytes_transm += bytes_received;
	fl_check_forms();
	for (i = 0; receive_buf[i] != '\n'; i++);
	receive_buf[i] = '\0';
	fl_addto_browser_chars(frv->br_view, receive_buf);
	fl_add_browser_line(frv->br_view, receive_buf + i + 1);
	if (bytes_transm < 1024)
	    sprintf(fsize, "%li", bytes_transm);
	else
	    sprintf(fsize, "%li k", bytes_transm >> 10);
	fl_set_object_label(frv->txt_transm, fsize);
	fl_set_slider_value(frv->sl_time, bytes_transm);
    }
  view_err1:
    close(sock_servDTP);
    close(sock_userDTP);
    if (aborted)
	get_reply(NULL);
    get_reply(NULL);
    fl_set_object_color(frv->sl_time, FL_COL1, FL_INACTIVE);
    fl_set_object_label(frv->btn_ok_cnc, "OK");
    fl_set_object_callback(frv->btn_ok_cnc, cb_remote_view_ok, 0);
    goto view_end;
  view_err:
    close(sock_userDTP);
    busy = 0;
    activate_object(fm->local_btns);
    activate_object(fm->remote_btns);
    activate_object(fm->br_remote);
    activate_object(fm->br_remote_size);
  view_end:
    if (aborted) {
	aborted = 0;
	fl_hide_form(frv->fd_remote_view);
	activate_form(fm->fd_main);
	busy = 0;
	activate_object(fm->local_btns);
	activate_object(fm->remote_btns);
	activate_object(fm->br_remote);
	activate_object(fm->br_remote_size);
    }
}

void cb_select(FL_OBJECT * ob, long arg)
{
    int i, x, y, lmax = fl_get_browser_maxline(fm->br_local);
    int rmax = fl_get_browser_maxline(fm->br_remote);
    int bmax = fl_get_browser_maxline(fm->br_buffer_name);
    const char *pattern;
    FL_OBJECT *ret_ob;

    fl_freeze_form(fm->fd_main);
    switch (arg) {
    case 1:
	for (i = 1; i <= lmax; i++) {
	    fl_select_browser_line(fm->br_local, i);
	    fl_select_browser_line(fm->br_local_size, i);
	}
	break;
    case 2:
	fl_deselect_browser(fm->br_local);
	fl_deselect_browser(fm->br_local_size);
	break;
    case 3:
	fl_set_input(fi->input, "");
	x = fm->fd_main->x + 5;
	y = fm->fd_main->y + fm->br_local->y + fm->br_local->h + 4;
	fl_set_form_position(fi->fd_input, x, y);
	fl_set_object_label(fi->txt_input, "Enter pattern:");
	fl_show_form(fi->fd_input, FL_PLACE_GEOMETRY, FL_TRANSIENT, "");
	deactivate_form(fm->fd_main);
	ret_ob = fl_do_forms();
	activate_form(fm->fd_main);
	fl_hide_form(fi->fd_input);
	if (ret_ob == fi->cancel) {
	    fl_unfreeze_form(fm->fd_main);
	    return;
	}
	pattern = fl_get_input(fi->input);
	for (i = 1; i <= lmax; i++)
	    if (fnmatch(pattern, local_files[i - 1]->file_name, 0) == 0) {
		fl_select_browser_line(fm->br_local, i);
		fl_select_browser_line(fm->br_local_size, i);
	    }
	break;
    case 4:
	for (i = 1; i <= rmax; i++) {
	    fl_select_browser_line(fm->br_remote, i);
	    fl_select_browser_line(fm->br_remote_size, i);
	}
	break;
    case 5:
	fl_deselect_browser(fm->br_remote);
	fl_deselect_browser(fm->br_remote_size);
	break;
    case 6:
	fl_set_input(fi->input, "");
	x = fm->fd_main->x + fm->txt_remote_dir->x + (fm->txt_remote_dir->w +
						   -fi->fd_input->w) / 2;
	y = fm->fd_main->y + fm->br_remote->y + fm->br_remote->h + 4;
	fl_set_form_position(fi->fd_input, x, y);
	fl_set_object_label(fi->txt_input, "Enter pattern:");
	fl_show_form(fi->fd_input, FL_PLACE_GEOMETRY, FL_TRANSIENT, "");
	deactivate_form(fm->fd_main);
	ret_ob = fl_do_forms();
	activate_form(fm->fd_main);
	fl_hide_form(fi->fd_input);
	if (ret_ob == fi->cancel) {
	    fl_unfreeze_form(fm->fd_main);
	    return;
	}
	pattern = fl_get_input(fi->input);
	for (i = 1; i <= rmax; i++)
	    if (fnmatch(pattern, remote_files[i - 1]->file_name, 0) == 0) {
		fl_select_browser_line(fm->br_remote, i);
		fl_select_browser_line(fm->br_remote_size, i);
	    }
	break;
    case 7:
	for (i = 1; i <= bmax; i++)
	    fl_select_browser_line(fm->br_buffer_name, i);
	break;
    case 8:
	fl_deselect_browser(fm->br_buffer_name);
    }
    fl_unfreeze_form(fm->fd_main);
}

/* fd_download callbacks: */

void cb_dwnld_cancel(FL_OBJECT * ob, long arg)
{
    char send_buf[20];

    if (aborted)
	return;
    sprintf(send_buf, "%c%c%c", IAC, IP, IAC);
    send_com_no_reply(send_buf, NULL, 0, 0);
    sprintf(send_buf, "%c", DM);
    send_com_no_reply(send_buf, NULL, MSG_OOB, 0);
    sprintf(send_buf, "ABOR");
    send_com_no_reply(send_buf, NULL, 0, 1);
    aborted = 1;
}

void cb_detach(FL_OBJECT * ob, long arg)
{
    ninteract = 1;
    if (fcntl(sock_servPI, F_SETFL, fcntl(sock_servPI, F_GETFL) & ~O_NONBLOCK) < 0) {
	add_to_log_err("fcntl");
	exit(1);
    }
    fcntl(sock_servDTP, F_SETFL, fcntl(sock_servPI, F_GETFL) & ~O_NONBLOCK);
    fl_finish();
}

/* fd_conn_par callbacks: */

void cb_anonymous(FL_OBJECT * ob, long arg)
{
    if (fcp->br_history->visible)
	cb_history(ob, 0);
    if (fl_get_button(ob)) {
	fl_set_input(fcp->user_name, "anonymous");
	fl_set_input(fcp->pass_unenc, e_mail ? e_mail : "");
	fl_show_object(fcp->pass_unenc);
	if (fcp->pass_enc->focus)
	    fl_set_focus_object(fcp->fd_conn_par, fcp->pass_unenc);
	fl_hide_object(fcp->pass_enc);
    } else {
	fl_set_input(fcp->pass_enc, "");
	fl_show_object(fcp->pass_enc);
	if (fcp->pass_unenc->focus)
	    fl_set_focus_object(fcp->fd_conn_par, fcp->pass_enc);
	fl_hide_object(fcp->pass_unenc);
    }
}

void cb_ok(FL_OBJECT * ob, long arg)
{
    const char *input;
    char *title, *syst_reply;
    char *password;
    int i;

    free(address);
    free(user_name);
    free(pass_enc);
    free(pass_unenc);
    free(local_dir_path_inp);
    free(remote_dir_path_inp);
    fl_set_object_label(fm->con_close, "Close");
    fl_set_object_callback(fm->con_close, cb_close, 0);
    anonym_login = fl_get_button(fcp->anonymous);
    fl_clear_browser(fm->br_log);
    input = fl_get_input(fcp->address);
    address = malloc(strlen(input) + 1);
    strcpy(address, input);
    input = fl_get_input(fcp->user_name);
    user_name = malloc(strlen(input) + 1);
    strcpy(user_name, input);
    if (anonym_login) {
	input = fl_get_input(fcp->pass_unenc);
	pass_unenc = malloc(strlen(input) + 1);
	strcpy(pass_unenc, input);
	*(pass_enc = malloc(1)) = '\0';
    } else {
	input = fl_get_input(fcp->pass_enc);
	pass_enc = malloc(strlen(input) + 1);
	strcpy(pass_enc, input);
	*(pass_unenc = malloc(1)) = '\0';
    }
    input = fl_get_input(fcp->local_dir);
    local_dir_path_inp = malloc(strlen(input) + 1);
    strcpy(local_dir_path_inp, input);
    chdir(local_dir_path_inp);
    input = fl_get_input(fcp->remote_dir);
    remote_dir_path_inp = malloc(strlen(input) + 1);
    strcpy(remote_dir_path_inp, input);
    busy = 1;
    deactivate_object(fm->local_btns);
    activate_form(fm->fd_main);
    fl_hide_form(fcp->fd_conn_par);
    XFlush(fl_get_display());
    read_local_dir();
    con_canceled = 0;
    add_to_history();
    if (open_ftp_connection() < 0)
	goto err_ok1;
    con_opened = 1;
    cur_type = ASCII;
    if (get_reply(NULL) != 220)
	goto err_ok;
    if ((i = send_command("USER", user_name, NULL)) != 331 && i != 230)
	goto err_ok;
    if (i == 331) {
	password = anonym_login ? pass_unenc : pass_enc;
	i = send_command("PASS", strcmp(password, "") ? password : " ", NULL);
	switch (i) {
	case 230:
	    break;
	case 332:
	    if (send_command("ACCT", e_mail, NULL) == 230)
		break;
	default:
	    goto err_ok;
	}
    }
    send_command("SYST", NULL, &syst_reply);
    if (strstr(syst_reply, "UNIX") != NULL)
	sys_unix = 1;
    else
	sys_unix = 0;
    if (*remote_dir_path_inp != '\0')
	send_command("CWD", remote_dir_path_inp, NULL);
    read_remote_dir(1);
    title = malloc(strlen(address) + 20);
    sprintf(title, "Xrmftp : %s", address);
    fl_set_form_title(fm->fd_main, title);
    fl_set_object_label(fm->txt_status, "");
    activate_object(fm->remote_btns);
    activate_object(fm->local_btns);
    activate_object(fm->br_remote);
    activate_object(fm->br_remote_size);
    busy = 0;
    free(title);
    return;

  err_ok:
    send_com_no_reply("QUIT", NULL, 0, 1);
    close(sock_servPI);
  err_ok1:
    activate_object(fm->local_btns);
    con_opened = 0;
    fl_set_form_title(fm->fd_main, "");
    fl_set_object_label(fm->txt_status, "");
    fl_set_object_label(fm->con_close, "Connect");
    fl_set_object_callback(fm->con_close, cb_connect, 0);
}

void cb_cancel(FL_OBJECT * ob, long arg)
{
    activate_form(fm->fd_main);
    fl_hide_form(fcp->fd_conn_par);
}

void cb_options(FL_OBJECT * ob, long arg)
{
    char input[20], *pc1;

    if (arg == 1) {
	if (fcp->br_history->visible)
	    cb_history(ob, 0);
	fo->fd_options->u_vdata = fcp->fd_conn_par;
	if (f_fold_hidden) {
	    fl_addto_tabfolder(fo->fld_options, "Files", fofl->fd_options_files);
	    f_fold_hidden = 0;
	}
    } else {
	fo->fd_options->u_vdata = fm->fd_main;
	if (!f_fold_hidden) {
	    if (fl_get_folder(fo->fld_options) == fofl->fd_options_files)
		fl_set_folder_bynumber(fo->fld_options, 1);
	    fl_delete_folder(fo->fld_options, fofl->fd_options_files);
	    f_fold_hidden = 1;
	}
    }
    sprintf(input, "%d", port);
    fl_set_input(fon->port, input);
    fl_set_input(fon->e_mail, e_mail);
    pc1 = strrchr(std_bookm_file, '/');
    fl_set_input(fofl->bookm_file, pc1 == NULL ? std_bookm_file : ++pc1);
    fl_set_choice(fof->font_txt, (font_size - 8) / 2);
    fl_set_choice(fof->font_br, (br_fsize - 8) / 2);
    fl_set_button(fofl->btn_show_hidden_local, show_hidden_local);
    fl_set_button(fofl->btn_show_hidden_remote, show_hidden_remote);
    fl_set_button(fon->btn_passive, passive);
    deactivate_form(fo->fd_options->u_vdata);
    fl_show_form(fo->fd_options, FL_PLACE_MOUSE, FL_TRANSIENT, "");
}

void cb_history(FL_OBJECT * ob, long arg)
{
    int i;

    fl_freeze_form(fcp->fd_conn_par);
    i = fl_get_button(fcp->anonymous);
    fl_set_focus_object(fcp->fd_conn_par, fcp->address);
    if (fcp->br_history->visible) {
	fl_hide_object(fcp->br_history);
	fl_show_object(fcp->user_name);
	fl_show_object(fcp->local_dir);
	fl_show_object(fcp->remote_dir);
	fl_show_object(i ? fcp->pass_unenc : fcp->pass_enc);
    } else {
	fl_show_object(fcp->br_history);
	fl_hide_object(fcp->user_name);
	fl_hide_object(fcp->local_dir);
	fl_hide_object(fcp->remote_dir);
	fl_hide_object(i ? fcp->pass_unenc : fcp->pass_enc);
    }
    fl_unfreeze_form(fcp->fd_conn_par);
}

void cb_bookm(FL_OBJECT * ob, long arg)
{
    if (strcmp(addr_file_name, std_bookm_file))
	deactivate_object(fb->btn_delete);
    read_bookmarks(addr_file_name);
    if (fcp->br_history->visible)
	cb_history(ob, 0);
    fl_show_form(fb->fd_bookmarks, FL_PLACE_MOUSE, FL_TRANSIENT, "");
    deactivate_form(fcp->fd_conn_par);
}

void cb_load(FL_OBJECT * ob, long arg)
{
    const char *selected_file, *pc1;

    deactivate_form(fcp->fd_conn_par);
    fl_set_fselector_fontsize(font_size);
    pc1 = strrchr(std_bookm_file, '/');
    selected_file = fl_show_fselector("Filename to load bookmarks from", home_dir, "*.html", pc1 == NULL ? std_bookm_file : ++pc1);
    if (selected_file != NULL) {
	free(addr_file_name);
	addr_file_name = malloc(strlen(selected_file) + 1);
	strcpy(addr_file_name, selected_file);
    }
    activate_form(fcp->fd_conn_par);
}

void cb_add(FL_OBJECT * ob, long arg)
{
    const char *addr, *dir;
    struct addr_item *pAd_it;

    read_bookmarks(std_bookm_file);
    pAd_it = bookm_first;
    addr = fl_get_input(fcp->address);
    dir = fl_get_input(fcp->remote_dir);
    while (pAd_it != NULL) {
	if (strcmp(addr, pAd_it->address) == 0 && strcmp(dir, pAd_it->dir) == 0)
	    return;
	pAd_it = pAd_it->next;
    }
    pAd_it = malloc(sizeof(struct addr_item));
    pAd_it->next = NULL;
    if (bookm_last != NULL)
	bookm_last->next = pAd_it;
    bookm_last = pAd_it;
    if (bookm_first == NULL)
	bookm_first = pAd_it;
    pAd_it->address = malloc(strlen(addr) + 1);
    pAd_it->dir = malloc(strlen(dir) + 1);
    strcpy(pAd_it->address, addr);
    strcpy(pAd_it->dir, dir);
    fl_add_browser_line(fb->br_bookmarks, addr);
    fl_addto_browser_chars(fb->br_bookmarks, dir);
    write_bookmarks();
    read_bookmarks(addr_file_name);
}

void cb_br_hist(FL_OBJECT * ob, long arg)
{
    int i;
    struct hist_item *pHist_it;

    i = fl_get_browser(ob);
    fl_hide_object(fcp->br_history);
    pHist_it = hist_first;
    for (; i > 1; i--)
	pHist_it = pHist_it->next;
    fl_set_button(fcp->anonymous, pHist_it->anonym_login);
    cb_anonymous(fcp->anonymous, 0);
    fl_set_input(fcp->address, pHist_it->address);
    fl_set_input(fcp->user_name, pHist_it->user_name);
    fl_set_input(fcp->pass_unenc, pHist_it->pass_unenc);
    fl_set_input(fcp->local_dir, pHist_it->local_dir);
    fl_set_input(fcp->remote_dir, pHist_it->remote_dir);
    fl_show_object(fcp->user_name);
    fl_show_object(fcp->local_dir);
    fl_show_object(fcp->remote_dir);
    fl_show_object(pHist_it->anonym_login ? fcp->pass_unenc : fcp->pass_enc);
}

/* fd_bookmarks callbacks */

void cb_bm_cancel(FL_OBJECT * ob, long arg)
{
    if (strcmp(addr_file_name, std_bookm_file))
	activate_object(fb->btn_delete);
    fl_hide_form(fb->fd_bookmarks);
    activate_form(fcp->fd_conn_par);
}

void cb_bm_delete(FL_OBJECT * ob, long arg)
{
    int i;
    struct addr_item *pAd_it, *pPrev_it = NULL, *pNext_it;

    pAd_it = bookm_first;
    for (i = 1; i <= fl_get_browser_maxline(fb->br_bookmarks);) {
	if (fl_isselected_browser_line(fb->br_bookmarks, i)) {
	    fl_delete_browser_line(fb->br_bookmarks, i);
	    pNext_it = pAd_it->next;
	    if (pNext_it == NULL)
		bookm_last = pPrev_it;
	    if (pPrev_it != NULL)
		pPrev_it->next = pAd_it->next;
	    else
		bookm_first = pAd_it->next;
	    free(pAd_it->address);
	    free(pAd_it->dir);
	    free(pAd_it);
	    pAd_it = pNext_it;
	} else {
	    pPrev_it = pAd_it;
	    pAd_it = pAd_it->next;
	    i++;
	}
    }
    write_bookmarks();
}

void cb2_br_bookmarks(FL_OBJECT * ob, long arg)
{
    int i;
    struct addr_item *pAd_it = bookm_first;

    i = abs(fl_get_browser(ob));
    for (; i > 1; i--)
	pAd_it = pAd_it->next;
    fl_set_input(fcp->address, pAd_it->address);
    fl_set_input(fcp->remote_dir, pAd_it->dir);
    if (strcmp(addr_file_name, std_bookm_file))
	activate_object(fb->btn_delete);
    fl_hide_form(fb->fd_bookmarks);
    activate_form(fcp->fd_conn_par);
}

void cb_bm_ok(FL_OBJECT * ob, long arg)
{
    int i, m;
    struct addr_item *pAd_it = bookm_first;

    m = fl_get_browser_maxline(fb->br_bookmarks);
    for (i = 1; !fl_isselected_browser_line(fb->br_bookmarks, i); i++)
	if (i > m)
	    return;
    for (; i > 1; i--)
	pAd_it = pAd_it->next;
    fl_set_input(fcp->address, pAd_it->address);
    fl_set_input(fcp->remote_dir, pAd_it->dir);
    if (strcmp(addr_file_name, std_bookm_file))
	activate_object(fb->btn_delete);
    fl_hide_form(fb->fd_bookmarks);
    activate_form(fcp->fd_conn_par);
}

/* fd_options callbacks */

void cb_op_ok(FL_OBJECT * ob, long arg)
{
    int tsize, bsize, r, g, b;
    const char *input;
    FILE *f_options;

    fl_redraw_form(fm->fd_main);
    activate_form(fo->fd_options->u_vdata);
    fl_hide_form(fo->fd_options);
    tsize = atoi(fl_get_choice_text(fof->font_txt));
    bsize = atoi(fl_get_choice_text(fof->font_br));
    if (tsize != font_size || bsize != br_fsize) {
	br_fsize = bsize;
	font_size = tsize;
	change_font_size();
    }
    port = atoi(fl_get_input(fon->port));
    input = fl_get_input(fon->e_mail);
    strcpy(e_mail, input);
    input = fl_get_input(fofl->bookm_file);
    free(std_bookm_file);
    std_bookm_file = malloc(strlen(input) + strlen(home_dir) + 2);
    sprintf(std_bookm_file, "%s%s", home_dir, input);
    free(addr_file_name);
    addr_file_name = malloc(strlen(std_bookm_file) + 1);
    strcpy(addr_file_name, std_bookm_file);
    read_bookmarks(std_bookm_file);
    show_hidden_local = fl_get_button(fofl->btn_show_hidden_local);
    show_hidden_remote = fl_get_button(fofl->btn_show_hidden_remote);
    passive = fl_get_button(fon->btn_passive);
    if ((f_options = fopen(opt_file_name, "w")) == NULL) {
	fl_set_object_label(fmsg->txt, "Can not save options file !");
	deactivate_form(fo->fd_options);
	fl_show_form(fmsg->fd_message, FL_PLACE_MOUSE, FL_TRANSIENT, "");
	fl_do_forms();
	fl_hide_form(fmsg->fd_message);
	activate_form(fo->fd_options);
	return;
    }
    fprintf(f_options, "%s\n", e_mail);
    fprintf(f_options, "%d\n", font_size);
    fprintf(f_options, "%d\n", br_fsize);
    fprintf(f_options, "%d\n", show_hidden_local);
    fprintf(f_options, "%d\n", show_hidden_remote);
    fprintf(f_options, "%d\n", passive);
    fprintf(f_options, "%s\n", input);
    fl_getmcolor(FL_FREE_COL1, &r, &g, &b);
    fprintf(f_options, "%d,%d,%d\n", r, g, b);
    fl_getmcolor(FL_FREE_COL1 + 1, &r, &g, &b);
    fprintf(f_options, "%d,%d,%d\n", r, g, b);
    fl_getmcolor(FL_FREE_COL1 + 2, &r, &g, &b);
    fprintf(f_options, "%d,%d,%d\n", r, g, b);
    fl_getmcolor(FL_FREE_COL1 + 3, &r, &g, &b);
    fprintf(f_options, "%d,%d,%d\n", r, g, b);
    fl_getmcolor(FL_FREE_COL1 + 4, &r, &g, &b);
    fprintf(f_options, "%d,%d,%d\n", r, g, b);
    fl_getmcolor(FL_FREE_COL1 + 5, &r, &g, &b);
    fprintf(f_options, "%d,%d,%d\n", r, g, b);
    fclose(f_options);
}

void cb_op_cancel(FL_OBJECT * ob, long arg)
{
    fl_hide_form(fo->fd_options);
    fl_redraw_form(fm->fd_main);
    activate_form(fo->fd_options->u_vdata);
}

void cb_chg_col(FL_OBJECT * ob, long arg)
{
    int r, g, b;
    int *rgb = malloc(3 * sizeof(int));
    char label[30];

    fc->txt_col->u_ldata = arg;
    deactivate_form(fo->fd_options);
    fl_set_object_lcol(fc->txt_col, FL_FREE_COL1 + arg);
    fl_set_object_lcol(fc->txt_col_sel, FL_FREE_COL1 + arg);
    switch (arg) {
    case 0:
	strcpy(label, "");
	break;
    case 1:
	strcpy(label, "");
	break;
    case 2:
	strcpy(label, "Directories");
	break;
    case 3:
	strcpy(label, "Links");
	break;
    case 4:
	strcpy(label, "Executable files");
	break;
    case 5:
	strcpy(label, "Other files");
    }
    fl_set_object_label(fc->txt_col, label);
    fl_set_object_label(fc->txt_col_sel, label);
    fl_getmcolor(FL_FREE_COL1 + arg, &r, &g, &b);
    rgb[0] = r;
    rgb[1] = g;
    rgb[2] = b;
    fc->txt_col->u_vdata = rgb;
    fl_set_slider_value(fc->sld_red, r);
    fl_set_slider_value(fc->sld_green, g);
    fl_set_slider_value(fc->sld_blue, b);
    fl_show_form(fc->fd_colors, FL_PLACE_MOUSE, FL_TRANSIENT, "");
}

void cb_col_ok(FL_OBJECT * ob, long arg)
{
    int i, no = fc->txt_col->u_ldata;

    fl_hide_form(fc->fd_colors);
    if (no == 0)
	for (i = 0; i < 6; i++)
	    fl_redraw_object(foc->btn_col[i]);
    else
	fl_redraw_object(foc->btn_col[no]);
    activate_form(fo->fd_options);
}

void cb_col_cancel(FL_OBJECT * ob, long arg)
{
    int *rgb;

    activate_form(fo->fd_options);
    fl_hide_form(fc->fd_colors);
    rgb = fc->txt_col->u_vdata;
    fl_mapcolor(FL_FREE_COL1 + fc->txt_col->u_ldata, rgb[0], rgb[1], rgb[2]);
    free(rgb);
}

void cb_sld_col(FL_OBJECT * ob, long arg)
{
    int r, g, b;
    FL_COLOR col_ind = FL_FREE_COL1 + fc->txt_col->u_ldata;

    r = fl_get_slider_value(fc->sld_red);
    g = fl_get_slider_value(fc->sld_green);
    b = fl_get_slider_value(fc->sld_blue);
    fl_mapcolor(col_ind, r, g, b);
    fl_redraw_object(fc->txt_col);
    fl_redraw_object(fc->txt_col_sel);
}

/* fd_remote_view callback */
void cb_remote_view_ok(FL_OBJECT * ob, long arg)
{
    fl_hide_form(frv->fd_remote_view);
    busy = 0;
    activate_object(fm->local_btns);
    activate_object(fm->remote_btns);
    activate_object(fm->br_remote);
    activate_object(fm->br_remote_size);
    activate_form(fm->fd_main);
}

/* fd_local_view callback */
void cb_local_view_ok(FL_OBJECT * ob, long arg)
{
    fl_hide_form(flv->fd_local_view);
}

/* fd_about callback */
void cb_about_ok(FL_OBJECT * ob, long arg)
{
    activate_form(fm->fd_main);
    fl_hide_form(fa->fd_about);
}

/*************/

char *
 get_cwdir()
{
    int i = 50;
    char *wd;

    i = 50;
    wd = malloc(i);
    while (getcwd(wd, i) == NULL) {
	if (errno == EACCES) {
	    free(wd);
	    wd = NULL;
	    return wd;
	}
	if (errno != ERANGE) {
	    perror("getcwd error");
	    exit(1);
	}
	free(wd);
	wd = malloc(i += 10);
    }
    return wd;
}

char *
 get_home_dir()
{
    struct passwd *pw_ent;
    char *h_dir;

    if ((pw_ent = getpwuid(getuid()))) {
	h_dir = malloc(strlen(pw_ent->pw_dir) + 3);
	strcpy(h_dir, pw_ent->pw_dir);
	strcat(h_dir, "/");
	return h_dir;
    }
    return NULL;
}

void read_bookmarks(const char *bookm_file)
{
    int bf, bytes_read;
    char read_buf[BUF_SIZE + 1], *full_addr, buf[BUF_SIZE + 1], *pc1,
    *pc2;
    struct addr_item *pAd_it;

    fl_clear_browser(fb->br_bookmarks);
    bookm_last = NULL;
    while (bookm_first != NULL) {
	free(bookm_first->address);
	free(bookm_first->dir);
	pAd_it = bookm_first->next;
	free(bookm_first);
	bookm_first = pAd_it;
    }
    if ((bf = open(bookm_file, O_RDONLY)) >= 0) {
	while ((bytes_read = read(bf, read_buf, BUF_SIZE)) != 0) {
	    read_buf[bytes_read] = '\0';
	    pc1 = read_buf;
	    while ((pc1 = strstr(pc1, "<A HREF=")) != NULL) {
		pc1 += 8;
		if (*pc1 == '"')
		    pc1++;
		if (strncmp(pc1, "ftp://", 6))
		    continue;
		pAd_it = malloc(sizeof(struct addr_item));
		pAd_it->next = NULL;
		if (bookm_last != NULL)
		    bookm_last->next = pAd_it;
		bookm_last = pAd_it;
		if (bookm_first == NULL)
		    bookm_first = pAd_it;
		pc1 += 6;
		while (*pc1 == ' ')
		    pc1++;
		pc2 = pc1;
		while (*pc2 != '>' && *pc2 != '/' && *pc2 != ' ' && *pc1 != '\0')
		    pc2++;
		if (*(pc2 - 1) == '"')
		    pc2--;
		pAd_it->address = malloc(pc2 - pc1 + 1);
		strncpy(pAd_it->address, pc1, pc2 - pc1);
		pAd_it->address[pc2 - pc1] = '\0';
		if (*pc2 == '>' || *pc2 == ' ') {
		    pAd_it->dir = malloc(1);
		    *pAd_it->dir = '\0';
		    pc1 = pc2;
		} else {
		    buf[0] = '\0';
		    pc1 = pc2;
		    while (*pc1 != '>' && *pc1 != ' ' && *pc1 != '\0')
			pc1++;
		    if (*pc1 == '\0') {
			strcpy(buf, pc2);
			if ((bytes_read = read(bf, read_buf, BUF_SIZE)) == 0) {
			    close(bf);
			    return;
			}
			read_buf[bytes_read] = '\0';
			pc2 = read_buf;
			if ((pc1 = strchr(pc2, ' ')) == NULL && (pc1 = strchr(pc2, '>')) == NULL)
			    return;
		    }
		    if (*(pc1 - 1) == '"')
			pc1--;
		    *pc1 = '\0';
		    strcat(buf, pc2);
		    pAd_it->dir = malloc(strlen(buf) + 1);
		    strcpy(pAd_it->dir, buf);
		    pc1++;
		}
	    }
	}
	close(bf);
	pAd_it = bookm_first;
	while (pAd_it != NULL) {
	    full_addr = malloc(strlen(pAd_it->address) + strlen(pAd_it->dir) + 2);
	    sprintf(full_addr, "%s%s", pAd_it->address, pAd_it->dir);
	    fl_add_browser_line(fb->br_bookmarks, full_addr);
	    free(full_addr);
	    pAd_it = pAd_it->next;
	}
    }
}

void write_bookmarks()
{
    struct addr_item *pAd_it;
    int i = 0;
    FILE *fbm;

    pAd_it = bookm_first;
    if ((fbm = fopen(std_bookm_file, "w")) != NULL) {
	fprintf(fbm, "<HTML>\n");
	fprintf(fbm, "<HEAD>\n");
	fprintf(fbm, "<TITLE>Xrmtfp bookmarks</TITLE>\n");
	fprintf(fbm, "</HEAD>\n");
	fprintf(fbm, "<BODY>\n");
	while (pAd_it != NULL) {
	    fprintf(fbm, "%d <A HREF=\"ftp://%s%s\">%s%s</A><BR>\n", ++i, pAd_it->address, pAd_it->dir, pAd_it->address, pAd_it->dir);
	    pAd_it = pAd_it->next;
	}
	fprintf(fbm, "</BODY>\n");
	fprintf(fbm, "</HTML>\n");
    }
    fclose(fbm);
}

char *
 read_hist_field(FILE * fh)
{
    char rl[MAXLINE], *fld;

    fgets(rl, MAXLINE, fh);
    rl[strlen(rl) - 1] = '\0';
    fld = malloc(strlen(rl) + 1);
    strcpy(fld, rl);
    return fld;
}

void read_hist()
{
    FILE *f_history;
    int i;
    struct hist_item *pHist_it;
    char rl[10];

    hist_last = NULL;
    while (hist_first != NULL) {
	free(hist_first->address);
	free(hist_first->user_name);
	free(hist_first->pass_unenc);
	free(hist_first->local_dir);
	free(hist_first->remote_dir);
	pHist_it = hist_first->next;
	free(hist_first);
	hist_first = pHist_it;
    }
    if ((f_history = fopen(hist_file_name, "r+")) != NULL) {
	fgets(rl, MAXLINE, f_history);
	n_hist = atoi(rl);
	if (n_hist > HIST_SIZE)
	    n_hist = HIST_SIZE;
	for (i = 0; i < n_hist; i++) {
	    pHist_it = malloc(sizeof(struct hist_item));
	    pHist_it->address = read_hist_field(f_history);
	    pHist_it->user_name = read_hist_field(f_history);
	    pHist_it->pass_unenc = read_hist_field(f_history);
	    pHist_it->local_dir = read_hist_field(f_history);
	    pHist_it->remote_dir = read_hist_field(f_history);
	    fgets(rl, MAXLINE, f_history);
	    pHist_it->anonym_login = atoi(rl);
	    pHist_it->next = NULL;
	    if (hist_last != NULL)
		hist_last->next = pHist_it;
	    hist_last = pHist_it;
	    if (hist_first == NULL)
		hist_first = pHist_it;
	}
	fl_clear_browser(fcp->br_history);
	pHist_it = hist_first;
	while (pHist_it != NULL) {
	    fl_add_browser_line(fcp->br_history, pHist_it->address);
	    fl_addto_browser_chars(fcp->br_history, " ");
	    fl_addto_browser_chars(fcp->br_history, pHist_it->remote_dir);
	    pHist_it = pHist_it->next;
	}
	fclose(f_history);
	return;
    }
}

int read_op(FILE * f_options, int *pOp)
{
    char op_line[MAXLINE];

    if (fgets(op_line, MAXLINE - 1, f_options) == NULL)
	return -1;
    op_line[strlen(op_line) - 1] = '\0';
    *pOp = atoi(op_line);
    return 1;
}

void read_init_files()
{
    FILE *f_options;
    char op_line[MAXLINE];
    int r, g, b;

    if ((f_options = fopen(opt_file_name, "r")) != NULL) {
	fgets(e_mail, 80, f_options);
	e_mail[strlen(e_mail) - 1] = '\0';
	if (read_op(f_options, &font_size) < 0)
	    font_size = 10;
	else if (font_size < 10 || font_size > 14)
	    font_size = 10;
	if (read_op(f_options, &br_fsize) < 0)
	    br_fsize = 10;
	else if (br_fsize < 10 || br_fsize > 14)
	    br_fsize = 10;
	if (read_op(f_options, &show_hidden_local) < 0)
	    show_hidden_local = 1;
	if (read_op(f_options, &show_hidden_remote) < 0)
	    show_hidden_remote = 1;
	if (read_op(f_options, &passive) < 0)
	    passive = 1;
	if (fgets(op_line, 80, f_options) != NULL) {
	    op_line[strlen(op_line) - 1] = '\0';
	    free(std_bookm_file);
	    std_bookm_file = malloc(strlen(home_dir) + strlen(op_line) + 2);
	    sprintf(std_bookm_file, "%s%s", home_dir, op_line);
	    addr_file_name = malloc(strlen(std_bookm_file) + 1);
	    strcpy(addr_file_name, std_bookm_file);
	    if (fscanf(f_options, "%d,%d,%d\n", &r, &g, &b) == 3)
		fl_mapcolor(FL_FREE_COL1, r, g, b);
	    if (fscanf(f_options, "%d,%d,%d\n", &r, &g, &b) == 3)
		fl_mapcolor(FL_FREE_COL1 + 1, r, g, b);
	    if (fscanf(f_options, "%d,%d,%d\n", &r, &g, &b) == 3)
		fl_mapcolor(FL_FREE_COL1 + 2, r, g, b);
	    if (fscanf(f_options, "%d,%d,%d\n", &r, &g, &b) == 3)
		fl_mapcolor(FL_FREE_COL1 + 3, r, g, b);
	    if (fscanf(f_options, "%d,%d,%d\n", &r, &g, &b) == 3)
		fl_mapcolor(FL_FREE_COL1 + 4, r, g, b);
	    if (fscanf(f_options, "%d,%d,%d\n", &r, &g, &b) == 3)
		fl_mapcolor(FL_FREE_COL1 + 5, r, g, b);
	}
	fclose(f_options);
    }
    read_hist();
    if (hist_first != NULL) {
	fl_set_input(fcp->address, hist_first->address);
	fl_set_input(fcp->user_name, hist_first->user_name);
	fl_set_input(fcp->pass_unenc, hist_first->pass_unenc);
	fl_set_input(fcp->local_dir, hist_first->local_dir);
	fl_set_input(fcp->remote_dir, hist_first->remote_dir);
    }
    read_bookmarks(addr_file_name);
    flog = fopen(log_file_name, "w");
}

int main(int argc, char *argv[])
{
    FL_OBJECT *vscroll_local, *vscroll_remote, *ob;
    FL_IOPT options;
    int x, y, r, g, b, i;

    home_dir = get_home_dir();
    addr_file_name = malloc(strlen(home_dir) + 30);
    std_bookm_file = malloc(strlen(home_dir) + 30);
    opt_file_name = malloc(strlen(home_dir) + 30);
    hist_file_name = malloc(strlen(home_dir) + 30);
    log_file_name = malloc(strlen(home_dir) + 30);
    strcpy(addr_file_name, home_dir);
    strcpy(opt_file_name, home_dir);
    strcpy(hist_file_name, home_dir);
    strcpy(log_file_name, home_dir);
    strcat(addr_file_name, "ftp_bookmarks.html");
    strcat(opt_file_name, ".Xrmftp_options");
    strcat(hist_file_name, ".Xrmftp_history");
    strcat(log_file_name, ".Xrmftp_log");
    strcpy(std_bookm_file, addr_file_name);
    *(address = malloc(1)) = '\0';
    *(user_name = malloc(1)) = '\0';
    *(pass_enc = malloc(1)) = '\0';
    *(pass_unenc = malloc(1)) = '\0';
    *(local_dir_path_inp = malloc(1)) = '\0';
    *(remote_dir_path_inp = malloc(1)) = '\0';
    *(remote_dir_path = malloc(1)) = '\0';
    options.borderWidth = -1;
    fl_set_defaults(FL_PDBorderWidth, &options);
    fl_initialize(&argc, argv, "", 0, 0);
    create_forms();
    sprintf(dir_col, "@C%d", FL_FREE_COL1 + 2);
    sprintf(lnk_col, "@C%d", FL_FREE_COL1 + 3);
    sprintf(exe_col, "@C%d", FL_FREE_COL1 + 4);
    sprintf(other_col, "@C%d", FL_FREE_COL1 + 5);
    fl_getmcolor(FL_COL1, &r, &g, &b);
    fl_mapcolor(FL_FREE_COL1, r, g, b);
    fl_getmcolor(FL_YELLOW, &r, &g, &b);
    fl_mapcolor(FL_FREE_COL1 + 1, r, g, b);
    fl_getmcolor(FL_BLUE, &r, &g, &b);
    fl_mapcolor(FL_FREE_COL1 + 2, r, g, b);
    fl_getmcolor(FL_GREEN, &r, &g, &b);
    fl_mapcolor(FL_FREE_COL1 + 3, r, g, b);
    fl_getmcolor(FL_RED, &r, &g, &b);
    fl_mapcolor(FL_FREE_COL1 + 4, r, g, b);
    fl_getmcolor(FL_BLACK, &r, &g, &b);
    fl_mapcolor(FL_FREE_COL1 + 5, r, g, b);
    fl_set_object_color(fc->txt_col, FL_FREE_COL1, FL_INACTIVE_COL);
    fl_set_object_color(fc->txt_col_sel, FL_FREE_COL1 + 1, FL_INACTIVE_COL);
    read_init_files();
    ob = fm->fd_main->first;
    while (1) {
	if (ob->objclass == FL_BROWSER)
	    fl_set_object_color(ob, FL_FREE_COL1, FL_FREE_COL1 + 1);
	if (ob == fm->fd_main->last)
	    break;
	ob = ob->next;
    }
    for (i = 2; i < 6; i++) {
	fl_set_object_color(foc->btn_col[i], FL_FREE_COL1, FL_FREE_COL1);
	fl_set_object_lcol(foc->btn_col[i], FL_FREE_COL1 + i);
    }
    fl_set_object_lcol(fm->br_log, FL_FREE_COL1 + 5);
    signal(SIGPIPE, SIG_IGN);
    fl_set_button(fofl->btn_show_hidden_local, show_hidden_local);
    fl_set_button(fofl->btn_show_hidden_remote, show_hidden_remote);
    fl_set_button(fon->btn_passive, passive);
    change_font_size();
    fl_deactivate_object(fd->sl_time);
    fl_deactivate_object(frv->sl_time);
    fl_hide_object(fcp->pass_unenc);
    fl_hide_object(fcp->br_history);
    fl_set_input_maxchars(fon->e_mail, 80);
    fl_addto_tabfolder(fo->fld_options, "Network", fon->fd_options_net);
    fl_addto_tabfolder(fo->fld_options, "Fonts", fof->fd_options_fonts);
    fl_addto_tabfolder(fo->fld_options, "Colors", foc->fd_options_colors);
    fl_addto_tabfolder(fo->fld_options, "Files", fofl->fd_options_files);

    fl_set_object_prehandler(fm->br_local_size, prehndl_local_size);
    fl_set_object_prehandler(fm->br_local, prehndl_local);
    fl_set_object_prehandler(fm->br_remote_size, prehndl_remote_size);
    fl_set_object_prehandler(fm->br_remote, prehndl_remote);
    vscroll_local = fl_get_object_component(fm->br_local_size, FL_SCROLLBAR, FL_VERT_THIN_SCROLLBAR, 0);
    vscroll_remote = fl_get_object_component(fm->br_remote_size, FL_SCROLLBAR, FL_VERT_THIN_SCROLLBAR, 0);
    cb_old_local = fl_set_object_callback(vscroll_local, cb_vscroll_local, 0);
    cb_old_remote = fl_set_object_callback(vscroll_remote, cb_vscroll_remote, 0);
    fl_set_browser_vscrollbar(fm->br_local, FL_OFF);
    fl_set_browser_hscrollbar(fm->br_local, FL_ON);
    fl_set_browser_hscrollbar(fm->br_local_size, FL_ON);
    fl_set_browser_scrollbarsize(fm->br_local, 15, 15);
    fl_set_browser_scrollbarsize(fm->br_local_size, 15, 15);
    fl_set_browser_dblclick_callback(fm->br_local, cb2_br_local, 0);
    fl_set_browser_dblclick_callback(fm->br_local_size, cb2_br_local, 0);
    fl_set_browser_dblclick_callback(fb->br_bookmarks, cb2_br_bookmarks, 0);

    fl_set_browser_vscrollbar(fm->br_remote, FL_OFF);
    fl_set_browser_hscrollbar(fm->br_remote, FL_ON);
    fl_set_browser_hscrollbar(fm->br_remote_size, FL_ON);
    fl_set_browser_scrollbarsize(fm->br_remote, 15, 15);
    fl_set_browser_scrollbarsize(fm->br_remote_size, 15, 15);
    fl_set_browser_dblclick_callback(fm->br_remote, cb2_br_remote, 0);
    fl_set_browser_dblclick_callback(fm->br_remote_size, cb2_br_remote, 0);

    fl_set_browser_hscrollbar(fm->br_buffer_name, FL_ON);
    fl_set_browser_scrollbarsize(fm->br_buffer_name, 15, 15);

    fl_set_browser_scrollbarsize(fm->br_log, 15, 15);
    fl_set_browser_scrollbarsize(fcp->br_history, 15, 15);
    fl_set_browser_scrollbarsize(fb->br_bookmarks, 15, 15);

    fl_set_choice(fof->font_txt, (font_size - 8) / 2);
    fl_set_choice(fof->font_br, (br_fsize - 8) / 2);
    deactivate_object(fm->remote_btns);
    deactivate_object(fm->br_remote);
    deactivate_object(fm->br_remote_size);
    fl_set_form_minsize(fm->fd_main, minx, miny);
    fl_show_form (fm->fd_main, FL_PLACE_FREE, FL_FULLBORDER, "Xrmftp");
    deactivate_form(fm->fd_main);
    x = fm->fd_main->x + (fm->fd_main->w - fcp->fd_conn_par->w) / 2;
    y = fm->fd_main->y + (fm->fd_main->h - fcp->fd_conn_par->h) / 2;
    fl_set_form_position(fcp->fd_conn_par, x, y);
    fl_show_form(fcp->fd_conn_par, FL_PLACE_GEOMETRY, FL_TRANSIENT, "");
    XFlush(fl_get_display());
    read_local_dir();
    while (1)
	fl_check_forms();
    return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1