⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftp.c

📁 ELinks is an advanced and well-established feature-rich text mode web (HTTP/FTP/..) browser. ELinks
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ftp.c * ftp:// processing * (c) 2002 Mikulas Patocka * This file is a part of the Links program, released under GPL. */#include "links.h"#define FTP_BUF	16384struct ftp_connection_info {	int pending_commands;	int opc;	int pasv;	int dir;	int rest_sent;	int conn_st;	int d;	int dpos;	int buf_pos;	unsigned char ftp_buffer[FTP_BUF];	unsigned char cmdbuf[1];};void ftp_get_banner(struct connection *);void ftp_got_banner(struct connection *, struct read_buffer *);void ftp_login(struct connection *);void ftp_logged(struct connection *);void ftp_sent_passwd(struct connection *);void ftp_got_reply(struct connection *, struct read_buffer *);void ftp_got_info(struct connection *, struct read_buffer *);void ftp_got_user_info(struct connection *, struct read_buffer *);void ftp_dummy_info(struct connection *, struct read_buffer *);void ftp_pass_info(struct connection *, struct read_buffer *);void ftp_send_retr_req(struct connection *, int);struct ftp_connection_info *add_file_cmd_to_str(struct connection *);void ftp_retr_1(struct connection *);void ftp_retr_file(struct connection *, struct read_buffer *);void ftp_got_final_response(struct connection *, struct read_buffer *);void created_data_connection(struct connection *);void got_something_from_data_connection(struct connection *);void ftp_end_request(struct connection *);int get_ftp_response(struct connection *, struct read_buffer *, int);int ftp_process_dirlist(struct cache_entry *, off_t *, int *, unsigned char *, int, int, int *);int get_ftp_response(struct connection *c, struct read_buffer *rb, int part){	int l;	set_timeout(c);	again:	for (l = 0; l < rb->len; l++) if (rb->data[l] == 10) {		unsigned char *e;		long k = strtoul(rb->data, (char **)(void *)&e, 10);		if (e != rb->data + 3 || k < 100 || k >= 1000) return -1;		if (*e == '-') {			int i;			for (i = 0; i < rb->len - 5; i++) {				if (rb->data[i] == 10 && !memcmp(rb->data+i+1, rb->data, 3) && rb->data[i+4] == ' ') {					for (i++; i < rb->len; i++) if (rb->data[i] == 10) goto ok;					return 0;				}			}			return 0;			ok:			l = i;		}		if (!part && k >= 100 && k < 200) {			kill_buffer_data(rb, l + 1);			goto again;		}		if (part == 2) return k;		kill_buffer_data(rb, l + 1);		return k;	}	return 0;}void ftp_func(struct connection *c){	/*setcstate(c, S_CONN);*/	/*set_timeout(c);*/	if (get_keepalive_socket(c)) {		int p;		if ((p = get_port(c->url)) == -1) {			setcstate(c, S_INTERNAL);			abort_connection(c);			return;		}		make_connection(c, p, &c->sock1, ftp_options.fast_ftp ? ftp_login : ftp_get_banner);	} else ftp_send_retr_req(c, S_SENT);}void ftp_get_banner(struct connection *c){	struct read_buffer *rb;	set_timeout(c);	setcstate(c, S_SENT);	if (!(rb = alloc_read_buffer(c))) return;	read_from_socket(c, c->sock1, rb, ftp_got_banner);}void ftp_got_banner(struct connection *c, struct read_buffer *rb){	int g = get_ftp_response(c, rb, 0);	if (g == -1) { setcstate(c, S_FTP_ERROR); abort_connection(c); return; }	if (!g) { read_from_socket(c, c->sock1, rb, ftp_got_banner); return; }	if (g >= 400) { setcstate(c, S_FTP_UNAVAIL); retry_connection(c); return; }	ftp_login(c);}void ftp_login(struct connection *c){	unsigned char *login;	unsigned char *u;	int logl = 0;	set_timeout(c);	login = init_str();	add_to_str(&login, &logl, "USER ");	if ((u = get_user_name(c->url)) && *u) add_to_str(&login, &logl, u);	else add_to_str(&login, &logl, "anonymous");	if (u) mem_free(u);	if (ftp_options.fast_ftp) {		struct ftp_connection_info *fi;		add_to_str(&login, &logl, "\r\nPASS ");		if ((u = get_pass(c->url)) && *u) add_to_str(&login, &logl, u);		else add_to_str(&login, &logl, ftp_options.anon_pass);		if (u) mem_free(u);		add_to_str(&login, &logl, "\r\n");		if (!(fi = add_file_cmd_to_str(c))) {			mem_free(login);			return;		}		add_to_str(&login, &logl, fi->cmdbuf);	} else add_to_str(&login, &logl, "\r\n");	write_to_socket(c, c->sock1, login, strlen(login), ftp_logged);	mem_free(login);	setcstate(c, S_SENT);}void ftp_logged(struct connection *c){	struct read_buffer *rb;	if (!(rb = alloc_read_buffer(c))) return;	if (!ftp_options.fast_ftp) {		ftp_got_user_info(c, rb);		return;	}	read_from_socket(c, c->sock1, rb, ftp_got_info);}void ftp_got_info(struct connection *c, struct read_buffer *rb){	int g = get_ftp_response(c, rb, 0);	if (g == -1) { setcstate(c, S_FTP_ERROR); abort_connection(c); return; }	if (!g) { read_from_socket(c, c->sock1, rb, ftp_got_info); return; }	if (g >= 400) { setcstate(c, S_FTP_UNAVAIL); retry_connection(c); return; }	ftp_got_user_info(c, rb);}void ftp_got_user_info(struct connection *c, struct read_buffer *rb){	int g = get_ftp_response(c, rb, 0);	if (g == -1) { setcstate(c, S_FTP_ERROR); abort_connection(c); return; }	if (!g) { read_from_socket(c, c->sock1, rb, ftp_got_user_info); return; }	if (g >= 530 && g < 540) { setcstate(c, S_FTP_LOGIN); retry_connection(c); return; }	if (g >= 400) { setcstate(c, S_FTP_UNAVAIL); retry_connection(c); return; }	if (g >= 200 && g < 300) {		if (ftp_options.fast_ftp) ftp_dummy_info(c, rb);		else ftp_send_retr_req(c, S_GETH);	} else {		if (ftp_options.fast_ftp) ftp_pass_info(c, rb);		else {			unsigned char *login;			unsigned char *u;			int logl = 0;			login = init_str();			add_to_str(&login, &logl, "PASS ");			if ((u = get_pass(c->url)) && *u) add_to_str(&login, &logl, u);			else add_to_str(&login, &logl, ftp_options.anon_pass);			if (u) mem_free(u);			add_to_str(&login, &logl, "\r\n");			write_to_socket(c, c->sock1, login, strlen(login), ftp_sent_passwd);			mem_free(login);			setcstate(c, S_LOGIN);		}	}}void ftp_dummy_info(struct connection *c, struct read_buffer *rb){	int g = get_ftp_response(c, rb, 0);	if (g == -1) { setcstate(c, S_FTP_ERROR); abort_connection(c); return; }	if (!g) { read_from_socket(c, c->sock1, rb, ftp_dummy_info); return; }	ftp_retr_file(c, rb);}void ftp_sent_passwd(struct connection *c){	struct read_buffer *rb;	if (!(rb = alloc_read_buffer(c))) return;	read_from_socket(c, c->sock1, rb, ftp_pass_info);}void ftp_pass_info(struct connection *c, struct read_buffer *rb){	int g = get_ftp_response(c, rb, 0);	if (g == -1) { setcstate(c, S_FTP_ERROR); abort_connection(c); return; }	if (!g) { read_from_socket(c, c->sock1, rb, ftp_pass_info); setcstate(c, S_LOGIN); return; }	if (g >= 530 && g < 540) { setcstate(c, S_FTP_LOGIN); abort_connection(c); return; }	if (g >= 400) { setcstate(c, S_FTP_UNAVAIL); abort_connection(c); return; }	if (ftp_options.fast_ftp) ftp_retr_file(c, rb);	else ftp_send_retr_req(c, S_GETH);}struct ftp_connection_info *add_file_cmd_to_str(struct connection *c){	unsigned char *d = get_url_data(c->url);	unsigned char *de;	int del;	unsigned char pc[6];	int ps;	struct ftp_connection_info *inf, *inf2;	unsigned char *s;	int l;	if (!d) {		internal("get_url_data failed");		setcstate(c, S_INTERNAL);		abort_connection(c);		return NULL;	}	de = init_str(), del = 0;	add_conv_str(&de, &del, d, strlen(d), -2);	d = de;	inf = mem_alloc(sizeof(struct ftp_connection_info));	memset(inf, 0, sizeof(struct ftp_connection_info));	l = 0;	s = init_str();	inf->pasv = ftp_options.passive_ftp;	if (*c->socks_proxy) inf->pasv = 1;	c->info = inf;	if (!inf->pasv) if ((ps = get_pasv_socket(c, c->sock1, &c->sock2, pc))) {		mem_free(d);		return NULL;	}#ifdef HAVE_IPTOS	if (ftp_options.set_tos) {		int on = IPTOS_THROUGHPUT;		setsockopt(c->sock2, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int));	}#endif	if (!(de = strchr(d, POST_CHAR))) de = d + strlen(d);	if (d == de || de[-1] == '/') {		inf->dir = 1;		inf->pending_commands = 4;		add_to_str(&s, &l, "TYPE A\r\n");		if (!inf->pasv) {			add_to_str(&s, &l, "PORT ");			add_num_to_str(&s, &l, pc[0]);			add_chr_to_str(&s, &l, ',');			add_num_to_str(&s, &l, pc[1]);			add_chr_to_str(&s, &l, ',');			add_num_to_str(&s, &l, pc[2]);			add_chr_to_str(&s, &l, ',');			add_num_to_str(&s, &l, pc[3]);			add_chr_to_str(&s, &l, ',');			add_num_to_str(&s, &l, pc[4]);			add_chr_to_str(&s, &l, ',');			add_num_to_str(&s, &l, pc[5]);			add_to_str(&s, &l, "\r\n");		} else {			add_to_str(&s, &l, "PASV\r\n");		}		add_to_str(&s, &l, "CWD /");		add_bytes_to_str(&s, &l, d, de - d);		add_to_str(&s, &l, "\r\nLIST\r\n");		c->from = 0;	} else {		inf->dir = 0;		inf->pending_commands = 3;		add_to_str(&s, &l, "TYPE I\r\n");		if (!inf->pasv) {			add_to_str(&s, &l, "PORT ");			add_num_to_str(&s, &l, pc[0]);			add_chr_to_str(&s, &l, ',');			add_num_to_str(&s, &l, pc[1]);			add_chr_to_str(&s, &l, ',');			add_num_to_str(&s, &l, pc[2]);			add_chr_to_str(&s, &l, ',');			add_num_to_str(&s, &l, pc[3]);			add_chr_to_str(&s, &l, ',');			add_num_to_str(&s, &l, pc[4]);			add_chr_to_str(&s, &l, ',');			add_num_to_str(&s, &l, pc[5]);			add_to_str(&s, &l, "\r\n");		} else {			add_to_str(&s, &l, "PASV\r\n");		}		if (c->from && c->no_cache < NC_IF_MOD) {			add_to_str(&s, &l, "REST ");			add_num_to_str(&s, &l, c->from);			add_to_str(&s, &l, "\r\n");			inf->rest_sent = 1;			inf->pending_commands++;		} else c->from = 0;		add_to_str(&s, &l, "RETR /");		add_bytes_to_str(&s, &l, d, de - d);		add_to_str(&s, &l, "\r\n");	}	inf->opc = inf->pending_commands;	if ((unsigned)l > MAXINT - sizeof(struct ftp_connection_info) - 1) overalloc();	inf2 = mem_realloc(inf, sizeof(struct ftp_connection_info) + l + 1);	strcpy((inf = inf2)->cmdbuf, s);	mem_free(s);	c->info = inf;	mem_free(d);	return inf;}void ftp_send_retr_req(struct connection *c, int state){	struct ftp_connection_info *fi;	unsigned char *login;	int logl = 0;	set_timeout(c);	login = init_str();	if (!c->info && !(fi = add_file_cmd_to_str(c))) {		mem_free(login);		return;	} else fi = c->info;	if (ftp_options.fast_ftp) a:add_to_str(&login, &logl, fi->cmdbuf);	else {		unsigned char *nl = strchr(fi->cmdbuf, '\n');		if (!nl) goto a;		nl++;		add_bytes_to_str(&login, &logl, fi->cmdbuf, nl - fi->cmdbuf);		memmove(fi->cmdbuf, nl, strlen(nl) + 1);	}	write_to_socket(c, c->sock1, login, strlen(login), ftp_retr_1);	mem_free(login);	setcstate(c, state);}void ftp_retr_1(struct connection *c){	struct read_buffer *rb;	if (!(rb = alloc_read_buffer(c))) return;	read_from_socket(c, c->sock1, rb, ftp_retr_file);}void ftp_retr_file(struct connection *c, struct read_buffer *rb){	int g;	struct ftp_connection_info *inf = c->info;	if (0) {		rep:		if (!ftp_options.fast_ftp) {			ftp_send_retr_req(c, S_GETH);			return;		}	}	if (inf->pending_commands > 1) {		unsigned char pc[6];		if (inf->pasv && inf->opc - (inf->pending_commands - 1) == 2) {			int i = 3, j;			while (i < rb->len) {				if (rb->data[i] >= '0' && rb->data[i] <= '9') {					for (j = 0; j < 6; j++) {						int n = 0;						while (rb->data[i] >= '0' && rb->data[i] <= '9') {							n = n * 10 + rb->data[i] - '0';							if (n >= 256) goto no_pasv;							if (++i >= rb->len) goto no_pasv;						}						pc[j] = n;						if (j != 5) {							if (rb->data[i] != ',') goto xa;							if (++i >= rb->len) goto xa;							if (rb->data[i] < '0' || rb->data[i] > '9') {								xa:								if (j != 1) goto no_pasv;								pc[4] = pc[0];								pc[5] = pc[1];								{									unsigned a;									struct sockaddr_in sa;									socklen_t nl = sizeof(sa);									if (getpeername(c->sock1, (struct sockaddr *)(void *)&sa, &nl)) goto no_pasv;									if (nl != sizeof(sa)) goto no_pasv;									a = ntohl(sa.sin_addr.s_addr);									pc[0] = a >> 24;									pc[1] = a >> 16;									pc[2] = a >> 8;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -