From 2a40743ed0c8fe728f139895afdb8bd14141e8a9 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 18 Aug 2023 09:34:34 -0500 Subject: [PATCH] xfer: reverse DCC parsing from RtL to LtR. This makes it easier to handle the optional "token" argument at the (right) end, which will be necessary to support passive DCC. Incidentally, this is RtL parsing order is the reason why you'd get a cryptic "0" address error when attempting to do passive DCC: the "token" argument gets misinterpreted as the "size" argument. Every argument "shifts" over by one, leaving an address (port) of "0". --- src/plugins/irc/irc-ctcp.c | 327 +++++++++++++++++++++++++++---------- 1 file changed, 242 insertions(+), 85 deletions(-) diff --git a/src/plugins/irc/irc-ctcp.c b/src/plugins/irc/irc-ctcp.c index c5e1bfa7a..e86a14c90 100644 --- a/src/plugins/irc/irc-ctcp.c +++ b/src/plugins/irc/irc-ctcp.c @@ -747,7 +747,7 @@ irc_ctcp_recv_dcc (struct t_irc_server *server, const char *nick, const char *arguments, const char *message) { char *dcc_args, *pos, *pos_file, *pos_addr, *pos_port, *pos_size; - char *pos_start_resume, *filename; + char *pos_start_resume, *pos_token, *filename; struct t_infolist *infolist; struct t_infolist_item *item; char charset_modifier[1024]; @@ -773,16 +773,58 @@ irc_ctcp_recv_dcc (struct t_irc_server *server, const char *nick, return; } - /* DCC filename */ + /* + * DCC SEND
[] + * ^^^^^^^^^^ + **/ pos_file = dcc_args; while (pos_file[0] == ' ') { pos_file++; } + if (pos_file[0] == '"') + { + /* The file name is wrapped in double-quotes; find the terminating double-quote. */ + pos = strrchr (pos_file, '"'); + if (!pos || (pos == pos_file)) + { + weechat_printf ( + server->buffer, + _("%s%s: cannot parse \"%s\" command"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, "privmsg"); + free (dcc_args); + return; + } + pos[1] = '\0'; + pos += 2; + } + else + { + pos = strchr (pos_file, ' '); + if (!pos) + { + weechat_printf ( + server->buffer, + _("%s%s: cannot parse \"%s\" command"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, "privmsg"); + free (dcc_args); + return; + } + pos[0] = '\0'; + pos++; + } - /* look for file size */ - pos_size = strrchr (pos_file, ' '); - if (!pos_size) + /* + * DCC SEND
[] + * ^^^^^^^^^ + **/ + pos_addr = pos; + while (pos_addr[0] == ' ') + { + pos_addr++; + } + pos = strchr (pos_addr, ' '); + if (!pos) { weechat_printf ( server->buffer, @@ -791,18 +833,20 @@ irc_ctcp_recv_dcc (struct t_irc_server *server, const char *nick, free (dcc_args); return; } + pos[0] = '\0'; + pos++; - pos = pos_size; - pos_size++; - while (pos[0] == ' ') + /* + * DCC SEND
[] + * ^^^^^^ + **/ + pos_port = pos; + while (pos_port[0] == ' ') { - pos--; + pos_port++; } - pos[1] = '\0'; - - /* look for DCC port */ - pos_port = strrchr (pos_file, ' '); - if (!pos_port) + pos = strchr (pos_port, ' '); + if (!pos) { weechat_printf ( server->buffer, @@ -811,38 +855,56 @@ irc_ctcp_recv_dcc (struct t_irc_server *server, const char *nick, free (dcc_args); return; } + pos[0] = '\0'; + pos++; - pos = pos_port; - pos_port++; - while (pos[0] == ' ') + /* + * DCC SEND
[] + * ^^^^^^^^^^ + **/ + pos_size = pos; + while (pos_size[0] == ' ') { - pos--; + pos_size++; } - pos[1] = '\0'; - - /* look for DCC IP address */ - pos_addr = strrchr (pos_file, ' '); - if (!pos_addr) + pos = strchr (pos_size, ' '); + if (pos) { - weechat_printf ( - server->buffer, - _("%s%s: cannot parse \"%s\" command"), - weechat_prefix ("error"), IRC_PLUGIN_NAME, "privmsg"); - free (dcc_args); - return; + /* + * DCC SEND
[] + * ^^^^^^^^^ + **/ + pos[0] = '\0'; + pos_token = ++pos; + while (pos_token[0] == ' ') + { + pos_token++; + } } - - pos = pos_addr; - pos_addr++; - while (pos[0] == ' ') + else { - pos--; + pos_token = NULL; } - pos[1] = '\0'; /* remove double quotes around filename */ filename = irc_ctcp_dcc_filename_without_quotes (pos_file); + /* use the local interface, from the server socket */ + memset (&addr, 0, sizeof (addr)); + length = sizeof (addr); + getsockname (server->sock, (struct sockaddr *)&addr, &length); + rc = getnameinfo ((struct sockaddr *)&addr, length, str_address, + sizeof (str_address), NULL, 0, NI_NUMERICHOST); + if (rc != 0) + { + weechat_printf ( + server->buffer, + _("%s%s: unable to resolve local address of server socket: error " + "%d %s"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, rc, gai_strerror (rc)); + return; + } + /* add DCC file via xfer plugin */ infolist = weechat_infolist_new (); if (infolist) @@ -863,6 +925,7 @@ irc_ctcp_recv_dcc (struct t_irc_server *server, const char *nick, IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_PROXY)); weechat_infolist_new_var_string (item, "remote_address", pos_addr); weechat_infolist_new_var_integer (item, "port", atoi (pos_port)); + weechat_infolist_new_var_string (item, "token", pos_token); (void) weechat_hook_signal_send ("xfer_add", WEECHAT_HOOK_SIGNAL_POINTER, infolist); @@ -897,16 +960,58 @@ irc_ctcp_recv_dcc (struct t_irc_server *server, const char *nick, return; } - /* DCC filename */ + /* + * DCC RESUME [] + * ^^^^^^^^^^ + **/ pos_file = dcc_args; while (pos_file[0] == ' ') { pos_file++; } + if (pos_file[0] == '"') + { + /* The file name is wrapped in double-quotes; find the terminating double-quote. */ + pos = strrchr (pos_file, '"'); + if (!pos || (pos == pos_file)) + { + weechat_printf ( + server->buffer, + _("%s%s: cannot parse \"%s\" command"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, "privmsg"); + free (dcc_args); + return; + } + pos[1] = '\0'; + pos += 2; + } + else + { + pos = strchr (pos_file, ' '); + if (!pos) + { + weechat_printf ( + server->buffer, + _("%s%s: cannot parse \"%s\" command"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, "privmsg"); + free (dcc_args); + return; + } + pos[0] = '\0'; + pos++; + } - /* look for resume start position */ - pos_start_resume = strrchr (pos_file, ' '); - if (!pos_start_resume) + /* + * DCC RESUME [] + * ^^^^^^ + **/ + pos_port = pos; + while (pos_port[0] == ' ') + { + pos_port++; + } + pos = strchr (pos_port, ' '); + if (!pos) { weechat_printf ( server->buffer, @@ -915,32 +1020,36 @@ irc_ctcp_recv_dcc (struct t_irc_server *server, const char *nick, free (dcc_args); return; } - pos = pos_start_resume; - pos_start_resume++; - while (pos[0] == ' ') - { - pos--; - } - pos[1] = '\0'; + pos[0] = '\0'; + pos++; - /* look for DCC port */ - pos_port = strrchr (pos_file, ' '); - if (!pos_port) + /* + * DCC RESUME [] + * ^^^^^^^^^^^^^^ + **/ + pos_start_resume = pos; + while (pos_start_resume[0] == ' ') { - weechat_printf ( - server->buffer, - _("%s%s: cannot parse \"%s\" command"), - weechat_prefix ("error"), IRC_PLUGIN_NAME, "privmsg"); - free (dcc_args); - return; + pos_start_resume++; } - pos = pos_port; - pos_port++; - while (pos[0] == ' ') + pos = strchr (pos_start_resume, ' '); + if (pos) { - pos--; + /* + * DCC RESUME [] + * ^^^^^^^^^ + **/ + pos[0] = '\0'; + pos_token = ++pos; + while (pos_token[0] == ' ') + { + pos_token++; + } + } + else + { + pos_token = NULL; } - pos[1] = '\0'; /* remove double quotes around filename */ filename = irc_ctcp_dcc_filename_without_quotes (pos_file); @@ -959,6 +1068,7 @@ irc_ctcp_recv_dcc (struct t_irc_server *server, const char *nick, (filename) ? filename : pos_file); weechat_infolist_new_var_integer (item, "port", atoi (pos_port)); weechat_infolist_new_var_string (item, "start_resume", pos_start_resume); + weechat_infolist_new_var_string (item, "token", pos_token); (void) weechat_hook_signal_send ("xfer_accept_resume", WEECHAT_HOOK_SIGNAL_POINTER, infolist); @@ -993,16 +1103,58 @@ irc_ctcp_recv_dcc (struct t_irc_server *server, const char *nick, return; } - /* DCC filename */ + /* + * DCC ACCEPT [] + * ^^^^^^^^^^ + **/ pos_file = dcc_args; while (pos_file[0] == ' ') { pos_file++; } + if (pos_file[0] == '"') + { + /* The file name is wrapped in double-quotes; find the terminating double-quote. */ + pos = strrchr (pos_file, '"'); + if (!pos || (pos == pos_file)) + { + weechat_printf ( + server->buffer, + _("%s%s: cannot parse \"%s\" command"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, "privmsg"); + free (dcc_args); + return; + } + pos[1] = '\0'; + pos += 2; + } + else + { + pos = strchr (pos_file, ' '); + if (!pos) + { + weechat_printf ( + server->buffer, + _("%s%s: cannot parse \"%s\" command"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, "privmsg"); + free (dcc_args); + return; + } + pos[0] = '\0'; + pos++; + } - /* look for resume start position */ - pos_start_resume = strrchr (pos_file, ' '); - if (!pos_start_resume) + /* + * DCC ACCEPT [] + * ^^^^^^ + **/ + pos_port = pos; + while (pos_port[0] == ' ') + { + pos_port++; + } + pos = strchr (pos_port, ' '); + if (!pos) { weechat_printf ( server->buffer, @@ -1011,32 +1163,36 @@ irc_ctcp_recv_dcc (struct t_irc_server *server, const char *nick, free (dcc_args); return; } - pos = pos_start_resume; - pos_start_resume++; - while (pos[0] == ' ') - { - pos--; - } - pos[1] = '\0'; + pos[0] = '\0'; + pos++; - /* look for DCC port */ - pos_port = strrchr (pos_file, ' '); - if (!pos_port) + /* + * DCC ACCEPT [] + * ^^^^^^^^^^^^^^ + **/ + pos_start_resume = pos; + while (pos_start_resume[0] == ' ') { - weechat_printf ( - server->buffer, - _("%s%s: cannot parse \"%s\" command"), - weechat_prefix ("error"), IRC_PLUGIN_NAME, "privmsg"); - free (dcc_args); - return; + pos_start_resume++; } - pos = pos_port; - pos_port++; - while (pos[0] == ' ') + pos = strchr (pos_start_resume, ' '); + if (pos) { - pos--; + /* + * DCC ACCEPT [] + * ^^^^^^^^^ + **/ + pos[0] = '\0'; + pos_token = ++pos; + while (pos_token[0] == ' ') + { + pos_token++; + } + } + else + { + pos_token = NULL; } - pos[1] = '\0'; /* remove double quotes around filename */ filename = irc_ctcp_dcc_filename_without_quotes (pos_file); @@ -1055,6 +1211,7 @@ irc_ctcp_recv_dcc (struct t_irc_server *server, const char *nick, (filename) ? filename : pos_file); weechat_infolist_new_var_integer (item, "port", atoi (pos_port)); weechat_infolist_new_var_string (item, "start_resume", pos_start_resume); + weechat_infolist_new_var_string (item, "token", pos_token); (void) weechat_hook_signal_send ("xfer_start_resume", WEECHAT_HOOK_SIGNAL_POINTER, infolist);