Changeset f81d8b8


Ignore:
Timestamp:
2015-05-06T09:18:10Z (10 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Children:
1a81c83
Parents:
8563fe7
Message:

Twitter module updated to use parson. It compiles and runs so far but will
need some mileage.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • protocols/twitter/twitter_lib.c

    r8563fe7 rf81d8b8  
    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
Note: See TracChangeset for help on using the changeset viewer.