Changeset 6e9ae72 for protocols/twitter/twitter_lib.c
- Timestamp:
- 2011-12-17T13:50:01Z (13 years ago)
- Branches:
- master
- Children:
- 18c6d36
- Parents:
- 87dddee (diff), 17f057d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/twitter/twitter_lib.c
r87dddee r6e9ae72 78 78 if (txu == NULL) 79 79 return; 80 80 81 g_free(txu->name); 81 82 g_free(txu->screen_name); … … 83 84 } 84 85 85 86 86 /** 87 87 * Frees a twitter_xml_status struct. … … 89 89 static void txs_free(struct twitter_xml_status *txs) 90 90 { 91 if (txs == NULL) 92 return; 93 91 94 g_free(txs->text); 92 95 txu_free(txs->user); … … 103 106 if (txl == NULL) 104 107 return; 105 for (l = txl->list; l; l = g_slist_next(l)) 106 if (txl->type == TXL_STATUS) 108 109 for (l = txl->list; l; l = g_slist_next(l)) { 110 if (txl->type == TXL_STATUS) { 107 111 txs_free((struct twitter_xml_status *) l->data); 108 else if (txl->type == TXL_ID)112 } else if (txl->type == TXL_ID) { 109 113 g_free(l->data); 110 else if (txl->type == TXL_USER)114 } else if (txl->type == TXL_USER) { 111 115 txu_free(l->data); 116 } 117 } 118 112 119 g_slist_free(txl->list); 113 120 g_free(txl); … … 115 122 116 123 /** 117 * Add a buddy if it is not allready added, set the status to logged in. 124 * Compare status elements 125 */ 126 static gint twitter_compare_elements(gconstpointer a, gconstpointer b) 127 { 128 struct twitter_xml_status *a_status = (struct twitter_xml_status *) a; 129 struct twitter_xml_status *b_status = (struct twitter_xml_status *) b; 130 131 if (a_status->created_at < b_status->created_at) { 132 return -1; 133 } else if (a_status->created_at > b_status->created_at) { 134 return 1; 135 } else { 136 return 0; 137 } 138 } 139 140 /** 141 * Add a buddy if it is not already added, set the status to logged in. 118 142 */ 119 143 static void twitter_add_buddy(struct im_connection *ic, char *name, const char *fullname) … … 132 156 exact Twitter username. */ 133 157 imcb_buddy_nick_hint(ic, name, name); 134 imcb_chat_add_buddy(td-> home_timeline_gc, name);158 imcb_chat_add_buddy(td->timeline_gc, name); 135 159 } else if (g_strcasecmp(mode, "many") == 0) 136 160 imcb_buddy_status(ic, name, OPT_LOGGED_IN, NULL, NULL); … … 260 284 261 285 /* Create the room now that we "logged in". */ 262 if (!td-> home_timeline_gc && g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0)286 if (!td->timeline_gc && g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0) 263 287 twitter_groupchat_init(ic); 264 288 … … 436 460 { 437 461 struct xt_node *child, *rt = NULL; 438 gboolean truncated = FALSE;439 462 440 463 // Walk over the nodes children. … … 442 465 if (g_strcasecmp("text", child->name) == 0) { 443 466 txs->text = g_memdup(child->text, child->text_len + 1); 444 } else if (g_strcasecmp("truncated", child->name) == 0 && child->text) {445 truncated = bool2int(child->text);446 467 } else if (g_strcasecmp("retweeted_status", child->name) == 0) { 447 468 rt = child; … … 464 485 } 465 486 466 /* If it's a truncated retweet, get the original because dots suck. */ 467 if (truncated && rt) { 487 /* If it's a (truncated) retweet, get the original. Even if the API claims it 488 wasn't truncated because it may be lying. */ 489 if (rt) { 468 490 struct twitter_xml_status *rtxs = g_new0(struct twitter_xml_status, 1); 469 491 if (twitter_xt_get_status(rt, rtxs) != XT_HANDLED) { … … 475 497 txs->text = g_strdup_printf("RT @%s: %s", rtxs->user->screen_name, rtxs->text); 476 498 txs_free(rtxs); 499 } else { 500 struct xt_node *urls, *url; 501 502 urls = xt_find_path(node, "entities/urls"); 503 for (url = urls ? urls->children : NULL; url; url = url->next) { 504 /* "short" is a reserved word. :-P */ 505 struct xt_node *kort = xt_find_node(url->children, "url"); 506 struct xt_node *disp = xt_find_node(url->children, "display_url"); 507 char *pos, *new; 508 509 if (!kort || !kort->text || !disp || !disp->text || 510 !(pos = strstr(txs->text, kort->text))) 511 continue; 512 513 *pos = '\0'; 514 new = g_strdup_printf("%s%s <%s>%s", txs->text, kort->text, 515 disp->text, pos + strlen(kort->text)); 516 517 g_free(txs->text); 518 txs->text = new; 519 } 477 520 } 478 521 … … 520 563 521 564 return XT_HANDLED; 522 }523 524 static void twitter_http_get_home_timeline(struct http_request *req);525 526 /**527 * Get the timeline.528 */529 void twitter_get_home_timeline(struct im_connection *ic, gint64 next_cursor)530 {531 struct twitter_data *td = ic->proto_data;532 533 char *args[4];534 args[0] = "cursor";535 args[1] = g_strdup_printf("%lld", (long long) next_cursor);536 if (td->home_timeline_id) {537 args[2] = "since_id";538 args[3] = g_strdup_printf("%llu", (long long unsigned int) td->home_timeline_id);539 }540 541 twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args,542 td->home_timeline_id ? 4 : 2);543 544 g_free(args[1]);545 if (td->home_timeline_id) {546 g_free(args[3]);547 }548 565 } 549 566 … … 586 603 GSList *l; 587 604 588 td-> home_timeline_gc = gc = imcb_chat_new(ic, "home/timeline");605 td->timeline_gc = gc = imcb_chat_new(ic, "twitter/timeline"); 589 606 590 607 name_hint = g_strdup_printf("%s_%s", td->prefix, ic->acc->user); … … 595 612 bee_user_t *bu = l->data; 596 613 if (bu->ic == ic) 597 imcb_chat_add_buddy(td-> home_timeline_gc, bu->handle);614 imcb_chat_add_buddy(td->timeline_gc, bu->handle); 598 615 } 599 616 } … … 608 625 struct twitter_xml_status *status; 609 626 struct groupchat *gc; 627 guint64 last_id = 0; 610 628 611 629 // Create a new groupchat if it does not exsist. 612 if (!td-> home_timeline_gc)630 if (!td->timeline_gc) 613 631 twitter_groupchat_init(ic); 614 632 615 gc = td-> home_timeline_gc;633 gc = td->timeline_gc; 616 634 if (!gc->joined) 617 635 imcb_chat_add_buddy(gc, ic->acc->user); … … 621 639 622 640 status = l->data; 623 if (status->user == NULL || status->text == NULL )641 if (status->user == NULL || status->text == NULL || last_id == status->id) 624 642 continue; 625 643 626 twitter_add_buddy(ic, status->user->screen_name, status->user->name);644 last_id = status->id; 627 645 628 646 strip_html(status->text); 647 629 648 msg = twitter_msg_add_id(ic, status, ""); 630 649 631 650 // Say it! 632 if (g_strcasecmp(td->user, status->user->screen_name) == 0) 651 if (g_strcasecmp(td->user, status->user->screen_name) == 0) { 633 652 imcb_chat_log(gc, "You: %s", msg ? msg : status->text); 634 else 653 } else { 654 twitter_add_buddy(ic, status->user->screen_name, status->user->name); 655 635 656 imcb_chat_msg(gc, status->user->screen_name, 636 657 msg ? msg : status->text, 0, status->created_at); 658 } 637 659 638 660 g_free(msg); 639 661 640 // Update the home_timeline_id to hold the highest id, so that by the next request662 // Update the timeline_id to hold the highest id, so that by the next request 641 663 // we won't pick up the updates already in the list. 642 td-> home_timeline_id = MAX(td->home_timeline_id, status->id);664 td->timeline_id = MAX(td->timeline_id, status->id); 643 665 } 644 666 } … … 654 676 char from[MAX_STRING]; 655 677 gboolean mode_one; 678 guint64 last_id = 0; 656 679 657 680 mode_one = g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "one") == 0; … … 666 689 667 690 status = l->data; 691 if (status->user == NULL || status->text == NULL || last_id == status->id) 692 continue; 693 694 last_id = status->id; 668 695 669 696 strip_html(status->text); … … 680 707 text ? text : status->text, 0, status->created_at); 681 708 682 // Update the home_timeline_id to hold the highest id, so that by the next request709 // Update the timeline_id to hold the highest id, so that by the next request 683 710 // we won't pick up the updates already in the list. 684 td-> home_timeline_id = MAX(td->home_timeline_id, status->id);711 td->timeline_id = MAX(td->timeline_id, status->id); 685 712 686 713 g_free(text); 687 714 g_free(prefix); 715 } 716 } 717 718 static void twitter_http_get_home_timeline(struct http_request *req); 719 static void twitter_http_get_mentions(struct http_request *req); 720 721 /** 722 * Get the timeline with optionally mentions 723 */ 724 void twitter_get_timeline(struct im_connection *ic, gint64 next_cursor) 725 { 726 struct twitter_data *td = ic->proto_data; 727 gboolean include_mentions = set_getbool(&ic->acc->set, "fetch_mentions"); 728 729 if (td->flags & TWITTER_DOING_TIMELINE) { 730 return; 731 } 732 733 td->flags |= TWITTER_DOING_TIMELINE; 734 735 twitter_get_home_timeline(ic, next_cursor); 736 737 if (include_mentions) { 738 twitter_get_mentions(ic, next_cursor); 739 } 740 } 741 742 /** 743 * Call this one after receiving timeline/mentions. Show to user once we have 744 * both. 745 */ 746 void twitter_flush_timeline(struct im_connection *ic) 747 { 748 struct twitter_data *td = ic->proto_data; 749 gboolean include_mentions = set_getbool(&ic->acc->set, "fetch_mentions"); 750 gboolean show_old_mentions = set_getbool(&ic->acc->set, "show_old_mentions"); 751 struct twitter_xml_list *home_timeline = td->home_timeline_obj; 752 struct twitter_xml_list *mentions = td->mentions_obj; 753 GSList *output = NULL; 754 GSList *l; 755 756 if (!(td->flags & TWITTER_GOT_TIMELINE)) { 757 return; 758 } 759 760 if (include_mentions && !(td->flags & TWITTER_GOT_MENTIONS)) { 761 return; 762 } 763 764 if (home_timeline && home_timeline->list) { 765 for (l = home_timeline->list; l; l = g_slist_next(l)) { 766 output = g_slist_insert_sorted(output, l->data, twitter_compare_elements); 767 } 768 } 769 770 if (include_mentions && mentions && mentions->list) { 771 for (l = mentions->list; l; l = g_slist_next(l)) { 772 if (!show_old_mentions && output && twitter_compare_elements(l->data, output->data) < 0) { 773 continue; 774 } 775 776 output = g_slist_insert_sorted(output, l->data, twitter_compare_elements); 777 } 778 } 779 780 // See if the user wants to see the messages in a groupchat window or as private messages. 781 if (g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0) 782 twitter_groupchat(ic, output); 783 else 784 twitter_private_message_chat(ic, output); 785 786 g_slist_free(output); 787 788 if (home_timeline && home_timeline->list) { 789 txl_free(home_timeline); 790 } 791 792 if (mentions && mentions->list) { 793 txl_free(mentions); 794 } 795 796 td->flags &= ~(TWITTER_DOING_TIMELINE | TWITTER_GOT_TIMELINE | TWITTER_GOT_MENTIONS); 797 } 798 799 /** 800 * Get the timeline. 801 */ 802 void twitter_get_home_timeline(struct im_connection *ic, gint64 next_cursor) 803 { 804 struct twitter_data *td = ic->proto_data; 805 806 td->home_timeline_obj = NULL; 807 td->flags &= ~TWITTER_GOT_TIMELINE; 808 809 char *args[6]; 810 args[0] = "cursor"; 811 args[1] = g_strdup_printf("%lld", (long long) next_cursor); 812 args[2] = "include_entities"; 813 args[3] = "true"; 814 if (td->timeline_id) { 815 args[4] = "since_id"; 816 args[5] = g_strdup_printf("%llu", (long long unsigned int) td->timeline_id); 817 } 818 819 if (twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args, 820 td->timeline_id ? 6 : 4) == NULL) { 821 if (++td->http_fails >= 5) 822 imcb_error(ic, "Could not retrieve %s: %s", 823 TWITTER_HOME_TIMELINE_URL, "connection failed"); 824 td->flags |= TWITTER_GOT_TIMELINE; 825 twitter_flush_timeline(ic); 826 } 827 828 g_free(args[1]); 829 if (td->timeline_id) { 830 g_free(args[5]); 831 } 832 } 833 834 /** 835 * Get mentions. 836 */ 837 void twitter_get_mentions(struct im_connection *ic, gint64 next_cursor) 838 { 839 struct twitter_data *td = ic->proto_data; 840 841 td->mentions_obj = NULL; 842 td->flags &= ~TWITTER_GOT_MENTIONS; 843 844 char *args[6]; 845 args[0] = "cursor"; 846 args[1] = g_strdup_printf("%lld", (long long) next_cursor); 847 args[2] = "include_entities"; 848 args[3] = "true"; 849 if (td->timeline_id) { 850 args[4] = "since_id"; 851 args[5] = g_strdup_printf("%llu", (long long unsigned int) td->timeline_id); 852 } 853 854 if (twitter_http(ic, TWITTER_MENTIONS_URL, twitter_http_get_mentions, ic, 0, args, 855 td->timeline_id ? 6 : 4) == NULL) { 856 if (++td->http_fails >= 5) 857 imcb_error(ic, "Could not retrieve %s: %s", 858 TWITTER_MENTIONS_URL, "connection failed"); 859 td->flags |= TWITTER_GOT_MENTIONS; 860 twitter_flush_timeline(ic); 861 } 862 863 g_free(args[1]); 864 if (td->timeline_id) { 865 g_free(args[5]); 688 866 } 689 867 } … … 713 891 imcb_error(ic, "Authentication failure"); 714 892 imc_logout(ic, FALSE); 715 return;893 goto end; 716 894 } else { 717 895 // It didn't go well, output the error and return. … … 720 898 TWITTER_HOME_TIMELINE_URL, twitter_parse_error(req)); 721 899 722 return;900 goto end; 723 901 } 724 902 … … 733 911 xt_free(parser); 734 912 735 // See if the user wants to see the messages in a groupchat window or as private messages. 736 if (txl->list == NULL); 737 else if (g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0) 738 twitter_groupchat(ic, txl->list); 739 else 740 twitter_private_message_chat(ic, txl->list); 741 742 // Free the structure. 743 txl_free(txl); 913 td->home_timeline_obj = txl; 914 915 end: 916 td->flags |= TWITTER_GOT_TIMELINE; 917 918 twitter_flush_timeline(ic); 919 } 920 921 /** 922 * Callback for getting mentions. 923 */ 924 static void twitter_http_get_mentions(struct http_request *req) 925 { 926 struct im_connection *ic = req->data; 927 struct twitter_data *td; 928 struct xt_parser *parser; 929 struct twitter_xml_list *txl; 930 931 // Check if the connection is still active. 932 if (!g_slist_find(twitter_connections, ic)) 933 return; 934 935 td = ic->proto_data; 936 937 // Check if the HTTP request went well. 938 if (req->status_code == 200) { 939 td->http_fails = 0; 940 if (!(ic->flags & OPT_LOGGED_IN)) 941 imcb_connected(ic); 942 } else if (req->status_code == 401) { 943 imcb_error(ic, "Authentication failure"); 944 imc_logout(ic, FALSE); 945 goto end; 946 } else { 947 // It didn't go well, output the error and return. 948 if (++td->http_fails >= 5) 949 imcb_error(ic, "Could not retrieve %s: %s", 950 TWITTER_MENTIONS_URL, twitter_parse_error(req)); 951 952 goto end; 953 } 954 955 txl = g_new0(struct twitter_xml_list, 1); 956 txl->list = NULL; 957 958 // Parse the data. 959 parser = xt_new(NULL, txl); 960 xt_feed(parser, req->reply_body, req->body_size); 961 // The root <statuses> node should hold the list of statuses <status> 962 twitter_xt_get_status_list(ic, parser->root, txl); 963 xt_free(parser); 964 965 td->mentions_obj = txl; 966 967 end: 968 td->flags |= TWITTER_GOT_MENTIONS; 969 970 twitter_flush_timeline(ic); 744 971 } 745 972
Note: See TracChangeset
for help on using the changeset viewer.