Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • protocols/twitter/twitter_lib.c

    r85c3004 rce402b2  
    5151
    5252struct twitter_xml_user {
     53        guint64 uid;
    5354        char *name;
    5455        char *screen_name;
     
    6162        guint64 id, rt_id; /* Usually equal, with RTs id == *original* id */
    6263        guint64 reply_to;
     64        gboolean from_filter;
     65        struct twitter_xml_status *rt;
    6366};
    6467
     
    8689        g_free(txs->text);
    8790        txu_free(txs->user);
     91        txs_free(txs->rt);
    8892        g_free(txs);
    8993}
     
    392396{
    393397        struct twitter_xml_user *txu;
     398        json_value *jv;
    394399       
    395400        txu = g_new0(struct twitter_xml_user, 1);
    396401        txu->name = g_strdup(json_o_str(node, "name"));
    397402        txu->screen_name = g_strdup(json_o_str(node, "screen_name"));
     403       
     404        jv = json_o_get(node, "id");
     405        txu->uid = jv->u.integer;
    398406       
    399407        return txu;
     
    483491                if (rtxs) {
    484492                        g_free(txs->text);
    485                         txs->text = g_strdup_printf("RT @%s: %s", rtxs->user->screen_name, rtxs->text);
     493                        txs->text = g_strdup(rtxs->text);
    486494                        txs->id = rtxs->id;
    487                         txs_free(rtxs);
     495                        txs->rt = rtxs;
    488496                }
    489497        } else if (entities) {
     
    603611}
    604612
     613/**
     614 * Function to properly format a tweet as per the users configuration.
     615 */
     616static char *twitter_msg_get_text(struct im_connection *ic, int log_id, int reply_to,
     617                                struct twitter_xml_status *txs, const char *prefix) {
     618        gchar * format = set_getstr(&ic->acc->set, "format_string");
     619        GString * text = g_string_new(NULL);
     620
     621        gchar *c;
     622        if (reply_to != -1)
     623                format = set_getstr(&ic->acc->set, "reply_format_string");
     624        if (txs->rt)
     625                format = set_getstr(&ic->acc->set, "retweet_format_string");
     626
     627        for (c = format; *c ; c++) {
     628                if (!(*c == '%' && *(c+1))) {
     629                        text = g_string_append_c(text, *c);
     630                        continue;
     631                }
     632                c++; // Move past the %
     633                switch (*c) {
     634                        case 'i':
     635                                g_string_append_printf(text, "%02x", log_id);
     636                                break;
     637                        case 'r':
     638                                if (reply_to != -1) // In case someone does put %r in the wrong format_string
     639                                g_string_append_printf(text, "%02x", reply_to);
     640                                break;
     641                        case 'a':
     642                                if (txs->rt) // In case someone does put %a in the wrong format_string
     643                                        text = g_string_append(text, txs->rt->user->screen_name);
     644                                break;
     645                        case 'c':
     646                                text = g_string_append(text, txs->text);
     647                                break;
     648                        default:
     649                                text = g_string_append_c(text, *c);
     650                }
     651        }
     652        text = g_string_prepend(text, prefix);
     653        return g_string_free(text, FALSE);
     654}
     655
    605656/* Will log messages either way. Need to keep track of IDs for stream deduping.
    606657   Plus, show_ids is on by default and I don't see why anyone would disable it. */
     
    641692                td->log[td->log_id].id = txs->rt_id;
    642693       
    643         if (set_getbool(&ic->acc->set, "show_ids")) {
    644                 if (reply_to != -1)
    645                         return g_strdup_printf("\002[\002%02x->%02x\002]\002 %s%s",
    646                                                td->log_id, reply_to, prefix, txs->text);
    647                 else
    648                         return g_strdup_printf("\002[\002%02x\002]\002 %s%s",
    649                                                td->log_id, prefix, txs->text);
    650         } else {
    651                 if (*prefix)
    652                         return g_strconcat(prefix, txs->text, NULL);
    653                 else
    654                         return NULL;
    655         }
     694        return twitter_msg_get_text(ic, td->log_id, reply_to, txs, prefix);
     695}
     696
     697/**
     698 * Function that is called to see the filter statuses in groupchat windows.
     699 */
     700static void twitter_status_show_filter(struct im_connection *ic, struct twitter_xml_status *status)
     701{
     702        struct twitter_data *td = ic->proto_data;
     703        char *msg = twitter_msg_add_id(ic, status, "");
     704        struct twitter_filter *tf;
     705        GSList *f;
     706        GSList *l;
     707
     708        for (f = td->filters; f; f = g_slist_next(f)) {
     709                tf = f->data;
     710
     711                switch (tf->type) {
     712                case TWITTER_FILTER_TYPE_FOLLOW:
     713                        if (status->user->uid != tf->uid)
     714                                continue;
     715                        break;
     716
     717                case TWITTER_FILTER_TYPE_TRACK:
     718                        if (strcasestr(status->text, tf->text) == NULL)
     719                                continue;
     720                        break;
     721
     722                default:
     723                        continue;
     724                }
     725
     726                for (l = tf->groupchats; l; l = g_slist_next(l)) {
     727                        imcb_chat_msg(l->data, status->user->screen_name,
     728                                      msg ? msg : status->text, 0, 0);
     729                }
     730        }
     731
     732        g_free(msg);
    656733}
    657734
     
    731808                strip_newlines(status->text);
    732809       
    733         if (td->flags & TWITTER_MODE_CHAT)
     810        if (status->from_filter)
     811                twitter_status_show_filter(ic, status);
     812        else if (td->flags & TWITTER_MODE_CHAT)
    734813                twitter_status_show_chat(ic, status);
    735814        else
     
    745824}
    746825
    747 static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o);
     826static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o, gboolean from_filter);
    748827
    749828static void twitter_http_stream(struct http_request *req)
     
    754833        int len = 0;
    755834        char c, *nl;
     835        gboolean from_filter;
    756836       
    757837        if (!g_slist_find(twitter_connections, ic))
     
    762842       
    763843        if ((req->flags & HTTPC_EOF) || !req->reply_body) {
    764                 td->stream = NULL;
     844                if (req == td->stream)
     845                        td->stream = NULL;
     846                else if (req == td->filter_stream)
     847                        td->filter_stream = NULL;
     848
    765849                imcb_error(ic, "Stream closed (%s)", req->status_string);
    766850                imc_logout(ic, TRUE);
     
    779863               
    780864                if ((parsed = json_parse(req->reply_body, req->body_size))) {
    781                         twitter_stream_handle_object(ic, parsed);
     865                        from_filter = (req == td->filter_stream);
     866                        twitter_stream_handle_object(ic, parsed, from_filter);
    782867                }
    783868                json_value_free(parsed);
     
    795880static gboolean twitter_stream_handle_status(struct im_connection *ic, struct twitter_xml_status *txs);
    796881
    797 static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o)
     882static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o, gboolean from_filter)
    798883{
    799884        struct twitter_data *td = ic->proto_data;
     
    802887       
    803888        if ((txs = twitter_xt_get_status(o))) {
     889                txs->from_filter = from_filter;
    804890                gboolean ret = twitter_stream_handle_status(ic, txs);
    805891                txs_free(txs);
     
    899985}
    900986
     987static gboolean twitter_filter_stream(struct im_connection *ic)
     988{
     989        struct twitter_data *td = ic->proto_data;
     990        char *args[4] = {"follow", NULL, "track", NULL};
     991        GString *followstr = g_string_new("");
     992        GString *trackstr = g_string_new("");
     993        gboolean ret = FALSE;
     994        struct twitter_filter *tf;
     995        GSList *l;
     996
     997        for (l = td->filters; l; l = g_slist_next(l)) {
     998                tf = l->data;
     999
     1000                switch (tf->type) {
     1001                case TWITTER_FILTER_TYPE_FOLLOW:
     1002                        if (followstr->len > 0)
     1003                                g_string_append_c(followstr, ',');
     1004
     1005                        g_string_append_printf(followstr, "%" G_GUINT64_FORMAT,
     1006                                               tf->uid);
     1007                        break;
     1008
     1009                case TWITTER_FILTER_TYPE_TRACK:
     1010                        if (trackstr->len > 0)
     1011                                g_string_append_c(trackstr, ',');
     1012
     1013                        g_string_append(trackstr, tf->text);
     1014                        break;
     1015
     1016                default:
     1017                        continue;
     1018                }
     1019        }
     1020
     1021        args[1] = followstr->str;
     1022        args[3] = trackstr->str;
     1023
     1024        if (td->filter_stream)
     1025                http_close(td->filter_stream);
     1026
     1027        if ((td->filter_stream = twitter_http(ic, TWITTER_FILTER_STREAM_URL,
     1028                                              twitter_http_stream, ic, 0,
     1029                                              args, 4))) {
     1030                /* This flag must be enabled or we'll get no data until EOF
     1031                   (which err, kind of, defeats the purpose of a streaming API). */
     1032                td->filter_stream->flags |= HTTPC_STREAMING;
     1033                ret = TRUE;
     1034        }
     1035
     1036        g_string_free(followstr, TRUE);
     1037        g_string_free(trackstr, TRUE);
     1038
     1039        return ret;
     1040}
     1041
     1042static void twitter_filter_users_post(struct http_request *req)
     1043{
     1044        struct im_connection *ic = req->data;
     1045        struct twitter_data *td;
     1046        struct twitter_filter *tf;
     1047        GList *users = NULL;
     1048        json_value *parsed;
     1049        json_value *id;
     1050        const char *name;
     1051        GString *fstr;
     1052        GSList *l;
     1053        GList *u;
     1054        int i;
     1055
     1056        // Check if the connection is still active.
     1057        if (!g_slist_find(twitter_connections, ic))
     1058                return;
     1059
     1060        td = ic->proto_data;
     1061
     1062        if (!(parsed = twitter_parse_response(ic, req)))
     1063                return;
     1064
     1065        for (l = td->filters; l; l = g_slist_next(l)) {
     1066                tf = l->data;
     1067
     1068                if (tf->type == TWITTER_FILTER_TYPE_FOLLOW)
     1069                        users = g_list_prepend(users, tf);
     1070        }
     1071
     1072        if (parsed->type != json_array)
     1073                goto finish;
     1074
     1075        for (i = 0; i < parsed->u.array.length; i++) {
     1076                id = json_o_get(parsed->u.array.values[i], "id");
     1077                name = json_o_str(parsed->u.array.values[i], "screen_name");
     1078
     1079                if (!name || !id || id->type != json_integer)
     1080                        continue;
     1081
     1082                for (u = users; u; u = g_list_next(u)) {
     1083                        tf = u->data;
     1084
     1085                        if (g_strcasecmp(tf->text, name) == 0) {
     1086                                tf->uid = id->u.integer;
     1087                                users = g_list_delete_link(users, u);
     1088                                break;
     1089                        }
     1090                }
     1091        }
     1092
     1093finish:
     1094        json_value_free(parsed);
     1095        twitter_filter_stream(ic);
     1096
     1097        if (!users)
     1098                return;
     1099
     1100        fstr = g_string_new("");
     1101
     1102        for (u = users; u; u = g_list_next(u)) {
     1103                if (fstr->len > 0)
     1104                        g_string_append(fstr, ", ");
     1105
     1106                g_string_append(fstr, tf->text);
     1107        }
     1108
     1109        imcb_error(ic, "Failed UID acquisitions: %s", fstr->str);
     1110
     1111        g_string_free(fstr, TRUE);
     1112        g_list_free(users);
     1113}
     1114
     1115gboolean twitter_open_filter_stream(struct im_connection *ic)
     1116{
     1117        struct twitter_data *td = ic->proto_data;
     1118        char *args[2] = {"screen_name", NULL};
     1119        GString *ustr = g_string_new("");
     1120        struct twitter_filter *tf;
     1121        struct http_request *req;
     1122        GSList *l;
     1123
     1124        for (l = td->filters; l; l = g_slist_next(l)) {
     1125                tf = l->data;
     1126
     1127                if (tf->type != TWITTER_FILTER_TYPE_FOLLOW || tf->uid != 0)
     1128                        continue;
     1129
     1130                if (ustr->len > 0)
     1131                        g_string_append_c(ustr, ',');
     1132
     1133                g_string_append(ustr, tf->text);
     1134        }
     1135
     1136        if (ustr->len == 0) {
     1137                g_string_free(ustr, TRUE);
     1138                return twitter_filter_stream(ic);
     1139        }
     1140
     1141        args[1] = ustr->str;
     1142        req = twitter_http(ic, TWITTER_USERS_LOOKUP_URL,
     1143                           twitter_filter_users_post,
     1144                           ic, 0, args, 2);
     1145
     1146        g_string_free(ustr, TRUE);
     1147        return req != NULL;
     1148}
     1149
    9011150static void twitter_get_home_timeline(struct im_connection *ic, gint64 next_cursor);
    9021151static void twitter_get_mentions(struct im_connection *ic, gint64 next_cursor);
Note: See TracChangeset for help on using the changeset viewer.