Blame bus/matchrule.c

Packit 3ff832
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
Packit 3ff832
/* vim:set et sts=4: */
Packit 3ff832
/* IBus - The Input Bus
Packit 3ff832
 * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
Packit 3ff832
 * Copyright (C) 2008-2010 Red Hat, Inc.
Packit 3ff832
 *
Packit 3ff832
 * This library is free software; you can redistribute it and/or
Packit 3ff832
 * modify it under the terms of the GNU Lesser General Public
Packit 3ff832
 * License as published by the Free Software Foundation; either
Packit 3ff832
 * version 2.1 of the License, or (at your option) any later version.
Packit 3ff832
 *
Packit 3ff832
 * This library is distributed in the hope that it will be useful,
Packit 3ff832
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 3ff832
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 3ff832
 * Lesser General Public License for more details.
Packit 3ff832
 *
Packit 3ff832
 * You should have received a copy of the GNU Lesser General Public
Packit 3ff832
 * License along with this library; if not, write to the Free Software
Packit 3ff832
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
Packit 3ff832
 * USA
Packit 3ff832
 */
Packit 3ff832
Packit 3ff832
#include "matchrule.h"
Packit 3ff832
Packit 3ff832
#include <string.h>
Packit 3ff832
Packit 3ff832
#include "dbusimpl.h"
Packit 3ff832
Packit 3ff832
typedef enum {
Packit 3ff832
    MATCH_TYPE          = 1 << 0,
Packit 3ff832
    MATCH_INTERFACE     = 1 << 1,
Packit 3ff832
    MATCH_MEMBER        = 1 << 2,
Packit 3ff832
    MATCH_SENDER        = 1 << 3,
Packit 3ff832
    MATCH_DESTINATION   = 1 << 4,
Packit 3ff832
    MATCH_PATH          = 1 << 5,
Packit 3ff832
    MATCH_ARGS          = 1 << 6,
Packit 3ff832
} BusMatchFlags;
Packit 3ff832
Packit 3ff832
struct _BusMatchRule {
Packit 3ff832
    IBusObject parent;
Packit 3ff832
    /* instance members */
Packit 3ff832
    gint   flags;
Packit 3ff832
    gint   message_type;
Packit 3ff832
    gchar *interface;
Packit 3ff832
    gchar *member;
Packit 3ff832
    gchar *sender;
Packit 3ff832
    gchar *destination;
Packit 3ff832
    gchar *path;
Packit 3ff832
    GArray *args;
Packit 3ff832
    GList *recipients;
Packit 3ff832
};
Packit 3ff832
Packit 3ff832
struct _BusMatchRuleClass {
Packit 3ff832
    IBusObjectClass parent;
Packit 3ff832
    /* class members */
Packit 3ff832
};
Packit 3ff832
Packit 3ff832
typedef struct _BusRecipient BusRecipient;
Packit 3ff832
struct _BusRecipient {
Packit 3ff832
    BusConnection *connection;
Packit 3ff832
    gint refcount;
Packit 3ff832
};
Packit 3ff832
Packit 3ff832
static BusRecipient *bus_recipient_new          (BusConnection      *connection);
Packit 3ff832
static void          bus_recipient_free         (BusRecipient       *recipient);
Packit 3ff832
static BusRecipient *bus_recipient_ref          (BusRecipient       *recipient);
Packit 3ff832
static gboolean      bus_recipient_unref        (BusRecipient       *recipient);
Packit 3ff832
static void          bus_match_rule_destroy     (BusMatchRule       *rule);
Packit 3ff832
static void          bus_match_rule_connection_destroy_cb
Packit 3ff832
                                                (BusConnection      *connection,
Packit 3ff832
                                                 BusMatchRule       *rule);
