summary refs log tree commit diff stats
path: root/src/common
diff options
context:
space:
mode:
authorPatrick Griffis <tingping@tingping.se>2019-11-24 13:01:48 -0800
committerPatrick Griffis <tingping@tingping.se>2019-11-24 13:01:48 -0800
commit7d9f3acfc905ca5d0c9747699eb21d2d95fbf821 (patch)
tree448c43e0eaca1252cc9cf15a0a7c667d4ca1d9fd /src/common
parentad5be08a0703659e1b90ec4a5c6ff58a42660bae (diff)
Fix capability negotiation ending before sasl finishes with multi-line cap
Closes #2398
Diffstat (limited to 'src/common')
-rw-r--r--src/common/hexchat.h1
-rw-r--r--src/common/inbound.c21
-rw-r--r--src/common/inbound.h2
-rw-r--r--src/common/proto-irc.c3
4 files changed, 20 insertions, 7 deletions
diff --git a/src/common/hexchat.h b/src/common/hexchat.h
index 16f10ded..c64e44a0 100644
--- a/src/common/hexchat.h
+++ b/src/common/hexchat.h
@@ -578,6 +578,7 @@ typedef struct server
 	unsigned int sasl_mech;			/* mechanism for sasl auth */
 	unsigned int sent_capend:1;	/* have sent CAP END yet */
 	unsigned int waiting_on_cap:1;	/* waiting on another line of CAP LS */
+	unsigned int waiting_on_sasl:1; /* waiting on sasl */
 #ifdef USE_OPENSSL
 	unsigned int use_ssl:1;				  /* is server SSL capable? */
 	unsigned int accept_invalid_cert:1;/* ignore result of server's cert. verify */
diff --git a/src/common/inbound.c b/src/common/inbound.c
index 9c77b231..eb7054f2 100644
--- a/src/common/inbound.c
+++ b/src/common/inbound.c
@@ -1768,7 +1768,6 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str,
 {
 	char buffer[500];	/* buffer for requesting capabilities and emitting the signal */
 	gboolean want_cap = FALSE; /* format the CAP REQ string based on previous capabilities being requested or not */
-	gboolean want_sasl = FALSE; /* CAP END shouldn't be sent when SASL is requested, it needs further responses */
 	char **extensions;
 	int i;
 
@@ -1816,7 +1815,7 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str,
 				serv->sasl_mech = sasl_mech;
 			}
 			want_cap = TRUE;
-			want_sasl = TRUE;
+			serv->waiting_on_sasl = TRUE;
 			g_strlcat (buffer, "sasl ", sizeof(buffer));
 			continue;
 		}
@@ -1842,7 +1841,7 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str,
 									  tags_data->timestamp);
 		tcp_sendf (serv, "%s\r\n", g_strchomp (buffer));
 	}
-	if (!want_sasl && !serv->waiting_on_cap)
+	if (!serv->waiting_on_sasl && !serv->waiting_on_cap)
 	{
 		/* if we use SASL, CAP END is dealt via raw numerics */
 		serv->sent_capend = TRUE;
@@ -1851,13 +1850,25 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str,
 }
 
 void
-inbound_cap_nak (server *serv, const message_tags_data *tags_data)
+inbound_cap_nak (server *serv, char *extensions_str, const message_tags_data *tags_data)
 {
-	if (!serv->waiting_on_cap && !serv->sent_capend)
+	char **extensions;
+	int i;
+
+	extensions = g_strsplit (extensions_str, " ", 0);
+	for (i=0; extensions[i]; i++)
+	{
+		if (!g_strcmp0 (extensions[i], "sasl"))
+			serv->waiting_on_sasl = FALSE;
+	}
+
+	if (!serv->waiting_on_cap && !serv->waiting_on_sasl && !serv->sent_capend)
 	{
 		serv->sent_capend = TRUE;
 		tcp_send_len (serv, "CAP END\r\n", 9);
 	}
+
+	g_strfreev (extensions);
 }
 
 void
diff --git a/src/common/inbound.h b/src/common/inbound.h
index 83e78d5d..6e7c171f 100644
--- a/src/common/inbound.h
+++ b/src/common/inbound.h
@@ -92,7 +92,7 @@ void inbound_cap_ack (server *serv, char *nick, char *extensions,
 							 const message_tags_data *tags_data);
 void inbound_cap_ls (server *serv, char *nick, char *extensions,
 							const message_tags_data *tags_data);
-void inbound_cap_nak (server *serv, const message_tags_data *tags_data);
+void inbound_cap_nak (server *serv, char *extensions, const message_tags_data *tags_data);
 void inbound_cap_list (server *serv, char *nick, char *extensions,
 							  const message_tags_data *tags_data);
 void inbound_cap_del (server *serv, char *nick, char *extensions,
diff --git a/src/common/proto-irc.c b/src/common/proto-irc.c
index 497cb6ca..59a60a8f 100644
--- a/src/common/proto-irc.c
+++ b/src/common/proto-irc.c
@@ -957,6 +957,7 @@ process_numeric (session * sess, int n,
 		EMIT_SIGNAL_TIMESTAMP (XP_TE_SASLRESPONSE, serv->server_session, word[1],
 									  word[2], word[3], ++word_eol[4], 0,
 									  tags_data->timestamp);
+		serv->waiting_on_sasl = FALSE;
 		if (!serv->sent_capend)
 		{
 			serv->sent_capend = TRUE;
@@ -1330,7 +1331,7 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
 				}
 				else if (strncasecmp (word[4], "NAK", 3) == 0)
 				{
-					inbound_cap_nak (serv, tags_data);
+					inbound_cap_nak (serv, word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5], tags_data);
 				}
 				else if (strncasecmp (word[4], "LIST", 4) == 0)	
 				{