#include "irc_client.h"
#include "log.h"
#include <stdlib.h>
#include <string.h>
err_t irc_client_create (struct irc_client **client_ptr, error_t *err)
{
struct irc_client *client;
// allocate
if ((client = calloc(1, sizeof(*client))) == NULL)
return SET_ERROR(err, ERR_CALLOC);
// init
TAILQ_INIT(&client->networks);
// ok
*client_ptr = client;
return SUCCESS;
}
void irc_client_destroy (struct irc_client *client)
{
struct irc_net *next = TAILQ_FIRST(&client->networks), *net;
// our networks
while (next) {
net = next;
next = TAILQ_NEXT(net, client_networks);
irc_net_destroy(net);
}
// ourselves
free(client);
}
void irc_client_set_defaults (struct irc_client *client, const struct irc_client_defaults *defaults)
{
client->defaults = *defaults;
}
#define APPLY_REGISTER_INFO_DEFAULT(out, value, def, _field_) ( \
((out)->register_info._field_ = ( \
(value)->register_info._field_ ? (value)->register_info._field_ : ( \
(def)->register_info._field_ \
) \
)) == NULL \
)
err_t irc_client_add_net (struct irc_client *client, struct irc_net **net_ptr, const struct irc_net_info *_net_info, error_t *err)
{
struct irc_net *net;
struct irc_net_info net_info = {
.ssl_cred = _net_info->ssl_cred,
};
// combine _net_info and defaults to get net_info
if (_net_info->transport)
RETURN_SET_ERROR_STR(err, ERR_IRC_NET_INFO, "transport");
if ((net_info.network = _net_info->network) == NULL)
RETURN_SET_ERROR_STR(err, ERR_IRC_NET_INFO, "network");
if ((net_info.hostname = _net_info->hostname) == NULL)
RETURN_SET_ERROR_STR(err, ERR_IRC_NET_INFO, "hostname");
if ((net_info.service = (_net_info->service ? _net_info->service : (
_net_info->ssl_cred ? client->defaults.service_ssl : client->defaults.service
))) == NULL)
RETURN_SET_ERROR_STR(err, ERR_IRC_NET_INFO, "service");
if (APPLY_REGISTER_INFO_DEFAULT(&net_info, _net_info, &client->defaults, nickname))
RETURN_SET_ERROR_STR(err, ERR_IRC_NET_INFO, "nickname");
if (APPLY_REGISTER_INFO_DEFAULT(&net_info, _net_info, &client->defaults, username))
RETURN_SET_ERROR_STR(err, ERR_IRC_NET_INFO, "username");
if (APPLY_REGISTER_INFO_DEFAULT(&net_info, _net_info, &client->defaults, realname))
RETURN_SET_ERROR_STR(err, ERR_IRC_NET_INFO, "realname");
// create the new irc_chan struct
if (irc_net_create(&net, &net_info, err))
return ERROR_CODE(err);
// add to network list
TAILQ_INSERT_TAIL(&client->networks, net, client_networks);
// ok
if (net_ptr)
*net_ptr = net;
return SET_ERROR(err, SUCCESS);
}
struct irc_net* irc_client_get_net (struct irc_client *client, const char *network)
{
struct irc_net *net = NULL;
// look for it...
TAILQ_FOREACH(net, &client->networks, client_networks) {
if (strcasecmp(net->info.network, network) == 0)
// found it
return net;
}
// no such network
return NULL;
}
struct irc_chan* irc_client_get_chan (struct irc_client *client, const char *network, const char *channel)
{
struct irc_net *net;
// lookup network
if ((net = irc_client_get_net(client, network)) == NULL)
return NULL;
// and then return channel lookup
return irc_net_get_chan(net, channel);
}
err_t irc_client_quit (struct irc_client *client, const char *message)
{
struct irc_net *net;
err_t err;
// quit each network
TAILQ_FOREACH(net, &client->networks, client_networks) {
if ((err = irc_net_quit(net, message))) {
log_err(err, "irc_net_quit: %s [%s]", net->info.network, message);
// XXX: destroy it?
}
}
// state
client->quitting = true;
// ok
return SUCCESS;
}