- Timestamp:
- 2015-05-04T21:58:50Z (10 years ago)
- Children:
- 5726a0d
- Parents:
- 531eabd (diff), 5ca1416 (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:
-
- 3 added
- 3 deleted
- 27 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/bee.h
r531eabd rb1dc403 154 154 G_MODULE_EXPORT void imcb_buddy_times(struct im_connection *ic, const char *handle, time_t login, time_t idle); 155 155 /* Call when a handle says something. 'flags' and 'sent_at may be just 0. */ 156 G_MODULE_EXPORT void imcb_buddy_msg(struct im_connection *ic, const char *handle, c har *msg, guint32 flags,156 G_MODULE_EXPORT void imcb_buddy_msg(struct im_connection *ic, const char *handle, const char *msg, guint32 flags, 157 157 time_t sent_at); 158 158 -
protocols/bee_user.c
r531eabd rb1dc403 68 68 } 69 69 70 bee->users = g_slist_remove(bee->users, bu); 71 70 72 g_free(bu->handle); 71 73 g_free(bu->fullname); … … 74 76 g_free(bu->status_msg); 75 77 g_free(bu); 76 77 bee->users = g_slist_remove(bee->users, bu);78 78 79 79 return 1; … … 247 247 } 248 248 249 void imcb_buddy_msg(struct im_connection *ic, const char *handle, c har *msg, uint32_t flags, time_t sent_at)249 void imcb_buddy_msg(struct im_connection *ic, const char *handle, const char *msg, uint32_t flags, time_t sent_at) 250 250 { 251 251 bee_t *bee = ic->bee; -
protocols/jabber/Makefile
r531eabd rb1dc403 13 13 14 14 # [SH] Program variables 15 objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o s5bytestream.o sasl.o si.o 15 objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o s5bytestream.o sasl.o si.o hipchat.o 16 16 17 17 LFLAGS += -r -
protocols/jabber/conference.c
r531eabd rb1dc403 359 359 360 360 if (subject && chat) { 361 s = bud? strchr(bud->ext_jid, '/') : NULL;361 s = (bud && bud->ext_jid) ? strchr(bud->ext_jid, '/') : NULL; 362 362 if (s) { 363 363 *s = 0; … … 419 419 } 420 420 if (body && body->text_len > 0) { 421 s = strchr(bud->ext_jid, '/');421 s = (bud->ext_jid) ? strchr(bud->ext_jid, '/') : NULL; 422 422 if (s) { 423 423 *s = 0; -
protocols/jabber/iq.c
r531eabd rb1dc403 27 27 static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 28 28 static xt_status jabber_iq_display_vcard(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 29 static int jabber_iq_disco_server(struct im_connection *ic);30 29 31 30 xt_status jabber_pkt_iq(struct xt_node *node, gpointer data) … … 374 373 static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 375 374 { 375 struct jabber_data *jd = ic->proto_data; 376 376 struct xt_node *query, *c; 377 377 int initial = (orig != NULL); … … 388 388 char *name = xt_find_attr(c, "name"); 389 389 char *sub = xt_find_attr(c, "subscription"); 390 char *mention_name = xt_find_attr(c, "mention_name"); 390 391 391 392 if (jid && sub) { … … 396 397 if (name) { 397 398 imcb_rename_buddy(ic, jid, name); 399 } 400 401 /* This could also be used to set the full name as nick for fb/gtalk, 402 * but i'm keeping the old (ugly?) default behavior just to be safe */ 403 if (mention_name && (jd->flags & JFLAG_HIPCHAT)) { 404 imcb_buddy_nick_hint(ic, jid, mention_name); 398 405 } 399 406 } else if (strcmp(sub, "remove") == 0) { … … 855 862 struct xt_node *node, struct xt_node *orig); 856 863 857 staticint jabber_iq_disco_server(struct im_connection *ic)864 int jabber_iq_disco_server(struct im_connection *ic) 858 865 { 859 866 struct xt_node *node, *iq; -
protocols/jabber/jabber.c
r531eabd rb1dc403 61 61 s = set_add(&acc->set, "activity_timeout", "600", set_eval_int, acc); 62 62 63 s = set_add(&acc->set, "oauth", "false", set_eval_oauth, acc);64 65 63 s = set_add(&acc->set, "display_name", NULL, NULL, acc); 66 64 … … 83 81 s = set_add(&acc->set, "server", NULL, set_eval_account, acc); 84 82 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK; 83 84 if (strcmp(acc->prpl->name, "hipchat") == 0) { 85 set_setstr(&acc->set, "server", "chat.hipchat.com"); 86 } else { 87 s = set_add(&acc->set, "oauth", "false", set_eval_oauth, acc); 88 } 85 89 86 90 s = set_add(&acc->set, "ssl", "false", set_eval_bool, acc); … … 121 125 122 126 jd->fd = jd->r_inpa = jd->w_inpa = -1; 127 128 if (strcmp(acc->prpl->name, "hipchat") == 0) { 129 jd->flags |= JFLAG_HIPCHAT; 130 } 123 131 124 132 if (jd->server == NULL) { … … 656 664 { 657 665 struct prpl *ret = g_new0(struct prpl, 1); 666 struct prpl *hipchat = NULL; 658 667 659 668 ret->name = "jabber"; … … 686 695 687 696 register_protocol(ret); 688 } 697 698 /* Another one for hipchat, which has completely different logins */ 699 hipchat = g_memdup(ret, sizeof(struct prpl)); 700 hipchat->name = "hipchat"; 701 register_protocol(hipchat); 702 } -
protocols/jabber/jabber.h
r531eabd rb1dc403 48 48 49 49 JFLAG_GTALK = 0x100000, /* Is Google Talk, as confirmed by iq discovery */ 50 JFLAG_HIPCHAT = 0x200000, /* Is hipchat, because prpl->name says so */ 50 51 51 52 JFLAG_SASL_FB = 0x10000, /* Trying Facebook authentication. */ … … 235 236 #define XMLNS_IBB "http://jabber.org/protocol/ibb" /* XEP-0047 */ 236 237 238 /* Hipchat protocol extensions*/ 239 #define XMLNS_HIPCHAT "http://hipchat.com" 240 #define XMLNS_HIPCHAT_PROFILE "http://hipchat.com/protocol/profile" 241 237 242 /* jabber.c */ 238 243 void jabber_connect(struct im_connection *ic); … … 249 254 xt_status jabber_iq_query_server(struct im_connection *ic, char *jid, char *xmlns); 250 255 void jabber_iq_version_send(struct im_connection *ic, struct jabber_buddy *bud, void *data); 256 int jabber_iq_disco_server(struct im_connection *ic); 251 257 252 258 /* si.c */ … … 341 347 void jabber_chat_invite(struct groupchat *c, char *who, char *message); 342 348 349 /* hipchat.c */ 350 int jabber_get_hipchat_profile(struct im_connection *ic); 351 xt_status jabber_parse_hipchat_profile(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 352 xt_status hipchat_handle_success(struct im_connection *ic, struct xt_node *node); 353 343 354 #endif -
protocols/jabber/jabber_util.c
r531eabd rb1dc403 566 566 567 567 if ((s = strchr(jid, '=')) == NULL) { 568 g_free(jid); 568 569 return NULL; 569 570 } -
protocols/jabber/s5bytestream.c
r531eabd rb1dc403 23 23 24 24 #include "jabber.h" 25 #include "sha1.h"26 25 #include "lib/ftutil.h" 27 26 #include <poll.h> … … 42 41 43 42 /* SHA1( SID + Initiator JID + Target JID) */ 44 char *pseudoad r;43 char *pseudoaddr; 45 44 46 45 gint connect_timeout; … … 130 129 } 131 130 132 g_free(bt->pseudoad r);131 g_free(bt->pseudoaddr); 133 132 134 133 while (bt->streamhosts) { … … 254 253 } 255 254 255 void jabber_bs_remove_events(struct bs_transfer *bt) 256 { 257 struct jabber_transfer *tf = bt->tf; 258 259 if (tf->watch_out) { 260 b_event_remove(tf->watch_out); 261 tf->watch_out = 0; 262 } 263 264 if (tf->watch_in) { 265 b_event_remove(tf->watch_in); 266 tf->watch_in = 0; 267 } 268 269 if (tf->fd != -1) { 270 closesocket(tf->fd); 271 tf->fd = -1; 272 } 273 274 if (bt->connect_timeout) { 275 b_event_remove(bt->connect_timeout); 276 bt->connect_timeout = 0; 277 } 278 } 279 256 280 /* Bad luck */ 257 281 void jabber_bs_canceled(file_transfer_t *ft, char *reason) … … 260 284 261 285 imcb_log(tf->ic, "File transfer aborted: %s", reason); 286 } 287 288 static struct jabber_transfer *get_ft_by_sid(GSList *tflist, char *sid) { 289 GSList *l; 290 for (l = tflist; l; l = g_slist_next(l)) { 291 struct jabber_transfer *tft = l->data; 292 if ((strcmp(tft->sid, sid) == 0)) { 293 return tft; 294 } 295 } 296 return NULL; 297 } 298 299 /* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value 300 * Returns a newly allocated string */ 301 static char *generate_pseudoaddr(char *sid, char *ini_jid, char *tgt_jid) { 302 char *contents = g_strconcat(sid, ini_jid, tgt_jid, NULL); 303 char *hash_hex = g_compute_checksum_for_string(G_CHECKSUM_SHA1, contents, -1); 304 g_free(contents); 305 return hash_hex; 306 } 307 308 static jabber_streamhost_t *jabber_streamhost_new(char *jid, char *host, int port) 309 { 310 jabber_streamhost_t *sh = g_new0(jabber_streamhost_t, 1); 311 sh->jid = g_strdup(jid); 312 sh->host = g_strdup(host); 313 if (port) { 314 g_snprintf(sh->port, sizeof(sh->port), "%u", port); 315 } 316 return sh; 262 317 } 263 318 … … 270 325 struct jabber_data *jd = ic->proto_data; 271 326 struct jabber_transfer *tf = NULL; 272 GSList *tflist;273 327 struct bs_transfer *bt; 274 328 GSList *shlist = NULL; 275 329 struct xt_node *shnode; 276 277 sha1_state_t sha;278 char hash_hex[41];279 unsigned char hash[20];280 int i;281 330 282 331 if (!(iq_id = xt_find_attr(node, "id")) || … … 303 352 (port_s = xt_find_attr(shnode, "port")) && 304 353 (sscanf(port_s, "%d", &port) == 1)) { 305 jabber_streamhost_t *sh = g_new0(jabber_streamhost_t, 1); 306 sh->jid = g_strdup(jid); 307 sh->host = g_strdup(host); 308 sprintf(sh->port, "%u", port); 309 shlist = g_slist_append(shlist, sh); 354 shlist = g_slist_append(shlist, jabber_streamhost_new(jid, host, port)); 310 355 } 311 356 shnode = shnode->next; … … 317 362 } 318 363 319 /* Let's see if we can find out what this bytestream should be for... */ 320 321 for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) { 322 struct jabber_transfer *tft = tflist->data; 323 if ((strcmp(tft->sid, sid) == 0) && 324 (strcmp(tft->ini_jid, ini_jid) == 0) && 325 (strcmp(tft->tgt_jid, tgt_jid) == 0)) { 326 tf = tft; 327 break; 328 } 329 } 330 331 if (!tf) { 364 if (!(tf = get_ft_by_sid(jd->filetransfers, sid))) { 332 365 imcb_log(ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid); 333 366 return XT_HANDLED; … … 339 372 340 373 tf->ft->canceled = jabber_bs_canceled; 341 342 /* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value */343 sha1_init(&sha);344 sha1_append(&sha, (unsigned char *) sid, strlen(sid));345 sha1_append(&sha, (unsigned char *) ini_jid, strlen(ini_jid));346 sha1_append(&sha, (unsigned char *) tgt_jid, strlen(tgt_jid));347 sha1_finish(&sha, hash);348 349 for (i = 0; i < 20; i++) {350 sprintf(hash_hex + i * 2, "%02x", hash[i]);351 }352 374 353 375 bt = g_new0(struct bs_transfer, 1); … … 356 378 bt->sh = shlist->data; 357 379 bt->phase = BS_PHASE_CONNECT; 358 bt->pseudoad r = g_strdup(hash_hex);380 bt->pseudoaddr = generate_pseudoaddr(sid, ini_jid, tgt_jid); 359 381 tf->streamhandle = bt; 360 382 tf->ft->free = jabber_bs_free_transfer; … … 451 473 .rsv = 0, 452 474 .atyp = 0x03, 453 .addrlen = strlen(bt->pseudoad r),475 .addrlen = strlen(bt->pseudoaddr), 454 476 .port = 0 455 477 }; … … 468 490 469 491 /* copy hash into connect message */ 470 memcpy(socks5_connect.address, bt->pseudoad r, socks5_connect.addrlen);492 memcpy(socks5_connect.address, bt->pseudoaddr, socks5_connect.addrlen); 471 493 472 494 ASSERTSOCKOP(send(fd, &socks5_connect, sizeof(struct socks5_message), 0), "Sending SOCKS5 Connect"); … … 558 580 if (shlist && shlist->next) { 559 581 bt->sh = shlist->next->data; 582 jabber_bs_remove_events(bt); 560 583 return jabber_bs_recv_handshake(bt, -1, 0); 561 584 } … … 731 754 struct jabber_data *jd = ic->proto_data; 732 755 struct bs_transfer *bt; 733 GSList *tflist;734 756 struct xt_node *c; 735 757 char *sid, *jid; … … 750 772 /* Let's see if we can find out what this bytestream should be for... */ 751 773 752 for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) { 753 struct jabber_transfer *tft = tflist->data; 754 if ((strcmp(tft->sid, sid) == 0)) { 755 tf = tft; 756 break; 757 } 758 } 759 760 if (!tf) { 774 if (!(tf = get_ft_by_sid(jd->filetransfers, sid))) { 761 775 imcb_log(ic, "WARNING: Received SOCKS5 bytestream reply to unknown request"); 762 776 return XT_HANDLED; … … 776 790 /* using a proxy, abort listen */ 777 791 778 if (tf->watch_in) { 779 b_event_remove(tf->watch_in); 780 tf->watch_in = 0; 781 } 782 783 if (tf->fd != -1) { 784 closesocket(tf->fd); 785 tf->fd = -1; 786 } 787 788 if (bt->connect_timeout) { 789 b_event_remove(bt->connect_timeout); 790 bt->connect_timeout = 0; 791 } 792 jabber_bs_remove_events(bt); 792 793 793 794 GSList *shlist; … … 838 839 { 839 840 char *sid; 840 GSList *tflist;841 841 struct jabber_transfer *tf = NULL; 842 842 struct xt_node *query; … … 846 846 sid = xt_find_attr(query, "sid"); 847 847 848 for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) { 849 struct jabber_transfer *tft = tflist->data; 850 if ((strcmp(tft->sid, sid) == 0)) { 851 tf = tft; 852 break; 853 } 854 } 855 856 if (!tf) { 848 if (!(tf = get_ft_by_sid(jd->filetransfers, sid))) { 857 849 imcb_log(ic, "WARNING: Received SOCKS5 bytestream activation for unknown stream"); 858 850 return XT_HANDLED; … … 883 875 *port++ = '\0'; 884 876 885 sh = g_new0(jabber_streamhost_t, 1); 886 sh->jid = g_strdup(jid); 887 sh->host = g_strdup(host); 888 g_snprintf(sh->port, sizeof(sh->port), "%s", port); 877 sh = jabber_streamhost_new(jid, host, 0); 878 strncpy(sh->port, port, sizeof(sh->port)); 889 879 890 880 return sh; … … 910 900 if (strcmp(proxy, "<local>") == 0) { 911 901 if ((tf->fd = ft_listen(&tf->saddr, host, port, jd->fd, FALSE, &errmsg)) != -1) { 912 sh = g_new0(jabber_streamhost_t, 1); 913 sh->jid = g_strdup(tf->ini_jid); 914 sh->host = g_strdup(host); 915 g_snprintf(sh->port, sizeof(sh->port), "%s", port); 902 sh = jabber_streamhost_new(tf->ini_jid, host, 0); 903 strncpy(sh->port, port, sizeof(sh->port)); 916 904 bt->streamhosts = g_slist_append(bt->streamhosts, sh); 917 905 … … 948 936 { 949 937 struct bs_transfer *bt; 950 sha1_state_t sha;951 char hash_hex[41];952 unsigned char hash[20];953 int i, ret;954 955 /* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value */956 sha1_init(&sha);957 sha1_append(&sha, (unsigned char *) tf->sid, strlen(tf->sid));958 sha1_append(&sha, (unsigned char *) tf->ini_jid, strlen(tf->ini_jid));959 sha1_append(&sha, (unsigned char *) tf->tgt_jid, strlen(tf->tgt_jid));960 sha1_finish(&sha, hash);961 962 for (i = 0; i < 20; i++) {963 sprintf(hash_hex + i * 2, "%02x", hash[i]);964 }965 938 966 939 bt = g_new0(struct bs_transfer, 1); 967 940 bt->tf = tf; 968 941 bt->phase = BS_PHASE_CONNECT; 969 bt->pseudoad r = g_strdup(hash_hex);942 bt->pseudoaddr = generate_pseudoaddr(tf->sid, tf->ini_jid, tf->tgt_jid); 970 943 tf->streamhandle = bt; 971 944 tf->ft->free = jabber_bs_free_transfer; … … 974 947 jabber_si_set_proxies(bt); 975 948 976 ret = jabber_bs_send_request(tf, bt->streamhosts); 977 978 return ret; 949 return jabber_bs_send_request(tf, bt->streamhosts); 979 950 } 980 951 … … 1139 1110 socks5_connect.atyp); 1140 1111 } 1141 if (!(memcmp(socks5_connect.address, bt->pseudoad r, 40) == 0)) {1112 if (!(memcmp(socks5_connect.address, bt->pseudoaddr, 40) == 0)) { 1142 1113 return jabber_bs_abort(bt, "SOCKS5 Connect message contained wrong digest"); 1143 1114 } -
protocols/jabber/sasl.c
r531eabd rb1dc403 42 42 "https://www.facebook.com/dialog/oauth", 43 43 "https://graph.facebook.com/oauth/access_token", 44 "http ://www.bitlbee.org/main.php/Facebook/oauth2.html",44 "https://www.bitlbee.org/main.php/Facebook/oauth2.html", 45 45 "offline_access,xmpp_login", 46 46 "126828914005625", … … 55 55 char *s; 56 56 int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_fb = 0; 57 int want_oauth = FALSE ;57 int want_oauth = FALSE, want_hipchat = FALSE; 58 58 GString *mechs; 59 59 … … 75 75 76 76 want_oauth = set_getbool(&ic->acc->set, "oauth"); 77 want_hipchat = (jd->flags & JFLAG_HIPCHAT); 77 78 78 79 mechs = g_string_new(""); … … 111 112 112 113 reply = xt_new_node("auth", NULL, NULL); 113 xt_add_attr(reply, "xmlns", XMLNS_SASL); 114 if (!want_hipchat) { 115 xt_add_attr(reply, "xmlns", XMLNS_SASL); 116 } else { 117 xt_add_attr(reply, "xmlns", XMLNS_HIPCHAT); 118 } 114 119 115 120 if (sup_gtalk && want_oauth) { … … 143 148 } else if (sup_plain) { 144 149 int len; 145 146 xt_add_attr(reply, "mechanism", "PLAIN"); 150 GString *gs; 151 char *username; 152 153 if (!want_hipchat) { 154 xt_add_attr(reply, "mechanism", "PLAIN"); 155 username = jd->username; 156 } else { 157 username = jd->me; 158 } 159 160 /* set an arbitrary initial size to avoid reallocations */ 161 gs = g_string_sized_new(128); 147 162 148 163 /* With SASL PLAIN in XMPP, the text should be b64(\0user\0pass) */ 149 len = strlen(jd->username) + strlen(ic->acc->pass) + 2; 150 s = g_malloc(len + 1); 151 s[0] = 0; 152 strcpy(s + 1, jd->username); 153 strcpy(s + 2 + strlen(jd->username), ic->acc->pass); 164 g_string_append_c(gs, '\0'); 165 g_string_append(gs, username); 166 g_string_append_c(gs, '\0'); 167 g_string_append(gs, ic->acc->pass); 168 if (want_hipchat) { 169 /* Hipchat's variation adds \0resource at the end */ 170 g_string_append_c(gs, '\0'); 171 g_string_append(gs, set_getstr(&ic->acc->set, "resource")); 172 } 173 174 len = gs->len; 175 s = g_string_free(gs, FALSE); 176 154 177 reply->text = base64_encode((unsigned char *) s, len); 155 178 reply->text_len = strlen(reply->text); … … 397 420 imcb_log(ic, "Authentication finished"); 398 421 jd->flags |= JFLAG_AUTHENTICATED | JFLAG_STREAM_RESTART; 422 423 if (jd->flags & JFLAG_HIPCHAT) { 424 return hipchat_handle_success(ic, node); 425 } 399 426 } else if (strcmp(node->name, "failure") == 0) { 400 427 imcb_error(ic, "Authentication failure"); -
protocols/msn/Makefile
r531eabd rb1dc403 13 13 14 14 # [SH] Program variables 15 objects = msn.o msn_util.o ns.o s b.o soap.o tables.o15 objects = msn.o msn_util.o ns.o soap.o tables.o gw.o 16 16 17 17 LFLAGS += -r -
protocols/msn/msn.c
r531eabd rb1dc403 30 30 int msn_chat_id; 31 31 GSList *msn_connections; 32 GSList *msn_switchboards;33 32 34 33 static char *set_eval_display_name(set_t *set, char *value); … … 41 40 s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY; 42 41 43 s = set_add(&acc->set, "server", MSN_NS_HOST, set_eval_account, acc);42 s = set_add(&acc->set, "server", NULL, set_eval_account, acc); 44 43 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY; 45 44 … … 48 47 49 48 set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc); 50 set_add(&acc->set, "switchboard_keepalives", "false", set_eval_bool, acc);51 49 52 50 acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE | … … 58 56 struct im_connection *ic = imcb_new(acc); 59 57 struct msn_data *md = g_new0(struct msn_data, 1); 58 char *server = set_getstr(&ic->acc->set, "server"); 60 59 61 60 ic->proto_data = md; 62 61 ic->flags |= OPT_PONGS | OPT_PONGED; 62 63 if (!server) { 64 server = "geo.gateway.messenger.live.com"; 65 } 63 66 64 67 if (strchr(acc->user, '@') == NULL) { … … 71 74 md->away_state = msn_away_state_list; 72 75 md->domaintree = g_tree_new(msn_domaintree_cmp); 73 md->ns->fd = -1; 76 md->fd = -1; 77 md->is_http = TRUE; 74 78 75 79 msn_connections = g_slist_prepend(msn_connections, ic); 76 80 77 81 imcb_log(ic, "Connecting"); 78 msn_ns_connect(ic, md->ns, 79 set_getstr(&ic->acc->set, "server"), 82 msn_ns_connect(ic, server, 80 83 set_getint(&ic->acc->set, "port")); 81 84 } … … 88 91 89 92 if (md) { 90 /** Disabling MSN ft support for now. 91 while( md->filetransfers ) { 92 imcb_file_canceled( md->filetransfers->data, "Closing connection" ); 93 } 94 */ 95 96 msn_ns_close(md->ns); 97 98 while (md->switchboards) { 99 msn_sb_destroy(md->switchboards->data); 100 } 101 102 msn_msgq_purge(ic, &md->msgq); 93 msn_ns_close(md); 94 103 95 msn_soapq_flush(ic, FALSE); 104 96 … … 112 104 while (md->groups) { 113 105 struct msn_group *mg = md->groups->data; 106 md->groups = g_slist_remove(md->groups, mg); 114 107 g_free(mg->id); 115 108 g_free(mg->name); 116 109 g_free(mg); 117 md->groups = g_slist_remove(md->groups, mg);118 110 } 119 111 … … 127 119 while (md->grpq) { 128 120 struct msn_groupadd *ga = md->grpq->data; 121 md->grpq = g_slist_remove(md->grpq, ga); 129 122 g_free(ga->group); 130 123 g_free(ga->who); 131 124 g_free(ga); 132 md->grpq = g_slist_remove(md->grpq, ga);133 125 } 134 126 … … 152 144 { 153 145 struct bee_user *bu = bee_user_by_handle(ic->bee, ic, who); 154 struct msn_buddy_data *bd = bu ? bu->data : NULL;155 struct msn_switchboard *sb;156 146 157 147 #ifdef DEBUG 158 148 if (strcmp(who, "raw") == 0) { 159 149 msn_ns_write(ic, -1, "%s\r\n", message); 160 } else 150 return 0; 151 } 161 152 #endif 162 if (bd && bd->flags & MSN_BUDDY_FED) { 163 msn_ns_sendmessage(ic, bu, message); 164 } else if ((sb = msn_sb_by_handle(ic, who))) { 165 return(msn_sb_sendmessage(sb, message)); 166 } else { 167 struct msn_message *m; 168 169 /* Create a message. We have to arrange a usable switchboard, and send the message later. */ 170 m = g_new0(struct msn_message, 1); 171 m->who = g_strdup(who); 172 m->text = g_strdup(message); 173 174 return msn_sb_write_msg(ic, m); 175 } 176 153 154 msn_ns_sendmessage(ic, bu, message); 177 155 return(0); 178 156 } … … 196 174 static void msn_set_away(struct im_connection *ic, char *state, char *message) 197 175 { 198 char *uux;199 176 struct msn_data *md = ic->proto_data; 177 char *nick, *psm, *idle, *statecode, *body, *buf; 200 178 201 179 if (state == NULL) { … … 205 183 } 206 184 207 if (!msn_ns_write(ic, -1, "CHG %d %s %d:%02d\r\n", ++md->trId, md->away_state->code, MSN_CAP1, MSN_CAP2)) { 208 return; 209 } 210 211 uux = g_markup_printf_escaped("<EndpointData><Capabilities>%d:%02d" 212 "</Capabilities></EndpointData>", 213 MSN_CAP1, MSN_CAP2); 214 msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux); 215 g_free(uux); 216 217 uux = g_markup_printf_escaped("<PrivateEndpointData><EpName>%s</EpName>" 218 "<Idle>%s</Idle><ClientType>%d</ClientType>" 219 "<State>%s</State></PrivateEndpointData>", 220 md->uuid, 221 strcmp(md->away_state->code, "IDL") ? "false" : "true", 222 1, /* ? */ 223 md->away_state->code); 224 msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux); 225 g_free(uux); 226 227 uux = g_markup_printf_escaped("<Data><DDP></DDP><PSM>%s</PSM>" 228 "<CurrentMedia></CurrentMedia>" 229 "<MachineGuid>%s</MachineGuid></Data>", 230 message ? message : "", md->uuid); 231 msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux); 232 g_free(uux); 185 statecode = (char *) md->away_state->code; 186 nick = set_getstr(&ic->acc->set, "display_name"); 187 psm = message ? message : ""; 188 idle = (strcmp(statecode, "IDL") == 0) ? "false" : "true"; 189 190 body = g_markup_printf_escaped(MSN_PUT_USER_BODY, 191 nick, psm, psm, md->uuid, statecode, md->uuid, idle, statecode, 192 MSN_CAP1, MSN_CAP2, MSN_CAP1, MSN_CAP2 193 ); 194 195 buf = g_strdup_printf(MSN_PUT_HEADERS, ic->acc->user, ic->acc->user, md->uuid, 196 "/user", "application/user+xml", 197 strlen(body), body); 198 msn_ns_write(ic, -1, "PUT %d %zd\r\n%s", ++md->trId, strlen(buf), buf); 199 200 g_free(buf); 201 g_free(body); 233 202 } 234 203 … … 256 225 static void msn_chat_msg(struct groupchat *c, char *message, int flags) 257 226 { 258 struct msn_switchboard *sb = msn_sb_by_chat(c); 259 260 if (sb) { 261 msn_sb_sendmessage(sb, message); 262 } 263 /* FIXME: Error handling (although this can't happen unless something's 264 already severely broken) disappeared here! */ 227 /* TODO: groupchats*/ 265 228 } 266 229 267 230 static void msn_chat_invite(struct groupchat *c, char *who, char *message) 268 231 { 269 struct msn_switchboard *sb = msn_sb_by_chat(c); 270 271 if (sb) { 272 msn_sb_write(sb, "CAL %d %s\r\n", ++sb->trId, who); 273 } 232 /* TODO: groupchats*/ 274 233 } 275 234 276 235 static void msn_chat_leave(struct groupchat *c) 277 236 { 278 struct msn_switchboard *sb = msn_sb_by_chat(c); 279 280 if (sb) { 281 msn_sb_write(sb, "OUT\r\n"); 282 } 237 /* TODO: groupchats*/ 283 238 } 284 239 285 240 static struct groupchat *msn_chat_with(struct im_connection *ic, char *who) 286 241 { 287 struct msn_switchboard *sb;242 /* TODO: groupchats*/ 288 243 struct groupchat *c = imcb_chat_new(ic, who); 289 290 if ((sb = msn_sb_by_handle(ic, who))) { 291 debug("Converting existing switchboard to %s to a groupchat", who); 292 return msn_sb_to_chat(sb); 293 } else { 294 struct msn_message *m; 295 296 /* Create a magic message. This is quite hackish, but who cares? :-P */ 297 m = g_new0(struct msn_message, 1); 298 m->who = g_strdup(who); 299 m->text = g_strdup(GROUPCHAT_SWITCHBOARD_MESSAGE); 300 301 msn_sb_write_msg(ic, m); 302 303 return c; 304 } 244 return c; 305 245 } 306 246 … … 322 262 static void msn_add_deny(struct im_connection *ic, char *who) 323 263 { 324 struct msn_switchboard *sb;325 326 264 msn_buddy_list_add(ic, MSN_BUDDY_BL, who, who, NULL); 327 328 /* If there's still a conversation with this person, close it. */329 if ((sb = msn_sb_by_handle(ic, who))) {330 msn_sb_destroy(sb);331 }332 265 } 333 266 … … 462 395 ret->buddy_action = msn_buddy_action; 463 396 464 //ret->transfer_request = msn_ftp_transfer_request;465 466 397 register_protocol(ret); 467 398 } -
protocols/msn/msn.h
r531eabd rb1dc403 32 32 #define NUDGE_MESSAGE "\r\r\rSHAKE THAT THING\r\r\r" 33 33 #define GROUPCHAT_SWITCHBOARD_MESSAGE "\r\r\rME WANT TALK TO MANY PEOPLE\r\r\r" 34 #define SB_KEEPALIVE_MESSAGE "\r\r\rDONT HANG UP ON ME!\r\r\r"35 34 36 35 #ifdef DEBUG_MSN … … 60 59 #define MSNP11_PROD_KEY "C1BX{V4W}Q3*10SM" 61 60 #define MSNP11_PROD_ID "PROD0120PW!CCV9@" 62 #define MSNP_VER "MSNP 18"61 #define MSNP_VER "MSNP21" 63 62 #define MSNP_BUILD "14.0.8117.416" 64 63 … … 68 67 #define MSN_CAP2 0x0000 69 68 70 #define MSN_MESSAGE_HEADERS "MIME-Version: 1.0\r\n" \ 69 #define MSN_BASE_HEADERS \ 70 "Routing: 1.0\r\n" \ 71 "To: 1:%s\r\n" \ 72 "From: 1:%s;epid={%s}\r\n" \ 73 "\r\n" \ 74 "Reliability: 1.0\r\n" \ 75 "\r\n" 76 77 #define MSN_MESSAGE_HEADERS MSN_BASE_HEADERS \ 78 "Messaging: 2.0\r\n" \ 79 "Message-Type: Text\r\n" \ 80 "Content-Length: %zd\r\n" \ 71 81 "Content-Type: text/plain; charset=UTF-8\r\n" \ 72 "User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \ 73 "X-MMS-IM-Format: FN=MS%20Shell%20Dlg; EF=; CO=0; CS=0; PF=0\r\n" \ 74 "\r\n" 82 "X-MMS-IM-Format: FN=Segoe%%20UI; EF=; CO=0; CS=0; PF=0\r\n" \ 83 "\r\n" \ 84 "%s" 85 86 #define MSN_PUT_HEADERS MSN_BASE_HEADERS \ 87 "Publication: 1.0\r\n" \ 88 "Uri: %s\r\n" \ 89 "Content-Type: %s\r\n" \ 90 "Content-Length: %zd\r\n" \ 91 "\r\n" \ 92 "%s" 93 94 #define MSN_PUT_USER_BODY \ 95 "<user>" \ 96 "<s n=\"PE\"><UserTileLocation></UserTileLocation><FriendlyName>%s</FriendlyName><PSM>%s</PSM><DDP></DDP>" \ 97 "<Scene></Scene><ASN></ASN><ColorScheme>-3</ColorScheme><BDG></BDG><RUM>%s</RUM><RUL></RUL><RLT>0</RLT>" \ 98 "<RID></RID><SUL></SUL><MachineGuid>%s</MachineGuid></s>" \ 99 "<s n=\"IM\"><Status>%s</Status><CurrentMedia></CurrentMedia></s>" \ 100 "<sep n=\"PD\"><ClientType>1</ClientType><EpName>%s</EpName><Idle>%s</Idle><State>%s</State></sep>" \ 101 "<sep n=\"PE\"><VER>BitlBee:" BITLBEE_VERSION "</VER><TYP>1</TYP><Capabilities>%d:%d</Capabilities></sep>" \ 102 "<sep n=\"IM\"><Capabilities>%d:%d</Capabilities></sep>" \ 103 "</user>" 75 104 76 105 #define MSN_TYPING_HEADERS "MIME-Version: 1.0\r\n" \ … … 84 113 "ID: 1\r\n" \ 85 114 "\r\n" 86 87 #define MSN_SB_KEEPALIVE_HEADERS "MIME-Version: 1.0\r\n" \88 "Content-Type: text/x-ping\r\n" \89 "\r\n\r\n"90 115 91 116 #define PROFILE_URL "http://members.msn.com/" … … 99 124 } msn_flags_t; 100 125 101 struct msn_handler_data { 126 struct msn_gw { 127 char *last_host; 128 int port; 129 gboolean ssl; 130 131 char *session_id; 132 133 GByteArray *in; 134 GByteArray *out; 135 136 int poll_timeout; 137 138 b_event_handler callback; 139 140 struct im_connection *ic; 141 struct msn_data *md; 142 143 gboolean open; 144 gboolean waiting; 145 gboolean polling; 146 }; 147 148 struct msn_data { 102 149 int fd, inpa; 103 150 int rxlen; … … 107 154 char *cmd_text; 108 155 109 /* Either ic or sb */110 gpointer data;111 112 int (*exec_command) (struct msn_handler_data *handler, char **cmd, int count);113 int (*exec_message) (struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int count);114 };115 116 struct msn_data {117 156 struct im_connection *ic; 118 157 119 struct msn_handler_data ns[1];120 158 msn_flags_t flags; 121 159 … … 126 164 127 165 GSList *msgq, *grpq, *soapq; 128 GSList *switchboards;129 int sb_failures;130 time_t first_sb_failure;131 166 132 167 const struct msn_away_state *away_state; … … 139 174 GTree *domaintree; 140 175 int adl_todo; 141 }; 142 143 struct msn_switchboard { 144 struct im_connection *ic; 145 146 /* The following two are also in the handler. TODO: Clean up. */ 147 int fd; 148 gint inp; 149 struct msn_handler_data *handler; 150 gint keepalive; 151 152 int trId; 153 int ready; 154 155 int session; 156 char *key; 157 158 GSList *msgq; 159 char *who; 160 struct groupchat *chat; 176 177 gboolean is_http; 178 struct msn_gw *gw; 161 179 }; 162 180 … … 205 223 #define STATUS_FATAL 1 206 224 #define STATUS_SB_FATAL 2 207 #define STATUS_SB_IM_SPARE 4 /* Make one-to-one conversation switchboard available again, invite failed. */208 #define STATUS_SB_CHAT_SPARE 8 /* Same, but also for groupchats (not used yet). */209 225 210 226 extern int msn_chat_id; … … 218 234 before doing *anything* else. */ 219 235 extern GSList *msn_connections; 220 extern GSList *msn_switchboards;221 236 222 237 /* ns.c */ 223 238 int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) G_GNUC_PRINTF(3, 4); 224 gboolean msn_ns_connect(struct im_connection *ic, struct msn_handler_data *handler,const char *host, int port);225 void msn_ns_close(struct msn_ handler_data *handler);239 gboolean msn_ns_connect(struct im_connection *ic, const char *host, int port); 240 void msn_ns_close(struct msn_data *handler); 226 241 void msn_auth_got_passport_token(struct im_connection *ic, const char *token, const char *error); 227 242 void msn_auth_got_contact_list(struct im_connection *ic); 228 243 int msn_ns_finish_login(struct im_connection *ic); 229 244 int msn_ns_sendmessage(struct im_connection *ic, struct bee_user *bu, const char *text); 230 void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq); 245 int msn_ns_command(struct msn_data *md, char **cmd, int num_parts); 246 int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts); 231 247 232 248 /* msn_util.c */ … … 235 251 int msn_buddy_list_remove(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group); 236 252 void msn_buddy_ask(bee_user_t *bu); 237 char **msn_linesplit(char *line); 238 int msn_handler(struct msn_handler_data *h); 239 void msn_msgq_purge(struct im_connection *ic, GSList **list); 253 void msn_queue_feed(struct msn_data *h, char *bytes, int st); 254 int msn_handler(struct msn_data *h); 240 255 char *msn_p11_challenge(char *challenge); 241 256 gint msn_domaintree_cmp(gconstpointer a_, gconstpointer b_); … … 251 266 const struct msn_status_code *msn_status_by_number(int number); 252 267 253 /* sb.c */ 254 int msn_sb_write(struct msn_switchboard *sb, const char *fmt, ...) G_GNUC_PRINTF(2, 3);; 255 struct msn_switchboard *msn_sb_create(struct im_connection *ic, char *host, int port, char *key, int session); 256 struct msn_switchboard *msn_sb_by_handle(struct im_connection *ic, const char *handle); 257 struct msn_switchboard *msn_sb_by_chat(struct groupchat *c); 258 struct msn_switchboard *msn_sb_spare(struct im_connection *ic); 259 int msn_sb_sendmessage(struct msn_switchboard *sb, char *text); 260 struct groupchat *msn_sb_to_chat(struct msn_switchboard *sb); 261 void msn_sb_destroy(struct msn_switchboard *sb); 262 gboolean msn_sb_connected(gpointer data, gint source, b_input_condition cond); 263 int msn_sb_write_msg(struct im_connection *ic, struct msn_message *m); 264 void msn_sb_start_keepalives(struct msn_switchboard *sb, gboolean initial); 265 void msn_sb_stop_keepalives(struct msn_switchboard *sb); 268 /* gw.c */ 269 struct msn_gw *msn_gw_new(struct im_connection *ic); 270 void msn_gw_free(struct msn_gw *gw); 271 void msn_gw_open(struct msn_gw *gw); 272 ssize_t msn_gw_read(struct msn_gw *gw, char **buf); 273 void msn_gw_write(struct msn_gw *gw, char *buf, size_t len); 266 274 267 275 #endif //_MSN_H -
protocols/msn/msn_util.c
r531eabd rb1dc403 55 55 56 56 *groupid = '\0'; 57 #if 058 if (group) {59 int i;60 for (i = 0; i < md->groupcount; i++) {61 if (g_strcasecmp(md->grouplist[i], group) == 0) {62 g_snprintf(groupid, sizeof(groupid), " %d", i);63 break;64 }65 }66 67 if (*groupid == '\0') {68 /* Have to create this group, it doesn't exist yet. */69 struct msn_groupadd *ga;70 GSList *l;71 72 for (l = md->grpq; l; l = l->next) {73 ga = l->data;74 if (g_strcasecmp(ga->group, group) == 0) {75 break;76 }77 }78 79 ga = g_new0(struct msn_groupadd, 1);80 ga->who = g_strdup(who);81 ga->group = g_strdup(group);82 md->grpq = g_slist_prepend(md->grpq, ga);83 84 if (l == NULL) {85 char groupname[strlen(group) + 1];86 strcpy(groupname, group);87 http_encode(groupname);88 g_snprintf(buf, sizeof(buf), "ADG %d %s %d\r\n", ++md->trId, groupname, 0);89 return msn_write(ic, buf, strlen(buf));90 } else {91 /* This can happen if the user's doing lots of adds to a92 new group at once; we're still waiting for the server93 to confirm group creation. */94 return 1;95 }96 }97 }98 #endif99 57 100 58 if (!((bu = bee_user_by_handle(ic->bee, ic, who)) || … … 132 90 133 91 *groupid = '\0'; 134 #if 0135 if (group) {136 int i;137 for (i = 0; i < md->groupcount; i++) {138 if (g_strcasecmp(md->grouplist[i], group) == 0) {139 g_snprintf(groupid, sizeof(groupid), " %d", i);140 break;141 }142 }143 }144 #endif145 92 146 93 if (!(bu = bee_user_by_handle(ic->bee, ic, who)) || … … 174 121 }; 175 122 176 static void msn_buddy_ask_ yes(void *data)123 static void msn_buddy_ask_free(void *data) 177 124 { 178 125 struct msn_buddy_ask_data *bla = data; 179 180 msn_buddy_list_add(bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL);181 182 imcb_ask_add(bla->ic, bla->handle, NULL);183 126 184 127 g_free(bla->handle); … … 187 130 } 188 131 132 static void msn_buddy_ask_yes(void *data) 133 { 134 struct msn_buddy_ask_data *bla = data; 135 136 msn_buddy_list_add(bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL); 137 138 imcb_ask_add(bla->ic, bla->handle, NULL); 139 140 msn_buddy_ask_free(bla); 141 } 142 189 143 static void msn_buddy_ask_no(void *data) 190 144 { … … 193 147 msn_buddy_list_add(bla->ic, MSN_BUDDY_BL, bla->handle, bla->realname, NULL); 194 148 195 g_free(bla->handle); 196 g_free(bla->realname); 197 g_free(bla); 149 msn_buddy_ask_free(bla); 198 150 } 199 151 … … 216 168 "The user %s (%s) wants to add you to his/her buddy list.", 217 169 bu->handle, bu->fullname); 218 imcb_ask(bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no); 219 } 220 221 /* *NOT* thread-safe, but that's not a problem for now... */ 222 char **msn_linesplit(char *line) 223 { 224 static char **ret = NULL; 225 static int size = 3; 226 int i, n = 0; 227 228 if (ret == NULL) { 229 ret = g_new0(char*, size); 230 } 231 232 for (i = 0; line[i] && line[i] == ' '; i++) { 233 ; 234 } 235 if (line[i]) { 236 ret[n++] = line + i; 237 for (i++; line[i]; i++) { 238 if (line[i] == ' ') { 239 line[i] = 0; 240 } else if (line[i] != ' ' && !line[i - 1]) { 241 ret[n++] = line + i; 242 } 243 244 if (n >= size) { 245 ret = g_renew(char*, ret, size += 2); 246 } 247 } 248 } 249 ret[n] = NULL; 250 251 return(ret); 170 171 imcb_ask_with_free(bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no, msn_buddy_ask_free); 172 } 173 174 void msn_queue_feed(struct msn_data *h, char *bytes, int st) 175 { 176 h->rxq = g_renew(char, h->rxq, h->rxlen + st); 177 memcpy(h->rxq + h->rxlen, bytes, st); 178 h->rxlen += st; 179 180 if (getenv("BITLBEE_DEBUG")) { 181 fprintf(stderr, "\n\x1b[92m<<< "); 182 write(2, bytes , st); 183 fprintf(stderr, "\x1b[97m"); 184 } 252 185 } 253 186 … … 260 193 1: OK */ 261 194 262 int msn_handler(struct msn_handler_data *h) 263 { 264 int st; 265 266 h->rxq = g_renew(char, h->rxq, h->rxlen + 1024); 267 st = read(h->fd, h->rxq + h->rxlen, 1024); 268 h->rxlen += st; 269 270 if (st <= 0) { 271 return(-1); 272 } 273 274 if (getenv("BITLBEE_DEBUG")) { 275 write(2, "->C:", 4); 276 write(2, h->rxq + h->rxlen - st, st); 277 } 195 int msn_handler(struct msn_data *h) 196 { 197 int st = 1; 278 198 279 199 while (st) { … … 287 207 288 208 cmd_text = g_strndup(h->rxq, i); 289 cmd = msn_linesplit(cmd_text); 290 for (count = 0; cmd[count]; count++) { 291 ; 292 } 293 st = h->exec_command(h, cmd, count); 209 cmd = g_strsplit_set(cmd_text, " ", -1); 210 count = g_strv_length(cmd); 211 212 st = msn_ns_command(h, cmd, count); 213 214 g_strfreev(cmd); 294 215 g_free(cmd_text); 295 216 … … 314 235 /* If we reached the end of the buffer, there's still an incomplete command there. 315 236 Return and wait for more data. */ 316 if (i == h->rxlen && h->rxq[i - 1] != '\r' && h->rxq[i - 1] != '\n') {237 if (i && i == h->rxlen && h->rxq[i - 1] != '\r' && h->rxq[i - 1] != '\n') { 317 238 break; 318 239 } … … 327 248 328 249 msg = g_strndup(h->rxq, h->msglen); 329 cmd = msn_linesplit(h->cmd_text); 330 for (count = 0; cmd[count]; count++) { 331 ; 332 } 333 334 st = h->exec_message(h, msg, h->msglen, cmd, count); 250 251 cmd = g_strsplit_set(h->cmd_text, " ", -1); 252 count = g_strv_length(cmd); 253 254 st = msn_ns_message(h, msg, h->msglen, cmd, count); 255 256 g_strfreev(cmd); 335 257 g_free(msg); 336 258 g_free(h->cmd_text); … … 366 288 } 367 289 368 void msn_msgq_purge(struct im_connection *ic, GSList **list)369 {370 struct msn_message *m;371 GString *ret;372 GSList *l;373 int n = 0;374 375 l = *list;376 if (l == NULL) {377 return;378 }379 380 m = l->data;381 ret = g_string_sized_new(1024);382 g_string_printf(ret, "Warning: Cleaning up MSN (switchboard) connection with unsent "383 "messages to %s:", m->who ? m->who : "unknown recipient");384 385 while (l) {386 m = l->data;387 388 if (strncmp(m->text, "\r\r\r", 3) != 0) {389 g_string_append_printf(ret, "\n%s", m->text);390 n++;391 }392 393 g_free(m->who);394 g_free(m->text);395 g_free(m);396 397 l = l->next;398 }399 g_slist_free(*list);400 *list = NULL;401 402 if (n > 0) {403 imcb_log(ic, "%s", ret->str);404 }405 g_string_free(ret, TRUE);406 }407 408 290 /* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */ 409 291 char *msn_p11_challenge(char *challenge) … … 529 411 int msn_ns_set_display_name(struct im_connection *ic, const char *value) 530 412 { 531 struct msn_data *md = ic->proto_data; 532 char fn[strlen(value) * 3 + 1]; 533 534 strcpy(fn, value); 535 http_encode(fn); 536 537 /* Note: We don't actually know if the server accepted the new name, 538 and won't give proper feedback yet if it doesn't. */ 539 return msn_ns_write(ic, -1, "PRP %d MFN %s\r\n", ++md->trId, fn); 413 // TODO, implement this through msn_set_away's method 414 return 1; 540 415 } 541 416 -
protocols/msn/ns.c
r531eabd rb1dc403 35 35 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond); 36 36 static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond); 37 static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts);38 static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts);39 37 40 38 static void msn_ns_send_adl_start(struct im_connection *ic); 41 39 static void msn_ns_send_adl(struct im_connection *ic); 40 static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd); 41 static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action); 42 static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put); 42 43 43 44 int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) … … 54 55 55 56 if (fd < 0) { 56 fd = md-> ns->fd;57 fd = md->fd; 57 58 } 58 59 59 60 if (getenv("BITLBEE_DEBUG")) { 60 fprintf(stderr, " ->NS%d:%s\n", fd, out);61 fprintf(stderr, "\x1b[91m>>>[NS%d] %s\n\x1b[97m", fd, out); 61 62 } 62 63 63 64 len = strlen(out); 64 st = write(fd, out, len); 65 66 if (md->is_http) { 67 st = len; 68 msn_gw_write(md->gw, out, len); 69 } else { 70 st = write(fd, out, len); 71 } 72 65 73 g_free(out); 66 74 if (st != len) { … … 73 81 } 74 82 75 gboolean msn_ns_connect(struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port) 76 { 77 if (handler->fd >= 0) { 78 closesocket(handler->fd); 79 } 80 81 handler->exec_command = msn_ns_command; 82 handler->exec_message = msn_ns_message; 83 handler->data = ic; 84 handler->fd = proxy_connect(host, port, msn_ns_connected, handler); 85 if (handler->fd < 0) { 83 gboolean msn_ns_connect(struct im_connection *ic, const char *host, int port) 84 { 85 struct msn_data *md = ic->proto_data; 86 87 if (md->fd >= 0) { 88 closesocket(md->fd); 89 } 90 91 if (md->is_http) { 92 md->gw = msn_gw_new(ic); 93 md->gw->callback = msn_ns_callback; 94 msn_ns_connected(md, -1, B_EV_IO_READ); 95 } else { 96 md->fd = proxy_connect(host, port, msn_ns_connected, md); 97 if (md->fd < 0) { 98 imcb_error(ic, "Could not connect to server"); 99 imc_logout(ic, TRUE); 100 return FALSE; 101 } 102 } 103 104 return TRUE; 105 } 106 107 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond) 108 { 109 struct msn_data *md = data; 110 struct im_connection *ic = md->ic; 111 112 if (source == -1 && !md->is_http) { 86 113 imcb_error(ic, "Could not connect to server"); 87 114 imc_logout(ic, TRUE); … … 89 116 } 90 117 91 return TRUE; 92 } 93 94 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond) 95 { 96 struct msn_handler_data *handler = data; 97 struct im_connection *ic = handler->data; 98 struct msn_data *md; 99 100 if (!g_slist_find(msn_connections, ic)) { 101 return FALSE; 102 } 103 104 md = ic->proto_data; 105 106 if (source == -1) { 107 imcb_error(ic, "Could not connect to server"); 108 imc_logout(ic, TRUE); 109 return FALSE; 110 } 111 112 g_free(handler->rxq); 113 handler->rxlen = 0; 114 handler->rxq = g_new0(char, 1); 118 g_free(md->rxq); 119 md->rxlen = 0; 120 md->rxq = g_new0(char, 1); 115 121 116 122 if (md->uuid == NULL) { … … 130 136 131 137 if (msn_ns_write(ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER)) { 132 handler->inpa = b_input_add(handler->fd, B_EV_IO_READ, msn_ns_callback, handler); 138 if (!md->is_http) { 139 md->inpa = b_input_add(md->fd, B_EV_IO_READ, msn_ns_callback, md); 140 } 133 141 imcb_log(ic, "Connected to server, waiting for reply"); 134 142 } … … 137 145 } 138 146 139 void msn_ns_close(struct msn_handler_data *handler) 140 { 141 if (handler->fd >= 0) { 142 closesocket(handler->fd); 143 b_event_remove(handler->inpa); 144 } 145 146 handler->fd = handler->inpa = -1; 147 g_free(handler->rxq); 148 g_free(handler->cmd_text); 149 150 handler->rxlen = 0; 151 handler->rxq = NULL; 152 handler->cmd_text = NULL; 147 void msn_ns_close(struct msn_data *md) 148 { 149 if (md->gw) { 150 msn_gw_free(md->gw); 151 } 152 if (md->fd >= 0) { 153 closesocket(md->fd); 154 b_event_remove(md->inpa); 155 } 156 157 md->fd = md->inpa = -1; 158 g_free(md->rxq); 159 g_free(md->cmd_text); 160 161 md->rxlen = 0; 162 md->rxq = NULL; 163 md->cmd_text = NULL; 153 164 } 154 165 155 166 static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond) 156 167 { 157 struct msn_handler_data *handler = data; 158 struct im_connection *ic = handler->data; 159 160 if (msn_handler(handler) == -1) { /* Don't do this on ret == 0, it's already done then. */ 168 struct msn_data *md = data; 169 struct im_connection *ic = md->ic; 170 char *bytes; 171 int st; 172 173 if (md->is_http) { 174 st = msn_gw_read(md->gw, &bytes); 175 } else { 176 bytes = g_malloc(1024); 177 st = read(md->fd, bytes, 1024); 178 } 179 180 if (st <= 0) { 161 181 imcb_error(ic, "Error while reading from server"); 162 182 imc_logout(ic, TRUE); 163 164 183 return FALSE; 165 } else { 166 return TRUE; 167 } 168 } 169 170 static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts) 171 { 172 struct im_connection *ic = handler->data; 173 struct msn_data *md = ic->proto_data; 184 } 185 186 msn_queue_feed(md, bytes, st); 187 188 g_free(bytes); 189 190 /* Ignore ret == 0, it's already disconnected then. */ 191 msn_handler(md); 192 193 return TRUE; 194 195 } 196 197 int msn_ns_command(struct msn_data *md, char **cmd, int num_parts) 198 { 199 struct im_connection *ic = md->ic; 174 200 175 201 if (num_parts == 0) { … … 185 211 } 186 212 187 return(msn_ns_write(ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n",213 return(msn_ns_write(ic, md->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s VmVyc2lvbjogMQ0KWGZyQ291bnQ6IDINClhmclNlbnRVVENUaW1lOiA2MzU2MTQ3OTU5NzgzOTAwMDANCklzR2VvWGZyOiB0cnVlDQo=\r\n", 188 214 ++md->trId, ic->acc->user)); 189 215 } else if (strcmp(cmd[0], "CVR") == 0) { 190 216 /* We don't give a damn about the information we just received */ 191 return msn_ns_write(ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user);217 return msn_ns_write(ic, md->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user); 192 218 } else if (strcmp(cmd[0], "XFR") == 0) { 193 219 char *server; … … 195 221 196 222 if (num_parts >= 6 && strcmp(cmd[2], "NS") == 0) { 197 b_event_remove( handler->inpa);198 handler->inpa = -1;223 b_event_remove(md->inpa); 224 md->inpa = -1; 199 225 200 226 server = strchr(cmd[3], ':'); … … 209 235 210 236 imcb_log(ic, "Transferring to other server"); 211 return msn_ns_connect(ic, handler, server, port); 212 } else if (num_parts >= 6 && strcmp(cmd[2], "SB") == 0) { 213 struct msn_switchboard *sb; 214 215 server = strchr(cmd[3], ':'); 216 if (!server) { 217 imcb_error(ic, "Syntax error"); 218 imc_logout(ic, TRUE); 219 return(0); 220 } 221 *server = 0; 222 port = atoi(server + 1); 223 server = cmd[3]; 224 225 if (strcmp(cmd[4], "CKI") != 0) { 226 imcb_error(ic, "Unknown authentication method for switchboard"); 227 imc_logout(ic, TRUE); 228 return(0); 229 } 230 231 debug("Connecting to a new switchboard with key %s", cmd[5]); 232 233 if ((sb = msn_sb_create(ic, server, port, cmd[5], MSN_SB_NEW)) == NULL) { 234 /* Although this isn't strictly fatal for the NS connection, it's 235 definitely something serious (we ran out of file descriptors?). */ 236 imcb_error(ic, "Could not create new switchboard"); 237 imc_logout(ic, TRUE); 238 return(0); 239 } 240 241 if (md->msgq) { 242 struct msn_message *m = md->msgq->data; 243 GSList *l; 244 245 sb->who = g_strdup(m->who); 246 247 /* Move all the messages to the first user in the message 248 queue to the switchboard message queue. */ 249 l = md->msgq; 250 while (l) { 251 m = l->data; 252 l = l->next; 253 if (strcmp(m->who, sb->who) == 0) { 254 sb->msgq = g_slist_append(sb->msgq, m); 255 md->msgq = g_slist_remove(md->msgq, m); 256 } 257 } 258 } 237 return msn_ns_connect(ic, server, port); 259 238 } else { 260 239 imcb_error(ic, "Syntax error"); … … 290 269 } 291 270 292 handler->msglen = atoi(cmd[3]);293 294 if ( handler->msglen <= 0) {271 md->msglen = atoi(cmd[3]); 272 273 if (md->msglen <= 0) { 295 274 imcb_error(ic, "Syntax error"); 296 275 imc_logout(ic, TRUE); 297 276 return(0); 298 277 } 299 } else if (strcmp(cmd[0], "BLP") == 0) {300 msn_ns_send_adl_start(ic);301 return msn_ns_finish_login(ic);302 278 } else if (strcmp(cmd[0], "ADL") == 0) { 303 279 if (num_parts >= 3 && strcmp(cmd[2], "OK") == 0) { … … 305 281 return msn_ns_finish_login(ic); 306 282 } else if (num_parts >= 3) { 307 handler->msglen = atoi(cmd[2]); 308 } 309 } else if (strcmp(cmd[0], "PRP") == 0) { 310 imcb_connected(ic); 283 md->msglen = atoi(cmd[2]); 284 } 311 285 } else if (strcmp(cmd[0], "CHL") == 0) { 312 286 char *resp; … … 326 300 g_free(resp); 327 301 return st; 328 } else if (strcmp(cmd[0], "ILN") == 0 || strcmp(cmd[0], "NLN") == 0) { 329 const struct msn_away_state *st; 330 const char *handle; 331 int cap = 0; 332 333 if (num_parts < 6) { 334 imcb_error(ic, "Syntax error"); 335 imc_logout(ic, TRUE); 336 return(0); 337 } 338 /* ILN and NLN are more or less the same, except ILN has a trId 339 at the start, and NLN has a capability field at the end. 340 Does ILN still exist BTW? */ 341 if (cmd[0][1] == 'I') { 342 cmd++; 343 } else { 344 cap = atoi(cmd[4]); 345 } 346 347 handle = msn_normalize_handle(cmd[2]); 348 if (strcmp(handle, ic->acc->user) == 0) { 349 return 1; /* That's me! */ 350 351 } 352 http_decode(cmd[3]); 353 imcb_rename_buddy(ic, handle, cmd[3]); 354 355 st = msn_away_state_by_code(cmd[1]); 356 if (!st) { 357 /* FIXME: Warn/Bomb about unknown away state? */ 358 st = msn_away_state_list + 1; 359 } 360 361 imcb_buddy_status(ic, handle, OPT_LOGGED_IN | 362 (st != msn_away_state_list ? OPT_AWAY : 0) | 363 (cap & 1 ? OPT_MOBILE : 0), 364 st->name, NULL); 365 366 msn_sb_stop_keepalives(msn_sb_by_handle(ic, handle)); 367 } else if (strcmp(cmd[0], "FLN") == 0) { 368 const char *handle; 369 370 if (cmd[1] == NULL) { 371 return 1; 372 } 373 374 handle = msn_normalize_handle(cmd[1]); 375 imcb_buddy_status(ic, handle, 0, NULL, NULL); 376 msn_sb_start_keepalives(msn_sb_by_handle(ic, handle), TRUE); 377 } else if (strcmp(cmd[0], "RNG") == 0) { 378 struct msn_switchboard *sb; 379 char *server; 380 int session, port; 381 382 if (num_parts < 7) { 383 imcb_error(ic, "Syntax error"); 384 imc_logout(ic, TRUE); 385 return(0); 386 } 387 388 session = atoi(cmd[1]); 389 390 server = strchr(cmd[2], ':'); 391 if (!server) { 392 imcb_error(ic, "Syntax error"); 393 imc_logout(ic, TRUE); 394 return(0); 395 } 396 *server = 0; 397 port = atoi(server + 1); 398 server = cmd[2]; 399 400 if (strcmp(cmd[3], "CKI") != 0) { 401 imcb_error(ic, "Unknown authentication method for switchboard"); 402 imc_logout(ic, TRUE); 403 return(0); 404 } 405 406 debug("Got a call from %s (session %d). Key = %s", cmd[5], session, cmd[4]); 407 408 if ((sb = msn_sb_create(ic, server, port, cmd[4], session)) == NULL) { 409 /* Although this isn't strictly fatal for the NS connection, it's 410 definitely something serious (we ran out of file descriptors?). */ 411 imcb_error(ic, "Could not create new switchboard"); 412 imc_logout(ic, TRUE); 413 return(0); 414 } else { 415 sb->who = g_strdup(msn_normalize_handle(cmd[5])); 416 } 302 } else if (strcmp(cmd[0], "QRY") == 0) { 303 /* CONGRATULATIONS */ 417 304 } else if (strcmp(cmd[0], "OUT") == 0) { 418 int allow_reconnect = TRUE; 419 420 if (cmd[1] && strcmp(cmd[1], "OTH") == 0) { 421 imcb_error(ic, "Someone else logged in with your account"); 422 allow_reconnect = FALSE; 423 } else if (cmd[1] && strcmp(cmd[1], "SSD") == 0) { 424 imcb_error(ic, "Terminating session because of server shutdown"); 425 } else { 426 imcb_error(ic, "Session terminated by remote server (%s)", 427 cmd[1] ? cmd[1] : "reason unknown)"); 428 } 429 430 imc_logout(ic, allow_reconnect); 305 imcb_error(ic, "Session terminated by remote server (%s)", cmd[1] ? cmd[1] : "reason unknown"); 306 imc_logout(ic, TRUE); 431 307 return(0); 432 } else if (strcmp(cmd[0], "IPG") == 0) { 433 imcb_error(ic, "Received IPG command, we don't handle them yet."); 434 435 handler->msglen = atoi(cmd[1]); 436 437 if (handler->msglen <= 0) { 438 imcb_error(ic, "Syntax error"); 439 imc_logout(ic, TRUE); 440 return(0); 441 } 442 } 443 #if 0 444 else if (strcmp(cmd[0], "ADG") == 0) { 445 char *group = g_strdup(cmd[3]); 446 int groupnum, i; 447 GSList *l, *next; 448 449 http_decode(group); 450 if (sscanf(cmd[4], "%d", &groupnum) == 1) { 451 if (groupnum >= md->groupcount) { 452 md->grouplist = g_renew(char *, md->grouplist, groupnum + 1); 453 for (i = md->groupcount; i <= groupnum; i++) { 454 md->grouplist[i] = NULL; 455 } 456 md->groupcount = groupnum + 1; 457 } 458 g_free(md->grouplist[groupnum]); 459 md->grouplist[groupnum] = group; 460 } else { 461 /* Shouldn't happen, but if it does, give up on the group. */ 462 g_free(group); 463 imcb_error(ic, "Syntax error"); 464 imc_logout(ic, TRUE); 465 return 0; 466 } 467 468 for (l = md->grpq; l; l = next) { 469 struct msn_groupadd *ga = l->data; 470 next = l->next; 471 if (g_strcasecmp(ga->group, group) == 0) { 472 if (!msn_buddy_list_add(ic, "FL", ga->who, ga->who, group)) { 473 return 0; 474 } 475 476 g_free(ga->group); 477 g_free(ga->who); 478 g_free(ga); 479 md->grpq = g_slist_remove(md->grpq, ga); 480 } 481 } 482 } 483 #endif 484 else if (strcmp(cmd[0], "GCF") == 0) { 308 } else if (strcmp(cmd[0], "GCF") == 0) { 485 309 /* Coming up is cmd[2] bytes of stuff we're supposed to 486 310 censore. Meh. */ 487 handler->msglen = atoi(cmd[2]); 488 } else if (strcmp(cmd[0], "UBX") == 0) { 489 /* Status message. */ 311 md->msglen = atoi(cmd[2]); 312 } else if ((strcmp(cmd[0], "NFY") == 0) || (strcmp(cmd[0], "SDG") == 0)) { 490 313 if (num_parts >= 3) { 491 handler->msglen = atoi(cmd[2]); 314 md->msglen = atoi(cmd[2]); 315 } 316 } else if (strcmp(cmd[0], "PUT") == 0) { 317 if (num_parts >= 4) { 318 md->msglen = atoi(cmd[3]); 492 319 } 493 320 } else if (strcmp(cmd[0], "NOT") == 0) { 494 /* Some kind of notification, poorly documented but495 apparently used to announce address book changes. */496 321 if (num_parts >= 2) { 497 handler->msglen = atoi(cmd[1]); 498 } 499 } else if (strcmp(cmd[0], "UBM") == 0) { 500 if (num_parts >= 7) { 501 handler->msglen = atoi(cmd[6]); 322 md->msglen = atoi(cmd[1]); 502 323 } 503 324 } else if (strcmp(cmd[0], "QNG") == 0) { … … 516 337 /* Oh yes, errors can have payloads too now. Discard them for now. */ 517 338 if (num_parts >= 3) { 518 handler->msglen = atoi(cmd[2]);339 md->msglen = atoi(cmd[2]); 519 340 } 520 341 } else { 521 /* debug( "Received unknown command from main server: %s", cmd[0] ); */342 imcb_error(ic, "Received unknown command from main server: %s", cmd[0]); 522 343 } 523 344 … … 525 346 } 526 347 527 static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts)528 { 529 struct im_connection *ic = handler->data;348 int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts) 349 { 350 struct im_connection *ic = md->ic; 530 351 char *body; 531 352 int blen = 0; … … 598 419 } 599 420 } else if (g_strncasecmp(ct, "text/x-msmsgsactivemailnotification", 35) == 0) { 600 } else if (g_strncasecmp(ct, "text/x-msmsgsinitialmdatanotification", 37) == 0 || 601 g_strncasecmp(ct, "text/x-msmsgsoimnotification", 28) == 0) { 602 /* We received an offline message. Or at least notification 603 that there is one waiting for us. Fetching the message(s) 604 and purging them from the server is a lot of SOAPy work 605 not worth doing IMHO. Also I thought it was possible to 606 have the notification server send them directly, I was 607 pretty sure I saw Pidgin do it.. 608 609 At least give a notification for now, seems like a 610 reasonable thing to do. Only problem is, they'll keep 611 coming back at login time until you read them using a 612 different client. :-( */ 613 614 char *xml = get_rfc822_header(body, "Mail-Data:", blen); 615 struct xt_node *md, *m; 616 617 if (!xml) { 618 return 1; 619 } 620 md = xt_from_string(xml, 0); 621 if (!md) { 622 return 1; 623 } 624 625 for (m = md->children; (m = xt_find_node(m, "M")); m = m->next) { 626 struct xt_node *e = xt_find_node(m->children, "E"); 627 struct xt_node *rt = xt_find_node(m->children, "RT"); 628 struct tm tp; 629 time_t msgtime = 0; 630 631 if (!e || !e->text) { 632 continue; 633 } 634 635 memset(&tp, 0, sizeof(tp)); 636 if (rt && rt->text && 637 sscanf(rt->text, "%4d-%2d-%2dT%2d:%2d:%2d.", 638 &tp.tm_year, &tp.tm_mon, &tp.tm_mday, 639 &tp.tm_hour, &tp.tm_min, &tp.tm_sec) == 6) { 640 tp.tm_year -= 1900; 641 tp.tm_mon--; 642 msgtime = mktime_utc(&tp); 643 644 } 645 imcb_buddy_msg(ic, e->text, 646 "<< \002BitlBee\002 - Received offline message. BitlBee can't show these. >>", 0, 647 msgtime); 648 } 649 650 g_free(xml); 651 xt_free_node(md); 421 /* Notification that a message has been read... Ignore it */ 652 422 } else { 653 423 debug("Can't handle %s packet from notification server", ct); … … 656 426 g_free(ct); 657 427 } 658 } else if (strcmp(cmd[0], "UBX") == 0) {659 struct xt_node *ubx, *psm;660 char *psm_text = NULL;661 662 ubx = xt_from_string(msg, msglen);663 if (ubx && strcmp(ubx->name, "Data") == 0 &&664 (psm = xt_find_node(ubx->children, "PSM"))) {665 psm_text = psm->text;666 }667 668 imcb_buddy_status_msg(ic, msn_normalize_handle(cmd[1]), psm_text);669 xt_free_node(ubx);670 428 } else if (strcmp(cmd[0], "ADL") == 0) { 671 429 struct xt_node *adl, *d, *c; … … 716 474 } 717 475 } 718 } else if (strcmp(cmd[0], "UBM") == 0) { 719 /* This one will give us msgs from federated networks. Technically 720 it should also get us offline messages, but I don't know how 721 I can signal MSN servers to use it. */ 722 char *ct, *handle; 723 724 if (strcmp(cmd[1], ic->acc->user) == 0) { 725 /* With MPOP, you'll get copies of your own msgs from other 726 sessions. Discard those at least for now. */ 727 return 1; 728 } 729 730 ct = get_rfc822_header(msg, "Content-Type", msglen); 731 if (strncmp(ct, "text/plain", 10) != 0) { 732 /* Typing notification or something? */ 733 g_free(ct); 734 return 1; 735 } 736 if (strcmp(cmd[2], "1") != 0) { 737 handle = g_strdup_printf("%s:%s", cmd[2], cmd[1]); 738 } else { 739 handle = g_strdup(cmd[1]); 740 } 741 742 imcb_buddy_msg(ic, handle, body, 0, 0); 743 g_free(handle); 476 } else if ((strcmp(cmd[0], "SDG") == 0) || (strcmp(cmd[0], "NFY") == 0)) { 477 msn_ns_structured_message(md, msg, msglen, cmd); 744 478 } 745 479 746 480 return 1; 481 } 482 483 static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd) 484 { 485 char **parts = NULL; 486 char *semicolon = NULL; 487 char *action = NULL; 488 char *from = NULL; 489 char *who = NULL; 490 491 parts = g_strsplit(msg, "\r\n\r\n", 4); 492 493 if (!(from = get_rfc822_header(parts[0], "From", 0))) { 494 goto cleanup; 495 } 496 497 /* either the semicolon or the end of the string */ 498 semicolon = strchr(from, ';') ? : (from + strlen(from)); 499 500 who = g_strndup(from + 2, semicolon - from - 2); 501 502 if ((strcmp(cmd[0], "SDG") == 0) && (action = get_rfc822_header(parts[2], "Message-Type", 0))) { 503 msn_ns_sdg(md, who, parts, action); 504 505 } else if ((strcmp(cmd[0], "NFY") == 0) && (action = get_rfc822_header(parts[2], "Uri", 0))) { 506 gboolean is_put = (strcmp(cmd[1], "PUT") == 0); 507 msn_ns_nfy(md, who, parts, action, is_put); 508 } 509 510 cleanup: 511 g_strfreev(parts); 512 g_free(action); 513 g_free(from); 514 g_free(who); 515 } 516 517 static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action) 518 { 519 struct im_connection *ic = md->ic; 520 521 if (strcmp(action, "Control/Typing") == 0) { 522 imcb_buddy_typing(ic, who, OPT_TYPING); 523 } else if (strcmp(action, "Text") == 0) { 524 imcb_buddy_msg(ic, who, parts[3], 0, 0); 525 } 526 } 527 528 static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put) 529 { 530 struct im_connection *ic = md->ic; 531 struct xt_node *body = NULL; 532 struct xt_node *s = NULL; 533 const char *state = NULL; 534 char *nick = NULL; 535 char *psm = NULL; 536 int flags = OPT_LOGGED_IN; 537 538 if (strcmp(action, "/user") != 0) { 539 return; 540 } 541 542 if (!(body = xt_from_string(parts[3], 0))) { 543 goto cleanup; 544 } 545 546 s = body->children; 547 while ((s = xt_find_node(s, "s"))) { 548 struct xt_node *s2; 549 char *n = xt_find_attr(s, "n"); /* service name: IM, PE, etc */ 550 551 if (strcmp(n, "IM") == 0) { 552 /* IM has basic presence information */ 553 if (!is_put) { 554 /* NFY DEL with a <s> usually means log out from the last endpoint */ 555 flags &= ~OPT_LOGGED_IN; 556 break; 557 } 558 559 s2 = xt_find_node(s->children, "Status"); 560 if (s2 && s2->text_len) { 561 const struct msn_away_state *msn_state = msn_away_state_by_code(s2->text); 562 state = msn_state->name; 563 if (msn_state != msn_away_state_list) { 564 flags |= OPT_AWAY; 565 } 566 } 567 } else if (strcmp(n, "PE") == 0) { 568 if ((s2 = xt_find_node(s->children, "PSM")) && s2->text_len) { 569 psm = s2->text; 570 } 571 if ((s2 = xt_find_node(s->children, "FriendlyName")) && s2->text_len) { 572 nick = s2->text; 573 } 574 } 575 s = s->next; 576 } 577 578 imcb_buddy_status(ic, who, flags, state, psm); 579 580 if (nick) { 581 imcb_rename_buddy(ic, who, nick); 582 } 583 584 cleanup: 585 xt_free_node(body); 747 586 } 748 587 … … 768 607 void msn_auth_got_contact_list(struct im_connection *ic) 769 608 { 770 struct msn_data *md;771 772 609 /* Dead connection? */ 773 610 if (g_slist_find(msn_connections, ic) == NULL) { … … 775 612 } 776 613 777 m d = ic->proto_data;778 msn_ns_ write(ic, -1, "BLP %d %s\r\n", ++md->trId, "BL");614 msn_ns_send_adl_start(ic); 615 msn_ns_finish_login(ic); 779 616 } 780 617 781 618 static gboolean msn_ns_send_adl_1(gpointer key, gpointer value, gpointer data) 782 619 { 783 struct xt_node *adl = data, *d, *c ;620 struct xt_node *adl = data, *d, *c, *s; 784 621 struct bee_user *bu = value; 785 622 struct msn_buddy_data *bd = bu->data; … … 810 647 c = xt_new_node("c", NULL, NULL); 811 648 xt_add_attr(c, "n", handle); 812 xt_add_attr(c, "l", l);813 649 xt_add_attr(c, "t", "1"); /* FIXME: Network type, i.e. 32 for Y!MSG */ 650 s = xt_new_node("s", NULL, NULL); 651 xt_add_attr(s, "n", "IM"); 652 xt_add_attr(s, "l", l); 653 xt_insert_child(c, s); 814 654 xt_insert_child(d, c); 815 655 … … 881 721 882 722 if ((md->flags & MSN_DONE_ADL) && (md->flags & MSN_GOT_PROFILE)) { 883 if (md->flags & MSN_EMAIL_UNVERIFIED) { 884 imcb_connected(ic); 885 } else { 886 return msn_ns_set_display_name(ic, set_getstr(&ic->acc->set, "display_name")); 887 } 723 imcb_connected(ic); 888 724 } 889 725 … … 891 727 } 892 728 729 // TODO: typing notifications, nudges lol, etc 893 730 int msn_ns_sendmessage(struct im_connection *ic, bee_user_t *bu, const char *text) 894 731 { 895 732 struct msn_data *md = ic->proto_data; 896 int type= 0;897 char *buf , *handle;733 int retval = 0; 734 char *buf; 898 735 899 736 if (strncmp(text, "\r\r\r", 3) == 0) { … … 903 740 } 904 741 905 /* This might be a federated contact. Get its network number, 906 prefixed to bu->handle with a colon. Default is 1. */ 907 for (handle = bu->handle; g_ascii_isdigit(*handle); handle++) { 908 type = type * 10 + *handle - '0'; 909 } 910 if (*handle == ':') { 911 handle++; 912 } else { 913 type = 1; 914 } 915 916 buf = g_strdup_printf("%s%s", MSN_MESSAGE_HEADERS, text); 917 918 if (msn_ns_write(ic, -1, "UUM %d %s %d %d %zd\r\n%s", 919 ++md->trId, handle, type, 920 1, /* type == IM (not nudge/typing) */ 921 strlen(buf), buf)) { 922 return 1; 923 } else { 924 return 0; 925 } 926 } 927 928 void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq) 929 { 930 GSList *l; 931 932 for (l = *msgq; l; l = l->next) { 933 struct msn_message *m = l->data; 934 bee_user_t *bu = bee_user_by_handle(ic->bee, ic, m->who); 935 936 if (bu) { 937 if (!msn_ns_sendmessage(ic, bu, m->text)) { 938 return; 939 } 940 } 941 } 942 943 while (*msgq != NULL) { 944 struct msn_message *m = (*msgq)->data; 945 946 g_free(m->who); 947 g_free(m->text); 948 g_free(m); 949 950 *msgq = g_slist_remove(*msgq, m); 951 } 952 } 742 buf = g_strdup_printf(MSN_MESSAGE_HEADERS, bu->handle, ic->acc->user, md->uuid, strlen(text), text); 743 retval = msn_ns_write(ic, -1, "SDG %d %zd\r\n%s", ++md->trId, strlen(buf), buf); 744 g_free(buf); 745 return retval; 746 } -
protocols/msn/soap.c
r531eabd rb1dc403 209 209 return; 210 210 } 211 fprintf(stderr, "\n\x1b[90mSOAP:\n"); 211 212 212 213 if (headers) { … … 225 226 xt_free_node(xt); 226 227 } 228 fprintf(stderr, "\n\x1b[97m\n"); 227 229 } 228 230 -
protocols/msn/soap.h
r531eabd rb1dc403 167 167 168 168 #define SOAP_MEMLIST_PAYLOAD \ 169 "<FindMembership xmlns=\"http://www.msn.com/webservices/AddressBook\"><serviceFilter xmlns=\"http://www.msn.com/webservices/AddressBook\"><Types xmlns=\"http://www.msn.com/webservices/AddressBook\"><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Messenger</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Invitation</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">SocialNetwork</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Space</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Profile</ServiceType></Types></serviceFilter>" \169 "<FindMembership xmlns=\"http://www.msn.com/webservices/AddressBook\"><serviceFilter><Types><ServiceType>Messenger</ServiceType><ServiceType>IMAvailability</ServiceType></Types></serviceFilter><expandMembership>true</expandMembership>" \ 170 170 "</FindMembership>" 171 171 -
protocols/msn/tables.c
r531eabd rb1dc403 73 73 { 206, "Domain name missing", 0 }, 74 74 { 207, "Already logged in", 0 }, 75 { 208, "Invalid handle", STATUS_SB_IM_SPARE},75 { 208, "Invalid handle", 0 }, 76 76 { 209, "Forbidden nickname", 0 }, 77 77 { 210, "Buddy list too long", 0 }, 78 78 { 215, "Handle is already in list", 0 }, 79 { 216, "Handle is not in list", STATUS_SB_IM_SPARE},80 { 217, "Person is off-line or non-existent", STATUS_SB_IM_SPARE},79 { 216, "Handle is not in list", 0 }, 80 { 217, "Person is off-line or non-existent", 0 }, 81 81 { 218, "Already in that mode", 0 }, 82 82 { 219, "Handle is already in opposite list", 0 }, … … 113 113 { 711, "Write is blocking", STATUS_FATAL }, 114 114 { 712, "Session is overloaded", STATUS_FATAL }, 115 { 713, "Calling too rapidly", STATUS_SB_IM_SPARE},115 { 713, "Calling too rapidly", 0 }, 116 116 { 714, "Too many sessions", STATUS_FATAL }, 117 117 { 715, "Not expected/Invalid argument/action", 0 }, -
protocols/nogaim.c
r531eabd rb1dc403 503 503 }; 504 504 505 static void imcb_ask_ auth_cb_no(void *data)505 static void imcb_ask_cb_free(void *data) 506 506 { 507 507 struct imcb_ask_cb_data *cbd = data; 508 509 cbd->ic->acc->prpl->auth_deny(cbd->ic, cbd->handle);510 508 511 509 g_free(cbd->handle); … … 513 511 } 514 512 513 static void imcb_ask_auth_cb_no(void *data) 514 { 515 struct imcb_ask_cb_data *cbd = data; 516 517 cbd->ic->acc->prpl->auth_deny(cbd->ic, cbd->handle); 518 519 imcb_ask_cb_free(cbd); 520 } 521 515 522 static void imcb_ask_auth_cb_yes(void *data) 516 523 { … … 519 526 cbd->ic->acc->prpl->auth_allow(cbd->ic, cbd->handle); 520 527 521 g_free(cbd->handle); 522 g_free(cbd); 528 imcb_ask_cb_free(cbd); 523 529 } 524 530 … … 540 546 data->handle = g_strdup(handle); 541 547 query_add((irc_t *) ic->bee->ui_data, ic, s, 542 imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, g_free, data); 543 } 544 545 546 static void imcb_ask_add_cb_no(void *data) 547 { 548 g_free(((struct imcb_ask_cb_data*) data)->handle); 549 g_free(data); 548 imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, imcb_ask_cb_free, data); 549 550 g_free(s); 550 551 } 551 552 … … 556 557 cbd->ic->acc->prpl->add_buddy(cbd->ic, cbd->handle, NULL); 557 558 558 imcb_ask_ add_cb_no(data);559 imcb_ask_cb_free(data); 559 560 } 560 561 561 562 void imcb_ask_add(struct im_connection *ic, const char *handle, const char *realname) 562 563 { 563 struct imcb_ask_cb_data *data = g_new0(struct imcb_ask_cb_data, 1);564 struct imcb_ask_cb_data *data; 564 565 char *s; 565 566 … … 569 570 } 570 571 572 data = g_new0(struct imcb_ask_cb_data, 1); 573 571 574 s = g_strdup_printf("The user %s is not in your buddy list yet. Do you want to add him/her now?", handle); 572 575 … … 574 577 data->handle = g_strdup(handle); 575 578 query_add((irc_t *) ic->bee->ui_data, ic, s, 576 imcb_ask_add_cb_yes, imcb_ask_add_cb_no, g_free, data); 579 imcb_ask_add_cb_yes, imcb_ask_cb_free, imcb_ask_cb_free, data); 580 581 g_free(s); 577 582 } 578 583 -
protocols/purple/ft-direct.c
r531eabd rb1dc403 28 28 29 29 #include "bitlbee.h" 30 #include "bpurple.h" 30 31 31 32 #include <stdarg.h> … … 207 208 void purple_transfer_request(struct im_connection *ic, file_transfer_t *ft, char *handle) 208 209 { 209 PurpleAccount *pa= ic->proto_data;210 struct purple_data *pd = ic->proto_data; 210 211 struct prpl_xfer_data *px; 211 212 … … 213 214 multi-threaded anyway. */ 214 215 next_ft = ft; 215 serv_send_file(purple_account_get_connection(pa), handle, ft->file_name); 216 serv_send_file(purple_account_get_connection(pd->account), handle, 217 ft->file_name); 216 218 217 219 ft->write = prpl_xfer_write; -
protocols/purple/ft.c
r531eabd rb1dc403 28 28 29 29 #include "bitlbee.h" 30 #include "bpurple.h" 30 31 31 32 #include <stdarg.h> … … 285 286 { 286 287 struct prpl_xfer_data *px = ft->data; 287 PurpleAccount *pa= px->ic->proto_data;288 struct purple_data *pd = px->ic->proto_data; 288 289 289 290 /* xfer_new() will pick up this variable. It's a hack but we're not 290 291 multi-threaded anyway. */ 291 292 next_ft = ft; 292 serv_send_file(purple_account_get_connection(pa), px->handle, px->fn); 293 serv_send_file(purple_account_get_connection(pd->account), 294 px->handle, px->fn); 293 295 } 294 296 -
protocols/purple/purple.c
r531eabd rb1dc403 23 23 24 24 #include "bitlbee.h" 25 #include "bpurple.h" 25 26 #include "help.h" 26 27 … … 39 40 static char *set_eval_display_name(set_t *set, char *value); 40 41 42 void purple_request_input_callback(guint id, struct im_connection *ic, 43 const char *message, const char *who); 44 45 /* purple_request_input specific stuff */ 46 typedef void (*ri_callback_t)(gpointer, const gchar *); 47 48 struct request_input_data { 49 ri_callback_t data_callback; 50 void *user_data; 51 struct im_connection *ic; 52 char *buddy; 53 guint id; 54 }; 55 41 56 struct im_connection *purple_ic_by_pa(PurpleAccount *pa) 42 57 { 43 58 GSList *i; 59 struct purple_data *pd; 44 60 45 61 for (i = purple_connections; i; i = i->next) { 46 if (((struct im_connection *) i->data)->proto_data == pa) { 62 pd = ((struct im_connection *) i->data)->proto_data; 63 if (pd->account == pa) { 47 64 return i->data; 48 65 } … … 290 307 { 291 308 struct im_connection *ic = imcb_new(acc); 292 PurpleAccount *pa;309 struct purple_data *pd; 293 310 294 311 if ((local_bee != NULL && local_bee != acc->bee) || … … 306 323 purple_connections = g_slist_prepend(purple_connections, ic); 307 324 308 ic->proto_data = pa = purple_account_new(acc->user, (char *) acc->prpl->data); 309 purple_account_set_password(pa, acc->pass); 310 purple_sync_settings(acc, pa); 311 312 purple_account_set_enabled(pa, "BitlBee", TRUE); 325 ic->proto_data = pd = g_new0(struct purple_data, 1); 326 pd->account = purple_account_new(acc->user, (char *) acc->prpl->data); 327 pd->input_requests = g_hash_table_new_full(g_direct_hash, g_direct_equal, 328 NULL, g_free); 329 pd->next_request_id = 0; 330 purple_account_set_password(pd->account, acc->pass); 331 purple_sync_settings(acc, pd->account); 332 333 purple_account_set_enabled(pd->account, "BitlBee", TRUE); 313 334 } 314 335 315 336 static void purple_logout(struct im_connection *ic) 316 337 { 317 PurpleAccount *pa = ic->proto_data; 318 319 purple_account_set_enabled(pa, "BitlBee", FALSE); 338 struct purple_data *pd = ic->proto_data; 339 340 if (!pd) { 341 return; 342 } 343 344 purple_account_set_enabled(pd->account, "BitlBee", FALSE); 320 345 purple_connections = g_slist_remove(purple_connections, ic); 321 purple_accounts_remove(pa); 346 purple_accounts_remove(pd->account); 347 g_hash_table_destroy(pd->input_requests); 348 g_free(pd); 322 349 } 323 350 … … 325 352 { 326 353 PurpleConversation *conv; 354 struct purple_data *pd = ic->proto_data; 355 356 if (!strncmp(who, PURPLE_REQUEST_HANDLE, sizeof(PURPLE_REQUEST_HANDLE) - 1)) { 357 guint request_id = atoi(who + sizeof(PURPLE_REQUEST_HANDLE)); 358 purple_request_input_callback(request_id, ic, message, who); 359 return 1; 360 } 327 361 328 362 if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, 329 who, ic->proto_data)) == NULL) {363 who, pd->account)) == NULL) { 330 364 conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, 331 ic->proto_data, who);365 pd->account, who); 332 366 } 333 367 … … 339 373 static GList *purple_away_states(struct im_connection *ic) 340 374 { 341 PurpleAccount *pa= ic->proto_data;375 struct purple_data *pd = ic->proto_data; 342 376 GList *st, *ret = NULL; 343 377 344 for (st = purple_account_get_status_types(p a); st; st = st->next) {378 for (st = purple_account_get_status_types(pd->account); st; st = st->next) { 345 379 PurpleStatusPrimitive prim = purple_status_type_get_primitive(st->data); 346 380 if (prim != PURPLE_STATUS_AVAILABLE && prim != PURPLE_STATUS_OFFLINE) { … … 354 388 static void purple_set_away(struct im_connection *ic, char *state_txt, char *message) 355 389 { 356 PurpleAccount *pa= ic->proto_data;357 GList *status_types = purple_account_get_status_types(p a), *st;390 struct purple_data *pd = ic->proto_data; 391 GList *status_types = purple_account_get_status_types(pd->account), *st; 358 392 PurpleStatusType *pst = NULL; 359 393 GList *args = NULL; … … 378 412 } 379 413 380 purple_account_set_status_list(pa, st ? purple_status_type_get_id(pst) : "away", 414 purple_account_set_status_list(pd->account, 415 st ? purple_status_type_get_id(pst) : "away", 381 416 TRUE, args); 382 417 … … 447 482 PurpleBuddy *pb; 448 483 PurpleGroup *pg = NULL; 484 struct purple_data *pd = ic->proto_data; 449 485 450 486 if (group && !(pg = purple_find_group(group))) { … … 453 489 } 454 490 455 pb = purple_buddy_new( (PurpleAccount *) ic->proto_data, who, NULL);491 pb = purple_buddy_new(pd->account, who, NULL); 456 492 purple_blist_add_buddy(pb, NULL, pg, NULL); 457 purple_account_add_buddy( (PurpleAccount *) ic->proto_data, pb);458 459 purple_gg_buddylist_export( ((PurpleAccount *) ic->proto_data)->gc);493 purple_account_add_buddy(pd->account, pb); 494 495 purple_gg_buddylist_export(pd->account->gc); 460 496 } 461 497 … … 463 499 { 464 500 PurpleBuddy *pb; 465 466 pb = purple_find_buddy((PurpleAccount *) ic->proto_data, who); 501 struct purple_data *pd = ic->proto_data; 502 503 pb = purple_find_buddy(pd->account, who); 467 504 if (pb != NULL) { 468 505 PurpleGroup *group; 469 506 470 507 group = purple_buddy_get_group(pb); 471 purple_account_remove_buddy( (PurpleAccount *) ic->proto_data, pb, group);508 purple_account_remove_buddy(pd->account, pb, group); 472 509 473 510 purple_blist_remove_buddy(pb); 474 511 } 475 512 476 purple_gg_buddylist_export( ((PurpleAccount *) ic->proto_data)->gc);513 purple_gg_buddylist_export(pd->account->gc); 477 514 } 478 515 479 516 static void purple_add_permit(struct im_connection *ic, char *who) 480 517 { 481 PurpleAccount *pa= ic->proto_data;482 483 purple_privacy_permit_add(p a, who, FALSE);518 struct purple_data *pd = ic->proto_data; 519 520 purple_privacy_permit_add(pd->account, who, FALSE); 484 521 } 485 522 486 523 static void purple_add_deny(struct im_connection *ic, char *who) 487 524 { 488 PurpleAccount *pa= ic->proto_data;489 490 purple_privacy_deny_add(p a, who, FALSE);525 struct purple_data *pd = ic->proto_data; 526 527 purple_privacy_deny_add(pd->account, who, FALSE); 491 528 } 492 529 493 530 static void purple_rem_permit(struct im_connection *ic, char *who) 494 531 { 495 PurpleAccount *pa= ic->proto_data;496 497 purple_privacy_permit_remove(p a, who, FALSE);532 struct purple_data *pd = ic->proto_data; 533 534 purple_privacy_permit_remove(pd->account, who, FALSE); 498 535 } 499 536 500 537 static void purple_rem_deny(struct im_connection *ic, char *who) 501 538 { 502 PurpleAccount *pa= ic->proto_data;503 504 purple_privacy_deny_remove(p a, who, FALSE);539 struct purple_data *pd = ic->proto_data; 540 541 purple_privacy_deny_remove(pd->account, who, FALSE); 505 542 } 506 543 507 544 static void purple_get_info(struct im_connection *ic, char *who) 508 545 { 509 serv_get_info(purple_account_get_connection(ic->proto_data), who); 546 struct purple_data *pd = ic->proto_data; 547 548 serv_get_info(purple_account_get_connection(pd->account), who); 510 549 } 511 550 … … 517 556 { 518 557 PurpleTypingState state = PURPLE_NOT_TYPING; 519 PurpleAccount *pa= ic->proto_data;558 struct purple_data *pd = ic->proto_data; 520 559 521 560 if (flags & OPT_TYPING) { … … 525 564 } 526 565 527 serv_send_typing(purple_account_get_connection(p a), who, state);566 serv_send_typing(purple_account_get_connection(pd->account), who, state); 528 567 529 568 return 1; … … 559 598 /* There went my nice afternoon. :-( */ 560 599 561 PurpleAccount *pa= ic->proto_data;562 PurplePlugin *prpl = purple_plugins_find_with_id(p a->protocol_id);600 struct purple_data *pd = ic->proto_data; 601 PurplePlugin *prpl = purple_plugins_find_with_id(pd->account->protocol_id); 563 602 PurplePluginProtocolInfo *pi = prpl->info->extra_info; 564 PurpleBuddy *pb = purple_find_buddy( (PurpleAccount *) ic->proto_data, who);603 PurpleBuddy *pb = purple_find_buddy(pd->account, who); 565 604 PurpleMenuAction *mi; 566 605 GList *menu; … … 597 636 PurpleConversation *pc = gc->data; 598 637 PurpleConvChat *pcc = PURPLE_CONV_CHAT(pc); 599 600 serv_chat_invite(purple_account_get_connection(gc->ic->proto_data), 638 struct purple_data *pd = gc->ic->proto_data; 639 640 serv_chat_invite(purple_account_get_connection(pd->account), 601 641 purple_conv_chat_get_id(pcc), 602 642 message && *message ? message : "Please join my chat", … … 623 663 set_t **sets) 624 664 { 625 PurpleAccount *pa= ic->proto_data;626 PurplePlugin *prpl = purple_plugins_find_with_id(p a->protocol_id);665 struct purple_data *pd = ic->proto_data; 666 PurplePlugin *prpl = purple_plugins_find_with_id(pd->account->protocol_id); 627 667 PurplePluginProtocolInfo *pi = prpl->info->extra_info; 628 668 GHashTable *chat_hash; … … 631 671 632 672 if (!pi->chat_info || !pi->chat_info_defaults || 633 !(info = pi->chat_info(purple_account_get_connection(p a)))) {673 !(info = pi->chat_info(purple_account_get_connection(pd->account)))) { 634 674 imcb_error(ic, "Joining chatrooms not supported by this protocol"); 635 675 return NULL; 636 676 } 637 677 638 if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, room, pa))) { 678 if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 679 room, pd->account))) { 639 680 purple_conversation_destroy(conv); 640 681 } 641 682 642 chat_hash = pi->chat_info_defaults(purple_account_get_connection(pa), room); 683 chat_hash = pi->chat_info_defaults( 684 purple_account_get_connection(pd->account), room 685 ); 643 686 644 687 for (l = info; l; l = l->next) { … … 654 697 } 655 698 656 serv_join_chat(purple_account_get_connection(p a), chat_hash);699 serv_join_chat(purple_account_get_connection(pd->account), chat_hash); 657 700 658 701 return NULL; … … 981 1024 pqad->yes(pqad->user_data, pqad->yes_i); 982 1025 } 983 g_free(pqad);984 1026 } 985 1027 … … 991 1033 pqad->no(pqad->user_data, pqad->no_i); 992 1034 } 993 g_free(pqad); 1035 } 1036 1037 /* q->free() callback from query_del()*/ 1038 static void prplcb_request_action_free(void *data) 1039 { 1040 struct prplcb_request_action_data *pqad = data; 1041 1042 pqad->bee_data = NULL; 1043 purple_request_close(PURPLE_REQUEST_ACTION, pqad); 994 1044 } 995 1045 … … 1026 1076 q = g_strdup_printf("Request: %s\n\n%s\n\n%s", title, primary, secondary); 1027 1077 pqad->bee_data = query_add(local_bee->ui_data, purple_ic_by_pa(account), q, 1028 prplcb_request_action_yes, prplcb_request_action_no, g_free, pqad); 1078 prplcb_request_action_yes, prplcb_request_action_no, 1079 prplcb_request_action_free, pqad); 1029 1080 1030 1081 g_free(q); … … 1033 1084 } 1034 1085 1035 /* 1036 static void prplcb_request_test() 1037 { 1038 fprintf( stderr, "bla\n" ); 1039 } 1040 */ 1086 /* So it turns out some requests have no account context at all, because 1087 * libpurple hates us. This means that query_del_by_conn() won't remove those 1088 * on logout, and will segfault if the user replies. That's why this exists. 1089 */ 1090 static void prplcb_close_request(PurpleRequestType type, void *data) 1091 { 1092 struct prplcb_request_action_data *pqad; 1093 struct request_input_data *ri; 1094 struct purple_data *pd; 1095 1096 if (!data) { 1097 return; 1098 } 1099 1100 switch (type) { 1101 case PURPLE_REQUEST_ACTION: 1102 pqad = data; 1103 /* if this is null, it's because query_del was run already */ 1104 if (pqad->bee_data) { 1105 query_del(local_bee->ui_data, pqad->bee_data); 1106 } 1107 g_free(pqad); 1108 break; 1109 case PURPLE_REQUEST_INPUT: 1110 ri = data; 1111 pd = ri->ic->proto_data; 1112 imcb_remove_buddy(ri->ic, ri->buddy, NULL); 1113 g_free(ri->buddy); 1114 g_hash_table_remove(pd->input_requests, GUINT_TO_POINTER(ri->id)); 1115 break; 1116 default: 1117 g_free(data); 1118 break; 1119 } 1120 1121 } 1122 1123 void* prplcb_request_input(const char *title, const char *primary, 1124 const char *secondary, const char *default_value, gboolean multiline, 1125 gboolean masked, gchar *hint, const char *ok_text, GCallback ok_cb, 1126 const char *cancel_text, GCallback cancel_cb, PurpleAccount *account, 1127 const char *who, PurpleConversation *conv, void *user_data) 1128 { 1129 struct im_connection *ic = purple_ic_by_pa(account); 1130 struct purple_data *pd = ic->proto_data; 1131 struct request_input_data *ri = g_new0(struct request_input_data, 1); 1132 guint id = pd->next_request_id++; 1133 1134 ri->id = id; 1135 ri->ic = ic; 1136 ri->buddy = g_strdup_printf("%s_%u", PURPLE_REQUEST_HANDLE, id); 1137 ri->data_callback = (ri_callback_t) ok_cb; 1138 ri->user_data = user_data; 1139 g_hash_table_insert(pd->input_requests, GUINT_TO_POINTER(id), ri); 1140 1141 imcb_add_buddy(ic, ri->buddy, NULL); 1142 imcb_buddy_msg(ic, ri->buddy, secondary, 0, 0); 1143 1144 return ri; 1145 } 1146 1147 void purple_request_input_callback(guint id, struct im_connection *ic, 1148 const char *message, const char *who) 1149 { 1150 struct purple_data *pd = ic->proto_data; 1151 struct request_input_data *ri; 1152 1153 if (!(ri = g_hash_table_lookup(pd->input_requests, GUINT_TO_POINTER(id)))) { 1154 return; 1155 } 1156 1157 ri->data_callback(ri->user_data, message); 1158 1159 purple_request_close(PURPLE_REQUEST_INPUT, ri); 1160 } 1161 1041 1162 1042 1163 static PurpleRequestUiOps bee_request_uiops = 1043 1164 { 1044 NULL,1165 prplcb_request_input, 1045 1166 NULL, 1046 1167 prplcb_request_action, 1047 1168 NULL, 1048 1169 NULL, 1049 NULL,1170 prplcb_close_request, 1050 1171 NULL, 1051 1172 }; -
protocols/skype/Makefile
r531eabd rb1dc403 6 6 DATE := $(shell date +%Y-%m-%d) 7 7 INSTALL = install 8 ASCIIDOC = yes9 8 10 ifeq ($(ASCIIDOC),yes) 9 10 ifdef ASCIIDOC 11 11 MANPAGES = skyped.1 12 12 else … … 29 29 30 30 install-doc: doc 31 if eq ($(ASCIIDOC),yes)31 ifdef ASCIIDOC 32 32 $(INSTALL) -d $(DESTDIR)$(MANDIR)/man1 33 33 $(INSTALL) -m644 $(MANPAGES) $(DESTDIR)$(MANDIR)/man1 -
protocols/twitter/twitter.c
r531eabd rb1dc403 852 852 } 853 853 854 /* Parses a decimal or hex tweet ID, returns TRUE on success */ 855 static gboolean twitter_parse_id(char *string, int base, guint64 *id) 856 { 857 guint64 parsed; 858 char *endptr; 859 860 errno = 0; 861 parsed = g_ascii_strtoull(string, &endptr, base); 862 if (errno || endptr == string || *endptr != '\0') { 863 return FALSE; 864 } 865 *id = parsed; 866 return TRUE; 867 } 868 869 bee_user_t twitter_log_local_user; 870 854 871 /** Convert the given bitlbee tweet ID, bitlbee username, or twitter tweet ID 855 872 * into a twitter tweet ID. … … 879 896 arg++; 880 897 } 881 if (sscanf(arg, "%" G_GINT64_MODIFIER "x", &id) == 1 && 882 id < TWITTER_LOG_LENGTH) { 898 if (twitter_parse_id(arg, 16, &id) && id < TWITTER_LOG_LENGTH) { 883 899 bu = td->log[id].bu; 884 900 id = td->log[id].id; 885 /* Beware of dangling pointers! */ 886 if (!g_slist_find(ic->bee->users, bu)) { 887 bu = NULL; 888 } 889 } else if (sscanf(arg, "%" G_GINT64_MODIFIER "d", &id) == 1) { 901 } else if (twitter_parse_id(arg, 10, &id)) { 890 902 /* Allow normal tweet IDs as well; not a very useful 891 903 feature but it's always been there. Just ignore … … 897 909 } 898 910 if (bu_) { 911 if (bu == &twitter_log_local_user) { 912 /* HACK alert. There's no bee_user object for the local 913 * user so just fake one for the few cmds that need it. */ 914 twitter_log_local_user.handle = td->user; 915 } else { 916 /* Beware of dangling pointers! */ 917 if (!g_slist_find(ic->bee->users, bu)) { 918 bu = NULL; 919 } 920 } 899 921 *bu_ = bu; 900 922 } … … 989 1011 in_reply_to = id; 990 1012 allow_post = TRUE; 1013 } else if (g_strcasecmp(cmd[0], "url") == 0) { 1014 id = twitter_message_id_from_command_arg(ic, cmd[1], &bu); 1015 if (!id) { 1016 twitter_log(ic, "Tweet `%s' does not exist", cmd[1]); 1017 } else { 1018 /* More common link is twitter.com/$UID/status/$ID (and that's 1019 * what this will 302 to) but can't generate that since for RTs, 1020 * bu here points at the retweeter while id contains the id of 1021 * the original message. */ 1022 twitter_log(ic, "https://twitter.com/statuses/%lld", id); 1023 } 1024 goto eof; 1025 991 1026 } else if (g_strcasecmp(cmd[0], "post") == 0) { 992 1027 message += 5; -
protocols/twitter/twitter.h
r531eabd rb1dc403 101 101 struct twitter_log_data { 102 102 guint64 id; 103 struct bee_user *bu; /* DANGER: can be a dead pointer. Check it first. */ 103 /* DANGER: bu can be a dead pointer. Check it first. 104 * twitter_message_id_from_command_arg() will do this. */ 105 struct bee_user *bu; 104 106 }; 105 107 … … 110 112 */ 111 113 extern GSList *twitter_connections; 114 115 /** 116 * Evil hack: Fake bee_user which will always point at the local user. 117 * Sometimes used as a return value by twitter_message_id_from_command_arg. 118 * NOT thread safe but don't you dare to even think of ever making BitlBee 119 * threaded. :-) 120 */ 121 extern bee_user_t twitter_log_local_user; 112 122 113 123 void twitter_login_finish(struct im_connection *ic); -
protocols/twitter/twitter_lib.c
r531eabd rb1dc403 460 460 #endif 461 461 462 static char* expand_entities(char* text, const json_value *entities);462 static void expand_entities(char **text, const json_value *node); 463 463 464 464 /** … … 473 473 { 474 474 struct twitter_xml_status *txs; 475 const json_value *rt = NULL , *entities = NULL;475 const json_value *rt = NULL; 476 476 477 477 if (node->type != json_object) { … … 501 501 } else if (strcmp("in_reply_to_status_id", k) == 0 && v->type == json_integer) { 502 502 txs->reply_to = v->u.integer; 503 } else if (strcmp("entities", k) == 0 && v->type == json_object) {504 entities = v;505 503 } 506 504 } … … 516 514 txs_free(rtxs); 517 515 } 518 } else if (entities){519 txs->text = expand_entities(txs->text, entities);516 } else { 517 expand_entities(&txs->text, node); 520 518 } 521 519 … … 534 532 { 535 533 struct twitter_xml_status *txs; 536 const json_value *entities = NULL;537 534 538 535 if (node->type != json_object) { … … 561 558 } 562 559 563 if (entities) { 564 txs->text = expand_entities(txs->text, entities); 565 } 560 expand_entities(&txs->text, node); 566 561 567 562 if (txs->text && txs->user && txs->id) { … … 573 568 } 574 569 575 static char* expand_entities(char* text, const json_value *entities) 576 { 570 static void expand_entities(char **text, const json_value *node) 571 { 572 json_value *entities, *quoted; 573 char *quote_url = NULL, *quote_text = NULL; 574 575 if (!((entities = json_o_get(node, "entities")) && entities->type == json_object)) 576 return; 577 if ((quoted = json_o_get(node, "quoted_status")) && quoted->type == json_object) { 578 /* New "retweets with comments" feature. Note that this info 579 * seems to be included in the streaming API only! Grab the 580 * full message and try to insert it when we run into the 581 * Tweet entity. */ 582 struct twitter_xml_status *txs = twitter_xt_get_status(quoted); 583 quote_text = g_strdup_printf("@%s: %s", txs->user->screen_name, txs->text); 584 quote_url = g_strdup_printf("%s/status/%" G_GUINT64_FORMAT, txs->user->screen_name, txs->id); 585 txs_free(txs); 586 } else { 587 quoted = NULL; 588 } 589 577 590 JSON_O_FOREACH(entities, k, v) { 578 591 int i; … … 586 599 587 600 for (i = 0; i < v->u.array.length; i++) { 601 const char *format = "%s%s <%s>%s"; 602 588 603 if (v->u.array.values[i]->type != json_object) { 589 604 continue; … … 592 607 const char *kort = json_o_str(v->u.array.values[i], "url"); 593 608 const char *disp = json_o_str(v->u.array.values[i], "display_url"); 609 const char *full = json_o_str(v->u.array.values[i], "expanded_url"); 594 610 char *pos, *new; 595 611 596 if (!kort || !disp || !(pos = strstr( text, kort))) {612 if (!kort || !disp || !(pos = strstr(*text, kort))) { 597 613 continue; 598 614 } 615 if (quote_url && strstr(full, quote_url)) { 616 format = "%s<%s> [%s]%s"; 617 disp = quote_text; 618 } 599 619 600 620 *pos = '\0'; 601 new = g_strdup_printf( "%s%s <%s>%s",text, kort,621 new = g_strdup_printf(format, *text, kort, 602 622 disp, pos + strlen(kort)); 603 623 604 g_free( text);605 text = new;606 } 607 } 608 609 return text;624 g_free(*text); 625 *text = new; 626 } 627 } 628 g_free(quote_text); 629 g_free(quote_url); 610 630 } 611 631 … … 681 701 if (g_strcasecmp(txs->user->screen_name, td->user) == 0) { 682 702 td->log[td->log_id].id = txs->rt_id; 703 /* More useful than NULL. */ 704 td->log[td->log_id].bu = &twitter_log_local_user; 683 705 } 684 706 … … 832 854 833 855 last_id_str = g_strdup_printf("%" G_GUINT64_FORMAT, td->timeline_id); 834 set_setstr(&ic->acc->set, " last_tweet", last_id_str);856 set_setstr(&ic->acc->set, "_last_tweet", last_id_str); 835 857 g_free(last_id_str); 836 858 } … … 862 884 863 885 imcb_error(ic, "Stream closed (%s)", req->status_string); 886 if (req->status_code == 401) { 887 imcb_error(ic, "Check your system clock."); 888 } 864 889 imc_logout(ic, TRUE); 865 890 return; -
protocols/yahoo/yahoo.c
r531eabd rb1dc403 733 733 inp = l->data; 734 734 if (inp->h == tag) { 735 byahoo_inputs = g_slist_remove(byahoo_inputs, inp); 735 736 g_free(inp->d); 736 737 g_free(inp); 737 byahoo_inputs = g_slist_remove(byahoo_inputs, inp);738 738 break; 739 739 }
Note: See TracChangeset
for help on using the changeset viewer.