<commit_before>#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <dbus/dbus.h>

#include <telepathy-glib/interfaces.h>
#include <telepathy-glib/channel.h>
#include <telepathy-glib/connection.h>
#include <mission-control/mcd-plugin.h>
#include <mission-control/mcd-dispatcher.h>
#include <mission-control/mcd-dispatcher-context.h>
#include <gconf/gconf-client.h>

#include "mcd-policy-filter-plugin.h"

#define PLUGIN_NAME "policy-filter"
#define MAX_CALLS   8
#define ALLOW       TRUE
#define REJECT      FALSE

#define EMIT(f, fmt, args...) do {                               \
        f("[%s] %s: "fmt, PLUGIN_NAME, __FUNCTION__, ## args);   \
    } while(0)

#define ERROR(fmt, args...)   EMIT(g_error  , fmt, ## args)
#define WARNING(fmt, args...) EMIT(g_warning, fmt, ## args)
#define INFO(fmt, args...)    EMIT(g_message, fmt, ## args)
#define DEBUG(fmt, args...)   EMIT(g_debug  , fmt, ## args)

#define DBUS_ERROR(err) ((err).message ? (err).message : "unknown")

static int  policy_call_request(const char *, int, McdDispatcherContext *);
static void policy_call_reply  (DBusPendingCall *, void *);
static int  policy_call_ended  (const char *);

static void call_allow (McdDispatcherContext *);
static void call_reject(McdDispatcherContext *);

static DBusHandlerResult owner_changed(DBusConnection *, DBusMessage *, void *);


static DBusConnection *bus;                 /* session bus connections */
static char           *calls[MAX_CALLS];    /* object paths of current calls */
static int             ncall;               /* number of current calls */

static int             policy_down = 1;     /* whether OHM/policy is down */


/*****************************************************************************
 *                             *** DBUS interface ***                        *
 *****************************************************************************/

static int
dbus_init(void)
{
#define FAIL(fmt, args...) do { WARNING(fmt, ## args); goto fail; } while (0)

    char *rule = "type='signal',sender='"DBUS_INTERFACE_DBUS"',"        \
        "interface='"DBUS_INTERFACE_DBUS"',member='"OWNER_CHANGED"'";
    DBusError  err;
    int        present;

    dbus_error_init(&err);

    if ((bus = dbus_bus_get(DBUS_BUS_SESSION, &err)) == NULL)
        FAIL("failed to connect to DBUS session bus (%s)", DBUS_ERROR(err));

    dbus_bus_add_match(bus, rule, &err);
    if (dbus_error_is_set(&err))
        FAIL("failed to install DBUS match rule %s (%s)", rule,
             DBUS_ERROR(err));

    if (!dbus_connection_add_filter(bus, owner_changed, NULL, NULL))
        FAIL("failed to install owner_changed filter");
    
    present = dbus_bus_name_has_owner(bus, POLICY_TELEPHONY_INTERFACE, &err);
    if (dbus_error_is_set(&err))
        FAIL("failed to query D-BUS for name %s", POLICY_TELEPHONY_INTERFACE);
    
    policy_down = !present;

    return TRUE;
    
fail:
    dbus_error_free(&err);
    return FALSE;
}


static DBusHandlerResult
owner_changed(DBusConnection *c, DBusMessage *msg, void *data)
{
    const char *name, *prev, *curr;
    
    if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS, OWNER_CHANGED))
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

    if (!dbus_message_get_args(msg, NULL,
                               DBUS_TYPE_STRING, &name,
                               DBUS_TYPE_STRING, &prev,
                               DBUS_TYPE_STRING, &curr,
                               DBUS_TYPE_INVALID))
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
                               
    if (strcmp(name, POLICY_TELEPHONY_INTERFACE))
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    
    if ((prev && prev[0]) && (!curr || !curr[0])) {
        INFO("policy interface at %s went down", prev);
        policy_down = 1;
        return DBUS_HANDLER_RESULT_HANDLED;
    }
    
    if ((!prev || !prev[0]) && (curr && curr[0])) {
        INFO("policy interface came up at %s", curr);
        policy_down = 0;
        /* XXX TODO: should send current list of calls... */
        return DBUS_HANDLER_RESULT_HANDLED;
    }
    
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

    (void)c;
    (void)data;
    
}




/*****************************************************************************
 *                            *** policy interface ***                       *
 *****************************************************************************/

