1
0
mirror of https://github.com/irssi/irssi.git synced 2024-11-03 04:27:19 -05:00

DCC send supports now queueing. Patch by Heikki Orsila <heikki@ee.tut.fi>,

although I did pretty heavy changes which hopefully didn't break it too
badly :)

New syntax: DCC SEND [-append | -prepend | flush | -rmtail | -rmhead] <nick>
-<file> [<file> ...]


git-svn-id: http://svn.irssi.org/repos/irssi/trunk@2994 dbcabf3a-b0e7-0310-adc4-f8d773084564
This commit is contained in:
Timo Sirainen 2002-11-11 06:35:12 +00:00 committed by cras
parent cd3ff41f3e
commit 488e7b70f4
9 changed files with 225 additions and 45 deletions

View File

@ -15,9 +15,12 @@ files.
/DCC GET [<nick> [<file>]] /DCC GET [<nick> [<file>]]
- Gets the file offered by remote client. The file is downloaded and - Gets the file offered by remote client. The file is downloaded and
saved into the current working directory. saved into the current working directory.
/DCC SEND <nick> <file> /DCC SEND [-append | -prepend | -flush | -rmtail | -rmhead]
<nick> <file> [<file> ...]
- Sends a DCC SEND request to remote client. Remote end has to accept - Sends a DCC SEND request to remote client. Remote end has to accept
the request before the transmission can be started. 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)
/DCC CLOSE <type> <nick> [<file>] /DCC CLOSE <type> <nick> [<file>]
- Closes a DCC-connection. Type can be either SEND, GET or CHAT. - Closes a DCC-connection. Type can be either SEND, GET or CHAT.

View File

