# HG changeset patch
# Node ID 2196b5c6028b
# Parent  2e6f09066f94
diff --git a/libpurple/protocols/ircv3/meson.build b/libpurple/protocols/ircv3/meson.build
--- a/libpurple/protocols/ircv3/meson.build
+++ b/libpurple/protocols/ircv3/meson.build
@@ -3,6 +3,8 @@
 	'purpleircv3connection.h',
 	'purpleircv3core.c',
 	'purpleircv3core.h',
+	'purpleircv3messagehandlers.c',
+	'purpleircv3messagehandlers.h',
 	'purpleircv3parser.c',
 	'purpleircv3parser.h',
 	'purpleircv3protocol.c',
diff --git a/libpurple/protocols/ircv3/purpleircv3connection.c b/libpurple/protocols/ircv3/purpleircv3connection.c
--- a/libpurple/protocols/ircv3/purpleircv3connection.c
+++ b/libpurple/protocols/ircv3/purpleircv3connection.c
@@ -21,6 +21,7 @@
 #include "purpleircv3connection.h"
 
 #include "purpleircv3core.h"
+#include "purpleircv3parser.h"
 
 enum {
 	PROP_0,
@@ -43,6 +44,8 @@
 
 	GDataInputStream *input;
 	PurpleQueuedOutputStream *output;
+
+	PurpleIRCv3Parser *parser;
 };
 
 G_DEFINE_DYNAMIC_TYPE(PurpleIRCv3Connection, purple_ircv3_connection,
@@ -108,6 +111,7 @@
 purple_ircv3_connection_read_cb(GObject *source, GAsyncResult *result,
                                 gpointer data)
 {
+	PurpleIRCv3Connection *connection = NULL;
 	PurpleConnection *purple_connection = data;
 	GDataInputStream *istream = G_DATA_INPUT_STREAM(source);
 	GError *error = NULL;
@@ -133,9 +137,18 @@
 		return;
 	}
 
-	g_message("received line: %s", line);
+	connection = g_object_get_data(G_OBJECT(purple_connection),
+	                               PURPLE_IRCV3_CONNECTION_KEY);
+	purple_ircv3_parser_parse(connection->parser, line, &error, connection);
 
 	g_free(line);
+
+	/* Call read_line_async again to continue reading lines. */
+	g_data_input_stream_read_line_async(connection->input,
+	                                    G_PRIORITY_DEFAULT,
+	                                    connection->cancellable,
+	                                    purple_ircv3_connection_read_cb,
+	                                    purple_connection);
 }
 
 static void
@@ -191,16 +204,25 @@
 	connection = g_object_get_data(G_OBJECT(purple_connection),
 	                               PURPLE_IRCV3_CONNECTION_KEY);
 
+	purple_connection_set_state(purple_connection,
+	                            PURPLE_CONNECTION_CONNECTED);
+
 	g_message("Successfully connected to %s", connection->server_name);
 
 	/* Save our connection and setup our input and outputs. */
 	connection->connection = conn;
 
+	/* Create our parser. */
+	connection->parser = purple_ircv3_parser_new();
+	purple_ircv3_parser_add_default_handlers(connection->parser);
+
 	ostream = g_io_stream_get_output_stream(G_IO_STREAM(conn));
 	connection->output = purple_queued_output_stream_new(ostream);
 
 	istream = g_io_stream_get_input_stream(G_IO_STREAM(conn));
 	connection->input = g_data_input_stream_new(istream);
+	g_data_input_stream_set_newline_type(G_DATA_INPUT_STREAM(connection->input),
+	                                     G_DATA_STREAM_NEWLINE_TYPE_CR_LF);
 
 	/* Add our read callback. */
 	g_data_input_stream_read_line_async(connection->input,
@@ -266,6 +288,8 @@
 	g_clear_object(&connection->output);
 	g_clear_object(&connection->connection);
 
+	g_clear_object(&connection->parser);
+
 	G_OBJECT_CLASS(purple_ircv3_connection_parent_class)->dispose(obj);
 }
 
