1
0
mirror of https://github.com/weechat/weechat.git synced 2026-06-26 04:46:37 +02:00

Added new plugin "xfer" (used by irc plugin for DCC file and chat) (warning: initial commit, not working yet)

This commit is contained in:
Sebastien Helleu
2008-05-04 20:24:20 +02:00
parent ff526c3168
commit e7a16efa0c
55 changed files with 5721 additions and 4206 deletions
+4
View File
@@ -71,3 +71,7 @@ ENDIF(NOT DISABLE_SCRIPTS AND NOT DISABLE_PERL AND NOT DISABLE_PYTHON AND NOT DI
IF(NOT DISABLE_TRIGGER)
ADD_SUBDIRECTORY( trigger )
ENDIF(NOT DISABLE_TRIGGER)
IF(NOT DISABLE_XFER)
ADD_SUBDIRECTORY( xfer )
ENDIF(NOT DISABLE_XFER)
+5 -1
View File
@@ -80,6 +80,10 @@ if PLUGIN_TRIGGER
trigger_dir = trigger
endif
if PLUGIN_XFER
xfer_dir = xfer
endif
SUBDIRS = . $(alias_dir) $(aspell_dir) $(charset_dir) $(debug_dir) \
$(demo_dir) $(fifo_dir) $(irc_dir) $(logger_dir) $(script_dir) \
$(trigger_dir)
$(trigger_dir) $(xfer_dir)
+15 -6
View File
@@ -14,17 +14,26 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
ADD_LIBRARY(irc MODULE irc.c irc.h irc-buffer.c irc-buffer.h irc-channel.c
irc-channel.h irc-color.c irc-color.h irc-command.c irc-command.h
irc-completion.c irc-completion.h irc-config.c irc-config.h irc-dcc.h
irc-debug.c irc-debug.h irc-display.c irc-display.h irc-input.c irc-input.h
irc-mode.c irc-mode.h irc-nick.c irc-nick.h irc-protocol.c irc-protocol.h
ADD_LIBRARY(irc MODULE
irc.c irc.h
irc-buffer.c irc-buffer.h
irc-channel.c irc-channel.h
irc-color.c irc-color.h
irc-command.c irc-command.h
irc-completion.c irc-completion.h
irc-config.c irc-config.h
irc-dcc.c irc-dcc.h
irc-debug.c irc-debug.h
irc-display.c irc-display.h
irc-input.c irc-input.h
irc-mode.c irc-mode.h
irc-nick.c irc-nick.h
irc-protocol.c irc-protocol.h
irc-server.c irc-server.h)
SET_TARGET_PROPERTIES(irc PROPERTIES PREFIX "")
CHECK_INCLUDE_FILES("regex.h" HAVE_REGEX_H)
CHECK_FUNCTION_EXISTS(regexec HAVE_REGEXEC)
CHECK_FUNCTION_EXISTS(uname HAVE_UNAME)
TARGET_LINK_LIBRARIES(irc)
+2 -3
View File
@@ -34,6 +34,7 @@ irc_la_SOURCES = irc.c \
irc-completion.h \
irc-config.c \
irc-config.h \
irc-dcc.c \
irc-dcc.h \
irc-debug.c \
irc-debug.h \
@@ -50,7 +51,5 @@ irc_la_SOURCES = irc.c \
irc-server.c \
irc-server.h
# irc-dcc.c
irc_la_LDFLAGS = -module
irc_la_LIBADD = $(GNUTLS_LFLAGS)
irc_la_LIBADD = $(IRC_LFLAGS) $(GNUTLS_LFLAGS)
+60 -6
View File
@@ -25,6 +25,9 @@
#include <ctype.h>
#include <sys/time.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "../weechat-plugin.h"
#include "irc.h"
@@ -855,16 +858,29 @@ int
irc_command_dcc (void *data, struct t_gui_buffer *buffer, int argc,
char **argv, char **argv_eol)
{
struct sockaddr_in addr;
socklen_t length;
unsigned long address;
struct t_plugin_infolist *infolist;
struct t_plugin_infolist_item *item;
char plugin_id[128], str_address[128];
IRC_GET_SERVER_CHANNEL(buffer);
if (!ptr_server || !ptr_server->is_connected)
return WEECHAT_RC_ERROR;
/* make compiler happy */
/* make C compiler happy */
(void) data;
(void) argv_eol; // to remove!
if (argc > 1)
{
/* use the local interface, from the server socket */
memset (&addr, 0, sizeof (struct sockaddr_in));
length = sizeof (addr);
getsockname (ptr_server->sock, (struct sockaddr *) &addr, &length);
addr.sin_family = AF_INET;
address = ntohl (addr.sin_addr.s_addr);
/* DCC SEND file */
if (weechat_strcasecmp (argv[1], "send") == 0)
{
@@ -872,8 +888,28 @@ irc_command_dcc (void *data, struct t_gui_buffer *buffer, int argc,
{
IRC_COMMAND_TOO_FEW_ARGUMENTS(ptr_server->buffer, "dcc send");
}
//irc_dcc_send_request (ptr_server, IRC_DCC_FILE_SEND,
// argv[2], argv_eol[3]);
infolist = weechat_infolist_new ();
if (infolist)
{
item = weechat_infolist_new_item (infolist);
if (item)
{
snprintf (plugin_id, sizeof (plugin_id),
"irc_%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, "filename", argv_eol[3]);
snprintf (str_address, sizeof (str_address),
"%lu", address);
weechat_infolist_new_var_string (item, "address", str_address);
weechat_hook_signal_send ("xfer_add",
WEECHAT_HOOK_SIGNAL_POINTER,
infolist);
}
weechat_infolist_free (infolist);
}
}
/* DCC CHAT */
else if (weechat_strcasecmp (argv[1], "chat") == 0)
@@ -882,8 +918,26 @@ irc_command_dcc (void *data, struct t_gui_buffer *buffer, int argc,
{
IRC_COMMAND_TOO_FEW_ARGUMENTS(ptr_server->buffer, "dcc chat");
}
//irc_dcc_send_request (ptr_server, IRC_DCC_CHAT_SEND,
// argv[2], NULL);
infolist = weechat_infolist_new ();
if (infolist)
{
item = weechat_infolist_new_item (infolist);
if (item)
{
snprintf (plugin_id, sizeof (plugin_id),
"irc_%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]);
snprintf (str_address, sizeof (str_address),
"%lu", address);
weechat_infolist_new_var_string (item, "address", str_address);
weechat_hook_signal_send ("xfer_add",
WEECHAT_HOOK_SIGNAL_POINTER,
infolist);
}
weechat_infolist_free (infolist);
}
}
/* close DCC CHAT */
else if (weechat_strcasecmp (argv[1], "close") == 0)
+11 -107
View File
@@ -33,7 +33,7 @@
#include "irc-server.h"
char *irc_config_server_option_str[IRC_CONFIG_NUM_SERVER_OPTIONS] =
char *irc_config_server_option_string[IRC_CONFIG_NUM_SERVER_OPTIONS] =
{ "autoconnect", "autoreconnect", "autoreconnect_delay", "addresses", "ipv6",
"ssl", "password", "nicks", "username", "realname", "hostname", "command",
"command_delay", "autojoin", "autorejoin", "notify_levels"
@@ -47,7 +47,7 @@ struct t_config_file *irc_config_file = NULL;
struct t_config_section *irc_config_section_server_default = NULL;
struct t_config_section *irc_config_section_server = NULL;
/* config, look section */
/* IRC config, look section */
struct t_config_option *irc_config_look_one_server_buffer;
struct t_config_option *irc_config_look_open_near_server;
@@ -59,7 +59,7 @@ struct t_config_option *irc_config_look_show_away_once;
struct t_config_option *irc_config_look_notice_as_pv;
struct t_config_option *irc_config_look_highlight;
/* config, network section */
/* IRC config, network section */
struct t_config_option *irc_config_network_default_msg_part;
struct t_config_option *irc_config_network_default_msg_quit;
@@ -73,29 +73,14 @@ struct t_config_option *irc_config_network_colors_receive;
struct t_config_option *irc_config_network_colors_send;
struct t_config_option *irc_config_network_send_unknown_commands;
/* config, dcc section */
struct t_config_option *irc_config_dcc_auto_accept_files;
struct t_config_option *irc_config_dcc_auto_accept_chats;
struct t_config_option *irc_config_dcc_timeout;
struct t_config_option *irc_config_dcc_blocksize;
struct t_config_option *irc_config_dcc_fast_send;
struct t_config_option *irc_config_dcc_port_range;
struct t_config_option *irc_config_dcc_own_ip;
struct t_config_option *irc_config_dcc_download_path;
struct t_config_option *irc_config_dcc_upload_path;
struct t_config_option *irc_config_dcc_convert_spaces;
struct t_config_option *irc_config_dcc_auto_rename;
struct t_config_option *irc_config_dcc_auto_resume;
/* config, log section */
/* IRC config, log section */
struct t_config_option *irc_config_log_auto_log_server;
struct t_config_option *irc_config_log_auto_log_channel;
struct t_config_option *irc_config_log_auto_log_private;
struct t_config_option *irc_config_log_hide_nickserv_pwd;
/* config, server section */
/* IRC config, server section */
struct t_config_option *irc_config_server_default[IRC_CONFIG_NUM_SERVER_OPTIONS];
@@ -117,7 +102,7 @@ irc_config_search_server_option (char *option_name)
for (i = 0; i < IRC_CONFIG_NUM_SERVER_OPTIONS; i++)
{
if (weechat_strcasecmp (irc_config_server_option_str[i],
if (weechat_strcasecmp (irc_config_server_option_string[i],
option_name) == 0)
return i;
}
@@ -757,9 +742,9 @@ irc_config_server_create_option (void *data, struct t_config_file *config_file,
option_name,
value,
&irc_config_server_change_cb,
irc_config_server_option_str[index_option],
irc_config_server_option_string[index_option],
&irc_config_server_delete_cb,
irc_config_server_option_str[index_option]);
irc_config_server_option_string[index_option]);
if (ptr_option)
{
@@ -857,10 +842,10 @@ irc_config_server_create_default_options (struct t_config_section *section)
irc_config_file,
section,
i,
irc_config_server_option_str[i],
irc_config_server_option_string[i],
default_value,
&irc_config_server_default_change_cb,
irc_config_server_option_str[i],
irc_config_server_option_string[i],
NULL,
NULL);
}
@@ -1013,83 +998,6 @@ irc_config_init ()
N_("send unknown commands to IRC server"),
NULL, 0, 0, "off", NULL, NULL, NULL, NULL, NULL, NULL);
ptr_section = weechat_config_new_section (irc_config_file, "dcc",
0, 0,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL);
if (!ptr_section)
{
weechat_config_free (irc_config_file);
return 0;
}
irc_config_dcc_auto_accept_files = weechat_config_new_option (
irc_config_file, ptr_section,
"auto_accept_files", "boolean",
N_("automatically accept incoming dcc files (use carefully!)"),
NULL, 0, 0, "off", NULL, NULL, NULL, NULL, NULL, NULL);
irc_config_dcc_auto_accept_chats = weechat_config_new_option (
irc_config_file, ptr_section,
"auto_accept_chats", "boolean",
N_("automatically accept dcc chats (use carefully!)"),
NULL, 0, 0, "off", NULL, NULL, NULL, NULL, NULL, NULL);
irc_config_dcc_timeout = weechat_config_new_option (
irc_config_file, ptr_section,
"timeout", "integer",
N_("timeout for dcc request (in seconds)"),
NULL, 5, INT_MAX, "300", NULL, NULL, NULL, NULL, NULL, NULL);
irc_config_dcc_blocksize = weechat_config_new_option (
irc_config_file, ptr_section,
"blocksize", "integer",
N_("block size for dcc packets in bytes"),
NULL, IRC_DCC_MIN_BLOCKSIZE, IRC_DCC_MAX_BLOCKSIZE, "65536",
NULL, NULL, NULL, NULL, NULL, NULL);
irc_config_dcc_fast_send = weechat_config_new_option (
irc_config_file, ptr_section,
"fast_send", "boolean",
N_("does not wait for ACK when sending file"),
NULL, 0, 0, "on", NULL, NULL, NULL, NULL, NULL, NULL);
irc_config_dcc_port_range = weechat_config_new_option (
irc_config_file, ptr_section,
"port_range", "string",
N_("restricts outgoing dcc to use only ports in the given range "
"(useful for NAT) (syntax: a single port, ie. 5000 or a port "
"range, ie. 5000-5015, empty value means any port)"),
NULL, 0, 0, "", NULL, NULL, NULL, NULL, NULL, NULL);
irc_config_dcc_own_ip = weechat_config_new_option (
irc_config_file, ptr_section,
"own_ip", "string",
N_("IP or DNS address used for outgoing dcc "
"(if empty, local interface IP is used)"),
NULL, 0, 0, "", NULL, NULL, NULL, NULL, NULL, NULL);
irc_config_dcc_download_path = weechat_config_new_option (
irc_config_file, ptr_section,
"download_path", "string",
N_("path for writing incoming files with dcc"),
NULL, 0, 0, "%h/dcc", NULL, NULL, NULL, NULL, NULL, NULL);
irc_config_dcc_upload_path = weechat_config_new_option (
irc_config_file, ptr_section,
"upload_path", "string",
N_("path for reading files when sending thru dcc (when no path is "
"specified)"),
NULL, 0, 0, "~", NULL, NULL, NULL, NULL, NULL, NULL);
irc_config_dcc_convert_spaces = weechat_config_new_option (
irc_config_file, ptr_section,
"convert_spaces", "boolean",
N_("convert spaces to underscores when sending files"),
NULL, 0, 0, "on", NULL, NULL, NULL, NULL, NULL, NULL);
irc_config_dcc_auto_rename = weechat_config_new_option (
irc_config_file, ptr_section,
"auto_rename", "boolean",
N_("rename incoming files if already exists (add '.1', '.2', ...)"),
NULL, 0, 0, "on", NULL, NULL, NULL, NULL, NULL, NULL);
irc_config_dcc_auto_resume = weechat_config_new_option (
irc_config_file, ptr_section,
"auto_resume", "boolean",
N_("automatically resume dcc transfer if connection with remote host "
"is loosed"),
NULL, 0, 0, "on", NULL, NULL, NULL, NULL, NULL, NULL);
ptr_section = weechat_config_new_section (irc_config_file, "log",
0, 0,
NULL, NULL, NULL, NULL,
@@ -1162,11 +1070,7 @@ irc_config_init ()
int
irc_config_read ()
{
int rc;
rc = weechat_config_read (irc_config_file);
return rc;
return weechat_config_read (irc_config_file);
}
/*
+1 -14
View File
@@ -57,7 +57,7 @@ enum t_irc_config_server_option
#define IRC_CONFIG_SERVER_DEFAULT_AUTOREJOIN 0
extern char *irc_config_server_option_str[];
extern char *irc_config_server_option_string[];
extern struct t_config_file *irc_config;
extern struct t_config_option *irc_config_look_one_server_buffer;
@@ -82,19 +82,6 @@ extern struct t_config_option *irc_config_network_colors_receive;
extern struct t_config_option *irc_config_network_colors_send;
extern struct t_config_option *irc_config_network_send_unknown_commands;
extern struct t_config_option *irc_config_dcc_auto_accept_files;
extern struct t_config_option *irc_config_dcc_auto_accept_chats;
extern struct t_config_option *irc_config_dcc_timeout;
extern struct t_config_option *irc_config_dcc_blocksize;
extern struct t_config_option *irc_config_dcc_fast_send;
extern struct t_config_option *irc_config_dcc_port_range;
extern struct t_config_option *irc_config_dcc_own_ip;
extern struct t_config_option *irc_config_dcc_download_path;
extern struct t_config_option *irc_config_dcc_upload_path;
extern struct t_config_option *irc_config_dcc_convert_spaces;
extern struct t_config_option *irc_config_dcc_auto_rename;
extern struct t_config_option *irc_config_dcc_auto_resume;
extern struct t_config_option *irc_config_log_auto_log_server;
extern struct t_config_option *irc_config_log_auto_log_channel;
extern struct t_config_option *irc_config_log_auto_log_private;
+13 -1630
View File
File diff suppressed because it is too large Load Diff
+9 -15
View File
@@ -63,20 +63,16 @@ irc_debug_printf (struct t_irc_server *server, int send, int modified,
if (!irc_debug_buffer)
{
/* search for irc debug buffer */
irc_debug_buffer = weechat_buffer_search ("irc", "debug");
irc_debug_buffer = weechat_buffer_new ("irc", "debug",
NULL, NULL,
&irc_debug_buffer_close_cb, NULL);
/* failed to create buffer ? then exit */
if (!irc_debug_buffer)
{
irc_debug_buffer = weechat_buffer_new ("irc", "debug",
NULL, NULL,
&irc_debug_buffer_close_cb, NULL);
/* failed to create buffer ? then exit */
if (!irc_debug_buffer)
return;
weechat_buffer_set (irc_debug_buffer,
"title", _("IRC debug messages"));
}
return;
weechat_buffer_set (irc_debug_buffer,
"title", _("IRC debug messages"));
}
buf = weechat_iconv_to_internal (NULL, message);
@@ -144,8 +140,6 @@ irc_debug_signal_debug_dump_cb (void *data, char *signal, char *type_data,
irc_server_print_log ();
//irc_dcc_print_log ();
weechat_log_printf ("");
weechat_log_printf ("***** End of \"%s\" plugin dump *****",
weechat_plugin->name);
+73 -388
View File
@@ -36,10 +36,6 @@
#include <arpa/inet.h>
#include <netdb.h>
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#endif
#include "../weechat-plugin.h"
#include "irc.h"
#include "irc-server.h"
@@ -2056,386 +2052,6 @@ irc_server_child_read_cb (void *arg_server)
return WEECHAT_RC_OK;
}
/*
* irc_server_convbase64_8x3_to_6x4 : convert 3 bytes of 8 bits in 4 bytes of 6 bits
*/
void
irc_server_convbase64_8x3_to_6x4 (char *from, char *to)
{
unsigned char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
to[0] = base64_table [ (from[0] & 0xfc) >> 2 ];
to[1] = base64_table [ ((from[0] & 0x03) << 4) + ((from[1] & 0xf0) >> 4) ];
to[2] = base64_table [ ((from[1] & 0x0f) << 2) + ((from[2] & 0xc0) >> 6) ];
to[3] = base64_table [ from[2] & 0x3f ];
}
/*
* irc_server_base64encode: encode a string in base64
*/
void
irc_server_base64encode (char *from, char *to)
{
char *f, *t;
int from_len;
from_len = strlen(from);
f = from;
t = to;
while (from_len >= 3)
{
irc_server_convbase64_8x3_to_6x4 (f, t);
f += 3 * sizeof (*f);
t += 4 * sizeof (*t);
from_len -= 3;
}
if (from_len > 0)
{
char rest[3] = { 0, 0, 0 };
switch (from_len)
{
case 1 :
rest[0] = f[0];
irc_server_convbase64_8x3_to_6x4 (rest, t);
t[2] = t[3] = '=';
break;
case 2 :
rest[0] = f[0];
rest[1] = f[1];
irc_server_convbase64_8x3_to_6x4 (rest, t);
t[3] = '=';
break;
}
t[4] = 0;
}
}
/*
* irc_server_pass_httpproxy: establish connection/authentification to an
* http proxy
* return :
* - 0 if connexion throw proxy was successful
* - 1 if connexion fails
*/
int
irc_server_pass_httpproxy (int sock, char *address, int port)
{
char buffer[256], authbuf[128], authbuf_base64[196];
char *config_proxy_username, *config_proxy_password;
int n, m;
config_proxy_username = weechat_config_string (
weechat_config_get ("weechat.proxy.username"));
config_proxy_username = weechat_config_string (
weechat_config_get ("weechat.proxy.password"));
if (config_proxy_username && config_proxy_username[0])
{
/* authentification */
snprintf (authbuf, sizeof (authbuf), "%s:%s",
config_proxy_username,
(config_proxy_password) ? config_proxy_password : "");
irc_server_base64encode (authbuf, authbuf_base64);
n = snprintf (buffer, sizeof (buffer),
"CONNECT %s:%d HTTP/1.0\r\nProxy-Authorization: Basic %s\r\n\r\n",
address, port, authbuf_base64);
}
else
{
/* no authentification */
n = snprintf (buffer, sizeof (buffer),
"CONNECT %s:%d HTTP/1.0\r\n\r\n", address, port);
}
m = send (sock, buffer, n, 0);
if (n != m)
return 1;
n = recv (sock, buffer, sizeof (buffer), 0);
/* success result must be like: "HTTP/1.0 200 OK" */
if (n < 12)
return 1;
if (memcmp (buffer, "HTTP/", 5) || memcmp (buffer + 9, "200", 3))
return 1;
return 0;
}
/*
* irc_server_resolve: resolve hostname on its IP address
* (works with ipv4 and ipv6)
* return :
* - 0 if resolution was successful
* - 1 if resolution fails
*/
int
irc_server_resolve (char *hostname, char *ip, int *version)
{
char ipbuffer[NI_MAXHOST];
struct addrinfo *res;
if (version != NULL)
*version = 0;
res = NULL;
if (getaddrinfo (hostname, NULL, NULL, &res) != 0)
return 1;
if (!res)
return 1;
if (getnameinfo (res->ai_addr, res->ai_addrlen, ipbuffer, sizeof(ipbuffer), NULL, 0, NI_NUMERICHOST) != 0)
{
freeaddrinfo (res);
return 1;
}
if ((res->ai_family == AF_INET) && (version != NULL))
*version = 4;
if ((res->ai_family == AF_INET6) && (version != NULL))
*version = 6;
strcpy (ip, ipbuffer);
freeaddrinfo (res);
return 0;
}
/*
* irc_server_pass_socks4proxy: establish connection/authentification thru a
* socks4 proxy
* return :
* - 0 if connexion thru proxy was successful
* - 1 if connexion fails
*/
int
irc_server_pass_socks4proxy (int sock, char *address, int port, char *username)
{
/*
* socks4 protocol is explained here:
* http://archive.socks.permeo.com/protocol/socks4.protocol
*
*/
struct s_socks4
{
char version; /* 1 byte */ /* socks version : 4 or 5 */
char method; /* 1 byte */ /* socks method : connect (1) or bind (2) */
unsigned short port; /* 2 bytes */ /* destination port */
unsigned long address; /* 4 bytes */ /* destination address */
char user[64]; /* username (64 characters seems to be enought) */
} socks4;
unsigned char buffer[24];
char ip_addr[NI_MAXHOST];
socks4.version = 4;
socks4.method = 1;
socks4.port = htons (port);
irc_server_resolve (address, ip_addr, NULL);
socks4.address = inet_addr (ip_addr);
strncpy (socks4.user, username, sizeof (socks4.user) - 1);
send (sock, (char *) &socks4, 8 + strlen (socks4.user) + 1, 0);
recv (sock, buffer, sizeof (buffer), 0);
if (buffer[0] == 0 && buffer[1] == 90)
return 0;
return 1;
}
/*
* irc_server_pass_socks5proxy: establish connection/authentification thru a
* socks5 proxy
* return :
* - 0 if connexion thru proxy was successful
* - 1 if connexion fails
*/
int
irc_server_pass_socks5proxy (int sock, char *address, int port)
{
/*
* socks5 protocol is explained in RFC 1928
* socks5 authentication with username/pass is explained in RFC 1929
*/
struct s_sock5
{
char version; /* 1 byte */ /* socks version : 4 or 5 */
char nmethods; /* 1 byte */ /* size in byte(s) of field 'method', here 1 byte */
char method; /* 1-255 bytes */ /* socks method : noauth (0), auth(user/pass) (2), ... */
} socks5;
unsigned char buffer[288];
int username_len, password_len, addr_len, addr_buffer_len;
unsigned char *addr_buffer;
char *config_proxy_username, *config_proxy_password;
socks5.version = 5;
socks5.nmethods = 1;
config_proxy_username = weechat_config_string (
weechat_config_get ("weechat.proxy.username"));
config_proxy_username = weechat_config_string (
weechat_config_get ("weechat.proxy.password"));
if (config_proxy_username && config_proxy_username[0])
socks5.method = 2; /* with authentication */
else
socks5.method = 0; /* without authentication */
send (sock, (char *) &socks5, sizeof(socks5), 0);
/* server socks5 must respond with 2 bytes */
if (recv (sock, buffer, 2, 0) != 2)
return 1;
if (config_proxy_username && config_proxy_username[0])
{
/* with authentication */
/* -> socks server must respond with :
* - socks version (buffer[0]) = 5 => socks5
* - socks method (buffer[1]) = 2 => authentication
*/
if (buffer[0] != 5 || buffer[1] != 2)
return 1;
/* authentication as in RFC 1929 */
username_len = strlen (config_proxy_username);
password_len = strlen (config_proxy_password);
/* make username/password buffer */
buffer[0] = 1;
buffer[1] = (unsigned char) username_len;
memcpy(buffer + 2, config_proxy_username, username_len);
buffer[2 + username_len] = (unsigned char) password_len;
memcpy (buffer + 3 + username_len, config_proxy_password, password_len);
send (sock, buffer, 3 + username_len + password_len, 0);
/* server socks5 must respond with 2 bytes */
if (recv (sock, buffer, 2, 0) != 2)
return 1;
/* buffer[1] = auth state, must be 0 for success */
if (buffer[1] != 0)
return 1;
}
else
{
/* without authentication */
/* -> socks server must respond with :
* - socks version (buffer[0]) = 5 => socks5
* - socks method (buffer[1]) = 0 => no authentication
*/
if (!(buffer[0] == 5 && buffer[1] == 0))
return 1;
}
/* authentication successful then giving address/port to connect */
addr_len = strlen(address);
addr_buffer_len = 4 + 1 + addr_len + 2;
addr_buffer = malloc (addr_buffer_len * sizeof(*addr_buffer));
if (!addr_buffer)
return 1;
addr_buffer[0] = 5; /* version 5 */
addr_buffer[1] = 1; /* command: 1 for connect */
addr_buffer[2] = 0; /* reserved */
addr_buffer[3] = 3; /* address type : ipv4 (1), domainname (3), ipv6 (4) */
addr_buffer[4] = (unsigned char) addr_len;
memcpy (addr_buffer + 5, address, addr_len); /* server address */
*((unsigned short *) (addr_buffer + 5 + addr_len)) = htons (port); /* server port */
send (sock, addr_buffer, addr_buffer_len, 0);
free (addr_buffer);
/* dialog with proxy server */
if (recv (sock, buffer, 4, 0) != 4)
return 1;
if (!(buffer[0] == 5 && buffer[1] == 0))
return 1;
/* buffer[3] = address type */
switch (buffer[3])
{
case 1:
/* ipv4
* server socks return server bound address and port
* address of 4 bytes and port of 2 bytes (= 6 bytes)
*/
if (recv (sock, buffer, 6, 0) != 6)
return 1;
break;
case 3:
/* domainname
* server socks return server bound address and port
*/
/* reading address length */
if (recv (sock, buffer, 1, 0) != 1)
return 1;
addr_len = buffer[0];
/* reading address + port = addr_len + 2 */
if (recv (sock, buffer, addr_len + 2, 0) != (addr_len + 2))
return 1;
break;
case 4:
/* ipv6
* server socks return server bound address and port
* address of 16 bytes and port of 2 bytes (= 18 bytes)
*/
if (recv (sock, buffer, 18, 0) != 18)
return 1;
break;
default:
return 1;
}
return 0;
}
/*
* irc_server_pass_proxy: establish connection/authentification to a proxy
* return :
* - 0 if connexion throw proxy was successful
* - 1 if connexion fails
*/
int
irc_server_pass_proxy (int sock, char *address, int port, char *username)
{
int rc;
char *config_proxy_type;
config_proxy_type = weechat_config_string (
weechat_config_get ("weechat.proxy.type"));
rc = 1;
if (config_proxy_type)
{
if (weechat_strcasecmp (config_proxy_type, "http") == 0)
rc = irc_server_pass_httpproxy (sock, address, port);
if (weechat_strcasecmp (config_proxy_type, "socks4") == 0)
rc = irc_server_pass_socks4proxy (sock, address, port, username);
if (weechat_strcasecmp (config_proxy_type, "socks5") == 0)
rc = irc_server_pass_socks5proxy (sock, address, port);
}
return rc;
}
/*
* irc_server_child: child process trying to connect to server
*/
@@ -2497,10 +2113,9 @@ irc_server_child (struct t_irc_server *server)
return 0;
}
if (irc_server_pass_proxy (server->sock,
server->addresses_array[server->current_address],
server->ports_array[server->current_address],
server->username))
if (weechat_network_pass_proxy (server->sock,
server->addresses_array[server->current_address],
server->ports_array[server->current_address]))
{
write (server->child_write, "4", 1);
freeaddrinfo (res);
@@ -3174,6 +2789,76 @@ irc_server_set_default_notify_level (struct t_irc_server *server, int notify)
*/
}
/*
* irc_server_xfer_send_ready_cb: callback called when user send (file or chat)
* to someone and that xfer plugin successfully
* initialized xfer and is ready for sending
* in that case, irc plugin send message to
* remote nick and wait for "accept" reply
*/
int
irc_server_xfer_send_ready_cb (void *data, char *signal, char *type_data,
void *signal_data)
{
struct t_plugin_infolist *infolist;
struct t_irc_server *server, *ptr_server;
char *plugin_id, *type;
/* make C compiler happy */
(void) data;
(void) signal;
(void) type_data;
infolist = (struct t_plugin_infolist *)signal_data;
if (weechat_infolist_next (infolist))
{
plugin_id = weechat_infolist_string (infolist, "plugin_id");
if (plugin_id)
{
if (strncmp (plugin_id, "irc_", 4) == 0)
{
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)
{
type = weechat_infolist_string (infolist, "type");
if (type)
{
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"));
}
}
}
}
}
}
return WEECHAT_RC_OK;
}
/*
* irc_server_print_log: print server infos in log (usually for crash dump)
*/
+2
View File
@@ -186,6 +186,8 @@ extern void irc_server_disconnect (struct t_irc_server *server, int reconnect);
extern void irc_server_disconnect_all ();
extern void irc_server_free (struct t_irc_server *server);
extern void irc_server_free_data (struct t_irc_server *server);
extern int irc_server_xfer_send_ready_cb (void *data, char *signal,
char *type_data, void *signal_data);
extern void irc_server_print_log ();
#endif /* irc-server.h */
+3 -33
View File
@@ -22,10 +22,6 @@
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#endif
#include "../weechat-plugin.h"
#include "irc.h"
#include "irc-command.h"
@@ -55,31 +51,6 @@ gnutls_certificate_credentials gnutls_xcred; /* gnutls client credentials */
#endif
/*
* irc_create_directories: create directories for IRC plugin
*/
void
irc_create_directories ()
{
char *weechat_dir, *dir1, *dir2;
/* create DCC download directory */
weechat_dir = weechat_info_get ("weechat_dir");
if (weechat_dir)
{
dir1 = weechat_string_replace (weechat_config_string (irc_config_dcc_download_path),
"~", getenv ("HOME"));
dir2 = weechat_string_replace (dir1, "%h", weechat_dir);
if (dir2)
(void) weechat_mkdir (dir2, 0700);
if (dir1)
free (dir1);
if (dir2)
free (dir2);
}
}
/*
* irc_signal_quit_cb: callback for "quit" signal
*/
@@ -128,14 +99,13 @@ weechat_plugin_init (struct t_weechat_plugin *plugin)
if (irc_config_read () < 0)
return WEECHAT_RC_ERROR;
irc_create_directories ();
irc_command_init ();
/* hook some signals */
irc_debug_init ();
weechat_hook_signal ("quit", &irc_signal_quit_cb, NULL);
weechat_hook_signal ("xfer_send_ready", &irc_server_xfer_send_ready_cb, NULL);
/* hook completions */
irc_completion_init ();
+11 -1
View File
@@ -38,6 +38,7 @@
#include "../core/wee-hook.h"
#include "../core/wee-list.h"
#include "../core/wee-log.h"
#include "../core/wee-network.h"
#include "../core/wee-string.h"
#include "../core/wee-utf8.h"
#include "../core/wee-util.h"
@@ -396,8 +397,17 @@ plugin_load (char *filename)
new_plugin->command = &plugin_api_command;
new_plugin->info_get = &plugin_api_info_get;
new_plugin->network_pass_proxy = &network_pass_proxy;
new_plugin->network_connect_to = &network_connect_to;
new_plugin->info_get = &plugin_api_info_get;
new_plugin->infolist_new = &plugin_infolist_new;
new_plugin->infolist_new_item = &plugin_infolist_new_item;
new_plugin->infolist_new_var_integer = &plugin_infolist_new_var_integer;
new_plugin->infolist_new_var_string = &plugin_infolist_new_var_string;
new_plugin->infolist_new_var_pointer = &plugin_infolist_new_var_pointer;
new_plugin->infolist_new_var_time = &plugin_infolist_new_var_time;
new_plugin->infolist_get = &plugin_api_infolist_get;
new_plugin->infolist_next = &plugin_api_infolist_next;
new_plugin->infolist_prev = &plugin_api_infolist_prev;
+36
View File
@@ -388,11 +388,29 @@ struct t_weechat_plugin
/* command */
void (*command) (struct t_weechat_plugin *plugin,
struct t_gui_buffer *buffer, char *command);
/* network */
int (*network_pass_proxy) (int sock, char *address, int port);
int (*network_connect_to) (int sock, unsigned long address, int port);
/* infos */
char *(*info_get) (struct t_weechat_plugin *plugin, char *info);
/* infolists */
struct t_plugin_infolist *(*infolist_new) ();
struct t_plugin_infolist_item *(*infolist_new_item) (struct t_plugin_infolist *list);
struct t_plugin_infolist_var *(*infolist_new_var_integer) (struct t_plugin_infolist_item *item,
char *name,
int value);
struct t_plugin_infolist_var *(*infolist_new_var_string) (struct t_plugin_infolist_item *item,
char *name,
char *value);
struct t_plugin_infolist_var *(*infolist_new_var_pointer) (struct t_plugin_infolist_item *item,
char *name,
void *pointer);
struct t_plugin_infolist_var *(*infolist_new_var_time) (struct t_plugin_infolist_item *item,
char *name,
time_t time);
struct t_plugin_infolist *(*infolist_get) (char *name, void *pointer,
char *arguments);
int (*infolist_next) (struct t_plugin_infolist *infolist);
@@ -792,11 +810,29 @@ extern int weechat_plugin_end (struct t_weechat_plugin *plugin);
#define weechat_command(__buffer, __command) \
weechat_plugin->command(weechat_plugin, __buffer, __command)
/* network */
#define weechat_network_pass_proxy(__sock, __address, __port) \
weechat_plugin->network_pass_proxy(__sock, __address, __port)
#define weechat_network_connect_to(__sock, __address, __port) \
weechat_plugin->network_connect_to(__sock, __address, __port)
/* infos */
#define weechat_info_get(__name) \
weechat_plugin->info_get(weechat_plugin, __name)
/* infolists */
#define weechat_infolist_new() \
weechat_plugin->infolist_new()
#define weechat_infolist_new_item(__list) \
weechat_plugin->infolist_new_item(__list)
#define weechat_infolist_new_var_integer(__item, __name, __value) \
weechat_plugin->infolist_new_var_integer(__item, __name, __value)
#define weechat_infolist_new_var_string(__item, __name, __value) \
weechat_plugin->infolist_new_var_string(__item, __name, __value)
#define weechat_infolist_new_var_pointer(__item, __name, __pointer) \
weechat_plugin->infolist_new_var_pointer(__item, __name, __pointer)
#define weechat_infolist_new_var_time(__item, __name, __time) \
weechat_plugin->infolist_new_var_time(__item, __name, __time)
#define weechat_infolist_get(__name, __pointer, __arguments) \
weechat_plugin->infolist_get(__name, __pointer, __arguments)
#define weechat_infolist_next(__list) \
+29
View File
@@ -0,0 +1,29 @@
# Copyright (c) 2003-2008 FlashCode <flashcode@flashtux.org>
#
# 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/>.
#
ADD_LIBRARY(xfer MODULE
xfer.c xfer.h
xfer-buffer.c xfer-buffer.h
xfer-chat.c xfer-chat.h
xfer-config.c xfer-config.h
xfer-dcc.c xfer-dcc.h
xfer-file.c xfer-file.h
xfer-network.c xfer-network.h)
SET_TARGET_PROPERTIES(xfer PROPERTIES PREFIX "")
TARGET_LINK_LIBRARIES(xfer)
INSTALL(TARGETS xfer LIBRARY DESTINATION lib/${PROJECT_NAME}/plugins)
+39
View File
@@ -0,0 +1,39 @@
# Copyright (c) 2003-2008 FlashCode <flashcode@flashtux.org>
#
# 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/>.
#
INCLUDES = -DLOCALEDIR=\"$(datadir)/locale\"
libdir = ${weechat_libdir}/plugins
lib_LTLIBRARIES = xfer.la
xfer_la_SOURCES = xfer.c \
xfer.h \
xfer-buffer.c \
xfer-buffer.h \
xfer-chat.c \
xfer-chat.h \
xfer-config.c \
xfer-config.h \
xfer-dcc.c \
xfer-dcc.h \
xfer-file.c \
xfer-file.h \
xfer-network.c \
xfer-network.h
xfer_la_LDFLAGS = -module
xfer_la_LIBADD = $(XFER_LFLAGS)
+117
View File
@@ -0,0 +1,117 @@
/*
* 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-buffer.c: display xfer list on xfer buffer */
#include <stdlib.h>
#include <stdio.h>
#include "../weechat-plugin.h"
#include "xfer.h"
#include "xfer-buffer.h"
#include "xfer-config.h"
struct t_gui_buffer *xfer_buffer = NULL;
int xfer_buffer_selected_line = 0;
/*
* xfer_buffer_close_cb: callback called when xfer buffer is closed
*/
int
xfer_buffer_close_cb (void *data, struct t_gui_buffer *buffer)
{
/* make C compiler happy */
(void) data;
(void) buffer;
xfer_buffer = NULL;
return WEECHAT_RC_OK;
}
/*
* xfer_buffer_open: open xfer buffer (to display list of xfer)
*/
void
xfer_buffer_open ()
{
if (!xfer_buffer)
{
xfer_buffer = weechat_buffer_new ("xfer", "xfer",
NULL, 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);
}
}
+28
View File
@@ -0,0 +1,28 @@
/*
* 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_DISPLAY_H
#define __WEECHAT_XFER_DISPLAY_H 1
extern struct t_gui_buffer *xfer_buffer;
extern void xfer_buffer_open ();
extern void xfer_buffer_refresh (char *hotlist);
#endif /* xfer.h */
+161
View File
@@ -0,0 +1,161 @@
/*
* 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-chat.c: chat with direct connection to remote host */
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "../weechat-plugin.h"
#include "xfer.h"
#include "xfer-chat.h"
#include "xfer-buffer.h"
/*
* xfer_chat_send: send data to remote host via xfer chat
*/
int
xfer_chat_send (struct t_xfer *xfer, char *buffer, int size_buf)
{
if (!xfer)
return -1;
return send (xfer->sock, buffer, size_buf, 0);
}
/*
* xfer_chat_sendf: send formatted data to remote host via DCC CHAT
*/
void
xfer_chat_sendf (struct t_xfer *xfer, char *format, ...)
{
va_list args;
static char buffer[4096];
int size_buf;
if (!xfer || (xfer->sock < 0))
return;
va_start (args, format);
size_buf = vsnprintf (buffer, sizeof (buffer) - 1, format, args);
va_end (args);
if (size_buf == 0)
return;
buffer[sizeof (buffer) - 1] = '\0';
if ((size_buf < 0) || (size_buf > (int) (sizeof (buffer) - 1)))
size_buf = strlen (buffer);
if (xfer_chat_send (xfer, buffer, strlen (buffer)) <= 0)
{
weechat_printf (NULL,
_("%s%s: error sending data to \"%s\" via xfer chat"),
weechat_prefix ("error"), "xfer", xfer->nick);
xfer_close (xfer, XFER_STATUS_FAILED);
}
}
/*
* xfer_chat_recv: receive data from xfer chat remote host
*/
void
xfer_chat_recv (struct t_xfer *xfer)
{
fd_set read_fd;
static struct timeval timeout;
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;
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)
{
buffer[num_read] = '\0';
buf2 = NULL;
ptr_buf = buffer;
if (xfer->unterminated_message)
{
buf2 = malloc (strlen (xfer->unterminated_message) +
strlen (buffer) + 1);
if (buf2)
{
strcpy (buf2, xfer->unterminated_message);
strcat (buf2, buffer);
}
ptr_buf = buf2;
free (xfer->unterminated_message);
xfer->unterminated_message = NULL;
}
while (ptr_buf && ptr_buf[0])
{
next_ptr_buf = NULL;
pos = strstr (ptr_buf, "\n");
if (pos)
{
pos[0] = '\0';
next_ptr_buf = pos + 1;
}
else
{
xfer->unterminated_message = strdup (ptr_buf);
ptr_buf = NULL;
next_ptr_buf = NULL;
}
if (ptr_buf)
{
weechat_printf (xfer->buffer, "%s\t%s", xfer->nick, ptr_buf);
}
ptr_buf = next_ptr_buf;
}
if (buf2)
free (buf2);
}
else
{
xfer_close (xfer, XFER_STATUS_ABORTED);
xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE);
}
}
+24
View File
@@ -0,0 +1,24 @@
/*
* 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_CHAT_H
#define __WEECHAT_XFER_CHAT_H 1
#endif /* xfer-chat.h */
+287
View File
@@ -0,0 +1,287 @@
/*
* 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-config.c: xfer configuration options */
#include <stdlib.h>
#include <limits.h>
#include "../weechat-plugin.h"
#include "xfer.h"
#include "xfer-config.h"
struct t_config_file *xfer_config_file = NULL;
/* xfer config, look section */
struct t_config_option *xfer_config_look_auto_open_buffer;
/* xfer config, color section */
struct t_config_option *xfer_config_color_text;
struct t_config_option *xfer_config_color_text_bg;
struct t_config_option *xfer_config_color_selected_bg;
struct t_config_option *xfer_config_color_status[XFER_NUM_STATUS];
/* xfer config, network section */
struct t_config_option *xfer_config_network_timeout;
struct t_config_option *xfer_config_network_blocksize;
struct t_config_option *xfer_config_network_fast_send;
struct t_config_option *xfer_config_network_port_range;
struct t_config_option *xfer_config_network_own_ip;
/* xfer config, file section */
struct t_config_option *xfer_config_file_download_path;
struct t_config_option *xfer_config_file_upload_path;
struct t_config_option *xfer_config_file_convert_spaces;
struct t_config_option *xfer_config_file_auto_rename;
struct t_config_option *xfer_config_file_auto_resume;
struct t_config_option *xfer_config_file_auto_accept_files;
struct t_config_option *xfer_config_file_auto_accept_chats;
/*
* xfer_config_reload: reload xfer configuration file
*/
int
xfer_config_reload (void *data, struct t_config_file *config_file)
{
/* make C compiler happy */
(void) data;
return weechat_config_reload (config_file);
}
/*
* xfer_config_init: init xfer configuration file
* return: 1 if ok, 0 if error
*/
int
xfer_config_init ()
{
struct t_config_section *ptr_section;
xfer_config_file = weechat_config_new (XFER_CONFIG_NAME,
&xfer_config_reload, NULL);
if (!xfer_config_file)
return 0;
ptr_section = weechat_config_new_section (xfer_config_file, "look",
0, 0,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL);
if (!ptr_section)
{
weechat_config_free (xfer_config_file);
return 0;
}
xfer_config_look_auto_open_buffer = weechat_config_new_option (
xfer_config_file, ptr_section,
"auto_open_buffer", "boolean",
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);
ptr_section = weechat_config_new_section (xfer_config_file, "color",
0, 0,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL);
if (!ptr_section)
{
weechat_config_free (xfer_config_file);
return 0;
}
xfer_config_color_text = weechat_config_new_option (
xfer_config_file, ptr_section,
"text", "color",
N_("text color"),
NULL, 0, 0, "default",
NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_color_text_bg = weechat_config_new_option (
xfer_config_file, ptr_section,
"text_bg", "color",
N_("background color"),
NULL, 0, 0, "default",
NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_color_selected_bg = weechat_config_new_option (
xfer_config_file, ptr_section,
"selected_bg", "color",
N_("background color for selected line"),
NULL, 0, 0, "magenta",
NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_color_status[XFER_STATUS_WAITING] = weechat_config_new_option (
xfer_config_file, ptr_section,
"status_waiting", "color",
N_("text color for \"waiting\" status"),
NULL, 0, 0, "lightcyan",
NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_color_status[XFER_STATUS_CONNECTING] = weechat_config_new_option (
xfer_config_file, ptr_section,
"status_connecting", "color",
N_("text color for \"connecting\" status"),
NULL, 0, 0, "yellow",
NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_color_status[XFER_STATUS_ACTIVE] = weechat_config_new_option (
xfer_config_file, ptr_section,
"status_active", "color",
N_("text color for \"active\" status"),
NULL, 0, 0, "lightblue",
NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_color_status[XFER_STATUS_DONE] = weechat_config_new_option (
xfer_config_file, ptr_section,
"status_done", "color",
N_("text color for \"done\" status"),
NULL, 0, 0, "lightgreen",
NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_color_status[XFER_STATUS_FAILED] = weechat_config_new_option (
xfer_config_file, ptr_section,
"status_failed", "color",
N_("text color for \"failed\" status"),
NULL, 0, 0, "lightred",
NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_color_status[XFER_STATUS_ABORTED] = weechat_config_new_option (
xfer_config_file, ptr_section,
"status_aborted", "color",
N_("text color for \"aborted\" status"),
NULL, 0, 0, "lightred",
NULL, NULL, NULL, NULL, NULL, NULL);
ptr_section = weechat_config_new_section (xfer_config_file, "network",
0, 0,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL);
if (!ptr_section)
{
weechat_config_free (xfer_config_file);
return 0;
}
xfer_config_network_timeout = weechat_config_new_option (
xfer_config_file, ptr_section,
"timeout", "integer",
N_("timeout for xfer request (in seconds)"),
NULL, 5, INT_MAX, "300", NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_network_blocksize = weechat_config_new_option (
xfer_config_file, ptr_section,
"blocksize", "integer",
N_("block size for sending packets, in bytes"),
NULL, XFER_BLOCKSIZE_MIN, XFER_BLOCKSIZE_MAX, "65536",
NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_network_fast_send = weechat_config_new_option (
xfer_config_file, ptr_section,
"fast_send", "boolean",
N_("does not wait for ACK when sending file"),
NULL, 0, 0, "on", NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_network_port_range = weechat_config_new_option (
xfer_config_file, ptr_section,
"port_range", "string",
N_("restricts outgoing files/chats to use only ports in the given "
"range (useful for NAT) (syntax: a single port, ie. 5000 or a port "
"range, ie. 5000-5015, empty value means any port)"),
NULL, 0, 0, "", NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_network_own_ip = weechat_config_new_option (
xfer_config_file, ptr_section,
"own_ip", "string",
N_("IP or DNS address used for sending files/chats "
"(if empty, local interface IP is used)"),
NULL, 0, 0, "", NULL, NULL, NULL, NULL, NULL, NULL);
ptr_section = weechat_config_new_section (xfer_config_file, "file",
0, 0,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL);
if (!ptr_section)
{
weechat_config_free (xfer_config_file);
return 0;
}
xfer_config_file_download_path = weechat_config_new_option (
xfer_config_file, ptr_section,
"download_path", "string",
N_("path for writing incoming files"),
NULL, 0, 0, "%h/xfer", NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_file_upload_path = weechat_config_new_option (
xfer_config_file, ptr_section,
"upload_path", "string",
N_("path for reading files when sending (when no path is "
"specified by user)"),
NULL, 0, 0, "~", NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_file_convert_spaces = weechat_config_new_option (
xfer_config_file, ptr_section,
"convert_spaces", "boolean",
N_("convert spaces to underscores when sending files"),
NULL, 0, 0, "on", NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_file_auto_rename = weechat_config_new_option (
xfer_config_file, ptr_section,
"auto_rename", "boolean",
N_("rename incoming files if already exists (add '.1', '.2', ...)"),
NULL, 0, 0, "on", NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_file_auto_resume = weechat_config_new_option (
xfer_config_file, ptr_section,
"auto_resume", "boolean",
N_("automatically resume file transfer if connection with remote host "
"is lost"),
NULL, 0, 0, "on", NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_file_auto_accept_files = weechat_config_new_option (
xfer_config_file, ptr_section,
"auto_accept_files", "boolean",
N_("automatically accept incoming files (use carefully!)"),
NULL, 0, 0, "off", NULL, NULL, NULL, NULL, NULL, NULL);
xfer_config_file_auto_accept_chats = weechat_config_new_option (
xfer_config_file, ptr_section,
"auto_accept_chats", "boolean",
N_("automatically accept chat requests (use carefully!)"),
NULL, 0, 0, "off", NULL, NULL, NULL, NULL, NULL, NULL);
return 1;
}
/*
* xfer_config_read: read xfer configuration file
* return: 0 = successful
* -1 = configuration file file not found
* -2 = error in configuration file
*/
int
xfer_config_read ()
{
return weechat_config_read (xfer_config_file);
}
/*
* xfer_config_write: write xfer configuration file
* return: 0 if ok
* < 0 if error
*/
int
xfer_config_write ()
{
return weechat_config_write (xfer_config_file);
}
+52
View File
@@ -0,0 +1,52 @@
/*
* 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_CONFIG_H
#define __WEECHAT_XFER_CONFIG_H 1
#define XFER_CONFIG_NAME "xfer"
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_color_text;
extern struct t_config_option *xfer_config_color_text_bg;
extern struct t_config_option *xfer_config_color_selected_bg;
extern struct t_config_option *xfer_config_color_status[];
extern struct t_config_option *xfer_config_network_timeout;
extern struct t_config_option *xfer_config_network_blocksize;
extern struct t_config_option *xfer_config_network_fast_send;
extern struct t_config_option *xfer_config_network_port_range;
extern struct t_config_option *xfer_config_network_own_ip;
extern struct t_config_option *xfer_config_file_download_path;
extern struct t_config_option *xfer_config_file_upload_path;
extern struct t_config_option *xfer_config_file_convert_spaces;
extern struct t_config_option *xfer_config_file_auto_rename;
extern struct t_config_option *xfer_config_file_auto_resume;
extern struct t_config_option *xfer_config_file_auto_accept_files;
extern struct t_config_option *xfer_config_file_auto_accept_chats;
extern int xfer_config_init ();
extern int xfer_config_read ();
extern int xfer_config_write ();
#endif /* xfer-config.h */
+208
View File
@@ -0,0 +1,208 @@
/*
* 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-dcc.c: file transfert via DCC protocol */
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <time.h>
#include <netdb.h>
#include <errno.h>
#include "../weechat-plugin.h"
#include "xfer.h"
#include "xfer-dcc.h"
#include "xfer-network.h"
/*
* xfer_dcc_send_file_child: child process for sending file with DCC protocol
*/
void
xfer_dcc_send_file_child (struct t_xfer *xfer)
{
int num_read, num_sent;
static char buffer[XFER_BLOCKSIZE_MAX];
uint32_t ack;
time_t last_sent, new_time;
last_sent = time (NULL);
while (1)
{
/* read DCC ACK (sent by receiver) */
if (xfer->pos > xfer->ack)
{
/* we should receive ACK for packets sent previously */
while (1)
{
num_read = recv (xfer->sock, (char *) &ack, 4, MSG_PEEK);
if ((num_read < 1) &&
((num_read != -1) || (errno != EAGAIN)))
{
xfer_network_write_pipe (xfer, XFER_STATUS_FAILED,
XFER_ERROR_SEND_BLOCK);
return;
}
if (num_read == 4)
{
recv (xfer->sock, (char *) &ack, 4, 0);
xfer->ack = ntohl (ack);
/* DCC send ok? */
if ((xfer->pos >= xfer->size)
&& (xfer->ack >= xfer->size))
{
xfer_network_write_pipe (xfer, XFER_STATUS_DONE,
XFER_NO_ERROR);
return;
}
}
else
break;
}
}
/* send a block to receiver */
if ((xfer->pos < xfer->size) &&
(xfer->fast_send || (xfer->pos <= xfer->ack)))
{
lseek (xfer->file, xfer->pos, SEEK_SET);
num_read = read (xfer->file, buffer, xfer->blocksize);
if (num_read < 1)
{
xfer_network_write_pipe (xfer, XFER_STATUS_FAILED,
XFER_ERROR_READ_LOCAL);
return;
}
num_sent = send (xfer->sock, buffer, num_read, 0);
if (num_sent < 0)
{
/* socket is temporarily not available (receiver can't receive
amount of data we sent ?!) */
if (errno == EAGAIN)
usleep (1000);
else
{
xfer_network_write_pipe (xfer, XFER_STATUS_FAILED,
XFER_ERROR_SEND_BLOCK);
return;
}
}
if (num_sent > 0)
{
xfer->pos += (unsigned long) num_sent;
new_time = time (NULL);
if (last_sent != new_time)
{
last_sent = new_time;
xfer_network_write_pipe (xfer, XFER_STATUS_ACTIVE,
XFER_NO_ERROR);
}
}
}
else
usleep (1000);
}
}
/*
* xfer_dcc_recv_file_child: child process for receiving file
*/
void
xfer_dcc_recv_file_child (struct t_xfer *xfer)
{
int num_read;
static char buffer[XFER_BLOCKSIZE_MAX];
uint32_t pos;
time_t last_sent, new_time;
/* first connect to sender (blocking) */
if (!weechat_network_connect_to (xfer->sock, xfer->address, xfer->port))
{
xfer_network_write_pipe (xfer, XFER_STATUS_FAILED,
XFER_ERROR_CONNECT_SENDER);
return;
}
/* connection is ok, change DCC status (inform parent process) */
xfer_network_write_pipe (xfer, XFER_STATUS_ACTIVE,
XFER_NO_ERROR);
last_sent = time (NULL);
while (1)
{
num_read = recv (xfer->sock, buffer, sizeof (buffer), 0);
if (num_read == -1)
{
/* socket is temporarily not available (sender is not fast ?!) */
if (errno == EAGAIN)
usleep (1000);
else
{
xfer_network_write_pipe (xfer, XFER_STATUS_FAILED,
XFER_ERROR_RECV_BLOCK);
return;
}
}
else
{
if (num_read == 0)
{
xfer_network_write_pipe (xfer, XFER_STATUS_FAILED,
XFER_ERROR_RECV_BLOCK);
return;
}
if (write (xfer->file, buffer, num_read) == -1)
{
xfer_network_write_pipe (xfer, XFER_STATUS_FAILED,
XFER_ERROR_WRITE_LOCAL);
return;
}
xfer->pos += (unsigned long) num_read;
pos = htonl (xfer->pos);
/* we don't check return code, not a problem if an ACK send failed */
send (xfer->sock, (char *) &pos, 4, 0);
/* file received ok? */
if (xfer->pos >= xfer->size)
{
xfer_network_write_pipe (xfer, XFER_STATUS_DONE,
XFER_NO_ERROR);
return;
}
new_time = time (NULL);
if (last_sent != new_time)
{
last_sent = new_time;
xfer_network_write_pipe (xfer, XFER_STATUS_ACTIVE,
XFER_NO_ERROR);
}
}
}
}
+26
View File
@@ -0,0 +1,26 @@
/*
* 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_DCC_H
#define __WEECHAT_XFER_DCC_H 1
extern void xfer_dcc_send_file_child (struct t_xfer *xfer);
extern void xfer_dcc_recv_file_child (struct t_xfer *xfer);
#endif /* xfer-dcc.h */
+209
View File
@@ -0,0 +1,209 @@
/*
* 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-file.c: file functions for xfer plugin */
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <sys/wait.h>
#include "../weechat-plugin.h"
#include "xfer.h"
#include "xfer-file.h"
#include "xfer-buffer.h"
#include "xfer-config.h"
/*
* xfer_file_resume: resume a download
* return 1 if ok, 0 if not resumable
*/
int
xfer_file_resume (struct t_xfer *xfer, char *filename)
{
struct stat st;
if (!weechat_config_boolean (xfer_config_file_auto_resume))
return 0;
if (access (filename, W_OK) == 0)
{
if (stat (filename, &st) != -1)
{
if ((unsigned long) st.st_size < xfer->size)
{
xfer->start_resume = (unsigned long) st.st_size;
xfer->pos = st.st_size;
xfer->last_check_pos = st.st_size;
return 1;
}
}
}
/* not resumable */
return 0;
}
/*
* xfer_file_find_filename: find local filename for a xfer
* if type if file/recv, add a suffix (like .1) if needed
* if download is resumable, set "start_resume" to good value
*/
void
xfer_file_find_filename (struct t_xfer *xfer)
{
char *weechat_home, *dir1, *dir2, *filename2, *dir_separator;
if (!XFER_IS_FILE(xfer->type))
return;
dir1 = weechat_string_replace (weechat_config_string (xfer_config_file_download_path),
"~",
getenv ("HOME"));
if (!dir1)
return;
weechat_home = weechat_info_get ("weechat_dir");
if (!weechat_home)
{
free (dir1);
return;
}
dir2 = weechat_string_replace (dir1, "%h", weechat_home);
if (!dir2)
{
free (dir1);
return;
}
xfer->local_filename = malloc (strlen (dir2) +
strlen (xfer->nick) +
strlen (xfer->filename) + 4);
if (!xfer->local_filename)
return;
strcpy (xfer->local_filename, dir2);
dir_separator = weechat_info_get("dir_separator");
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, ".");
strcat (xfer->local_filename, xfer->filename);
if (dir1)
free (dir1);
if (dir2 )
free (dir2);
/* file already exists? */
if (access (xfer->local_filename, F_OK) == 0)
{
if (xfer_file_resume (xfer, xfer->local_filename))
return;
/* if auto rename is not set, then abort xfer */
if (!xfer_config_file_auto_rename)
{
xfer_close (xfer, XFER_STATUS_FAILED);
xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE);
return;
}
filename2 = malloc (strlen (xfer->local_filename) + 16);
if (!filename2)
{
xfer_close (xfer, XFER_STATUS_FAILED);
xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE);
return;
}
xfer->filename_suffix = 0;
do
{
xfer->filename_suffix++;
sprintf (filename2, "%s.%d",
xfer->local_filename,
xfer->filename_suffix);
if (access (filename2, F_OK) == 0)
{
if (xfer_file_resume (xfer, filename2))
break;
}
else
break;
}
while (1);
free (xfer->local_filename);
xfer->local_filename = strdup (filename2);
free (filename2);
}
}
/*
* xfer_file_calculate_speed: calculate xfer speed (for files only)
*/
void
xfer_file_calculate_speed (struct t_xfer *xfer, int ended)
{
time_t local_time, elapsed;
unsigned long bytes_per_sec_total;
local_time = time (NULL);
if (ended || local_time > xfer->last_check_time)
{
if (ended)
{
/* calculate bytes per second (global) */
elapsed = local_time - xfer->start_transfer;
if (elapsed == 0)
elapsed = 1;
xfer->bytes_per_sec = (xfer->pos - xfer->start_resume) / elapsed;
xfer->eta = 0;
}
else
{
/* calculate ETA */
elapsed = local_time - xfer->start_transfer;
if (elapsed == 0)
elapsed = 1;
bytes_per_sec_total = (xfer->pos - xfer->start_resume) / elapsed;
if (bytes_per_sec_total == 0)
bytes_per_sec_total = 1;
xfer->eta = (xfer->size - xfer->pos) / bytes_per_sec_total;
/* calculate bytes per second (since last check time) */
elapsed = local_time - xfer->last_check_time;
if (elapsed == 0)
elapsed = 1;
xfer->bytes_per_sec = (xfer->pos - xfer->last_check_pos) / elapsed;
}
xfer->last_check_time = local_time;
xfer->last_check_pos = xfer->pos;
}
}
+27
View File
@@ -0,0 +1,27 @@
/*
* 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_FILE_H
#define __WEECHAT_XFER_FILE_H 1
extern int xfer_file_resume (struct t_xfer *xfer, char *filename);
extern void xfer_file_find_filename (struct t_xfer *xfer);
extern void xfer_file_calculate_speed (struct t_xfer *xfer, int ended);
#endif /* xfer-file.h */
+371
View File
@@ -0,0 +1,371 @@
/*
* 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-network.c: network functions for xfer plugin */
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <time.h>
#include "../weechat-plugin.h"
#include "xfer.h"
#include "xfer-network.h"
#include "xfer-buffer.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
*/
int
xfer_network_create_pipe (struct t_xfer *xfer)
{
int child_pipe[2];
if (pipe (child_pipe) < 0)
{
weechat_printf (NULL,
_("%s%s: unable to create pipe"),
weechat_prefix ("error"), "xfer");
xfer_close (xfer, XFER_STATUS_FAILED);
xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE);
return 0;
}
xfer->child_read = child_pipe[0];
xfer->child_write = child_pipe[1];
return 1;
}
/*
* xfer_network_write_pipe: write data into pipe
*/
void
xfer_network_write_pipe (struct t_xfer *xfer, int status, int error)
{
char buffer[1 + 1 + 12 + 1]; /* status + error + pos + \0 */
snprintf (buffer, sizeof (buffer), "%c%c%012lu",
status + '0', error + '0', xfer->pos);
write (xfer->child_write, buffer, sizeof (buffer));
}
/*
* xfer_network_child_read_cb: read data from child via pipe
*/
int
xfer_network_child_read_cb (void *arg_xfer)
{
struct t_xfer *xfer;
char bufpipe[1 + 1 + 12 + 1];
int num_read;
char *error;
xfer = (struct t_xfer *)arg_xfer;
num_read = read (xfer->child_read, bufpipe, sizeof (bufpipe));
if (num_read > 0)
{
error = NULL;
xfer->pos = strtol (bufpipe + 2, &error, 10);
xfer->last_activity = time (NULL);
xfer_file_calculate_speed (xfer, 0);
/* read error code */
switch (bufpipe[1] - '0')
{
/* errors for sender */
case XFER_ERROR_READ_LOCAL:
weechat_printf (NULL,
_("%s%s: unable to read local file"),
weechat_prefix ("error"), "xfer");
break;
case XFER_ERROR_SEND_BLOCK:
weechat_printf (NULL,
_("%s%s: unable to send block to receiver"),
weechat_prefix ("error"), "xfer");
break;
case XFER_ERROR_READ_ACK:
weechat_printf (NULL,
_("%s%s: unable to read ACK from receiver"),
weechat_prefix ("error"), "xfer");
break;
/* errors for receiver */
case XFER_ERROR_CONNECT_SENDER:
weechat_printf (NULL,
_("%s%s: unable to connect to sender"),
weechat_prefix ("error"), "xfer");
break;
case XFER_ERROR_RECV_BLOCK:
weechat_printf (NULL,
_("%s%s: unable to receive block from sender"),
weechat_prefix ("error"), "xfer");
break;
case XFER_ERROR_WRITE_LOCAL:
weechat_printf (NULL,
_("%s%s: unable to write local file"),
weechat_prefix ("error"), "xfer");
break;
}
/* read new DCC status */
switch (bufpipe[0] - '0')
{
case XFER_STATUS_ACTIVE:
if (xfer->status == XFER_STATUS_CONNECTING)
{
/* connection was successful by child, init transfert times */
xfer->status = XFER_STATUS_ACTIVE;
xfer->start_transfer = time (NULL);
xfer->last_check_time = time (NULL);
xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE);
}
else
xfer_buffer_refresh (WEECHAT_HOTLIST_LOW);
break;
case XFER_STATUS_DONE:
xfer_close (xfer, XFER_STATUS_DONE);
xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE);
break;
case XFER_STATUS_FAILED:
xfer_close (xfer, XFER_STATUS_FAILED);
xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE);
break;
}
}
return WEECHAT_RC_OK;
}
/*
* xfer_network_send_file_fork: fork process for sending file
*/
void
xfer_network_send_file_fork (struct t_xfer *xfer)
{
pid_t pid;
if (!xfer_network_create_pipe (xfer))
return;
xfer->file = open (xfer->local_filename, O_RDONLY | O_NONBLOCK, 0644);
switch (pid = fork ())
{
/* fork failed */
case -1:
weechat_printf (NULL,
_("%s%s: unable to fork"),
weechat_prefix ("error"), "xfer");
xfer_close (xfer, XFER_STATUS_FAILED);
xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE);
return;
/* child process */
case 0:
setuid (getuid ());
switch (xfer->protocol)
{
case XFER_NO_PROTOCOL:
_exit (EXIT_SUCCESS);
break;
case XFER_PROTOCOL_DCC:
xfer_dcc_send_file_child (xfer);
break;
case XFER_NUM_PROTOCOLS:
break;
}
_exit (EXIT_SUCCESS);
}
/* parent process */
xfer->child_pid = pid;
xfer->hook_fd = weechat_hook_fd (xfer->child_read,
1, 0, 0,
xfer_network_child_read_cb,
xfer);
}
/*
* xfer_network_recv_file_fork: fork process for receiving file
*/
void
xfer_network_recv_file_fork (struct t_xfer *xfer)
{
pid_t pid;
if (!xfer_network_create_pipe (xfer))
return;
if (xfer->start_resume > 0)
xfer->file = open (xfer->local_filename,
O_APPEND | O_WRONLY | O_NONBLOCK);
else
xfer->file = open (xfer->local_filename,
O_CREAT | O_TRUNC | O_WRONLY | O_NONBLOCK,
0644);
switch (pid = fork ())
{
/* fork failed */
case -1:
weechat_printf (NULL,
_("%s%s: unable to fork"),
weechat_prefix ("error"), "xfer");
xfer_close (xfer, XFER_STATUS_FAILED);
xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE);
return;
/* child process */
case 0:
setuid (getuid ());
switch (xfer->protocol)
{
case XFER_NO_PROTOCOL:
_exit (EXIT_SUCCESS);
break;
case XFER_PROTOCOL_DCC:
xfer_dcc_recv_file_child (xfer);
break;
case XFER_NUM_PROTOCOLS:
break;
}
_exit (EXIT_SUCCESS);
}
/* parent process */
xfer->child_pid = pid;
xfer->hook_fd = weechat_hook_fd (xfer->child_read,
1, 0, 0,
xfer_network_child_read_cb,
xfer);
}
/*
* xfer_network_connect_init: connect to sender and init file or chat
*/
void
xfer_network_connect_init (struct t_xfer *xfer)
{
if (!xfer_network_connect (xfer))
{
xfer_close (xfer, XFER_STATUS_FAILED);
xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE);
}
else
{
/* for a file: launch child process */
if (XFER_IS_FILE(xfer->type))
{
xfer->status = XFER_STATUS_CONNECTING;
xfer_network_recv_file_fork (xfer);
}
else
{
/* for a chat => associate with buffer */
xfer->status = XFER_STATUS_ACTIVE;
// TODO: create buffer for xfer chat
}
}
xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE);
}
/*
* 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;
}
}
+30
View File
@@ -0,0 +1,30 @@
/*
* 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_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);
#endif /* xfer-network.h */
File diff suppressed because it is too large Load Diff
+156
View File
@@ -0,0 +1,156 @@
/*
* 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_H
#define __WEECHAT_XFER_H 1
#define weechat_plugin weechat_xfer_plugin
/* xfer types */
enum t_xfer_type
{
XFER_TYPE_FILE_RECV = 0,
XFER_TYPE_FILE_SEND,
XFER_TYPE_CHAT_RECV,
XFER_TYPE_CHAT_SEND,
/* number of xfer types */
XFER_NUM_TYPES,
};
/* xfer protocol (for file transfert) */
enum t_xfer_protocol
{
XFER_NO_PROTOCOL = 0,
XFER_PROTOCOL_DCC,
/* number of xfer protocols */
XFER_NUM_PROTOCOLS,
};
/* xfer status */
enum t_xfer_status
{
XFER_STATUS_WAITING = 0, /* waiting for host answer */
XFER_STATUS_CONNECTING, /* connecting to host */
XFER_STATUS_ACTIVE, /* sending/receiving data */
XFER_STATUS_DONE, /* transfer done */
XFER_STATUS_FAILED, /* transfer failed */
XFER_STATUS_ABORTED, /* transfer aborded by user */
/* number of xfer status */
XFER_NUM_STATUS,
};
/* xfer errors */
enum t_xfer_error
{
XFER_NO_ERROR = 0, /* no error to report, all ok! */
XFER_ERROR_READ_LOCAL, /* unable to read local file */
XFER_ERROR_SEND_BLOCK, /* unable to send block to receiver */
XFER_ERROR_READ_ACK, /* unable to read ACK from receiver */
XFER_ERROR_CONNECT_SENDER, /* unable to connect to sender */
XFER_ERROR_RECV_BLOCK, /* unable to recv block from sender */
XFER_ERROR_WRITE_LOCAL, /* unable to write to local file */
/* number of errors */
XFER_NUM_ERRORS,
};
/* xfer blocksize */
#define XFER_BLOCKSIZE_MIN 1024 /* min blocksize when sending file */
#define XFER_BLOCKSIZE_MAX 102400 /* max blocksize when sending file */
/* separator in filenames */
#ifdef _WIN32
#define DIR_SEPARATOR "\\"
#define DIR_SEPARATOR_CHAR '\\'
#else
#define DIR_SEPARATOR "/"
#define DIR_SEPARATOR_CHAR '/'
#endif
/* macros for type/status */
#define XFER_IS_FILE(type) ((type == XFER_TYPE_FILE_RECV) || \
(type == XFER_TYPE_FILE_SEND))
#define XFER_IS_CHAT(type) ((type == XFER_TYPE_CHAT_RECV) || \
(type == XFER_TYPE_CHAT_SEND))
#define XFER_IS_RECV(type) ((type == XFER_TYPE_FILE_RECV) || \
(type == XFER_TYPE_CHAT_RECV))
#define XFER_IS_SEND(type) ((type == XFER_TYPE_FILE_SEND) || \
(type == XFER_TYPE_CHAT_SEND))
#define XFER_HAS_ENDED(status) ((status == XFER_STATUS_DONE) || \
(status == XFER_STATUS_FAILED) || \
(status == XFER_STATUS_ABORTED))
struct t_xfer
{
/* data received by xfer to initiate a transfer */
char *plugin_id; /* plugin identifier */
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 *filename; /* filename */
unsigned long size; /* file size */
unsigned long address; /* local or remote IP address */
int port; /* remote port */
/* internal data */
enum t_xfer_status status; /* xfer status (waiting, sending,..) */
struct t_gui_buffer *buffer; /* buffer (for chat only) */
int fast_send; /* fast send file: does not wait ACK */
int blocksize; /* block size for sending file */
time_t start_time; /* time when xfer started */
time_t start_transfer; /* time when xfer transfer started */
int sock; /* socket for connection */
pid_t child_pid; /* pid of child process (send/recv) */
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 */
char *unterminated_message; /* beginning of a message */
int file; /* local file (read or write) */
char *local_filename; /* local filename (with path) */
int filename_suffix; /* suffix (like .1) if renaming file */
unsigned long pos; /* number of bytes received/sent */
unsigned long ack; /* number of bytes received OK */
unsigned long start_resume; /* start of resume (in bytes) */
time_t last_check_time; /* last time we checked bytes snt/rcv*/
unsigned long last_check_pos; /* bytes sent/recv at last check */
time_t last_activity; /* time of last byte received/sent */
unsigned long bytes_per_sec; /* bytes per second */
unsigned long eta; /* estimated time of arrival */
struct t_xfer *prev_xfer; /* link to previous xfer */
struct t_xfer *next_xfer; /* link to next xfer */
};
extern struct t_weechat_plugin *weechat_xfer_plugin;
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_debug;
extern void xfer_close (struct t_xfer *xfer, enum t_xfer_status status);
extern struct t_xfer *xfer_alloc ();
#endif /* xfer.h */