Changes in / [24de9fa:69b94c3]


Ignore:
Files:
7 added
4 deleted
22 edited

Legend:

Unmodified
Added
Removed
  • .gitignore

    r24de9fa r69b94c3  
    3232bitlbee.service
    3333bitlbee@.service
     34*.pyc
  • configure

    r24de9fa r69b94c3  
    3232jabber="default-on"
    3333oscar="default-on"
     34rpc="rpc-on"
    3435yahoo="default-on"
    3536
     
    130131--purple=0/1    Disable/enable libpurple support        $purple
    131132                (automatically disables other protocol modules)
     133--rpc=0/1       Disable/enable RPC interface            $rpc
    132134
    133135--doc=0/1       Disable/enable help.txt generation      $doc
     
    820822        protocols=$protocols'twitter '
    821823        protoobjs=$protoobjs'twitter_mod.o '
     824fi
     825
     826if [ "$rpc" = 0 ]; then
     827        echo '#undef WITH_RPC' >> config.h
     828else
     829        echo '#define WITH_RPC' >> config.h
     830        protocols=$protocols'rpc '
     831        protoobjs=$protoobjs'rpc_mod.o '
    822832fi
    823833
  • doc/user-guide/commands.xml

    r24de9fa r69b94c3  
    11861186        </bitlbee-setting>
    11871187
     1188        <bitlbee-setting name="anonymous" type="boolean" scope="account">
     1189                <default>false</default>
     1190
     1191                <description>
     1192                        <para>
     1193                                This enables SASL ANONYMOUS login for jabber accounts, as specified by XEP-0175.
     1194                        </para>
     1195
     1196                        <para>
     1197                                With this setting enabled, if the server allows this method, a password isn't required and the username part of the JID is ignored (you can use anonymous@jabber.example.com). Servers will usually assign you a random numeric username instead.
     1198                        </para>
     1199                </description>
     1200
     1201        </bitlbee-setting>
     1202
    11881203        <bitlbee-setting name="ops" type="string" scope="global">
    11891204                <default>both</default>
  • irc_channel.c

    r24de9fa r69b94c3  
    724724        }
    725725
     726        if (!bu->ic->acc->prpl->add_buddy) {
     727                irc_send_num(ic->irc, 482, "%s :IM protocol does not support contact list modification", ic->name);
     728                return FALSE;
     729        }
     730
    726731        bu->ic->acc->prpl->add_buddy(bu->ic, bu->handle,
    727732                                     icc->group ? icc->group->name : NULL);
     
    741746        if (icc->type != IRC_CC_TYPE_GROUP) {
    742747                irc_send_num(ic->irc, 482, "%s :Kicks are only possible to fill_by=group channels", ic->name);
     748                return;
     749        }
     750
     751        if (!bu->ic->acc->prpl->remove_buddy) {
     752                irc_send_num(ic->irc, 482, "%s :IM protocol does not support contact list modification", ic->name);
    743753                return;
    744754        }
  • irc_commands.c

    r24de9fa r69b94c3  
    166166                           showed an error message, or is doing some work
    167167                           before the join should be confirmed. (In the
    168                            latter case, the caller should take care of that
     168                           latter case, the callee should take care of that
    169169                           confirmation.) TRUE means all's good, let the
    170170                           user join the channel right away. */
  • lib/Makefile

    r24de9fa r69b94c3  
    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

    r24de9fa r69b94c3  
    427427}
    428428
    429 int is_bool(char *value)
     429int is_bool(const char *value)
    430430{
    431431        if (*value == 0) {
     
    453453}
    454454
    455 int bool2int(char *value)
     455int bool2int(const char *value)
    456456{
    457457        int i;
  • lib/misc.h

    r24de9fa r69b94c3  
    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

    r24de9fa r69b94c3  
    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

    r24de9fa r69b94c3  
    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);
     
    463459        return a->auto_reconnect_delay;
    464460}
    465 
    466 int protocol_account_islocal(const char* protocol)
    467 {
    468         const char** p = account_protocols_local;
    469 
    470         do {
    471                 if (strcmp(*p, protocol) == 0) {
    472                         return 1;
    473                 }
    474         } while (*(++p));
    475         return 0;
    476 }
  • protocols/account.h

    r24de9fa r69b94c3  
    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/jabber/jabber.c

    r24de9fa r69b94c3  
    8585                set_setstr(&acc->set, "server", "chat.hipchat.com");
    8686        } else {
    87                 s = set_add(&acc->set, "oauth", "false", set_eval_oauth, acc);
     87                set_add(&acc->set, "oauth", "false", set_eval_oauth, acc);
     88
     89                /* this reuses set_eval_oauth, which clears the password */
     90                set_add(&acc->set, "anonymous", "false", set_eval_oauth, acc);
    8891        }
    8992
  • protocols/jabber/s5bytestream.c

    r24de9fa r69b94c3  
    8585                return jabber_bs_abort(bt, msg ": %s", strerror(errno)); }
    8686
    87 gboolean jabber_bs_abort(struct bs_transfer *bt, char *format, ...);
     87gboolean jabber_bs_abort(struct bs_transfer *bt, char *format, ...) G_GNUC_PRINTF(2, 3);
    8888void jabber_bs_canceled(file_transfer_t *ft, char *reason);
    8989void jabber_bs_free_transfer(file_transfer_t *ft);
  • protocols/jabber/sasl.c

    r24de9fa r69b94c3  
    5454        struct xt_node *c, *reply;
    5555        char *s;
    56         int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_fb = 0;
    57         int want_oauth = FALSE, want_hipchat = FALSE;
     56        int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_fb = 0, sup_anonymous = 0;
     57        int want_oauth = FALSE, want_hipchat = FALSE, want_anonymous = FALSE;
    5858        GString *mechs;
    5959
     
    7474        }
    7575
     76        want_anonymous = set_getbool(&ic->acc->set, "anonymous");
    7677        want_oauth = set_getbool(&ic->acc->set, "oauth");
    7778        want_hipchat = (jd->flags & JFLAG_HIPCHAT);
     
    8485                } else if (c->text && g_strcasecmp(c->text, "DIGEST-MD5") == 0) {
    8586                        sup_digest = 1;
     87                } else if (c->text && g_strcasecmp(c->text, "ANONYMOUS") == 0) {
     88                        sup_anonymous = 1;
    8689                } else if (c->text && g_strcasecmp(c->text, "X-OAUTH2") == 0) {
    8790                        sup_gtalk = 1;
     
    139142        } else if (want_oauth) {
    140143                imcb_error(ic, "OAuth requested, but not supported by server");
     144                imc_logout(ic, FALSE);
     145                xt_free_node(reply);
     146                return XT_ABORT;
     147        } else if (want_anonymous && sup_anonymous) {
     148                xt_add_attr(reply, "mechanism", "ANONYMOUS");
     149
     150                /* Well, that was easy. */
     151        } else if (want_anonymous) {
     152                imcb_error(ic, "Anonymous login requested, but not supported by server");
    141153                imc_logout(ic, FALSE);
    142154                xt_free_node(reply);
  • protocols/nogaim.c

    r24de9fa r69b94c3  
    132132        extern void twitter_initmodule();
    133133        extern void purple_initmodule();
     134        extern void rpc_initmodule();
    134135
    135136#ifdef WITH_MSN
     
    155156#ifdef WITH_PURPLE
    156157        purple_initmodule();
     158#endif
     159
     160#ifdef WITH_RPC
     161        rpc_initmodule();
    157162#endif
    158163
     
    307312        }
    308313
    309         if (ic->acc->flags & ACC_FLAG_LOCAL) {
     314        if ((ic->acc->flags & ACC_FLAG_LOCAL_CONTACTS) &&
     315            !(ic->flags & OPT_LOCAL_CONTACTS_SENT) &&
     316            ic->acc->prpl->add_buddy) {
    310317                GHashTableIter nicks;
    311                 gpointer k, v;
     318                gpointer handle;
    312319                g_hash_table_iter_init(&nicks, ic->acc->nicks);
    313                 while (g_hash_table_iter_next(&nicks, &k, &v)) {
    314                         ic->acc->prpl->add_buddy(ic, (char *) k, NULL);
     320                while (g_hash_table_iter_next(&nicks, &handle, NULL)) {
     321                        ic->acc->prpl->add_buddy(ic, (char *) handle, NULL);
    315322                }
    316323        }
     
    407414        query_del_by_conn((irc_t *) ic->bee->ui_data, ic);
    408415
     416        /* Throw away groupchats owned by this account. Historically this was only
     417           ever done by IM modules which is a bug. But it gives them opportunity
     418           to clean up protocol-specific bits as well so keep it that way, just
     419           do another cleanup here as a fallback. Don't want to leave any dangling
     420           pointers! */
     421        while (ic->groupchats) {
     422                imcb_chat_free(ic->groupchats->data);
     423        }
     424
    409425        if (!a) {
    410426                /* Uhm... This is very sick. */
     
    492508}
    493509
     510/* Returns the local contacts for an IM account (based on assigned nicks).
     511   Linked list should be freed, the strings themselves not! So look at it
     512   like a GSList<const char*> I guess? Empty list means NULL retval (as
     513   always with GSList). */
     514GSList *imcb_get_local_contacts(struct im_connection *ic)
     515{
     516        GHashTableIter nicks;
     517        GSList *ret = NULL;
     518       
     519        if (!(ic->acc->flags & ACC_FLAG_LOCAL_CONTACTS)) {
     520                /* Only allow protocols that indicate local contact list
     521                   support to use this function. */
     522                return ret;
     523        }
     524       
     525        g_hash_table_iter_init(&nicks, ic->acc->nicks);
     526        gpointer handle;
     527        while (g_hash_table_iter_next(&nicks, &handle, NULL)) {
     528                ret = g_slist_prepend(ret, (char *) handle);
     529        }
     530       
     531        /* If the protocol asked for the list, assume we won't have to send it
     532           anymore in imcb_connected(). */
     533        ic->flags |= OPT_LOCAL_CONTACTS_SENT;
     534       
     535        return ret;
     536}
     537
    494538
    495539struct imcb_ask_cb_data {
     
    550594        struct imcb_ask_cb_data *cbd = data;
    551595
    552         cbd->ic->acc->prpl->add_buddy(cbd->ic, cbd->handle, NULL);
     596        if (cbd->ic->acc->prpl->add_buddy) {
     597                cbd->ic->acc->prpl->add_buddy(cbd->ic, cbd->handle, NULL);
     598        }
    553599
    554600        imcb_ask_cb_free(data);
  • protocols/nogaim.h

    r24de9fa r69b94c3  
    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
    7379/* ok. now the fun begins. first we create a connection structure */
     
    324330G_MODULE_EXPORT void imcb_buddy_nick_hint(struct im_connection *ic, const char *handle, const char *nick);
    325331G_MODULE_EXPORT void imcb_buddy_action_response(bee_user_t *bu, const char *action, char * const args[], void *data);
     332G_MODULE_EXPORT GSList *imcb_get_local_contacts(struct im_connection *ic);
    326333
    327334G_MODULE_EXPORT void imcb_buddy_typing(struct im_connection *ic, const char *handle, uint32_t flags);
  • protocols/purple/purple.c

    r24de9fa r69b94c3  
    264264        }
    265265        purple_accounts_remove(pa);
     266       
     267        /* Last, some protocols want their contact lists locally. */
     268        if (strcmp(acc->prpl->name, "whatsapp") == 0 || strcmp(acc->prpl->name, "gg") == 0) {
     269                acc->flags |= ACC_FLAG_LOCAL_CONTACTS;
     270        }
    266271}
    267272
  • protocols/twitter/twitter_lib.c

    r24de9fa r69b94c3  
    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;
     
    410412}
    411413
    412 struct twitter_xml_user *twitter_xt_get_user(const json_value *node)
     414struct twitter_xml_user *twitter_xt_get_user(const JSON_Object *node)
    413415{
    414416        struct twitter_xml_user *txu;
    415         json_value *jv;
     417       
     418        if (!node)
     419                return NULL;
    416420
    417421        txu = g_new0(struct twitter_xml_user, 1);
    418         txu->name = g_strdup(json_o_str(node, "name"));
    419         txu->screen_name = g_strdup(json_o_str(node, "screen_name"));
    420 
    421         jv = json_o_get(node, "id");
    422         txu->uid = jv->u.integer;
     422        txu->name = g_strdup(json_object_get_string(node, "name"));
     423        txu->screen_name = g_strdup(json_object_get_string(node, "screen_name"));
     424        txu->uid = json_object_get_integer(node, "id");
    423425
    424426        return txu;
     
    430432 *  - all <user>s from the <users> element.
    431433 */
    432 static gboolean twitter_xt_get_users(json_value *node, struct twitter_xml_list *txl)
     434static gboolean twitter_xt_get_users(JSON_Value *node, struct twitter_xml_list *txl)
    433435{
    434436        struct twitter_xml_user *txu;
     
    438440        txl->type = TXL_USER;
    439441
    440         if (!node || node->type != json_array) {
     442        if (json_type(node) != JSONArray) {
    441443                return FALSE;
    442444        }
    443 
     445       
    444446        // The root <users> node should hold the list of users <user>
    445447        // Walk over the nodes children.
    446         for (i = 0; i < node->u.array.length; i++) {
    447                 txu = twitter_xt_get_user(node->u.array.values[i]);
     448        JSON_Array *arr = json_array(node);
     449        for (i = 0; i < json_array_get_count(arr); i++) {
     450                JSON_Object *o = json_array_get_object(arr, i);
     451                if (!o)
     452                        continue;
     453                txu = twitter_xt_get_user(o);
    448454                if (txu) {
    449455                        txl->list = g_slist_prepend(txl->list, txu);
     
    460466#endif
    461467
    462 static void expand_entities(char **text, const json_value *node);
     468static void expand_entities(char **text, const JSON_Object *node);
    463469
    464470/**
     
    470476 *  - the user in a twitter_xml_user struct.
    471477 */
    472 static struct twitter_xml_status *twitter_xt_get_status(const json_value *node)
     478static struct twitter_xml_status *twitter_xt_get_status(const JSON_Object *node)
    473479{
    474480        struct twitter_xml_status *txs;
    475         const json_value *rt = NULL;
    476 
    477         if (node->type != json_object) {
     481        const JSON_Object *rt = NULL;
     482
     483        if (!node) {
    478484                return FALSE;
    479485        }
     
    481487
    482488        JSON_O_FOREACH(node, k, v) {
    483                 if (strcmp("text", k) == 0 && v->type == json_string) {
    484                         txs->text = g_memdup(v->u.string.ptr, v->u.string.length + 1);
     489                if (strcmp("text", k) == 0 && (txs->text = g_strdup(json_string(v)))) {
     490                        // TODO: Huh strip html? In json? Not sure whether I have to..
    485491                        strip_html(txs->text);
    486                 } else if (strcmp("retweeted_status", k) == 0 && v->type == json_object) {
    487                         rt = v;
    488                 } else if (strcmp("created_at", k) == 0 && v->type == json_string) {
     492                } else if (strcmp("retweeted_status", k) == 0 && (rt = json_object(v))) {
     493                        // Handling below.
     494                } else if (strcmp("created_at", k) == 0 && json_type(v) == JSONString) {
    489495                        struct tm parsed;
    490496
     
    492498                           this field. :-( Also assumes the timezone used
    493499                           is UTC since C time handling functions suck. */
    494                         if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL) {
     500                        if (strptime(json_string(v), TWITTER_TIME_FORMAT, &parsed) != NULL) {
    495501                                txs->created_at = mktime_utc(&parsed);
    496502                        }
    497                 } else if (strcmp("user", k) == 0 && v->type == json_object) {
    498                         txs->user = twitter_xt_get_user(v);
    499                 } else if (strcmp("id", k) == 0 && v->type == json_integer) {
    500                         txs->rt_id = txs->id = v->u.integer;
    501                 } else if (strcmp("in_reply_to_status_id", k) == 0 && v->type == json_integer) {
    502                         txs->reply_to = v->u.integer;
     503                } else if (strcmp("user", k) == 0 && json_type(v) == JSONObject) {
     504                        txs->user = twitter_xt_get_user(json_object(v));
     505                } else if (strcmp("id", k) == 0 && json_type(v) == JSONInteger) {
     506                        txs->rt_id = txs->id = json_integer(v);
     507                } else if (strcmp("in_reply_to_status_id", k) == 0 && json_type(v) == JSONInteger) {
     508                        txs->reply_to = json_integer(v);
    503509                }
    504510        }
     
    529535 * Function to fill a twitter_xml_status struct (DM variant).
    530536 */
    531 static struct twitter_xml_status *twitter_xt_get_dm(const json_value *node)
     537static struct twitter_xml_status *twitter_xt_get_dm(const JSON_Object *node)
    532538{
    533539        struct twitter_xml_status *txs;
    534540
    535         if (node->type != json_object) {
     541        if (!node) {
    536542                return FALSE;
    537543        }
     
    539545
    540546        JSON_O_FOREACH(node, k, v) {
    541                 if (strcmp("text", k) == 0 && v->type == json_string) {
    542                         txs->text = g_memdup(v->u.string.ptr, v->u.string.length + 1);
     547                if (strcmp("text", k) == 0 && (txs->text = g_strdup(json_string(v)))) {
    543548                        strip_html(txs->text);
    544                 } else if (strcmp("created_at", k) == 0 && v->type == json_string) {
     549                } else if (strcmp("created_at", k) == 0 && json_type(v) == JSONString) {
    545550                        struct tm parsed;
    546551
     
    548553                           this field. :-( Also assumes the timezone used
    549554                           is UTC since C time handling functions suck. */
    550                         if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL) {
     555                        if (strptime(json_string(v), TWITTER_TIME_FORMAT, &parsed) != NULL) {
    551556                                txs->created_at = mktime_utc(&parsed);
    552557                        }
    553                 } else if (strcmp("sender", k) == 0 && v->type == json_object) {
    554                         txs->user = twitter_xt_get_user(v);
    555                 } else if (strcmp("id", k) == 0 && v->type == json_integer) {
    556                         txs->id = v->u.integer;
     558                } else if (strcmp("sender", k) == 0 && json_type(v) == JSONObject) {
     559                        txs->user = twitter_xt_get_user(json_object(v));
     560                } else if (strcmp("id", k) == 0 && json_type(v) == JSONInteger) {
     561                        txs->id = json_integer(v);
    557562                }
    558563        }
     
    568573}
    569574
    570 static void expand_entities(char **text, const json_value *node)
    571 {
    572         json_value *entities, *quoted;
     575static void expand_entities(char **text, const JSON_Object *node)
     576{
     577        JSON_Object *entities, *quoted;
    573578        char *quote_url = NULL, *quote_text = NULL;
    574579
    575         if (!((entities = json_o_get(node, "entities")) && entities->type == json_object))
    576                 return;
    577         if ((quoted = json_o_get(node, "quoted_status")) && quoted->type == json_object) {
     580        if (!(entities = json_object_get_object(node, "entities")))
     581                return;
     582        if ((quoted = json_object_get_object(node, "quoted_status"))) {
    578583                /* New "retweets with comments" feature. Note that this info
    579584                 * seems to be included in the streaming API only! Grab the
     
    591596                int i;
    592597
    593                 if (v->type != json_array) {
     598                if (json_type(v) != JSONArray) {
    594599                        continue;
    595600                }
     
    598603                }
    599604
    600                 for (i = 0; i < v->u.array.length; i++) {
     605                for (i = 0; i < json_array_get_count(json_array(v)); i++) {
    601606                        const char *format = "%s%s <%s>%s";
    602 
    603                         if (v->u.array.values[i]->type != json_object) {
     607                        JSON_Object *r = json_array_get_object(json_array(v), i);
     608
     609                        if (!r) {
    604610                                continue;
    605611                        }
    606612
    607                         const char *kort = json_o_str(v->u.array.values[i], "url");
    608                         const char *disp = json_o_str(v->u.array.values[i], "display_url");
    609                         const char *full = json_o_str(v->u.array.values[i], "expanded_url");
     613                        const char *kort = json_object_get_string(r, "url");
     614                        const char *disp = json_object_get_string(r, "display_url");
     615                        const char *full = json_object_get_string(r, "expanded_url");
    610616                        char *pos, *new;
    611617
     
    636642 *  - the next_cursor.
    637643 */
    638 static gboolean twitter_xt_get_status_list(struct im_connection *ic, const json_value *node,
     644static gboolean twitter_xt_get_status_list(struct im_connection *ic, const JSON_Value *node,
    639645                                           struct twitter_xml_list *txl)
    640646{
     
    645651        txl->type = TXL_STATUS;
    646652
    647         if (node->type != json_array) {
     653        if (json_type(node) != JSONArray) {
    648654                return FALSE;
    649655        }
     
    651657        // The root <statuses> node should hold the list of statuses <status>
    652658        // Walk over the nodes children.
    653         for (i = 0; i < node->u.array.length; i++) {
    654                 txs = twitter_xt_get_status(node->u.array.values[i]);
     659        for (i = 0; i < json_array_get_count(json_array(node)); i++) {
     660                txs = twitter_xt_get_status(json_array_get_object(json_array(node), i));
    655661                if (!txs) {
    656662                        continue;
     
    858864}
    859865
    860 static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o, gboolean from_filter);
     866static gboolean twitter_stream_handle_object(struct im_connection *ic, JSON_Object *o, gboolean from_filter);
    861867
    862868static void twitter_http_stream(struct http_request *req)
     
    864870        struct im_connection *ic = req->data;
    865871        struct twitter_data *td;
    866         json_value *parsed;
     872        JSON_Value *parsed;
    867873        int len = 0;
    868874        char c, *nl;
     
    902908                req->reply_body[len] = '\0';
    903909
    904                 if ((parsed = json_parse(req->reply_body, req->body_size))) {
     910                if ((parsed = json_parse_string(req->reply_body))) {
    905911                        from_filter = (req == td->filter_stream);
    906                         twitter_stream_handle_object(ic, parsed, from_filter);
     912                        twitter_stream_handle_object(ic, json_object(parsed), from_filter);
    907913                }
    908914                json_value_free(parsed);
     
    918924}
    919925
    920 static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value *o);
     926static gboolean twitter_stream_handle_event(struct im_connection *ic, JSON_Object *o);
    921927static gboolean twitter_stream_handle_status(struct im_connection *ic, struct twitter_xml_status *txs);
    922928
    923 static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o, gboolean from_filter)
     929static gboolean twitter_stream_handle_object(struct im_connection *ic, JSON_Object *o, gboolean from_filter)
    924930{
    925931        struct twitter_data *td = ic->proto_data;
    926932        struct twitter_xml_status *txs;
    927         json_value *c;
     933        JSON_Object *c;
    928934
    929935        if ((txs = twitter_xt_get_status(o))) {
     
    932938                txs_free(txs);
    933939                return ret;
    934         } else if ((c = json_o_get(o, "direct_message")) &&
     940        } else if ((c = json_object_get_object(o, "direct_message")) &&
    935941                   (txs = twitter_xt_get_dm(c))) {
    936942                if (g_strcasecmp(txs->user->screen_name, td->user) != 0) {
     
    940946                txs_free(txs);
    941947                return TRUE;
    942         } else if ((c = json_o_get(o, "event")) && c->type == json_string) {
     948        } else if (json_object_get_string(o, "event")) {
    943949                twitter_stream_handle_event(ic, o);
    944950                return TRUE;
    945         } else if ((c = json_o_get(o, "disconnect")) && c->type == json_object) {
     951        } else if ((c = json_object_get_object(o, "disconnect"))) {
    946952                /* HACK: Because we're inside an event handler, we can't just
    947953                   disconnect here. Instead, just change the HTTP status string
    948954                   into a Twitter status string. */
    949                 char *reason = json_o_strdup(c, "reason");
     955                char *reason = g_strdup(json_object_get_string(c, "reason"));
    950956                if (reason) {
    951957                        g_free(td->stream->status_string);
     
    986992}
    987993
    988 static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value *o)
    989 {
    990         struct twitter_data *td = ic->proto_data;
    991         json_value *source = json_o_get(o, "source");
    992         json_value *target = json_o_get(o, "target");
    993         const char *type = json_o_str(o, "event");
    994 
    995         if (!type || !source || source->type != json_object
    996             || !target || target->type != json_object) {
     994static gboolean twitter_stream_handle_event(struct im_connection *ic, JSON_Object *o)
     995{
     996        struct twitter_data *td = ic->proto_data;
     997        JSON_Object *source = json_object_get_object(o, "source");
     998        JSON_Object *target = json_object_get_object(o, "target");
     999        const char *type = json_object_get_string(o, "event");
     1000
     1001        if (!type || !source || !target) {
    9971002                return FALSE;
    9981003        }
     
    10911096        struct twitter_filter *tf;
    10921097        GList *users = NULL;
    1093         json_value *parsed;
    1094         json_value *id;
    1095         const char *name;
     1098        JSON_Value *parsed;
    10961099        GString *fstr;
    10971100        GSList *l;
     
    11181121        }
    11191122
    1120         if (parsed->type != json_array) {
     1123        if (json_type(parsed) != JSONArray) {
    11211124                goto finish;
    11221125        }
    11231126
    1124         for (i = 0; i < parsed->u.array.length; i++) {
    1125                 id = json_o_get(parsed->u.array.values[i], "id");
    1126                 name = json_o_str(parsed->u.array.values[i], "screen_name");
    1127 
    1128                 if (!name || !id || id->type != json_integer) {
     1127        for (i = 0; i < json_array_get_count(json_array(parsed)); i++) {
     1128                JSON_Object *o = json_array_get_object(json_array(parsed), i);
     1129                jint id = json_object_get_integer(o, "id");
     1130                const char *name = json_object_get_string(o, "screen_name");
     1131
     1132                if (!name || !id) {
    11291133                        continue;
    11301134                }
     
    11341138
    11351139                        if (g_strcasecmp(tf->text, name) == 0) {
    1136                                 tf->uid = id->u.integer;
     1140                                tf->uid = id;
    11371141                                users = g_list_delete_link(users, u);
    11381142                                break;
     
    13751379        struct im_connection *ic = req->data;
    13761380        struct twitter_data *td;
    1377         json_value *parsed;
     1381        JSON_Value *parsed;
    13781382        struct twitter_xml_list *txl;
    13791383
     
    14141418        struct im_connection *ic = req->data;
    14151419        struct twitter_data *td;
    1416         json_value *parsed;
     1420        JSON_Value *parsed;
    14171421        struct twitter_xml_list *txl;
    14181422
     
    14541458        struct im_connection *ic = req->data;
    14551459        struct twitter_data *td;
    1456         json_value *parsed, *id;
     1460        JSON_Value *parsed;
     1461        jint id;
    14571462
    14581463        // Check if the connection is still active.
     
    14681473        }
    14691474
    1470         if ((id = json_o_get(parsed, "id")) && id->type == json_integer) {
    1471                 td->last_status_id = id->u.integer;
     1475        if ((id = json_object_get_integer(json_object(parsed), "id"))) {
     1476                td->last_status_id = id;
    14721477        }
    14731478
     
    15771582{
    15781583        struct im_connection *ic = req->data;
    1579         json_value *parsed, *id;
     1584        JSON_Value *parsed;
     1585        uint64_t id;
    15801586        const char *name;
    15811587
     
    15891595        }
    15901596
    1591         /* for the parson branch:
    15921597        name = json_object_dotget_string(json_object(parsed), "user.screen_name");
    15931598        id = json_object_get_integer(json_object(parsed), "id");
    1594         */
    1595 
    1596         name = json_o_str(json_o_get(parsed, "user"), "screen_name");
    1597         id = json_o_get(parsed, "id");
    1598 
    1599         if (name && id && id->type == json_integer) {
    1600                 twitter_log(ic, "https://twitter.com/%s/status/%" G_GUINT64_FORMAT, name, id->u.integer);
     1599
     1600        if (name && id) {
     1601                twitter_log(ic, "https://twitter.com/%s/status/%" G_GUINT64_FORMAT, name, id);
    16011602        } else {
    16021603                twitter_log(ic, "Error: could not fetch tweet url.");
  • root_commands.c

    r24de9fa r69b94c3  
    460460
    461461                for (a = irc->b->accounts; a; a = a->next) {
    462                         char *con;
     462                        char *con = NULL, *protocol = NULL;
    463463
    464464                        if (a->ic && (a->ic->flags & OPT_LOGGED_IN)) {
     
    471471                                con = "";
    472472                        }
    473 
    474                         irc_rootmsg(irc, "%2d (%s): %s, %s%s", i, a->tag, a->prpl->name, a->user, con);
     473                        if (a->prpl == &protocol_missing) {
     474                                protocol = g_strdup_printf("%s (missing!)", set_getstr(&a->set, "_protocol_name"));
     475                        } else {
     476                                protocol = g_strdup(a->prpl->name);
     477                        }
     478
     479                        irc_rootmsg(irc, "%2d (%s): %s, %s%s", i, a->tag, protocol, a->user, con);
     480                        g_free(protocol);
    475481
    476482                        i++;
     
    486492
    487493                        for (a = irc->b->accounts; a; a = a->next) {
    488                                 if (!a->ic && a->auto_connect) {
     494                                if (!a->ic && a->auto_connect && a->prpl != &protocol_missing) {
    489495                                        if (strcmp(a->pass, PASSWORD_PENDING) == 0) {
    490496                                                irc_rootmsg(irc, "Enter password for account %s "
     
    543549                        irc_rootmsg(irc, "Enter password for account %s "
    544550                                    "first (use /OPER)", a->tag);
     551                } else if (a->prpl == &protocol_missing) {
     552                        irc_rootmsg(irc, "Protocol `%s' not recognised (plugin may be missing or not running?)",
     553                                    set_getstr(&a->set, "_protocol_name"));
    545554                } else {
    546555                        account_on(irc->b, a);
     
    647656                irc_rootmsg(irc, "That account is not on-line");
    648657                return;
     658        } else if (add_on_server && !a->prpl->add_buddy) {
     659                irc_rootmsg(irc, "IM protocol does not support contact list modification");
     660                return;
     661        }
     662
     663        if ((a->flags & ACC_FLAG_HANDLE_DOMAINS) && cmd[2][0] != '_' &&
     664            (!(s = strchr(cmd[2], '@')) || s[1] == '\0')) {
     665                /* If there's no @ or it's the last char, append the user's
     666                   domain name now. Exclude handles starting with a _ so
     667                   adding _xmlconsole will keep working. */
     668                if (s) {
     669                        *s = '\0';
     670                }
     671                if ((s = strchr(a->user, '@'))) {
     672                        cmd[2] = handle = g_strconcat(cmd[2], s, NULL);
     673                }
    649674        }
    650675
     
    661686        }
    662687
    663         if ((a->flags & ACC_FLAG_HANDLE_DOMAINS) && cmd[2][0] != '_' &&
    664             (!(s = strchr(cmd[2], '@')) || s[1] == '\0')) {
    665                 /* If there's no @ or it's the last char, append the user's
    666                    domain name now. Exclude handles starting with a _ so
    667                    adding _xmlconsole will keep working. */
    668                 if (s) {
    669                         *s = '\0';
    670                 }
    671                 if ((s = strchr(a->user, '@'))) {
    672                         cmd[2] = handle = g_strconcat(cmd[2], s, NULL);
    673                 }
    674         }
    675 
    676688        if (add_on_server) {
    677689                irc_channel_t *ic;
     
    717729        s = g_strdup(bu->handle);
    718730
    719         bu->ic->acc->prpl->remove_buddy(bu->ic, bu->handle, NULL);
     731        if (bu->ic->acc->prpl->remove_buddy) {
     732                bu->ic->acc->prpl->remove_buddy(bu->ic, bu->handle, NULL);
     733        } else {
     734                irc_rootmsg(irc, "IM protocol does not support contact list modification, "
     735                                 "removal will likely not be permanent");
     736        }
     737
    720738        nick_del(bu);
    721739        if (g_slist_find(irc->users, iu)) {
  • storage.c

    r24de9fa r69b94c3  
    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

    r24de9fa r69b94c3  
    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

    r24de9fa r69b94c3  
    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.