Changes in protocols/twitter/twitter_lib.c [85c3004:ce402b2]
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/twitter/twitter_lib.c
r85c3004 rce402b2 51 51 52 52 struct twitter_xml_user { 53 guint64 uid; 53 54 char *name; 54 55 char *screen_name; … … 61 62 guint64 id, rt_id; /* Usually equal, with RTs id == *original* id */ 62 63 guint64 reply_to; 64 gboolean from_filter; 65 struct twitter_xml_status *rt; 63 66 }; 64 67 … … 86 89 g_free(txs->text); 87 90 txu_free(txs->user); 91 txs_free(txs->rt); 88 92 g_free(txs); 89 93 } … … 392 396 { 393 397 struct twitter_xml_user *txu; 398 json_value *jv; 394 399 395 400 txu = g_new0(struct twitter_xml_user, 1); 396 401 txu->name = g_strdup(json_o_str(node, "name")); 397 402 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; 398 406 399 407 return txu; … … 483 491 if (rtxs) { 484 492 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); 486 494 txs->id = rtxs->id; 487 txs _free(rtxs);495 txs->rt = rtxs; 488 496 } 489 497 } else if (entities) { … … 603 611 } 604 612 613 /** 614 * Function to properly format a tweet as per the users configuration. 615 */ 616 static 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 605 656 /* Will log messages either way. Need to keep track of IDs for stream deduping. 606 657 Plus, show_ids is on by default and I don't see why anyone would disable it. */ … … 641 692 td->log[td->log_id].id = txs->rt_id; 642 693 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 */ 700 static 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); 656 733 } 657 734 … … 731 808 strip_newlines(status->text); 732 809 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) 734 813 twitter_status_show_chat(ic, status); 735 814 else … … 745 824 } 746 825 747 static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o );826 static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o, gboolean from_filter); 748 827 749 828 static void twitter_http_stream(struct http_request *req) … … 754 833 int len = 0; 755 834 char c, *nl; 835 gboolean from_filter; 756 836 757 837 if (!g_slist_find(twitter_connections, ic)) … … 762 842 763 843 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 765 849 imcb_error(ic, "Stream closed (%s)", req->status_string); 766 850 imc_logout(ic, TRUE); … … 779 863 780 864 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); 782 867 } 783 868 json_value_free(parsed); … … 795 880 static gboolean twitter_stream_handle_status(struct im_connection *ic, struct twitter_xml_status *txs); 796 881 797 static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o )882 static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o, gboolean from_filter) 798 883 { 799 884 struct twitter_data *td = ic->proto_data; … … 802 887 803 888 if ((txs = twitter_xt_get_status(o))) { 889 txs->from_filter = from_filter; 804 890 gboolean ret = twitter_stream_handle_status(ic, txs); 805 891 txs_free(txs); … … 899 985 } 900 986 987 static 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 1042 static 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 1093 finish: 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 1115 gboolean 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 901 1150 static void twitter_get_home_timeline(struct im_connection *ic, gint64 next_cursor); 902 1151 static void twitter_get_mentions(struct im_connection *ic, gint64 next_cursor);
Note: See TracChangeset
for help on using the changeset viewer.