Changes in / [82cb190:3fbce97]


Ignore:
Files:
7 added
4 deleted
18 edited

Legend:

Unmodified
Added
Removed
  • .gitignore

    r82cb190 r3fbce97  
    3232bitlbee.service
    3333bitlbee@.service
     34*.pyc
  • configure

    r82cb190 r3fbce97  
    1616config='/var/lib/bitlbee/'
    1717plugindir='$prefix/lib/bitlbee/'
     18rpcplugindir='$plugindir/rpc/'
    1819includedir='$prefix/include/bitlbee/'
    1920systemdsystemunitdir=''
     
    3940twitter=1
    4041purple=0
     42rpc=1
    4143
    4244doc=1
     
    121123--datadir=...                                           $datadir
    122124--plugindir=...                                         $plugindir
     125--rpcplugindir=...                                      $rpcplugindir
    123126--systemdsystemunitdir=...                              $systemdsystemunitdir
    124127--pidfile=...                                           $pidfile
     
    133136--purple=0/1    Disable/enable libpurple support        $purple
    134137                (automatically disables other protocol modules)
     138--rpc=0/1       Disable/enable RPC plugin interface     $rpc
    135139
    136140--doc=0/1       Disable/enable help.txt generation      $doc
     
    168172config=$(eval echo "$config/" | sed 's/\/\{1,\}/\//g')
    169173plugindir=$(eval echo "$plugindir/" | sed 's/\/\{1,\}/\//g')
     174rpcplugindir=$(eval echo "$rpcplugindir/" | sed 's/\/\{1,\}/\//g')
    170175includedir=$(eval echo "$includedir"/ | sed 's/\/\{1,\}/\//g')
    171176libevent=$(eval echo "$libevent"/ | sed 's/\/\{1,\}/\//g')
     
    189194DATADIR=$datadir
    190195PLUGINDIR=$plugindir
     196RPCPLUGINDIR=$rpcplugindir
    191197CONFIG=$config
    192198INCLUDEDIR=$includedir
     
    240246#define VARDIR "$datadir"
    241247#define PLUGINDIR "$plugindir"
     248#define RPCPLUGINDIR "$rpcplugindir"
    242249#define PIDFILE "$pidfile"
    243250#define IPCSOCKET "$ipcsocket"
     
    282289        LDFLAGS="$LDFLAGS -fsanitize=address"
    283290        debug=1
     291fi
     292
     293if [ "$tsan" = "1" ]; then
     294        echo
     295        echo "Threaded BitlBee? Have a nice tall glass of http://imgur.com/gallery/tX4qxzS"
     296        echo "No need to sanitise threads in a single-threaded process!"
    284297fi
    285298
     
    672685fi
    673686
     687if [ "$rpc" = 0 ]; then
     688        # Somewhat pointless at this stage already but at least this keeps it
     689        # out of bitlbee.pc which is probably a good thing.
     690        rpcplugindir=""
     691fi
     692
    674693otrprefix=""
    675694if [ "$otr" = "auto" ]; then
     
    750769includedir=$includedir
    751770plugindir=$plugindir
     771rpcplugindir=$rpcplugindir
    752772
    753773Name: bitlbee
     
    842862        protocols=$protocols'twitter '
    843863        protoobjs=$protoobjs'twitter_mod.o '
     864fi
     865
     866if [ "$rpc" = 0 ]; then
     867        echo '#undef WITH_RPC' >> config.h
     868else
     869        echo '#define WITH_RPC' >> config.h
     870        protocols=$protocols'rpc '
     871        protoobjs=$protoobjs'rpc_mod.o '
    844872fi
    845873
     
    931959echo '  Using event handler: '$events
    932960echo '  Using SSL library: '$ssl
    933 #echo '  Building with these storage backends: '$STORAGES
    934961
    935962if [ -n "$protocols" ]; then
  • irc_channel.c

    r82cb190 r3fbce97  
    755755        }
    756756
     757        if (!bu->ic->acc->prpl->add_buddy) {
     758                irc_send_num(ic->irc, 482, "%s :IM protocol does not support contact list modification", ic->name);
     759                return FALSE;
     760        }
     761
    757762        bu->ic->acc->prpl->add_buddy(bu->ic, bu->handle,
    758763                                     icc->group ? icc->group->name : NULL);
     
    772777        if (icc->type != IRC_CC_TYPE_GROUP) {
    773778                irc_send_num(ic->irc, 482, "%s :Kicks are only possible to fill_by=group channels", ic->name);
     779                return;
     780        }
     781
     782        if (!bu->ic->acc->prpl->remove_buddy) {
     783                irc_send_num(ic->irc, 482, "%s :IM protocol does not support contact list modification", ic->name);
    774784                return;
    775785        }
  • irc_commands.c

    r82cb190 r3fbce97  
    287287                           showed an error message, or is doing some work
    288288                           before the join should be confirmed. (In the
    289                            latter case, the caller should take care of that
     289                           latter case, the callee should take care of that
    290290                           confirmation.) TRUE means all's good, let the
    291291                           user join the channel right away. */
  • lib/Makefile

    r82cb190 r3fbce97  
    1313
    1414# [SH] Program variables
    15 objects = arc.o base64.o $(EVENT_HANDLER) ftutil.o http_client.o ini.o json.o json_util.o md5.o misc.o oauth.o oauth2.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o ns_parse.o
     15objects = arc.o base64.o $(EVENT_HANDLER) ftutil.o http_client.o ini.o md5.o misc.o oauth.o oauth2.o parson.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o ns_parse.o
    1616
    1717LFLAGS += -r
  • lib/misc.c

    r82cb190 r3fbce97  
    431431}
    432432
    433 int is_bool(char *value)
     433int is_bool(const char *value)
    434434{
    435435        if (*value == 0) {
     
    457457}
    458458
    459 int bool2int(char *value)
     459int bool2int(const char *value)
    460460{
    461461        int i;
  • lib/misc.h

    r82cb190 r3fbce97  
    137137G_MODULE_EXPORT void random_bytes(unsigned char *buf, int count);
    138138
    139 G_MODULE_EXPORT int is_bool(char *value);
    140 G_MODULE_EXPORT int bool2int(char *value);
     139G_MODULE_EXPORT int is_bool(const char *value);
     140G_MODULE_EXPORT int bool2int(const char *value);
    141141
    142142G_MODULE_EXPORT struct ns_srv_reply **srv_lookup(char *service, char *protocol, char *domain);
  • lib/oauth2.c

    r82cb190 r3fbce97  
    4242#include "oauth2.h"
    4343#include "oauth.h"
    44 #include "json.h"
    45 #include "json_util.h"
     44#include "parson.h"
    4645#include "url.h"
     46
     47#define JSON_O_FOREACH(o, k, v) \
     48    const char *k; const JSON_Value *v; int __i; \
     49    for (__i = 0; json_object_get_tuple(o, __i, &k, &v); __i++)
    4750
    4851char *oauth2_url(const struct oauth2_service *sp)
     
    113116}
    114117
    115 static char* oauth2_parse_error(json_value *e)
     118static char* oauth2_parse_error(const JSON_Value *e)
    116119{
    117120        /* This does a reasonable job with some of the flavours of error
    118121           responses I've seen. Because apparently it's not standardised. */
    119122
    120         if (e->type == json_object) {
     123        if (json_type(e) == JSONObject) {
    121124                /* Facebook style */
    122                 const char *msg = json_o_str(e, "message");
    123                 const char *type = json_o_str(e, "type");
    124                 json_value *code_o = json_o_get(e, "code");
    125                 int code = 0;
    126 
    127                 if (code_o && code_o->type == json_integer) {
    128                         code = code_o->u.integer;
    129                 }
    130 
     125                const char *msg = json_object_get_string(json_object(e), "message");
     126                const char *type = json_object_get_string(json_object(e), "type");
     127                JSON_Value *code_o = json_object_get_value(json_object(e), "code");
     128                int code = json_value_get_integer(code_o);
    131129                return g_strdup_printf("Error %d: %s", code, msg ? msg : type ? type : "Unknown error");
    132         } else if (e->type == json_string) {
    133                 return g_strdup(e->u.string.ptr);
     130        } else if (json_type(e) == JSONString) {
     131                return g_strdup(json_string(e));
    134132        }
    135133        return NULL;
     
    156154        if (content_type && (strstr(content_type, "application/json") ||
    157155                             strstr(content_type, "text/javascript"))) {
    158                 json_value *js = json_parse(req->reply_body, req->body_size);
    159                 if (js && js->type == json_object) {
    160                         JSON_O_FOREACH(js, k, v){
     156                JSON_Value *js = json_parse_string(req->reply_body);
     157                if (js && json_type(js) == JSONObject) {
     158                        JSON_O_FOREACH(json_object(js), k, v){
    161159                                if (strcmp(k, "error") == 0) {
    162160                                        error = oauth2_parse_error(v);
    163161                                }
    164                                 if (v->type != json_string) {
     162                                if (json_type(v) != JSONString) {
    165163                                        continue;
    166164                                }
    167165                                if (strcmp(k, "access_token") == 0) {
    168                                         atoken = g_strdup(v->u.string.ptr);
     166                                        atoken = g_strdup(json_string(v));
    169167                                }
    170168                                if (strcmp(k, "refresh_token") == 0) {
    171                                         rtoken = g_strdup(v->u.string.ptr);
     169                                        rtoken = g_strdup(json_string(v));
    172170                                }
    173171                        }
  • protocols/account.c

    r82cb190 r3fbce97  
    2727#include "bitlbee.h"
    2828#include "account.h"
    29 
    30 static const char* account_protocols_local[] = {
    31         "gg", "whatsapp", NULL
    32 };
    3329
    3430static char *set_eval_nick_source(set_t *set, char *value);
     
    461457        return a->auto_reconnect_delay;
    462458}
    463 
    464 int protocol_account_islocal(const char* protocol)
    465 {
    466         const char** p = account_protocols_local;
    467 
    468         do {
    469                 if (strcmp(*p, protocol) == 0) {
    470                         return 1;
    471                 }
    472         } while (*(++p));
    473         return 0;
    474 }
  • protocols/account.h

    r82cb190 r3fbce97  
    5858int account_reconnect_delay(account_t *a);
    5959
    60 int protocol_account_islocal(const char* protocol);
    61 
    6260typedef enum {
    6361        ACC_SET_OFFLINE_ONLY = 0x02,    /* Allow changes only if the acct is offline. */
     
    6967        ACC_FLAG_STATUS_MESSAGE = 0x02, /* Supports status messages (without being away). */
    7068        ACC_FLAG_HANDLE_DOMAINS = 0x04, /* Contact handles need a domain portion. */
    71         ACC_FLAG_LOCAL = 0x08,          /* Contact list is local. */
     69        ACC_FLAG_LOCAL_CONTACTS = 0x08, /* Contact list is local. */
    7270} account_flag_t;
    7371
  • protocols/nogaim.c

    r82cb190 r3fbce97  
    135135        extern void twitter_initmodule();
    136136        extern void purple_initmodule();
     137        extern void rpc_initmodule();
    137138
    138139#ifdef WITH_MSN
     
    158159#ifdef WITH_PURPLE
    159160        purple_initmodule();
     161#endif
     162
     163#ifdef WITH_RPC
     164        rpc_initmodule();
    160165#endif
    161166
     
    313318        }
    314319
    315         if (ic->acc->flags & ACC_FLAG_LOCAL) {
     320        if ((ic->acc->flags & ACC_FLAG_LOCAL_CONTACTS) &&
     321            !(ic->flags & OPT_LOCAL_CONTACTS_SENT) &&
     322            ic->acc->prpl->add_buddy) {
    316323                GHashTableIter nicks;
    317                 gpointer k, v;
     324                gpointer handle;
    318325                g_hash_table_iter_init(&nicks, ic->acc->nicks);
    319                 while (g_hash_table_iter_next(&nicks, &k, &v)) {
    320                         ic->acc->prpl->add_buddy(ic, (char *) k, NULL);
     326                while (g_hash_table_iter_next(&nicks, &handle, NULL)) {
     327                        ic->acc->prpl->add_buddy(ic, (char *) handle, NULL);
    321328                }
    322329        }
     
    413420        query_del_by_conn((irc_t *) ic->bee->ui_data, ic);
    414421
     422        /* Throw away groupchats owned by this account. Historically this was only
     423           ever done by IM modules which is a bug. But it gives them opportunity
     424           to clean up protocol-specific bits as well so keep it that way, just
     425           do another cleanup here as a fallback. Don't want to leave any dangling
     426           pointers! */
     427        while (ic->groupchats) {
     428                imcb_chat_free(ic->groupchats->data);
     429        }
     430
    415431        if (!a) {
    416432                /* Uhm... This is very sick. */
     
    498514}
    499515
     516/* Returns the local contacts for an IM account (based on assigned nicks).
     517   Linked list should be freed, the strings themselves not! So look at it
     518   like a GSList<const char*> I guess? Empty list means NULL retval (as
     519   always with GSList). */
     520GSList *imcb_get_local_contacts(struct im_connection *ic)
     521{
     522        GHashTableIter nicks;
     523        GSList *ret = NULL;
     524       
     525        if (!(ic->acc->flags & ACC_FLAG_LOCAL_CONTACTS)) {
     526                /* Only allow protocols that indicate local contact list
     527                   support to use this function. */
     528                return ret;
     529        }
     530       
     531        g_hash_table_iter_init(&nicks, ic->acc->nicks);
     532        gpointer handle;
     533        while (g_hash_table_iter_next(&nicks, &handle, NULL)) {
     534                ret = g_slist_prepend(ret, (char *) handle);
     535        }
     536       
     537        /* If the protocol asked for the list, assume we won't have to send it
     538           anymore in imcb_connected(). */
     539        ic->flags |= OPT_LOCAL_CONTACTS_SENT;
     540       
     541        return ret;
     542}
     543
    500544
    501545struct imcb_ask_cb_data {
     
    556600        struct imcb_ask_cb_data *cbd = data;
    557601
    558         cbd->ic->acc->prpl->add_buddy(cbd->ic, cbd->handle, NULL);
     602        if (cbd->ic->acc->prpl->add_buddy) {
     603                cbd->ic->acc->prpl->add_buddy(cbd->ic, cbd->handle, NULL);
     604        }
    559605
    560606        imcb_ask_cb_free(data);
  • protocols/nogaim.h

    r82cb190 r3fbce97  
    5757
    5858/* Sharing flags between all kinds of things. I just hope I won't hit any
    59    limits before 32-bit machines become extinct. ;-) */
     59   limits before 32-bit machines become extinct. ;-)
     60   
     61   Argh! This needs to be renamed to be more clear which field they're used
     62   for. As said it's currently mixed which is nonsense. Some are for the
     63   im_connection flags field, some for imcb_buddy_status(), some for typing
     64   notifications, and who knows what else... */
    6065#define OPT_LOGGED_IN   0x00000001
    6166#define OPT_LOGGING_OUT 0x00000002
     
    7075#define OPT_PONGS       0x00010000 /* Service sends us keep-alives */
    7176#define OPT_PONGED      0x00020000 /* Received a keep-alive during last interval */
     77#define OPT_LOCAL_CONTACTS_SENT 0x00040000 /* Protocol already requested local contact list, so don't send it after finishing login. */
    7278#define OPT_SELFMESSAGE 0x00080000 /* A message sent by self from another location */
    7379
     
    325331G_MODULE_EXPORT void imcb_buddy_nick_hint(struct im_connection *ic, const char *handle, const char *nick);
    326332G_MODULE_EXPORT void imcb_buddy_action_response(bee_user_t *bu, const char *action, char * const args[], void *data);
     333G_MODULE_EXPORT GSList *imcb_get_local_contacts(struct im_connection *ic);
    327334
    328335G_MODULE_EXPORT void imcb_buddy_typing(struct im_connection *ic, const char *handle, guint32 flags);
  • protocols/purple/purple.c

    r82cb190 r3fbce97  
    277277        }
    278278        purple_accounts_remove(pa);
     279       
     280        /* Last, some protocols want their contact lists locally. */
     281        if (strcmp(acc->prpl->name, "whatsapp") == 0 || strcmp(acc->prpl->name, "gg") == 0) {
     282                acc->flags |= ACC_FLAG_LOCAL_CONTACTS;
     283        }
    279284}
    280285
  • protocols/twitter/twitter_lib.c

    r82cb190 r3fbce97  
    3636#include "base64.h"
    3737#include "twitter_lib.h"
    38 #include "json_util.h"
     38#include "parson.h"
    3939#include <ctype.h>
    4040#include <errno.h>
     
    6464        gboolean from_filter;
    6565};
     66
     67#define JSON_O_FOREACH(o, k, v) \
     68    const char *k; const JSON_Value *v; int __i; \
     69    for (__i = 0; json_object_get_tuple(o, __i, &k, &v); __i++)
    6670
    6771/**
     
    166170{
    167171        static char *ret = NULL;
    168         json_value *root, *err;
     172        JSON_Value *root, *err;
    169173
    170174        g_free(ret);
     
    172176
    173177        if (req->body_size > 0) {
    174                 root = json_parse(req->reply_body, req->body_size);
    175                 err = json_o_get(root, "errors");
    176                 if (err && err->type == json_array && (err = err->u.array.values[0]) &&
    177                     err->type == json_object) {
    178                         const char *msg = json_o_str(err, "message");
     178                root = json_parse_string(req->reply_body);
     179                err = json_object_get_value(json_object(root), "errors");
     180                if (err && json_type(err) == JSONArray &&
     181                    (err = json_array_get_value(json_array(err), 0)) &&
     182                    json_type(err) == JSONObject) {
     183                        const char *msg = json_object_get_string(json_object(err), "message");
    179184                        if (msg) {
    180185                                ret = g_strdup_printf("%s (%s)", req->status_string, msg);
     
    189194/* WATCH OUT: This function might or might not destroy your connection.
    190195   Sub-optimal indeed, but just be careful when this returns NULL! */
    191 static json_value *twitter_parse_response(struct im_connection *ic, struct http_request *req)
     196static JSON_Value *twitter_parse_response(struct im_connection *ic, struct http_request *req)
    192197{
    193198        gboolean logging_in = !(ic->flags & OPT_LOGGED_IN);
    194199        gboolean periodic;
    195200        struct twitter_data *td = ic->proto_data;
    196         json_value *ret;
     201        JSON_Value *ret;
    197202        char path[64] = "", *s;
    198203
     
    232237        }
    233238
    234         if ((ret = json_parse(req->reply_body, req->body_size)) == NULL) {
     239        if ((ret = json_parse_string(req->reply_body)) == NULL) {
    235240                imcb_error(ic, "Could not retrieve %s: %s",
    236241                           path, "XML parse error");
     
    259264 * Fill a list of ids.
    260265 */
    261 static gboolean twitter_xt_get_friends_id_list(json_value *node, struct twitter_xml_list *txl)
    262 {
    263         json_value *c;
     266static gboolean twitter_xt_get_friends_id_list(JSON_Value *node, struct twitter_xml_list *txl)
     267{
     268        JSON_Array *c;
    264269        int i;
    265270
     
    267272        txl->type = TXL_ID;
    268273
    269         c = json_o_get(node, "ids");
    270         if (!c || c->type != json_array) {
     274        if (!(c = json_object_get_array(json_object(node), "ids"))) {
    271275                return FALSE;
    272276        }
    273277
    274         for (i = 0; i < c->u.array.length; i++) {
    275                 if (c->u.array.values[i]->type != json_integer) {
    276                         continue;
    277                 }
     278        for (i = 0; i < json_array_get_count(c); i++) {
     279                jint id = json_array_get_integer(c, i);
    278280
    279281                txl->list = g_slist_prepend(txl->list,
    280                                             g_strdup_printf("%" PRIu64, c->u.array.values[i]->u.integer));
    281         }
    282 
    283         c = json_o_get(node, "next_cursor");
    284         if (c && c->type == json_integer) {
    285                 txl->next_cursor = c->u.integer;
     282                                            g_strdup_printf("%lld", id));
     283        }
     284
     285        JSON_Value *next = json_object_get_value(json_object(node), "next_cursor");
     286        if (next && json_type(next) == JSONInteger) {
     287                txl->next_cursor = json_integer(next);
    286288        } else {
    287289                txl->next_cursor = -1;
     
    299301{
    300302        struct im_connection *ic;
    301         json_value *parsed;
     303        JSON_Value *parsed;
    302304        struct twitter_xml_list *txl;
    303305        struct twitter_data *td;
     
    337339}
    338340
    339 static gboolean twitter_xt_get_users(json_value *node, struct twitter_xml_list *txl);
     341static gboolean twitter_xt_get_users(JSON_Value *node, struct twitter_xml_list *txl);
    340342static void twitter_http_get_users_lookup(struct http_request *req);
    341343
     
    378380{
    379381        struct im_connection *ic = req->data;
    380         json_value *parsed;
     382        JSON_Value *parsed;
    381383        struct twitter_xml_list *txl;
    382384        GSList *l = NULL;
     
    411413}
    412414
    413 struct twitter_xml_user *twitter_xt_get_user(const json_value *node)
     415struct twitter_xml_user *twitter_xt_get_user(const JSON_Object *node)
    414416{
    415417        struct twitter_xml_user *txu;
    416         json_value *jv;
     418       
     419        if (!node)
     420                return NULL;
    417421
    418422        txu = g_new0(struct twitter_xml_user, 1);
    419         txu->name = g_strdup(json_o_str(node, "name"));
    420         txu->screen_name = g_strdup(json_o_str(node, "screen_name"));
    421 
    422         jv = json_o_get(node, "id");
    423         txu->uid = jv->u.integer;
     423        txu->name = g_strdup(json_object_get_string(node, "name"));
     424        txu->screen_name = g_strdup(json_object_get_string(node, "screen_name"));
     425        txu->uid = json_object_get_integer(node, "id");
    424426
    425427        return txu;
     
    431433 *  - all <user>s from the <users> element.
    432434 */
    433 static gboolean twitter_xt_get_users(json_value *node, struct twitter_xml_list *txl)
     435static gboolean twitter_xt_get_users(JSON_Value *node, struct twitter_xml_list *txl)
    434436{
    435437        struct twitter_xml_user *txu;
     
    439441        txl->type = TXL_USER;
    440442
    441         if (!node || node->type != json_array) {
     443        if (json_type(node) != JSONArray) {
    442444                return FALSE;
    443445        }
    444 
     446       
    445447        // The root <users> node should hold the list of users <user>
    446448        // Walk over the nodes children.
    447         for (i = 0; i < node->u.array.length; i++) {
    448                 txu = twitter_xt_get_user(node->u.array.values[i]);
     449        JSON_Array *arr = json_array(node);
     450        for (i = 0; i < json_array_get_count(arr); i++) {
     451                JSON_Object *o = json_array_get_object(arr, i);
     452                if (!o)
     453                        continue;
     454                txu = twitter_xt_get_user(o);
    449455                if (txu) {
    450456                        txl->list = g_slist_prepend(txl->list, txu);
     
    461467#endif
    462468
    463 static void expand_entities(char **text, const json_value *node);
     469static void expand_entities(char **text, const JSON_Object *node);
    464470
    465471/**
     
    471477 *  - the user in a twitter_xml_user struct.
    472478 */
    473 static struct twitter_xml_status *twitter_xt_get_status(const json_value *node)
     479static struct twitter_xml_status *twitter_xt_get_status(const JSON_Object *node)
    474480{
    475481        struct twitter_xml_status *txs;
    476         const json_value *rt = NULL;
    477 
    478         if (node->type != json_object) {
     482        const JSON_Object *rt = NULL;
     483
     484        if (!node) {
    479485                return FALSE;
    480486        }
     
    482488
    483489        JSON_O_FOREACH(node, k, v) {
    484                 if (strcmp("text", k) == 0 && v->type == json_string) {
    485                         txs->text = g_memdup(v->u.string.ptr, v->u.string.length + 1);
     490                if (strcmp("text", k) == 0 && (txs->text = g_strdup(json_string(v)))) {
     491                        // TODO: Huh strip html? In json? Not sure whether I have to..
    486492                        strip_html(txs->text);
    487                 } else if (strcmp("retweeted_status", k) == 0 && v->type == json_object) {
    488                         rt = v;
    489                 } else if (strcmp("created_at", k) == 0 && v->type == json_string) {
     493                } else if (strcmp("retweeted_status", k) == 0 && (rt = json_object(v))) {
     494                        // Handling below.
     495                } else if (strcmp("created_at", k) == 0 && json_type(v) == JSONString) {
    490496                        struct tm parsed;
    491497
     
    493499                           this field. :-( Also assumes the timezone used
    494500                           is UTC since C time handling functions suck. */
    495                         if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL) {
     501                        if (strptime(json_string(v), TWITTER_TIME_FORMAT, &parsed) != NULL) {
    496502                                txs->created_at = mktime_utc(&parsed);
    497503                        }
    498                 } else if (strcmp("user", k) == 0 && v->type == json_object) {
    499                         txs->user = twitter_xt_get_user(v);
    500                 } else if (strcmp("id", k) == 0 && v->type == json_integer) {
    501                         txs->rt_id = txs->id = v->u.integer;
    502                 } else if (strcmp("in_reply_to_status_id", k) == 0 && v->type == json_integer) {
    503                         txs->reply_to = v->u.integer;
     504                } else if (strcmp("user", k) == 0 && json_type(v) == JSONObject) {
     505                        txs->user = twitter_xt_get_user(json_object(v));
     506                } else if (strcmp("id", k) == 0 && json_type(v) == JSONInteger) {
     507                        txs->rt_id = txs->id = json_integer(v);
     508                } else if (strcmp("in_reply_to_status_id", k) == 0 && json_type(v) == JSONInteger) {
     509                        txs->reply_to = json_integer(v);
    504510                }
    505511        }
     
    530536 * Function to fill a twitter_xml_status struct (DM variant).
    531537 */
    532 static struct twitter_xml_status *twitter_xt_get_dm(const json_value *node)
     538static struct twitter_xml_status *twitter_xt_get_dm(const JSON_Object *node)
    533539{
    534540        struct twitter_xml_status *txs;
    535541
    536         if (node->type != json_object) {
     542        if (!node) {
    537543                return FALSE;
    538544        }
     
    540546
    541547        JSON_O_FOREACH(node, k, v) {
    542                 if (strcmp("text", k) == 0 && v->type == json_string) {
    543                         txs->text = g_memdup(v->u.string.ptr, v->u.string.length + 1);
     548                if (strcmp("text", k) == 0 && (txs->text = g_strdup(json_string(v)))) {
    544549                        strip_html(txs->text);
    545                 } else if (strcmp("created_at", k) == 0 && v->type == json_string) {
     550                } else if (strcmp("created_at", k) == 0 && json_type(v) == JSONString) {
    546551                        struct tm parsed;
    547552
     
    549554                           this field. :-( Also assumes the timezone used
    550555                           is UTC since C time handling functions suck. */
    551                         if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL) {
     556                        if (strptime(json_string(v), TWITTER_TIME_FORMAT, &parsed) != NULL) {
    552557                                txs->created_at = mktime_utc(&parsed);
    553558                        }
    554                 } else if (strcmp("sender", k) == 0 && v->type == json_object) {
    555                         txs->user = twitter_xt_get_user(v);
    556                 } else if (strcmp("id", k) == 0 && v->type == json_integer) {
    557                         txs->id = v->u.integer;
     559                } else if (strcmp("sender", k) == 0 && json_type(v) == JSONObject) {
     560                        txs->user = twitter_xt_get_user(json_object(v));
     561                } else if (strcmp("id", k) == 0 && json_type(v) == JSONInteger) {
     562                        txs->id = json_integer(v);
    558563                }
    559564        }
     
    569574}
    570575
    571 static void expand_entities(char **text, const json_value *node)
    572 {
    573         json_value *entities, *quoted;
     576static void expand_entities(char **text, const JSON_Object *node)
     577{
     578        JSON_Object *entities, *quoted;
    574579        char *quote_url = NULL, *quote_text = NULL;
    575580
    576         if (!((entities = json_o_get(node, "entities")) && entities->type == json_object))
    577                 return;
    578         if ((quoted = json_o_get(node, "quoted_status")) && quoted->type == json_object) {
     581        if (!(entities = json_object_get_object(node, "entities")))
     582                return;
     583        if ((quoted = json_object_get_object(node, "quoted_status"))) {
    579584                /* New "retweets with comments" feature. Note that this info
    580585                 * seems to be included in the streaming API only! Grab the
     
    592597                int i;
    593598
    594                 if (v->type != json_array) {
     599                if (json_type(v) != JSONArray) {
    595600                        continue;
    596601                }
     
    599604                }
    600605
    601                 for (i = 0; i < v->u.array.length; i++) {
     606                for (i = 0; i < json_array_get_count(json_array(v)); i++) {
    602607                        const char *format = "%s%s <%s>%s";
    603 
    604                         if (v->u.array.values[i]->type != json_object) {
     608                        JSON_Object *r = json_array_get_object(json_array(v), i);
     609
     610                        if (!r) {
    605611                                continue;
    606612                        }
    607613
    608                         const char *kort = json_o_str(v->u.array.values[i], "url");
    609                         const char *disp = json_o_str(v->u.array.values[i], "display_url");
    610                         const char *full = json_o_str(v->u.array.values[i], "expanded_url");
     614                        const char *kort = json_object_get_string(r, "url");
     615                        const char *disp = json_object_get_string(r, "display_url");
     616                        const char *full = json_object_get_string(r, "expanded_url");
    611617                        char *pos, *new;
    612618
     
    637643 *  - the next_cursor.
    638644 */
    639 static gboolean twitter_xt_get_status_list(struct im_connection *ic, const json_value *node,
     645static gboolean twitter_xt_get_status_list(struct im_connection *ic, const JSON_Value *node,
    640646                                           struct twitter_xml_list *txl)
    641647{
     
    646652        txl->type = TXL_STATUS;
    647653
    648         if (node->type != json_array) {
     654        if (json_type(node) != JSONArray) {
    649655                return FALSE;
    650656        }
     
    652658        // The root <statuses> node should hold the list of statuses <status>
    653659        // Walk over the nodes children.
    654         for (i = 0; i < node->u.array.length; i++) {
    655                 txs = twitter_xt_get_status(node->u.array.values[i]);
     660        for (i = 0; i < json_array_get_count(json_array(node)); i++) {
     661                txs = twitter_xt_get_status(json_array_get_object(json_array(node), i));
    656662                if (!txs) {
    657663                        continue;
     
    859865}
    860866
    861 static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o, gboolean from_filter);
     867static gboolean twitter_stream_handle_object(struct im_connection *ic, JSON_Object *o, gboolean from_filter);
    862868
    863869static void twitter_http_stream(struct http_request *req)
     
    865871        struct im_connection *ic = req->data;
    866872        struct twitter_data *td;
    867         json_value *parsed;
     873        JSON_Value *parsed;
    868874        int len = 0;
    869875        char c, *nl;
     
    903909                req->reply_body[len] = '\0';
    904910
    905                 if ((parsed = json_parse(req->reply_body, req->body_size))) {
     911                if ((parsed = json_parse_string(req->reply_body))) {
    906912                        from_filter = (req == td->filter_stream);
    907                         twitter_stream_handle_object(ic, parsed, from_filter);
     913                        twitter_stream_handle_object(ic, json_object(parsed), from_filter);
    908914                }
    909915                json_value_free(parsed);
     
    919925}
    920926
    921 static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value *o);
     927static gboolean twitter_stream_handle_event(struct im_connection *ic, JSON_Object *o);
    922928static gboolean twitter_stream_handle_status(struct im_connection *ic, struct twitter_xml_status *txs);
    923929
    924 static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o, gboolean from_filter)
     930static gboolean twitter_stream_handle_object(struct im_connection *ic, JSON_Object *o, gboolean from_filter)
    925931{
    926932        struct twitter_data *td = ic->proto_data;
    927933        struct twitter_xml_status *txs;
    928         json_value *c;
     934        JSON_Object *c;
    929935
    930936        if ((txs = twitter_xt_get_status(o))) {
     
    933939                txs_free(txs);
    934940                return ret;
    935         } else if ((c = json_o_get(o, "direct_message")) &&
     941        } else if ((c = json_object_get_object(o, "direct_message")) &&
    936942                   (txs = twitter_xt_get_dm(c))) {
    937943                if (g_strcasecmp(txs->user->screen_name, td->user) != 0) {
     
    941947                txs_free(txs);
    942948                return TRUE;
    943         } else if ((c = json_o_get(o, "event")) && c->type == json_string) {
     949        } else if (json_object_get_string(o, "event")) {
    944950                twitter_stream_handle_event(ic, o);
    945951                return TRUE;
    946         } else if ((c = json_o_get(o, "disconnect")) && c->type == json_object) {
     952        } else if ((c = json_object_get_object(o, "disconnect"))) {
    947953                /* HACK: Because we're inside an event handler, we can't just
    948954                   disconnect here. Instead, just change the HTTP status string
    949955                   into a Twitter status string. */
    950                 char *reason = json_o_strdup(c, "reason");
     956                char *reason = g_strdup(json_object_get_string(c, "reason"));
    951957                if (reason) {
    952958                        g_free(td->stream->status_string);
     
    987993}
    988994
    989 static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value *o)
    990 {
    991         struct twitter_data *td = ic->proto_data;
    992         json_value *source = json_o_get(o, "source");
    993         json_value *target = json_o_get(o, "target");
    994         const char *type = json_o_str(o, "event");
    995 
    996         if (!type || !source || source->type != json_object
    997             || !target || target->type != json_object) {
     995static gboolean twitter_stream_handle_event(struct im_connection *ic, JSON_Object *o)
     996{
     997        struct twitter_data *td = ic->proto_data;
     998        JSON_Object *source = json_object_get_object(o, "source");
     999        JSON_Object *target = json_object_get_object(o, "target");
     1000        const char *type = json_object_get_string(o, "event");
     1001
     1002        if (!type || !source || !target) {
    9981003                return FALSE;
    9991004        }
     
    10921097        struct twitter_filter *tf;
    10931098        GList *users = NULL;
    1094         json_value *parsed;
    1095         json_value *id;
    1096         const char *name;
     1099        JSON_Value *parsed;
    10971100        GString *fstr;
    10981101        GSList *l;
     
    11191122        }
    11201123
    1121         if (parsed->type != json_array) {
     1124        if (json_type(parsed) != JSONArray) {
    11221125                goto finish;
    11231126        }
    11241127
    1125         for (i = 0; i < parsed->u.array.length; i++) {
    1126                 id = json_o_get(parsed->u.array.values[i], "id");
    1127                 name = json_o_str(parsed->u.array.values[i], "screen_name");
    1128 
    1129                 if (!name || !id || id->type != json_integer) {
     1128        for (i = 0; i < json_array_get_count(json_array(parsed)); i++) {
     1129                JSON_Object *o = json_array_get_object(json_array(parsed), i);
     1130                jint id = json_object_get_integer(o, "id");
     1131                const char *name = json_object_get_string(o, "screen_name");
     1132
     1133                if (!name || !id) {
    11301134                        continue;
    11311135                }
     
    11351139
    11361140                        if (g_strcasecmp(tf->text, name) == 0) {
    1137                                 tf->uid = id->u.integer;
     1141                                tf->uid = id;
    11381142                                users = g_list_delete_link(users, u);
    11391143                                break;
     
    13761380        struct im_connection *ic = req->data;
    13771381        struct twitter_data *td;
    1378         json_value *parsed;
     1382        JSON_Value *parsed;
    13791383        struct twitter_xml_list *txl;
    13801384
     
    14161420        struct im_connection *ic = req->data;
    14171421        struct twitter_data *td;
    1418         json_value *parsed;
     1422        JSON_Value *parsed;
    14191423        struct twitter_xml_list *txl;
    14201424
     
    14571461        struct im_connection *ic = req->data;
    14581462        struct twitter_data *td;
    1459         json_value *parsed, *id;
     1463        JSON_Value *parsed;
     1464        jint id;
    14601465
    14611466        // Check if the connection is still active.
     
    14711476        }
    14721477
    1473         if ((id = json_o_get(parsed, "id")) && id->type == json_integer) {
    1474                 td->last_status_id = id->u.integer;
     1478        if ((id = json_object_get_integer(json_object(parsed), "id"))) {
     1479                td->last_status_id = id;
    14751480        }
    14761481
     
    15801585{
    15811586        struct im_connection *ic = req->data;
    1582         json_value *parsed, *id;
     1587        JSON_Value *parsed;
     1588        uint64_t id;
    15831589        const char *name;
    15841590
     
    15921598        }
    15931599
    1594         /* for the parson branch:
    15951600        name = json_object_dotget_string(json_object(parsed), "user.screen_name");
    15961601        id = json_object_get_integer(json_object(parsed), "id");
    1597         */
    1598 
    1599         name = json_o_str(json_o_get(parsed, "user"), "screen_name");
    1600         id = json_o_get(parsed, "id");
    1601 
    1602         if (name && id && id->type == json_integer) {
    1603                 twitter_log(ic, "https://twitter.com/%s/status/%" G_GUINT64_FORMAT, name, id->u.integer);
     1602
     1603        if (name && id) {
     1604                twitter_log(ic, "https://twitter.com/%s/status/%" G_GUINT64_FORMAT, name, id);
    16041605        } else {
    16051606                twitter_log(ic, "Error: could not fetch tweet url.");
  • root_commands.c

    r82cb190 r3fbce97  
    476476
    477477                for (a = irc->b->accounts; a; a = a->next) {
    478                         char *con;
     478                        char *con = NULL, *protocol = NULL;
    479479
    480480                        if (a->ic && (a->ic->flags & OPT_LOGGED_IN)) {
     
    487487                                con = "";
    488488                        }
    489 
    490                         irc_rootmsg(irc, "%2d (%s): %s, %s%s", i, a->tag, a->prpl->name, a->user, con);
     489                        if (a->prpl == &protocol_missing) {
     490                                protocol = g_strdup_printf("%s (missing!)", set_getstr(&a->set, "_protocol_name"));
     491                        } else {
     492                                protocol = g_strdup(a->prpl->name);
     493                        }
     494
     495                        irc_rootmsg(irc, "%2d (%s): %s, %s%s", i, a->tag, protocol, a->user, con);
     496                        g_free(protocol);
    491497
    492498                        i++;
     
    502508
    503509                        for (a = irc->b->accounts; a; a = a->next) {
    504                                 if (!a->ic && a->auto_connect) {
     510                                if (!a->ic && a->auto_connect && a->prpl != &protocol_missing) {
    505511                                        if (strcmp(a->pass, PASSWORD_PENDING) == 0) {
    506512                                                irc_rootmsg(irc, "Enter password for account %s "
     
    559565                        irc_rootmsg(irc, "Enter password for account %s "
    560566                                    "first (use /OPER)", a->tag);
     567                } else if (a->prpl == &protocol_missing) {
     568                        irc_rootmsg(irc, "Protocol `%s' not recognised (plugin may be missing or not running?)",
     569                                    set_getstr(&a->set, "_protocol_name"));
    561570                } else {
    562571                        account_on(irc->b, a);
     
    663672                irc_rootmsg(irc, "That account is not on-line");
    664673                return;
     674        } else if (add_on_server && !a->prpl->add_buddy) {
     675                irc_rootmsg(irc, "IM protocol does not support contact list modification");
     676                return;
     677        }
     678
     679        if ((a->flags & ACC_FLAG_HANDLE_DOMAINS) && cmd[2][0] != '_' &&
     680            (!(s = strchr(cmd[2], '@')) || s[1] == '\0')) {
     681                /* If there's no @ or it's the last char, append the user's
     682                   domain name now. Exclude handles starting with a _ so
     683                   adding _xmlconsole will keep working. */
     684                if (s) {
     685                        *s = '\0';
     686                }
     687                if ((s = strchr(a->user, '@'))) {
     688                        cmd[2] = handle = g_strconcat(cmd[2], s, NULL);
     689                }
    665690        }
    666691
     
    677702        }
    678703
    679         if ((a->flags & ACC_FLAG_HANDLE_DOMAINS) && cmd[2][0] != '_' &&
    680             (!(s = strchr(cmd[2], '@')) || s[1] == '\0')) {
    681                 /* If there's no @ or it's the last char, append the user's
    682                    domain name now. Exclude handles starting with a _ so
    683                    adding _xmlconsole will keep working. */
    684                 if (s) {
    685                         *s = '\0';
    686                 }
    687                 if ((s = strchr(a->user, '@'))) {
    688                         cmd[2] = handle = g_strconcat(cmd[2], s, NULL);
    689                 }
    690         }
    691 
    692704        if (add_on_server) {
    693705                irc_channel_t *ic;
     
    733745        s = g_strdup(bu->handle);
    734746
    735         bu->ic->acc->prpl->remove_buddy(bu->ic, bu->handle, NULL);
     747        if (bu->ic->acc->prpl->remove_buddy) {
     748                bu->ic->acc->prpl->remove_buddy(bu->ic, bu->handle, NULL);
     749        } else {
     750                irc_rootmsg(irc, "IM protocol does not support contact list modification, "
     751                                 "removal will likely not be permanent");
     752        }
     753
    736754        nick_del(bu);
    737755        if (g_slist_find(irc->users, iu)) {
  • storage.c

    r82cb190 r3fbce97  
    3333
    3434static GList *storage_backends = NULL;
     35
     36const struct prpl protocol_missing = {
     37        .name = "_unknown",
     38};
    3539
    3640void register_storage_backend(storage_t *backend)
  • storage.h

    r82cb190 r3fbce97  
    6262G_GNUC_MALLOC GList *storage_init(const char *primary, char **migrate);
    6363
     64extern const struct prpl protocol_missing;
     65
    6466#endif /* __STORAGE_H__ */
  • storage_xml.c

    r82cb190 r3fbce97  
    8383}
    8484
     85/* Use for unsupported/not-found protocols. Save settings as-is but don't allow changes. */
     86static void handle_settings_raw(struct xt_node *node, set_t **head)
     87{
     88        struct xt_node *c;
     89
     90        for (c = node->children; (c = xt_find_node(c, "setting")); c = c->next) {
     91                char *name = xt_find_attr(c, "name");
     92
     93                if (!name) {
     94                        continue;
     95                }
     96
     97                set_t *s = set_add(head, name, NULL, NULL, NULL);
     98                set_setstr(head, name, c->text);
     99                s->flags |= SET_HIDDEN |
     100                            ACC_SET_OFFLINE_ONLY | ACC_SET_ONLINE_ONLY;
     101        }
     102}
     103
    85104static xt_status handle_account(struct xt_node *node, gpointer data)
    86105{
     
    89108        char *pass_b64 = NULL;
    90109        unsigned char *pass_cr = NULL;
    91         int pass_len, local = 0;
     110        int pass_len;
    92111        struct prpl *prpl = NULL;
    93112        account_t *acc;
     
    104123                prpl = find_protocol(protocol);
    105124                if (!prpl) {
    106                         irc_rootmsg(xd->irc, "Error loading user config: Protocol not found: `%s'", protocol);
    107                         return XT_ABORT;
    108                 }
    109                 local = protocol_account_islocal(protocol);
     125                        irc_rootmsg(xd->irc, "Warning: Protocol not found: `%s'", protocol);
     126                        prpl = (struct prpl*) &protocol_missing;
     127                }
    110128        }
    111129
     
    124142                        set_setstr(&acc->set, "tag", tag);
    125143                }
    126                 if (local) {
    127                         acc->flags |= ACC_FLAG_LOCAL;
     144                if (prpl == &protocol_missing) {
     145                        set_t *s = set_add(&acc->set, "_protocol_name", protocol, NULL, NULL);
     146                        s->flags |= SET_HIDDEN | SET_NOSAVE |
     147                                    ACC_SET_OFFLINE_ONLY | ACC_SET_ONLINE_ONLY;
    128148                }
    129149        } else {
     
    136156        g_free(password);
    137157
    138         handle_settings(node, &acc->set);
     158        if (prpl == &protocol_missing) {
     159                handle_settings_raw(node, &acc->set);
     160        } else {
     161                handle_settings(node, &acc->set);
     162        }
    139163
    140164        for (c = node->children; (c = xt_find_node(c, "buddy")); c = c->next) {
     
    312336
    313337                cur = xt_new_node("account", NULL, NULL);
    314                 xt_add_attr(cur, "protocol", acc->prpl->name);
     338                if (acc->prpl == &protocol_missing) {
     339                        xt_add_attr(cur, "protocol", set_getstr(&acc->set, "_protocol_name"));
     340                } else {
     341                        xt_add_attr(cur, "protocol", acc->prpl->name);
     342                }
    315343                xt_add_attr(cur, "handle", acc->user);
    316344                xt_add_attr(cur, "password", pass_b64);
Note: See TracChangeset for help on using the changeset viewer.