Packit 3ff832
Packit 3ff832
static BusRecipient *
Packit 3ff832
bus_recipient_new (BusConnection *connection)
Packit 3ff832
{
Packit 3ff832
    BusRecipient *recipient = g_slice_new (BusRecipient);
Packit 3ff832
    g_object_ref (connection);
Packit 3ff832
    recipient->connection = connection;
Packit 3ff832
    recipient->refcount = 1;
Packit 3ff832
    return recipient;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
bus_recipient_free (BusRecipient *recipient)
Packit 3ff832
{
Packit 3ff832
    g_object_unref (recipient->connection);
Packit 3ff832
    g_slice_free (BusRecipient, recipient);
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static BusRecipient *
Packit 3ff832
bus_recipient_ref (BusRecipient *recipient)
Packit 3ff832
{
Packit 3ff832
    recipient->refcount ++;
Packit 3ff832
    return recipient;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static gboolean
Packit 3ff832
bus_recipient_unref (BusRecipient *recipient)
Packit 3ff832
{
Packit 3ff832
    recipient->refcount --;
Packit 3ff832
    if (recipient->refcount == 0) {
Packit 3ff832
        bus_recipient_free (recipient);
Packit 3ff832
        return TRUE;
Packit 3ff832
    }
Packit 3ff832
    return FALSE;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
G_DEFINE_TYPE (BusMatchRule, bus_match_rule, IBUS_TYPE_OBJECT)
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
bus_match_rule_class_init (BusMatchRuleClass *class)
Packit 3ff832
{
Packit 3ff832
    IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (class);
Packit 3ff832
Packit 3ff832
    ibus_object_class->destroy = (IBusObjectDestroyFunc) bus_match_rule_destroy;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
bus_match_rule_init (BusMatchRule *rule)
Packit 3ff832
{
Packit 3ff832
    rule->flags = 0;
Packit 3ff832
    rule->message_type = G_DBUS_MESSAGE_TYPE_INVALID;
Packit 3ff832
    rule->interface = NULL;
Packit 3ff832
    rule->member = NULL;
Packit 3ff832
    rule->sender = NULL;
Packit 3ff832
    rule->destination = NULL;
Packit 3ff832
    rule->path = NULL;
Packit 3ff832
    rule->args = g_array_new (TRUE, TRUE, sizeof (gchar *));
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
bus_match_rule_destroy (BusMatchRule *rule)
Packit 3ff832
{
Packit 3ff832
    g_free (rule->interface);
Packit 3ff832
    g_free (rule->member);
Packit 3ff832
    g_free (rule->sender);
Packit 3ff832
    g_free (rule->destination);
Packit 3ff832
    g_free (rule->path);
Packit 3ff832
Packit 3ff832
    gint i;
Packit 3ff832
    for (i = 0; i < rule->args->len; i++) {
Packit 3ff832
        g_free (g_array_index (rule->args, gchar *, i));
Packit 3ff832
    }
Packit 3ff832
    g_array_free (rule->args, TRUE);
Packit 3ff832
Packit 3ff832
    GList *p;
Packit 3ff832
    for (p = rule->recipients; p != NULL; p = p->next) {
Packit 3ff832
        BusRecipient *recipient = (BusRecipient *) p->data;
Packit 3ff832
        g_signal_handlers_disconnect_by_func (recipient->connection,
Packit 3ff832
                                              G_CALLBACK (bus_match_rule_connection_destroy_cb), rule);
Packit 3ff832
        bus_recipient_free (recipient);
Packit 3ff832
    }
Packit 3ff832
    g_list_free (rule->recipients);
Packit 3ff832
Packit 3ff832
    IBUS_OBJECT_CLASS(bus_match_rule_parent_class)->destroy (IBUS_OBJECT (rule));
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
Packit 3ff832
typedef struct _Token {
Packit 3ff832
    gchar *key;
Packit 3ff832
    gchar *value;
Packit 3ff832
} Token;
Packit 3ff832
Packit 3ff832
#define SKIP_WHITE(a)   \
Packit 3ff832
    while (*(a) == ' ' || *(a) == '\t' || *(a) == '\n') { (a)++; }
Packit 3ff832
#define IS_ALPHA(a) \
Packit 3ff832
    ((*(a) >= 'a' && *(a) <= 'z') || (*(a) >= 'A' && *(a) <= 'Z'))
Packit 3ff832
#define IS_NUMBER(a) \
Packit 3ff832
    (*(a) >= '0' && *(a) <= '9')
Packit 3ff832
Packit 3ff832
static gchar *
Packit 3ff832
find_key (const gchar **p)
Packit 3ff832
{
Packit 3ff832
    GString *text;
Packit 3ff832
Packit 3ff832
    text = g_string_new ("");
Packit 3ff832
Packit 3ff832
    SKIP_WHITE(*p)
Packit 3ff832
    if (!IS_ALPHA (*p))
Packit 3ff832
        goto failed;
Packit 3ff832
Packit 3ff832
    g_string_append_c (text, **p);
Packit 3ff832
    (*p) ++;
Packit 3ff832
Packit 3ff832
    while (IS_ALPHA (*p) || IS_NUMBER (*p)) {
Packit 3ff832
        g_string_append_c (text, **p);
Packit 3ff832
        (*p) ++;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    return g_string_free (text, FALSE);
Packit 3ff832
Packit 3ff832
failed:
Packit 3ff832
    g_string_free (text, TRUE);
Packit 3ff832
    return NULL;
Packit 3ff832
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static gchar *
Packit 3ff832
find_value (const gchar **p)
Packit 3ff832
{
Packit 3ff832
    SKIP_WHITE (*p);
Packit 3ff832
Packit 3ff832
    if (**p == '\'') {
Packit 3ff832
        GString *text = g_string_new ("");
Packit 3ff832
        (*p) ++;
Packit 3ff832
        while (**p != '\'') {
Packit 3ff832
            if (**p == '\0') {
Packit 3ff832
                g_string_free (text, TRUE);
Packit 3ff832
                return NULL;
Packit 3ff832
            }
Packit 3ff832
            if (**p == '\\')
Packit 3ff832
                (*p) ++;
Packit 3ff832
            g_string_append_c (text, **p);
Packit 3ff832
            (*p) ++;
Packit 3ff832
        }
Packit 3ff832
        (*p) ++;
Packit 3ff832
        return g_string_free (text, FALSE);
Packit 3ff832
    } else if (strncmp (*p, "true", 4) == 0) {
Packit 3ff832
        *p += 4;
Packit 3ff832
        return g_strdup ("true");
Packit 3ff832
    } else if (strncmp (*p, "false", 5) == 0) {
Packit 3ff832
        *p += 5;
Packit 3ff832
        return g_strdup ("false");
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    return NULL;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static Token *
Packit 3ff832
tokenize_rule (const gchar *text)
Packit 3ff832
{
Packit 3ff832
    GArray *tokens;
Packit 3ff832
    Token token;
Packit 3ff832
    const gchar *p;
Packit 3ff832
    gint i;
Packit 3ff832
Packit 3ff832
    tokens = g_array_new (TRUE, TRUE, sizeof (Token));
Packit 3ff832
Packit 3ff832
    p = text;
Packit 3ff832
Packit 3ff832
    while (*p != '\0') {
Packit 3ff832
        gchar *key;
Packit 3ff832
        gchar *value;
Packit 3ff832
Packit 3ff832
        SKIP_WHITE (p);
Packit 3ff832
        key = find_key (&p);
Packit 3ff832
        if (key == NULL)
Packit 3ff832
            goto failed;
Packit 3ff832
        SKIP_WHITE (p);
Packit 3ff832
        if (*p != '=')
Packit 3ff832
            goto failed;
Packit 3ff832
        p ++;
Packit 3ff832
        SKIP_WHITE (p);
Packit 3ff832
        value = find_value (&p);
Packit 3ff832
        if (value == NULL) {
Packit 3ff832
            g_free (key);
Packit 3ff832
            goto failed;
Packit 3ff832
        }
Packit 3ff832
        SKIP_WHITE (p);
Packit 3ff832
        if (*p != ',' && *p != '\0') {
Packit 3ff832
            g_free (key);
Packit 3ff832
            g_free (value);
Packit 3ff832
            goto failed;
Packit 3ff832
        }
Packit 3ff832
Packit 3ff832
        if (*p == ',')
Packit 3ff832
         p ++;
Packit 3ff832
        token.key = key;
Packit 3ff832
        token.value = value;
Packit 3ff832
        g_array_append_val (tokens, token);
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    return (Token *)g_array_free (tokens, FALSE);
Packit 3ff832
Packit 3ff832
failed:
Packit 3ff832
    for (i = 0; i < tokens->len; i++) {
Packit 3ff832
        Token *p = &g_array_index (tokens, Token, i);
Packit 3ff832
        g_free (p->key);
Packit 3ff832
        g_free (p->value);
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    g_array_free (tokens, TRUE);
Packit 3ff832
    return NULL;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
tokens_free (Token *tokens)
Packit 3ff832
{
Packit 3ff832
    Token *p;
Packit 3ff832
    p = tokens;
Packit 3ff832
Packit 3ff832
    while (p != NULL && p->key != NULL) {
Packit 3ff832
        g_free (p->key);
Packit 3ff832
        g_free (p->value);
Packit 3ff832
        p ++;
Packit 3ff832
    }
Packit 3ff832
    g_free (tokens);
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static gboolean
Packit 3ff832
_atoi (const gchar *text, gint *i)
Packit 3ff832
{
Packit 3ff832
    const gchar *p = text;
Packit 3ff832
    *i = 0;
Packit 3ff832
    while (*p != '\0') {
Packit 3ff832
        if (!IS_NUMBER(p))
Packit 3ff832
            return FALSE;
Packit 3ff832
        *i = (*i) * 10 - '0'  + *p;
Packit 3ff832
        p ++;
Packit 3ff832
    }
Packit 3ff832
    return TRUE;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
BusMatchRule *
Packit 3ff832
bus_match_rule_new (const gchar *text)
Packit 3ff832
{
Packit 3ff832
    g_assert (text != NULL);
Packit 3ff832
Packit 3ff832
    Token *tokens, *p;
Packit 3ff832
    BusMatchRule *rule;
Packit 3ff832
Packit 3ff832
    rule = BUS_MATCH_RULE (g_object_new (BUS_TYPE_MATCH_RULE, NULL));
Packit 3ff832
Packit 3ff832
    /* parse rule */
Packit 3ff832
    tokens = tokenize_rule (text);
Packit 3ff832
Packit 3ff832
    if (tokens == NULL)
Packit 3ff832
        goto failed;
Packit 3ff832
Packit 3ff832
    for (p = tokens; p != NULL && p->key != 0; p++) {
Packit 3ff832
        if (g_strcmp0 (p->key, "type") == 0) {
Packit 3ff832
            if (g_strcmp0 (p->value, "signal") == 0) {
Packit 3ff832
                bus_match_rule_set_message_type (rule, G_DBUS_MESSAGE_TYPE_SIGNAL);
Packit 3ff832
            }
Packit 3ff832
            else if (g_strcmp0 (p->value, "method_call") == 0) {
Packit 3ff832
                bus_match_rule_set_message_type (rule, G_DBUS_MESSAGE_TYPE_METHOD_CALL);
Packit 3ff832
            }
Packit 3ff832
            else if (g_strcmp0 (p->value, "method_return") == 0) {
Packit 3ff832
                bus_match_rule_set_message_type (rule, G_DBUS_MESSAGE_TYPE_METHOD_RETURN);
Packit 3ff832
            }
Packit 3ff832
            else if (g_strcmp0 (p->value, "error") == 0) {
Packit 3ff832
                bus_match_rule_set_message_type (rule, G_DBUS_MESSAGE_TYPE_ERROR);
Packit 3ff832
            }
Packit 3ff832
            else
Packit 3ff832
                goto failed;
Packit 3ff832
        }
Packit 3ff832
        else if (g_strcmp0 (p->key, "sender") == 0) {
Packit 3ff832
            if (!g_dbus_is_name (p->value))
Packit 3ff832
                goto failed;
Packit 3ff832
            bus_match_rule_set_sender (rule, p->value);
Packit 3ff832
        }
Packit 3ff832
        else if (g_strcmp0 (p->key, "interface") == 0) {
Packit 3ff832
            if (!g_dbus_is_interface_name (p->value))
Packit 3ff832
                goto failed;
Packit 3ff832
            bus_match_rule_set_interface (rule, p->value);
Packit 3ff832
        }
Packit 3ff832
        else if (g_strcmp0 (p->key, "member") == 0) {
Packit 3ff832
            if (!g_dbus_is_member_name (p->value))
Packit 3ff832
                goto failed;
Packit 3ff832
            bus_match_rule_set_member (rule, p->value);
Packit 3ff832
        }
Packit 3ff832
        else if (g_strcmp0 (p->key, "path") == 0) {
Packit 3ff832
            bus_match_rule_set_path (rule, p->value);
Packit 3ff832
        }
Packit 3ff832
        else if (g_strcmp0 (p->key, "destination") == 0) {
Packit 3ff832
            if (!g_dbus_is_name (p->value))
Packit 3ff832
                goto failed;
Packit 3ff832
            bus_match_rule_set_destination (rule, p->value);
Packit 3ff832
        }
Packit 3ff832
        else if (strncmp (p->key, "arg", 3) == 0) {
Packit 3ff832
            gint i;
Packit 3ff832
            if (! _atoi (p->key + 3, &i))
Packit 3ff832
                goto failed;
Packit 3ff832
            bus_match_rule_set_arg (rule, i, p->value);
Packit 3ff832
        }
Packit 3ff832
        else if (g_strcmp0 (p->key, "eavesdrop") == 0) {
Packit 3ff832
            if (g_strcmp0 (p->value, "true") != 0 &&
Packit 3ff832
                g_strcmp0 (p->value, "false") != 0)
Packit 3ff832
                goto failed;
Packit 3ff832
        }
Packit 3ff832
        else
Packit 3ff832
            goto failed;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    tokens_free (tokens);
Packit 3ff832
    return rule;
Packit 3ff832
Packit 3ff832
failed:
Packit 3ff832
    tokens_free (tokens);
Packit 3ff832
    g_object_unref (rule);
Packit 3ff832
    return NULL;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
gboolean
Packit 3ff832
bus_match_rule_set_message_type (BusMatchRule   *rule,
Packit 3ff832
                                 gint            type)
Packit 3ff832
{
Packit 3ff832
    g_assert (rule != NULL);
Packit 3ff832
    g_assert (type == G_DBUS_MESSAGE_TYPE_SIGNAL ||
Packit 3ff832
              type == G_DBUS_MESSAGE_TYPE_METHOD_CALL ||
Packit 3ff832
              type == G_DBUS_MESSAGE_TYPE_METHOD_RETURN ||
Packit 3ff832
              type == G_DBUS_MESSAGE_TYPE_ERROR);
Packit 3ff832
Packit 3ff832
    rule->flags |= MATCH_TYPE;
Packit 3ff832
    rule->message_type = type;
Packit 3ff832
Packit 3ff832
    return TRUE;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
gboolean
Packit 3ff832
bus_match_rule_set_sender  (BusMatchRule    *rule,
Packit 3ff832
                            const gchar     *sender)
Packit 3ff832
{
Packit 3ff832
    g_assert (rule != NULL);
Packit 3ff832
    g_assert (sender != NULL);
Packit 3ff832
Packit 3ff832
    rule->flags |= MATCH_SENDER;
Packit 3ff832
Packit 3ff832
    g_free (rule->sender);
Packit 3ff832
    rule->sender = g_strdup (sender);
Packit 3ff832
Packit 3ff832
    return TRUE;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
gboolean
Packit 3ff832
bus_match_rule_set_interface (BusMatchRule   *rule,
Packit 3ff832
                              const gchar    *interface)
Packit 3ff832
{
Packit 3ff832
    g_assert (rule != NULL);
Packit 3ff832
    g_assert (interface != NULL);
Packit 3ff832
Packit 3ff832
    rule->flags |= MATCH_INTERFACE;
Packit 3ff832
Packit 3ff832
    g_free (rule->interface);
Packit 3ff832
    rule->interface = g_strdup (interface);
Packit 3ff832
    return TRUE;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
gboolean
Packit 3ff832
bus_match_rule_set_member (BusMatchRule   *rule,
Packit 3ff832
                           const gchar    *member)
Packit 3ff832
{
Packit 3ff832
    g_assert (rule != NULL);
Packit 3ff832
    g_assert (member != NULL);
Packit 3ff832
Packit 3ff832
    rule->flags |= MATCH_MEMBER;
Packit 3ff832
Packit 3ff832
    g_free (rule->member);
Packit 3ff832
    rule->member = g_strdup (member);
Packit 3ff832
Packit 3ff832
    return TRUE;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
gboolean
Packit 3ff832
bus_match_rule_set_path (BusMatchRule   *rule,
Packit 3ff832
                         const gchar    *path)
Packit 3ff832
{
Packit 3ff832
    g_assert (rule != NULL);
Packit 3ff832
    g_assert (path != NULL);
Packit 3ff832
Packit 3ff832
    rule->flags |= MATCH_PATH;
Packit 3ff832
Packit 3ff832
    g_free (rule->path);
Packit 3ff832
    rule->path = g_strdup (path);
Packit 3ff832
Packit 3ff832
    return TRUE;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
gboolean
Packit 3ff832
bus_match_rule_set_destination (BusMatchRule   *rule,
Packit 3ff832
                                const gchar    *dest)
Packit 3ff832
{
Packit 3ff832
    g_assert (rule != NULL);
Packit 3ff832
    g_assert (dest != NULL);
Packit 3ff832
Packit 3ff832
    rule->flags |= MATCH_DESTINATION;
Packit 3ff832
Packit 3ff832
    g_free (rule->destination);
Packit 3ff832
    rule->destination = g_strdup (dest);
Packit 3ff832
Packit 3ff832
    return TRUE;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
gboolean
Packit 3ff832
bus_match_rule_set_arg (BusMatchRule   *rule,
Packit 3ff832
                        guint           arg_i,
Packit 3ff832
                        const gchar    *arg)
Packit 3ff832
{
Packit 3ff832
    g_assert (rule != NULL);
Packit 3ff832
    g_assert (arg != NULL);
Packit 3ff832
Packit 3ff832
    rule->flags |= MATCH_ARGS;
Packit 3ff832
Packit 3ff832
    if (arg_i >= rule->args->len) {
Packit 3ff832
        g_array_set_size (rule->args, arg_i + 1);
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    g_free (g_array_index (rule->args, gchar *, arg_i));
Packit 3ff832
    g_array_index (rule->args, gchar *, arg_i) = g_strdup (arg);
Packit 3ff832
    return TRUE;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static gboolean
Packit 3ff832
bus_match_rule_match_name (const gchar *name,
Packit 3ff832
                           const gchar *match_name)
Packit 3ff832
{
Packit 3ff832
    if (g_dbus_is_unique_name (name) && !g_dbus_is_unique_name (match_name)) {
Packit 3ff832
        BusConnection *connection =
Packit 3ff832
                bus_dbus_impl_get_connection_by_name (BUS_DEFAULT_DBUS, match_name);
Packit 3ff832
        if (connection == NULL)
Packit 3ff832
            return FALSE;
Packit 3ff832
        return g_strcmp0 (name, bus_connection_get_unique_name (connection)) == 0;
Packit 3ff832
    }
Packit 3ff832
    return g_strcmp0 (name, match_name) == 0;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
gboolean
Packit 3ff832
bus_match_rule_match (BusMatchRule   *rule,
Packit 3ff832
                      GDBusMessage   *message)
Packit 3ff832
{
Packit 3ff832
    g_assert (rule != NULL);
Packit 3ff832
    g_assert (message != NULL);
Packit 3ff832
Packit 3ff832
    if (rule->flags & MATCH_TYPE) {
Packit 3ff832
        if (g_dbus_message_get_message_type (message) != rule->message_type)
Packit 3ff832
            return FALSE;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    if (rule->flags & MATCH_INTERFACE) {
Packit 3ff832
        if (g_strcmp0 (g_dbus_message_get_interface (message), rule->interface) != 0)
Packit 3ff832
            return FALSE;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    if (rule->flags & MATCH_MEMBER) {
Packit 3ff832
        if (g_strcmp0 (g_dbus_message_get_member (message), rule->member) != 0)
Packit 3ff832
            return FALSE;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    if (rule->flags & MATCH_SENDER) {
Packit 3ff832
        if (!bus_match_rule_match_name (g_dbus_message_get_sender (message), rule->sender))
Packit 3ff832
            return FALSE;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    if (rule->flags & MATCH_DESTINATION) {
Packit 3ff832
        if (!bus_match_rule_match_name (g_dbus_message_get_destination (message), rule->destination))
Packit 3ff832
            return FALSE;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    if (rule->flags & MATCH_PATH) {
Packit 3ff832
        if (g_strcmp0 (g_dbus_message_get_path (message), rule->path) != 0)
Packit 3ff832
            return FALSE;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    if (rule->flags & MATCH_ARGS) {
Packit 3ff832
        guint i;
Packit 3ff832
        GVariant *arguments = g_dbus_message_get_body (message);
Packit 3ff832
        if (arguments == NULL)
Packit 3ff832
            return FALSE;
Packit 3ff832
Packit 3ff832
        for (i = 0; i < rule->args->len; i++) {
Packit 3ff832
            const gchar *arg = g_array_index (rule->args, const gchar *, i);
Packit 3ff832
            if (arg == NULL)
Packit 3ff832
                continue;
Packit 3ff832
            GVariant * variant = g_variant_get_child_value (arguments, i);
Packit 3ff832
            if (variant == NULL)
Packit 3ff832
                return FALSE;
Packit 3ff832
            switch (g_variant_classify (variant)) {
Packit 3ff832
            case G_VARIANT_CLASS_STRING:
Packit 3ff832
            case G_VARIANT_CLASS_OBJECT_PATH:
Packit 3ff832
                if (g_strcmp0 (arg, g_variant_get_string (variant, NULL)) == 0) {
Packit 3ff832
                    g_variant_unref (variant);
Packit 3ff832
                    continue;
Packit 3ff832
                }
Packit 3ff832
            default:
Packit 3ff832
                break;
Packit 3ff832
            }
Packit 3ff832
            g_variant_unref (variant);
Packit 3ff832
            return FALSE;
Packit 3ff832
        }
Packit 3ff832
    }
Packit 3ff832
    return TRUE;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
gboolean
Packit 3ff832
bus_match_rule_is_equal (BusMatchRule   *a,
Packit 3ff832
                         BusMatchRule   *b)
Packit 3ff832
{
Packit 3ff832
    g_assert (a != NULL);
Packit 3ff832
    g_assert (b != NULL);
Packit 3ff832
Packit 3ff832
    if (a->flags != b->flags)
Packit 3ff832
        return FALSE;
Packit 3ff832
Packit 3ff832
    if (a->flags & MATCH_TYPE) {
Packit 3ff832
        if (a->message_type != b->message_type)
Packit 3ff832
            return FALSE;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    if (a->flags & MATCH_INTERFACE) {
Packit 3ff832
        if (g_strcmp0 (a->interface, b->interface) != 0)
Packit 3ff832
            return FALSE;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    if (a->flags & MATCH_MEMBER) {
Packit 3ff832
        if (g_strcmp0 (a->member, b->member) != 0)
Packit 3ff832
            return FALSE;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    if (a->flags & MATCH_SENDER) {
Packit 3ff832
        if (g_strcmp0 (a->sender, b->sender) != 0)
Packit 3ff832
            return FALSE;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    if (a->flags & MATCH_DESTINATION) {
Packit 3ff832
        if (g_strcmp0 (a->destination, b->destination) != 0)
Packit 3ff832
            return FALSE;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    if (a->flags & MATCH_PATH) {
Packit 3ff832
        if (g_strcmp0 (a->path, b->path) != 0)
Packit 3ff832
            return FALSE;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    if (a->flags & MATCH_ARGS) {
Packit 3ff832
        if (a->args->len != b->args->len)
Packit 3ff832
            return FALSE;
Packit 3ff832
Packit 3ff832
        gint i;
Packit 3ff832
Packit 3ff832
        for (i = 0; i < a->args->len; i++) {
Packit 3ff832
            if (g_strcmp0 (g_array_index (a->args, gchar *, i),
Packit 3ff832
                           g_array_index (b->args, gchar *, i)) != 0)
Packit 3ff832
                return FALSE;
Packit 3ff832
        }
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    return TRUE;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
bus_match_rule_connection_destroy_cb (BusConnection *connection,
Packit 3ff832
                                      BusMatchRule  *rule)
Packit 3ff832
{
Packit 3ff832
    GList *p;
Packit 3ff832
    for (p = rule->recipients; p != NULL; p = p->next) {
Packit 3ff832
        BusRecipient *recipient = (BusRecipient *)p->data;
Packit 3ff832
Packit 3ff832
        if (recipient->connection == connection) {
Packit 3ff832
            rule->recipients = g_list_remove_link (rule->recipients, p);
Packit 3ff832
            bus_recipient_free (recipient);
Packit 3ff832
            return;
Packit 3ff832
        }
Packit 3ff832
Packit 3ff832
        if (rule->recipients == NULL) {
Packit 3ff832
            ibus_object_destroy (IBUS_OBJECT (rule));
Packit 3ff832
        }
Packit 3ff832
    }
Packit 3ff832
    g_assert_not_reached ();
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
void
Packit 3ff832
bus_match_rule_add_recipient (BusMatchRule    *rule,
Packit 3ff832
                              BusConnection   *connection)
Packit 3ff832
{
Packit 3ff832
    g_assert (BUS_IS_MATCH_RULE (rule));
Packit 3ff832
    g_assert (BUS_IS_CONNECTION (connection));
Packit 3ff832
Packit 3ff832
    GList *p;
Packit 3ff832
    for (p = rule->recipients; p != NULL; p = p->next) {
Packit 3ff832
        BusRecipient *recipient = (BusRecipient *) p->data;
Packit 3ff832
        if (connection == recipient->connection) {
Packit 3ff832
            bus_recipient_ref (recipient);
Packit 3ff832
            return;
Packit 3ff832
        }
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    /* alloc a new recipient */
Packit 3ff832
    BusRecipient *recipient = bus_recipient_new (connection);
Packit 3ff832
    rule->recipients = g_list_append (rule->recipients, recipient);
Packit 3ff832
    g_signal_connect (connection,
Packit 3ff832
                      "destroy",
Packit 3ff832
                      G_CALLBACK (bus_match_rule_connection_destroy_cb),
Packit 3ff832
                      rule);
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
void
Packit 3ff832
bus_match_rule_remove_recipient (BusMatchRule  *rule,
Packit 3ff832
                                 BusConnection *connection)
Packit 3ff832
{
Packit 3ff832
    g_assert (BUS_IS_MATCH_RULE (rule));
Packit 3ff832
    g_assert (BUS_IS_CONNECTION (connection));
Packit 3ff832
Packit 3ff832
    GList *p;
Packit 3ff832
    for (p = rule->recipients; p != NULL; p = p->next) {
Packit 3ff832
        BusRecipient *recipient = (BusRecipient *) p->data;
Packit 3ff832
        if (connection == recipient->connection) {
Packit 3ff832
            if (bus_recipient_unref (recipient)) {
Packit 3ff832
                rule->recipients = g_list_remove_link (rule->recipients, p);
Packit 3ff832
                g_signal_handlers_disconnect_by_func (connection,
Packit 3ff832
                                                      G_CALLBACK (bus_match_rule_connection_destroy_cb),
Packit 3ff832
                                                      rule);
Packit 3ff832
            }
Packit 3ff832
Packit 3ff832
            if (rule->recipients == NULL ) {
Packit 3ff832
                ibus_object_destroy (IBUS_OBJECT(rule));
Packit 3ff832
            }
Packit 3ff832
            return;
Packit 3ff832
        }
Packit 3ff832
    }
Packit 3ff832
    g_return_if_reached ();
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
GList *
Packit 3ff832
bus_match_rule_get_recipients (BusMatchRule   *rule,
Packit 3ff832
                               GDBusMessage   *message)
Packit 3ff832
{
Packit 3ff832
    g_assert (BUS_IS_MATCH_RULE (rule));
Packit 3ff832
    g_assert (message != NULL);
Packit 3ff832
Packit 3ff832
    GList *link;
Packit 3ff832
    GList *recipients = NULL;
Packit 3ff832
Packit 3ff832
    if (!bus_match_rule_match (rule, message))
Packit 3ff832
        return FALSE;
Packit 3ff832
Packit 3ff832
    for (link = rule->recipients; link != NULL; link = link->next) {
Packit 3ff832
        BusRecipient *recipient = (BusRecipient *) link->data;
Packit 3ff832
Packit 3ff832
        recipients = g_list_append (recipients, recipient->connection);
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    return recipients;
Packit 3ff832
}
Packit 3ff832