diff options
-rw-r--r-- | src/core/commands.c | 4 | ||||
-rw-r--r-- | src/core/commands.h | 6 | ||||
-rw-r--r-- | src/fe-common/irc/dcc/fe-dcc.c | 471 | ||||
-rw-r--r-- | src/fe-common/irc/dcc/module-formats.c | 14 | ||||
-rw-r--r-- | src/fe-common/irc/dcc/module-formats.h | 8 | ||||
-rw-r--r-- | src/fe-common/irc/fe-irc-commands.c | 60 | ||||
-rw-r--r-- | src/irc/core/irc-commands.c | 6 | ||||
-rw-r--r-- | src/irc/core/irc.h | 3 | ||||
-rw-r--r-- | src/irc/core/query.c | 9 | ||||
-rw-r--r-- | src/irc/dcc/dcc-chat.c | 384 | ||||
-rw-r--r-- | src/irc/dcc/dcc-files.c | 926 | ||||
-rw-r--r-- | src/irc/dcc/dcc.c | 363 | ||||
-rw-r--r-- | src/irc/dcc/dcc.h | 102 |
13 files changed, 1191 insertions, 1165 deletions
diff --git a/src/core/commands.c b/src/core/commands.c index 10cf9123..1a05e7a3 100644 --- a/src/core/commands.c +++ b/src/core/commands.c @@ -39,7 +39,7 @@ char *current_command; static GSList *cmdget_funcs; static int signal_default_command; -void command_bind(const char *cmd, const char *category, SIGNAL_FUNC func) +void command_bind_to(int pos, const char *cmd, const char *category, SIGNAL_FUNC func) { COMMAND_REC *rec; char *str; @@ -53,7 +53,7 @@ void command_bind(const char *cmd, const char *category, SIGNAL_FUNC func) if (func != NULL) { str = g_strconcat("command ", cmd, NULL); - signal_add(str, func); + signal_add_to(MODULE_NAME, pos, str, func); g_free(str); } diff --git a/src/core/commands.h b/src/core/commands.h index 554a60e5..dcff89c2 100644 --- a/src/core/commands.h +++ b/src/core/commands.h @@ -25,7 +25,11 @@ enum { extern GSList *commands; extern char *current_command; -void command_bind(const char *cmd, const char *category, SIGNAL_FUNC func); +void command_bind_to(int pos, const char *cmd, const char *category, SIGNAL_FUNC func); +#define command_bind(a, b, c) command_bind_to(1, a, b, c) +#define command_bind_first(a, b, c) command_bind_to(0, a, b, c) +#define command_bind_last(a, b, c) command_bind_to(2, a, b, c) + void command_unbind(const char *cmd, SIGNAL_FUNC func); void command_runsub(const char *cmd, const char *data, void *p1, void *p2); diff --git a/src/fe-common/irc/dcc/fe-dcc.c b/src/fe-common/irc/dcc/fe-dcc.c index 1ca4b167..0bc08fb9 100644 --- a/src/fe-common/irc/dcc/fe-dcc.c +++ b/src/fe-common/irc/dcc/fe-dcc.c @@ -27,6 +27,7 @@ #include "levels.h" #include "irc.h" #include "channels.h" +#include "query.h" #include "irc/dcc/dcc.h" @@ -35,279 +36,294 @@ static void dcc_connected(DCC_REC *dcc) { - gchar *str; - - g_return_if_fail(dcc != NULL); - - switch (dcc->dcc_type) - { - case DCC_TYPE_CHAT: - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_CHAT_CONNECTED, - dcc->nick, dcc->addrstr, dcc->port); - - str = g_strconcat("=", dcc->nick, NULL); - /*FIXME: dcc_chat_create(dcc->server, str, FALSE);*/ - g_free(str); - break; - case DCC_TYPE_SEND: - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND_CONNECTED, - dcc->arg, dcc->nick, dcc->addrstr, dcc->port); - break; - case DCC_TYPE_GET: - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_GET_CONNECTED, - dcc->arg, dcc->nick, dcc->addrstr, dcc->port); - break; - } + char *sender; + + g_return_if_fail(dcc != NULL); + + switch (dcc->type) { + case DCC_TYPE_CHAT: + sender = g_strconcat("=", dcc->nick, NULL); + printformat(dcc->server, sender, MSGLEVEL_DCC, IRCTXT_DCC_CHAT_CONNECTED, + dcc->nick, dcc->addrstr, dcc->port); + if (query_find(NULL, sender) == NULL) + query_create(dcc->server, sender, TRUE); + g_free(sender); + break; + case DCC_TYPE_SEND: + printformat(dcc->server, dcc->nick, MSGLEVEL_DCC, IRCTXT_DCC_SEND_CONNECTED, + dcc->arg, dcc->nick, dcc->addrstr, dcc->port); + break; + case DCC_TYPE_GET: + printformat(dcc->server, dcc->nick, MSGLEVEL_DCC, IRCTXT_DCC_GET_CONNECTED, + dcc->arg, dcc->nick, dcc->addrstr, dcc->port); + break; + } } static void dcc_rejected(DCC_REC *dcc) { - g_return_if_fail(dcc != NULL); + g_return_if_fail(dcc != NULL); - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_CLOSE, - dcc_type2str(dcc->dcc_type), dcc->nick, dcc->arg); + printformat(dcc->server, dcc->nick, MSGLEVEL_DCC, IRCTXT_DCC_CLOSE, + dcc_type2str(dcc->type), dcc->nick, dcc->arg); } static void dcc_closed(DCC_REC *dcc) { - time_t secs; - gdouble kbs; - - g_return_if_fail(dcc != NULL); - - secs = dcc->starttime == 0 ? -1 : time(NULL)-dcc->starttime; - kbs = (gdouble) (dcc->transfd-dcc->skipped) / (secs == 0 ? 1 : secs) / 1024.0; - - switch (dcc->dcc_type) - { - case DCC_TYPE_CHAT: - { - /* nice kludge :) if connection was lost, close the channel. - after closed channel (can be done with /unquery too) - prints the disconnected-text.. */ - CHANNEL_REC *channel; - gchar *str; - - str = g_strdup_printf("=%s", dcc->nick); - printformat(dcc->server, str, MSGLEVEL_DCC, - IRCTXT_DCC_CHAT_DISCONNECTED, dcc->nick); - - channel = channel_find(dcc->server, str); - if (channel != NULL) - channel_destroy(channel); - g_free(str); - } - break; - case DCC_TYPE_SEND: - if (secs == -1) - { - /* aborted */ - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND_ABORTED, - dcc->arg, dcc->nick); - } - else - { - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND_COMPLETE, - dcc->arg, dcc->transfd/1024, dcc->nick, (glong) secs, kbs); - } - break; - case DCC_TYPE_GET: - if (secs == -1) - { - /* aborted */ - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_GET_ABORTED, - dcc->arg, dcc->nick); - } - else - { - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_GET_COMPLETE, - dcc->arg, dcc->transfd/1024, dcc->nick, (glong) secs, kbs); - } - break; - } + char *sender; + double kbs; + time_t secs; + + g_return_if_fail(dcc != NULL); + + secs = dcc->starttime == 0 ? -1 : time(NULL)-dcc->starttime; + kbs = (double) (dcc->transfd-dcc->skipped) / (secs == 0 ? 1 : secs) / 1024.0; + + switch (dcc->type) { + case DCC_TYPE_CHAT: + sender = g_strconcat("=", dcc->nick, NULL); + printformat(dcc->server, sender, MSGLEVEL_DCC, + IRCTXT_DCC_CHAT_DISCONNECTED, dcc->nick); + g_free(sender); + break; + case DCC_TYPE_SEND: + if (secs == -1) { + /* aborted */ + printformat(dcc->server, dcc->nick, MSGLEVEL_DCC, IRCTXT_DCC_SEND_ABORTED, + dcc->arg, dcc->nick); + } else { + printformat(dcc->server, dcc->nick, MSGLEVEL_DCC, IRCTXT_DCC_SEND_COMPLETE, + dcc->arg, dcc->transfd/1024, dcc->nick, (long) secs, kbs); + } + break; + case DCC_TYPE_GET: + if (secs == -1) { + /* aborted */ + printformat(dcc->server, dcc->nick, MSGLEVEL_DCC, IRCTXT_DCC_GET_ABORTED, + dcc->arg, dcc->nick); + } else { + printformat(dcc->server, dcc->nick, MSGLEVEL_DCC, IRCTXT_DCC_GET_COMPLETE, + dcc->arg, dcc->transfd/1024, dcc->nick, (long) secs, kbs); + } + break; + } } -static void dcc_chat_in_action(gchar *msg, DCC_REC *dcc) +static void dcc_chat_action(const char *msg, DCC_REC *dcc) { - gchar *sender; + char *sender; - g_return_if_fail(dcc != NULL); - g_return_if_fail(msg != NULL); + g_return_if_fail(dcc != NULL); + g_return_if_fail(msg != NULL); - sender = g_strconcat("=", dcc->nick, NULL); - printformat(NULL, sender, MSGLEVEL_DCC, - IRCTXT_ACTION_DCC, dcc->nick, msg); - g_free(sender); + sender = g_strconcat("=", dcc->nick, NULL); + printformat(NULL, sender, MSGLEVEL_DCC, + IRCTXT_ACTION_DCC, dcc->nick, msg); + g_free(sender); } -static void dcc_chat_ctcp(gchar *msg, DCC_REC *dcc) +static void dcc_chat_ctcp(const char *msg, DCC_REC *dcc) { - gchar *sender; + char *sender; - g_return_if_fail(dcc != NULL); - g_return_if_fail(msg != NULL); + g_return_if_fail(dcc != NULL); + g_return_if_fail(msg != NULL); - sender = g_strconcat("=", dcc->nick, NULL); - printformat(NULL, sender, MSGLEVEL_DCC, IRCTXT_DCC_CTCP, dcc->nick, msg); - g_free(sender); + sender = g_strconcat("=", dcc->nick, NULL); + printformat(NULL, sender, MSGLEVEL_DCC, IRCTXT_DCC_CTCP, dcc->nick, msg); + g_free(sender); } -static void dcc_chat_msg(DCC_REC *dcc, gchar *msg) +static void dcc_chat_msg(DCC_REC *dcc, const char *msg) { - gchar *nick; + char *sender; - g_return_if_fail(dcc != NULL); - g_return_if_fail(msg != NULL); + g_return_if_fail(dcc != NULL); + g_return_if_fail(msg != NULL); - nick = g_strconcat("=", dcc->nick, NULL); - printformat(NULL, nick, MSGLEVEL_DCC, IRCTXT_DCC_MSG, dcc->nick, msg); - g_free(nick); + sender = g_strconcat("=", dcc->nick, NULL); + printformat(NULL, sender, MSGLEVEL_DCC, + query_find(NULL, sender) ? IRCTXT_DCC_MSG_QUERY : + IRCTXT_DCC_MSG, dcc->nick, msg); + g_free(sender); } static void dcc_request(DCC_REC *dcc) { - g_return_if_fail(dcc != NULL); - - switch (dcc->dcc_type) - { - case DCC_TYPE_CHAT: - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_CHAT, - dcc->nick, dcc->addrstr, dcc->port); - break; - case DCC_TYPE_GET: - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND, - dcc->nick, dcc->addrstr, dcc->port, dcc->arg, dcc->size); - break; - } + g_return_if_fail(dcc != NULL); + + switch (dcc->type) { + case DCC_TYPE_CHAT: + printformat(dcc->server, dcc->nick, MSGLEVEL_DCC, IRCTXT_DCC_CHAT, + dcc->nick, dcc->addrstr, dcc->port); + break; + case DCC_TYPE_GET: + printformat(dcc->server, dcc->nick, MSGLEVEL_DCC, IRCTXT_DCC_SEND, + dcc->nick, dcc->addrstr, dcc->port, dcc->arg, dcc->size); + break; + } } static void dcc_error_connect(DCC_REC *dcc) { - g_return_if_fail(dcc != NULL); + g_return_if_fail(dcc != NULL); - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_CONNECT_ERROR, dcc->addrstr, dcc->port); + printformat(dcc->server, dcc->nick, MSGLEVEL_DCC, IRCTXT_DCC_CONNECT_ERROR, dcc->addrstr, dcc->port); } -static void dcc_error_file_create(DCC_REC *dcc, gchar *fname) +static void dcc_error_file_create(DCC_REC *dcc, const char *fname) { - g_return_if_fail(dcc != NULL); + g_return_if_fail(dcc != NULL); - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_CANT_CREATE, fname); + printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_CANT_CREATE, fname); } -static void dcc_error_file_not_found(gchar *nick, gchar *fname) +static void dcc_error_file_not_found(const char *nick, const char *fname) { - g_return_if_fail(nick != NULL); - g_return_if_fail(fname != NULL); + g_return_if_fail(nick != NULL); + g_return_if_fail(fname != NULL); - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND_FILE_NOT_FOUND, fname); + printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND_FILE_NOT_FOUND, fname); } -static void dcc_error_get_not_found(gchar *nick) +static void dcc_error_get_not_found(const char *nick) { - g_return_if_fail(nick != NULL); + g_return_if_fail(nick != NULL); - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_GET_NOT_FOUND, nick); + printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_GET_NOT_FOUND, nick); } -static void dcc_error_send_exists(gchar *nick, gchar *fname) +static void dcc_error_send_exists(const char *nick, const char *fname) { - g_return_if_fail(nick != NULL); - g_return_if_fail(fname != NULL); + g_return_if_fail(nick != NULL); + g_return_if_fail(fname != NULL); - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND_EXISTS, fname, nick); + printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND_EXISTS, fname, nick); } -static void dcc_error_unknown_type(gchar *type) +static void dcc_error_unknown_type(const char *type) { - g_return_if_fail(type != NULL); + g_return_if_fail(type != NULL); - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_UNKNOWN_TYPE, type); + printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_UNKNOWN_TYPE, type); } -static void dcc_error_close_not_found(gchar *type, gchar *nick, gchar *fname) +static void dcc_error_close_not_found(const char *type, const char *nick, const char *fname) { - g_return_if_fail(type != NULL); - g_return_if_fail(nick != NULL); - g_return_if_fail(fname != NULL); - - if (fname == '\0') fname = "(ANY)"; - switch (dcc_str2type(type)) - { - case DCC_TYPE_CHAT: - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_CHAT_NOT_FOUND, nick); - break; - case DCC_TYPE_SEND: - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND_NOT_FOUND, nick, fname); - break; - case DCC_TYPE_GET: - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_GET_NOT_FOUND, nick, fname); - break; - } + g_return_if_fail(type != NULL); + g_return_if_fail(nick != NULL); + g_return_if_fail(fname != NULL); + + if (fname == '\0') fname = "(ANY)"; + switch (dcc_str2type(type)) { + case DCC_TYPE_CHAT: + printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_CHAT_NOT_FOUND, nick); + break; + case DCC_TYPE_SEND: + printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND_NOT_FOUND, nick, fname); + break; + case DCC_TYPE_GET: + printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_GET_NOT_FOUND, nick, fname); + break; + } } -static void dcc_unknown_ctcp(gchar *data, gchar *sender) +static void dcc_unknown_ctcp(const char *data, const char *sender) { - gchar *params, *type, *args; + char *params, *type, *args; - g_return_if_fail(data != NULL); + g_return_if_fail(data != NULL); - params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &type, &args); - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_UNKNOWN_CTCP, type, sender, args); - g_free(params); + params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &type, &args); + printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_UNKNOWN_CTCP, type, sender, args); + g_free(params); } -static void dcc_unknown_reply(gchar *data, gchar *sender) +static void dcc_unknown_reply(const char *data, const char *sender) { - gchar *params, *type, *args; + char *params, *type, *args; - g_return_if_fail(data != NULL); + g_return_if_fail(data != NULL); - params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &type, &args); - printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_UNKNOWN_REPLY, type, sender, args); - g_free(params); + params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &type, &args); + printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_UNKNOWN_REPLY, type, sender, args); + g_free(params); } -static void dcc_chat_write(gchar *data) +static void sig_dcc_destroyed(DCC_REC *dcc) { - DCC_REC *dcc; - gchar *params, *text, *target; + QUERY_REC *query; + char *nick; + + if (dcc->type != DCC_TYPE_CHAT) + return; - g_return_if_fail(data != NULL); + nick = g_strconcat("=", dcc->nick, NULL); + query = query_find(NULL, nick); + g_free(nick); - params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &text); + if (query != NULL) { + /* DCC chat closed, close the query with it. */ + query_destroy(query); + } +} - if (*target == '=') - { - /* dcc msg */ - dcc = dcc_find_item(DCC_TYPE_CHAT, target+1, NULL); - if (dcc == NULL) - { - printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, - IRCTXT_DCC_CHAT_NOT_FOUND, target+1); - return; - } +static void sig_query_destroyed(QUERY_REC *query) +{ + DCC_REC *dcc; - printformat(NULL, target, MSGLEVEL_DCC, IRCTXT_OWN_DCC, target+1, text); - } + if (*query->nick != '=') + return; - g_free(params); + dcc = dcc_find_item(DCC_TYPE_CHAT, query->nick+1, NULL); + if (dcc != NULL && !dcc->destroyed) { + /* DCC query window closed, close the dcc chat too. */ + signal_emit("dcc closed", 1, dcc); + dcc_destroy(dcc); + } } -static void dcc_chat_out_me(gchar *data, SERVER_REC *server, WI_IRC_REC *item) +static void cmd_msg(const char *data) { DCC_REC *dcc; + char *params, *text, *target; g_return_if_fail(data != NULL); - dcc = irc_item_dcc_chat(item); + if (*data != '=') { + /* handle only DCC messages */ + return; + } + + params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &text); + + dcc = dcc_find_item(DCC_TYPE_CHAT, target+1, NULL); + if (dcc == NULL) { + printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, + IRCTXT_DCC_CHAT_NOT_FOUND, target+1); + } else { + printformat(NULL, target, MSGLEVEL_DCC, + query_find(NULL, target) ? IRCTXT_OWN_DCC_QUERY : + IRCTXT_OWN_DCC, dcc->mynick, text); + } + + g_free(params); +} + +static void cmd_me(const char *data, SERVER_REC *server, WI_IRC_REC *item) +{ + DCC_REC *dcc; + + g_return_if_fail(data != NULL); + + dcc = item_get_dcc(item); if (dcc == NULL) return; printformat(NULL, item->name, MSGLEVEL_DCC, IRCTXT_OWN_DCC_ME, dcc->mynick, data); } -static void dcc_chat_out_action(const char *data, SERVER_REC *server, WI_IRC_REC *item) +static void cmd_action(const char *data, SERVER_REC *server, WI_IRC_REC *item) { char *params, *target, *text; DCC_REC *dcc; @@ -323,17 +339,17 @@ static void dcc_chat_out_action(const char *data, SERVER_REC *server, WI_IRC_REC if (*target == '\0' || *text == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); dcc = dcc_find_item(DCC_TYPE_CHAT, target+1, NULL); - if (dcc == NULL){ + if (dcc == NULL) { printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, IRCTXT_DCC_CHAT_NOT_FOUND, target+1); } else { - printformat(NULL, item->name, MSGLEVEL_DCC, + printformat(NULL, target, MSGLEVEL_DCC, IRCTXT_OWN_DCC_ME, dcc->mynick, text); } g_free(params); } -static void dcc_chat_out_ctcp(gchar *data, SERVER_REC *server) +static void cmd_ctcp(const char *data, SERVER_REC *server) { char *params, *target, *ctcpcmd, *ctcpdata; DCC_REC *dcc; @@ -363,44 +379,29 @@ static void dcc_chat_out_ctcp(gchar *data, SERVER_REC *server) g_free(params); } -static void cmd_dcc_list(gchar *data) +static void cmd_dcc_list(const char *data) { - GSList *tmp; - time_t going; - - g_return_if_fail(data != NULL); - - printtext(NULL, NULL, MSGLEVEL_DCC, "%gDCC connections"); - for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next) - { - DCC_REC *dcc = tmp->data; - - going = time(NULL) - dcc->starttime; - if (going == 0) going = 1; /* no division by zeros :) */ - - if (dcc->dcc_type == DCC_TYPE_CHAT) - printtext(NULL, NULL, MSGLEVEL_DCC, "%g %s %s", dcc->nick, dcc_type2str(dcc->dcc_type)); - else - printtext(NULL, NULL, MSGLEVEL_DCC, "%g %s %s: %luk of %luk (%d%%) - %fkB/s - %s", - dcc->nick, dcc_type2str(dcc->dcc_type), dcc->transfd/1024, dcc->size/1024, - dcc->size == 0 ? 0 : (100*dcc->transfd/dcc->size), - (gdouble) (dcc->transfd-dcc->skipped)/going/1024, dcc->arg); - } -} + GSList *tmp; + time_t going; -static void dcc_chat_closed(WINDOW_REC *window, WI_IRC_REC *item) -{ - DCC_REC *dcc; + g_return_if_fail(data != NULL); - dcc = irc_item_dcc_chat(item); - if (dcc == NULL) return; + printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_LIST_HEADER); + for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next) { + DCC_REC *dcc = tmp->data; - /* check that we haven't got here from dcc_destroy() so we won't try to - close the dcc again.. */ - if (!dcc->destroyed) { - /* DCC query window closed, close the dcc chat too. */ - dcc_destroy(dcc); + going = time(NULL) - dcc->starttime; + if (going == 0) going = 1; /* no division by zeros :) */ + + if (dcc->type == DCC_TYPE_CHAT) + printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_LIST_LINE_CHAT, dcc->nick, dcc_type2str(dcc->type)); + else + printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_LIST_LINE_FILE, + dcc->nick, dcc_type2str(dcc->type), dcc->transfd/1024, dcc->size/1024, + dcc->size == 0 ? 0 : (100*dcc->transfd/dcc->size), + (double) (dcc->transfd-dcc->skipped)/going/1024, dcc->arg); } + printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_LIST_FOOTER); } void fe_irc_dcc_init(void) @@ -409,7 +410,7 @@ void fe_irc_dcc_init(void) signal_add("dcc rejected", (SIGNAL_FUNC) dcc_rejected); signal_add("dcc closed", (SIGNAL_FUNC) dcc_closed); signal_add("dcc chat message", (SIGNAL_FUNC) dcc_chat_msg); - signal_add("dcc ctcp action", (SIGNAL_FUNC) dcc_chat_in_action); + signal_add("dcc ctcp action", (SIGNAL_FUNC) dcc_chat_action); signal_add("default dcc ctcp", (SIGNAL_FUNC) dcc_chat_ctcp); signal_add("dcc request", (SIGNAL_FUNC) dcc_request); signal_add("dcc error connect", (SIGNAL_FUNC) dcc_error_connect); @@ -421,13 +422,14 @@ void fe_irc_dcc_init(void) signal_add("dcc error close not found", (SIGNAL_FUNC) dcc_error_close_not_found); signal_add("dcc unknown ctcp", (SIGNAL_FUNC) dcc_unknown_ctcp); signal_add("dcc unknown reply", (SIGNAL_FUNC) dcc_unknown_reply); - command_bind("msg", NULL, (SIGNAL_FUNC) dcc_chat_write); - command_bind("me", NULL, (SIGNAL_FUNC) dcc_chat_out_me); - command_bind("action", NULL, (SIGNAL_FUNC) dcc_chat_out_action); - command_bind("ctcp", NULL, (SIGNAL_FUNC) dcc_chat_out_ctcp); + signal_add("dcc destroyed", (SIGNAL_FUNC) sig_dcc_destroyed); + signal_add("query destroyed", (SIGNAL_FUNC) sig_query_destroyed); + command_bind("msg", NULL, (SIGNAL_FUNC) cmd_msg); + command_bind("me", NULL, (SIGNAL_FUNC) cmd_me); + command_bind("action", NULL, (SIGNAL_FUNC) cmd_action); + command_bind("ctcp", NULL, (SIGNAL_FUNC) cmd_ctcp); command_bind("dcc ", NULL, (SIGNAL_FUNC) cmd_dcc_list); command_bind("dcc list", NULL, (SIGNAL_FUNC) cmd_dcc_list); - signal_add("window item remove", (SIGNAL_FUNC) dcc_chat_closed); theme_register(fecommon_irc_dcc_formats); } @@ -440,7 +442,7 @@ void fe_irc_dcc_deinit(void) signal_remove("dcc rejected", (SIGNAL_FUNC) dcc_rejected); signal_remove("dcc closed", (SIGNAL_FUNC) dcc_closed); signal_remove("dcc chat message", (SIGNAL_FUNC) dcc_chat_msg); - signal_remove("dcc ctcp action", (SIGNAL_FUNC) dcc_chat_in_action); + signal_remove("dcc ctcp action", (SIGNAL_FUNC) dcc_chat_action); signal_remove("default dcc ctcp", (SIGNAL_FUNC) dcc_chat_ctcp); signal_remove("dcc request", (SIGNAL_FUNC) dcc_request); signal_remove("dcc error connect", (SIGNAL_FUNC) dcc_error_connect); @@ -452,11 +454,12 @@ void fe_irc_dcc_deinit(void) signal_remove("dcc error close not found", (SIGNAL_FUNC) dcc_error_close_not_found); signal_remove("dcc unknown ctcp", (SIGNAL_FUNC) dcc_unknown_ctcp); signal_remove("dcc unknown reply", (SIGNAL_FUNC) dcc_unknown_reply); - command_unbind("msg", (SIGNAL_FUNC) dcc_chat_write); - command_unbind("me", (SIGNAL_FUNC) dcc_chat_out_me); - command_unbind("action", (SIGNAL_FUNC) dcc_chat_out_action); - command_unbind("ctcp", (SIGNAL_FUNC) dcc_chat_out_ctcp); + signal_remove("dcc destroyed", (SIGNAL_FUNC) sig_dcc_destroyed); + signal_remove("query destroyed", (SIGNAL_FUNC) sig_query_destroyed); + command_unbind("msg", (SIGNAL_FUNC) cmd_msg); + command_unbind("me", (SIGNAL_FUNC) cmd_me); + command_unbind("action", (SIGNAL_FUNC) cmd_action); + command_unbind("ctcp", (SIGNAL_FUNC) cmd_ctcp); command_unbind("dcc ", (SIGNAL_FUNC) cmd_dcc_list); command_unbind("dcc list", (SIGNAL_FUNC) cmd_dcc_list); - signal_remove("window item remove", (SIGNAL_FUNC) dcc_chat_closed); } diff --git a/src/fe-common/irc/dcc/module-formats.c b/src/fe-common/irc/dcc/module-formats.c index 4dee15f7..da2cdc68 100644 --- a/src/fe-common/irc/dcc/module-formats.c +++ b/src/fe-common/irc/dcc/module-formats.c @@ -27,11 +27,13 @@ FORMAT_REC fecommon_irc_dcc_formats[] = { /* ---- */ { NULL, "DCC", 0 }, - { "own_dcc", "%K[%rdcc%K(%R$0%K)]%n $1", 2, { 0, 0 } }, - { "own_dcc_me", "%W * $0%n $1", 2, { 0, 0 } }, + { "own_dcc", "%K[%rdcc%K(%R$0%K)]%n %|$1", 2, { 0, 0 } }, + { "own_dcc_me", "%W * $0%n %|$1", 2, { 0, 0 } }, { "own_dcc_ctcp", "%K[%rctcp%K(%R$0%K)]%n $1 $2", 3, { 0, 0, 0 } }, - { "dcc_msg", "%K[%G$0%K(%gdcc%K)]%n $1", 2, { 0, 0 } }, - { "action_dcc", "%W (*dcc*) $0%n $1", 2, { 0, 0 } }, + { "dcc_msg", "%K[%G$0%K(%gdcc%K)]%n %|$1", 2, { 0, 0 } }, + { "action_dcc", "%W (*dcc*) $0%n %|$1", 2, { 0, 0 } }, + { "own_dcc_query", "%K<%W$0%K>%n %|$1", 2, { 0, 0 } }, + { "dcc_msg_query", "%K<%G$0%K>%n %|$1", 2, { 0, 0 } }, { "dcc_ctcp", "%g>>> DCC CTCP received from %_$0%_%K: %g$1", 2, { 0, 0 } }, { "dcc_chat", "%gDCC CHAT from %_$0%_ %K[%g$1 port $2%K]", 3, { 0, 0, 1 } }, { "dcc_chat_not_found", "%gNo DCC CHAT connection open to %_$0", 1, { 0 } }, @@ -55,6 +57,10 @@ FORMAT_REC fecommon_irc_dcc_formats[] = { { "dcc_cant_create", "%gDCC can't create file %G$0%g", 1, { 0 } }, { "dcc_rejected", "%gDCC %G$0%g was rejected by %_$1%_ %K[%G$2%K]", 3, { 0, 0, 0 } }, { "dcc_close", "%gDCC %G$0%g close for %_$1%_ %K[%G$2%K]", 3, { 0, 0, 0 } }, + { "dcc_list_header", "%gDCC connections", 0 }, + { "dcc_list_line_chat", "%g $0 $1", 2, { 0, 0 } }, + { "dcc_list_line_file", "%g $0 $1: $2k of $3k ($4%%) - $5kB/s - $6", 7, { 0, 0, 2, 2, 1, 3, 0 } }, + { "dcc_list_footer", "", 0 }, { NULL, NULL, 0 } }; diff --git a/src/fe-common/irc/dcc/module-formats.h b/src/fe-common/irc/dcc/module-formats.h index d7fe8eff..b61faad5 100644 --- a/src/fe-common/irc/dcc/module-formats.h +++ b/src/fe-common/irc/dcc/module-formats.h @@ -10,6 +10,8 @@ enum { IRCTXT_OWN_DCC_CTCP, IRCTXT_DCC_MSG, IRCTXT_ACTION_DCC, + IRCTXT_OWN_DCC_QUERY, + IRCTXT_DCC_MSG_QUERY, IRCTXT_DCC_CTCP, IRCTXT_DCC_CHAT, IRCTXT_DCC_CHAT_NOT_FOUND, @@ -32,7 +34,11 @@ enum { IRCTXT_DCC_CONNECT_ERROR, IRCTXT_DCC_CANT_CREATE, IRCTXT_DCC_REJECTED, - IRCTXT_DCC_CLOSE + IRCTXT_DCC_CLOSE, + IRCTXT_DCC_LIST_HEADER, + IRCTXT_DCC_LIST_LINE_CHAT, + IRCTXT_DCC_LIST_LINE_FILE, + IRCTXT_DCC_LIST_FOOTER }; extern FORMAT_REC fecommon_irc_dcc_formats[]; diff --git a/src/fe-common/irc/fe-irc-commands.c b/src/fe-common/irc/fe-irc-commands.c index dc844346..fa8d9a2f 100644 --- a/src/fe-common/irc/fe-irc-commands.c +++ b/src/fe-common/irc/fe-irc-commands.c @@ -161,25 +161,6 @@ static void cmd_msg(gchar *data, IRC_SERVER_REC *server, WI_ITEM_REC *item) g_free(params); } -static void cmd_notice(gchar *data, IRC_SERVER_REC *server) -{ - char *params, *target, *msg; - - g_return_if_fail(data != NULL); - if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED); - - params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg); - if (*target == '\0' || *msg == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); - - if (*target == '@' && ischannel(target[1])) - target++; /* Hybrid 6 feature, send notice to all ops in channel */ - - printformat(server, target, MSGLEVEL_NOTICES | MSGLEVEL_NOHILIGHT, - IRCTXT_OWN_NOTICE, target, msg); - - g_free(params); -} - static void cmd_me(gchar *data, IRC_SERVER_REC *server, WI_IRC_REC *item) { g_return_if_fail(data != NULL); @@ -187,11 +168,6 @@ static void cmd_me(gchar *data, IRC_SERVER_REC *server, WI_IRC_REC *item) if (!irc_item_check(item)) return; - if (irc_item_dcc_chat(item)) { - /* DCC action - handled by fe-dcc.c */ - return; - } - if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED); printformat(server, item->name, MSGLEVEL_ACTIONS, @@ -206,10 +182,6 @@ static void cmd_action(const char *data, IRC_SERVER_REC *server) g_return_if_fail(data != NULL); if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED); - if (*data == '=') { - /* DCC action - handled by fe-dcc.c */ - return; - } params = cmd_get_params(data, 3 | PARAM_FLAG_GETREST, &target, &text); if (*target == '\0' || *text == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); @@ -219,6 +191,25 @@ static void cmd_action(const char *data, IRC_SERVER_REC *server) g_free(params); } +static void cmd_notice(gchar *data, IRC_SERVER_REC *server) +{ + char *params, *target, *msg; + + g_return_if_fail(data != NULL); + if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED); + + params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg); + if (*target == '\0' || *msg == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); + + if (*target == '@' && ischannel(target[1])) + target++; /* Hybrid 6 feature, send notice to all ops in channel */ + + printformat(server, target, MSGLEVEL_NOTICES | MSGLEVEL_NOHILIGHT, + IRCTXT_OWN_NOTICE, target, msg); + + g_free(params); +} + static void cmd_ctcp(const char *data, IRC_SERVER_REC *server) { char *params, *target, *ctcpcmd, *ctcpdata; @@ -229,11 +220,6 @@ static void cmd_ctcp(const char *data, IRC_SERVER_REC *server) params = cmd_get_params(data, 3 | PARAM_FLAG_GETREST, &target, &ctcpcmd, &ctcpdata); if (*target == '\0' || *ctcpcmd == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); - if (*target == '=') { - /* send CTCP via DCC CHAT */ - g_free(params); - return; - } if (*target == '@' && ischannel(target[1])) target++; /* Hybrid 6 feature, send ctcp to all ops in channel */ @@ -401,10 +387,10 @@ void fe_irc_commands_init(void) { command_bind("query", NULL, (SIGNAL_FUNC) cmd_query); command_bind("unquery", NULL, (SIGNAL_FUNC) cmd_unquery); - command_bind("msg", NULL, (SIGNAL_FUNC) cmd_msg); + command_bind_last("msg", NULL, (SIGNAL_FUNC) cmd_msg); + command_bind_last("me", NULL, (SIGNAL_FUNC) cmd_me); + command_bind_last("action", NULL, (SIGNAL_FUNC) cmd_action); command_bind("notice", NULL, (SIGNAL_FUNC) cmd_notice); - command_bind("me", NULL, (SIGNAL_FUNC) cmd_me); - command_bind("action", NULL, (SIGNAL_FUNC) cmd_action); command_bind("ctcp", NULL, (SIGNAL_FUNC) cmd_ctcp); command_bind("nctcp", NULL, (SIGNAL_FUNC) cmd_nctcp); command_bind("ban", NULL, (SIGNAL_FUNC) cmd_ban); @@ -420,9 +406,9 @@ void fe_irc_commands_deinit(void) command_unbind("query", (SIGNAL_FUNC) cmd_query); command_unbind("unquery", (SIGNAL_FUNC) cmd_unquery); command_unbind("msg", (SIGNAL_FUNC) cmd_msg); - command_unbind("notice", (SIGNAL_FUNC) cmd_notice); command_unbind("me", (SIGNAL_FUNC) cmd_me); command_unbind("action", (SIGNAL_FUNC) cmd_action); + command_unbind("notice", (SIGNAL_FUNC) cmd_notice); command_unbind("ctcp", (SIGNAL_FUNC) cmd_ctcp); command_unbind("nctcp", (SIGNAL_FUNC) cmd_nctcp); command_unbind("ban", (SIGNAL_FUNC) cmd_ban); diff --git a/src/irc/core/irc-commands.c b/src/irc/core/irc-commands.c index 22a24ebb..23c9ad07 100644 --- a/src/irc/core/irc-commands.c +++ b/src/irc/core/irc-commands.c @@ -203,12 +203,6 @@ static void cmd_msg(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item) params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg); if (*target == '\0' || *msg == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); - if (*target == '=') { - /* dcc msg - don't even try to handle here.. */ - g_free(params); - return; - } - if (server == NULL || !server->connected || !irc_server_check(server)) cmd_param_error(CMDERR_NOT_CONNECTED); diff --git a/src/irc/core/irc.h b/src/irc/core/irc.h index a971670c..13e1dfca 100644 --- a/src/irc/core/irc.h +++ b/src/irc/core/irc.h @@ -19,8 +19,7 @@ /* values returned by module_category() */ enum { WI_IRC_CHANNEL, - WI_IRC_QUERY, - WI_IRC_DCC_CHAT + WI_IRC_QUERY }; /* *MUST* have the same contents as WI_ITEM_REC in same order. */ diff --git a/src/irc/core/query.c b/src/irc/core/query.c index 4f85b3f1..68ec1a73 100644 --- a/src/irc/core/query.c +++ b/src/irc/core/query.c @@ -33,18 +33,19 @@ QUERY_REC *query_create(IRC_SERVER_REC *server, const char *nick, int automatic) { QUERY_REC *rec; - g_return_val_if_fail(server != NULL, NULL); g_return_val_if_fail(nick != NULL, NULL); rec = g_new0(QUERY_REC, 1); queries = g_slist_append(queries, rec); - server->queries = g_slist_append(server->queries, rec); + if (server != NULL) server->queries = g_slist_append(server->queries, rec); MODULE_DATA_INIT(rec); rec->type = module_get_uniq_id("IRC", WI_IRC_QUERY); rec->nick = g_strdup(nick); - rec->server_tag = g_strdup(server->tag); - rec->server = server; + if (server != NULL) { + rec->server_tag = g_strdup(server->tag); + rec->server = server; + } signal_emit("query created", 2, rec, GINT_TO_POINTER(automatic)); return rec; diff --git a/src/irc/dcc/dcc-chat.c b/src/irc/dcc/dcc-chat.c index 699af0d4..642cbb7e 100644 --- a/src/irc/dcc/dcc-chat.c +++ b/src/irc/dcc/dcc-chat.c @@ -29,53 +29,72 @@ #include "masks.h" #include "irc.h" #include "server-setup.h" +#include "query.h" #include "dcc.h" +/* Send `data' to dcc chat. */ +void dcc_chat_send(DCC_REC *dcc, const char *data) +{ + g_return_if_fail(dcc != NULL); + g_return_if_fail(data != NULL); + + /* FIXME: we need output queue! */ + net_transmit(dcc->handle, data, strlen(data)); + net_transmit(dcc->handle, "\n", 1); +} + +/* If `item' is a query of a =nick, return DCC chat record of nick */ +DCC_REC *item_get_dcc(void *item) +{ + QUERY_REC *query; + + query = irc_item_query(item); + if (query == NULL || *query->nick != '=') return NULL; + + return dcc_find_item(DCC_TYPE_CHAT, query->nick+1, NULL); +} + /* Send text to DCC chat */ -static void dcc_chat_write(gchar *data) +static void cmd_msg(const char *data) { - DCC_REC *dcc; - gchar *params, *text, *target; - gint len; - - g_return_if_fail(text != NULL); - - params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &text); - - if (*target == '=') - { - /* dcc msg */ - dcc = dcc_find_item(DCC_TYPE_CHAT, ++target, NULL); - if (dcc != NULL) - { - len = strlen(text); - /* FIXME: we need output queue! */ - if (net_transmit(dcc->handle, text, len) != len) - g_warning("dcc_chat_write() : could not send all data!"); - net_transmit(dcc->handle, "\n", 1); + DCC_REC *dcc; + char *params, *text, *target; + + g_return_if_fail(text != NULL); + + if (*data != '=') { + /* handle only DCC messages */ + return; } - } - g_free(params); + params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &text); + + dcc = dcc_find_item(DCC_TYPE_CHAT, ++target, NULL); + if (dcc != NULL) dcc_chat_send(dcc, text); + + g_free(params); + signal_stop(); } -static void dcc_chat_me(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item) +static void cmd_me(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item) { DCC_REC *dcc; char *str; g_return_if_fail(data != NULL); - dcc = irc_item_dcc_chat(item); + dcc = item_get_dcc(item); if (dcc == NULL) return; str = g_strdup_printf("ACTION %s", data); dcc_ctcp_message(dcc->nick, NULL, dcc, FALSE, str); g_free(str); + + signal_stop(); } -static void dcc_chat_action(const char *data, IRC_SERVER_REC *server) +static void cmd_action(const char *data, IRC_SERVER_REC *server) { char *params, *target, *text; DCC_REC *dcc; @@ -93,14 +112,16 @@ static void dcc_chat_action(const char *data, IRC_SERVER_REC *server) dcc = dcc_find_item(DCC_TYPE_CHAT, target+1, NULL); if (dcc != NULL) { - str = g_strdup_printf("ACTION %s", data); + str = g_strdup_printf("ACTION %s", text); dcc_ctcp_message(dcc->nick, NULL, dcc, FALSE, str); g_free(str); } + g_free(params); + signal_stop(); } -static void dcc_chat_ctcp(const char *data, IRC_SERVER_REC *server) +static void cmd_ctcp(const char *data, IRC_SERVER_REC *server) { char *params, *target, *ctcpcmd, *ctcpdata; DCC_REC *dcc; @@ -128,62 +149,7 @@ static void dcc_chat_ctcp(const char *data, IRC_SERVER_REC *server) } g_free(params); -} - -/* DCC CHAT: text received */ -static void dcc_chat_msg(DCC_REC *dcc, gchar *msg) -{ - gchar *cmd, *ptr; - gboolean reply; - - g_return_if_fail(dcc != NULL); - g_return_if_fail(msg != NULL); - - reply = FALSE; - if (g_strncasecmp(msg, "CTCP_MESSAGE ", 13) != 0) - { - if (g_strncasecmp(msg, "CTCP_REPLY ", 11) != 0) - { - /* Use the mirc style CTCPing from now on.. */ - dcc->mirc_ctcp = TRUE; - } - else - { - /* bitchx (and ircii?) sends this */ - msg += 11; - reply = TRUE; - dcc->mirc_ctcp = FALSE; - } - } - else - { - /* bitchx (and ircii?) sends this */ - msg += 13; - dcc->mirc_ctcp = FALSE; - } - - /* Handle only DCC CTCPs */ - if (*msg != 1) - return; - - msg = g_strdup(msg+1); - /* remove the later \001 */ - ptr = strrchr(msg, 1); - if (ptr != NULL) *ptr = '\0'; - - /* get ctcp command */ - cmd = g_strconcat(reply ? "dcc reply " : "dcc ctcp ", msg, NULL); - ptr = strchr(cmd+9, ' '); - if (ptr != NULL) *ptr++ = '\0'; else ptr = ""; - - g_strdown(cmd+9); - if (!signal_emit(cmd, 2, ptr, dcc)) - signal_emit(reply ? "default dcc reply" : "default dcc ctcp", 2, msg, dcc); - - g_free(cmd); - g_free(msg); - - signal_stop(); + signal_stop(); } /* input function: DCC CHAT received some data.. */ @@ -200,7 +166,6 @@ static void dcc_chat_input(DCC_REC *dcc) ret = line_split(tmpbuf, recvlen, &str, (LINEBUF_REC **) &dcc->databuf); if (ret == -1) { /* connection lost */ - dcc->destroyed = TRUE; signal_emit("dcc closed", 1, dcc); dcc_destroy(dcc); break; @@ -216,114 +181,114 @@ static void dcc_chat_input(DCC_REC *dcc) /* input function: DCC CHAT - someone tried to connect to our socket */ static void dcc_chat_listen(DCC_REC *dcc) { - IPADDR ip; - gint handle, port; + IPADDR ip; + int handle, port; - g_return_if_fail(dcc != NULL); + g_return_if_fail(dcc != NULL); - /* accept connection */ - handle = net_accept(dcc->handle, &ip, &port); - if (handle == -1) - return; + /* accept connection */ + handle = net_accept(dcc->handle, &ip, &port); + if (handle == -1) + return; - /* FIXME: add paranoia checking, check if host ip is the same as to who - we sent the DCC CHAT request.. */ + /* TODO: add paranoia check - see dcc-files.c */ - g_source_remove(dcc->tagread); - close(dcc->handle); + g_source_remove(dcc->tagread); + close(dcc->handle); - dcc->starttime = time(NULL); - dcc->handle = handle; - memcpy(&dcc->addr, &ip, sizeof(IPADDR)); - net_ip2host(&dcc->addr, dcc->addrstr); - dcc->port = port; - dcc->tagread = g_input_add(handle, G_INPUT_READ, - (GInputFunction) dcc_chat_input, dcc); + dcc->starttime = time(NULL); + dcc->handle = handle; + memcpy(&dcc->addr, &ip, sizeof(IPADDR)); + net_ip2host(&dcc->addr, dcc->addrstr); + dcc->port = port; + dcc->tagread = g_input_add(handle, G_INPUT_READ, + (GInputFunction) dcc_chat_input, dcc); - signal_emit("dcc connected", 1, dcc); + signal_emit("dcc connected", 1, dcc); } /* callback: DCC CHAT - net_connect_nonblock() finished */ -static void dcc_chat_connect(DCC_REC *dcc) +static void sig_chat_connected(DCC_REC *dcc) { - g_return_if_fail(dcc != NULL); - - g_source_remove(dcc->tagread); - if (net_geterror(dcc->handle) != 0) - { - /* error connecting */ - signal_emit("dcc error connect", 1, dcc); - dcc_destroy(dcc); - return; - } - - /* connect ok. */ - dcc->starttime = time(NULL); - dcc->tagread = g_input_add(dcc->handle, G_INPUT_READ, - (GInputFunction) dcc_chat_input, dcc); - - signal_emit("dcc connected", 1, dcc); + g_return_if_fail(dcc != NULL); + + g_source_remove(dcc->tagread); + if (net_geterror(dcc->handle) != 0) { + /* error connecting */ + signal_emit("dcc error connect", 1, dcc); + dcc_destroy(dcc); + return; + } + + /* connect ok. */ + dcc->starttime = time(NULL); + dcc->tagread = g_input_add(dcc->handle, G_INPUT_READ, + (GInputFunction) dcc_chat_input, dcc); + + signal_emit("dcc connected", 1, dcc); } -/* command: DCC CHAT */ -static void cmd_dcc_chat(gchar *data, IRC_SERVER_REC *server) +static void dcc_chat_connect(DCC_REC *dcc) { - DCC_REC *dcc; - IPADDR addr; - gchar *str; - gint port, handle; - - g_return_if_fail(data != NULL); - if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS); - - dcc = dcc_find_item(DCC_TYPE_CHAT, data, NULL); - if (dcc != NULL) - { - if (dcc->addrstr[0] == '\0' || dcc->starttime != 0) - { - /* already sent a chat request / already chatting */ - return; + g_return_if_fail(dcc != NULL); + + if (dcc->addrstr[0] == '\0' || dcc->starttime != 0) { + /* already sent a chat request / already chatting */ + return; } - /* found from dcc list - so we're the connecting side.. */ dcc->handle = net_connect_ip(&dcc->addr, dcc->port, source_host_ok ? source_host_ip : NULL); - if (dcc->handle != -1) - { - dcc->tagread = g_input_add(dcc->handle, G_INPUT_WRITE|G_INPUT_READ|G_INPUT_EXCEPTION, - (GInputFunction) dcc_chat_connect, dcc); - } - else - { - /* error connecting */ - signal_emit("dcc error connect", 1, dcc); - dcc_destroy(dcc); + if (dcc->handle != -1) { + dcc->tagread = g_input_add(dcc->handle, G_INPUT_WRITE|G_INPUT_READ|G_INPUT_EXCEPTION, + (GInputFunction) sig_chat_connected, dcc); + } else { + /* error connecting */ + signal_emit("dcc error connect", 1, dcc); + dcc_destroy(dcc); } +} - return; - } +/* command: DCC CHAT */ +static void cmd_dcc_chat(const char *data, IRC_SERVER_REC *server) +{ + DCC_REC *dcc; + IPADDR own_ip; + char *str, host[MAX_IP_LEN]; + int port, handle; + + g_return_if_fail(data != NULL); + if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS); + + dcc = dcc_find_item(DCC_TYPE_CHAT, data, NULL); + if (dcc != NULL) { + /* found from dcc list - so we're the connecting side.. */ + dcc_chat_connect(dcc); + return; + } - /* send dcc chat request */ - if (server == NULL || !server->connected) - cmd_return_error(CMDERR_NOT_CONNECTED); + /* send dcc chat request */ + if (server == NULL || !server->connected) + cmd_return_error(CMDERR_NOT_CONNECTED); - if (net_getsockname(server->handle, &addr, NULL) == -1) - cmd_return_error(CMDERR_ERRNO); + if (net_getsockname(server->handle, &own_ip, NULL) == -1) + cmd_return_error(CMDERR_ERRNO); - port = settings_get_int("dcc_port"); - handle = net_listen(&addr, &port); - if (handle == -1) - cmd_return_error(CMDERR_ERRNO); + port = settings_get_int("dcc_port"); + handle = net_listen(&own_ip, &port); + if (handle == -1) + cmd_return_error(CMDERR_ERRNO); - dcc = dcc_create(DCC_TYPE_CHAT, handle, data, "chat", server, NULL); - dcc->tagread = g_input_add(dcc->handle, G_INPUT_READ, - (GInputFunction) dcc_chat_listen, dcc); + dcc = dcc_create(DCC_TYPE_CHAT, handle, data, "chat", server, NULL); + dcc->tagread = g_input_add(dcc->handle, G_INPUT_READ, + (GInputFunction) dcc_chat_listen, dcc); - /* send the request */ - str = g_strdup_printf("PRIVMSG %s :\001DCC CHAT CHAT %s %d\001", - data, dcc_make_address(&addr), port); - irc_send_cmd(server, str); - g_free(str); + /* send the request */ + dcc_make_address(&own_ip, host); + str = g_strdup_printf("PRIVMSG %s :\001DCC CHAT CHAT %s %d\001", + data, host, port); + irc_send_cmd(server, str); + g_free(str); } static void cmd_mircdcc(gchar *data, IRC_SERVER_REC *server, WI_IRC_REC *item) @@ -332,40 +297,83 @@ static void cmd_mircdcc(gchar *data, IRC_SERVER_REC *server, WI_IRC_REC *item) g_return_if_fail(data != NULL); - dcc = irc_item_dcc_chat(item); + dcc = item_get_dcc(item); if (dcc == NULL) return; dcc->mirc_ctcp = toupper(*data) == 'N' ? FALSE : TRUE; } +/* DCC CHAT: text received */ +static void dcc_chat_msg(DCC_REC *dcc, const char *msg) +{ + char *cmd, *ptr; + int reply; + + g_return_if_fail(dcc != NULL); + g_return_if_fail(msg != NULL); + + reply = FALSE; + if (g_strncasecmp(msg, "CTCP_MESSAGE ", 13) == 0) { + /* bitchx (and ircii?) sends this */ + msg += 13; + dcc->mirc_ctcp = FALSE; + } else if (g_strncasecmp(msg, "CTCP_REPLY ", 11) == 0) { + /* bitchx (and ircii?) sends this */ + msg += 11; + reply = TRUE; + dcc->mirc_ctcp = FALSE; + } else if (*msg == 1) { + /* Use the mirc style CTCPs from now on.. */ + dcc->mirc_ctcp = TRUE; + } + + /* Handle only DCC CTCPs */ + if (*msg != 1) + return; + + /* get ctcp command, remove \001 chars */ + cmd = g_strconcat(reply ? "dcc reply " : "dcc ctcp ", msg+1, NULL); + if (cmd[strlen(cmd)-1] == 1) cmd[strlen(cmd)-1] = '\0'; + + ptr = strchr(cmd+9, ' '); + if (ptr != NULL) *ptr++ = '\0'; else ptr = ""; + + g_strdown(cmd+9); + if (!signal_emit(cmd, 2, ptr, dcc)) + signal_emit(reply ? "default dcc reply" : "default dcc ctcp", 2, msg, dcc); + g_free(cmd); + + signal_stop(); +} + static void dcc_ctcp_redirect(gchar *msg, DCC_REC *dcc) { - g_return_if_fail(msg != NULL); - g_return_if_fail(dcc != NULL); + g_return_if_fail(msg != NULL); + g_return_if_fail(dcc != NULL); - signal_emit("ctcp msg dcc", 6, msg, dcc->server, dcc->nick, "dcc", dcc->mynick, dcc); + signal_emit("ctcp msg dcc", 6, msg, dcc->server, dcc->nick, "dcc", dcc->mynick, dcc); } void dcc_chat_init(void) { - command_bind("msg", NULL, (SIGNAL_FUNC) dcc_chat_write); - command_bind("me", NULL, (SIGNAL_FUNC) dcc_chat_me); - command_bind("action", NULL, (SIGNAL_FUNC) dcc_chat_action); - command_bind("ctcp", NULL, (SIGNAL_FUNC) dcc_chat_ctcp); - command_bind("dcc chat", NULL, (SIGNAL_FUNC) cmd_dcc_chat); - signal_add_first("dcc chat message", (SIGNAL_FUNC) dcc_chat_msg); - command_bind("mircdcc", NULL, (SIGNAL_FUNC) cmd_mircdcc); - signal_add("dcc ctcp dcc", (SIGNAL_FUNC) dcc_ctcp_redirect); + command_bind("msg", NULL, (SIGNAL_FUNC) cmd_msg); + command_bind("me", NULL, (SIGNAL_FUNC) cmd_me); + 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_bind("mircdcc", NULL, (SIGNAL_FUNC) cmd_mircdcc); + signal_add_first("dcc chat message", (SIGNAL_FUNC) dcc_chat_msg); + signal_add("dcc ctcp dcc", (SIGNAL_FUNC) dcc_ctcp_redirect); } void dcc_chat_deinit(void) { - command_unbind("msg", (SIGNAL_FUNC) dcc_chat_write); - command_unbind("me", (SIGNAL_FUNC) dcc_chat_me); - command_unbind("action", (SIGNAL_FUNC) dcc_chat_action); - command_unbind("ctcp", (SIGNAL_FUNC) dcc_chat_ctcp); - command_unbind("dcc chat", (SIGNAL_FUNC) cmd_dcc_chat); - signal_remove("dcc chat message", (SIGNAL_FUNC) dcc_chat_msg); - command_unbind("mircdcc", (SIGNAL_FUNC) cmd_mircdcc); - signal_remove("dcc ctcp dcc", (SIGNAL_FUNC) dcc_ctcp_redirect); + command_unbind("msg", (SIGNAL_FUNC) cmd_msg); + command_unbind("me", (SIGNAL_FUNC) cmd_me); + command_unbind("action", (SIGNAL_FUNC) cmd_action); + command_unbind("ctcp", (SIGNAL_FUNC) cmd_ctcp); + command_unbind("dcc chat", (SIGNAL_FUNC) cmd_dcc_chat); + command_unbind("mircdcc", (SIGNAL_FUNC) cmd_mircdcc); + signal_remove("dcc chat message", (SIGNAL_FUNC) dcc_chat_msg); + signal_remove("dcc ctcp dcc", (SIGNAL_FUNC) dcc_ctcp_redirect); } diff --git a/src/irc/dcc/dcc-files.c b/src/irc/dcc/dcc-files.c index 61989ce1..7ba49261 100644 --- a/src/irc/dcc/dcc-files.c +++ b/src/irc/dcc/dcc-files.c @@ -32,255 +32,306 @@ #include "dcc.h" -static gint dcc_file_create_mode; +static int dcc_file_create_mode; -static gchar *dcc_prepare_path(gchar *fname) +static char *dcc_prepare_path(const char *fname) { - gchar *str, *ptr, *downpath; + char *str, *downpath; - /* strip all paths from file. */ - ptr = strrchr(fname, '/'); - if (ptr == NULL) ptr = fname; else ptr++; + downpath = convert_home(settings_get_str("dcc_download_path")); + str = g_strconcat(downpath, G_DIR_SEPARATOR_S, g_basename(fname), NULL); + g_free(downpath); - downpath = convert_home(settings_get_str("dcc_download_path")); - str = g_strdup_printf("%s/%s", downpath, ptr); - g_free(downpath); + return str; +} + +static void sig_dccget_send(DCC_REC *dcc); - return str; +void dcc_get_send_received(DCC_REC *dcc) +{ + guint32 recd; + + recd = (guint32) htonl(dcc->transfd); + memcpy(dcc->count_buf, &recd, 4); + + dcc->count_pos = net_transmit(dcc->handle, dcc->count_buf+dcc->count_pos, 4-dcc->count_pos); + if (dcc->count_pos == 4) dcc->count_pos = 0; + + /* count_pos might be -1 here. if this happens, the + count_buf should be re-sent.. also, if it's 1, 2 or 3, the + last 1-3 bytes should be sent later. these happen probably + never, but I just want to do it right.. :) */ + if (dcc->tagwrite != -1) { + dcc->tagwrite = g_input_add(dcc->handle, G_INPUT_WRITE, + (GInputFunction) sig_dccget_send, dcc); + } +} + +/* input function: DCC GET is free to send data */ +static void sig_dccget_send(DCC_REC *dcc) +{ + guint32 recd; + int ret; + + if (dcc->count_pos != 0) { + ret = net_transmit(dcc->handle, dcc->count_buf+dcc->count_pos, 4-dcc->count_pos); + if (dcc->count_pos <= 0) + dcc->count_pos = ret; + else if (ret > 0) + dcc->count_pos += ret; + + if (dcc->count_pos == 4) dcc->count_pos = 0; + + } + + if (dcc->count_pos == 0) { + g_source_remove(dcc->tagwrite); + dcc->tagwrite = -1; + } + + memcpy(&recd, dcc->count_buf, 4); + if (recd != (guint32) htonl(dcc->transfd)) + dcc_get_send_received(dcc); } /* input function: DCC GET received data */ -static void dcc_receive(DCC_REC *dcc) +static void sig_dccget_receive(DCC_REC *dcc) { - guint32 recd; - gint len, ret; - - g_return_if_fail(dcc != NULL); - - for (;;) - { - len = net_receive(dcc->handle, dcc->databuf, dcc->databufsize); - if (len == 0) break; - if (len < 0) - { - /* socket closed - transmit complete (or other side died..) */ - signal_emit("dcc closed", 1, dcc); - dcc_destroy(dcc); - return; - } - - write(dcc->fhandle, dcc->databuf, len); - dcc->transfd += len; - } - - /* send number of total bytes received - if for some reason we couldn't - send the 4 characters last time, try to somehow fix it this time by - sending missing amount of 0 characters.. */ - if (dcc->trans_bytes != 0) - { - recd = (guint32) htonl(0); - dcc->trans_bytes += net_transmit(dcc->handle, ((gchar *) &recd)+dcc->trans_bytes, 4-dcc->trans_bytes); - if (dcc->trans_bytes == 4) dcc->trans_bytes = 0; - } - - if (dcc->trans_bytes == 0) - { - recd = (guint32) htonl(dcc->transfd); - ret = net_transmit(dcc->handle, ((gchar *) &recd), 4); - if (ret > 0 && ret < 4) dcc->trans_bytes = ret; - } - signal_emit("dcc transfer update", 1, dcc); + int ret; + + g_return_if_fail(dcc != NULL); + + for (;;) { + ret = net_receive(dcc->handle, dcc->databuf, dcc->databufsize); + if (ret == 0) break; + + if (ret < 0) { + /* socket closed - transmit complete, + or other side died.. */ + signal_emit("dcc closed", 1, dcc); + dcc_destroy(dcc); + return; + } + + write(dcc->fhandle, dcc->databuf, ret); + dcc->transfd += ret; + } + + /* send number of total bytes received */ + if (dcc->count_pos <= 0) + dcc_get_send_received(dcc); + + signal_emit("dcc transfer update", 1, dcc); +} + +static char *get_rename_file(const char *fname) +{ + GString *newname; + struct stat statbuf; + char *ret; + int num; + + newname = g_string_new(NULL); + num = 1; + do { + g_string_sprintf(newname, "%s.%d", fname, num); + num++; + } while (stat(newname->str, &statbuf) == 0); + + ret = newname->str; + g_string_free(newname, FALSE); + return ret; } /* callback: net_connect() finished for DCC GET */ -static void dcc_get_connect(DCC_REC *dcc) +static void sig_dccget_connected(DCC_REC *dcc) { - struct stat statbuf; - - g_return_if_fail(dcc != NULL); - - g_source_remove(dcc->tagread); - if (net_geterror(dcc->handle) != 0) - { - /* error connecting */ - signal_emit("dcc error connect", 1, dcc); - dcc_destroy(dcc); - return; - } - dcc->file = dcc_prepare_path(dcc->arg); - - /* if some plugin wants to change the file name/path here.. */ - signal_emit("dcc get receive", 1, dcc); - - if (stat(dcc->file, &statbuf) == 0 && - (dcc->get_type == DCC_GET_RENAME || dcc->get_type == DCC_GET_DEFAULT)) - { - /* file exists, rename.. */ - GString *newname; - gint num; - - newname = g_string_new(NULL); - for (num = 1; ; num++) - { - g_string_sprintf(newname, "%s.%d", dcc->file, num); - if (stat(newname->str, &statbuf) != 0) break; - } - g_free(dcc->file); - dcc->file = newname->str; - g_string_free(newname, FALSE); - } - - if (dcc->get_type != DCC_GET_RESUME) - { - dcc->fhandle = open(dcc->file, O_WRONLY | O_TRUNC | O_CREAT, dcc_file_create_mode); - if (dcc->fhandle == -1) - { - signal_emit("dcc error file create", 2, dcc, dcc->file); - dcc_destroy(dcc); - return; - } - } - - dcc->databufsize = settings_get_int("dcc_block_size") > 0 ? settings_get_int("dcc_block_size") : 2048; - dcc->databuf = g_malloc(dcc->databufsize); - - dcc->starttime = time(NULL); - dcc->tagread = g_input_add(dcc->handle, G_INPUT_READ, - (GInputFunction) dcc_receive, dcc); - signal_emit("dcc connected", 1, dcc); + struct stat statbuf; + char *fname; + + g_return_if_fail(dcc != NULL); + + g_source_remove(dcc->tagread); + if (net_geterror(dcc->handle) != 0) { + /* error connecting */ + signal_emit("dcc error connect", 1, dcc); + dcc_destroy(dcc); + return; + } + + dcc->file = dcc_prepare_path(dcc->arg); + + /* if some plugin wants to change the file name/path here.. */ + signal_emit("dcc get receive", 1, dcc); + + if (stat(dcc->file, &statbuf) == 0 && dcc->get_type == DCC_GET_RENAME) { + /* file exists, rename.. */ + fname = get_rename_file(dcc->file); + g_free(dcc->file); + dcc->file = fname; + } + + if (dcc->get_type != DCC_GET_RESUME) { + dcc->fhandle = open(dcc->file, O_WRONLY | O_TRUNC | O_CREAT, dcc_file_create_mode); + if (dcc->fhandle == -1) { + signal_emit("dcc error file create", 2, dcc, dcc->file); + dcc_destroy(dcc); + return; + } + } + + dcc->databufsize = settings_get_int("dcc_block_size"); + if (dcc->databufsize <= 0) dcc->databufsize = 2048; + dcc->databuf = g_malloc(dcc->databufsize); + + dcc->starttime = time(NULL); + dcc->tagread = g_input_add(dcc->handle, G_INPUT_READ, + (GInputFunction) sig_dccget_receive, dcc); + signal_emit("dcc connected", 1, dcc); } -/* command: DCC GET */ -static void cmd_dcc_get(gchar *data) +static void dcc_get_connect(DCC_REC *dcc) { - DCC_REC *dcc; - GSList *tmp, *next; - gchar *params, *nick, *fname; - gboolean found; - - g_return_if_fail(data != NULL); - - params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &nick, &fname); - if (*nick == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); - - dcc = NULL; found = FALSE; - for (tmp = dcc_conns; tmp != NULL; tmp = next) - { - dcc = tmp->data; - next = tmp->next; - - if (dcc->dcc_type == DCC_TYPE_GET && dcc->handle == -1 && g_strcasecmp(dcc->nick, nick) == 0 && - (*fname == '\0' || strcmp(dcc->arg, fname) == 0)) - { - /* found! */ - found = TRUE; - dcc->handle = net_connect_ip(&dcc->addr, dcc->port, - source_host_ok ? source_host_ip : NULL); - if (dcc->handle != -1) - { + dcc->handle = net_connect_ip(&dcc->addr, dcc->port, + source_host_ok ? source_host_ip : NULL); + if (dcc->handle != -1) { dcc->tagread = g_input_add(dcc->handle, G_INPUT_WRITE|G_INPUT_READ|G_INPUT_EXCEPTION, - (GInputFunction) dcc_get_connect, dcc); - } - else - { + (GInputFunction) sig_dccget_connected, dcc); + } else { /* error connecting */ signal_emit("dcc error connect", 1, dcc); dcc_destroy(dcc); - } } - } +} + +#define dcc_is_unget(dcc) \ + ((dcc)->type == DCC_TYPE_GET && (dcc)->handle == -1) + +static void cmd_dcc_get(const char *data) +{ + DCC_REC *dcc; + GSList *tmp, *next; + char *params, *nick, *fname; + int found; + + g_return_if_fail(data != NULL); + + params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &nick, &fname); + if (*nick == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); + + dcc = NULL; found = FALSE; + for (tmp = dcc_conns; tmp != NULL; tmp = next) { + dcc = tmp->data; + next = tmp->next; + + if (dcc_is_unget(dcc) && g_strcasecmp(dcc->nick, nick) == 0 && + (*fname == '\0' || strcmp(dcc->arg, fname) == 0)) { + found = TRUE; + dcc_get_connect(dcc); + } + } - if (!found) - signal_emit("dcc error get not found", 1, nick); + if (!found) + signal_emit("dcc error get not found", 1, nick); - g_free(params); + g_free(params); +} + +static void dcc_resume_send(DCC_REC *dcc, int port) +{ + char *str; + + g_return_if_fail(dcc != NULL); + g_return_if_fail(dcc->type != DCC_TYPE_SEND); + + str = g_strdup_printf("DCC ACCEPT %s %d %lu", + dcc->arg, port, dcc->transfd); + dcc_ctcp_message(dcc->nick, dcc->server, dcc->chat, FALSE, str); + g_free(str); } -/* resume setup: DCC SEND - we either said resume on get, or when we sent, - someone chose resume */ -static void dcc_resume_setup(DCC_REC *dcc, gint port) +static void dcc_resume_get(DCC_REC *dcc) { - gchar *str; - - /* Check for DCC_SEND_RESUME */ - if (dcc->dcc_type == DCC_TYPE_SEND) - { - if (lseek(dcc->fhandle, dcc->transfd, SEEK_SET) == -1) - { - signal_emit("dcc closed", 1, dcc); - dcc_destroy(dcc); - return; - } - else - { - str = g_strdup_printf("DCC ACCEPT %s %d %lu", - dcc->arg, port, dcc->transfd); - dcc_ctcp_message(dcc->nick, dcc->server, dcc->chat, FALSE, str); - g_free(str); - } - } - - /* Check for DCC_GET_RESUME */ - if (dcc->dcc_type == DCC_TYPE_GET && dcc->get_type == DCC_GET_RESUME) - { + g_return_if_fail(dcc != NULL); + g_return_if_fail(dcc->type != DCC_TYPE_GET); + dcc->handle = net_connect_ip(&dcc->addr, dcc->port, source_host_ok ? source_host_ip : NULL); - if (dcc->handle != -1) - { - dcc->tagread = g_input_add(dcc->handle, G_INPUT_WRITE|G_INPUT_READ|G_INPUT_EXCEPTION, - (GInputFunction) dcc_get_connect, dcc); - } - else - { - /* error connecting */ - signal_emit("dcc error connect", 1, dcc); - dcc_destroy(dcc); + if (dcc->handle != -1) { + dcc->tagread = g_input_add(dcc->handle, G_INPUT_WRITE|G_INPUT_READ|G_INPUT_EXCEPTION, + (GInputFunction) dcc_get_connect, dcc); + } else { + /* error connecting */ + signal_emit("dcc error connect", 1, dcc); + dcc_destroy(dcc); } - } } -static void dcc_ctcp_msg(gchar *data, IRC_SERVER_REC *server, gchar *sender, gchar *sendaddr, gchar *target, DCC_REC *chat) +#define is_resume_type(type) \ + (g_strcasecmp(type, "RESUME") == 0 || g_strcasecmp(type, "ACCEPT") == 0) + +#define is_resume_ok(type, dcc) \ + (g_strcasecmp(type, "RESUME") != 0 || ((dcc)->type == DCC_TYPE_SEND && (dcc)->transfd == 0)) + +#define is_accept_ok(type, dcc) \ + (g_strcasecmp(type, "ACCEPT") != 0 || ((dcc)->type == DCC_TYPE_GET && (dcc)->type == DCC_GET_RESUME)) + +static void dcc_ctcp_msg(const char *data, IRC_SERVER_REC *server, + const char *sender, const char *sendaddr, + const char *target, DCC_REC *chat) { - gchar *params, *type, *arg, *portstr, *sizestr; - gulong size; - gint port; - DCC_REC *dcc; + char *params, *type, *arg, *portstr, *sizestr; + unsigned long size; + int port; + DCC_REC *dcc; - g_return_if_fail(data != NULL); - g_return_if_fail(sender != NULL); + g_return_if_fail(data != NULL); + g_return_if_fail(sender != NULL); - params = cmd_get_params(data, 4, &type, &arg, &portstr, &sizestr); - if (g_strcasecmp(type, "RESUME") == 0 || g_strcasecmp(type, "ACCEPT") == 0) - { - if (sscanf(portstr, "%d", &port) != 1) port = 0; - if (sscanf(sizestr, "%lu", &size) != 1) size = 0; + params = cmd_get_params(data, 4, &type, &arg, &portstr, &sizestr); + + port = atoi(portstr); + size = atol(sizestr); dcc = dcc_find_by_port(sender, port); - if (dcc != NULL && (dcc->dcc_type == DCC_TYPE_GET || dcc->transfd == 0)) - { - dcc->transfd = size; - dcc->skipped = size; - dcc_resume_setup(dcc, port); + if (dcc == NULL || !is_resume_type(type) || + !is_resume_ok(type, dcc) || !is_accept_ok(type, dcc)) { + g_free(params); + return; } - } - g_free(params); + if (lseek(dcc->fhandle, size, SEEK_SET) != dcc->transfd) { + /* error, or trying to seek after end of file */ + signal_emit("dcc closed", 1, dcc); + dcc_destroy(dcc); + return; + } + dcc->transfd = dcc->skipped = size; + + if (dcc->type == DCC_TYPE_SEND) + dcc_resume_send(dcc, port); + else + dcc_resume_get(dcc); + + g_free(params); } static void dcc_resume_rec(DCC_REC *dcc) { - gchar *str; - - dcc->file = dcc_prepare_path(dcc->arg); - - dcc->fhandle = open(dcc->file, O_WRONLY, dcc_file_create_mode); - if (dcc->fhandle == -1) - { - signal_emit("dcc error file not found", 2, dcc, dcc->file); - dcc_destroy(dcc); - } - else - { + char *str; + + g_return_if_fail(dcc != NULL); + + dcc->get_type = DCC_GET_RESUME; + dcc->file = dcc_prepare_path(dcc->arg); + + dcc->fhandle = open(dcc->file, O_WRONLY, dcc_file_create_mode); + if (dcc->fhandle == -1) { + signal_emit("dcc error file not found", 2, dcc, dcc->file); + dcc_destroy(dcc); + return; + } + dcc->transfd = lseek(dcc->fhandle, 0, SEEK_END); if (dcc->transfd < 0) dcc->transfd = 0; dcc->skipped = dcc->transfd; @@ -289,266 +340,247 @@ static void dcc_resume_rec(DCC_REC *dcc) dcc->arg, dcc->port, dcc->transfd); dcc_ctcp_message(dcc->nick, dcc->server, dcc->chat, FALSE, str); g_free(str); - } } -/* command: DCC RESUME */ -static void cmd_dcc_resume(gchar *data) +static void cmd_dcc_resume(const char *data) { - DCC_REC *dcc; - GSList *tmp; - gchar *params, *nick, *fname; - gboolean found; - - g_return_if_fail(data != NULL); - - params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &nick, &fname); - if (*nick == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); - - dcc = NULL; found = FALSE; - for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next) - { - dcc = tmp->data; - - if (dcc->dcc_type == DCC_TYPE_GET && dcc->handle == -1 && g_strcasecmp(dcc->nick, nick) == 0 && - (*fname == '\0' || strcmp(dcc->arg, fname) == 0)) - { - /* found! */ - dcc->get_type = DCC_GET_RESUME; - dcc_resume_rec(dcc); - found = TRUE; - } - } - - if (!found) - signal_emit("dcc error get not found", 1, nick); - - g_free(params); + DCC_REC *dcc; + GSList *tmp; + char *params, *nick, *fname; + int found; + + g_return_if_fail(data != NULL); + + params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &nick, &fname); + if (*nick == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); + + dcc = NULL; found = FALSE; + for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next) { + dcc = tmp->data; + + if (dcc_is_unget(dcc) && g_strcasecmp(dcc->nick, nick) == 0 && + (*fname == '\0' || strcmp(dcc->arg, fname) == 0)) { + dcc_resume_rec(dcc); + found = TRUE; + } + } + + if (!found) + signal_emit("dcc error get not found", 1, nick); + + g_free(params); } -/* input function: DCC SEND send more data */ +/* input function: DCC SEND - we're ready to send more data */ static void dcc_send_data(DCC_REC *dcc) { - gint n; - - g_return_if_fail(dcc != NULL); - - if (!dcc->fastsend && !dcc->gotalldata) - { - /* haven't received everything we've send there yet.. */ - return; - } - - n = read(dcc->fhandle, dcc->databuf, dcc->databufsize); - if (n <= 0) - { - /* end of file .. or some error .. */ - if (dcc->fastsend) - { - /* no need to call this function anymore.. in fact it just eats - all the cpu.. */ - dcc->waitforend = TRUE; - g_source_remove(dcc->tagwrite); - dcc->tagwrite = -1; - } - else - { - signal_emit("dcc closed", 1, dcc); - dcc_destroy(dcc); - } - return; - } - - dcc->transfd += net_transmit(dcc->handle, dcc->databuf, n); - dcc->gotalldata = FALSE; - - lseek(dcc->fhandle, dcc->transfd, SEEK_SET); - - signal_emit("dcc transfer update", 1, dcc); + int ret; + + g_return_if_fail(dcc != NULL); + + if (!dcc->fastsend && !dcc->gotalldata) { + /* haven't received everything we've send there yet.. */ + return; + } + + ret = read(dcc->fhandle, dcc->databuf, dcc->databufsize); + if (ret <= 0) { + /* end of file .. or some error .. */ + if (dcc->fastsend) { + /* no need to call this function anymore.. + in fact it just eats all the cpu.. */ + dcc->waitforend = TRUE; + g_source_remove(dcc->tagwrite); + dcc->tagwrite = -1; + } else { + signal_emit("dcc closed", 1, dcc); + dcc_destroy(dcc); + } + return; + } + + ret = net_transmit(dcc->handle, dcc->databuf, ret); + if (ret > 0) dcc->transfd += ret; + dcc->gotalldata = FALSE; + + lseek(dcc->fhandle, dcc->transfd, SEEK_SET); + + signal_emit("dcc transfer update", 1, dcc); } -/* input function: DCC SEND received some data */ +/* input function: DCC SEND - received some data */ static void dcc_send_read_size(DCC_REC *dcc) { - guint32 bytes; - gint ret; - - g_return_if_fail(dcc != NULL); - - if (dcc->read_pos == 4) - return; - - /* we need to get 4 bytes.. */ - ret = net_receive(dcc->handle, dcc->read_buf+dcc->read_pos, 4-dcc->read_pos); - if (ret == -1) - { - signal_emit("dcc closed", 1, dcc); - dcc_destroy(dcc); - return; - } - - dcc->read_pos += ret; - - if (dcc->read_pos == 4) - { - bytes = 0; memcpy(&bytes, dcc->read_buf, 4); - bytes = (guint32) ntohl(bytes); - - dcc->gotalldata = bytes == dcc->transfd; - dcc->read_pos = 0; - - if (!dcc->fastsend) - { - /* send more data.. */ - dcc_send_data(dcc); - } - - if (dcc->waitforend && dcc->gotalldata) - { - /* file is sent */ - signal_emit("dcc closed", 1, dcc); - dcc_destroy(dcc); - return; - } - } + guint32 bytes; + int ret; + + g_return_if_fail(dcc != NULL); + + if (dcc->count_pos == 4) + return; + + /* we need to get 4 bytes.. */ + ret = net_receive(dcc->handle, dcc->count_buf+dcc->count_pos, 4-dcc->count_pos); + if (ret == -1) { + signal_emit("dcc closed", 1, dcc); + dcc_destroy(dcc); + return; + } + + dcc->count_pos += ret; + + if (dcc->count_pos != 4) + return; + + memcpy(&bytes, dcc->count_buf, 4); + bytes = (guint32) ntohl(bytes); + + dcc->gotalldata = bytes == dcc->transfd; + dcc->count_pos = 0; + + if (!dcc->fastsend) { + /* send more data.. */ + dcc_send_data(dcc); + } + + if (dcc->waitforend && dcc->gotalldata) { + /* file is sent */ + signal_emit("dcc closed", 1, dcc); + dcc_destroy(dcc); + } } /* input function: DCC SEND - someone tried to connect to our socket */ static void dcc_send_init(DCC_REC *dcc) { - gint handle, port; - IPADDR addr; - - g_return_if_fail(dcc != NULL); - - /* accept connection */ - handle = net_accept(dcc->handle, &addr, &port); - if (handle == -1) - return; - - /* FIXME: add paranoia checking, check if host ip is the same as to who - we sent the DCC SEND request.. */ - - g_source_remove(dcc->tagread); - close(dcc->handle); - - dcc->fastsend = settings_get_bool("dcc_fast_send"); - dcc->handle = handle; - memcpy(&dcc->addr, &addr, sizeof(IPADDR)); - net_ip2host(&dcc->addr, dcc->addrstr); - dcc->port = port; - dcc->databufsize = settings_get_int("dcc_block_size") > 0 ? settings_get_int("dcc_block_size") : 2048; - dcc->databuf = g_malloc(dcc->databufsize); - dcc->starttime = time(NULL); - dcc->tagread = g_input_add(handle, G_INPUT_READ, - (GInputFunction) dcc_send_read_size, dcc); - dcc->tagwrite = !dcc->fastsend ? -1 : - g_input_add(handle, G_INPUT_WRITE, (GInputFunction) dcc_send_data, dcc); - - signal_emit("dcc connected", 1, dcc); - - if (!dcc->fastsend) - { - /* send first block */ - dcc->gotalldata = TRUE; - dcc_send_data(dcc); - } + int handle, port; + IPADDR addr; + + g_return_if_fail(dcc != NULL); + + /* accept connection */ + handle = net_accept(dcc->handle, &addr, &port); + if (handle == -1) + return; + + /* TODO: some kind of paranoia check would be nice. it would check + that the host of the nick who we sent the request matches the + address who connected us. */ + + g_source_remove(dcc->tagread); + close(dcc->handle); + + dcc->starttime = time(NULL); + dcc->fastsend = settings_get_bool("dcc_fast_send"); + dcc->handle = handle; + memcpy(&dcc->addr, &addr, sizeof(IPADDR)); + net_ip2host(&dcc->addr, dcc->addrstr); + dcc->port = port; + + dcc->databufsize = settings_get_int("dcc_block_size"); + if (dcc->databufsize <= 0) dcc->databufsize = 2048; + dcc->databuf = g_malloc(dcc->databufsize); + + dcc->tagread = g_input_add(handle, G_INPUT_READ, + (GInputFunction) dcc_send_read_size, dcc); + dcc->tagwrite = !dcc->fastsend ? -1 : + g_input_add(handle, G_INPUT_WRITE, (GInputFunction) dcc_send_data, dcc); + + signal_emit("dcc connected", 1, dcc); + + if (!dcc->fastsend) { + /* send first block */ + dcc->gotalldata = TRUE; + dcc_send_data(dcc); + } } /* command: DCC SEND */ -static void cmd_dcc_send(gchar *data, IRC_SERVER_REC *server, WI_IRC_REC *item) +static void cmd_dcc_send(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item) { - gchar *params, *target, *fname, *str, *ptr; - gint fh, h, port; - glong fsize; - DCC_REC *dcc, *chat; - IPADDR addr; + char *params, *target, *fname, *str, *ptr; + char host[MAX_IP_LEN]; + int hfile, hlisten, port; + long fsize; + DCC_REC *dcc, *chat; + IPADDR own_ip; + + g_return_if_fail(data != NULL); + + params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &fname); + if (*target == '\0' || *fname == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); - g_return_if_fail(data != NULL); + /* if we're in dcc chat, send the request via it. */ + chat = item_get_dcc(item); - params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &fname); + if (chat != NULL && (chat->mirc_ctcp || g_strcasecmp(target, chat->nick) != 0)) + chat = NULL; - /* if we're in dcc chat, send the request via it. */ - chat = irc_item_dcc_chat(item); + if ((server == NULL || !server->connected) && chat == NULL) + cmd_param_error(CMDERR_NOT_CONNECTED); - if (chat != NULL && (chat->mirc_ctcp || g_strcasecmp(target, chat->nick) != 0)) - chat = NULL; + if (dcc_find_item(DCC_TYPE_SEND, target, fname)) { + signal_emit("dcc error send exists", 2, target, fname); + g_free(params); + return; + } + + str = convert_home(fname); + if (!g_path_is_absolute(str)) { + char *path; - if ((server == NULL || !server->connected) && chat == NULL) - cmd_param_error(CMDERR_NOT_CONNECTED); + g_free(str); + path = convert_home(settings_get_str("dcc_upload_path")); + str = g_strconcat(path, G_DIR_SEPARATOR_S, fname, NULL); + g_free(path); + } - if (*target == '\0' || *fname == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); + hfile = open(str, O_RDONLY); + g_free(str); - if (dcc_find_item(DCC_TYPE_SEND, target, fname)) - { - signal_emit("dcc error send exists", 2, target, fname); - g_free(params); - return; - } + if (hfile == -1) { + signal_emit("dcc error file not found", 2, target, fname); + g_free(params); + return; + } + fsize = lseek(hfile, 0, SEEK_END); + lseek(hfile, 0, SEEK_SET); - str = convert_home(fname); - if (*str != '/') - { - gchar *path; + /* get the IP address we use with IRC server */ + if (net_getsockname(chat != NULL ? chat->handle : server->handle, &own_ip, NULL) == -1) { + close(hfile); + cmd_param_error(CMDERR_ERRNO); + } - g_free(str); - path = convert_home(settings_get_str("dcc_upload_path")); - str = g_strconcat(path, "/", fname, NULL); - g_free(path); - } + /* start listening */ + port = settings_get_int("dcc_port"); + hlisten = net_listen(&own_ip, &port); + if (hlisten == -1) { + close(hfile); + cmd_param_error(CMDERR_ERRNO); + } - fh = open(str, O_RDONLY); - g_free(str); + /* skip path, change all spaces to _ */ + fname = g_strdup(g_basename(fname)); + for (ptr = fname; *ptr != '\0'; ptr++) + if (*ptr == ' ') *ptr = '_'; + + dcc = dcc_create(DCC_TYPE_SEND, hlisten, target, fname, server, chat); + dcc->port = port; + dcc->size = fsize; + dcc->fhandle = hfile; + dcc->tagread = g_input_add(hlisten, G_INPUT_READ, + (GInputFunction) dcc_send_init, dcc); + + /* send DCC request */ + dcc_make_address(&own_ip, host); + str = g_strdup_printf("DCC SEND %s %s %d %lu", + fname, host, port, fsize); + dcc_ctcp_message(target, server, chat, FALSE, str); + g_free(str); - if (fh == -1) - { - signal_emit("dcc error file not found", 2, target, fname); + g_free(fname); g_free(params); - return; - } - fsize = lseek(fh, 0, SEEK_END); - lseek(fh, 0, SEEK_SET); - - /* get the IP address we use with IRC server */ - if (net_getsockname(chat != NULL ? chat->handle : server->handle, &addr, NULL) == -1) - { - close(fh); - cmd_param_error(CMDERR_ERRNO); - } - - /* start listening */ - port = settings_get_int("dcc_port"); - h = net_listen(&addr, &port); - if (h == -1) - { - close(fh); - cmd_param_error(CMDERR_ERRNO); - } - - /* skip path */ - ptr = strrchr(fname, '/'); - if (ptr != NULL) fname = ptr+1; - - /* change all spaces to _ */ - fname = g_strdup(fname); - for (ptr = fname; *ptr != '\0'; ptr++) - if (*ptr == ' ') *ptr = '_'; - - dcc = dcc_create(DCC_TYPE_SEND, h, target, fname, server, chat); - dcc->port = port; - dcc->size = fsize; - dcc->fhandle = fh; - dcc->tagread = g_input_add(h, G_INPUT_READ, - (GInputFunction) dcc_send_init, dcc); - - /* send DCC request */ - str = g_strdup_printf("DCC SEND %s %s %d %lu", - fname, dcc_make_address(&addr), port, fsize); - dcc_ctcp_message(target, server, chat, FALSE, str); - g_free(str); - - g_free(fname); - g_free(params); } static void read_settings(void) @@ -558,20 +590,20 @@ static void read_settings(void) void dcc_files_init(void) { - signal_add("ctcp msg dcc", (SIGNAL_FUNC) dcc_ctcp_msg); - signal_add("setup changed", (SIGNAL_FUNC) read_settings); - signal_add("irssi init finished", (SIGNAL_FUNC) read_settings); - command_bind("dcc send", NULL, (SIGNAL_FUNC) cmd_dcc_send); - command_bind("dcc get", NULL, (SIGNAL_FUNC) cmd_dcc_get); - command_bind("dcc resume", NULL, (SIGNAL_FUNC) cmd_dcc_resume); + signal_add("ctcp msg dcc", (SIGNAL_FUNC) dcc_ctcp_msg); + signal_add("setup changed", (SIGNAL_FUNC) read_settings); + signal_add("irssi init finished", (SIGNAL_FUNC) read_settings); + command_bind("dcc send", NULL, (SIGNAL_FUNC) cmd_dcc_send); + command_bind("dcc get", NULL, (SIGNAL_FUNC) cmd_dcc_get); + command_bind("dcc resume", NULL, (SIGNAL_FUNC) cmd_dcc_resume); } void dcc_files_deinit(void) { - signal_remove("ctcp msg dcc", (SIGNAL_FUNC) dcc_ctcp_msg); - signal_remove("setup changed", (SIGNAL_FUNC) read_settings); - signal_remove("irssi init finished", (SIGNAL_FUNC) read_settings); - command_unbind("dcc send", (SIGNAL_FUNC) cmd_dcc_send); - command_unbind("dcc get", (SIGNAL_FUNC) cmd_dcc_get); - command_unbind("dcc resume", (SIGNAL_FUNC) cmd_dcc_resume); + signal_remove("ctcp msg dcc", (SIGNAL_FUNC) dcc_ctcp_msg); + signal_remove("setup changed", (SIGNAL_FUNC) read_settings); + signal_remove("irssi init finished", (SIGNAL_FUNC) read_settings); + command_unbind("dcc send", (SIGNAL_FUNC) cmd_dcc_send); + command_unbind("dcc get", (SIGNAL_FUNC) cmd_dcc_get); + command_unbind("dcc resume", (SIGNAL_FUNC) cmd_dcc_resume); } diff --git a/src/irc/dcc/dcc.c b/src/irc/dcc/dcc.c index 5bfc417f..ae6fd586 100644 --- a/src/irc/dcc/dcc.c +++ b/src/irc/dcc/dcc.c @@ -1,7 +1,7 @@ /* dcc.c : irssi - Copyright (C) 1999 Timo Sirainen + Copyright (C) 1999-2000 Timo Sirainen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -38,181 +38,178 @@ void dcc_files_deinit(void); #define DCC_TYPES 5 -static gchar *dcc_types[] = -{ - "CHAT", - "SEND", - "GET", - "RESUME", - "ACCEPT" +static char *dcc_types[] = { + "CHAT", + "SEND", + "GET", + "RESUME", + "ACCEPT" }; GSList *dcc_conns; -static gint dcc_timeouttag; +static int dcc_timeouttag; /* Create new DCC record */ -DCC_REC *dcc_create(gint type, gint handle, gchar *nick, gchar *arg, IRC_SERVER_REC *server, DCC_REC *chat) +DCC_REC *dcc_create(int type, int handle, const char *nick, const char *arg, + IRC_SERVER_REC *server, DCC_REC *chat) { - DCC_REC *dcc; - - g_return_val_if_fail(nick != NULL, NULL); - g_return_val_if_fail(arg != NULL, NULL); - - dcc = g_new0(DCC_REC, 1); - dcc->type = type == DCC_TYPE_CHAT ? module_get_uniq_id("IRC", WI_IRC_DCC_CHAT) : -1; - dcc->mirc_ctcp = settings_get_bool("dcc_mirc_ctcp"); - dcc->created = time(NULL); - dcc->chat = chat; - dcc->dcc_type = type; - dcc->arg = g_strdup(arg); - dcc->nick = g_strdup(nick); - dcc->handle = handle; - dcc->fhandle = -1; - dcc->tagread = dcc->tagwrite = -1; - dcc->server = server; - dcc->mynick = g_strdup(server != NULL ? server->nick : - chat != NULL ? chat->nick : "??"); - dcc->ircnet = server == NULL ? - chat == NULL || chat->ircnet == NULL ? NULL : g_strdup(chat->ircnet) : - server->connrec->ircnet == NULL ? NULL : g_strdup(server->connrec->ircnet); - dcc_conns = g_slist_append(dcc_conns, dcc); - - signal_emit("dcc created", 1, dcc); - return dcc; + DCC_REC *dcc; + + g_return_val_if_fail(nick != NULL, NULL); + g_return_val_if_fail(arg != NULL, NULL); + + dcc = g_new0(DCC_REC, 1); + dcc->mirc_ctcp = settings_get_bool("dcc_mirc_ctcp"); + dcc->created = time(NULL); + dcc->chat = chat; + dcc->type = type; + dcc->arg = g_strdup(arg); + dcc->nick = g_strdup(nick); + dcc->handle = handle; + dcc->fhandle = -1; + dcc->tagread = dcc->tagwrite = -1; + dcc->server = server; + dcc->mynick = g_strdup(server != NULL ? server->nick : + chat != NULL ? chat->nick : "??"); + + dcc->ircnet = server == NULL ? + (chat == NULL || chat->ircnet == NULL ? NULL : g_strdup(chat->ircnet)) : + (server->connrec->ircnet == NULL ? NULL : g_strdup(server->connrec->ircnet)); + dcc_conns = g_slist_append(dcc_conns, dcc); + + signal_emit("dcc created", 1, dcc); + return dcc; } -/* Destroy DCC record */ -void dcc_destroy(DCC_REC *dcc) +static void dcc_remove_chat_refs(DCC_REC *dcc) { - GSList *tmp; - - g_return_if_fail(dcc != NULL); - - dcc_conns = g_slist_remove(dcc_conns, dcc); + GSList *tmp; - /* remove dcc chat references.. */ - for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next) - { - DCC_REC *rec = tmp->data; + g_return_if_fail(dcc != NULL); - if (rec->chat == dcc) - rec->chat = NULL; - } + for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next) { + DCC_REC *rec = tmp->data; - signal_emit("dcc destroyed", 1, dcc); - - if (dcc->fhandle != -1) close(dcc->fhandle); - if (dcc->handle != -1) net_disconnect(dcc->handle); - if (dcc->tagread != -1) g_source_remove(dcc->tagread); - if (dcc->tagwrite != -1) g_source_remove(dcc->tagwrite); - - if (dcc->dcc_type == DCC_TYPE_CHAT) - line_split_free((LINEBUF_REC *) dcc->databuf); - else if (dcc->databuf != NULL) g_free(dcc->databuf); - if (dcc->file != NULL) g_free(dcc->file); - if (dcc->ircnet != NULL) g_free(dcc->ircnet); - g_free(dcc->mynick); - g_free(dcc->nick); - g_free(dcc->arg); - g_free(dcc); + if (rec->chat == dcc) + rec->chat = NULL; + } } -gchar *dcc_make_address(IPADDR *ip) +/* Destroy DCC record */ +void dcc_destroy(DCC_REC *dcc) { - static gchar str[MAX_IP_LEN]; - gulong addr; - - if (is_ipv6_addr(ip)) - { - /* IPv6 */ - net_ip2host(ip, str); - } - else - { - memcpy(&addr, &ip->addr, 4); - sprintf(str, "%lu", (unsigned long) htonl(addr)); - } + g_return_if_fail(dcc != NULL); + if (dcc->destroyed) return; + + dcc_conns = g_slist_remove(dcc_conns, dcc); + dcc_remove_chat_refs(dcc); + + dcc->destroyed = TRUE; + signal_emit("dcc destroyed", 1, dcc); + + if (dcc->fhandle != -1) close(dcc->fhandle); + if (dcc->handle != -1) net_disconnect(dcc->handle); + if (dcc->tagread != -1) g_source_remove(dcc->tagread); + if (dcc->tagwrite != -1) g_source_remove(dcc->tagwrite); + + if (dcc->type == DCC_TYPE_CHAT) + line_split_free((LINEBUF_REC *) dcc->databuf); + else if (dcc->databuf != NULL) + g_free(dcc->databuf); + + g_free_not_null(dcc->file); + g_free_not_null(dcc->ircnet); + g_free(dcc->mynick); + g_free(dcc->nick); + g_free(dcc->arg); + g_free(dcc); +} - return str; +void dcc_make_address(IPADDR *ip, char *host) +{ + unsigned long addr; + + if (is_ipv6_addr(ip)) { + /* IPv6 */ + net_ip2host(ip, host); + } else { + memcpy(&addr, &ip->addr, 4); + sprintf(host, "%lu", (unsigned long) htonl(addr)); + } } /* Find DCC record, arg can be NULL */ -DCC_REC *dcc_find_item(gint type, gchar *nick, gchar *arg) +DCC_REC *dcc_find_item(int type, const char *nick, const char *arg) { - DCC_REC *dcc; - GSList *tmp; + DCC_REC *dcc; + GSList *tmp; - g_return_val_if_fail(nick != NULL, NULL); + g_return_val_if_fail(nick != NULL, NULL); - for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next) - { - dcc = tmp->data; + for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next) { + dcc = tmp->data; - if (dcc->dcc_type == type && g_strcasecmp(dcc->nick, nick) == 0 && - (arg == NULL || strcmp(dcc->arg, arg) == 0)) - return dcc; - } + if (dcc->type == type && g_strcasecmp(dcc->nick, nick) == 0 && + (arg == NULL || strcmp(dcc->arg, arg) == 0)) + return dcc; + } - return NULL; + return NULL; } /* Find DCC record by port # */ -DCC_REC *dcc_find_by_port(gchar *nick, gint port) +DCC_REC *dcc_find_by_port(const char *nick, int port) { - DCC_REC *dcc; - GSList *tmp; + DCC_REC *dcc; + GSList *tmp; - for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next) - { - dcc = tmp->data; + for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next) { + dcc = tmp->data; - if (dcc->port == port && ((dcc->dcc_type == DCC_TYPE_GET || dcc->dcc_type == DCC_TYPE_SEND) && g_strcasecmp(dcc->nick, nick) == 0)) - { - /* found! */ - return dcc; - } - } + if ((dcc->type == DCC_TYPE_GET || dcc->type == DCC_TYPE_SEND) && + dcc->port == port && g_strcasecmp(dcc->nick, nick) == 0) + return dcc; + } - return NULL; + return NULL; } -gchar *dcc_type2str(gint type) +const char *dcc_type2str(int type) { - g_return_val_if_fail(type >= 1 && type <= DCC_TYPES, NULL); - return dcc_types[type-1]; + g_return_val_if_fail(type >= 1 && type <= DCC_TYPES, NULL); + + return dcc_types[type-1]; } -gint dcc_str2type(gchar *type) +int dcc_str2type(const char *type) { - gint num; + int num; - for (num = 0; num < DCC_TYPES; num++) - if (g_strcasecmp(dcc_types[num], type) == 0) return num+1; + for (num = 0; num < DCC_TYPES; num++) { + if (g_strcasecmp(dcc_types[num], type) == 0) + return num+1; + } - return 0; + return 0; } -void dcc_ctcp_message(gchar *target, IRC_SERVER_REC *server, DCC_REC *chat, gboolean notice, gchar *msg) +void dcc_ctcp_message(const char *target, IRC_SERVER_REC *server, DCC_REC *chat, int notice, const char *msg) { - gchar *str; - - if (chat != NULL) - { - /* send it via open DCC chat */ - /* FIXME: we need output queue! */ - str = g_strdup_printf("%s\001%s\001\n", chat->mirc_ctcp ? "" : - notice ? "CTCP_REPLY " : "CTCP_MESSAGE ", msg); - net_transmit(chat->handle, str, strlen(str)); - } - else - { - str = g_strdup_printf("%s %s :\001%s\001", - notice ? "NOTICE" : "PRIVMSG", target, msg); - irc_send_cmd(server, str); - } + char *str; + + if (chat != NULL) { + /* send it via open DCC chat */ + str = g_strdup_printf("%s\001%s\001", chat->mirc_ctcp ? "" : + notice ? "CTCP_REPLY " : "CTCP_MESSAGE ", msg); + dcc_chat_send(chat, str); + } else { + str = g_strdup_printf("%s %s :\001%s\001", + notice ? "NOTICE" : "PRIVMSG", target, msg); + irc_send_cmd(server, str); + } - g_free(str); + g_free(str); } /* Server connected, check if there's any open dcc sessions for this ircnet.. */ @@ -240,59 +237,52 @@ static void dcc_server_connected(IRC_SERVER_REC *server) /* Server disconnected, remove it from all dcc records */ static void dcc_server_disconnected(IRC_SERVER_REC *server) { - GSList *tmp; + GSList *tmp; - g_return_if_fail(server != NULL); + g_return_if_fail(server != NULL); - for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next) - { - DCC_REC *dcc = tmp->data; + for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next) { + DCC_REC *dcc = tmp->data; - if (dcc->server == server) - { - if (dcc->ircnet == NULL) - dcc->server = NULL; - else - { - dcc->server = (IRC_SERVER_REC *) server_find_ircnet(dcc->ircnet); - if (dcc->server != NULL) - { - g_free(dcc->mynick); - dcc->mynick = g_strdup(dcc->server->nick); - } - } - } - } + if (dcc->server != server) + continue; + + if (dcc->ircnet == NULL) + dcc->server = NULL; + else { + dcc->server = (IRC_SERVER_REC *) server_find_ircnet(dcc->ircnet); + if (dcc->server != NULL) { + g_free(dcc->mynick); + dcc->mynick = g_strdup(dcc->server->nick); + } + } + } } -static void dcc_get_address(gchar *str, IPADDR *ip) +static void dcc_get_address(const char *str, IPADDR *ip) { - gulong addr; - - if (strchr(str, ':') == NULL) - { - /* normal IPv4 address */ - if (sscanf(str, "%lu", &addr)!=1) - addr = 0; - ip->family = AF_INET; - addr = (gulong) ntohl(addr); - memcpy(&ip->addr, &addr, 4); - } - else - { - /* IPv6 */ - net_host2ip(str, ip); - } + unsigned long addr; + + if (strchr(str, ':') == NULL) { + /* normal IPv4 address in 32bit number form */ + addr = atol(str); + ip->family = AF_INET; + addr = (unsigned long) ntohl(addr); + memcpy(&ip->addr, &addr, 4); + } else { + /* IPv6 - in standard form */ + net_host2ip(str, ip); + } } /* Handle incoming DCC CTCP messages */ -static void dcc_ctcp_msg(gchar *data, IRC_SERVER_REC *server, gchar *sender, gchar *sendaddr, gchar *target, DCC_REC *chat) +static void dcc_ctcp_msg(char *data, IRC_SERVER_REC *server, char *sender, char *sendaddr, char *target, DCC_REC *chat) { - gchar *params, *type, *arg, *addrstr, *portstr, *sizestr, *str; + char *params, *type, *arg, *addrstr, *portstr, *sizestr, *str; const char *cstr; DCC_REC *dcc; gulong size; - gint port; + int port; g_return_if_fail(data != NULL); g_return_if_fail(sender != NULL); @@ -308,7 +298,7 @@ static void dcc_ctcp_msg(gchar *data, IRC_SERVER_REC *server, gchar *sender, gch dcc->port = port; dcc->size = size; - switch (dcc->dcc_type) + switch (dcc->type) { case DCC_TYPE_GET: cstr = settings_get_str("dcc_autoget_masks"); @@ -362,10 +352,10 @@ static void dcc_ctcp_msg(gchar *data, IRC_SERVER_REC *server, gchar *sender, gch } /* Handle incoming DCC CTCP replies */ -static void dcc_ctcp_reply(gchar *data, IRC_SERVER_REC *server, gchar *sender, gchar *sendaddr) +static void dcc_ctcp_reply(char *data, IRC_SERVER_REC *server, char *sender, char *sendaddr) { - gchar *params, *cmd, *subcmd, *args; - gint type; + char *params, *cmd, *subcmd, *args; + int type; DCC_REC *dcc; g_return_if_fail(data != NULL); @@ -379,7 +369,6 @@ static void dcc_ctcp_reply(gchar *data, IRC_SERVER_REC *server, gchar *sender, g dcc = dcc_find_item(type, sender, type == DCC_TYPE_CHAT ? NULL : args); if (dcc != NULL) { - dcc->destroyed = TRUE; signal_emit("dcc closed", 1, dcc); dcc_destroy(dcc); } @@ -395,34 +384,33 @@ static void dcc_ctcp_reply(gchar *data, IRC_SERVER_REC *server, gchar *sender, g static void dcc_reject(DCC_REC *dcc, IRC_SERVER_REC *server) { - gchar *str; + char *str; g_return_if_fail(dcc != NULL); if (dcc->server != NULL) server = dcc->server; - if (server != NULL && (dcc->dcc_type != DCC_TYPE_CHAT || dcc->starttime == 0)) + if (server != NULL && (dcc->type != DCC_TYPE_CHAT || dcc->starttime == 0)) { signal_emit("dcc rejected", 1, dcc); str = g_strdup_printf("NOTICE %s :\001DCC REJECT %s %s\001", - dcc->nick, dcc_type2str(SWAP_SENDGET(dcc->dcc_type)), dcc->arg); + dcc->nick, dcc_type2str(SWAP_SENDGET(dcc->type)), dcc->arg); irc_send_cmd(server, str); g_free(str); } - dcc->destroyed = TRUE; signal_emit("dcc closed", 1, dcc); dcc_destroy(dcc); } /* command: DCC CLOSE */ -static void cmd_dcc_close(gchar *data, IRC_SERVER_REC *server) +static void cmd_dcc_close(char *data, IRC_SERVER_REC *server) { DCC_REC *dcc; GSList *tmp, *next; - gchar *params, *type, *nick, *arg; + char *params, *type, *nick, *arg; gboolean found; - gint itype; + int itype; g_return_if_fail(data != NULL); @@ -443,7 +431,7 @@ static void cmd_dcc_close(gchar *data, IRC_SERVER_REC *server) dcc = tmp->data; next = tmp->next; - if (dcc->dcc_type == itype && g_strcasecmp(nick, dcc->nick) == 0) + if (dcc->type == itype && g_strcasecmp(nick, dcc->nick) == 0) { dcc_reject(dcc, server); found = TRUE; @@ -481,9 +469,9 @@ static int dcc_timeout_func(void) return 1; } -static void event_no_such_nick(gchar *data, IRC_SERVER_REC *server) +static void event_no_such_nick(char *data, IRC_SERVER_REC *server) { - gchar *params, *nick; + char *params, *nick; GSList *tmp, *next; g_return_if_fail(data != NULL); @@ -499,7 +487,6 @@ static void event_no_such_nick(gchar *data, IRC_SERVER_REC *server) if (g_strcasecmp(rec->nick, nick) == 0 && rec->starttime == 0) { /* timed out. */ - rec->destroyed = TRUE; signal_emit("dcc closed", 1, rec); dcc_destroy(rec); } diff --git a/src/irc/dcc/dcc.h b/src/irc/dcc/dcc.h index da640b41..7fe5e9ee 100644 --- a/src/irc/dcc/dcc.h +++ b/src/irc/dcc/dcc.h @@ -3,72 +3,67 @@ #include "network.h" -enum -{ - DCC_TYPE_CHAT = 1, - DCC_TYPE_SEND, - DCC_TYPE_GET, - DCC_TYPE_RESUME, - DCC_TYPE_ACCEPT +enum { + DCC_TYPE_CHAT = 1, + DCC_TYPE_SEND, + DCC_TYPE_GET, + DCC_TYPE_RESUME, + DCC_TYPE_ACCEPT }; -enum -{ - DCC_GET_DEFAULT = 0, - DCC_GET_OVERWRITE, - DCC_GET_RENAME, - DCC_GET_RESUME +enum { + DCC_GET_RENAME = 0, /* this also acts as default */ + DCC_GET_OVERWRITE, + DCC_GET_RESUME }; #define SWAP_SENDGET(a) ((a) == DCC_TYPE_SEND ? DCC_TYPE_GET : \ (a) == DCC_TYPE_GET ? DCC_TYPE_SEND : (a)) -typedef struct DCC_REC -{ +typedef struct DCC_REC { int type; - GHashTable *module_data; + time_t created; IRC_SERVER_REC *server; - gchar *nick; + char *nick; struct DCC_REC *chat; /* if the request came through DCC chat */ - gchar *ircnet; - gchar *mynick; + char *ircnet; + char *mynick; - gchar *arg; - gchar *file; /* file name we're really moving, arg is just the reference.. */ - - time_t created; - gint dcc_type; + char *arg; + char *file; /* file name we're really moving, arg is just the reference.. */ IPADDR addr; /* address we're connected in */ - gchar addrstr[MAX_IP_LEN]; /* in readable form */ - gint port; /* port we're connected in */ + char addrstr[MAX_IP_LEN]; /* in readable form */ + int port; /* port we're connected in */ - glong size, transfd, skipped; /* file size / bytes transferred / skipped at start */ - gint handle; /* socket handle */ - gint tagread, tagwrite; - gint fhandle; /* file handle */ + long size, transfd, skipped; /* file size / bytes transferred / skipped at start */ + int handle; /* socket handle */ + int tagread, tagwrite; + int fhandle; /* file handle */ time_t starttime; /* transfer start time */ - gint trans_bytes; + int trans_bytes; - gboolean fastsend; /* fastsending (just in case that global fastsend toggle changes while transferring..) */ - gboolean waitforend; /* DCC fast send: file is sent, just wait for the replies from the other side */ - gboolean gotalldata; /* DCC fast send: got all acks from the other end (needed to make sure the end of transfer works right) */ - gint get_type; /* DCC get: what to do if file exists? */ + int get_type; /* DCC get: what to do if file exists? */ - gboolean mirc_ctcp; /* DCC chat: Send CTCPs without the CTCP_MESSAGE prefix */ - gboolean destroyed; /* We're about to destroy this DCC recond */ + int fastsend:1; /* fastsending (just in case that global fastsend toggle changes while transferring..) */ + int waitforend:1; /* DCC fast send: file is sent, just wait for the replies from the other side */ + int gotalldata:1; /* DCC fast send: got all acks from the other end (needed to make sure the end of transfer works right) */ - /* read counter buffer */ - gchar read_buf[4]; - gint read_pos; + int mirc_ctcp:1; /* DCC chat: Send CTCPs without the CTCP_MESSAGE prefix */ + int destroyed:1; /* We're about to destroy this DCC recond */ - gchar *databuf; /* buffer for receiving/transmitting data */ - gint databufsize; -} -DCC_REC; + /* read/write counter buffer */ + char count_buf[4]; + int count_pos; + + char *databuf; /* buffer for receiving/transmitting data */ + int databufsize; + + GHashTable *module_data; +} DCC_REC; extern GSList *dcc_conns; @@ -76,16 +71,21 @@ void dcc_init(void); void dcc_deinit(void); /* Find DCC record, arg can be NULL */ -DCC_REC *dcc_find_item(gint type, gchar *nick, gchar *arg); -DCC_REC *dcc_find_by_port(gchar *nick, gint port); +DCC_REC *dcc_find_item(int type, const char *nick, const char *arg); +DCC_REC *dcc_find_by_port(const char *nick, int port); -gchar *dcc_type2str(gint type); -gint dcc_str2type(gchar *type); -gchar *dcc_make_address(IPADDR *ip); +const char *dcc_type2str(int type); +int dcc_str2type(const char *type); +void dcc_make_address(IPADDR *ip, char *host); -DCC_REC *dcc_create(gint type, gint handle, gchar *nick, gchar *arg, IRC_SERVER_REC *server, DCC_REC *chat); +DCC_REC *dcc_create(int type, int handle, const char *nick, const char *arg, IRC_SERVER_REC *server, DCC_REC *chat); void dcc_destroy(DCC_REC *dcc); -void dcc_ctcp_message(gchar *target, IRC_SERVER_REC *server, DCC_REC *chat, gboolean notice, gchar *msg); +void dcc_ctcp_message(const char *target, IRC_SERVER_REC *server, DCC_REC *chat, int notice, const char *msg); + +/* Send `data' to dcc chat. */ +void dcc_chat_send(DCC_REC *dcc, const char *data); +/* If `item' is a query of a =nick, return DCC chat record of nick */ +DCC_REC *item_get_dcc(void *item); #endif |