250
90
msn_slplink_queue_slpmsg(slplink, slpmsg);
253
/* XXX: this could be improved if we tracked custom smileys
254
* per-protocol, per-account, per-session or (ideally) per-conversation
256
static PurpleStoredImage *
257
find_valid_emoticon(PurpleAccount *account, const char *path)
261
if (!purple_account_get_bool(account, "custom_smileys", TRUE))
264
smileys = purple_smileys_get_all();
266
for (; smileys; smileys = g_list_delete_link(smileys, smileys)) {
267
PurpleSmiley *smiley;
268
PurpleStoredImage *img;
270
smiley = smileys->data;
271
img = purple_smiley_get_stored_image(smiley);
273
if (purple_strequal(path, purple_imgstore_get_filename(img))) {
274
g_list_free(smileys);
278
purple_imgstore_unref(img);
281
purple_debug_error("msn", "Received illegal request for file %s\n", path);
286
parse_dc_nonce(const char *content, MsnDirectConnNonceType *ntype)
290
*ntype = DC_NONCE_UNKNOWN;
292
nonce = get_token(content, "Hashed-Nonce: {", "}\r\n");
294
*ntype = DC_NONCE_SHA1;
297
guint16 n2, n3, n4, n5;
298
nonce = get_token(content, "Nonce: {", "}\r\n");
300
&& sscanf(nonce, "%08x-%04hx-%04hx-%04hx-%04hx%08x",
301
&n1, &n2, &n3, &n4, &n5, &n6) == 6) {
302
*ntype = DC_NONCE_PLAIN;
304
nonce = g_malloc(16);
305
*(guint32 *)(nonce + 0) = GUINT32_TO_LE(n1);
306
*(guint16 *)(nonce + 4) = GUINT16_TO_LE(n2);
307
*(guint16 *)(nonce + 6) = GUINT16_TO_LE(n3);
308
*(guint16 *)(nonce + 8) = GUINT16_TO_BE(n4);
309
*(guint16 *)(nonce + 10) = GUINT16_TO_BE(n5);
310
*(guint32 *)(nonce + 12) = GUINT32_TO_BE(n6);
312
/* Invalid nonce, so ignore request */
322
msn_slp_process_transresp(MsnSlpCall *slpcall, const char *content)
324
/* A direct connection negotiation response */
328
MsnDirectConn *dc = slpcall->slplink->dc;
329
MsnDirectConnNonceType ntype;
331
purple_debug_info("msn", "process_transresp\n");
333
/* Direct connections are disabled. */
334
if (!purple_account_get_bool(slpcall->slplink->session->account, "direct_connect", TRUE))
337
g_return_if_fail(dc != NULL);
338
g_return_if_fail(dc->state == DC_STATE_CLOSED);
340
bridge = get_token(content, "Bridge: ", "\r\n");
341
nonce = parse_dc_nonce(content, &ntype);
342
listening = get_token(content, "Listening: ", "\r\n");
343
if (listening && bridge && !strcmp(bridge, "TCPv1")) {
344
/* Ok, the client supports direct TCP connection */
346
/* We always need this. */
347
if (ntype == DC_NONCE_SHA1) {
348
strncpy(dc->remote_nonce, nonce, 36);
349
dc->remote_nonce[36] = '\0';
352
if (!strcasecmp(listening, "false")) {
353
if (dc->listen_data != NULL) {
355
* We'll listen for incoming connections but
356
* the listening socket isn't ready yet so we cannot
357
* send the INVITE packet now. Put the slpcall into waiting mode
358
* and let the callback send the invite.
360
slpcall->wait_for_socket = TRUE;
362
} else if (dc->listenfd != -1) {
363
/* The listening socket is ready. Send the INVITE here. */
364
msn_dc_send_invite(dc);
367
/* We weren't able to create a listener either. Use SB. */
368
msn_dc_fallback_to_sb(dc);
373
* We should connect to the client so parse
374
* IP/port from response.
379
if (ntype == DC_NONCE_PLAIN) {
380
/* Only needed for listening side. */
381
memcpy(dc->nonce, nonce, 16);
384
/* Cancel any listen attempts because we don't need them. */
385
if (dc->listenfd_handle != 0) {
386
purple_input_remove(dc->listenfd_handle);
387
dc->listenfd_handle = 0;
389
if (dc->connect_timeout_handle != 0) {
390
purple_timeout_remove(dc->connect_timeout_handle);
391
dc->connect_timeout_handle = 0;
393
if (dc->listenfd != -1) {
394
purple_network_remove_port_mapping(dc->listenfd);
398
if (dc->listen_data != NULL) {
399
purple_network_listen_cancel(dc->listen_data);
400
dc->listen_data = NULL;
403
/* Save external IP/port for later use. We'll try local connection first. */
404
dc->ext_ip = get_token(content, "IPv4External-Addrs: ", "\r\n");
405
port_str = get_token(content, "IPv4External-Port: ", "\r\n");
407
dc->ext_port = atoi(port_str);
411
ip = get_token(content, "IPv4Internal-Addrs: ", "\r\n");
412
port_str = get_token(content, "IPv4Internal-Port: ", "\r\n");
414
port = atoi(port_str);
419
/* Try internal address first */
420
dc->connect_data = purple_proxy_connect(
422
slpcall->slplink->session->account,
425
msn_dc_connected_to_peer_cb,
429
if (dc->connect_data) {
430
/* Add connect timeout handle */
431
dc->connect_timeout_handle = purple_timeout_add_seconds(
433
msn_dc_outgoing_connection_timeout_cb,
439
* Try external IP/port (if specified)
441
msn_dc_outgoing_connection_timeout_cb(dc);
446
* Omitted or invalid internal IP address / port
447
* Try external IP/port (if specified)
449
msn_dc_outgoing_connection_timeout_cb(dc);
457
* Invalid direct connect invitation or
458
* TCP connection is not supported
470
got_sessionreq(MsnSlpCall *slpcall, const char *branch,
471
const char *euf_guid, const char *context)
473
gboolean accepted = FALSE;
475
if (!strcmp(euf_guid, MSN_OBJ_GUID))
477
/* Emoticon or UserDisplay */
481
MsnSlpMessage *slpmsg;
484
PurpleStoredImage *img = NULL;
488
content = g_strdup_printf("SessionID: %lu\r\n\r\n",
489
slpcall->session_id);
491
msn_slp_send_ok(slpcall, branch, "application/x-msnmsgr-sessionreqbody",
496
slplink = slpcall->slplink;
498
msnobj_data = (char *)purple_base64_decode(context, &len);
499
obj = msn_object_new_from_string(msnobj_data);
500
type = msn_object_get_type(obj);
502
if (type == MSN_OBJECT_EMOTICON) {
503
img = find_valid_emoticon(slplink->session->account, obj->location);
504
} else if (type == MSN_OBJECT_USERTILE) {
505
img = msn_object_get_image(obj);
507
purple_imgstore_ref(img);
509
msn_object_destroy(obj);
513
slpmsg = msn_slpmsg_new(slplink);
514
slpmsg->slpcall = slpcall;
515
slpmsg->session_id = slpcall->session_id;
516
msn_slpmsg_set_body(slpmsg, NULL, 4);
517
slpmsg->info = "SLP DATA PREP";
518
msn_slplink_queue_slpmsg(slplink, slpmsg);
521
slpmsg = msn_slpmsg_new(slplink);
522
slpmsg->slpcall = slpcall;
523
slpmsg->flags = 0x20;
524
slpmsg->info = "SLP DATA";
525
msn_slpmsg_set_image(slpmsg, img);
526
msn_slplink_queue_slpmsg(slplink, slpmsg);
527
purple_imgstore_unref(img);
532
purple_debug_error("msn", "Wrong object.\n");
536
else if (!strcmp(euf_guid, MSN_FT_GUID))
539
PurpleAccount *account;
541
MsnFileContext *header;
546
account = slpcall->slplink->session->account;
548
slpcall->end_cb = msn_xfer_end_cb;
549
slpcall->branch = g_strdup(branch);
551
slpcall->pending = TRUE;
553
xfer = purple_xfer_new(account, PURPLE_XFER_RECEIVE,
554
slpcall->slplink->remote_user);
556
header = (MsnFileContext *)purple_base64_decode(context, &bin_len);
557
if (header != NULL && bin_len >= sizeof(MsnFileContext) - 1 &&
558
(header->version == 2 ||
559
(header->version == 3 && header->length == sizeof(MsnFileContext) + 63))) {
560
file_size = GUINT64_FROM_LE(header->file_size);
562
file_name = g_convert((const gchar *)&header->file_name,
563
MAX_FILE_NAME_LEN * 2,
567
purple_xfer_set_filename(xfer, file_name ? file_name : "");
569
purple_xfer_set_size(xfer, file_size);
570
purple_xfer_set_init_fnc(xfer, msn_xfer_init);
571
purple_xfer_set_request_denied_fnc(xfer, msn_xfer_cancel);
572
purple_xfer_set_cancel_recv_fnc(xfer, msn_xfer_cancel);
573
purple_xfer_set_read_fnc(xfer, msn_xfer_read);
574
purple_xfer_set_write_fnc(xfer, msn_xfer_write);
576
slpcall->u.incoming_data = g_byte_array_new();
578
slpcall->xfer = xfer;
579
purple_xfer_ref(slpcall->xfer);
581
xfer->data = slpcall;
583
if (header->type == 0 && bin_len >= sizeof(MsnFileContext)) {
584
purple_xfer_set_thumbnail(xfer, &header->preview,
585
bin_len - sizeof(MsnFileContext),
589
purple_xfer_request(xfer);
595
} else if (!strcmp(euf_guid, MSN_CAM_REQUEST_GUID)) {
596
purple_debug_info("msn", "Cam request.\n");
597
if (slpcall && slpcall->slplink &&
598
slpcall->slplink->session) {
599
PurpleConversation *conv;
600
gchar *from = slpcall->slplink->remote_user;
601
conv = purple_find_conversation_with_account(
602
PURPLE_CONV_TYPE_IM, from,
603
slpcall->slplink->session->account);
606
buf = g_strdup_printf(
607
_("%s requests to view your "
608
"webcam, but this request is "
609
"not yet supported."), from);
610
purple_conversation_write(conv, NULL, buf,
611
PURPLE_MESSAGE_SYSTEM |
612
PURPLE_MESSAGE_NOTIFY,
618
} else if (!strcmp(euf_guid, MSN_CAM_GUID)) {
619
purple_debug_info("msn", "Cam invite.\n");
620
if (slpcall && slpcall->slplink &&
621
slpcall->slplink->session) {
622
PurpleConversation *conv;
623
gchar *from = slpcall->slplink->remote_user;
624
conv = purple_find_conversation_with_account(
625
PURPLE_CONV_TYPE_IM, from,
626
slpcall->slplink->session->account);
629
buf = g_strdup_printf(
630
_("%s invited you to view his/her webcam, but "
631
"this is not yet supported."), from);
632
purple_conversation_write(conv, NULL, buf,
633
PURPLE_MESSAGE_SYSTEM |
634
PURPLE_MESSAGE_NOTIFY,
641
purple_debug_warning("msn", "SLP SessionReq with unknown EUF-GUID: %s\n", euf_guid);
644
char *content = g_strdup_printf("SessionID: %lu\r\n\r\n",
645
slpcall->session_id);
646
msn_slp_send_decline(slpcall, branch, "application/x-msnmsgr-sessionreqbody", content);
652
send_bye(MsnSlpCall *slpcall, const char *type)
655
PurpleAccount *account;
656
MsnSlpMessage *slpmsg;
659
slplink = slpcall->slplink;
661
g_return_if_fail(slplink != NULL);
663
account = slplink->session->account;
665
header = g_strdup_printf("BYE MSNMSGR:%s MSNSLP/1.0",
666
purple_account_get_username(account));
668
slpmsg = msn_slpmsg_sip_new(slpcall, 0, header,
669
"A0D624A6-6C0C-4283-A9E0-BC97B4B46D32",
674
slpmsg->info = "SLP BYE";
675
slpmsg->text_body = TRUE;
677
msn_slplink_queue_slpmsg(slplink, slpmsg);
681
got_invite(MsnSlpCall *slpcall,
682
const char *branch, const char *type, const char *content)
686
slplink = slpcall->slplink;
688
if (!strcmp(type, "application/x-msnmsgr-sessionreqbody"))
690
char *euf_guid, *context;
693
euf_guid = get_token(content, "EUF-GUID: {", "}\r\n");
695
temp = get_token(content, "SessionID: ", "\r\n");
697
slpcall->session_id = atoi(temp);
700
temp = get_token(content, "AppID: ", "\r\n");
702
slpcall->app_id = atoi(temp);
705
context = get_token(content, "Context: ", "\r\n");
708
got_sessionreq(slpcall, branch, euf_guid, context);
713
else if (!strcmp(type, "application/x-msnmsgr-transreqbody"))
715
/* A direct connection negotiation request */
718
MsnDirectConnNonceType ntype;
720
purple_debug_info("msn", "got_invite: transreqbody received\n");
722
/* Direct connections may be disabled. */
723
if (!purple_account_get_bool(slplink->session->account, "direct_connect", TRUE)) {
724
msn_slp_send_ok(slpcall, branch,
725
"application/x-msnmsgr-transrespbody",
727
"Listening: false\r\n"
728
"Nonce: {00000000-0000-0000-0000-000000000000}\r\n"
730
msn_slpcall_session_init(slpcall);
735
/* Don't do anything if we already have a direct connection */
736
if (slplink->dc != NULL)
739
bridges = get_token(content, "Bridges: ", "\r\n");
740
nonce = parse_dc_nonce(content, &ntype);
741
if (bridges && strstr(bridges, "TCPv1") != NULL) {
743
* Ok, the client supports direct TCP connection
744
* Try to create a listening port
748
dc = msn_dc_new(slpcall);
749
if (ntype == DC_NONCE_PLAIN) {
750
/* There is only one nonce for plain auth. */
751
dc->nonce_type = ntype;
752
memcpy(dc->nonce, nonce, 16);
753
} else if (ntype == DC_NONCE_SHA1) {
754
/* Each side has a nonce in SHA1 auth. */
755
dc->nonce_type = ntype;
756
strncpy(dc->remote_nonce, nonce, 36);
757
dc->remote_nonce[36] = '\0';
760
dc->listen_data = purple_network_listen_range(
763
msn_dc_listen_socket_created_cb,
767
if (dc->listen_data == NULL) {
768
/* Listen socket creation failed */
770
purple_debug_info("msn", "got_invite: listening failed\n");
772
if (dc->nonce_type != DC_NONCE_PLAIN)
773
msn_slp_send_ok(slpcall, branch,
774
"application/x-msnmsgr-transrespbody",
776
"Listening: false\r\n"
777
"Hashed-Nonce: {00000000-0000-0000-0000-000000000000}\r\n"
780
msn_slp_send_ok(slpcall, branch,
781
"application/x-msnmsgr-transrespbody",
783
"Listening: false\r\n"
784
"Nonce: {00000000-0000-0000-0000-000000000000}\r\n"
789
* Listen socket created successfully.
790
* Don't send anything here because we don't know the parameters
791
* of the created socket yet. msn_dc_send_ok will be called from
792
* the callback function: dc_listen_socket_created_cb
794
purple_debug_info("msn", "got_invite: listening socket created\n");
796
dc->send_connection_info_msg_cb = msn_dc_send_ok;
797
slpcall->wait_for_socket = TRUE;
802
* Invalid direct connect invitation or
803
* TCP connection is not supported.
810
else if (!strcmp(type, "application/x-msnmsgr-transrespbody"))
812
/* A direct connection negotiation response */
813
msn_slp_process_transresp(slpcall, content);
818
got_ok(MsnSlpCall *slpcall,
819
const char *type, const char *content)
821
g_return_if_fail(slpcall != NULL);
822
g_return_if_fail(type != NULL);
824
if (!strcmp(type, "application/x-msnmsgr-sessionreqbody"))
829
MsnSession *session = slpcall->slplink->session;
834
if (!purple_account_get_bool(session->account, "direct_connect", TRUE)) {
835
/* Don't attempt a direct connection if disabled. */
836
msn_slpcall_session_init(slpcall);
840
if (slpcall->slplink->dc != NULL) {
841
/* If we already have an established direct connection
842
* then just start the transfer.
844
msn_slpcall_session_init(slpcall);
848
user = msn_userlist_find_user(session->userlist,
849
slpcall->slplink->remote_user);
850
if (!user || !(user->clientid & 0xF0000000)) {
851
/* Just start a normal SB transfer. */
852
msn_slpcall_session_init(slpcall);
856
/* Try direct file transfer by sending a second INVITE */
857
dc = msn_dc_new(slpcall);
858
slpcall->branch = rand_guid();
860
dc->listen_data = purple_network_listen_range(
863
msn_dc_listen_socket_created_cb,
867
header = g_strdup_printf(
868
"INVITE MSNMSGR:%s MSNSLP/1.0",
869
slpcall->slplink->remote_user
872
if (dc->nonce_type == DC_NONCE_SHA1)
873
nonce = g_strdup_printf("Hashed-Nonce: {%s}\r\n", dc->nonce_hash);
875
if (dc->listen_data == NULL) {
876
/* Listen socket creation failed */
877
purple_debug_info("msn", "got_ok: listening failed\n");
879
content = g_strdup_printf(
882
"Conn-Type: IP-Restrict-NAT\r\n"
888
rand() % G_MAXUINT32,
893
/* Listen socket created successfully. */
894
purple_debug_info("msn", "got_ok: listening socket created\n");
896
content = g_strdup_printf(
899
"Conn-Type: Direct-Connect\r\n"
909
msg = msn_slpmsg_sip_new(
914
"application/x-msnmsgr-transreqbody",
917
msg->info = "DC INVITE";
918
msg->text_body = TRUE;
923
msn_slplink_queue_slpmsg(slpcall->slplink, msg);
925
else if (!strcmp(type, "application/x-msnmsgr-transreqbody"))
927
/* Do we get this? */
928
purple_debug_info("msn", "OK with transreqbody\n");
930
else if (!strcmp(type, "application/x-msnmsgr-transrespbody"))
932
msn_slp_process_transresp(slpcall, content);
937
got_error(MsnSlpCall *slpcall,
938
const char *error, const char *type, const char *content)
940
/* It's not valid. Kill this off. */
941
purple_debug_error("msn", "Received non-OK result: %s\n",
942
error ? error : "Unknown");
944
if (type && (!strcmp(type, "application/x-msnmsgr-transreqbody")
945
|| !strcmp(type, "application/x-msnmsgr-transrespbody"))) {
946
MsnDirectConn *dc = slpcall->slplink->dc;
948
msn_dc_fallback_to_sb(dc);
953
slpcall->wasted = TRUE;
957
msn_slp_sip_recv(MsnSlpLink *slplink, const char *body)
963
purple_debug_warning("msn", "received bogus message\n");
967
if (!strncmp(body, "INVITE", strlen("INVITE")))
974
/* From: <msnmsgr:buddy@hotmail.com> */
976
slpcall->remote_user = get_token(body, "From: <msnmsgr:", ">\r\n");
979
branch = get_token(body, ";branch={", "}");
981
call_id = get_token(body, "Call-ID: {", "}");
984
long content_len = -1;
986
temp = get_token(body, "Content-Length: ", "\r\n");
988
content_len = atoi(temp);
991
content_type = get_token(body, "Content-Type: ", "\r\n");
993
content = get_token(body, "\r\n\r\n", NULL);
996
if (branch && call_id)
998
slpcall = msn_slplink_find_slp_call(slplink, call_id);
1001
g_free(slpcall->branch);
1002
slpcall->branch = g_strdup(branch);
1003
got_invite(slpcall, branch, content_type, content);
1005
else if (content_type && content)
1007
slpcall = msn_slpcall_new(slplink);
1008
slpcall->id = g_strdup(call_id);
1009
got_invite(slpcall, branch, content_type, content);
1015
g_free(content_type);
1018
else if (!strncmp(body, "MSNSLP/1.0 ", strlen("MSNSLP/1.0 ")))
1022
/* Make sure this is "OK" */
1023
const char *status = body + strlen("MSNSLP/1.0 ");
1026
call_id = get_token(body, "Call-ID: {", "}");
1027
slpcall = msn_slplink_find_slp_call(slplink, call_id);
1030
g_return_val_if_fail(slpcall != NULL, NULL);
1032
content_type = get_token(body, "Content-Type: ", "\r\n");
1034
content = get_token(body, "\r\n\r\n", NULL);
1036
if (strncmp(status, "200 OK", 6))
1042
if ((c = strchr(status, '\r')) || (c = strchr(status, '\n')) ||
1043
(c = strchr(status, '\0')))
1045
size_t len = c - status;
1046
error = g_strndup(status, len);
1049
got_error(slpcall, error, content_type, content);
1053
/* Everything's just dandy */
1054
got_ok(slpcall, content_type, content);
1057
g_free(content_type);
1060
else if (!strncmp(body, "BYE", strlen("BYE")))
1064
call_id = get_token(body, "Call-ID: {", "}");
1065
slpcall = msn_slplink_find_slp_call(slplink, call_id);
1068
if (slpcall != NULL)
1069
slpcall->wasted = TRUE;
1071
/* msn_slpcall_destroy(slpcall); */
1079
93
/**************************************************************************
1081
95
**************************************************************************/
1084
msn_p2p_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
1086
MsnSession *session;
1087
MsnSlpLink *slplink;
1091
session = cmdproc->servconn->session;
1092
slplink = msn_session_get_slplink(session, msg->remote_user);
1094
if (slplink->swboard == NULL)
1097
* We will need swboard in order to change its flags. If its
1098
* NULL, something has probably gone wrong earlier on. I
1099
* didn't want to do this, but MSN 7 is somehow causing us
1100
* to crash here, I couldn't reproduce it to debug more,
1101
* and people are reporting bugs. Hopefully this doesn't
1102
* cause more crashes. Stu.
1104
if (cmdproc->data == NULL)
1105
g_warning("msn_p2p_msg cmdproc->data was NULL\n");
1107
slplink->swboard = (MsnSwitchBoard *)cmdproc->data;
1108
slplink->swboard->slplinks = g_list_prepend(slplink->swboard->slplinks, slplink);
1112
data = msn_message_get_bin_data(msg, &len);
1114
msn_slplink_process_msg(slplink, &msg->msnslp_header, data, len);
1118
got_emoticon(MsnSlpCall *slpcall,
1119
const guchar *data, gsize size)
1121
PurpleConversation *conv;
1122
MsnSwitchBoard *swboard;
1124
swboard = slpcall->slplink->swboard;
1125
conv = swboard->conv;
1128
/* FIXME: it would be better if we wrote the data as we received it
1129
instead of all at once, calling write multiple times and
1130
close once at the very end
1132
purple_conv_custom_smiley_write(conv, slpcall->data_info, data, size);
1133
purple_conv_custom_smiley_close(conv, slpcall->data_info );
1135
if (purple_debug_is_verbose())
1136
purple_debug_info("msn", "Got smiley: %s\n", slpcall->data_info);
1140
msn_emoticon_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
1142
MsnSession *session;
1143
MsnSlpLink *slplink;
1144
MsnSwitchBoard *swboard;
1147
char *smile, *body_str;
1148
const char *body, *who, *sha1;
1152
PurpleConversation *conv;
1154
session = cmdproc->servconn->session;
1156
if (!purple_account_get_bool(session->account, "custom_smileys", TRUE))
1159
swboard = cmdproc->data;
1160
conv = swboard->conv;
1162
body = msn_message_get_bin_data(msg, &body_len);
1163
if (!body || !body_len)
1165
body_str = g_strndup(body, body_len);
1167
/* MSN Messenger 7 may send more than one MSNObject in a single message...
1168
* Maybe 10 tokens is a reasonable max value. */
1169
tokens = g_strsplit(body_str, "\t", 10);
1173
for (tok = 0; tok < 9; tok += 2) {
1174
if (tokens[tok] == NULL || tokens[tok + 1] == NULL) {
1178
smile = tokens[tok];
1179
obj = msn_object_new_from_string(purple_url_decode(tokens[tok + 1]));
1184
who = msn_object_get_creator(obj);
1185
sha1 = msn_object_get_sha1(obj);
1187
slplink = msn_session_get_slplink(session, who);
1188
if (slplink->swboard != swboard) {
1189
if (slplink->swboard != NULL)
1191
* Apparently we're using a different switchboard now or
1192
* something? I don't know if this is normal, but it
1193
* definitely happens. So make sure the old switchboard
1194
* doesn't still have a reference to us.
1196
slplink->swboard->slplinks = g_list_remove(slplink->swboard->slplinks, slplink);
1197
slplink->swboard = swboard;
1198
slplink->swboard->slplinks = g_list_prepend(slplink->swboard->slplinks, slplink);
1201
/* If the conversation doesn't exist then this is a custom smiley
1202
* used in the first message in a MSN conversation: we need to create
1203
* the conversation now, otherwise the custom smiley won't be shown.
1204
* This happens because every GtkIMHtml has its own smiley tree: if
1205
* the conversation doesn't exist then we cannot associate the new
1206
* smiley with its GtkIMHtml widget. */
1208
conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, session->account, who);
1211
if (purple_conv_custom_smiley_add(conv, smile, "sha1", sha1, TRUE)) {
1212
msn_slplink_request_object(slplink, smile, got_emoticon, NULL, obj);
1215
msn_object_destroy(obj);
1224
buddy_icon_cached(PurpleConnection *gc, MsnObject *obj)
1226
PurpleAccount *account;
1231
g_return_val_if_fail(obj != NULL, FALSE);
1233
account = purple_connection_get_account(gc);
1235
buddy = purple_find_buddy(account, msn_object_get_creator(obj));
1239
old = purple_buddy_icons_get_checksum_for_user(buddy);
1240
new = msn_object_get_sha1(obj);
1245
/* If the old and new checksums are the same, and the file actually exists,
1246
* then return TRUE */
1247
if (old != NULL && !strcmp(old, new))
1254
msn_release_buddy_icon_request(MsnUserList *userlist)
1258
g_return_if_fail(userlist != NULL);
1260
if (purple_debug_is_verbose())
1261
purple_debug_info("msn", "Releasing buddy icon request\n");
1263
if (userlist->buddy_icon_window > 0)
1267
queue = userlist->buddy_icon_requests;
1269
if (g_queue_is_empty(userlist->buddy_icon_requests))
1272
user = g_queue_pop_head(queue);
1274
userlist->buddy_icon_window--;
1275
request_user_display(user);
1277
if (purple_debug_is_verbose())
1278
purple_debug_info("msn",
1279
"msn_release_buddy_icon_request(): buddy_icon_window-- yields =%d\n",
1280
userlist->buddy_icon_window);
1285
98
* Called on a timeout from end_user_display(). Frees a buddy icon window slow and dequeues the next
1286
99
* buddy icon request if there is one.