6 * Copyright (C) 2011-2013 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
);
641 current_container_id
= -1;
646 /* recalculate AL below */
647 current_container_id
= sipe_ocs2007_find_access_level(sipe_private
, type
, value
, NULL
);
649 /* assign/publish new access level */
650 if (container_id
!= current_container_id
&& container_id
>= 0) {
651 struct sipe_container
*container
= sipe_find_container(sipe_private
, container_id
);
652 guint version
= container
? container
->version
: 0;
654 sipe_send_container_members_prepare(container_id
, version
, "add", type
, value
, &container_xmls
);
657 if (container_xmls
) {
658 sipe_send_set_container_members(sipe_private
, container_xmls
);
660 g_free(container_xmls
);
663 void sipe_core_change_access_level_from_container(struct sipe_core_public
*sipe_public
,
666 struct sipe_container
*container
= parameter
;
667 struct sipe_container_member
*member
;
669 if (!container
|| !container
->members
) return;
671 member
= ((struct sipe_container_member
*)container
->members
->data
);
673 if (!member
->type
) return;
675 SIPE_DEBUG_INFO("sipe_ocs2007_change_access_level_from_container: container->id=%d, member->type=%s, member->value=%s",
676 container
->id
, member
->type
, member
->value
? member
->value
: "");
678 sipe_ocs2007_change_access_level(SIPE_CORE_PRIVATE
,
685 void sipe_core_change_access_level_for_domain(struct sipe_core_public
*sipe_public
,
689 /* move Blocked first */
690 guint i
= (index
== 4) ? 0 : index
+ 1;
691 guint container_id
= containers
[i
];
693 SIPE_DEBUG_INFO("sipe_core_change_access_level_from_id: domain=%s, container_id=(%d)%d",
694 domain
? domain
: "", index
, container_id
);
696 sipe_ocs2007_change_access_level(SIPE_CORE_PRIVATE
,
703 * Schedules process of self status publish
704 * based on own calendar information.
705 * Should be scheduled to the beginning of every
706 * 15 min interval, like:
707 * 13:00, 13:15, 13:30, 13:45, etc.
710 static void schedule_publish_update(struct sipe_core_private
*sipe_private
,
711 time_t calculate_from
)
714 /** start of the beginning of closest 5 min interval. */
715 time_t next_start
= ((time_t)((int)((int)calculate_from
)/interval
+ 1)*interval
);
717 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: calculate_from time: %s",
718 asctime(localtime(&calculate_from
)));
719 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: next start time : %s",
720 asctime(localtime(&next_start
)));
722 sipe_schedule_seconds(sipe_private
,
723 "<+2007-cal-status>",
725 next_start
- time(NULL
),
726 sipe_ocs2007_presence_publish
,
731 * An availability XML entry for SIPE_PUB_XML_STATE_CALENDAR
732 * @param availability (%d) Ex.: 6500
734 #define SIPE_PUB_XML_STATE_CALENDAR_AVAIL \
735 "<availability>%d</availability>"
737 * An activity XML entry for SIPE_PUB_XML_STATE_CALENDAR
738 * @param token (%s) Ex.: in-a-meeting
739 * @param minAvailability_attr (%s) Ex.: minAvailability="6500"
740 * @param maxAvailability_attr (%s) Ex.: maxAvailability="8999" or none
742 #define SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY \
743 "<activity token=\"%s\" %s %s></activity>"
745 * Publishes 'calendarState' category.
746 * @param instance (%u) Ex.: 1339299275
747 * @param version (%u) Ex.: 1
748 * @param uri (%s) Ex.: john@contoso.com
749 * @param start_time_str (%s) Ex.: 2008-01-11T19:00:00Z
750 * @param availability (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_AVAIL
751 * @param activity (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
752 * @param meeting_subject (%s) Ex.: Customer Meeting
753 * @param meeting_location (%s) Ex.: Conf Room 100
755 * @param instance (%u) Ex.: 1339299275
756 * @param version (%u) Ex.: 1
757 * @param uri (%s) Ex.: john@contoso.com
758 * @param start_time_str (%s) Ex.: 2008-01-11T19:00:00Z
759 * @param availability (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_AVAIL
760 * @param activity (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
761 * @param meeting_subject (%s) Ex.: Customer Meeting
762 * @param meeting_location (%s) Ex.: Conf Room 100
764 #define SIPE_PUB_XML_STATE_CALENDAR \
765 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
766 "<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\">"\
769 "<endpointLocation/>"\
770 "<meetingSubject>%s</meetingSubject>"\
771 "<meetingLocation>%s</meetingLocation>"\
774 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
775 "<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\">"\
778 "<endpointLocation/>"\
779 "<meetingSubject>%s</meetingSubject>"\
780 "<meetingLocation>%s</meetingLocation>"\
784 * Publishes to clear 'calendarState' and 'phoneState' category
785 * @param instance (%u) Ex.: 1251210982
786 * @param version (%u) Ex.: 1
788 #define SIPE_PUB_XML_STATE_CALENDAR_PHONE_CLEAR \
789 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"\
790 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"
793 * Publishes to clear any category
794 * @param category_name (%s) Ex.: state
795 * @param instance (%u) Ex.: 536870912
796 * @param container (%u) Ex.: 3
797 * @param version (%u) Ex.: 1
798 * @param expireType (%s) Ex.: static
800 #define SIPE_PUB_XML_PUBLICATION_CLEAR \
801 "<publication categoryName=\"%s\" instance=\"%u\" container=\"%u\" version=\"%u\" expireType=\"%s\" expires=\"0\"/>"
804 * Publishes 'note' category.
805 * @param instance (%u) Ex.: 2135971629; 0 for personal
806 * @param container (%u) Ex.: 200
807 * @param version (%u) Ex.: 2
808 * @param type (%s) Ex.: personal or OOF
809 * @param startTime_attr (%s) Ex.: startTime="2008-01-11T19:00:00Z"
810 * @param endTime_attr (%s) Ex.: endTime="2008-01-15T19:00:00Z"
811 * @param body (%s) Ex.: In the office
813 #define SIPE_PUB_XML_NOTE \
814 "<publication categoryName=\"note\" instance=\"%u\" container=\"%u\" version=\"%d\" expireType=\"static\">"\
815 "<note xmlns=\"http://schemas.microsoft.com/2006/09/sip/note\">"\
816 "<body type=\"%s\" uri=\"\"%s%s>%s</body>"\
820 * Publishes 'phoneState' category.
821 * @param instance (%u) Ex.: 1339299275
822 * @param version (%u) Ex.: 1
823 * @param availability (%u) Ex.: 6500
824 * @param token (%s) Ex.: on-the-phone
825 * @param minAvailability (%u) generally same as availability
827 * @param instance (%u) Ex.: 1339299275
828 * @param version (%u) Ex.: 1
829 * @param availability (%u) Ex.: 6500
830 * @param token (%s) Ex.: on-the-phone
831 * @param minAvailability (%u) generally same as availability
833 #define SIPE_PUB_XML_STATE_PHONE \
834 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
835 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"phoneState\">"\
836 "<availability>%u</availability>"\
837 "<activity token=\"%s\" minAvailability=\"%u\" maxAvailability=\"8999\"/>"\
840 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
841 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"phoneState\">"\
842 "<availability>%u</availability>"\
843 "<activity token=\"%s\" minAvailability=\"%u\" maxAvailability=\"8999\"/>"\
848 * Only Busy and OOF calendar event are published.
849 * Different instances are used for that.
851 * Must be g_free'd after use.
853 static gchar
*sipe_publish_get_category_state_calendar(struct sipe_core_private
*sipe_private
,
854 struct sipe_cal_event
*event
,
858 gchar
*start_time_str
;
859 int availability
= 0;
862 guint instance
= (cal_satus
== SIPE_CAL_OOF
) ?
863 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR_OOF
) :
864 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR
);
866 /* key is <category><instance><container> */
867 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
868 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
869 struct sipe_publication
*publication_2
=
870 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_2
);
871 struct sipe_publication
*publication_3
=
872 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_3
);
877 if (!publication_3
&& !event
) { /* was nothing, have nothing, exiting */
878 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
879 "Exiting as no publication and no event for cal_satus:%d", cal_satus
);
885 (publication_3
->availability
== availability
) &&
886 sipe_strequal(publication_3
->cal_event_hash
, (tmp
= sipe_cal_event_hash(event
))))
889 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
890 "cal state has NOT changed for cal_satus:%d. Exiting.", cal_satus
);
891 return NULL
; /* nothing to update */
896 (event
->cal_status
== SIPE_CAL_BUSY
||
897 event
->cal_status
== SIPE_CAL_OOF
))
899 gchar
*availability_xml_str
= NULL
;
900 gchar
*activity_xml_str
= NULL
;
901 gchar
*escaped_subject
= event
->subject
? g_markup_escape_text(event
->subject
, -1) : NULL
;
902 gchar
*escaped_location
= event
->location
? g_markup_escape_text(event
->location
, -1) : NULL
;
904 if (event
->cal_status
== SIPE_CAL_BUSY
) {
905 availability_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_AVAIL
,
906 SIPE_OCS2007_AVAILABILITY_BUSY
);
909 if (event
->cal_status
== SIPE_CAL_BUSY
&& event
->is_meeting
) {
910 activity_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
,
911 sipe_status_activity_to_token(SIPE_ACTIVITY_IN_MEETING
),
912 "minAvailability=\"6500\"",
913 "maxAvailability=\"8999\"");
914 } else if (event
->cal_status
== SIPE_CAL_OOF
) {
915 activity_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
,
916 sipe_status_activity_to_token(SIPE_ACTIVITY_OOF
),
917 "minAvailability=\"12000\"",
920 start_time_str
= sipe_utils_time_to_str(event
->start_time
);
922 res
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR
,
924 publication_2
? publication_2
->version
: 0,
927 availability_xml_str
? availability_xml_str
: "",
928 activity_xml_str
? activity_xml_str
: "",
929 escaped_subject
? escaped_subject
: "",
930 escaped_location
? escaped_location
: "",
933 publication_3
? publication_3
->version
: 0,
936 availability_xml_str
? availability_xml_str
: "",
937 activity_xml_str
? activity_xml_str
: "",
938 escaped_subject
? escaped_subject
: "",
939 escaped_location
? escaped_location
: ""
941 g_free(escaped_location
);
942 g_free(escaped_subject
);
943 g_free(start_time_str
);
944 g_free(availability_xml_str
);
945 g_free(activity_xml_str
);
948 else /* including !event, SIPE_CAL_FREE, SIPE_CAL_TENTATIVE */
950 res
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_PHONE_CLEAR
,
952 publication_2
? publication_2
->version
: 0,
955 publication_3
? publication_3
->version
: 0
963 * Returns 'note' XML part for publication.
964 * Must be g_free'd after use.
966 * Protocol format for Note is plain text.
968 * @param note a note in Sipe internal HTML format
969 * @param note_type either personal or OOF
971 static gchar
*sipe_publish_get_category_note(struct sipe_core_private
*sipe_private
,
972 const char *note
, /* html */
973 const char *note_type
,
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 (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 is_user_state
)
1463 int availability
= sipe_ocs2007_availability_from_status(sipe_private
->status
, NULL
);
1464 guint instance
= is_user_state
? sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_USER
) :
1465 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_MACHINE
);
1466 /* key is <category><instance><container> */
1467 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
1468 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
1469 struct sipe_publication
*publication_2
=
1470 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_2
);
1471 struct sipe_publication
*publication_3
=
1472 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_3
);
1477 if (publication_2
&& (publication_2
->availability
== availability
))
1479 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_state: state has NOT changed. Exiting.");
1480 return NULL
; /* nothing to update */
1483 return g_strdup_printf( is_user_state
? SIPE_PUB_XML_STATE_USER
: SIPE_PUB_XML_STATE_MACHINE
,
1485 publication_2
? publication_2
->version
: 0,
1488 publication_3
? publication_3
->version
: 0,
1493 * Returns 'machineState' XML part for publication.
1494 * Must be g_free'd after use.
1496 static gchar
*sipe_publish_get_category_state_machine(struct sipe_core_private
*sipe_private
)
1498 return sipe_publish_get_category_state(sipe_private
, FALSE
);
1502 * Returns 'userState' XML part for publication.
1503 * Must be g_free'd after use.
1505 static gchar
*sipe_publish_get_category_state_user(struct sipe_core_private
*sipe_private
)
1507 return sipe_publish_get_category_state(sipe_private
, TRUE
);
1510 static void send_publish_category_initial(struct sipe_core_private
*sipe_private
)
1512 gchar
*pub_device
= sipe_publish_get_category_device(sipe_private
);
1514 gchar
*publications
;
1516 sipe_status_set_activity(sipe_private
, SIPE_ACTIVITY_AVAILABLE
);
1518 pub_machine
= sipe_publish_get_category_state_machine(sipe_private
);
1519 publications
= g_strdup_printf("%s%s",
1521 pub_machine
? pub_machine
: "");
1523 g_free(pub_machine
);
1525 send_presence_publish(sipe_private
, publications
);
1526 g_free(publications
);
1529 static gboolean
process_send_presence_category_publish_response(struct sipe_core_private
*sipe_private
,
1531 struct transaction
*trans
)
1533 const gchar
*contenttype
= sipmsg_find_header(msg
, "Content-Type");
1535 if (msg
->response
== 200 && g_str_has_prefix(contenttype
, "application/vnd-microsoft-roaming-self+xml")) {
1536 sipe_ocs2007_process_roaming_self(sipe_private
, msg
);
1537 } else if (msg
->response
== 409 && g_str_has_prefix(contenttype
, "application/msrtc-fault+xml")) {
1539 const sipe_xml
*node
;
1543 gboolean has_device_publication
= FALSE
;
1545 xml
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
1547 /* test if version mismatch fault */
1548 fault_code
= sipe_xml_data(sipe_xml_child(xml
, "Faultcode"));
1549 if (!sipe_strequal(fault_code
, "Client.BadCall.WrongDelta")) {
1550 SIPE_DEBUG_INFO("process_send_presence_category_publish_response: unsupported fault code:%s returning.", fault_code
);
1557 /* accumulating information about faulty versions */
1558 faults
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
1559 for (node
= sipe_xml_child(xml
, "details/operation");
1561 node
= sipe_xml_twin(node
))
1563 const gchar
*index
= sipe_xml_attribute(node
, "index");
1564 const gchar
*curVersion
= sipe_xml_attribute(node
, "curVersion");
1566 g_hash_table_insert(faults
, g_strdup(index
), g_strdup(curVersion
));
1567 SIPE_DEBUG_INFO("fault added: index:%s curVersion:%s", index
, curVersion
);
1571 /* here we are parsing our own request to figure out what publication
1572 * referenced here only by index went wrong
1574 xml
= sipe_xml_parse(trans
->msg
->body
, trans
->msg
->bodylen
);
1577 for (node
= sipe_xml_child(xml
, "publications/publication"),
1578 index_our
= 1; /* starts with 1 - our first publication */
1580 node
= sipe_xml_twin(node
), index_our
++)
1582 gchar
*idx
= g_strdup_printf("%d", index_our
);
1583 const gchar
*curVersion
= g_hash_table_lookup(faults
, idx
);
1584 const gchar
*categoryName
= sipe_xml_attribute(node
, "categoryName");
1587 if (sipe_strequal("device", categoryName
)) {
1588 has_device_publication
= TRUE
;
1591 if (curVersion
) { /* fault exist on this index */
1592 const gchar
*container
= sipe_xml_attribute(node
, "container");
1593 const gchar
*instance
= sipe_xml_attribute(node
, "instance");
1594 /* key is <category><instance><container> */
1595 gchar
*key
= g_strdup_printf("<%s><%s><%s>", categoryName
, instance
, container
);
1596 GHashTable
*category
= g_hash_table_lookup(sipe_private
->our_publications
, categoryName
);
1599 struct sipe_publication
*publication
=
1600 g_hash_table_lookup(category
, key
);
1602 SIPE_DEBUG_INFO("key is %s", key
);
1605 SIPE_DEBUG_INFO("Updating %s with version %s. Was %d before.",
1606 key
, curVersion
, publication
->version
);
1607 /* updating publication's version to the correct one */
1608 publication
->version
= atoi(curVersion
);
1611 /* We somehow lost this category from our publications... */
1612 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
1613 publication
->category
= g_strdup(categoryName
);
1614 publication
->instance
= atoi(instance
);
1615 publication
->container
= atoi(container
);
1616 publication
->version
= atoi(curVersion
);
1617 category
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
1618 g_free
, (GDestroyNotify
)free_publication
);
1619 g_hash_table_insert(category
, g_strdup(key
), publication
);
1620 g_hash_table_insert(sipe_private
->our_publications
, g_strdup(categoryName
), category
);
1621 SIPE_DEBUG_INFO("added lost category '%s' key '%s'", categoryName
, key
);
1627 g_hash_table_destroy(faults
);
1629 /* rebublishing with right versions */
1630 if (has_device_publication
) {
1631 send_publish_category_initial(sipe_private
);
1633 sipe_status_update(sipe_private
, NULL
);
1640 * Publishes categories.
1641 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1642 * @param publications (%s) XML publications
1644 #define SIPE_SEND_PRESENCE \
1645 "<publish xmlns=\"http://schemas.microsoft.com/2006/09/sip/rich-presence\">"\
1646 "<publications uri=\"%s\">"\
1651 static void send_presence_publish(struct sipe_core_private
*sipe_private
,
1652 const char *publications
)
1659 uri
= sip_uri_self(sipe_private
);
1660 doc
= g_strdup_printf(SIPE_SEND_PRESENCE
,
1664 tmp
= get_contact(sipe_private
);
1665 hdr
= g_strdup_printf("Contact: %s\r\n"
1666 "Content-Type: application/msrtc-category-publish+xml\r\n", tmp
);
1668 sip_transport_service(sipe_private
,
1672 process_send_presence_category_publish_response
);
1681 * Publishes self status
1682 * based on own calendar information.
1684 void sipe_ocs2007_presence_publish(struct sipe_core_private
*sipe_private
,
1685 SIPE_UNUSED_PARAMETER
void *unused
)
1687 struct sipe_calendar
* cal
= sipe_private
->calendar
;
1688 struct sipe_cal_event
* event
= NULL
;
1689 gchar
*pub_cal_working_hours
= NULL
;
1690 gchar
*pub_cal_free_busy
= NULL
;
1691 gchar
*pub_calendar
= NULL
;
1692 gchar
*pub_calendar2
= NULL
;
1693 gchar
*pub_oof_note
= NULL
;
1694 const gchar
*oof_note
;
1695 time_t oof_start
= 0;
1699 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() no calendar data.");
1703 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() started.");
1704 if (cal
->cal_events
) {
1705 event
= sipe_cal_get_event(cal
->cal_events
, time(NULL
));
1709 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: current event is NULL");
1711 char *desc
= sipe_cal_event_describe(event
);
1712 SIPE_DEBUG_INFO("publish_calendar_status_self: current event is:\n%s", desc
? desc
: "");
1718 OOF publish, Busy clean
1720 OOF clean, Busy publish
1722 OOF clean, Busy clean
1724 if (event
&& event
->cal_status
== SIPE_CAL_OOF
) {
1725 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, event
, cal
->email
, SIPE_CAL_OOF
);
1726 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_BUSY
);
1727 } else if (event
&& event
->cal_status
== SIPE_CAL_BUSY
) {
1728 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_OOF
);
1729 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, event
, cal
->email
, SIPE_CAL_BUSY
);
1731 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_OOF
);
1732 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_BUSY
);
1735 oof_note
= sipe_ews_get_oof_note(cal
);
1736 if (sipe_strequal("Scheduled", cal
->oof_state
)) {
1737 oof_start
= cal
->oof_start
;
1738 oof_end
= cal
->oof_end
;
1740 pub_oof_note
= sipe_publish_get_category_note(sipe_private
, oof_note
, "OOF", oof_start
, oof_end
);
1742 pub_cal_working_hours
= sipe_publish_get_category_cal_working_hours(sipe_private
);
1743 pub_cal_free_busy
= sipe_publish_get_category_cal_free_busy(sipe_private
);
1745 if (!pub_cal_working_hours
&& !pub_cal_free_busy
&& !pub_calendar
&& !pub_calendar2
&& !pub_oof_note
) {
1746 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: nothing has changed.");
1748 gchar
*publications
= g_strdup_printf("%s%s%s%s%s",
1749 pub_cal_working_hours
? pub_cal_working_hours
: "",
1750 pub_cal_free_busy
? pub_cal_free_busy
: "",
1751 pub_calendar
? pub_calendar
: "",
1752 pub_calendar2
? pub_calendar2
: "",
1753 pub_oof_note
? pub_oof_note
: "");
1755 send_presence_publish(sipe_private
, publications
);
1756 g_free(publications
);
1759 g_free(pub_cal_working_hours
);
1760 g_free(pub_cal_free_busy
);
1761 g_free(pub_calendar
);
1762 g_free(pub_calendar2
);
1763 g_free(pub_oof_note
);
1765 /* repeat scheduling */
1766 schedule_publish_update(sipe_private
, time(NULL
));
1769 void sipe_ocs2007_category_publish(struct sipe_core_private
*sipe_private
)
1771 gchar
*pub_state
= sipe_status_changed_by_user(sipe_private
) ?
1772 sipe_publish_get_category_state_user(sipe_private
) :
1773 sipe_publish_get_category_state_machine(sipe_private
);
1774 gchar
*pub_note
= sipe_publish_get_category_note(sipe_private
,
1776 SIPE_CORE_PRIVATE_FLAG_IS(OOF_NOTE
) ? "OOF" : "personal",
1779 gchar
*publications
;
1781 if (!pub_state
&& !pub_note
) {
1782 SIPE_DEBUG_INFO_NOFORMAT("sipe_osc2007_category_publish: nothing has changed. Exiting.");
1786 publications
= g_strdup_printf("%s%s",
1787 pub_state
? pub_state
: "",
1788 pub_note
? pub_note
: "");
1793 send_presence_publish(sipe_private
, publications
);
1794 g_free(publications
);
1797 void sipe_ocs2007_phone_state_publish(struct sipe_core_private
*sipe_private
)
1799 gchar
*publications
= NULL
;
1800 guint instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_PHONE_VOIP
);
1802 /* key is <category><instance><container> */
1803 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
1804 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
1805 struct sipe_publication
*publication_2
=
1806 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_2
);
1807 struct sipe_publication
*publication_3
=
1808 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_3
);
1813 if (sipe_private
->media_call
) {
1816 if (sipe_media_is_conference_call(sipe_private
->media_call
)) {
1817 availability
= 7000;
1818 token
= sipe_status_activity_to_token(SIPE_ACTIVITY_IN_CONF
);
1820 availability
= 6500;
1821 token
= sipe_status_activity_to_token(SIPE_ACTIVITY_ON_PHONE
);
1824 publications
= g_strdup_printf(SIPE_PUB_XML_STATE_PHONE
,
1825 instance
, publication_2
? publication_2
->version
: 0,
1826 availability
, token
, availability
,
1827 instance
, publication_3
? publication_3
->version
: 0,
1828 availability
, token
, availability
);
1832 publications
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_PHONE_CLEAR
,
1833 instance
, publication_2
? publication_2
->version
: 0,
1834 instance
, publication_3
? publication_3
->version
: 0);
1837 send_presence_publish(sipe_private
, publications
);
1838 g_free(publications
);
1841 static void sipe_publish_get_cat_state_user_to_clear(SIPE_UNUSED_PARAMETER
const char *name
,
1845 struct sipe_publication
*publication
= value
;
1847 g_string_append_printf( str
,
1848 SIPE_PUB_XML_PUBLICATION_CLEAR
,
1849 publication
->category
,
1850 publication
->instance
,
1851 publication
->container
,
1852 publication
->version
,
1856 void sipe_ocs2007_reset_status(struct sipe_core_private
*sipe_private
)
1859 gchar
*publications
;
1861 if (!sipe_private
->user_state_publications
|| g_hash_table_size(sipe_private
->user_state_publications
) == 0) {
1862 SIPE_DEBUG_INFO_NOFORMAT("sipe_reset_status: no userState publications, exiting.");
1866 str
= g_string_new(NULL
);
1867 g_hash_table_foreach(sipe_private
->user_state_publications
, (GHFunc
)sipe_publish_get_cat_state_user_to_clear
, str
);
1868 publications
= g_string_free(str
, FALSE
);
1870 send_presence_publish(sipe_private
, publications
);
1871 g_free(publications
);
1874 /* key is <category><instance><container> */
1875 static gboolean
sipe_is_our_publication(struct sipe_core_private
*sipe_private
,
1880 /* filling keys for our publications if not yet cached */
1881 if (!sipe_private
->our_publication_keys
) {
1882 guint device_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_DEVICE
);
1883 guint machine_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_MACHINE
);
1884 guint user_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_USER
);
1885 guint calendar_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR
);
1886 guint cal_oof_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR_OOF
);
1887 guint phone_voip_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_PHONE_VOIP
);
1888 guint cal_data_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_CALENDAR_DATA
);
1889 guint note_oof_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_NOTE_OOF
);
1891 SIPE_DEBUG_INFO_NOFORMAT("* Our Publication Instances *");
1892 SIPE_DEBUG_INFO("\tDevice : %u\t0x%08X", device_instance
, device_instance
);
1893 SIPE_DEBUG_INFO("\tMachine State : %u\t0x%08X", machine_instance
, machine_instance
);
1894 SIPE_DEBUG_INFO("\tUser Stare : %u\t0x%08X", user_instance
, user_instance
);
1895 SIPE_DEBUG_INFO("\tCalendar State : %u\t0x%08X", calendar_instance
, calendar_instance
);
1896 SIPE_DEBUG_INFO("\tCalendar OOF State : %u\t0x%08X", cal_oof_instance
, cal_oof_instance
);
1897 SIPE_DEBUG_INFO("\tVOIP Phone State : %u\t0x%08X", phone_voip_instance
, phone_voip_instance
);
1898 SIPE_DEBUG_INFO("\tCalendar FreeBusy : %u\t0x%08X", cal_data_instance
, cal_data_instance
);
1899 SIPE_DEBUG_INFO("\tOOF Note : %u\t0x%08X", note_oof_instance
, note_oof_instance
);
1900 SIPE_DEBUG_INFO("\tNote : %u", 0);
1901 SIPE_DEBUG_INFO("\tCalendar WorkingHours: %u", 0);
1904 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1905 g_strdup_printf("<%s><%u><%u>", "device", device_instance
, 2));
1907 /* state:machineState */
1908 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1909 g_strdup_printf("<%s><%u><%u>", "state", machine_instance
, 2));
1910 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1911 g_strdup_printf("<%s><%u><%u>", "state", machine_instance
, 3));
1913 /* state:userState */
1914 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1915 g_strdup_printf("<%s><%u><%u>", "state", user_instance
, 2));
1916 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1917 g_strdup_printf("<%s><%u><%u>", "state", user_instance
, 3));
1919 /* state:calendarState */
1920 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1921 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance
, 2));
1922 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1923 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance
, 3));
1925 /* state:calendarState OOF */
1926 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1927 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance
, 2));
1928 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1929 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance
, 3));
1931 /* state:phoneState */
1932 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1933 g_strdup_printf("<%s><%u><%u>", "state", phone_voip_instance
, 2));
1934 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1935 g_strdup_printf("<%s><%u><%u>", "state", phone_voip_instance
, 3));
1938 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1939 g_strdup_printf("<%s><%u><%u>", "note", 0, 200));
1940 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1941 g_strdup_printf("<%s><%u><%u>", "note", 0, 300));
1942 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1943 g_strdup_printf("<%s><%u><%u>", "note", 0, 400));
1946 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1947 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 200));
1948 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1949 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 300));
1950 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1951 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 400));
1953 /* calendarData:WorkingHours */
1954 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1955 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1));
1956 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1957 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100));
1958 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1959 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200));
1960 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1961 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300));
1962 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1963 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400));
1964 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1965 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000));
1967 /* calendarData:FreeBusy */
1968 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1969 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 1));
1970 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1971 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 100));
1972 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1973 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 200));
1974 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1975 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 300));
1976 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1977 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 400));
1978 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1979 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 32000));
1981 //SIPE_DEBUG_INFO("sipe_is_our_publication: sipe_private->our_publication_keys length=%d",
1982 // sipe_private->our_publication_keys ? (int) g_slist_length(sipe_private->our_publication_keys) : -1);
1985 //SIPE_DEBUG_INFO("sipe_is_our_publication: key=%s", key);
1987 entry
= sipe_private
->our_publication_keys
;
1989 //SIPE_DEBUG_INFO(" sipe_is_our_publication: entry->data=%s", entry->data);
1990 if (sipe_strequal(entry
->data
, key
)) {
1993 entry
= entry
->next
;
1998 static void sipe_refresh_blocked_status_cb(char *buddy_name
,
1999 SIPE_UNUSED_PARAMETER
struct sipe_buddy
*buddy
,
2000 struct sipe_core_private
*sipe_private
)
2002 int container_id
= sipe_ocs2007_find_access_level(sipe_private
, "user", buddy_name
, NULL
);
2003 gboolean blocked
= (container_id
== 32000);
2004 gboolean blocked_in_blist
= sipe_backend_buddy_is_blocked(SIPE_CORE_PUBLIC
, buddy_name
);
2006 /* SIPE_DEBUG_INFO("sipe_refresh_blocked_status_cb: buddy_name=%s, blocked=%s, blocked_in_blist=%s",
2007 buddy_name, blocked ? "T" : "F", blocked_in_blist ? "T" : "F"); */
2009 if (blocked
!= blocked_in_blist
) {
2010 sipe_backend_buddy_set_blocked_status(SIPE_CORE_PUBLIC
, buddy_name
, blocked
);
2014 static void sipe_refresh_blocked_status(struct sipe_core_private
*sipe_private
)
2016 sipe_buddy_foreach(sipe_private
,
2017 (GHFunc
) sipe_refresh_blocked_status_cb
,
2022 * When we receive some self (BE) NOTIFY with a new subscriber
2023 * we sends a setSubscribers request to him [SIP-PRES] 4.8
2026 void sipe_ocs2007_process_roaming_self(struct sipe_core_private
*sipe_private
,
2032 const sipe_xml
*node
;
2033 const sipe_xml
*node2
;
2034 char *display_name
= NULL
;
2036 GSList
*category_names
= NULL
;
2037 int aggreg_avail
= 0;
2038 gchar
*activity_token
= NULL
;
2039 gboolean do_update_status
= FALSE
;
2040 gboolean has_note_cleaned
= FALSE
;
2041 GHashTable
*devices
;
2043 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self");
2045 xml
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
2048 contact
= get_contact(sipe_private
);
2049 to
= sip_uri_self(sipe_private
);
2052 /* set list of categories participating in this XML */
2053 for (node
= sipe_xml_child(xml
, "categories/category"); node
; node
= sipe_xml_twin(node
)) {
2054 const gchar
*name
= sipe_xml_attribute(node
, "name");
2055 category_names
= sipe_utils_slist_insert_unique_sorted(category_names
,
2057 (GCompareFunc
)strcmp
,
2060 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: category_names length=%d",
2061 category_names
? (int) g_slist_length(category_names
) : -1);
2062 /* drop category information */
2063 if (category_names
) {
2064 GSList
*entry
= category_names
;
2066 GHashTable
*cat_publications
;
2067 const gchar
*category
= entry
->data
;
2068 entry
= entry
->next
;
2069 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: dropping category: %s", category
);
2070 cat_publications
= g_hash_table_lookup(sipe_private
->our_publications
, category
);
2071 if (cat_publications
) {
2072 g_hash_table_remove(sipe_private
->our_publications
, category
);
2073 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: dropped category: %s", category
);
2077 g_slist_free(category_names
);
2079 /* filling our categories reflected in roaming data */
2080 devices
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
2082 for (node
= sipe_xml_child(xml
, "categories/category"); node
; node
= sipe_xml_twin(node
)) {
2084 const gchar
*name
= sipe_xml_attribute(node
, "name");
2085 guint container
= sipe_xml_int_attribute(node
, "container", -1);
2086 guint instance
= sipe_xml_int_attribute(node
, "instance", -1);
2087 guint version
= sipe_xml_int_attribute(node
, "version", 0);
2088 time_t publish_time
= (tmp
= sipe_xml_attribute(node
, "publishTime")) ?
2089 sipe_utils_str_to_time(tmp
) : 0;
2091 GHashTable
*cat_publications
= g_hash_table_lookup(sipe_private
->our_publications
, name
);
2093 /* Ex. clear note: <category name="note"/> */
2094 if (container
== (guint
)-1) {
2095 g_free(sipe_private
->note
);
2096 sipe_private
->note
= NULL
;
2097 do_update_status
= TRUE
;
2101 /* Ex. clear note: <category name="note" container="200"/> */
2102 if (instance
== (guint
)-1) {
2103 if (container
== 200) {
2104 g_free(sipe_private
->note
);
2105 sipe_private
->note
= NULL
;
2106 do_update_status
= TRUE
;
2108 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removing publications for: %s/%u", name
, container
);
2109 sipe_remove_category_container_publications(
2110 sipe_private
->our_publications
, name
, container
);
2114 /* key is <category><instance><container> */
2115 key
= g_strdup_printf("<%s><%u><%u>", name
, instance
, container
);
2116 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: key=%s version=%d", key
, version
);
2118 /* capture all userState publication for later clean up if required */
2119 if (sipe_strequal(name
, "state") && (container
== 2 || container
== 3)) {
2120 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
2122 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "userState")) {
2123 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
2124 publication
->category
= g_strdup(name
);
2125 publication
->instance
= instance
;
2126 publication
->container
= container
;
2127 publication
->version
= version
;
2129 if (!sipe_private
->user_state_publications
) {
2130 sipe_private
->user_state_publications
= g_hash_table_new_full(
2131 g_str_hash
, g_str_equal
,
2132 g_free
, (GDestroyNotify
)free_publication
);
2134 g_hash_table_insert(sipe_private
->user_state_publications
, g_strdup(key
), publication
);
2135 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added to user_state_publications key=%s version=%d",
2140 /* count each client instance only once */
2141 if (sipe_strequal(name
, "device"))
2142 g_hash_table_replace(devices
, g_strdup_printf("%u", instance
), NULL
);
2144 if (sipe_is_our_publication(sipe_private
, key
)) {
2145 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
2147 publication
->category
= g_strdup(name
);
2148 publication
->instance
= instance
;
2149 publication
->container
= container
;
2150 publication
->version
= version
;
2152 /* filling publication->availability */
2153 if (sipe_strequal(name
, "state")) {
2154 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
2155 const sipe_xml
*xn_avail
= sipe_xml_child(xn_state
, "availability");
2158 gchar
*avail_str
= sipe_xml_data(xn_avail
);
2160 publication
->availability
= atoi(avail_str
);
2164 /* for calendarState */
2165 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "calendarState")) {
2166 const sipe_xml
*xn_activity
= sipe_xml_child(xn_state
, "activity");
2167 struct sipe_cal_event
*event
= g_new0(struct sipe_cal_event
, 1);
2169 event
->start_time
= sipe_utils_str_to_time(sipe_xml_attribute(xn_state
, "startTime"));
2171 if (sipe_strequal(sipe_xml_attribute(xn_activity
, "token"),
2172 sipe_status_activity_to_token(SIPE_ACTIVITY_IN_MEETING
)))
2174 event
->is_meeting
= TRUE
;
2177 event
->subject
= sipe_xml_data(sipe_xml_child(xn_state
, "meetingSubject"));
2178 event
->location
= sipe_xml_data(sipe_xml_child(xn_state
, "meetingLocation"));
2180 publication
->cal_event_hash
= sipe_cal_event_hash(event
);
2181 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: hash=%s",
2182 publication
->cal_event_hash
);
2183 sipe_cal_event_free(event
);
2186 /* filling publication->note */
2187 if (sipe_strequal(name
, "note")) {
2188 const sipe_xml
*xn_body
= sipe_xml_child(node
, "note/body");
2190 if (!has_note_cleaned
) {
2191 has_note_cleaned
= TRUE
;
2193 g_free(sipe_private
->note
);
2194 sipe_private
->note
= NULL
;
2195 sipe_private
->note_since
= publish_time
;
2197 do_update_status
= TRUE
;
2200 g_free(publication
->note
);
2201 publication
->note
= NULL
;
2205 publication
->note
= g_markup_escape_text((tmp
= sipe_xml_data(xn_body
)), -1);
2207 if (publish_time
>= sipe_private
->note_since
) {
2208 g_free(sipe_private
->note
);
2209 sipe_private
->note
= g_strdup(publication
->note
);
2210 sipe_private
->note_since
= publish_time
;
2211 if (sipe_strequal(sipe_xml_attribute(xn_body
, "type"), "OOF"))
2212 SIPE_CORE_PRIVATE_FLAG_SET(OOF_NOTE
);
2214 SIPE_CORE_PRIVATE_FLAG_UNSET(OOF_NOTE
);
2216 do_update_status
= TRUE
;
2221 /* filling publication->fb_start_str, free_busy_base64, working_hours_xml_str */
2222 if (sipe_strequal(name
, "calendarData") && (publication
->container
== 300)) {
2223 const sipe_xml
*xn_free_busy
= sipe_xml_child(node
, "calendarData/freeBusy");
2224 const sipe_xml
*xn_working_hours
= sipe_xml_child(node
, "calendarData/WorkingHours");
2226 publication
->fb_start_str
= g_strdup(sipe_xml_attribute(xn_free_busy
, "startTime"));
2227 publication
->free_busy_base64
= sipe_xml_data(xn_free_busy
);
2229 if (xn_working_hours
) {
2230 publication
->working_hours_xml_str
= sipe_xml_stringify(xn_working_hours
);
2234 if (!cat_publications
) {
2235 cat_publications
= g_hash_table_new_full(
2236 g_str_hash
, g_str_equal
,
2237 g_free
, (GDestroyNotify
)free_publication
);
2238 g_hash_table_insert(sipe_private
->our_publications
, g_strdup(name
), cat_publications
);
2239 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added GHashTable cat=%s", name
);
2241 g_hash_table_insert(cat_publications
, g_strdup(key
), publication
);
2242 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added key=%s version=%d", key
, version
);
2246 /* aggregateState (not an our publication) from 2-nd container */
2247 if (sipe_strequal(name
, "state") && container
== 2) {
2248 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
2249 const sipe_xml
*xn_activity
= sipe_xml_child(xn_state
, "activity");
2251 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "aggregateState")) {
2252 const sipe_xml
*xn_avail
= sipe_xml_child(xn_state
, "availability");
2255 gchar
*avail_str
= sipe_xml_data(xn_avail
);
2257 aggreg_avail
= atoi(avail_str
);
2262 do_update_status
= TRUE
;
2266 activity_token
= g_strdup(sipe_xml_attribute(xn_activity
, "token"));
2270 /* userProperties published by server from AD */
2271 if (!sipe_private
->csta
&&
2272 sipe_strequal(name
, "userProperties")) {
2273 const sipe_xml
*line
;
2274 /* line, for Remote Call Control (RCC) or external Lync/Communicator call */
2275 for (line
= sipe_xml_child(node
, "userProperties/lines/line"); line
; line
= sipe_xml_twin(line
)) {
2276 const gchar
*line_type
= sipe_xml_attribute(line
, "lineType");
2277 gchar
*line_uri
= sipe_xml_data(line
);
2282 if (sipe_strequal(line_type
, "Rcc") || sipe_strequal(line_type
, "Dual")) {
2283 const gchar
*line_server
= sipe_xml_attribute(line
, "lineServer");
2285 gchar
*tmp
= g_strstrip(line_uri
);
2286 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: line_uri=%s server=%s",
2288 sip_csta_open(sipe_private
, tmp
, line_server
);
2292 else if (sipe_strequal(line_type
, "Uc")) {
2294 if (!sipe_private
->uc_line_uri
) {
2295 sipe_private
->uc_line_uri
= g_strdup(g_strstrip(line_uri
));
2297 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self: "
2298 "sipe_private->uc_line_uri is already set.");
2309 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sipe_private->our_publications size=%d",
2310 sipe_private
->our_publications
? (int) g_hash_table_size(sipe_private
->our_publications
) : -1);
2312 /* active clients for user account */
2313 if (g_hash_table_size(devices
) > 1) {
2314 SIPE_CORE_PRIVATE_FLAG_SET(MPOP
);
2315 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: multiple clients detected (%d)",
2316 g_hash_table_size(devices
));
2318 SIPE_CORE_PRIVATE_FLAG_UNSET(MPOP
);
2319 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self: single client detected");
2321 g_hash_table_destroy(devices
);
2324 for (node
= sipe_xml_child(xml
, "containers/container"); node
; node
= sipe_xml_twin(node
)) {
2325 guint id
= sipe_xml_int_attribute(node
, "id", 0);
2326 struct sipe_container
*container
= sipe_find_container(sipe_private
, id
);
2329 sipe_private
->containers
= g_slist_remove(sipe_private
->containers
, container
);
2330 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removed existing container id=%d v%d", container
->id
, container
->version
);
2331 sipe_ocs2007_free_container(container
);
2333 container
= g_new0(struct sipe_container
, 1);
2335 container
->version
= sipe_xml_int_attribute(node
, "version", 0);
2336 sipe_private
->containers
= g_slist_append(sipe_private
->containers
, container
);
2337 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container id=%d v%d", container
->id
, container
->version
);
2339 for (node2
= sipe_xml_child(node
, "member"); node2
; node2
= sipe_xml_twin(node2
)) {
2340 struct sipe_container_member
*member
= g_new0(struct sipe_container_member
, 1);
2341 member
->type
= g_strdup(sipe_xml_attribute(node2
, "type"));
2342 member
->value
= g_strdup(sipe_xml_attribute(node2
, "value"));
2343 container
->members
= g_slist_append(container
->members
, member
);
2344 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container member type=%s value=%s",
2345 member
->type
, member
->value
? member
->value
: "");
2349 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: access_level_set=%s",
2350 SIPE_CORE_PRIVATE_FLAG_IS(ACCESS_LEVEL_SET
) ? "TRUE" : "FALSE");
2351 if (!SIPE_CORE_PRIVATE_FLAG_IS(ACCESS_LEVEL_SET
) && sipe_xml_child(xml
, "containers")) {
2352 char *container_xmls
= NULL
;
2353 int sameEnterpriseAL
= sipe_ocs2007_find_access_level(sipe_private
, "sameEnterprise", NULL
, NULL
);
2354 int federatedAL
= sipe_ocs2007_find_access_level(sipe_private
, "federated", NULL
, NULL
);
2356 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sameEnterpriseAL=%d", sameEnterpriseAL
);
2357 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: federatedAL=%d", federatedAL
);
2358 /* initial set-up to let counterparties see your status */
2359 if (sameEnterpriseAL
< 0) {
2360 struct sipe_container
*container
= sipe_find_container(sipe_private
, 200);
2361 guint version
= container
? container
->version
: 0;
2362 sipe_send_container_members_prepare(200, version
, "add", "sameEnterprise", NULL
, &container_xmls
);
2364 if (federatedAL
< 0) {
2365 struct sipe_container
*container
= sipe_find_container(sipe_private
, 100);
2366 guint version
= container
? container
->version
: 0;
2367 sipe_send_container_members_prepare(100, version
, "add", "federated", NULL
, &container_xmls
);
2369 SIPE_CORE_PRIVATE_FLAG_SET(ACCESS_LEVEL_SET
);
2371 if (container_xmls
) {
2372 sipe_send_set_container_members(sipe_private
, container_xmls
);
2374 g_free(container_xmls
);
2377 /* Refresh contacts' blocked status */
2378 sipe_refresh_blocked_status(sipe_private
);
2381 for (node
= sipe_xml_child(xml
, "subscribers/subscriber"); node
; node
= sipe_xml_twin(node
)) {
2383 const char *acknowledged
;
2387 user
= sipe_xml_attribute(node
, "user"); /* without 'sip:' prefix */
2388 if (!user
) continue;
2389 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user %s", user
);
2390 display_name
= g_strdup(sipe_xml_attribute(node
, "displayName"));
2391 uri
= sip_uri_from_name(user
);
2393 sipe_buddy_update_property(sipe_private
, uri
, SIPE_BUDDY_INFO_DISPLAY_NAME
, display_name
);
2394 sipe_backend_buddy_refresh_properties(SIPE_CORE_PUBLIC
, uri
);
2396 acknowledged
= sipe_xml_attribute(node
, "acknowledged");
2397 if(sipe_strcase_equal(acknowledged
,"false")){
2398 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user added you %s", user
);
2399 if (!sipe_backend_buddy_find(SIPE_CORE_PUBLIC
, uri
, NULL
)) {
2400 sipe_backend_buddy_request_add(SIPE_CORE_PUBLIC
, uri
, display_name
);
2403 hdr
= g_strdup_printf(
2405 "Content-Type: application/msrtc-presence-setsubscriber+xml\r\n", contact
);
2407 body
= g_strdup_printf(
2408 "<setSubscribers xmlns=\"http://schemas.microsoft.com/2006/09/sip/presence-subscribers\">"
2409 "<subscriber user=\"%s\" acknowledged=\"true\"/>"
2410 "</setSubscribers>", user
);
2412 sip_transport_service(sipe_private
,
2420 g_free(display_name
);
2427 /* Publish initial state if not yet.
2428 * Assuming this happens on initial responce to subscription to roaming-self
2429 * so we've already updated our roaming data in full.
2432 if (!SIPE_CORE_PRIVATE_FLAG_IS(INITIAL_PUBLISH
)) {
2433 send_publish_category_initial(sipe_private
);
2434 SIPE_CORE_PRIVATE_FLAG_SET(INITIAL_PUBLISH
);
2436 sipe_cal_delayed_calendar_update(sipe_private
);
2437 do_update_status
= FALSE
;
2438 } else if (aggreg_avail
) {
2441 (aggreg_avail
< SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE
)) {
2443 sipe_status_set_token(sipe_private
,
2444 sipe_ocs2007_status_from_legacy_availability(aggreg_avail
, activity_token
));
2446 /* do not let offline status switch us off */
2447 sipe_status_set_activity(sipe_private
,
2448 SIPE_ACTIVITY_INVISIBLE
);
2452 if (do_update_status
) {
2453 sipe_status_and_note(sipe_private
, NULL
);
2457 g_free(activity_token
);
2461 * for Access levels menu
2463 #define INDENT_FMT " %s"
2466 * Member is indirectly belong to access level container.
2467 * For example 'sameEnterprise' is in the container and user
2468 * belongs to that same enterprise.
2470 #define INDENT_MARKED_INHERITED_FMT "= %s"
2472 static struct sipe_backend_buddy_menu
*access_levels_menu(struct sipe_core_private
*sipe_private
,
2473 struct sipe_backend_buddy_menu
*menu
,
2474 const gchar
*member_type
,
2475 const gchar
*member_value
,
2476 const gboolean extra_menu
)
2479 gboolean is_group_access
= FALSE
;
2483 menu
= sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC
);
2485 container_id
= sipe_ocs2007_find_access_level(sipe_private
,
2490 for (i
= 1; i
<= CONTAINERS_LEN
; i
++) {
2492 * Blocked should remain in the first place
2493 * in the containers[] array.
2495 unsigned int j
= (i
== CONTAINERS_LEN
) ? 0 : i
;
2496 int container_j
= containers
[j
];
2497 const gchar
*acc_level_name
= sipe_ocs2007_access_level_name(container_j
);
2498 struct sipe_container
*container
= create_container(j
,
2504 /* libpurple memory leak workaround */
2505 blist_menu_remember_container(sipe_private
, container
);
2507 /* current container/access level */
2508 if (container_j
== container_id
) {
2509 label
= is_group_access
?
2510 g_strdup_printf(INDENT_MARKED_INHERITED_FMT
, acc_level_name
) :
2511 g_strdup_printf(SIPE_OCS2007_INDENT_MARKED_FMT
, acc_level_name
);
2513 label
= g_strdup_printf(INDENT_FMT
, acc_level_name
);
2516 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2519 SIPE_BUDDY_MENU_CHANGE_ACCESS_LEVEL
,
2524 if (extra_menu
&& (container_id
>= 0) && !is_group_access
) {
2525 struct sipe_container
*container
= create_container(0,
2532 menu
= sipe_backend_buddy_menu_separator(SIPE_CORE_PUBLIC
,
2537 /* libpurple memory leak workaround */
2538 blist_menu_remember_container(sipe_private
, container
);
2540 /* Translators: remove (clear) previously assigned access level */
2541 label
= g_strdup_printf(INDENT_FMT
, _("Unspecify"));
2542 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2545 SIPE_BUDDY_MENU_CHANGE_ACCESS_LEVEL
,
2553 static struct sipe_backend_buddy_menu
*access_groups_menu(struct sipe_core_private
*sipe_private
)
2555 struct sipe_backend_buddy_menu
*menu
= sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC
);
2556 GSList
*access_domains
, *entry
;
2558 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2560 _("People in my company"),
2561 access_levels_menu(sipe_private
,
2567 /* this is original name, don't edit */
2568 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2570 _("People in domains connected with my company"),
2571 access_levels_menu(sipe_private
,
2577 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2579 _("People in public domains"),
2580 access_levels_menu(sipe_private
,
2586 entry
= access_domains
= get_access_domains(sipe_private
);
2588 gchar
*domain
= entry
->data
;
2589 gchar
*menu_name
= g_strdup_printf(_("People at %s"), domain
);
2591 /* takes over ownership of entry->data (= domain) */
2592 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2595 access_levels_menu(sipe_private
,
2602 entry
= entry
->next
;
2604 g_slist_free(access_domains
);
2607 /* People in domains connected with my company */
2608 menu
= sipe_backend_buddy_menu_separator(SIPE_CORE_PUBLIC
,
2610 "-------------------------------------------");
2612 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2614 _("Add new domain..."),
2615 SIPE_BUDDY_MENU_ADD_NEW_DOMAIN
,
2621 struct sipe_backend_buddy_menu
*sipe_ocs2007_access_control_menu(struct sipe_core_private
*sipe_private
,
2622 const gchar
*buddy_name
)
2624 struct sipe_backend_buddy_menu
*menu
= sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC
);
2628 * Workaround for missing libpurple API to release resources allocated
2629 * during blist_node_menu() callback. See also:
2631 * <http://developer.pidgin.im/ticket/12597>
2633 * We remember all memory blocks in a list and deallocate them when
2635 * - the next time we enter the callback, or
2636 * - the account is disconnected
2638 * That means that after the buddy menu has been closed we have unused
2639 * resources but at least we don't leak them anymore...
2641 sipe_core_buddy_menu_free(SIPE_CORE_PUBLIC
);
2643 label
= g_strdup_printf(INDENT_FMT
, _("Online help..."));
2644 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2647 SIPE_BUDDY_MENU_ACCESS_LEVEL_HELP
,
2651 label
= g_strdup_printf(INDENT_FMT
, _("Access groups"));
2652 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2655 access_groups_menu(sipe_private
));
2658 menu
= access_levels_menu(sipe_private
,
2661 sipe_get_no_sip_uri(buddy_name
),