6 * Copyright (C) 2011-2016 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-media.h"
50 #include "sipe-ocs2007.h"
51 #include "sipe-schedule.h"
52 #include "sipe-status.h"
53 #include "sipe-utils.h"
56 /** MS-PRES publication */
57 struct sipe_publication
{
62 /** for 'state' category */
64 /** for 'state:calendarState' category */
66 /** for 'note' category */
68 /** for 'calendarData' category; 300(Team) container */
69 char *working_hours_xml_str
;
71 char *free_busy_base64
;
75 * 2007-style Activity and Availability.
79 * Conversion of legacyInterop availability ranges and activity tokens into
80 * SIPE activity tokens. The descriptions of availability ranges are defined at:
82 * http://msdn.microsoft.com/en-us/library/lync/dd941370%28v=office.13%29.aspx
84 * The values define the starting point of a range.
86 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_AVAILABLE 3000
87 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_AVAILABLE_IDLE 4500
88 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY 6000
89 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSYIDLE 7500
90 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_DND 9000 /* do not disturb */
91 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_BRB 12000 /* be right back */
92 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY 15000
93 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE 18000
95 const gchar
*sipe_ocs2007_status_from_legacy_availability(guint availability
,
96 const gchar
*activity
)
100 if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_AVAILABLE
) {
101 type
= SIPE_ACTIVITY_OFFLINE
;
102 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_AVAILABLE_IDLE
) {
103 type
= SIPE_ACTIVITY_AVAILABLE
;
104 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY
) {
105 type
= SIPE_ACTIVITY_INACTIVE
;
106 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSYIDLE
) {
107 type
= sipe_status_token_to_activity(activity
);
108 if ((type
!= SIPE_ACTIVITY_ON_PHONE
) &&
109 (type
!= SIPE_ACTIVITY_IN_CONF
))
110 type
= SIPE_ACTIVITY_BUSY
;
111 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_DND
) {
112 type
= SIPE_ACTIVITY_BUSYIDLE
;
113 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_BRB
) {
114 type
= SIPE_ACTIVITY_DND
;
115 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY
) {
116 type
= SIPE_ACTIVITY_BRB
;
117 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE
) {
118 type
= SIPE_ACTIVITY_AWAY
;
120 type
= SIPE_ACTIVITY_OFFLINE
;
123 return sipe_status_activity_to_token(type
);
126 const gchar
*sipe_ocs2007_legacy_activity_description(guint availability
)
128 if ((availability
>= SIPE_OCS2007_LEGACY_AVAILIBILITY_AVAILABLE_IDLE
) &&
129 (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY
)) {
130 return(sipe_core_activity_description(SIPE_ACTIVITY_INACTIVE
));
131 } else if ((availability
>= SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSYIDLE
) &&
132 (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_DND
)) {
133 return(sipe_core_activity_description(SIPE_ACTIVITY_BUSYIDLE
));
140 * @param sipe_status_id (in)
141 * @param activity_token (out) [only sipe-ocs2005.c/send_presence_soap()
142 * requests this token]
144 #define SIPE_OCS2007_AVAILABILITY_UNKNOWN 0
145 #define SIPE_OCS2007_AVAILABILITY_ONLINE 3500
146 #define SIPE_OCS2007_AVAILABILITY_BUSY 6500
147 #define SIPE_OCS2007_AVAILABILITY_DND 9500 /* do not disturb */
148 #define SIPE_OCS2007_AVAILABILITY_BRB 12500 /* be right back */
149 #define SIPE_OCS2007_AVAILABILITY_AWAY 15500
150 #define SIPE_OCS2007_AVAILABILITY_OFFLINE 18500
151 guint
sipe_ocs2007_availability_from_status(const gchar
*sipe_status_id
,
152 const gchar
**activity_token
)
157 if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_AWAY
))) {
158 availability
= SIPE_OCS2007_AVAILABILITY_AWAY
;
159 activity
= SIPE_ACTIVITY_AWAY
;
160 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_BRB
))) {
161 availability
= SIPE_OCS2007_AVAILABILITY_BRB
;
162 activity
= SIPE_ACTIVITY_BRB
;
163 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_DND
))) {
164 availability
= SIPE_OCS2007_AVAILABILITY_DND
;
165 activity
= SIPE_ACTIVITY_DND
;
166 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_BUSY
))) {
167 availability
= SIPE_OCS2007_AVAILABILITY_BUSY
;
168 activity
= SIPE_ACTIVITY_BUSY
;
169 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_AVAILABLE
))) {
170 availability
= SIPE_OCS2007_AVAILABILITY_ONLINE
;
171 activity
= SIPE_ACTIVITY_ONLINE
;
172 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_UNSET
))) {
173 availability
= SIPE_OCS2007_AVAILABILITY_UNKNOWN
;
174 activity
= SIPE_ACTIVITY_UNSET
;
176 /* Offline or invisible */
177 availability
= SIPE_OCS2007_AVAILABILITY_OFFLINE
;
178 activity
= SIPE_ACTIVITY_OFFLINE
;
181 if (activity_token
) {
182 *activity_token
= sipe_status_activity_to_token(activity
);
185 return(availability
);
188 gboolean
sipe_ocs2007_status_is_busy(const gchar
*status_id
)
190 return(SIPE_OCS2007_AVAILABILITY_BUSY
>=
191 sipe_ocs2007_availability_from_status(status_id
, NULL
));
195 gboolean
sipe_ocs2007_availability_is_away(guint availability
)
197 return(availability
>= SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY
);
200 static void send_presence_publish(struct sipe_core_private
*sipe_private
,
201 const char *publications
);
203 static void free_publication(struct sipe_publication
*publication
)
205 g_free(publication
->category
);
206 g_free(publication
->cal_event_hash
);
207 g_free(publication
->note
);
209 g_free(publication
->working_hours_xml_str
);
210 g_free(publication
->fb_start_str
);
211 g_free(publication
->free_busy_base64
);
216 struct hash_table_delete_payload
{
217 GHashTable
*hash_table
;
221 static void sipe_remove_category_container_publications_cb(const gchar
*name
,
222 struct sipe_publication
*publication
,
223 struct hash_table_delete_payload
*payload
)
225 if (publication
->container
== payload
->container
) {
226 g_hash_table_remove(payload
->hash_table
, name
);
230 static void sipe_remove_category_container_publications(GHashTable
*our_publications
,
231 const gchar
*category
,
234 struct hash_table_delete_payload payload
;
235 payload
.hash_table
= g_hash_table_lookup(our_publications
, category
);
237 if (!payload
.hash_table
) return;
239 payload
.container
= container
;
240 g_hash_table_foreach(payload
.hash_table
,
241 (GHFunc
)sipe_remove_category_container_publications_cb
,
245 /** MS-PRES container */
246 struct sipe_container
{
252 /** MS-PRES container member */
253 struct sipe_container_member
{
254 /** user, domain, sameEnterprise, federated, publicCloud; everyone */
259 static const guint containers
[] = {32000, 400, 300, 200, 100};
260 #define CONTAINERS_LEN (sizeof(containers) / sizeof(guint))
262 static void free_container_member(struct sipe_container_member
*member
)
266 g_free(member
->type
);
267 g_free(member
->value
);
271 static void sipe_ocs2007_free_container(struct sipe_container
*container
)
275 if (!container
) return;
277 entry
= container
->members
;
279 void *data
= entry
->data
;
280 entry
= g_slist_remove(entry
, data
);
281 free_container_member((struct sipe_container_member
*)data
);
286 void sipe_core_buddy_menu_free(struct sipe_core_public
*sipe_public
)
288 struct sipe_core_private
*sipe_private
= SIPE_CORE_PRIVATE
;
289 sipe_utils_slist_free_full(sipe_private
->blist_menu_containers
,
290 (GDestroyNotify
) sipe_ocs2007_free_container
);
291 sipe_private
->blist_menu_containers
= NULL
;
294 static void blist_menu_remember_container(struct sipe_core_private
*sipe_private
,
295 struct sipe_container
*container
)
297 sipe_private
->blist_menu_containers
= g_slist_prepend(sipe_private
->blist_menu_containers
,
301 static struct sipe_container
*create_container(guint index
,
302 const gchar
*member_type
,
303 const gchar
*member_value
,
306 struct sipe_container
*container
= g_new0(struct sipe_container
, 1);
307 struct sipe_container_member
*member
= g_new0(struct sipe_container_member
, 1);
309 container
->id
= is_group
? (guint
) -1 : containers
[index
];
310 container
->members
= g_slist_append(container
->members
, member
);
311 member
->type
= g_strdup(member_type
);
312 member
->value
= g_strdup(member_value
);
317 void sipe_ocs2007_free(struct sipe_core_private
*sipe_private
)
319 sipe_utils_slist_free_full(sipe_private
->containers
,
320 (GDestroyNotify
) sipe_ocs2007_free_container
);
324 * Finds locally stored MS-PRES container member
326 static struct sipe_container_member
*
327 sipe_find_container_member(struct sipe_container
*container
,
331 struct sipe_container_member
*member
;
334 if (container
== NULL
|| type
== NULL
) {
338 entry
= container
->members
;
340 member
= entry
->data
;
341 if (sipe_strcase_equal(member
->type
, type
) &&
342 sipe_strcase_equal(member
->value
, value
))
352 * Finds locally stored MS-PRES container by id
354 static struct sipe_container
*sipe_find_container(struct sipe_core_private
*sipe_private
,
357 GSList
*entry
= sipe_private
->containers
;
359 struct sipe_container
*container
= entry
->data
;
360 if (id
== container
->id
) {
368 static int sipe_find_member_access_level(struct sipe_core_private
*sipe_private
,
373 const gchar
*value_mod
= value
;
375 if (!type
) return -1;
377 if (sipe_strequal("user", type
)) {
378 value_mod
= sipe_get_no_sip_uri(value
);
381 for (i
= 0; i
< CONTAINERS_LEN
; i
++) {
382 struct sipe_container_member
*member
;
383 struct sipe_container
*container
= sipe_find_container(sipe_private
, containers
[i
]);
384 if (!container
) continue;
386 member
= sipe_find_container_member(container
, type
, value_mod
);
387 if (member
) return containers
[i
];
394 * Returns pointer to domain part in provided Email URL
396 * @param email an email URL. Example: first.last@hq.company.com
397 * @return pointer to domain part of email URL. Coresponding example: hq.company.com
399 * Doesn't allocate memory
401 static const gchar
*sipe_get_domain(const gchar
*email
)
405 if (!email
) return NULL
;
407 tmp
= strstr(email
, "@");
409 if (tmp
&& ((tmp
+1) < (email
+ strlen(email
)))) {
416 /* @TODO: replace with binary search for faster access? */
417 /** source: http://support.microsoft.com/kb/897567 */
418 static const gchar
* const public_domains
[] = {
419 "aol.com", "icq.com", "love.com", "mac.com", "br.live.com",
420 "hotmail.co.il", "hotmail.co.jp", "hotmail.co.th", "hotmail.co.uk",
421 "hotmail.com", "hotmail.com.ar", "hotmail.com.tr", "hotmail.es",
422 "hotmail.de", "hotmail.fr", "hotmail.it", "live.at", "live.be",
423 "live.ca", "live.cl", "live.cn", "live.co.in", "live.co.kr",
424 "live.co.uk", "live.co.za", "live.com", "live.com.ar", "live.com.au",
425 "live.com.co", "live.com.mx", "live.com.my", "live.com.pe",
426 "live.com.ph", "live.com.pk", "live.com.pt", "live.com.sg",
427 "live.com.ve", "live.de", "live.dk", "live.fr", "live.hk", "live.ie",
428 "live.in", "live.it", "live.jp", "live.nl", "live.no", "live.ph",
429 "live.ru", "live.se", "livemail.com.br", "livemail.tw",
430 "messengeruser.com", "msn.com", "passport.com", "sympatico.ca",
431 "tw.live.com", "webtv.net", "windowslive.com", "windowslive.es",
435 static gboolean
sipe_is_public_domain(const gchar
*domain
)
438 while (public_domains
[i
]) {
439 if (sipe_strcase_equal(public_domains
[i
], domain
)) {
455 const gchar
*sipe_ocs2007_access_level_name(guint id
)
458 case 32000: return _("Blocked");
459 case 400: return _("Personal");
460 case 300: return _("Team");
461 case 200: return _("Company");
462 case 100: return _("Public");
467 /** Member type: user, domain, sameEnterprise, federated, publicCloud; everyone */
468 int sipe_ocs2007_find_access_level(struct sipe_core_private
*sipe_private
,
471 gboolean
*is_group_access
)
473 int container_id
= -1;
475 if (sipe_strequal("user", type
)) {
477 const char *no_sip_uri
= sipe_get_no_sip_uri(value
);
479 container_id
= sipe_find_member_access_level(sipe_private
, "user", no_sip_uri
);
480 if (container_id
>= 0) {
481 if (is_group_access
) *is_group_access
= FALSE
;
485 domain
= sipe_get_domain(no_sip_uri
);
486 container_id
= sipe_find_member_access_level(sipe_private
, "domain", domain
);
487 if (container_id
>= 0) {
488 if (is_group_access
) *is_group_access
= TRUE
;
492 container_id
= sipe_find_member_access_level(sipe_private
, "sameEnterprise", NULL
);
493 if ((container_id
>= 0) && sipe_strcase_equal(sipe_private
->public.sip_domain
, domain
)) {
494 if (is_group_access
) *is_group_access
= TRUE
;
498 container_id
= sipe_find_member_access_level(sipe_private
, "publicCloud", NULL
);
499 if ((container_id
>= 0) && sipe_is_public_domain(domain
)) {
500 if (is_group_access
) *is_group_access
= TRUE
;
504 container_id
= sipe_find_member_access_level(sipe_private
, "everyone", NULL
);
505 if ((container_id
>= 0)) {
506 if (is_group_access
) *is_group_access
= TRUE
;
510 container_id
= sipe_find_member_access_level(sipe_private
, type
, value
);
511 if (is_group_access
) *is_group_access
= FALSE
;
517 static GSList
*get_access_domains(struct sipe_core_private
*sipe_private
)
519 struct sipe_container
*container
;
520 struct sipe_container_member
*member
;
525 entry
= sipe_private
->containers
;
527 container
= entry
->data
;
529 entry2
= container
->members
;
531 member
= entry2
->data
;
532 if (sipe_strcase_equal(member
->type
, "domain"))
534 res
= sipe_utils_slist_insert_unique_sorted(res
,
535 g_strdup(member
->value
),
536 (GCompareFunc
)g_ascii_strcasecmp
,
539 entry2
= entry2
->next
;
546 static void sipe_send_container_members_prepare(const guint container_id
,
547 const guint container_version
,
551 char **container_xmls
)
553 gchar
*value_str
= value
? g_strdup_printf(" value=\"%s\"", value
) : g_strdup("");
556 if (!container_xmls
) return;
558 body
= g_strdup_printf(
559 "<container id=\"%d\" version=\"%d\"><member action=\"%s\" type=\"%s\"%s/></container>",
567 if ((*container_xmls
) == NULL
) {
568 *container_xmls
= body
;
570 char *tmp
= *container_xmls
;
572 *container_xmls
= g_strconcat(*container_xmls
, body
, NULL
);
578 static void sipe_send_set_container_members(struct sipe_core_private
*sipe_private
,
579 char *container_xmls
)
586 if (!container_xmls
) return;
588 self
= sip_uri_self(sipe_private
);
589 body
= g_strdup_printf(
590 "<setContainerMembers xmlns=\"http://schemas.microsoft.com/2006/09/sip/container-management\">"
592 "</setContainerMembers>",
595 contact
= get_contact(sipe_private
);
596 hdr
= g_strdup_printf("Contact: %s\r\n"
597 "Content-Type: application/msrtc-setcontainermembers+xml\r\n", contact
);
600 sip_transport_service(sipe_private
,
612 * @param container_id a new access level. If -1 then current access level
613 * is just removed (I.e. the member is removed from all containers).
614 * @param type a type of member. E.g. "user", "sameEnterprise", etc.
615 * @param value a value for member. E.g. SIP URI for "user" member type.
617 void sipe_ocs2007_change_access_level(struct sipe_core_private
*sipe_private
,
618 const int container_id
,
623 int current_container_id
= -1;
624 char *container_xmls
= NULL
;
626 /* for each container: find/delete */
627 for (i
= 0; i
< CONTAINERS_LEN
; i
++) {
628 struct sipe_container_member
*member
;
629 struct sipe_container
*container
= sipe_find_container(sipe_private
, containers
[i
]);
631 if (!container
) continue;
633 member
= sipe_find_container_member(container
, type
, value
);
635 current_container_id
= containers
[i
];
636 /* delete/publish current access level */
637 if (container_id
< 0 || container_id
!= current_container_id
) {
638 sipe_send_container_members_prepare(current_container_id
, container
->version
, "remove", type
, value
, &container_xmls
);
639 /* remove member from our cache, to be able to recalculate AL below */
640 container
->members
= g_slist_remove(container
->members
, member
);
645 /* recalculate AL below */
646 current_container_id
= sipe_ocs2007_find_access_level(sipe_private
, type
, value
, NULL
);
648 /* assign/publish new access level */
649 if (container_id
!= current_container_id
&& container_id
>= 0) {
650 struct sipe_container
*container
= sipe_find_container(sipe_private
, container_id
);
651 guint version
= container
? container
->version
: 0;
653 sipe_send_container_members_prepare(container_id
, version
, "add", type
, value
, &container_xmls
);
656 if (container_xmls
) {
657 sipe_send_set_container_members(sipe_private
, container_xmls
);
659 g_free(container_xmls
);
662 void sipe_core_change_access_level_from_container(struct sipe_core_public
*sipe_public
,
665 struct sipe_container
*container
= parameter
;
666 struct sipe_container_member
*member
;
668 if (!container
|| !container
->members
) return;
670 member
= ((struct sipe_container_member
*)container
->members
->data
);
672 if (!member
->type
) return;
674 SIPE_DEBUG_INFO("sipe_ocs2007_change_access_level_from_container: container->id=%d, member->type=%s, member->value=%s",
675 container
->id
, member
->type
, member
->value
? member
->value
: "");
677 sipe_ocs2007_change_access_level(SIPE_CORE_PRIVATE
,
684 void sipe_core_change_access_level_for_domain(struct sipe_core_public
*sipe_public
,
688 /* move Blocked first */
689 guint i
= (index
== 4) ? 0 : index
+ 1;
690 guint container_id
= containers
[i
];
692 SIPE_DEBUG_INFO("sipe_core_change_access_level_from_id: domain=%s, container_id=(%d)%d",
693 domain
? domain
: "", index
, container_id
);
695 sipe_ocs2007_change_access_level(SIPE_CORE_PRIVATE
,
702 * Schedules process of self status publish
703 * based on own calendar information.
704 * Should be scheduled to the beginning of every
705 * 15 min interval, like:
706 * 13:00, 13:15, 13:30, 13:45, etc.
709 static void schedule_publish_update(struct sipe_core_private
*sipe_private
,
710 time_t calculate_from
)
713 /** start of the beginning of closest 5 min interval. */
714 time_t next_start
= ((time_t)((int)((int)calculate_from
)/interval
+ 1)*interval
);
716 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: calculate_from time: %s",
717 sipe_utils_time_to_debug_str(localtime(&calculate_from
)));
718 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: next start time : %s",
719 sipe_utils_time_to_debug_str(localtime(&next_start
)));
721 sipe_schedule_seconds(sipe_private
,
722 "<+2007-cal-status>",
724 next_start
- time(NULL
),
725 sipe_ocs2007_presence_publish
,
730 * An availability XML entry for SIPE_PUB_XML_STATE_CALENDAR
731 * @param availability (%d) Ex.: 6500
733 #define SIPE_PUB_XML_STATE_CALENDAR_AVAIL \
734 "<availability>%d</availability>"
736 * An activity XML entry for SIPE_PUB_XML_STATE_CALENDAR
737 * @param token (%s) Ex.: in-a-meeting
738 * @param minAvailability_attr (%s) Ex.: minAvailability="6500"
739 * @param maxAvailability_attr (%s) Ex.: maxAvailability="8999" or none
741 #define SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY \
742 "<activity token=\"%s\" %s %s></activity>"
744 * Publishes 'calendarState' category.
745 * @param instance (%u) Ex.: 1339299275
746 * @param version (%u) Ex.: 1
747 * @param uri (%s) Ex.: john@contoso.com
748 * @param start_time_str (%s) Ex.: 2008-01-11T19:00:00Z
749 * @param availability (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_AVAIL
750 * @param activity (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
751 * @param meeting_subject (%s) Ex.: Customer Meeting
752 * @param meeting_location (%s) Ex.: Conf Room 100
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 #define SIPE_PUB_XML_STATE_CALENDAR \
764 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
765 "<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\">"\
768 "<endpointLocation/>"\
769 "<meetingSubject>%s</meetingSubject>"\
770 "<meetingLocation>%s</meetingLocation>"\
773 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" 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>"\
783 * Publishes to clear 'calendarState' and 'phoneState' category
784 * @param instance (%u) Ex.: 1251210982
785 * @param version (%u) Ex.: 1
787 #define SIPE_PUB_XML_STATE_CALENDAR_PHONE_CLEAR \
788 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"\
789 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"
792 * Publishes to clear any category
793 * @param category_name (%s) Ex.: state
794 * @param instance (%u) Ex.: 536870912
795 * @param container (%u) Ex.: 3
796 * @param version (%u) Ex.: 1
797 * @param expireType (%s) Ex.: static
799 #define SIPE_PUB_XML_PUBLICATION_CLEAR \
800 "<publication categoryName=\"%s\" instance=\"%u\" container=\"%u\" version=\"%u\" expireType=\"%s\" expires=\"0\"/>"
803 * Publishes 'note' category.
804 * @param instance (%u) Ex.: 2135971629; 0 for personal
805 * @param container (%u) Ex.: 200
806 * @param version (%u) Ex.: 2
807 * @param type (%s) Ex.: personal or OOF
808 * @param startTime_attr (%s) Ex.: startTime="2008-01-11T19:00:00Z"
809 * @param endTime_attr (%s) Ex.: endTime="2008-01-15T19:00:00Z"
810 * @param body (%s) Ex.: In the office
812 #define SIPE_PUB_XML_NOTE \
813 "<publication categoryName=\"note\" instance=\"%u\" container=\"%u\" version=\"%d\" expireType=\"static\">"\
814 "<note xmlns=\"http://schemas.microsoft.com/2006/09/sip/note\">"\
815 "<body type=\"%s\" uri=\"\"%s%s>%s</body>"\
819 * Publishes 'phoneState' category.
820 * @param instance (%u) Ex.: 1339299275
821 * @param version (%u) Ex.: 1
822 * @param availability (%u) Ex.: 6500
823 * @param token (%s) Ex.: on-the-phone
824 * @param minAvailability (%u) generally same as availability
826 * @param instance (%u) Ex.: 1339299275
827 * @param version (%u) Ex.: 1
828 * @param availability (%u) Ex.: 6500
829 * @param token (%s) Ex.: on-the-phone
830 * @param minAvailability (%u) generally same as availability
832 #define SIPE_PUB_XML_STATE_PHONE \
833 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
834 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"phoneState\">"\
835 "<availability>%u</availability>"\
836 "<activity token=\"%s\" minAvailability=\"%u\" maxAvailability=\"8999\"/>"\
839 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
840 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"phoneState\">"\
841 "<availability>%u</availability>"\
842 "<activity token=\"%s\" minAvailability=\"%u\" maxAvailability=\"8999\"/>"\
847 * Only Busy and OOF calendar event are published.
848 * Different instances are used for that.
850 * Must be g_free'd after use.
852 static gchar
*sipe_publish_get_category_state_calendar(struct sipe_core_private
*sipe_private
,
853 struct sipe_cal_event
*event
,
857 gchar
*start_time_str
;
858 int availability
= 0;
861 guint instance
= (cal_satus
== SIPE_CAL_OOF
) ?
862 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR_OOF
) :
863 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR
);
865 /* key is <category><instance><container> */
866 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
867 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
868 struct sipe_publication
*publication_2
=
869 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_2
);
870 struct sipe_publication
*publication_3
=
871 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_3
);
876 if (!publication_3
&& !event
) { /* was nothing, have nothing, exiting */
877 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
878 "Exiting as no publication and no event for cal_satus:%d", cal_satus
);
884 (publication_3
->availability
== availability
) &&
885 sipe_strequal(publication_3
->cal_event_hash
, (tmp
= sipe_cal_event_hash(event
))))
888 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
889 "cal state has NOT changed for cal_satus:%d. Exiting.", cal_satus
);
890 return NULL
; /* nothing to update */
895 (event
->cal_status
== SIPE_CAL_BUSY
||
896 event
->cal_status
== SIPE_CAL_OOF
))
898 gchar
*availability_xml_str
= NULL
;
899 gchar
*activity_xml_str
= NULL
;
900 gchar
*escaped_subject
= event
->subject
? g_markup_escape_text(event
->subject
, -1) : NULL
;
901 gchar
*escaped_location
= event
->location
? g_markup_escape_text(event
->location
, -1) : NULL
;
903 if (event
->cal_status
== SIPE_CAL_BUSY
) {
904 availability_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_AVAIL
,
905 SIPE_OCS2007_AVAILABILITY_BUSY
);
908 if (event
->cal_status
== SIPE_CAL_BUSY
&& event
->is_meeting
) {
909 activity_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
,
910 sipe_status_activity_to_token(SIPE_ACTIVITY_IN_MEETING
),
911 "minAvailability=\"6500\"",
912 "maxAvailability=\"8999\"");
913 } else if (event
->cal_status
== SIPE_CAL_OOF
) {
914 activity_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
,
915 sipe_status_activity_to_token(SIPE_ACTIVITY_OOF
),
916 "minAvailability=\"12000\"",
919 start_time_str
= sipe_utils_time_to_str(event
->start_time
);
921 res
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR
,
923 publication_2
? publication_2
->version
: 0,
926 availability_xml_str
? availability_xml_str
: "",
927 activity_xml_str
? activity_xml_str
: "",
928 escaped_subject
? escaped_subject
: "",
929 escaped_location
? escaped_location
: "",
932 publication_3
? publication_3
->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
: ""
940 g_free(escaped_location
);
941 g_free(escaped_subject
);
942 g_free(start_time_str
);
943 g_free(availability_xml_str
);
944 g_free(activity_xml_str
);
947 else /* including !event, SIPE_CAL_FREE, SIPE_CAL_TENTATIVE */
949 res
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_PHONE_CLEAR
,
951 publication_2
? publication_2
->version
: 0,
954 publication_3
? publication_3
->version
: 0
962 * Returns 'note' XML part for publication.
963 * Must be g_free'd after use.
965 * Protocol format for Note is plain text.
967 * @param note a note in Sipe internal HTML format
968 * @param note_type either personal or OOF
970 static gchar
*sipe_publish_get_category_note(struct sipe_core_private
*sipe_private
,
971 const char *note
, /* html */
972 const char *note_type
,
975 gboolean force_publish
)
977 guint instance
= sipe_strequal("OOF", note_type
) ? sipe_get_pub_instance(sipe_private
, SIPE_PUB_NOTE_OOF
) : 0;
978 /* key is <category><instance><container> */
979 gchar
*key_note_200
= g_strdup_printf("<%s><%u><%u>", "note", instance
, 200);
980 gchar
*key_note_300
= g_strdup_printf("<%s><%u><%u>", "note", instance
, 300);
981 gchar
*key_note_400
= g_strdup_printf("<%s><%u><%u>", "note", instance
, 400);
983 struct sipe_publication
*publication_note_200
=
984 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "note"), key_note_200
);
985 struct sipe_publication
*publication_note_300
=
986 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "note"), key_note_300
);
987 struct sipe_publication
*publication_note_400
=
988 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "note"), key_note_400
);
990 char *tmp
= note
? sipe_backend_markup_strip_html(note
) : NULL
;
991 char *n1
= tmp
? g_markup_escape_text(tmp
, -1) : NULL
;
992 const char *n2
= publication_note_200
? publication_note_200
->note
: NULL
;
993 char *res
, *tmp1
, *tmp2
, *tmp3
;
994 char *start_time_attr
;
999 g_free(key_note_200
);
1000 g_free(key_note_300
);
1001 g_free(key_note_400
);
1003 /* we even need to republish empty note */
1004 if (!force_publish
&& sipe_strequal(n1
, n2
))
1006 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_note: note has NOT changed. Exiting.");
1008 return NULL
; /* nothing to update */
1011 start_time_attr
= note_start
? g_strdup_printf(" startTime=\"%s\"", (tmp
= sipe_utils_time_to_str(note_start
))) : NULL
;
1014 end_time_attr
= note_end
? g_strdup_printf(" endTime=\"%s\"", (tmp
= sipe_utils_time_to_str(note_end
))) : NULL
;
1018 tmp1
= g_strdup_printf(SIPE_PUB_XML_NOTE
,
1021 publication_note_200
? publication_note_200
->version
: 0,
1023 start_time_attr
? start_time_attr
: "",
1024 end_time_attr
? end_time_attr
: "",
1027 tmp2
= g_strdup_printf(SIPE_PUB_XML_NOTE
,
1030 publication_note_300
? publication_note_300
->version
: 0,
1032 start_time_attr
? start_time_attr
: "",
1033 end_time_attr
? end_time_attr
: "",
1036 tmp3
= g_strdup_printf(SIPE_PUB_XML_NOTE
,
1039 publication_note_400
? publication_note_400
->version
: 0,
1041 start_time_attr
? start_time_attr
: "",
1042 end_time_attr
? end_time_attr
: "",
1045 tmp1
= g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR
,
1049 publication_note_200
? publication_note_200
->version
: 0,
1051 tmp2
= g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR
,
1055 publication_note_200
? publication_note_200
->version
: 0,
1057 tmp3
= g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR
,
1061 publication_note_200
? publication_note_200
->version
: 0,
1064 res
= g_strconcat(tmp1
, tmp2
, tmp3
, NULL
);
1066 g_free(start_time_attr
);
1067 g_free(end_time_attr
);
1077 * Publishes 'calendarData' category's WorkingHours.
1079 * @param version (%u) Ex.: 1
1080 * @param email (%s) Ex.: alice@cosmo.local
1081 * @param working_hours_xml_str (%s) Ex.: <WorkingHours xmlns=.....
1083 * @param version (%u)
1085 * @param version (%u)
1087 * @param working_hours_xml_str (%s)
1089 * @param version (%u)
1091 * @param working_hours_xml_str (%s)
1093 * @param version (%u)
1095 * @param working_hours_xml_str (%s)
1097 * @param version (%u)
1099 #define SIPE_PUB_XML_WORKING_HOURS \
1100 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"1\" version=\"%d\" expireType=\"static\">"\
1101 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1104 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"100\" version=\"%d\" expireType=\"static\">"\
1105 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1107 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"200\" version=\"%d\" expireType=\"static\">"\
1108 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1111 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"300\" version=\"%d\" expireType=\"static\">"\
1112 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1115 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"400\" 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=\"32000\" version=\"%d\" expireType=\"static\">"\
1120 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1124 * Returns 'calendarData' XML part with WorkingHours for publication.
1125 * Must be g_free'd after use.
1127 static gchar
*sipe_publish_get_category_cal_working_hours(struct sipe_core_private
*sipe_private
)
1129 struct sipe_calendar
* cal
= sipe_private
->calendar
;
1131 /* key is <category><instance><container> */
1132 gchar
*key_cal_1
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1);
1133 gchar
*key_cal_100
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100);
1134 gchar
*key_cal_200
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200);
1135 gchar
*key_cal_300
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300);
1136 gchar
*key_cal_400
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400);
1137 gchar
*key_cal_32000
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000);
1139 struct sipe_publication
*publication_cal_1
=
1140 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_1
);
1141 struct sipe_publication
*publication_cal_100
=
1142 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_100
);
1143 struct sipe_publication
*publication_cal_200
=
1144 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_200
);
1145 struct sipe_publication
*publication_cal_300
=
1146 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_300
);
1147 struct sipe_publication
*publication_cal_400
=
1148 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_400
);
1149 struct sipe_publication
*publication_cal_32000
=
1150 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_32000
);
1152 const char *n1
= cal
? cal
->working_hours_xml_str
: NULL
;
1153 const char *n2
= publication_cal_300
? publication_cal_300
->working_hours_xml_str
: NULL
;
1156 g_free(key_cal_100
);
1157 g_free(key_cal_200
);
1158 g_free(key_cal_300
);
1159 g_free(key_cal_400
);
1160 g_free(key_cal_32000
);
1162 if (!cal
|| is_empty(cal
->email
) || is_empty(cal
->working_hours_xml_str
)) {
1163 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_working_hours: no data to publish, exiting");
1167 if (sipe_strequal(n1
, n2
))
1169 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_working_hours: WorkingHours has NOT changed. Exiting.");
1170 return NULL
; /* nothing to update */
1173 return g_strdup_printf(SIPE_PUB_XML_WORKING_HOURS
,
1175 publication_cal_1
? publication_cal_1
->version
: 0,
1177 cal
->working_hours_xml_str
,
1179 publication_cal_100
? publication_cal_100
->version
: 0,
1181 publication_cal_200
? publication_cal_200
->version
: 0,
1183 cal
->working_hours_xml_str
,
1185 publication_cal_300
? publication_cal_300
->version
: 0,
1187 cal
->working_hours_xml_str
,
1188 /* 400 - Personal */
1189 publication_cal_400
? publication_cal_400
->version
: 0,
1191 cal
->working_hours_xml_str
,
1192 /* 32000 - Blocked */
1193 publication_cal_32000
? publication_cal_32000
->version
: 0
1198 * Publishes 'calendarData' category's FreeBusy.
1200 * @param instance (%u) Ex.: 1300372959
1201 * @param version (%u) Ex.: 1
1203 * @param instance (%u) Ex.: 1300372959
1204 * @param version (%u) Ex.: 1
1206 * @param instance (%u) Ex.: 1300372959
1207 * @param version (%u) Ex.: 1
1208 * @param email (%s) Ex.: alice@cosmo.local
1209 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1210 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1212 * @param instance (%u) Ex.: 1300372959
1213 * @param version (%u) Ex.: 1
1214 * @param email (%s) Ex.: alice@cosmo.local
1215 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1216 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1218 * @param instance (%u) Ex.: 1300372959
1219 * @param version (%u) Ex.: 1
1220 * @param email (%s) Ex.: alice@cosmo.local
1221 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1222 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1224 * @param instance (%u) Ex.: 1300372959
1225 * @param version (%u) Ex.: 1
1227 #define SIPE_PUB_XML_FREE_BUSY \
1228 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"1\" version=\"%d\" expireType=\"endpoint\">"\
1229 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1231 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"100\" version=\"%d\" expireType=\"endpoint\">"\
1232 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1234 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"200\" version=\"%d\" expireType=\"endpoint\">"\
1235 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1236 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1239 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"300\" version=\"%d\" expireType=\"endpoint\">"\
1240 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1241 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1244 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"400\" version=\"%d\" expireType=\"endpoint\">"\
1245 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1246 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1249 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"32000\" version=\"%d\" expireType=\"endpoint\">"\
1250 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1254 * Returns 'calendarData' XML part with FreeBusy for publication.
1255 * Must be g_free'd after use.
1257 static gchar
*sipe_publish_get_category_cal_free_busy(struct sipe_core_private
*sipe_private
)
1259 struct sipe_calendar
* cal
= sipe_private
->calendar
;
1260 guint cal_data_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_CALENDAR_DATA
);
1262 char *free_busy_base64
;
1263 /* const char *st; */
1264 /* const char *fb; */
1267 /* key is <category><instance><container> */
1268 gchar
*key_cal_1
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 1);
1269 gchar
*key_cal_100
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 100);
1270 gchar
*key_cal_200
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 200);
1271 gchar
*key_cal_300
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 300);
1272 gchar
*key_cal_400
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 400);
1273 gchar
*key_cal_32000
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 32000);
1275 struct sipe_publication
*publication_cal_1
=
1276 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_1
);
1277 struct sipe_publication
*publication_cal_100
=
1278 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_100
);
1279 struct sipe_publication
*publication_cal_200
=
1280 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_200
);
1281 struct sipe_publication
*publication_cal_300
=
1282 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_300
);
1283 struct sipe_publication
*publication_cal_400
=
1284 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_400
);
1285 struct sipe_publication
*publication_cal_32000
=
1286 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_32000
);
1289 g_free(key_cal_100
);
1290 g_free(key_cal_200
);
1291 g_free(key_cal_300
);
1292 g_free(key_cal_400
);
1293 g_free(key_cal_32000
);
1295 if (!cal
|| is_empty(cal
->email
) || !cal
->fb_start
|| is_empty(cal
->free_busy
)) {
1296 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_free_busy: no data to publish, exiting");
1300 fb_start_str
= sipe_utils_time_to_str(cal
->fb_start
);
1301 free_busy_base64
= sipe_cal_get_freebusy_base64(cal
->free_busy
);
1303 /* we will rebuplish the same data to refresh publication time,
1304 * so if data from multiple sources, most recent will be choosen
1306 // st = publication_cal_300 ? publication_cal_300->fb_start_str : NULL;
1307 // fb = publication_cal_300 ? publication_cal_300->free_busy_base64 : NULL;
1309 //if (sipe_strequal(st, fb_start_str) && sipe_strequal(fb, free_busy_base64))
1311 // SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_free_busy: FreeBusy has NOT changed. Exiting.");
1312 // g_free(fb_start_str);
1313 // g_free(free_busy_base64);
1314 // return NULL; /* nothing to update */
1317 res
= g_strdup_printf(SIPE_PUB_XML_FREE_BUSY
,
1320 publication_cal_1
? publication_cal_1
->version
: 0,
1323 publication_cal_100
? publication_cal_100
->version
: 0,
1326 publication_cal_200
? publication_cal_200
->version
: 0,
1332 publication_cal_300
? publication_cal_300
->version
: 0,
1336 /* 400 - Personal */
1338 publication_cal_400
? publication_cal_400
->version
: 0,
1342 /* 32000 - Blocked */
1344 publication_cal_32000
? publication_cal_32000
->version
: 0
1347 g_free(fb_start_str
);
1348 g_free(free_busy_base64
);
1354 * Publishes 'device' category.
1355 * @param instance (%u) Ex.: 1938468728
1356 * @param version (%u) Ex.: 1
1357 * @param endpointId (%s) Ex.: C707E38E-1E10-5413-94D9-ECAC260A0269
1358 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1359 * @param timezone (%s) Ex.: 00:00:00+01:00
1360 * @param machineName (%s) Ex.: BOSTON-OCS07
1362 #define SIPE_PUB_XML_DEVICE \
1363 "<publication categoryName=\"device\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
1364 "<device xmlns=\"http://schemas.microsoft.com/2006/09/sip/device\" endpointId=\"%s\">"\
1365 "<capabilities preferred=\"false\" uri=\"%s\">"\
1366 "<text capture=\"true\" render=\"true\" publish=\"false\"/>"\
1367 "<gifInk capture=\"false\" render=\"true\" publish=\"false\"/>"\
1368 "<isfInk capture=\"false\" render=\"true\" publish=\"false\"/>"\
1370 "<timezone>%s</timezone>"\
1371 "<machineName>%s</machineName>"\
1376 * Returns 'device' XML part for publication.
1377 * Must be g_free'd after use.
1379 static gchar
*sipe_publish_get_category_device(struct sipe_core_private
*sipe_private
)
1383 gchar
*uuid
= get_uuid(sipe_private
);
1384 guint device_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_DEVICE
);
1385 /* key is <category><instance><container> */
1386 gchar
*key
= g_strdup_printf("<%s><%u><%u>", "device", device_instance
, 2);
1387 struct sipe_publication
*publication
=
1388 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "device"), key
);
1392 uri
= sip_uri_self(sipe_private
);
1393 doc
= g_strdup_printf(SIPE_PUB_XML_DEVICE
,
1395 publication
? publication
->version
: 0,
1398 "00:00:00+01:00", /* @TODO make timezone real*/
1409 * Publishes 'machineState' category.
1410 * @param instance (%u) Ex.: 926460663
1411 * @param version (%u) Ex.: 22
1412 * @param availability (%d) Ex.: 3500
1413 * @param instance (%u) Ex.: 926460663
1414 * @param version (%u) Ex.: 22
1415 * @param availability (%d) Ex.: 3500
1417 #define SIPE_PUB_XML_STATE_MACHINE \
1418 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
1419 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"machineState\">"\
1420 "<availability>%d</availability>"\
1421 "<endpointLocation/>"\
1424 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
1425 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"machineState\">"\
1426 "<availability>%d</availability>"\
1427 "<endpointLocation/>"\
1432 * Publishes 'userState' category.
1433 * @param instance (%u) User. Ex.: 536870912
1434 * @param version (%u) User Container 2. Ex.: 22
1435 * @param availability (%d) User Container 2. Ex.: 15500
1436 * @param instance (%u) User. Ex.: 536870912
1437 * @param version (%u) User Container 3.Ex.: 22
1438 * @param availability (%d) User Container 3. Ex.: 15500
1440 #define SIPE_PUB_XML_STATE_USER \
1441 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"static\">"\
1442 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"true\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"userState\">"\
1443 "<availability>%d</availability>"\
1444 "<endpointLocation/>"\
1447 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"static\">"\
1448 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"true\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"userState\">"\
1449 "<availability>%d</availability>"\
1450 "<endpointLocation/>"\
1455 * A service method - use
1456 * - send_publish_get_category_state_machine and
1457 * - send_publish_get_category_state_user instead.
1458 * Must be g_free'd after use.
1460 static gchar
*sipe_publish_get_category_state(struct sipe_core_private
*sipe_private
,
1461 gboolean force_publish
,
1462 gboolean is_user_state
)
1464 int availability
= sipe_ocs2007_availability_from_status(sipe_private
->status
, NULL
);
1465 guint instance
= is_user_state
? sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_USER
) :
1466 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_MACHINE
);
1467 /* key is <category><instance><container> */
1468 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
1469 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
1470 struct sipe_publication
*publication_2
=
1471 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_2
);
1472 struct sipe_publication
*publication_3
=
1473 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_3
);
1478 if (!force_publish
&& publication_2
&& (publication_2
->availability
== availability
))
1480 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_state: state has NOT changed. Exiting.");
1481 return NULL
; /* nothing to update */
1484 return g_strdup_printf( is_user_state
? SIPE_PUB_XML_STATE_USER
: SIPE_PUB_XML_STATE_MACHINE
,
1486 publication_2
? publication_2
->version
: 0,
1489 publication_3
? publication_3
->version
: 0,
1494 * Returns 'machineState' XML part for publication.
1495 * Must be g_free'd after use.
1497 static gchar
*sipe_publish_get_category_state_machine(struct sipe_core_private
*sipe_private
,
1498 gboolean force_publish
)
1500 return sipe_publish_get_category_state(sipe_private
, force_publish
, FALSE
);
1504 * Returns 'userState' XML part for publication.
1505 * Must be g_free'd after use.
1507 static gchar
*sipe_publish_get_category_state_user(struct sipe_core_private
*sipe_private
,
1508 gboolean force_publish
)
1510 return sipe_publish_get_category_state(sipe_private
, force_publish
, TRUE
);
1513 static void send_publish_category_initial(struct sipe_core_private
*sipe_private
)
1515 gchar
*pub_device
= sipe_publish_get_category_device(sipe_private
);
1517 gchar
*publications
;
1519 sipe_status_set_activity(sipe_private
, SIPE_ACTIVITY_AVAILABLE
);
1521 pub_machine
= sipe_publish_get_category_state_machine(sipe_private
,
1523 publications
= g_strdup_printf("%s%s",
1525 pub_machine
? pub_machine
: "");
1527 g_free(pub_machine
);
1529 send_presence_publish(sipe_private
, publications
);
1530 g_free(publications
);
1533 static gboolean
process_send_presence_category_publish_response(struct sipe_core_private
*sipe_private
,
1535 struct transaction
*trans
)
1537 const gchar
*contenttype
= sipmsg_find_header(msg
, "Content-Type");
1539 if (msg
->response
== 200 && g_str_has_prefix(contenttype
, "application/vnd-microsoft-roaming-self+xml")) {
1540 sipe_ocs2007_process_roaming_self(sipe_private
, msg
);
1541 } else if (msg
->response
== 409 && g_str_has_prefix(contenttype
, "application/msrtc-fault+xml")) {
1543 const sipe_xml
*node
;
1547 gboolean has_device_publication
= FALSE
;
1549 xml
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
1551 /* test if version mismatch fault */
1552 fault_code
= sipe_xml_data(sipe_xml_child(xml
, "Faultcode"));
1553 if (!sipe_strequal(fault_code
, "Client.BadCall.WrongDelta")) {
1554 SIPE_DEBUG_INFO("process_send_presence_category_publish_response: unsupported fault code:%s returning.", fault_code
);
1561 /* accumulating information about faulty versions */
1562 faults
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
1563 for (node
= sipe_xml_child(xml
, "details/operation");
1565 node
= sipe_xml_twin(node
))
1567 const gchar
*index
= sipe_xml_attribute(node
, "index");
1568 const gchar
*curVersion
= sipe_xml_attribute(node
, "curVersion");
1570 g_hash_table_insert(faults
, g_strdup(index
), g_strdup(curVersion
));
1571 SIPE_DEBUG_INFO("fault added: index:%s curVersion:%s", index
, curVersion
);
1575 /* here we are parsing our own request to figure out what publication
1576 * referenced here only by index went wrong
1578 xml
= sipe_xml_parse(trans
->msg
->body
, trans
->msg
->bodylen
);
1581 for (node
= sipe_xml_child(xml
, "publications/publication"),
1582 index_our
= 1; /* starts with 1 - our first publication */
1584 node
= sipe_xml_twin(node
), index_our
++)
1586 gchar
*idx
= g_strdup_printf("%d", index_our
);
1587 const gchar
*curVersion
= g_hash_table_lookup(faults
, idx
);
1588 const gchar
*categoryName
= sipe_xml_attribute(node
, "categoryName");
1591 if (sipe_strequal("device", categoryName
)) {
1592 has_device_publication
= TRUE
;
1595 if (curVersion
) { /* fault exist on this index */
1596 const gchar
*container
= sipe_xml_attribute(node
, "container");
1597 const gchar
*instance
= sipe_xml_attribute(node
, "instance");
1598 /* key is <category><instance><container> */
1599 gchar
*key
= g_strdup_printf("<%s><%s><%s>", categoryName
, instance
, container
);
1600 GHashTable
*category
= g_hash_table_lookup(sipe_private
->our_publications
, categoryName
);
1603 struct sipe_publication
*publication
=
1604 g_hash_table_lookup(category
, key
);
1606 SIPE_DEBUG_INFO("key is %s", key
);
1609 SIPE_DEBUG_INFO("Updating %s with version %s. Was %d before.",
1610 key
, curVersion
, publication
->version
);
1611 /* updating publication's version to the correct one */
1612 publication
->version
= atoi(curVersion
);
1615 /* We somehow lost this category from our publications... */
1616 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
1617 publication
->category
= g_strdup(categoryName
);
1618 publication
->instance
= atoi(instance
);
1619 publication
->container
= atoi(container
);
1620 publication
->version
= atoi(curVersion
);
1621 category
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
1622 g_free
, (GDestroyNotify
)free_publication
);
1623 g_hash_table_insert(category
, g_strdup(key
), publication
);
1624 g_hash_table_insert(sipe_private
->our_publications
, g_strdup(categoryName
), category
);
1625 SIPE_DEBUG_INFO("added lost category '%s' key '%s'", categoryName
, key
);
1631 g_hash_table_destroy(faults
);
1633 /* rebublishing with right versions */
1634 if (has_device_publication
) {
1635 send_publish_category_initial(sipe_private
);
1637 sipe_ocs2007_category_publish(sipe_private
, TRUE
);
1644 * Publishes categories.
1645 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1646 * @param publications (%s) XML publications
1648 #define SIPE_SEND_PRESENCE \
1649 "<publish xmlns=\"http://schemas.microsoft.com/2006/09/sip/rich-presence\">"\
1650 "<publications uri=\"%s\">"\
1655 static void send_presence_publish(struct sipe_core_private
*sipe_private
,
1656 const char *publications
)
1663 uri
= sip_uri_self(sipe_private
);
1664 doc
= g_strdup_printf(SIPE_SEND_PRESENCE
,
1668 tmp
= get_contact(sipe_private
);
1669 hdr
= g_strdup_printf("Contact: %s\r\n"
1670 "Content-Type: application/msrtc-category-publish+xml\r\n", tmp
);
1672 sip_transport_service(sipe_private
,
1676 process_send_presence_category_publish_response
);
1685 * Publishes self status
1686 * based on own calendar information.
1688 void sipe_ocs2007_presence_publish(struct sipe_core_private
*sipe_private
,
1689 SIPE_UNUSED_PARAMETER
void *unused
)
1691 struct sipe_calendar
* cal
= sipe_private
->calendar
;
1692 struct sipe_cal_event
* event
= NULL
;
1693 gchar
*pub_cal_working_hours
= NULL
;
1694 gchar
*pub_cal_free_busy
= NULL
;
1695 gchar
*pub_calendar
= NULL
;
1696 gchar
*pub_calendar2
= NULL
;
1697 gchar
*pub_oof_note
= NULL
;
1698 const gchar
*oof_note
;
1699 time_t oof_start
= 0;
1703 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() no calendar data.");
1707 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() started.");
1708 if (cal
->cal_events
) {
1709 event
= sipe_cal_get_event(cal
->cal_events
, time(NULL
));
1713 sipe_cal_event_debug(event
, "publish_calendar_status_self: current event is:\n");
1715 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: current event is NULL");
1720 OOF publish, Busy clean
1722 OOF clean, Busy publish
1724 OOF clean, Busy clean
1726 if (event
&& event
->cal_status
== SIPE_CAL_OOF
) {
1727 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, event
, cal
->email
, SIPE_CAL_OOF
);
1728 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_BUSY
);
1729 } else if (event
&& event
->cal_status
== SIPE_CAL_BUSY
) {
1730 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_OOF
);
1731 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, event
, cal
->email
, SIPE_CAL_BUSY
);
1733 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_OOF
);
1734 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_BUSY
);
1737 oof_note
= sipe_ews_get_oof_note(cal
);
1738 if (sipe_strequal("Scheduled", cal
->oof_state
)) {
1739 oof_start
= cal
->oof_start
;
1740 oof_end
= cal
->oof_end
;
1742 pub_oof_note
= sipe_publish_get_category_note(sipe_private
, oof_note
, "OOF", oof_start
, oof_end
, FALSE
);
1744 pub_cal_working_hours
= sipe_publish_get_category_cal_working_hours(sipe_private
);
1745 pub_cal_free_busy
= sipe_publish_get_category_cal_free_busy(sipe_private
);
1747 if (!pub_cal_working_hours
&& !pub_cal_free_busy
&& !pub_calendar
&& !pub_calendar2
&& !pub_oof_note
) {
1748 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: nothing has changed.");
1750 gchar
*publications
= g_strdup_printf("%s%s%s%s%s",
1751 pub_cal_working_hours
? pub_cal_working_hours
: "",
1752 pub_cal_free_busy
? pub_cal_free_busy
: "",
1753 pub_calendar
? pub_calendar
: "",
1754 pub_calendar2
? pub_calendar2
: "",
1755 pub_oof_note
? pub_oof_note
: "");
1757 send_presence_publish(sipe_private
, publications
);
1758 g_free(publications
);
1761 g_free(pub_cal_working_hours
);
1762 g_free(pub_cal_free_busy
);
1763 g_free(pub_calendar
);
1764 g_free(pub_calendar2
);
1765 g_free(pub_oof_note
);
1767 /* repeat scheduling */
1768 schedule_publish_update(sipe_private
, time(NULL
));
1771 void sipe_ocs2007_category_publish(struct sipe_core_private
*sipe_private
,
1772 gboolean force_publish
)
1774 GString
*publications
= g_string_new("");
1777 if (force_publish
|| sipe_private
->status_set_by_user
) {
1778 tmp
= sipe_publish_get_category_state_user(sipe_private
,
1781 g_string_append(publications
, tmp
);
1786 tmp
= sipe_publish_get_category_state_machine(sipe_private
,
1789 g_string_append(publications
, tmp
);
1793 tmp
= sipe_publish_get_category_note(sipe_private
,
1795 SIPE_CORE_PRIVATE_FLAG_IS(OOF_NOTE
) ? "OOF" : "personal",
1800 g_string_append(publications
, tmp
);
1804 if (publications
->len
)
1805 send_presence_publish(sipe_private
, publications
->str
);
1807 SIPE_DEBUG_INFO_NOFORMAT("sipe_osc2007_category_publish: nothing has changed. Exiting.");
1809 g_string_free(publications
, TRUE
);
1812 void sipe_ocs2007_phone_state_publish(struct sipe_core_private
*sipe_private
)
1814 gchar
*publications
= NULL
;
1815 guint instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_PHONE_VOIP
);
1817 /* key is <category><instance><container> */
1818 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
1819 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
1820 struct sipe_publication
*publication_2
=
1821 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_2
);
1822 struct sipe_publication
*publication_3
=
1823 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_3
);
1828 if (g_hash_table_size(sipe_private
->media_calls
)) {
1829 guint availability
= 0;
1830 const gchar
*token
= NULL
;
1831 GList
*calls
= g_hash_table_get_values(sipe_private
->media_calls
);
1834 if (sipe_core_media_get_call(SIPE_CORE_PUBLIC
)) {
1835 availability
= 6500;
1836 token
= sipe_status_activity_to_token(SIPE_ACTIVITY_ON_PHONE
);
1839 for (i
= calls
; i
; i
= i
->next
) {
1840 if (sipe_media_is_conference_call(i
->data
)) {
1841 availability
= 7000;
1842 token
= sipe_status_activity_to_token(SIPE_ACTIVITY_IN_CONF
);
1850 publications
= g_strdup_printf(SIPE_PUB_XML_STATE_PHONE
,
1851 instance
, publication_2
? publication_2
->version
: 0,
1852 availability
, token
, availability
,
1853 instance
, publication_3
? publication_3
->version
: 0,
1854 availability
, token
, availability
);
1859 publications
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_PHONE_CLEAR
,
1860 instance
, publication_2
? publication_2
->version
: 0,
1861 instance
, publication_3
? publication_3
->version
: 0);
1865 send_presence_publish(sipe_private
, publications
);
1866 g_free(publications
);
1870 static void sipe_publish_get_cat_state_user_to_clear(SIPE_UNUSED_PARAMETER
const char *name
,
1874 struct sipe_publication
*publication
= value
;
1876 g_string_append_printf( str
,
1877 SIPE_PUB_XML_PUBLICATION_CLEAR
,
1878 publication
->category
,
1879 publication
->instance
,
1880 publication
->container
,
1881 publication
->version
,
1885 void sipe_ocs2007_reset_status(struct sipe_core_private
*sipe_private
)
1888 gchar
*publications
;
1890 if (!sipe_private
->user_state_publications
|| g_hash_table_size(sipe_private
->user_state_publications
) == 0) {
1891 SIPE_DEBUG_INFO_NOFORMAT("sipe_reset_status: no userState publications, exiting.");
1895 str
= g_string_new(NULL
);
1896 g_hash_table_foreach(sipe_private
->user_state_publications
, (GHFunc
)sipe_publish_get_cat_state_user_to_clear
, str
);
1897 publications
= g_string_free(str
, FALSE
);
1899 send_presence_publish(sipe_private
, publications
);
1900 g_free(publications
);
1903 /* key is <category><instance><container> */
1904 static gboolean
sipe_is_our_publication(struct sipe_core_private
*sipe_private
,
1909 /* filling keys for our publications if not yet cached */
1910 if (!sipe_private
->our_publication_keys
) {
1911 guint device_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_DEVICE
);
1912 guint machine_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_MACHINE
);
1913 guint user_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_USER
);
1914 guint calendar_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR
);
1915 guint cal_oof_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR_OOF
);
1916 guint phone_voip_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_PHONE_VOIP
);
1917 guint cal_data_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_CALENDAR_DATA
);
1918 guint note_oof_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_NOTE_OOF
);
1920 SIPE_DEBUG_INFO_NOFORMAT("* Our Publication Instances *");
1921 SIPE_DEBUG_INFO("\tDevice : %u\t0x%08X", device_instance
, device_instance
);
1922 SIPE_DEBUG_INFO("\tMachine State : %u\t0x%08X", machine_instance
, machine_instance
);
1923 SIPE_DEBUG_INFO("\tUser Stare : %u\t0x%08X", user_instance
, user_instance
);
1924 SIPE_DEBUG_INFO("\tCalendar State : %u\t0x%08X", calendar_instance
, calendar_instance
);
1925 SIPE_DEBUG_INFO("\tCalendar OOF State : %u\t0x%08X", cal_oof_instance
, cal_oof_instance
);
1926 SIPE_DEBUG_INFO("\tVOIP Phone State : %u\t0x%08X", phone_voip_instance
, phone_voip_instance
);
1927 SIPE_DEBUG_INFO("\tCalendar FreeBusy : %u\t0x%08X", cal_data_instance
, cal_data_instance
);
1928 SIPE_DEBUG_INFO("\tOOF Note : %u\t0x%08X", note_oof_instance
, note_oof_instance
);
1929 SIPE_DEBUG_INFO("\tNote : %u", 0);
1930 SIPE_DEBUG_INFO("\tCalendar WorkingHours: %u", 0);
1933 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1934 g_strdup_printf("<%s><%u><%u>", "device", device_instance
, 2));
1936 /* state:machineState */
1937 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1938 g_strdup_printf("<%s><%u><%u>", "state", machine_instance
, 2));
1939 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1940 g_strdup_printf("<%s><%u><%u>", "state", machine_instance
, 3));
1942 /* state:userState */
1943 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1944 g_strdup_printf("<%s><%u><%u>", "state", user_instance
, 2));
1945 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1946 g_strdup_printf("<%s><%u><%u>", "state", user_instance
, 3));
1948 /* state:calendarState */
1949 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1950 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance
, 2));
1951 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1952 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance
, 3));
1954 /* state:calendarState OOF */
1955 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1956 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance
, 2));
1957 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1958 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance
, 3));
1960 /* state:phoneState */
1961 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1962 g_strdup_printf("<%s><%u><%u>", "state", phone_voip_instance
, 2));
1963 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1964 g_strdup_printf("<%s><%u><%u>", "state", phone_voip_instance
, 3));
1967 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1968 g_strdup_printf("<%s><%u><%u>", "note", 0, 200));
1969 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1970 g_strdup_printf("<%s><%u><%u>", "note", 0, 300));
1971 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1972 g_strdup_printf("<%s><%u><%u>", "note", 0, 400));
1975 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1976 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 200));
1977 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1978 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 300));
1979 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1980 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 400));
1982 /* calendarData:WorkingHours */
1983 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1984 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1));
1985 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1986 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100));
1987 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1988 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200));
1989 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1990 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300));
1991 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1992 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400));
1993 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1994 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000));
1996 /* calendarData:FreeBusy */
1997 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1998 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 1));
1999 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2000 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 100));
2001 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2002 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 200));
2003 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2004 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 300));
2005 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2006 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 400));
2007 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
2008 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 32000));
2010 //SIPE_DEBUG_INFO("sipe_is_our_publication: sipe_private->our_publication_keys length=%d",
2011 // sipe_private->our_publication_keys ? (int) g_slist_length(sipe_private->our_publication_keys) : -1);
2014 //SIPE_DEBUG_INFO("sipe_is_our_publication: key=%s", key);
2016 entry
= sipe_private
->our_publication_keys
;
2018 //SIPE_DEBUG_INFO(" sipe_is_our_publication: entry->data=%s", entry->data);
2019 if (sipe_strequal(entry
->data
, key
)) {
2022 entry
= entry
->next
;
2027 static void sipe_refresh_blocked_status_cb(char *buddy_name
,
2028 SIPE_UNUSED_PARAMETER
struct sipe_buddy
*buddy
,
2029 struct sipe_core_private
*sipe_private
)
2031 int container_id
= sipe_ocs2007_find_access_level(sipe_private
, "user", buddy_name
, NULL
);
2032 gboolean blocked
= (container_id
== 32000);
2033 gboolean blocked_in_blist
= sipe_backend_buddy_is_blocked(SIPE_CORE_PUBLIC
, buddy_name
);
2035 /* SIPE_DEBUG_INFO("sipe_refresh_blocked_status_cb: buddy_name=%s, blocked=%s, blocked_in_blist=%s",
2036 buddy_name, blocked ? "T" : "F", blocked_in_blist ? "T" : "F"); */
2038 if (blocked
!= blocked_in_blist
) {
2039 sipe_backend_buddy_set_blocked_status(SIPE_CORE_PUBLIC
, buddy_name
, blocked
);
2043 static void sipe_refresh_blocked_status(struct sipe_core_private
*sipe_private
)
2045 sipe_buddy_foreach(sipe_private
,
2046 (GHFunc
) sipe_refresh_blocked_status_cb
,
2051 * When we receive some self (BE) NOTIFY with a new subscriber
2052 * we sends a setSubscribers request to him [SIP-PRES] 4.8
2055 void sipe_ocs2007_process_roaming_self(struct sipe_core_private
*sipe_private
,
2061 const sipe_xml
*node
;
2062 const sipe_xml
*node2
;
2063 char *display_name
= NULL
;
2065 GSList
*category_names
= NULL
;
2066 int aggreg_avail
= 0;
2067 gchar
*activity_token
= NULL
;
2068 gboolean do_update_status
= FALSE
;
2069 gboolean has_note_cleaned
= FALSE
;
2070 GHashTable
*devices
;
2072 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self");
2074 xml
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
2077 contact
= get_contact(sipe_private
);
2078 to
= sip_uri_self(sipe_private
);
2081 /* set list of categories participating in this XML */
2082 for (node
= sipe_xml_child(xml
, "categories/category"); node
; node
= sipe_xml_twin(node
)) {
2083 const gchar
*name
= sipe_xml_attribute(node
, "name");
2084 category_names
= sipe_utils_slist_insert_unique_sorted(category_names
,
2086 (GCompareFunc
)strcmp
,
2089 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: category_names length=%d",
2090 category_names
? (int) g_slist_length(category_names
) : -1);
2091 /* drop category information */
2092 if (category_names
) {
2093 GSList
*entry
= category_names
;
2095 GHashTable
*cat_publications
;
2096 const gchar
*category
= entry
->data
;
2097 entry
= entry
->next
;
2098 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: dropping category: %s", category
);
2099 cat_publications
= g_hash_table_lookup(sipe_private
->our_publications
, category
);
2100 if (cat_publications
) {
2101 g_hash_table_remove(sipe_private
->our_publications
, category
);
2102 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: dropped category: %s", category
);
2106 g_slist_free(category_names
);
2108 /* filling our categories reflected in roaming data */
2109 devices
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
2111 for (node
= sipe_xml_child(xml
, "categories/category"); node
; node
= sipe_xml_twin(node
)) {
2113 const gchar
*name
= sipe_xml_attribute(node
, "name");
2114 guint container
= sipe_xml_int_attribute(node
, "container", -1);
2115 guint instance
= sipe_xml_int_attribute(node
, "instance", -1);
2116 guint version
= sipe_xml_int_attribute(node
, "version", 0);
2117 time_t publish_time
= (tmp
= sipe_xml_attribute(node
, "publishTime")) ?
2118 sipe_utils_str_to_time(tmp
) : 0;
2120 GHashTable
*cat_publications
= g_hash_table_lookup(sipe_private
->our_publications
, name
);
2122 /* Ex. clear note: <category name="note"/> */
2123 if (container
== (guint
)-1) {
2124 g_free(sipe_private
->note
);
2125 sipe_private
->note
= NULL
;
2126 do_update_status
= TRUE
;
2130 /* Ex. clear note: <category name="note" container="200"/> */
2131 if (instance
== (guint
)-1) {
2132 if (container
== 200) {
2133 g_free(sipe_private
->note
);
2134 sipe_private
->note
= NULL
;
2135 do_update_status
= TRUE
;
2137 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removing publications for: %s/%u", name
, container
);
2138 sipe_remove_category_container_publications(
2139 sipe_private
->our_publications
, name
, container
);
2143 /* key is <category><instance><container> */
2144 key
= g_strdup_printf("<%s><%u><%u>", name
, instance
, container
);
2145 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: key=%s version=%d", key
, version
);
2147 /* capture all userState publication for later clean up if required */
2148 if (sipe_strequal(name
, "state") && (container
== 2 || container
== 3)) {
2149 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
2151 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "userState")) {
2152 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
2153 publication
->category
= g_strdup(name
);
2154 publication
->instance
= instance
;
2155 publication
->container
= container
;
2156 publication
->version
= version
;
2158 if (!sipe_private
->user_state_publications
) {
2159 sipe_private
->user_state_publications
= g_hash_table_new_full(
2160 g_str_hash
, g_str_equal
,
2161 g_free
, (GDestroyNotify
)free_publication
);
2163 g_hash_table_insert(sipe_private
->user_state_publications
, g_strdup(key
), publication
);
2164 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added to user_state_publications key=%s version=%d",
2169 /* count each client instance only once */
2170 if (sipe_strequal(name
, "device"))
2171 g_hash_table_replace(devices
, g_strdup_printf("%u", instance
), NULL
);
2173 if (sipe_is_our_publication(sipe_private
, key
)) {
2174 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
2176 publication
->category
= g_strdup(name
);
2177 publication
->instance
= instance
;
2178 publication
->container
= container
;
2179 publication
->version
= version
;
2181 /* filling publication->availability */
2182 if (sipe_strequal(name
, "state")) {
2183 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
2184 const sipe_xml
*xn_avail
= sipe_xml_child(xn_state
, "availability");
2187 gchar
*avail_str
= sipe_xml_data(xn_avail
);
2189 publication
->availability
= atoi(avail_str
);
2193 /* for calendarState */
2194 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "calendarState")) {
2195 const sipe_xml
*xn_activity
= sipe_xml_child(xn_state
, "activity");
2196 struct sipe_cal_event
*event
= g_new0(struct sipe_cal_event
, 1);
2198 event
->start_time
= sipe_utils_str_to_time(sipe_xml_attribute(xn_state
, "startTime"));
2200 if (sipe_strequal(sipe_xml_attribute(xn_activity
, "token"),
2201 sipe_status_activity_to_token(SIPE_ACTIVITY_IN_MEETING
)))
2203 event
->is_meeting
= TRUE
;
2206 event
->subject
= sipe_xml_data(sipe_xml_child(xn_state
, "meetingSubject"));
2207 event
->location
= sipe_xml_data(sipe_xml_child(xn_state
, "meetingLocation"));
2209 publication
->cal_event_hash
= sipe_cal_event_hash(event
);
2210 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: hash=%s",
2211 publication
->cal_event_hash
);
2212 sipe_cal_event_free(event
);
2215 /* filling publication->note */
2216 if (sipe_strequal(name
, "note")) {
2217 const sipe_xml
*xn_body
= sipe_xml_child(node
, "note/body");
2219 if (!has_note_cleaned
) {
2220 has_note_cleaned
= TRUE
;
2222 g_free(sipe_private
->note
);
2223 sipe_private
->note
= NULL
;
2224 sipe_private
->note_since
= publish_time
;
2226 do_update_status
= TRUE
;
2229 g_free(publication
->note
);
2230 publication
->note
= NULL
;
2234 publication
->note
= g_markup_escape_text((tmp
= sipe_xml_data(xn_body
)), -1);
2236 if (publish_time
>= sipe_private
->note_since
) {
2237 g_free(sipe_private
->note
);
2238 sipe_private
->note
= g_strdup(publication
->note
);
2239 sipe_private
->note_since
= publish_time
;
2240 if (sipe_strequal(sipe_xml_attribute(xn_body
, "type"), "OOF"))
2241 SIPE_CORE_PRIVATE_FLAG_SET(OOF_NOTE
);
2243 SIPE_CORE_PRIVATE_FLAG_UNSET(OOF_NOTE
);
2245 do_update_status
= TRUE
;
2250 /* filling publication->fb_start_str, free_busy_base64, working_hours_xml_str */
2251 if (sipe_strequal(name
, "calendarData") && (publication
->container
== 300)) {
2252 const sipe_xml
*xn_free_busy
= sipe_xml_child(node
, "calendarData/freeBusy");
2253 const sipe_xml
*xn_working_hours
= sipe_xml_child(node
, "calendarData/WorkingHours");
2255 publication
->fb_start_str
= g_strdup(sipe_xml_attribute(xn_free_busy
, "startTime"));
2256 publication
->free_busy_base64
= sipe_xml_data(xn_free_busy
);
2258 if (xn_working_hours
) {
2259 publication
->working_hours_xml_str
= sipe_xml_stringify(xn_working_hours
);
2263 if (!cat_publications
) {
2264 cat_publications
= g_hash_table_new_full(
2265 g_str_hash
, g_str_equal
,
2266 g_free
, (GDestroyNotify
)free_publication
);
2267 g_hash_table_insert(sipe_private
->our_publications
, g_strdup(name
), cat_publications
);
2268 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added GHashTable cat=%s", name
);
2270 g_hash_table_insert(cat_publications
, g_strdup(key
), publication
);
2271 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added key=%s version=%d", key
, version
);
2275 /* aggregateState (not an our publication) from 2-nd container */
2276 if (sipe_strequal(name
, "state") && container
== 2) {
2277 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
2278 const sipe_xml
*xn_activity
= sipe_xml_child(xn_state
, "activity");
2280 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "aggregateState")) {
2281 const sipe_xml
*xn_avail
= sipe_xml_child(xn_state
, "availability");
2284 gchar
*avail_str
= sipe_xml_data(xn_avail
);
2286 aggreg_avail
= atoi(avail_str
);
2291 do_update_status
= TRUE
;
2295 activity_token
= g_strdup(sipe_xml_attribute(xn_activity
, "token"));
2299 /* userProperties published by server from AD */
2300 if (!sipe_private
->csta
&&
2301 sipe_strequal(name
, "userProperties")) {
2302 const sipe_xml
*line
;
2303 /* line, for Remote Call Control (RCC) or external Lync/Communicator call */
2304 for (line
= sipe_xml_child(node
, "userProperties/lines/line"); line
; line
= sipe_xml_twin(line
)) {
2305 const gchar
*line_type
= sipe_xml_attribute(line
, "lineType");
2306 gchar
*line_uri
= sipe_xml_data(line
);
2311 if (sipe_strequal(line_type
, "Rcc") || sipe_strequal(line_type
, "Dual")) {
2312 const gchar
*line_server
= sipe_xml_attribute(line
, "lineServer");
2314 gchar
*tmp
= g_strstrip(line_uri
);
2315 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: line_uri=%s server=%s",
2317 sip_csta_open(sipe_private
, tmp
, line_server
);
2321 else if (sipe_strequal(line_type
, "Uc")) {
2323 if (!sipe_private
->uc_line_uri
) {
2324 sipe_private
->uc_line_uri
= g_strdup(g_strstrip(line_uri
));
2326 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self: "
2327 "sipe_private->uc_line_uri is already set.");
2338 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sipe_private->our_publications size=%d",
2339 sipe_private
->our_publications
? (int) g_hash_table_size(sipe_private
->our_publications
) : -1);
2341 /* active clients for user account */
2342 if (g_hash_table_size(devices
) > 1) {
2343 SIPE_CORE_PRIVATE_FLAG_SET(MPOP
);
2344 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: multiple clients detected (%d)",
2345 g_hash_table_size(devices
));
2347 SIPE_CORE_PRIVATE_FLAG_UNSET(MPOP
);
2348 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self: single client detected");
2350 g_hash_table_destroy(devices
);
2353 for (node
= sipe_xml_child(xml
, "containers/container"); node
; node
= sipe_xml_twin(node
)) {
2354 guint id
= sipe_xml_int_attribute(node
, "id", 0);
2355 struct sipe_container
*container
= sipe_find_container(sipe_private
, id
);
2358 sipe_private
->containers
= g_slist_remove(sipe_private
->containers
, container
);
2359 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removed existing container id=%d v%d", container
->id
, container
->version
);
2360 sipe_ocs2007_free_container(container
);
2362 container
= g_new0(struct sipe_container
, 1);
2364 container
->version
= sipe_xml_int_attribute(node
, "version", 0);
2365 sipe_private
->containers
= g_slist_append(sipe_private
->containers
, container
);
2366 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container id=%d v%d", container
->id
, container
->version
);
2368 for (node2
= sipe_xml_child(node
, "member"); node2
; node2
= sipe_xml_twin(node2
)) {
2369 struct sipe_container_member
*member
= g_new0(struct sipe_container_member
, 1);
2370 member
->type
= g_strdup(sipe_xml_attribute(node2
, "type"));
2371 member
->value
= g_strdup(sipe_xml_attribute(node2
, "value"));
2372 container
->members
= g_slist_append(container
->members
, member
);
2373 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container member type=%s value=%s",
2374 member
->type
, member
->value
? member
->value
: "");
2378 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: access_level_set=%s",
2379 SIPE_CORE_PRIVATE_FLAG_IS(ACCESS_LEVEL_SET
) ? "TRUE" : "FALSE");
2380 if (!SIPE_CORE_PRIVATE_FLAG_IS(ACCESS_LEVEL_SET
) && sipe_xml_child(xml
, "containers")) {
2381 char *container_xmls
= NULL
;
2382 int sameEnterpriseAL
= sipe_ocs2007_find_access_level(sipe_private
, "sameEnterprise", NULL
, NULL
);
2383 int federatedAL
= sipe_ocs2007_find_access_level(sipe_private
, "federated", NULL
, NULL
);
2385 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sameEnterpriseAL=%d", sameEnterpriseAL
);
2386 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: federatedAL=%d", federatedAL
);
2387 /* initial set-up to let counterparties see your status */
2388 if (sameEnterpriseAL
< 0) {
2389 struct sipe_container
*container
= sipe_find_container(sipe_private
, 200);
2390 guint version
= container
? container
->version
: 0;
2391 sipe_send_container_members_prepare(200, version
, "add", "sameEnterprise", NULL
, &container_xmls
);
2393 if (federatedAL
< 0) {
2394 struct sipe_container
*container
= sipe_find_container(sipe_private
, 100);
2395 guint version
= container
? container
->version
: 0;
2396 sipe_send_container_members_prepare(100, version
, "add", "federated", NULL
, &container_xmls
);
2398 SIPE_CORE_PRIVATE_FLAG_SET(ACCESS_LEVEL_SET
);
2400 if (container_xmls
) {
2401 sipe_send_set_container_members(sipe_private
, container_xmls
);
2403 g_free(container_xmls
);
2406 /* Refresh contacts' blocked status */
2407 sipe_refresh_blocked_status(sipe_private
);
2410 for (node
= sipe_xml_child(xml
, "subscribers/subscriber"); node
; node
= sipe_xml_twin(node
)) {
2412 const char *acknowledged
;
2416 user
= sipe_xml_attribute(node
, "user"); /* without 'sip:' prefix */
2417 if (!user
) continue;
2418 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user %s", user
);
2419 display_name
= g_strdup(sipe_xml_attribute(node
, "displayName"));
2420 uri
= sip_uri_from_name(user
);
2422 sipe_buddy_update_property(sipe_private
, uri
, SIPE_BUDDY_INFO_DISPLAY_NAME
, display_name
);
2423 sipe_backend_buddy_refresh_properties(SIPE_CORE_PUBLIC
, uri
);
2425 acknowledged
= sipe_xml_attribute(node
, "acknowledged");
2426 if(sipe_strcase_equal(acknowledged
,"false")){
2427 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user added you %s", user
);
2428 if (!sipe_backend_buddy_find(SIPE_CORE_PUBLIC
, uri
, NULL
)) {
2429 sipe_backend_buddy_request_add(SIPE_CORE_PUBLIC
, uri
, display_name
);
2432 hdr
= g_strdup_printf(
2434 "Content-Type: application/msrtc-presence-setsubscriber+xml\r\n", contact
);
2436 body
= g_strdup_printf(
2437 "<setSubscribers xmlns=\"http://schemas.microsoft.com/2006/09/sip/presence-subscribers\">"
2438 "<subscriber user=\"%s\" acknowledged=\"true\"/>"
2439 "</setSubscribers>", user
);
2441 sip_transport_service(sipe_private
,
2449 g_free(display_name
);
2456 /* Publish initial state if not yet.
2457 * Assuming this happens on initial responce to subscription to roaming-self
2458 * so we've already updated our roaming data in full.
2461 if (!SIPE_CORE_PRIVATE_FLAG_IS(INITIAL_PUBLISH
)) {
2462 send_publish_category_initial(sipe_private
);
2463 SIPE_CORE_PRIVATE_FLAG_SET(INITIAL_PUBLISH
);
2465 sipe_cal_delayed_calendar_update(sipe_private
);
2466 do_update_status
= FALSE
;
2467 } else if (aggreg_avail
) {
2470 (aggreg_avail
< SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE
)) {
2472 sipe_status_set_token(sipe_private
,
2473 sipe_ocs2007_status_from_legacy_availability(aggreg_avail
, activity_token
));
2475 /* do not let offline status switch us off */
2476 sipe_status_set_activity(sipe_private
,
2477 SIPE_ACTIVITY_INVISIBLE
);
2481 if (do_update_status
) {
2482 sipe_status_and_note(sipe_private
, NULL
);
2486 g_free(activity_token
);
2490 * for Access levels menu
2492 #define INDENT_FMT " %s"
2495 * Member is indirectly belong to access level container.
2496 * For example 'sameEnterprise' is in the container and user
2497 * belongs to that same enterprise.
2499 #define INDENT_MARKED_INHERITED_FMT "= %s"
2501 static struct sipe_backend_buddy_menu
*access_levels_menu(struct sipe_core_private
*sipe_private
,
2502 struct sipe_backend_buddy_menu
*menu
,
2503 const gchar
*member_type
,
2504 const gchar
*member_value
,
2505 const gboolean extra_menu
)
2508 gboolean is_group_access
= FALSE
;
2512 menu
= sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC
);
2514 container_id
= sipe_ocs2007_find_access_level(sipe_private
,
2519 for (i
= 1; i
<= CONTAINERS_LEN
; i
++) {
2521 * Blocked should remain in the first place
2522 * in the containers[] array.
2524 unsigned int j
= (i
== CONTAINERS_LEN
) ? 0 : i
;
2525 int container_j
= containers
[j
];
2526 const gchar
*acc_level_name
= sipe_ocs2007_access_level_name(container_j
);
2527 struct sipe_container
*container
= create_container(j
,
2533 /* libpurple memory leak workaround */
2534 blist_menu_remember_container(sipe_private
, container
);
2536 /* current container/access level */
2537 if (container_j
== container_id
) {
2538 label
= is_group_access
?
2539 g_strdup_printf(INDENT_MARKED_INHERITED_FMT
, acc_level_name
) :
2540 g_strdup_printf(SIPE_OCS2007_INDENT_MARKED_FMT
, acc_level_name
);
2542 label
= g_strdup_printf(INDENT_FMT
, acc_level_name
);
2545 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2548 SIPE_BUDDY_MENU_CHANGE_ACCESS_LEVEL
,
2553 if (extra_menu
&& (container_id
>= 0) && !is_group_access
) {
2554 struct sipe_container
*container
= create_container(0,
2561 menu
= sipe_backend_buddy_menu_separator(SIPE_CORE_PUBLIC
,
2566 /* libpurple memory leak workaround */
2567 blist_menu_remember_container(sipe_private
, container
);
2569 /* Translators: remove (clear) previously assigned access level */
2570 label
= g_strdup_printf(INDENT_FMT
, _("Unspecify"));
2571 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2574 SIPE_BUDDY_MENU_CHANGE_ACCESS_LEVEL
,
2582 static struct sipe_backend_buddy_menu
*access_groups_menu(struct sipe_core_private
*sipe_private
)
2584 struct sipe_backend_buddy_menu
*menu
= sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC
);
2585 GSList
*access_domains
, *entry
;
2587 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2589 _("People in my company"),
2590 access_levels_menu(sipe_private
,
2596 /* this is original name, don't edit */
2597 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2599 _("People in domains connected with my company"),
2600 access_levels_menu(sipe_private
,
2606 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2608 _("People in public domains"),
2609 access_levels_menu(sipe_private
,
2615 entry
= access_domains
= get_access_domains(sipe_private
);
2617 gchar
*domain
= entry
->data
;
2618 gchar
*menu_name
= g_strdup_printf(_("People at %s"), domain
);
2620 /* takes over ownership of entry->data (= domain) */
2621 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2624 access_levels_menu(sipe_private
,
2631 entry
= entry
->next
;
2633 g_slist_free(access_domains
);
2636 /* People in domains connected with my company */
2637 menu
= sipe_backend_buddy_menu_separator(SIPE_CORE_PUBLIC
,
2639 "-------------------------------------------");
2641 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2643 _("Add new domain..."),
2644 SIPE_BUDDY_MENU_ADD_NEW_DOMAIN
,
2650 struct sipe_backend_buddy_menu
*sipe_ocs2007_access_control_menu(struct sipe_core_private
*sipe_private
,
2651 const gchar
*buddy_name
)
2653 struct sipe_backend_buddy_menu
*menu
= sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC
);
2657 * Workaround for missing libpurple API to release resources allocated
2658 * during blist_node_menu() callback. See also:
2660 * <http://developer.pidgin.im/ticket/12597>
2662 * We remember all memory blocks in a list and deallocate them when
2664 * - the next time we enter the callback, or
2665 * - the account is disconnected
2667 * That means that after the buddy menu has been closed we have unused
2668 * resources but at least we don't leak them anymore...
2670 sipe_core_buddy_menu_free(SIPE_CORE_PUBLIC
);
2672 label
= g_strdup_printf(INDENT_FMT
, _("Online help..."));
2673 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2676 SIPE_BUDDY_MENU_ACCESS_LEVEL_HELP
,
2680 label
= g_strdup_printf(INDENT_FMT
, _("Access groups"));
2681 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2684 access_groups_menu(sipe_private
));
2687 menu
= access_levels_menu(sipe_private
,
2690 sipe_get_no_sip_uri(buddy_name
),