# HG changeset patch
# Node ID 5d8a8cdc6d00
# Parent  472d8f2226bc
diff --git a/ibis/reference/getting-started.md b/ibis/reference/getting-started.md
new file mode 100644
--- /dev/null
+++ b/ibis/reference/getting-started.md
@@ -0,0 +1,169 @@
+Title: Getting Started
+Slug: getting-started
+
+# Getting Started
+
+Ibis is a protocol integration library which means that a certain level of
+knowledge about the protocol is required to use it. This document will help you
+through the initial integration, but it is highly recommend that you
+familiarize yourself with the
+[Modern IRC Documentation](https://modern.ircdocs.horse/).
+
+If you're looking for a crash course, you can look at the
+[command line interface](https://keep.imfreedom.org/ibis/ibis/file/default/ibis-cli/ibiscli.c)
+in the source code. This is more of a development tool, but it does show how to
+integrate with with [class@Gio.Application].
+
+## The Client
+
+All interactions with the server are done via [class@Client]. To get started
+you will need to create a new instance and set at least the `nick` on it.
+
+```c
+IbisClient *client = NULL;
+
+/* Create the client. */
+client = ibis_client_new();
+
+/* Set the primary nick. */
+ibis_client_set_nick(client, "mynick");
+```
+
+Before connecting to a server, you'll want to connect to the
+[signal@Ibis.Client::message] signal on the client. This signal supports
+`details` that all you to connect a signal handler based on the `COMMAND` part
+of the message received. Multiple handlers may be connected for the same
+command, so the first handler to return %TRUE will stop any remaining handlers
+from being called.
+
+```c
+/* Add a signal handler for just the PRIVMSG command. This uses a constant that
+ * Ibis provides to make help avoid typos.
+ */
+g_signal_connect(client, "message::" IBIS_MSG_PRIVMSG,
+                 G_CALLBACK(privmsg_cb), NULL);
+
+/* This handler will be called for all messages that weren't handled. It is
+ * important that this signal runs after the default handler because the order
+ * in which signals are registered and called can not be guaranteed. So by
+ * having this called after the default handler all other signal handlers will
+ * be called first.
+ */
+g_signal_connect_after(client, "message", G_CALLBACK(fallback_cb), NULL);
+```
+
+Now that we have the signals connected, lets implement their handlers. We'll
+start with the fallback and it's very straight forward.
+
+```c
+static gboolean
+fallback_cb(IbisClient *client, const char *command, IbisMessage *message,
+            gpointer data)
+{
+	/* Since this command wasn't handled, we just output the raw message via
+	 * g_warning.
+	 */
+
+	g_warning("unhandled message: '%s'",
+	          ibis_message_get_raw_message(message));
+
+	/* Return TRUE as we "handled" the message. */
+	return TRUE;
+}
+```
+
+Now that we've seen the basics of handling a message lets look at a more
+complex example by implementing the `PRIVMSG` handler.
+
+```c
+static gboolean
+privmsg_cb(IbisClient *client, const char *command, IbisMessage *message,
+           gpointer data)
+{
+	/* PRIVMSG messages have a source of the user sending the message, and two
+	 * parameters. The first parameter is the target, either a user or a
+	 * channel, and the second parameter is the body of the message. However,
+	 * some servers implement this by using multiple parameters so we have to
+	 * work around this.
+	 */
+	GStrv params = NULL;
+	char *body = NULL;
+	const char *source = NULL;
+	const char *target = NULL;
+
+	/* Get the params from the message as we need to manipulate them. */
+	params = ibis_message_get_params(message);
+
+	/* Use g_strjoinv to merge the params, except for the first, into a space
+	 * separated string.
+	 */
+	body = g_strjoinv(" ", params + 1);
+
+	/* Store the source and target. */
+	source = ibis_message_get_source(message);
+	target = params[0];
+
+	/* Output the message to standard out. */
+	g_print("[%s] %s: %s\n", target, source, body);
+
+	/* Free the space separated string we created. */
+	g_free(body);
+
+	/* Finally return TRUE as we have handled the message. */
+	return TRUE;
+}
+```
+
+You will also probably want to connect to the notify signal for the
+[property@Client:connected] property. [class@Client] will set this property to
+`TRUE` once it has finished registration and is ready for general commands.
+
+```c
+g_signal_connect(client, "notify::connected", G_CALLBACK(connected_cb), NULL);
+```
+
+We'll add a simple handler here to join a channel.
+
+```c
+static void
+connected_cb(GObject *source, GParamSpec *pspec, gpointer data) {
+	IbisClient *client = IBIS_CLIENT(source);
+
+	/* This handler will be called whenever the property changes, even when it
+	 * is set to FALSE, so we need to verify it before sending a command.
+	 */
+	if(ibis_client_get_connected(client)) {
+		IbisMessage *message = NULL;
+
+		/* Messages are created by specifying the command they are for. */
+		message = ibis_message_new(IBIS_MSG_JOIN);
+
+		/* Message parameters can then be set via ibis_message_set_params. The
+		 * first parameter for a JOIN message is the name of the channel to
+		 * join.
+		 */
+		ibis_message_set_params(message, "#mychannel", NULL);
+
+		/* Now that the message is fully constructed, it can be sent to the
+		 * server via ibis_client_write, which will also take ownership of the
+		 * message and free it after it has been sent.
+		 */
+		ibis_client_write(client, message);
+	}
+}
+```
+
+Now that we have some signal handlers connected we can finally connect to a
+server.
+
+```c
+/* This will connect the client to irc.example.com on port 6667, without a
+ * server password, without tls, and without a proxy. Any of those values can
+ * be filled in as necessary, see [method@Client.connect] for more information.
+ */
+ibis_client_connect(client, "irc.example.com", 6667, NULL, FALSE, NULL);
+```
+
+That's it! You can now send and receive messages and Ibis will take care of
+everything else! When you want to disconnect, you can call
+[method@Client.disconnect].
diff --git a/ibis/reference/ibis.toml.in b/ibis/reference/ibis.toml.in
--- a/ibis/reference/ibis.toml.in
+++ b/ibis/reference/ibis.toml.in
@@ -36,7 +36,9 @@
 
 [extra]
 # The same order will be used when generating the index
-content_files = []
+content_files = [
+  'getting-started.md',
+]
 content_images = []
 urlmap_file = "urlmap.js"
 
diff --git a/ibis/reference/meson.build b/ibis/reference/meson.build
--- a/ibis/reference/meson.build
+++ b/ibis/reference/meson.build
@@ -2,7 +2,9 @@
   subdir_done()
 endif
 
-ibis_doc_content_files = []
+ibis_doc_content_files = [
+  'getting-started.md',
+]
 
 ibis_gidocgen_toml = configure_file(
   input : 'ibis.toml.in',
@@ -25,7 +27,7 @@
     '--content-dir=@0@'.format(meson.current_source_dir()),
     '@INPUT1@'
   ],
-  depend_files : [ ibis_doc_content_files ],
+  depend_files : ibis_doc_content_files,
   build_by_default : true,
   install : true,
   install_dir : docs_dir,
