summaryrefslogtreecommitdiff
path: root/src/irc
diff options
context:
space:
mode:
Diffstat (limited to 'src/irc')
-rw-r--r--src/irc/dcc/dcc-chat.c157
-rw-r--r--src/irc/dcc/dcc-get.c135
-rw-r--r--src/irc/dcc/dcc-get.h4
-rw-r--r--src/irc/dcc/dcc-queue.c25
-rw-r--r--src/irc/dcc/dcc-queue.h4
-rw-r--r--src/irc/dcc/dcc-rec.h2
-rw-r--r--src/irc/dcc/dcc-resume.c65
-rw-r--r--src/irc/dcc/dcc-send.c116
-rw-r--r--src/irc/dcc/dcc.c4
-rw-r--r--src/irc/dcc/dcc.h4
10 files changed, 415 insertions, 101 deletions
diff --git a/src/irc/dcc/dcc-chat.c b/src/irc/dcc/dcc-chat.c
index 3d97ae0c..c1eeafca 100644
--- a/src/irc/dcc/dcc-chat.c
+++ b/src/irc/dcc/dcc-chat.c
@@ -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);
diff --git a/src/irc/dcc/dcc-get.c b/src/irc/dcc/dcc-get.c
index aa0c6390..e99d3cf6 100644
--- a/src/irc/dcc/dcc-get.c
+++ b/src/irc/dcc/dcc-get.c
@@ -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));
+ }
- 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));
+ /* 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)
+ 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)
diff --git a/src/irc/dcc/dcc-get.h b/src/irc/dcc/dcc-get.h
index 321a8b4e..7ac7b3c1 100644
--- a/src/irc/dcc/dcc-get.h
+++ b/src/irc/dcc/dcc-get.h
@@ -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);
diff --git a/src/irc/dcc/dcc-queue.c b/src/irc/dcc/dcc-queue.c
index 677bc07b..9f982ed9 100644
--- a/src/irc/dcc/dcc-queue.c
+++ b/src/irc/dcc/dcc-queue.c
@@ -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)
diff --git a/src/irc/dcc/dcc-queue.h b/src/irc/dcc/dcc-queue.h
index 85bd2083..d13fae66 100644
--- a/src/irc/dcc/dcc-queue.h
+++ b/src/irc/dcc/dcc-queue.h
@@ -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);
diff --git a/src/irc/dcc/dcc-rec.h b/src/irc/dcc/dcc-rec.h
index 9fdd9582..afb029d3 100644
--- a/src/irc/dcc/dcc-rec.h
+++ b/src/irc/dcc/dcc-rec.h
@@ -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;
diff --git a/src/irc/dcc/dcc-resume.c b/src/irc/dcc/dcc-resume.c
index 3cae3fa5..19167ee3 100644
--- a/src/irc/dcc/dcc-resume.c
+++ b/src/irc/dcc/dcc-resume.c
@@ -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)
diff --git a/src/irc/dcc/dcc-send.c b/src/irc/dcc/dcc-send.c
index 93a85fa1..cb90fca8 100644
--- a/src/irc/dcc/dcc-send.c
+++ b/src/irc/dcc/dcc-send.c
@@ -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);
}
diff --git a/src/irc/dcc/dcc.c b/src/irc/dcc/dcc.c
index b66db5f1..ddf31b4f 100644
--- a/src/irc/dcc/dcc.c
+++ b/src/irc/dcc/dcc.c
@@ -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);
}
diff --git a/src/irc/dcc/dcc.h b/src/irc/dcc/dcc.h
index 5a4c9e23..10639207 100644
--- a/src/irc/dcc/dcc.h
+++ b/src/irc/dcc/dcc.h
@@ -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);