diff --git a/trunk/src/common/dcc.c b/trunk/src/common/dcc.c index 89b57d9..6c08d33 100644 --- a/trunk/src/common/dcc.c +++ b/trunk/src/common/dcc.c @@ -170,7 +170,7 @@ void dcc_check_timeouts (void) { struct DCC *dcc; - time_t tim = time (0); + time_t tim = time (NULL); GSList *next, *list = dcc_list; while (list) diff --git a/trunk/src/common/ignore.c b/trunk/src/common/ignore.c index 960cb44..9d0372a 100644 --- a/trunk/src/common/ignore.c +++ b/trunk/src/common/ignore.c @@ -313,14 +313,11 @@ flood_check (char *nick, char *host, server *serv, rage_session *sess, int what) if (what == 0 ) { value = 10; - if (prefs.ctcp_number_limit > 0 && gen_parm_throttle (&serv->ctcp_counter, &value, &value, - &prefs.ctcp_number_limit, &serv->ctcp_last_time)) + if (prefs.ctcp_number_limit > 0 && + queue_count(serv, nick, 2) > prefs.ctcp_number_limit) { char *tmp = strchr(host, '@'); snprintf (real_ip, sizeof (real_ip), "*!*%s", tmp); - - serv->ctcp_counter = 0; - snprintf (buf, sizeof (buf), _("You are being CTCP flooded from %s, ignoring %s\n"), nick, real_ip); diff --git a/trunk/src/common/modes.c b/trunk/src/common/modes.c index 17b3388..1de4797 100644 --- a/trunk/src/common/modes.c +++ b/trunk/src/common/modes.c @@ -679,7 +679,7 @@ run_005 (server * serv) } if((pre = get_isupport(serv, "NAMESX"))) - tcp_send_len (serv, "PROTOCTL NAMESX\r\n", 17); + send_command (serv, NULL, "PROTOCTL NAMESX\r\n"); if((pre = get_isupport(serv, "NETWORK"))) { @@ -691,6 +691,6 @@ run_005 (server * serv) } if(isupport(serv, "CAPAB")) /* after this we get a 290 numeric reply */ - tcp_send_len (serv, "CAPAB IDENTIFY-MSG\r\n", 20); + send_command (serv, NULL, "CAPAB IDENTIFY-MSG\r\n"); } diff --git a/trunk/src/common/proto-irc.c b/trunk/src/common/proto-irc.c index df3c92b..7548a22 100644 --- a/trunk/src/common/proto-irc.c +++ b/trunk/src/common/proto-irc.c @@ -29,17 +29,17 @@ irc_login (server *serv, char *user, char *realname) char hostname[128]; if (serv->password[0]) - tcp_sendf (serv, "PASS %s\r\n", serv->password); + send_commandf (serv, NULL, "PASS %s\r\n", serv->password); gethostname (hostname, sizeof (hostname) - 1); hostname[sizeof (hostname) - 1] = 0; if (hostname[0] == 0) strcpy (hostname, "0"); - tcp_sendf (serv, - "NICK %s\r\n" - "USER %s %s %s :%s\r\n", - serv->nick, user, hostname, serv->servername, realname); + send_commandf (serv, NULL, + "NICK %s\r\n" + "USER %s %s %s :%s\r\n", + serv->nick, user, hostname, serv->servername, realname); } static void @@ -49,13 +49,14 @@ irc_nickserv (server *serv, char *pass) switch (serv->nickservtype) { case 0: - tcp_sendf (serv, "PRIVMSG NickServ :identify %s\r\n", pass); + send_commandf (serv, "NickServ", + "PRIVMSG NickServ :identify %s\r\n", pass); break; case 1: - tcp_sendf (serv, "NICKSERV :identify %s\r\n", pass); + send_commandf (serv, NULL, "NICKSERV :identify %s\r\n", pass); break; case 2: - tcp_sendf (serv, "NS :identify %s\r\n", pass); + send_commandf (serv, NULL, "NS :identify %s\r\n", pass); } } @@ -63,78 +64,78 @@ static void irc_join (server *serv, char *channel, char *key) { if (key[0]) - tcp_sendf (serv, "JOIN %s %s\r\n", channel, key); + send_commandf (serv, channel, "JOIN %s %s\r\n", channel, key); else - tcp_sendf (serv, "JOIN %s\r\n", channel); + send_commandf (serv, channel, "JOIN %s\r\n", channel); } static void irc_part (server *serv, char *channel, char *reason) { if (reason[0]) - tcp_sendf (serv, "PART %s :%s\r\n", channel, reason); + send_commandf (serv, NULL, "PART %s :%s\r\n", channel, reason); else - tcp_sendf (serv, "PART %s\r\n", channel); + send_commandf (serv, NULL, "PART %s\r\n", channel); } static void irc_quit (server *serv, char *reason) { if (reason[0]) - tcp_sendf (serv, "QUIT :%s\r\n", reason); + send_commandf (serv, NULL, "QUIT :%s\r\n", reason); else - tcp_send_len (serv, "QUIT\r\n", 6); + send_command (serv, NULL, "QUIT\r\n"); } static void irc_set_back (server *serv) { - tcp_send_len (serv, "AWAY\r\n", 6); + send_command (serv, NULL, "AWAY\r\n"); } static void irc_set_away (server *serv, char *reason) { - tcp_sendf (serv, "AWAY :%s\r\n", reason); + send_commandf (serv, NULL, "AWAY :%s\r\n", reason); } static void irc_ctcp (server *serv, char *to, char *msg) { - tcp_sendf (serv, "PRIVMSG %s :\001%s\001\r\n", to, msg); + send_messagef (serv, to, "\001%s\001\r\n", msg); } static void irc_nctcp (server *serv, char *to, char *msg) { - tcp_sendf (serv, "NOTICE %s :\001%s\001\r\n", to, msg); + send_replyf (serv, to, "\001%s\001\r\n", msg); } static void irc_cycle (server *serv, char *channel, char *key) { - tcp_sendf (serv, "PART %s\r\nJOIN %s %s\r\n", channel, channel, key); + send_commandf (serv, NULL, "PART %s\r\nJOIN %s %s\r\n", channel, channel, key); } static void irc_kick (server *serv, char *channel, char *nick, char *reason) { if (reason[0]) - tcp_sendf (serv, "KICK %s %s :%s\r\n", channel, nick, reason); + send_commandf (serv, nick, "KICK %s %s :%s\r\n", channel, nick, reason); else - tcp_sendf (serv, "KICK %s %s\r\n", channel, nick); + send_commandf (serv, nick, "KICK %s %s\r\n", channel, nick); } static void irc_invite (server *serv, char *channel, char *nick) { - tcp_sendf (serv, "INVITE %s %s\r\n", nick, channel); + send_commandf (serv, nick, "INVITE %s %s\r\n", nick, channel); } static void irc_mode (server *serv, char *target, char *mode) { - tcp_sendf (serv, "MODE %s %s\r\n", target, mode); + send_commandf (serv, target, "MODE %s %s\r\n", target, mode); } /* find channel info when joined */ @@ -142,7 +143,7 @@ irc_mode (server *serv, char *target, char *mode) static void irc_join_info (server *serv, char *channel) { - tcp_sendf (serv, "MODE %s\r\n", channel); + send_commandf (serv, channel, "MODE %s\r\n", channel); } /* initiate userlist retreival */ @@ -150,7 +151,7 @@ irc_join_info (server *serv, char *channel) static void irc_user_list (server *serv, char *channel) { - tcp_sendf (serv, "WHO %s\r\n", channel); + send_commandf (serv, channel, "WHO %s\r\n", channel); } /* userhost */ @@ -158,22 +159,22 @@ irc_user_list (server *serv, char *channel) static void irc_userhost (server *serv, char *nick) { - tcp_sendf (serv, "USERHOST %s\r\n", nick); + send_commandf (serv, nick, "USERHOST %s\r\n", nick); } static void irc_away_status (server *serv, char *channel) { if (isupport(serv, "WHOX")) - tcp_sendf (serv, "WHO %s %%ctnf,152\r\n", channel); + send_commandf (serv, channel, "WHO %s %%ctnf,152\r\n", channel); else - tcp_sendf (serv, "WHO %s\r\n", channel); + send_commandf (serv, channel, "WHO %s\r\n", channel); } /*static void irc_get_ip (server *serv, char *nick) { - tcp_sendf (serv, "WHO %s\r\n", nick); + tcp__nomatch__sendf (serv, "WHO %s\r\n", nick); }*/ @@ -184,7 +185,8 @@ irc_get_ip (server *serv, char *nick) static void irc_user_whois (server *serv, char *nicks) { - tcp_sendf (serv, "WHOIS %s\r\n", nicks); + /* FIXME: should this be fixed in a better way? */ + send_commandf (serv, NULL, "WHOIS %s\r\n", nicks); } static void @@ -194,18 +196,15 @@ irc_message (server *serv, char *channel, char *text) /* Make sure it's not a channel then check if the front session * has whats needed for cmsg */ if (isupport(serv, "CPRIVMSG") && find_ctarget(serv, targetchan, channel)) - { - tcp_sendf (serv, "CPRIVMSG %s %s :%s\r\n", channel, - targetchan, text); - } + send_cmessagef (serv, channel, targetchan, "%s\r\n", text); else - tcp_sendf (serv, "PRIVMSG %s :%s\r\n", channel, text); + send_messagef (serv, channel, "%s\r\n", text); } static void irc_action (server *serv, char *channel, char *act) { - tcp_sendf (serv, "PRIVMSG %s :\001ACTION %s\001\r\n", channel, act); + send_messagef (serv, channel, "\001ACTION %s\001\r\n", act); } static void @@ -215,23 +214,20 @@ irc_notice (server *serv, char *channel, char *text) /* Make sure it's not a channel then check if the front session * has whats needed for cnotice */ if (isupport(serv, "CNOTICE") && find_ctarget(serv, targetchan, channel)) - { - tcp_sendf (serv, "CNOTICE %s %s :%s\r\n", channel, - targetchan, text); - } + send_cnoticef (serv, channel, targetchan, "%s\r\n", text); else - tcp_sendf (serv, "NOTICE %s :%s\r\n", channel, text); + send_noticef (serv, channel, "%s\r\n", text); } static void irc_topic (server *serv, char *channel, char *topic) { - if (!topic) - tcp_sendf (serv, "TOPIC %s :\r\n", channel); + if (!topic) /* Used by fe-gtk to clear a topic. */ + send_commandf (serv, channel, "TOPIC %s :\r\n", channel); else if (topic[0]) - tcp_sendf (serv, "TOPIC %s :%s\r\n", channel, topic); + send_commandf (serv, channel, "TOPIC %s :%s\r\n", channel, topic); else - tcp_sendf (serv, "TOPIC %s\r\n", channel); + send_commandf (serv, channel, "TOPIC %s\r\n", channel); } static void @@ -239,55 +235,54 @@ irc_list_channels (server *serv, char *arg) { if (arg[0]) { - tcp_sendf (serv, "LIST %s\r\n", arg); + send_commandf (serv, NULL, "LIST %s\r\n", arg); return; } if (serv->use_listargs) /* 1234567890123456 */ - tcp_send_len (serv, "LIST >0,<10000\r\n", 16); + send_command (serv, NULL, "LIST >0,<10000\r\n"); else - tcp_send_len (serv, "LIST\r\n", 6); + send_command (serv, NULL, "LIST\r\n"); } static void irc_names (server *serv, char *channel) { - tcp_sendf (serv, "NAMES %s\r\n", channel); + send_commandf (serv, channel, "NAMES %s\r\n", channel); } static void irc_change_nick (server *serv, char *new_nick) { - tcp_sendf (serv, "NICK %s\r\n", new_nick); + send_commandf (serv, NULL, "NICK %s\r\n", new_nick); } static void irc_ping (server *serv, char *to, char *timestring) { if (*to) - tcp_sendf (serv, "PRIVMSG %s :\001PING %s\001\r\n", to, timestring); + send_messagef (serv, to, "\001PING %s\001\r\n", timestring); else - tcp_sendf (serv, "PING %s\r\n", timestring); + send_commandf (serv, NULL, "PING %s\r\n", timestring); } static int irc_raw (server *serv, char *raw) { - size_t len; - char tbuf[4096]; + char tbuf[1024]; if (*raw) { - len = strlen (raw); +/* len = strlen (raw); if (len < sizeof (tbuf) - 3) + { */ + snprintf (tbuf, sizeof (tbuf), "%s\r\n", raw); + send_command (serv, NULL, tbuf); +/* pomcode } else // disabled for now { - len = snprintf (tbuf, sizeof (tbuf), "%s\r\n", raw); - tcp_send_len (serv, tbuf, (int)len); - } else - { - tcp_send_len (serv, raw, (int)len); - tcp_send_len (serv, "\r\n", 2); - } + tcp__nomatch__send_len (serv, raw, (int)len); + tcp__nomatch__send_len (serv, "\r\n", 2); + } */ return TRUE; } return FALSE; @@ -807,6 +802,12 @@ PARSE_FUNC(numeric_endofmotd) return 1; } +PARSE_FUNC(numeric_nosuchtarget) +{ + queue_remove_target(sess->server, parv[3]); + return 0; +} + PARSE_FUNC(numeric_nicknameinuse) { if (sess->server->end_of_motd) @@ -913,6 +914,9 @@ static ircparser_numeric irc_numerics[] = { {RPL_MOTD, numeric_motd}, /* 372 */ {RPL_MOTDSTART, numeric_motd}, /* 375 */ {RPL_ENDOFMOTD, numeric_endofmotd}, /* 376 */ + {ERR_NOSUCHNICK, numeric_nosuchtarget}, /* 401 */ + {ERR_NOSUCHCHANNEL, numeric_nosuchtarget}, /* 403 */ + {ERR_CANNOTSENDTOCHAN, numeric_nosuchtarget}, /* 404 */ {ERR_NOMOTD, numeric_endofmotd}, /* 422 */ {ERR_NICKNAMEINUSE, numeric_nicknameinuse}, /* 433 */ {ERR_BANNICKCHANGE, numeric_bannickchange}, /* 437 */ @@ -964,6 +968,7 @@ PARSE_FUNC(servermsg_mode) PARSE_FUNC(servermsg_nick) { inbound_newnick(sess->server,nick,parv[2],FALSE); + queue_target_change(sess->server, nick, parv[2]); return 1; } @@ -1082,6 +1087,7 @@ PARSE_FUNC(servermsg_pong) PARSE_FUNC(servermsg_quit) { inbound_quit(sess->server, nick, ip, parv[2]); + queue_remove_target(sess->server, nick); return 1; } @@ -1121,7 +1127,7 @@ PARSE_FUNC(servermsg_wallops) PARSE_FUNC(servermsg_ping) { - tcp_sendf(sess->server, "PONG %s\r\n", parv[2]); + send_commandf (sess->server, NULL, "PONG %s\r\n", parv[2]); return 0; } diff --git a/trunk/src/common/rage_data.h b/trunk/src/common/rage_data.h index bfab299..b615c26 100644 --- a/trunk/src/common/rage_data.h +++ b/trunk/src/common/rage_data.h @@ -8,6 +8,7 @@ #ifndef XCHAT_H #define XCHAT_H +#include #include "history.h" #ifndef WIN32 #include "../../config.h" @@ -395,7 +396,13 @@ typedef struct server void *network; /* points to entry in servlist.c or NULL! */ - GSList *outbound_queue; + /* things relating to the queue including leaky bucket + * throttling and the timer. */ + time_t queue_time; + int queue_level; + guint queue_timer; + GQueue *out_queue[3]; + time_t next_send; /* cptr->since in ircu */ time_t prev_now; /* previous now-time */ int sendq_len; /* queue size */ diff --git a/trunk/src/common/server.c b/trunk/src/common/server.c index 605839f..a3a1d27 100644 --- a/trunk/src/common/server.c +++ b/trunk/src/common/server.c @@ -18,6 +18,17 @@ #include "rage.h" +enum { + QUEUE_COMMAND, QUEUE_MESSAGE, QUEUE_REPLY, QUEUE_NOTICE, + QUEUE_CMESSAGE, QUEUE_CNOTICE +}; + +typedef struct queued_msg { + char *msg; + char *target; + int len; +} queued_msg; + static void auto_reconnect (server *serv, int send_quit, int err); static void server_disconnect (rage_session * sess, int sendquit, int err); static int server_cleanup (server * serv); @@ -26,177 +37,375 @@ static void server_connect (server *serv, char *hostname, int port, int no_login static rage_session *g_sess = NULL; #endif -/* actually send to the socket. This might do a character translation or - send via SSL */ +struct it_check_data { char *old_target; char *new_target; }; -static int -tcp_send_real (server *serv, char *buf, int len) +/* Iterator used to change the target for all data that should go to + * the old target */ +static void +queue_rename_target_it(gpointer data, gpointer user_data) { - int ret; - char *locale; - gsize loc_len; + queued_msg *msg = (queued_msg *)data; + struct it_check_data *it = (struct it_check_data *)user_data; + if (msg->target && strcasecmp(msg->target, it->old_target) == 0) + { + g_free(msg->target); + msg->target = g_strdup(it->new_target); + } +} - fe_add_rawlog (serv, buf, len, TRUE); +/* Change target for all data matching the old target */ +void +queue_target_change(server *serv, char *old_target, char *new_target) +{ + struct it_check_data it = {old_target, new_target}; + int i; + + for (i = 0; i < 3; i++) + { + if (!g_queue_is_empty(serv->out_queue[i])) /* ->length > 0) */ + g_queue_foreach(serv->out_queue[i], + queue_rename_target_it, &it); + } +} - if (serv->encoding == NULL) /* system */ +struct it_remove_data { GQueue *queue; char *target; }; + +/* Iterator used to remove all data to a specific target */ +static void +queue_remove_target_it(gpointer data, gpointer user_data) +{ + queued_msg *msg = (queued_msg *)data; + struct it_remove_data *it = (struct it_remove_data *)user_data; + + if (msg->target && strcasecmp(msg->target, it->target) == 0) + g_queue_remove(it->queue, data); +} + +/* Remove all queued data for a specific target */ +void +queue_remove_target(server *serv, char *target) +{ + struct it_remove_data it = {NULL, target}; + int i; + + for (i = 0; i < 3; i++) { - locale = NULL; - if (!prefs.utf8_locale) + if (!g_queue_is_empty(serv->out_queue[i])) /* ->length > 0) */ { - const gchar *charset; - - g_get_charset (&charset); - locale = g_convert_with_fallback (buf, len, charset, "UTF-8", - "?", 0, &loc_len, 0); + it.queue = serv->out_queue[i]; + g_queue_foreach(serv->out_queue[i], + queue_remove_target_it, &it); } - } else - { - locale = g_convert_with_fallback (buf, len, serv->encoding, "UTF-8", - "?", 0, &loc_len, 0); } +} - if (locale) - { - len = loc_len; -#ifdef USE_OPENSSL - if (!serv->ssl) - ret = send (serv->sok, locale, len, 0); - else - ret = _SSL_send (serv->ssl, locale, len); -#else - ret = send (serv->sok, locale, len, 0); -#endif - g_free (locale); - } else +void +queue_clean_it(gpointer data, gpointer user_data) +{ + GQueue *q = (GQueue *)user_data; + queued_msg *msg = (queued_msg *)data; + + g_queue_remove(q, data); + g_free(msg->target); + g_free(msg->msg); + g_free(msg); +} + +void +queue_clean(server *serv) +{ + int i; + + for (i = 0; i < 3; i++) { -#ifdef USE_OPENSSL - if (!serv->ssl) - ret = send (serv->sok, buf, len, 0); - else - ret = _SSL_send (serv->ssl, buf, len); -#else - ret = send (serv->sok, buf, len, 0); -#endif + if (!g_queue_is_empty(serv->out_queue[i])) + g_queue_foreach(serv->out_queue[i], + queue_clean_it, serv->out_queue[i]); } +} - return ret; +struct it_count_data {char *target; int count; }; + +void +queue_count_it(gpointer data, gpointer user_data) +{ + queued_msg *msg = (queued_msg *)data; + struct it_count_data *it = (struct it_count_data *)user_data; + + if (msg->target && strcasecmp(msg->target, it->target) == 0) + it->count++; } -/* new throttling system, uses the same method as the Undernet - ircu2.10 server; under test, a 200-line paste didn't flood - off the client */ +int +queue_count(server *serv, char *target, int queue) +{ + struct it_count_data it = {target, 0 }; + + if (!g_queue_is_empty(serv->out_queue[queue])) + g_queue_foreach(serv->out_queue[queue], + queue_count_it, &it); + return it.count; +} +/* actually send to the socket. This might do a character translation or + send via SSL */ static int -tcp_send_queue (server *serv) +tcp_send_data (server *serv, queued_msg *msg) { - char *buf, *p; - size_t len; - int i, pri; - GSList *list; - time_t now = time (0); + int ret; - /* did the server close since the timeout was added? */ - if (!is_server (serv)) - return 0; +#ifdef USE_OPENSSL + if (serv->ssl) + ret = _SSL_send (serv->ssl, msg->msg, msg->len); + else +#endif + ret = send (serv->sok, msg->msg, msg->len, 0); + /* Free the message */ + g_free (msg->msg); + g_free (msg->target); + g_free (msg); + return ret; +} + +inline void +set_queue_len(server *serv) +{ + int i, value = 0; + for (i = 0; i < 3; i++) + value += serv->out_queue[i]->length; + serv->sendq_len = value; + printf("Value is now: %i\n", value); + fe_set_throttle (serv); +} + +int +tcp_send_queue(server *serv) +{ + queued_msg *msg; + int i; + + set_queue_len(serv); - /* first try priority 1 entries */ - pri = 1; - while (pri >= 0) + if (!is_server (serv)) + queue_clean(serv); + else { - list = serv->outbound_queue; - while (list) + for (i = 0; i < 3; i++) { - buf = (char *) list->data; - if (buf[0] == pri) + if (!g_queue_is_empty(serv->out_queue[i])) /* ->length > 0) */ { - buf++; /* skip the priority byte */ - len = strlen (buf); + msg = (queued_msg *)g_queue_pop_head(serv->out_queue[i]); + tcp_send_data(serv, msg); + return TRUE; + } + } + } + /* Tell others that there is no queue */ + serv->queue_timer = 0; + serv->sendq_len = 0; + /* Lets stop the timer by returning false */ + return FALSE; +} - if (serv->next_send < now) - serv->next_send = now; - if (serv->next_send - now >= 10) - { - /* check for clock skew */ - if (now >= serv->prev_now) - return 1; /* don't remove the timeout handler */ - /* it is skewed, reset to something sane */ - serv->next_send = now; - } +inline static int +queue_throttle(server *serv) +{ + time_t tp = time(NULL); - for (p = buf, i = (int)len; i && *p != ' '; p++, i--); - serv->next_send += (2 + i / 120); - serv->sendq_len -= (int)len; - serv->prev_now = now; - fe_set_throttle (serv); + if (serv->queue_time == 0) + { + serv->queue_time = tp; + serv->queue_level = 0; + } - tcp_send_real (serv, buf, (int)len); + serv->queue_level += 10; + serv->queue_level -= 5 * (tp - serv->queue_time); - buf--; - serv->outbound_queue = g_slist_remove (serv->outbound_queue, buf); - free (buf); - list = serv->outbound_queue; - } else - { - list = list->next; - } + serv->queue_time = tp; + + if (serv->queue_level < 0) /* check for underflows */ + serv->queue_level = 0; + if (serv->queue_level >= 50) + return 1; + return 0; +} + +void +tcp_queue_data (server *serv, int type, char *target, char *channel, char *buf) +{ + queued_msg *msg = g_malloc(sizeof(queued_msg)); + gsize written, len = g_utf8_strlen(buf, 520); + gchar *line = NULL; + int throttle; + + if (!prefs.utf8_locale) + { + if (serv->encoding == NULL) + g_get_charset((const char **)&serv->encoding); + + line = g_convert(buf, len, serv->encoding, "UTF-8", NULL, &written, NULL); + } + + if (type == QUEUE_COMMAND) + msg->msg = line ? line : g_strdup(buf); + else + { + char tmp[520]; + char *txt = line ? line : buf; + + switch(type) + { + case QUEUE_MESSAGE: + snprintf(tmp, sizeof(tmp)-1, "PRIVMSG %s :%s%s", target, + line ? "" : "\xEF\xBB\xBF", txt); + break; + case QUEUE_NOTICE: + type = QUEUE_MESSAGE; + case QUEUE_REPLY: + snprintf(tmp, sizeof(tmp)-1, "NOTICE %s :%s%s", target, + line ? "" : "\xEF\xBB\xBF", txt); + break; + case QUEUE_CMESSAGE: + type = QUEUE_MESSAGE; + snprintf(tmp, sizeof(tmp)-1, "CMESSAGE %s %s :%s%s", target, + channel, line ? "" : "\xEF\xBB\xBF", txt); + break; + case QUEUE_CNOTICE: + type = QUEUE_MESSAGE; + snprintf(tmp, sizeof(tmp)-1, "CNOTICE %s %s :%s%s", target, + channel, line ? "" : "\xEF\xBB\xBF", txt); } - /* now try pri 0 */ - pri--; + tmp[sizeof(tmp)] = 0; + g_free(line); + msg->msg = g_strdup(tmp); } - return 0; /* remove the timeout handler */ + msg->target = target ? g_strdup(target) : NULL; + msg->len = strlen(msg->msg); + + /* Add line to the rawlog ui */ + fe_add_rawlog (serv, buf, msg->len, TRUE); + + /* Calc on each line to know when to stop throttling... */ + throttle = queue_throttle(serv); + + if (serv->queue_timer || throttle) + { + g_queue_push_tail(serv->out_queue[type], msg); + if (!serv->queue_timer) + serv->queue_timer = g_timeout_add(2000, (GSourceFunc)tcp_send_queue, serv); + } + else + tcp_send_data(serv, msg); } -int -tcp_send_len (server *serv, char *buf, int len) +/* Inline wrapper functions */ +inline void send_command(server *serv, char *target, char *buf) +{ tcp_queue_data (serv, QUEUE_COMMAND, target, NULL, buf); } + +inline void send_message(server *serv, char *target, char *buf) +{ tcp_queue_data (serv, QUEUE_MESSAGE, target, NULL, buf); } + +inline void send_cmessage(server *serv, char *target, char *channel, char *buf) +{ tcp_queue_data (serv, QUEUE_CMESSAGE, target, channel, buf); } + +inline void send_notice(server *serv, char *target, char *buf) +{ tcp_queue_data (serv, QUEUE_NOTICE, target, NULL, buf); } + +inline void send_cnotice(server *serv, char *target, char *channel, char *buf) +{ tcp_queue_data (serv, QUEUE_CNOTICE, target, channel, buf); } + +inline void send_reply(server *serv, char *target, char *buf) +{ tcp_queue_data (serv, QUEUE_REPLY, target, NULL, buf); } + +void +send_commandf(server *serv, char *target, char *fmt, ...) { - char *dbuf; - int noqueue = !serv->outbound_queue; + va_list args; + char send_buf[520]; + + va_start (args, fmt); + vsnprintf (send_buf, sizeof (send_buf) - 1, fmt, args); + va_end (args); - if (!prefs.throttle) - return tcp_send_real (serv, buf, len); + send_buf[sizeof (send_buf) - 1] = '\0'; + + tcp_queue_data (serv, QUEUE_COMMAND, target, NULL, send_buf); +} - dbuf = malloc (len + 2); /* first byte is the priority */ - dbuf[0] = 1; /* pri 1 for most things */ - memcpy (dbuf + 1, buf, len); - dbuf[len + 1] = 0; +void +send_messagef(server *serv, char *target, char *fmt, ...) +{ + va_list args; + char send_buf[520]; - /* privmsg and notice get a lower priority */ - if (strncasecmp (dbuf + 1, "PRIVMSG", 7) == 0 || - strncasecmp (dbuf + 1, "NOTICE", 6) == 0) - dbuf[0] = 0; + va_start (args, fmt); + vsnprintf (send_buf, sizeof (send_buf) - 1, fmt, args); + va_end (args); - serv->outbound_queue = g_slist_append (serv->outbound_queue, dbuf); - serv->sendq_len += len; /* tcp_send_queue uses strlen */ + send_buf[sizeof (send_buf) - 1] = '\0'; - if (tcp_send_queue (serv) && noqueue) - g_timeout_add (500, (GSourceFunc)tcp_send_queue, serv); + tcp_queue_data (serv, QUEUE_MESSAGE, target, NULL, send_buf); +} - return 1; +void +send_cmessagef(server *serv, char *target, char *channel, char *fmt, ...) +{ + va_list args; + char send_buf[520]; + + va_start (args, fmt); + vsnprintf (send_buf, sizeof (send_buf) - 1, fmt, args); + va_end (args); + + send_buf[sizeof (send_buf) - 1] = '\0'; + + tcp_queue_data (serv, QUEUE_CMESSAGE, target, channel, send_buf); } -/*int -tcp_send (server *serv, char *buf) +void +send_noticef(server *serv, char *target, char *fmt, ...) { - return tcp_send_len (serv, buf, strlen (buf)); -}*/ + va_list args; + char send_buf[520]; + + va_start (args, fmt); + vsnprintf (send_buf, sizeof (send_buf) - 1, fmt, args); + va_end (args); + + send_buf[sizeof (send_buf) - 1] = '\0'; + + tcp_queue_data (serv, QUEUE_NOTICE, target, NULL, send_buf); +} void -tcp_sendf (server *serv, char *fmt, ...) +send_cnoticef(server *serv, char *target, char *channel, char *fmt, ...) { va_list args; - /* keep this buffer in BSS */ - static char send_buf[520]; /* good code hey (no it's not overflowable) */ - size_t len; + char send_buf[520]; va_start (args, fmt); - len = vsnprintf (send_buf, sizeof (send_buf) - 1, fmt, args); + vsnprintf (send_buf, sizeof (send_buf) - 1, fmt, args); va_end (args); send_buf[sizeof (send_buf) - 1] = '\0'; - if (len < 0 || len > (sizeof (send_buf) - 1)) - len = strlen (send_buf); - tcp_send_len (serv, send_buf, (int)len); + tcp_queue_data (serv, QUEUE_CNOTICE, target, channel, send_buf); +} + + +void +send_replyf(server *serv, char *target, char *fmt, ...) +{ + va_list args; + char send_buf[520]; + + va_start (args, fmt); + vsnprintf (send_buf, sizeof (send_buf) - 1, fmt, args); + va_end (args); + + send_buf[sizeof (send_buf) - 1] = '\0'; + + tcp_queue_data (serv, QUEUE_REPLY, target, NULL, send_buf); } static int @@ -266,14 +475,17 @@ server_inline (server *serv, char *line, size_t len) { err = NULL; retry = FALSE; - utf_line_allocated = g_convert_with_fallback (conv_line, conv_len, "UTF-8", encoding, "?", &read_len, &utf_len, &err); + utf_line_allocated = g_convert_with_fallback (conv_line, conv_len, + "UTF-8", encoding, "?", &read_len, &utf_len, &err); if (err != NULL) { if (err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE) { /* Make our best bet by removing the erroneous char. - This will work for casual 8-bit strings with non-standard chars. */ - memmove (conv_line + read_len, conv_line + read_len + 1, conv_len - read_len -1); + * This will work for casual 8-bit strings with + * non-standard chars. */ + memmove (conv_line + read_len, conv_line + read_len + 1, + conv_len - read_len -1); conv_len--; retry = TRUE; } @@ -284,7 +496,7 @@ server_inline (server *serv, char *line, size_t len) g_free (conv_line); /* If any conversion has occured at all. Conversion might fail - due to errors other than invalid sequences, e.g. unknown charset. */ + * due to errors other than invalid sequences, e.g. unknown charset. */ if (utf_line_allocated != NULL) { line = utf_line_allocated; @@ -739,7 +951,7 @@ auto_reconnect (server *serv, int send_quit, int err) static void server_flush_queue (server *serv) { - list_free (&serv->outbound_queue); + queue_clean(serv); serv->sendq_len = 0; fe_set_throttle (serv); } @@ -1508,6 +1720,14 @@ server_connect (server *serv, char *hostname, int port, int no_login) void server_fill_her_up (server *serv) { + int i; + + for (i = 0; i < 3; i++) + { + if(!serv->out_queue[i]) + serv->out_queue[i] = g_queue_new(); + } + serv->connect = server_connect; serv->disconnect = server_disconnect; serv->cleanup = server_cleanup; diff --git a/trunk/src/common/server.h b/trunk/src/common/server.h index b9409e7..ba97aeb 100644 --- a/trunk/src/common/server.h +++ b/trunk/src/common/server.h @@ -1,10 +1,27 @@ #ifndef XCHAT_SERVER_H #define XCHAT_SERVER_H -/* eventually need to keep the tcp_* functions isolated to server.c */ -int tcp_send_len (server *serv, char *buf, int len); -int tcp_send (server *serv, char *buf); -void tcp_sendf (server *serv, char *fmt, ...); +/* Common send commands */ +inline void send_command(server *serv, char *target, char *buf); +inline void send_message(server *serv, char *target, char *buf); +inline void send_cmessage(server *serv, char *target, char *channel, char *buf); +inline void send_notice(server *serv, char *target, char *buf); +inline void send_cnotice(server *serv, char *target, char *channel, char *buf); +inline void send_reply(server *serv, char *target, char *buf); + +/* Fomatted send commands */ +void send_commandf(server *serv, char *target, char *fmt, ...); +void send_messagef(server *serv, char *target, char *fmt, ...); +void send_cmessagef(server *serv, char *target, char *channel, char *fmt, ...); +void send_noticef(server *serv, char *target, char *fmt, ...); +void send_cnoticef(server *serv, char *target, char *channel, char *fmt, ...); +void send_replyf(server *serv, char *target, char *fmt, ...); + +/* Data manipulation */ +void queue_target_change(server *serv, char *old_target, char *new_target); +void queue_remove_target(server *serv, char *target); + +int queue_count(server *serv, char *target, int queue); void server_fill_her_up (server *serv); diff --git a/trunk/src/fe-gtk/fe-gtk.c b/trunk/src/fe-gtk/fe-gtk.c index 64b32f0..4541acf 100644 --- a/trunk/src/fe-gtk/fe-gtk.c +++ b/trunk/src/fe-gtk/fe-gtk.c @@ -595,7 +595,7 @@ fe_set_throttle (server *serv) float per; char tbuf[64]; - per = (float) serv->sendq_len / 1024.0; + per = (float) serv->sendq_len / 20.0; if (per > 1.0) per = 1.0; @@ -604,7 +604,7 @@ fe_set_throttle (server *serv) sess = list->data; if (sess->server == serv) { - snprintf (tbuf, sizeof (tbuf) - 1, _("%d bytes"), serv->sendq_len); + snprintf (tbuf, sizeof (tbuf) - 1, _("%d lines"), serv->sendq_len); if (!sess->gui->is_tab || current_tab == sess) {