예제 #1
0
kvpair_t* load_kvpairs(conflate_handle_t *handle, const char *filename)
{
    char* errmsg = NULL;
    sqlite3 *db = NULL;
    kvpair_t* pairs = NULL;

    if (sqlite3_open(filename, &db) != SQLITE_OK) {
        goto finished;
    }

    if (sqlite3_exec(db, LOAD_KVPAIRS, &append_kvpair_from_db, &pairs, &errmsg) != SQLITE_OK) {
        goto finished;
    }

 finished:
    if (sqlite3_errcode(db) != SQLITE_OK) {
        CONFLATE_LOG(handle, LOG_LVL_ERROR, "DB error %d:  %s",
                     sqlite3_errcode(db), sqlite3_errmsg(db));
        if (errmsg) {
            CONFLATE_LOG(handle, LOG_LVL_ERROR, "  %s", errmsg);
            sqlite3_free(errmsg);
        }
    }

    sqlite3_close(db);

    return pairs;
}
예제 #2
0
static enum conflate_mgmt_cb_result process_serverlist(void *opaque,
                                                       conflate_handle_t *handle,
                                                       const char *cmd,
                                                       bool direct,
                                                       kvpair_t *conf,
                                                       conflate_form_result *r)
{
    /* If we have "config_is_private" set to "yes" we should only
       process this if it's direct (i.e. ignore pubsub) */
    if (!direct) {
        char *priv = conflate_get_private(handle, "config_is_private",
                                          handle->conf->save_path);

        if (priv && strcmp(priv, "yes") == 0) {
            CONFLATE_LOG(handle, INFO,
                         "Currently using a private config, ignoring update.");
            return RV_OK;
        }
        free(priv);
    }

    CONFLATE_LOG(handle, INFO, "Processing a serverlist");

    /* Persist the config lists */
    if (!save_kvpairs(handle, conf, handle->conf->save_path)) {
        CONFLATE_LOG(handle, ERROR, "Can not save config to %s",
                     handle->conf->save_path);
    }

    /* Send the config to the callback */
    handle->conf->new_config(handle->conf->userdata, conf);

    return RV_OK;
}
예제 #3
0
char *conflate_get_private(conflate_handle_t *handle,
                           const char *k, const char *filename)
{
    char *errmsg = NULL;
    sqlite3 *db = NULL;
    sqlite3_stmt *get = NULL;
    char *rv = NULL;
    bool done = false;
    int steps_run = 0, err = 0;

    if (sqlite3_open(filename, &db) != SQLITE_OK) {
        goto finished;
    }

    if (sqlite3_prepare_v2(db, SEL_PRIV, strlen(SEL_PRIV),
                           &get, NULL) != SQLITE_OK) {
        goto finished;
    }

    sqlite3_bind_text(get, 1, k, strlen(k), SQLITE_TRANSIENT);

    while (!done) {
        switch(sqlite3_step(get)) {
        case SQLITE_BUSY:
            CONFLATE_LOG(handle, LOG_LVL_INFO, "DB was busy, retrying...\n");
            break;
        case SQLITE_ROW:
            assert(rv == NULL);
            rv = safe_strdup((char*)sqlite3_column_text(get, 0));
            CONFLATE_LOG(handle, LOG_LVL_DEBUG, "Retrieved value for ``%s'':  ``%s''",
                         k, rv);
            break;
        case SQLITE_DONE:
            done = true;
            break;
        }
        ++steps_run;
        assert(steps_run < MAX_STEPS);
    }

 finished:
    err = sqlite3_errcode(db);
    if (err != SQLITE_OK && err != SQLITE_DONE) {
        CONFLATE_LOG(handle, LOG_LVL_ERROR, "DB error %d:  %s",
                     sqlite3_errcode(db), sqlite3_errmsg(db));
        if (errmsg) {
            CONFLATE_LOG(handle, LOG_LVL_ERROR, "  %s", errmsg);
            sqlite3_free(errmsg);
        }
    }

    if (get) {
        sqlite3_finalize(get);
    }

    sqlite3_close(db);

    return rv;
}
예제 #4
0
void* run_conflate(void *arg) {
    conflate_handle_t* handle = (conflate_handle_t*)arg;

    /* Before connecting and all that, load the stored config */
    kvpair_t* conf = load_kvpairs(handle, handle->conf->save_path);
    if (conf) {
        handle->conf->new_config(handle->conf->userdata, conf);
        free_kvpair(conf);
    }

    xmpp_log_t strophe_logger = { &conflate_strophe_logger, handle };

    /* Run forever */
    for (;;) {
        handle->ctx = xmpp_ctx_new(NULL, &strophe_logger);
        assert(handle->ctx);

        handle->conn = xmpp_conn_new(handle->ctx);
        assert(handle->conn);

        /* Use the stored jid if there is one */
        char *db_jid = conflate_get_private(handle, STORED_JID_KEY,
                                            handle->conf->save_path);
        if (db_jid) {
            CONFLATE_LOG(handle, LOG_LVL_DEBUG, "Using jid from db: %s",
                         db_jid);
            xmpp_conn_set_jid(handle->conn, db_jid);
            free(db_jid);
        } else {
            CONFLATE_LOG(handle, LOG_LVL_DEBUG, "Using provided jid:  %s",
                         handle->conf->jid);
            xmpp_conn_set_jid(handle->conn, handle->conf->jid);
        }

        xmpp_conn_set_pass(handle->conn, handle->conf->pass);

        xmpp_connect_client(handle->conn, handle->conf->host, 0,
                            conn_handler, handle);
        xmpp_run(handle->ctx);
        CONFLATE_LOG(handle, LOG_LVL_INFO, "xmpp_run exited");

        xmpp_conn_release(handle->conn);
        xmpp_ctx_free(handle->ctx);

        sleep(5);
        CONFLATE_LOG(handle, LOG_LVL_INFO, "reconnecting");
    }
    CONFLATE_LOG(handle, LOG_LVL_FATAL, "Exited an infinite loop.");
    return NULL;
}
예제 #5
0
static void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
                         const int error, xmpp_stream_error_t * const stream_error,
                         void * const userdata)
{
    conflate_handle_t *handle = (conflate_handle_t *)userdata;

    if (status == XMPP_CONN_CONNECT) {
        xmpp_stanza_t* pres = NULL, *priority = NULL, *pri_text = NULL;
        CONFLATE_LOG(handle, LOG_LVL_INFO, "Connected.");
        xmpp_handler_add(conn, version_handler, "jabber:iq:version", "iq", NULL, handle);
        xmpp_handler_add(conn, command_handler, "http://jabber.org/protocol/commands",
                         "iq", NULL, handle);
        xmpp_handler_add(conn, disco_items_handler,
                         "http://jabber.org/protocol/disco#items", "iq", NULL, handle);
        xmpp_handler_add(conn, message_handler, NULL, "message", NULL, handle);
        xmpp_timed_handler_add(conn, keepalive_handler, 60000, handle);
        xmpp_timed_handler_add(conn, alarmqueue_handler, 10000, handle);

        /* Send initial <presence/> so that we appear online to contacts */
        pres = xmpp_stanza_new(handle->ctx);
        assert(pres);
        xmpp_stanza_set_name(pres, "presence");

        priority = xmpp_stanza_new(handle->ctx);
        assert(priority);
        xmpp_stanza_set_name(priority, "priority");
        add_and_release(pres, priority);

        pri_text = xmpp_stanza_new(handle->ctx);
        assert(pri_text);
        xmpp_stanza_set_text(pri_text, "5");
        add_and_release(priority, pri_text);

        xmpp_send(conn, pres);
        xmpp_stanza_release(pres);

        /* Store the bound jid */
        if (!conflate_save_private(handle, STORED_JID_KEY,
                                   xmpp_conn_get_bound_jid(conn),
                                   handle->conf->save_path)) {
            CONFLATE_LOG(handle, LOG_LVL_WARN, "Failed to save the bound jid");
        }
    }
    else {
        CONFLATE_LOG(handle, LOG_LVL_INFO, "disconnected.");
        xmpp_stop(handle->ctx);
    }
}
예제 #6
0
static int command_handler(xmpp_conn_t * const conn,
                           xmpp_stanza_t * const stanza,
                           void * const userdata)
{
    xmpp_stanza_t *reply = NULL, *req = NULL;
    char *cmd = NULL;

    /* Figure out what the command is */
    req = xmpp_stanza_get_child_by_name(stanza, "command");
    assert(req);
    assert(strcmp(xmpp_stanza_get_name(req), "command") == 0);
    cmd = xmpp_stanza_get_attribute(req, "node");
    assert(cmd);

    CONFLATE_LOG(((conflate_handle_t *)userdata), LOG_LVL_INFO,
                 "Command:  %s", cmd);

    reply = command_dispatch(conn, stanza, userdata, cmd, req, true);

    if (reply) {
        xmpp_send(conn, reply);
        xmpp_stanza_release(reply);
    }

    return 1;
}
예제 #7
0
static xmpp_stanza_t* n_handler(const char *cmd,
                                xmpp_stanza_t* cmd_stanza,
                                xmpp_conn_t * const conn,
                                xmpp_stanza_t * const stanza,
                                void * const userdata,
                                bool direct,
                                conflate_mgmt_cb_t cb)
{
    conflate_handle_t *handle = (conflate_handle_t*) userdata;
    xmpp_ctx_t *ctx = handle->ctx;
    conflate_form_result result = { .conn = conn,
                                    .ctx = ctx,
                                    .reply = NULL,
                                    .cmd_res = NULL,
                                    .container = NULL };
    kvpair_t *form = NULL;

    assert(cb);

    result.reply = create_reply(ctx, stanza);
    result.cmd_res = create_cmd_response(ctx, cmd_stanza);

    add_and_release(result.reply, result.cmd_res);

    xmpp_stanza_t *x = xmpp_stanza_get_child_by_name(cmd_stanza, "x");
    if (x) {
        xmpp_stanza_t *fields = xmpp_stanza_get_child_by_name(x, "field");
        if (fields) {
            form = grok_form(fields);
        }
    }

    enum conflate_mgmt_cb_result rv = cb(handle->conf->userdata, handle,
                                         cmd, direct, form, &result);

    CONFLATE_LOG(handle, LOG_LVL_DEBUG, "Result of %s:  %s", cmd, cb_name(rv));

    switch (rv) {
    case RV_ERROR:
        add_cmd_error(ctx, result.reply, "500",
                      "urn:ietf:params:xml:ns:xmpp-stanzas",
                      "internal-server-error", NULL, NULL);
        break;
    case RV_BADARG:
        add_cmd_error(ctx, result.reply, "400",
                      "urn:ietf:params:xml:ns:xmpp-stanzas", "bad-request",
                      "http://jabber.org/protocol/commands", "bad-payload");
        break;
    case RV_OK:
        /* Things are good, use the built form */
        break;
    }

    free_kvpair(form);

    return result.reply;
}
예제 #8
0
static int run_mod_steps(conflate_handle_t *handle, sqlite3 *db,
                         sqlite3_stmt *statement)
{
    int steps_run = 0, rc = 0;
    while ((rc = sqlite3_step(statement)) != SQLITE_DONE) {
        steps_run++;
        assert(steps_run < MAX_STEPS);
        CONFLATE_LOG(handle, LOG_LVL_DEBUG, "statement step result: %d", rc);
    }
    return sqlite3_changes(db);
}
예제 #9
0
bool conflate_delete_private(conflate_handle_t *handle,
                             const char *k, const char *filename)
{
    bool rv = false;
    int err = 0, deleted = 0;
    sqlite3 *db = NULL;
    sqlite3_stmt *del = NULL;

    if ((err = open_and_initialize_db(handle, filename, &db)) != SQLITE_OK) {
        goto finished;
    }

    assert(db != NULL);

    if ((err = sqlite3_prepare_v2(db, DEL_PRIV, strlen(DEL_PRIV),
                                  &del, NULL)) != SQLITE_OK) {
        goto finished;
    }

    sqlite3_bind_text(del, 1, k, strlen(k), SQLITE_TRANSIENT);

    deleted = run_mod_steps(handle, db, del);
    CONFLATE_LOG(handle, LOG_LVL_DEBUG, "Removed %d records", deleted);
    rv = deleted >= 0;

 finished:
    err = sqlite3_errcode(db);
    if (err != SQLITE_OK && err != SQLITE_DONE) {
        CONFLATE_LOG(handle, LOG_LVL_ERROR, "DB error %d:  %s",
                     sqlite3_errcode(db), sqlite3_errmsg(db));
    }

    if (del) {
        sqlite3_finalize(del);
    }

    sqlite3_close(db);

    return rv;
}
예제 #10
0
static bool db_do(conflate_handle_t *handle, sqlite3 *db, const char* query)
{
    char* errmsg = NULL;
    bool rv = true;

    if (sqlite3_exec(db, query, NULL, NULL, &errmsg) != SQLITE_OK) {
        CONFLATE_LOG(handle, LOG_LVL_ERROR, "DB Error:  %s\n%s", errmsg, query);
        sqlite3_free(errmsg);
        rv = false;
    }

    return rv;
}
예제 #11
0
static bool maybe_create_table(conflate_handle_t *handle,
                               sqlite3 *db, int flag, int flags,
                               const char* query)
{
    assert(db);
    assert(query);

    bool rv = true;
    char* table_name = get_table_name(flag);

    if (flag & flags) {
        CONFLATE_LOG(handle, LOG_LVL_DEBUG, "Table %s already exists", table_name);
    } else {
        if (db_do(handle, db, query)) {
            CONFLATE_LOG(handle, LOG_LVL_INFO, "Created table:  %s", table_name);
        } else {
            CONFLATE_LOG(handle, LOG_LVL_WARN, "DB error creating table:  %s", table_name);
            rv = false;
        }
    }

    return rv;
}
예제 #12
0
static int message_handler(xmpp_conn_t * const conn,
                           xmpp_stanza_t * const stanza,
                           void * const userdata)
{
    xmpp_stanza_t* event = NULL, *items = NULL, *item = NULL,
        *command = NULL, *reply = NULL;
    conflate_handle_t *handle = (conflate_handle_t*)userdata;
    CONFLATE_LOG(handle, LOG_LVL_DEBUG, "Got a message from %s",
                 xmpp_stanza_get_attribute(stanza, "from"));

    event = xmpp_stanza_get_child_by_name(stanza, "event");
    assert(event);
    items = xmpp_stanza_get_child_by_name(event, "items");
    assert(items);
    item = xmpp_stanza_get_child_by_name(items, "item");

    if (item) {
        command = xmpp_stanza_get_child_by_name(item, "command");
        assert(command);

        CONFLATE_LOG(handle, LOG_LVL_INFO, "Pubsub comand:  %s",
                     xmpp_stanza_get_attribute(command, "command"));

        reply = command_dispatch(conn, stanza, userdata,
                                 xmpp_stanza_get_attribute(command, "command"),
                                 command, false);

        if (reply) {
            xmpp_stanza_release(reply);
        }
    } else {
        CONFLATE_LOG(handle, LOG_LVL_INFO, "Received pubsub event with no items.");
    }

    return 1;
}
예제 #13
0
static void conflate_strophe_logger(void *const userdata,
                                    const xmpp_log_level_t level,
                                    const char *const area,
                                    const char *const msg)
{
   enum conflate_log_level lvl = LOG_LVL_ERROR;
    switch(level) {
    case XMPP_LEVEL_DEBUG: lvl = LOG_LVL_DEBUG; break;
    case XMPP_LEVEL_INFO: lvl = LOG_LVL_INFO; break;
    case XMPP_LEVEL_WARN: lvl = LOG_LVL_WARN; break;
    case XMPP_LEVEL_ERROR: lvl = LOG_LVL_ERROR; break;
    }

    conflate_handle_t *handle = (conflate_handle_t*)userdata;
    CONFLATE_LOG(handle, lvl, "%s", msg);
}
예제 #14
0
static int open_and_initialize_db(conflate_handle_t *handle,
                                  const char *filename,
                                  sqlite3 **db)
{
    int err = 0;

    if ((err = sqlite3_open(filename, &*db)) != SQLITE_OK) {
        return err;
    }

    if (!initialize_db(handle, *db)) {
        CONFLATE_LOG(handle, LOG_LVL_ERROR, "Error initializing tables");
        return SQLITE_ERROR;
    }

    return SQLITE_OK;
}
예제 #15
0
static int set_table_mask(void* arg, int n, char **vals, char **cols)
{
    (void)cols;
    struct table_mask_userdata *udata = (struct table_mask_userdata*)arg;
    assert(n == 1);

    if (strcmp(vals[0], "keys") == 0) {
        udata->found |= HAS_KEYS;
    } else if(strcmp(vals[0], "vals") == 0) {
        udata->found |= HAS_VALUES;
    } else if(strcmp(vals[0], "private") == 0) {
        udata->found |= HAS_PRIVATE;
    } else {
        CONFLATE_LOG(udata->handle, LOG_LVL_WARN, "Unknown table:  %s", vals[0]);
    }

    return SQLITE_OK;
}
예제 #16
0
bool conflate_save_private(conflate_handle_t *handle,
                           const char *k, const char *v, const char *filename)
{
    bool rv = false;
    int err = 0;
    sqlite3 *db = NULL;
    sqlite3_stmt *ins = NULL;

    if ((err = open_and_initialize_db(handle, filename, &db)) != SQLITE_OK) {
        goto finished;
    }

    assert(db != NULL);

    if ((err = sqlite3_prepare_v2(db, INS_PRIV, strlen(INS_PRIV),
                                  &ins, NULL)) != SQLITE_OK) {
        goto finished;
    }

    sqlite3_bind_text(ins, 1, k, strlen(k), SQLITE_TRANSIENT);
    sqlite3_bind_text(ins, 2, v, strlen(v), SQLITE_TRANSIENT);

    rv = run_mod_steps(handle, db, ins) == 1;

 finished:
    err = sqlite3_errcode(db);
    if (err != SQLITE_OK && err != SQLITE_DONE) {
        CONFLATE_LOG(handle, LOG_LVL_ERROR, "DB error %d:  %s",
                     sqlite3_errcode(db), sqlite3_errmsg(db));
    }

    if (ins) {
        sqlite3_finalize(ins);
    }

    sqlite3_close(db);

    return rv;
}
예제 #17
0
static bool initialize_db(conflate_handle_t *handle, sqlite3 *db)
{
    bool rv = true;
    char *errmsg = NULL;
    char* query = "SELECT name FROM sqlite_master "
        "WHERE type='table' "
        "ORDER BY name;";

    assert(db);

    struct table_mask_userdata udata = { 0, handle };

    if (sqlite3_exec(db, query, set_table_mask, &udata, &errmsg) != SQLITE_OK) {
        CONFLATE_LOG(handle, LOG_LVL_ERROR, "DB error:  %s", errmsg);
        sqlite3_free(errmsg);
    } else {
        rv &= maybe_create_table(handle, db, HAS_KEYS, udata.found, CREATE_KEYS);
        rv &= maybe_create_table(handle, db, HAS_VALUES, udata.found, CREATE_VALUES);
        rv &= maybe_create_table(handle, db, HAS_PRIVATE, udata.found, CREATE_PRIVATE);
    }

    return rv;
}
예제 #18
0
bool save_kvpairs(conflate_handle_t *handle, kvpair_t* kvpair,
                  const char *filename)
{
    bool rv = false;
    sqlite3 *db = NULL;
    sqlite3_stmt *ins_keys = NULL, *ins_vals = NULL;

    if ( open_and_initialize_db(handle, filename, &db) != SQLITE_OK) {
        goto finished;
    }

    assert(db != NULL);

    if (!db_do(handle, db, "begin transaction")) {
        goto finished;
    }

    /* Cleanup the existing stuff */

    if (!db_do(handle, db, "delete from keys")) {
        goto finished;
    }

    if (!db_do(handle, db, "delete from vals")) {
        goto finished;
    }

    /* Add the keys */
    if (sqlite3_prepare_v2(db, INS_KEYS, strlen(INS_KEYS),
                           &ins_keys, NULL) != SQLITE_OK) {
        goto finished;
    }
    /* Add the values */
    if (sqlite3_prepare_v2(db, INS_VALS, strlen(INS_VALS),
                           &ins_vals, NULL) != SQLITE_OK) {
        goto finished;
    }

    /* OK, Add them all in */
    while (kvpair) {
        int j = 0;
        sqlite_int64 key_id;

        sqlite3_clear_bindings(ins_keys);
        sqlite3_clear_bindings(ins_vals);

        sqlite3_bind_text(ins_keys, 1, kvpair->key, strlen(kvpair->key),
                          SQLITE_TRANSIENT);

        if (run_mod_steps(handle, db, ins_keys) != 1) {
            goto finished;
        }

        key_id = sqlite3_last_insert_rowid(db);

        for (j = 0; kvpair->values[j]; j++) {
            char* val = kvpair->values[j];

            sqlite3_bind_int64(ins_vals, 1, key_id);
            sqlite3_bind_text(ins_vals, 2, val, strlen(val), SQLITE_TRANSIENT);

            if (run_mod_steps(handle, db, ins_vals) != 1) {
                goto finished;
            }

            sqlite3_reset(ins_vals);
        }

        sqlite3_reset(ins_keys);

        kvpair = kvpair -> next;
    }

    if (!db_do(handle, db, "commit")) {
        goto finished;
    }

    rv = true;

 finished:
    if (sqlite3_errcode(db) != SQLITE_OK) {
        CONFLATE_LOG(handle, LOG_LVL_ERROR, "DB error %d:  %s",
                     sqlite3_errcode(db), sqlite3_errmsg(db));
    }

    if (ins_keys) {
        sqlite3_finalize(ins_keys);
    }
    if (ins_vals) {
        sqlite3_finalize(ins_vals);
    }
    sqlite3_close(db);

    return rv;
}