Changeset 5ebff60 for protocols/twitter
- Timestamp:
- 2015-02-20T22:50:54Z (10 years ago)
- Branches:
- master
- Children:
- 0b9daac, 3d45471, 7733b8c
- Parents:
- af359b4
- git-author:
- Indent <please@…> (19-02-15 05:47:20)
- git-committer:
- dequis <dx@…> (20-02-15 22:50:54)
- Location:
- protocols/twitter
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/twitter/twitter.c
raf359b4 r5ebff60 91 91 struct twitter_data *td = c->ic->proto_data; 92 92 struct twitter_filter *tf = NULL; 93 struct twitter_filter tfc = { type, (char*) text};93 struct twitter_filter tfc = { type, (char *) text }; 94 94 GSList *l; 95 95 … … 97 97 tf = l->data; 98 98 99 if (twitter_filter_cmp(tf, &tfc) == 0) 99 if (twitter_filter_cmp(tf, &tfc) == 0) { 100 100 break; 101 } 101 102 102 103 tf = NULL; … … 110 111 } 111 112 112 if (!g_slist_find(tf->groupchats, c)) 113 if (!g_slist_find(tf->groupchats, c)) { 113 114 tf->groupchats = g_slist_prepend(tf->groupchats, c); 114 115 if (td->filter_update_id > 0) 115 } 116 117 if (td->filter_update_id > 0) { 116 118 b_event_remove(td->filter_update_id); 119 } 117 120 118 121 /* Wait for other possible filter changes to avoid request spam */ 119 122 td->filter_update_id = b_timeout_add(TWITTER_FILTER_UPDATE_WAIT, 120 123 twitter_filter_update, c->ic); 121 124 return tf; 122 125 } … … 149 152 } 150 153 151 if (td->filter_update_id > 0) 154 if (td->filter_update_id > 0) { 152 155 b_event_remove(td->filter_update_id); 156 } 153 157 154 158 /* Wait for other possible filter changes to avoid request spam */ 155 159 td->filter_update_id = b_timeout_add(TWITTER_FILTER_UPDATE_WAIT, 156 twitter_filter_update, c->ic);} 160 twitter_filter_update, c->ic); 161 } 157 162 158 163 static void twitter_filter_remove_all(struct im_connection *ic) … … 169 174 /* Build up a list of groupchats to be freed */ 170 175 for (p = tf->groupchats; p; p = g_slist_next(p)) { 171 if (!g_slist_find(chats, p->data)) 176 if (!g_slist_find(chats, p->data)) { 172 177 chats = g_slist_prepend(chats, p->data); 178 } 173 179 } 174 180 … … 217 223 218 224 for (f = fs; *f; f++) { 219 if ((v = strchr(*f, ':')) == NULL) 225 if ((v = strchr(*f, ':')) == NULL) { 220 226 continue; 227 } 221 228 222 229 *(v++) = 0; … … 229 236 } 230 237 231 if (t < 0 || strlen(v) == 0) 238 if (t < 0 || strlen(v) == 0) { 232 239 continue; 240 } 233 241 234 242 tf = twitter_filter_get(c, types[t], v); … … 248 256 249 257 // Check if we are still logged in... 250 if (!g_slist_find(twitter_connections, ic)) 258 if (!g_slist_find(twitter_connections, ic)) { 251 259 return FALSE; 260 } 252 261 253 262 // Do stuff.. … … 261 270 262 271 char *last_tweet = set_getstr(&ic->acc->set, "_last_tweet"); 263 if (last_tweet) 272 273 if (last_tweet) { 264 274 td->timeline_id = g_ascii_strtoull(last_tweet, NULL, 0); 275 } 265 276 266 277 /* Create the room now that we "logged in". */ 267 if (td->flags & TWITTER_MODE_CHAT) 278 if (td->flags & TWITTER_MODE_CHAT) { 268 279 twitter_groupchat_init(ic); 280 } 269 281 270 282 imcb_log(ic, "Getting initial statuses"); … … 273 285 // stream if available). 274 286 twitter_main_loop(ic, -1, 0); 275 287 276 288 if (set_getbool(&ic->acc->set, "stream")) { 277 289 /* That fetch was just to get backlog, the stream will give 278 290 us the rest. \o/ */ 279 291 twitter_open_stream(ic); 280 292 281 293 /* Stream sends keepalives (empty lines) or actual data at 282 294 least twice a minute. Disconnect if this stops. */ … … 286 298 fashioned way. :-( */ 287 299 td->main_loop_id = 288 b_timeout_add(set_getint(&ic->acc->set, "fetch_interval") * 1000,289 twitter_main_loop, ic);300 b_timeout_add(set_getint(&ic->acc->set, "fetch_interval") * 1000, 301 twitter_main_loop, ic); 290 302 } 291 303 } … … 298 310 GSList *l; 299 311 300 if (td->timeline_gc) 312 if (td->timeline_gc) { 301 313 return td->timeline_gc; 314 } 302 315 303 316 td->timeline_gc = gc = imcb_chat_new(ic, "twitter/timeline"); … … 309 322 for (l = ic->bee->users; l; l = l->next) { 310 323 bee_user_t *bu = l->data; 311 if (bu->ic == ic) 324 if (bu->ic == ic) { 312 325 imcb_chat_add_buddy(gc, bu->handle); 326 } 313 327 } 314 328 imcb_chat_add_buddy(gc, ic->acc->user); 315 329 316 330 return gc; 317 331 } … … 325 339 td->flags &= ~TWITTER_DOING_TIMELINE; 326 340 327 if (set_getbool(&ic->acc->set, "oauth") && !td->oauth_info) 341 if (set_getbool(&ic->acc->set, "oauth") && !td->oauth_info) { 328 342 twitter_oauth_start(ic); 329 else if (!(td->flags & TWITTER_MODE_ONE) &&330 !(td->flags & TWITTER_HAVE_FRIENDS)) {343 } else if (!(td->flags & TWITTER_MODE_ONE) && 344 !(td->flags & TWITTER_HAVE_FRIENDS)) { 331 345 imcb_log(ic, "Getting contact list"); 332 346 twitter_get_friends_ids(ic, -1); 333 } else 347 } else { 334 348 twitter_main_loop_start(ic); 349 } 335 350 } 336 351 … … 357 372 struct twitter_data *td = ic->proto_data; 358 373 359 if (strstr(td->url_host, "identi.ca")) 374 if (strstr(td->url_host, "identi.ca")) { 360 375 return &identica_oauth; 361 else376 } else { 362 377 return &twitter_oauth; 378 } 363 379 364 380 /* Could add more services, or allow configuring your own base URL + … … 372 388 373 389 imcb_log(ic, "Requesting OAuth request token"); 374 375 if (!strstr(url, "twitter.com") && !strstr(url, "identi.ca")) 390 391 if (!strstr(url, "twitter.com") && !strstr(url, "identi.ca")) { 376 392 imcb_log(ic, "Warning: OAuth only works with identi.ca and " 377 "Twitter."); 393 "Twitter."); 394 } 378 395 379 396 td->oauth_info = oauth_request_token(get_oauth_service(ic), twitter_oauth_callback, ic); … … 389 406 struct twitter_data *td; 390 407 391 if (!g_slist_find(twitter_connections, ic)) 408 if (!g_slist_find(twitter_connections, ic)) { 392 409 return FALSE; 410 } 393 411 394 412 td = ic->proto_data; … … 404 422 name = g_strdup_printf("%s_%s", td->prefix, ic->acc->user); 405 423 msg = g_strdup_printf("To finish OAuth authentication, please visit " 406 407 424 "%s and respond with the resulting PIN code.", 425 info->auth_url); 408 426 imcb_buddy_msg(ic, name, msg, 0, 0); 409 427 g_free(name); … … 411 429 } else if (info->stage == OAUTH_ACCESS_TOKEN) { 412 430 const char *sn; 413 431 414 432 if (info->token == NULL || info->token_secret == NULL) { 415 433 imcb_error(ic, "OAuth error: %s", twitter_parse_error(info->http)); … … 417 435 return FALSE; 418 436 } 419 437 420 438 if ((sn = oauth_params_get(&info->params, "screen_name"))) { 421 if (ic->acc->prpl->handle_cmp(sn, ic->acc->user) != 0) 439 if (ic->acc->prpl->handle_cmp(sn, ic->acc->user) != 0) { 422 440 imcb_log(ic, "Warning: You logged in via OAuth as %s " 423 441 "instead of %s.", sn, ic->acc->user); 442 } 424 443 g_free(td->user); 425 444 td->user = g_strdup(sn); … … 444 463 GMatchInfo *match_info; 445 464 446 if (regex == NULL) 465 if (regex == NULL) { 447 466 regex = g_regex_new("(^|\\s)(http(s)?://[^\\s$]+)", 0, 0, NULL); 448 467 } 468 449 469 g_regex_match(regex, msg, 0, &match_info); 450 470 while (g_match_info_matches(match_info)) { … … 452 472 url_len_diff += target_len - g_utf8_strlen(url, -1); 453 473 /* Add another character for https://t.co/... URLs */ 454 if (g_match_info_fetch(match_info, 3) != NULL) 474 if (g_match_info_fetch(match_info, 3) != NULL) { 455 475 url_len_diff += 1; 476 } 456 477 g_free(url); 457 478 g_match_info_next(match_info, NULL); … … 468 489 int url_len_diff = 0; 469 490 470 if (target_len > 0) 491 if (target_len > 0) { 471 492 url_len_diff = twitter_url_len_diff(msg, target_len); 472 473 if (max == 0 || (len = g_utf8_strlen(msg, -1) + url_len_diff) <= max) 493 } 494 495 if (max == 0 || (len = g_utf8_strlen(msg, -1) + url_len_diff) <= max) { 474 496 return TRUE; 497 } 475 498 476 499 twitter_log(ic, "Maximum message length exceeded: %d > %d", len, max); … … 481 504 static char *set_eval_commands(set_t * set, char *value) 482 505 { 483 if (g_strcasecmp(value, "strict") == 0 )506 if (g_strcasecmp(value, "strict") == 0) { 484 507 return value; 485 else508 } else { 486 509 return set_eval_bool(set, value); 510 } 487 511 } 488 512 … … 490 514 { 491 515 if (g_strcasecmp(value, "one") == 0 || 492 g_strcasecmp(value, "many") == 0 || g_strcasecmp(value, "chat") == 0) 516 g_strcasecmp(value, "many") == 0 || g_strcasecmp(value, "chat") == 0) { 493 517 return value; 494 else518 } else { 495 519 return NULL; 520 } 496 521 } 497 522 … … 507 532 def_tul = "22"; 508 533 def_mentions = "true"; 509 } else { 534 } else { /* if( strcmp( acc->prpl->name, "identica" ) == 0 ) */ 510 535 def_url = IDENTICA_API_URL; 511 536 def_tul = "0"; … … 539 564 540 565 s = set_add(&acc->set, "strip_newlines", "false", set_eval_bool, acc); 541 566 542 567 s = set_add(&acc->set, "_last_tweet", "0", NULL, acc); 543 568 s->flags |= SET_HIDDEN | SET_NOSAVE; … … 560 585 url_t url; 561 586 char *s; 562 587 563 588 if (!url_set(&url, set_getstr(&ic->acc->set, "base_url")) || 564 589 (url.proto != PROTO_HTTP && url.proto != PROTO_HTTPS)) { … … 571 596 set_getbool(&ic->acc->set, "stream")) { 572 597 imcb_error(ic, "Warning: The streaming API is only supported by Twitter, " 573 598 "and you seem to be connecting to a different service."); 574 599 } 575 600 … … 584 609 td->url_port = url.port; 585 610 td->url_host = g_strdup(url.host); 586 if (strcmp(url.file, "/") != 0) 611 if (strcmp(url.file, "/") != 0) { 587 612 td->url_path = g_strdup(url.file); 588 else {613 } else { 589 614 td->url_path = g_strdup(""); 590 if (g_str_has_suffix(url.host, "twitter.com")) 615 if (g_str_has_suffix(url.host, "twitter.com")) { 591 616 /* May fire for people who turned on HTTPS. */ 592 617 imcb_error(ic, "Warning: Twitter requires a version number in API calls " 593 "now. Try resetting the base_url account setting."); 594 } 595 618 "now. Try resetting the base_url account setting."); 619 } 620 } 621 596 622 /* Hacky string mangling: Turn identi.ca into identi.ca and api.twitter.com 597 623 into twitter, and try to be sensible if we get anything else. */ 598 624 td->prefix = g_strdup(url.host); 599 if (g_str_has_suffix(td->prefix, ".com")) 625 if (g_str_has_suffix(td->prefix, ".com")) { 600 626 td->prefix[strlen(url.host) - 4] = '\0'; 627 } 601 628 if ((s = strrchr(td->prefix, '.')) && strlen(s) > 4) { 602 629 /* If we have at least 3 chars after the last dot, cut off the rest. … … 606 633 td->prefix = s; 607 634 } 608 609 if (strstr(acc->pass, "oauth_token=")) 635 636 if (strstr(acc->pass, "oauth_token=")) { 610 637 td->oauth_info = oauth_from_string(acc->pass, get_oauth_service(ic)); 638 } 611 639 612 640 sprintf(name, "%s_%s", td->prefix, acc->user); … … 616 644 td->log = g_new0(struct twitter_log_data, TWITTER_LOG_LENGTH); 617 645 td->log_id = -1; 618 646 619 647 s = set_getstr(&ic->acc->set, "mode"); 620 if (g_strcasecmp(s, "one") == 0) 648 if (g_strcasecmp(s, "one") == 0) { 621 649 td->flags |= TWITTER_MODE_ONE; 622 else if (g_strcasecmp(s, "many") == 0)650 } else if (g_strcasecmp(s, "many") == 0) { 623 651 td->flags |= TWITTER_MODE_MANY; 624 else652 } else { 625 653 td->flags |= TWITTER_MODE_CHAT; 654 } 626 655 627 656 twitter_login_finish(ic); … … 641 670 b_event_remove(td->main_loop_id); 642 671 643 if (td->timeline_gc) 672 if (td->timeline_gc) { 644 673 imcb_chat_free(td->timeline_gc); 674 } 645 675 646 676 if (td) { 647 if (td->filter_update_id > 0) 677 if (td->filter_update_id > 0) { 648 678 b_event_remove(td->filter_update_id); 679 } 649 680 650 681 http_close(td->stream); … … 679 710 680 711 strcpy(pin, message); 681 for (s = pin + sizeof(pin) - 2; s > pin && g_ascii_isspace(*s); s--) 712 for (s = pin + sizeof(pin) - 2; s > pin && g_ascii_isspace(*s); s--) { 682 713 *s = '\0'; 714 } 683 715 for (s = pin; *s && g_ascii_isspace(*s); s++) { 684 716 } … … 686 718 if (!oauth_access_token(s, td->oauth_info)) { 687 719 imcb_error(ic, "OAuth error: %s", 688 720 "Failed to send access token request"); 689 721 imc_logout(ic, TRUE); 690 722 return FALSE; 691 723 } 692 } else 724 } else { 693 725 twitter_handle_command(ic, message); 726 } 694 727 } else { 695 728 twitter_direct_messages_new(ic, who, message); … … 714 747 static void twitter_chat_msg(struct groupchat *c, char *message, int flags) 715 748 { 716 if (c && message) 749 if (c && message) { 717 750 twitter_handle_command(c->ic, message); 751 } 718 752 } 719 753 … … 737 771 tf = l->data; 738 772 739 if (topic->len > 0) 773 if (topic->len > 0) { 740 774 g_string_append(topic, ", "); 741 742 if (tf->type == TWITTER_FILTER_TYPE_FOLLOW) 775 } 776 777 if (tf->type == TWITTER_FILTER_TYPE_FOLLOW) { 743 778 g_string_append_c(topic, '@'); 779 } 744 780 745 781 g_string_append(topic, tf->text); 746 782 } 747 783 748 if (topic->len > 0) 784 if (topic->len > 0) { 749 785 g_string_prepend(topic, "Twitter Filter: "); 786 } 750 787 751 788 imcb_chat_topic(c, NULL, topic->str, 0); … … 820 857 * Returns 0 if the user provides garbage. 821 858 */ 822 static guint64 twitter_message_id_from_command_arg(struct im_connection *ic, char *arg, bee_user_t **bu_) { 859 static guint64 twitter_message_id_from_command_arg(struct im_connection *ic, char *arg, bee_user_t **bu_) 860 { 823 861 struct twitter_data *td = ic->proto_data; 824 862 struct twitter_user_data *tud; 825 863 bee_user_t *bu = NULL; 826 864 guint64 id = 0; 827 828 if (bu_) 865 866 if (bu_) { 829 867 *bu_ = NULL; 830 if (!arg || !arg[0]) 868 } 869 if (!arg || !arg[0]) { 831 870 return 0; 832 871 } 872 833 873 if (arg[0] != '#' && (bu = bee_user_by_handle(ic->bee, ic, arg))) { 834 if ((tud = bu->data)) 874 if ((tud = bu->data)) { 835 875 id = tud->last_id; 876 } 836 877 } else { 837 if (arg[0] == '#') 878 if (arg[0] == '#') { 838 879 arg++; 880 } 839 881 if (sscanf(arg, "%" G_GINT64_MODIFIER "x", &id) == 1 && 840 882 id < TWITTER_LOG_LENGTH) { … … 842 884 id = td->log[id].id; 843 885 /* Beware of dangling pointers! */ 844 if (!g_slist_find(ic->bee->users, bu)) 886 if (!g_slist_find(ic->bee->users, bu)) { 845 887 bu = NULL; 888 } 846 889 } else if (sscanf(arg, "%" G_GINT64_MODIFIER "d", &id) == 1) { 847 890 /* Allow normal tweet IDs as well; not a very useful 848 891 feature but it's always been there. Just ignore 849 892 very low IDs to avoid accidents. */ 850 if (id < 1000000) 893 if (id < 1000000) { 851 894 id = 0; 852 } 853 } 854 if (bu_) 895 } 896 } 897 } 898 if (bu_) { 855 899 *bu_ = bu; 900 } 856 901 return id; 857 902 } … … 863 908 guint64 in_reply_to = 0, id; 864 909 gboolean allow_post = 865 910 g_strcasecmp(set_getstr(&ic->acc->set, "commands"), "strict") != 0; 866 911 bee_user_t *bu = NULL; 867 912 … … 874 919 /* Not supporting commands if "commands" is set to true/strict. */ 875 920 } else if (g_strcasecmp(cmd[0], "undo") == 0) { 876 if (cmd[1] == NULL) 921 if (cmd[1] == NULL) { 877 922 twitter_status_destroy(ic, td->last_status_id); 878 else if ((id = twitter_message_id_from_command_arg(ic, cmd[1], NULL)))923 } else if ((id = twitter_message_id_from_command_arg(ic, cmd[1], NULL))) { 879 924 twitter_status_destroy(ic, id); 880 else925 } else { 881 926 twitter_log(ic, "Could not undo last action"); 927 } 882 928 883 929 goto eof; 884 930 } else if ((g_strcasecmp(cmd[0], "favourite") == 0 || 885 886 931 g_strcasecmp(cmd[0], "favorite") == 0 || 932 g_strcasecmp(cmd[0], "fav") == 0) && cmd[1]) { 887 933 if ((id = twitter_message_id_from_command_arg(ic, cmd[1], NULL))) { 888 934 twitter_favourite_tweet(ic, id); … … 900 946 g_strcasecmp(cmd[0], "spam") == 0) && cmd[1]) { 901 947 char *screen_name; 902 948 903 949 /* Report nominally works on users but look up the user who 904 950 posted the given ID if the user wants to do it that way */ 905 951 twitter_message_id_from_command_arg(ic, cmd[1], &bu); 906 if (bu) 952 if (bu) { 907 953 screen_name = bu->handle; 908 else954 } else { 909 955 screen_name = cmd[1]; 910 956 } 957 911 958 twitter_report_spam(ic, screen_name); 912 959 goto eof; … … 915 962 916 963 td->last_status_id = 0; 917 if (id) 964 if (id) { 918 965 twitter_status_retweet(ic, id); 919 else966 } else { 920 967 twitter_log(ic, "User `%s' does not exist or didn't " 921 "post any statuses recently", cmd[1]); 968 "post any statuses recently", cmd[1]); 969 } 922 970 923 971 goto eof; … … 926 974 if (!id || !bu) { 927 975 twitter_log(ic, "User `%s' does not exist or didn't " 928 976 "post any statuses recently", cmd[1]); 929 977 goto eof; 930 978 } … … 949 997 char *s; 950 998 951 if (!twitter_length_check(ic, message)) 999 if (!twitter_length_check(ic, message)) { 952 1000 goto eof; 1001 } 953 1002 954 1003 s = cmd[0] + strlen(cmd[0]) - 1; … … 960 1009 961 1010 new = g_strdup_printf("@%s %s", bu->handle, 962 1011 message + (s - cmd[0]) + 2); 963 1012 message = new; 964 1013 965 1014 if (time(NULL) < tud->last_time + 966 set_getint(&ic->acc->set, "auto_reply_timeout")) 1015 set_getint(&ic->acc->set, "auto_reply_timeout")) { 967 1016 in_reply_to = tud->last_id; 1017 } 968 1018 } 969 1019 } … … 981 1031 } 982 1032 983 void twitter_log(struct im_connection *ic, char *format, ... 1033 void twitter_log(struct im_connection *ic, char *format, ...) 984 1034 { 985 1035 struct twitter_data *td = ic->proto_data; 986 1036 va_list params; 987 1037 char *text; 988 1038 989 1039 va_start(params, format); 990 1040 text = g_strdup_vprintf(format, params); 991 1041 va_end(params); 992 993 if (td->timeline_gc) 1042 1043 if (td->timeline_gc) { 994 1044 imcb_chat_log(td->timeline_gc, "%s", text); 995 else1045 } else { 996 1046 imcb_log(ic, "%s", text); 997 1047 } 1048 998 1049 g_free(text); 999 1050 } -
protocols/twitter/twitter.h
raf359b4 r5ebff60 29 29 30 30 #ifdef DEBUG_TWITTER 31 #define debug( text... ) imcb_log( ic, text);31 #define debug(text ...) imcb_log(ic, text); 32 32 #else 33 #define debug( text...)33 #define debug(text ...) 34 34 #endif 35 35 36 typedef enum 37 { 36 typedef enum { 38 37 TWITTER_HAVE_FRIENDS = 0x00001, 39 38 TWITTER_MODE_ONE = 0x00002, … … 45 44 } twitter_flags_t; 46 45 47 typedef enum 48 { 46 typedef enum { 49 47 TWITTER_FILTER_TYPE_FOLLOW = 0, 50 48 TWITTER_FILTER_TYPE_TRACK … … 53 51 struct twitter_log_data; 54 52 55 struct twitter_data 56 { 53 struct twitter_data { 57 54 char* user; 58 55 struct oauth_info *oauth_info; … … 65 62 GSList *follow_ids; 66 63 GSList *filters; 67 64 68 65 guint64 last_status_id; /* For undo */ 69 66 gint main_loop_id; … … 74 71 gint http_fails; 75 72 twitter_flags_t flags; 76 73 77 74 /* set base_url */ 78 75 gboolean url_ssl; … … 82 79 83 80 char *prefix; /* Used to generate contact + channel name. */ 84 81 85 82 /* set show_ids */ 86 83 struct twitter_log_data *log; … … 89 86 90 87 #define TWITTER_FILTER_UPDATE_WAIT 3000 91 struct twitter_filter 92 { 88 struct twitter_filter { 93 89 twitter_filter_type_t type; 94 90 char *text; … … 97 93 }; 98 94 99 struct twitter_user_data 100 { 95 struct twitter_user_data { 101 96 guint64 last_id; 102 97 time_t last_time; … … 104 99 105 100 #define TWITTER_LOG_LENGTH 256 106 struct twitter_log_data 107 { 101 struct twitter_log_data { 108 102 guint64 id; 109 103 struct bee_user *bu; /* DANGER: can be a dead pointer. Check it first. */ … … 111 105 112 106 /** 113 * This has the same function as the msn_connections GSList. We use this to 107 * This has the same function as the msn_connections GSList. We use this to 114 108 * make sure the connection is still alive in callbacks before we do anything 115 109 * else. … … 117 111 extern GSList *twitter_connections; 118 112 119 void twitter_login_finish( struct im_connection *ic);113 void twitter_login_finish(struct im_connection *ic); 120 114 121 115 struct http_request; 122 char *twitter_parse_error( struct http_request *req);116 char *twitter_parse_error(struct http_request *req); 123 117 124 void twitter_log(struct im_connection *ic, char *format, ... 118 void twitter_log(struct im_connection *ic, char *format, ...); 125 119 struct groupchat *twitter_groupchat_init(struct im_connection *ic); 126 120 -
protocols/twitter/twitter_http.c
raf359b4 r5ebff60 48 48 */ 49 49 struct http_request *twitter_http(struct im_connection *ic, char *url_string, http_input_function func, 50 50 gpointer data, int is_post, char **arguments, int arguments_len) 51 51 { 52 52 struct twitter_data *td = ic->proto_data; … … 68 68 } 69 69 } 70 70 71 71 if (strstr(url_string, "://")) { 72 72 base_url = g_new0(url_t, 1); … … 76 76 } 77 77 } 78 78 79 79 // Make the request. 80 80 g_string_printf(request, "%s %s%s%s%s HTTP/1.1\r\n" 81 82 83 84 85 86 87 81 "Host: %s\r\n" 82 "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n", 83 is_post ? "POST" : "GET", 84 base_url ? base_url->file : td->url_path, 85 base_url ? "" : url_string, 86 is_post ? "" : "?", is_post ? "" : url_arguments, 87 base_url ? base_url->host : td->url_host); 88 88 89 89 // If a pass and user are given we append them to the request. … … 92 92 char *full_url; 93 93 94 if (base_url) 94 if (base_url) { 95 95 full_url = g_strdup(url_string); 96 else96 } else { 97 97 full_url = g_strconcat(set_getstr(&ic->acc->set, "base_url"), url_string, NULL); 98 } 98 99 full_header = oauth_http_header(td->oauth_info, is_post ? "POST" : "GET", 99 100 full_url, url_arguments); 100 101 101 102 g_string_append_printf(request, "Authorization: %s\r\n", full_header); … … 116 117 // Append the Content-Type and url-encoded arguments. 117 118 g_string_append_printf(request, 118 119 120 119 "Content-Type: application/x-www-form-urlencoded\r\n" 120 "Content-Length: %zd\r\n\r\n%s", 121 strlen(url_arguments), url_arguments); 121 122 } else { 122 123 // Append an extra \r\n to end the request... … … 124 125 } 125 126 126 if (base_url) 127 ret = http_dorequest(base_url->host, base_url->port, base_url->proto == PROTO_HTTPS, request->str, func, data); 128 else 127 if (base_url) { 128 ret = http_dorequest(base_url->host, base_url->port, base_url->proto == PROTO_HTTPS, request->str, func, 129 data); 130 } else { 129 131 ret = http_dorequest(td->url_host, td->url_port, td->url_ssl, request->str, func, data); 132 } 130 133 131 134 g_free(url_arguments); … … 136 139 137 140 struct http_request *twitter_http_f(struct im_connection *ic, char *url_string, http_input_function func, 138 gpointer data, int is_post, char **arguments, int arguments_len, twitter_http_flags_t flags) 141 gpointer data, int is_post, char **arguments, int arguments_len, 142 twitter_http_flags_t flags) 139 143 { 140 144 struct http_request *ret = twitter_http(ic, url_string, func, data, is_post, arguments, arguments_len); 141 if (ret) 145 146 if (ret) { 142 147 ret->flags |= flags; 148 } 143 149 return ret; 144 150 } … … 147 153 { 148 154 char *key_encoded = g_strndup(key, 3 * strlen(key)); 155 149 156 http_encode(key_encoded); 150 157 char *value_encoded = g_strndup(value, 3 * strlen(value)); … … 152 159 153 160 char *retval; 154 if (strlen(url) != 0) 161 if (strlen(url) != 0) { 155 162 retval = g_strdup_printf("%s&%s=%s", url, key_encoded, value_encoded); 156 else163 } else { 157 164 retval = g_strdup_printf("%s=%s", key_encoded, value_encoded); 165 } 158 166 159 167 g_free(key_encoded); -
protocols/twitter/twitter_http.h
raf359b4 r5ebff60 39 39 gpointer data, int is_post, char** arguments, int arguments_len); 40 40 struct http_request *twitter_http_f(struct im_connection *ic, char *url_string, http_input_function func, 41 gpointer data, int is_post, char** arguments, int arguments_len, twitter_http_flags_t flags); 41 gpointer data, int is_post, char** arguments, int arguments_len, 42 twitter_http_flags_t flags); 42 43 43 44 #endif //_TWITTER_HTTP_H -
protocols/twitter/twitter_lib.c
raf359b4 r5ebff60 24 24 25 25 /* For strptime(): */ 26 #if (__sun)26 #if (__sun) 27 27 #else 28 28 #define _XOPEN_SOURCE … … 70 70 static void txu_free(struct twitter_xml_user *txu) 71 71 { 72 if (txu == NULL) 73 return; 72 if (txu == NULL) { 73 return; 74 } 74 75 75 76 g_free(txu->name); … … 83 84 static void txs_free(struct twitter_xml_status *txs) 84 85 { 85 if (txs == NULL) 86 return; 86 if (txs == NULL) { 87 return; 88 } 87 89 88 90 g_free(txs->text); … … 98 100 { 99 101 GSList *l; 100 if (txl == NULL) 101 return; 102 103 if (txl == NULL) { 104 return; 105 } 102 106 103 107 for (l = txl->list; l; l = g_slist_next(l)) { … … 148 152 exact Twitter username. */ 149 153 imcb_buddy_nick_hint(ic, name, name); 150 if (td->timeline_gc) 154 if (td->timeline_gc) { 151 155 imcb_chat_add_buddy(td->timeline_gc, name); 152 } else if (td->flags & TWITTER_MODE_MANY) 156 } 157 } else if (td->flags & TWITTER_MODE_MANY) { 153 158 imcb_buddy_status(ic, name, OPT_LOGGED_IN, NULL, NULL); 159 } 154 160 } 155 161 } … … 171 177 err->type == json_object) { 172 178 const char *msg = json_o_str(err, "message"); 173 if (msg) 179 if (msg) { 174 180 ret = g_strdup_printf("%s (%s)", req->status_string, msg); 181 } 175 182 } 176 183 json_value_free(root); … … 189 196 json_value *ret; 190 197 char path[64] = "", *s; 191 198 192 199 if ((s = strchr(req->request, ' '))) { 193 path[sizeof(path) -1] = '\0';200 path[sizeof(path) - 1] = '\0'; 194 201 strncpy(path, s + 1, sizeof(path) - 1); 195 if ((s = strchr(path, '?')) || (s = strchr(path, ' '))) 202 if ((s = strchr(path, '?')) || (s = strchr(path, ' '))) { 196 203 *s = '\0'; 197 } 198 204 } 205 } 206 199 207 /* Kinda nasty. :-( Trying to suppress error messages, but only 200 208 for periodic (i.e. mentions/timeline) queries. */ 201 209 periodic = strstr(path, "timeline") || strstr(path, "mentions"); 202 210 203 211 if (req->status_code == 401 && logging_in) { 204 212 /* IIRC Twitter once had an outage where they were randomly … … 206 214 only during login. */ 207 215 imcb_error(ic, "Authentication failure (%s)", 208 216 twitter_parse_error(req)); 209 217 imc_logout(ic, FALSE); 210 218 return NULL; 211 219 } else if (req->status_code != 200) { 212 220 // It didn't go well, output the error and return. 213 if (!periodic || logging_in || ++td->http_fails >= 5) 221 if (!periodic || logging_in || ++td->http_fails >= 5) { 214 222 twitter_log(ic, "Error: Could not retrieve %s: %s", 215 path, twitter_parse_error(req)); 216 217 if (logging_in) 223 path, twitter_parse_error(req)); 224 } 225 226 if (logging_in) { 218 227 imc_logout(ic, TRUE); 228 } 219 229 return NULL; 220 230 } else { … … 224 234 if ((ret = json_parse(req->reply_body, req->body_size)) == NULL) { 225 235 imcb_error(ic, "Could not retrieve %s: %s", 226 236 path, "XML parse error"); 227 237 } 228 238 return ret; … … 238 248 // Primitive, but hey! It works... 239 249 char *args[2]; 250 240 251 args[0] = "cursor"; 241 252 args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); … … 257 268 258 269 c = json_o_get(node, "ids"); 259 if (!c || c->type != json_array) 270 if (!c || c->type != json_array) { 260 271 return FALSE; 261 262 for (i = 0; i < c->u.array.length; i ++) { 263 if (c->u.array.values[i]->type != json_integer) 272 } 273 274 for (i = 0; i < c->u.array.length; i++) { 275 if (c->u.array.values[i]->type != json_integer) { 264 276 continue; 265 277 } 278 266 279 txl->list = g_slist_prepend(txl->list, 267 268 } 269 280 g_strdup_printf("%" PRIu64, c->u.array.values[i]->u.integer)); 281 } 282 270 283 c = json_o_get(node, "next_cursor"); 271 if (c && c->type == json_integer) 284 if (c && c->type == json_integer) { 272 285 txl->next_cursor = c->u.integer; 273 else286 } else { 274 287 txl->next_cursor = -1; 275 288 } 289 276 290 return TRUE; 277 291 } … … 292 306 293 307 // Check if the connection is still active. 294 if (!g_slist_find(twitter_connections, ic)) 295 return; 308 if (!g_slist_find(twitter_connections, ic)) { 309 return; 310 } 296 311 297 312 td = ic->proto_data; … … 301 316 302 317 // Parse the data. 303 if (!(parsed = twitter_parse_response(ic, req))) 304 return; 305 318 if (!(parsed = twitter_parse_response(ic, req))) { 319 return; 320 } 321 306 322 twitter_xt_get_friends_id_list(parsed, txl); 307 323 json_value_free(parsed); 308 324 309 325 td->follow_ids = txl->list; 310 if (txl->next_cursor) 326 if (txl->next_cursor) { 311 327 /* These were just numbers. Up to 4000 in a response AFAIK so if we get here 312 328 we may be using a spammer account. \o/ */ 313 329 twitter_get_friends_ids(ic, txl->next_cursor); 314 else330 } else { 315 331 /* Now to convert all those numbers into names.. */ 316 332 twitter_get_users_lookup(ic); 333 } 317 334 318 335 txl->list = NULL; … … 332 349 GString *ids = g_string_new(""); 333 350 int i; 334 351 335 352 /* We can request up to 100 users at a time. */ 336 for (i = 0; i < 100 && td->follow_ids; i 337 g_string_append_printf(ids, ",%s", (char *) td->follow_ids->data);353 for (i = 0; i < 100 && td->follow_ids; i++) { 354 g_string_append_printf(ids, ",%s", (char *) td->follow_ids->data); 338 355 g_free(td->follow_ids->data); 339 356 td->follow_ids = g_slist_remove(td->follow_ids, td->follow_ids->data); … … 354 371 * Callback for getting (twitter)friends... 355 372 * 356 * Be afraid, be very afraid! This function will potentially add hundreds of "friends". "Who has 357 * hundreds of friends?" you wonder? You probably not, since you are reading the source of 373 * Be afraid, be very afraid! This function will potentially add hundreds of "friends". "Who has 374 * hundreds of friends?" you wonder? You probably not, since you are reading the source of 358 375 * BitlBee... Get a life and meet new people! 359 376 */ … … 367 384 368 385 // Check if the connection is still active. 369 if (!g_slist_find(twitter_connections, ic)) 370 return; 386 if (!g_slist_find(twitter_connections, ic)) { 387 return; 388 } 371 389 372 390 txl = g_new0(struct twitter_xml_list, 1); … … 374 392 375 393 // Get the user list from the parsed xml feed. 376 if (!(parsed = twitter_parse_response(ic, req))) 377 return; 394 if (!(parsed = twitter_parse_response(ic, req))) { 395 return; 396 } 378 397 twitter_xt_get_users(parsed, txl); 379 398 json_value_free(parsed); … … 395 414 struct twitter_xml_user *txu; 396 415 json_value *jv; 397 416 398 417 txu = g_new0(struct twitter_xml_user, 1); 399 418 txu->name = g_strdup(json_o_str(node, "name")); 400 419 txu->screen_name = g_strdup(json_o_str(node, "screen_name")); 401 420 402 421 jv = json_o_get(node, "id"); 403 422 txu->uid = jv->u.integer; 404 423 405 424 return txu; 406 425 } … … 419 438 txl->type = TXL_USER; 420 439 421 if (!node || node->type != json_array) 440 if (!node || node->type != json_array) { 422 441 return FALSE; 442 } 423 443 424 444 // The root <users> node should hold the list of users <user> 425 445 // Walk over the nodes children. 426 for (i = 0; i < node->u.array.length; i 446 for (i = 0; i < node->u.array.length; i++) { 427 447 txu = twitter_xt_get_user(node->u.array.values[i]); 428 if (txu) 448 if (txu) { 429 449 txl->list = g_slist_prepend(txl->list, txu); 450 } 430 451 } 431 452 … … 453 474 struct twitter_xml_status *txs; 454 475 const json_value *rt = NULL, *entities = NULL; 455 456 if (node->type != json_object) 476 477 if (node->type != json_object) { 457 478 return FALSE; 479 } 458 480 txs = g_new0(struct twitter_xml_status, 1); 459 481 460 JSON_O_FOREACH 482 JSON_O_FOREACH(node, k, v) { 461 483 if (strcmp("text", k) == 0 && v->type == json_string) { 462 484 txs->text = g_memdup(v->u.string.ptr, v->u.string.length + 1); … … 470 492 this field. :-( Also assumes the timezone used 471 493 is UTC since C time handling functions suck. */ 472 if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL) 494 if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL) { 473 495 txs->created_at = mktime_utc(&parsed); 496 } 474 497 } else if (strcmp("user", k) == 0 && v->type == json_object) { 475 498 txs->user = twitter_xt_get_user(v); … … 497 520 } 498 521 499 if (txs->text && txs->user && txs->id) 522 if (txs->text && txs->user && txs->id) { 500 523 return txs; 501 524 } 525 502 526 txs_free(txs); 503 527 return NULL; … … 511 535 struct twitter_xml_status *txs; 512 536 const json_value *entities = NULL; 513 514 if (node->type != json_object) 537 538 if (node->type != json_object) { 515 539 return FALSE; 540 } 516 541 txs = g_new0(struct twitter_xml_status, 1); 517 542 518 JSON_O_FOREACH 543 JSON_O_FOREACH(node, k, v) { 519 544 if (strcmp("text", k) == 0 && v->type == json_string) { 520 545 txs->text = g_memdup(v->u.string.ptr, v->u.string.length + 1); … … 526 551 this field. :-( Also assumes the timezone used 527 552 is UTC since C time handling functions suck. */ 528 if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL) 553 if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL) { 529 554 txs->created_at = mktime_utc(&parsed); 555 } 530 556 } else if (strcmp("sender", k) == 0 && v->type == json_object) { 531 557 txs->user = twitter_xt_get_user(v); … … 539 565 } 540 566 541 if (txs->text && txs->user && txs->id) 567 if (txs->text && txs->user && txs->id) { 542 568 return txs; 543 569 } 570 544 571 txs_free(txs); 545 572 return NULL; 546 573 } 547 574 548 static char* expand_entities(char* text, const json_value *entities) { 549 JSON_O_FOREACH (entities, k, v) { 575 static char* expand_entities(char* text, const json_value *entities) 576 { 577 JSON_O_FOREACH(entities, k, v) { 550 578 int i; 551 552 if (v->type != json_array) 579 580 if (v->type != json_array) { 553 581 continue; 554 if (strcmp(k, "urls") != 0 && strcmp(k, "media") != 0) 582 } 583 if (strcmp(k, "urls") != 0 && strcmp(k, "media") != 0) { 555 584 continue; 556 557 for (i = 0; i < v->u.array.length; i ++) { 558 if (v->u.array.values[i]->type != json_object) 585 } 586 587 for (i = 0; i < v->u.array.length; i++) { 588 if (v->u.array.values[i]->type != json_object) { 559 589 continue; 560 590 } 591 561 592 const char *kort = json_o_str(v->u.array.values[i], "url"); 562 593 const char *disp = json_o_str(v->u.array.values[i], "display_url"); 563 594 char *pos, *new; 564 565 if (!kort || !disp || !(pos = strstr(text, kort))) 595 596 if (!kort || !disp || !(pos = strstr(text, kort))) { 566 597 continue; 567 598 } 599 568 600 *pos = '\0'; 569 601 new = g_strdup_printf("%s%s <%s>%s", text, kort, 570 602 disp, pos + strlen(kort)); 571 603 572 604 g_free(text); 573 605 text = new; 574 606 } 575 607 } 576 608 577 609 return text; 578 610 } … … 592 624 // Set the type of the list. 593 625 txl->type = TXL_STATUS; 594 595 if (node->type != json_array) 626 627 if (node->type != json_array) { 596 628 return FALSE; 629 } 597 630 598 631 // The root <statuses> node should hold the list of statuses <status> 599 632 // Walk over the nodes children. 600 for (i = 0; i < node->u.array.length; i 633 for (i = 0; i < node->u.array.length; i++) { 601 634 txs = twitter_xt_get_status(node->u.array.values[i]); 602 if (!txs) 635 if (!txs) { 603 636 continue; 604 637 } 638 605 639 txl->list = g_slist_prepend(txl->list, txs); 606 640 } … … 612 646 Plus, show_ids is on by default and I don't see why anyone would disable it. */ 613 647 static char *twitter_msg_add_id(struct im_connection *ic, 614 648 struct twitter_xml_status *txs, const char *prefix) 615 649 { 616 650 struct twitter_data *td = ic->proto_data; … … 620 654 if (txs->reply_to) { 621 655 int i; 622 for (i = 0; i < TWITTER_LOG_LENGTH; i++) 656 for (i = 0; i < TWITTER_LOG_LENGTH; i++) { 623 657 if (td->log[i].id == txs->reply_to) { 624 658 reply_to = i; 625 659 break; 626 660 } 661 } 627 662 } 628 663 … … 636 671 } 637 672 } 638 673 639 674 td->log_id = (td->log_id + 1) % TWITTER_LOG_LENGTH; 640 675 td->log[td->log_id].id = txs->id; 641 676 td->log[td->log_id].bu = bee_user_by_handle(ic->bee, ic, txs->user->screen_name); 642 677 643 678 /* This is all getting hairy. :-( If we RT'ed something ourselves, 644 679 remember OUR id instead so undo will work. In other cases, the 645 680 original tweet's id should be remembered for deduplicating. */ 646 if (g_strcasecmp(txs->user->screen_name, td->user) == 0) 681 if (g_strcasecmp(txs->user->screen_name, td->user) == 0) { 647 682 td->log[td->log_id].id = txs->rt_id; 648 683 } 684 649 685 if (set_getbool(&ic->acc->set, "show_ids")) { 650 if (reply_to != -1) 686 if (reply_to != -1) { 651 687 return g_strdup_printf("\002[\002%02x->%02x\002]\002 %s%s", 652 688 td->log_id, reply_to, prefix, txs->text); 653 else689 } else { 654 690 return g_strdup_printf("\002[\002%02x\002]\002 %s%s", 655 691 td->log_id, prefix, txs->text); 692 } 656 693 } else { 657 if (*prefix) 694 if (*prefix) { 658 695 return g_strconcat(prefix, txs->text, NULL); 659 else696 } else { 660 697 return NULL; 698 } 661 699 } 662 700 } … … 678 716 switch (tf->type) { 679 717 case TWITTER_FILTER_TYPE_FOLLOW: 680 if (status->user->uid != tf->uid) 718 if (status->user->uid != tf->uid) { 681 719 continue; 720 } 682 721 break; 683 722 684 723 case TWITTER_FILTER_TYPE_TRACK: 685 if (strcasestr(status->text, tf->text) == NULL) 724 if (strcasestr(status->text, tf->text) == NULL) { 686 725 continue; 726 } 687 727 break; 688 728 … … 693 733 for (l = tf->groupchats; l; l = g_slist_next(l)) { 694 734 imcb_chat_msg(l->data, status->user->screen_name, 695 735 msg ? msg : status->text, 0, 0); 696 736 } 697 737 } … … 713 753 gc = twitter_groupchat_init(ic); 714 754 715 if (!me) 755 if (!me) { 716 756 /* MUST be done before twitter_msg_add_id() to avoid #872. */ 717 757 twitter_add_buddy(ic, status->user->screen_name, status->user->name); 758 } 718 759 msg = twitter_msg_add_id(ic, status, ""); 719 760 720 761 // Say it! 721 762 if (me) { … … 723 764 } else { 724 765 imcb_chat_msg(gc, status->user->screen_name, 725 766 msg ? msg : status->text, 0, status->created_at); 726 767 } 727 768 … … 744 785 } 745 786 746 if (td->flags & TWITTER_MODE_ONE) 787 if (td->flags & TWITTER_MODE_ONE) { 747 788 prefix = g_strdup_printf("\002<\002%s\002>\002 ", 748 789 status->user->screen_name); 749 else if (!me)790 } else if (!me) { 750 791 twitter_add_buddy(ic, status->user->screen_name, status->user->name); 751 else792 } else { 752 793 prefix = g_strdup("You: "); 794 } 753 795 754 796 text = twitter_msg_add_id(ic, status, prefix ? prefix : ""); … … 766 808 struct twitter_data *td = ic->proto_data; 767 809 char *last_id_str; 768 769 if (status->user == NULL || status->text == NULL) 770 return; 771 810 811 if (status->user == NULL || status->text == NULL) { 812 return; 813 } 814 772 815 /* Grrrr. Would like to do this during parsing, but can't access 773 816 settings from there. */ 774 if (set_getbool(&ic->acc->set, "strip_newlines")) 817 if (set_getbool(&ic->acc->set, "strip_newlines")) { 775 818 strip_newlines(status->text); 776 777 if (status->from_filter) 819 } 820 821 if (status->from_filter) { 778 822 twitter_status_show_filter(ic, status); 779 else if (td->flags & TWITTER_MODE_CHAT)823 } else if (td->flags & TWITTER_MODE_CHAT) { 780 824 twitter_status_show_chat(ic, status); 781 else825 } else { 782 826 twitter_status_show_msg(ic, status); 827 } 783 828 784 829 // Update the timeline_id to hold the highest id, so that by the next request … … 801 846 char c, *nl; 802 847 gboolean from_filter; 803 804 if (!g_slist_find(twitter_connections, ic)) 805 return; 806 848 849 if (!g_slist_find(twitter_connections, ic)) { 850 return; 851 } 852 807 853 ic->flags |= OPT_PONGED; 808 854 td = ic->proto_data; 809 855 810 856 if ((req->flags & HTTPC_EOF) || !req->reply_body) { 811 if (req == td->stream) 857 if (req == td->stream) { 812 858 td->stream = NULL; 813 else if (req == td->filter_stream)859 } else if (req == td->filter_stream) { 814 860 td->filter_stream = NULL; 861 } 815 862 816 863 imcb_error(ic, "Stream closed (%s)", req->status_string); … … 818 865 return; 819 866 } 820 867 821 868 /* MUST search for CRLF, not just LF: 822 869 https://dev.twitter.com/docs/streaming-apis/processing#Parsing_responses */ 823 if (!(nl = strstr(req->reply_body, "\r\n"))) 824 return; 825 870 if (!(nl = strstr(req->reply_body, "\r\n"))) { 871 return; 872 } 873 826 874 len = nl - req->reply_body; 827 875 if (len > 0) { 828 876 c = req->reply_body[len]; 829 877 req->reply_body[len] = '\0'; 830 878 831 879 if ((parsed = json_parse(req->reply_body, req->body_size))) { 832 880 from_filter = (req == td->filter_stream); … … 836 884 req->reply_body[len] = c; 837 885 } 838 886 839 887 http_flush_bytes(req, len + 2); 840 888 841 889 /* One notification might bring multiple events! */ 842 if (req->body_size > 0) 890 if (req->body_size > 0) { 843 891 twitter_http_stream(req); 892 } 844 893 } 845 894 … … 852 901 struct twitter_xml_status *txs; 853 902 json_value *c; 854 903 855 904 if ((txs = twitter_xt_get_status(o))) { 856 905 txs->from_filter = from_filter; … … 860 909 } else if ((c = json_o_get(o, "direct_message")) && 861 910 (txs = twitter_xt_get_dm(c))) { 862 if (g_strcasecmp(txs->user->screen_name, td->user) != 0) 911 if (g_strcasecmp(txs->user->screen_name, td->user) != 0) { 863 912 imcb_buddy_msg(ic, txs->user->screen_name, 864 txs->text, 0, txs->created_at); 913 txs->text, 0, txs->created_at); 914 } 865 915 txs_free(txs); 866 916 return TRUE; … … 886 936 struct twitter_data *td = ic->proto_data; 887 937 int i; 888 938 889 939 for (i = 0; i < TWITTER_LOG_LENGTH; i++) { 890 940 if (td->log[i].id == txs->id) { … … 893 943 } 894 944 } 895 945 896 946 if (!(g_strcasecmp(txs->user->screen_name, td->user) == 0 || 897 947 set_getbool(&ic->acc->set, "fetch_mentions") || … … 905 955 return TRUE; 906 956 } 907 957 908 958 twitter_status_show(ic, txs); 909 959 910 960 return TRUE; 911 961 } … … 917 967 json_value *target = json_o_get(o, "target"); 918 968 const char *type = json_o_str(o, "event"); 919 969 920 970 if (!type || !source || source->type != json_object 921 971 || !target || target->type != json_object) { 922 972 return FALSE; 923 973 } 924 974 925 975 if (strcmp(type, "follow") == 0) { 926 976 struct twitter_xml_user *us = twitter_xt_get_user(source); … … 932 982 txu_free(ut); 933 983 } 934 984 935 985 return TRUE; 936 986 } … … 939 989 { 940 990 struct twitter_data *td = ic->proto_data; 941 char *args[2] = { "with", "followings"};942 991 char *args[2] = { "with", "followings" }; 992 943 993 if ((td->stream = twitter_http(ic, TWITTER_USER_STREAM_URL, 944 994 twitter_http_stream, ic, 0, args, 2))) { … … 948 998 return TRUE; 949 999 } 950 1000 951 1001 return FALSE; 952 1002 } … … 955 1005 { 956 1006 struct twitter_data *td = ic->proto_data; 957 char *args[4] = { "follow", NULL, "track", NULL};1007 char *args[4] = { "follow", NULL, "track", NULL }; 958 1008 GString *followstr = g_string_new(""); 959 1009 GString *trackstr = g_string_new(""); … … 967 1017 switch (tf->type) { 968 1018 case TWITTER_FILTER_TYPE_FOLLOW: 969 if (followstr->len > 0) 1019 if (followstr->len > 0) { 970 1020 g_string_append_c(followstr, ','); 1021 } 971 1022 972 1023 g_string_append_printf(followstr, "%" G_GUINT64_FORMAT, 973 1024 tf->uid); 974 1025 break; 975 1026 976 1027 case TWITTER_FILTER_TYPE_TRACK: 977 if (trackstr->len > 0) 1028 if (trackstr->len > 0) { 978 1029 g_string_append_c(trackstr, ','); 1030 } 979 1031 980 1032 g_string_append(trackstr, tf->text); … … 989 1041 args[3] = trackstr->str; 990 1042 991 if (td->filter_stream) 1043 if (td->filter_stream) { 992 1044 http_close(td->filter_stream); 1045 } 993 1046 994 1047 if ((td->filter_stream = twitter_http(ic, TWITTER_FILTER_STREAM_URL, 995 1048 twitter_http_stream, ic, 0, 996 1049 args, 4))) { 997 1050 /* This flag must be enabled or we'll get no data until EOF 998 1051 (which err, kind of, defeats the purpose of a streaming API). */ … … 1022 1075 1023 1076 // Check if the connection is still active. 1024 if (!g_slist_find(twitter_connections, ic)) 1025 return; 1077 if (!g_slist_find(twitter_connections, ic)) { 1078 return; 1079 } 1026 1080 1027 1081 td = ic->proto_data; 1028 1082 1029 if (!(parsed = twitter_parse_response(ic, req))) 1030 return; 1083 if (!(parsed = twitter_parse_response(ic, req))) { 1084 return; 1085 } 1031 1086 1032 1087 for (l = td->filters; l; l = g_slist_next(l)) { 1033 1088 tf = l->data; 1034 1089 1035 if (tf->type == TWITTER_FILTER_TYPE_FOLLOW) 1090 if (tf->type == TWITTER_FILTER_TYPE_FOLLOW) { 1036 1091 users = g_list_prepend(users, tf); 1037 } 1038 1039 if (parsed->type != json_array) 1092 } 1093 } 1094 1095 if (parsed->type != json_array) { 1040 1096 goto finish; 1097 } 1041 1098 1042 1099 for (i = 0; i < parsed->u.array.length; i++) { … … 1044 1101 name = json_o_str(parsed->u.array.values[i], "screen_name"); 1045 1102 1046 if (!name || !id || id->type != json_integer) 1103 if (!name || !id || id->type != json_integer) { 1047 1104 continue; 1105 } 1048 1106 1049 1107 for (u = users; u; u = g_list_next(u)) { … … 1062 1120 twitter_filter_stream(ic); 1063 1121 1064 if (!users) 1065 return; 1122 if (!users) { 1123 return; 1124 } 1066 1125 1067 1126 fstr = g_string_new(""); 1068 1127 1069 1128 for (u = users; u; u = g_list_next(u)) { 1070 if (fstr->len > 0) 1129 if (fstr->len > 0) { 1071 1130 g_string_append(fstr, ", "); 1131 } 1072 1132 1073 1133 g_string_append(fstr, tf->text); … … 1083 1143 { 1084 1144 struct twitter_data *td = ic->proto_data; 1085 char *args[2] = { "screen_name", NULL};1145 char *args[2] = { "screen_name", NULL }; 1086 1146 GString *ustr = g_string_new(""); 1087 1147 struct twitter_filter *tf; … … 1092 1152 tf = l->data; 1093 1153 1094 if (tf->type != TWITTER_FILTER_TYPE_FOLLOW || tf->uid != 0) 1154 if (tf->type != TWITTER_FILTER_TYPE_FOLLOW || tf->uid != 0) { 1095 1155 continue; 1096 1097 if (ustr->len > 0) 1156 } 1157 1158 if (ustr->len > 0) { 1098 1159 g_string_append_c(ustr, ','); 1160 } 1099 1161 1100 1162 g_string_append(ustr, tf->text); … … 1108 1170 args[1] = ustr->str; 1109 1171 req = twitter_http(ic, TWITTER_USERS_LOOKUP_URL, 1110 1111 1172 twitter_filter_users_post, 1173 ic, 0, args, 2); 1112 1174 1113 1175 g_string_free(ustr, TRUE); … … 1141 1203 twitter_get_mentions(ic, next_cursor); 1142 1204 } 1143 1205 1144 1206 return TRUE; 1145 1207 } … … 1161 1223 1162 1224 imcb_connected(ic); 1163 1225 1164 1226 if (!(td->flags & TWITTER_GOT_TIMELINE)) { 1165 1227 return; … … 1189 1251 while (output) { 1190 1252 struct twitter_xml_status *txs = output->data; 1191 if (txs->id != last_id) 1253 if (txs->id != last_id) { 1192 1254 twitter_status_show(ic, txs); 1255 } 1193 1256 last_id = txs->id; 1194 1257 output = g_slist_remove(output, txs); … … 1227 1290 1228 1291 if (twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args, 1229 1230 if (++td->http_fails >= 5) 1292 td->timeline_id ? 6 : 4) == NULL) { 1293 if (++td->http_fails >= 5) { 1231 1294 imcb_error(ic, "Could not retrieve %s: %s", 1232 1295 TWITTER_HOME_TIMELINE_URL, "connection failed"); 1296 } 1233 1297 td->flags |= TWITTER_GOT_TIMELINE; 1234 1298 twitter_flush_timeline(ic); … … 1267 1331 if (twitter_http(ic, TWITTER_MENTIONS_URL, twitter_http_get_mentions, 1268 1332 ic, 0, args, 6) == NULL) { 1269 if (++td->http_fails >= 5) 1333 if (++td->http_fails >= 5) { 1270 1334 imcb_error(ic, "Could not retrieve %s: %s", 1271 1335 TWITTER_MENTIONS_URL, "connection failed"); 1336 } 1272 1337 td->flags |= TWITTER_GOT_MENTIONS; 1273 1338 twitter_flush_timeline(ic); … … 1289 1354 1290 1355 // Check if the connection is still active. 1291 if (!g_slist_find(twitter_connections, ic)) 1292 return; 1356 if (!g_slist_find(twitter_connections, ic)) { 1357 return; 1358 } 1293 1359 1294 1360 td = ic->proto_data; … … 1298 1364 1299 1365 // The root <statuses> node should hold the list of statuses <status> 1300 if (!(parsed = twitter_parse_response(ic, req))) 1366 if (!(parsed = twitter_parse_response(ic, req))) { 1301 1367 goto end; 1368 } 1302 1369 twitter_xt_get_status_list(ic, parsed, txl); 1303 1370 json_value_free(parsed); … … 1305 1372 td->home_timeline_obj = txl; 1306 1373 1307 end: 1308 if (!g_slist_find(twitter_connections, ic)) 1309 return; 1374 end: 1375 if (!g_slist_find(twitter_connections, ic)) { 1376 return; 1377 } 1310 1378 1311 1379 td->flags |= TWITTER_GOT_TIMELINE; … … 1325 1393 1326 1394 // Check if the connection is still active. 1327 if (!g_slist_find(twitter_connections, ic)) 1328 return; 1395 if (!g_slist_find(twitter_connections, ic)) { 1396 return; 1397 } 1329 1398 1330 1399 td = ic->proto_data; … … 1334 1403 1335 1404 // The root <statuses> node should hold the list of statuses <status> 1336 if (!(parsed = twitter_parse_response(ic, req))) 1405 if (!(parsed = twitter_parse_response(ic, req))) { 1337 1406 goto end; 1407 } 1338 1408 twitter_xt_get_status_list(ic, parsed, txl); 1339 1409 json_value_free(parsed); … … 1341 1411 td->mentions_obj = txl; 1342 1412 1343 end: 1344 if (!g_slist_find(twitter_connections, ic)) 1345 return; 1413 end: 1414 if (!g_slist_find(twitter_connections, ic)) { 1415 return; 1416 } 1346 1417 1347 1418 td->flags |= TWITTER_GOT_MENTIONS; … … 1361 1432 1362 1433 // Check if the connection is still active. 1363 if (!g_slist_find(twitter_connections, ic)) 1364 return; 1434 if (!g_slist_find(twitter_connections, ic)) { 1435 return; 1436 } 1365 1437 1366 1438 td = ic->proto_data; 1367 1439 td->last_status_id = 0; 1368 1440 1369 if (!(parsed = twitter_parse_response(ic, req))) 1370 return; 1371 1441 if (!(parsed = twitter_parse_response(ic, req))) { 1442 return; 1443 } 1444 1372 1445 if ((id = json_o_get(parsed, "id")) && id->type == json_integer) { 1373 1446 td->last_status_id = id->u.integer; 1374 1447 } 1375 1448 1376 1449 json_value_free(parsed); 1377 1378 if (req->flags & TWITTER_HTTP_USER_ACK) 1450 1451 if (req->flags & TWITTER_HTTP_USER_ACK) { 1379 1452 twitter_log(ic, "Command processed successfully"); 1453 } 1380 1454 } 1381 1455 … … 1390 1464 g_strdup_printf("%" G_GUINT64_FORMAT, in_reply_to) 1391 1465 }; 1466 1392 1467 twitter_http(ic, TWITTER_STATUS_UPDATE_URL, twitter_http_post, ic, 1, 1393 1468 args, in_reply_to ? 4 : 2); 1394 1469 g_free(args[3]); 1395 1470 } … … 1402 1477 { 1403 1478 char *args[4]; 1479 1404 1480 args[0] = "screen_name"; 1405 1481 args[1] = who; … … 1413 1489 { 1414 1490 char *args[2]; 1491 1415 1492 args[0] = "screen_name"; 1416 1493 args[1] = who; 1417 1494 twitter_http(ic, create ? TWITTER_FRIENDSHIPS_CREATE_URL : TWITTER_FRIENDSHIPS_DESTROY_URL, 1418 1495 twitter_http_post, ic, 1, args, 2); 1419 1496 } 1420 1497 … … 1422 1499 { 1423 1500 char *url; 1501 1424 1502 url = g_strdup_printf("%s%" G_GUINT64_FORMAT "%s", 1425 1503 TWITTER_STATUS_DESTROY_URL, id, ".json"); … … 1432 1510 { 1433 1511 char *url; 1512 1434 1513 url = g_strdup_printf("%s%" G_GUINT64_FORMAT "%s", 1435 1514 TWITTER_STATUS_RETWEET_URL, id, ".json"); … … 1448 1527 NULL, 1449 1528 }; 1529 1450 1530 args[1] = screen_name; 1451 1531 twitter_http_f(ic, TWITTER_REPORT_SPAM_URL, twitter_http_post, … … 1462 1542 NULL, 1463 1543 }; 1544 1464 1545 args[1] = g_strdup_printf("%" G_GUINT64_FORMAT, id); 1465 1546 twitter_http_f(ic, TWITTER_FAVORITE_CREATE_URL, twitter_http_post,
Note: See TracChangeset
for help on using the changeset viewer.