6 * Copyright (C) 2011-12 SIPE Project <http://sipe.sourceforge.net/>
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
24 * OCS2007+ specific code
38 #include "sipe-common.h"
41 #include "sip-transport.h"
42 #include "sipe-backend.h"
43 #include "sipe-buddy.h"
45 #include "sipe-core.h"
46 #include "sipe-core-private.h"
48 #include "sipe-groupchat.h"
49 #include "sipe-media.h"
51 #include "sipe-ocs2007.h"
52 #include "sipe-schedule.h"
53 #include "sipe-status.h"
54 #include "sipe-utils.h"
57 /** MS-PRES publication */
58 struct sipe_publication
{
63 /** for 'state' category */
65 /** for 'state:calendarState' category */
67 /** for 'note' category */
69 /** for 'calendarData' category; 300(Team) container */
70 char *working_hours_xml_str
;
72 char *free_busy_base64
;
76 * 2007-style Activity and Availability.
80 * Conversion of legacyInterop availability ranges and activity tokens into
81 * SIPE activity tokens. The descriptions of availability ranges are defined at:
83 * http://msdn.microsoft.com/en-us/library/lync/dd941370%28v=office.13%29.aspx
85 * The values define the starting point of a range.
87 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_AVAILABLE 3000
88 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_AVAILABLE_IDLE 4500
89 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY 6000
90 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSYIDLE 7500
91 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_DND 9000 /* do not disturb */
92 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_BRB 12000 /* be right back */
93 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY 15000
94 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE 18000
96 const gchar
*sipe_ocs2007_status_from_legacy_availability(guint availability
,
97 const gchar
*activity
)
101 if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_AVAILABLE
) {
102 type
= SIPE_ACTIVITY_OFFLINE
;
103 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_AVAILABLE_IDLE
) {
104 type
= SIPE_ACTIVITY_AVAILABLE
;
105 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY
) {
106 type
= SIPE_ACTIVITY_INACTIVE
;
107 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSYIDLE
) {
108 type
= sipe_status_token_to_activity(activity
);
109 if ((type
!= SIPE_ACTIVITY_ON_PHONE
) &&
110 (type
!= SIPE_ACTIVITY_IN_CONF
))
111 type
= SIPE_ACTIVITY_BUSY
;
112 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_DND
) {
113 type
= SIPE_ACTIVITY_BUSYIDLE
;
114 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_BRB
) {
115 type
= SIPE_ACTIVITY_DND
;
116 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY
) {
117 type
= SIPE_ACTIVITY_BRB
;
118 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE
) {
119 type
= SIPE_ACTIVITY_AWAY
;
121 type
= SIPE_ACTIVITY_OFFLINE
;
124 return sipe_status_activity_to_token(type
);
127 const gchar
*sipe_ocs2007_legacy_activity_description(guint availability
)
129 if ((availability
>= SIPE_OCS2007_LEGACY_AVAILIBILITY_AVAILABLE_IDLE
) &&
130 (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY
)) {
131 return(sipe_core_activity_description(SIPE_ACTIVITY_INACTIVE
));
132 } else if ((availability
>= SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSYIDLE
) &&
133 (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_DND
)) {
134 return(sipe_core_activity_description(SIPE_ACTIVITY_BUSYIDLE
));
141 * @param sipe_status_id (in)
142 * @param activity_token (out) [only sipe-ocs2005.c/send_presence_soap()
143 * requests this token]
145 #define SIPE_OCS2007_AVAILABILITY_UNKNOWN 0
146 #define SIPE_OCS2007_AVAILABILITY_ONLINE 3500
147 #define SIPE_OCS2007_AVAILABILITY_BUSY 6500
148 #define SIPE_OCS2007_AVAILABILITY_DND 9500 /* do not disturb */
149 #define SIPE_OCS2007_AVAILABILITY_BRB 12500 /* be right back */
150 #define SIPE_OCS2007_AVAILABILITY_AWAY 15500
151 #define SIPE_OCS2007_AVAILABILITY_OFFLINE 18500
152 guint
sipe_ocs2007_availability_from_status(const gchar
*sipe_status_id
,
153 const gchar
**activity_token
)
158 if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_AWAY
))) {
159 availability
= SIPE_OCS2007_AVAILABILITY_AWAY
;
160 activity
= SIPE_ACTIVITY_AWAY
;
161 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_BRB
))) {
162 availability
= SIPE_OCS2007_AVAILABILITY_BRB
;
163 activity
= SIPE_ACTIVITY_BRB
;
164 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_DND
))) {
165 availability
= SIPE_OCS2007_AVAILABILITY_DND
;
166 activity
= SIPE_ACTIVITY_DND
;
167 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_BUSY
))) {
168 availability
= SIPE_OCS2007_AVAILABILITY_BUSY
;
169 activity
= SIPE_ACTIVITY_BUSY
;
170 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_AVAILABLE
))) {
171 availability
= SIPE_OCS2007_AVAILABILITY_ONLINE
;
172 activity
= SIPE_ACTIVITY_ONLINE
;
173 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_UNSET
))) {
174 availability
= SIPE_OCS2007_AVAILABILITY_UNKNOWN
;
175 activity
= SIPE_ACTIVITY_UNSET
;
177 /* Offline or invisible */
178 availability
= SIPE_OCS2007_AVAILABILITY_OFFLINE
;
179 activity
= SIPE_ACTIVITY_OFFLINE
;
182 if (activity_token
) {
183 *activity_token
= sipe_status_activity_to_token(activity
);
186 return(availability
);
189 gboolean
sipe_ocs2007_status_is_busy(const gchar
*status_id
)
191 return(SIPE_OCS2007_AVAILABILITY_BUSY
>=
192 sipe_ocs2007_availability_from_status(status_id
, NULL
));
196 gboolean
sipe_ocs2007_availability_is_away(guint availability
)
198 return(availability
>= SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY
);
201 static void send_presence_publish(struct sipe_core_private
*sipe_private
,
202 const char *publications
);
204 static void free_publication(struct sipe_publication
*publication
)
206 g_free(publication
->category
);
207 g_free(publication
->cal_event_hash
);
208 g_free(publication
->note
);
210 g_free(publication
->working_hours_xml_str
);
211 g_free(publication
->fb_start_str
);
212 g_free(publication
->free_busy_base64
);
217 struct hash_table_delete_payload
{
218 GHashTable
*hash_table
;
222 static void sipe_remove_category_container_publications_cb(const gchar
*name
,
223 struct sipe_publication
*publication
,
224 struct hash_table_delete_payload
*payload
)
226 if (publication
->container
== payload
->container
) {
227 g_hash_table_remove(payload
->hash_table
, name
);
231 static void sipe_remove_category_container_publications(GHashTable
*our_publications
,
232 const gchar
*category
,
235 struct hash_table_delete_payload payload
;
236 payload
.hash_table
= g_hash_table_lookup(our_publications
, category
);
238 if (!payload
.hash_table
) return;
240 payload
.container
= container
;
241 g_hash_table_foreach(payload
.hash_table
,
242 (GHFunc
)sipe_remove_category_container_publications_cb
,
246 /** MS-PRES container */
247 struct sipe_container
{
253 /** MS-PRES container member */
254 struct sipe_container_member
{
255 /** user, domain, sameEnterprise, federated, publicCloud; everyone */
260 static const guint containers
[] = {32000, 400, 300, 200, 100};
261 #define CONTAINERS_LEN (sizeof(containers) / sizeof(guint))
263 static void free_container_member(struct sipe_container_member
*member
)
267 g_free(member
->type
);
268 g_free(member
->value
);
272 static void sipe_ocs2007_free_container(struct sipe_container
*container
)
276 if (!container
) return;
278 entry
= container
->members
;
280 void *data
= entry
->data
;
281 entry
= g_slist_remove(entry
, data
);
282 free_container_member((struct sipe_container_member
*)data
);
287 void sipe_core_buddy_menu_free(struct sipe_core_public
*sipe_public
)
289 struct sipe_core_private
*sipe_private
= SIPE_CORE_PRIVATE
;
290 GSList
*entry
= sipe_private
->blist_menu_containers
;
292 sipe_ocs2007_free_container(entry
->data
);
295 g_slist_free(sipe_private
->blist_menu_containers
);
296 sipe_private
->blist_menu_containers
= NULL
;
299 static void blist_menu_remember_container(struct sipe_core_private
*sipe_private
,
300 struct sipe_container
*container
)
302 sipe_private
->blist_menu_containers
= g_slist_prepend(sipe_private
->blist_menu_containers
,
306 static struct sipe_container
*create_container(guint index
,
307 const gchar
*member_type
,
308 const gchar
*member_value
,
311 struct sipe_container
*container
= g_new0(struct sipe_container
, 1);
312 struct sipe_container_member
*member
= g_new0(struct sipe_container_member
, 1);
314 container
->id
= is_group
? (guint
) -1 : containers
[index
];
315 container
->members
= g_slist_append(container
->members
, member
);
316 member
->type
= g_strdup(member_type
);
317 member
->value
= g_strdup(member_value
);
322 void sipe_ocs2007_free(struct sipe_core_private
*sipe_private
)
324 if (sipe_private
->containers
) {
325 GSList
*entry
= sipe_private
->containers
;
327 sipe_ocs2007_free_container((struct sipe_container
*)entry
->data
);
331 g_slist_free(sipe_private
->containers
);
335 * Finds locally stored MS-PRES container member
337 static struct sipe_container_member
*
338 sipe_find_container_member(struct sipe_container
*container
,
342 struct sipe_container_member
*member
;
345 if (container
== NULL
|| type
== NULL
) {
349 entry
= container
->members
;
351 member
= entry
->data
;
352 if (sipe_strcase_equal(member
->type
, type
) &&
353 sipe_strcase_equal(member
->value
, value
))
363 * Finds locally stored MS-PRES container by id
365 static struct sipe_container
*sipe_find_container(struct sipe_core_private
*sipe_private
,
368 GSList
*entry
= sipe_private
->containers
;
370 struct sipe_container
*container
= entry
->data
;
371 if (id
== container
->id
) {
379 static int sipe_find_member_access_level(struct sipe_core_private
*sipe_private
,
384 const gchar
*value_mod
= value
;
386 if (!type
) return -1;
388 if (sipe_strequal("user", type
)) {
389 value_mod
= sipe_get_no_sip_uri(value
);
392 for (i
= 0; i
< CONTAINERS_LEN
; i
++) {
393 struct sipe_container_member
*member
;
394 struct sipe_container
*container
= sipe_find_container(sipe_private
, containers
[i
]);
395 if (!container
) continue;
397 member
= sipe_find_container_member(container
, type
, value_mod
);
398 if (member
) return containers
[i
];
405 * Returns pointer to domain part in provided Email URL
407 * @param email an email URL. Example: first.last@hq.company.com
408 * @return pointer to domain part of email URL. Coresponding example: hq.company.com
410 * Doesn't allocate memory
412 static const gchar
*sipe_get_domain(const gchar
*email
)
416 if (!email
) return NULL
;
418 tmp
= strstr(email
, "@");
420 if (tmp
&& ((tmp
+1) < (email
+ strlen(email
)))) {
427 /* @TODO: replace with binary search for faster access? */
428 /** source: http://support.microsoft.com/kb/897567 */
429 static const gchar
* const public_domains
[] = {
430 "aol.com", "icq.com", "love.com", "mac.com", "br.live.com",
431 "hotmail.co.il", "hotmail.co.jp", "hotmail.co.th", "hotmail.co.uk",
432 "hotmail.com", "hotmail.com.ar", "hotmail.com.tr", "hotmail.es",
433 "hotmail.de", "hotmail.fr", "hotmail.it", "live.at", "live.be",
434 "live.ca", "live.cl", "live.cn", "live.co.in", "live.co.kr",
435 "live.co.uk", "live.co.za", "live.com", "live.com.ar", "live.com.au",
436 "live.com.co", "live.com.mx", "live.com.my", "live.com.pe",
437 "live.com.ph", "live.com.pk", "live.com.pt", "live.com.sg",
438 "live.com.ve", "live.de", "live.dk", "live.fr", "live.hk", "live.ie",
439 "live.in", "live.it", "live.jp", "live.nl", "live.no", "live.ph",
440 "live.ru", "live.se", "livemail.com.br", "livemail.tw",
441 "messengeruser.com", "msn.com", "passport.com", "sympatico.ca",
442 "tw.live.com", "webtv.net", "windowslive.com", "windowslive.es",
446 static gboolean
sipe_is_public_domain(const gchar
*domain
)
449 while (public_domains
[i
]) {
450 if (sipe_strcase_equal(public_domains
[i
], domain
)) {
466 const gchar
*sipe_ocs2007_access_level_name(guint id
)
469 case 32000: return _("Blocked");
470 case 400: return _("Personal");
471 case 300: return _("Team");
472 case 200: return _("Company");
473 case 100: return _("Public");
478 /** Member type: user, domain, sameEnterprise, federated, publicCloud; everyone */
479 int sipe_ocs2007_find_access_level(struct sipe_core_private
*sipe_private
,
482 gboolean
*is_group_access
)
484 int container_id
= -1;
486 if (sipe_strequal("user", type
)) {
488 const char *no_sip_uri
= sipe_get_no_sip_uri(value
);
490 container_id
= sipe_find_member_access_level(sipe_private
, "user", no_sip_uri
);
491 if (container_id
>= 0) {
492 if (is_group_access
) *is_group_access
= FALSE
;
496 domain
= sipe_get_domain(no_sip_uri
);
497 container_id
= sipe_find_member_access_level(sipe_private
, "domain", domain
);
498 if (container_id
>= 0) {
499 if (is_group_access
) *is_group_access
= TRUE
;
503 container_id
= sipe_find_member_access_level(sipe_private
, "sameEnterprise", NULL
);
504 if ((container_id
>= 0) && sipe_strcase_equal(sipe_private
->public.sip_domain
, domain
)) {
505 if (is_group_access
) *is_group_access
= TRUE
;
509 container_id
= sipe_find_member_access_level(sipe_private
, "publicCloud", NULL
);
510 if ((container_id
>= 0) && sipe_is_public_domain(domain
)) {
511 if (is_group_access
) *is_group_access
= TRUE
;
515 container_id
= sipe_find_member_access_level(sipe_private
, "everyone", NULL
);
516 if ((container_id
>= 0)) {
517 if (is_group_access
) *is_group_access
= TRUE
;
521 container_id
= sipe_find_member_access_level(sipe_private
, type
, value
);
522 if (is_group_access
) *is_group_access
= FALSE
;
528 static GSList
*get_access_domains(struct sipe_core_private
*sipe_private
)
530 struct sipe_container
*container
;
531 struct sipe_container_member
*member
;
536 entry
= sipe_private
->containers
;
538 container
= entry
->data
;
540 entry2
= container
->members
;
542 member
= entry2
->data
;
543 if (sipe_strcase_equal(member
->type
, "domain"))
545 res
= slist_insert_unique_sorted(res
, g_strdup(member
->value
), (GCompareFunc
)g_ascii_strcasecmp
);
547 entry2
= entry2
->next
;
554 static void sipe_send_container_members_prepare(const guint container_id
,
555 const guint container_version
,
559 char **container_xmls
)
561 gchar
*value_str
= value
? g_strdup_printf(" value=\"%s\"", value
) : g_strdup("");
564 if (!container_xmls
) return;
566 body
= g_strdup_printf(
567 "<container id=\"%d\" version=\"%d\"><member action=\"%s\" type=\"%s\"%s/></container>",
575 if ((*container_xmls
) == NULL
) {
576 *container_xmls
= body
;
578 char *tmp
= *container_xmls
;
580 *container_xmls
= g_strconcat(*container_xmls
, body
, NULL
);
586 static void sipe_send_set_container_members(struct sipe_core_private
*sipe_private
,
587 char *container_xmls
)
594 if (!container_xmls
) return;
596 self
= sip_uri_self(sipe_private
);
597 body
= g_strdup_printf(
598 "<setContainerMembers xmlns=\"http://schemas.microsoft.com/2006/09/sip/container-management\">"
600 "</setContainerMembers>",
603 contact
= get_contact(sipe_private
);
604 hdr
= g_strdup_printf("Contact: %s\r\n"
605 "Content-Type: application/msrtc-setcontainermembers+xml\r\n", contact
);
608 sip_transport_service(sipe_private
,
620 * @param container_id a new access level. If -1 then current access level
621 * is just removed (I.e. the member is removed from all containers).
622 * @param type a type of member. E.g. "user", "sameEnterprise", etc.
623 * @param value a value for member. E.g. SIP URI for "user" member type.
625 void sipe_ocs2007_change_access_level(struct sipe_core_private
*sipe_private
,
626 const int container_id
,
631 int current_container_id
= -1;
632 char *container_xmls
= NULL
;
634 /* for each container: find/delete */
635 for (i
= 0; i
< CONTAINERS_LEN
; i
++) {
636 struct sipe_container_member
*member
;
637 struct sipe_container
*container
= sipe_find_container(sipe_private
, containers
[i
]);
639 if (!container
) continue;
641 member
= sipe_find_container_member(container
, type
, value
);
643 current_container_id
= containers
[i
];
644 /* delete/publish current access level */
645 if (container_id
< 0 || container_id
!= current_container_id
) {
646 sipe_send_container_members_prepare(current_container_id
, container
->version
, "remove", type
, value
, &container_xmls
);
647 /* remove member from our cache, to be able to recalculate AL below */
648 container
->members
= g_slist_remove(container
->members
, member
);
649 current_container_id
= -1;
654 /* recalculate AL below */
655 current_container_id
= sipe_ocs2007_find_access_level(sipe_private
, type
, value
, NULL
);
657 /* assign/publish new access level */
658 if (container_id
!= current_container_id
&& container_id
>= 0) {
659 struct sipe_container
*container
= sipe_find_container(sipe_private
, container_id
);
660 guint version
= container
? container
->version
: 0;
662 sipe_send_container_members_prepare(container_id
, version
, "add", type
, value
, &container_xmls
);
665 if (container_xmls
) {
666 sipe_send_set_container_members(sipe_private
, container_xmls
);
668 g_free(container_xmls
);
671 void sipe_core_change_access_level_from_container(struct sipe_core_public
*sipe_public
,
674 struct sipe_container
*container
= parameter
;
675 struct sipe_container_member
*member
;
677 if (!container
|| !container
->members
) return;
679 member
= ((struct sipe_container_member
*)container
->members
->data
);
681 if (!member
->type
) return;
683 SIPE_DEBUG_INFO("sipe_ocs2007_change_access_level_from_container: container->id=%d, member->type=%s, member->value=%s",
684 container
->id
, member
->type
, member
->value
? member
->value
: "");
686 sipe_ocs2007_change_access_level(SIPE_CORE_PRIVATE
,
693 void sipe_core_change_access_level_for_domain(struct sipe_core_public
*sipe_public
,
697 /* move Blocked first */
698 guint i
= (index
== 4) ? 0 : index
+ 1;
699 guint container_id
= containers
[i
];
701 SIPE_DEBUG_INFO("sipe_core_change_access_level_from_id: domain=%s, container_id=(%d)%d",
702 domain
? domain
: "", index
, container_id
);
704 sipe_ocs2007_change_access_level(SIPE_CORE_PRIVATE
,
711 * Schedules process of self status publish
712 * based on own calendar information.
713 * Should be scheduled to the beginning of every
714 * 15 min interval, like:
715 * 13:00, 13:15, 13:30, 13:45, etc.
718 static void schedule_publish_update(struct sipe_core_private
*sipe_private
,
719 time_t calculate_from
)
722 /** start of the beginning of closest 5 min interval. */
723 time_t next_start
= ((time_t)((int)((int)calculate_from
)/interval
+ 1)*interval
);
725 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: calculate_from time: %s",
726 asctime(localtime(&calculate_from
)));
727 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: next start time : %s",
728 asctime(localtime(&next_start
)));
730 sipe_schedule_seconds(sipe_private
,
731 "<+2007-cal-status>",
733 next_start
- time(NULL
),
734 sipe_ocs2007_presence_publish
,
739 * An availability XML entry for SIPE_PUB_XML_STATE_CALENDAR
740 * @param availability (%d) Ex.: 6500
742 #define SIPE_PUB_XML_STATE_CALENDAR_AVAIL \
743 "<availability>%d</availability>"
745 * An activity XML entry for SIPE_PUB_XML_STATE_CALENDAR
746 * @param token (%s) Ex.: in-a-meeting
747 * @param minAvailability_attr (%s) Ex.: minAvailability="6500"
748 * @param maxAvailability_attr (%s) Ex.: maxAvailability="8999" or none
750 #define SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY \
751 "<activity token=\"%s\" %s %s></activity>"
753 * Publishes 'calendarState' category.
754 * @param instance (%u) Ex.: 1339299275
755 * @param version (%u) Ex.: 1
756 * @param uri (%s) Ex.: john@contoso.com
757 * @param start_time_str (%s) Ex.: 2008-01-11T19:00:00Z
758 * @param availability (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_AVAIL
759 * @param activity (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
760 * @param meeting_subject (%s) Ex.: Customer Meeting
761 * @param meeting_location (%s) Ex.: Conf Room 100
763 * @param instance (%u) Ex.: 1339299275
764 * @param version (%u) Ex.: 1
765 * @param uri (%s) Ex.: john@contoso.com
766 * @param start_time_str (%s) Ex.: 2008-01-11T19:00:00Z
767 * @param availability (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_AVAIL
768 * @param activity (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
769 * @param meeting_subject (%s) Ex.: Customer Meeting
770 * @param meeting_location (%s) Ex.: Conf Room 100
772 #define SIPE_PUB_XML_STATE_CALENDAR \
773 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
774 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" uri=\"%s\" startTime=\"%s\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"calendarState\">"\
777 "<endpointLocation/>"\
778 "<meetingSubject>%s</meetingSubject>"\
779 "<meetingLocation>%s</meetingLocation>"\
782 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
783 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" uri=\"%s\" startTime=\"%s\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"calendarState\">"\
786 "<endpointLocation/>"\
787 "<meetingSubject>%s</meetingSubject>"\
788 "<meetingLocation>%s</meetingLocation>"\
792 * Publishes to clear 'calendarState' and 'phoneState' category
793 * @param instance (%u) Ex.: 1251210982
794 * @param version (%u) Ex.: 1
796 #define SIPE_PUB_XML_STATE_CALENDAR_PHONE_CLEAR \
797 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"\
798 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"
801 * Publishes to clear any category
802 * @param category_name (%s) Ex.: state
803 * @param instance (%u) Ex.: 536870912
804 * @param container (%u) Ex.: 3
805 * @param version (%u) Ex.: 1
806 * @param expireType (%s) Ex.: static
808 #define SIPE_PUB_XML_PUBLICATION_CLEAR \
809 "<publication categoryName=\"%s\" instance=\"%u\" container=\"%u\" version=\"%u\" expireType=\"%s\" expires=\"0\"/>"
812 * Publishes 'note' category.
813 * @param instance (%u) Ex.: 2135971629; 0 for personal
814 * @param container (%u) Ex.: 200
815 * @param version (%u) Ex.: 2
816 * @param type (%s) Ex.: personal or OOF
817 * @param startTime_attr (%s) Ex.: startTime="2008-01-11T19:00:00Z"
818 * @param endTime_attr (%s) Ex.: endTime="2008-01-15T19:00:00Z"
819 * @param body (%s) Ex.: In the office
821 #define SIPE_PUB_XML_NOTE \
822 "<publication categoryName=\"note\" instance=\"%u\" container=\"%u\" version=\"%d\" expireType=\"static\">"\
823 "<note xmlns=\"http://schemas.microsoft.com/2006/09/sip/note\">"\
824 "<body type=\"%s\" uri=\"\"%s%s>%s</body>"\
828 * Publishes 'phoneState' category.
829 * @param instance (%u) Ex.: 1339299275
830 * @param version (%u) Ex.: 1
831 * @param availability (%u) Ex.: 6500
832 * @param token (%s) Ex.: on-the-phone
833 * @param minAvailability (%u) generally same as availability
835 * @param instance (%u) Ex.: 1339299275
836 * @param version (%u) Ex.: 1
837 * @param availability (%u) Ex.: 6500
838 * @param token (%s) Ex.: on-the-phone
839 * @param minAvailability (%u) generally same as availability
841 #define SIPE_PUB_XML_STATE_PHONE \
842 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
843 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"phoneState\">"\
844 "<availability>%u</availability>"\
845 "<activity token=\"%s\" minAvailability=\"%u\" maxAvailability=\"8999\"/>"\
848 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
849 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"phoneState\">"\
850 "<availability>%u</availability>"\
851 "<activity token=\"%s\" minAvailability=\"%u\" maxAvailability=\"8999\"/>"\
856 * Only Busy and OOF calendar event are published.
857 * Different instances are used for that.
859 * Must be g_free'd after use.
861 static gchar
*sipe_publish_get_category_state_calendar(struct sipe_core_private
*sipe_private
,
862 struct sipe_cal_event
*event
,
866 gchar
*start_time_str
;
867 int availability
= 0;
870 guint instance
= (cal_satus
== SIPE_CAL_OOF
) ?
871 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR_OOF
) :
872 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR
);
874 /* key is <category><instance><container> */
875 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
876 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
877 struct sipe_publication
*publication_2
=
878 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_2
);
879 struct sipe_publication
*publication_3
=
880 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_3
);
885 if (!publication_3
&& !event
) { /* was nothing, have nothing, exiting */
886 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
887 "Exiting as no publication and no event for cal_satus:%d", cal_satus
);
893 (publication_3
->availability
== availability
) &&
894 sipe_strequal(publication_3
->cal_event_hash
, (tmp
= sipe_cal_event_hash(event
))))
897 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
898 "cal state has NOT changed for cal_satus:%d. Exiting.", cal_satus
);
899 return NULL
; /* nothing to update */
904 (event
->cal_status
== SIPE_CAL_BUSY
||
905 event
->cal_status
== SIPE_CAL_OOF
))
907 gchar
*availability_xml_str
= NULL
;
908 gchar
*activity_xml_str
= NULL
;
909 gchar
*escaped_subject
= event
->subject
? g_markup_escape_text(event
->subject
, -1) : NULL
;
910 gchar
*escaped_location
= event
->location
? g_markup_escape_text(event
->location
, -1) : NULL
;
912 if (event
->cal_status
== SIPE_CAL_BUSY
) {
913 availability_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_AVAIL
,
914 SIPE_OCS2007_AVAILABILITY_BUSY
);
917 if (event
->cal_status
== SIPE_CAL_BUSY
&& event
->is_meeting
) {
918 activity_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
,
919 sipe_status_activity_to_token(SIPE_ACTIVITY_IN_MEETING
),
920 "minAvailability=\"6500\"",
921 "maxAvailability=\"8999\"");
922 } else if (event
->cal_status
== SIPE_CAL_OOF
) {
923 activity_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
,
924 sipe_status_activity_to_token(SIPE_ACTIVITY_OOF
),
925 "minAvailability=\"12000\"",
928 start_time_str
= sipe_utils_time_to_str(event
->start_time
);
930 res
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR
,
932 publication_2
? publication_2
->version
: 0,
935 availability_xml_str
? availability_xml_str
: "",
936 activity_xml_str
? activity_xml_str
: "",
937 escaped_subject
? escaped_subject
: "",
938 escaped_location
? escaped_location
: "",
941 publication_3
? publication_3
->version
: 0,
944 availability_xml_str
? availability_xml_str
: "",
945 activity_xml_str
? activity_xml_str
: "",
946 escaped_subject
? escaped_subject
: "",
947 escaped_location
? escaped_location
: ""
949 g_free(escaped_location
);
950 g_free(escaped_subject
);
951 g_free(start_time_str
);
952 g_free(availability_xml_str
);
953 g_free(activity_xml_str
);
956 else /* including !event, SIPE_CAL_FREE, SIPE_CAL_TENTATIVE */
958 res
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_PHONE_CLEAR
,
960 publication_2
? publication_2
->version
: 0,
963 publication_3
? publication_3
->version
: 0
971 * Returns 'note' XML part for publication.
972 * Must be g_free'd after use.
974 * Protocol format for Note is plain text.
976 * @param note a note in Sipe internal HTML format
977 * @param note_type either personal or OOF
979 static gchar
*sipe_publish_get_category_note(struct sipe_core_private
*sipe_private
,
980 const char *note
, /* html */
981 const char *note_type
,
985 guint instance
= sipe_strequal("OOF", note_type
) ? sipe_get_pub_instance(sipe_private
, SIPE_PUB_NOTE_OOF
) : 0;
986 /* key is <category><instance><container> */
987 gchar
*key_note_200
= g_strdup_printf("<%s><%u><%u>", "note", instance
, 200);
988 gchar
*key_note_300
= g_strdup_printf("<%s><%u><%u>", "note", instance
, 300);
989 gchar
*key_note_400
= g_strdup_printf("<%s><%u><%u>", "note", instance
, 400);
991 struct sipe_publication
*publication_note_200
=
992 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "note"), key_note_200
);
993 struct sipe_publication
*publication_note_300
=
994 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "note"), key_note_300
);
995 struct sipe_publication
*publication_note_400
=
996 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "note"), key_note_400
);
998 char *tmp
= note
? sipe_backend_markup_strip_html(note
) : NULL
;
999 char *n1
= tmp
? g_markup_escape_text(tmp
, -1) : NULL
;
1000 const char *n2
= publication_note_200
? publication_note_200
->note
: NULL
;
1001 char *res
, *tmp1
, *tmp2
, *tmp3
;
1002 char *start_time_attr
;
1003 char *end_time_attr
;
1007 g_free(key_note_200
);
1008 g_free(key_note_300
);
1009 g_free(key_note_400
);
1011 /* we even need to republish empty note */
1012 if (sipe_strequal(n1
, n2
))
1014 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_note: note has NOT changed. Exiting.");
1016 return NULL
; /* nothing to update */
1019 start_time_attr
= note_start
? g_strdup_printf(" startTime=\"%s\"", (tmp
= sipe_utils_time_to_str(note_start
))) : NULL
;
1022 end_time_attr
= note_end
? g_strdup_printf(" endTime=\"%s\"", (tmp
= sipe_utils_time_to_str(note_end
))) : NULL
;
1026 tmp1
= g_strdup_printf(SIPE_PUB_XML_NOTE
,
1029 publication_note_200
? publication_note_200
->version
: 0,
1031 start_time_attr
? start_time_attr
: "",
1032 end_time_attr
? end_time_attr
: "",
1035 tmp2
= g_strdup_printf(SIPE_PUB_XML_NOTE
,
1038 publication_note_300
? publication_note_300
->version
: 0,
1040 start_time_attr
? start_time_attr
: "",
1041 end_time_attr
? end_time_attr
: "",
1044 tmp3
= g_strdup_printf(SIPE_PUB_XML_NOTE
,
1047 publication_note_400
? publication_note_400
->version
: 0,
1049 start_time_attr
? start_time_attr
: "",
1050 end_time_attr
? end_time_attr
: "",
1053 tmp1
= g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR
,
1057 publication_note_200
? publication_note_200
->version
: 0,
1059 tmp2
= g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR
,
1063 publication_note_200
? publication_note_200
->version
: 0,
1065 tmp3
= g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR
,
1069 publication_note_200
? publication_note_200
->version
: 0,
1072 res
= g_strconcat(tmp1
, tmp2
, tmp3
, NULL
);
1074 g_free(start_time_attr
);
1075 g_free(end_time_attr
);
1085 * Publishes 'calendarData' category's WorkingHours.
1087 * @param version (%u) Ex.: 1
1088 * @param email (%s) Ex.: alice@cosmo.local
1089 * @param working_hours_xml_str (%s) Ex.: <WorkingHours xmlns=.....
1091 * @param version (%u)
1093 * @param version (%u)
1095 * @param working_hours_xml_str (%s)
1097 * @param version (%u)
1099 * @param working_hours_xml_str (%s)
1101 * @param version (%u)
1103 * @param working_hours_xml_str (%s)
1105 * @param version (%u)
1107 #define SIPE_PUB_XML_WORKING_HOURS \
1108 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"1\" version=\"%d\" expireType=\"static\">"\
1109 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1112 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"100\" version=\"%d\" expireType=\"static\">"\
1113 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1115 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"200\" version=\"%d\" expireType=\"static\">"\
1116 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1119 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"300\" version=\"%d\" expireType=\"static\">"\
1120 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1123 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"400\" version=\"%d\" expireType=\"static\">"\
1124 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1127 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"32000\" version=\"%d\" expireType=\"static\">"\
1128 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1132 * Returns 'calendarData' XML part with WorkingHours for publication.
1133 * Must be g_free'd after use.
1135 static gchar
*sipe_publish_get_category_cal_working_hours(struct sipe_core_private
*sipe_private
)
1137 struct sipe_calendar
* cal
= sipe_private
->calendar
;
1139 /* key is <category><instance><container> */
1140 gchar
*key_cal_1
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1);
1141 gchar
*key_cal_100
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100);
1142 gchar
*key_cal_200
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200);
1143 gchar
*key_cal_300
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300);
1144 gchar
*key_cal_400
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400);
1145 gchar
*key_cal_32000
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000);
1147 struct sipe_publication
*publication_cal_1
=
1148 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_1
);
1149 struct sipe_publication
*publication_cal_100
=
1150 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_100
);
1151 struct sipe_publication
*publication_cal_200
=
1152 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_200
);
1153 struct sipe_publication
*publication_cal_300
=
1154 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_300
);
1155 struct sipe_publication
*publication_cal_400
=
1156 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_400
);
1157 struct sipe_publication
*publication_cal_32000
=
1158 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_32000
);
1160 const char *n1
= cal
? cal
->working_hours_xml_str
: NULL
;
1161 const char *n2
= publication_cal_300
? publication_cal_300
->working_hours_xml_str
: NULL
;
1164 g_free(key_cal_100
);
1165 g_free(key_cal_200
);
1166 g_free(key_cal_300
);
1167 g_free(key_cal_400
);
1168 g_free(key_cal_32000
);
1170 if (!cal
|| is_empty(cal
->email
) || is_empty(cal
->working_hours_xml_str
)) {
1171 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_working_hours: no data to publish, exiting");
1175 if (sipe_strequal(n1
, n2
))
1177 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_working_hours: WorkingHours has NOT changed. Exiting.");
1178 return NULL
; /* nothing to update */
1181 return g_strdup_printf(SIPE_PUB_XML_WORKING_HOURS
,
1183 publication_cal_1
? publication_cal_1
->version
: 0,
1185 cal
->working_hours_xml_str
,
1187 publication_cal_100
? publication_cal_100
->version
: 0,
1189 publication_cal_200
? publication_cal_200
->version
: 0,
1191 cal
->working_hours_xml_str
,
1193 publication_cal_300
? publication_cal_300
->version
: 0,
1195 cal
->working_hours_xml_str
,
1196 /* 400 - Personal */
1197 publication_cal_400
? publication_cal_400
->version
: 0,
1199 cal
->working_hours_xml_str
,
1200 /* 32000 - Blocked */
1201 publication_cal_32000
? publication_cal_32000
->version
: 0
1206 * Publishes 'calendarData' category's FreeBusy.
1208 * @param instance (%u) Ex.: 1300372959
1209 * @param version (%u) Ex.: 1
1211 * @param instance (%u) Ex.: 1300372959
1212 * @param version (%u) Ex.: 1
1214 * @param instance (%u) Ex.: 1300372959
1215 * @param version (%u) Ex.: 1
1216 * @param email (%s) Ex.: alice@cosmo.local
1217 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1218 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1220 * @param instance (%u) Ex.: 1300372959
1221 * @param version (%u) Ex.: 1
1222 * @param email (%s) Ex.: alice@cosmo.local
1223 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1224 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1226 * @param instance (%u) Ex.: 1300372959
1227 * @param version (%u) Ex.: 1
1228 * @param email (%s) Ex.: alice@cosmo.local
1229 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1230 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1232 * @param instance (%u) Ex.: 1300372959
1233 * @param version (%u) Ex.: 1
1235 #define SIPE_PUB_XML_FREE_BUSY \
1236 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"1\" version=\"%d\" expireType=\"endpoint\">"\
1237 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1239 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"100\" version=\"%d\" expireType=\"endpoint\">"\
1240 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1242 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"200\" version=\"%d\" expireType=\"endpoint\">"\
1243 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1244 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1247 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"300\" version=\"%d\" expireType=\"endpoint\">"\
1248 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1249 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1252 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"400\" version=\"%d\" expireType=\"endpoint\">"\
1253 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1254 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1257 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"32000\" version=\"%d\" expireType=\"endpoint\">"\
1258 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1262 * Returns 'calendarData' XML part with FreeBusy for publication.
1263 * Must be g_free'd after use.
1265 static gchar
*sipe_publish_get_category_cal_free_busy(struct sipe_core_private
*sipe_private
)
1267 struct sipe_calendar
* cal
= sipe_private
->calendar
;
1268 guint cal_data_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_CALENDAR_DATA
);
1270 char *free_busy_base64
;
1271 /* const char *st; */
1272 /* const char *fb; */
1275 /* key is <category><instance><container> */
1276 gchar
*key_cal_1
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 1);
1277 gchar
*key_cal_100
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 100);
1278 gchar
*key_cal_200
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 200);
1279 gchar
*key_cal_300
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 300);
1280 gchar
*key_cal_400
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 400);
1281 gchar
*key_cal_32000
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 32000);
1283 struct sipe_publication
*publication_cal_1
=
1284 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_1
);
1285 struct sipe_publication
*publication_cal_100
=
1286 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_100
);
1287 struct sipe_publication
*publication_cal_200
=
1288 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_200
);
1289 struct sipe_publication
*publication_cal_300
=
1290 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_300
);
1291 struct sipe_publication
*publication_cal_400
=
1292 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_400
);
1293 struct sipe_publication
*publication_cal_32000
=
1294 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_32000
);
1297 g_free(key_cal_100
);
1298 g_free(key_cal_200
);
1299 g_free(key_cal_300
);
1300 g_free(key_cal_400
);
1301 g_free(key_cal_32000
);
1303 if (!cal
|| is_empty(cal
->email
) || !cal
->fb_start
|| is_empty(cal
->free_busy
)) {
1304 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_free_busy: no data to publish, exiting");
1308 fb_start_str
= sipe_utils_time_to_str(cal
->fb_start
);
1309 free_busy_base64
= sipe_cal_get_freebusy_base64(cal
->free_busy
);
1311 /* we will rebuplish the same data to refresh publication time,
1312 * so if data from multiple sources, most recent will be choosen
1314 // st = publication_cal_300 ? publication_cal_300->fb_start_str : NULL;
1315 // fb = publication_cal_300 ? publication_cal_300->free_busy_base64 : NULL;
1317 //if (sipe_strequal(st, fb_start_str) && sipe_strequal(fb, free_busy_base64))
1319 // SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_free_busy: FreeBusy has NOT changed. Exiting.");
1320 // g_free(fb_start_str);
1321 // g_free(free_busy_base64);
1322 // return NULL; /* nothing to update */
1325 res
= g_strdup_printf(SIPE_PUB_XML_FREE_BUSY
,
1328 publication_cal_1
? publication_cal_1
->version
: 0,
1331 publication_cal_100
? publication_cal_100
->version
: 0,
1334 publication_cal_200
? publication_cal_200
->version
: 0,
1340 publication_cal_300
? publication_cal_300
->version
: 0,
1344 /* 400 - Personal */
1346 publication_cal_400
? publication_cal_400
->version
: 0,
1350 /* 32000 - Blocked */
1352 publication_cal_32000
? publication_cal_32000
->version
: 0
1355 g_free(fb_start_str
);
1356 g_free(free_busy_base64
);
1362 * Publishes 'device' category.
1363 * @param instance (%u) Ex.: 1938468728
1364 * @param version (%u) Ex.: 1
1365 * @param endpointId (%s) Ex.: C707E38E-1E10-5413-94D9-ECAC260A0269
1366 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1367 * @param timezone (%s) Ex.: 00:00:00+01:00
1368 * @param machineName (%s) Ex.: BOSTON-OCS07
1370 #define SIPE_PUB_XML_DEVICE \
1371 "<publication categoryName=\"device\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
1372 "<device xmlns=\"http://schemas.microsoft.com/2006/09/sip/device\" endpointId=\"%s\">"\
1373 "<capabilities preferred=\"false\" uri=\"%s\">"\
1374 "<text capture=\"true\" render=\"true\" publish=\"false\"/>"\
1375 "<gifInk capture=\"false\" render=\"true\" publish=\"false\"/>"\
1376 "<isfInk capture=\"false\" render=\"true\" publish=\"false\"/>"\
1378 "<timezone>%s</timezone>"\
1379 "<machineName>%s</machineName>"\
1384 * Returns 'device' XML part for publication.
1385 * Must be g_free'd after use.
1387 static gchar
*sipe_publish_get_category_device(struct sipe_core_private
*sipe_private
)
1391 gchar
*uuid
= get_uuid(sipe_private
);
1392 guint device_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_DEVICE
);
1393 /* key is <category><instance><container> */
1394 gchar
*key
= g_strdup_printf("<%s><%u><%u>", "device", device_instance
, 2);
1395 struct sipe_publication
*publication
=
1396 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "device"), key
);
1400 uri
= sip_uri_self(sipe_private
);
1401 doc
= g_strdup_printf(SIPE_PUB_XML_DEVICE
,
1403 publication
? publication
->version
: 0,
1406 "00:00:00+01:00", /* @TODO make timezone real*/
1417 * Publishes 'machineState' category.
1418 * @param instance (%u) Ex.: 926460663
1419 * @param version (%u) Ex.: 22
1420 * @param availability (%d) Ex.: 3500
1421 * @param instance (%u) Ex.: 926460663
1422 * @param version (%u) Ex.: 22
1423 * @param availability (%d) Ex.: 3500
1425 #define SIPE_PUB_XML_STATE_MACHINE \
1426 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
1427 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"machineState\">"\
1428 "<availability>%d</availability>"\
1429 "<endpointLocation/>"\
1432 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
1433 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"machineState\">"\
1434 "<availability>%d</availability>"\
1435 "<endpointLocation/>"\
1440 * Publishes 'userState' category.
1441 * @param instance (%u) User. Ex.: 536870912
1442 * @param version (%u) User Container 2. Ex.: 22
1443 * @param availability (%d) User Container 2. Ex.: 15500
1444 * @param instance (%u) User. Ex.: 536870912
1445 * @param version (%u) User Container 3.Ex.: 22
1446 * @param availability (%d) User Container 3. Ex.: 15500
1448 #define SIPE_PUB_XML_STATE_USER \
1449 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"static\">"\
1450 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"true\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"userState\">"\
1451 "<availability>%d</availability>"\
1452 "<endpointLocation/>"\
1455 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"static\">"\
1456 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"true\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"userState\">"\
1457 "<availability>%d</availability>"\
1458 "<endpointLocation/>"\
1463 * A service method - use
1464 * - send_publish_get_category_state_machine and
1465 * - send_publish_get_category_state_user instead.
1466 * Must be g_free'd after use.
1468 static gchar
*sipe_publish_get_category_state(struct sipe_core_private
*sipe_private
,
1469 gboolean is_user_state
)
1471 int availability
= sipe_ocs2007_availability_from_status(sipe_private
->status
, NULL
);
1472 guint instance
= is_user_state
? sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_USER
) :
1473 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_MACHINE
);
1474 /* key is <category><instance><container> */
1475 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
1476 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
1477 struct sipe_publication
*publication_2
=
1478 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_2
);
1479 struct sipe_publication
*publication_3
=
1480 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_3
);
1485 if (publication_2
&& (publication_2
->availability
== availability
))
1487 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_state: state has NOT changed. Exiting.");
1488 return NULL
; /* nothing to update */
1491 return g_strdup_printf( is_user_state
? SIPE_PUB_XML_STATE_USER
: SIPE_PUB_XML_STATE_MACHINE
,
1493 publication_2
? publication_2
->version
: 0,
1496 publication_3
? publication_3
->version
: 0,
1501 * Returns 'machineState' XML part for publication.
1502 * Must be g_free'd after use.
1504 static gchar
*sipe_publish_get_category_state_machine(struct sipe_core_private
*sipe_private
)
1506 return sipe_publish_get_category_state(sipe_private
, FALSE
);
1510 * Returns 'userState' XML part for publication.
1511 * Must be g_free'd after use.
1513 static gchar
*sipe_publish_get_category_state_user(struct sipe_core_private
*sipe_private
)
1515 return sipe_publish_get_category_state(sipe_private
, TRUE
);
1518 static void send_publish_category_initial(struct sipe_core_private
*sipe_private
)
1520 gchar
*pub_device
= sipe_publish_get_category_device(sipe_private
);
1522 gchar
*publications
;
1524 sipe_status_set_activity(sipe_private
, SIPE_ACTIVITY_AVAILABLE
);
1526 pub_machine
= sipe_publish_get_category_state_machine(sipe_private
);
1527 publications
= g_strdup_printf("%s%s",
1529 pub_machine
? pub_machine
: "");
1531 g_free(pub_machine
);
1533 send_presence_publish(sipe_private
, publications
);
1534 g_free(publications
);
1537 static gboolean
process_send_presence_category_publish_response(struct sipe_core_private
*sipe_private
,
1539 struct transaction
*trans
)
1541 const gchar
*contenttype
= sipmsg_find_header(msg
, "Content-Type");
1543 if (msg
->response
== 409 && g_str_has_prefix(contenttype
, "application/msrtc-fault+xml")) {
1545 const sipe_xml
*node
;
1549 gboolean has_device_publication
= FALSE
;
1551 xml
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
1553 /* test if version mismatch fault */
1554 fault_code
= sipe_xml_data(sipe_xml_child(xml
, "Faultcode"));
1555 if (!sipe_strequal(fault_code
, "Client.BadCall.WrongDelta")) {
1556 SIPE_DEBUG_INFO("process_send_presence_category_publish_response: unsupported fault code:%s returning.", fault_code
);
1563 /* accumulating information about faulty versions */
1564 faults
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
1565 for (node
= sipe_xml_child(xml
, "details/operation");
1567 node
= sipe_xml_twin(node
))
1569 const gchar
*index
= sipe_xml_attribute(node
, "index");
1570 const gchar
*curVersion
= sipe_xml_attribute(node
, "curVersion");
1572 g_hash_table_insert(faults
, g_strdup(index
), g_strdup(curVersion
));
1573 SIPE_DEBUG_INFO("fault added: index:%s curVersion:%s", index
, curVersion
);
1577 /* here we are parsing our own request to figure out what publication
1578 * referenced here only by index went wrong
1580 xml
= sipe_xml_parse(trans
->msg
->body
, trans
->msg
->bodylen
);
1583 for (node
= sipe_xml_child(xml
, "publications/publication"),
1584 index_our
= 1; /* starts with 1 - our first publication */
1586 node
= sipe_xml_twin(node
), index_our
++)
1588 gchar
*idx
= g_strdup_printf("%d", index_our
);
1589 const gchar
*curVersion
= g_hash_table_lookup(faults
, idx
);
1590 const gchar
*categoryName
= sipe_xml_attribute(node
, "categoryName");
1593 if (sipe_strequal("device", categoryName
)) {
1594 has_device_publication
= TRUE
;
1597 if (curVersion
) { /* fault exist on this index */
1598 const gchar
*container
= sipe_xml_attribute(node
, "container");
1599 const gchar
*instance
= sipe_xml_attribute(node
, "instance");
1600 /* key is <category><instance><container> */
1601 gchar
*key
= g_strdup_printf("<%s><%s><%s>", categoryName
, instance
, container
);
1602 GHashTable
*category
= g_hash_table_lookup(sipe_private
->our_publications
, categoryName
);
1605 struct sipe_publication
*publication
=
1606 g_hash_table_lookup(category
, key
);
1608 SIPE_DEBUG_INFO("key is %s", key
);
1611 SIPE_DEBUG_INFO("Updating %s with version %s. Was %d before.",
1612 key
, curVersion
, publication
->version
);
1613 /* updating publication's version to the correct one */
1614 publication
->version
= atoi(curVersion
);
1617 /* We somehow lost this category from our publications... */
1618 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
1619 publication
->category
= g_strdup(categoryName
);
1620 publication
->instance
= atoi(instance
);
1621 publication
->container
= atoi(container
);
1622 publication
->version
= atoi(curVersion
);
1623 category
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
1624 g_free
, (GDestroyNotify
)free_publication
);
1625 g_hash_table_insert(category
, g_strdup(key
), publication
);
1626 g_hash_table_insert(sipe_private
->our_publications
, g_strdup(categoryName
), category
);
1627 SIPE_DEBUG_INFO("added lost category '%s' key '%s'", categoryName
, key
);
1633 g_hash_table_destroy(faults
);
1635 /* rebublishing with right versions */
1636 if (has_device_publication
) {
1637 send_publish_category_initial(sipe_private
);
1639 sipe_status_update(sipe_private
, NULL
);
1646 * Publishes categories.
1647 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1648 * @param publications (%s) XML publications
1650 #define SIPE_SEND_PRESENCE \
1651 "<publish xmlns=\"http://schemas.microsoft.com/2006/09/sip/rich-presence\">"\
1652 "<publications uri=\"%s\">"\
1657 static void send_presence_publish(struct sipe_core_private
*sipe_private
,
1658 const char *publications
)
1665 uri
= sip_uri_self(sipe_private
);
1666 doc
= g_strdup_printf(SIPE_SEND_PRESENCE
,
1670 tmp
= get_contact(sipe_private
);
1671 hdr
= g_strdup_printf("Contact: %s\r\n"
1672 "Content-Type: application/msrtc-category-publish+xml\r\n", tmp
);
1674 sip_transport_service(sipe_private
,
1678 process_send_presence_category_publish_response
);
1687 * Publishes self status
1688 * based on own calendar information.
1690 void sipe_ocs2007_presence_publish(struct sipe_core_private
*sipe_private
,
1691 SIPE_UNUSED_PARAMETER
void *unused
)
1693 struct sipe_calendar
* cal
= sipe_private
->calendar
;
1694 struct sipe_cal_event
* event
= NULL
;
1695 gchar
*pub_cal_working_hours
= NULL
;
1696 gchar
*pub_cal_free_busy
= NULL
;
1697 gchar
*pub_calendar
= NULL
;
1698 gchar
*pub_calendar2
= NULL
;
1699 gchar
*pub_oof_note
= NULL
;
1700 const gchar
*oof_note
;
1701 time_t oof_start
= 0;
1705 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() no calendar data.");
1709 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() started.");
1710 if (cal
->cal_events
) {
1711 event
= sipe_cal_get_event(cal
->cal_events
, time(NULL
));
1715 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: current event is NULL");
1717 char *desc
= sipe_cal_event_describe(event
);
1718 SIPE_DEBUG_INFO("publish_calendar_status_self: current event is:\n%s", desc
? desc
: "");
1724 OOF publish, Busy clean
1726 OOF clean, Busy publish
1728 OOF clean, Busy clean
1730 if (event
&& event
->cal_status
== SIPE_CAL_OOF
) {
1731 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, event
, cal
->email
, SIPE_CAL_OOF
);
1732 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_BUSY
);
1733 } else if (event
&& event
->cal_status
== SIPE_CAL_BUSY
) {
1734 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_OOF
);
1735 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, event
, cal
->email
, SIPE_CAL_BUSY
);
1737 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_OOF
);
1738 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_BUSY
);
1741 oof_note
= sipe_ews_get_oof_note(cal
);
1742 if (sipe_strequal("Scheduled", cal
->oof_state
)) {
1743 oof_start
= cal
->oof_start
;
1744 oof_end
= cal
->oof_end
;
1746 pub_oof_note
= sipe_publish_get_category_note(sipe_private
, oof_note
, "OOF", oof_start
, oof_end
);
1748 pub_cal_working_hours
= sipe_publish_get_category_cal_working_hours(sipe_private
);
1749 pub_cal_free_busy
= sipe_publish_get_category_cal_free_busy(sipe_private
);
1751 if (!pub_cal_working_hours
&& !pub_cal_free_busy
&& !pub_calendar
&& !pub_calendar2
&& !pub_oof_note
) {
1752 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: nothing has changed.");
1754 gchar
*publications
= g_strdup_printf("%s%s%s%s%s",
1755 pub_cal_working_hours
? pub_cal_working_hours
: "",
1756 pub_cal_free_busy
? pub_cal_free_busy
: "",
1757 pub_calendar
? pub_calendar
: "",
1758 pub_calendar2
? pub_calendar2
: "",
1759 pub_oof_note
? pub_oof_note
: "");
1761 send_presence_publish(sipe_private
, publications
);
1762 g_free(publications
);
1765 g_free(pub_cal_working_hours
);
1766 g_free(pub_cal_free_busy
);
1767 g_free(pub_calendar
);
1768 g_free(pub_calendar2
);
1769 g_free(pub_oof_note
);
1771 /* repeat scheduling */
1772 schedule_publish_update(sipe_private
, time(NULL
));
1775 void sipe_ocs2007_category_publish(struct sipe_core_private
*sipe_private
)
1777 gchar
*pub_state
= sipe_status_changed_by_user(sipe_private
) ?
1778 sipe_publish_get_category_state_user(sipe_private
) :
1779 sipe_publish_get_category_state_machine(sipe_private
);
1780 gchar
*pub_note
= sipe_publish_get_category_note(sipe_private
,
1782 SIPE_CORE_PRIVATE_FLAG_IS(OOF_NOTE
) ? "OOF" : "personal",
1785 gchar
*publications
;
1787 if (!pub_state
&& !pub_note
) {
1788 SIPE_DEBUG_INFO_NOFORMAT("sipe_osc2007_category_publish: nothing has changed. Exiting.");
1792 publications
= g_strdup_printf("%s%s",
1793 pub_state
? pub_state
: "",
1794 pub_note
? pub_note
: "");
1799 send_presence_publish(sipe_private
, publications
);
1800 g_free(publications
);
1803 void sipe_ocs2007_phone_state_publish(struct sipe_core_private
*sipe_private
)
1805 gchar
*publications
= NULL
;
1806 guint instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_PHONE_VOIP
);
1808 /* key is <category><instance><container> */
1809 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
1810 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
1811 struct sipe_publication
*publication_2
=
1812 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_2
);
1813 struct sipe_publication
*publication_3
=
1814 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_3
);
1819 if (sipe_private
->media_call
) {
1822 if (sipe_media_is_conference_call(sipe_private
->media_call
)) {
1823 availability
= 7000;
1824 token
= sipe_status_activity_to_token(SIPE_ACTIVITY_IN_CONF
);
1826 availability
= 6500;
1827 token
= sipe_status_activity_to_token(SIPE_ACTIVITY_ON_PHONE
);
1830 publications
= g_strdup_printf(SIPE_PUB_XML_STATE_PHONE
,
1831 instance
, publication_2
? publication_2
->version
: 0,
1832 availability
, token
, availability
,
1833 instance
, publication_3
? publication_3
->version
: 0,
1834 availability
, token
, availability
);
1838 publications
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_PHONE_CLEAR
,
1839 instance
, publication_2
? publication_2
->version
: 0,
1840 instance
, publication_3
? publication_3
->version
: 0);
1843 send_presence_publish(sipe_private
, publications
);
1844 g_free(publications
);
1847 static void sipe_publish_get_cat_state_user_to_clear(SIPE_UNUSED_PARAMETER
const char *name
,
1851 struct sipe_publication
*publication
= value
;
1853 g_string_append_printf( str
,
1854 SIPE_PUB_XML_PUBLICATION_CLEAR
,
1855 publication
->category
,
1856 publication
->instance
,
1857 publication
->container
,
1858 publication
->version
,
1862 void sipe_ocs2007_reset_status(struct sipe_core_private
*sipe_private
)
1865 gchar
*publications
;
1867 if (!sipe_private
->user_state_publications
|| g_hash_table_size(sipe_private
->user_state_publications
) == 0) {
1868 SIPE_DEBUG_INFO_NOFORMAT("sipe_reset_status: no userState publications, exiting.");
1872 str
= g_string_new(NULL
);
1873 g_hash_table_foreach(sipe_private
->user_state_publications
, (GHFunc
)sipe_publish_get_cat_state_user_to_clear
, str
);
1874 publications
= g_string_free(str
, FALSE
);
1876 send_presence_publish(sipe_private
, publications
);
1877 g_free(publications
);
1880 /* key is <category><instance><container> */
1881 static gboolean
sipe_is_our_publication(struct sipe_core_private
*sipe_private
,
1886 /* filling keys for our publications if not yet cached */
1887 if (!sipe_private
->our_publication_keys
) {
1888 guint device_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_DEVICE
);
1889 guint machine_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_MACHINE
);
1890 guint user_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_USER
);
1891 guint calendar_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR
);
1892 guint cal_oof_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR_OOF
);
1893 guint phone_voip_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_PHONE_VOIP
);
1894 guint cal_data_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_CALENDAR_DATA
);
1895 guint note_oof_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_NOTE_OOF
);
1897 SIPE_DEBUG_INFO_NOFORMAT("* Our Publication Instances *");
1898 SIPE_DEBUG_INFO("\tDevice : %u\t0x%08X", device_instance
, device_instance
);
1899 SIPE_DEBUG_INFO("\tMachine State : %u\t0x%08X", machine_instance
, machine_instance
);
1900 SIPE_DEBUG_INFO("\tUser Stare : %u\t0x%08X", user_instance
, user_instance
);
1901 SIPE_DEBUG_INFO("\tCalendar State : %u\t0x%08X", calendar_instance
, calendar_instance
);
1902 SIPE_DEBUG_INFO("\tCalendar OOF State : %u\t0x%08X", cal_oof_instance
, cal_oof_instance
);
1903 SIPE_DEBUG_INFO("\tVOIP Phone State : %u\t0x%08X", phone_voip_instance
, phone_voip_instance
);
1904 SIPE_DEBUG_INFO("\tCalendar FreeBusy : %u\t0x%08X", cal_data_instance
, cal_data_instance
);
1905 SIPE_DEBUG_INFO("\tOOF Note : %u\t0x%08X", note_oof_instance
, note_oof_instance
);
1906 SIPE_DEBUG_INFO("\tNote : %u", 0);
1907 SIPE_DEBUG_INFO("\tCalendar WorkingHours: %u", 0);
1910 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1911 g_strdup_printf("<%s><%u><%u>", "device", device_instance
, 2));
1913 /* state:machineState */
1914 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1915 g_strdup_printf("<%s><%u><%u>", "state", machine_instance
, 2));
1916 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1917 g_strdup_printf("<%s><%u><%u>", "state", machine_instance
, 3));
1919 /* state:userState */
1920 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1921 g_strdup_printf("<%s><%u><%u>", "state", user_instance
, 2));
1922 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1923 g_strdup_printf("<%s><%u><%u>", "state", user_instance
, 3));
1925 /* state:calendarState */
1926 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1927 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance
, 2));
1928 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1929 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance
, 3));
1931 /* state:calendarState OOF */
1932 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1933 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance
, 2));
1934 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1935 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance
, 3));
1937 /* state:phoneState */
1938 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1939 g_strdup_printf("<%s><%u><%u>", "state", phone_voip_instance
, 2));
1940 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1941 g_strdup_printf("<%s><%u><%u>", "state", phone_voip_instance
, 3));
1944 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1945 g_strdup_printf("<%s><%u><%u>", "note", 0, 200));
1946 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1947 g_strdup_printf("<%s><%u><%u>", "note", 0, 300));
1948 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1949 g_strdup_printf("<%s><%u><%u>", "note", 0, 400));
1952 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1953 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 200));
1954 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1955 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 300));
1956 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1957 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 400));
1959 /* calendarData:WorkingHours */
1960 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1961 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1));
1962 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1963 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100));
1964 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1965 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200));
1966 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1967 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300));
1968 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1969 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400));
1970 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1971 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000));
1973 /* calendarData:FreeBusy */
1974 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1975 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 1));
1976 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1977 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 100));
1978 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1979 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 200));
1980 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1981 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 300));
1982 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1983 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 400));
1984 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1985 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 32000));
1987 //SIPE_DEBUG_INFO("sipe_is_our_publication: sipe_private->our_publication_keys length=%d",
1988 // sipe_private->our_publication_keys ? (int) g_slist_length(sipe_private->our_publication_keys) : -1);
1991 //SIPE_DEBUG_INFO("sipe_is_our_publication: key=%s", key);
1993 entry
= sipe_private
->our_publication_keys
;
1995 //SIPE_DEBUG_INFO(" sipe_is_our_publication: entry->data=%s", entry->data);
1996 if (sipe_strequal(entry
->data
, key
)) {
1999 entry
= entry
->next
;
2004 static void sipe_refresh_blocked_status_cb(char *buddy_name
,
2005 SIPE_UNUSED_PARAMETER
struct sipe_buddy
*buddy
,
2006 struct sipe_core_private
*sipe_private
)
2008 int container_id
= sipe_ocs2007_find_access_level(sipe_private
, "user", buddy_name
, NULL
);
2009 gboolean blocked
= (container_id
== 32000);
2010 gboolean blocked_in_blist
= sipe_backend_buddy_is_blocked(SIPE_CORE_PUBLIC
, buddy_name
);
2012 /* SIPE_DEBUG_INFO("sipe_refresh_blocked_status_cb: buddy_name=%s, blocked=%s, blocked_in_blist=%s",
2013 buddy_name, blocked ? "T" : "F", blocked_in_blist ? "T" : "F"); */
2015 if (blocked
!= blocked_in_blist
) {
2016 sipe_backend_buddy_set_blocked_status(SIPE_CORE_PUBLIC
, buddy_name
, blocked
);
2020 static void sipe_refresh_blocked_status(struct sipe_core_private
*sipe_private
)
2022 g_hash_table_foreach(sipe_private
->buddies
,
2023 (GHFunc
) sipe_refresh_blocked_status_cb
,
2028 * When we receive some self (BE) NOTIFY with a new subscriber
2029 * we sends a setSubscribers request to him [SIP-PRES] 4.8
2032 void sipe_ocs2007_process_roaming_self(struct sipe_core_private
*sipe_private
,
2038 const sipe_xml
*node
;
2039 const sipe_xml
*node2
;
2040 char *display_name
= NULL
;
2042 GSList
*category_names
= NULL
;
2043 int aggreg_avail
= 0;
2044 gchar
*activity_token
= NULL
;
2045 gboolean do_update_status
= FALSE
;
2046 gboolean has_note_cleaned
= FALSE
;
2047 GHashTable
*devices
;
2049 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self");
2051 xml
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
2054 contact
= get_contact(sipe_private
);
2055 to
= sip_uri_self(sipe_private
);
2058 /* set list of categories participating in this XML */
2059 for (node
= sipe_xml_child(xml
, "categories/category"); node
; node
= sipe_xml_twin(node
)) {
2060 const gchar
*name
= sipe_xml_attribute(node
, "name");
2061 category_names
= slist_insert_unique_sorted(category_names
, (gchar
*)name
, (GCompareFunc
)strcmp
);
2063 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: category_names length=%d",
2064 category_names
? (int) g_slist_length(category_names
) : -1);
2065 /* drop category information */
2066 if (category_names
) {
2067 GSList
*entry
= category_names
;
2069 GHashTable
*cat_publications
;
2070 const gchar
*category
= entry
->data
;
2071 entry
= entry
->next
;
2072 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: dropping category: %s", category
);
2073 cat_publications
= g_hash_table_lookup(sipe_private
->our_publications
, category
);
2074 if (cat_publications
) {
2075 g_hash_table_remove(sipe_private
->our_publications
, category
);
2076 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: dropped category: %s", category
);
2080 g_slist_free(category_names
);
2082 /* filling our categories reflected in roaming data */
2083 devices
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
2085 for (node
= sipe_xml_child(xml
, "categories/category"); node
; node
= sipe_xml_twin(node
)) {
2087 const gchar
*name
= sipe_xml_attribute(node
, "name");
2088 guint container
= sipe_xml_int_attribute(node
, "container", -1);
2089 guint instance
= sipe_xml_int_attribute(node
, "instance", -1);
2090 guint version
= sipe_xml_int_attribute(node
, "version", 0);
2091 time_t publish_time
= (tmp
= sipe_xml_attribute(node
, "publishTime")) ?
2092 sipe_utils_str_to_time(tmp
) : 0;
2094 GHashTable
*cat_publications
= g_hash_table_lookup(sipe_private
->our_publications
, name
);
2096 /* Ex. clear note: <category name="note"/> */
2097 if (container
== (guint
)-1) {
2098 g_free(sipe_private
->note
);
2099 sipe_private
->note
= NULL
;
2100 do_update_status
= TRUE
;
2104 /* Ex. clear note: <category name="note" container="200"/> */
2105 if (instance
== (guint
)-1) {
2106 if (container
== 200) {
2107 g_free(sipe_private
->note
);
2108 sipe_private
->note
= NULL
;
2109 do_update_status
= TRUE
;
2111 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removing publications for: %s/%u", name
, container
);
2112 sipe_remove_category_container_publications(
2113 sipe_private
->our_publications
, name
, container
);
2117 /* key is <category><instance><container> */
2118 key
= g_strdup_printf("<%s><%u><%u>", name
, instance
, container
);
2119 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: key=%s version=%d", key
, version
);
2121 /* capture all userState publication for later clean up if required */
2122 if (sipe_strequal(name
, "state") && (container
== 2 || container
== 3)) {
2123 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
2125 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "userState")) {
2126 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
2127 publication
->category
= g_strdup(name
);
2128 publication
->instance
= instance
;
2129 publication
->container
= container
;
2130 publication
->version
= version
;
2132 if (!sipe_private
->user_state_publications
) {
2133 sipe_private
->user_state_publications
= g_hash_table_new_full(
2134 g_str_hash
, g_str_equal
,
2135 g_free
, (GDestroyNotify
)free_publication
);
2137 g_hash_table_insert(sipe_private
->user_state_publications
, g_strdup(key
), publication
);
2138 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added to user_state_publications key=%s version=%d",
2143 /* count each client instance only once */
2144 if (sipe_strequal(name
, "device"))
2145 g_hash_table_replace(devices
, g_strdup_printf("%u", instance
), NULL
);
2147 if (sipe_is_our_publication(sipe_private
, key
)) {
2148 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
2150 publication
->category
= g_strdup(name
);
2151 publication
->instance
= instance
;
2152 publication
->container
= container
;
2153 publication
->version
= version
;
2155 /* filling publication->availability */
2156 if (sipe_strequal(name
, "state")) {
2157 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
2158 const sipe_xml
*xn_avail
= sipe_xml_child(xn_state
, "availability");
2161 gchar
*avail_str
= sipe_xml_data(xn_avail
);
2163 publication
->availability
= atoi(avail_str
);
2167 /* for calendarState */
2168 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "calendarState")) {
2169 const sipe_xml
*xn_activity
= sipe_xml_child(xn_state
, "activity");
2170 struct sipe_cal_event
*event
= g_new0(struct sipe_cal_event
, 1);
2172 event
->start_time
= sipe_utils_str_to_time(sipe_xml_attribute(xn_state
, "startTime"));
2174 if (sipe_strequal(sipe_xml_attribute(xn_activity
, "token"),
2175 sipe_status_activity_to_token(SIPE_ACTIVITY_IN_MEETING
)))
2177 event
->is_meeting
= TRUE
;
2180 event
->subject
= sipe_xml_data(sipe_xml_child(xn_state
, "meetingSubject"));
2181 event
->location
= sipe_xml_data(sipe_xml_child(xn_state
, "meetingLocation"));
2183 publication
->cal_event_hash
= sipe_cal_event_hash(event
);
2184 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: hash=%s",
2185 publication
->cal_event_hash
);
2186 sipe_cal_event_free(event
);
2189 /* filling publication->note */
2190 if (sipe_strequal(name
, "note")) {
2191 const sipe_xml
*xn_body
= sipe_xml_child(node
, "note/body");
2193 if (!has_note_cleaned
) {
2194 has_note_cleaned
= TRUE
;
2196 g_free(sipe_private
->note
);
2197 sipe_private
->note
= NULL
;
2198 sipe_private
->note_since
= publish_time
;
2200 do_update_status
= TRUE
;
2203 g_free(publication
->note
);
2204 publication
->note
= NULL
;
2208 publication
->note
= g_markup_escape_text((tmp
= sipe_xml_data(xn_body
)), -1);
2210 if (publish_time
>= sipe_private
->note_since
) {
2211 g_free(sipe_private
->note
);
2212 sipe_private
->note
= g_strdup(publication
->note
);
2213 sipe_private
->note_since
= publish_time
;
2214 if (sipe_strequal(sipe_xml_attribute(xn_body
, "type"), "OOF"))
2215 SIPE_CORE_PRIVATE_FLAG_SET(OOF_NOTE
);
2217 SIPE_CORE_PRIVATE_FLAG_UNSET(OOF_NOTE
);
2219 do_update_status
= TRUE
;
2224 /* filling publication->fb_start_str, free_busy_base64, working_hours_xml_str */
2225 if (sipe_strequal(name
, "calendarData") && (publication
->container
== 300)) {
2226 const sipe_xml
*xn_free_busy
= sipe_xml_child(node
, "calendarData/freeBusy");
2227 const sipe_xml
*xn_working_hours
= sipe_xml_child(node
, "calendarData/WorkingHours");
2229 publication
->fb_start_str
= g_strdup(sipe_xml_attribute(xn_free_busy
, "startTime"));
2230 publication
->free_busy_base64
= sipe_xml_data(xn_free_busy
);
2232 if (xn_working_hours
) {
2233 publication
->working_hours_xml_str
= sipe_xml_stringify(xn_working_hours
);
2237 if (!cat_publications
) {
2238 cat_publications
= g_hash_table_new_full(
2239 g_str_hash
, g_str_equal
,
2240 g_free
, (GDestroyNotify
)free_publication
);
2241 g_hash_table_insert(sipe_private
->our_publications
, g_strdup(name
), cat_publications
);
2242 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added GHashTable cat=%s", name
);
2244 g_hash_table_insert(cat_publications
, g_strdup(key
), publication
);
2245 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added key=%s version=%d", key
, version
);
2249 /* aggregateState (not an our publication) from 2-nd container */
2250 if (sipe_strequal(name
, "state") && container
== 2) {
2251 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
2252 const sipe_xml
*xn_activity
= sipe_xml_child(xn_state
, "activity");
2254 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "aggregateState")) {
2255 const sipe_xml
*xn_avail
= sipe_xml_child(xn_state
, "availability");
2258 gchar
*avail_str
= sipe_xml_data(xn_avail
);
2260 aggreg_avail
= atoi(avail_str
);
2265 do_update_status
= TRUE
;
2269 activity_token
= g_strdup(sipe_xml_attribute(xn_activity
, "token"));
2273 /* userProperties published by server from AD */
2274 if (!sipe_private
->csta
&&
2275 sipe_strequal(name
, "userProperties")) {
2276 const sipe_xml
*line
;
2277 /* line, for Remote Call Control (RCC) */
2278 for (line
= sipe_xml_child(node
, "userProperties/lines/line"); line
; line
= sipe_xml_twin(line
)) {
2279 const gchar
*line_server
= sipe_xml_attribute(line
, "lineServer");
2280 const gchar
*line_type
= sipe_xml_attribute(line
, "lineType");
2283 if (!line_server
|| !(sipe_strequal(line_type
, "Rcc") || sipe_strequal(line_type
, "Dual"))) continue;
2285 line_uri
= sipe_xml_data(line
);
2287 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: line_uri=%s server=%s", line_uri
, line_server
);
2288 sip_csta_open(sipe_private
, line_uri
, line_server
);
2296 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sipe_private->our_publications size=%d",
2297 sipe_private
->our_publications
? (int) g_hash_table_size(sipe_private
->our_publications
) : -1);
2299 /* active clients for user account */
2300 if (g_hash_table_size(devices
) > 1) {
2301 SIPE_CORE_PRIVATE_FLAG_SET(MPOP
);
2302 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: multiple clients detected (%d)",
2303 g_hash_table_size(devices
));
2305 SIPE_CORE_PRIVATE_FLAG_UNSET(MPOP
);
2306 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self: single client detected");
2308 g_hash_table_destroy(devices
);
2311 for (node
= sipe_xml_child(xml
, "containers/container"); node
; node
= sipe_xml_twin(node
)) {
2312 guint id
= sipe_xml_int_attribute(node
, "id", 0);
2313 struct sipe_container
*container
= sipe_find_container(sipe_private
, id
);
2316 sipe_private
->containers
= g_slist_remove(sipe_private
->containers
, container
);
2317 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removed existing container id=%d v%d", container
->id
, container
->version
);
2318 sipe_ocs2007_free_container(container
);
2320 container
= g_new0(struct sipe_container
, 1);
2322 container
->version
= sipe_xml_int_attribute(node
, "version", 0);
2323 sipe_private
->containers
= g_slist_append(sipe_private
->containers
, container
);
2324 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container id=%d v%d", container
->id
, container
->version
);
2326 for (node2
= sipe_xml_child(node
, "member"); node2
; node2
= sipe_xml_twin(node2
)) {
2327 struct sipe_container_member
*member
= g_new0(struct sipe_container_member
, 1);
2328 member
->type
= g_strdup(sipe_xml_attribute(node2
, "type"));
2329 member
->value
= g_strdup(sipe_xml_attribute(node2
, "value"));
2330 container
->members
= g_slist_append(container
->members
, member
);
2331 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container member type=%s value=%s",
2332 member
->type
, member
->value
? member
->value
: "");
2336 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: access_level_set=%s",
2337 SIPE_CORE_PRIVATE_FLAG_IS(ACCESS_LEVEL_SET
) ? "TRUE" : "FALSE");
2338 if (!SIPE_CORE_PRIVATE_FLAG_IS(ACCESS_LEVEL_SET
) && sipe_xml_child(xml
, "containers")) {
2339 char *container_xmls
= NULL
;
2340 int sameEnterpriseAL
= sipe_ocs2007_find_access_level(sipe_private
, "sameEnterprise", NULL
, NULL
);
2341 int federatedAL
= sipe_ocs2007_find_access_level(sipe_private
, "federated", NULL
, NULL
);
2343 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sameEnterpriseAL=%d", sameEnterpriseAL
);
2344 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: federatedAL=%d", federatedAL
);
2345 /* initial set-up to let counterparties see your status */
2346 if (sameEnterpriseAL
< 0) {
2347 struct sipe_container
*container
= sipe_find_container(sipe_private
, 200);
2348 guint version
= container
? container
->version
: 0;
2349 sipe_send_container_members_prepare(200, version
, "add", "sameEnterprise", NULL
, &container_xmls
);
2351 if (federatedAL
< 0) {
2352 struct sipe_container
*container
= sipe_find_container(sipe_private
, 100);
2353 guint version
= container
? container
->version
: 0;
2354 sipe_send_container_members_prepare(100, version
, "add", "federated", NULL
, &container_xmls
);
2356 SIPE_CORE_PRIVATE_FLAG_SET(ACCESS_LEVEL_SET
);
2358 if (container_xmls
) {
2359 sipe_send_set_container_members(sipe_private
, container_xmls
);
2361 g_free(container_xmls
);
2364 /* Refresh contacts' blocked status */
2365 sipe_refresh_blocked_status(sipe_private
);
2368 for (node
= sipe_xml_child(xml
, "subscribers/subscriber"); node
; node
= sipe_xml_twin(node
)) {
2370 const char *acknowledged
;
2374 user
= sipe_xml_attribute(node
, "user"); /* without 'sip:' prefix */
2375 if (!user
) continue;
2376 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user %s", user
);
2377 display_name
= g_strdup(sipe_xml_attribute(node
, "displayName"));
2378 uri
= sip_uri_from_name(user
);
2380 sipe_buddy_update_property(sipe_private
, uri
, SIPE_BUDDY_INFO_DISPLAY_NAME
, display_name
);
2381 sipe_backend_buddy_refresh_properties(SIPE_CORE_PUBLIC
, uri
);
2383 acknowledged
= sipe_xml_attribute(node
, "acknowledged");
2384 if(sipe_strcase_equal(acknowledged
,"false")){
2385 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user added you %s", user
);
2386 if (!sipe_backend_buddy_find(SIPE_CORE_PUBLIC
, uri
, NULL
)) {
2387 sipe_backend_buddy_request_add(SIPE_CORE_PUBLIC
, uri
, display_name
);
2390 hdr
= g_strdup_printf(
2392 "Content-Type: application/msrtc-presence-setsubscriber+xml\r\n", contact
);
2394 body
= g_strdup_printf(
2395 "<setSubscribers xmlns=\"http://schemas.microsoft.com/2006/09/sip/presence-subscribers\">"
2396 "<subscriber user=\"%s\" acknowledged=\"true\"/>"
2397 "</setSubscribers>", user
);
2399 sip_transport_service(sipe_private
,
2407 g_free(display_name
);
2414 /* Publish initial state if not yet.
2415 * Assuming this happens on initial responce to subscription to roaming-self
2416 * so we've already updated our roaming data in full.
2419 if (!SIPE_CORE_PRIVATE_FLAG_IS(INITIAL_PUBLISH
)) {
2420 send_publish_category_initial(sipe_private
);
2421 sipe_groupchat_init(sipe_private
);
2422 SIPE_CORE_PRIVATE_FLAG_SET(INITIAL_PUBLISH
);
2424 sipe_cal_delayed_calendar_update(sipe_private
);
2425 do_update_status
= FALSE
;
2426 } else if (aggreg_avail
) {
2429 (aggreg_avail
< SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE
)) {
2431 sipe_status_set_token(sipe_private
,
2432 sipe_ocs2007_status_from_legacy_availability(aggreg_avail
, activity_token
));
2434 /* do not let offline status switch us off */
2435 sipe_status_set_activity(sipe_private
,
2436 SIPE_ACTIVITY_INVISIBLE
);
2440 if (do_update_status
) {
2441 sipe_status_and_note(sipe_private
, NULL
);
2445 g_free(activity_token
);
2449 * for Access levels menu
2451 #define INDENT_FMT " %s"
2454 * Member is indirectly belong to access level container.
2455 * For example 'sameEnterprise' is in the container and user
2456 * belongs to that same enterprise.
2458 #define INDENT_MARKED_INHERITED_FMT "= %s"
2460 static struct sipe_backend_buddy_menu
*access_levels_menu(struct sipe_core_private
*sipe_private
,
2461 struct sipe_backend_buddy_menu
*menu
,
2462 const gchar
*member_type
,
2463 const gchar
*member_value
,
2464 const gboolean extra_menu
)
2467 gboolean is_group_access
= FALSE
;
2471 menu
= sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC
);
2473 container_id
= sipe_ocs2007_find_access_level(sipe_private
,
2478 for (i
= 1; i
<= CONTAINERS_LEN
; i
++) {
2480 * Blocked should remain in the first place
2481 * in the containers[] array.
2483 unsigned int j
= (i
== CONTAINERS_LEN
) ? 0 : i
;
2484 int container_j
= containers
[j
];
2485 const gchar
*acc_level_name
= sipe_ocs2007_access_level_name(container_j
);
2486 struct sipe_container
*container
= create_container(j
,
2492 /* libpurple memory leak workaround */
2493 blist_menu_remember_container(sipe_private
, container
);
2495 /* current container/access level */
2496 if (container_j
== container_id
) {
2497 label
= is_group_access
?
2498 g_strdup_printf(INDENT_MARKED_INHERITED_FMT
, acc_level_name
) :
2499 g_strdup_printf(SIPE_OCS2007_INDENT_MARKED_FMT
, acc_level_name
);
2501 label
= g_strdup_printf(INDENT_FMT
, acc_level_name
);
2504 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2507 SIPE_BUDDY_MENU_CHANGE_ACCESS_LEVEL
,
2512 if (extra_menu
&& (container_id
>= 0) && !is_group_access
) {
2513 struct sipe_container
*container
= create_container(0,
2520 menu
= sipe_backend_buddy_menu_separator(SIPE_CORE_PUBLIC
,
2525 /* libpurple memory leak workaround */
2526 blist_menu_remember_container(sipe_private
, container
);
2528 /* Translators: remove (clear) previously assigned access level */
2529 label
= g_strdup_printf(INDENT_FMT
, _("Unspecify"));
2530 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2533 SIPE_BUDDY_MENU_CHANGE_ACCESS_LEVEL
,
2541 static struct sipe_backend_buddy_menu
*access_groups_menu(struct sipe_core_private
*sipe_private
)
2543 struct sipe_backend_buddy_menu
*menu
= sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC
);
2544 GSList
*access_domains
, *entry
;
2546 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2548 _("People in my company"),
2549 access_levels_menu(sipe_private
,
2555 /* this is original name, don't edit */
2556 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2558 _("People in domains connected with my company"),
2559 access_levels_menu(sipe_private
,
2565 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2567 _("People in public domains"),
2568 access_levels_menu(sipe_private
,
2574 entry
= access_domains
= get_access_domains(sipe_private
);
2576 gchar
*domain
= entry
->data
;
2577 gchar
*menu_name
= g_strdup_printf(_("People at %s"), domain
);
2579 /* takes over ownership of entry->data (= domain) */
2580 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2583 access_levels_menu(sipe_private
,
2590 entry
= entry
->next
;
2592 g_slist_free(access_domains
);
2595 /* People in domains connected with my company */
2596 menu
= sipe_backend_buddy_menu_separator(SIPE_CORE_PUBLIC
,
2598 "-------------------------------------------");
2600 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2602 _("Add new domain..."),
2603 SIPE_BUDDY_MENU_ADD_NEW_DOMAIN
,
2609 struct sipe_backend_buddy_menu
*sipe_ocs2007_access_control_menu(struct sipe_core_private
*sipe_private
,
2610 const gchar
*buddy_name
)
2612 struct sipe_backend_buddy_menu
*menu
= sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC
);
2616 * Workaround for missing libpurple API to release resources allocated
2617 * during blist_node_menu() callback. See also:
2619 * <http://developer.pidgin.im/ticket/12597>
2621 * We remember all memory blocks in a list and deallocate them when
2623 * - the next time we enter the callback, or
2624 * - the account is disconnected
2626 * That means that after the buddy menu has been closed we have unused
2627 * resources but at least we don't leak them anymore...
2629 sipe_core_buddy_menu_free(SIPE_CORE_PUBLIC
);
2631 label
= g_strdup_printf(INDENT_FMT
, _("Online help..."));
2632 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2635 SIPE_BUDDY_MENU_ACCESS_LEVEL_HELP
,
2639 label
= g_strdup_printf(INDENT_FMT
, _("Access groups"));
2640 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2643 access_groups_menu(sipe_private
));
2646 menu
= access_levels_menu(sipe_private
,
2649 sipe_get_no_sip_uri(buddy_name
),