src/irc_client.c
author Tero Marttila <terom@fixme.fi>
Thu, 28 May 2009 01:17:36 +0300
branchnew-lib-errors
changeset 219 cefec18b8268
parent 217 7728d6ec3abf
permissions -rw-r--r--
some of the lib/transport stuff compiles
#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;
}