diff -ur irssi-0.7.98.4/src/irc/dcc/dcc-rec.h irssi-0.7.98.4.limited/src/irc/dcc/dcc-rec.h --- irssi-0.7.98.4/src/irc/dcc/dcc-rec.h Mon Feb 19 04:40:06 2001 +++ irssi-0.7.98.4.limited/src/irc/dcc/dcc-rec.h Sat Jan 19 19:40:16 2002 @@ -20,6 +20,12 @@ time_t starttime; /* transfer start time */ unsigned long 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.7.98.4/src/irc/dcc/dcc-send.c irssi-0.7.98.4.limited/src/irc/dcc/dcc-send.c --- irssi-0.7.98.4/src/irc/dcc/dcc-send.c Wed Feb 28 20:26:21 2001 +++ irssi-0.7.98.4.limited/src/irc/dcc/dcc-send.c Sat Jan 19 19:43:15 2002 @@ -48,14 +48,83 @@ { if (!IS_DCC_SEND(dcc)) return; + if (dcc->timeout_tag != -1) + g_source_remove(dcc->timeout_tag); + if (dcc->fhandle != -1) close(dcc->fhandle); } +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; + } + + 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) { @@ -116,6 +185,7 @@ GIOChannel *handle; IPADDR addr; int port; + GTimeVal gtv; /* accept connection */ handle = net_accept(dcc->handle, &addr, &port); @@ -129,6 +199,14 @@ g_source_remove(dcc->tagconn); net_disconnect(dcc->handle); + dcc->timeout_tag = -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)); @@ -246,6 +324,7 @@ { dcc_register_type("SEND"); settings_add_str("dcc", "dcc_upload_path", "~"); + 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);