static int
policy_call_request(const char *id, int incoming, McdDispatcherContext *ctx)
{
#define FAIL(fmt, args...) do { WARNING(fmt, ## args); goto fail; } while (0)

    DBusMessage     *msg     = NULL;
    DBusPendingCall *pending = NULL;;
    char            *name, *path, *iface, *method;
    dbus_bool_t      in = incoming ? TRUE : FALSE;
    dbus_int32_t     n;

    if (bus == NULL)
        FAIL("no connection to D-BUS");

    if (policy_down)
        FAIL("policy service is currently down");
    
    name   = POLICY_TELEPHONY_INTERFACE;
    path   = POLICY_TELEPHONY_PATH;
    iface  = POLICY_TELEPHONY_INTERFACE;
    method = POLICY_TELEPHONY_CALL_REQ;
    n      = ncall;
    msg    = dbus_message_new_method_call(name, path, iface, method);

    if (msg == NULL)
        FAIL("failed to create DBUS method call");
    
    if (!dbus_message_append_args(msg,
                                  DBUS_TYPE_STRING, &id,
                                  DBUS_TYPE_BOOLEAN, &in,
                                  DBUS_TYPE_INT32, &n, DBUS_TYPE_INVALID))
        FAIL("failed to create DBUS method call");
    
    if (!dbus_connection_send_with_reply(bus, msg, &pending, DBUS_TIMEOUT))
        FAIL("failed to send DBUS message to %s", name);

    if (!dbus_pending_call_set_notify(pending, policy_call_reply, ctx, NULL))
        FAIL("failed to set pending DBUS call callback");
    
    return TRUE;


 fail:
    if (pending)
        dbus_pending_call_cancel(pending);
    if (msg)        
        dbus_message_unref(msg);

    return FALSE;

#undef FAIL
}


static void
policy_call_reply(DBusPendingCall *pending, void *user_data)
{
#define FAIL(fmt, args...) do { WARNING(fmt, ## args); goto fail; } while (0)
<commit_msg>More diagnostic printouts...<commit_after>#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <dbus/dbus.h>

#include <telepathy-glib/interfaces.h>
#include <telepathy-glib/channel.h>
#include <telepathy-glib/connection.h>
#include <mission-control/mcd-plugin.h>
#include <mission-control/mcd-dispatcher.h>
#include <mission-control/mcd-dispatcher-context.h>
#include <gconf/gconf-client.h>

#include "mcd-policy-filter-plugin.h"

#define PLUGIN_NAME "policy-filter"
#define MAX_CALLS   8
#define ALLOW       TRUE
#define REJECT      FALSE

#define EMIT(f, fmt, args...) do {                               \
        f("[%s] %s: "fmt, PLUGIN_NAME, __FUNCTION__, ## args);   \
    } while(0)

#define ERROR(fmt, args...)   EMIT(g_error  , fmt, ## args)
#define WARNING(fmt, args...) EMIT(g_warning, fmt, ## args)
#define INFO(fmt, args...)    EMIT(g_message, fmt, ## args)
#define DEBUG(fmt, args...)   EMIT(g_debug  , fmt, ## args)

#define DBUS_ERROR(err) ((err).message ? (err).message : "unknown")

static int  policy_call_request(const char *, int, McdDispatcherContext *);
static void policy_call_reply  (DBusPendingCall *, void *);
static int  policy_call_ended  (const char *);

static void call_allow (McdDispatcherContext *);
static void call_reject(McdDispatcherContext *);

static DBusHandlerResult owner_changed(DBusConnection *, DBusMessage *, void *);


static DBusConnection *bus;                 /* session bus connections */
static char           *calls[MAX_CALLS];    /* object paths of current calls */
static int             ncall;               /* number of current calls */

static int             policy_down = 1;     /* whether OHM/policy is down */


/*****************************************************************************
 *                             *** DBUS interface ***                        *
 *****************************************************************************/

static int
dbus_init(void)
{
#define FAIL(fmt, args...) do { WARNING(fmt, ## args); goto fail; } while (0)

    char *rule = "type='signal',sender='"DBUS_INTERFACE_DBUS"',"        \
        "interface='"DBUS_INTERFACE_DBUS"',member='"OWNER_CHANGED"'";
    DBusError  err;
    int        present;

    dbus_error_init(&err);

    if ((bus = dbus_bus_get(DBUS_BUS_SESSION, &err)) == NULL)
        FAIL("failed to connect to DBUS session bus (%s)", DBUS_ERROR(err));

    dbus_bus_add_match(bus, rule, &err);
    if (dbus_error_is_set(&err))
        FAIL("failed to install DBUS match rule %s (%s)", rule,
             DBUS_ERROR(err));

    if (!dbus_connection_add_filter(bus, owner_changed, NULL, NULL))
        FAIL("failed to install owner_changed filter");
    
    present = dbus_bus_name_has_owner(bus, POLICY_TELEPHONY_INTERFACE, &err);
    if (dbus_error_is_set(&err))
        FAIL("failed to query D-BUS for name %s", POLICY_TELEPHONY_INTERFACE);
    
    policy_down = !present;

    return TRUE;
    
fail:
    dbus_error_free(&err);
    return FALSE;
}


static DBusHandlerResult
owner_changed(DBusConnection *c, DBusMessage *msg, void *data)
{
    const char *name, *prev, *curr;
    
    if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS, OWNER_CHANGED))
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

    if (!dbus_message_get_args(msg, NULL,
                               DBUS_TYPE_STRING, &name,
                               DBUS_TYPE_STRING, &prev,
                               DBUS_TYPE_STRING, &curr,
                               DBUS_TYPE_INVALID))
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
                               
    if (strcmp(name, POLICY_TELEPHONY_INTERFACE))
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    
    if ((prev && prev[0]) && (!curr || !curr[0])) {
        INFO("policy interface at %s went down", prev);
        policy_down = 1;
        return DBUS_HANDLER_RESULT_HANDLED;
    }
    
    if ((!prev || !prev[0]) && (curr && curr[0])) {
        INFO("policy interface came up at %s", curr);
        policy_down = 0;
        /* XXX TODO: should send current list of calls... */
        return DBUS_HANDLER_RESULT_HANDLED;
    }
    
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

    (void)c;
    (void)data;
    
}




