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 allow 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 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, let's 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 let's 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].
