6 * Copyright (C) 2011-2018 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"
47 #include "sipe-appshare.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_status_token_to_activity(activity
);
116 if (type
!= SIPE_ACTIVITY_IN_PRES
) {
117 type
= SIPE_ACTIVITY_DND
;
119 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY
) {
120 type
= SIPE_ACTIVITY_BRB
;
121 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE
) {
122 type
= SIPE_ACTIVITY_AWAY
;
124 type
= SIPE_ACTIVITY_OFFLINE
;
127 return sipe_status_activity_to_token(type
);
130 const gchar
*sipe_ocs2007_legacy_activity_description(guint availability
)
132 if ((availability
>= SIPE_OCS2007_LEGACY_AVAILIBILITY_AVAILABLE_IDLE
) &&
133 (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY
)) {
134 return(sipe_core_activity_description(SIPE_ACTIVITY_INACTIVE
));
135 } else if ((availability
>= SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSYIDLE
) &&
136 (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_DND
)) {
137 return(sipe_core_activity_description(SIPE_ACTIVITY_BUSYIDLE
));
144 * @param sipe_status_id (in)
145 * @param activity_token (out) [only sipe-ocs2005.c/send_presence_soap()
146 * requests this token]
148 #define SIPE_OCS2007_AVAILABILITY_UNKNOWN 0
149 #define SIPE_OCS2007_AVAILABILITY_ONLINE 3500
150 #define SIPE_OCS2007_AVAILABILITY_BUSY 6500
151 #define SIPE_OCS2007_AVAILABILITY_DND 9500 /* do not disturb */
152 #define SIPE_OCS2007_AVAILABILITY_BRB 12500 /* be right back */
153 #define SIPE_OCS2007_AVAILABILITY_AWAY 15500
154 #define SIPE_OCS2007_AVAILABILITY_OFFLINE 18500
155 guint
sipe_ocs2007_availability_from_status(const gchar
*sipe_status_id
,
156 const gchar
**activity_token
)
161 if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_AWAY
))) {
162 availability
= SIPE_OCS2007_AVAILABILITY_AWAY
;
163 activity
= SIPE_ACTIVITY_AWAY
;
164 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_BRB
))) {
165 availability
= SIPE_OCS2007_AVAILABILITY_BRB
;
166 activity
= SIPE_ACTIVITY_BRB
;
167 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_DND
))) {
168 availability
= SIPE_OCS2007_AVAILABILITY_DND
;
169 activity
= SIPE_ACTIVITY_DND
;
170 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_BUSY
))) {
171 availability
= SIPE_OCS2007_AVAILABILITY_BUSY
;
172 activity
= SIPE_ACTIVITY_BUSY
;
173 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_AVAILABLE
))) {
174 availability
= SIPE_OCS2007_AVAILABILITY_ONLINE
;
175 activity
= SIPE_ACTIVITY_ONLINE
;
176 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_UNSET
))) {
177 availability
= SIPE_OCS2007_AVAILABILITY_UNKNOWN
;
178 activity
= SIPE_ACTIVITY_UNSET
;
180 /* Offline or invisible */
181 availability
= SIPE_OCS2007_AVAILABILITY_OFFLINE
;
182 activity
= SIPE_ACTIVITY_OFFLINE
;
185 if (activity_token
) {
186 *activity_token
= sipe_status_activity_to_token(activity
);
189 return(availability
);
192 gboolean
sipe_ocs2007_status_is_busy(const gchar
*status_id
)
194 return(SIPE_OCS2007_AVAILABILITY_BUSY
>=
195 sipe_ocs2007_availability_from_status(status_id
, NULL
));
199 gboolean
sipe_ocs2007_availability_is_away(guint availability
)
201 return(availability
>= SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY
);
204 static void send_presence_publish(struct sipe_core_private
*sipe_private
,
205 const char *publications
);
207 static void free_publication(struct sipe_publication
*publication
)
209 g_free(publication
->category
);
210 g_free(publication
->cal_event_hash
);
211 g_free(publication
->note
);
213 g_free(publication
->working_hours_xml_str
);
214 g_free(publication
->fb_start_str
);
215 g_free(publication
->free_busy_base64
);
220 struct hash_table_delete_payload
{
221 GHashTable
*hash_table
;
225 static void sipe_remove_category_container_publications_cb(const gchar
*name
,
226 struct sipe_publication
*publication
,
227 struct hash_table_delete_payload
*payload
)
229 if (publication
->container
== payload
->container
) {
230 g_hash_table_remove(payload
->hash_table
, name
);
234 static void sipe_remove_category_container_publications(GHashTable
*our_publications
,
235 const gchar
*category
,
238 struct hash_table_delete_payload payload
;
239 payload
.hash_table
= g_hash_table_lookup(our_publications
, category
);
241 if (!payload
.hash_table
) return;
243 payload
.container
= container
;
244 g_hash_table_foreach(payload
.hash_table
,
245 (GHFunc
)sipe_remove_category_container_publications_cb
,
249 /** MS-PRES container */
250 struct sipe_container
{
256 /** MS-PRES container member */
257 struct sipe_container_member
{
258 /** user, domain, sameEnterprise, federated, publicCloud; everyone */
263 static const guint containers
[] = {32000, 400, 300, 200, 100};
264 #define CONTAINERS_LEN (sizeof(containers) / sizeof(guint))
266 static void free_container_member(struct sipe_container_member
*member
)
270 g_free(member
->type
);
271 g_free(member
->value
);
275 static void sipe_ocs2007_free_container(struct sipe_container
*container
)
279 if (!container
) return;
281 entry
= container
->members
;
283 void *data
= entry
->data
;
284 entry
= g_slist_remove(entry
, data
);
285 free_container_member((struct sipe_container_member
*)data
);
290 void sipe_core_buddy_menu_free(struct sipe_core_public
*sipe_public
)
292 struct sipe_core_private
*sipe_private
= SIPE_CORE_PRIVATE
;
293 sipe_utils_slist_free_full(sipe_private
->blist_menu_containers
,
294 (GDestroyNotify
) sipe_ocs2007_free_container
);
295 sipe_private
->blist_menu_containers
= NULL
;
298 static void blist_menu_remember_container(struct sipe_core_private
*sipe_private
,
299 struct sipe_container
*container
)
301 sipe_private
->blist_menu_containers
= g_slist_prepend(sipe_private
->blist_menu_containers
,
305 static struct sipe_container
*create_container(guint index
,
306 const gchar
*member_type
,
307 const gchar
*member_value
,
310 struct sipe_container
*container
= g_new0(struct sipe_container
, 1);
311 struct sipe_container_member
*member
= g_new0(struct sipe_container_member
, 1);
313 container
->id
= is_group
? (guint
) -1 : containers
[index
];
314 container
->members
= g_slist_append(container
->members
, member
);
315 member
->type
= g_strdup(member_type
);
316 member
->value
= g_strdup(member_value
);
321 void sipe_ocs2007_free(struct sipe_core_private
*sipe_private
)
323 sipe_utils_slist_free_full(sipe_private
->containers
,
324 (GDestroyNotify
) sipe_ocs2007_free_container
);
328 * Finds locally stored MS-PRES container member
330 static struct sipe_container_member
*
331 sipe_find_container_member(struct sipe_container
*container
,
335 struct sipe_container_member
*member
;
338 if (container
== NULL
|| type
== NULL
) {
342 entry
= container
->members
;
344 member
= entry
->data
;
345 if (sipe_strcase_equal(member
->type
, type
) &&
346 sipe_strcase_equal(member
->value
, value
))
356 * Finds locally stored MS-PRES container by id
358 static struct sipe_container
*sipe_find_container(struct sipe_core_private
*sipe_private
,
361 GSList
*entry
= sipe_private
->containers
;
363 struct sipe_container
*container
= entry
->data
;
364 if (id
== container
->id
) {
372 static int sipe_find_member_access_level(struct sipe_core_private
*sipe_private
,
377 const gchar
*value_mod
= value
;
379 if (!type
) return -1;
381 if (sipe_strequal("user", type
)) {
382 value_mod
= sipe_get_no_sip_uri(value
);
385 for (i
= 0; i
< CONTAINERS_LEN
; i
++) {
386 struct sipe_container_member
*member
;
387 struct sipe_container
*container
= sipe_find_container(sipe_private
, containers
[i
]);
388 if (!container
) continue;
390 member
= sipe_find_container_member(container
, type
, value_mod
);
391 if (member
) return containers
[i
];
398 * Returns pointer to domain part in provided Email URL
400 * @param email an email URL. Example: first.last@hq.company.com
401 * @return pointer to domain part of email URL. Coresponding example: hq.company.com
403 * Doesn't allocate memory
405 static const gchar
*sipe_get_domain(const gchar
*email
)
409 if (!email
) return NULL
;
411 tmp
= strstr(email
, "@");
413 if (tmp
&& ((tmp
+1) < (email
+ strlen(email
)))) {
420 /* @TODO: replace with binary search for faster access? */
421 /** source: http://support.microsoft.com/kb/897567 */
422 static const gchar
* const public_domains
[] = {
423 "aol.com", "icq.com", "love.com", "mac.com", "br.live.com",
424 "hotmail.co.il", "hotmail.co.jp", "hotmail.co.th", "hotmail.co.uk",
425 "hotmail.com", "hotmail.com.ar", "hotmail.com.tr", "hotmail.es",
426 "hotmail.de", "hotmail.fr", "hotmail.it", "live.at", "live.be",
427 "live.ca", "live.cl", "live.cn", "live.co.in", "live.co.kr",
428 "live.co.uk", "live.co.za", "live.com", "live.com.ar", "live.com.au",
429 "live.com.co", "live.com.mx", "live.com.my", "live.com.pe",
430 "live.com.ph", "live.com.pk", "live.com.pt", "live.com.sg",
431 "live.com.ve", "live.de", "live.dk", "live.fr", "live.hk", "live.ie",
432 "live.in", "live.it", "live.jp", "live.nl", "live.no", "live.ph",
433 "live.ru", "live.se", "livemail.com.br", "livemail.tw",
434 "messengeruser.com", "msn.com", "passport.com", "sympatico.ca",
435 "tw.live.com", "webtv.net", "windowslive.com", "windowslive.es",
439 static gboolean
sipe_is_public_domain(const gchar
*domain
)
442 while (public_domains
[i
]) {
443 if (sipe_strcase_equal(public_domains
[i
], domain
)) {
459 const gchar
*sipe_ocs2007_access_level_name(guint id
)
462 case 32000: return _("Blocked");
463 case 400: return _("Personal");
464 case 300: return _("Team");
465 case 200: return _("Company");
466 case 100: return _("Public");
471 /** Member type: user, domain, sameEnterprise, federated, publicCloud; everyone */
472 int sipe_ocs2007_find_access_level(struct sipe_core_private
*sipe_private
,
475 gboolean
*is_group_access
)
477 int container_id
= -1;
479 if (sipe_strequal("user", type
)) {
481 const char *no_sip_uri
= sipe_get_no_sip_uri(value
);
483 container_id
= sipe_find_member_access_level(sipe_private
, "user", no_sip_uri
);
484 if (container_id
>= 0) {
485 if (is_group_access
) *is_group_access
= FALSE
;
489 domain
= sipe_get_domain(no_sip_uri
);
490 container_id
= sipe_find_member_access_level(sipe_private
, "domain", domain
);
491 if (container_id
>= 0) {
492 if (is_group_access
) *is_group_access
= TRUE
;
496 container_id
= sipe_find_member_access_level(sipe_private
, "sameEnterprise", NULL
);
497 if ((container_id
>= 0) && sipe_strcase_equal(sipe_private
->public.sip_domain
, domain
)) {
498 if (is_group_access
) *is_group_access
= TRUE
;
502 container_id
= sipe_find_member_access_level(sipe_private
, "publicCloud", NULL
);
503 if ((container_id
>= 0) && sipe_is_public_domain(domain
)) {
504 if (is_group_access
) *is_group_access
= TRUE
;
508 container_id
= sipe_find_member_access_level(sipe_private
, "everyone", NULL
);
509 if ((container_id
>= 0)) {
510 if (is_group_access
) *is_group_access
= TRUE
;
514 container_id
= sipe_find_member_access_level(sipe_private
, type
, value
);
515 if (is_group_access
) *is_group_access
= FALSE
;
521 static GSList
*get_access_domains(struct sipe_core_private
*sipe_private
)
523 struct sipe_container
*container
;
524 struct sipe_container_member
*member
;
529 entry
= sipe_private
->containers
;
531 container
= entry
->data
;
533 entry2
= container
->members
;
535 member
= entry2
->data
;
536 if (sipe_strcase_equal(member
->type
, "domain"))
538 res
= sipe_utils_slist_insert_unique_sorted(res
,
539 g_strdup(member
->value
),
540 (GCompareFunc
)g_ascii_strcasecmp
,
543 entry2
= entry2
->next
;
550 static void sipe_send_container_members_prepare(const guint container_id
,
551 const guint container_version
,
555 char **container_xmls
)
557 gchar
*value_str
= value
? g_strdup_printf(" value=\"%s\"", value
) : g_strdup("");
560 if (!container_xmls
) return;
562 body
= g_strdup_printf(
563 "<container id=\"%d\" version=\"%d\"><member action=\"%s\" type=\"%s\"%s/></container>",
571 if ((*container_xmls
) == NULL
) {
572 *container_xmls
= body
;
574 char *tmp
= *container_xmls
;
576 *container_xmls
= g_strconcat(*container_xmls
, body
, NULL
);
582 static void sipe_send_set_container_members(struct sipe_core_private
*sipe_private
,
583 char *container_xmls
)
590 if (!container_xmls
) return;
592 self
= sip_uri_self(sipe_private
);
593 body
= g_strdup_printf(
594 "<setContainerMembers xmlns=\"http://schemas.microsoft.com/2006/09/sip/container-management\">"
596 "</setContainerMembers>",
599 contact
= get_contact(sipe_private
);
600 hdr
= g_strdup_printf("Contact: %s\r\n"
601 "Content-Type: application/msrtc-setcontainermembers+xml\r\n", contact
);
604 sip_transport_service(sipe_private
,
616 * @param container_id a new access level. If -1 then current access level
617 * is just removed (I.e. the member is removed from all containers).
618 * @param type a type of member. E.g. "user", "sameEnterprise", etc.
619 * @param value a value for member. E.g. SIP URI for "user" member type.
621 void sipe_ocs2007_change_access_level(struct sipe_core_private
*sipe_private
,
622 const int container_id
,
627 int current_container_id
= -1;
628 char *container_xmls
= NULL
;
630 /* for each container: find/delete */
631 for (i
= 0; i
< CONTAINERS_LEN
; i
++) {
632 struct sipe_container_member
*member
;
633 struct sipe_container
*container
= sipe_find_container(sipe_private
, containers
[i
]);
635 if (!container
) continue;
637 member
= sipe_find_container_member(container
, type
, value
);
639 current_container_id
= containers
[i
];
640 /* delete/publish current access level */
641 if (container_id
< 0 || container_id
!= current_container_id
) {
642 sipe_send_container_members_prepare(current_container_id
, container
->version
, "remove", type
, value
, &container_xmls
);
643 /* remove member from our cache, to be able to recalculate AL below */
644 container
->members
= g_slist_remove(container
->members
, member
);
649 /* recalculate AL below */
650 current_container_id
= sipe_ocs2007_find_access_level(sipe_private
, type
, value
, NULL
);
652 /* assign/publish new access level */
653 if (container_id
!= current_container_id
&& container_id
>= 0) {
654 struct sipe_container
*container
= sipe_find_container(sipe_private
, container_id
);
655 guint version
= container
? container
->version
: 0;
657 sipe_send_container_members_prepare(container_id
, version
, "add", type
, value
, &container_xmls
);
660 if (container_xmls
) {
661 sipe_send_set_container_members(sipe_private
, container_xmls
);
663 g_free(container_xmls
);
666 void sipe_core_change_access_level_from_container(struct sipe_core_public
*sipe_public
,
669 struct sipe_container
*container
= parameter
;
670 struct sipe_container_member
*member
;
672 if (!container
|| !container
->members
) return;
674 member
= ((struct sipe_container_member
*)container
->members
->data
);
676 if (!member
->type
) return;
678 SIPE_DEBUG_INFO("sipe_ocs2007_change_access_level_from_container: container->id=%d, member->type=%s, member->value=%s",
679 container
->id
, member
->type
, member
->value
? member
->value
: "");
681 sipe_ocs2007_change_access_level(SIPE_CORE_PRIVATE
,
688 void sipe_core_change_access_level_for_domain(struct sipe_core_public
*sipe_public
,
692 /* move Blocked first */
693 guint i
= (index
== 4) ? 0 : index
+ 1;
694 guint container_id
= containers
[i
];
696 SIPE_DEBUG_INFO("sipe_core_change_access_level_from_id: domain=%s, container_id=(%d)%d",
697 domain
? domain
: "", index
, container_id
);
699 sipe_ocs2007_change_access_level(SIPE_CORE_PRIVATE
,
706 * Schedules process of self status publish
707 * based on own calendar information.
708 * Should be scheduled to the beginning of every
709 * 15 min interval, like:
710 * 13:00, 13:15, 13:30, 13:45, etc.
713 static void schedule_publish_update(struct sipe_core_private
*sipe_private
,
714 time_t calculate_from
)
717 /** start of the beginning of closest 5 min interval. */
718 time_t next_start
= ((time_t)((int)((int)calculate_from
)/interval
+ 1)*interval
);
720 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: calculate_from time: %s",
721 sipe_utils_time_to_debug_str(localtime(&calculate_from
)));
722 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: next start time : %s",
723 sipe_utils_time_to_debug_str(localtime(&next_start
)));
725 sipe_schedule_seconds(sipe_private
,
726 "<+2007-cal-status>",
728 next_start
- time(NULL
),
729 sipe_ocs2007_presence_publish
,
734 * An availability XML entry for SIPE_PUB_XML_STATE_CALENDAR
735 * @param availability (%d) Ex.: 6500
737 #define SIPE_PUB_XML_STATE_CALENDAR_AVAIL \
738 "<availability>%d</availability>"
740 * An activity XML entry for SIPE_PUB_XML_STATE_CALENDAR
741 * @param token (%s) Ex.: in-a-meeting
742 * @param minAvailability_attr (%s) Ex.: minAvailability="6500"
743 * @param maxAvailability_attr (%s) Ex.: maxAvailability="8999" or none
745 #define SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY \
746 "<activity token=\"%s\" %s %s></activity>"
748 * Publishes 'calendarState' category.
749 * @param instance (%u) Ex.: 1339299275
750 * @param version (%u) Ex.: 1
751 * @param uri (%s) Ex.: john@contoso.com
752 * @param start_time_str (%s) Ex.: 2008-01-11T19:00:00Z
753 * @param availability (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_AVAIL
754 * @param activity (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
755 * @param meeting_subject (%s) Ex.: Customer Meeting
756 * @param meeting_location (%s) Ex.: Conf Room 100
758 * @param instance (%u) Ex.: 1339299275
759 * @param version (%u) Ex.: 1
760 * @param uri (%s) Ex.: john@contoso.com
761 * @param start_time_str (%s) Ex.: 2008-01-11T19:00:00Z
762 * @param availability (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_AVAIL
763 * @param activity (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
764 * @param meeting_subject (%s) Ex.: Customer Meeting
765 * @param meeting_location (%s) Ex.: Conf Room 100
767 #define SIPE_PUB_XML_STATE_CALENDAR \
768 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
769 "<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\">"\
772 "<endpointLocation/>"\
773 "<meetingSubject>%s</meetingSubject>"\
774 "<meetingLocation>%s</meetingLocation>"\
777 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
778 "<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\">"\
781 "<endpointLocation/>"\
782 "<meetingSubject>%s</meetingSubject>"\
783 "<meetingLocation>%s</meetingLocation>"\
787 * Publishes to clear 'calendarState' and 'phoneState' category
788 * @param instance (%u) Ex.: 1251210982
789 * @param version (%u) Ex.: 1
791 #define SIPE_PUB_XML_STATE_CALENDAR_PHONE_CLEAR \
792 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"\
793 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"
796 * Publishes to clear any category
797 * @param category_name (%s) Ex.: state
798 * @param instance (%u) Ex.: 536870912
799 * @param container (%u) Ex.: 3
800 * @param version (%u) Ex.: 1
801 * @param expireType (%s) Ex.: static
803 #define SIPE_PUB_XML_PUBLICATION_CLEAR \
804 "<publication categoryName=\"%s\" instance=\"%u\" container=\"%u\" version=\"%u\" expireType=\"%s\" expires=\"0\"/>"
807 * Publishes 'note' category.
808 * @param instance (%u) Ex.: 2135971629; 0 for personal
809 * @param container (%u) Ex.: 200
810 * @param version (%u) Ex.: 2
811 * @param type (%s) Ex.: personal or OOF
812 * @param startTime_attr (%s) Ex.: startTime="2008-01-11T19:00:00Z"
813 * @param endTime_attr (%s) Ex.: endTime="2008-01-15T19:00:00Z"
814 * @param body (%s) Ex.: In the office
816 #define SIPE_PUB_XML_NOTE \
817 "<publication categoryName=\"note\" instance=\"%u\" container=\"%u\" version=\"%d\" expireType=\"static\">"\
818 "<note xmlns=\"http://schemas.microsoft.com/2006/09/sip/note\">"\
819 "<body type=\"%s\" uri=\"\"%s%s>%s</body>"\
823 * Publishes 'phoneState' category.
824 * @param instance (%u) Ex.: 1339299275
825 * @param version (%u) Ex.: 1
826 * @param availability (%u) Ex.: 6500
827 * @param token (%s) Ex.: on-the-phone
828 * @param minAvailability (%u) generally same as availability
830 * @param instance (%u) Ex.: 1339299275
831 * @param version (%u) Ex.: 1
832 * @param availability (%u) Ex.: 6500
833 * @param token (%s) Ex.: on-the-phone
834 * @param minAvailability (%u) generally same as availability
836 #define SIPE_PUB_XML_STATE_PHONE \
837 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
838 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"phoneState\">"\
839 "<availability>%u</availability>"\
840 "<activity token=\"%s\" minAvailability=\"%u\" maxAvailability=\"%u\"/>"\
843 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
844 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"phoneState\">"\
845 "<availability>%u</availability>"\
846 "<activity token=\"%s\" minAvailability=\"%u\" maxAvailability=\"%u\"/>"\
851 * Only Busy and OOF calendar event are published.
852 * Different instances are used for that.
854 * Must be g_free'd after use.
856 static gchar
*sipe_publish_get_category_state_calendar(struct sipe_core_private
*sipe_private
,
857 struct sipe_cal_event
*event
,
861 gchar
*start_time_str
;
862 int availability
= 0;
865 guint instance
= (cal_satus
== SIPE_CAL_OOF
) ?
866 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR_OOF
) :
867 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR
);
869 /* key is <category><instance><container> */
870 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
871 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
872 gpointer state
= g_hash_table_lookup(sipe_private
->our_publications
, "state");
873 struct sipe_publication
*publication_2
= state
? g_hash_table_lookup(state
, key_2
) : NULL
;
874 struct sipe_publication
*publication_3
= state
? g_hash_table_lookup(state
, key_3
) : NULL
;
879 if (!publication_3
&& !event
) { /* was nothing, have nothing, exiting */
880 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
881 "Exiting as no publication and no event for cal_satus:%d", cal_satus
);
887 (publication_3
->availability
== availability
) &&
888 sipe_strequal(publication_3
->cal_event_hash
, (tmp
= sipe_cal_event_hash(event
))))
891 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
892 "cal state has NOT changed for cal_satus:%d. Exiting.", cal_satus
);
893 return NULL
; /* nothing to update */
898 (event
->cal_status
== SIPE_CAL_BUSY
||
899 event
->cal_status
== SIPE_CAL_OOF
))
901 gchar
*availability_xml_str
= NULL
;
902 gchar
*activity_xml_str
= NULL
;
903 gchar
*escaped_subject
= event
->subject
? g_markup_escape_text(event
->subject
, -1) : NULL
;
904 gchar
*escaped_location
= event
->location
? g_markup_escape_text(event
->location
, -1) : NULL
;
906 if (event
->cal_status
== SIPE_CAL_BUSY
) {
907 availability_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_AVAIL
,
908 SIPE_OCS2007_AVAILABILITY_BUSY
);
911 if (event
->cal_status
== SIPE_CAL_BUSY
&& event
->is_meeting
) {
912 activity_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
,
913 sipe_status_activity_to_token(SIPE_ACTIVITY_IN_MEETING
),
914 "minAvailability=\"6500\"",
915 "maxAvailability=\"8999\"");
916 } else if (event
->cal_status
== SIPE_CAL_OOF
) {
917 activity_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
,
918 sipe_status_activity_to_token(SIPE_ACTIVITY_OOF
),
919 "minAvailability=\"12000\"",
922 start_time_str
= sipe_utils_time_to_str(event
->start_time
);
924 res
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR
,
926 publication_2
? publication_2
->version
: 0,
929 availability_xml_str
? availability_xml_str
: "",
930 activity_xml_str
? activity_xml_str
: "",
931 escaped_subject
? escaped_subject
: "",
932 escaped_location
? escaped_location
: "",
935 publication_3
? publication_3
->version
: 0,
938 availability_xml_str
? availability_xml_str
: "",
939 activity_xml_str
? activity_xml_str
: "",
940 escaped_subject
? escaped_subject
: "",
941 escaped_location
? escaped_location
: ""
943 g_free(escaped_location
);
944 g_free(escaped_subject
);
945 g_free(start_time_str
);
946 g_free(availability_xml_str
);
947 g_free(activity_xml_str
);
950 else /* including !event, SIPE_CAL_FREE, SIPE_CAL_TENTATIVE */
952 res
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_PHONE_CLEAR
,
954 publication_2
? publication_2
->version
: 0,
957 publication_3
? publication_3
->version
: 0
965 * Returns 'note' XML part for publication.
966 * Must be g_free'd after use.
968 * Protocol format for Note is plain text.
970 * @param note a note in Sipe internal HTML format
971 * @param note_type either personal or OOF
973 static gchar
*sipe_publish_get_category_note(struct sipe_core_private
*sipe_private
,
974 const char *note
, /* html */
975 const char *note_type
,
978 gboolean force_publish
)
980 guint instance
= sipe_strequal("OOF", note_type
) ? sipe_get_pub_instance(sipe_private
, SIPE_PUB_NOTE_OOF
) : 0;
981 /* key is <category><instance><container> */
982 gchar
*key_note_200
= g_strdup_printf("<%s><%u><%u>", "note", instance
, 200);
983 gchar
*key_note_300
= g_strdup_printf("<%s><%u><%u>", "note", instance
, 300);
984 gchar
*key_note_400
= g_strdup_printf("<%s><%u><%u>", "note", instance
, 400);
986 gpointer notes
= g_hash_table_lookup(sipe_private
->our_publications
, "note");
987 struct sipe_publication
*publication_note_200
= notes
? g_hash_table_lookup(notes
, key_note_200
) : NULL
;
988 struct sipe_publication
*publication_note_300
= notes
? g_hash_table_lookup(notes
, key_note_300
) : NULL
;
989 struct sipe_publication
*publication_note_400
= notes
? g_hash_table_lookup(notes
, key_note_400
) : NULL
;
991 char *tmp
= note
? sipe_backend_markup_strip_html(note
) : NULL
;
992 char *n1
= tmp
? g_markup_escape_text(tmp
, -1) : NULL
;
993 const char *n2
= publication_note_200
? publication_note_200
->note
: NULL
;
994 char *res
, *tmp1
, *tmp2
, *tmp3
;
995 char *start_time_attr
;
1000 g_free(key_note_200
);
1001 g_free(key_note_300
);
1002 g_free(key_note_400
);
1004 /* we even need to republish empty note */
1005 if (!force_publish
&& sipe_strequal(n1
, n2
))
1007 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_note: note has NOT changed. Exiting.");
1009 return NULL
; /* nothing to update */
1012 start_time_attr
= note_start
? g_strdup_printf(" startTime=\"%s\"", (tmp
= sipe_utils_time_to_str(note_start
))) : NULL
;
1015 end_time_attr
= note_end
? g_strdup_printf(" endTime=\"%s\"", (tmp
= sipe_utils_time_to_str(note_end
))) : NULL
;
1019 tmp1
= g_strdup_printf(SIPE_PUB_XML_NOTE
,
1022 publication_note_200
? publication_note_200
->version
: 0,
1024 start_time_attr
? start_time_attr
: "",
1025 end_time_attr
? end_time_attr
: "",
1028 tmp2
= g_strdup_printf(SIPE_PUB_XML_NOTE
,
1031 publication_note_300
? publication_note_300
->version
: 0,
1033 start_time_attr
? start_time_attr
: "",
1034 end_time_attr
? end_time_attr
: "",
1037 tmp3
= g_strdup_printf(SIPE_PUB_XML_NOTE
,
1040 publication_note_400
? publication_note_400
->version
: 0,
1042 start_time_attr
? start_time_attr
: "",
1043 end_time_attr
? end_time_attr
: "",
1046 tmp1
= g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR
,
1050 publication_note_200
? publication_note_200
->version
: 0,
1052 tmp2
= g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR
,
1056 publication_note_200
? publication_note_200
->version
: 0,
1058 tmp3
= g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR
,
1062 publication_note_200
? publication_note_200
->version
: 0,
1065 res
= g_strconcat(tmp1
, tmp2
, tmp3
, NULL
);
1067 g_free(start_time_attr
);
1068 g_free(end_time_attr
);
1078 * Publishes 'calendarData' category's WorkingHours.
1080 * @param version (%u) Ex.: 1
1081 * @param email (%s) Ex.: alice@cosmo.local
1082 * @param working_hours_xml_str (%s) Ex.: <WorkingHours xmlns=.....
1084 * @param version (%u)
1086 * @param version (%u)
1088 * @param working_hours_xml_str (%s)
1090 * @param version (%u)
1092 * @param working_hours_xml_str (%s)
1094 * @param version (%u)
1096 * @param working_hours_xml_str (%s)
1098 * @param version (%u)
1100 #define SIPE_PUB_XML_WORKING_HOURS \
1101 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"1\" version=\"%d\" expireType=\"static\">"\
1102 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1105 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"100\" version=\"%d\" expireType=\"static\">"\
1106 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1108 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"200\" 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=\"300\" version=\"%d\" expireType=\"static\">"\
1113 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1116 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"400\" version=\"%d\" expireType=\"static\">"\
1117 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1120 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"32000\" version=\"%d\" expireType=\"static\">"\
1121 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1125 * Returns 'calendarData' XML part with WorkingHours for publication.
1126 * Must be g_free'd after use.
1128 static gchar
*sipe_publish_get_category_cal_working_hours(struct sipe_core_private
*sipe_private
)
1130 struct sipe_calendar
* cal
= sipe_private
->calendar
;
1132 /* key is <category><instance><container> */
1133 gchar
*key_cal_1
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1);
1134 gchar
*key_cal_100
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100);
1135 gchar
*key_cal_200
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200);
1136 gchar
*key_cal_300
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300);
1137 gchar
*key_cal_400
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400);
1138 gchar
*key_cal_32000
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000);
1140 gpointer tmp
= g_hash_table_lookup(sipe_private
->our_publications
, "calendarData");
1141 struct sipe_publication
*publication_cal_1
= tmp
? g_hash_table_lookup(tmp
, key_cal_1
) : NULL
;
1142 struct sipe_publication
*publication_cal_100
= tmp
? g_hash_table_lookup(tmp
, key_cal_100
) : NULL
;
1143 struct sipe_publication
*publication_cal_200
= tmp
? g_hash_table_lookup(tmp
, key_cal_200
) : NULL
;
1144 struct sipe_publication
*publication_cal_300
= tmp
? g_hash_table_lookup(tmp
, key_cal_300
) : NULL
;
1145 struct sipe_publication
*publication_cal_400
= tmp
? g_hash_table_lookup(tmp
, key_cal_400
) : NULL
;
1146 struct sipe_publication
*publication_cal_32000
= tmp
? g_hash_table_lookup(tmp
, key_cal_32000
) : NULL
;
1148 const char *n1
= cal
? cal
->working_hours_xml_str
: NULL
;
1149 const char *n2
= publication_cal_300
? publication_cal_300
->working_hours_xml_str
: NULL
;
1152 g_free(key_cal_100
);
1153 g_free(key_cal_200
);
1154 g_free(key_cal_300
);
1155 g_free(key_cal_400
);
1156 g_free(key_cal_32000
);
1158 if (!cal
|| is_empty(cal
->email
) || is_empty(cal
->working_hours_xml_str
)) {
1159 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_working_hours: no data to publish, exiting");
1163 if (sipe_strequal(n1
, n2
))
1165 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_working_hours: WorkingHours has NOT changed. Exiting.");
1166 return NULL
; /* nothing to update */
1169 return g_strdup_printf(SIPE_PUB_XML_WORKING_HOURS
,
1171 publication_cal_1
? publication_cal_1
->version
: 0,
1173 cal
->working_hours_xml_str
,
1175 publication_cal_100
? publication_cal_100
->version
: 0,
1177 publication_cal_200
? publication_cal_200
->version
: 0,
1179 cal
->working_hours_xml_str
,
1181 publication_cal_300
? publication_cal_300
->version
: 0,
1183 cal
->working_hours_xml_str
,
1184 /* 400 - Personal */
1185 publication_cal_400
? publication_cal_400
->version
: 0,
1187 cal
->working_hours_xml_str
,
1188 /* 32000 - Blocked */
1189 publication_cal_32000
? publication_cal_32000
->version
: 0
1194 * Publishes 'calendarData' category's FreeBusy.
1196 * @param instance (%u) Ex.: 1300372959
1197 * @param version (%u) Ex.: 1
1199 * @param instance (%u) Ex.: 1300372959
1200 * @param version (%u) Ex.: 1
1202 * @param instance (%u) Ex.: 1300372959
1203 * @param version (%u) Ex.: 1
1204 * @param email (%s) Ex.: alice@cosmo.local
1205 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1206 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1208 * @param instance (%u) Ex.: 1300372959
1209 * @param version (%u) Ex.: 1
1210 * @param email (%s) Ex.: alice@cosmo.local
1211 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1212 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
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
1223 #define SIPE_PUB_XML_FREE_BUSY \
1224 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"1\" version=\"%d\" expireType=\"endpoint\">"\
1225 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1227 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"100\" version=\"%d\" expireType=\"endpoint\">"\
1228 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1230 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"200\" version=\"%d\" expireType=\"endpoint\">"\
1231 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1232 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1235 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"300\" version=\"%d\" expireType=\"endpoint\">"\
1236 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1237 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1240 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"400\" version=\"%d\" expireType=\"endpoint\">"\
1241 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1242 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1245 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"32000\" version=\"%d\" expireType=\"endpoint\">"\
1246 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1250 * Returns 'calendarData' XML part with FreeBusy for publication.
1251 * Must be g_free'd after use.
1253 static gchar
*sipe_publish_get_category_cal_free_busy(struct sipe_core_private
*sipe_private
)
1255 struct sipe_calendar
* cal
= sipe_private
->calendar
;
1256 guint cal_data_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_CALENDAR_DATA
);
1258 char *free_busy_base64
;
1259 /* const char *st; */
1260 /* const char *fb; */
1263 /* key is <category><instance><container> */
1264 gchar
*key_cal_1
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 1);
1265 gchar
*key_cal_100
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 100);
1266 gchar
*key_cal_200
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 200);
1267 gchar
*key_cal_300
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 300);
1268 gchar
*key_cal_400
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 400);
1269 gchar
*key_cal_32000
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 32000);
1271 gpointer tmp
= g_hash_table_lookup(sipe_private
->our_publications
, "calendarData");
1272 struct sipe_publication
*publication_cal_1
= tmp
? g_hash_table_lookup(tmp
, key_cal_1
) : NULL
;
1273 struct sipe_publication
*publication_cal_100
= tmp
? g_hash_table_lookup(tmp
, key_cal_100
) : NULL
;
1274 struct sipe_publication
*publication_cal_200
= tmp
? g_hash_table_lookup(tmp
, key_cal_200
) : NULL
;
1275 struct sipe_publication
*publication_cal_300
= tmp
? g_hash_table_lookup(tmp
, key_cal_300
) : NULL
;
1276 struct sipe_publication
*publication_cal_400
= tmp
? g_hash_table_lookup(tmp
, key_cal_400
) : NULL
;
1277 struct sipe_publication
*publication_cal_32000
= tmp
? g_hash_table_lookup(tmp
, key_cal_32000
) : NULL
;
1280 g_free(key_cal_100
);
1281 g_free(key_cal_200
);
1282 g_free(key_cal_300
);
1283 g_free(key_cal_400
);
1284 g_free(key_cal_32000
);
1286 if (!cal
|| is_empty(cal
->email
) || !cal
->fb_start
|| is_empty(cal
->free_busy
)) {
1287 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_free_busy: no data to publish, exiting");
1291 fb_start_str
= sipe_utils_time_to_str(cal
->fb_start
);
1292 free_busy_base64
= sipe_cal_get_freebusy_base64(cal
->free_busy
);
1294 /* we will rebuplish the same data to refresh publication time,
1295 * so if data from multiple sources, most recent will be choosen
1297 // st = publication_cal_300 ? publication_cal_300->fb_start_str : NULL;
1298 // fb = publication_cal_300 ? publication_cal_300->free_busy_base64 : NULL;
1300 //if (sipe_strequal(st, fb_start_str) && sipe_strequal(fb, free_busy_base64))
1302 // SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_free_busy: FreeBusy has NOT changed. Exiting.");
1303 // g_free(fb_start_str);
1304 // g_free(free_busy_base64);
1305 // return NULL; /* nothing to update */
1308 res
= g_strdup_printf(SIPE_PUB_XML_FREE_BUSY
,
1311 publication_cal_1
? publication_cal_1
->version
: 0,
1314 publication_cal_100
? publication_cal_100
->version
: 0,
1317 publication_cal_200
? publication_cal_200
->version
: 0,
1323 publication_cal_300
? publication_cal_300
->version
: 0,
1327 /* 400 - Personal */
1329 publication_cal_400
? publication_cal_400
->version
: 0,
1333 /* 32000 - Blocked */
1335 publication_cal_32000
? publication_cal_32000
->version
: 0
1338 g_free(fb_start_str
);
1339 g_free(free_busy_base64
);
1344 #define SIPE_PUB_XML_DEVICE_VV \
1345 "<voice capture=\"true\" render=\"true\" publish=\"false\"/>"\
1346 "<video capture=\"true\" render=\"true\" publish=\"false\"/>"
1348 #define SIPE_PUB_XML_DEVICE_VV
1352 #define SIPE_PUB_XML_DEVICE_APPSHARE \
1353 "<applicationSharing capture=\"true\" render=\"true\" publish=\"false\"/>"\
1354 "<contentPowerPoint capture=\"true\" render=\"true\" publish=\"false\"/>"
1356 #define SIPE_PUB_XML_DEVICE_APPSHARE
1360 * Publishes 'device' category.
1361 * @param instance (%u) Ex.: 1938468728
1362 * @param version (%u) Ex.: 1
1363 * @param endpointId (%s) Ex.: C707E38E-1E10-5413-94D9-ECAC260A0269
1364 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1365 * @param timezone (%s) Ex.: 00:00:00+01:00
1366 * @param machineName (%s) Ex.: BOSTON-OCS07
1368 #define SIPE_PUB_XML_DEVICE \
1369 "<publication categoryName=\"device\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
1370 "<device xmlns=\"http://schemas.microsoft.com/2006/09/sip/device\" endpointId=\"%s\">"\
1371 "<capabilities preferred=\"false\" uri=\"%s\">"\
1372 "<text capture=\"true\" render=\"true\" publish=\"false\"/>"\
1373 "<gifInk capture=\"false\" render=\"true\" publish=\"false\"/>"\
1374 "<isfInk capture=\"false\" render=\"true\" publish=\"false\"/>"\
1375 SIPE_PUB_XML_DEVICE_VV\
1376 SIPE_PUB_XML_DEVICE_APPSHARE\
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 GHashTable
*tmp
= g_hash_table_lookup(sipe_private
->our_publications
, "device");
1396 struct sipe_publication
*publication
= tmp
? g_hash_table_lookup(tmp
, key
) : NULL
;
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 force_publish
,
1470 gboolean is_user_state
)
1472 int availability
= sipe_ocs2007_availability_from_status(sipe_private
->status
, NULL
);
1473 guint instance
= is_user_state
? sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_USER
) :
1474 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_MACHINE
);
1475 /* key is <category><instance><container> */
1476 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
1477 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
1478 gpointer state
= g_hash_table_lookup(sipe_private
->our_publications
, "state");
1479 struct sipe_publication
*publication_2
= state
? g_hash_table_lookup(state
, key_2
) : NULL
;
1480 struct sipe_publication
*publication_3
= state
? g_hash_table_lookup(state
, key_3
) : NULL
;
1485 if (!force_publish
&& 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
,
1505 gboolean force_publish
)
1507 return sipe_publish_get_category_state(sipe_private
, force_publish
, FALSE
);
1511 * Returns 'userState' XML part for publication.
1512 * Must be g_free'd after use.
1514 static gchar
*sipe_publish_get_category_state_user(struct sipe_core_private
*sipe_private
,
1515 gboolean force_publish
)
1517 return sipe_publish_get_category_state(sipe_private
, force_publish
, TRUE
);
1520 static void send_publish_category_initial(struct sipe_core_private
*sipe_private
)
1522 gchar
*pub_device
= sipe_publish_get_category_device(sipe_private
);
1525 gchar
*publications
;
1527 sipe_status_set_activity(sipe_private
,
1528 sipe_backend_status(SIPE_CORE_PUBLIC
));
1530 pub_machine
= sipe_publish_get_category_state_machine(sipe_private
,
1532 pub_user
= sipe_publish_get_category_state_user(sipe_private
, TRUE
);
1534 publications
= g_strdup_printf("%s%s%s",
1536 pub_machine
? pub_machine
: "",
1537 pub_user
? pub_user
: "");
1539 g_free(pub_machine
);
1542 send_presence_publish(sipe_private
, publications
);
1543 g_free(publications
);
1546 static gboolean
process_send_presence_category_publish_response(struct sipe_core_private
*sipe_private
,
1548 struct transaction
*trans
)
1550 const gchar
*contenttype
= sipmsg_find_header(msg
, "Content-Type");
1552 if (msg
->response
== 200 && g_str_has_prefix(contenttype
, "application/vnd-microsoft-roaming-self+xml")) {
1553 sipe_ocs2007_process_roaming_self(sipe_private
, msg
);
1554 } else if (msg
->response
== 409 && g_str_has_prefix(contenttype
, "application/msrtc-fault+xml")) {
1556 const sipe_xml
*node
;
1560 gboolean has_device_publication
= FALSE
;
1562 xml
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
1564 /* test if version mismatch fault */
1565 fault_code
= sipe_xml_data(sipe_xml_child(xml
, "Faultcode"));
1566 if (!sipe_strequal(fault_code
, "Client.BadCall.WrongDelta")) {
1567 SIPE_DEBUG_INFO("process_send_presence_category_publish_response: unsupported fault code:%s returning.", fault_code
);
1574 /* accumulating information about faulty versions */
1575 faults
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
1576 for (node
= sipe_xml_child(xml
, "details/operation");
1578 node
= sipe_xml_twin(node
))
1580 const gchar
*index
= sipe_xml_attribute(node
, "index");
1581 const gchar
*curVersion
= sipe_xml_attribute(node
, "curVersion");
1583 g_hash_table_insert(faults
, g_strdup(index
), g_strdup(curVersion
));
1584 SIPE_DEBUG_INFO("fault added: index:%s curVersion:%s", index
, curVersion
);
1588 /* here we are parsing our own request to figure out what publication
1589 * referenced here only by index went wrong
1591 xml
= sipe_xml_parse(trans
->msg
->body
, trans
->msg
->bodylen
);
1594 for (node
= sipe_xml_child(xml
, "publications/publication"),
1595 index_our
= 1; /* starts with 1 - our first publication */
1597 node
= sipe_xml_twin(node
), index_our
++)
1599 gchar
*idx
= g_strdup_printf("%d", index_our
);
1600 const gchar
*curVersion
= g_hash_table_lookup(faults
, idx
);
1601 const gchar
*categoryName
= sipe_xml_attribute(node
, "categoryName");
1604 if (sipe_strequal("device", categoryName
)) {
1605 has_device_publication
= TRUE
;
1608 if (curVersion
) { /* fault exist on this index */
1609 const gchar
*container
= sipe_xml_attribute(node
, "container");
1610 const gchar
*instance
= sipe_xml_attribute(node
, "instance");
1611 /* key is <category><instance><container> */
1612 gchar
*key
= g_strdup_printf("<%s><%s><%s>", categoryName
, instance
, container
);
1613 GHashTable
*category
= g_hash_table_lookup(sipe_private
->our_publications
, categoryName
);
1616 struct sipe_publication
*publication
=
1617 g_hash_table_lookup(category
, key
);
1619 SIPE_DEBUG_INFO("key is %s", key
);
1622 SIPE_DEBUG_INFO("Updating %s with version %s. Was %d before.",
1623 key
, curVersion
, publication
->version
);
1624 /* updating publication's version to the correct one */
1625 publication
->version
= atoi(curVersion
);
1628 /* We somehow lost this category from our publications... */
1629 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
1630 publication
->category
= g_strdup(categoryName
);
1631 publication
->instance
= atoi(instance
);
1632 publication
->container
= atoi(container
);
1633 publication
->version
= atoi(curVersion
);
1634 category
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
1635 g_free
, (GDestroyNotify
)free_publication
);
1636 g_hash_table_insert(category
, g_strdup(key
), publication
);
1637 g_hash_table_insert(sipe_private
->our_publications
, g_strdup(categoryName
), category
);
1638 SIPE_DEBUG_INFO("added lost category '%s' key '%s'", categoryName
, key
);
1644 g_hash_table_destroy(faults
);
1646 /* rebublishing with right versions */
1647 if (has_device_publication
) {
1648 send_publish_category_initial(sipe_private
);
1650 sipe_ocs2007_category_publish(sipe_private
, TRUE
);
1657 * Publishes categories.
1658 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1659 * @param publications (%s) XML publications
1661 #define SIPE_SEND_PRESENCE \
1662 "<publish xmlns=\"http://schemas.microsoft.com/2006/09/sip/rich-presence\">"\
1663 "<publications uri=\"%s\">"\
1668 static void send_presence_publish(struct sipe_core_private
*sipe_private
,
1669 const char *publications
)
1676 uri
= sip_uri_self(sipe_private
);
1677 doc
= g_strdup_printf(SIPE_SEND_PRESENCE
,
1681 tmp
= get_contact(sipe_private
);
1682 hdr
= g_strdup_printf("Contact: %s\r\n"
1683 "Content-Type: application/msrtc-category-publish+xml\r\n", tmp
);
1685 sip_transport_service(sipe_private
,
1689 process_send_presence_category_publish_response
);
1698 * Publishes self status
1699 * based on own calendar information.
1701 void sipe_ocs2007_presence_publish(struct sipe_core_private
*sipe_private
,
1702 SIPE_UNUSED_PARAMETER
void *unused
)
1704 struct sipe_calendar
* cal
= sipe_private
->calendar
;
1705 struct sipe_cal_event
* event
= NULL
;
1706 gchar
*pub_cal_working_hours
= NULL
;
1707 gchar
*pub_cal_free_busy
= NULL
;
1708 gchar
*pub_calendar
= NULL
;
1709 gchar
*pub_calendar2
= NULL
;
1710 gchar
*pub_oof_note
= NULL
;
1711 const gchar
*oof_note
;
1712 time_t oof_start
= 0;
1716 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() no calendar data.");
1720 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() started.");
1721 if (cal
->cal_events
) {
1722 event
= sipe_cal_get_event(cal
->cal_events
, time(NULL
));
1726 sipe_cal_event_debug(event
, "publish_calendar_status_self: current event is:\n");
1728 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: current event is NULL");
1733 OOF publish, Busy clean
1735 OOF clean, Busy publish
1737 OOF clean, Busy clean
1739 if (event
&& event
->cal_status
== SIPE_CAL_OOF
) {
1740 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, event
, cal
->email
, SIPE_CAL_OOF
);
1741 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_BUSY
);
1742 } else if (event
&& event
->cal_status
== SIPE_CAL_BUSY
) {
1743 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_OOF
);
1744 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, event
, cal
->email
, SIPE_CAL_BUSY
);
1746 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_OOF
);
1747 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_BUSY
);
1750 oof_note
= sipe_ews_get_oof_note(cal
);
1751 if (sipe_strequal("Scheduled", cal
->oof_state
)) {
1752 oof_start
= cal
->oof_start
;
1753 oof_end
= cal
->oof_end
;
1755 pub_oof_note
= sipe_publish_get_category_note(sipe_private
, oof_note
, "OOF", oof_start
, oof_end
, FALSE
);
1757 pub_cal_working_hours
= sipe_publish_get_category_cal_working_hours(sipe_private
);
1758 pub_cal_free_busy
= sipe_publish_get_category_cal_free_busy(sipe_private
);
1760 if (!pub_cal_working_hours
&& !pub_cal_free_busy
&& !pub_calendar
&& !pub_calendar2
&& !pub_oof_note
) {
1761 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: nothing has changed.");
1763 gchar
*publications
= g_strdup_printf("%s%s%s%s%s",
1764 pub_cal_working_hours
? pub_cal_working_hours
: "",
1765 pub_cal_free_busy
? pub_cal_free_busy
: "",
1766 pub_calendar
? pub_calendar
: "",
1767 pub_calendar2
? pub_calendar2
: "",
1768 pub_oof_note
? pub_oof_note
: "");
1770 send_presence_publish(sipe_private
, publications
);
1771 g_free(publications
);
1774 g_free(pub_cal_working_hours
);
1775 g_free(pub_cal_free_busy
);
1776 g_free(pub_calendar
);
1777 g_free(pub_calendar2
);
1778 g_free(pub_oof_note
);
1780 /* repeat scheduling */
1781 schedule_publish_update(sipe_private
, time(NULL
));
1784 void sipe_ocs2007_category_publish(struct sipe_core_private
*sipe_private
,
1785 gboolean force_publish
)
1787 GString
*publications
= g_string_new("");
1790 if (force_publish
|| sipe_private
->status_set_by_user
) {
1791 tmp
= sipe_publish_get_category_state_user(sipe_private
,
1794 g_string_append(publications
, tmp
);
1799 tmp
= sipe_publish_get_category_state_machine(sipe_private
,
1802 g_string_append(publications
, tmp
);
1806 tmp
= sipe_publish_get_category_note(sipe_private
,
1808 SIPE_CORE_PRIVATE_FLAG_IS(OOF_NOTE
) ? "OOF" : "personal",
1813 g_string_append(publications
, tmp
);
1817 if (publications
->len
)
1818 send_presence_publish(sipe_private
, publications
->str
);
1820 SIPE_DEBUG_INFO_NOFORMAT("sipe_osc2007_category_publish: nothing has changed. Exiting.");
1822 g_string_free(publications
, TRUE
);
1825 void sipe_ocs2007_phone_state_publish(struct sipe_core_private
*sipe_private
)
1827 gchar
*publications
= NULL
;
1828 guint instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_PHONE_VOIP
);
1830 /* key is <category><instance><container> */
1831 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
1832 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
1833 gpointer state
= g_hash_table_lookup(sipe_private
->our_publications
, "state");
1834 struct sipe_publication
*publication_2
= state
? g_hash_table_lookup(state
, key_2
) : NULL
;
1835 struct sipe_publication
*publication_3
= state
? g_hash_table_lookup(state
, key_3
) : NULL
;
1840 if (g_hash_table_size(sipe_private
->media_calls
)) {
1841 guint availability_min
= 0;
1842 guint availability_max
= 8999;
1843 const gchar
*token
= NULL
;
1844 GList
*calls
= g_hash_table_get_values(sipe_private
->media_calls
);
1847 if (sipe_core_media_get_call(SIPE_CORE_PUBLIC
)) {
1848 availability_min
= 6500;
1849 token
= sipe_status_activity_to_token(SIPE_ACTIVITY_ON_PHONE
);
1852 for (i
= calls
; i
; i
= i
->next
) {
1853 if (sipe_media_is_conference_call(i
->data
)) {
1854 availability_min
= 7000;
1855 token
= sipe_status_activity_to_token(SIPE_ACTIVITY_IN_CONF
);
1858 if (sipe_appshare_get_role(i
->data
) == SIPE_APPSHARE_ROLE_PRESENTER
) {
1859 availability_min
= 9000;
1860 availability_max
= 11999;
1861 token
= sipe_status_activity_to_token(SIPE_ACTIVITY_IN_PRES
);
1868 publications
= g_strdup_printf(SIPE_PUB_XML_STATE_PHONE
,
1869 instance
, publication_2
? publication_2
->version
: 0,
1870 availability_min
, token
, availability_min
, availability_max
,
1871 instance
, publication_3
? publication_3
->version
: 0,
1872 availability_min
, token
, availability_min
, availability_max
);
1877 publications
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_PHONE_CLEAR
,
1878 instance
, publication_2
? publication_2
->version
: 0,
1879 instance
, publication_3
? publication_3
->version
: 0);
1883 send_presence_publish(sipe_private
, publications
);
1884 g_free(publications
);
1888 static void sipe_publish_get_cat_state_user_to_clear(SIPE_UNUSED_PARAMETER
const char *name
,
1892 struct sipe_publication
*publication
= value
;
1894 g_string_append_printf( str
,
1895 SIPE_PUB_XML_PUBLICATION_CLEAR
,
1896 publication
->category
,
1897 publication
->instance
,
1898 publication
->container
,
1899 publication
->version
,
1903 void sipe_ocs2007_reset_status(struct sipe_core_private
*sipe_private
)
1906 gchar
*publications
;
1908 if (!sipe_private
->user_state_publications
|| g_hash_table_size(sipe_private
->user_state_publications
) == 0) {
1909 SIPE_DEBUG_INFO_NOFORMAT("sipe_reset_status: no userState publications, exiting.");
1913 str
= g_string_new(NULL
);
1914 g_hash_table_foreach(sipe_private
->user_state_publications
, (GHFunc
)sipe_publish_get_cat_state_user_to_clear
, str
);
1915 publications
= g_string_free(str
, FALSE
);
1917 send_presence_publish(sipe_private
, publications
);
1918 g_free(publications
);
1921 /* key is <category><instance><container> */
1922 static gboolean
sipe_is_our_publication(struct sipe_core_private
*sipe_private
,
1927 /* filling keys for our publications if not yet cached */
1928 if (!sipe_private
->our_publication_keys
) {
1929 guint device_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_DEVICE
);
1930 guint machine_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_MACHINE
);
1931 guint user_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_USER
);
1932 guint calendar_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR
);
1933 guint cal_oof_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR_OOF
);
1934 guint phone_voip_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_PHONE_VOIP
);
1935 guint cal_data_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_CALENDAR_DATA
);
1936 guint note_oof_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_NOTE_OOF
);
1938 SIPE_DEBUG_INFO_NOFORMAT("* Our Publication Instances *");
1939 SIPE_DEBUG_INFO("\tDevice : %u\t0x%08X", device_instance
, device_instance
);
1940 SIPE_DEBUG_INFO("\tMachine State : %u\t0x%08X", machine_instance
, machine_instance
);
1941 SIPE_DEBUG_INFO("\tUser Stare : %u\t0x%08X", user_instance
, user_instance
);
1942 SIPE_DEBUG_INFO("\tCalendar State : %u\t0x%08X", calendar_instance
, calendar_instance
);
1943 SIPE_DEBUG_INFO("\tCalendar OOF State : %u\t0x%08X", cal_oof_instance
, cal_oof_instance
);
1944 SIPE_DEBUG_INFO("\tVOIP Phone State : %u\t0x%08X", phone_voip_instance
, phone_voip_instance
);
1945 SIPE_DEBUG_INFO("\tCalendar FreeBusy : %u\t0x%08X", cal_data_instance
, cal_data_instance
);
1946 SIPE_DEBUG_INFO("\tOOF Note : %u\t0x%08X", note_oof_instance
, note_oof_instance
);
1947 SIPE_DEBUG_INFO("\tNote : %u", 0);
1948 SIPE_DEBUG_INFO("\tCalendar WorkingHours: %u", 0);
1951 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1952 g_strdup_printf("<%s><%u><%u>", "device", device_instance
, 2));
1954 /* state:machineState */
1955 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1956 g_strdup_printf("<%s><%u><%u>", "state", machine_instance
, 2));
1957 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1958 g_strdup_printf("<%s><%u><%u>", "state", machine_instance
, 3));
1960 /* state:userState */
1961 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1962 g_strdup_printf("<%s><%u><%u>", "state", user_instance
, 2));
1963 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1964 g_strdup_printf("<%s><%u><%u>", "state", user_instance
, 3));
1966 /* state:calendarState */
1967 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1968 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance
, 2));
1969 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1970 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance
, 3));
1972 /* state:calendarState OOF */
1973 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1974 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance
, 2));
1975 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1976 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance
, 3));
1978 /* state:phoneState */
1979 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1980 g_strdup_printf("<%s><%u><%u>", "state", phone_voip_instance
, 2));
1981 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1982 g_strdup_printf("<%s><%u><%u>", "state", phone_voip_instance
, 3));
1985 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1986 g_strdup_printf("<%s><%u><%u>", "note", 0, 200));
1987 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1988 g_strdup_printf("<%s><%u><%u>", "note", 0, 300));
1989 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1990 g_strdup_printf("<%s><%u><%u>", "note", 0, 400));
1993 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1994 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 200));
1995 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1996 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 300));
1997 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1998 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 400));
2000 /* calendarData:WorkingHours */
2001 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2002 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1));
2003 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2004 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100));
2005 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2006 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200));
2007 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2008 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300));
2009 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2010 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400));
2011 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2012 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000));
2014 /* calendarData:FreeBusy */
2015 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2016 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 1));
2017 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2018 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 100));
2019 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2020 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 200));
2021 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2022 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 300));
2023 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2024 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 400));
2025 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2026 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 32000));
2028 //SIPE_DEBUG_INFO("sipe_is_our_publication: sipe_private->our_publication_keys length=%d",
2029 // sipe_private->our_publication_keys ? (int) g_slist_length(sipe_private->our_publication_keys) : -1);
2032 //SIPE_DEBUG_INFO("sipe_is_our_publication: key=%s", key);
2034 entry
= sipe_private
->our_publication_keys
;
2036 //SIPE_DEBUG_INFO(" sipe_is_our_publication: entry->data=%s", entry->data);
2037 if (sipe_strequal(entry
->data
, key
)) {
2040 entry
= entry
->next
;
2045 static void sipe_refresh_blocked_status_cb(char *buddy_name
,
2046 SIPE_UNUSED_PARAMETER
struct sipe_buddy
*buddy
,
2047 struct sipe_core_private
*sipe_private
)
2049 int container_id
= sipe_ocs2007_find_access_level(sipe_private
, "user", buddy_name
, NULL
);
2050 gboolean blocked
= (container_id
== 32000);
2051 gboolean blocked_in_blist
= sipe_backend_buddy_is_blocked(SIPE_CORE_PUBLIC
, buddy_name
);
2053 /* SIPE_DEBUG_INFO("sipe_refresh_blocked_status_cb: buddy_name=%s, blocked=%s, blocked_in_blist=%s",
2054 buddy_name, blocked ? "T" : "F", blocked_in_blist ? "T" : "F"); */
2056 if (blocked
!= blocked_in_blist
) {
2057 sipe_backend_buddy_set_blocked_status(SIPE_CORE_PUBLIC
, buddy_name
, blocked
);
2061 static void sipe_refresh_blocked_status(struct sipe_core_private
*sipe_private
)
2063 sipe_buddy_foreach(sipe_private
,
2064 (GHFunc
) sipe_refresh_blocked_status_cb
,
2069 * When we receive some self (BE) NOTIFY with a new subscriber
2070 * we sends a setSubscribers request to him [SIP-PRES] 4.8
2073 void sipe_ocs2007_process_roaming_self(struct sipe_core_private
*sipe_private
,
2079 const sipe_xml
*node
;
2080 const sipe_xml
*node2
;
2081 char *display_name
= NULL
;
2083 GSList
*category_names
= NULL
;
2084 int aggreg_avail
= 0;
2085 gchar
*activity_token
= NULL
;
2086 gboolean do_update_status
= FALSE
;
2087 gboolean has_note_cleaned
= FALSE
;
2088 GHashTable
*devices
;
2090 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self");
2092 xml
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
2095 contact
= get_contact(sipe_private
);
2096 to
= sip_uri_self(sipe_private
);
2099 /* set list of categories participating in this XML */
2100 for (node
= sipe_xml_child(xml
, "categories/category"); node
; node
= sipe_xml_twin(node
)) {
2101 const gchar
*name
= sipe_xml_attribute(node
, "name");
2102 category_names
= sipe_utils_slist_insert_unique_sorted(category_names
,
2104 (GCompareFunc
)strcmp
,
2107 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: category_names length=%d",
2108 category_names
? (int) g_slist_length(category_names
) : -1);
2109 /* drop category information */
2110 if (category_names
) {
2111 GSList
*entry
= category_names
;
2113 GHashTable
*cat_publications
;
2114 const gchar
*category
= entry
->data
;
2115 entry
= entry
->next
;
2116 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: dropping category: %s", category
);
2117 cat_publications
= g_hash_table_lookup(sipe_private
->our_publications
, category
);
2118 if (cat_publications
) {
2119 g_hash_table_remove(sipe_private
->our_publications
, category
);
2120 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: dropped category: %s", category
);
2124 g_slist_free(category_names
);
2126 /* filling our categories reflected in roaming data */
2127 devices
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
2129 for (node
= sipe_xml_child(xml
, "categories/category"); node
; node
= sipe_xml_twin(node
)) {
2131 const gchar
*name
= sipe_xml_attribute(node
, "name");
2132 guint container
= sipe_xml_int_attribute(node
, "container", -1);
2133 guint instance
= sipe_xml_int_attribute(node
, "instance", -1);
2134 guint version
= sipe_xml_int_attribute(node
, "version", 0);
2135 time_t publish_time
= (tmp
= sipe_xml_attribute(node
, "publishTime")) ?
2136 sipe_utils_str_to_time(tmp
) : 0;
2138 GHashTable
*cat_publications
= g_hash_table_lookup(sipe_private
->our_publications
, name
);
2140 /* Ex. clear note: <category name="note"/> */
2141 if (container
== (guint
)-1) {
2142 g_free(sipe_private
->note
);
2143 sipe_private
->note
= NULL
;
2144 do_update_status
= TRUE
;
2148 /* Ex. clear note: <category name="note" container="200"/> */
2149 if (instance
== (guint
)-1) {
2150 if (container
== 200) {
2151 g_free(sipe_private
->note
);
2152 sipe_private
->note
= NULL
;
2153 do_update_status
= TRUE
;
2155 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removing publications for: %s/%u", name
, container
);
2156 sipe_remove_category_container_publications(
2157 sipe_private
->our_publications
, name
, container
);
2161 /* key is <category><instance><container> */
2162 key
= g_strdup_printf("<%s><%u><%u>", name
, instance
, container
);
2163 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: key=%s version=%d", key
, version
);
2165 /* capture all userState publication for later clean up if required */
2166 if (sipe_strequal(name
, "state") && (container
== 2 || container
== 3)) {
2167 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
2169 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "userState")) {
2170 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
2171 publication
->category
= g_strdup(name
);
2172 publication
->instance
= instance
;
2173 publication
->container
= container
;
2174 publication
->version
= version
;
2176 if (!sipe_private
->user_state_publications
) {
2177 sipe_private
->user_state_publications
= g_hash_table_new_full(
2178 g_str_hash
, g_str_equal
,
2179 g_free
, (GDestroyNotify
)free_publication
);
2181 g_hash_table_insert(sipe_private
->user_state_publications
, g_strdup(key
), publication
);
2182 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added to user_state_publications key=%s version=%d",
2187 /* count each client instance only once */
2188 if (sipe_strequal(name
, "device"))
2189 g_hash_table_replace(devices
, g_strdup_printf("%u", instance
), NULL
);
2191 if (sipe_is_our_publication(sipe_private
, key
)) {
2192 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
2194 publication
->category
= g_strdup(name
);
2195 publication
->instance
= instance
;
2196 publication
->container
= container
;
2197 publication
->version
= version
;
2199 /* filling publication->availability */
2200 if (sipe_strequal(name
, "state")) {
2201 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
2202 const sipe_xml
*xn_avail
= sipe_xml_child(xn_state
, "availability");
2205 gchar
*avail_str
= sipe_xml_data(xn_avail
);
2207 publication
->availability
= atoi(avail_str
);
2211 /* for calendarState */
2212 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "calendarState")) {
2213 const sipe_xml
*xn_activity
= sipe_xml_child(xn_state
, "activity");
2214 struct sipe_cal_event
*event
= g_new0(struct sipe_cal_event
, 1);
2216 event
->start_time
= sipe_utils_str_to_time(sipe_xml_attribute(xn_state
, "startTime"));
2218 if (sipe_strequal(sipe_xml_attribute(xn_activity
, "token"),
2219 sipe_status_activity_to_token(SIPE_ACTIVITY_IN_MEETING
)))
2221 event
->is_meeting
= TRUE
;
2224 event
->subject
= sipe_xml_data(sipe_xml_child(xn_state
, "meetingSubject"));
2225 event
->location
= sipe_xml_data(sipe_xml_child(xn_state
, "meetingLocation"));
2227 publication
->cal_event_hash
= sipe_cal_event_hash(event
);
2228 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: hash=%s",
2229 publication
->cal_event_hash
);
2230 sipe_cal_event_free(event
);
2233 /* filling publication->note */
2234 if (sipe_strequal(name
, "note")) {
2235 const sipe_xml
*xn_body
= sipe_xml_child(node
, "note/body");
2237 if (!has_note_cleaned
) {
2238 has_note_cleaned
= TRUE
;
2240 g_free(sipe_private
->note
);
2241 sipe_private
->note
= NULL
;
2242 sipe_private
->note_since
= publish_time
;
2244 do_update_status
= TRUE
;
2247 g_free(publication
->note
);
2248 publication
->note
= NULL
;
2252 publication
->note
= g_markup_escape_text((tmp
= sipe_xml_data(xn_body
)), -1);
2254 if (publish_time
>= sipe_private
->note_since
) {
2255 g_free(sipe_private
->note
);
2256 sipe_private
->note
= g_strdup(publication
->note
);
2257 sipe_private
->note_since
= publish_time
;
2258 if (sipe_strequal(sipe_xml_attribute(xn_body
, "type"), "OOF"))
2259 SIPE_CORE_PRIVATE_FLAG_SET(OOF_NOTE
);
2261 SIPE_CORE_PRIVATE_FLAG_UNSET(OOF_NOTE
);
2263 do_update_status
= TRUE
;
2268 /* filling publication->fb_start_str, free_busy_base64, working_hours_xml_str */
2269 if (sipe_strequal(name
, "calendarData") && (publication
->container
== 300)) {
2270 const sipe_xml
*xn_free_busy
= sipe_xml_child(node
, "calendarData/freeBusy");
2271 const sipe_xml
*xn_working_hours
= sipe_xml_child(node
, "calendarData/WorkingHours");
2273 publication
->fb_start_str
= g_strdup(sipe_xml_attribute(xn_free_busy
, "startTime"));
2274 publication
->free_busy_base64
= sipe_xml_data(xn_free_busy
);
2276 if (xn_working_hours
) {
2277 publication
->working_hours_xml_str
= sipe_xml_stringify(xn_working_hours
);
2281 if (!cat_publications
) {
2282 cat_publications
= g_hash_table_new_full(
2283 g_str_hash
, g_str_equal
,
2284 g_free
, (GDestroyNotify
)free_publication
);
2285 g_hash_table_insert(sipe_private
->our_publications
, g_strdup(name
), cat_publications
);
2286 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added GHashTable cat=%s", name
);
2288 g_hash_table_insert(cat_publications
, g_strdup(key
), publication
);
2289 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added key=%s version=%d", key
, version
);
2293 /* aggregateState (not an our publication) from 2-nd container */
2294 if (sipe_strequal(name
, "state") && container
== 2) {
2295 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
2296 const sipe_xml
*xn_activity
= sipe_xml_child(xn_state
, "activity");
2298 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "aggregateState")) {
2299 const sipe_xml
*xn_avail
= sipe_xml_child(xn_state
, "availability");
2302 gchar
*avail_str
= sipe_xml_data(xn_avail
);
2304 aggreg_avail
= atoi(avail_str
);
2309 do_update_status
= TRUE
;
2313 activity_token
= g_strdup(sipe_xml_attribute(xn_activity
, "token"));
2317 /* userProperties published by server from AD */
2318 if (!sipe_private
->csta
&&
2319 sipe_strequal(name
, "userProperties")) {
2320 const sipe_xml
*line
;
2321 /* line, for Remote Call Control (RCC) or external Lync/Communicator call */
2322 for (line
= sipe_xml_child(node
, "userProperties/lines/line"); line
; line
= sipe_xml_twin(line
)) {
2323 const gchar
*line_type
= sipe_xml_attribute(line
, "lineType");
2324 gchar
*line_uri
= sipe_xml_data(line
);
2329 if (sipe_strequal(line_type
, "Rcc") || sipe_strequal(line_type
, "Dual")) {
2330 const gchar
*line_server
= sipe_xml_attribute(line
, "lineServer");
2332 gchar
*tmp
= g_strstrip(line_uri
);
2333 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: line_uri=%s server=%s",
2335 sip_csta_open(sipe_private
, tmp
, line_server
);
2339 else if (sipe_strequal(line_type
, "Uc")) {
2341 if (!sipe_private
->uc_line_uri
) {
2342 sipe_private
->uc_line_uri
= g_strdup(g_strstrip(line_uri
));
2344 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self: "
2345 "sipe_private->uc_line_uri is already set.");
2356 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sipe_private->our_publications size=%d",
2357 sipe_private
->our_publications
? (int) g_hash_table_size(sipe_private
->our_publications
) : -1);
2359 /* active clients for user account */
2360 if (g_hash_table_size(devices
) == 0) {
2361 /* updated roaming information without device information - no need to update MPOP flag */
2362 } else if (g_hash_table_size(devices
) > 1) {
2363 SIPE_CORE_PRIVATE_FLAG_SET(MPOP
);
2364 SIPE_LOG_INFO("sipe_ocs2007_process_roaming_self: multiple clients detected (%d)",
2365 g_hash_table_size(devices
));
2367 SIPE_CORE_PRIVATE_FLAG_UNSET(MPOP
);
2368 SIPE_LOG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self: single client detected");
2370 g_hash_table_destroy(devices
);
2373 for (node
= sipe_xml_child(xml
, "containers/container"); node
; node
= sipe_xml_twin(node
)) {
2374 guint id
= sipe_xml_int_attribute(node
, "id", 0);
2375 struct sipe_container
*container
= sipe_find_container(sipe_private
, id
);
2378 sipe_private
->containers
= g_slist_remove(sipe_private
->containers
, container
);
2379 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removed existing container id=%d v%d", container
->id
, container
->version
);
2380 sipe_ocs2007_free_container(container
);
2382 container
= g_new0(struct sipe_container
, 1);
2384 container
->version
= sipe_xml_int_attribute(node
, "version", 0);
2385 sipe_private
->containers
= g_slist_append(sipe_private
->containers
, container
);
2386 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container id=%d v%d", container
->id
, container
->version
);
2388 for (node2
= sipe_xml_child(node
, "member"); node2
; node2
= sipe_xml_twin(node2
)) {
2389 struct sipe_container_member
*member
= g_new0(struct sipe_container_member
, 1);
2390 member
->type
= g_strdup(sipe_xml_attribute(node2
, "type"));
2391 member
->value
= g_strdup(sipe_xml_attribute(node2
, "value"));
2392 container
->members
= g_slist_append(container
->members
, member
);
2393 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container member type=%s value=%s",
2394 member
->type
, member
->value
? member
->value
: "");
2398 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: access_level_set=%s",
2399 SIPE_CORE_PRIVATE_FLAG_IS(ACCESS_LEVEL_SET
) ? "TRUE" : "FALSE");
2400 if (!SIPE_CORE_PRIVATE_FLAG_IS(ACCESS_LEVEL_SET
) && sipe_xml_child(xml
, "containers")) {
2401 char *container_xmls
= NULL
;
2402 int sameEnterpriseAL
= sipe_ocs2007_find_access_level(sipe_private
, "sameEnterprise", NULL
, NULL
);
2403 int federatedAL
= sipe_ocs2007_find_access_level(sipe_private
, "federated", NULL
, NULL
);
2405 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sameEnterpriseAL=%d", sameEnterpriseAL
);
2406 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: federatedAL=%d", federatedAL
);
2407 /* initial set-up to let counterparties see your status */
2408 if (sameEnterpriseAL
< 0) {
2409 struct sipe_container
*container
= sipe_find_container(sipe_private
, 200);
2410 guint version
= container
? container
->version
: 0;
2411 sipe_send_container_members_prepare(200, version
, "add", "sameEnterprise", NULL
, &container_xmls
);
2413 if (federatedAL
< 0) {
2414 struct sipe_container
*container
= sipe_find_container(sipe_private
, 100);
2415 guint version
= container
? container
->version
: 0;
2416 sipe_send_container_members_prepare(100, version
, "add", "federated", NULL
, &container_xmls
);
2418 SIPE_CORE_PRIVATE_FLAG_SET(ACCESS_LEVEL_SET
);
2420 if (container_xmls
) {
2421 sipe_send_set_container_members(sipe_private
, container_xmls
);
2423 g_free(container_xmls
);
2426 /* Refresh contacts' blocked status */
2427 sipe_refresh_blocked_status(sipe_private
);
2430 for (node
= sipe_xml_child(xml
, "subscribers/subscriber"); node
; node
= sipe_xml_twin(node
)) {
2432 const char *acknowledged
;
2436 user
= sipe_xml_attribute(node
, "user"); /* without 'sip:' prefix */
2437 if (!user
) continue;
2438 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user %s", user
);
2439 display_name
= g_strdup(sipe_xml_attribute(node
, "displayName"));
2440 uri
= sip_uri_from_name(user
);
2442 sipe_buddy_update_property(sipe_private
, uri
, SIPE_BUDDY_INFO_DISPLAY_NAME
, display_name
);
2443 sipe_backend_buddy_refresh_properties(SIPE_CORE_PUBLIC
, uri
);
2445 acknowledged
= sipe_xml_attribute(node
, "acknowledged");
2446 if(sipe_strcase_equal(acknowledged
,"false")){
2447 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user added you %s", user
);
2448 if (!sipe_backend_buddy_find(SIPE_CORE_PUBLIC
, uri
, NULL
)) {
2449 sipe_backend_buddy_request_add(SIPE_CORE_PUBLIC
, uri
, display_name
);
2452 hdr
= g_strdup_printf(
2454 "Content-Type: application/msrtc-presence-setsubscriber+xml\r\n", contact
);
2456 body
= g_strdup_printf(
2457 "<setSubscribers xmlns=\"http://schemas.microsoft.com/2006/09/sip/presence-subscribers\">"
2458 "<subscriber user=\"%s\" acknowledged=\"true\"/>"
2459 "</setSubscribers>", user
);
2461 sip_transport_service(sipe_private
,
2469 g_free(display_name
);
2476 /* Publish initial state if not yet.
2477 * Assuming this happens on initial responce to subscription to roaming-self
2478 * so we've already updated our roaming data in full.
2481 if (!SIPE_CORE_PRIVATE_FLAG_IS(INITIAL_PUBLISH
)) {
2482 send_publish_category_initial(sipe_private
);
2483 SIPE_CORE_PRIVATE_FLAG_SET(INITIAL_PUBLISH
);
2485 sipe_cal_delayed_calendar_update(sipe_private
);
2486 do_update_status
= FALSE
;
2487 } else if (aggreg_avail
) {
2490 (aggreg_avail
< SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE
)) {
2492 sipe_status_set_token(sipe_private
,
2493 sipe_ocs2007_status_from_legacy_availability(aggreg_avail
, activity_token
));
2495 /* do not let offline status switch us off */
2496 sipe_status_set_activity(sipe_private
,
2497 SIPE_ACTIVITY_INVISIBLE
);
2501 if (do_update_status
) {
2502 sipe_status_and_note(sipe_private
, NULL
);
2506 g_free(activity_token
);
2510 * for Access levels menu
2512 #define INDENT_FMT " %s"
2515 * Member is indirectly belong to access level container.
2516 * For example 'sameEnterprise' is in the container and user
2517 * belongs to that same enterprise.
2519 #define INDENT_MARKED_INHERITED_FMT "= %s"
2521 static struct sipe_backend_buddy_menu
*access_levels_menu(struct sipe_core_private
*sipe_private
,
2522 struct sipe_backend_buddy_menu
*menu
,
2523 const gchar
*member_type
,
2524 const gchar
*member_value
,
2525 const gboolean extra_menu
)
2528 gboolean is_group_access
= FALSE
;
2532 menu
= sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC
);
2534 container_id
= sipe_ocs2007_find_access_level(sipe_private
,
2539 for (i
= 1; i
<= CONTAINERS_LEN
; i
++) {
2541 * Blocked should remain in the first place
2542 * in the containers[] array.
2544 unsigned int j
= (i
== CONTAINERS_LEN
) ? 0 : i
;
2545 int container_j
= containers
[j
];
2546 const gchar
*acc_level_name
= sipe_ocs2007_access_level_name(container_j
);
2547 struct sipe_container
*container
= create_container(j
,
2553 /* libpurple memory leak workaround */
2554 blist_menu_remember_container(sipe_private
, container
);
2556 /* current container/access level */
2557 if (container_j
== container_id
) {
2558 label
= is_group_access
?
2559 g_strdup_printf(INDENT_MARKED_INHERITED_FMT
, acc_level_name
) :
2560 g_strdup_printf(SIPE_OCS2007_INDENT_MARKED_FMT
, acc_level_name
);
2562 label
= g_strdup_printf(INDENT_FMT
, acc_level_name
);
2565 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2568 SIPE_BUDDY_MENU_CHANGE_ACCESS_LEVEL
,
2573 if (extra_menu
&& (container_id
>= 0) && !is_group_access
) {
2574 struct sipe_container
*container
= create_container(0,
2581 menu
= sipe_backend_buddy_menu_separator(SIPE_CORE_PUBLIC
,
2586 /* libpurple memory leak workaround */
2587 blist_menu_remember_container(sipe_private
, container
);
2589 /* Translators: remove (clear) previously assigned access level */
2590 label
= g_strdup_printf(INDENT_FMT
, _("Unspecify"));
2591 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2594 SIPE_BUDDY_MENU_CHANGE_ACCESS_LEVEL
,
2602 static struct sipe_backend_buddy_menu
*access_groups_menu(struct sipe_core_private
*sipe_private
)
2604 struct sipe_backend_buddy_menu
*menu
= sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC
);
2605 GSList
*access_domains
, *entry
;
2607 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2609 _("People in my company"),
2610 access_levels_menu(sipe_private
,
2616 /* this is original name, don't edit */
2617 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2619 _("People in domains connected with my company"),
2620 access_levels_menu(sipe_private
,
2626 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2628 _("People in public domains"),
2629 access_levels_menu(sipe_private
,
2635 entry
= access_domains
= get_access_domains(sipe_private
);
2637 gchar
*domain
= entry
->data
;
2638 gchar
*menu_name
= g_strdup_printf(_("People at %s"), domain
);
2640 /* takes over ownership of entry->data (= domain) */
2641 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2644 access_levels_menu(sipe_private
,
2651 entry
= entry
->next
;
2653 g_slist_free(access_domains
);
2656 /* People in domains connected with my company */
2657 menu
= sipe_backend_buddy_menu_separator(SIPE_CORE_PUBLIC
,
2659 "-------------------------------------------");
2661 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2663 _("Add new domain..."),
2664 SIPE_BUDDY_MENU_ADD_NEW_DOMAIN
,
2670 struct sipe_backend_buddy_menu
*sipe_ocs2007_access_control_menu(struct sipe_core_private
*sipe_private
,
2671 const gchar
*buddy_name
)
2673 struct sipe_backend_buddy_menu
*menu
= sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC
);
2677 * Workaround for missing libpurple API to release resources allocated
2678 * during blist_node_menu() callback. See also:
2680 * <http://developer.pidgin.im/ticket/12597>
2682 * We remember all memory blocks in a list and deallocate them when
2684 * - the next time we enter the callback, or
2685 * - the account is disconnected
2687 * That means that after the buddy menu has been closed we have unused
2688 * resources but at least we don't leak them anymore...
2690 sipe_core_buddy_menu_free(SIPE_CORE_PUBLIC
);
2692 label
= g_strdup_printf(INDENT_FMT
, _("Online help..."));
2693 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2696 SIPE_BUDDY_MENU_ACCESS_LEVEL_HELP
,
2700 label
= g_strdup_printf(INDENT_FMT
, _("Access groups"));
2701 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2704 access_groups_menu(sipe_private
));
2707 menu
= access_levels_menu(sipe_private
,
2710 sipe_get_no_sip_uri(buddy_name
),