mirror of
https://github.com/rkd77/elinks.git
synced 2025-02-02 15:09:23 -05:00
- FSP protocol
This commit is contained in:
parent
183f0e3ba4
commit
9341c9085e
@ -107,6 +107,7 @@ CONFIG_EXMODE = @CONFIG_EXMODE@
|
|||||||
CONFIG_FASTMEM = @CONFIG_FASTMEM@
|
CONFIG_FASTMEM = @CONFIG_FASTMEM@
|
||||||
CONFIG_FINGER = @CONFIG_FINGER@
|
CONFIG_FINGER = @CONFIG_FINGER@
|
||||||
CONFIG_FORMHIST = @CONFIG_FORMHIST@
|
CONFIG_FORMHIST = @CONFIG_FORMHIST@
|
||||||
|
CONFIG_FSP = @CONFIG_FSP@
|
||||||
CONFIG_FTP = @CONFIG_FTP@
|
CONFIG_FTP = @CONFIG_FTP@
|
||||||
CONFIG_GLOBHIST = @CONFIG_GLOBHIST@
|
CONFIG_GLOBHIST = @CONFIG_GLOBHIST@
|
||||||
CONFIG_GNUTLS = @CONFIG_GNUTLS@
|
CONFIG_GNUTLS = @CONFIG_GNUTLS@
|
||||||
|
18
configure.in
18
configure.in
@ -1077,6 +1077,24 @@ EL_ARG_DEPEND(CONFIG_CGI, cgi, [HAVE_SETENV_OR_PUTENV:yes], [Local CGI],
|
|||||||
EL_ARG_ENABLE(CONFIG_FINGER, finger, [Finger protocol],
|
EL_ARG_ENABLE(CONFIG_FINGER, finger, [Finger protocol],
|
||||||
[ --enable-finger enable finger protocol support])
|
[ --enable-finger enable finger protocol support])
|
||||||
|
|
||||||
|
dnl ===================================================================
|
||||||
|
dnl FSP protocol
|
||||||
|
dnl ===================================================================
|
||||||
|
|
||||||
|
EL_ARG_ENABLE(CONFIG_FSP, fsp, [FSP protocol],
|
||||||
|
[ --enable-fsp enable FSP protocol support])
|
||||||
|
|
||||||
|
if test "x${enable_fsp}" != xno; then
|
||||||
|
AC_CHECK_HEADERS(fsplib.h, CONFIG_FSP=yes, CONFIG_FSP=no)
|
||||||
|
|
||||||
|
if test "$CONFIG_FSP" = yes; then
|
||||||
|
AC_CHECK_LIB(fsplib, fsp_open_session, CONFIG_FSP=yes, CONFIG_FSP=no)
|
||||||
|
if test "$CONFIG_FSP" = yes; then
|
||||||
|
LIBS="$LIBS -lfsplib"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
EL_ARG_ENABLE(CONFIG_FTP, ftp, [FTP protocol],
|
EL_ARG_ENABLE(CONFIG_FTP, ftp, [FTP protocol],
|
||||||
[ --disable-ftp disable ftp protocol support])
|
[ --disable-ftp disable ftp protocol support])
|
||||||
|
|
||||||
|
@ -297,6 +297,13 @@ CONFIG_DATA=yes
|
|||||||
|
|
||||||
CONFIG_FINGER=no
|
CONFIG_FINGER=no
|
||||||
|
|
||||||
|
### FSP protocol
|
||||||
|
#
|
||||||
|
# See: http://fsp.sourceforge.net/
|
||||||
|
#
|
||||||
|
# Default: disabled
|
||||||
|
|
||||||
|
CONFIG_FSP=no
|
||||||
|
|
||||||
### File Transfer Protocol Support
|
### File Transfer Protocol Support
|
||||||
#
|
#
|
||||||
|
@ -3,6 +3,7 @@ include $(top_builddir)/Makefile.config
|
|||||||
|
|
||||||
SUBDIRS-$(CONFIG_BITTORRENT) += bittorrent
|
SUBDIRS-$(CONFIG_BITTORRENT) += bittorrent
|
||||||
SUBDIRS-$(CONFIG_FINGER) += finger
|
SUBDIRS-$(CONFIG_FINGER) += finger
|
||||||
|
SUBDIRS-$(CONFIG_FSP) += fsp
|
||||||
SUBDIRS-$(CONFIG_FTP) += ftp
|
SUBDIRS-$(CONFIG_FTP) += ftp
|
||||||
SUBDIRS-$(CONFIG_GOPHER) += gopher
|
SUBDIRS-$(CONFIG_GOPHER) += gopher
|
||||||
SUBDIRS-$(CONFIG_NNTP) += nntp
|
SUBDIRS-$(CONFIG_NNTP) += nntp
|
||||||
|
6
src/protocol/fsp/Makefile
Normal file
6
src/protocol/fsp/Makefile
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
top_builddir=../../..
|
||||||
|
include $(top_builddir)/Makefile.config
|
||||||
|
|
||||||
|
OBJS = fsp.o
|
||||||
|
|
||||||
|
include $(top_srcdir)/Makefile.lib
|
341
src/protocol/fsp/fsp.c
Normal file
341
src/protocol/fsp/fsp.c
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
/* Internal FSP protocol implementation */
|
||||||
|
|
||||||
|
#ifndef _GNU_SOURCE
|
||||||
|
#define _GNU_SOURCE /* Needed for asprintf() */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fsplib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef HAVE_SYS_TIME_H
|
||||||
|
#include <sys/time.h> /* FreeBSD needs this before resource.h */
|
||||||
|
#endif
|
||||||
|
#include <sys/types.h> /* FreeBSD needs this before resource.h */
|
||||||
|
#ifdef HAVE_SYS_RESOURCE_H
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_FCNTL_H
|
||||||
|
#include <fcntl.h> /* OS/2 needs this after sys/types.h */
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "elinks.h"
|
||||||
|
|
||||||
|
#include "cache/cache.h"
|
||||||
|
#include "config/options.h"
|
||||||
|
#include "intl/gettext/libintl.h"
|
||||||
|
#include "main/module.h"
|
||||||
|
#include "main/select.h"
|
||||||
|
#include "network/connection.h"
|
||||||
|
#include "network/socket.h"
|
||||||
|
#include "osdep/osdep.h"
|
||||||
|
#include "protocol/protocol.h"
|
||||||
|
#include "protocol/fsp/fsp.h"
|
||||||
|
#include "protocol/uri.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
#include "util/snprintf.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct option_info fsp_options[] = {
|
||||||
|
INIT_OPT_TREE("protocol", N_("FSP"),
|
||||||
|
"fsp", 0,
|
||||||
|
N_("FSP specific options.")),
|
||||||
|
|
||||||
|
INIT_OPT_BOOL("protocol.fsp", N_("Sort entries"),
|
||||||
|
"sort", 0, 1,
|
||||||
|
N_("Whether sort entries in directory listings.")),
|
||||||
|
|
||||||
|
NULL_OPTION_INFO,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct module fsp_protocol_module = struct_module(
|
||||||
|
/* name: */ N_("FSP"),
|
||||||
|
/* options: */ fsp_options,
|
||||||
|
/* hooks: */ NULL,
|
||||||
|
/* submodules: */ NULL,
|
||||||
|
/* data: */ NULL,
|
||||||
|
/* init: */ NULL,
|
||||||
|
/* done: */ NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
struct fsp_info {
|
||||||
|
int init;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsp_error(unsigned char *error)
|
||||||
|
{
|
||||||
|
puts(error);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare(FSP_RDENTRY *a, FSP_RDENTRY *b)
|
||||||
|
{
|
||||||
|
int res = ((b->type == FSP_RDTYPE_DIR) - (a->type == FSP_RDTYPE_DIR));
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
return strcmp(a->name, b->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
sort_and_display_entries(FSP_DIR *dir)
|
||||||
|
{
|
||||||
|
FSP_RDENTRY fentry, *fresult, *table = NULL;
|
||||||
|
int size = 0;
|
||||||
|
int i;
|
||||||
|
unsigned char dircolor[8];
|
||||||
|
|
||||||
|
if (get_opt_bool("document.browse.links.color_dirs")) {
|
||||||
|
color_to_string(get_opt_color("document.colors.dirs"),
|
||||||
|
(unsigned char *) &dircolor);
|
||||||
|
} else {
|
||||||
|
dircolor[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!fsp_readdir_native(dir, &fentry, &fresult)) {
|
||||||
|
FSP_RDENTRY *new_table;
|
||||||
|
|
||||||
|
if (!fresult) break;
|
||||||
|
if (!strcmp(fentry.name, "."))
|
||||||
|
continue;
|
||||||
|
new_table = mem_realloc(table, (size + 1) * sizeof(*table));
|
||||||
|
if (!new_table)
|
||||||
|
continue;
|
||||||
|
table = new_table;
|
||||||
|
memcpy(&table[size], &fentry, sizeof(fentry));
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
qsort(table, size, sizeof(fentry),
|
||||||
|
(int (*)(const void *, const void *)) compare);
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
printf("%10d\t<a href=\"%s\">", table[i].size, table[i].name);
|
||||||
|
if (fentry.type == FSP_RDTYPE_DIR && *dircolor) {
|
||||||
|
printf("<font color=\"%s\"><b>", dircolor);
|
||||||
|
}
|
||||||
|
printf("%s", table[i].name);
|
||||||
|
if (fentry.type == FSP_RDTYPE_DIR && *dircolor) {
|
||||||
|
printf("</b></font>");
|
||||||
|
}
|
||||||
|
puts("</a>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsp_directory(FSP_SESSION *ses, struct uri *uri)
|
||||||
|
{
|
||||||
|
struct string buf;
|
||||||
|
FSP_DIR *dir;
|
||||||
|
unsigned char *data = get_uri_string(uri, URI_DATA);
|
||||||
|
|
||||||
|
if (!init_string(&buf))
|
||||||
|
fsp_error("Out of memory");
|
||||||
|
|
||||||
|
add_to_string(&buf, "fsp://");
|
||||||
|
if (uri->passwordlen) {
|
||||||
|
add_to_string(&buf, "u:");
|
||||||
|
add_bytes_to_string(&buf, uri->password, uri->passwordlen);
|
||||||
|
add_char_to_string(&buf, '@');
|
||||||
|
}
|
||||||
|
add_bytes_to_string(&buf, uri->host, uri->hostlen);
|
||||||
|
if (uri->portlen) {
|
||||||
|
add_char_to_string(&buf, ':');
|
||||||
|
add_bytes_to_string(&buf, uri->port, uri->portlen);
|
||||||
|
}
|
||||||
|
add_char_to_string(&buf, '/');
|
||||||
|
if (uri->datalen) {
|
||||||
|
add_bytes_to_string(&buf, uri->data, uri->datalen);
|
||||||
|
add_char_to_string(&buf, '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("<html><head><title>%s</title><base href=\"%s\">"
|
||||||
|
"</head><body><pre>", buf.source, buf.source);
|
||||||
|
|
||||||
|
dir = fsp_opendir(ses, data);
|
||||||
|
if (!dir) goto end;
|
||||||
|
|
||||||
|
if (get_opt_bool("protocol.fsp.sort")) {
|
||||||
|
sort_and_display_entries(dir);
|
||||||
|
} else {
|
||||||
|
FSP_RDENTRY fentry, *fresult;
|
||||||
|
unsigned char dircolor[8];
|
||||||
|
|
||||||
|
if (get_opt_bool("document.browse.links.color_dirs")) {
|
||||||
|
color_to_string(get_opt_color("document.colors.dirs"),
|
||||||
|
(unsigned char *) &dircolor);
|
||||||
|
} else {
|
||||||
|
dircolor[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!fsp_readdir_native(dir, &fentry, &fresult)) {
|
||||||
|
if (!fresult) break;
|
||||||
|
printf("%10d\t<a href=\"%s\">", fentry.size, fentry.name);
|
||||||
|
if (fentry.type == FSP_RDTYPE_DIR && *dircolor) {
|
||||||
|
printf("<font color=\"%s\"><b>", dircolor);
|
||||||
|
}
|
||||||
|
printf("%s", fentry.name);
|
||||||
|
if (fentry.type == FSP_RDTYPE_DIR && *dircolor) {
|
||||||
|
printf("</b></font>");
|
||||||
|
}
|
||||||
|
puts("</a>");
|
||||||
|
}
|
||||||
|
fsp_closedir(dir);
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
puts("</pre></body></html>");
|
||||||
|
fsp_close_session(ses);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define READ_SIZE 4096
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_fsp(struct connection *conn)
|
||||||
|
{
|
||||||
|
struct stat sb;
|
||||||
|
struct uri *uri = conn->uri;
|
||||||
|
unsigned char *host = get_uri_string(uri, URI_HOST);
|
||||||
|
unsigned char *password = get_uri_string(uri, URI_PASSWORD);
|
||||||
|
unsigned char *data = get_uri_string(uri, URI_DATA);
|
||||||
|
unsigned short port = (unsigned short)get_uri_port(uri);
|
||||||
|
FSP_SESSION *ses = fsp_open_session(host, port, password);
|
||||||
|
|
||||||
|
if (!ses)
|
||||||
|
fsp_error("Session initialization failed.");
|
||||||
|
if (fsp_stat(ses, data, &sb))
|
||||||
|
fsp_error("File not found.");
|
||||||
|
if (S_ISDIR(sb.st_mode))
|
||||||
|
fsp_directory(ses, uri);
|
||||||
|
else { /* regular file */
|
||||||
|
char buf[4096];
|
||||||
|
FSP_FILE *file = fsp_fopen(ses, data, "r");
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
fsp_error("fsp_fopen error.");
|
||||||
|
|
||||||
|
while ((r = fsp_fread(buf, 1, READ_SIZE, file)) > 0)
|
||||||
|
fwrite(buf, 1, r, stdout);
|
||||||
|
fsp_fclose(file);
|
||||||
|
fsp_close_session(ses);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsp_got_data(struct socket *socket, struct read_buffer *rb)
|
||||||
|
{
|
||||||
|
int len = rb->length;
|
||||||
|
struct connection *conn = socket->conn;
|
||||||
|
|
||||||
|
if (len < 0) {
|
||||||
|
abort_connection(conn, -errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (len == 0) {
|
||||||
|
if (conn->from)
|
||||||
|
normalize_cache_entry(conn->cached, conn->from);
|
||||||
|
close_socket(socket);
|
||||||
|
abort_connection(conn, S_OK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->socket->state = SOCKET_END_ONCLOSE;
|
||||||
|
conn->received += len;
|
||||||
|
if (add_fragment(conn->cached, conn->from, rb->data, len) == 1)
|
||||||
|
conn->tries = 0;
|
||||||
|
conn->from += len;
|
||||||
|
kill_buffer_data(rb, len);
|
||||||
|
read_from_socket(socket, rb, S_TRANS, fsp_got_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef READ_SIZE
|
||||||
|
|
||||||
|
|
||||||
|
/* Close all non-terminal file descriptors. */
|
||||||
|
static void
|
||||||
|
close_all_non_term_fd(void)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
int max = 1024;
|
||||||
|
#ifdef RLIMIT_NOFILE
|
||||||
|
struct rlimit lim;
|
||||||
|
|
||||||
|
if (!getrlimit(RLIMIT_NOFILE, &lim))
|
||||||
|
max = lim.rlim_max;
|
||||||
|
#endif
|
||||||
|
for (n = 3; n < max; n++)
|
||||||
|
close(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fsp_protocol_handler(struct connection *conn)
|
||||||
|
{
|
||||||
|
int fsp_pipe[2] = { -1, -1 };
|
||||||
|
int cpid;
|
||||||
|
struct read_buffer *buf;
|
||||||
|
|
||||||
|
if (c_pipe(fsp_pipe)) {
|
||||||
|
int s_errno = errno;
|
||||||
|
|
||||||
|
if (fsp_pipe[0] >= 0) close(fsp_pipe[0]);
|
||||||
|
if (fsp_pipe[1] >= 0) close(fsp_pipe[1]);
|
||||||
|
abort_connection(conn, -s_errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->cached = get_cache_entry(conn->uri);
|
||||||
|
if (!conn->cached) {
|
||||||
|
abort_connection(conn, S_OUT_OF_MEM);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
conn->from = 0;
|
||||||
|
conn->unrestartable = 1;
|
||||||
|
|
||||||
|
cpid = fork();
|
||||||
|
if (cpid == -1) {
|
||||||
|
int s_errno = errno;
|
||||||
|
|
||||||
|
close(fsp_pipe[0]);
|
||||||
|
close(fsp_pipe[1]);
|
||||||
|
retry_connection(conn, -s_errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cpid) {
|
||||||
|
close(1);
|
||||||
|
dup2(fsp_pipe[1], 1);
|
||||||
|
close(0);
|
||||||
|
dup2(open("/dev/null", O_RDONLY), 0);
|
||||||
|
close(2);
|
||||||
|
dup2(open("/dev/null", O_RDONLY), 2);
|
||||||
|
close(fsp_pipe[0]);
|
||||||
|
|
||||||
|
close_all_non_term_fd();
|
||||||
|
do_fsp(conn);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
conn->socket->fd = fsp_pipe[0];
|
||||||
|
close(fsp_pipe[1]);
|
||||||
|
buf = alloc_read_buffer(conn->socket);
|
||||||
|
if (!buf) {
|
||||||
|
close(fsp_pipe[0]);
|
||||||
|
abort_connection(conn, S_OUT_OF_MEM);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
read_from_socket(conn->socket, buf, S_CONN, fsp_got_data);
|
||||||
|
}
|
||||||
|
}
|
16
src/protocol/fsp/fsp.h
Normal file
16
src/protocol/fsp/fsp.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
#ifndef EL__PROTOCOL_FSP_FSP_H
|
||||||
|
#define EL__PROTOCOL_FSP_FSP_H
|
||||||
|
|
||||||
|
#include "main/module.h"
|
||||||
|
#include "protocol/protocol.h"
|
||||||
|
|
||||||
|
extern struct module fsp_protocol_module;
|
||||||
|
|
||||||
|
#ifdef CONFIG_FSP
|
||||||
|
extern protocol_handler_T fsp_protocol_handler;
|
||||||
|
#else
|
||||||
|
#define fsp_protocol_handler NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -31,6 +31,7 @@
|
|||||||
#include "protocol/data.h"
|
#include "protocol/data.h"
|
||||||
#include "protocol/file/file.h"
|
#include "protocol/file/file.h"
|
||||||
#include "protocol/finger/finger.h"
|
#include "protocol/finger/finger.h"
|
||||||
|
#include "protocol/fsp/fsp.h"
|
||||||
#include "protocol/ftp/ftp.h"
|
#include "protocol/ftp/ftp.h"
|
||||||
#include "protocol/gopher/gopher.h"
|
#include "protocol/gopher/gopher.h"
|
||||||
#include "protocol/http/http.h"
|
#include "protocol/http/http.h"
|
||||||
@ -57,6 +58,7 @@ static const struct protocol_backend protocol_backends[] = {
|
|||||||
{ "data", 0, data_protocol_handler, 0, 0, 1, 0 },
|
{ "data", 0, data_protocol_handler, 0, 0, 1, 0 },
|
||||||
{ "file", 0, file_protocol_handler, 1, 0, 0, 0 },
|
{ "file", 0, file_protocol_handler, 1, 0, 0, 0 },
|
||||||
{ "finger", 79, finger_protocol_handler, 1, 1, 0, 0 },
|
{ "finger", 79, finger_protocol_handler, 1, 1, 0, 0 },
|
||||||
|
{ "fsp", 21, fsp_protocol_handler, 1, 1, 0, 0 },
|
||||||
{ "ftp", 21, ftp_protocol_handler, 1, 1, 0, 0 },
|
{ "ftp", 21, ftp_protocol_handler, 1, 1, 0, 0 },
|
||||||
{ "gopher", 70, gopher_protocol_handler, 1, 1, 0, 0 },
|
{ "gopher", 70, gopher_protocol_handler, 1, 1, 0, 0 },
|
||||||
{ "http", 80, http_protocol_handler, 1, 1, 0, 0 },
|
{ "http", 80, http_protocol_handler, 1, 1, 0, 0 },
|
||||||
@ -276,6 +278,9 @@ static struct module *protocol_submodules[] = {
|
|||||||
#ifdef CONFIG_FINGER
|
#ifdef CONFIG_FINGER
|
||||||
&finger_protocol_module,
|
&finger_protocol_module,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_FSP
|
||||||
|
&fsp_protocol_module,
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_FTP
|
#ifdef CONFIG_FTP
|
||||||
&ftp_protocol_module,
|
&ftp_protocol_module,
|
||||||
#endif
|
#endif
|
||||||
|
@ -14,6 +14,7 @@ enum protocol {
|
|||||||
PROTOCOL_DATA,
|
PROTOCOL_DATA,
|
||||||
PROTOCOL_FILE,
|
PROTOCOL_FILE,
|
||||||
PROTOCOL_FINGER,
|
PROTOCOL_FINGER,
|
||||||
|
PROTOCOL_FSP,
|
||||||
PROTOCOL_FTP,
|
PROTOCOL_FTP,
|
||||||
PROTOCOL_GOPHER,
|
PROTOCOL_GOPHER,
|
||||||
PROTOCOL_HTTP,
|
PROTOCOL_HTTP,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user