1
0
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:
Timo Sirainen 2004-03-23 22:06:41 +00:00 committed by cras
parent 2a12dfb9d0
commit af4bcb70f2
11 changed files with 424 additions and 108 deletions

View File

@ -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 -

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);