Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • protocols/twitter/twitter_lib.c

    red83279 rbbff22d  
    3636#include "base64.h"
    3737#include "twitter_lib.h"
    38 #include "parson.h"
     38#include "json_util.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++)
    7066
    7167/**
     
    170166{
    171167        static char *ret = NULL;
    172         JSON_Value *root, *err;
     168        json_value *root, *err;
    173169
    174170        g_free(ret);
     
    176172
    177173        if (req->body_size > 0) {
    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");
     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");
    184179                        if (msg) {
    185180                                ret = g_strdup_printf("%s (%s)", req->status_string, msg);
     
    194189/* WATCH OUT: This function might or might not destroy your connection.
    195190   Sub-optimal indeed, but just be careful when this returns NULL! */
    196 static JSON_Value *twitter_parse_response(struct im_connection *ic, struct http_request *req)
     191static json_value *twitter_parse_response(struct im_connection *ic, struct http_request *req)
    197192{
    198193        gboolean logging_in = !(ic->flags & OPT_LOGGED_IN);
    199194        gboolean periodic;
    200195        struct twitter_data *td = ic->proto_data;
    201         JSON_Value *ret;
     196        json_value *ret;
    202197        char path[64] = "", *s;
    203198
     
    237232        }
    238233
    239         if ((ret = json_parse_string(req->reply_body)) == NULL) {
     234        if ((ret = json_parse(req->reply_body, req->body_size)) == NULL) {
    240235                imcb_error(ic, "Could not retrieve %s: %s",
    241236                           path, "XML parse error");
     
    264259 * Fill a list of ids.
    265260 */
    266 static gboolean twitter_xt_get_friends_id_list(JSON_Value *node, struct twitter_xml_list *txl)
    267 {
    268         JSON_Array *c;
     261static gboolean twitter_xt_get_friends_id_list(json_value *node, struct twitter_xml_list *txl)
     262{
     263        json_value *c;
    269264        int i;
    270265
     
    272267        txl->type = TXL_ID;
    273268
    274         if (!(c = json_object_get_array(json_object(node), "ids"))) {
     269        c = json_o_get(node, "ids");
     270        if (!c || c->type != json_array) {
    275271                return FALSE;
    276272        }
    277273
    278         for (i = 0; i < json_array_get_count(c); i++) {
    279                 jint id = json_array_get_integer(c, i);
     274        for (i = 0; i < c->u.array.length; i++) {
     275                if (c->u.array.values[i]->type != json_integer) {
     276                        continue;
     277                }
    280278
    281279                txl->list = g_slist_prepend(txl->list,
    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);
     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;
    288286        } else {
    289287                txl->next_cursor = -1;
     
    301299{
    302300        struct im_connection *ic;
    303         JSON_Value *parsed;
     301        json_value *parsed;
    304302        struct twitter_xml_list *txl;
    305303        struct twitter_data *td;
     
    314312        td = ic->proto_data;
    315313
     314        // Parse the data.
     315        if (!(parsed = twitter_parse_response(ic, req))) {
     316                return;
     317        }
     318
    316319        txl = g_new0(struct twitter_xml_list, 1);
    317320        txl->list = td->follow_ids;
    318 
    319         // Parse the data.
    320         if (!(parsed = twitter_parse_response(ic, req))) {
    321                 return;
    322         }
    323321
    324322        twitter_xt_get_friends_id_list(parsed, txl);
     
    339337}
    340338
    341 static gboolean twitter_xt_get_users(JSON_Value *node, struct twitter_xml_list *txl);
     339static gboolean twitter_xt_get_users(json_value *node, struct twitter_xml_list *txl);
    342340static void twitter_http_get_users_lookup(struct http_request *req);
    343341
     
    380378{
    381379        struct im_connection *ic = req->data;
    382         JSON_Value *parsed;
     380        json_value *parsed;
    383381        struct twitter_xml_list *txl;
    384382        GSList *l = NULL;
     
    390388        }
    391389
     390        // Get the user list from the parsed xml feed.
     391        if (!(parsed = twitter_parse_response(ic, req))) {
     392                return;
     393        }
     394
    392395        txl = g_new0(struct twitter_xml_list, 1);
    393396        txl->list = NULL;
    394397
    395         // Get the user list from the parsed xml feed.
    396         if (!(parsed = twitter_parse_response(ic, req))) {
    397                 return;
    398         }
    399398        twitter_xt_get_users(parsed, txl);
    400399        json_value_free(parsed);
     
    412411}
    413412
    414 struct twitter_xml_user *twitter_xt_get_user(const JSON_Object *node)
     413struct twitter_xml_user *twitter_xt_get_user(const json_value *node)
    415414{
    416415        struct twitter_xml_user *txu;
    417        
    418         if (!node)
    419                 return NULL;
     416        json_value *jv;
    420417
    421418        txu = g_new0(struct twitter_xml_user, 1);
    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");
     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;
    425424
    426425        return txu;
     
    432431 *  - all <user>s from the <users> element.
    433432 */
    434 static gboolean twitter_xt_get_users(JSON_Value *node, struct twitter_xml_list *txl)
     433static gboolean twitter_xt_get_users(json_value *node, struct twitter_xml_list *txl)
    435434{
    436435        struct twitter_xml_user *txu;
     
    440439        txl->type = TXL_USER;
    441440
    442         if (json_type(node) != JSONArray) {
     441        if (!node || node->type != json_array) {
    443442                return FALSE;
    444443        }
    445        
     444
    446445        // The root <users> node should hold the list of users <user>
    447446        // Walk over the nodes children.
    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);
     447        for (i = 0; i < node->u.array.length; i++) {
     448                txu = twitter_xt_get_user(node->u.array.values[i]);
    454449                if (txu) {
    455450                        txl->list = g_slist_prepend(txl->list, txu);
     
    466461#endif
    467462
    468 static void expand_entities(char **text, const JSON_Object *node);
     463static void expand_entities(char **text, const json_value *node);
    469464
    470465/**
     
    476471 *  - the user in a twitter_xml_user struct.
    477472 */
    478 static struct twitter_xml_status *twitter_xt_get_status(const JSON_Object *node)
     473static struct twitter_xml_status *twitter_xt_get_status(const json_value *node)
    479474{
    480475        struct twitter_xml_status *txs;
    481         const JSON_Object *rt = NULL;
    482 
    483         if (!node) {
     476        const json_value *rt = NULL;
     477
     478        if (node->type != json_object) {
    484479                return FALSE;
    485480        }
     
    487482
    488483        JSON_O_FOREACH(node, k, v) {
    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..
     484                if (strcmp("text", k) == 0 && v->type == json_string) {
     485                        txs->text = g_memdup(v->u.string.ptr, v->u.string.length + 1);
    491486                        strip_html(txs->text);
    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) {
     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) {
    495490                        struct tm parsed;
    496491
     
    498493                           this field. :-( Also assumes the timezone used
    499494                           is UTC since C time handling functions suck. */
    500                         if (strptime(json_string(v), TWITTER_TIME_FORMAT, &parsed) != NULL) {
     495                        if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL) {
    501496                                txs->created_at = mktime_utc(&parsed);
    502497                        }
    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);
     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;
    509504                }
    510505        }
     
    535530 * Function to fill a twitter_xml_status struct (DM variant).
    536531 */
    537 static struct twitter_xml_status *twitter_xt_get_dm(const JSON_Object *node)
     532static struct twitter_xml_status *twitter_xt_get_dm(const json_value *node)
    538533{
    539534        struct twitter_xml_status *txs;
    540535
    541         if (!node) {
     536        if (node->type != json_object) {
    542537                return FALSE;
    543538        }
     
    545540
    546541        JSON_O_FOREACH(node, k, v) {
    547                 if (strcmp("text", k) == 0 && (txs->text = g_strdup(json_string(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);
    548544                        strip_html(txs->text);
    549                 } else if (strcmp("created_at", k) == 0 && json_type(v) == JSONString) {
     545                } else if (strcmp("created_at", k) == 0 && v->type == json_string) {
    550546                        struct tm parsed;
    551547
     
    553549                           this field. :-( Also assumes the timezone used
    554550                           is UTC since C time handling functions suck. */
    555                         if (strptime(json_string(v), TWITTER_TIME_FORMAT, &parsed) != NULL) {
     551                        if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL) {
    556552                                txs->created_at = mktime_utc(&parsed);
    557553                        }
    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);
     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;
    562558                }
    563559        }
     
    573569}
    574570
    575 static void expand_entities(char **text, const JSON_Object *node)
    576 {
    577         JSON_Object *entities, *quoted;
     571static void expand_entities(char **text, const json_value *node)
     572{
     573        json_value *entities, *quoted;
    578574        char *quote_url = NULL, *quote_text = NULL;
    579575
    580         if (!(entities = json_object_get_object(node, "entities")))
    581                 return;
    582         if ((quoted = json_object_get_object(node, "quoted_status"))) {
     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) {
    583579                /* New "retweets with comments" feature. Note that this info
    584580                 * seems to be included in the streaming API only! Grab the
     
    596592                int i;
    597593
    598                 if (json_type(v) != JSONArray) {
     594                if (v->type != json_array) {
    599595                        continue;
    600596                }
     
    603599                }
    604600
    605                 for (i = 0; i < json_array_get_count(json_array(v)); i++) {
     601                for (i = 0; i < v->u.array.length; i++) {
    606602                        const char *format = "%s%s <%s>%s";
    607                         JSON_Object *r = json_array_get_object(json_array(v), i);
    608 
    609                         if (!r) {
     603
     604                        if (v->u.array.values[i]->type != json_object) {
    610605                                continue;
    611606                        }
    612607
    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");
     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");
    616611                        char *pos, *new;
    617612
     
    642637 *  - the next_cursor.
    643638 */
    644 static gboolean twitter_xt_get_status_list(struct im_connection *ic, const JSON_Value *node,
     639static gboolean twitter_xt_get_status_list(struct im_connection *ic, const json_value *node,
    645640                                           struct twitter_xml_list *txl)
    646641{
     
    651646        txl->type = TXL_STATUS;
    652647
    653         if (json_type(node) != JSONArray) {
     648        if (node->type != json_array) {
    654649                return FALSE;
    655650        }
     
    657652        // The root <statuses> node should hold the list of statuses <status>
    658653        // Walk over the nodes children.
    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));
     654        for (i = 0; i < node->u.array.length; i++) {
     655                txs = twitter_xt_get_status(node->u.array.values[i]);
    661656                if (!txs) {
    662657                        continue;
     
    864859}
    865860
    866 static gboolean twitter_stream_handle_object(struct im_connection *ic, JSON_Object *o, gboolean from_filter);
     861static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o, gboolean from_filter);
    867862
    868863static void twitter_http_stream(struct http_request *req)
     
    870865        struct im_connection *ic = req->data;
    871866        struct twitter_data *td;
    872         JSON_Value *parsed;
     867        json_value *parsed;
    873868        int len = 0;
    874869        char c, *nl;
     
    908903                req->reply_body[len] = '\0';
    909904
    910                 if ((parsed = json_parse_string(req->reply_body))) {
     905                if ((parsed = json_parse(req->reply_body, req->body_size))) {
    911906                        from_filter = (req == td->filter_stream);
    912                         twitter_stream_handle_object(ic, json_object(parsed), from_filter);
     907                        twitter_stream_handle_object(ic, parsed, from_filter);
    913908                }
    914909                json_value_free(parsed);
     
    924919}
    925920
    926 static gboolean twitter_stream_handle_event(struct im_connection *ic, JSON_Object *o);
     921static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value *o);
    927922static gboolean twitter_stream_handle_status(struct im_connection *ic, struct twitter_xml_status *txs);
    928923
    929 static gboolean twitter_stream_handle_object(struct im_connection *ic, JSON_Object *o, gboolean from_filter)
     924static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o, gboolean from_filter)
    930925{
    931926        struct twitter_data *td = ic->proto_data;
    932927        struct twitter_xml_status *txs;
    933         JSON_Object *c;
     928        json_value *c;
    934929
    935930        if ((txs = twitter_xt_get_status(o))) {
     
    938933                txs_free(txs);
    939934                return ret;
    940         } else if ((c = json_object_get_object(o, "direct_message")) &&
     935        } else if ((c = json_o_get(o, "direct_message")) &&
    941936                   (txs = twitter_xt_get_dm(c))) {
    942937                if (g_strcasecmp(txs->user->screen_name, td->user) != 0) {
     
    946941                txs_free(txs);
    947942                return TRUE;
    948         } else if (json_object_get_string(o, "event")) {
     943        } else if ((c = json_o_get(o, "event")) && c->type == json_string) {
    949944                twitter_stream_handle_event(ic, o);
    950945                return TRUE;
    951         } else if ((c = json_object_get_object(o, "disconnect"))) {
     946        } else if ((c = json_o_get(o, "disconnect")) && c->type == json_object) {
    952947                /* HACK: Because we're inside an event handler, we can't just
    953948                   disconnect here. Instead, just change the HTTP status string
    954949                   into a Twitter status string. */
    955                 char *reason = g_strdup(json_object_get_string(c, "reason"));
     950                char *reason = json_o_strdup(c, "reason");
    956951                if (reason) {
    957952                        g_free(td->stream->status_string);
     
    992987}
    993988
    994 static 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) {
     989static 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) {
    1002998                return FALSE;
    1003999        }
     
    10961092        struct twitter_filter *tf;
    10971093        GList *users = NULL;
    1098         JSON_Value *parsed;
     1094        json_value *parsed;
     1095        json_value *id;
     1096        const char *name;
    10991097        GString *fstr;
    11001098        GSList *l;
     
    11211119        }
    11221120
    1123         if (json_type(parsed) != JSONArray) {
     1121        if (parsed->type != json_array) {
    11241122                goto finish;
    11251123        }
    11261124
    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) {
     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) {
    11331130                        continue;
    11341131                }
     
    11381135
    11391136                        if (g_strcasecmp(tf->text, name) == 0) {
    1140                                 tf->uid = id;
     1137                                tf->uid = id->u.integer;
    11411138                                users = g_list_delete_link(users, u);
    11421139                                break;
     
    13791376        struct im_connection *ic = req->data;
    13801377        struct twitter_data *td;
    1381         JSON_Value *parsed;
     1378        json_value *parsed;
    13821379        struct twitter_xml_list *txl;
    13831380
     
    13881385
    13891386        td = ic->proto_data;
    1390 
    1391         txl = g_new0(struct twitter_xml_list, 1);
    1392         txl->list = NULL;
    13931387
    13941388        // The root <statuses> node should hold the list of statuses <status>
     
    13961390                goto end;
    13971391        }
     1392
     1393        txl = g_new0(struct twitter_xml_list, 1);
     1394        txl->list = NULL;
     1395
    13981396        twitter_xt_get_status_list(ic, parsed, txl);
    13991397        json_value_free(parsed);
     
    14181416        struct im_connection *ic = req->data;
    14191417        struct twitter_data *td;
    1420         JSON_Value *parsed;
     1418        json_value *parsed;
    14211419        struct twitter_xml_list *txl;
    14221420
     
    14271425
    14281426        td = ic->proto_data;
    1429 
    1430         txl = g_new0(struct twitter_xml_list, 1);
    1431         txl->list = NULL;
    14321427
    14331428        // The root <statuses> node should hold the list of statuses <status>
     
    14351430                goto end;
    14361431        }
     1432
     1433        txl = g_new0(struct twitter_xml_list, 1);
     1434        txl->list = NULL;
     1435
    14371436        twitter_xt_get_status_list(ic, parsed, txl);
    14381437        json_value_free(parsed);
     
    14581457        struct im_connection *ic = req->data;
    14591458        struct twitter_data *td;
    1460         JSON_Value *parsed;
    1461         jint id;
     1459        json_value *parsed, *id;
    14621460
    14631461        // Check if the connection is still active.
     
    14731471        }
    14741472
    1475         if ((id = json_object_get_integer(json_object(parsed), "id"))) {
    1476                 td->last_status_id = id;
     1473        if ((id = json_o_get(parsed, "id")) && id->type == json_integer) {
     1474                td->last_status_id = id->u.integer;
    14771475        }
    14781476
     
    15821580{
    15831581        struct im_connection *ic = req->data;
    1584         JSON_Value *parsed;
    1585         uint64_t id;
     1582        json_value *parsed, *id;
    15861583        const char *name;
    15871584
     
    15951592        }
    15961593
     1594        /* for the parson branch:
    15971595        name = json_object_dotget_string(json_object(parsed), "user.screen_name");
    15981596        id = json_object_get_integer(json_object(parsed), "id");
    1599 
    1600         if (name && id) {
    1601                 twitter_log(ic, "https://twitter.com/%s/status/%" G_GUINT64_FORMAT, name, 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);
    16021604        } else {
    16031605                twitter_log(ic, "Error: could not fetch tweet url.");
Note: See TracChangeset for help on using the changeset viewer.