diff --git a/libpurple/protocols/ircv3/purpleircv3messagehandlers.h b/libpurple/protocols/ircv3/purpleircv3messagehandlers.h
new file mode 100644
--- /dev/null
+++ b/libpurple/protocols/ircv3/purpleircv3messagehandlers.h
@@ -0,0 +1,60 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef PURPLE_IRCV3_MESSAGE_HANDLERS_H
+#define PURPLE_IRCV3_MESSAGE_HANDLERS_H
+
+#include <glib.h>
+
+#include <purple.h>
+
+G_BEGIN_DECLS
+
+/**
+ * PurpleIRCv3MessageHandler:
+ * @tags: (element-type utf8 utf8): A [struct@GLib.HashTable] of tags for this
+ *        message.
+ * @source: The source of the command.
+ * @command: The command or numeric of the message.
+ * @n_params: The number of parameters.
+ * @params: (array_length=n_params): The parameters of the message.
+ * @error: (nullable) (optional): A return address for a [type@GLib.Error].
+ * @data: The user data that was passed to [method@PurpleIRCv3.Parser.parse].
+ *
+ * Defines the type of a function that will be called to handle a message.
+ *
+ * Returns: %TRUE if the command was handled properly, otherwise %FALSE and
+ *          @error may be set.
+ *
+ * Since: 3.0.0
+ */
+typedef gboolean (*PurpleIRCv3MessageHandler)(GHashTable *tags,
+                                              const char *source,
+                                              const char *command,
+                                              guint n_params,
+                                              GStrv params,
+                                              GError **error,
+                                              gpointer data);
+
+G_GNUC_INTERNAL gboolean purple_ircv3_messager_handler_fallback(GHashTable *tags, const char *source, const char *command, guint n_params, GStrv params, GError **error, gpointer data);
+
+G_GNUC_INTERNAL gboolean purple_ircv3_messager_handler_ping(GHashTable *tags, const char *source, const char *command, guint n_params, GStrv params, GError **error, gpointer data);
+
+G_END_DECLS
+
+#endif /* PURPLE_IRCV3_MESSAGE_HANDLERS_H */
diff --git a/libpurple/protocols/ircv3/purpleircv3messagehandlers.c b/libpurple/protocols/ircv3/purpleircv3messagehandlers.c
new file mode 100644
--- /dev/null
+++ b/libpurple/protocols/ircv3/purpleircv3messagehandlers.c
@@ -0,0 +1,57 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "purpleircv3messagehandlers.h"
+
+#include "purpleircv3connection.h"
+
+gboolean
+purple_ircv3_messager_handler_fallback(GHashTable *tags, const char *source,
+                                       const char *command, guint n_params,
+                                       GStrv params, GError **error,
+                                       gpointer data)
+{
+	gchar *joined = g_strjoinv(" ", params);
+
+	g_message("-- unhandled message --");
+	g_message("source: %s", source);
+	g_message("command: %s", command);
+	g_message("params: %s", joined);
+	g_message("-- end of unhandled message --");
+
+	g_free(joined);
+
+	return TRUE;
+}
+
+gboolean
+purple_ircv3_messager_handler_ping(GHashTable *tags, const char *source,
+                                   const char *command, guint n_params,
+                                   GStrv params, GError **error,
+                                   gpointer data)
+{
+	PurpleIRCv3Connection *connection = data;
+
+	if(n_params == 1) {
+		purple_ircv3_connection_writef(connection, "PONG %s", params[0]);
+	} else {
+		purple_ircv3_connection_writef(connection, "PONG");
+	}
+
+	return TRUE;
+}
diff --git a/libpurple/protocols/ircv3/purpleircv3parser.h b/libpurple/protocols/ircv3/purpleircv3parser.h
--- a/libpurple/protocols/ircv3/purpleircv3parser.h
+++ b/libpurple/protocols/ircv3/purpleircv3parser.h
@@ -24,15 +24,9 @@
 
 #include <purple.h>
 
-G_BEGIN_DECLS
+#include "purpleircv3messagehandlers.h"
 
-typedef gboolean (*PurpleIRCv3MessageHandler)(GHashTable *tags,
-                                              const gchar *source,
-                                              const gchar *command,
-                                              guint n_params,
-                                              GStrv params,
-                                              GError **error,
-                                              gpointer data);
+G_BEGIN_DECLS
 
 #define PURPLE_IRCV3_TYPE_PARSER (purple_ircv3_parser_get_type())
 G_DECLARE_FINAL_TYPE(PurpleIRCv3Parser, purple_ircv3_parser, PURPLE_IRCV3,
@@ -74,6 +68,16 @@
  */
 G_GNUC_INTERNAL gboolean purple_ircv3_parser_parse(PurpleIRCv3Parser *parser, const gchar *buffer, GError **error, gpointer data);
 
+/**
+ * purple_ircv3_parser_add_default_handlers:
+ * @parser: The instance.
+ *
+ * Adds all of the default handlers to @parser.
+ *
+ * Since: 3.0.0
+ */
+G_GNUC_INTERNAL void purple_ircv3_parser_add_default_handlers(PurpleIRCv3Parser *parser);
+
 G_END_DECLS
 
 #endif /* PURPLE_IRCV3_PARSER_H */
diff --git a/libpurple/protocols/ircv3/purpleircv3parser.c b/libpurple/protocols/ircv3/purpleircv3parser.c
--- a/libpurple/protocols/ircv3/purpleircv3parser.c
+++ b/libpurple/protocols/ircv3/purpleircv3parser.c
@@ -19,6 +19,7 @@
 #include "purpleircv3parser.h"
 
 #include "purpleircv3core.h"
+#include "purpleircv3messagehandlers.h"
 
 struct _PurpleIRCv3Parser {
 	GObject parent;
@@ -166,6 +167,18 @@
 	return result;
 }
 
+static void
+purple_ircv3_parser_add_handler(PurpleIRCv3Parser *parser,
+                                const gchar *command,
+                                PurpleIRCv3MessageHandler handler)
+{
+	g_return_if_fail(PURPLE_IRCV3_IS_PARSER(parser));
+	g_return_if_fail(command != NULL);
+	g_return_if_fail(handler != NULL);
+
+	g_hash_table_insert(parser->handlers, g_strdup(command), handler);
+}
+
 /******************************************************************************
  * Handlers
  *****************************************************************************/
@@ -333,3 +346,14 @@
 
 	return result;
 }
+
+void
+purple_ircv3_parser_add_default_handlers(PurpleIRCv3Parser *parser) {
+	g_return_if_fail(PURPLE_IRCV3_IS_PARSER(parser));
+
+	purple_ircv3_parser_set_fallback_handler(parser,
+	                                         purple_ircv3_messager_handler_fallback);
+
+	purple_ircv3_parser_add_handler(parser, "PING",
+	                                purple_ircv3_messager_handler_ping);
+}