/*****************************************************************************
 *                            *** policy interface ***                       *
 *****************************************************************************/

static int
policy_call_request(const char *id, int incoming, McdDispatcherContext *ctx)
{
#define FAIL(fmt, args...) do { WARNING(fmt, ## args); goto fail; } while (0)

    DBusMessage     *msg     = NULL;
    DBusPendingCall *pending = NULL;;
    char            *name, *path, *iface, *method;
    dbus_bool_t      in = incoming ? TRUE : FALSE;
    dbus_int32_t     n;

    if (bus == NULL)
        FAIL("no connection to D-BUS");

    if (policy_down)
        FAIL("policy service is currently down");
    
    name   = POLICY_TELEPHONY_INTERFACE;
    path   = POLICY_TELEPHONY_PATH;
    iface  = POLICY_TELEPHONY_INTERFACE;
    method = POLICY_TELEPHONY_CALL_REQ;
    n      = ncall;
    msg    = dbus_message_new_method_call(name, path, iface, method);

    if (msg == NULL)
        FAIL("failed to create DBUS method call");
    
    if (!dbus_message_append_args(msg,
                                  DBUS_TYPE_STRING, &id,
                                  DBUS_TYPE_BOOLEAN, &in,
                                  DBUS_TYPE_INT32, &n, DBUS_TYPE_INVALID))
        FAIL("failed to create DBUS method call");
    
    if (!dbus_connection_send_with_reply(bus, msg, &pending, DBUS_TIMEOUT))
        FAIL("failed to send DBUS message to %s", name);

    if (!dbus_pending_call_set_notify(pending, policy_call_reply, ctx, NULL))
        FAIL("failed to set pending DBUS call callback");

    INFO("sent policy request for %s call", incoming ? "incoming" : "outgoing");
    
    return TRUE;


 fail:
    if (pending)
        dbus_pending_call_cancel(pending);
    if (msg)        
        dbus_message_unref(msg);

    return FALSE;

#undef FAIL
}


static void
policy_call_reply(DBusPendingCall *pending, void *user_data)
{
#define FAIL(fmt, args...) do { WARNING(fmt, ## args); goto fail; } while (0)

{'fraction_non_alphanumeric': 0.16285232474102626, 'fraction_numerical': 0.0025696619288524854, 'mean_word_length': 2.6977434679334915, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1790209', 'n_tokens_mistral': 4055, 'n_tokens_neox': 3901, 'n_words': 901}