1
0
mirror of https://github.com/irssi/irssi.git synced 2024-06-23 06:35:36 +00: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>]]
- Gets the file offered by remote client. The file is downloaded and
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
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>]
- 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;
}
static char *cmd_get_quoted_param(char **data)
char *cmd_get_quoted_param(char **data)
{
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)
char *cmd_get_param(char **data);
char *cmd_get_quoted_param(char **data);
/* 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.

View File

@ -26,6 +26,7 @@
#include "dcc-file.h"
#include "dcc-send.h"
#include "dcc-queue.h"
#include "module-formats.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);
}
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,
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)
{
if (IS_DCC_SEND(dcc))
dcc_list_print_file((FILE_DCC_REC *) dcc);
GSList *queue;
if (!IS_DCC_SEND(dcc))
return;
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)
@ -139,6 +160,7 @@ void fe_dcc_send_init(void)
signal_add("dcc closed", (SIGNAL_FUNC) dcc_closed);
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 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("complete command dcc send", (SIGNAL_FUNC) sig_dcc_send_complete);
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 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 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("complete command dcc send", (SIGNAL_FUNC) sig_dcc_send_complete);
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_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_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_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 } },
@ -68,6 +69,7 @@ FORMAT_REC fecommon_irc_dcc_formats[] = {
{ "dcc_list_header", "{dcc DCC connections}", 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_queued_send", "{dcc - $0 $2 (queued)}", 3, { 0, 0, 0 } },
{ "dcc_list_footer", "", 0 },
{ NULL, NULL, 0 }

View File

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

View File

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

View File

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

View File

@ -18,6 +18,11 @@
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 "signals.h"
#include "commands.h"
@ -30,6 +35,155 @@
#include "dcc-send.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,
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->type = module_get_uniq_id_str("DCC", "SEND");
dcc->fhandle = -1;
dcc->queue = -1;
dcc_init_rec(DCC(dcc), server, chat, nick, arg);
return dcc;
@ -50,7 +205,10 @@ static void sig_dcc_destroyed(SEND_DCC_REC *dcc)
{
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 */
@ -161,45 +319,20 @@ static char *dcc_send_get_file(const char *fname)
return str;
}
/* SYNTAX: DCC SEND <nick> <file> */
static void cmd_dcc_send(const char *data, IRC_SERVER_REC *server,
WI_ITEM_REC *item)
static int dcc_send_one_file(int queue, const char *target, const char *fname,
IRC_SERVER_REC *server, CHAT_DCC_REC *chat)
{
char *target, *str, *fname;
void *free_arg;
char *str;
char host[MAX_IP_LEN];
int hfile, port;
long fsize;
SEND_DCC_REC *dcc;
CHAT_DCC_REC *chat;
IPADDR own_ip;
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)) {
signal_emit("dcc error send exists", 2, target, fname);
cmd_params_free(free_arg);
return;
signal_emit("dcc error send exists", 2, target, fname);
return FALSE;
}
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) {
signal_emit("dcc error file open", 3, target, fname,
GINT_TO_POINTER(errno));
cmd_params_free(free_arg);
return;
return FALSE;
}
fsize = lseek(hfile, 0, SEEK_END);
lseek(hfile, 0, SEEK_SET);
@ -221,21 +353,30 @@ static void cmd_dcc_send(const char *data, IRC_SERVER_REC *server,
&own_ip, &port);
if (handle == NULL) {
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
intellgent clients can communicate.. */
if (settings_get_bool("dcc_send_replace_space_with_underscore"))
g_strdelimit(fname, " ", '_');
if (!settings_get_bool("dcc_send_replace_space_with_underscore"))
str = NULL;
else {
str = g_strdup(fname);
g_strdelimit(str, " ", '_');
fname = str;
}
dcc = dcc_send_create(server, chat, target, fname);
dcc->handle = handle;
g_free(str);
dcc->handle = handle;
dcc->port = port;
dcc->size = fsize;
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);
@ -251,7 +392,7 @@ static void cmd_dcc_send(const char *data, IRC_SERVER_REC *server,
dcc_ctcp_message(server, target, chat, FALSE, str);
g_free(str);
cmd_params_free(free_arg);
return TRUE;
}
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);
signal_add("dcc destroyed", (SIGNAL_FUNC) sig_dcc_destroyed);
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)
{
dcc_queue_deinit();
dcc_unregister_type("SEND");
signal_remove("dcc destroyed", (SIGNAL_FUNC) sig_dcc_destroyed);
command_unbind("dcc send", (SIGNAL_FUNC) cmd_dcc_send);