mirror of
https://github.com/irssi/irssi.git
synced 2025-01-03 14:56:47 -05:00
Passive DCC support by Francesco Fracassi (francesco.f at openssl.it)
git-svn-id: http://svn.irssi.org/repos/irssi/trunk@3236 dbcabf3a-b0e7-0310-adc4-f8d773084564
This commit is contained in:
parent
2a12dfb9d0
commit
af4bcb70f2
@ -1,27 +1,29 @@
|
||||
|
||||
@SYNTAX:dcc@
|
||||
|
||||
This is a command to handle different DCC-connections. DCC is mainly
|
||||
used for more reliable and faster chatting and for sending and receiving
|
||||
files.
|
||||
|
||||
/DCC LIST
|
||||
- Shows all the open DCC connections.
|
||||
/DCC RESUME [<nick> [<file>]]
|
||||
- Resumes a DCC SEND/GET connection.
|
||||
/DCC CHAT [<nick>]
|
||||
/DCC CHAT [-passive] [<nick>]
|
||||
- Sends a chat connection request to remote client or accepts
|
||||
a chat connection if the remote end has already sent a request.
|
||||
If -passive is used then the passive DCC protocol is used (as mIRC
|
||||
can do). This is useful to bypass a NAT/firewall which limit your
|
||||
possibility in listening for remote connections.
|
||||
/DCC GET [<nick> [<file>]]
|
||||
- Gets the file offered by remote client. The file is downloaded and
|
||||
saved into the current working directory.
|
||||
/DCC SEND [-append | -prepend | -flush | -rmtail | -rmhead]
|
||||
/DCC SEND [-passive] [-append | -prepend | -flush | -rmtail | -rmhead]
|
||||
<nick> <file> [<file> ...]
|
||||
- Sends a DCC SEND request to remote client. Remote end has to accept
|
||||
the request before the transmission can be started. Giving multiple files
|
||||
queues them. File names may contain shell expansion characters: * ? [] ~
|
||||
(~ expansion may not be supported on all platforms). Files with spaces
|
||||
in their names need to be quoted (eg. "file name").
|
||||
in their names need to be quoted (eg. "file name"). If -passive is used
|
||||
then the passive DCC protocol is used (as mIRC and xchat > 2.0.7 can do).
|
||||
This is useful to bypass a NAT/firewall which limit your possibility in
|
||||
listening for remote connections.
|
||||
/DCC SERVER [<+|-scf> <port>]
|
||||
- Starts a DCC SERVER on the specified port. The remote can connect to this
|
||||
server and initiate chat, send and fserve requests. You can specify + or -
|
||||
|
@ -388,35 +388,77 @@ static void dcc_chat_connect(CHAT_DCC_REC *dcc)
|
||||
}
|
||||
}
|
||||
|
||||
/* SYNTAX: DCC CHAT [<nick>] */
|
||||
static void dcc_chat_passive(CHAT_DCC_REC *dcc)
|
||||
{
|
||||
IPADDR own_ip;
|
||||
int port;
|
||||
GIOChannel *handle;
|
||||
char host[MAX_IP_LEN];
|
||||
|
||||
g_return_if_fail(IS_DCC_CHAT(dcc));
|
||||
|
||||
if (dcc->addrstr[0] == '\0' ||
|
||||
dcc->starttime != 0 || dcc->handle != NULL) {
|
||||
/* already sent a chat request / already chatting */
|
||||
return;
|
||||
}
|
||||
|
||||
handle = dcc_listen(net_sendbuffer_handle(dcc->server->handle),
|
||||
&own_ip, &port);
|
||||
if (handle == NULL)
|
||||
cmd_return_error(CMDERR_ERRNO);
|
||||
|
||||
dcc->handle = handle;
|
||||
dcc->tagconn = g_input_add(dcc->handle, G_INPUT_READ,
|
||||
(GInputFunction) dcc_chat_listen, dcc);
|
||||
|
||||
/* Let's send the reply to the other client! */
|
||||
dcc_ip2str(&own_ip, host);
|
||||
irc_send_cmdv(dcc->server, "PRIVMSG %s :\001DCC CHAT CHAT %s %d %d\001",
|
||||
dcc->nick, host, port, dcc->pasv_id);
|
||||
|
||||
}
|
||||
|
||||
/* SYNTAX: DCC CHAT [-passive] [<nick>] */
|
||||
static void cmd_dcc_chat(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
void *free_arg;
|
||||
CHAT_DCC_REC *dcc;
|
||||
IPADDR own_ip;
|
||||
GIOChannel *handle;
|
||||
GIOChannel *handle;
|
||||
GHashTable *optlist;
|
||||
int p_id;
|
||||
char *nick, host[MAX_IP_LEN];
|
||||
int port;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
if (!cmd_get_params(data, &free_arg, 1, &nick))
|
||||
if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS,
|
||||
"dcc chat", &optlist, &nick))
|
||||
return;
|
||||
|
||||
if (*nick == '\0') {
|
||||
dcc = DCC_CHAT(dcc_find_request_latest(DCC_CHAT_TYPE));
|
||||
if (dcc != NULL)
|
||||
dcc_chat_connect(dcc);
|
||||
if (dcc != NULL) {
|
||||
if (!dcc_is_passive(dcc))
|
||||
dcc_chat_connect(dcc);
|
||||
else
|
||||
dcc_chat_passive(dcc);
|
||||
}
|
||||
cmd_params_free(free_arg);
|
||||
return;
|
||||
}
|
||||
|
||||
dcc = dcc_chat_find_id(nick);
|
||||
if (dcc != NULL && dcc_is_waiting_user(dcc)) {
|
||||
/* found from dcc chat requests,
|
||||
we're the connecting side */
|
||||
dcc_chat_connect(dcc);
|
||||
cmd_params_free(free_arg);
|
||||
if (!dcc_is_passive(dcc)) {
|
||||
/* found from dcc chat requests,
|
||||
we're the connecting side */
|
||||
dcc_chat_connect(dcc);
|
||||
} else {
|
||||
/* We are accepting a passive DCC CHAT. */
|
||||
dcc_chat_passive(dcc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -424,30 +466,50 @@ static void cmd_dcc_chat(const char *data, IRC_SERVER_REC *server)
|
||||
dcc->server == server) {
|
||||
/* sending request again even while old request is
|
||||
still waiting, remove it. */
|
||||
dcc_destroy(DCC(dcc));
|
||||
dcc_destroy(DCC(dcc));
|
||||
}
|
||||
|
||||
/* start listening */
|
||||
if (!IS_IRC_SERVER(server) || !server->connected)
|
||||
cmd_param_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
handle = dcc_listen(net_sendbuffer_handle(server->handle),
|
||||
&own_ip, &port);
|
||||
if (handle == NULL)
|
||||
cmd_param_error(CMDERR_ERRNO);
|
||||
|
||||
dcc = dcc_chat_create(server, NULL, nick, "chat");
|
||||
dcc->handle = handle;
|
||||
dcc->tagconn = g_input_add(dcc->handle, G_INPUT_READ,
|
||||
(GInputFunction) dcc_chat_listen, dcc);
|
||||
|
||||
/* send the chat request */
|
||||
signal_emit("dcc request send", 1, dcc);
|
||||
if (g_hash_table_lookup(optlist, "passive") == NULL) {
|
||||
/* Standard DCC CHAT... let's listen for incoming connections */
|
||||
handle = dcc_listen(net_sendbuffer_handle(server->handle),
|
||||
&own_ip, &port);
|
||||
if (handle == NULL)
|
||||
cmd_param_error(CMDERR_ERRNO);
|
||||
|
||||
dcc_ip2str(&own_ip, host);
|
||||
irc_send_cmdv(server, "PRIVMSG %s :\001DCC CHAT CHAT %s %d\001",
|
||||
nick, host, port);
|
||||
dcc->handle = handle;
|
||||
dcc->tagconn =
|
||||
g_input_add(dcc->handle, G_INPUT_READ,
|
||||
(GInputFunction) dcc_chat_listen, dcc);
|
||||
|
||||
/* send the chat request */
|
||||
signal_emit("dcc request send", 1, dcc);
|
||||
|
||||
dcc_ip2str(&own_ip, host);
|
||||
irc_send_cmdv(server, "PRIVMSG %s :\001DCC CHAT CHAT %s %d\001",
|
||||
nick, host, port);
|
||||
} else {
|
||||
/* Passive protocol... we want the other side to listen */
|
||||
/* send the chat request */
|
||||
dcc->port = 0;
|
||||
signal_emit("dcc request send", 1, dcc);
|
||||
|
||||
/* generate a random id */
|
||||
srand(time(NULL));
|
||||
p_id = rand() % 64;
|
||||
dcc->pasv_id = p_id;
|
||||
|
||||
/* 16974599 is the long format of 1.3.3.7, we use a fake IP
|
||||
since the other side shouldn't care of it: they will send
|
||||
the address for us to connect to in the reply */
|
||||
irc_send_cmdv(server,
|
||||
"PRIVMSG %s :\001DCC CHAT CHAT 16974599 0 %d\001",
|
||||
nick, p_id);
|
||||
}
|
||||
cmd_params_free(free_arg);
|
||||
}
|
||||
|
||||
@ -541,16 +603,18 @@ static void ctcp_msg_dcc_chat(IRC_SERVER_REC *server, const char *data,
|
||||
CHAT_DCC_REC *dcc;
|
||||
char **params;
|
||||
int paramcount;
|
||||
int autoallow = FALSE;
|
||||
|
||||
int passive, autoallow = FALSE;
|
||||
|
||||
/* CHAT <unused> <address> <port> */
|
||||
/* CHAT <unused> <address> 0 <id> (DCC CHAT passive protocol) */
|
||||
params = g_strsplit(data, " ", -1);
|
||||
paramcount = strarray_length(params);
|
||||
|
||||
if (paramcount < 3) {
|
||||
g_strfreev(params);
|
||||
return;
|
||||
return;
|
||||
}
|
||||
passive = paramcount == 4 && strcmp(params[2], "0") == 0;
|
||||
|
||||
dcc = DCC_CHAT(dcc_find_request(DCC_CHAT_TYPE, nick, NULL));
|
||||
if (dcc != NULL) {
|
||||
@ -559,24 +623,50 @@ static void ctcp_msg_dcc_chat(IRC_SERVER_REC *server, const char *data,
|
||||
dcc chat from us .. allow it. */
|
||||
dcc_destroy(DCC(dcc));
|
||||
autoallow = TRUE;
|
||||
} else {
|
||||
} else if (!dcc_is_passive(dcc)) {
|
||||
/* we already have one dcc chat request
|
||||
from this nick, remove it. */
|
||||
dcc_destroy(DCC(dcc));
|
||||
dcc_destroy(DCC(dcc));
|
||||
} else if (passive) {
|
||||
if (dcc->pasv_id != atoi(params[3])) {
|
||||
/* IDs don't match! */
|
||||
dcc_destroy(DCC(dcc));
|
||||
} else {
|
||||
/* IDs are ok! Update address and port and
|
||||
connect! */
|
||||
dcc->target = g_strdup(target);
|
||||
dcc->port = atoi(params[2]);
|
||||
dcc_str2ip(params[1], &dcc->addr);
|
||||
net_ip2host(&dcc->addr, dcc->addrstr);
|
||||
|
||||
dcc_chat_connect(dcc);
|
||||
g_strfreev(params);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dcc = dcc_chat_create(server, chat, nick, params[0]);
|
||||
dcc->target = g_strdup(target);
|
||||
dcc->port = atoi(params[2]);
|
||||
|
||||
if (passive)
|
||||
dcc->pasv_id = atoi(params[3]);
|
||||
|
||||
dcc_str2ip(params[1], &dcc->addr);
|
||||
net_ip2host(&dcc->addr, dcc->addrstr);
|
||||
|
||||
signal_emit("dcc request", 2, dcc, addr);
|
||||
|
||||
if (autoallow || DCC_CHAT_AUTOACCEPT(dcc, server, nick, addr))
|
||||
dcc_chat_connect(dcc);
|
||||
|
||||
if (autoallow || DCC_CHAT_AUTOACCEPT(dcc, server, nick, addr)) {
|
||||
if (passive) {
|
||||
/* Passive DCC... let's set up a listening socket
|
||||
and send reply back */
|
||||
dcc_chat_passive(dcc);
|
||||
} else {
|
||||
dcc_chat_connect(dcc);
|
||||
}
|
||||
}
|
||||
g_strfreev(params);
|
||||
}
|
||||
|
||||
@ -716,6 +806,7 @@ void dcc_chat_init(void)
|
||||
command_bind("action", NULL, (SIGNAL_FUNC) cmd_action);
|
||||
command_bind("ctcp", NULL, (SIGNAL_FUNC) cmd_ctcp);
|
||||
command_bind("dcc chat", NULL, (SIGNAL_FUNC) cmd_dcc_chat);
|
||||
command_set_options("dcc chat", "passive");
|
||||
command_bind("mircdcc", NULL, (SIGNAL_FUNC) cmd_mircdcc);
|
||||
command_bind("dcc close", NULL, (SIGNAL_FUNC) cmd_dcc_close);
|
||||
command_bind("whois", NULL, (SIGNAL_FUNC) cmd_whois);
|
||||
|
@ -24,10 +24,11 @@
|
||||
#include "network.h"
|
||||
#include "misc.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "net-sendbuffer.h"
|
||||
#include "irc-servers.h"
|
||||
|
||||
#include "dcc-get.h"
|
||||
#include "dcc-send.h"
|
||||
|
||||
static int dcc_file_create_mode;
|
||||
|
||||
@ -290,6 +291,54 @@ void dcc_get_connect(GET_DCC_REC *dcc)
|
||||
}
|
||||
}
|
||||
|
||||
static void dcc_get_listen(GET_DCC_REC *dcc)
|
||||
{
|
||||
GIOChannel *handle;
|
||||
IPADDR addr;
|
||||
int port;
|
||||
|
||||
/* accept connection */
|
||||
handle = net_accept(dcc->handle, &addr, &port);
|
||||
if (handle == NULL)
|
||||
return;
|
||||
|
||||
net_disconnect(dcc->handle);
|
||||
g_source_remove(dcc->tagconn);
|
||||
dcc->tagconn = -1;
|
||||
|
||||
dcc->starttime = time(NULL);
|
||||
dcc->handle = handle;
|
||||
memcpy(&dcc->addr, &addr, sizeof(IPADDR));
|
||||
net_ip2host(&dcc->addr, dcc->addrstr);
|
||||
dcc->port = port;
|
||||
|
||||
dcc->tagconn = g_input_add(handle, G_INPUT_READ | G_INPUT_WRITE,
|
||||
(GInputFunction) sig_dccget_connected, dcc);
|
||||
}
|
||||
|
||||
void dcc_get_passive(GET_DCC_REC *dcc)
|
||||
{
|
||||
GIOChannel *handle;
|
||||
IPADDR own_ip;
|
||||
int port;
|
||||
char host[MAX_IP_LEN];
|
||||
|
||||
handle = dcc_listen(net_sendbuffer_handle(dcc->server->handle),
|
||||
&own_ip, &port);
|
||||
if (handle == NULL)
|
||||
cmd_return_error(CMDERR_ERRNO);
|
||||
|
||||
dcc->handle = handle;
|
||||
dcc->tagconn = g_input_add(dcc->handle, G_INPUT_READ,
|
||||
(GInputFunction) dcc_get_listen, dcc);
|
||||
|
||||
/* Let's send the reply to the other client! */
|
||||
dcc_ip2str(&own_ip, host);
|
||||
irc_send_cmdv(dcc->server,
|
||||
"PRIVMSG %s :\001DCC SEND %s %s %d %"PRIuUOFF_T" %d\001",
|
||||
dcc->nick, dcc->arg, host, port, dcc->size, dcc->pasv_id);
|
||||
}
|
||||
|
||||
#define get_params_match(params, pos) \
|
||||
((is_numeric(params[pos], '\0') || is_ipv6_address(params[pos])) && \
|
||||
is_numeric(params[(pos)+1], '\0') && atol(params[(pos)+1]) < 65536 && \
|
||||
@ -332,14 +381,18 @@ static void ctcp_msg_dcc_send(IRC_SERVER_REC *server, const char *data,
|
||||
const char *target, CHAT_DCC_REC *chat)
|
||||
{
|
||||
GET_DCC_REC *dcc;
|
||||
IPADDR ip;
|
||||
SEND_DCC_REC *temp_dcc;
|
||||
IPADDR ip;
|
||||
const char *address;
|
||||
char **params, *fname;
|
||||
int paramcount, fileparams;
|
||||
int port, len, quoted = FALSE;
|
||||
uoff_t size;
|
||||
int p_id = -1;
|
||||
int passive = FALSE;
|
||||
|
||||
/* SEND <file name> <address> <port> <size> [...] */
|
||||
/* SEND <file name> <address> 0 <size> <id> (DCC SEND passive protocol) */
|
||||
params = g_strsplit(data, " ", -1);
|
||||
paramcount = strarray_length(params);
|
||||
|
||||
@ -357,6 +410,12 @@ static void ctcp_msg_dcc_send(IRC_SERVER_REC *server, const char *data,
|
||||
port = atoi(params[fileparams+1]);
|
||||
size = str_to_uofft(params[fileparams+2]);
|
||||
|
||||
/* If this DCC uses passive protocol then store the id for later use. */
|
||||
if (paramcount == fileparams + 4) {
|
||||
p_id = atoi(params[fileparams+3]);
|
||||
passive = TRUE;
|
||||
}
|
||||
|
||||
params[fileparams] = NULL;
|
||||
fname = g_strjoinv(" ", params);
|
||||
g_strfreev(params);
|
||||
@ -368,36 +427,73 @@ static void ctcp_msg_dcc_send(IRC_SERVER_REC *server, const char *data,
|
||||
g_memmove(fname, fname+1, len);
|
||||
quoted = TRUE;
|
||||
}
|
||||
|
||||
if (passive && port != 0) {
|
||||
/* This is NOT a DCC SEND request! This is a reply to our
|
||||
passive request. We MUST check the IDs and then connect to
|
||||
the remote host. */
|
||||
|
||||
temp_dcc = DCC_SEND(dcc_find_request(DCC_SEND_TYPE, nick, fname));
|
||||
if (temp_dcc != NULL && p_id == temp_dcc->pasv_id) {
|
||||
temp_dcc->target = g_strdup(target);
|
||||
temp_dcc->port = port;
|
||||
temp_dcc->size = size;
|
||||
temp_dcc->file_quoted = quoted;
|
||||
|
||||
memcpy(&temp_dcc->addr, &ip, sizeof(IPADDR));
|
||||
if (temp_dcc->addr.family == AF_INET)
|
||||
net_ip2host(&temp_dcc->addr, temp_dcc->addrstr);
|
||||
else {
|
||||
/* with IPv6, show it to us as it was sent */
|
||||
strocpy(temp_dcc->addrstr, address,
|
||||
sizeof(temp_dcc->addrstr));
|
||||
}
|
||||
|
||||
/* This new signal is added to let us invoke
|
||||
dcc_send_connect() which is found in dcc-send.c */
|
||||
signal_emit("dcc reply send pasv", 1, temp_dcc);
|
||||
g_free(fname);
|
||||
return;
|
||||
} else if (temp_dcc != NULL && p_id != temp_dcc->pasv_id) {
|
||||
/* IDs don't match... remove the old DCC SEND and
|
||||
return */
|
||||
dcc_destroy(DCC(temp_dcc));
|
||||
g_free(fname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dcc = DCC_GET(dcc_find_request(DCC_GET_TYPE, nick, fname));
|
||||
if (dcc != NULL) {
|
||||
/* same DCC request offered again, remove the old one */
|
||||
dcc_destroy(DCC(dcc));
|
||||
}
|
||||
if (dcc != NULL)
|
||||
dcc_destroy(DCC(dcc)); /* remove the old DCC */
|
||||
|
||||
dcc = dcc_get_create(server, chat, nick, fname);
|
||||
dcc->target = g_strdup(target);
|
||||
|
||||
if (passive && port == 0)
|
||||
dcc->pasv_id = p_id; /* Assign the ID to the DCC */
|
||||
|
||||
memcpy(&dcc->addr, &ip, sizeof(ip));
|
||||
if (dcc->addr.family == AF_INET)
|
||||
net_ip2host(&dcc->addr, dcc->addrstr);
|
||||
else {
|
||||
/* with IPv6, show it to us as it was sent */
|
||||
strncpy(dcc->addrstr, address, sizeof(dcc->addrstr)-1);
|
||||
dcc->addrstr[sizeof(dcc->addrstr)-1] = '\0';
|
||||
strocpy(dcc->addrstr, address, sizeof(dcc->addrstr));
|
||||
}
|
||||
dcc->port = port;
|
||||
dcc->size = size;
|
||||
dcc->file_quoted = quoted;
|
||||
dcc->file_quoted = quoted;
|
||||
|
||||
signal_emit("dcc request", 2, dcc, addr);
|
||||
|
||||
g_free(fname);
|
||||
g_free(fname);
|
||||
}
|
||||
|
||||
/* handle receiving DCC - GET/RESUME. */
|
||||
void cmd_dcc_receive(const char *data, DCC_GET_FUNC accept_func)
|
||||
void cmd_dcc_receive(const char *data, DCC_GET_FUNC accept_func,
|
||||
DCC_GET_FUNC pasv_accept_func)
|
||||
{
|
||||
GET_DCC_REC *dcc;
|
||||
GET_DCC_REC *dcc;
|
||||
GSList *tmp, *next;
|
||||
char *nick, *fname;
|
||||
void *free_arg;
|
||||
@ -411,8 +507,12 @@ void cmd_dcc_receive(const char *data, DCC_GET_FUNC accept_func)
|
||||
|
||||
if (*nick == '\0') {
|
||||
dcc = DCC_GET(dcc_find_request_latest(DCC_GET_TYPE));
|
||||
if (dcc != NULL)
|
||||
accept_func(dcc);
|
||||
if (dcc != NULL) {
|
||||
if (!dcc_is_passive(dcc))
|
||||
accept_func(dcc);
|
||||
else
|
||||
pasv_accept_func(dcc);
|
||||
}
|
||||
cmd_params_free(free_arg);
|
||||
return;
|
||||
}
|
||||
@ -426,7 +526,10 @@ void cmd_dcc_receive(const char *data, DCC_GET_FUNC accept_func)
|
||||
(dcc_is_waiting_user(dcc) || dcc->from_dccserver) &&
|
||||
(*fname == '\0' || strcmp(dcc->arg, fname) == 0)) {
|
||||
found = TRUE;
|
||||
accept_func(dcc);
|
||||
if (!dcc_is_passive(dcc))
|
||||
accept_func(dcc);
|
||||
else
|
||||
pasv_accept_func(dcc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -439,7 +542,7 @@ void cmd_dcc_receive(const char *data, DCC_GET_FUNC accept_func)
|
||||
/* SYNTAX: DCC GET [<nick> [<file>]] */
|
||||
static void cmd_dcc_get(const char *data)
|
||||
{
|
||||
cmd_dcc_receive(data, dcc_get_connect);
|
||||
cmd_dcc_receive(data, dcc_get_connect, dcc_get_passive);
|
||||
}
|
||||
|
||||
static void read_settings(void)
|
||||
|
@ -32,8 +32,10 @@ typedef struct {
|
||||
typedef void (*DCC_GET_FUNC) (GET_DCC_REC *);
|
||||
|
||||
/* handle receiving DCC - GET/RESUME. */
|
||||
void cmd_dcc_receive(const char *data, DCC_GET_FUNC accept_func);
|
||||
void cmd_dcc_receive(const char *data, DCC_GET_FUNC accept_func,
|
||||
DCC_GET_FUNC pasv_accept_func);
|
||||
|
||||
void dcc_get_passive(GET_DCC_REC *dcc);
|
||||
void dcc_get_connect(GET_DCC_REC *dcc);
|
||||
char *dcc_get_download_path(const char *fname);
|
||||
|
||||
|
@ -122,6 +122,31 @@ void dcc_queue_add(int queue, int mode, const char *nick, const char *fname,
|
||||
rec->servertag = g_strdup(servertag);
|
||||
rec->nick = g_strdup(nick);
|
||||
rec->file = g_strdup(fname);
|
||||
rec->passive = FALSE;
|
||||
|
||||
qlist = (GSList **) &g_ptr_array_index(queuelist, queue);
|
||||
if (mode == DCC_QUEUE_PREPEND)
|
||||
*qlist = g_slist_insert(*qlist, rec, 1);
|
||||
else
|
||||
*qlist = g_slist_append(*qlist, rec);
|
||||
}
|
||||
|
||||
/* Same as above but adds a passive DCC to the queue */
|
||||
void dcc_queue_add_passive(int queue, int mode, const char *nick,
|
||||
const char *fname, const char *servertag,
|
||||
CHAT_DCC_REC *chat)
|
||||
{
|
||||
DCC_QUEUE_REC *rec;
|
||||
GSList **qlist;
|
||||
|
||||
g_assert(queue >= 0 && queue < queuelist->len);
|
||||
|
||||
rec = g_new0(DCC_QUEUE_REC, 1);
|
||||
rec->chat = chat;
|
||||
rec->servertag = g_strdup(servertag);
|
||||
rec->nick = g_strdup(nick);
|
||||
rec->file = g_strdup(fname);
|
||||
rec->passive = TRUE;
|
||||
|
||||
qlist = (GSList **) &g_ptr_array_index(queuelist, queue);
|
||||
if (mode == DCC_QUEUE_PREPEND)
|
||||
|
@ -14,6 +14,7 @@ typedef struct {
|
||||
char *servertag;
|
||||
char *nick;
|
||||
char *file;
|
||||
int passive; /* for passive DCCs */
|
||||
} DCC_QUEUE_REC;
|
||||
|
||||
/* create a new queue. returns it's designation number (int) */
|
||||
@ -28,6 +29,9 @@ int dcc_queue_old(const char *nick, const char *servertag);
|
||||
/* adds nick/fname/servertag triplet into queue */
|
||||
void dcc_queue_add(int queue, int mode, const char *nick, const char *fname,
|
||||
const char *servertag, CHAT_DCC_REC *chat);
|
||||
void dcc_queue_add_passive(int queue, int mode, const char *nick,
|
||||
const char *fname, const char *servertag,
|
||||
CHAT_DCC_REC *chat);
|
||||
|
||||
int dcc_queue_remove_head(int queue);
|
||||
|
||||
|
@ -20,6 +20,8 @@ int tagconn, tagread, tagwrite;
|
||||
time_t starttime; /* transfer start time */
|
||||
uoff_t transfd; /* bytes transferred */
|
||||
|
||||
int pasv_id; /* DCC Id for passive DCCs. <0 means a passive DCC, >=0 means a standard DCC */
|
||||
|
||||
unsigned int destroyed:1; /* We're about to destroy this DCC recond */
|
||||
|
||||
GHashTable *module_data;
|
||||
|
@ -45,24 +45,29 @@ static FILE_DCC_REC *dcc_resume_find(int type, const char *nick, int port)
|
||||
}
|
||||
|
||||
static int dcc_ctcp_resume_parse(int type, const char *data, const char *nick,
|
||||
FILE_DCC_REC **dcc, uoff_t *size)
|
||||
FILE_DCC_REC **dcc, uoff_t *size, int *pasv_id)
|
||||
{
|
||||
char **params;
|
||||
int paramcount;
|
||||
int port;
|
||||
|
||||
/* RESUME|ACCEPT <file name> <port> <size> */
|
||||
/* RESUME|ACCEPT <file name> 0 <size> <id> (passive protocol) */
|
||||
params = g_strsplit(data, " ", -1);
|
||||
paramcount = strarray_length(params);
|
||||
|
||||
if (paramcount >= 3) {
|
||||
port = atoi(params[paramcount-2]);
|
||||
*size = str_to_uofft(params[paramcount-1]);
|
||||
|
||||
port = atoi(params[1]);
|
||||
*size = str_to_uofft(params[2]);
|
||||
*pasv_id = (port == 0) ? atoi(params[3]) : -1;
|
||||
*dcc = dcc_resume_find(type, nick, port);
|
||||
g_strfreev(params);
|
||||
|
||||
/* If the ID is different then the DCC cannot be resumed */
|
||||
return ((*dcc)->pasv_id == *pasv_id);
|
||||
}
|
||||
g_strfreev(params);
|
||||
return paramcount >= 3;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int dcc_resume_file_check(FILE_DCC_REC *dcc, IRC_SERVER_REC *server,
|
||||
@ -90,16 +95,24 @@ static void ctcp_msg_dcc_resume(IRC_SERVER_REC *server, const char *data,
|
||||
{
|
||||
FILE_DCC_REC *dcc;
|
||||
char *str;
|
||||
uoff_t size;
|
||||
uoff_t size;
|
||||
int pasv_id = -1;
|
||||
|
||||
if (!dcc_ctcp_resume_parse(DCC_SEND_TYPE, data, nick, &dcc, &size)) {
|
||||
if (!dcc_ctcp_resume_parse(DCC_SEND_TYPE, data, nick, &dcc, &size, &pasv_id)) {
|
||||
signal_emit("dcc error ctcp", 5, "RESUME", data,
|
||||
nick, addr, target);
|
||||
} else if (dcc != NULL && dcc_resume_file_check(dcc, server, size)) {
|
||||
str = g_strdup_printf(DCC_SEND(dcc)->file_quoted ?
|
||||
"DCC ACCEPT \"%s\" %d %"PRIuUOFF_T :
|
||||
"DCC ACCEPT %s %d %"PRIuUOFF_T,
|
||||
dcc->arg, dcc->port, dcc->transfd);
|
||||
if (!dcc_is_passive(dcc)) {
|
||||
str = g_strdup_printf(DCC_SEND(dcc)->file_quoted ?
|
||||
"DCC ACCEPT \"%s\" %d %"PRIuUOFF_T :
|
||||
"DCC ACCEPT %s %d %"PRIuUOFF_T,
|
||||
dcc->arg, dcc->port, dcc->transfd);
|
||||
} else {
|
||||
str = g_strdup_printf(DCC_SEND(dcc)->file_quoted ?
|
||||
"DCC ACCEPT \"%s\" 0 %"PRIuUOFF_T" %d" :
|
||||
"DCC ACCEPT %s 0 %"PRIuUOFF_T" %d",
|
||||
dcc->arg, dcc->transfd, dcc->pasv_id);
|
||||
}
|
||||
dcc_ctcp_message(dcc->server, dcc->nick,
|
||||
dcc->chat, FALSE, str);
|
||||
g_free(str);
|
||||
@ -113,13 +126,18 @@ static void ctcp_msg_dcc_accept(IRC_SERVER_REC *server, const char *data,
|
||||
{
|
||||
FILE_DCC_REC *dcc;
|
||||
uoff_t size;
|
||||
int pasv_id;
|
||||
|
||||
if (!dcc_ctcp_resume_parse(DCC_GET_TYPE, data, nick, &dcc, &size) ||
|
||||
if (!dcc_ctcp_resume_parse(DCC_GET_TYPE, data, nick, &dcc, &size, &pasv_id) ||
|
||||
(dcc != NULL && DCC_GET(dcc)->get_type != DCC_GET_RESUME)) {
|
||||
signal_emit("dcc error ctcp", 5, "ACCEPT", data,
|
||||
nick, addr, target);
|
||||
} else if (dcc != NULL && dcc_resume_file_check(dcc, server, size))
|
||||
dcc_get_connect(DCC_GET(dcc));
|
||||
} else if (dcc != NULL && dcc_resume_file_check(dcc, server, size)) {
|
||||
if (!dcc_is_passive(dcc))
|
||||
dcc_get_connect(DCC_GET(dcc));
|
||||
else
|
||||
dcc_get_passive(DCC_GET(dcc));
|
||||
}
|
||||
}
|
||||
|
||||
/* Resume a DCC GET */
|
||||
@ -128,7 +146,7 @@ static void dcc_send_resume(GET_DCC_REC *dcc)
|
||||
off_t pos;
|
||||
char *str;
|
||||
|
||||
g_return_if_fail(dcc != NULL);
|
||||
g_return_if_fail(dcc != NULL);
|
||||
|
||||
dcc->file = dcc_get_download_path(dcc->arg);
|
||||
dcc->fhandle = open(dcc->file, O_WRONLY);
|
||||
@ -149,10 +167,17 @@ static void dcc_send_resume(GET_DCC_REC *dcc)
|
||||
dcc->starttime = time(NULL);
|
||||
dcc_reject(DCC(dcc), NULL);
|
||||
} else {
|
||||
str = g_strdup_printf(dcc->file_quoted ?
|
||||
"DCC RESUME \"%s\" %d %"PRIuUOFF_T :
|
||||
"DCC RESUME %s %d %"PRIuUOFF_T,
|
||||
dcc->arg, dcc->port, dcc->transfd);
|
||||
if (!dcc_is_passive(dcc)) {
|
||||
str = g_strdup_printf(dcc->file_quoted ?
|
||||
"DCC RESUME \"%s\" %d %"PRIuUOFF_T :
|
||||
"DCC RESUME %s %d %"PRIuUOFF_T,
|
||||
dcc->arg, dcc->port, dcc->transfd);
|
||||
} else {
|
||||
str = g_strdup_printf(dcc->file_quoted ?
|
||||
"DCC RESUME \"%s\" 0 %"PRIuUOFF_T" %d" :
|
||||
"DCC RESUME %s 0 %"PRIuUOFF_T" %d",
|
||||
dcc->arg, dcc->transfd, dcc->pasv_id);
|
||||
}
|
||||
dcc_ctcp_message(dcc->server, dcc->nick,
|
||||
dcc->chat, FALSE, str);
|
||||
g_free(str);
|
||||
@ -162,7 +187,7 @@ static void dcc_send_resume(GET_DCC_REC *dcc)
|
||||
/* SYNTAX: DCC RESUME [<nick> [<file>]] */
|
||||
static void cmd_dcc_resume(const char *data)
|
||||
{
|
||||
cmd_dcc_receive(data, dcc_send_resume);
|
||||
cmd_dcc_receive(data, dcc_send_resume, dcc_send_resume);
|
||||
}
|
||||
|
||||
void dcc_resume_init(void)
|
||||
|
@ -39,7 +39,8 @@
|
||||
#endif
|
||||
|
||||
static int dcc_send_one_file(int queue, const char *target, const char *fname,
|
||||
IRC_SERVER_REC *server, CHAT_DCC_REC *chat);
|
||||
IRC_SERVER_REC *server, CHAT_DCC_REC *chat,
|
||||
int passive);
|
||||
|
||||
static void dcc_queue_send_next(int queue)
|
||||
{
|
||||
@ -58,7 +59,8 @@ static void dcc_queue_send_next(int queue)
|
||||
} else {
|
||||
send_started = dcc_send_one_file(queue, qrec->nick,
|
||||
qrec->file, server,
|
||||
qrec->chat);
|
||||
qrec->chat,
|
||||
qrec->passive);
|
||||
}
|
||||
dcc_queue_remove_head(queue);
|
||||
}
|
||||
@ -70,7 +72,8 @@ static void dcc_queue_send_next(int queue)
|
||||
}
|
||||
|
||||
static void dcc_send_add(const char *servertag, CHAT_DCC_REC *chat,
|
||||
const char *nick, char *fileargs, int add_mode)
|
||||
const char *nick, char *fileargs, int add_mode,
|
||||
int passive)
|
||||
{
|
||||
struct stat st;
|
||||
glob_t globbuf;
|
||||
@ -127,8 +130,12 @@ static void dcc_send_add(const char *servertag, CHAT_DCC_REC *chat,
|
||||
}
|
||||
}
|
||||
|
||||
dcc_queue_add(queue, add_mode, nick,
|
||||
fname, servertag, chat);
|
||||
if (!passive)
|
||||
dcc_queue_add(queue, add_mode, nick,
|
||||
fname, servertag, chat);
|
||||
else
|
||||
dcc_queue_add_passive(queue, add_mode, nick,
|
||||
fname, servertag, chat);
|
||||
files++;
|
||||
}
|
||||
|
||||
@ -138,7 +145,7 @@ static void dcc_send_add(const char *servertag, CHAT_DCC_REC *chat,
|
||||
globfree(&globbuf);
|
||||
}
|
||||
|
||||
/* DCC SEND [-append | -prepend | -flush | -rmtail | -rmhead]
|
||||
/* DCC SEND [-append | -prepend | -flush | -rmtail | -rmhead | -passive]
|
||||
<nick> <file> [<file> ...] */
|
||||
static void cmd_dcc_send(const char *data, IRC_SERVER_REC *server,
|
||||
WI_ITEM_REC *item)
|
||||
@ -148,7 +155,7 @@ static void cmd_dcc_send(const char *data, IRC_SERVER_REC *server,
|
||||
void *free_arg;
|
||||
CHAT_DCC_REC *chat;
|
||||
GHashTable *optlist;
|
||||
int queue, mode;
|
||||
int queue, mode, passive;
|
||||
|
||||
if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
|
||||
PARAM_FLAG_GETREST, "dcc send",
|
||||
@ -168,6 +175,8 @@ static void cmd_dcc_send(const char *data, IRC_SERVER_REC *server,
|
||||
if (servertag == NULL && chat == NULL)
|
||||
cmd_param_error(CMDERR_NOT_CONNECTED);
|
||||
|
||||
passive = g_hash_table_lookup(optlist, "passive") != NULL;
|
||||
|
||||
if (g_hash_table_lookup(optlist, "rmhead") != NULL) {
|
||||
queue = dcc_queue_old(nick, servertag);
|
||||
if (queue != -1)
|
||||
@ -190,8 +199,8 @@ static void cmd_dcc_send(const char *data, IRC_SERVER_REC *server,
|
||||
|
||||
if (*fileargs == '\0')
|
||||
cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
dcc_send_add(servertag, chat, nick, fileargs, mode);
|
||||
|
||||
dcc_send_add(servertag, chat, nick, fileargs, mode, passive);
|
||||
}
|
||||
|
||||
cmd_params_free(free_arg);
|
||||
@ -310,6 +319,28 @@ static void dcc_send_connected(SEND_DCC_REC *dcc)
|
||||
signal_emit("dcc connected", 1, dcc);
|
||||
}
|
||||
|
||||
/* input function: DCC SEND - connect to the receiver (passive protocol) */
|
||||
static void dcc_send_connect(SEND_DCC_REC *dcc)
|
||||
{
|
||||
dcc->handle = dcc_connect_ip(&dcc->addr, dcc->port);
|
||||
|
||||
if (dcc->handle != NULL) {
|
||||
dcc->starttime = time(NULL);
|
||||
|
||||
dcc->tagread = g_input_add(dcc->handle, G_INPUT_READ,
|
||||
(GInputFunction) dcc_send_read_size,
|
||||
dcc);
|
||||
dcc->tagwrite = g_input_add(dcc->handle, G_INPUT_WRITE,
|
||||
(GInputFunction) dcc_send_data,
|
||||
dcc);
|
||||
signal_emit("dcc connected", 1, dcc);
|
||||
} else {
|
||||
/* error connecting */
|
||||
signal_emit("dcc error connect", 1, dcc);
|
||||
dcc_destroy(DCC(dcc));
|
||||
}
|
||||
}
|
||||
|
||||
static char *dcc_send_get_file(const char *fname)
|
||||
{
|
||||
char *str, *path;
|
||||
@ -329,22 +360,23 @@ static char *dcc_send_get_file(const char *fname)
|
||||
}
|
||||
|
||||
static int dcc_send_one_file(int queue, const char *target, const char *fname,
|
||||
IRC_SERVER_REC *server, CHAT_DCC_REC *chat)
|
||||
IRC_SERVER_REC *server, CHAT_DCC_REC *chat,
|
||||
int passive)
|
||||
{
|
||||
struct stat st;
|
||||
char *str;
|
||||
char host[MAX_IP_LEN];
|
||||
int hfile, port;
|
||||
int hfile, port = 0;
|
||||
SEND_DCC_REC *dcc;
|
||||
IPADDR own_ip;
|
||||
GIOChannel *handle;
|
||||
GIOChannel *handle;
|
||||
|
||||
if (dcc_find_request(DCC_SEND_TYPE, target, fname)) {
|
||||
signal_emit("dcc error send exists", 2, target, fname);
|
||||
signal_emit("dcc error send exists", 2, target, fname);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
str = dcc_send_get_file(fname);
|
||||
str = dcc_send_get_file(fname);
|
||||
hfile = open(str, O_RDONLY);
|
||||
g_free(str);
|
||||
|
||||
@ -360,14 +392,19 @@ static int dcc_send_one_file(int queue, const char *target, const char *fname,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* start listening */
|
||||
handle = dcc_listen(chat != NULL ? chat->handle :
|
||||
net_sendbuffer_handle(server->handle),
|
||||
&own_ip, &port);
|
||||
if (handle == NULL) {
|
||||
close(hfile);
|
||||
g_warning("dcc_listen() failed: %s", strerror(errno));
|
||||
return FALSE;
|
||||
/* start listening (only if passive == FALSE )*/
|
||||
|
||||
if (passive == FALSE) {
|
||||
handle = dcc_listen(chat != NULL ? chat->handle :
|
||||
net_sendbuffer_handle(server->handle),
|
||||
&own_ip, &port);
|
||||
if (handle == NULL) {
|
||||
close(hfile);
|
||||
g_warning("dcc_listen() failed: %s", strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
handle = NULL;
|
||||
}
|
||||
|
||||
fname = g_basename(fname);
|
||||
@ -391,20 +428,37 @@ static int dcc_send_one_file(int queue, const char *target, const char *fname,
|
||||
dcc->fhandle = hfile;
|
||||
dcc->queue = queue;
|
||||
dcc->file_quoted = strchr(fname, ' ') != NULL;
|
||||
dcc->tagconn = g_input_add(handle, G_INPUT_READ,
|
||||
(GInputFunction) dcc_send_connected, dcc);
|
||||
if (!passive) {
|
||||
dcc->tagconn = g_input_add(handle, G_INPUT_READ,
|
||||
(GInputFunction) dcc_send_connected,
|
||||
dcc);
|
||||
}
|
||||
|
||||
/* Generate an ID for this send if using passive protocol */
|
||||
if (passive) {
|
||||
srand(time(NULL));
|
||||
dcc->pasv_id = rand() % 64;
|
||||
}
|
||||
|
||||
/* send DCC request */
|
||||
signal_emit("dcc request send", 1, dcc);
|
||||
|
||||
|
||||
dcc_ip2str(&own_ip, host);
|
||||
str = g_strdup_printf(dcc->file_quoted ?
|
||||
"DCC SEND \"%s\" %s %d %"PRIuUOFF_T :
|
||||
"DCC SEND %s %s %d %"PRIuUOFF_T,
|
||||
dcc->arg, host, port, dcc->size);
|
||||
if (passive == FALSE) {
|
||||
str = g_strdup_printf(dcc->file_quoted ?
|
||||
"DCC SEND \"%s\" %s %d %"PRIuUOFF_T :
|
||||
"DCC SEND %s %s %d %"PRIuUOFF_T,
|
||||
dcc->arg, host, port, dcc->size);
|
||||
} else {
|
||||
str = g_strdup_printf(dcc->file_quoted ?
|
||||
"DCC SEND \"%s\" 16974599 0 %"PRIuUOFF_T" %d" :
|
||||
"DCC SEND %s 16974599 0 %"PRIuUOFF_T" %d",
|
||||
dcc->arg, dcc->size, dcc->pasv_id);
|
||||
}
|
||||
dcc_ctcp_message(server, target, chat, FALSE, str);
|
||||
g_free(str);
|
||||
|
||||
g_free(str);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -414,8 +468,9 @@ void dcc_send_init(void)
|
||||
settings_add_str("dcc", "dcc_upload_path", "~");
|
||||
settings_add_bool("dcc", "dcc_send_replace_space_with_underscore", FALSE);
|
||||
signal_add("dcc destroyed", (SIGNAL_FUNC) sig_dcc_destroyed);
|
||||
signal_add("dcc reply send pasv", (SIGNAL_FUNC) dcc_send_connect);
|
||||
command_bind("dcc send", NULL, (SIGNAL_FUNC) cmd_dcc_send);
|
||||
command_set_options("dcc send", "append flush prepend rmhead rmtail");
|
||||
command_set_options("dcc send", "append flush prepend rmhead rmtail passive");
|
||||
|
||||
dcc_queue_init();
|
||||
}
|
||||
@ -426,5 +481,6 @@ void dcc_send_deinit(void)
|
||||
|
||||
dcc_unregister_type("SEND");
|
||||
signal_remove("dcc destroyed", (SIGNAL_FUNC) sig_dcc_destroyed);
|
||||
signal_remove("dcc reply send pasv", (SIGNAL_FUNC) dcc_send_connect);
|
||||
command_unbind("dcc send", (SIGNAL_FUNC) cmd_dcc_send);
|
||||
}
|
||||
|
@ -92,7 +92,9 @@ void dcc_init_rec(DCC_REC *dcc, IRC_SERVER_REC *server, CHAT_DCC_REC *chat,
|
||||
|
||||
dcc->servertag = server != NULL ? g_strdup(server->tag) :
|
||||
(chat == NULL ? NULL : g_strdup(chat->servertag));
|
||||
|
||||
|
||||
dcc->pasv_id = -1; /* Not a passive DCC */
|
||||
|
||||
dcc_conns = g_slist_append(dcc_conns, dcc);
|
||||
signal_emit("dcc created", 1, dcc);
|
||||
}
|
||||
|
@ -24,6 +24,10 @@ typedef struct {
|
||||
#define dcc_is_waiting_user(dcc) \
|
||||
((dcc)->handle == NULL)
|
||||
|
||||
/* passive DCC */
|
||||
#define dcc_is_passive(dcc) \
|
||||
((dcc)->pasv_id >= 0)
|
||||
|
||||
extern GSList *dcc_conns;
|
||||
|
||||
void dcc_register_type(const char *type);
|
||||
|
Loading…
Reference in New Issue
Block a user