summaryrefslogtreecommitdiff
path: root/src/irc/irc-dcc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/irc/irc-dcc.c')
-rw-r--r--src/irc/irc-dcc.c631
1 files changed, 481 insertions, 150 deletions
diff --git a/src/irc/irc-dcc.c b/src/irc/irc-dcc.c
index 2d51c7e1a..6cc21774f 100644
--- a/src/irc/irc-dcc.c
+++ b/src/irc/irc-dcc.c
@@ -27,6 +27,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+#include <stdarg.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -70,7 +71,10 @@ dcc_connect (t_irc_dcc *ptr_dcc)
{
struct sockaddr_in addr;
- ptr_dcc->status = DCC_CONNECTING;
+ if (ptr_dcc->type == DCC_CHAT_SEND)
+ ptr_dcc->status = DCC_WAITING;
+ else
+ ptr_dcc->status = DCC_CONNECTING;
if (ptr_dcc->sock == -1)
{
@@ -81,8 +85,8 @@ dcc_connect (t_irc_dcc *ptr_dcc)
if (fcntl (ptr_dcc->sock, F_SETFL, O_NONBLOCK) == -1)
return 0;
- /* for DCC SEND, listen to socket for a connection */
- if (ptr_dcc->type == DCC_FILE_SEND)
+ /* for sending (chat or file), listen to socket for a connection */
+ if (DCC_IS_SEND(ptr_dcc->type))
{
if (listen (ptr_dcc->sock, 1) == -1)
return 0;
@@ -90,8 +94,8 @@ dcc_connect (t_irc_dcc *ptr_dcc)
return 0;
}
- /* for DCC RECV, connect to listening host */
- if (ptr_dcc->type == DCC_FILE_RECV)
+ /* for receiving (chat or file), connect to listening host */
+ if (DCC_IS_RECV(ptr_dcc->type))
{
memset (&addr, 0, sizeof (addr));
addr.sin_port = htons (ptr_dcc->port);
@@ -125,6 +129,8 @@ dcc_free (t_irc_dcc *ptr_dcc)
if (ptr_dcc->nick)
free (ptr_dcc->nick);
+ if (ptr_dcc->unterminated_message)
+ free (ptr_dcc->unterminated_message);
if (ptr_dcc->filename)
free (ptr_dcc->filename);
@@ -143,7 +149,7 @@ dcc_close (t_irc_dcc *ptr_dcc, int status)
if (status == DCC_DONE)
{
- if ((ptr_dcc->type == DCC_FILE_SEND) || (ptr_dcc->type == DCC_FILE_RECV))
+ if (DCC_IS_FILE(ptr_dcc->type))
{
irc_display_prefix (ptr_dcc->server->buffer, PREFIX_INFO);
gui_printf (ptr_dcc->server->buffer, _("DCC: file "));
@@ -167,6 +173,25 @@ dcc_close (t_irc_dcc *ptr_dcc, int status)
gui_printf (ptr_dcc->server->buffer, _(": ok!\n"));
}
}
+ if (status == DCC_ABORTED)
+ {
+ if (DCC_IS_CHAT(ptr_dcc->type))
+ {
+ irc_display_prefix (ptr_dcc->channel->buffer, PREFIX_INFO);
+ gui_printf (ptr_dcc->channel->buffer, _("DCC chat closed with "));
+ gui_printf_color (ptr_dcc->channel->buffer, COLOR_WIN_CHAT_NICK,
+ "%s", ptr_dcc->nick);
+ gui_printf_color (ptr_dcc->channel->buffer, COLOR_WIN_CHAT_DARK, " (");
+ gui_printf_color (ptr_dcc->channel->buffer, COLOR_WIN_CHAT_HOST,
+ "%d.%d.%d.%d",
+ ptr_dcc->addr >> 24, (ptr_dcc->addr >> 16) & 0xff,
+ (ptr_dcc->addr >> 8) & 0xff, ptr_dcc->addr & 0xff);
+ gui_printf_color (ptr_dcc->channel->buffer, COLOR_WIN_CHAT_DARK, ")\n");
+ }
+ }
+
+ if (DCC_IS_CHAT(ptr_dcc->type))
+ channel_remove_dcc (ptr_dcc);
if (ptr_dcc->sock != -1)
{
@@ -181,6 +206,39 @@ dcc_close (t_irc_dcc *ptr_dcc, int status)
}
/*
+ * dcc_channel_for_chat: create channel for DCC chat
+ */
+
+void
+dcc_channel_for_chat (t_irc_dcc *ptr_dcc)
+{
+ if (!channel_create_dcc (ptr_dcc))
+ {
+ irc_display_prefix (ptr_dcc->server->buffer, PREFIX_ERROR);
+ gui_printf (ptr_dcc->server->buffer,
+ _("%s can't associate DCC chat with private buffer "
+ "(maybe private buffer has already DCC CHAT?)\n"),
+ WEECHAT_ERROR);
+ dcc_close (ptr_dcc, DCC_FAILED);
+ dcc_redraw (1);
+ return;
+ }
+
+ irc_display_prefix (ptr_dcc->channel->buffer, PREFIX_INFO);
+ gui_printf_type (ptr_dcc->channel->buffer, MSG_TYPE_MSG,
+ _("Connected to "));
+ gui_printf_color (ptr_dcc->channel->buffer, COLOR_WIN_CHAT_NICK,
+ "%s", ptr_dcc->nick);
+ gui_printf_color (ptr_dcc->channel->buffer, COLOR_WIN_CHAT_DARK, " (");
+ gui_printf_color (ptr_dcc->channel->buffer, COLOR_WIN_CHAT_HOST,
+ "%d.%d.%d.%d",
+ ptr_dcc->addr >> 24, (ptr_dcc->addr >> 16) & 0xff,
+ (ptr_dcc->addr >> 8) & 0xff, ptr_dcc->addr & 0xff);
+ gui_printf_color (ptr_dcc->channel->buffer, COLOR_WIN_CHAT_DARK, ") ");
+ gui_printf (ptr_dcc->channel->buffer, _("via DCC chat\n"));
+}
+
+/*
* dcc_accept: accepts a DCC file or chat request
*/
@@ -197,67 +255,77 @@ dcc_accept (t_irc_dcc *ptr_dcc)
else
{
ptr_dcc->status = DCC_ACTIVE;
- ptr_home = getenv ("HOME");
- ptr_dcc->local_filename = (char *) malloc (strlen (cfg_dcc_download_path) +
- strlen (ptr_dcc->nick) +
- strlen (ptr_dcc->filename) +
- ((cfg_dcc_download_path[0] == '~') ?
- strlen (ptr_home) : 0) +
- 4);
- if (!ptr_dcc->local_filename)
- {
- dcc_close (ptr_dcc, DCC_FAILED);
- dcc_redraw (1);
- return;
- }
- if (cfg_dcc_download_path[0] == '~')
- {
- strcpy (ptr_dcc->local_filename, ptr_home);
- strcat (ptr_dcc->local_filename, cfg_dcc_download_path + 1);
- }
- else
- strcpy (ptr_dcc->local_filename, cfg_dcc_download_path);
- if (ptr_dcc->local_filename[strlen (ptr_dcc->local_filename) - 1] != DIR_SEPARATOR_CHAR)
- strcat (ptr_dcc->local_filename, DIR_SEPARATOR);
- strcat (ptr_dcc->local_filename, ptr_dcc->nick);
- strcat (ptr_dcc->local_filename, ".");
- strcat (ptr_dcc->local_filename, ptr_dcc->filename);
- /* file already exists? */
- if (access (ptr_dcc->local_filename, F_OK) == 0)
+ /* DCC file => look for local filename and open it in writing mode */
+ if (DCC_IS_FILE(ptr_dcc->type))
{
- /* if auto rename is not set, then abort DCC */
- if (!cfg_dcc_auto_rename)
+ ptr_home = getenv ("HOME");
+ ptr_dcc->local_filename = (char *) malloc (strlen (cfg_dcc_download_path) +
+ strlen (ptr_dcc->nick) +
+ strlen (ptr_dcc->filename) +
+ ((cfg_dcc_download_path[0] == '~') ?
+ strlen (ptr_home) : 0) +
+ 4);
+ if (!ptr_dcc->local_filename)
{
dcc_close (ptr_dcc, DCC_FAILED);
dcc_redraw (1);
return;
}
-
- filename2 = (char *) malloc (strlen (ptr_dcc->local_filename) + 16);
- if (!filename2)
+ if (cfg_dcc_download_path[0] == '~')
{
- dcc_close (ptr_dcc, DCC_FAILED);
- dcc_redraw (1);
- return;
+ strcpy (ptr_dcc->local_filename, ptr_home);
+ strcat (ptr_dcc->local_filename, cfg_dcc_download_path + 1);
}
- ptr_dcc->filename_suffix = 0;
- do
+ else
+ strcpy (ptr_dcc->local_filename, cfg_dcc_download_path);
+ if (ptr_dcc->local_filename[strlen (ptr_dcc->local_filename) - 1] != DIR_SEPARATOR_CHAR)
+ strcat (ptr_dcc->local_filename, DIR_SEPARATOR);
+ strcat (ptr_dcc->local_filename, ptr_dcc->nick);
+ strcat (ptr_dcc->local_filename, ".");
+ strcat (ptr_dcc->local_filename, ptr_dcc->filename);
+
+ /* file already exists? */
+ if (access (ptr_dcc->local_filename, F_OK) == 0)
{
- ptr_dcc->filename_suffix++;
- sprintf (filename2, "%s.%d",
- ptr_dcc->local_filename,
- ptr_dcc->filename_suffix);
+ /* if auto rename is not set, then abort DCC */
+ if (!cfg_dcc_auto_rename)
+ {
+ dcc_close (ptr_dcc, DCC_FAILED);
+ dcc_redraw (1);
+ return;
+ }
+
+ filename2 = (char *) malloc (strlen (ptr_dcc->local_filename) + 16);
+ if (!filename2)
+ {
+ dcc_close (ptr_dcc, DCC_FAILED);
+ dcc_redraw (1);
+ return;
+ }
+ ptr_dcc->filename_suffix = 0;
+ do
+ {
+ ptr_dcc->filename_suffix++;
+ sprintf (filename2, "%s.%d",
+ ptr_dcc->local_filename,
+ ptr_dcc->filename_suffix);
+ }
+ while (access (filename2, F_OK) == 0);
+
+ free (ptr_dcc->local_filename);
+ ptr_dcc->local_filename = strdup (filename2);
+ free (filename2);
}
- while (access (filename2, F_OK) == 0);
-
- free (ptr_dcc->local_filename);
- ptr_dcc->local_filename = strdup (filename2);
- free (filename2);
+ ptr_dcc->file = open (ptr_dcc->local_filename,
+ O_CREAT | O_TRUNC | O_WRONLY | O_NONBLOCK,
+ 0644);
+ }
+ else
+ {
+ /* DCC CHAT => associate DCC with channel */
+ dcc_channel_for_chat (ptr_dcc);
}
- ptr_dcc->file = open (ptr_dcc->local_filename,
- O_CREAT | O_TRUNC | O_WRONLY | O_NONBLOCK,
- 0644);
}
dcc_redraw (1);
}
@@ -272,22 +340,31 @@ dcc_add (t_irc_server *server, int type, unsigned long addr, int port, char *nic
{
t_irc_dcc *new_dcc;
+ /* create new DCC struct */
if ((new_dcc = (t_irc_dcc *) malloc (sizeof (t_irc_dcc))) == NULL)
{
- gui_printf_nolog (server->buffer,
- _("%s not enough memory for new DCC\n"),
- WEECHAT_ERROR);
+ irc_display_prefix (server->buffer, PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s not enough memory for new DCC\n"),
+ WEECHAT_ERROR);
return NULL;
}
+
+ /* initialize new DCC */
new_dcc->server = server;
+ new_dcc->channel = NULL;
new_dcc->type = type;
new_dcc->status = DCC_WAITING;
new_dcc->addr = addr;
new_dcc->port = port;
new_dcc->nick = strdup (nick);
new_dcc->sock = sock;
+ new_dcc->unterminated_message = NULL;
new_dcc->file = -1;
- new_dcc->filename = strdup (filename);
+ if (DCC_IS_CHAT(type))
+ new_dcc->filename = strdup (_("DCC chat"));
+ else
+ new_dcc->filename = (filename) ? strdup (filename) : NULL;
new_dcc->local_filename = (local_filename) ? strdup (local_filename) : NULL;
new_dcc->filename_suffix = -1;
new_dcc->size = size;
@@ -302,6 +379,7 @@ dcc_add (t_irc_server *server, int type, unsigned long addr, int port, char *nic
gui_current_window->dcc_first = NULL;
gui_current_window->dcc_selected = NULL;
+ /* write info message on server buffer */
if (type == DCC_FILE_RECV)
{
irc_display_prefix (server->buffer, PREFIX_INFO);
@@ -318,17 +396,11 @@ dcc_add (t_irc_server *server, int type, unsigned long addr, int port, char *nic
gui_printf_color (server->buffer, COLOR_WIN_CHAT_CHANNEL, "%lu", size);
gui_printf (server->buffer, _(" bytes\n"));
}
-
if (type == DCC_FILE_SEND)
{
irc_display_prefix (server->buffer, PREFIX_INFO);
gui_printf (server->buffer, _("Sending DCC file to "));
gui_printf_color (server->buffer, COLOR_WIN_CHAT_NICK, "%s", nick);
- gui_printf_color (server->buffer, COLOR_WIN_CHAT_DARK, " (");
- gui_printf_color (server->buffer, COLOR_WIN_CHAT_HOST,
- "%d.%d.%d.%d",
- addr >> 24, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
- gui_printf_color (server->buffer, COLOR_WIN_CHAT_DARK, ")");
gui_printf (server->buffer, ": ");
gui_printf_color (server->buffer, COLOR_WIN_CHAT_CHANNEL, "%s", filename);
gui_printf (server->buffer, _(" (local filename: "));
@@ -337,8 +409,26 @@ dcc_add (t_irc_server *server, int type, unsigned long addr, int port, char *nic
gui_printf_color (server->buffer, COLOR_WIN_CHAT_CHANNEL, "%lu", size);
gui_printf (server->buffer, _(" bytes\n"));
}
+ if (type == DCC_CHAT_RECV)
+ {
+ irc_display_prefix (server->buffer, PREFIX_INFO);
+ gui_printf (server->buffer, _("Incoming DCC chat request from "));
+ gui_printf_color (server->buffer, COLOR_WIN_CHAT_NICK, "%s", nick);
+ gui_printf_color (server->buffer, COLOR_WIN_CHAT_DARK, " (");
+ gui_printf_color (server->buffer, COLOR_WIN_CHAT_HOST,
+ "%d.%d.%d.%d",
+ addr >> 24, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
+ gui_printf_color (server->buffer, COLOR_WIN_CHAT_DARK, ")\n");
+ }
+ if (type == DCC_CHAT_SEND)
+ {
+ irc_display_prefix (server->buffer, PREFIX_INFO);
+ gui_printf (server->buffer, _("Sending DCC chat request to "));
+ gui_printf_color (server->buffer, COLOR_WIN_CHAT_NICK, "%s\n", nick);
+ }
- if (type == DCC_FILE_SEND)
+ /* connect if needed and redraw DCC buffer */
+ if (DCC_IS_SEND(type))
{
if (!dcc_connect (new_dcc))
{
@@ -358,11 +448,11 @@ dcc_add (t_irc_server *server, int type, unsigned long addr, int port, char *nic
}
/*
- * dcc_send: send DCC request (file or chat)
+ * dcc_send_request: send DCC request (file or chat)
*/
void
-dcc_send (t_irc_server *server, char *nick, char *filename)
+dcc_send_request (t_irc_server *server, int type, char *nick, char *filename)
{
char *ptr_home, *filename2, *short_filename, *pos;
int spaces;
@@ -371,57 +461,66 @@ dcc_send (t_irc_server *server, char *nick, char *filename)
struct sockaddr_in addr;
socklen_t length;
unsigned long local_addr;
+ t_irc_dcc *ptr_dcc;
- /* add home if filename not beginning with '/' (not for Win32) */
- #ifdef _WIN32
- filename2 = strdup (filename);
- #else
- if (filename[0] == '/')
- filename2 = strdup (filename);
- else
+ filename2 = NULL;
+ short_filename = NULL;
+ spaces = 0;
+
+ if (type == DCC_FILE_SEND)
{
- ptr_home = getenv ("HOME");
- filename2 = (char *) malloc (strlen (cfg_dcc_upload_path) +
- strlen (filename) +
- ((cfg_dcc_upload_path[0] == '~') ?
- strlen (ptr_home) : 0) +
- 4);
- if (!filename2)
+ /* add home if filename not beginning with '/' (not for Win32) */
+ #ifdef _WIN32
+ filename2 = strdup (filename);
+ #else
+ if (filename[0] == '/')
+ filename2 = strdup (filename);
+ else
{
- irc_display_prefix (server->buffer, PREFIX_ERROR);
- gui_printf_nolog (server->buffer,
- _("%s not enough memory for DCC SEND\n"),
- WEECHAT_ERROR);
- return;
+ ptr_home = getenv ("HOME");
+ filename2 = (char *) malloc (strlen (cfg_dcc_upload_path) +
+ strlen (filename) +
+ ((cfg_dcc_upload_path[0] == '~') ?
+ strlen (ptr_home) : 0) +
+ 4);
+ if (!filename2)
+ {
+ irc_display_prefix (server->buffer, PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s not enough memory for DCC SEND\n"),
+ WEECHAT_ERROR);
+ return;
+ }
+ if (cfg_dcc_upload_path[0] == '~')
+ {
+ strcpy (filename2, ptr_home);
+ strcat (filename2, cfg_dcc_upload_path + 1);
+ }
+ else
+ strcpy (filename2, cfg_dcc_upload_path);
+ if (filename2[strlen (filename2) - 1] != DIR_SEPARATOR_CHAR)
+ strcat (filename2, DIR_SEPARATOR);
+ strcat (filename2, filename);
}
- if (cfg_dcc_upload_path[0] == '~')
+ #endif
+
+ /* check if file exists */
+ if (stat (filename2, &st) == -1)
{
- strcpy (filename2, ptr_home);
- strcat (filename2, cfg_dcc_upload_path + 1);
+ irc_display_prefix (server->buffer, PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s cannot access file \"%s\"\n"),
+ WEECHAT_ERROR, filename2);
+ if (filename2)
+ free (filename2);
+ return;
}
- else
- strcpy (filename2, cfg_dcc_upload_path);
- if (filename2[strlen (filename2) - 1] != DIR_SEPARATOR_CHAR)
- strcat (filename2, DIR_SEPARATOR);
- strcat (filename2, filename);
- }
- #endif
-
- /* check if file exists */
- if (stat (filename2, &st) == -1)
- {
- irc_display_prefix (server->buffer, PREFIX_ERROR);
- gui_printf_nolog (server->buffer,
- _("%s cannot access file \"%s\"\n"),
- WEECHAT_ERROR, filename2);
- free (filename2);
- return;
}
/* get local IP address */
memset (&addr, 0, sizeof (struct sockaddr_in));
length = sizeof (addr);
- getsockname (server->sock4, (struct sockaddr *) &addr, &length);
+ getsockname (server->sock, (struct sockaddr *) &addr, &length);
addr.sin_family = AF_INET;
local_addr = ntohl (addr.sin_addr.s_addr);
@@ -430,10 +529,11 @@ dcc_send (t_irc_server *server, char *nick, char *filename)
if (sock == -1)
{
irc_display_prefix (server->buffer, PREFIX_ERROR);
- gui_printf_nolog (server->buffer,
- _("%s cannot create socket for DCC\n"),
- WEECHAT_ERROR);
- free (filename2);
+ gui_printf (server->buffer,
+ _("%s cannot create socket for DCC\n"),
+ WEECHAT_ERROR);
+ if (filename2)
+ free (filename2);
return;
}
@@ -442,68 +542,243 @@ dcc_send (t_irc_server *server, char *nick, char *filename)
if (bind (sock, (struct sockaddr *) &addr, sizeof (addr)) == -1)
{
irc_display_prefix (server->buffer, PREFIX_ERROR);
- gui_printf_nolog (server->buffer,
- _("%s cannot find port for DCC\n"),
- WEECHAT_ERROR);
+ gui_printf (server->buffer,
+ _("%s cannot find port for DCC\n"),
+ WEECHAT_ERROR);
close (sock);
- free (filename2);
+ if (filename2)
+ free (filename2);
return;
}
length = sizeof (addr);
getsockname (sock, (struct sockaddr *) &addr, &length);
port = ntohs (addr.sin_port);
- /* extract short filename (without path) */
- pos = strrchr (filename2, DIR_SEPARATOR_CHAR);
- if (pos)
- short_filename = strdup (pos + 1);
- else
- short_filename = strdup (filename2);
-
- /* convert spaces to underscore if asked and needed */
- pos = short_filename;
- spaces = 0;
- while (pos[0])
+ if (type == DCC_FILE_SEND)
{
- if (pos[0] == ' ')
+ /* extract short filename (without path) */
+ pos = strrchr (filename2, DIR_SEPARATOR_CHAR);
+ if (pos)
+ short_filename = strdup (pos + 1);
+ else
+ short_filename = strdup (filename2);
+
+ /* convert spaces to underscore if asked and needed */
+ pos = short_filename;
+ spaces = 0;
+ while (pos[0])
{
- if (cfg_dcc_convert_spaces)
- pos[0] = '_';
- else
- spaces = 1;
+ if (pos[0] == ' ')
+ {
+ if (cfg_dcc_convert_spaces)
+ pos[0] = '_';
+ else
+ spaces = 1;
+ }
+ pos++;
}
- pos++;
}
/* add DCC entry and listen to socket */
- if (!dcc_add (server, DCC_FILE_SEND, local_addr, port, nick, sock,
- short_filename, filename2, st.st_size))
+ if (type == DCC_CHAT_SEND)
+ ptr_dcc = dcc_add (server, DCC_CHAT_SEND, local_addr, port, nick, sock,
+ NULL, NULL, 0);
+ else
+ ptr_dcc = dcc_add (server, DCC_FILE_SEND, local_addr, port, nick, sock,
+ short_filename, filename2, st.st_size);
+ if (!ptr_dcc)
{
irc_display_prefix (server->buffer, PREFIX_ERROR);
- gui_printf_nolog (server->buffer,
- _("%s cannot send DCC\n"),
- WEECHAT_ERROR);
+ gui_printf (server->buffer,
+ _("%s cannot send DCC\n"),
+ WEECHAT_ERROR);
close (sock);
- free (short_filename);
- free (filename2);
+ if (short_filename)
+ free (short_filename);
+ if (filename2)
+ free (filename2);
return;
}
/* send DCC request to nick */
- server_sendf (server,
- (spaces) ?
- "PRIVMSG %s :\01DCC SEND \"%s\" %lu %d %u\01\r\n" :
- "PRIVMSG %s :\01DCC SEND %s %lu %d %u\01\r\n",
- nick, short_filename, local_addr, port,
- (unsigned long) st.st_size);
-
- free (short_filename);
- free (filename2);
+ if (type == DCC_CHAT_SEND)
+ server_sendf (server,
+ "PRIVMSG %s :\01DCC CHAT chat %lu %d\01\r\n",
+ nick, local_addr, port);
+ else
+ server_sendf (server,
+ (spaces) ?
+ "PRIVMSG %s :\01DCC SEND \"%s\" %lu %d %u\01\r\n" :
+ "PRIVMSG %s :\01DCC SEND %s %lu %d %u\01\r\n",
+ nick, short_filename, local_addr, port,
+ (unsigned long) st.st_size);
+
+ if (short_filename)
+ free (short_filename);
+ if (filename2)
+ free (filename2);
}
+/*
+ * dcc_chat_send: send data to remote host via DCC CHAT
+ */
+
+int
+dcc_chat_send (t_irc_dcc *ptr_dcc, char *buffer, int size_buf)
+{
+ if (!ptr_dcc)
+ return -1;
+
+ return send (ptr_dcc->sock, buffer, size_buf, 0);
+}
+
+/*
+ * dcc_chat_sendf: send formatted data to remote host via DCC CHAT
+ */
+
+void
+dcc_chat_sendf (t_irc_dcc *ptr_dcc, char *fmt, ...)
+{
+ va_list args;
+ static char buffer[4096];
+ char *buf2;
+ int size_buf;
+
+ if (!ptr_dcc || (ptr_dcc->sock == -1))
+ return;
+
+ va_start (args, fmt);
+ size_buf = vsnprintf (buffer, sizeof (buffer) - 1, fmt, args);
+ va_end (args);
+
+ if ((size_buf == 0) || (strcmp (buffer, "\r\n") == 0))
+ return;
+
+ buffer[sizeof (buffer) - 1] = '\0';
+ if ((size_buf < 0) || (size_buf > (int) (sizeof (buffer) - 1)))
+ size_buf = strlen (buffer);
+ #ifdef DEBUG
+ buffer[size_buf - 2] = '\0';
+ gui_printf (ptr_dcc->server->buffer, "[DEBUG] Sending to remote host (DCC CHAT) >>> %s\n", buffer);
+ buffer[size_buf - 2] = '\r';
+ #endif
+ buf2 = weechat_convert_encoding ((cfg_look_charset_internal && cfg_look_charset_internal[0]) ?
+ cfg_look_charset_internal : local_charset,
+ cfg_look_charset_encode,
+ buffer);
+ if (dcc_chat_send (ptr_dcc, buf2, strlen (buf2)) <= 0)
+ {
+ irc_display_prefix (ptr_dcc->server->buffer, PREFIX_ERROR);
+ gui_printf (ptr_dcc->server->buffer, _("%s error sending data to \"%s\" via DCC CHAT\n"),
+ WEECHAT_ERROR, ptr_dcc->nick);
+ dcc_close (ptr_dcc, DCC_FAILED);
+ }
+ free (buf2);
+}
/*
- * dcc_handle: receive/send data for each active DCC
+ * dcc_chat_recv: receive data from DCC CHAT host
+ */
+
+void
+dcc_chat_recv (t_irc_dcc *ptr_dcc)
+{
+ static char buffer[4096 + 2];
+ char *buf2, *pos, *ptr_buf, *next_ptr_buf;
+ int num_read;
+
+ num_read = recv (ptr_dcc->sock, buffer, sizeof (buffer) - 2, 0);
+ if (num_read > 0)
+ {
+ buffer[num_read] = '\0';
+
+ buf2 = NULL;
+ ptr_buf = buffer;
+ if (ptr_dcc->unterminated_message)
+ {
+ buf2 = (char *) malloc (strlen (ptr_dcc->unterminated_message) +
+ strlen (buffer) + 1);
+ if (buf2)
+ {
+ strcpy (buf2, ptr_dcc->unterminated_message);
+ strcat (buf2, buffer);
+ }
+ ptr_buf = buf2;
+ free (ptr_dcc->unterminated_message);
+ ptr_dcc->unterminated_message = NULL;
+ }
+
+ while (ptr_buf && ptr_buf[0])
+ {
+ next_ptr_buf = NULL;
+ pos = strstr (ptr_buf, "\r\n");
+ if (pos)
+ {
+ pos[0] = '\0';
+ next_ptr_buf = pos + 2;
+ }
+ else
+ {
+ pos = strstr (ptr_buf, "\n");
+ if (pos)
+ {
+ pos[0] = '\0';
+ next_ptr_buf = pos + 1;
+ }
+ else
+ {
+ ptr_dcc->unterminated_message = strdup (ptr_buf);
+ ptr_buf = NULL;
+ next_ptr_buf = NULL;
+ }
+ }
+
+ if (ptr_buf)
+ {
+ gui_printf_type_color (ptr_dcc->channel->buffer,
+ MSG_TYPE_NICK,
+ COLOR_WIN_CHAT_DARK, "<");
+ if (strstr (ptr_buf, ptr_dcc->server->nick))
+ {
+ gui_printf_type_color (ptr_dcc->channel->buffer,
+ MSG_TYPE_NICK | MSG_TYPE_HIGHLIGHT,
+ COLOR_WIN_CHAT_HIGHLIGHT,
+ "%s", ptr_dcc->nick);
+ if ( (cfg_look_infobar_delay_highlight > 0)
+ && (ptr_dcc->channel->buffer != gui_current_window->buffer) )
+ gui_infobar_printf (cfg_look_infobar_delay_highlight,
+ COLOR_WIN_INFOBAR_HIGHLIGHT,
+ _("Private %s> %s"),
+ ptr_dcc->nick, ptr_buf);
+ }
+ else
+ gui_printf_type_color (ptr_dcc->channel->buffer,
+ MSG_TYPE_NICK,
+ COLOR_WIN_NICK_PRIVATE,
+ "%s", ptr_dcc->nick);
+ gui_printf_type_color (ptr_dcc->channel->buffer,
+ MSG_TYPE_NICK,
+ COLOR_WIN_CHAT_DARK, "> ");
+ gui_printf_type_color (ptr_dcc->channel->buffer,
+ MSG_TYPE_MSG,
+ COLOR_WIN_CHAT, "%s\n", ptr_buf);
+ }
+
+ ptr_buf = next_ptr_buf;
+ }
+
+ if (buf2)
+ free (buf2);
+ }
+ else
+ {
+ dcc_close (ptr_dcc, DCC_ABORTED);
+ dcc_redraw (1);
+ }
+}
+
+/*
+ * dcc_handle: receive/send data for each active DCC (files only)
*/
void
@@ -555,6 +830,47 @@ dcc_handle ()
ptr_dcc->addr = ntohl (addr.sin_addr.s_addr);
ptr_dcc->status = DCC_ACTIVE;
ptr_dcc->file = open (ptr_dcc->local_filename, O_RDONLY | O_NONBLOCK, 0644);
+ dcc_redraw (1);
+ }
+ }
+ }
+ }
+
+ if (ptr_dcc->status == DCC_WAITING)
+ {
+ if (ptr_dcc->type == DCC_CHAT_SEND)
+ {
+ FD_ZERO (&read_fd);
+ FD_SET (ptr_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 (ptr_dcc->sock, &read_fd))
+ {
+ length = sizeof (addr);
+ sock = accept (ptr_dcc->sock, (struct sockaddr *) &addr, &length);
+ close (ptr_dcc->sock);
+ ptr_dcc->sock = -1;
+ if (sock < 0)
+ {
+ dcc_close (ptr_dcc, DCC_FAILED);
+ dcc_redraw (1);
+ return;
+ }
+ ptr_dcc->sock = sock;
+ if (fcntl (ptr_dcc->sock, F_SETFL, O_NONBLOCK) == -1)
+ {
+ dcc_close (ptr_dcc, DCC_FAILED);
+ dcc_redraw (1);
+ return;
+ }
+ ptr_dcc->addr = ntohl (addr.sin_addr.s_addr);
+ ptr_dcc->status = DCC_ACTIVE;
+ dcc_redraw (1);
+ dcc_channel_for_chat (ptr_dcc);
}
}
}
@@ -562,6 +878,20 @@ dcc_handle ()
if (ptr_dcc->status == DCC_ACTIVE)
{
+ if (DCC_IS_CHAT(ptr_dcc->type))
+ {
+ FD_ZERO (&read_fd);
+ FD_SET (ptr_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 (ptr_dcc->sock, &read_fd))
+ dcc_chat_recv (ptr_dcc);
+ }
+ }
if (ptr_dcc->type == DCC_FILE_RECV)
{
num_read = recv (ptr_dcc->sock, buffer, sizeof (buffer), 0);
@@ -596,6 +926,7 @@ dcc_handle ()
{
if (cfg_dcc_blocksize > (int) sizeof (buffer))
{
+ irc_display_prefix (NULL, PREFIX_ERROR);
gui_printf (NULL, _("%s DCC failed because blocksize is too "
"big. Check value of \"dcc_blocksize\" option, "
"max is %d.\n"),