summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--src/irc/irc-dcc.c341
-rw-r--r--src/irc/irc-recv.c116
-rw-r--r--src/irc/irc.h7
-rw-r--r--weechat/ChangeLog4
-rw-r--r--weechat/src/irc/irc-dcc.c341
-rw-r--r--weechat/src/irc/irc-recv.c116
-rw-r--r--weechat/src/irc/irc.h7
8 files changed, 780 insertions, 156 deletions
diff --git a/ChangeLog b/ChangeLog
index 75aab1732..ff578a522 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,11 +1,11 @@
WeeChat - Wee Enhanced Environment for Chat
===========================================
-ChangeLog - 2005-07-12
+ChangeLog - 2005-07-13
Versoin 0.1.4 (under dev!):
- * added DCC timeout
+ * added DCC resume and timeout
* added function for Perl/Python to get DCC list
* fixed FIFO pipe (command now authorized on a buffer not connected
to an IRC server)
diff --git a/src/irc/irc-dcc.c b/src/irc/irc-dcc.c
index 45de99ab0..6e15ada74 100644
--- a/src/irc/irc-dcc.c
+++ b/src/irc/irc-dcc.c
@@ -64,6 +64,133 @@ dcc_redraw (int highlight)
}
/*
+ * dcc_search: search a DCC
+ */
+
+t_irc_dcc *
+dcc_search (t_irc_server *server, int type, int status, int port)
+{
+ t_irc_dcc *ptr_dcc;
+
+ for (ptr_dcc = dcc_list; ptr_dcc; ptr_dcc = ptr_dcc->next_dcc)
+ {
+ if ((ptr_dcc->server == server)
+ && (ptr_dcc->type == type)
+ && (ptr_dcc->status = status)
+ && (ptr_dcc->port == port))
+ return ptr_dcc;
+ }
+
+ /* DCC not found */
+ return NULL;
+}
+
+/*
+ * dcc_file_is_resumable: check if a file can be used for resuming a download
+ */
+
+int
+dcc_file_is_resumable (t_irc_dcc *ptr_dcc, char *filename)
+{
+ struct stat st;
+
+ if (access (filename, W_OK) == 0)
+ {
+ if (stat (filename, &st) != -1)
+ {
+ if ((unsigned long) st.st_size < ptr_dcc->size)
+ {
+ ptr_dcc->start_resume = (unsigned long) st.st_size;
+ ptr_dcc->pos = st.st_size;
+ ptr_dcc->last_check_pos = st.st_size;
+ return 1;
+ }
+ }
+ }
+
+ /* not resumable */
+ return 0;
+}
+
+/*
+ * dcc_find_filename: find local filename for a DCC
+ * if type if file/recv, add a suffix (like .1) if needed
+ * if download is resumable, set "start_resume" to good value
+ */
+
+void
+dcc_find_filename (t_irc_dcc *ptr_dcc)
+{
+ char *ptr_home, *filename2;
+
+ 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)
+ 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)
+ {
+ if (dcc_file_is_resumable (ptr_dcc, ptr_dcc->local_filename))
+ return;
+
+ /* 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);
+ if (access (filename2, F_OK) == 0)
+ {
+ if (dcc_file_is_resumable (ptr_dcc, filename2))
+ break;
+ }
+ else
+ break;
+ }
+ while (1);
+
+ free (ptr_dcc->local_filename);
+ ptr_dcc->local_filename = strdup (filename2);
+ free (filename2);
+ }
+}
+
+/*
* dcc_calculate_speed: calculate DCC speed (for files only)
*/
@@ -81,7 +208,7 @@ dcc_calculate_speed (t_irc_dcc *ptr_dcc, int ended)
elapsed = local_time - ptr_dcc->start_transfer;
if (elapsed == 0)
elapsed = 1;
- ptr_dcc->bytes_per_sec = ptr_dcc->pos / elapsed;
+ ptr_dcc->bytes_per_sec = (ptr_dcc->pos - ptr_dcc->start_resume) / elapsed;
}
else
{
@@ -199,7 +326,7 @@ dcc_close (t_irc_dcc *ptr_dcc, int status)
COLOR_WIN_CHAT_CHANNEL,
"%s",
ptr_dcc->local_filename);
- gui_printf (ptr_dcc->server->buffer, ") ");
+ gui_printf (ptr_dcc->server->buffer, ")");
}
if (ptr_dcc->type == DCC_FILE_SEND)
gui_printf (ptr_dcc->server->buffer, _(" sent to "));
@@ -294,14 +421,12 @@ dcc_channel_for_chat (t_irc_dcc *ptr_dcc)
}
/*
- * dcc_accept: accepts a DCC file or chat request
+ * dcc_recv_connect_init: connect to sender and init file or chat
*/
void
-dcc_accept (t_irc_dcc *ptr_dcc)
+dcc_recv_connect_init (t_irc_dcc *ptr_dcc)
{
- char *ptr_home, *filename2;
-
if (!dcc_connect (ptr_dcc))
{
dcc_close (ptr_dcc, DCC_FAILED);
@@ -314,68 +439,15 @@ dcc_accept (t_irc_dcc *ptr_dcc)
/* DCC file => look for local filename and open it in writing mode */
if (DCC_IS_FILE(ptr_dcc->type))
{
- 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);
- }
+ if (ptr_dcc->start_resume > 0)
+ ptr_dcc->file = open (ptr_dcc->local_filename,
+ O_APPEND | O_WRONLY | O_NONBLOCK);
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)
- {
- /* 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);
- }
- ptr_dcc->file = open (ptr_dcc->local_filename,
- O_CREAT | O_TRUNC | O_WRONLY | O_NONBLOCK,
- 0644);
+ ptr_dcc->file = open (ptr_dcc->local_filename,
+ O_CREAT | O_TRUNC | O_WRONLY | O_NONBLOCK,
+ 0644);
ptr_dcc->start_transfer = time (NULL);
+ ptr_dcc->last_check_time = time (NULL);
}
else
{
@@ -387,6 +459,93 @@ dcc_accept (t_irc_dcc *ptr_dcc)
}
/*
+ * dcc_accept: accepts a DCC file or chat request
+ */
+
+void
+dcc_accept (t_irc_dcc *ptr_dcc)
+{
+ if (DCC_IS_FILE(ptr_dcc->type) && (ptr_dcc->start_resume > 0))
+ {
+ ptr_dcc->status = DCC_CONNECTING;
+ server_sendf (ptr_dcc->server,
+ (strchr (ptr_dcc->filename, ' ')) ?
+ "PRIVMSG %s :\01DCC RESUME \"%s\" %d %u\01\r\n" :
+ "PRIVMSG %s :\01DCC RESUME %s %d %u\01\r\n",
+ ptr_dcc->nick, ptr_dcc->filename,
+ ptr_dcc->port, ptr_dcc->start_resume);
+ dcc_redraw (1);
+ }
+ else
+ dcc_recv_connect_init (ptr_dcc);
+}
+
+/*
+ * dcc_accept_resume: accepts a resume and inform the receiver
+ */
+
+void
+dcc_accept_resume (t_irc_server *server, char *filename, int port,
+ unsigned long pos_start)
+{
+ t_irc_dcc *ptr_dcc;
+
+ ptr_dcc = dcc_search (server, DCC_FILE_SEND, DCC_CONNECTING, port);
+ if (ptr_dcc)
+ {
+ ptr_dcc->pos = pos_start;
+ ptr_dcc->ack = pos_start;
+ ptr_dcc->start_resume = pos_start;
+ ptr_dcc->last_check_pos = pos_start;
+ server_sendf (ptr_dcc->server,
+ (strchr (ptr_dcc->filename, ' ')) ?
+ "PRIVMSG %s :\01DCC ACCEPT \"%s\" %d %u\01\r\n" :
+ "PRIVMSG %s :\01DCC ACCEPT %s %d %u\01\r\n",
+ ptr_dcc->nick, ptr_dcc->filename,
+ ptr_dcc->port, ptr_dcc->start_resume);
+
+ irc_display_prefix (ptr_dcc->server->buffer, PREFIX_INFO);
+ gui_printf (ptr_dcc->server->buffer, _("DCC: file "));
+ gui_printf_color (ptr_dcc->server->buffer,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s ",
+ ptr_dcc->filename);
+ gui_printf (ptr_dcc->server->buffer, _("resumed at position %u\n"),
+ ptr_dcc->start_resume);
+ dcc_redraw (1);
+ }
+ else
+ gui_printf (server->buffer,
+ _("%s can't resume file \"%s\" (port: %d, start position: %u): DCC not found or ended\n"),
+ WEECHAT_ERROR, filename, port, pos_start);
+}
+
+/*
+ * dcc_start_resume: called when "DCC ACCEPT" is received (resume accepted by sender)
+ */
+
+void
+dcc_start_resume (t_irc_server *server, char *filename, int port,
+ unsigned long pos_start)
+{
+ t_irc_dcc *ptr_dcc;
+
+ ptr_dcc = dcc_search (server, DCC_FILE_RECV, DCC_CONNECTING, port);
+ if (ptr_dcc)
+ {
+ ptr_dcc->pos = pos_start;
+ ptr_dcc->ack = pos_start;
+ ptr_dcc->start_resume = pos_start;
+ ptr_dcc->last_check_pos = pos_start;
+ dcc_recv_connect_init (ptr_dcc);
+ }
+ else
+ gui_printf (server->buffer,
+ _("%s can't resume file \"%s\" (port: %d, start position: %u): DCC not found or ended\n"),
+ WEECHAT_ERROR, filename, port, pos_start);
+}
+
+/*
* dcc_add: add a DCC file to queue
*/
@@ -423,15 +582,20 @@ dcc_add (t_irc_server *server, int type, unsigned long addr, int port, char *nic
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->local_filename = NULL;
new_dcc->filename_suffix = -1;
new_dcc->size = size;
new_dcc->pos = 0;
new_dcc->ack = 0;
- new_dcc->last_check_time = 0;
+ new_dcc->start_resume = 0;
+ new_dcc->last_check_time = time (NULL);
new_dcc->last_check_pos = 0;
new_dcc->bytes_per_sec = 0;
new_dcc->last_activity = time (NULL);
+ if (local_filename)
+ new_dcc->local_filename = strdup (local_filename);
+ else
+ dcc_find_filename (new_dcc);
new_dcc->prev_dcc = NULL;
new_dcc->next_dcc = dcc_list;
if (dcc_list)
@@ -457,6 +621,7 @@ dcc_add (t_irc_server *server, int type, unsigned long addr, int port, char *nic
gui_printf (server->buffer, ", ");
gui_printf_color (server->buffer, COLOR_WIN_CHAT_CHANNEL, "%lu", size);
gui_printf (server->buffer, _(" bytes\n"));
+ dcc_redraw (1);
}
if (type == DCC_FILE_SEND)
{
@@ -470,6 +635,7 @@ dcc_add (t_irc_server *server, int type, unsigned long addr, int port, char *nic
gui_printf (server->buffer, "), ");
gui_printf_color (server->buffer, COLOR_WIN_CHAT_CHANNEL, "%lu", size);
gui_printf (server->buffer, _(" bytes\n"));
+ dcc_redraw (1);
}
if (type == DCC_CHAT_RECV)
{
@@ -481,12 +647,40 @@ dcc_add (t_irc_server *server, int type, unsigned long addr, int port, char *nic
"%d.%d.%d.%d",
addr >> 24, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
gui_printf_color (server->buffer, COLOR_WIN_CHAT_DARK, ")\n");
+ dcc_redraw (1);
}
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);
+ dcc_redraw (1);
+ }
+
+ if (DCC_IS_FILE(type) && (!new_dcc->local_filename))
+ {
+ dcc_close (new_dcc, DCC_FAILED);
+ dcc_redraw (1);
+ return NULL;
+ }
+
+ if (DCC_IS_FILE(type) && (new_dcc->start_resume > 0))
+ {
+ irc_display_prefix (new_dcc->server->buffer, PREFIX_INFO);
+ gui_printf (new_dcc->server->buffer, _("DCC: file "));
+ gui_printf_color (new_dcc->server->buffer,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s",
+ new_dcc->filename);
+ gui_printf (new_dcc->server->buffer, _(" (local filename: "));
+ gui_printf_color (new_dcc->server->buffer,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s",
+ new_dcc->local_filename);
+ gui_printf (new_dcc->server->buffer, ") ");
+ gui_printf (new_dcc->server->buffer, _("will be resumed at position %u\n"),
+ new_dcc->start_resume);
+ dcc_redraw (1);
}
/* connect if needed and redraw DCC buffer */
@@ -495,6 +689,7 @@ dcc_add (t_irc_server *server, int type, unsigned long addr, int port, char *nic
if (!dcc_connect (new_dcc))
{
dcc_close (new_dcc, DCC_FAILED);
+ dcc_redraw (1);
return NULL;
}
}
@@ -532,9 +727,9 @@ dcc_send_request (t_irc_server *server, int type, char *nick, char *filename)
if (type == DCC_FILE_SEND)
{
/* add home if filename not beginning with '/' (not for Win32) */
- #ifdef _WIN32
+#ifdef _WIN32
filename2 = strdup (filename);
- #else
+#else
if (filename[0] == '/')
filename2 = strdup (filename);
else
@@ -564,7 +759,7 @@ dcc_send_request (t_irc_server *server, int type, char *nick, char *filename)
strcat (filename2, DIR_SEPARATOR);
strcat (filename2, filename);
}
- #endif
+#endif
/* check if file exists */
if (stat (filename2, &st) == -1)
@@ -719,11 +914,11 @@ dcc_chat_sendf (t_irc_dcc *ptr_dcc, char *fmt, ...)
buffer[sizeof (buffer) - 1] = '\0';
if ((size_buf < 0) || (size_buf > (int) (sizeof (buffer) - 1)))
size_buf = strlen (buffer);
- #ifdef DEBUG
+#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
+#endif
buf2 = weechat_convert_encoding ((cfg_look_charset_internal && cfg_look_charset_internal[0]) ?
cfg_look_charset_internal : local_charset,
cfg_look_charset_encode,
diff --git a/src/irc/irc-recv.c b/src/irc/irc-recv.c
index 85bbbfbc2..55ebfa981 100644
--- a/src/irc/irc-recv.c
+++ b/src/irc/irc-recv.c
@@ -1159,7 +1159,7 @@ int
irc_cmd_recv_privmsg (t_irc_server *server, char *host, char *arguments)
{
char *pos, *pos2, *host2;
- char *pos_file, *pos_addr, *pos_port, *pos_size; /* for DCC */
+ char *pos_file, *pos_addr, *pos_port, *pos_size, *pos_start_resume; /* for DCC */
t_irc_channel *ptr_channel;
t_irc_nick *ptr_nick;
struct utsname *buf;
@@ -1425,6 +1425,120 @@ irc_cmd_recv_privmsg (t_irc_server *server, char *host, char *arguments)
return 0;
}
+ /* incoming DCC RESUME (asked by receiver) */
+ if (strncmp (pos, "\01DCC RESUME", 11) == 0)
+ {
+ /* check if DCC RESUME is ok, i.e. with 0x01 at end */
+ pos2 = strchr (pos + 1, '\01');
+ if (!pos2)
+ {
+ irc_display_prefix (server->buffer, PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2[0] = '\0';
+
+ /* DCC filename */
+ pos_file = pos + 11;
+ while (pos_file[0] == ' ')
+ pos_file++;
+
+ /* look for resume start position */
+ pos_start_resume = strrchr (pos_file, ' ');
+ if (!pos_start_resume)
+ {
+ irc_display_prefix (server->buffer, PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2 = pos_start_resume;
+ pos_start_resume++;
+ while (pos2[0] == ' ')
+ pos2--;
+ pos2[1] = '\0';
+
+ /* look for DCC port */
+ pos_port = strrchr (pos_file, ' ');
+ if (!pos_port)
+ {
+ irc_display_prefix (server->buffer, PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2 = pos_port;
+ pos_port++;
+ while (pos2[0] == ' ')
+ pos2--;
+ pos2[1] = '\0';
+
+ dcc_accept_resume (server, pos_file, atoi (pos_port),
+ (unsigned long) atol (pos_start_resume));
+ return 0;
+ }
+
+ /* incoming DCC ACCEPT (resume accepted by sender) */
+ if (strncmp (pos, "\01DCC ACCEPT", 11) == 0)
+ {
+ /* check if DCC ACCEPT is ok, i.e. with 0x01 at end */
+ pos2 = strchr (pos + 1, '\01');
+ if (!pos2)
+ {
+ irc_display_prefix (server->buffer, PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2[0] = '\0';
+
+ /* DCC filename */
+ pos_file = pos + 11;
+ while (pos_file[0] == ' ')
+ pos_file++;
+
+ /* look for resume start position */
+ pos_start_resume = strrchr (pos_file, ' ');
+ if (!pos_start_resume)
+ {
+ irc_display_prefix (server->buffer, PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2 = pos_start_resume;
+ pos_start_resume++;
+ while (pos2[0] == ' ')
+ pos2--;
+ pos2[1] = '\0';
+
+ /* look for DCC port */
+ pos_port = strrchr (pos_file, ' ');
+ if (!pos_port)
+ {
+ irc_display_prefix (server->buffer, PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2 = pos_port;
+ pos_port++;
+ while (pos2[0] == ' ')
+ pos2--;
+ pos2[1] = '\0';
+
+ dcc_start_resume (server, pos_file, atoi (pos_port),
+ (unsigned long) atol (pos_start_resume));
+ return 0;
+ }
+
/* incoming DCC CHAT */
if (strncmp (pos, "\01DCC CHAT", 9) == 0)
{
diff --git a/src/irc/irc.h b/src/irc/irc.h
index fc379603e..e958b8a96 100644
--- a/src/irc/irc.h
+++ b/src/irc/irc.h
@@ -166,10 +166,10 @@ struct t_irc_server
int child_write; /* to write into child pipe */
int sock; /* socket for server (IPv4 or IPv6) */
int is_connected; /* 1 if WeeChat is connected to server */
- #ifdef HAVE_GNUTLS
+#ifdef HAVE_GNUTLS
int ssl_connected; /* = 1 if connected with SSL */
gnutls_session gnutls_sess; /* gnutls session (only if SSL is used) */
- #endif
+#endif
char *unterminated_message; /* beginning of a message in input buf */
char *nick; /* current nickname */
@@ -242,6 +242,7 @@ struct t_irc_dcc
unsigned long size; /* file size */
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 looked at bytes sent/rcv*/
unsigned long last_check_pos; /* bytes sent/recv at last check */
unsigned long bytes_per_sec; /* bytes per second */
@@ -331,6 +332,8 @@ extern void dcc_redraw (int);
extern void dcc_free (t_irc_dcc *);
extern void dcc_close (t_irc_dcc *, int);
extern void dcc_accept (t_irc_dcc *);
+extern void dcc_accept_resume (t_irc_server *, char *, int, unsigned long);
+extern void dcc_start_resume (t_irc_server *, char *, int, unsigned long);
extern t_irc_dcc *dcc_add (t_irc_server *, int, unsigned long, int, char *, int,
char *, char *, unsigned long);
extern void dcc_send_request (t_irc_server *, int, char *, char *);
diff --git a/weechat/ChangeLog b/weechat/ChangeLog
index 75aab1732..ff578a522 100644
--- a/weechat/ChangeLog
+++ b/weechat/ChangeLog
@@ -1,11 +1,11 @@
WeeChat - Wee Enhanced Environment for Chat
===========================================
-ChangeLog - 2005-07-12
+ChangeLog - 2005-07-13
Versoin 0.1.4 (under dev!):
- * added DCC timeout
+ * added DCC resume and timeout
* added function for Perl/Python to get DCC list
* fixed FIFO pipe (command now authorized on a buffer not connected
to an IRC server)
diff --git a/weechat/src/irc/irc-dcc.c b/weechat/src/irc/irc-dcc.c
index 45de99ab0..6e15ada74 100644
--- a/weechat/src/irc/irc-dcc.c
+++ b/weechat/src/irc/irc-dcc.c
@@ -64,6 +64,133 @@ dcc_redraw (int highlight)
}
/*
+ * dcc_search: search a DCC
+ */
+
+t_irc_dcc *
+dcc_search (t_irc_server *server, int type, int status, int port)
+{
+ t_irc_dcc *ptr_dcc;
+
+ for (ptr_dcc = dcc_list; ptr_dcc; ptr_dcc = ptr_dcc->next_dcc)
+ {
+ if ((ptr_dcc->server == server)
+ && (ptr_dcc->type == type)
+ && (ptr_dcc->status = status)
+ && (ptr_dcc->port == port))
+ return ptr_dcc;
+ }
+
+ /* DCC not found */
+ return NULL;
+}
+
+/*
+ * dcc_file_is_resumable: check if a file can be used for resuming a download
+ */
+
+int
+dcc_file_is_resumable (t_irc_dcc *ptr_dcc, char *filename)
+{
+ struct stat st;
+
+ if (access (filename, W_OK) == 0)
+ {
+ if (stat (filename, &st) != -1)
+ {
+ if ((unsigned long) st.st_size < ptr_dcc->size)
+ {
+ ptr_dcc->start_resume = (unsigned long) st.st_size;
+ ptr_dcc->pos = st.st_size;
+ ptr_dcc->last_check_pos = st.st_size;
+ return 1;
+ }
+ }
+ }
+
+ /* not resumable */
+ return 0;
+}
+
+/*
+ * dcc_find_filename: find local filename for a DCC
+ * if type if file/recv, add a suffix (like .1) if needed
+ * if download is resumable, set "start_resume" to good value
+ */
+
+void
+dcc_find_filename (t_irc_dcc *ptr_dcc)
+{
+ char *ptr_home, *filename2;
+
+ 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)
+ 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)
+ {
+ if (dcc_file_is_resumable (ptr_dcc, ptr_dcc->local_filename))
+ return;
+
+ /* 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);
+ if (access (filename2, F_OK) == 0)
+ {
+ if (dcc_file_is_resumable (ptr_dcc, filename2))
+ break;
+ }
+ else
+ break;
+ }
+ while (1);
+
+ free (ptr_dcc->local_filename);
+ ptr_dcc->local_filename = strdup (filename2);
+ free (filename2);
+ }
+}
+
+/*
* dcc_calculate_speed: calculate DCC speed (for files only)
*/
@@ -81,7 +208,7 @@ dcc_calculate_speed (t_irc_dcc *ptr_dcc, int ended)
elapsed = local_time - ptr_dcc->start_transfer;
if (elapsed == 0)
elapsed = 1;
- ptr_dcc->bytes_per_sec = ptr_dcc->pos / elapsed;
+ ptr_dcc->bytes_per_sec = (ptr_dcc->pos - ptr_dcc->start_resume) / elapsed;
}
else
{
@@ -199,7 +326,7 @@ dcc_close (t_irc_dcc *ptr_dcc, int status)
COLOR_WIN_CHAT_CHANNEL,
"%s",
ptr_dcc->local_filename);
- gui_printf (ptr_dcc->server->buffer, ") ");
+ gui_printf (ptr_dcc->server->buffer, ")");
}
if (ptr_dcc->type == DCC_FILE_SEND)
gui_printf (ptr_dcc->server->buffer, _(" sent to "));
@@ -294,14 +421,12 @@ dcc_channel_for_chat (t_irc_dcc *ptr_dcc)
}
/*
- * dcc_accept: accepts a DCC file or chat request
+ * dcc_recv_connect_init: connect to sender and init file or chat
*/
void
-dcc_accept (t_irc_dcc *ptr_dcc)
+dcc_recv_connect_init (t_irc_dcc *ptr_dcc)
{
- char *ptr_home, *filename2;
-
if (!dcc_connect (ptr_dcc))
{
dcc_close (ptr_dcc, DCC_FAILED);
@@ -314,68 +439,15 @@ dcc_accept (t_irc_dcc *ptr_dcc)
/* DCC file => look for local filename and open it in writing mode */
if (DCC_IS_FILE(ptr_dcc->type))
{
- 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);
- }
+ if (ptr_dcc->start_resume > 0)
+ ptr_dcc->file = open (ptr_dcc->local_filename,
+ O_APPEND | O_WRONLY | O_NONBLOCK);
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)
- {
- /* 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);
- }
- ptr_dcc->file = open (ptr_dcc->local_filename,
- O_CREAT | O_TRUNC | O_WRONLY | O_NONBLOCK,
- 0644);
+ ptr_dcc->file = open (ptr_dcc->local_filename,
+ O_CREAT | O_TRUNC | O_WRONLY | O_NONBLOCK,
+ 0644);
ptr_dcc->start_transfer = time (NULL);
+ ptr_dcc->last_check_time = time (NULL);
}
else
{
@@ -387,6 +459,93 @@ dcc_accept (t_irc_dcc *ptr_dcc)
}
/*
+ * dcc_accept: accepts a DCC file or chat request
+ */
+
+void
+dcc_accept (t_irc_dcc *ptr_dcc)
+{
+ if (DCC_IS_FILE(ptr_dcc->type) && (ptr_dcc->start_resume > 0))
+ {
+ ptr_dcc->status = DCC_CONNECTING;
+ server_sendf (ptr_dcc->server,
+ (strchr (ptr_dcc->filename, ' ')) ?
+ "PRIVMSG %s :\01DCC RESUME \"%s\" %d %u\01\r\n" :
+ "PRIVMSG %s :\01DCC RESUME %s %d %u\01\r\n",
+ ptr_dcc->nick, ptr_dcc->filename,
+ ptr_dcc->port, ptr_dcc->start_resume);
+ dcc_redraw (1);
+ }
+ else
+ dcc_recv_connect_init (ptr_dcc);
+}
+
+/*
+ * dcc_accept_resume: accepts a resume and inform the receiver
+ */
+
+void
+dcc_accept_resume (t_irc_server *server, char *filename, int port,
+ unsigned long pos_start)
+{
+ t_irc_dcc *ptr_dcc;
+
+ ptr_dcc = dcc_search (server, DCC_FILE_SEND, DCC_CONNECTING, port);
+ if (ptr_dcc)
+ {
+ ptr_dcc->pos = pos_start;
+ ptr_dcc->ack = pos_start;
+ ptr_dcc->start_resume = pos_start;
+ ptr_dcc->last_check_pos = pos_start;
+ server_sendf (ptr_dcc->server,
+ (strchr (ptr_dcc->filename, ' ')) ?
+ "PRIVMSG %s :\01DCC ACCEPT \"%s\" %d %u\01\r\n" :
+ "PRIVMSG %s :\01DCC ACCEPT %s %d %u\01\r\n",
+ ptr_dcc->nick, ptr_dcc->filename,
+ ptr_dcc->port, ptr_dcc->start_resume);
+
+ irc_display_prefix (ptr_dcc->server->buffer, PREFIX_INFO);
+ gui_printf (ptr_dcc->server->buffer, _("DCC: file "));
+ gui_printf_color (ptr_dcc->server->buffer,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s ",
+ ptr_dcc->filename);
+ gui_printf (ptr_dcc->server->buffer, _("resumed at position %u\n"),
+ ptr_dcc->start_resume);
+ dcc_redraw (1);
+ }
+ else
+ gui_printf (server->buffer,
+ _("%s can't resume file \"%s\" (port: %d, start position: %u): DCC not found or ended\n"),
+ WEECHAT_ERROR, filename, port, pos_start);
+}
+
+/*
+ * dcc_start_resume: called when "DCC ACCEPT" is received (resume accepted by sender)
+ */
+
+void
+dcc_start_resume (t_irc_server *server, char *filename, int port,
+ unsigned long pos_start)
+{
+ t_irc_dcc *ptr_dcc;
+
+ ptr_dcc = dcc_search (server, DCC_FILE_RECV, DCC_CONNECTING, port);
+ if (ptr_dcc)
+ {
+ ptr_dcc->pos = pos_start;
+ ptr_dcc->ack = pos_start;
+ ptr_dcc->start_resume = pos_start;
+ ptr_dcc->last_check_pos = pos_start;
+ dcc_recv_connect_init (ptr_dcc);
+ }
+ else
+ gui_printf (server->buffer,
+ _("%s can't resume file \"%s\" (port: %d, start position: %u): DCC not found or ended\n"),
+ WEECHAT_ERROR, filename, port, pos_start);
+}
+
+/*
* dcc_add: add a DCC file to queue
*/
@@ -423,15 +582,20 @@ dcc_add (t_irc_server *server, int type, unsigned long addr, int port, char *nic
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->local_filename = NULL;
new_dcc->filename_suffix = -1;
new_dcc->size = size;
new_dcc->pos = 0;
new_dcc->ack = 0;
- new_dcc->last_check_time = 0;
+ new_dcc->start_resume = 0;
+ new_dcc->last_check_time = time (NULL);
new_dcc->last_check_pos = 0;
new_dcc->bytes_per_sec = 0;
new_dcc->last_activity = time (NULL);
+ if (local_filename)
+ new_dcc->local_filename = strdup (local_filename);
+ else
+ dcc_find_filename (new_dcc);
new_dcc->prev_dcc = NULL;
new_dcc->next_dcc = dcc_list;
if (dcc_list)
@@ -457,6 +621,7 @@ dcc_add (t_irc_server *server, int type, unsigned long addr, int port, char *nic
gui_printf (server->buffer, ", ");
gui_printf_color (server->buffer, COLOR_WIN_CHAT_CHANNEL, "%lu", size);
gui_printf (server->buffer, _(" bytes\n"));
+ dcc_redraw (1);
}
if (type == DCC_FILE_SEND)
{
@@ -470,6 +635,7 @@ dcc_add (t_irc_server *server, int type, unsigned long addr, int port, char *nic
gui_printf (server->buffer, "), ");
gui_printf_color (server->buffer, COLOR_WIN_CHAT_CHANNEL, "%lu", size);
gui_printf (server->buffer, _(" bytes\n"));
+ dcc_redraw (1);
}
if (type == DCC_CHAT_RECV)
{
@@ -481,12 +647,40 @@ dcc_add (t_irc_server *server, int type, unsigned long addr, int port, char *nic
"%d.%d.%d.%d",
addr >> 24, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
gui_printf_color (server->buffer, COLOR_WIN_CHAT_DARK, ")\n");
+ dcc_redraw (1);
}
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);
+ dcc_redraw (1);
+ }
+
+ if (DCC_IS_FILE(type) && (!new_dcc->local_filename))
+ {
+ dcc_close (new_dcc, DCC_FAILED);
+ dcc_redraw (1);
+ return NULL;
+ }
+
+ if (DCC_IS_FILE(type) && (new_dcc->start_resume > 0))
+ {
+ irc_display_prefix (new_dcc->server->buffer, PREFIX_INFO);
+ gui_printf (new_dcc->server->buffer, _("DCC: file "));
+ gui_printf_color (new_dcc->server->buffer,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s",
+ new_dcc->filename);
+ gui_printf (new_dcc->server->buffer, _(" (local filename: "));
+ gui_printf_color (new_dcc->server->buffer,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s",
+ new_dcc->local_filename);
+ gui_printf (new_dcc->server->buffer, ") ");
+ gui_printf (new_dcc->server->buffer, _("will be resumed at position %u\n"),
+ new_dcc->start_resume);
+ dcc_redraw (1);
}
/* connect if needed and redraw DCC buffer */
@@ -495,6 +689,7 @@ dcc_add (t_irc_server *server, int type, unsigned long addr, int port, char *nic
if (!dcc_connect (new_dcc))
{
dcc_close (new_dcc, DCC_FAILED);
+ dcc_redraw (1);
return NULL;
}
}
@@ -532,9 +727,9 @@ dcc_send_request (t_irc_server *server, int type, char *nick, char *filename)
if (type == DCC_FILE_SEND)
{
/* add home if filename not beginning with '/' (not for Win32) */
- #ifdef _WIN32
+#ifdef _WIN32
filename2 = strdup (filename);
- #else
+#else
if (filename[0] == '/')
filename2 = strdup (filename);
else
@@ -564,7 +759,7 @@ dcc_send_request (t_irc_server *server, int type, char *nick, char *filename)
strcat (filename2, DIR_SEPARATOR);
strcat (filename2, filename);
}
- #endif
+#endif
/* check if file exists */
if (stat (filename2, &st) == -1)
@@ -719,11 +914,11 @@ dcc_chat_sendf (t_irc_dcc *ptr_dcc, char *fmt, ...)
buffer[sizeof (buffer) - 1] = '\0';
if ((size_buf < 0) || (size_buf > (int) (sizeof (buffer) - 1)))
size_buf = strlen (buffer);
- #ifdef DEBUG
+#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
+#endif
buf2 = weechat_convert_encoding ((cfg_look_charset_internal && cfg_look_charset_internal[0]) ?
cfg_look_charset_internal : local_charset,
cfg_look_charset_encode,
diff --git a/weechat/src/irc/irc-recv.c b/weechat/src/irc/irc-recv.c
index 85bbbfbc2..55ebfa981 100644
--- a/weechat/src/irc/irc-recv.c
+++ b/weechat/src/irc/irc-recv.c
@@ -1159,7 +1159,7 @@ int
irc_cmd_recv_privmsg (t_irc_server *server, char *host, char *arguments)
{
char *pos, *pos2, *host2;
- char *pos_file, *pos_addr, *pos_port, *pos_size; /* for DCC */
+ char *pos_file, *pos_addr, *pos_port, *pos_size, *pos_start_resume; /* for DCC */
t_irc_channel *ptr_channel;
t_irc_nick *ptr_nick;
struct utsname *buf;
@@ -1425,6 +1425,120 @@ irc_cmd_recv_privmsg (t_irc_server *server, char *host, char *arguments)
return 0;
}
+ /* incoming DCC RESUME (asked by receiver) */
+ if (strncmp (pos, "\01DCC RESUME", 11) == 0)
+ {
+ /* check if DCC RESUME is ok, i.e. with 0x01 at end */
+ pos2 = strchr (pos + 1, '\01');
+ if (!pos2)
+ {
+ irc_display_prefix (server->buffer, PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2[0] = '\0';
+
+ /* DCC filename */
+ pos_file = pos + 11;
+ while (pos_file[0] == ' ')
+ pos_file++;
+
+ /* look for resume start position */
+ pos_start_resume = strrchr (pos_file, ' ');
+ if (!pos_start_resume)
+ {
+ irc_display_prefix (server->buffer, PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2 = pos_start_resume;
+ pos_start_resume++;
+ while (pos2[0] == ' ')
+ pos2--;
+ pos2[1] = '\0';
+
+ /* look for DCC port */
+ pos_port = strrchr (pos_file, ' ');
+ if (!pos_port)
+ {
+ irc_display_prefix (server->buffer, PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2 = pos_port;
+ pos_port++;
+ while (pos2[0] == ' ')
+ pos2--;
+ pos2[1] = '\0';
+
+ dcc_accept_resume (server, pos_file, atoi (pos_port),
+ (unsigned long) atol (pos_start_resume));
+ return 0;
+ }
+
+ /* incoming DCC ACCEPT (resume accepted by sender) */
+ if (strncmp (pos, "\01DCC ACCEPT", 11) == 0)
+ {
+ /* check if DCC ACCEPT is ok, i.e. with 0x01 at end */
+ pos2 = strchr (pos + 1, '\01');
+ if (!pos2)
+ {
+ irc_display_prefix (server->buffer, PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2[0] = '\0';
+
+ /* DCC filename */
+ pos_file = pos + 11;
+ while (pos_file[0] == ' ')
+ pos_file++;
+
+ /* look for resume start position */
+ pos_start_resume = strrchr (pos_file, ' ');
+ if (!pos_start_resume)
+ {
+ irc_display_prefix (server->buffer, PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2 = pos_start_resume;
+ pos_start_resume++;
+ while (pos2[0] == ' ')
+ pos2--;
+ pos2[1] = '\0';
+
+ /* look for DCC port */
+ pos_port = strrchr (pos_file, ' ');
+ if (!pos_port)
+ {
+ irc_display_prefix (server->buffer, PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2 = pos_port;
+ pos_port++;
+ while (pos2[0] == ' ')
+ pos2--;
+ pos2[1] = '\0';
+
+ dcc_start_resume (server, pos_file, atoi (pos_port),
+ (unsigned long) atol (pos_start_resume));
+ return 0;
+ }
+
/* incoming DCC CHAT */
if (strncmp (pos, "\01DCC CHAT", 9) == 0)
{
diff --git a/weechat/src/irc/irc.h b/weechat/src/irc/irc.h
index fc379603e..e958b8a96 100644
--- a/weechat/src/irc/irc.h
+++ b/weechat/src/irc/irc.h
@@ -166,10 +166,10 @@ struct t_irc_server
int child_write; /* to write into child pipe */
int sock; /* socket for server (IPv4 or IPv6) */
int is_connected; /* 1 if WeeChat is connected to server */
- #ifdef HAVE_GNUTLS
+#ifdef HAVE_GNUTLS
int ssl_connected; /* = 1 if connected with SSL */
gnutls_session gnutls_sess; /* gnutls session (only if SSL is used) */
- #endif
+#endif
char *unterminated_message; /* beginning of a message in input buf */
char *nick; /* current nickname */
@@ -242,6 +242,7 @@ struct t_irc_dcc
unsigned long size; /* file size */
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 looked at bytes sent/rcv*/
unsigned long last_check_pos; /* bytes sent/recv at last check */
unsigned long bytes_per_sec; /* bytes per second */
@@ -331,6 +332,8 @@ extern void dcc_redraw (int);
extern void dcc_free (t_irc_dcc *);
extern void dcc_close (t_irc_dcc *, int);
extern void dcc_accept (t_irc_dcc *);
+extern void dcc_accept_resume (t_irc_server *, char *, int, unsigned long);
+extern void dcc_start_resume (t_irc_server *, char *, int, unsigned long);
extern t_irc_dcc *dcc_add (t_irc_server *, int, unsigned long, int, char *, int,
char *, char *, unsigned long);
extern void dcc_send_request (t_irc_server *, int, char *, char *);