- Timestamp:
- 2016-11-20T08:40:36Z (8 years ago)
- Children:
- 3f44e43
- Parents:
- ba52ac5 (diff), 9f03c47 (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. - Location:
- protocols
- Files:
-
- 27 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/account.c
rba52ac5 r537d9b9 63 63 64 64 s = set_add(&a->set, "password", NULL, set_eval_account, a); 65 s->flags |= SET_NOSAVE | SET_NULL_OK | SET_PASSWORD ;65 s->flags |= SET_NOSAVE | SET_NULL_OK | SET_PASSWORD | ACC_SET_LOCKABLE; 66 66 67 67 s = set_add(&a->set, "tag", NULL, set_eval_account, a); … … 69 69 70 70 s = set_add(&a->set, "username", NULL, set_eval_account, a); 71 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY ;71 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY | ACC_SET_LOCKABLE; 72 72 set_setstr(&a->set, "username", user); 73 73 -
protocols/account.h
rba52ac5 r537d9b9 61 61 ACC_SET_OFFLINE_ONLY = 0x02, /* Allow changes only if the acct is offline. */ 62 62 ACC_SET_ONLINE_ONLY = 0x04, /* Allow changes only if the acct is online. */ 63 ACC_SET_LOCKABLE = 0x08 /* Setting cannot be changed if the account is locked down */ 63 64 } account_set_flag_t; 64 65 … … 68 69 ACC_FLAG_HANDLE_DOMAINS = 0x04, /* Contact handles need a domain portion. */ 69 70 ACC_FLAG_LOCAL_CONTACTS = 0x08, /* Contact list is local. */ 71 ACC_FLAG_LOCKED = 0x10, /* Account is locked (cannot be deleted, certain settings can't changed) */ 70 72 } account_flag_t; 71 73 -
protocols/bee.h
rba52ac5 r537d9b9 84 84 } bee_user_t; 85 85 86 typedef struct bee_chat_info { 87 char *title; 88 char *topic; 89 } bee_chat_info_t; 90 86 91 /* This one's mostly used so save space and make it easier (cheaper) to 87 92 compare groups of contacts, etc. */ … … 131 136 132 137 void (*log)(bee_t *bee, const char *tag, const char *msg); 138 gboolean (*user_nick_change)(bee_t *bee, bee_user_t *bu, const char *hint); 133 139 } bee_ui_funcs_t; 134 140 … … 184 190 G_MODULE_EXPORT void imcb_chat_invite(struct im_connection *ic, const char *name, const char *who, const char *msg); 185 191 192 G_GNUC_DEPRECATED G_MODULE_EXPORT void bee_chat_list_finish(struct im_connection *ic); 193 G_MODULE_EXPORT void imcb_chat_list_finish(struct im_connection *ic); 194 G_MODULE_EXPORT void imcb_chat_list_free(struct im_connection *ic); 195 186 196 #endif /* __BEE_H__ */ -
protocols/bee_chat.c
rba52ac5 r537d9b9 274 274 } 275 275 } 276 277 void imcb_chat_list_finish(struct im_connection *ic) 278 { 279 cmd_chat_list_finish(ic); 280 } 281 282 void bee_chat_list_finish(struct im_connection *ic) 283 { 284 imcb_log(ic, "Warning: using deprecated bee_chat_list_finish. This will be removed in the stable release."); 285 imcb_chat_list_finish(ic); 286 } 287 288 void imcb_chat_list_free(struct im_connection *ic) 289 { 290 bee_chat_info_t *ci; 291 GSList *l = ic->chatlist; 292 293 while (l) { 294 ci = l->data; 295 l = g_slist_delete_link(l, l); 296 297 g_free(ci->title); 298 g_free(ci->topic); 299 g_free(ci); 300 } 301 302 ic->chatlist = NULL; 303 } -
protocols/bee_ft.c
rba52ac5 r537d9b9 31 31 bee_user_t *bu = bee_user_by_handle(bee, ic, handle); 32 32 33 if (bee->ui->ft_in_start ) {33 if (bee->ui->ft_in_start && bu) { 34 34 return bee->ui->ft_in_start(bee, bu, file_name, file_size); 35 35 } else { -
protocols/jabber/conference.c
rba52ac5 r537d9b9 28 28 static xt_status jabber_chat_self_message(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 29 29 30 struct groupchat *jabber_chat_join(struct im_connection *ic, const char *room, const char *nick, const char *password) 30 struct groupchat *jabber_chat_join(struct im_connection *ic, const char *room, const char *nick, const char *password, 31 gboolean always_use_nicks) 31 32 { 32 33 struct jabber_chat *jc; … … 57 58 g_free(jc); 58 59 return NULL; 60 } 61 62 if (always_use_nicks) { 63 jc->flags = JCFLAG_ALWAYS_USE_NICKS; 59 64 } 60 65 … … 95 100 g_free(cserv); 96 101 97 c = jabber_chat_join(ic, rjid, jd->username, NULL );102 c = jabber_chat_join(ic, rjid, jd->username, NULL, FALSE); 98 103 g_free(rjid); 99 104 if (c == NULL) { … … 244 249 } 245 250 251 static int jabber_chat_has_other_resources(struct im_connection *ic, struct jabber_buddy *bud) 252 { 253 struct jabber_buddy *cur; 254 255 for (cur = jabber_buddy_by_jid(ic, bud->bare_jid, GET_BUDDY_FIRST); cur; cur = cur->next) { 256 if (cur != bud && jabber_compare_jid(cur->ext_jid, bud->ext_jid)) { 257 return TRUE; 258 } 259 } 260 261 return FALSE; 262 } 263 246 264 /* Not really the same syntax as the normal pkt_ functions, but this isn't 247 265 called by the xmltree parser directly and this way I can add some extra … … 328 346 *s = 0; /* Should NEVER be NULL, but who knows... */ 329 347 } 348 349 if (bud != jc->me && (jc->flags & JCFLAG_ALWAYS_USE_NICKS) && !(bud->flags & JBFLAG_IS_ANONYMOUS)) { 350 imcb_buddy_nick_change(ic, bud->ext_jid, bud->resource); 351 } 352 330 353 imcb_chat_add_buddy(chat, bud->ext_jid); 331 354 if (s) { … … 333 356 } 334 357 } else if (type) { /* type can only be NULL or "unavailable" in this function */ 335 if ((bud->flags & JBFLAG_IS_CHATROOM) && bud->ext_jid ) {358 if ((bud->flags & JBFLAG_IS_CHATROOM) && bud->ext_jid && !jabber_chat_has_other_resources(ic, bud)) { 336 359 char *reason = NULL; 337 360 char *status = NULL; … … 443 466 444 467 if (subject && chat) { 445 char *subject_text = subject->text_len > 0 ? subject->text : ""; 468 char empty[1] = ""; 469 char *subject_text = subject->text_len > 0 ? subject->text : empty; 446 470 if (g_strcmp0(chat->topic, subject_text) != 0) { 447 471 bare_jid = (bud) ? jabber_get_bare_jid(bud->ext_jid) : NULL; … … 479 503 bare_jid = jabber_get_bare_jid(bud->ext_jid ? bud->ext_jid : bud->full_jid); 480 504 final_from = bare_jid; 481 flags = (bud == jc->me) ? OPT_SELFMESSAGE : 0; 505 if (bud == jc->me || (g_strcasecmp(final_from, ic->acc->user) == 0)) { 506 flags = OPT_SELFMESSAGE; 507 } 482 508 } else { 483 509 final_from = nick; -
protocols/jabber/iq.c
rba52ac5 r537d9b9 67 67 xt_add_child(reply, xt_new_node("name", set_getstr(&ic->acc->set, "user_agent"), NULL)); 68 68 xt_add_child(reply, xt_new_node("version", BITLBEE_VERSION, NULL)); 69 xt_add_child(reply, xt_new_node("os", ARCH, NULL));70 69 } else if (strcmp(s, XMLNS_TIME_OLD) == 0) { 71 70 time_t time_ep; … … 234 233 imcb_log(ic, "Warning: Received incomplete IQ packet while authenticating"); 235 234 imc_logout(ic, FALSE); 236 return XT_ HANDLED;235 return XT_ABORT; 237 236 } 238 237 … … 287 286 imcb_log(ic, "Warning: Received incomplete IQ packet while authenticating"); 288 287 imc_logout(ic, FALSE); 289 return XT_ HANDLED;288 return XT_ABORT; 290 289 } 291 290 … … 1060 1059 return XT_HANDLED; 1061 1060 } 1061 1062 xt_status jabber_iq_disco_muc_response(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 1063 1064 int jabber_iq_disco_muc(struct im_connection *ic, const char *muc_server) 1065 { 1066 struct xt_node *node; 1067 int st; 1068 1069 node = xt_new_node("query", NULL, NULL); 1070 xt_add_attr(node, "xmlns", XMLNS_DISCO_ITEMS); 1071 node = jabber_make_packet("iq", "get", (char *) muc_server, node); 1072 1073 jabber_cache_add(ic, node, jabber_iq_disco_muc_response); 1074 st = jabber_write_packet(ic, node); 1075 1076 return st; 1077 } 1078 1079 xt_status jabber_iq_disco_muc_response(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 1080 { 1081 struct xt_node *query, *c; 1082 struct jabber_error *err; 1083 GSList *rooms = NULL; 1084 1085 if ((err = jabber_error_parse(xt_find_node(node->children, "error"), XMLNS_STANZA_ERROR))) { 1086 imcb_error(ic, "The server replied with an error: %s%s%s", 1087 err->code, err->text ? ": " : "", err->text ? err->text : ""); 1088 jabber_error_free(err); 1089 return XT_HANDLED; 1090 } 1091 1092 if (!(query = xt_find_node(node->children, "query"))) { 1093 imcb_error(ic, "Received incomplete MUC list reply"); 1094 return XT_HANDLED; 1095 } 1096 1097 c = query->children; 1098 while ((c = xt_find_node(c, "item"))) { 1099 char *jid = xt_find_attr(c, "jid"); 1100 1101 if (!jid || !strchr(jid, '@')) { 1102 c = c->next; 1103 continue; 1104 } 1105 1106 bee_chat_info_t *ci = g_new(bee_chat_info_t, 1); 1107 ci->title = g_strdup(xt_find_attr(c, "jid")); 1108 ci->topic = g_strdup(xt_find_attr(c, "name")); 1109 rooms = g_slist_prepend(rooms, ci); 1110 1111 c = c->next; 1112 } 1113 1114 imcb_chat_list_free(ic); 1115 ic->chatlist = g_slist_reverse(rooms); 1116 imcb_chat_list_finish(ic); 1117 1118 return XT_HANDLED; 1119 } -
protocols/jabber/jabber.c
rba52ac5 r537d9b9 82 82 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK; 83 83 84 set_add(&acc->set, "oauth", "false", set_eval_oauth, acc); 85 84 86 if (strcmp(acc->prpl->name, "hipchat") == 0) { 85 87 set_setstr(&acc->set, "server", "chat.hipchat.com"); 86 88 } else { 87 set_add(&acc->set, "oauth", "false", set_eval_oauth, acc);88 89 89 /* this reuses set_eval_oauth, which clears the password */ 90 90 set_add(&acc->set, "anonymous", "false", set_eval_oauth, acc); … … 321 321 struct jabber_data *jd = ic->proto_data; 322 322 323 imcb_chat_list_free(ic); 324 323 325 while (jd->filetransfers) { 324 326 imcb_file_canceled(ic, (( struct jabber_transfer *) jd->filetransfers->data)->ft, "Logging out"); … … 397 399 if (g_strcasecmp(who, JABBER_OAUTH_HANDLE) == 0 && 398 400 !(jd->flags & OPT_LOGGED_IN) && jd->fd == -1) { 399 if (sasl_oauth2_get_refresh_token(ic, message)) { 401 402 if (jd->flags & JFLAG_HIPCHAT) { 403 sasl_oauth2_got_token(ic, message, NULL, NULL); 404 return 1; 405 } else if (sasl_oauth2_get_refresh_token(ic, message)) { 400 406 return 1; 401 407 } else { … … 577 583 } else { 578 584 /* jabber_chat_join without the underscore is the conference.c one */ 579 return jabber_chat_join(ic, room, final_nick, set_getstr(sets, "password")); 585 return jabber_chat_join(ic, room, final_nick, set_getstr(sets, "password"), 586 set_getbool(sets, "always_use_nicks")); 580 587 } 581 588 … … 586 593 { 587 594 return jabber_chat_with(ic, who); 595 } 596 597 static void jabber_chat_list_(struct im_connection *ic, const char *server) 598 { 599 struct jabber_data *jd = ic->proto_data; 600 601 if (server && *server) { 602 jabber_iq_disco_muc(ic, server); 603 } else if (jd->muc_host && *jd->muc_host) { 604 jabber_iq_disco_muc(ic, jd->muc_host); 605 } else { 606 /* throw an error here, don't query conference.[server] directly. 607 * for things like jabber.org it gets you 18000 results of garbage */ 608 imcb_error(ic, "Please specify a server name such as `conference.%s'", jd->server); 609 } 588 610 } 589 611 … … 686 708 void jabber_chat_add_settings(account_t *acc, set_t **head) 687 709 { 710 set_add(head, "always_use_nicks", "false", set_eval_bool, NULL); 711 688 712 /* Meh. Stupid room passwords. Not trying to obfuscate/hide 689 713 them from the user for now. */ … … 693 717 void jabber_chat_free_settings(account_t *acc, set_t **head) 694 718 { 719 set_del(head, "always_use_nicks"); 720 695 721 set_del(head, "password"); 696 722 } … … 759 785 ret->chat_join = jabber_chat_join_; 760 786 ret->chat_with = jabber_chat_with_; 787 ret->chat_list = jabber_chat_list_; 761 788 ret->chat_add_settings = jabber_chat_add_settings; 762 789 ret->chat_free_settings = jabber_chat_free_settings; -
protocols/jabber/jabber.h
rba52ac5 r537d9b9 75 75 JCFLAG_MESSAGE_SENT = 1, /* Set this after sending the first message, so 76 76 we can detect echoes/backlogs. */ 77 JCFLAG_ALWAYS_USE_NICKS = 2, 77 78 } jabber_chat_flags_t; 78 79 … … 262 263 void jabber_iq_version_send(struct im_connection *ic, struct jabber_buddy *bud, void *data); 263 264 int jabber_iq_disco_server(struct im_connection *ic); 265 int jabber_iq_disco_muc(struct im_connection *ic, const char *muc_server); 264 266 265 267 /* si.c */ … … 339 341 int sasl_oauth2_get_refresh_token(struct im_connection *ic, const char *msg); 340 342 int sasl_oauth2_refresh(struct im_connection *ic, const char *refresh_token); 343 void sasl_oauth2_got_token(gpointer data, const char *access_token, const char *refresh_token, const char *error); 341 344 342 345 extern const struct oauth2_service oauth2_service_google; 343 346 344 347 /* conference.c */ 345 struct groupchat *jabber_chat_join(struct im_connection *ic, const char *room, const char *nick, const char *password); 348 struct groupchat *jabber_chat_join(struct im_connection *ic, const char *room, const char *nick, const char *password, 349 gboolean always_use_nicks); 346 350 struct groupchat *jabber_chat_with(struct im_connection *ic, char *who); 347 351 struct groupchat *jabber_chat_by_jid(struct im_connection *ic, const char *name); -
protocols/jabber/jabber_util.c
rba52ac5 r537d9b9 315 315 int i; 316 316 317 if (!jid1 || !jid2) { 318 return FALSE; 319 } 320 317 321 for (i = 0;; i++) { 318 322 if (jid1[i] == '\0' || jid1[i] == '/' || jid2[i] == '\0' || jid2[i] == '/') { -
protocols/jabber/message.c
rba52ac5 r537d9b9 27 27 { 28 28 struct im_connection *ic = data; 29 struct jabber_data *jd = ic->proto_data;30 29 char *from = xt_find_attr(node, carbons_sent ? "to" : "from"); 31 30 char *type = xt_find_attr(node, "type"); … … 38 37 if (!from) { 39 38 return XT_HANDLED; /* Consider this packet corrupted. */ 40 }41 42 /* try to detect hipchat's own version of self-messages */43 if (jd->flags & JFLAG_HIPCHAT) {44 struct xt_node *c;45 46 if ((c = xt_find_node_by_attr(node->children, "delay", "xmlns", XMLNS_DELAY)) &&47 (s = xt_find_attr(c, "from_jid")) &&48 jabber_compare_jid(s, jd->me)) {49 carbons_sent = TRUE;50 }51 39 } 52 40 -
protocols/jabber/presence.c
rba52ac5 r537d9b9 222 222 cap = xt_new_node("c", NULL, NULL); 223 223 xt_add_attr(cap, "xmlns", XMLNS_CAPS); 224 225 if (jd->flags & JFLAG_HIPCHAT) { 226 /* hipchat specific node, whitelisted by request to receive self-messages */ 227 xt_add_attr(cap, "node", "http://bitlbee.org/xmpp/caps/hipchat"); 228 } else { 229 xt_add_attr(cap, "node", "http://bitlbee.org/xmpp/caps"); 230 } 224 xt_add_attr(cap, "node", "http://bitlbee.org/xmpp/caps"); 231 225 xt_add_attr(cap, "ver", BITLBEE_VERSION); /* The XEP wants this hashed, but nobody's doing that. */ 232 226 xt_add_child(node, cap); -
protocols/jabber/s5bytestream.c
rba52ac5 r537d9b9 928 928 proxy = next; 929 929 } 930 931 g_free(proxysetting); 930 932 } 931 933 -
protocols/jabber/sasl.c
rba52ac5 r537d9b9 39 39 }; 40 40 41 /* """"""""""""""""""""""""""""""oauth"""""""""""""""""""""""""""""" */ 42 #define HIPCHAT_SO_CALLED_OAUTH_URL "https://hipchat.com/account/api" 43 41 44 xt_status sasl_pkt_mechanisms(struct xt_node *node, gpointer data) 42 45 { … … 45 48 struct xt_node *c, *reply; 46 49 char *s; 47 int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_anonymous = 0 ;50 int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_anonymous = 0, sup_hipchat_oauth = 0; 48 51 int want_oauth = FALSE, want_hipchat = FALSE, want_anonymous = FALSE; 49 52 GString *mechs; … … 80 83 } else if (c->text && g_strcasecmp(c->text, "X-OAUTH2") == 0) { 81 84 sup_gtalk = 1; 85 } else if (c->text && g_strcasecmp(c->text, "X-HIPCHAT-OAUTH2") == 0) { 86 sup_hipchat_oauth = 1; 82 87 } 83 88 … … 90 95 91 96 if (!want_oauth && !sup_plain && !sup_digest) { 92 if ( !sup_gtalk) {97 if (sup_gtalk || sup_hipchat_oauth) { 93 98 imcb_error(ic, "This server requires OAuth " 94 99 "(supported schemes:%s)", mechs->str); … … 110 115 } 111 116 112 if (sup_gtalk && want_oauth) { 113 int len; 114 115 /* X-OAUTH2 is, not *the* standard OAuth2 SASL/XMPP implementation. 116 It's currently used by GTalk and vaguely documented on 117 http://code.google.com/apis/cloudprint/docs/rawxmpp.html . */ 118 xt_add_attr(reply, "mechanism", "X-OAUTH2"); 119 120 len = strlen(jd->username) + strlen(jd->oauth2_access_token) + 2; 121 s = g_malloc(len + 1); 122 s[0] = 0; 123 strcpy(s + 1, jd->username); 124 strcpy(s + 2 + strlen(jd->username), jd->oauth2_access_token); 125 reply->text = base64_encode((unsigned char *) s, len); 117 if ((sup_gtalk || sup_hipchat_oauth) && want_oauth) { 118 GString *gs; 119 120 gs = g_string_sized_new(128); 121 122 g_string_append_c(gs, '\0'); 123 124 if (sup_gtalk) { 125 /* X-OAUTH2 is not *the* standard OAuth2 SASL/XMPP implementation. 126 It's currently used by GTalk and vaguely documented on 127 http://code.google.com/apis/cloudprint/docs/rawxmpp.html */ 128 xt_add_attr(reply, "mechanism", "X-OAUTH2"); 129 130 g_string_append(gs, jd->username); 131 g_string_append_c(gs, '\0'); 132 g_string_append(gs, jd->oauth2_access_token); 133 } else if (sup_hipchat_oauth) { 134 /* Hipchat's variant, not standard either, is documented here: 135 https://docs.atlassian.com/hipchat.xmpp/latest/xmpp/auth.html */ 136 xt_add_attr(reply, "mechanism", "oauth2"); 137 138 g_string_append(gs, jd->oauth2_access_token); 139 g_string_append_c(gs, '\0'); 140 g_string_append(gs, set_getstr(&ic->acc->set, "resource")); 141 } 142 143 reply->text = base64_encode((unsigned char *) gs->str, gs->len); 126 144 reply->text_len = strlen(reply->text); 127 g_free(s); 145 g_string_free(gs, TRUE); 146 128 147 } else if (want_oauth) { 129 148 imcb_error(ic, "OAuth requested, but not supported by server"); … … 149 168 /* The rest will be done later, when we receive a <challenge/>. */ 150 169 } else if (sup_plain) { 151 int len;152 170 GString *gs; 153 171 char *username; … … 174 192 } 175 193 176 len = gs->len; 177 s = g_string_free(gs, FALSE); 178 179 reply->text = base64_encode((unsigned char *) s, len); 194 reply->text = base64_encode((unsigned char *) gs->str, gs->len); 180 195 reply->text_len = strlen(reply->text); 181 g_ free(s);196 g_string_free(gs, TRUE); 182 197 } 183 198 … … 428 443 { 429 444 struct jabber_data *jd = ic->proto_data; 430 char *msg, *url;431 445 432 446 imcb_log(ic, "Starting OAuth authentication"); … … 434 448 /* Temporary contact, just used to receive the OAuth response. */ 435 449 imcb_add_buddy(ic, JABBER_OAUTH_HANDLE, NULL); 436 url = oauth2_url(jd->oauth2_service); 437 msg = g_strdup_printf("Open this URL in your browser to authenticate: %s", url); 438 imcb_buddy_msg(ic, JABBER_OAUTH_HANDLE, msg, 0, 0); 450 451 if (jd->flags & JFLAG_HIPCHAT) { 452 imcb_buddy_msg(ic, JABBER_OAUTH_HANDLE, 453 "Open this URL and generate a token with 'View Group' and 'Send Message' scopes: " 454 HIPCHAT_SO_CALLED_OAUTH_URL, 0, 0); 455 } else { 456 char *msg, *url; 457 458 url = oauth2_url(jd->oauth2_service); 459 msg = g_strdup_printf("Open this URL in your browser to authenticate: %s", url); 460 imcb_buddy_msg(ic, JABBER_OAUTH_HANDLE, msg, 0, 0); 461 462 g_free(msg); 463 g_free(url); 464 } 439 465 imcb_buddy_msg(ic, JABBER_OAUTH_HANDLE, "Respond to this message with the returned " 440 466 "authorization token.", 0, 0); 441 467 442 g_free(msg);443 g_free(url);444 468 } 445 469 … … 453 477 return FALSE; 454 478 } 455 456 static void sasl_oauth2_got_token(gpointer data, const char *access_token, const char *refresh_token,457 const char *error);458 479 459 480 int sasl_oauth2_get_refresh_token(struct im_connection *ic, const char *msg) … … 486 507 } 487 508 488 staticvoid sasl_oauth2_got_token(gpointer data, const char *access_token, const char *refresh_token, const char *error)509 void sasl_oauth2_got_token(gpointer data, const char *access_token, const char *refresh_token, const char *error) 489 510 { 490 511 struct im_connection *ic = data; -
protocols/jabber/si.c
rba52ac5 r537d9b9 393 393 struct jabber_transfer *tf = NULL; 394 394 struct jabber_data *jd = ic->proto_data; 395 struct jabber_error *err; 395 396 396 397 if (!(tgt_jid = xt_find_attr(node, "from")) || 397 !(ini_jid = xt_find_attr(node, "to"))) { 398 !(ini_jid = xt_find_attr(node, "to")) || 399 !(iq_id = xt_find_attr(node, "id"))) { 398 400 imcb_log(ic, "Invalid SI response from=%s to=%s", tgt_jid, ini_jid); 401 return XT_HANDLED; 402 } 403 404 /* Let's see if we can find out what this bytestream should be for... */ 405 406 for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) { 407 struct jabber_transfer *tft = tflist->data; 408 if ((strcmp(tft->iq_id, iq_id) == 0)) { 409 tf = tft; 410 break; 411 } 412 } 413 414 if (!tf) { 415 imcb_log(ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid); 416 return XT_HANDLED; 417 } 418 419 err = jabber_error_parse(xt_find_node(node->children, "error"), XMLNS_STANZA_ERROR); 420 421 if (err) { 422 if (g_strcmp0(err->code, "forbidden") == 0) { 423 imcb_log(ic, "File %s: %s rejected the transfer", tf->ft->file_name, tgt_jid); 424 } else { 425 imcb_log(ic, "Error: Stream initiation request failed: %s (%s)", err->code, err->text); 426 } 427 imcb_file_canceled(ic, tf->ft, "Stream initiation request failed"); 428 jabber_error_free(err); 399 429 return XT_HANDLED; 400 430 } … … 409 439 * <value> 410 440 */ 411 if (!(tgt_jid = xt_find_attr(node, "from")) || 412 !(ini_jid = xt_find_attr(node, "to")) || 413 !(iq_id = xt_find_attr(node, "id")) || 414 !(c = xt_find_node(node->children, "si")) || 441 if (!(c = xt_find_node(node->children, "si")) || 415 442 !(cmp = xt_find_attr(c, "xmlns")) || 416 443 !(strcmp(cmp, XMLNS_SI) == 0) || … … 439 466 } 440 467 441 /* Let's see if we can find out what this bytestream should be for... */442 443 for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) {444 struct jabber_transfer *tft = tflist->data;445 if ((strcmp(tft->iq_id, iq_id) == 0)) {446 tf = tft;447 break;448 }449 }450 451 if (!tf) {452 imcb_log(ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid);453 return XT_HANDLED;454 }455 456 468 tf->ini_jid = g_strdup(ini_jid); 457 469 tf->tgt_jid = g_strdup(tgt_jid); -
protocols/nogaim.c
rba52ac5 r537d9b9 40 40 41 41 #ifdef WITH_PLUGINS 42 GList *plugins = NULL; 43 44 static gint pluginscmp(gconstpointer a, gconstpointer b, gpointer data) 45 { 46 const struct plugin_info *ia = a; 47 const struct plugin_info *ib = b; 48 49 return g_strcasecmp(ia->name, ib->name); 50 } 51 42 52 gboolean load_plugin(char *path) 43 53 { 54 GList *l; 55 struct plugin_info *i; 56 struct plugin_info *info; 57 struct plugin_info * (*info_function) (void) = NULL; 44 58 void (*init_function) (void); 45 59 46 60 GModule *mod = g_module_open(path, G_MODULE_BIND_LAZY); 61 gboolean loaded = FALSE; 47 62 48 63 if (!mod) { 49 log_message(LOGLVL_ERROR, " Can't find `%s', not loading (%s)\n", path, g_module_error());64 log_message(LOGLVL_ERROR, "Error loading plugin `%s': %s\n", path, g_module_error()); 50 65 return FALSE; 66 } 67 68 if (g_module_symbol(mod, "init_plugin_info", (gpointer *) &info_function)) { 69 info = info_function(); 70 71 if (info->abiver != BITLBEE_ABI_VERSION_CODE) { 72 log_message(LOGLVL_ERROR, 73 "`%s' uses ABI %u but %u is required\n", 74 path, info->abiver, 75 BITLBEE_ABI_VERSION_CODE); 76 g_module_close(mod); 77 return FALSE; 78 } 79 80 if (!info->name || !info->version) { 81 log_message(LOGLVL_ERROR, 82 "Name or version missing from the " 83 "plugin info in `%s'\n", path); 84 g_module_close(mod); 85 return FALSE; 86 } 87 88 for (l = plugins; l; l = l->next) { 89 i = l->data; 90 91 if (g_strcasecmp(i->name, info->name) == 0) { 92 loaded = TRUE; 93 break; 94 } 95 } 96 97 if (loaded) { 98 log_message(LOGLVL_WARNING, 99 "%s plugin already loaded\n", 100 info->name); 101 g_module_close(mod); 102 return FALSE; 103 } 104 } else { 105 log_message(LOGLVL_WARNING, "Can't find function `init_plugin_info' in `%s'\n", path); 51 106 } 52 107 53 108 if (!g_module_symbol(mod, "init_plugin", (gpointer *) &init_function)) { 54 109 log_message(LOGLVL_WARNING, "Can't find function `init_plugin' in `%s'\n", path); 110 g_module_close(mod); 55 111 return FALSE; 56 112 } 57 113 114 if (info_function) { 115 plugins = g_list_insert_sorted_with_data(plugins, info, 116 pluginscmp, NULL); 117 } 118 58 119 init_function(); 59 60 120 return TRUE; 61 121 } … … 73 133 74 134 while ((entry = g_dir_read_name(dir))) { 135 if (!g_str_has_suffix(entry, "." G_MODULE_SUFFIX)) { 136 continue; 137 } 138 75 139 path = g_build_filename(global.conf->plugindir, entry, NULL); 76 140 if (!path) { … … 86 150 g_dir_close(dir); 87 151 } 152 } 153 154 GList *get_plugins() 155 { 156 return plugins; 88 157 } 89 158 #endif … … 168 237 load_plugins(); 169 238 #endif 239 } 240 241 GList *get_protocols() 242 { 243 return protocols; 244 } 245 246 GList *get_protocols_disabled() 247 { 248 return disabled_protocols; 170 249 } 171 250 … … 495 574 } 496 575 497 /* Mainly meant for ICQ (and now also for Jabber conferences) to allow IM 498 modules to suggest a nickname for a handle. */ 499 void imcb_buddy_nick_hint(struct im_connection *ic, const char *handle, const char *nick) 576 /* Implements either imcb_buddy_nick_hint() or imcb_buddy_nick_change() depending on the value of 'change' */ 577 static void buddy_nick_hint_or_change(struct im_connection *ic, const char *handle, const char *nick, gboolean change) 500 578 { 501 579 bee_t *bee = ic->bee; … … 509 587 bu->nick = g_strdup(nick); 510 588 511 if (bee->ui->user_nick_hint) { 589 if (change && bee->ui->user_nick_change) { 590 bee->ui->user_nick_change(bee, bu, nick); 591 } else if (!change && bee->ui->user_nick_hint) { 512 592 bee->ui->user_nick_hint(bee, bu, nick); 513 593 } 594 } 595 596 /* Soft variant, for newly created users. Does nothing if it's already online */ 597 void imcb_buddy_nick_hint(struct im_connection *ic, const char *handle, const char *nick) 598 { 599 buddy_nick_hint_or_change(ic, handle, nick, FALSE); 600 } 601 602 /* Hard variant, always changes the nick */ 603 void imcb_buddy_nick_change(struct im_connection *ic, const char *handle, const char *nick) 604 { 605 buddy_nick_hint_or_change(ic, handle, nick, TRUE); 514 606 } 515 607 … … 667 759 if (away && *away) { 668 760 GList *m = ic->acc->prpl->away_states(ic); 761 if (m == NULL) { 762 return 0; 763 } 669 764 msg = ic->acc->flags & ACC_FLAG_AWAY_MESSAGE ? away : NULL; 670 765 away = imc_away_state_find(m, away, &msg) ? : -
protocols/nogaim.h
rba52ac5 r537d9b9 102 102 103 103 GSList *groupchats; 104 GSList *chatlist; 104 105 }; 105 106 … … 144 145 char *description; 145 146 }; 147 148 /* This enum takes a few things from libpurple and a few things from old OPT_ flags. 149 * The only flag that was used before this struct was PRPL_OPT_NOOTR. 150 * 151 * The libpurple ones only use the same values as the PurpleProtocolOptions 152 * enum for convenience, but there's no promise of direct compatibility with 153 * those values. As of libpurple 2.8.0 they use up to 0x800 (1 << 11), which is 154 * a nice coincidence. 155 */ 156 typedef enum { 157 /* The protocol doesn't use passwords 158 * Mirrors libpurple's OPT_PROTO_NO_PASSWORD */ 159 PRPL_OPT_NO_PASSWORD = 1 << 4, 160 161 /* The protocol doesn't require passwords, but may use them 162 * Mirrors libpurple's OPT_PROTO_PASSWORD_OPTIONAL */ 163 PRPL_OPT_PASSWORD_OPTIONAL = 1 << 7, 164 165 /* The protocol is not suitable for OTR, see OPT_NOOTR */ 166 PRPL_OPT_NOOTR = 1 << 12, 167 } prpl_options_t; 146 168 147 169 struct prpl { … … 269 291 gboolean (* handle_is_self) (struct im_connection *, const char *who); 270 292 293 /* This sets/updates the im_connection->chatlist field with a 294 * bee_chat_info_t GSList. This function should ensure the 295 * bee_chat_list_finish() function gets called at some point 296 * after the chat list is completely updated. 297 */ 298 void (* chat_list) (struct im_connection *, const char *server); 299 271 300 /* Some placeholders so eventually older plugins may cooperate with newer BitlBees. */ 272 301 void *resv1; … … 277 306 }; 278 307 308 struct plugin_info 309 { 310 guint abiver; 311 const char *name; 312 const char *version; 313 const char *description; 314 const char *author; 315 const char *url; 316 }; 317 318 #ifdef WITH_PLUGINS 319 G_MODULE_EXPORT GList *get_plugins(); 320 #endif 321 279 322 /* im_api core stuff. */ 280 323 void nogaim_init(); 324 G_MODULE_EXPORT GList *get_protocols(); 325 G_MODULE_EXPORT GList *get_protocols_disabled(); 281 326 G_MODULE_EXPORT GSList *get_connections(); 282 327 G_MODULE_EXPORT struct prpl *find_protocol(const char *name); … … 330 375 G_MODULE_EXPORT void imcb_rename_buddy(struct im_connection *ic, const char *handle, const char *realname); 331 376 G_MODULE_EXPORT void imcb_buddy_nick_hint(struct im_connection *ic, const char *handle, const char *nick); 377 G_MODULE_EXPORT void imcb_buddy_nick_change(struct im_connection *ic, const char *handle, const char *nick); 332 378 G_MODULE_EXPORT void imcb_buddy_action_response(bee_user_t *bu, const char *action, char * const args[], void *data); 333 379 G_MODULE_EXPORT GSList *imcb_get_local_contacts(struct im_connection *ic); -
protocols/oscar/conn.c
rba52ac5 r537d9b9 383 383 { 384 384 aim_conn_t *connstruct; 385 guint16 port = AIM_LOGIN_PORT;386 char *host;387 int i;388 385 389 386 if (!(connstruct = aim_conn_getnext(sess))) { … … 400 397 } 401 398 402 /* 403 * As of 23 Jul 1999, AOL now sends the port number, preceded by a 404 * colon, in the BOS redirect. This fatally breaks all previous 405 * libfaims. Bad, bad AOL. 406 * 407 * We put this here to catch every case. 408 * 409 */ 410 411 for (i = 0; i < (int) strlen(dest); i++) { 412 if (dest[i] == ':') { 413 port = atoi(&(dest[i + 1])); 414 break; 415 } 416 } 417 418 host = (char *) g_malloc(i + 1); 419 strncpy(host, dest, i); 420 host[i] = '\0'; 421 422 connstruct->fd = proxy_connect(host, port, NULL, NULL); 423 424 g_free(host); 399 /* The code that used to be here was very broken */ 400 g_return_val_if_reached(connstruct); 425 401 426 402 return connstruct; -
protocols/purple/bpurple.h
rba52ac5 r537d9b9 13 13 GHashTable *input_requests; 14 14 guint next_request_id; 15 char *chat_list_server; 16 GSList *filetransfers; 15 17 }; 16 18 -
protocols/purple/ft.c
rba52ac5 r537d9b9 42 42 char *fn, *handle; 43 43 gboolean ui_wants_data; 44 int timeout; 44 45 }; 45 46 … … 64 65 struct prpl_xfer_data *px = ft->data; 65 66 66 purple_xfer_request_denied(px->xfer); 67 if (px->xfer) { 68 if (!purple_xfer_is_completed(px->xfer) && !purple_xfer_is_canceled(px->xfer)) { 69 purple_xfer_cancel_local(px->xfer); 70 } 71 px->xfer->ui_data = NULL; 72 purple_xfer_unref(px->xfer); 73 px->xfer = NULL; 74 } 75 } 76 77 static void prpl_xfer_free(struct file_transfer *ft) 78 { 79 struct prpl_xfer_data *px = ft->data; 80 struct purple_data *pd = px->ic->proto_data; 81 82 pd->filetransfers = g_slist_remove(pd->filetransfers, px); 83 84 if (px->xfer) { 85 px->xfer->ui_data = NULL; 86 purple_xfer_unref(px->xfer); 87 } 88 89 if (px->timeout) { 90 b_event_remove(px->timeout); 91 } 92 93 g_free(px->fn); 94 g_free(px->handle); 95 if (px->fd >= 0) { 96 close(px->fd); 97 } 98 g_free(px); 67 99 } 68 100 69 101 static void prplcb_xfer_new(PurpleXfer *xfer) 70 102 { 103 purple_xfer_ref(xfer); 104 71 105 if (purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE) { 72 106 struct prpl_xfer_data *px = g_new0(struct prpl_xfer_data, 1); 107 struct purple_data *pd; 73 108 74 109 xfer->ui_data = px; … … 77 112 px->fd = -1; 78 113 px->ic = purple_ic_by_pa(xfer->account); 114 115 pd = px->ic->proto_data; 116 pd->filetransfers = g_slist_prepend(pd->filetransfers, px); 79 117 80 118 purple_xfer_set_local_filename(xfer, px->fn); … … 112 150 px->ft->accept = prpl_xfer_accept; 113 151 px->ft->canceled = prpl_xfer_canceled; 152 px->ft->free = prpl_xfer_free; 114 153 px->ft->write_request = prpl_xfer_write_request; 115 154 … … 164 203 165 204 166 /* Generic (IM<>UI): */167 205 static void prplcb_xfer_destroy(PurpleXfer *xfer) 168 206 { 169 207 struct prpl_xfer_data *px = xfer->ui_data; 170 208 171 g_free(px->fn); 172 g_free(px->handle); 173 if (px->fd >= 0) { 174 close(px->fd); 175 } 176 g_free(px); 209 if (px) { 210 px->xfer = NULL; 211 } 177 212 } 178 213 … … 224 259 struct prpl_xfer_data *px = xfer->ui_data; 225 260 226 if (px ->ft) {261 if (px && px->ft) { 227 262 imcb_file_canceled(px->ic, px->ft, "Canceled by remote end"); 228 } else {263 } else if (px) { 229 264 /* px->ft == NULL for sends, because of the two stages. :-/ */ 230 265 imcb_error(px->ic, "File transfer cancelled by remote end"); … … 240 275 { 241 276 struct prpl_xfer_data *px = g_new0(struct prpl_xfer_data, 1); 277 struct purple_data *pd; 242 278 char *dir, *basename; 243 279 244 280 ft->data = px; 245 281 px->ft = ft; 282 px->ft->free = prpl_xfer_free; 246 283 247 284 dir = g_strdup("/tmp/bitlbee-purple-ft.XXXXXX"); … … 272 309 px->handle = g_strdup(handle); 273 310 311 pd = px->ic->proto_data; 312 pd->filetransfers = g_slist_prepend(pd->filetransfers, px); 313 274 314 imcb_log(ic, 275 315 "Due to libpurple limitations, the file has to be cached locally before proceeding with the actual file transfer. Please wait..."); 276 316 277 b_timeout_add(0, purple_transfer_request_cb, ft);317 px->timeout = b_timeout_add(0, purple_transfer_request_cb, ft); 278 318 } 279 319 … … 295 335 struct prpl_xfer_data *px = ft->data; 296 336 337 px->timeout = 0; 338 297 339 if (ft->write == NULL) { 298 340 ft->write = prpl_xfer_write; … … 322 364 px->ft = NULL; 323 365 } else { 324 b_timeout_add(0, purple_transfer_request_cb, ft);366 px->timeout = b_timeout_add(0, purple_transfer_request_cb, ft); 325 367 } 326 368 327 369 return TRUE; 370 } 371 372 void purple_transfer_cancel_all(struct im_connection *ic) 373 { 374 struct purple_data *pd = ic->proto_data; 375 376 while (pd->filetransfers) { 377 struct prpl_xfer_data *px = pd->filetransfers->data; 378 379 if (px->ft) { 380 imcb_file_canceled(ic, px->ft, "Logging out"); 381 } 382 383 pd->filetransfers = g_slist_remove(pd->filetransfers, px); 384 } 328 385 } 329 386 -
protocols/purple/purple.c
rba52ac5 r537d9b9 43 43 const char *message, const char *who); 44 44 45 void purple_transfer_cancel_all(struct im_connection *ic); 46 45 47 /* purple_request_input specific stuff */ 46 48 typedef void (*ri_callback_t)(gpointer, const gchar *); … … 54 56 }; 55 57 58 struct purple_roomlist_data { 59 GSList *chats; 60 gint topic; 61 gboolean initialized; 62 }; 63 64 56 65 struct im_connection *purple_ic_by_pa(PurpleAccount *pa) 57 66 { … … 94 103 } 95 104 105 static char *purple_get_account_prpl_id(account_t *acc) 106 { 107 /* "oscar" is how non-purple bitlbee calls it, 108 * and it might be icq or aim, depending on the username */ 109 if (g_strcmp0(acc->prpl->name, "oscar") == 0) { 110 return (g_ascii_isdigit(acc->user[0])) ? "prpl-icq" : "prpl-aim"; 111 } 112 113 return acc->prpl->data; 114 } 115 96 116 static void purple_init(account_t *acc) 97 117 { 98 PurplePlugin *prpl = purple_plugins_find_with_id((char *) acc->prpl->data); 118 char *prpl_id = purple_get_account_prpl_id(acc); 119 PurplePlugin *prpl = purple_plugins_find_with_id(prpl_id); 99 120 PurplePluginProtocolInfo *pi = prpl->info->extra_info; 100 121 PurpleAccount *pa; … … 262 283 /* Go through all away states to figure out if away/status messages 263 284 are possible. */ 264 pa = purple_account_new(acc->user, (char *) acc->prpl->data);285 pa = purple_account_new(acc->user, prpl_id); 265 286 for (st = purple_account_get_status_types(pa); st; st = st->next) { 266 287 PurpleStatusPrimitive prim = purple_status_type_get_primitive(st->data); … … 345 366 346 367 ic->proto_data = pd = g_new0(struct purple_data, 1); 347 pd->account = purple_account_new(acc->user, (char *) acc->prpl->data);368 pd->account = purple_account_new(acc->user, purple_get_account_prpl_id(acc)); 348 369 pd->input_requests = g_hash_table_new_full(g_direct_hash, g_direct_equal, 349 370 NULL, g_free); … … 371 392 } 372 393 394 if (pd->filetransfers) { 395 purple_transfer_cancel_all(ic); 396 } 397 373 398 purple_account_set_enabled(pd->account, "BitlBee", FALSE); 374 399 purple_connections = g_slist_remove(purple_connections, ic); 375 400 purple_accounts_remove(pd->account); 401 imcb_chat_list_free(ic); 402 g_free(pd->chat_list_server); 376 403 g_hash_table_destroy(pd->input_requests); 377 404 g_free(pd); … … 673 700 } 674 701 702 void purple_chat_set_topic(struct groupchat *gc, char *topic) 703 { 704 PurpleConversation *pc = gc->data; 705 PurpleConvChat *pcc = PURPLE_CONV_CHAT(pc); 706 struct purple_data *pd = gc->ic->proto_data; 707 PurplePlugin *prpl = purple_plugins_find_with_id(pd->account->protocol_id); 708 PurplePluginProtocolInfo *pi = prpl->info->extra_info; 709 710 if (pi->set_chat_topic) { 711 pi->set_chat_topic(purple_account_get_connection(pd->account), 712 purple_conv_chat_get_id(pcc), 713 topic); 714 } 715 } 716 675 717 void purple_chat_kick(struct groupchat *gc, char *who, const char *message) 676 718 { … … 697 739 GHashTable *chat_hash; 698 740 PurpleConversation *conv; 741 struct groupchat *gc; 699 742 GList *info, *l; 700 743 … … 730 773 g_list_free(info); 731 774 775 /* do this before serv_join_chat to handle cases where prplcb_conv_new is called immediately (not async) */ 776 gc = imcb_chat_new(ic, room); 777 732 778 serv_join_chat(purple_account_get_connection(pd->account), chat_hash); 733 779 734 780 g_hash_table_destroy(chat_hash); 735 781 736 return imcb_chat_new(ic, room); 782 return gc; 783 } 784 785 void purple_chat_list(struct im_connection *ic, const char *server) 786 { 787 PurpleRoomlist *list; 788 struct purple_data *pd = ic->proto_data; 789 PurplePlugin *prpl = purple_plugins_find_with_id(pd->account->protocol_id); 790 PurplePluginProtocolInfo *pi = prpl->info->extra_info; 791 792 if (!pi || !pi->roomlist_get_list) { 793 imcb_log(ic, "Room listing unsupported by this purple plugin"); 794 return; 795 } 796 797 g_free(pd->chat_list_server); 798 pd->chat_list_server = (server && *server) ? g_strdup(server) : NULL; 799 800 list = purple_roomlist_get_list(pd->account->gc); 801 802 if (list) { 803 struct purple_roomlist_data *rld = list->ui_data; 804 rld->initialized = TRUE; 805 806 purple_roomlist_ref(list); 807 } 737 808 } 738 809 … … 970 1041 971 1042 /* Generic handler for IM or chat messages, covers write_chat, write_im and write_conv */ 972 static void handle_conv_msg(PurpleConversation *conv, const char *who, const char *message , guint32 bee_flags, time_t mtime)1043 static void handle_conv_msg(PurpleConversation *conv, const char *who, const char *message_, guint32 bee_flags, time_t mtime) 973 1044 { 974 1045 struct im_connection *ic = purple_ic_by_pa(conv->account); 975 1046 struct groupchat *gc = conv->ui_data; 1047 char *message = g_strdup(message_); 976 1048 PurpleBuddy *buddy; 977 1049 … … 982 1054 983 1055 if (conv->type == PURPLE_CONV_TYPE_IM) { 984 imcb_buddy_msg(ic, (char *) who, (char *)message, bee_flags, mtime);1056 imcb_buddy_msg(ic, who, message, bee_flags, mtime); 985 1057 } else if (gc) { 986 imcb_chat_msg(gc, who, (char *) message, bee_flags, mtime); 987 } 1058 imcb_chat_msg(gc, who, message, bee_flags, mtime); 1059 } 1060 1061 g_free(message); 988 1062 } 989 1063 … … 1171 1245 struct im_connection *ic = purple_ic_by_pa(account); 1172 1246 struct purple_data *pd = ic->proto_data; 1173 struct request_input_data *ri = g_new0(struct request_input_data, 1); 1174 guint id = pd->next_request_id++; 1247 struct request_input_data *ri; 1248 guint id; 1249 1250 /* hack so that jabber's chat list doesn't ask for conference server twice */ 1251 if (pd->chat_list_server && title && g_strcmp0(title, "Enter a Conference Server") == 0) { 1252 ((ri_callback_t) ok_cb)(user_data, pd->chat_list_server); 1253 g_free(pd->chat_list_server); 1254 pd->chat_list_server = NULL; 1255 return NULL; 1256 } 1257 1258 id = pd->next_request_id++; 1259 ri = g_new0(struct request_input_data, 1); 1175 1260 1176 1261 ri->id = id; … … 1182 1267 1183 1268 imcb_add_buddy(ic, ri->buddy, NULL); 1184 imcb_buddy_msg(ic, ri->buddy, secondary, 0, 0); 1269 1270 if (title && *title) { 1271 imcb_buddy_msg(ic, ri->buddy, title, 0, 0); 1272 } 1273 1274 if (primary && *primary) { 1275 imcb_buddy_msg(ic, ri->buddy, primary, 0, 0); 1276 } 1277 1278 if (secondary && *secondary) { 1279 imcb_buddy_msg(ic, ri->buddy, secondary, 0, 0); 1280 } 1185 1281 1186 1282 return ri; … … 1256 1352 prplcb_privacy_deny_added, /* deny_added */ 1257 1353 prplcb_privacy_deny_removed, /* deny_removed */ 1354 }; 1355 1356 static void prplcb_roomlist_create(PurpleRoomlist *list) 1357 { 1358 struct purple_roomlist_data *rld; 1359 1360 list->ui_data = rld = g_new0(struct purple_roomlist_data, 1); 1361 rld->topic = -1; 1362 } 1363 1364 static void prplcb_roomlist_set_fields(PurpleRoomlist *list, GList *fields) 1365 { 1366 gint topic = -1; 1367 GList *l; 1368 guint i; 1369 PurpleRoomlistField *field; 1370 struct purple_roomlist_data *rld = list->ui_data; 1371 1372 for (i = 0, l = fields; l; i++, l = l->next) { 1373 field = l->data; 1374 1375 /* Use the first visible string field as a fallback topic */ 1376 if (i != 0 && topic < 0 && !field->hidden && 1377 field->type == PURPLE_ROOMLIST_FIELD_STRING) { 1378 topic = i; 1379 } 1380 1381 if ((g_strcasecmp(field->name, "description") == 0) || 1382 (g_strcasecmp(field->name, "topic") == 0)) { 1383 if (field->type == PURPLE_ROOMLIST_FIELD_STRING) { 1384 rld->topic = i; 1385 } 1386 } 1387 } 1388 1389 if (rld->topic < 0) { 1390 rld->topic = topic; 1391 } 1392 } 1393 1394 static void prplcb_roomlist_add_room(PurpleRoomlist *list, PurpleRoomlistRoom *room) 1395 { 1396 bee_chat_info_t *ci; 1397 const char *title; 1398 const char *topic; 1399 GList *fields; 1400 struct purple_roomlist_data *rld = list->ui_data; 1401 1402 fields = purple_roomlist_room_get_fields(room); 1403 title = purple_roomlist_room_get_name(room); 1404 1405 if (rld->topic >= 0) { 1406 topic = g_list_nth_data(fields, rld->topic); 1407 } else { 1408 topic = NULL; 1409 } 1410 1411 ci = g_new(bee_chat_info_t, 1); 1412 ci->title = g_strdup(title); 1413 ci->topic = g_strdup(topic); 1414 rld->chats = g_slist_prepend(rld->chats, ci); 1415 } 1416 1417 static void prplcb_roomlist_in_progress(PurpleRoomlist *list, gboolean in_progress) 1418 { 1419 struct im_connection *ic; 1420 struct purple_data *pd; 1421 struct purple_roomlist_data *rld = list->ui_data; 1422 1423 if (in_progress || !rld) { 1424 return; 1425 } 1426 1427 ic = purple_ic_by_pa(list->account); 1428 imcb_chat_list_free(ic); 1429 1430 pd = ic->proto_data; 1431 g_free(pd->chat_list_server); 1432 pd->chat_list_server = NULL; 1433 1434 ic->chatlist = g_slist_reverse(rld->chats); 1435 rld->chats = NULL; 1436 1437 imcb_chat_list_finish(ic); 1438 1439 if (rld->initialized) { 1440 purple_roomlist_unref(list); 1441 } 1442 } 1443 1444 static void prplcb_roomlist_destroy(PurpleRoomlist *list) 1445 { 1446 g_free(list->ui_data); 1447 list->ui_data = NULL; 1448 } 1449 1450 static PurpleRoomlistUiOps bee_roomlist_uiops = 1451 { 1452 NULL, /* show_with_account */ 1453 prplcb_roomlist_create, /* create */ 1454 prplcb_roomlist_set_fields, /* set_fields */ 1455 prplcb_roomlist_add_room, /* add_room */ 1456 prplcb_roomlist_in_progress, /* in_progress */ 1457 prplcb_roomlist_destroy, /* destroy */ 1258 1458 }; 1259 1459 … … 1422 1622 purple_request_set_ui_ops(&bee_request_uiops); 1423 1623 purple_privacy_set_ui_ops(&bee_privacy_uiops); 1624 purple_roomlist_set_ui_ops(&bee_roomlist_uiops); 1424 1625 purple_notify_set_ui_ops(&bee_notify_uiops); 1425 1626 purple_accounts_set_ui_ops(&bee_account_uiops); … … 1438 1639 char *dir; 1439 1640 1641 if (purple_get_core() != NULL) { 1642 log_message(LOGLVL_ERROR, "libpurple already initialized. " 1643 "Please use inetd or ForkDaemon mode instead."); 1644 return; 1645 } 1646 1440 1647 g_assert((int) B_EV_IO_READ == (int) PURPLE_INPUT_READ); 1441 1648 g_assert((int) B_EV_IO_WRITE == (int) PURPLE_INPUT_WRITE); … … 1443 1650 dir = g_strdup_printf("%s/purple", global.conf->configdir); 1444 1651 purple_util_set_user_dir(dir); 1652 g_free(dir); 1653 1654 dir = g_strdup_printf("%s/purple", global.conf->plugindir); 1655 purple_plugins_add_search_path(dir); 1445 1656 g_free(dir); 1446 1657 … … 1506 1717 funcs.chat_with = purple_chat_with; 1507 1718 funcs.chat_invite = purple_chat_invite; 1719 funcs.chat_topic = purple_chat_set_topic; 1508 1720 funcs.chat_kick = purple_chat_kick; 1509 1721 funcs.chat_leave = purple_chat_leave; 1510 1722 funcs.chat_join = purple_chat_join; 1723 funcs.chat_list = purple_chat_list; 1511 1724 funcs.transfer_request = purple_transfer_request; 1512 1725 … … 1517 1730 for (prots = purple_plugins_get_protocols(); prots; prots = prots->next) { 1518 1731 PurplePlugin *prot = prots->data; 1732 PurplePluginProtocolInfo *pi = prot->info->extra_info; 1519 1733 struct prpl *ret; 1520 1734 … … 1530 1744 ret->name += 5; 1531 1745 } 1746 1747 if (pi->options & OPT_PROTO_NO_PASSWORD) { 1748 ret->options |= PRPL_OPT_NO_PASSWORD; 1749 } 1750 1751 if (pi->options & OPT_PROTO_PASSWORD_OPTIONAL) { 1752 ret->options |= PRPL_OPT_PASSWORD_OPTIONAL; 1753 } 1754 1532 1755 register_protocol(ret); 1533 1756 … … 1539 1762 ret = g_memdup(&funcs, sizeof(funcs)); 1540 1763 ret->name = "oscar"; 1541 ret->data = prot->info->id; 1764 /* purple_get_account_prpl_id() determines the actual protocol ID (icq/aim) */ 1765 ret->data = NULL; 1542 1766 register_protocol(ret); 1543 1767 } -
protocols/skype/skype.c
rba52ac5 r537d9b9 1763 1763 register_protocol(ret); 1764 1764 } 1765 1766 struct plugin_info *init_plugin_info(void) 1767 { 1768 static struct plugin_info info = { 1769 BITLBEE_ABI_VERSION_CODE, 1770 "skype", 1771 BITLBEE_VERSION, 1772 "Skype protocol plugin", 1773 NULL, 1774 NULL 1775 }; 1776 1777 return &info; 1778 } -
protocols/twitter/twitter.c
rba52ac5 r537d9b9 345 345 imcb_log(ic, "Getting contact list"); 346 346 twitter_get_friends_ids(ic, -1); 347 twitter_get_mutes_ids(ic, -1); 348 twitter_get_noretweets_ids(ic, -1); 347 349 } else { 348 350 twitter_main_loop_start(ic); … … 469 471 g_regex_match(regex, msg, 0, &match_info); 470 472 while (g_match_info_matches(match_info)) { 471 gchar * s, *url;473 gchar *url; 472 474 473 475 url = g_match_info_fetch(match_info, 2); 474 476 url_len_diff += target_len - g_utf8_strlen(url, -1); 475 477 476 /* Add another character for https://t.co/... URLs */477 if ((s = g_match_info_fetch(match_info, 3))) {478 url_len_diff += 1;479 g_free(s);480 }481 478 g_free(url); 482 479 g_match_info_next(match_info, NULL); … … 541 538 if (strcmp(acc->prpl->name, "twitter") == 0) { 542 539 def_url = TWITTER_API_URL; 543 def_tul = "2 2";540 def_tul = "23"; 544 541 def_mentions = "true"; 545 542 } else { /* if( strcmp( acc->prpl->name, "identica" ) == 0 ) */ … … 690 687 } 691 688 689 g_slist_foreach(td->mutes_ids, (GFunc) g_free, NULL); 690 g_slist_free(td->mutes_ids); 691 692 g_slist_foreach(td->noretweets_ids, (GFunc) g_free, NULL); 693 g_slist_free(td->noretweets_ids); 694 692 695 http_close(td->stream); 693 696 twitter_filter_remove_all(ic); … … 948 951 } else if ((g_strcasecmp(cmd[0], "favourite") == 0 || 949 952 g_strcasecmp(cmd[0], "favorite") == 0 || 950 g_strcasecmp(cmd[0], "fav") == 0) && cmd[1]) { 953 g_strcasecmp(cmd[0], "fav") == 0 || 954 g_strcasecmp(cmd[0], "like") == 0) && cmd[1]) { 951 955 if ((id = twitter_message_id_from_command_arg(ic, cmd[1], NULL))) { 952 956 twitter_favourite_tweet(ic, id); … … 960 964 } else if (g_strcasecmp(cmd[0], "unfollow") == 0 && cmd[1]) { 961 965 twitter_remove_buddy(ic, cmd[1], NULL); 966 goto eof; 967 } else if (g_strcasecmp(cmd[0], "mute") == 0 && cmd[1]) { 968 twitter_mute_create_destroy(ic, cmd[1], 1); 969 goto eof; 970 } else if (g_strcasecmp(cmd[0], "unmute") == 0 && cmd[1]) { 971 twitter_mute_create_destroy(ic, cmd[1], 0); 962 972 goto eof; 963 973 } else if ((g_strcasecmp(cmd[0], "report") == 0 || … … 1082 1092 struct prpl *ret = g_new0(struct prpl, 1); 1083 1093 1084 ret->options = OPT_NOOTR;1094 ret->options = PRPL_OPT_NOOTR | PRPL_OPT_NO_PASSWORD; 1085 1095 ret->name = "twitter"; 1086 1096 ret->login = twitter_login; … … 1109 1119 ret = g_memdup(ret, sizeof(struct prpl)); 1110 1120 ret->name = "identica"; 1121 ret->options = PRPL_OPT_NOOTR; 1111 1122 register_protocol(ret); 1112 1123 } -
protocols/twitter/twitter.h
rba52ac5 r537d9b9 61 61 62 62 GSList *follow_ids; 63 GSList *mutes_ids; 64 GSList *noretweets_ids; 63 65 GSList *filters; 64 66 -
protocols/twitter/twitter_http.c
rba52ac5 r537d9b9 79 79 g_string_printf(request, "%s %s%s%s%s HTTP/1.1\r\n" 80 80 "Host: %s\r\n" 81 "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n",81 "User-Agent: BitlBee " BITLBEE_VERSION "\r\n", 82 82 is_post ? "POST" : "GET", 83 83 base_url ? base_url->file : td->url_path, -
protocols/twitter/twitter_lib.c
rba52ac5 r537d9b9 245 245 246 246 static void twitter_http_get_friends_ids(struct http_request *req); 247 static void twitter_http_get_mutes_ids(struct http_request *req); 248 static void twitter_http_get_noretweets_ids(struct http_request *req); 247 249 248 250 /** … … 257 259 args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); 258 260 twitter_http(ic, TWITTER_FRIENDS_IDS_URL, twitter_http_get_friends_ids, ic, 0, args, 2); 261 262 g_free(args[1]); 263 } 264 265 /** 266 * Get the muted users ids. 267 */ 268 void twitter_get_mutes_ids(struct im_connection *ic, gint64 next_cursor) 269 { 270 char *args[2]; 271 272 args[0] = "cursor"; 273 args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); 274 twitter_http(ic, TWITTER_MUTES_IDS_URL, twitter_http_get_mutes_ids, ic, 0, args, 2); 275 276 g_free(args[1]); 277 } 278 279 /** 280 * Get the ids for users from whom we should ignore retweets. 281 */ 282 void twitter_get_noretweets_ids(struct im_connection *ic, gint64 next_cursor) 283 { 284 char *args[2]; 285 286 args[0] = "cursor"; 287 args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); 288 twitter_http(ic, TWITTER_NORETWEETS_IDS_URL, twitter_http_get_noretweets_ids, ic, 0, args, 2); 259 289 260 290 g_free(args[1]); … … 334 364 twitter_get_users_lookup(ic); 335 365 } 366 367 txl->list = NULL; 368 txl_free(txl); 369 } 370 371 /** 372 * Callback for getting the mutes ids. 373 */ 374 static void twitter_http_get_mutes_ids(struct http_request *req) 375 { 376 struct im_connection *ic = req->data; 377 JSON_Value *parsed; 378 struct twitter_xml_list *txl; 379 struct twitter_data *td; 380 381 // Check if the connection is stil active 382 if (!g_slist_find(twitter_connections, ic)) { 383 return; 384 } 385 386 td = ic->proto_data; 387 388 if (req->status_code != 200) { 389 /* Fail silently */ 390 return; 391 } 392 393 // Parse the data. 394 if (!(parsed = twitter_parse_response(ic, req))) { 395 return; 396 } 397 398 txl = g_new0(struct twitter_xml_list, 1); 399 txl->list = td->mutes_ids; 400 401 /* mute ids API response is similar enough to friends response 402 to reuse this method */ 403 twitter_xt_get_friends_id_list(parsed, txl); 404 json_value_free(parsed); 405 406 td->mutes_ids = txl->list; 407 if (txl->next_cursor) { 408 /* Recurse while there are still more pages */ 409 twitter_get_mutes_ids(ic, txl->next_cursor); 410 } 411 412 txl->list = NULL; 413 txl_free(txl); 414 } 415 416 /** 417 * Callback for getting the no-retweets ids. 418 */ 419 static void twitter_http_get_noretweets_ids(struct http_request *req) 420 { 421 struct im_connection *ic = req->data; 422 JSON_Value *parsed; 423 struct twitter_xml_list *txl; 424 struct twitter_data *td; 425 426 // Check if the connection is stil active 427 if (!g_slist_find(twitter_connections, ic)) { 428 return; 429 } 430 431 if (req->status_code != 200) { 432 /* Fail silently */ 433 return; 434 } 435 436 td = ic->proto_data; 437 438 // Parse the data. 439 if (!(parsed = twitter_parse_response(ic, req))) { 440 return; 441 } 442 443 txl = g_new0(struct twitter_xml_list, 1); 444 txl->list = td->noretweets_ids; 445 446 // Process the retweet ids 447 txl->type = TXL_ID; 448 if (json_type(parsed) == JSONArray) { 449 JSON_Array *arr = json_array(parsed); 450 unsigned int i; 451 for (i = 0; i < json_array_get_count(arr); i++) { 452 jint id = json_array_get_integer(arr, i); 453 txl->list = g_slist_prepend(txl->list, 454 g_strdup_printf("%lld", id)); 455 } 456 } 457 458 json_value_free(parsed); 459 td->noretweets_ids = txl->list; 336 460 337 461 txl->list = NULL; … … 467 591 #endif 468 592 469 static void expand_entities(char **text, const JSON_Object *node );593 static void expand_entities(char **text, const JSON_Object *node, const JSON_Object *extended_node); 470 594 471 595 /** … … 479 603 static struct twitter_xml_status *twitter_xt_get_status(const JSON_Object *node) 480 604 { 481 struct twitter_xml_status *txs ;605 struct twitter_xml_status *txs = {0}; 482 606 const JSON_Object *rt = NULL; 607 const JSON_Value *text_value = NULL; 608 const JSON_Object *extended_node = NULL; 483 609 484 610 if (!node) { … … 488 614 489 615 JSON_O_FOREACH(node, k, v) { 490 if (strcmp("text", k) == 0 && (txs->text = g_strdup(json_string(v)))) { 491 // TODO: Huh strip html? In json? Not sure whether I have to.. 492 strip_html(txs->text); 616 if (strcmp("text", k) == 0 && json_type(v) == JSONString && text_value == NULL) { 617 text_value = v; 618 } else if (strcmp("full_text", k) == 0 && json_type(v) == JSONString) { 619 text_value = v; 620 } else if (strcmp("extended_tweet", k) == 0 && json_type(v) == JSONObject) { 621 text_value = json_object_get_value(json_object(v), "full_text"); 622 extended_node = json_object(v); 493 623 } else if (strcmp("retweeted_status", k) == 0 && (rt = json_object(v))) { 494 624 // Handling below. … … 516 646 struct twitter_xml_status *rtxs = twitter_xt_get_status(rt); 517 647 if (rtxs) { 518 g_free(txs->text);519 648 txs->text = g_strdup_printf("RT @%s: %s", rtxs->user->screen_name, rtxs->text); 520 649 txs->id = rtxs->id; 521 650 txs_free(rtxs); 522 651 } 523 } else { 524 expand_entities(&txs->text, node); 652 } else if (text_value && json_type(text_value) == JSONString) { 653 txs->text = g_strdup(json_string(text_value)); 654 strip_html(txs->text); 655 expand_entities(&txs->text, node, extended_node); 525 656 } 526 657 … … 564 695 } 565 696 566 expand_entities(&txs->text, node );697 expand_entities(&txs->text, node, NULL); 567 698 568 699 if (txs->text && txs->user && txs->id) { … … 574 705 } 575 706 576 static void expand_entities(char **text, const JSON_Object *node )577 { 578 JSON_Object *entities, * quoted;707 static void expand_entities(char **text, const JSON_Object *node, const JSON_Object *extended_node) 708 { 709 JSON_Object *entities, *extended_entities, *quoted; 579 710 char *quote_url = NULL, *quote_text = NULL; 580 711 … … 594 725 } 595 726 727 if (extended_node) { 728 extended_entities = json_object_get_object(extended_node, "entities"); 729 if (extended_entities) { 730 entities = extended_entities; 731 } 732 } 733 596 734 JSON_O_FOREACH(entities, k, v) { 597 735 int i; … … 837 975 struct twitter_data *td = ic->proto_data; 838 976 char *last_id_str; 977 char *uid_str; 839 978 840 979 if (status->user == NULL || status->text == NULL) { 980 return; 981 } 982 983 /* Check this is not a tweet that should be muted */ 984 uid_str = g_strdup_printf("%" G_GUINT64_FORMAT, status->user->uid); 985 986 if (g_slist_find_custom(td->mutes_ids, uid_str, (GCompareFunc)strcmp)) { 987 g_free(uid_str); 988 return; 989 } 990 if (status->id != status->rt_id && g_slist_find_custom(td->noretweets_ids, uid_str, (GCompareFunc)strcmp)) { 991 g_free(uid_str); 841 992 return; 842 993 } … … 863 1014 set_setstr(&ic->acc->set, "_last_tweet", last_id_str); 864 1015 g_free(last_id_str); 1016 g_free(uid_str); 865 1017 } 866 1018 … … 880 1032 } 881 1033 882 ic->flags |= OPT_PONGED;883 1034 td = ic->proto_data; 884 1035 … … 896 1047 imc_logout(ic, TRUE); 897 1048 return; 1049 } 1050 1051 if (req == td->stream) { 1052 ic->flags |= OPT_PONGED; 898 1053 } 899 1054 … … 999 1154 JSON_Object *target = json_object_get_object(o, "target"); 1000 1155 const char *type = json_object_get_string(o, "event"); 1156 struct twitter_xml_user *us = NULL; 1157 struct twitter_xml_user *ut = NULL; 1001 1158 1002 1159 if (!type || !source || !target) { … … 1005 1162 1006 1163 if (strcmp(type, "follow") == 0) { 1007 struct twitter_xml_user *us = twitter_xt_get_user(source);1008 struct twitter_xml_user *ut = twitter_xt_get_user(target);1164 us = twitter_xt_get_user(source); 1165 ut = twitter_xt_get_user(target); 1009 1166 if (g_strcasecmp(us->screen_name, td->user) == 0) { 1010 1167 twitter_add_buddy(ic, ut->screen_name, ut->name); 1011 1168 } 1012 txu_free(us); 1013 txu_free(ut); 1014 } 1169 } else if (strcmp(type, "mute") == 0) { 1170 GSList *found; 1171 char *uid_str; 1172 ut = twitter_xt_get_user(target); 1173 uid_str = g_strdup_printf("%" G_GUINT64_FORMAT, ut->uid); 1174 if (!(found = g_slist_find_custom(td->mutes_ids, uid_str, 1175 (GCompareFunc)strcmp))) { 1176 td->mutes_ids = g_slist_prepend(td->mutes_ids, uid_str); 1177 } 1178 twitter_log(ic, "Muted user %s", ut->screen_name); 1179 if (getenv("BITLBEE_DEBUG")) { 1180 fprintf(stderr, "New mute: %s %"G_GUINT64_FORMAT"\n", 1181 ut->screen_name, ut->uid); 1182 } 1183 } else if (strcmp(type, "unmute") == 0) { 1184 GSList *found; 1185 char *uid_str; 1186 ut = twitter_xt_get_user(target); 1187 uid_str = g_strdup_printf("%" G_GUINT64_FORMAT, ut->uid); 1188 if ((found = g_slist_find_custom(td->mutes_ids, uid_str, 1189 (GCompareFunc)strcmp))) { 1190 char *found_str = found->data; 1191 td->mutes_ids = g_slist_delete_link(td->mutes_ids, found); 1192 g_free(found_str); 1193 } 1194 g_free(uid_str); 1195 twitter_log(ic, "Unmuted user %s", ut->screen_name); 1196 if (getenv("BITLBEE_DEBUG")) { 1197 fprintf(stderr, "New unmute: %s %"G_GUINT64_FORMAT"\n", 1198 ut->screen_name, ut->uid); 1199 } 1200 } 1201 1202 txu_free(us); 1203 txu_free(ut); 1015 1204 1016 1205 return TRUE; … … 1309 1498 td->flags &= ~TWITTER_GOT_TIMELINE; 1310 1499 1311 char *args[ 6];1500 char *args[8]; 1312 1501 args[0] = "cursor"; 1313 1502 args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); 1314 1503 args[2] = "include_entities"; 1315 1504 args[3] = "true"; 1505 args[4] = "tweet_mode"; 1506 args[5] = "extended"; 1316 1507 if (td->timeline_id) { 1317 args[ 4] = "since_id";1318 args[ 5] = g_strdup_printf("%" G_GUINT64_FORMAT, td->timeline_id);1508 args[6] = "since_id"; 1509 args[7] = g_strdup_printf("%" G_GUINT64_FORMAT, td->timeline_id); 1319 1510 } 1320 1511 1321 1512 if (twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args, 1322 td->timeline_id ? 6 : 4) == NULL) {1513 td->timeline_id ? 8 : 6) == NULL) { 1323 1514 if (++td->http_fails >= 5) { 1324 1515 imcb_error(ic, "Could not retrieve %s: %s", … … 1331 1522 g_free(args[1]); 1332 1523 if (td->timeline_id) { 1333 g_free(args[ 5]);1524 g_free(args[7]); 1334 1525 } 1335 1526 } … … 1346 1537 td->flags &= ~TWITTER_GOT_MENTIONS; 1347 1538 1348 char *args[ 6];1539 char *args[8]; 1349 1540 args[0] = "cursor"; 1350 1541 args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); … … 1358 1549 args[5] = g_strdup_printf("%d", set_getint(&ic->acc->set, "show_old_mentions")); 1359 1550 } 1551 args[6] = "tweet_mode"; 1552 args[7] = "extended"; 1360 1553 1361 1554 if (twitter_http(ic, TWITTER_MENTIONS_URL, twitter_http_get_mentions, 1362 ic, 0, args, 6) == NULL) {1555 ic, 0, args, 8) == NULL) { 1363 1556 if (++td->http_fails >= 5) { 1364 1557 imcb_error(ic, "Could not retrieve %s: %s", … … 1529 1722 } 1530 1723 1724 /** 1725 * Mute or unmute a user 1726 */ 1727 void twitter_mute_create_destroy(struct im_connection *ic, char *who, int create) 1728 { 1729 char *args[2]; 1730 1731 args[0] = "screen_name"; 1732 args[1] = who; 1733 twitter_http(ic, create ? TWITTER_MUTES_CREATE_URL : TWITTER_MUTES_DESTROY_URL, 1734 twitter_http_post, ic, 1, args, 2); 1735 } 1736 1531 1737 void twitter_status_destroy(struct im_connection *ic, guint64 id) 1532 1738 { -
protocols/twitter/twitter_lib.h
rba52ac5 r537d9b9 63 63 #define TWITTER_FRIENDS_IDS_URL "/friends/ids.json" 64 64 #define TWITTER_FOLLOWERS_IDS_URL "/followers/ids.json" 65 #define TWITTER_MUTES_IDS_URL "/mutes/users/ids.json" 66 #define TWITTER_NORETWEETS_IDS_URL "/friendships/no_retweets/ids.json" 65 67 66 68 /* Account URLs */ … … 76 78 #define TWITTER_BLOCKS_DESTROY_URL "/blocks/destroy/" 77 79 80 /* Mute URLs */ 81 #define TWITTER_MUTES_CREATE_URL "/mutes/users/create.json" 82 #define TWITTER_MUTES_DESTROY_URL "/mutes/users/destroy.json" 83 78 84 /* Report spam */ 79 85 #define TWITTER_REPORT_SPAM_URL "/users/report_spam.json" … … 87 93 gboolean twitter_get_timeline(struct im_connection *ic, gint64 next_cursor); 88 94 void twitter_get_friends_ids(struct im_connection *ic, gint64 next_cursor); 95 void twitter_get_mutes_ids(struct im_connection *ic, gint64 next_cursor); 96 void twitter_get_noretweets_ids(struct im_connection *ic, gint64 next_cursor); 89 97 void twitter_get_statuses_friends(struct im_connection *ic, gint64 next_cursor); 90 98 … … 92 100 void twitter_direct_messages_new(struct im_connection *ic, char *who, char *message); 93 101 void twitter_friendships_create_destroy(struct im_connection *ic, char *who, int create); 102 void twitter_mute_create_destroy(struct im_connection *ic, char *who, int create); 94 103 void twitter_status_destroy(struct im_connection *ic, guint64 id); 95 104 void twitter_status_retweet(struct im_connection *ic, guint64 id);
Note: See TracChangeset
for help on using the changeset viewer.