2 * @file msnslp.c MSNSLP support
6 * Purple is the legal property of its developers, whose names are too numerous
7 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
31 #include "switchboard.h"
35 /* ms to delay between sending buddy icon requests to the server. */
36 #define BUDDY_ICON_DELAY 20
40 static void send_ok(MsnSlpCall
*slpcall
, const char *branch
,
41 const char *type
, const char *content
);
43 static void send_decline(MsnSlpCall
*slpcall
, const char *branch
,
44 const char *type
, const char *content
);
46 static void request_user_display(MsnUser
*user
);
48 /**************************************************************************
50 **************************************************************************/
53 get_token(const char *str
, const char *start
, const char *end
)
57 if ((c
= strstr(str
, start
)) == NULL
)
64 if ((c2
= strstr(c
, end
)) == NULL
)
67 return g_strndup(c
, c2
- c
);
71 /* This has to be changed */
77 /**************************************************************************
79 **************************************************************************/
82 msn_xfer_init(PurpleXfer
*xfer
)
85 /* MsnSlpLink *slplink; */
88 purple_debug_info("msn", "xfer_init\n");
93 content
= g_strdup_printf("SessionID: %lu\r\n\r\n",
96 send_ok(slpcall
, slpcall
->branch
, "application/x-msnmsgr-sessionreqbody",
100 msn_slplink_send_queued_slpmsgs(slpcall
->slplink
);
104 msn_xfer_cancel(PurpleXfer
*xfer
)
109 g_return_if_fail(xfer
!= NULL
);
110 g_return_if_fail(xfer
->data
!= NULL
);
112 slpcall
= xfer
->data
;
114 if (purple_xfer_get_status(xfer
) == PURPLE_XFER_STATUS_CANCEL_LOCAL
)
116 if (slpcall
->started
)
118 msn_slpcall_close(slpcall
);
122 content
= g_strdup_printf("SessionID: %lu\r\n\r\n",
123 slpcall
->session_id
);
125 send_decline(slpcall
, slpcall
->branch
, "application/x-msnmsgr-sessionreqbody",
129 msn_slplink_send_queued_slpmsgs(slpcall
->slplink
);
131 msn_slpcall_destroy(slpcall
);
137 msn_xfer_progress_cb(MsnSlpCall
*slpcall
, gsize total_length
, gsize len
, gsize offset
)
141 xfer
= slpcall
->xfer
;
143 xfer
->bytes_sent
= (offset
+ len
);
144 xfer
->bytes_remaining
= total_length
- (offset
+ len
);
146 purple_xfer_update_progress(xfer
);
150 msn_xfer_end_cb(MsnSlpCall
*slpcall
, MsnSession
*session
)
152 if ((purple_xfer_get_status(slpcall
->xfer
) != PURPLE_XFER_STATUS_DONE
) &&
153 (purple_xfer_get_status(slpcall
->xfer
) != PURPLE_XFER_STATUS_CANCEL_REMOTE
) &&
154 (purple_xfer_get_status(slpcall
->xfer
) != PURPLE_XFER_STATUS_CANCEL_LOCAL
))
156 purple_xfer_cancel_remote(slpcall
->xfer
);
161 msn_xfer_completed_cb(MsnSlpCall
*slpcall
, const guchar
*body
,
164 PurpleXfer
*xfer
= slpcall
->xfer
;
165 purple_xfer_set_completed(xfer
, TRUE
);
166 purple_xfer_end(xfer
);
169 /**************************************************************************
171 **************************************************************************/
175 got_transresp(MsnSlpCall
*slpcall
, const char *nonce
,
176 const char *ips_str
, int port
)
178 MsnDirectConn
*directconn
;
179 char **ip_addrs
, **c
;
181 directconn
= msn_directconn_new(slpcall
->slplink
);
183 directconn
->initial_call
= slpcall
;
185 /* msn_directconn_parse_nonce(directconn, nonce); */
186 directconn
->nonce
= g_strdup(nonce
);
188 ip_addrs
= g_strsplit(ips_str
, " ", -1);
190 for (c
= ip_addrs
; *c
!= NULL
; c
++)
192 purple_debug_info("msn", "ip_addr = %s\n", *c
);
193 if (msn_directconn_connect(directconn
, *c
, port
))
197 g_strfreev(ip_addrs
);
202 send_ok(MsnSlpCall
*slpcall
, const char *branch
,
203 const char *type
, const char *content
)
206 MsnSlpMessage
*slpmsg
;
208 slplink
= slpcall
->slplink
;
211 slpmsg
= msn_slpmsg_sip_new(slpcall
, 1,
213 branch
, type
, content
);
216 slpmsg
->info
= "SLP 200 OK";
217 slpmsg
->text_body
= TRUE
;
220 msn_slplink_queue_slpmsg(slplink
, slpmsg
);
222 msn_slpcall_session_init(slpcall
);
226 send_decline(MsnSlpCall
*slpcall
, const char *branch
,
227 const char *type
, const char *content
)
230 MsnSlpMessage
*slpmsg
;
232 slplink
= slpcall
->slplink
;
235 slpmsg
= msn_slpmsg_sip_new(slpcall
, 1,
236 "MSNSLP/1.0 603 Decline",
237 branch
, type
, content
);
240 slpmsg
->info
= "SLP 603 Decline";
241 slpmsg
->text_body
= TRUE
;
244 msn_slplink_queue_slpmsg(slplink
, slpmsg
);
247 #define MAX_FILE_NAME_LEN 0x226
250 got_sessionreq(MsnSlpCall
*slpcall
, const char *branch
,
251 const char *euf_guid
, const char *context
)
253 if (!strcmp(euf_guid
, MSN_OBJ_GUID
))
255 /* Emoticon or UserDisplay */
259 MsnSlpMessage
*slpmsg
;
262 PurpleStoredImage
*img
;
266 content
= g_strdup_printf("SessionID: %lu\r\n\r\n",
267 slpcall
->session_id
);
269 send_ok(slpcall
, branch
, "application/x-msnmsgr-sessionreqbody",
274 slplink
= slpcall
->slplink
;
276 msnobj_data
= (char *)purple_base64_decode(context
, &len
);
277 obj
= msn_object_new_from_string(msnobj_data
);
278 type
= msn_object_get_type(obj
);
281 if ((type
!= MSN_OBJECT_USERTILE
) && (type
!= MSN_OBJECT_EMOTICON
))
283 purple_debug_error("msn", "Wrong object?\n");
284 msn_object_destroy(obj
);
285 g_return_if_reached();
288 if (type
== MSN_OBJECT_EMOTICON
) {
290 path
= g_build_filename(purple_smileys_get_storing_dir(),
291 obj
->location
, NULL
);
292 img
= purple_imgstore_new_from_file(path
);
295 img
= msn_object_get_image(obj
);
297 purple_imgstore_ref(img
);
299 msn_object_destroy(obj
);
303 purple_debug_error("msn", "Wrong object.\n");
304 g_return_if_reached();
308 slpmsg
= msn_slpmsg_new(slplink
);
309 slpmsg
->slpcall
= slpcall
;
310 slpmsg
->session_id
= slpcall
->session_id
;
311 msn_slpmsg_set_body(slpmsg
, NULL
, 4);
313 slpmsg
->info
= "SLP DATA PREP";
315 msn_slplink_queue_slpmsg(slplink
, slpmsg
);
318 slpmsg
= msn_slpmsg_new(slplink
);
319 slpmsg
->slpcall
= slpcall
;
320 slpmsg
->flags
= 0x20;
322 slpmsg
->info
= "SLP DATA";
324 msn_slpmsg_set_image(slpmsg
, img
);
325 msn_slplink_queue_slpmsg(slplink
, slpmsg
);
326 purple_imgstore_unref(img
);
328 else if (!strcmp(euf_guid
, MSN_FT_GUID
))
331 PurpleAccount
*account
;
339 account
= slpcall
->slplink
->session
->account
;
341 slpcall
->cb
= msn_xfer_completed_cb
;
342 slpcall
->end_cb
= msn_xfer_end_cb
;
343 slpcall
->progress_cb
= msn_xfer_progress_cb
;
344 slpcall
->branch
= g_strdup(branch
);
346 slpcall
->pending
= TRUE
;
348 xfer
= purple_xfer_new(account
, PURPLE_XFER_RECEIVE
,
349 slpcall
->slplink
->remote_user
);
352 bin
= (char *)purple_base64_decode(context
, &bin_len
);
353 file_size
= GUINT32_FROM_LE(*(gsize
*)(bin
+ 8));
355 uni_name
= (gunichar2
*)(bin
+ 20);
356 while(*uni_name
!= 0 && ((char *)uni_name
- (bin
+ 20)) < MAX_FILE_NAME_LEN
) {
357 *uni_name
= GUINT16_FROM_LE(*uni_name
);
361 file_name
= g_utf16_to_utf8((const gunichar2
*)(bin
+ 20), -1,
366 purple_xfer_set_filename(xfer
, file_name
? file_name
: "");
368 purple_xfer_set_size(xfer
, file_size
);
369 purple_xfer_set_init_fnc(xfer
, msn_xfer_init
);
370 purple_xfer_set_request_denied_fnc(xfer
, msn_xfer_cancel
);
371 purple_xfer_set_cancel_recv_fnc(xfer
, msn_xfer_cancel
);
373 slpcall
->xfer
= xfer
;
374 purple_xfer_ref(slpcall
->xfer
);
376 xfer
->data
= slpcall
;
378 purple_xfer_request(xfer
);
381 purple_debug_warning("msn", "SLP SessionReq with unknown EUF-GUID: %s\n", euf_guid
);
385 send_bye(MsnSlpCall
*slpcall
, const char *type
)
388 PurpleAccount
*account
;
389 MsnSlpMessage
*slpmsg
;
392 slplink
= slpcall
->slplink
;
394 g_return_if_fail(slplink
!= NULL
);
396 account
= slplink
->session
->account
;
398 header
= g_strdup_printf("BYE MSNMSGR:%s MSNSLP/1.0",
399 purple_account_get_username(account
));
401 slpmsg
= msn_slpmsg_sip_new(slpcall
, 0, header
,
402 "A0D624A6-6C0C-4283-A9E0-BC97B4B46D32",
408 slpmsg
->info
= "SLP BYE";
409 slpmsg
->text_body
= TRUE
;
412 msn_slplink_queue_slpmsg(slplink
, slpmsg
);
416 got_invite(MsnSlpCall
*slpcall
,
417 const char *branch
, const char *type
, const char *content
)
421 slplink
= slpcall
->slplink
;
423 if (!strcmp(type
, "application/x-msnmsgr-sessionreqbody"))
425 char *euf_guid
, *context
;
428 euf_guid
= get_token(content
, "EUF-GUID: {", "}\r\n");
430 temp
= get_token(content
, "SessionID: ", "\r\n");
432 slpcall
->session_id
= atoi(temp
);
435 temp
= get_token(content
, "AppID: ", "\r\n");
437 slpcall
->app_id
= atoi(temp
);
440 context
= get_token(content
, "Context: ", "\r\n");
443 got_sessionreq(slpcall
, branch
, euf_guid
, context
);
448 else if (!strcmp(type
, "application/x-msnmsgr-transreqbody"))
450 /* A direct connection? */
452 char *listening
, *nonce
;
458 MsnDirectConn
*directconn
;
459 /* const char *ip_addr; */
463 /* ip_addr = purple_prefs_get_string("/purple/ft/public_ip"); */
468 directconn
= msn_directconn_new(slplink
);
470 /* msn_directconn_parse_nonce(directconn, nonce); */
471 directconn
->nonce
= g_strdup(nonce
);
473 msn_directconn_listen(directconn
);
475 port
= directconn
->port
;
477 content
= g_strdup_printf(
481 "Ipv4Internal-Addrs: 192.168.0.82\r\n"
482 "Ipv4Internal-Port: %d\r\n"
492 nonce
= g_strdup("00000000-0000-0000-0000-000000000000");
494 content
= g_strdup_printf(
503 send_ok(slpcall
, branch
,
504 "application/x-msnmsgr-transrespbody", content
);
509 else if (!strcmp(type
, "application/x-msnmsgr-transrespbody"))
517 nonce
= get_token(content
, "Nonce: {", "}\r\n");
518 if (ip_addrs
== NULL
)
521 ip_addrs
= get_token(content
, "IPv4Internal-Addrs: ", "\r\n");
523 temp
= get_token(content
, "IPv4Internal-Port: ", "\r\n");
531 got_transresp(slpcall
, nonce
, ip_addrs
, port
);
540 got_ok(MsnSlpCall
*slpcall
,
541 const char *type
, const char *content
)
543 g_return_if_fail(slpcall
!= NULL
);
544 g_return_if_fail(type
!= NULL
);
546 if (!strcmp(type
, "application/x-msnmsgr-sessionreqbody"))
549 if (slpcall
->type
== MSN_SLPCALL_DC
)
551 /* First let's try a DirectConnection. */
554 MsnSlpMessage
*slpmsg
;
559 slplink
= slpcall
->slplink
;
561 branch
= rand_guid();
563 content
= g_strdup_printf(
564 "Bridges: TRUDPv1 TCPv1\r\n"
566 "Conn-Type: Direct-Connect\r\n"
571 header
= g_strdup_printf("INVITE MSNMSGR:%s MSNSLP/1.0",
572 slplink
->remote_user
);
574 slpmsg
= msn_slp_sipmsg_new(slpcall
, 0, header
, branch
,
575 "application/x-msnmsgr-transreqbody",
579 slpmsg
->info
= "SLP INVITE";
580 slpmsg
->text_body
= TRUE
;
582 msn_slplink_send_slpmsg(slplink
, slpmsg
);
591 msn_slpcall_session_init(slpcall
);
594 msn_slpcall_session_init(slpcall
);
597 else if (!strcmp(type
, "application/x-msnmsgr-transreqbody"))
599 /* Do we get this? */
600 purple_debug_info("msn", "OK with transreqbody\n");
602 else if (!strcmp(type
, "application/x-msnmsgr-transrespbody"))
610 nonce
= get_token(content
, "Nonce: {", "}\r\n");
611 if (ip_addrs
== NULL
)
614 ip_addrs
= get_token(content
, "IPv4Internal-Addrs: ", "\r\n");
616 temp
= get_token(content
, "IPv4Internal-Port: ", "\r\n");
624 got_transresp(slpcall
, nonce
, ip_addrs
, port
);
633 msn_slp_sip_recv(MsnSlpLink
*slplink
, const char *body
)
639 purple_debug_warning("msn", "received bogus message\n");
643 if (!strncmp(body
, "INVITE", strlen("INVITE")))
649 slpcall
= msn_slpcall_new(slplink
);
651 /* From: <msnmsgr:buddy@hotmail.com> */
653 slpcall
->remote_user
= get_token(body
, "From: <msnmsgr:", ">\r\n");
656 branch
= get_token(body
, ";branch={", "}");
658 slpcall
->id
= get_token(body
, "Call-ID: {", "}");
661 long content_len
= -1;
663 temp
= get_token(body
, "Content-Length: ", "\r\n");
665 content_len
= atoi(temp
);
668 content_type
= get_token(body
, "Content-Type: ", "\r\n");
670 content
= get_token(body
, "\r\n\r\n", NULL
);
672 got_invite(slpcall
, branch
, content_type
, content
);
675 g_free(content_type
);
678 else if (!strncmp(body
, "MSNSLP/1.0 ", strlen("MSNSLP/1.0 ")))
682 /* Make sure this is "OK" */
683 const char *status
= body
+ strlen("MSNSLP/1.0 ");
686 call_id
= get_token(body
, "Call-ID: {", "}");
687 slpcall
= msn_slplink_find_slp_call(slplink
, call_id
);
690 g_return_val_if_fail(slpcall
!= NULL
, NULL
);
692 if (strncmp(status
, "200 OK", 6))
694 /* It's not valid. Kill this off. */
699 if ((c
= strchr(status
, '\r')) || (c
= strchr(status
, '\n')) ||
700 (c
= strchr(status
, '\0')))
702 size_t offset
= c
- status
;
703 if (offset
>= sizeof(temp
))
704 offset
= sizeof(temp
) - 1;
706 strncpy(temp
, status
, offset
);
710 purple_debug_error("msn", "Received non-OK result: %s\n", temp
);
712 slpcall
->wasted
= TRUE
;
714 /* msn_slpcall_destroy(slpcall); */
718 content_type
= get_token(body
, "Content-Type: ", "\r\n");
720 content
= get_token(body
, "\r\n\r\n", NULL
);
722 got_ok(slpcall
, content_type
, content
);
724 g_free(content_type
);
727 else if (!strncmp(body
, "BYE", strlen("BYE")))
731 call_id
= get_token(body
, "Call-ID: {", "}");
732 slpcall
= msn_slplink_find_slp_call(slplink
, call_id
);
736 slpcall
->wasted
= TRUE
;
738 /* msn_slpcall_destroy(slpcall); */
746 /**************************************************************************
748 **************************************************************************/
751 msn_p2p_msg(MsnCmdProc
*cmdproc
, MsnMessage
*msg
)
756 session
= cmdproc
->servconn
->session
;
757 slplink
= msn_session_get_slplink(session
, msg
->remote_user
);
759 if (slplink
->swboard
== NULL
)
762 * We will need swboard in order to change its flags. If its
763 * NULL, something has probably gone wrong earlier on. I
764 * didn't want to do this, but MSN 7 is somehow causing us
765 * to crash here, I couldn't reproduce it to debug more,
766 * and people are reporting bugs. Hopefully this doesn't
767 * cause more crashes. Stu.
769 if (cmdproc
->data
== NULL
)
770 g_warning("msn_p2p_msg cmdproc->data was NULL\n");
772 slplink
->swboard
= (MsnSwitchBoard
*)cmdproc
->data
;
773 slplink
->swboard
->slplinks
= g_list_prepend(slplink
->swboard
->slplinks
, slplink
);
777 msn_slplink_process_msg(slplink
, msg
);
781 got_emoticon(MsnSlpCall
*slpcall
,
782 const guchar
*data
, gsize size
)
784 PurpleConversation
*conv
;
785 MsnSwitchBoard
*swboard
;
787 swboard
= slpcall
->slplink
->swboard
;
788 conv
= swboard
->conv
;
791 /* FIXME: it would be better if we wrote the data as we received it
792 instead of all at once, calling write multiple times and
793 close once at the very end
795 purple_conv_custom_smiley_write(conv
, slpcall
->data_info
, data
, size
);
796 purple_conv_custom_smiley_close(conv
, slpcall
->data_info
);
799 purple_debug_info("msn", "Got smiley: %s\n", slpcall
->data_info
);
804 msn_emoticon_msg(MsnCmdProc
*cmdproc
, MsnMessage
*msg
)
808 MsnSwitchBoard
*swboard
;
811 char *smile
, *body_str
;
812 const char *body
, *who
, *sha1
;
816 PurpleConversation
*conv
;
818 session
= cmdproc
->servconn
->session
;
820 if (!purple_account_get_bool(session
->account
, "custom_smileys", TRUE
))
823 swboard
= cmdproc
->data
;
824 conv
= swboard
->conv
;
826 body
= msn_message_get_bin_data(msg
, &body_len
);
827 body_str
= g_strndup(body
, body_len
);
829 /* MSN Messenger 7 may send more than one MSNObject in a single message...
830 * Maybe 10 tokens is a reasonable max value. */
831 tokens
= g_strsplit(body_str
, "\t", 10);
835 for (tok
= 0; tok
< 9; tok
+= 2) {
836 if (tokens
[tok
] == NULL
|| tokens
[tok
+ 1] == NULL
) {
841 obj
= msn_object_new_from_string(purple_url_decode(tokens
[tok
+ 1]));
846 who
= msn_object_get_creator(obj
);
847 sha1
= msn_object_get_sha1(obj
);
849 slplink
= msn_session_get_slplink(session
, who
);
850 if (slplink
->swboard
!= swboard
) {
851 if (slplink
->swboard
!= NULL
)
853 * Apparently we're using a different switchboard now or
854 * something? I don't know if this is normal, but it
855 * definitely happens. So make sure the old switchboard
856 * doesn't still have a reference to us.
858 slplink
->swboard
->slplinks
= g_list_remove(slplink
->swboard
->slplinks
, slplink
);
859 slplink
->swboard
= swboard
;
860 slplink
->swboard
->slplinks
= g_list_prepend(slplink
->swboard
->slplinks
, slplink
);
863 /* If the conversation doesn't exist then this is a custom smiley
864 * used in the first message in a MSN conversation: we need to create
865 * the conversation now, otherwise the custom smiley won't be shown.
866 * This happens because every GtkIMHtml has its own smiley tree: if
867 * the conversation doesn't exist then we cannot associate the new
868 * smiley with its GtkIMHtml widget. */
870 conv
= purple_conversation_new(PURPLE_CONV_TYPE_IM
, session
->account
, who
);
873 if (purple_conv_custom_smiley_add(conv
, smile
, "sha1", sha1
, TRUE
)) {
874 msn_slplink_request_object(slplink
, smile
, got_emoticon
, NULL
, obj
);
877 msn_object_destroy(obj
);
886 buddy_icon_cached(PurpleConnection
*gc
, MsnObject
*obj
)
888 PurpleAccount
*account
;
893 g_return_val_if_fail(obj
!= NULL
, FALSE
);
895 account
= purple_connection_get_account(gc
);
897 buddy
= purple_find_buddy(account
, msn_object_get_creator(obj
));
901 old
= purple_buddy_icons_get_checksum_for_user(buddy
);
902 new = msn_object_get_sha1(obj
);
907 /* If the old and new checksums are the same, and the file actually exists,
908 * then return TRUE */
909 if (old
!= NULL
&& !strcmp(old
, new))
916 msn_release_buddy_icon_request(MsnUserList
*userlist
)
920 g_return_if_fail(userlist
!= NULL
);
923 purple_debug_info("msn", "Releasing buddy icon request\n");
926 if (userlist
->buddy_icon_window
> 0)
929 PurpleAccount
*account
;
930 const char *username
;
932 queue
= userlist
->buddy_icon_requests
;
934 if (g_queue_is_empty(userlist
->buddy_icon_requests
))
937 user
= g_queue_pop_head(queue
);
939 account
= userlist
->session
->account
;
940 username
= user
->passport
;
942 userlist
->buddy_icon_window
--;
943 request_user_display(user
);
946 purple_debug_info("msn", "msn_release_buddy_icon_request(): buddy_icon_window-- yields =%d\n",
947 userlist
->buddy_icon_window
);
953 * Called on a timeout from end_user_display(). Frees a buddy icon window slow and dequeues the next
954 * buddy icon request if there is one.
957 msn_release_buddy_icon_request_timeout(gpointer data
)
959 MsnUserList
*userlist
= (MsnUserList
*)data
;
961 /* Free one window slot */
962 userlist
->buddy_icon_window
++;
964 /* Clear the tag for our former request timer */
965 userlist
->buddy_icon_request_timer
= 0;
967 msn_release_buddy_icon_request(userlist
);
973 msn_queue_buddy_icon_request(MsnUser
*user
)
975 PurpleAccount
*account
;
979 g_return_if_fail(user
!= NULL
);
981 account
= user
->userlist
->session
->account
;
983 obj
= msn_user_get_object(user
);
987 purple_buddy_icons_set_for_user(account
, user
->passport
, NULL
, 0, NULL
);
991 if (!buddy_icon_cached(account
->gc
, obj
))
993 MsnUserList
*userlist
;
995 userlist
= user
->userlist
;
996 queue
= userlist
->buddy_icon_requests
;
999 purple_debug_info("msn", "Queueing buddy icon request for %s (buddy_icon_window = %i)\n",
1000 user
->passport
, userlist
->buddy_icon_window
);
1003 g_queue_push_tail(queue
, user
);
1005 if (userlist
->buddy_icon_window
> 0)
1006 msn_release_buddy_icon_request(userlist
);
1011 got_user_display(MsnSlpCall
*slpcall
,
1012 const guchar
*data
, gsize size
)
1014 MsnUserList
*userlist
;
1016 PurpleAccount
*account
;
1018 g_return_if_fail(slpcall
!= NULL
);
1020 info
= slpcall
->data_info
;
1022 purple_debug_info("msn", "Got User Display: %s\n", slpcall
->slplink
->remote_user
);
1025 userlist
= slpcall
->slplink
->session
->userlist
;
1026 account
= slpcall
->slplink
->session
->account
;
1028 purple_buddy_icons_set_for_user(account
, slpcall
->slplink
->remote_user
,
1029 g_memdup(data
, size
), size
, info
);
1032 /* Free one window slot */
1033 userlist
->buddy_icon_window
++;
1035 purple_debug_info("msn", "got_user_display(): buddy_icon_window++ yields =%d\n",
1036 userlist
->buddy_icon_window
);
1038 msn_release_buddy_icon_request(userlist
);
1043 end_user_display(MsnSlpCall
*slpcall
, MsnSession
*session
)
1045 MsnUserList
*userlist
;
1047 g_return_if_fail(session
!= NULL
);
1050 purple_debug_info("msn", "End User Display\n");
1053 userlist
= session
->userlist
;
1055 /* If the session is being destroyed we better stop doing anything. */
1056 if (session
->destroying
)
1059 /* Delay before freeing a buddy icon window slot and requesting the next icon, if appropriate.
1060 * If we don't delay, we'll rapidly hit the MSN equivalent of AIM's rate limiting; the server will
1061 * send us an error 800 like so:
1063 * C: NS 000: XFR 21 SB
1066 if (userlist
->buddy_icon_request_timer
) {
1067 /* Free the window slot used by this previous request */
1068 userlist
->buddy_icon_window
++;
1070 /* Clear our pending timeout */
1071 purple_timeout_remove(userlist
->buddy_icon_request_timer
);
1074 /* Wait BUDDY_ICON_DELAY s before freeing our window slot and requesting the next icon. */
1075 userlist
->buddy_icon_request_timer
= purple_timeout_add_seconds(BUDDY_ICON_DELAY
,
1076 msn_release_buddy_icon_request_timeout
, userlist
);
1080 request_user_display(MsnUser
*user
)
1082 PurpleAccount
*account
;
1083 MsnSession
*session
;
1084 MsnSlpLink
*slplink
;
1088 session
= user
->userlist
->session
;
1089 account
= session
->account
;
1091 slplink
= msn_session_get_slplink(session
, user
->passport
);
1093 obj
= msn_user_get_object(user
);
1095 info
= msn_object_get_sha1(obj
);
1097 if (g_ascii_strcasecmp(user
->passport
,
1098 purple_account_get_username(account
)))
1100 msn_slplink_request_object(slplink
, info
, got_user_display
,
1101 end_user_display
, obj
);
1105 MsnObject
*my_obj
= NULL
;
1106 gconstpointer data
= NULL
;
1110 purple_debug_info("msn", "Requesting our own user display\n");
1113 my_obj
= msn_user_get_object(session
->user
);
1117 PurpleStoredImage
*img
= msn_object_get_image(my_obj
);
1118 data
= purple_imgstore_get_data(img
);
1119 len
= purple_imgstore_get_size(img
);
1122 purple_buddy_icons_set_for_user(account
, user
->passport
, g_memdup(data
, len
), len
, info
);
1124 /* Free one window slot */
1125 session
->userlist
->buddy_icon_window
++;
1128 purple_debug_info("msn", "request_user_display(): buddy_icon_window++ yields =%d\n",
1129 session
->userlist
->buddy_icon_window
);
1132 msn_release_buddy_icon_request(session
->userlist
);