AmendHub

Download:

jcs

/

wallops

/

amendments

/

27

irc: Print dying gasps in irc_recv, catch nick list trailing space

An Unreal3.2.10.2 server returned a trailing space at the end of
nick lists when joining a channel, causing an infinite loop in
sorting.

jcs made amendment 27 over 2 years ago
--- irc.c Thu Feb 10 10:57:31 2022 +++ irc.c Thu Feb 10 11:33:08 2022 @@ -30,7 +30,7 @@ char * irc_get_line(struct chatter *chatter, size_t *r struct irc_user * irc_parse_user(char *str); bool irc_can_send(struct chatter *chatter); void irc_login(struct chatter *chatter); -void irc_process_server(struct chatter *chatter); +bool irc_process_server(struct chatter *chatter); void irc_set_active_channel(struct chatter *chatter, char *channame); void irc_parse_names(struct chatter *chatter, char *line); void irc_add_nick_to_channel(struct chatter *chatter, char *nick, @@ -160,36 +160,38 @@ short irc_recv(struct chatter *chatter) { unsigned short rlen; - short error, n; - - if (chatter->irc_ibuflen >= sizeof(chatter->irc_ibuf)) - return 0; - + short error, rerror, n; + error = _TCPStatus(&chatter->irc_rcv_pb, chatter->irc_stream, &chatter->irc_status_pb, nil, nil, false); - if (error) { - chatter_printf(chatter, "$B*!* TCPStatus failed: %d$0", error); - irc_abort(chatter); - return 0; - } - if (chatter->irc_status_pb.amtUnreadData == 0) - return 0; + if (chatter->irc_status_pb.amtUnreadData > 0 && + chatter->irc_ibuflen < sizeof(chatter->irc_ibuf)) { + rlen = chatter->irc_status_pb.amtUnreadData; + if (chatter->irc_ibuflen + rlen > sizeof(chatter->irc_ibuf)) + rlen = sizeof(chatter->irc_ibuf) - chatter->irc_ibuflen; + + rerror = _TCPRcv(&chatter->irc_rcv_pb, chatter->irc_stream, + (Ptr)(chatter->irc_ibuf + chatter->irc_ibuflen), &rlen, nil, nil, + false); + if (rerror) { + chatter_printf(chatter, "$B*!* TCPRecv failed: %d$0", error); + irc_abort(chatter); + return 0; + } - rlen = chatter->irc_status_pb.amtUnreadData; - if (chatter->irc_ibuflen + rlen > sizeof(chatter->irc_ibuf)) - rlen = sizeof(chatter->irc_ibuf) - chatter->irc_ibuflen; + chatter->irc_ibuflen += rlen; + } - error = _TCPRcv(&chatter->irc_rcv_pb, chatter->irc_stream, - (Ptr)(chatter->irc_ibuf + chatter->irc_ibuflen), &rlen, nil, nil, - false); if (error) { - chatter_printf(chatter, "$B*!* TCPRecv failed: %d$0", error); - irc_close(chatter); + /* let already-consumed buffer finish processing */ + while (irc_process_server(chatter)) + ; + chatter_printf(chatter, "$B*!* TCPStatus failed: %d$0", error); + irc_abort(chatter); return 0; } - - chatter->irc_ibuflen += rlen; + return rlen; } @@ -355,7 +357,7 @@ irc_get_line(struct chatter *chatter, size_t *retsize) return NULL; } -void +bool irc_process_server(struct chatter *chatter) { struct irc_msg msg; @@ -366,7 +368,7 @@ irc_process_server(struct chatter *chatter) line = irc_get_line(chatter, &size); if (size == 0 || line == NULL) - return; + return false; memset(&msg, 0, sizeof(msg)); @@ -468,13 +470,13 @@ irc_process_server(struct chatter *chatter) chatter_printf(chatter, "$B[%s($0%s@%s$B):%s]$0$/ %s", user->nick, user->username, user->hostname, msg.arg[0], msg.msg); - return; + return true; } if (strcmp(msg.cmd, "ERROR") == 0) { chatter_printf(chatter, "$B*!* Disconnected$0 from $B%s$0:$/ %s", chatter->irc_hostname, msg.msg); irc_abort(chatter); - return; + return true; } if (strcmp(msg.cmd, "JOIN") == 0) { user = irc_parse_user(msg.source); @@ -485,7 +487,7 @@ irc_process_server(struct chatter *chatter) irc_set_active_channel(chatter, msg.arg[0]); else irc_add_nick_to_channel(chatter, user->nick, 0); - return; + return true; } if (strcmp(msg.cmd, "KICK") == 0) { user = irc_parse_user(msg.source); @@ -496,7 +498,7 @@ irc_process_server(struct chatter *chatter) irc_set_active_channel(chatter, NULL); else irc_remove_nick_from_channel(chatter, msg.arg[1]); - return; + return true; } if (strcmp(msg.cmd, "KILL") == 0) { user = irc_parse_user(msg.source); @@ -507,7 +509,7 @@ irc_process_server(struct chatter *chatter) irc_set_active_channel(chatter, NULL); else irc_remove_nick_from_channel(chatter, user->nick); - return; + return true; } if (strcmp(msg.cmd, "MODE") == 0) { if (strcmp(msg.arg[0], chatter->irc_nick) == 0) @@ -537,21 +539,21 @@ irc_process_server(struct chatter *chatter) irc_parse_channel_mode_change(chatter, msg.arg[1], msg.msg); } - return; + return true; } if (strcmp(msg.cmd, "NICK") == 0) { user = irc_parse_user(msg.source); chatter_printf(chatter, "$B*** %s$0 is now known as $B%s$0", user->nick, msg.msg); irc_change_user_nick(chatter, user, msg.msg); - return; + return true; } if (strcmp(msg.cmd, "NOTICE") == 0) { if (strncmp(msg.msg, "*** ", 4) == 0) chatter_printf(chatter, "$B***$0 $/%s", msg.msg + 4); else chatter_printf(chatter, "$/%s", msg.msg); - return; + return true; } if (strcmp(msg.cmd, "PART") == 0) { user = irc_parse_user(msg.source); @@ -562,11 +564,11 @@ irc_process_server(struct chatter *chatter) irc_set_active_channel(chatter, NULL); else irc_remove_nick_from_channel(chatter, user->nick); - return; + return true; } if (strcmp(msg.cmd, "PING") == 0) { irc_printf(chatter, "PONG :%s\r\n", msg.msg); - return; + return true; } if (strcmp(msg.cmd, "QUIT") == 0) { user = irc_parse_user(msg.source); @@ -576,7 +578,7 @@ irc_process_server(struct chatter *chatter) irc_set_active_channel(chatter, NULL); else irc_remove_nick_from_channel(chatter, user->nick); - return; + return true; } goto unknown; } @@ -600,49 +602,53 @@ irc_process_server(struct chatter *chatter) case 265: case 266: /* server stats, unhelpful */ - return; + return true; + case 307: + /* WHOIS regnick */ + chatter_printf(chatter, "$B*** |$0 Authenticated:$/ %s", msg.msg); + return true; case 311: /* WHOIS nick: "nick :ident hostname * :name" */ chatter_printf(chatter, "$B*** %s ($0%s@%s$B)$0", msg.arg[1], msg.arg[2], msg.arg[3]); chatter_printf(chatter, "$B*** |$0 Name:$/ %s", msg.msg); - return; + return true; case 312: /* WHOIS server */ chatter_printf(chatter, "$B*** |$0 Server:$/ %s (%s)", msg.arg[2], msg.msg); - return; + return true; case 671: /* WHOIS server */ chatter_printf(chatter, "$B*** |$0 Connection:$/ %s", msg.msg); - return; + return true; case 317: /* WHOIS idle */ chatter_printf(chatter, "$B*** |$0 Idle:$/ %s %s", msg.arg[2], msg.msg); - return; + return true; case 318: /* WHOIS end */ chatter_printf(chatter, "$B*** `-------$0"); - return; + return true; case 319: /* WHOIS channels */ chatter_printf(chatter, "$B*** |$0 Channels:$/ %s", msg.msg); - return; + return true; case 330: /* WHOIS account */ chatter_printf(chatter, "$B*** |$0 Account:$/ %s %s", msg.msg, msg.arg[2]); - return; + return true; case 338: case 378: /* WHOIS host */ chatter_printf(chatter, "$B*** |$0 Host:$/ %s %s", msg.msg, msg.arg[2]); - return; + return true; case 328: /* channel URL, we probably can't do anything with it anyway */ - return; + return true; case 332: /* TOPIC */ chatter_printf(chatter, "$B***$0 Topic for $B%s$0:$/ %s", @@ -652,10 +658,10 @@ irc_process_server(struct chatter *chatter) strlcpy(chatter->irc_channel->topic, msg.msg, sizeof(chatter->irc_channel->topic)); } - return; + return true; case 333: /* TOPIC creator */ - return; + return true; case 352: /* WHO output */ goto unknown; @@ -667,13 +673,13 @@ irc_process_server(struct chatter *chatter) if (chatter->irc_channel && strcmp(msg.arg[2], chatter->irc_channel->name) == 0) irc_parse_names(chatter, msg.msg); - return; + return true; case 366: /* end of NAMES output */ if (chatter->irc_channel && strcmp(msg.arg[1], chatter->irc_channel->name) == 0) chatter_sync_nick_list(chatter, true); - return; + return true; case 372: case 375: case 376: @@ -682,20 +688,21 @@ irc_process_server(struct chatter *chatter) case 396: /* Cloak */ chatter_printf(chatter, "$B***$0$/ %s %s", msg.arg[1], msg.msg); - return; + return true; default: goto unknown; } print_msg: chatter_printf(chatter, "$B***$0$/ %s", msg.msg); - return; + return true; unknown: chatter_printf(chatter, "$B[?]$0$/ code:%d cmd:%s source:%s " "arg0:%s arg1:%s arg2:%s arg3:%s arg4:%s msg:%s", msg.code, msg.cmd, msg.source, msg.arg[0], msg.arg[1], msg.arg[2], msg.arg[3], msg.arg[4], msg.msg); + return true; } void @@ -825,6 +832,9 @@ irc_parse_names(struct chatter *chatter, char *line) } else if (nick[0] == '+') { flags = IRC_NICK_FLAG_VOICE; nick++; + } else if (nick[0] == '\0') { + /* some servers send a trailing space */ + break; } else flags = 0;