diff options
author | Sebastien Helleu <flashcode@flashtux.org> | 2008-05-06 16:51:30 +0200 |
---|---|---|
committer | Sebastien Helleu <flashcode@flashtux.org> | 2008-05-06 16:51:30 +0200 |
commit | e9603acb1a1943bda3c2cc809e5e39ff8a13b68c (patch) | |
tree | d4fb7fef63f5a4c1d415fdca9c1938016b23bbb3 /src | |
parent | e7a16efa0cf5123f87ef6d7072fbbb9ccdd42bac (diff) | |
download | weechat-e9603acb1a1943bda3c2cc809e5e39ff8a13b68c.zip |
IRC DCC chat and file (without resume) reintroduced, via xfer plugin (called by /dcc command)
Diffstat (limited to 'src')
28 files changed, 1195 insertions, 555 deletions
diff --git a/src/gui/curses/gui-curses-window.c b/src/gui/curses/gui-curses-window.c index 77a8ece29..c7fb4c250 100644 --- a/src/gui/curses/gui-curses-window.c +++ b/src/gui/curses/gui-curses-window.c @@ -323,6 +323,7 @@ gui_window_set_custom_color_fg_bg (WINDOW *window, int fg, int bg) if ((fg >= 0) && (fg < GUI_CURSES_NUM_WEECHAT_COLORS) && (bg >= 0) && (bg < GUI_CURSES_NUM_WEECHAT_COLORS)) { + gui_window_remove_color_style (window, A_BOLD); wattron (window, gui_weechat_colors[fg].attributes); gui_window_set_color (window, gui_weechat_colors[fg].foreground, diff --git a/src/plugins/irc/irc-command.c b/src/plugins/irc/irc-command.c index 6cfa50d64..0741dc51c 100644 --- a/src/plugins/irc/irc-command.c +++ b/src/plugins/irc/irc-command.c @@ -894,12 +894,14 @@ irc_command_dcc (void *data, struct t_gui_buffer *buffer, int argc, item = weechat_infolist_new_item (infolist); if (item) { + weechat_infolist_new_var_string (item, "plugin_name", weechat_plugin->name); snprintf (plugin_id, sizeof (plugin_id), - "irc_%x", (unsigned int)ptr_server); + "%x", (unsigned int)ptr_server); weechat_infolist_new_var_string (item, "plugin_id", plugin_id); weechat_infolist_new_var_string (item, "type", "file_send"); weechat_infolist_new_var_string (item, "protocol", "dcc"); - weechat_infolist_new_var_string (item, "nick", argv[2]); + weechat_infolist_new_var_string (item, "remote_nick", argv[2]); + weechat_infolist_new_var_string (item, "local_nick", ptr_server->nick); weechat_infolist_new_var_string (item, "filename", argv_eol[3]); snprintf (str_address, sizeof (str_address), "%lu", address); @@ -924,11 +926,13 @@ irc_command_dcc (void *data, struct t_gui_buffer *buffer, int argc, item = weechat_infolist_new_item (infolist); if (item) { + weechat_infolist_new_var_string (item, "plugin_name", weechat_plugin->name); snprintf (plugin_id, sizeof (plugin_id), - "irc_%x", (unsigned int)ptr_server); + "%x", (unsigned int)ptr_server); weechat_infolist_new_var_string (item, "plugin_id", plugin_id); weechat_infolist_new_var_string (item, "type", "chat_send"); - weechat_infolist_new_var_string (item, "nick", argv[2]); + weechat_infolist_new_var_string (item, "remote_nick", argv[2]); + weechat_infolist_new_var_string (item, "local_nick", ptr_server->nick); snprintf (str_address, sizeof (str_address), "%lu", address); weechat_infolist_new_var_string (item, "address", str_address); @@ -939,17 +943,6 @@ irc_command_dcc (void *data, struct t_gui_buffer *buffer, int argc, weechat_infolist_free (infolist); } } - /* close DCC CHAT */ - else if (weechat_strcasecmp (argv[1], "close") == 0) - { - if (ptr_channel && (ptr_channel != IRC_CHANNEL_TYPE_CHANNEL) - && (ptr_channel->dcc_chat)) - { - //irc_dcc_close (ptr_channel->dcc_chat, - // IRC_DCC_ABORTED); - //irc_dcc_redraw (1); - } - } /* unknown DCC action */ else { @@ -3589,7 +3582,7 @@ irc_command_init () "given, away status is removed)"), "-all", &irc_command_away, NULL); weechat_hook_command ("ban", - N_("bans nicks or hosts"), + N_("ban nicks or hosts"), N_("[channel] [nickname [nickname ...]]"), N_(" channel: channel for ban\n" "nickname: user or host to ban"), @@ -3627,28 +3620,27 @@ irc_command_init () "users)"), "%(irc_msg_part)", &irc_command_cycle, NULL); weechat_hook_command ("dcc", - N_("starts DCC (file or chat) or close chat"), + N_("start DCC (file or chat)"), N_("action [nickname [file]]"), - N_(" action: 'send' (file) or 'chat' or 'close' " - "(chat)\n" + N_(" action: 'send' (file) or 'chat'\n" "nickname: nickname to send file or chat\n" " file: filename (on local host)"), - "chat|send|close %n %f", + "chat|send %n %f", &irc_command_dcc, NULL); weechat_hook_command ("dehalfop", - N_("removes half channel operator status from " + N_("remove half channel operator status from " "nickname(s)"), N_("[nickname [nickname]]"), "", NULL, &irc_command_dehalfop, NULL); weechat_hook_command ("deop", - N_("removes channel operator status from " + N_("remove channel operator status from " "nickname(s)"), N_("[nickname [nickname]]"), "", NULL, &irc_command_deop, NULL); weechat_hook_command ("devoice", - N_("removes voice from nickname(s)"), + N_("remove voice from nickname(s)"), N_("[nickname [nickname]]"), "", NULL, &irc_command_devoice, NULL); @@ -3664,7 +3656,7 @@ irc_command_init () "servername: server name to disconnect"), "%(irc_servers)|-all", &irc_command_disconnect, NULL); weechat_hook_command ("halfop", - N_("gives half channel operator status to " + N_("give half channel operator status to " "nickname(s)"), N_("[nickname [nickname]]"), "", @@ -3798,7 +3790,7 @@ irc_command_init () " text: text to send"), "%n %-", &irc_command_notice, NULL); weechat_hook_command ("op", - N_("gives channel operator status to nickname(s)"), + N_("give channel operator status to nickname(s)"), N_("nickname [nickname]"), "", NULL, &irc_command_op, NULL); @@ -3961,7 +3953,7 @@ irc_command_init () N_("target: server"), NULL, &irc_command_trace, NULL); weechat_hook_command ("unban", - N_("unbans nicks or hosts"), + N_("unban nicks or hosts"), N_("[channel] nickname [nickname ...]"), N_(" channel: channel for unban\n" "nickname: user or host to unban"), @@ -3977,14 +3969,14 @@ irc_command_init () N_("target: server"), NULL, &irc_command_users, NULL); weechat_hook_command ("version", - N_("gives the version info of nick or server " + N_("give the version info of nick or server " "(current or specified)"), N_("[server | nickname]"), N_(" server: server name\n" "nickname: nickname"), "%n", &irc_command_version, NULL); weechat_hook_command ("voice", - N_("gives voice to nickname(s)"), + N_("give voice to nickname(s)"), N_("[nickname [nickname]]"), "", NULL, &irc_command_voice, NULL); diff --git a/src/plugins/irc/irc-dcc.c b/src/plugins/irc/irc-dcc.c index 5a4efe982..7557941f1 100644 --- a/src/plugins/irc/irc-dcc.c +++ b/src/plugins/irc/irc-dcc.c @@ -45,41 +45,7 @@ struct t_irc_dcc *irc_dcc_list = NULL; /* DCC files & chat list */ struct t_irc_dcc *irc_last_dcc = NULL; /* last DCC in list */ -/* - * irc_dcc_channel_for_chat: create channel for DCC chat - */ -/* -void -irc_dcc_channel_for_chat (struct t_irc_dcc *dcc) -{ - if (!irc_channel_create_dcc (dcc)) - { - gui_chat_printf_error (dcc->server->buffer, - _("%s can't associate DCC chat with private " - "buffer (maybe private buffer has already " - "DCC CHAT?)\n"), - WEECHAT_ERROR); - irc_dcc_close (dcc, IRC_DCC_FAILED); - irc_dcc_redraw (WEECHAT_HOTLIST_MESSAGE); - return; - } - - gui_chat_printf_type (dcc->channel->buffer, GUI_MSG_TYPE_MSG, - cfg_look_prefix_info, cfg_col_chat_prefix_info, - _("Connected to %s%s %s(%s%d.%d.%d.%d%s)%s via DCC " - "chat\n"), - GUI_COLOR(GUI_COLOR_CHAT_NICK), - dcc->nick, - GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS), - GUI_COLOR(GUI_COLOR_CHAT_HOST), - dcc->addr >> 24, - (dcc->addr >> 16) & 0xff, - (dcc->addr >> 8) & 0xff, - dcc->addr & 0xff, - GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS), - GUI_COLOR(GUI_COLOR_CHAT)); -} -*/ + /* * irc_dcc_chat_remove_channel: remove a buffer for DCC chat */ @@ -167,142 +133,3 @@ irc_dcc_start_resume (struct t_irc_server *server, char *filename, int port, WEECHAT_ERROR, filename, port, pos_start); } */ -/* - * irc_dcc_handle: receive/send data for all active DCC - */ -/* -void -irc_dcc_handle () -{ - struct t_irc_dcc *dcc; - fd_set read_fd; - static struct timeval timeout; - int sock; - struct sockaddr_in addr; - socklen_t length; - - for (dcc = irc_dcc_list; dcc; dcc = dcc->next_dcc) - { - // check DCC timeout - if (IRC_DCC_IS_FILE(dcc->type) && !IRC_DCC_ENDED(dcc->status)) - { - if ((irc_cfg_dcc_timeout != 0) - && (time (NULL) > dcc->last_activity + irc_cfg_dcc_timeout)) - { - gui_chat_printf_error (dcc->server->buffer, - _("%s DCC: timeout\n"), - WEECHAT_ERROR); - irc_dcc_close (dcc, IRC_DCC_FAILED); - irc_dcc_redraw (WEECHAT_HOTLIST_MESSAGE); - continue; - } - } - - if (dcc->status == IRC_DCC_CONNECTING) - { - if (dcc->type == IRC_DCC_FILE_SEND) - { - FD_ZERO (&read_fd); - FD_SET (dcc->sock, &read_fd); - timeout.tv_sec = 0; - timeout.tv_usec = 0; - - // something to read on socket? - if (select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout) > 0) - { - if (FD_ISSET (dcc->sock, &read_fd)) - { - dcc->last_activity = time (NULL); - length = sizeof (addr); - sock = accept (dcc->sock, - (struct sockaddr *) &addr, &length); - close (dcc->sock); - dcc->sock = -1; - if (sock < 0) - { - gui_chat_printf_error (dcc->server->buffer, - _("%s DCC: unable to " - "create socket for " - "sending file\n"), - WEECHAT_ERROR); - irc_dcc_close (dcc, IRC_DCC_FAILED); - irc_dcc_redraw (WEECHAT_HOTLIST_MESSAGE); - continue; - } - dcc->sock = sock; - if (fcntl (dcc->sock, F_SETFL, O_NONBLOCK) == -1) - { - gui_chat_printf_error (dcc->server->buffer, - _("%s DCC: unable to set " - "'nonblock' option for " - "socket\n"), - WEECHAT_ERROR); - irc_dcc_close (dcc, IRC_DCC_FAILED); - irc_dcc_redraw (WEECHAT_HOTLIST_MESSAGE); - continue; - } - dcc->addr = ntohl (addr.sin_addr.s_addr); - dcc->status = IRC_DCC_ACTIVE; - dcc->start_transfer = time (NULL); - irc_dcc_redraw (WEECHAT_HOTLIST_MESSAGE); - irc_dcc_file_send_fork (dcc); - } - } - } - if (dcc->type == IRC_DCC_FILE_RECV) - { - if (dcc->child_read != -1) - irc_dcc_file_child_read (dcc); - } - } - - if (dcc->status == IRC_DCC_WAITING) - { - if (dcc->type == IRC_DCC_CHAT_SEND) - { - FD_ZERO (&read_fd); - FD_SET (dcc->sock, &read_fd); - timeout.tv_sec = 0; - timeout.tv_usec = 0; - - // something to read on socket? - if (select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout) > 0) - { - if (FD_ISSET (dcc->sock, &read_fd)) - { - length = sizeof (addr); - sock = accept (dcc->sock, (struct sockaddr *) &addr, &length); - close (dcc->sock); - dcc->sock = -1; - if (sock < 0) - { - irc_dcc_close (dcc, IRC_DCC_FAILED); - irc_dcc_redraw (WEECHAT_HOTLIST_MESSAGE); - continue; - } - dcc->sock = sock; - if (fcntl (dcc->sock, F_SETFL, O_NONBLOCK) == -1) - { - irc_dcc_close (dcc, IRC_DCC_FAILED); - irc_dcc_redraw (WEECHAT_HOTLIST_MESSAGE); - continue; - } - dcc->addr = ntohl (addr.sin_addr.s_addr); - dcc->status = IRC_DCC_ACTIVE; - irc_dcc_redraw (WEECHAT_HOTLIST_MESSAGE); - irc_dcc_channel_for_chat (dcc); - } - } - } - } - - if (dcc->status == IRC_DCC_ACTIVE) - { - if (IRC_DCC_IS_CHAT(dcc->type)) - irc_dcc_chat_recv (dcc); - else - irc_dcc_file_child_read (dcc); - } - } -} -*/ diff --git a/src/plugins/irc/irc-protocol.c b/src/plugins/irc/irc-protocol.c index 95e845816..b945f3fbc 100644 --- a/src/plugins/irc/irc-protocol.c +++ b/src/plugins/irc/irc-protocol.c @@ -1331,6 +1331,9 @@ irc_protocol_cmd_privmsg (struct t_irc_server *server, char *command, { char *nick, *host, *pos_args, *pos_end_01, *pos, *pos_message; char *dcc_args, *pos_file, *pos_addr, *pos_port, *pos_size, *pos_start_resume; /* for DCC */ + struct t_plugin_infolist *infolist; + struct t_plugin_infolist_item *item; + char plugin_id[128]; struct t_irc_channel *ptr_channel; struct t_irc_nick *ptr_nick; int highlight_displayed, look_infobar_delay_highlight; @@ -1644,11 +1647,9 @@ irc_protocol_cmd_privmsg (struct t_irc_server *server, char *command, "privmsg"); return WEECHAT_RC_ERROR; } - - pos_end_01[0] = '\0'; - dcc_args = strdup (pos_args + 9); - pos_end_01[0] = '\01'; - + + dcc_args = weechat_strndup (pos_args + 9, pos_end_01 - pos_args - 9); + if (!dcc_args) { weechat_printf (server->buffer, @@ -1722,7 +1723,33 @@ irc_protocol_cmd_privmsg (struct t_irc_server *server, char *command, pos--; } pos[1] = '\0'; - + + /* add DCC file via xfer plugin */ + infolist = weechat_infolist_new (); + if (infolist) + { + item = weechat_infolist_new_item (infolist); + if (item) + { + weechat_infolist_new_var_string (item, "plugin_name", weechat_plugin->name); + snprintf (plugin_id, sizeof (plugin_id), + "%x", (unsigned int)server); + weechat_infolist_new_var_string (item, "plugin_id", plugin_id); + weechat_infolist_new_var_string (item, "type", "file_recv"); + weechat_infolist_new_var_string (item, "protocol", "dcc"); + weechat_infolist_new_var_string (item, "remote_nick", nick); + weechat_infolist_new_var_string (item, "local_nick", server->nick); + weechat_infolist_new_var_string (item, "filename", pos_file); + weechat_infolist_new_var_string (item, "size", pos_size); + weechat_infolist_new_var_string (item, "address", pos_addr); + weechat_infolist_new_var_integer (item, "port", atoi (pos_port)); + weechat_hook_signal_send ("xfer_add", + WEECHAT_HOOK_SIGNAL_POINTER, + infolist); + } + weechat_infolist_free (infolist); + } + /* TODO: add DCC file */ //irc_dcc_add (server, IRC_DCC_FILE_RECV, // strtoul (pos_addr, NULL, 10), @@ -1751,11 +1778,9 @@ irc_protocol_cmd_privmsg (struct t_irc_server *server, char *command, "privmsg"); return WEECHAT_RC_ERROR; } - - pos_end_01[0] = '\0'; - dcc_args = strdup (pos_args + 11); - pos_end_01[0] = '\01'; - + + dcc_args = weechat_strndup (pos_args + 11, pos_end_01 - pos_args - 11); + if (!dcc_args) { weechat_printf (server->buffer, @@ -1825,7 +1850,7 @@ irc_protocol_cmd_privmsg (struct t_irc_server *server, char *command, } /* incoming DCC ACCEPT (resume accepted by sender) */ - if (strncmp (pos, "\01DCC ACCEPT", 11) == 0) + if (strncmp (pos_args, "\01DCC ACCEPT", 11) == 0) { /* check if DCC ACCEPT is ok, i.e. with 0x01 at end */ pos_end_01 = strchr (pos_args + 1, '\01'); @@ -1837,11 +1862,9 @@ irc_protocol_cmd_privmsg (struct t_irc_server *server, char *command, "privmsg"); return WEECHAT_RC_ERROR; } - - pos_end_01[0] = '\0'; - dcc_args = strdup (pos_args + 11); - pos_end_01[0] = '\01'; - + + dcc_args = weechat_strndup (pos_args + 11, pos_end_01 - pos_args - 11); + if (!dcc_args) { weechat_printf (server->buffer, @@ -1911,7 +1934,7 @@ irc_protocol_cmd_privmsg (struct t_irc_server *server, char *command, } /* incoming DCC CHAT */ - if (strncmp (pos, "\01DCC CHAT", 9) == 0) + if (strncmp (pos_args, "\01DCC CHAT", 9) == 0) { /* check if DCC CHAT is ok, i.e. with 0x01 at end */ pos_end_01 = strchr (pos_args + 1, '\01'); @@ -1924,10 +1947,8 @@ irc_protocol_cmd_privmsg (struct t_irc_server *server, char *command, return WEECHAT_RC_ERROR; } - pos_end_01[0] = '\0'; - dcc_args = strdup (pos_args + 9); - pos_end_01[0] = '\01'; - + dcc_args = weechat_strndup (pos_args + 9, pos_end_01 - pos_args - 9); + if (!dcc_args) { weechat_printf (server->buffer, @@ -1944,7 +1965,7 @@ irc_protocol_cmd_privmsg (struct t_irc_server *server, char *command, { pos_file++; } - + /* DCC IP address */ pos_addr = strchr (pos_file, ' '); if (!pos_addr) @@ -1995,11 +2016,29 @@ irc_protocol_cmd_privmsg (struct t_irc_server *server, char *command, return WEECHAT_RC_ERROR; } - /* TODO: add DCC chat */ - //irc_dcc_add (server, IRC_DCC_CHAT_RECV, - // strtoul (pos_addr, NULL, 10), - // atoi (pos_port), nick, -1, NULL, NULL, 0); - + /* add DCC chat via xfer plugin */ + infolist = weechat_infolist_new (); + if (infolist) + { + item = weechat_infolist_new_item (infolist); + if (item) + { + weechat_infolist_new_var_string (item, "plugin_name", weechat_plugin->name); + snprintf (plugin_id, sizeof (plugin_id), + "%x", (unsigned int)server); + weechat_infolist_new_var_string (item, "plugin_id", plugin_id); + weechat_infolist_new_var_string (item, "type", "chat_recv"); + weechat_infolist_new_var_string (item, "remote_nick", nick); + weechat_infolist_new_var_string (item, "local_nick", server->nick); + weechat_infolist_new_var_string (item, "address", pos_addr); + weechat_infolist_new_var_integer (item, "port", atoi (pos_port)); + weechat_hook_signal_send ("xfer_add", + WEECHAT_HOOK_SIGNAL_POINTER, + infolist); + } + weechat_infolist_free (infolist); + } + weechat_hook_signal_send ("irc_dcc", WEECHAT_HOOK_SIGNAL_STRING, argv_eol[0]); @@ -2012,7 +2051,7 @@ irc_protocol_cmd_privmsg (struct t_irc_server *server, char *command, /* private message received => display it */ ptr_channel = irc_channel_search (server, nick); - if (strncmp (pos, "\01ACTION ", 8) == 0) + if (strncmp (pos_args, "\01ACTION ", 8) == 0) { if (!ptr_channel) { diff --git a/src/plugins/irc/irc-server.c b/src/plugins/irc/irc-server.c index bef2fdcaf..9cd9dbded 100644 --- a/src/plugins/irc/irc-server.c +++ b/src/plugins/irc/irc-server.c @@ -2803,8 +2803,9 @@ irc_server_xfer_send_ready_cb (void *data, char *signal, char *type_data, { struct t_plugin_infolist *infolist; struct t_irc_server *server, *ptr_server; - char *plugin_id, *type; - + char *plugin_name, *plugin_id, *type, *filename; + int spaces_in_name; + /* make C compiler happy */ (void) data; (void) signal; @@ -2814,42 +2815,44 @@ irc_server_xfer_send_ready_cb (void *data, char *signal, char *type_data, if (weechat_infolist_next (infolist)) { + plugin_name = weechat_infolist_string (infolist, "plugin_name"); plugin_id = weechat_infolist_string (infolist, "plugin_id"); - if (plugin_id) + if (plugin_name && (strcmp (plugin_name, "irc") == 0) && plugin_id) { - if (strncmp (plugin_id, "irc_", 4) == 0) + sscanf (plugin_id, "%x", (unsigned int *)&server); + for (ptr_server = irc_servers; ptr_server; + ptr_server = ptr_server->next_server) { - sscanf (plugin_id + 4, "%x", (unsigned int *)&server); - for (ptr_server = irc_servers; ptr_server; - ptr_server = ptr_server->next_server) - { - if (ptr_server == server) - break; - } - if (ptr_server) + if (ptr_server == server) + break; + } + if (ptr_server) + { + type = weechat_infolist_string (infolist, "type"); + if (type) { - type = weechat_infolist_string (infolist, "type"); - if (type) + if (strcmp (type, "file_send") == 0) { - if (strcmp (type, "file_send") == 0) - { - irc_server_sendf (server, - "PRIVMSG %s :\01DCC SEND \"%s\" " - "%s %d %s\01\n", - weechat_infolist_string (infolist, "nick"), - weechat_infolist_string (infolist, "filename"), - weechat_infolist_string (infolist, "address"), - weechat_infolist_integer (infolist, "port"), - weechat_infolist_string (infolist, "size")); - } - else if (strcmp (type, "chat_send") == 0) - { - irc_server_sendf (server, - "PRIVMSG %s :\01DCC CHAT chat %s %d\01", - weechat_infolist_string (infolist, "nick"), - weechat_infolist_string (infolist, "address"), - weechat_infolist_integer (infolist, "port")); - } + filename = weechat_infolist_string (infolist, "filename"); + spaces_in_name = (strchr (filename, ' ') != NULL); + irc_server_sendf (server, + "PRIVMSG %s :\01DCC SEND %s%s%s " + "%s %d %s\01", + weechat_infolist_string (infolist, "remote_nick"), + (spaces_in_name) ? "\"" : "", + filename, + (spaces_in_name) ? "\"" : "", + weechat_infolist_string (infolist, "address"), + weechat_infolist_integer (infolist, "port"), + weechat_infolist_string (infolist, "size")); + } + else if (strcmp (type, "chat_send") == 0) + { + irc_server_sendf (server, + "PRIVMSG %s :\01DCC CHAT chat %s %d\01", + weechat_infolist_string (infolist, "remote_nick"), + weechat_infolist_string (infolist, "address"), + weechat_infolist_integer (infolist, "port")); } } } diff --git a/src/plugins/plugin-infolist.c b/src/plugins/plugin-infolist.c index 689345ecb..2b780f707 100644 --- a/src/plugins/plugin-infolist.c +++ b/src/plugins/plugin-infolist.c @@ -111,7 +111,8 @@ plugin_infolist_new_var_integer (struct t_plugin_infolist_item *item, new_var->name = strdup (name); new_var->type = PLUGIN_INFOLIST_INTEGER; new_var->value = malloc (sizeof (int)); - *((int *)new_var->value) = value; + if (new_var->value) + *((int *)new_var->value) = value; new_var->prev_var = item->last_var; new_var->next_var = NULL; @@ -208,7 +209,8 @@ plugin_infolist_new_var_time (struct t_plugin_infolist_item *item, new_var->name = strdup (name); new_var->type = PLUGIN_INFOLIST_TIME; new_var->value = malloc (sizeof (time_t)); - *((time_t *)new_var->value) = time; + if (new_var->value) + *((time_t *)new_var->value) = time; new_var->prev_var = item->last_var; new_var->next_var = NULL; diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c index 90979594e..fd26a3347 100644 --- a/src/plugins/plugin.c +++ b/src/plugins/plugin.c @@ -372,6 +372,7 @@ plugin_load (char *filename) new_plugin->buffer_new = &gui_buffer_new; new_plugin->buffer_search = &gui_buffer_search_by_category_name; + new_plugin->buffer_clear = &gui_buffer_clear; new_plugin->buffer_close = &gui_buffer_close; new_plugin->buffer_get_string = &gui_buffer_get_string; new_plugin->buffer_get_pointer = &gui_buffer_get_pointer; diff --git a/src/plugins/scripts/lua/weechat-lua-api.c b/src/plugins/scripts/lua/weechat-lua-api.c index fe874cb46..9e0431da1 100644 --- a/src/plugins/scripts/lua/weechat-lua-api.c +++ b/src/plugins/scripts/lua/weechat-lua-api.c @@ -3291,6 +3291,42 @@ weechat_lua_api_buffer_search (lua_State *L) } /* + * weechat_lua_api_buffer_clear: clear a buffer + */ + +static int +weechat_lua_api_buffer_clear (lua_State *L) +{ + const char *buffer; + int n; + + /* make C compiler happy */ + (void) L; + + if (!lua_current_script) + { + WEECHAT_SCRIPT_MSG_NOT_INITIALIZED("buffer_clear"); + LUA_RETURN_ERROR; + } + + buffer = NULL; + + n = lua_gettop (lua_current_interpreter); + + if (n < 1) + { + WEECHAT_SCRIPT_MSG_WRONG_ARGUMENTS("buffer_clear"); + LUA_RETURN_ERROR; + } + + buffer = lua_tostring (lua_current_interpreter, -1); + + weechat_buffer_clear (script_str2ptr ((char *)buffer)); + + LUA_RETURN_OK; +} + +/* * weechat_lua_api_buffer_close: close a buffer */ @@ -4794,6 +4830,7 @@ const struct luaL_reg weechat_lua_api_funcs[] = { { "unhook_all", &weechat_lua_api_unhook_all }, { "buffer_new", &weechat_lua_api_buffer_new }, { "buffer_search", &weechat_lua_api_buffer_search }, + { "buffer_clear", &weechat_lua_api_buffer_clear }, { "buffer_close", &weechat_lua_api_buffer_close }, { "buffer_get_string", &weechat_lua_api_buffer_get_string }, { "buffer_get_pointer", &weechat_lua_api_buffer_get_pointer }, diff --git a/src/plugins/scripts/perl/weechat-perl-api.c b/src/plugins/scripts/perl/weechat-perl-api.c index 082363983..b1081e00f 100644 --- a/src/plugins/scripts/perl/weechat-perl-api.c +++ b/src/plugins/scripts/perl/weechat-perl-api.c @@ -2751,6 +2751,34 @@ static XS (XS_weechat_buffer_search) } /* + * weechat::buffer_clear: clear a buffer + */ + +static XS (XS_weechat_buffer_clear) +{ + dXSARGS; + + /* make C compiler happy */ + (void) cv; + + if (!perl_current_script) + { + WEECHAT_SCRIPT_MSG_NOT_INITIALIZED("buffer_clear"); + PERL_RETURN_ERROR; + } + + if (items < 1) + { + WEECHAT_SCRIPT_MSG_WRONG_ARGUMENTS("buffer_clear"); + PERL_RETURN_ERROR; + } + + weechat_buffer_clear (script_str2ptr (SvPV (ST (0), PL_na))); /* buffer */ + + PERL_RETURN_OK; +} + +/* * weechat::buffer_close: close a buffer */ @@ -3867,6 +3895,7 @@ weechat_perl_api_init (pTHX) newXS ("weechat::unhook_all", XS_weechat_unhook_all, "weechat"); newXS ("weechat::buffer_new", XS_weechat_buffer_new, "weechat"); newXS ("weechat::buffer_search", XS_weechat_buffer_search, "weechat"); + newXS ("weechat::buffer_clear", XS_weechat_buffer_clear, "weechat"); newXS ("weechat::buffer_close", XS_weechat_buffer_close, "weechat"); newXS ("weechat::buffer_get_string", XS_weechat_buffer_get_string, "weechat"); newXS ("weechat::buffer_get_pointer", XS_weechat_buffer_get_pointer, "weechat"); diff --git a/src/plugins/scripts/python/weechat-python-api.c b/src/plugins/scripts/python/weechat-python-api.c index 9a7696c24..c1ea8821d 100644 --- a/src/plugins/scripts/python/weechat-python-api.c +++ b/src/plugins/scripts/python/weechat-python-api.c @@ -2919,6 +2919,37 @@ weechat_python_api_buffer_search (PyObject *self, PyObject *args) } /* + * weechat_python_api_buffer_clear: clear a buffer + */ + +static PyObject * +weechat_python_api_buffer_clear (PyObject *self, PyObject *args) +{ + char *buffer; + + /* make C compiler happy */ + (void) self; + + if (!python_current_script) + { + WEECHAT_SCRIPT_MSG_NOT_INITIALIZED("buffer_clear"); + PYTHON_RETURN_ERROR; + } + + buffer = NULL; + + if (!PyArg_ParseTuple (args, "s", &buffer)) + { + WEECHAT_SCRIPT_MSG_WRONG_ARGUMENTS("buffer_clear"); + PYTHON_RETURN_ERROR; + } + + weechat_buffer_clear (script_str2ptr (buffer)); + + PYTHON_RETURN_OK; +} + +/* * weechat_python_api_buffer_close: close a buffer */ @@ -4110,6 +4141,7 @@ PyMethodDef weechat_python_funcs[] = { "unhook_all", &weechat_python_api_unhook_all, METH_VARARGS, "" }, { "buffer_new", &weechat_python_api_buffer_new, METH_VARARGS, "" }, { "buffer_search", &weechat_python_api_buffer_search, METH_VARARGS, "" }, + { "buffer_clear", &weechat_python_api_buffer_clear, METH_VARARGS, "" }, { "buffer_close", &weechat_python_api_buffer_close, METH_VARARGS, "" }, { "buffer_get_string", &weechat_python_api_buffer_get_string, METH_VARARGS, "" }, { "buffer_get_pointer", &weechat_python_api_buffer_get_pointer, METH_VARARGS, "" }, diff --git a/src/plugins/scripts/ruby/weechat-ruby-api.c b/src/plugins/scripts/ruby/weechat-ruby-api.c index 70bba8fde..2439b1b36 100644 --- a/src/plugins/scripts/ruby/weechat-ruby-api.c +++ b/src/plugins/scripts/ruby/weechat-ruby-api.c @@ -3349,6 +3349,41 @@ weechat_ruby_api_buffer_search (VALUE class, VALUE category, VALUE name) } /* + * weechat_ruby_api_buffer_clear: clear a buffer + */ + +static VALUE +weechat_ruby_api_buffer_clear (VALUE class, VALUE buffer) +{ + char *c_buffer; + + /* make C compiler happy */ + (void) class; + + if (!ruby_current_script) + { + WEECHAT_SCRIPT_MSG_NOT_INITIALIZED("buffer_clear"); + RUBY_RETURN_ERROR; + } + + c_buffer = NULL; + + if (NIL_P (buffer)) + { + WEECHAT_SCRIPT_MSG_WRONG_ARGUMENTS("buffer_clear"); + RUBY_RETURN_ERROR; + } + + Check_Type (buffer, T_STRING); + + c_buffer = STR2CSTR (buffer); + + weechat_buffer_clear (script_str2ptr (c_buffer)); + + RUBY_RETURN_OK; +} + +/* * weechat_ruby_api_buffer_close: close a buffer */ @@ -4714,6 +4749,7 @@ weechat_ruby_api_init (VALUE ruby_mWeechat) rb_define_module_function (ruby_mWeechat, "unhook_all", &weechat_ruby_api_unhook_all, 0); rb_define_module_function (ruby_mWeechat, "buffer_new", &weechat_ruby_api_buffer_new, 4); rb_define_module_function (ruby_mWeechat, "buffer_search", &weechat_ruby_api_buffer_search, 2); + rb_define_module_function (ruby_mWeechat, "buffer_clear", &weechat_ruby_api_buffer_clear, 1); rb_define_module_function (ruby_mWeechat, "buffer_close", &weechat_ruby_api_buffer_close, 1); rb_define_module_function (ruby_mWeechat, "buffer_get_string", &weechat_ruby_api_buffer_get_string, 2); rb_define_module_function (ruby_mWeechat, "buffer_get_pointer", &weechat_ruby_api_buffer_get_pointer, 2); diff --git a/src/plugins/weechat-plugin.h b/src/plugins/weechat-plugin.h index 557fc6608..0bcf417fc 100644 --- a/src/plugins/weechat-plugin.h +++ b/src/plugins/weechat-plugin.h @@ -335,6 +335,7 @@ struct t_weechat_plugin struct t_gui_buffer *buffer), void *close_callback_data); struct t_gui_buffer *(*buffer_search) (char *category, char *name); + void (*buffer_clear) (struct t_gui_buffer *buffer); void (*buffer_close) (struct t_gui_buffer *buffer, int switch_to_another); char *(*buffer_get_string) (struct t_gui_buffer *buffer, char *property); void *(*buffer_get_pointer) (struct t_gui_buffer *buffer, char *property); @@ -749,6 +750,8 @@ extern int weechat_plugin_end (struct t_weechat_plugin *plugin); weechat_plugin->buffer_search(__category, __name) #define weechat_current_buffer \ weechat_plugin->buffer_search(NULL, NULL) +#define weechat_buffer_clear(__buffer) \ + weechat_plugin->buffer_clear(__buffer) #define weechat_buffer_close(__buffer, __switch_to_another) \ weechat_plugin->buffer_close(__buffer, __switch_to_another) #define weechat_buffer_get_string(__buffer, __property) \ diff --git a/src/plugins/xfer/CMakeLists.txt b/src/plugins/xfer/CMakeLists.txt index f9849e367..78c1c006b 100644 --- a/src/plugins/xfer/CMakeLists.txt +++ b/src/plugins/xfer/CMakeLists.txt @@ -18,6 +18,7 @@ ADD_LIBRARY(xfer MODULE xfer.c xfer.h xfer-buffer.c xfer-buffer.h xfer-chat.c xfer-chat.h +xfer-command.c xfer-command.h xfer-config.c xfer-config.h xfer-dcc.c xfer-dcc.h xfer-file.c xfer-file.h diff --git a/src/plugins/xfer/Makefile.am b/src/plugins/xfer/Makefile.am index ad7538bb4..9280fa432 100644 --- a/src/plugins/xfer/Makefile.am +++ b/src/plugins/xfer/Makefile.am @@ -26,6 +26,8 @@ xfer_la_SOURCES = xfer.c \ xfer-buffer.h \ xfer-chat.c \ xfer-chat.h \ + xfer-command.c \ + xfer-command.h \ xfer-config.c \ xfer-config.h \ xfer-dcc.c \ diff --git a/src/plugins/xfer/xfer-buffer.c b/src/plugins/xfer/xfer-buffer.c index 52823985f..dd32ca0b0 100644 --- a/src/plugins/xfer/xfer-buffer.c +++ b/src/plugins/xfer/xfer-buffer.c @@ -21,11 +21,13 @@ #include <stdlib.h> #include <stdio.h> +#include <string.h> +#include <time.h> #include "../weechat-plugin.h" #include "xfer.h" -#include "xfer-buffer.h" #include "xfer-config.h" +#include "xfer-network.h" struct t_gui_buffer *xfer_buffer = NULL; @@ -33,6 +35,249 @@ int xfer_buffer_selected_line = 0; /* + * xfer_buffer_refresh: update a xfer in buffer and update hotlist for xfer buffer + */ + +void +xfer_buffer_refresh (char *hotlist) +{ + struct t_xfer *ptr_xfer; + char str_color[256], status[64], date[128], *progress_bar, format[128]; + char format_per_sec[128], bytes_per_sec[256], eta[128]; + int i, length, line, progress_bar_size, num_bars, num_unit; + int num_unit_per_sec; + unsigned long pct_complete; + char *unit_name[] = { N_("bytes"), N_("KB"), N_("MB"), N_("GB") }; + char *unit_format[] = { "%.0f", "%.1f", "%.02f", "%.02f" }; + float unit_divide[] = { 1, 1024, 1024*1024, 1024*1024*1024 }; + struct tm *date_tmp; + + if (xfer_buffer) + { + weechat_buffer_clear (xfer_buffer); + line = 0; + for (ptr_xfer = xfer_list; ptr_xfer; ptr_xfer = ptr_xfer->next_xfer) + { + snprintf (str_color, sizeof (str_color), + "%s,%s", + weechat_config_string (xfer_config_color_text), + weechat_config_string (xfer_config_color_text_bg)); + + /* display first line with remote nick and filename */ + weechat_printf_y (xfer_buffer, line * 2, + "%s%s%-25s %s%s%s", + weechat_color(str_color), + (line == xfer_buffer_selected_line) ? + "*** " : " ", + ptr_xfer->remote_nick, + (XFER_IS_FILE(ptr_xfer->type)) ? "\"" : "", + (XFER_IS_FILE(ptr_xfer->type)) ? + ptr_xfer->filename : _("xfer chat"), + (XFER_IS_FILE(ptr_xfer->type)) ? "\"" : ""); + + snprintf (status, sizeof (status), + "%s", _(xfer_status_string[ptr_xfer->status])); + length = strlen (status); + if (length < 20) + { + for (i = 0; i < 20 - length; i++) + { + strcat (status, " "); + } + } + + if (XFER_IS_CHAT(ptr_xfer->type)) + { + /* display second line for chat with status and date */ + date_tmp = localtime (&(ptr_xfer->start_time)); + strftime (date, sizeof (date), + "%a, %d %b %Y %H:%M:%S", date_tmp); + weechat_printf_y (xfer_buffer, (line * 2) + 1, + "%s%s%s %s%s %s%s%s", + weechat_color(str_color), + (line == xfer_buffer_selected_line) ? + "*** " : " ", + (XFER_IS_SEND(ptr_xfer->type)) ? + "<<--" : "-->>", + weechat_color(weechat_config_string (xfer_config_color_status[ptr_xfer->status])), + status, + weechat_color ("reset"), + weechat_color (str_color), + date); + } + else + { + /* build progress bar */ + progress_bar = NULL; + progress_bar_size = weechat_config_integer (xfer_config_look_progress_bar_size); + if (progress_bar_size > 0) + { + progress_bar = malloc (1 + progress_bar_size + 1 + 1); + strcpy (progress_bar, "["); + if (ptr_xfer->size == 0) + { + if (ptr_xfer->status == XFER_STATUS_DONE) + num_bars = progress_bar_size; + else + num_bars = 0; + } + else + num_bars = (int)(((float)(ptr_xfer->pos)/(float)(ptr_xfer->size)) * (float)progress_bar_size); + for (i = 0; i < num_bars - 1; i++) + { + strcat (progress_bar, "="); + } + if (num_bars > 0) + strcat (progress_bar, ">"); + for (i = 0; i < progress_bar_size - num_bars; i++) + { + strcat (progress_bar, " "); + } + strcat (progress_bar, "]"); + } + + /* computes pourcentage */ + if (ptr_xfer->size < 1024*10) + num_unit = 0; + else if (ptr_xfer->size < 1024*1024) + num_unit = 1; + else if (ptr_xfer->size < 1024*1024*1024) + num_unit = 2; + else + num_unit = 3; + if (ptr_xfer->size == 0) + { + if (ptr_xfer->status == XFER_STATUS_DONE) + pct_complete = 100; + else + pct_complete = 0; + } + else + pct_complete = (unsigned long)(((float)(ptr_xfer->pos)/(float)(ptr_xfer->size)) * 100); + + snprintf (format, sizeof (format), + "%%s%%s%%s %%s%%s%%s%%s %%3lu%%%% %s %%s / %s %%s (%%s%%s)", + unit_format[num_unit], + unit_format[num_unit]); + + /* bytes per second */ + bytes_per_sec[0] = '\0'; + if (ptr_xfer->bytes_per_sec < 1024*10) + num_unit_per_sec = 0; + else if (ptr_xfer->bytes_per_sec < 1024*1024) + num_unit_per_sec = 1; + else if (ptr_xfer->bytes_per_sec < 1024*1024*1024) + num_unit_per_sec = 2; + else + num_unit_per_sec = 3; + snprintf (format_per_sec, sizeof (format_per_sec), + "%s %%s/s", + unit_format[num_unit_per_sec]); + snprintf (bytes_per_sec, sizeof (bytes_per_sec), + format_per_sec, + ((float)ptr_xfer->bytes_per_sec) / ((float)(unit_divide[num_unit_per_sec])), + _(unit_name[num_unit_per_sec])); + + /* ETA */ + eta[0] = '\0'; + if (ptr_xfer->status == XFER_STATUS_ACTIVE) + { + snprintf (eta, sizeof (eta), + "%s: %.2lu:%.2lu:%.2lu - ", + _("ETA"), + ptr_xfer->eta / 3600, + (ptr_xfer->eta / 60) % 60, + ptr_xfer->eta % 60); + } + + /* display second line for file with status, progress bar and estimated time */ + weechat_printf_y (xfer_buffer, (line * 2) + 1, + format, + weechat_color(str_color), + (line == xfer_buffer_selected_line) ? + "*** " : " ", + (XFER_IS_SEND(ptr_xfer->type)) ? + "<<--" : "-->>", + weechat_color(weechat_config_string (xfer_config_color_status[ptr_xfer->status])), + status, + weechat_color (str_color), + (progress_bar) ? progress_bar : "", + pct_complete, + ((float)(ptr_xfer->pos)) / unit_divide[num_unit], + _(unit_name[num_unit]), + ((float)(ptr_xfer->size)) / unit_divide[num_unit], + _(unit_name[num_unit]), + eta, + bytes_per_sec); + } + line++; + } + weechat_buffer_set (xfer_buffer, "hotlist", hotlist); + } +} + +/* + * xfer_buffer_input_cb: callback called when user send data to xfer list + * buffer + */ + +int +xfer_buffer_input_cb (void *data, struct t_gui_buffer *buffer, + char *input_data) +{ + struct t_xfer *xfer, *ptr_xfer, *next_xfer; + + /* make C compiler happy */ + (void) data; + (void) buffer; + + xfer = xfer_search_by_number (xfer_buffer_selected_line); + + /* accept xfer */ + if (weechat_strcasecmp (input_data, "a") == 0) + { + if (xfer && XFER_IS_RECV(xfer->type) + && (xfer->status == XFER_STATUS_WAITING)) + { + xfer_network_accept (xfer); + } + } + /* cancel xfer */ + else if (weechat_strcasecmp (input_data, "c") == 0) + { + if (xfer && !XFER_HAS_ENDED(xfer->status)) + { + xfer_close (xfer, XFER_STATUS_ABORTED); + xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); + } + } + /* purge old xfer */ + else if (weechat_strcasecmp (input_data, "p") == 0) + { + ptr_xfer = xfer_list; + while (ptr_xfer) + { + next_xfer = ptr_xfer->next_xfer; + if (XFER_HAS_ENDED(ptr_xfer->status)) + xfer_free (ptr_xfer); + ptr_xfer = next_xfer; + } + xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); + } + /* remove xfer */ + else if (weechat_strcasecmp (input_data, "r") == 0) + { + if (xfer && XFER_HAS_ENDED(xfer->status)) + { + xfer_free (xfer); + xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); + } + } + + return WEECHAT_RC_OK; +} + +/* * xfer_buffer_close_cb: callback called when xfer buffer is closed */ @@ -57,61 +302,18 @@ xfer_buffer_open () { if (!xfer_buffer) { - xfer_buffer = weechat_buffer_new ("xfer", "xfer", - NULL, NULL, + xfer_buffer = weechat_buffer_new ("xfer", "list", + &xfer_buffer_input_cb, NULL, &xfer_buffer_close_cb, NULL); /* failed to create buffer ? then exit */ if (!xfer_buffer) return; - + weechat_buffer_set (xfer_buffer, "type", "free"); weechat_buffer_set (xfer_buffer, "title", _("Xfer list")); - } -} - -/* - * xfer_buffer_refresh: update a xfer in buffer and update hotlist for xfer buffer - */ - -void -xfer_buffer_refresh (char *hotlist) -{ - struct t_xfer *ptr_xfer; - char str_color[256]; - int line; - - if (xfer_buffer) - { - line = 0; - for (ptr_xfer = xfer_list; ptr_xfer; ptr_xfer = ptr_xfer->next_xfer) - { - if (XFER_IS_FILE(ptr_xfer->type)) - { - snprintf (str_color, sizeof (str_color), - "%s,%s", - weechat_config_string (xfer_config_color_text), - weechat_config_string (xfer_config_color_text_bg)); - weechat_printf_y (xfer_buffer, line * 2, - "%s%s%-20s \"%s\"", - weechat_color(str_color), - (line == xfer_buffer_selected_line) ? - "*** " : " ", - ptr_xfer->nick, ptr_xfer->filename); - weechat_printf_y (xfer_buffer, (line * 2) + 1, - "%s%s%s %s%-15s ", - weechat_color(str_color), - (line == xfer_buffer_selected_line) ? - "*** " : " ", - (XFER_IS_SEND(ptr_xfer->type)) ? - "<<--" : "-->>", - weechat_color( - weechat_config_string ( - xfer_config_color_status[ptr_xfer->status])), - _(xfer_status_string[ptr_xfer->status])); - } - line++; - } - weechat_buffer_set (xfer_buffer, "hotlist", hotlist); + weechat_buffer_set (xfer_buffer, "key_bind_meta2-A", "/xfer up"); + weechat_buffer_set (xfer_buffer, "key_bind_meta2-B", "/xfer down"); + weechat_buffer_set (xfer_buffer, "display", "1"); } } diff --git a/src/plugins/xfer/xfer-buffer.h b/src/plugins/xfer/xfer-buffer.h index aea4291e1..22f26ce76 100644 --- a/src/plugins/xfer/xfer-buffer.h +++ b/src/plugins/xfer/xfer-buffer.h @@ -21,8 +21,9 @@ #define __WEECHAT_XFER_DISPLAY_H 1 extern struct t_gui_buffer *xfer_buffer; +extern int xfer_buffer_selected_line; -extern void xfer_buffer_open (); extern void xfer_buffer_refresh (char *hotlist); +extern void xfer_buffer_open (); -#endif /* xfer.h */ +#endif /* xfer-buffer.h */ diff --git a/src/plugins/xfer/xfer-chat.c b/src/plugins/xfer/xfer-chat.c index 4999817e5..2dab0a2c8 100644 --- a/src/plugins/xfer/xfer-chat.c +++ b/src/plugins/xfer/xfer-chat.c @@ -74,37 +74,25 @@ xfer_chat_sendf (struct t_xfer *xfer, char *format, ...) { weechat_printf (NULL, _("%s%s: error sending data to \"%s\" via xfer chat"), - weechat_prefix ("error"), "xfer", xfer->nick); + weechat_prefix ("error"), "xfer", xfer->remote_nick); xfer_close (xfer, XFER_STATUS_FAILED); } } /* - * xfer_chat_recv: receive data from xfer chat remote host + * xfer_chat_recv_cb: receive data from xfer chat remote host */ -void -xfer_chat_recv (struct t_xfer *xfer) +int +xfer_chat_recv_cb (void *arg_xfer) { - fd_set read_fd; - static struct timeval timeout; + struct t_xfer *xfer; static char buffer[4096 + 2]; char *buf2, *pos, *ptr_buf, *next_ptr_buf; int num_read; - FD_ZERO (&read_fd); - FD_SET (xfer->sock, &read_fd); - timeout.tv_sec = 0; - timeout.tv_usec = 0; - - /* something to read on socket? */ - if (select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout) <= 0) - return; + xfer = (struct t_xfer *)arg_xfer; - if (!FD_ISSET (xfer->sock, &read_fd)) - return; - - /* there's something to read on socket! */ num_read = recv (xfer->sock, buffer, sizeof (buffer) - 2, 0); if (num_read > 0) { @@ -144,7 +132,7 @@ xfer_chat_recv (struct t_xfer *xfer) if (ptr_buf) { - weechat_printf (xfer->buffer, "%s\t%s", xfer->nick, ptr_buf); + weechat_printf (xfer->buffer, "%s\t%s", xfer->remote_nick, ptr_buf); } ptr_buf = next_ptr_buf; @@ -158,4 +146,94 @@ xfer_chat_recv (struct t_xfer *xfer) xfer_close (xfer, XFER_STATUS_ABORTED); xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); } + + return WEECHAT_RC_OK; +} + +/* + * xfer_chat_buffer_input_cb: callback called when user send data to xfer chat + * buffer + */ + +int +xfer_chat_buffer_input_cb (void *data, struct t_gui_buffer *buffer, + char *input_data) +{ + struct t_xfer *xfer; + + xfer = (struct t_xfer *)data; + + if (!XFER_HAS_ENDED(xfer->status)) + { + xfer_chat_sendf (xfer, "%s\n", input_data); + if (!XFER_HAS_ENDED(xfer->status)) + { + weechat_printf (buffer, + "%s\t%s", + xfer->local_nick, + input_data); + } + } + + return WEECHAT_RC_OK; +} + +/* + * xfer_chat_close_buffer_cb: callback called when a buffer with direct chat + * is closed + */ + +int +xfer_chat_buffer_close_cb (void *data, struct t_gui_buffer *buffer) +{ + struct t_xfer *xfer; + + /* make C compiler happy */ + (void) buffer; + + xfer = (struct t_xfer *)data; + + if (!XFER_HAS_ENDED(xfer->status)) + { + xfer_close (xfer, XFER_STATUS_ABORTED); + xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); + } + + xfer->buffer = NULL; + + return WEECHAT_RC_OK; +} + +/* + * xfer_chat_open_buffer: create channel for DCC chat + */ + +void +xfer_chat_open_buffer (struct t_xfer *xfer) +{ + char *name; + int length; + + length = strlen (xfer->plugin_name) + 1 + strlen (xfer->remote_nick) + 1; + name = malloc (length); + if (name) + { + snprintf (name, length, "%s_%s", xfer->plugin_name, xfer->remote_nick); + xfer->buffer = weechat_buffer_new ("xfer", name, + &xfer_chat_buffer_input_cb, xfer, + &xfer_chat_buffer_close_cb, xfer); + if (xfer->buffer) + { + weechat_buffer_set (xfer->buffer, "title", _("xfer chat")); + weechat_printf (xfer->buffer, + _("Connected to %s (%d.%d.%d.%d) via " + "xfer chat"), + xfer->remote_nick, + xfer->address >> 24, + (xfer->address >> 16) & 0xff, + (xfer->address >> 8) & 0xff, + xfer->address & 0xff); + } + free (name); + } } diff --git a/src/plugins/xfer/xfer-chat.h b/src/plugins/xfer/xfer-chat.h index b3470aca5..131a6111f 100644 --- a/src/plugins/xfer/xfer-chat.h +++ b/src/plugins/xfer/xfer-chat.h @@ -20,5 +20,7 @@ #ifndef __WEECHAT_XFER_CHAT_H #define __WEECHAT_XFER_CHAT_H 1 +extern int xfer_chat_recv_cb (void *arg_xfer); +extern void xfer_chat_open_buffer (struct t_xfer *xfer); #endif /* xfer-chat.h */ diff --git a/src/plugins/xfer/xfer-command.c b/src/plugins/xfer/xfer-command.c new file mode 100644 index 000000000..95d5adfff --- /dev/null +++ b/src/plugins/xfer/xfer-command.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2003-2008 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* xfer-command.c: xfer command */ + + +#include <stdlib.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "xfer.h" +#include "xfer-buffer.h" + + +/* + * xfer_command_xfer: command /xfer + */ + +int +xfer_command_xfer (void *data, struct t_gui_buffer *buffer, int argc, + char **argv, char **argv_eol) +{ + /* make C compiler happy */ + (void) data; + (void) buffer; + (void) argc; + (void) argv; + (void) argv_eol; + + if (!xfer_buffer) + xfer_buffer_open (); + + if (argc > 1) + { + if (strcmp (argv[1], "up") == 0) + { + if (xfer_buffer_selected_line > 0) + { + xfer_buffer_selected_line--; + xfer_buffer_refresh (NULL); + } + } + else if (strcmp (argv[1], "down") == 0) + { + if (xfer_buffer_selected_line < xfer_count - 1) + { + xfer_buffer_selected_line++; + xfer_buffer_refresh (NULL); + } + } + } + + return WEECHAT_RC_OK; +} + +/* + * xfer_command: xfer command + */ + +void +xfer_command_init () +{ + weechat_hook_command ("xfer", + N_("xfer control"), + "", + _("Open buffer with xfer list"), + NULL, &xfer_command_xfer, NULL); +} diff --git a/src/plugins/xfer/xfer-command.h b/src/plugins/xfer/xfer-command.h new file mode 100644 index 000000000..7b29cafc5 --- /dev/null +++ b/src/plugins/xfer/xfer-command.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2003-2008 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_XFER_COMMAND_H +#define __WEECHAT_XFER_COMMAND_H 1 + +extern void xfer_command_init (); + +#endif /* xfer-command.h */ diff --git a/src/plugins/xfer/xfer-config.c b/src/plugins/xfer/xfer-config.c index c532c7bc5..3efc0e487 100644 --- a/src/plugins/xfer/xfer-config.c +++ b/src/plugins/xfer/xfer-config.c @@ -32,6 +32,7 @@ struct t_config_file *xfer_config_file = NULL; /* xfer config, look section */ struct t_config_option *xfer_config_look_auto_open_buffer; +struct t_config_option *xfer_config_look_progress_bar_size; /* xfer config, color section */ @@ -104,6 +105,12 @@ xfer_config_init () N_("auto open xfer buffer and switch to it when a new xfer is added " "to list"), NULL, 0, 0, "on", NULL, NULL, NULL, NULL, NULL, NULL); + xfer_config_look_progress_bar_size = weechat_config_new_option ( + xfer_config_file, ptr_section, + "progress_bar_size", "integer", + N_("size of progress bar, in chars (if 0, progress bar is disabled)"), + NULL, 0, XFER_CONFIG_PROGRESS_BAR_MAX_SIZE, "20", + NULL, NULL, NULL, NULL, NULL, NULL); ptr_section = weechat_config_new_section (xfer_config_file, "color", 0, 0, diff --git a/src/plugins/xfer/xfer-config.h b/src/plugins/xfer/xfer-config.h index a7753d024..3101693a4 100644 --- a/src/plugins/xfer/xfer-config.h +++ b/src/plugins/xfer/xfer-config.h @@ -22,9 +22,12 @@ #define XFER_CONFIG_NAME "xfer" +#define XFER_CONFIG_PROGRESS_BAR_MAX_SIZE 256 + extern struct t_config_file *xfer_config; extern struct t_config_option *xfer_config_look_auto_open_buffer; +extern struct t_config_option *xfer_config_look_progress_bar_size; extern struct t_config_option *xfer_config_color_text; extern struct t_config_option *xfer_config_color_text_bg; diff --git a/src/plugins/xfer/xfer-dcc.c b/src/plugins/xfer/xfer-dcc.c index 5737ce515..4f94b5d1c 100644 --- a/src/plugins/xfer/xfer-dcc.c +++ b/src/plugins/xfer/xfer-dcc.c @@ -31,7 +31,6 @@ #include "../weechat-plugin.h" #include "xfer.h" -#include "xfer-dcc.h" #include "xfer-network.h" diff --git a/src/plugins/xfer/xfer-file.c b/src/plugins/xfer/xfer-file.c index cc067f1b4..e43729bd7 100644 --- a/src/plugins/xfer/xfer-file.c +++ b/src/plugins/xfer/xfer-file.c @@ -101,7 +101,7 @@ xfer_file_find_filename (struct t_xfer *xfer) } xfer->local_filename = malloc (strlen (dir2) + - strlen (xfer->nick) + + strlen (xfer->remote_nick) + strlen (xfer->filename) + 4); if (!xfer->local_filename) return; @@ -111,7 +111,7 @@ xfer_file_find_filename (struct t_xfer *xfer) if (dir_separator && (xfer->local_filename[strlen (xfer->local_filename) - 1] != dir_separator[0])) strcat (xfer->local_filename, dir_separator); - strcat (xfer->local_filename, xfer->nick); + strcat (xfer->local_filename, xfer->remote_nick); strcat (xfer->local_filename, "."); strcat (xfer->local_filename, xfer->filename); diff --git a/src/plugins/xfer/xfer-network.c b/src/plugins/xfer/xfer-network.c index 2c9247996..e0f26e0b7 100644 --- a/src/plugins/xfer/xfer-network.c +++ b/src/plugins/xfer/xfer-network.c @@ -28,59 +28,18 @@ #include <sys/socket.h> #include <signal.h> #include <time.h> +#include <netdb.h> #include "../weechat-plugin.h" #include "xfer.h" -#include "xfer-network.h" #include "xfer-buffer.h" +#include "xfer-chat.h" +#include "xfer-config.h" #include "xfer-dcc.h" #include "xfer-file.h" /* - * xfer_network_connect: connect to another host - */ - -int -xfer_network_connect (struct t_xfer *xfer) -{ - if (xfer->type == XFER_TYPE_CHAT_SEND) - xfer->status = XFER_STATUS_WAITING; - else - xfer->status = XFER_STATUS_CONNECTING; - - if (xfer->sock < 0) - { - xfer->sock = socket (AF_INET, SOCK_STREAM, 0); - if (xfer->sock < 0) - return 0; - } - - /* for chat or file sending, listen to socket for a connection */ - if (XFER_IS_SEND(xfer->type)) - { - if (fcntl (xfer->sock, F_SETFL, O_NONBLOCK) == -1) - return 0; - if (listen (xfer->sock, 1) == -1) - return 0; - if (fcntl (xfer->sock, F_SETFL, 0) == -1) - return 0; - } - - /* for chat receiving, connect to listening host */ - if (xfer->type == XFER_TYPE_CHAT_RECV) - { - if (fcntl (xfer->sock, F_SETFL, O_NONBLOCK) == -1) - return 0; - weechat_network_connect_to (xfer->sock, xfer->address, xfer->port); - } - - /* for file receiving, connection is made in child process (blocking) */ - - return 1; -} - -/* * xfer_network_create_pipe: create pipe for communication with child process * return 1 if ok, 0 if error */ @@ -313,6 +272,239 @@ xfer_network_recv_file_fork (struct t_xfer *xfer) } /* + * xfer_network_child_kill: kill child process and close pipe + */ + +void +xfer_network_child_kill (struct t_xfer *xfer) +{ + /* kill process */ + if (xfer->child_pid > 0) + { + kill (xfer->child_pid, SIGKILL); + waitpid (xfer->child_pid, NULL, 0); + xfer->child_pid = 0; + } + + /* close pipe used with child */ + if (xfer->child_read != -1) + { + close (xfer->child_read); + xfer->child_read = -1; + } + if (xfer->child_write != -1) + { + close (xfer->child_write); + xfer->child_write = -1; + } +} + +/* + * xfer_network_fd_cb: callback called when data is available on xfer socket + */ + +int +xfer_network_fd_cb (void *arg_xfer) +{ + struct t_xfer *xfer; + int sock; + struct sockaddr_in addr; + socklen_t length; + + xfer = (struct t_xfer *)arg_xfer; + + if (xfer->status == XFER_STATUS_CONNECTING) + { + if (xfer->type == XFER_TYPE_FILE_SEND) + { + xfer->last_activity = time (NULL); + length = sizeof (addr); + sock = accept (xfer->sock, + (struct sockaddr *) &addr, &length); + weechat_unhook (xfer->hook_fd); + xfer->hook_fd = NULL; + close (xfer->sock); + xfer->sock = -1; + if (sock < 0) + { + weechat_printf (NULL, + _("%s%s: unable to create socket for sending " + "file"), + weechat_prefix ("error"), "xfer"); + xfer_close (xfer, XFER_STATUS_FAILED); + xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); + return WEECHAT_RC_OK; + } + xfer->sock = sock; + if (fcntl (xfer->sock, F_SETFL, O_NONBLOCK) == -1) + { + weechat_printf (NULL, + _("%s%s: unable to set option \"nonblock\" " + "for socket"), + weechat_prefix ("error"), "xfer"); + xfer_close (xfer, XFER_STATUS_FAILED); + xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); + return WEECHAT_RC_OK; + } + xfer->address = ntohl (addr.sin_addr.s_addr); + xfer->status = XFER_STATUS_ACTIVE; + xfer->start_transfer = time (NULL); + xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); + xfer_network_send_file_fork (xfer); + } + /* + if (xfer->type == XFER_TYPE_FILE_RECV) + { + if (xfer->child_read != -1) + irc_dcc_file_child_read (dcc); + } + */ + } + + if (xfer->status == XFER_STATUS_WAITING) + { + if (xfer->type == XFER_TYPE_CHAT_SEND) + { + length = sizeof (addr); + sock = accept (xfer->sock, (struct sockaddr *) &addr, &length); + weechat_unhook (xfer->hook_fd); + xfer->hook_fd = NULL; + close (xfer->sock); + xfer->sock = -1; + if (sock < 0) + { + weechat_printf (NULL, + _("%s%s: unable to create socket for sending " + "file"), + weechat_prefix ("error"), "xfer"); + xfer_close (xfer, XFER_STATUS_FAILED); + xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); + return WEECHAT_RC_OK; + } + xfer->sock = sock; + if (fcntl (xfer->sock, F_SETFL, O_NONBLOCK) == -1) + { + weechat_printf (NULL, + _("%s%s: unable to set option \"nonblock\" " + "for socket"), + weechat_prefix ("error"), "xfer"); + xfer_close (xfer, XFER_STATUS_FAILED); + xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); + return WEECHAT_RC_OK; + } + xfer->address = ntohl (addr.sin_addr.s_addr); + xfer->status = XFER_STATUS_ACTIVE; + xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); + xfer->hook_fd = weechat_hook_fd (xfer->sock, + 1, 0, 0, + &xfer_chat_recv_cb, + xfer); + xfer_chat_open_buffer (xfer); + } + } + /* + if (xfer->status == XFER_STATUS_ACTIVE) + { + if (XFER_IS_CHAT(dcc->type)) + { + irc_dcc_chat_recv (dcc); + } + else + irc_dcc_file_child_read (dcc); + } + */ + return WEECHAT_RC_OK; +} + +/* + * xfer_network_timer_cb: callback called to check if there's a timeout for xfer + * (called only one time for xfer) + */ + +int +xfer_network_timer_cb (void *arg_xfer) +{ + struct t_xfer *xfer; + + xfer = (struct t_xfer *)arg_xfer; + + if ((xfer->status == XFER_STATUS_WAITING) + || (xfer->status == XFER_STATUS_CONNECTING)) + { + weechat_printf (NULL, + _("%s%s: timeout for \"%s\" with %s"), + weechat_prefix ("error"), "xfer", + xfer->filename, xfer->remote_nick); + xfer_close (xfer, XFER_STATUS_FAILED); + xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); + } + + return WEECHAT_RC_OK; +} + +/* + * xfer_network_connect: connect to another host + */ + +int +xfer_network_connect (struct t_xfer *xfer) +{ + if (xfer->type == XFER_TYPE_CHAT_SEND) + xfer->status = XFER_STATUS_WAITING; + else + xfer->status = XFER_STATUS_CONNECTING; + + if (xfer->sock < 0) + { + xfer->sock = socket (AF_INET, SOCK_STREAM, 0); + if (xfer->sock < 0) + return 0; + } + + if (XFER_IS_SEND(xfer->type)) + { + /* listen to socket */ + if (fcntl (xfer->sock, F_SETFL, O_NONBLOCK) == -1) + return 0; + if (listen (xfer->sock, 1) == -1) + return 0; + if (fcntl (xfer->sock, F_SETFL, 0) == -1) + return 0; + + xfer->hook_fd = weechat_hook_fd (xfer->sock, + 1, 0, 0, + &xfer_network_fd_cb, + xfer); + + /* add timeout */ + if (weechat_config_integer (xfer_config_network_timeout) > 0) + { + xfer->hook_timer = weechat_hook_timer (weechat_config_integer (xfer_config_network_timeout) * 1000, + 0, 1, + &xfer_network_timer_cb, + xfer); + } + } + + /* for chat receiving, connect to listening host */ + if (xfer->type == XFER_TYPE_CHAT_RECV) + { + if (fcntl (xfer->sock, F_SETFL, O_NONBLOCK) == -1) + return 0; + weechat_network_connect_to (xfer->sock, xfer->address, xfer->port); + + xfer->hook_fd = weechat_hook_fd (xfer->sock, + 1, 0, 0, + &xfer_chat_recv_cb, + xfer); + } + + /* for file receiving, connection is made in child process (blocking) */ + + return 1; +} + +/* * xfer_network_connect_init: connect to sender and init file or chat */ @@ -336,36 +528,33 @@ xfer_network_connect_init (struct t_xfer *xfer) { /* for a chat => associate with buffer */ xfer->status = XFER_STATUS_ACTIVE; - // TODO: create buffer for xfer chat + xfer_chat_open_buffer (xfer); } } xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); } /* - * xfer_network_child_kill: kill child process and close pipe + * xfer_network_accept: accept a xfer file or chat request */ void -xfer_network_child_kill (struct t_xfer *xfer) +xfer_network_accept (struct t_xfer *xfer) { - /* kill process */ - if (xfer->child_pid > 0) - { - kill (xfer->child_pid, SIGKILL); - waitpid (xfer->child_pid, NULL, 0); - xfer->child_pid = 0; - } - - /* close pipe used with child */ - if (xfer->child_read != -1) + if (XFER_IS_FILE(xfer->type) && (xfer->start_resume > 0)) { - close (xfer->child_read); - xfer->child_read = -1; - } - if (xfer->child_write != -1) - { - close (xfer->child_write); - xfer->child_write = -1; + xfer->status = XFER_STATUS_CONNECTING; + xfer_send_signal (xfer, "xfer_accepted"); + /* + irc_server_sendf (dcc->server, + (strchr (dcc->filename, ' ')) ? + "PRIVMSG %s :\01DCC RESUME \"%s\" %d %u\01\n" : + "PRIVMSG %s :\01DCC RESUME %s %d %u\01", + dcc->nick, dcc->filename, + dcc->port, dcc->start_resume); + */ + xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); } + else + xfer_network_connect_init (xfer); } diff --git a/src/plugins/xfer/xfer-network.h b/src/plugins/xfer/xfer-network.h index a542ed542..17b007662 100644 --- a/src/plugins/xfer/xfer-network.h +++ b/src/plugins/xfer/xfer-network.h @@ -20,11 +20,12 @@ #ifndef __WEECHAT_XFER_NETWORK_H #define __WEECHAT_XFER_NETWORK_H 1 -extern int xfer_network_connect (struct t_xfer *xfer); extern int xfer_network_create_pipe (struct t_xfer *xfer); extern void xfer_network_write_pipe (struct t_xfer *xfer, int status, int error); extern void xfer_network_connect_init (struct t_xfer *xfer); extern void xfer_network_child_kill (struct t_xfer *xfer); +extern int xfer_network_connect (struct t_xfer *xfer); +extern void xfer_network_accept (struct t_xfer *xfer); #endif /* xfer-network.h */ diff --git a/src/plugins/xfer/xfer.c b/src/plugins/xfer/xfer.c index 5df3f2370..86a8cec19 100644 --- a/src/plugins/xfer/xfer.c +++ b/src/plugins/xfer/xfer.c @@ -32,6 +32,7 @@ #include "../weechat-plugin.h" #include "xfer.h" #include "xfer-buffer.h" +#include "xfer-command.h" #include "xfer-config.h" #include "xfer-file.h" #include "xfer-network.h" @@ -64,6 +65,7 @@ char *xfer_status_string[] = /* strings for status */ struct t_xfer *xfer_list = NULL; /* list of files/chats */ struct t_xfer *last_xfer = NULL; /* last file/chat in list */ +int xfer_count = 0; /* number of xfer */ int xfer_debug = 0; @@ -155,6 +157,114 @@ xfer_search (enum t_xfer_type type, enum t_xfer_status status, int port) } /* + * xfer_search_by_number: search a xfer by number (first xfer is 0) + */ + +struct t_xfer * +xfer_search_by_number (int number) +{ + struct t_xfer *ptr_xfer; + int i; + + i = 0; + for (ptr_xfer = xfer_list; ptr_xfer; ptr_xfer = ptr_xfer->next_xfer) + { + if (i == number) + return ptr_xfer; + i++; + } + + /* xfer not found */ + return NULL; +} + +/* + * xfer_close: close a xfer + */ + +void +xfer_close (struct t_xfer *xfer, enum t_xfer_status status) +{ + struct stat st; + + xfer->status = status; + + if (XFER_HAS_ENDED(xfer->status)) + { + if (xfer->hook_fd) + { + weechat_unhook (xfer->hook_fd); + xfer->hook_fd = NULL; + } + if (xfer->hook_timer) + { + weechat_unhook (xfer->hook_timer); + xfer->hook_timer = NULL; + } + if (XFER_IS_FILE(xfer->type)) + { + weechat_printf (NULL, + _("%s%s: file %s %s %s: %s"), + (xfer->status == XFER_STATUS_DONE) ? + "" : weechat_prefix ("error"), + "xfer", + xfer->filename, + (xfer->type == XFER_TYPE_FILE_SEND) ? + _("sent to") : _("received from"), + xfer->remote_nick, + (xfer->status == XFER_STATUS_DONE) ? + _("OK") : _("FAILED")); + xfer_network_child_kill (xfer); + } + } + if (xfer->status == XFER_STATUS_ABORTED) + { + if (XFER_IS_CHAT(xfer->type)) + { + weechat_printf (xfer->buffer, + _("%s: chat closed with %s " + "(%d.%d.%d.%d)"), + "xfer", + xfer->remote_nick, + xfer->address >> 24, + (xfer->address >> 16) & 0xff, + (xfer->address >> 8) & 0xff, + xfer->address & 0xff); + } + } + + /* remove empty file if received file failed and nothing was transfered */ + if (((xfer->status == XFER_STATUS_FAILED) + || (xfer->status == XFER_STATUS_ABORTED)) + && XFER_IS_FILE(xfer->type) + && XFER_IS_RECV(xfer->type) + && xfer->local_filename + && xfer->pos == 0) + { + /* erase file only if really empty on disk */ + if (stat (xfer->local_filename, &st) != -1) + { + if ((unsigned long) st.st_size == 0) + unlink (xfer->local_filename); + } + } + + if (XFER_IS_FILE(xfer->type)) + xfer_file_calculate_speed (xfer, 1); + + if (xfer->sock >= 0) + { + close (xfer->sock); + xfer->sock = -1; + } + if (xfer->file >= 0) + { + close (xfer->file); + xfer->file = -1; + } +} + +/* * xfer_port_in_use: return 1 if a port is in used * (by an active or connecting xfer) */ @@ -192,14 +302,18 @@ xfer_send_signal (struct t_xfer *xfer, char *signal) item = weechat_infolist_new_item (infolist); if (item) { + weechat_infolist_new_var_string (item, "plugin_name", + xfer->plugin_name); weechat_infolist_new_var_string (item, "plugin_id", xfer->plugin_id); weechat_infolist_new_var_string (item, "type", xfer_type_string[xfer->type]); weechat_infolist_new_var_string (item, "protocol", xfer_protocol_string[xfer->protocol]); - weechat_infolist_new_var_string (item, "nick", - xfer->nick); + weechat_infolist_new_var_string (item, "remote_nick", + xfer->remote_nick); + weechat_infolist_new_var_string (item, "local_nick", + xfer->local_nick); weechat_infolist_new_var_string (item, "filename", xfer->filename); snprintf (str_long, sizeof (str_long), "%lu", xfer->size); @@ -239,7 +353,8 @@ xfer_alloc () new_xfer->size = 0; new_xfer->address = 0; new_xfer->port = 0; - new_xfer->nick = NULL; + new_xfer->remote_nick = NULL; + new_xfer->local_nick = NULL; new_xfer->type = 0; new_xfer->protocol = 0; @@ -254,6 +369,7 @@ xfer_alloc () new_xfer->child_read = -1; new_xfer->child_write = -1; new_xfer->hook_fd = NULL; + new_xfer->hook_timer = NULL; new_xfer->unterminated_message = NULL; new_xfer->file = -1; new_xfer->local_filename = NULL; @@ -275,41 +391,19 @@ xfer_alloc () last_xfer = new_xfer; xfer_list = new_xfer; + xfer_count++; + return new_xfer; } /* - * xfer_accept: accept a xfer file or chat request - */ - -void -xfer_accept (struct t_xfer *xfer) -{ - if (XFER_IS_FILE(xfer->type) && (xfer->start_resume > 0)) - { - xfer->status = XFER_STATUS_CONNECTING; - xfer_send_signal (xfer, "xfer_accepted"); - /* - irc_server_sendf (dcc->server, - (strchr (dcc->filename, ' ')) ? - "PRIVMSG %s :\01DCC RESUME \"%s\" %d %u\01\n" : - "PRIVMSG %s :\01DCC RESUME %s %d %u\01", - dcc->nick, dcc->filename, - dcc->port, dcc->start_resume); - */ - xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); - } - else - xfer_network_connect_init (xfer); -} - -/* * xfer_new: add a xfer to list */ struct t_xfer * -xfer_new (char *plugin_id, enum t_xfer_type type, - enum t_xfer_protocol protocol, char *nick, char *filename, +xfer_new (char *plugin_name, char *plugin_id, enum t_xfer_type type, + enum t_xfer_protocol protocol, char *remote_nick, char *local_nick, + char *filename, unsigned long size, unsigned long address, int port, int sock, char *local_filename) { @@ -331,12 +425,16 @@ xfer_new (char *plugin_id, enum t_xfer_type type, } /* initialize new xfer */ + new_xfer->plugin_name = strdup (plugin_name); new_xfer->plugin_id = strdup (plugin_id); new_xfer->type = type; new_xfer->protocol = protocol; - new_xfer->nick = strdup (nick); + new_xfer->remote_nick = strdup (remote_nick); + new_xfer->local_nick = (local_nick) ? strdup (local_nick) : NULL; if (XFER_IS_FILE(type)) new_xfer->filename = (filename) ? strdup (filename) : NULL; + else + new_xfer->filename = strdup (_("xfer chat")); new_xfer->size = size; new_xfer->address = address; new_xfer->port = port; @@ -356,7 +454,7 @@ xfer_new (char *plugin_id, enum t_xfer_type type, _("%s: incoming file from %s " "(%d.%d.%d.%d): %s, %lu bytes (protocol: %s)"), "xfer", - nick, + remote_nick, address >> 24, (address >> 16) & 0xff, (address >> 8) & 0xff, @@ -371,7 +469,7 @@ xfer_new (char *plugin_id, enum t_xfer_type type, _("%s: sending file to %s: %s " "(local filename: %s), %lu bytes (protocol: %s)"), "xfer", - nick, + remote_nick, filename, local_filename, size, @@ -383,7 +481,7 @@ xfer_new (char *plugin_id, enum t_xfer_type type, _("%s: incoming chat request from %s " "(%d.%d.%d.%d)"), "xfer", - nick, + remote_nick, address >> 24, (address >> 16) & 0xff, (address >> 8) & 0xff, @@ -394,7 +492,7 @@ xfer_new (char *plugin_id, enum t_xfer_type type, weechat_printf (NULL, _("%s: sending chat request to %s"), "xfer", - nick); + remote_nick); xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); break; case XFER_NUM_TYPES: @@ -431,11 +529,11 @@ xfer_new (char *plugin_id, enum t_xfer_type type, } } - if ( ( (type == XFER_TYPE_CHAT_RECV) - && (weechat_config_boolean (xfer_config_file_auto_accept_chats)) ) - || ( (type == XFER_TYPE_FILE_RECV) - && (weechat_config_boolean (xfer_config_file_auto_accept_files)) ) ) - xfer_accept (new_xfer); + if ( ( (type == XFER_TYPE_FILE_RECV) + && (weechat_config_boolean (xfer_config_file_auto_accept_files)) ) + || ( (type == XFER_TYPE_CHAT_RECV) + && (weechat_config_boolean (xfer_config_file_auto_accept_chats)) ) ) + xfer_network_accept (new_xfer); else xfer_buffer_refresh (WEECHAT_HOTLIST_PRIVATE); @@ -454,10 +552,9 @@ xfer_free (struct t_xfer *xfer) if (!xfer) return; - /* close chat buffer */ if (xfer->buffer) { - /* TODO: close chat buffer */ + weechat_buffer_close (xfer->buffer, 1); } /* remove xfer from list */ @@ -472,12 +569,14 @@ xfer_free (struct t_xfer *xfer) new_xfer_list = xfer->next_xfer; if (xfer->next_xfer) (xfer->next_xfer)->prev_xfer = xfer->prev_xfer; - + /* free data */ if (xfer->plugin_id) free (xfer->plugin_id); - if (xfer->nick) - free (xfer->nick); + if (xfer->remote_nick) + free (xfer->remote_nick); + if (xfer->local_nick) + free (xfer->local_nick); if (xfer->filename) free (xfer->filename); if (xfer->unterminated_message) @@ -488,80 +587,10 @@ xfer_free (struct t_xfer *xfer) free (xfer); xfer_list = new_xfer_list; -} - -/* - * xfer_close: close a xfer - */ - -void -xfer_close (struct t_xfer *xfer, enum t_xfer_status status) -{ - struct stat st; - - xfer->status = status; - - if (XFER_HAS_ENDED(xfer->status)) - { - if (XFER_IS_FILE(xfer->type)) - { - weechat_printf (NULL, - _("%s: file %s %s %s: %s"), - "xfer", - xfer->filename, - (xfer->type == XFER_TYPE_FILE_SEND) ? - _("sent to") : _("received from"), - xfer->nick, - (xfer->status == XFER_STATUS_DONE) ? - _("OK") : _("FAILED")); - xfer_network_child_kill (xfer); - } - } - if (xfer->status == XFER_STATUS_ABORTED) - { - if (XFER_IS_CHAT(xfer->type)) - { - weechat_printf (xfer->buffer, - _("%s: chat closed with %s " - "(%d.%d.%d.%d)"), - "xfer", - xfer->nick, - xfer->address >> 24, - (xfer->address >> 16) & 0xff, - (xfer->address >> 8) & 0xff, - xfer->address & 0xff); - } - } - /* remove empty file if received file failed and nothing was transfered */ - if (((xfer->status == XFER_STATUS_FAILED) - || (xfer->status == XFER_STATUS_ABORTED)) - && XFER_IS_FILE(xfer->type) - && XFER_IS_RECV(xfer->type) - && xfer->local_filename - && xfer->pos == 0) - { - /* erase file only if really empty on disk */ - if (stat (xfer->local_filename, &st) != -1) - { - if ((unsigned long) st.st_size == 0) - unlink (xfer->local_filename); - } - } - - if (XFER_IS_FILE(xfer->type)) - xfer_file_calculate_speed (xfer, 1); - - if (xfer->sock >= 0) - { - close (xfer->sock); - xfer->sock = -1; - } - if (xfer->file >= 0) - { - close (xfer->file); - xfer->file = -1; - } + xfer_count--; + if (xfer_buffer_selected_line >= xfer_count) + xfer_buffer_selected_line = (xfer_count == 0) ? 0 : xfer_count - 1; } /* @@ -572,7 +601,8 @@ int xfer_add_cb (void *data, char *signal, char *type_data, void *signal_data) { struct t_plugin_infolist *infolist; - char *plugin_id, *str_type, *nick, *filename, *str_protocol; + char *plugin_name, *plugin_id, *str_type, *str_protocol; + char *remote_nick, *local_nick, *filename; int type, protocol; char *weechat_dir, *dir1, *dir2, *filename2, *short_filename, *pos; int spaces, args, port_start, port_end; @@ -612,14 +642,16 @@ xfer_add_cb (void *data, char *signal, char *type_data, void *signal_data) return WEECHAT_RC_ERROR; } + plugin_name = weechat_infolist_string (infolist, "plugin_name"); plugin_id = weechat_infolist_string (infolist, "plugin_id"); str_type = weechat_infolist_string (infolist, "type"); - nick = weechat_infolist_string (infolist, "nick"); - filename = weechat_infolist_string (infolist, "filename"); str_protocol = weechat_infolist_string (infolist, "protocol"); + remote_nick = weechat_infolist_string (infolist, "remote_nick"); + local_nick = weechat_infolist_string (infolist, "local_nick"); + filename = weechat_infolist_string (infolist, "filename"); protocol = XFER_NO_PROTOCOL; - if (!plugin_id || !str_type || !nick) + if (!plugin_name || !plugin_id || !str_type || !remote_nick || !local_nick) { weechat_printf (NULL, _("%s%s: missing arguments"), @@ -636,19 +668,11 @@ xfer_add_cb (void *data, char *signal, char *type_data, void *signal_data) return WEECHAT_RC_ERROR; } - if (XFER_IS_FILE(type) && !filename) + if (XFER_IS_FILE(type) && (!filename || !str_protocol)) { weechat_printf (NULL, - _("%s%s: filename missing for type \"%s\""), - weechat_prefix ("error"), "xfer", str_type); - return WEECHAT_RC_ERROR; - } - - if (XFER_IS_FILE(type) && !str_protocol) - { - weechat_printf (NULL, - _("%s%s: protocol missing for type \"%s\""), - weechat_prefix ("error"), "xfer", str_type); + _("%s%s: missing arguments"), + weechat_prefix ("error"), "xfer"); return WEECHAT_RC_ERROR; } @@ -670,11 +694,10 @@ xfer_add_cb (void *data, char *signal, char *type_data, void *signal_data) if (type == XFER_TYPE_FILE_RECV) { - filename2 = weechat_infolist_string (infolist, "filename"); + filename2 = strdup (filename); sscanf (weechat_infolist_string (infolist, "size"), "%lu", &file_size); - port = weechat_infolist_integer (infolist, "port"); } - + if (type == XFER_TYPE_FILE_SEND) { /* add home if filename not beginning with '/' or '~' (not for Win32) */ @@ -744,7 +767,7 @@ xfer_add_cb (void *data, char *signal, char *type_data, void *signal_data) if (XFER_IS_RECV(type)) { sscanf (weechat_infolist_string (infolist, "address"), "%lu", &local_addr); - sscanf (weechat_infolist_string (infolist, "size"), "%lu", &file_size); + port = weechat_infolist_integer (infolist, "port"); } else { @@ -848,7 +871,7 @@ xfer_add_cb (void *data, char *signal, char *type_data, void *signal_data) } } - if (type == XFER_TYPE_FILE_SEND) + if (XFER_IS_FILE(type)) { /* extract short filename (without path) */ pos = strrchr (filename2, DIR_SEPARATOR_CHAR); @@ -872,14 +895,25 @@ xfer_add_cb (void *data, char *signal, char *type_data, void *signal_data) pos++; } } + + if (type == XFER_TYPE_FILE_RECV) + { + if (filename2) + { + free (filename2); + filename2 = NULL; + } + } /* add xfer entry and listen to socket if type is file or chat "send" */ if (XFER_IS_FILE(type)) - ptr_xfer = xfer_new (plugin_id, type, protocol, nick, short_filename, + ptr_xfer = xfer_new (plugin_name, plugin_id, type, protocol, + remote_nick, local_nick, short_filename, file_size, local_addr, port, sock, filename2); else - ptr_xfer = xfer_new (plugin_id, type, protocol, nick, NULL, 0, - local_addr, port, sock, NULL); + ptr_xfer = xfer_new (plugin_name, plugin_id, type, protocol, + remote_nick, local_nick, NULL, 0, local_addr, + port, sock, NULL); if (!ptr_xfer) { @@ -896,7 +930,8 @@ xfer_add_cb (void *data, char *signal, char *type_data, void *signal_data) } /* send signal if type is file or chat "send" */ - xfer_send_signal (ptr_xfer, "xfer_send_ready"); + if (XFER_IS_SEND(ptr_xfer->type)) + xfer_send_signal (ptr_xfer, "xfer_send_ready"); if (short_filename) free (short_filename); @@ -919,11 +954,13 @@ xfer_print_log () { weechat_log_printf (""); weechat_log_printf ("[xfer (addr:0x%x)]", ptr_xfer); + weechat_log_printf (" plugin_name . . . . : '%s'", ptr_xfer->plugin_name); weechat_log_printf (" plugin_id . . . . . : '%s'", ptr_xfer->plugin_id); weechat_log_printf (" type. . . . . . . . : %d (%s)", ptr_xfer->type, xfer_type_string[ptr_xfer->type]); - weechat_log_printf (" nick. . . . . . . . : '%s'", ptr_xfer->nick); + weechat_log_printf (" remote_nick . . . . : '%s'", ptr_xfer->remote_nick); + weechat_log_printf (" local_nick. . . . . : '%s'", ptr_xfer->local_nick); weechat_log_printf (" filename. . . . . . : '%s'", ptr_xfer->filename); weechat_log_printf (" size. . . . . . . . : %lu", ptr_xfer->size); weechat_log_printf (" address . . . . . . : %lu", ptr_xfer->address); @@ -1002,6 +1039,8 @@ weechat_plugin_init (struct t_weechat_plugin *plugin) xfer_create_directories (); + xfer_command_init (); + weechat_hook_signal ("xfer_add", &xfer_add_cb, NULL); weechat_hook_signal ("debug_dump", &xfer_debug_dump_cb, NULL); @@ -1029,10 +1068,10 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) weechat_printf (NULL, _("%s%s: aborting active xfer: \"%s\" from %s"), weechat_prefix ("error"), "xfer", - ptr_xfer->filename, ptr_xfer->nick); - weechat_log_printf (_("%s: aborting active xfer: \"%s\" from %s"), - "xfer", - ptr_xfer->filename, ptr_xfer->nick); + ptr_xfer->filename, ptr_xfer->remote_nick); + weechat_log_printf (_("%s%s: aborting active xfer: \"%s\" from %s"), + "", "xfer", + ptr_xfer->filename, ptr_xfer->remote_nick); } xfer_close (ptr_xfer, XFER_STATUS_FAILED); } diff --git a/src/plugins/xfer/xfer.h b/src/plugins/xfer/xfer.h index ac580d5a4..a357fbefa 100644 --- a/src/plugins/xfer/xfer.h +++ b/src/plugins/xfer/xfer.h @@ -106,10 +106,12 @@ enum t_xfer_error struct t_xfer { /* data received by xfer to initiate a transfer */ - char *plugin_id; /* plugin identifier */ + char *plugin_name; /* plugin name */ + char *plugin_id; /* id used by plugin */ enum t_xfer_type type; /* xfer type (send/recv file) */ enum t_xfer_protocol protocol; /* xfer protocol (for file transfer) */ - char *nick; /* remote nick */ + char *remote_nick; /* remote nick */ + char *local_nick; /* local nick */ char *filename; /* filename */ unsigned long size; /* file size */ unsigned long address; /* local or remote IP address */ @@ -127,6 +129,7 @@ struct t_xfer int child_read; /* to read into child pipe */ int child_write; /* to write into child pipe */ struct t_hook *hook_fd; /* hook for socket or child pipe */ + struct t_hook *hook_timer; /* timeout for recever accept */ char *unterminated_message; /* beginning of a message */ int file; /* local file (read or write) */ char *local_filename; /* local filename (with path) */ @@ -148,9 +151,12 @@ extern char *xfer_type_string[]; extern char *xfer_protocol_string[]; extern char *xfer_status_string[]; extern struct t_xfer *xfer_list, *last_xfer; +extern int xfer_count; extern int xfer_debug; +extern struct t_xfer *xfer_search_by_number (int number); extern void xfer_close (struct t_xfer *xfer, enum t_xfer_status status); -extern struct t_xfer *xfer_alloc (); +extern void xfer_send_signal (struct t_xfer *xfer, char *signal); +extern void xfer_free (struct t_xfer *xfer); #endif /* xfer.h */ |