6 * Copyright (C) 2009 pier11 <pier11@kinozal.tv>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "sipe-conf.h"
31 #include "sipe-dialog.h"
33 #include "sipe-session.h"
34 #include "sipe-utils.h"
37 * Add Conference request to FocusFactory.
38 * @param focus_factory_uri (%s) Ex.: sip:bob7@boston.local;gruu;opaque=app:conf:focusfactory
39 * @param from (%s) Ex.: sip:bob7@boston.local
40 * @param request_id (%d) Ex.: 1094520
41 * @param conference_id (%s) Ex.: 8386E6AEAAA41E4AA6627BA76D43B6D1
42 * @param expiry_time (%s) Ex.: 2009-07-13T17:57:09Z , Default duration: 7 hours
44 #define SIPE_SEND_CONF_ADD \
45 "<?xml version=\"1.0\"?>"\
46 "<request xmlns=\"urn:ietf:params:xml:ns:cccp\" "\
47 "xmlns:mscp=\"http://schemas.microsoft.com/rtc/2005/08/cccpextensions\" "\
53 "<ci:conference-info xmlns:ci=\"urn:ietf:params:xml:ns:conference-info\" entity=\"\" xmlns:msci=\"http://schemas.microsoft.com/rtc/2005/08/confinfoextensions\">"\
54 "<ci:conference-description>"\
56 "<msci:conference-id>%s</msci:conference-id>"\
57 "<msci:expiry-time>%s</msci:expiry-time>"\
58 "<msci:admission-policy>openAuthenticated</msci:admission-policy>"\
59 "</ci:conference-description>"\
60 "<msci:conference-view>"\
61 "<msci:entity-view entity=\"chat\"/>"\
62 "</msci:conference-view>"\
63 "</ci:conference-info>"\
68 * AddUser request to Focus.
70 * focus_URI, from, request_id, focus_URI, from, endpoint_GUID
72 #define SIPE_SEND_CONF_ADD_USER \
73 "<?xml version=\"1.0\"?>"\
74 "<request xmlns=\"urn:ietf:params:xml:ns:cccp\" xmlns:mscp=\"http://schemas.microsoft.com/rtc/2005/08/cccpextensions\" "\
80 "<conferenceKeys confEntity=\"%s\"/>"\
81 "<ci:user xmlns:ci=\"urn:ietf:params:xml:ns:conference-info\" entity=\"%s\">"\
83 "<ci:entry>attendee</ci:entry>"\
85 "<ci:endpoint entity=\"{%s}\" xmlns:msci=\"http://schemas.microsoft.com/rtc/2005/08/confinfoextensions\"/>"\
91 * ModifyUserRoles request to Focus. Makes user a leader.
92 * @param focus_uri (%s)
94 * @param request_id (%d)
95 * @param focus_uri (%s)
98 #define SIPE_SEND_CONF_MODIFY_USER_ROLES \
99 "<?xml version=\"1.0\"?>"\
100 "<request xmlns=\"urn:ietf:params:xml:ns:cccp\" xmlns:mscp=\"http://schemas.microsoft.com/rtc/2005/08/cccpextensions\" "\
106 "<userKeys confEntity=\"%s\" userEntity=\"%s\"/>"\
107 "<user-roles xmlns=\"urn:ietf:params:xml:ns:conference-info\">"\
108 "<entry>presenter</entry>"\
110 "</modifyUserRoles>"\
114 * ModifyConferenceLock request to Focus. Locks/unlocks conference.
115 * @param focus_uri (%s)
117 * @param request_id (%d)
118 * @param focus_uri (%s)
119 * @param locked (%s) "true" or "false" values applicable
121 #define SIPE_SEND_CONF_MODIFY_CONF_LOCK \
122 "<?xml version=\"1.0\"?>"\
123 "<request xmlns=\"urn:ietf:params:xml:ns:cccp\" xmlns:mscp=\"http://schemas.microsoft.com/rtc/2005/08/cccpextensions\" "\
128 "<modifyConferenceLock>"\
129 "<conferenceKeys confEntity=\"%s\"/>"\
130 "<locked>%s</locked>"\
131 "</modifyConferenceLock>"\
135 * ModifyConferenceLock request to Focus. Locks/unlocks conference.
136 * @param focus_uri (%s)
138 * @param request_id (%d)
139 * @param focus_uri (%s)
142 #define SIPE_SEND_CONF_DELETE_USER \
143 "<?xml version=\"1.0\"?>"\
144 "<request xmlns=\"urn:ietf:params:xml:ns:cccp\" xmlns:mscp=\"http://schemas.microsoft.com/rtc/2005/08/cccpextensions\" "\
150 "<userKeys confEntity=\"%s\" userEntity=\"%s\"/>"\
155 * Invite counterparty to join conference.
156 * @param focus_uri (%s)
157 * @param subject (%s) of conference
159 #define SIPE_SEND_CONF_INVITE \
160 "<Conferencing version=\"2.0\">"\
161 "<focus-uri>%s</focus-uri>"\
162 "<subject>%s</subject>"\
163 "<im available=\"true\">"\
169 * Generates random GUID.
170 * This method is borrowed from pidgin's msnutils.c
175 return g_strdup_printf("%4X%4X-%4X-%4X-%4X-%4X%4X%4X",
176 rand() % 0xAAFF + 0x1111,
177 rand() % 0xAAFF + 0x1111,
178 rand() % 0xAAFF + 0x1111,
179 rand() % 0xAAFF + 0x1111,
180 rand() % 0xAAFF + 0x1111,
181 rand() % 0xAAFF + 0x1111,
182 rand() % 0xAAFF + 0x1111,
183 rand() % 0xAAFF + 0x1111);
187 * @param expires not respected if set to negative value (E.g. -1)
190 sipe_subscribe_conference(struct sipe_account_data
*sip
,
191 struct sip_session
*session
,
194 gchar
*expires_hdr
= (expires
>= 0) ? g_strdup_printf("Expires: %d\r\n", expires
) : g_strdup("");
195 gchar
*contact
= get_contact(sip
);
196 gchar
*hdr
= g_strdup_printf(
197 "Event: conference\r\n"
199 "Accept: application/conference-info+xml\r\n"
200 "Supported: com.microsoft.autoextend\r\n"
201 "Supported: ms-benotify\r\n"
202 "Proxy-Require: ms-benotify\r\n"
203 "Supported: ms-piggyback-first-notify\r\n"
210 send_sip_request(sip
->gc
,
217 process_subscribe_response
);
221 /** Invite us to the focus callback */
223 process_invite_conf_focus_response(struct sipe_account_data
*sip
,
225 struct transaction
*trans
)
227 struct sip_session
*session
= NULL
;
228 char *focus_uri
= parse_from(sipmsg_find_header(msg
, "To"));
230 session
= sipe_session_find_conference(sip
, focus_uri
);
233 purple_debug_info("sipe", "process_invite_conf_focus_response: unable to find conf session with focus=%s\n", focus_uri
);
238 if (!session
->focus_dialog
) {
239 purple_debug_info("sipe", "process_invite_conf_focus_response: session's focus_dialog is NULL\n");
244 sipe_dialog_parse(session
->focus_dialog
, msg
, TRUE
);
246 if (msg
->response
>= 200) {
247 /* send ACK to focus */
248 session
->focus_dialog
->cseq
= 0;
249 send_sip_request(sip
->gc
, "ACK", session
->focus_dialog
->with
, session
->focus_dialog
->with
, NULL
, NULL
, session
->focus_dialog
, NULL
);
250 session
->focus_dialog
->outgoing_invite
= NULL
;
251 session
->focus_dialog
->is_established
= TRUE
;
254 if (msg
->response
>= 400) {
255 purple_debug_info("sipe", "process_invite_conf_focus_response: INVITE response is not 200. Failed to join focus.\n");
256 /* @TODO notify user of failure to join focus */
257 sipe_session_remove(sip
, session
);
260 } else if (msg
->response
== 200) {
261 xmlnode
*xn_response
= xmlnode_from_str(msg
->body
, msg
->bodylen
);
262 const gchar
*code
= xmlnode_get_attrib(xn_response
, "code");
263 if (!strcmp(code
, "success")) {
264 /* subscribe to focus */
265 sipe_subscribe_conference(sip
, session
, -1);
267 xmlnode_free(xn_response
);
274 /** Invite us to the focus */
276 sipe_invite_conf_focus(struct sipe_account_data
*sip
,
277 struct sip_session
*session
)
284 if (session
->focus_dialog
&& session
->focus_dialog
->is_established
) {
285 purple_debug_info("sipe", "session with %s already has a dialog open\n", session
->focus_uri
);
289 if(!session
->focus_dialog
) {
290 session
->focus_dialog
= g_new0(struct sip_dialog
, 1);
291 session
->focus_dialog
->callid
= gencallid();
292 session
->focus_dialog
->with
= g_strdup(session
->focus_uri
);
293 session
->focus_dialog
->endpoint_GUID
= rand_guid();
295 if (!(session
->focus_dialog
->ourtag
)) {
296 session
->focus_dialog
->ourtag
= gentag();
299 contact
= get_contact(sip
);
300 hdr
= g_strdup_printf(
301 "Supported: ms-sender\r\n"
303 "Content-Type: application/cccp+xml\r\n",
307 /* @TODO put request_id to queue to further compare with incoming one */
308 /* focus_URI, from, request_id, focus_URI, from, endpoint_GUID */
309 self
= sip_uri_self(sip
);
310 body
= g_strdup_printf(
311 SIPE_SEND_CONF_ADD_USER
,
312 session
->focus_dialog
->with
,
314 session
->request_id
++,
315 session
->focus_dialog
->with
,
317 session
->focus_dialog
->endpoint_GUID
);
320 session
->focus_dialog
->outgoing_invite
= send_sip_request(sip
->gc
,
322 session
->focus_dialog
->with
,
323 session
->focus_dialog
->with
,
326 session
->focus_dialog
,
327 process_invite_conf_focus_response
);
332 /** Modify User Role */
334 sipe_conf_modify_user_role(struct sipe_account_data
*sip
,
335 struct sip_session
*session
,
342 if (!session
->focus_dialog
|| !session
->focus_dialog
->is_established
) {
343 purple_debug_info("sipe", "sipe_conf_modify_user_role: no dialog with focus, exiting.\n");
348 "Content-Type: application/cccp+xml\r\n");
350 /* @TODO put request_id to queue to further compare with incoming one */
351 self
= sip_uri_self(sip
);
352 body
= g_strdup_printf(
353 SIPE_SEND_CONF_MODIFY_USER_ROLES
,
354 session
->focus_dialog
->with
,
356 session
->request_id
++,
357 session
->focus_dialog
->with
,
361 send_sip_request(sip
->gc
,
363 session
->focus_dialog
->with
,
364 session
->focus_dialog
->with
,
367 session
->focus_dialog
,
373 /** Modify Conference Lock */
375 sipe_conf_modify_conference_lock(struct sipe_account_data
*sip
,
376 struct sip_session
*session
,
377 const gboolean locked
)
383 if (!session
->focus_dialog
|| !session
->focus_dialog
->is_established
) {
384 purple_debug_info("sipe", "sipe_conf_modify_conference_lock: no dialog with focus, exiting.\n");
389 "Content-Type: application/cccp+xml\r\n");
391 /* @TODO put request_id to queue to further compare with incoming one */
392 self
= sip_uri_self(sip
);
393 body
= g_strdup_printf(
394 SIPE_SEND_CONF_MODIFY_CONF_LOCK
,
395 session
->focus_dialog
->with
,
397 session
->request_id
++,
398 session
->focus_dialog
->with
,
399 locked
? "true" : "false");
402 send_sip_request(sip
->gc
,
404 session
->focus_dialog
->with
,
405 session
->focus_dialog
->with
,
408 session
->focus_dialog
,
414 /** Modify Delete User */
416 sipe_conf_delete_user(struct sipe_account_data
*sip
,
417 struct sip_session
*session
,
424 if (!session
->focus_dialog
|| !session
->focus_dialog
->is_established
) {
425 purple_debug_info("sipe", "sipe_conf_delete_user: no dialog with focus, exiting.\n");
430 "Content-Type: application/cccp+xml\r\n");
432 /* @TODO put request_id to queue to further compare with incoming one */
433 self
= sip_uri_self(sip
);
434 body
= g_strdup_printf(
435 SIPE_SEND_CONF_DELETE_USER
,
436 session
->focus_dialog
->with
,
438 session
->request_id
++,
439 session
->focus_dialog
->with
,
443 send_sip_request(sip
->gc
,
445 session
->focus_dialog
->with
,
446 session
->focus_dialog
->with
,
449 session
->focus_dialog
,
455 /** Invite counterparty to join conference callback */
457 process_invite_conf_response(struct sipe_account_data
*sip
,
459 struct transaction
*trans
)
461 struct sip_dialog
*dialog
= g_new0(struct sip_dialog
, 1);
463 dialog
->callid
= g_strdup(sipmsg_find_header(msg
, "Call-ID"));
464 dialog
->cseq
= parse_cseq(sipmsg_find_header(msg
, "CSeq"));
465 dialog
->with
= parse_from(sipmsg_find_header(msg
, "To"));
466 sipe_dialog_parse(dialog
, msg
, TRUE
);
468 if (msg
->response
>= 200) {
469 /* send ACK to counterparty */
471 send_sip_request(sip
->gc
, "ACK", dialog
->with
, dialog
->with
, NULL
, NULL
, dialog
, NULL
);
472 dialog
->outgoing_invite
= NULL
;
473 dialog
->is_established
= TRUE
;
476 if (msg
->response
>= 400) {
477 purple_debug_info("sipe", "process_invite_conf_response: INVITE response is not 200. Failed to invite %s.\n", dialog
->with
);
478 /* @TODO notify user of failure to invite counterparty */
479 sipe_dialog_free(dialog
);
482 if (msg
->response
>= 200) {
483 /* send BYE to counterparty */
484 send_sip_request(sip
->gc
, "BYE", dialog
->with
, dialog
->with
, NULL
, NULL
, dialog
, NULL
);
487 sipe_dialog_free(dialog
);
492 * Invites counterparty to join conference.
495 sipe_invite_conf(struct sipe_account_data
*sip
,
496 struct sip_session
*session
,
502 struct sip_dialog
*dialog
= NULL
;
504 /* It will be short lived special dialog.
505 * Will not be stored in session.
507 dialog
= g_new0(struct sip_dialog
, 1);
508 dialog
->callid
= gencallid();
509 dialog
->with
= g_strdup(who
);
510 dialog
->ourtag
= gentag();
512 contact
= get_contact(sip
);
513 hdr
= g_strdup_printf(
514 "Supported: ms-sender\r\n"
516 "Content-Type: application/ms-conf-invite+xml\r\n",
520 body
= g_strdup_printf(
521 SIPE_SEND_CONF_INVITE
,
523 session
->subject
? session
->subject
: ""
526 send_sip_request( sip
->gc
,
533 process_invite_conf_response
);
535 sipe_dialog_free(dialog
);
540 /** Create conference callback */
542 process_conf_add_response(struct sipe_account_data
*sip
,
544 struct transaction
*trans
)
546 if (msg
->response
>= 400) {
547 purple_debug_info("sipe", "process_conf_add_response: SERVICE response is not 200. Failed to create conference.\n");
548 /* @TODO notify user of failure to create conference */
551 if (msg
->response
== 200) {
552 xmlnode
*xn_response
= xmlnode_from_str(msg
->body
, msg
->bodylen
);
553 if (!strcmp("success", xmlnode_get_attrib(xn_response
, "code")))
555 gchar
*who
= (gchar
*)trans
->payload
;
556 struct sip_session
*session
;
557 xmlnode
*xn_conference_info
= xmlnode_get_descendant(xn_response
, "addConference", "conference-info", NULL
);
559 session
= sipe_session_add_chat(sip
);
560 session
->is_multiparty
= FALSE
;
561 session
->focus_uri
= g_strdup(xmlnode_get_attrib(xn_conference_info
, "entity"));
562 purple_debug_info("sipe", "process_conf_add_response: session->focus_uri=%s\n",
563 session
->focus_uri
? session
->focus_uri
: "");
565 session
->pending_invite_queue
= slist_insert_unique_sorted(
566 session
->pending_invite_queue
, g_strdup(who
), (GCompareFunc
)strcmp
);
568 /* add self to conf */
569 sipe_invite_conf_focus(sip
, session
);
571 xmlnode_free(xn_response
);
578 * Creates conference.
581 sipe_conf_add(struct sipe_account_data
*sip
,
585 gchar
*conference_id
;
589 struct transaction
* tr
;
590 struct sip_dialog
*dialog
= NULL
;
591 time_t expiry
= time(NULL
) + 7*60*60; /* 7 hours */
592 const char *expiry_time
;
594 contact
= get_contact(sip
);
595 hdr
= g_strdup_printf(
596 "Supported: ms-sender\r\n"
598 "Content-Type: application/cccp+xml\r\n",
602 expiry_time
= purple_utf8_strftime("%Y-%m-%dT%H:%M:%SZ", gmtime(&expiry
));
603 self
= sip_uri_self(sip
);
604 conference_id
= genconfid();
605 body
= g_strdup_printf(
607 sip
->focus_factory_uri
,
612 g_free(conference_id
);
615 tr
= send_sip_request( sip
->gc
,
617 sip
->focus_factory_uri
,
618 sip
->focus_factory_uri
,
622 process_conf_add_response
);
623 tr
->payload
= g_strdup(who
);
625 sipe_dialog_free(dialog
);
631 process_incoming_invite_conf(struct sipe_account_data
*sip
,
634 struct sip_session
*session
= NULL
;
635 struct sip_dialog
*dialog
= NULL
;
636 xmlnode
*xn_conferencing
= xmlnode_from_str(msg
->body
, msg
->bodylen
);
637 xmlnode
*xn_focus_uri
= xmlnode_get_child(xn_conferencing
, "focus-uri");
638 char *focus_uri
= xmlnode_get_data(xn_focus_uri
);
640 xmlnode_free(xn_conferencing
);
643 purple_debug_info("sipe", "We have received invitation to Conference. Focus URI=%s\n", focus_uri
);
644 send_sip_response(sip
->gc
, msg
, 200, "OK", NULL
);
646 session
= sipe_session_add_chat(sip
);
647 session
->focus_uri
= focus_uri
;
648 session
->is_multiparty
= FALSE
;
650 /* temporary dialog with invitor */
651 dialog
= g_new0(struct sip_dialog
, 1);
652 dialog
->callid
= g_strdup(sipmsg_find_header(msg
, "Call-ID"));
653 dialog
->cseq
= parse_cseq(sipmsg_find_header(msg
, "CSeq"));
654 dialog
->with
= parse_from(sipmsg_find_header(msg
, "From"));
655 sipe_dialog_parse(dialog
, msg
, FALSE
);
657 /* send BYE to invitor */
658 send_sip_request(sip
->gc
, "BYE", dialog
->with
, dialog
->with
, NULL
, NULL
, dialog
, NULL
);
659 sipe_dialog_free(dialog
);
661 /* add self to conf */
662 sipe_invite_conf_focus(sip
, session
);
666 sipe_process_conference(struct sipe_account_data
*sip
,
669 xmlnode
*xn_conference_info
;
672 const gchar
*focus_uri
;
673 struct sip_session
*session
;
674 gboolean just_joined
= FALSE
;
676 if (msg
->response
!= 0 && msg
->response
!= 200) return;
678 if (msg
->bodylen
== 0 || msg
->body
== NULL
|| strcmp(sipmsg_find_header(msg
, "Event"), "conference")) return;
680 xn_conference_info
= xmlnode_from_str(msg
->body
, msg
->bodylen
);
681 if (!xn_conference_info
) return;
683 focus_uri
= xmlnode_get_attrib(xn_conference_info
, "entity");
684 session
= sipe_session_find_conference(sip
, focus_uri
);
687 purple_debug_info("sipe", "sipe_process_conference: unable to find conf session with focus=%s\n", focus_uri
);
691 if (session
->focus_uri
&& !session
->conv
) {
692 gchar
*chat_name
= g_strdup_printf(_("Chat #%d"), ++sip
->chat_seq
);
693 gchar
*self
= sip_uri_self(sip
);
694 /* create prpl chat */
695 session
->conv
= serv_got_joined_chat(sip
->gc
, session
->chat_id
, chat_name
);
696 session
->chat_name
= chat_name
;
697 purple_conv_chat_set_nick(PURPLE_CONV_CHAT(session
->conv
), self
);
699 /* @TODO ask for full state (re-subscribe) if it was a partial one -
700 * this is to obtain full list of conference participants.
706 if ((xn_subject
= xmlnode_get_descendant(xn_conference_info
, "conference-description", "subject", NULL
))) {
707 g_free(session
->subject
);
708 session
->subject
= xmlnode_get_data(xn_subject
);
709 purple_conv_chat_set_topic(PURPLE_CONV_CHAT(session
->conv
), NULL
, session
->subject
);
710 purple_debug_info("sipe", "sipe_process_conference: subject=%s\n", session
->subject
? session
->subject
: "");
714 if (!session
->im_mcu_uri
) {
715 for (node
= xmlnode_get_descendant(xn_conference_info
, "conference-description", "conf-uris", "entry", NULL
);
717 node
= xmlnode_get_next_twin(node
))
719 gchar
*purpose
= xmlnode_get_data(xmlnode_get_child(node
, "purpose"));
721 if (purpose
&& !strcmp("chat", purpose
)) {
723 session
->im_mcu_uri
= xmlnode_get_data(xmlnode_get_child(node
, "uri"));
724 purple_debug_info("sipe", "sipe_process_conference: im_mcu_uri=%s\n", session
->im_mcu_uri
);
732 for (node
= xmlnode_get_descendant(xn_conference_info
, "users", "user", NULL
); node
; node
= xmlnode_get_next_twin(node
)) {
733 xmlnode
*endpoint
= NULL
;
734 const gchar
*user_uri
= xmlnode_get_attrib(node
, "entity");
735 const gchar
*state
= xmlnode_get_attrib(node
, "state");
736 gchar
*role
= xmlnode_get_data(xmlnode_get_descendant(node
, "roles", "entry", NULL
));
737 PurpleConvChatBuddyFlags flags
= PURPLE_CBFLAGS_NONE
;
738 PurpleConvChat
*chat
= PURPLE_CONV_CHAT(session
->conv
);
739 gboolean is_in_im_mcu
= FALSE
;
740 gchar
*self
= sip_uri_self(sip
);
742 if (role
&& !strcmp(role
, "presenter")) {
743 flags
|= PURPLE_CBFLAGS_OP
;
746 if (!strcmp("deleted", state
)) {
747 if (purple_conv_chat_find_user(chat
, user_uri
)) {
748 purple_conv_chat_remove_user(chat
, user_uri
, NULL
/* reason */);
752 for (endpoint
= xmlnode_get_child(node
, "endpoint"); endpoint
; endpoint
= xmlnode_get_next_twin(endpoint
)) {
753 if (!strcmp("chat", xmlnode_get_attrib(endpoint
, "session-type"))) {
754 gchar
*status
= xmlnode_get_data(xmlnode_get_child(endpoint
, "status"));
755 if (!strcmp("connected", status
)) {
757 if (!purple_conv_chat_find_user(chat
, user_uri
)) {
758 purple_conv_chat_add_user(chat
, user_uri
, NULL
, flags
,
759 !just_joined
&& g_strcasecmp(user_uri
, self
));
761 purple_conv_chat_user_set_flags(chat
, user_uri
, flags
);
769 if (purple_conv_chat_find_user(chat
, user_uri
)) {
770 purple_conv_chat_remove_user(chat
, user_uri
, NULL
/* reason */);
778 /* entity-view, locked */
779 for (node
= xmlnode_get_descendant(xn_conference_info
, "conference-view", "entity-view", NULL
);
781 node
= xmlnode_get_next_twin(node
)) {
783 xmlnode
*xn_type
= xmlnode_get_descendant(node
, "entity-state", "media", "entry", "type", NULL
);
785 if (xn_type
&& !strcmp("chat", (tmp
= xmlnode_get_data(xn_type
)))) {
786 xmlnode
*xn_locked
= xmlnode_get_descendant(node
, "entity-state", "locked", NULL
);
788 gchar
*locked
= xmlnode_get_data(xn_locked
);
789 gboolean prev_locked
= session
->locked
;
790 session
->locked
= (locked
&& !strcmp(locked
, "true")) ? TRUE
: FALSE
;
791 if (prev_locked
&& !session
->locked
) {
792 sipe_present_info(sip
, session
,
793 _("This conference is no longer locked. Additional participants can now join."));
795 if (!prev_locked
&& session
->locked
) {
796 sipe_present_info(sip
, session
,
797 _("This conference is locked. Nobody else can join the conference while it is locked."));
800 purple_debug_info("sipe", "sipe_process_conference: session->locked=%s\n",
801 session
->locked
? "TRUE" : "FALSE");
807 xmlnode_free(xn_conference_info
);
809 if (session
->im_mcu_uri
) {
810 struct sip_dialog
*dialog
= sipe_dialog_find(session
, session
->im_mcu_uri
);
812 dialog
= sipe_dialog_add(session
);
814 dialog
->callid
= g_strdup(session
->callid
);
815 dialog
->with
= g_strdup(session
->im_mcu_uri
);
817 /* send INVITE to IM MCU */
818 sipe_invite(sip
, session
, dialog
->with
, NULL
, NULL
, FALSE
);
822 sipe_process_pending_invite_queue(sip
, session
);
826 sipe_conf_immcu_closed(struct sipe_account_data
*sip
,
827 struct sip_session
*session
)
829 sipe_present_info(sip
, session
,
830 _("You have been disconnected from this conference."));
831 purple_conv_chat_clear_users(PURPLE_CONV_CHAT(session
->conv
));
835 conf_session_close(struct sipe_account_data
*sip
,
836 struct sip_session
*session
)
839 /* unsubscribe from focus */
840 sipe_subscribe_conference(sip
, session
, 0);
842 if (session
->focus_dialog
) {
843 /* send BYE to focus */
844 send_sip_request(sip
->gc
,
846 session
->focus_dialog
->with
,
847 session
->focus_dialog
->with
,
850 session
->focus_dialog
,
857 sipe_process_imdn(struct sipe_account_data
*sip
,
860 gchar
*call_id
= sipmsg_find_header(msg
, "Call-ID");
861 static struct sip_session
*session
;
867 session
= sipe_session_find_chat_by_callid(sip
, call_id
);
869 xn_imdn
= xmlnode_from_str(msg
->body
, msg
->bodylen
);
870 message_id
= xmlnode_get_data(xmlnode_get_child(xn_imdn
, "message-id"));
872 message
= g_hash_table_lookup(session
->conf_unconfirmed_messages
, message_id
);
875 for (node
= xmlnode_get_child(xn_imdn
, "recipient"); node
; node
= xmlnode_get_next_twin(node
)) {
876 gchar
*tmp
= parse_from(xmlnode_get_attrib(node
, "uri"));
877 gchar
*uri
= parse_from(tmp
);
878 sipe_present_message_undelivered_err(sip
, session
, uri
, message
);
883 xmlnode_free(xn_imdn
);
885 g_hash_table_remove(session
->conf_unconfirmed_messages
, message_id
);
886 purple_debug_info("sipe", "sipe_process_imdn: removed message %s from conf_unconfirmed_messages(count=%d)\n",
887 message_id
, g_hash_table_size(session
->conf_unconfirmed_messages
));