diff -ur irssi-0.8.4.orig/src/irc/dcc/dcc-rec.h irssi-0.8.4/src/irc/dcc/dcc-rec.h --- irssi-0.8.4.orig/src/irc/dcc/dcc-rec.h Mon Feb 19 04:40:06 2001 +++ irssi-0.8.4/src/irc/dcc/dcc-rec.h Thu Mar 14 02:20:25 2002 @@ -20,6 +20,12 @@ time_t starttime; /* transfer start time */ uoff_t transfd; /* bytes transferred */ +int timeout_tag; + +unsigned long skip_bytes; +unsigned long limit_starttime; +unsigned long max_speed; + unsigned int destroyed:1; /* We're about to destroy this DCC recond */ GHashTable *module_data; diff -ur irssi-0.8.4.orig/src/irc/dcc/dcc-send.c irssi-0.8.4/src/irc/dcc/dcc-send.c --- irssi-0.8.4.orig/src/irc/dcc/dcc-send.c Sun Jan 20 04:10:27 2002 +++ irssi-0.8.4/src/irc/dcc/dcc-send.c Thu Mar 14 02:21:22 2002 @@ -217,17 +217,87 @@ { if (!IS_DCC_SEND(dcc)) return; + if (dcc->timeout_tag != -1) + g_source_remove(dcc->timeout_tag); + if (dcc->fhandle != -1) close(dcc->fhandle); dcc_queue_send_next(dcc->queue); } +static int sent_too_much(SEND_DCC_REC *dcc) +{ + GTimeVal gtv; + gulong timediff, curtime; + gulong transfd, speed; + + /* 0 == unlimited speed */ + if (dcc->max_speed == 0) return 0; + + /* get time difference in milliseconds */ + g_get_current_time(>v); + curtime = (gtv.tv_sec * 1000) + (gtv.tv_usec / 1000); + + transfd = (dcc->transfd - dcc->skip_bytes); + timediff = curtime - dcc->limit_starttime + 1; + speed = ((transfd * 1000) / timediff); + + /* reset speed counter every 30 seconds */ + if (timediff >= 30000) { + dcc->limit_starttime = curtime; + dcc->skip_bytes = dcc->transfd; + } + + return (speed > (dcc->max_speed * 1024)); +} + +static void dcc_send_data(SEND_DCC_REC *dcc); + +static void reset_dcc_send(SEND_DCC_REC *dcc) +{ + if (g_slist_find(dcc_conns, dcc) == NULL) { + /* the DCC was closed during the wait */ + return; + } + + if (dcc->timeout_tag != -1) + g_source_remove(dcc->timeout_tag); + dcc->timeout_tag = -1; + + dcc->tagwrite = g_input_add(dcc->handle, G_INPUT_WRITE, + (GInputFunction) dcc_send_data, dcc); + + return; +} + /* input function: DCC SEND - we're ready to send more data */ static void dcc_send_data(SEND_DCC_REC *dcc) { char buffer[512]; - int ret; + int ret, max_speed; + GTimeVal gtv; + + max_speed = settings_get_int("dcc_send_top_speed"); + if (max_speed != dcc->max_speed) { + /* speed setting has changed, calculate speed from current position + instead of from the start to eliminate speed boosts/slowdowns */ + + dcc->max_speed = max_speed; + dcc->skip_bytes = dcc->transfd; + + g_get_current_time(>v); + dcc->limit_starttime = (gtv.tv_sec * 1000) + (gtv.tv_usec / 1000); + } + + if (sent_too_much(dcc)) { + /* disable calling this function for 1/10th of a second. */ + g_source_remove(dcc->tagwrite); + dcc->tagwrite = -1; + dcc->timeout_tag = g_timeout_add(100, (GSourceFunc) + reset_dcc_send, dcc); + return; + } ret = read(dcc->fhandle, buffer, sizeof(buffer)); if (ret <= 0) { @@ -282,6 +352,7 @@ GIOChannel *handle; IPADDR addr; int port; + GTimeVal gtv; /* accept connection */ handle = net_accept(dcc->handle, &addr, &port); @@ -296,6 +366,13 @@ g_source_remove(dcc->tagconn); dcc->tagconn = -1; + dcc->skip_bytes = 0; + dcc->max_speed = settings_get_int("dcc_send_top_speed"); + + /* get starttime in milliseconds */ + g_get_current_time(>v); + dcc->limit_starttime = (gtv.tv_sec * 1000) + (gtv.tv_usec / 1000); + dcc->starttime = time(NULL); dcc->handle = handle; memcpy(&dcc->addr, &addr, sizeof(IPADDR)); @@ -429,6 +429,7 @@ dcc->size = st.st_size; dcc->fhandle = hfile; dcc->queue = queue; + dcc->timeout_tag = -1; dcc->file_quoted = strchr(fname, ' ') != NULL; if (!passive) { dcc->tagconn = g_input_add(handle, G_INPUT_READ, @@ -412,6 +490,7 @@ dcc_register_type("SEND"); settings_add_str("dcc", "dcc_upload_path", "~"); settings_add_bool("dcc", "dcc_send_replace_space_with_underscore", FALSE); + settings_add_int("dcc", "dcc_send_top_speed", 0); signal_add("dcc destroyed", (SIGNAL_FUNC) sig_dcc_destroyed); command_bind("dcc send", NULL, (SIGNAL_FUNC) cmd_dcc_send); command_set_options("dcc send", "append flush prepend rmhead rmtail");