@ -483,7 +483,7 @@ char *cmd_get_param(char **data)
return pos; return pos;
} }
static char *cmd_get_quoted_param(char **data) char *cmd_get_quoted_param(char **data)
{ {
char *pos, quote; char *pos, quote;

View File

@ -150,6 +150,7 @@ int command_have_option(const char *cmd, const char *option);
#define PARAM_FLAG_OPTCHAN_NAME (0x00020000|PARAM_FLAG_OPTCHAN) #define PARAM_FLAG_OPTCHAN_NAME (0x00020000|PARAM_FLAG_OPTCHAN)
char *cmd_get_param(char **data); char *cmd_get_param(char **data);
char *cmd_get_quoted_param(char **data);
/* get parameters from command - you should point free_me somewhere and /* get parameters from command - you should point free_me somewhere and
cmd_params_free() it after you don't use any of the parameters anymore. cmd_params_free() it after you don't use any of the parameters anymore.

View File

@ -26,6 +26,7 @@
#include "dcc-file.h" #include "dcc-file.h"
#include "dcc-send.h" #include "dcc-send.h"
#include "dcc-queue.h"
#include "module-formats.h" #include "module-formats.h"
#include "printtext.h" #include "printtext.h"
@ -86,6 +87,12 @@ static void dcc_error_send_exists(const char *nick, const char *fname)
IRCTXT_DCC_SEND_EXISTS, fname, nick); IRCTXT_DCC_SEND_EXISTS, fname, nick);
} }
static void dcc_error_send_no_route(const char *nick, const char *fname)
{
printformat(NULL, NULL, MSGLEVEL_DCC,
IRCTXT_DCC_SEND_NO_ROUTE, nick, fname);
}
static void dcc_error_close_not_found(const char *type, const char *nick, static void dcc_error_close_not_found(const char *type, const char *nick,
const char *fname) const char *fname)
{ {
@ -129,8 +136,22 @@ static void sig_dcc_send_complete(GList **list, WINDOW_REC *window,
static void sig_dcc_list_print(SEND_DCC_REC *dcc) static void sig_dcc_list_print(SEND_DCC_REC *dcc)
{ {
if (IS_DCC_SEND(dcc)) GSList *queue;
if (!IS_DCC_SEND(dcc))
return;
dcc_list_print_file((FILE_DCC_REC *) dcc); dcc_list_print_file((FILE_DCC_REC *) dcc);
queue = dcc_queue_get_queue(dcc->queue);
for (; queue != NULL; queue = queue->next) {
DCC_QUEUE_REC *rec = queue->data;
printformat(NULL, NULL, MSGLEVEL_DCC,
IRCTXT_DCC_LIST_LINE_QUEUED_SEND, rec->nick,
rec->servertag == NULL ? "" : rec->servertag,
rec->file);
}
} }
void fe_dcc_send_init(void) void fe_dcc_send_init(void)
@ -139,6 +160,7 @@ void fe_dcc_send_init(void)
signal_add("dcc closed", (SIGNAL_FUNC) dcc_closed); signal_add("dcc closed", (SIGNAL_FUNC) dcc_closed);
signal_add("dcc error file open", (SIGNAL_FUNC) dcc_error_file_open); signal_add("dcc error file open", (SIGNAL_FUNC) dcc_error_file_open);
signal_add("dcc error send exists", (SIGNAL_FUNC) dcc_error_send_exists); signal_add("dcc error send exists", (SIGNAL_FUNC) dcc_error_send_exists);
signal_add("dcc error send no route", (SIGNAL_FUNC) dcc_error_send_no_route);
signal_add("dcc error close not found", (SIGNAL_FUNC) dcc_error_close_not_found); signal_add("dcc error close not found", (SIGNAL_FUNC) dcc_error_close_not_found);
signal_add("complete command dcc send", (SIGNAL_FUNC) sig_dcc_send_complete); signal_add("complete command dcc send", (SIGNAL_FUNC) sig_dcc_send_complete);
signal_add("dcc list print", (SIGNAL_FUNC) sig_dcc_list_print); signal_add("dcc list print", (SIGNAL_FUNC) sig_dcc_list_print);
@ -150,6 +172,7 @@ void fe_dcc_send_deinit(void)
signal_remove("dcc closed", (SIGNAL_FUNC) dcc_closed); signal_remove("dcc closed", (SIGNAL_FUNC) dcc_closed);
signal_remove("dcc error file open", (SIGNAL_FUNC) dcc_error_file_open); signal_remove("dcc error file open", (SIGNAL_FUNC) dcc_error_file_open);
signal_remove("dcc error send exists", (SIGNAL_FUNC) dcc_error_send_exists); signal_remove("dcc error send exists", (SIGNAL_FUNC) dcc_error_send_exists);
signal_remove("dcc error send no route", (SIGNAL_FUNC) dcc_error_send_no_route);
signal_remove("dcc error close not found", (SIGNAL_FUNC) dcc_error_close_not_found); signal_remove("dcc error close not found", (SIGNAL_FUNC) dcc_error_close_not_found);
signal_remove("complete command dcc send", (SIGNAL_FUNC) sig_dcc_send_complete); signal_remove("complete command dcc send", (SIGNAL_FUNC) sig_dcc_send_complete);
signal_remove("dcc list print", (SIGNAL_FUNC) sig_dcc_list_print); signal_remove("dcc list print", (SIGNAL_FUNC) sig_dcc_list_print);

View File

@ -45,6 +45,7 @@ FORMAT_REC fecommon_irc_dcc_formats[] = {
{ "dcc_send", "{dcc DCC SEND from {nick $0} [$1 port $2]: $3 [$4 bytes]}", 5, { 0, 0, 1, 0, 2 } }, { "dcc_send", "{dcc DCC SEND from {nick $0} [$1 port $2]: $3 [$4 bytes]}", 5, { 0, 0, 1, 0, 2 } },
{ "dcc_send_channel", "{dcc DCC SEND from {nick $0} [$1 port $2]: $3 [$4 bytes] requested in channel {channel $5}}", 6, { 0, 0, 1, 0, 2, 0 } }, { "dcc_send_channel", "{dcc DCC SEND from {nick $0} [$1 port $2]: $3 [$4 bytes] requested in channel {channel $5}}", 6, { 0, 0, 1, 0, 2, 0 } },
{ "dcc_send_exists", "{dcc DCC already sending file {dccfile $0} for {nick $1}}", 2, { 0, 0 } }, { "dcc_send_exists", "{dcc DCC already sending file {dccfile $0} for {nick $1}}", 2, { 0, 0 } },
{ "dcc_send_no_route", "{dcc DCC route lost to nick {nick $0} when trying to send file {dccfile $1}}", 2, { 0, 0 } },
{ "dcc_send_not_found", "{dcc DCC not sending file {dccfile $1} to {nick $0}}", 2, { 0, 0 } }, { "dcc_send_not_found", "{dcc DCC not sending file {dccfile $1} to {nick $0}}", 2, { 0, 0 } },
{ "dcc_send_file_open_error", "{dcc DCC can't open file {dccfile $0}: $1}", 2, { 0, 0 } }, { "dcc_send_file_open_error", "{dcc DCC can't open file {dccfile $0}: $1}", 2, { 0, 0 } },
{ "dcc_send_connected", "{dcc DCC sending file {dccfile $0} for {nick $1} [$2 port $3]}", 4, { 0, 0, 0, 1 } }, { "dcc_send_connected", "{dcc DCC sending file {dccfile $0} for {nick $1} [$2 port $3]}", 4, { 0, 0, 0, 1 } },
@ -68,6 +69,7 @@ FORMAT_REC fecommon_irc_dcc_formats[] = {
{ "dcc_list_header", "{dcc DCC connections}", 0 }, { "dcc_list_header", "{dcc DCC connections}", 0 },
{ "dcc_list_line_chat", "{dcc $0 $1}", 2, { 0, 0 } }, { "dcc_list_line_chat", "{dcc $0 $1}", 2, { 0, 0 } },
{ "dcc_list_line_file", "{dcc $0 $1: $2k of $3k ($4%%) - $5kB/s - $6}", 7, { 0, 0, 2, 2, 1, 3, 0 } }, { "dcc_list_line_file", "{dcc $0 $1: $2k of $3k ($4%%) - $5kB/s - $6}", 7, { 0, 0, 2, 2, 1, 3, 0 } },
{ "dcc_list_line_queued_send", "{dcc - $0 $2 (queued)}", 3, { 0, 0, 0 } },
{ "dcc_list_footer", "", 0 }, { "dcc_list_footer", "", 0 },
{ NULL, NULL, 0 } { NULL, NULL, 0 }

View File

@ -23,6 +23,7 @@ enum {
IRCTXT_DCC_SEND, IRCTXT_DCC_SEND,
IRCTXT_DCC_SEND_CHANNEL, IRCTXT_DCC_SEND_CHANNEL,
IRCTXT_DCC_SEND_EXISTS, IRCTXT_DCC_SEND_EXISTS,
IRCTXT_DCC_SEND_NO_ROUTE,
IRCTXT_DCC_SEND_NOT_FOUND, IRCTXT_DCC_SEND_NOT_FOUND,
IRCTXT_DCC_SEND_FILE_OPEN_ERROR, IRCTXT_DCC_SEND_FILE_OPEN_ERROR,
IRCTXT_DCC_SEND_CONNECTED, IRCTXT_DCC_SEND_CONNECTED,
@ -46,6 +47,7 @@ enum {
IRCTXT_DCC_LIST_HEADER, IRCTXT_DCC_LIST_HEADER,
IRCTXT_DCC_LIST_LINE_CHAT, IRCTXT_DCC_LIST_LINE_CHAT,
IRCTXT_DCC_LIST_LINE_FILE, IRCTXT_DCC_LIST_LINE_FILE,
IRCTXT_DCC_LIST_LINE_QUEUED_SEND,
IRCTXT_DCC_LIST_FOOTER IRCTXT_DCC_LIST_FOOTER
}; };

View File

@ -12,7 +12,8 @@ libirc_dcc_a_SOURCES = \
dcc-get.c \ dcc-get.c \
dcc-send.c \ dcc-send.c \
dcc-resume.c \ dcc-resume.c \
dcc-autoget.c dcc-autoget.c \
dcc-queue.c
noinst_HEADERS = \ noinst_HEADERS = \
dcc-rec.h \ dcc-rec.h \
@ -22,4 +23,5 @@ noinst_HEADERS = \
dcc-chat.h \ dcc-chat.h \
dcc-get.h \ dcc-get.h \
dcc-send.h \ dcc-send.h \
dcc-queue.h \
module.h module.h

View File

@ -2,6 +2,7 @@
unsigned long size, skipped; /* file size / skipped at start */ unsigned long size, skipped; /* file size / skipped at start */
int fhandle; /* file handle */ int fhandle; /* file handle */
int queue; /* queue number */
/* counter buffer */ /* counter buffer */
char count_buf[4]; char count_buf[4];

View File

@ -18,6 +18,11 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <glob.h>
#include "module.h" #include "module.h"
#include "signals.h" #include "signals.h"
#include "commands.h" #include "commands.h"
@ -30,6 +35,155 @@
#include "dcc-send.h" #include "dcc-send.h"
#include "dcc-chat.h" #include "dcc-chat.h"
#include "dcc-queue.h"
#ifndef GLOB_TILDE
# define GLOBL_TILDE 0
#endif
static int dcc_send_one_file(int queue, const char *target, const char *fname,
IRC_SERVER_REC *server, CHAT_DCC_REC *chat);
static void dcc_queue_send_next(int queue)
{
IRC_SERVER_REC *server;
DCC_QUEUE_REC *qrec;
int send_started = FALSE;
while ((qrec = dcc_queue_get_next(queue)) != NULL && !send_started) {
server = qrec->servertag == NULL ? NULL :
IRC_SERVER(server_find_tag(qrec->servertag));
if (server == NULL && qrec->chat == NULL) {
/* no way to send this request */
signal_emit("dcc error send no route", 2,
qrec->nick, qrec->file);
} else {
send_started = dcc_send_one_file(queue, qrec->nick,
qrec->file, server,
qrec->chat);
}
dcc_queue_remove_head(queue);
}
if (!send_started) {
/* no files in queue anymore, remove it */
dcc_queue_free(queue);
}
}
static void dcc_send_add(const char *servertag, CHAT_DCC_REC *chat,
const char *nick, char *fileargs, int add_mode)
{
struct stat st;
glob_t globbuf;
char *fname;
int i, files, flags, queue, start_new_transfer;
globbuf.gl_offs = 0;
flags = GLOB_NOCHECK | GLOB_TILDE;
/* this loop parses all <file> parameters and adds them to glubbuf */
for (;;) {
fname = cmd_get_quoted_param(&fileargs);
if (*fname == '\0')
break;
if (glob(fname, flags, 0, &globbuf) < 0)
break;
/* this flag must not be set before first call to glob!
(man glob) */
flags |= GLOB_APPEND;
}
files = 0; queue = -1; start_new_transfer = 0;
/* add all globbed files to a proper queue */
for (i = 0; i < globbuf.gl_pathc; i++) {
if (stat(globbuf.gl_pathv[i], &st) == 0 &&
S_ISREG(st.st_mode) && st.st_size > 0) {
if (queue < 0) {
/* in append and prepend mode try to find an
old queue. if an old queue is not found
create a new queue. if not in append or
prepend mode, create a new queue */
if (add_mode != DCC_QUEUE_NORMAL)
queue = dcc_queue_old(nick, servertag);
start_new_transfer = 0;
if (queue < 0) {
queue = dcc_queue_new();
start_new_transfer = 1;
}
}
dcc_queue_add(queue, add_mode, nick,
globbuf.gl_pathv[i], servertag, chat);
files++;
}
}
if (files > 0 && start_new_transfer)
dcc_queue_send_next(queue);
globfree(&globbuf);
}
/* DCC SEND [-append | -prepend | -flush | -rmtail | -rmhead]
<nick> <file> [<file> ...] */
static void cmd_dcc_send(const char *data, IRC_SERVER_REC *server,
WI_ITEM_REC *item)
{
const char *servertag;
char *nick, *fileargs;
void *free_arg;
CHAT_DCC_REC *chat;
GHashTable *optlist;
int queue, mode;
if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
PARAM_FLAG_GETREST, "dcc send",
&optlist, &nick, &fileargs))
return;
chat = item_get_dcc(item);
if (chat != NULL &&
(chat->mirc_ctcp || g_strcasecmp(nick, chat->nick) != 0))
chat = NULL;
if (!IS_IRC_SERVER(server) || !server->connected)
servertag = NULL;
else
servertag = server->tag;
if (servertag == NULL && chat == NULL)
cmd_param_error(CMDERR_NOT_CONNECTED);
if (g_hash_table_lookup(optlist, "rmhead") != NULL) {
queue = dcc_queue_old(nick, servertag);
dcc_queue_remove_head(queue);
} else if (g_hash_table_lookup(optlist, "rmtail") != NULL) {
queue = dcc_queue_old(nick, servertag);
dcc_queue_remove_tail(queue);
} else if (g_hash_table_lookup(optlist, "flush") != NULL) {
queue = dcc_queue_old(nick, servertag);
while (dcc_queue_remove_head(queue)) ;
} else {
if (g_hash_table_lookup(optlist, "append") != NULL)
mode = DCC_QUEUE_APPEND;
else if (g_hash_table_lookup(optlist, "prepend") != NULL)
mode = DCC_QUEUE_PREPEND;
else
mode = DCC_QUEUE_NORMAL;
if (*fileargs == '\0')
cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
dcc_send_add(servertag, chat, nick, fileargs, mode);
}
cmd_params_free(free_arg);
}
static SEND_DCC_REC *dcc_send_create(IRC_SERVER_REC *server, static SEND_DCC_REC *dcc_send_create(IRC_SERVER_REC *server,
CHAT_DCC_REC *chat, CHAT_DCC_REC *chat,
@ -41,6 +195,7 @@ static SEND_DCC_REC *dcc_send_create(IRC_SERVER_REC *server,
dcc->orig_type = module_get_uniq_id_str("DCC", "GET"); dcc->orig_type = module_get_uniq_id_str("DCC", "GET");
dcc->type = module_get_uniq_id_str("DCC", "SEND"); dcc->type = module_get_uniq_id_str("DCC", "SEND");
dcc->fhandle = -1; dcc->fhandle = -1;
dcc->queue = -1;
dcc_init_rec(DCC(dcc), server, chat, nick, arg); dcc_init_rec(DCC(dcc), server, chat, nick, arg);
return dcc; return dcc;
@ -50,7 +205,10 @@ static void sig_dcc_destroyed(SEND_DCC_REC *dcc)
{ {
if (!IS_DCC_SEND(dcc)) return; if (!IS_DCC_SEND(dcc)) return;
if (dcc->fhandle != -1) close(dcc->fhandle); if (dcc->fhandle != -1)
close(dcc->fhandle);
dcc_queue_send_next(dcc->queue);
} }
/* input function: DCC SEND - we're ready to send more data */ /* input function: DCC SEND - we're ready to send more data */
@ -161,45 +319,20 @@ static char *dcc_send_get_file(const char *fname)
return str; return str;
} }
/* SYNTAX: DCC SEND <nick> <file> */ static int dcc_send_one_file(int queue, const char *target, const char *fname,
static void cmd_dcc_send(const char *data, IRC_SERVER_REC *server, IRC_SERVER_REC *server, CHAT_DCC_REC *chat)
WI_ITEM_REC *item)
{ {
char *target, *str, *fname; char *str;
void *free_arg;
char host[MAX_IP_LEN]; char host[MAX_IP_LEN];
int hfile, port; int hfile, port;
long fsize; long fsize;
SEND_DCC_REC *dcc; SEND_DCC_REC *dcc;
CHAT_DCC_REC *chat;
IPADDR own_ip; IPADDR own_ip;
GIOChannel *handle; GIOChannel *handle;
g_return_if_fail(data != NULL);
if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST,
&target, &fname))
return;
if (*target == '\0' || *fname == '\0')
cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
/* if we're in dcc chat, send the request via it. */
chat = item_get_dcc(item);
if (chat != NULL && (chat->mirc_ctcp ||
g_strcasecmp(target, chat->nick) != 0))
chat = NULL;
if (!IS_IRC_SERVER(server))
server = NULL;
if ((server == NULL || !server->connected) && chat == NULL)
cmd_param_error(CMDERR_NOT_CONNECTED);
if (dcc_find_request(DCC_SEND_TYPE, target, fname)) { 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);
cmd_params_free(free_arg); return FALSE;
return;
} }
str = dcc_send_get_file(fname); str = dcc_send_get_file(fname);
@ -209,8 +342,7 @@ static void cmd_dcc_send(const char *data, IRC_SERVER_REC *server,
if (hfile == -1) { if (hfile == -1) {
signal_emit("dcc error file open", 3, target, fname, signal_emit("dcc error file open", 3, target, fname,
GINT_TO_POINTER(errno)); GINT_TO_POINTER(errno));
cmd_params_free(free_arg); return FALSE;
return;
} }
fsize = lseek(hfile, 0, SEEK_END); fsize = lseek(hfile, 0, SEEK_END);
lseek(hfile, 0, SEEK_SET); lseek(hfile, 0, SEEK_SET);
@ -221,21 +353,30 @@ static void cmd_dcc_send(const char *data, IRC_SERVER_REC *server,
&own_ip, &port); &own_ip, &port);
if (handle == NULL) { if (handle == NULL) {
close(hfile); close(hfile);
cmd_param_error(CMDERR_ERRNO); g_warning("dcc_listen() failed: %s", strerror(errno));
return FALSE;
} }
fname = (char *) g_basename(fname); fname = g_basename(fname);
/* Replace all the spaces with underscore so that lesser /* Replace all the spaces with underscore so that lesser
intellgent clients can communicate.. */ intellgent clients can communicate.. */
if (settings_get_bool("dcc_send_replace_space_with_underscore")) if (!settings_get_bool("dcc_send_replace_space_with_underscore"))
g_strdelimit(fname, " ", '_'); str = NULL;
else {
str = g_strdup(fname);
g_strdelimit(str, " ", '_');
fname = str;
}
dcc = dcc_send_create(server, chat, target, fname); dcc = dcc_send_create(server, chat, target, fname);
g_free(str);
dcc->handle = handle; dcc->handle = handle;
dcc->port = port; dcc->port = port;
dcc->size = fsize; dcc->size = fsize;
dcc->fhandle = hfile; dcc->fhandle = hfile;
dcc->queue = queue;
dcc->file_quoted = strchr(fname, ' ') != NULL; dcc->file_quoted = strchr(fname, ' ') != NULL;
dcc->tagconn = g_input_add(handle, G_INPUT_READ, dcc->tagconn = g_input_add(handle, G_INPUT_READ,
(GInputFunction) dcc_send_connected, dcc); (GInputFunction) dcc_send_connected, dcc);
@ -251,7 +392,7 @@ static void cmd_dcc_send(const char *data, IRC_SERVER_REC *server,
dcc_ctcp_message(server, target, chat, FALSE, str); dcc_ctcp_message(server, target, chat, FALSE, str);
g_free(str); g_free(str);
cmd_params_free(free_arg); return TRUE;
} }
void dcc_send_init(void) void dcc_send_init(void)
@ -261,10 +402,15 @@ void dcc_send_init(void)
settings_add_bool("dcc", "dcc_send_replace_space_with_underscore", FALSE); settings_add_bool("dcc", "dcc_send_replace_space_with_underscore", FALSE);
signal_add("dcc destroyed", (SIGNAL_FUNC) sig_dcc_destroyed); signal_add("dcc destroyed", (SIGNAL_FUNC) sig_dcc_destroyed);
command_bind("dcc send", NULL, (SIGNAL_FUNC) cmd_dcc_send); command_bind("dcc send", NULL, (SIGNAL_FUNC) cmd_dcc_send);
command_set_options("dcc send", "append flush prepend rmhead rmtail");
dcc_queue_init();
} }
void dcc_send_deinit(void) void dcc_send_deinit(void)
{ {
dcc_queue_deinit();
dcc_unregister_type("SEND"); dcc_unregister_type("SEND");
signal_remove("dcc destroyed", (SIGNAL_FUNC) sig_dcc_destroyed); signal_remove("dcc destroyed", (SIGNAL_FUNC) sig_dcc_destroyed);
command_unbind("dcc send", (SIGNAL_FUNC) cmd_dcc_send); command_unbind("dcc send", (SIGNAL_FUNC) cmd_dcc_send);