6 * Copyright (C) 2011 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"
39 #include "http-conn.h"
42 #include "sip-transport.h"
43 #include "sipe-backend.h"
44 #include "sipe-buddy.h"
46 #include "sipe-core.h"
47 #include "sipe-core-private.h"
49 #include "sipe-groupchat.h"
51 #include "sipe-ocs2007.h"
52 #include "sipe-schedule.h"
53 #include "sipe-status.h"
54 #include "sipe-utils.h"
57 #define _SIPE_NEED_ACTIVITIES /* ugly hack :-( */
60 static void send_presence_publish(struct sipe_core_private
*sipe_private
,
61 const char *publications
);
63 static void free_publication(struct sipe_publication
*publication
)
65 g_free(publication
->category
);
66 g_free(publication
->cal_event_hash
);
67 g_free(publication
->note
);
69 g_free(publication
->working_hours_xml_str
);
70 g_free(publication
->fb_start_str
);
71 g_free(publication
->free_busy_base64
);
76 struct hash_table_delete_payload
{
77 GHashTable
*hash_table
;
81 static void sipe_remove_category_container_publications_cb(const gchar
*name
,
82 struct sipe_publication
*publication
,
83 struct hash_table_delete_payload
*payload
)
85 if (publication
->container
== payload
->container
) {
86 g_hash_table_remove(payload
->hash_table
, name
);
90 static void sipe_remove_category_container_publications(GHashTable
*our_publications
,
91 const gchar
*category
,
94 struct hash_table_delete_payload payload
;
95 payload
.hash_table
= g_hash_table_lookup(our_publications
, category
);
97 if (!payload
.hash_table
) return;
99 payload
.container
= container
;
100 g_hash_table_foreach(payload
.hash_table
,
101 (GHFunc
)sipe_remove_category_container_publications_cb
,
105 /** MS-PRES container */
106 struct sipe_container
{
112 /** MS-PRES container member */
113 struct sipe_container_member
{
114 /** user, domain, sameEnterprise, federated, publicCloud; everyone */
119 static const guint containers
[] = {32000, 400, 300, 200, 100};
120 #define CONTAINERS_LEN (sizeof(containers) / sizeof(guint))
122 guint
sipe_ocs2007_containers(void)
124 return(CONTAINERS_LEN
);
127 static void free_container_member(struct sipe_container_member
*member
)
131 g_free(member
->type
);
132 g_free(member
->value
);
136 void sipe_ocs2007_free_container(struct sipe_container
*container
)
140 if (!container
) return;
142 entry
= container
->members
;
144 void *data
= entry
->data
;
145 entry
= g_slist_remove(entry
, data
);
146 free_container_member((struct sipe_container_member
*)data
);
151 struct sipe_container
*sipe_ocs2007_create_container(guint index
,
152 const gchar
*member_type
,
153 const gchar
*member_value
,
156 struct sipe_container
*container
= g_new0(struct sipe_container
, 1);
157 struct sipe_container_member
*member
= g_new0(struct sipe_container_member
, 1);
159 container
->id
= is_group
? (guint
) -1 : containers
[index
];
160 container
->members
= g_slist_append(container
->members
, member
);
161 member
->type
= g_strdup(member_type
);
162 member
->value
= g_strdup(member_value
);
167 void sipe_ocs2007_free(struct sipe_core_private
*sipe_private
)
169 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
171 if (sip
->containers
) {
172 GSList
*entry
= sip
->containers
;
174 sipe_ocs2007_free_container((struct sipe_container
*)entry
->data
);
178 g_slist_free(sip
->containers
);
182 * Finds locally stored MS-PRES container member
184 static struct sipe_container_member
*
185 sipe_find_container_member(struct sipe_container
*container
,
189 struct sipe_container_member
*member
;
192 if (container
== NULL
|| type
== NULL
) {
196 entry
= container
->members
;
198 member
= entry
->data
;
199 if (sipe_strcase_equal(member
->type
, type
) &&
200 sipe_strcase_equal(member
->value
, value
))
210 * Finds locally stored MS-PRES container by id
212 static struct sipe_container
*sipe_find_container(struct sipe_core_private
*sipe_private
,
215 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
216 struct sipe_container
*container
;
223 entry
= sip
->containers
;
225 container
= entry
->data
;
226 if (id
== container
->id
) {
234 static int sipe_find_member_access_level(struct sipe_core_private
*sipe_private
,
239 const gchar
*value_mod
= value
;
241 if (!type
) return -1;
243 if (sipe_strequal("user", type
)) {
244 value_mod
= sipe_get_no_sip_uri(value
);
247 for (i
= 0; i
< CONTAINERS_LEN
; i
++) {
248 struct sipe_container_member
*member
;
249 struct sipe_container
*container
= sipe_find_container(sipe_private
, containers
[i
]);
250 if (!container
) continue;
252 member
= sipe_find_container_member(container
, type
, value_mod
);
253 if (member
) return containers
[i
];
260 * Returns pointer to domain part in provided Email URL
262 * @param email an email URL. Example: first.last@hq.company.com
263 * @return pointer to domain part of email URL. Coresponding example: hq.company.com
265 * Doesn't allocate memory
267 static const gchar
*sipe_get_domain(const gchar
*email
)
271 if (!email
) return NULL
;
273 tmp
= strstr(email
, "@");
275 if (tmp
&& ((tmp
+1) < (email
+ strlen(email
)))) {
282 /* @TODO: replace with binary search for faster access? */
283 /** source: http://support.microsoft.com/kb/897567 */
284 static const gchar
* const public_domains
[] = {
285 "aol.com", "icq.com", "love.com", "mac.com", "br.live.com",
286 "hotmail.co.il", "hotmail.co.jp", "hotmail.co.th", "hotmail.co.uk",
287 "hotmail.com", "hotmail.com.ar", "hotmail.com.tr", "hotmail.es",
288 "hotmail.de", "hotmail.fr", "hotmail.it", "live.at", "live.be",
289 "live.ca", "live.cl", "live.cn", "live.co.in", "live.co.kr",
290 "live.co.uk", "live.co.za", "live.com", "live.com.ar", "live.com.au",
291 "live.com.co", "live.com.mx", "live.com.my", "live.com.pe",
292 "live.com.ph", "live.com.pk", "live.com.pt", "live.com.sg",
293 "live.com.ve", "live.de", "live.dk", "live.fr", "live.hk", "live.ie",
294 "live.in", "live.it", "live.jp", "live.nl", "live.no", "live.ph",
295 "live.ru", "live.se", "livemail.com.br", "livemail.tw",
296 "messengeruser.com", "msn.com", "passport.com", "sympatico.ca",
297 "tw.live.com", "webtv.net", "windowslive.com", "windowslive.es",
301 static gboolean
sipe_is_public_domain(const gchar
*domain
)
304 while (public_domains
[i
]) {
305 if (sipe_strcase_equal(public_domains
[i
], domain
)) {
321 const gchar
*sipe_ocs2007_access_level_name(guint id
)
324 case 32000: return _("Blocked");
325 case 400: return _("Personal");
326 case 300: return _("Team");
327 case 200: return _("Company");
328 case 100: return _("Public");
333 int sipe_ocs2007_container_id(guint index
)
335 return(containers
[index
]);
338 /** Member type: user, domain, sameEnterprise, federated, publicCloud; everyone */
339 int sipe_ocs2007_find_access_level(struct sipe_core_private
*sipe_private
,
342 gboolean
*is_group_access
)
344 int container_id
= -1;
346 if (sipe_strequal("user", type
)) {
348 const char *no_sip_uri
= sipe_get_no_sip_uri(value
);
350 container_id
= sipe_find_member_access_level(sipe_private
, "user", no_sip_uri
);
351 if (container_id
>= 0) {
352 if (is_group_access
) *is_group_access
= FALSE
;
356 domain
= sipe_get_domain(no_sip_uri
);
357 container_id
= sipe_find_member_access_level(sipe_private
, "domain", domain
);
358 if (container_id
>= 0) {
359 if (is_group_access
) *is_group_access
= TRUE
;
363 container_id
= sipe_find_member_access_level(sipe_private
, "sameEnterprise", NULL
);
364 if ((container_id
>= 0) && sipe_strcase_equal(sipe_private
->public.sip_domain
, domain
)) {
365 if (is_group_access
) *is_group_access
= TRUE
;
369 container_id
= sipe_find_member_access_level(sipe_private
, "publicCloud", NULL
);
370 if ((container_id
>= 0) && sipe_is_public_domain(domain
)) {
371 if (is_group_access
) *is_group_access
= TRUE
;
375 container_id
= sipe_find_member_access_level(sipe_private
, "everyone", NULL
);
376 if ((container_id
>= 0)) {
377 if (is_group_access
) *is_group_access
= TRUE
;
381 container_id
= sipe_find_member_access_level(sipe_private
, type
, value
);
382 if (is_group_access
) *is_group_access
= FALSE
;
388 GSList
*sipe_ocs2007_get_access_domains(struct sipe_core_private
*sipe_private
)
390 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
391 struct sipe_container
*container
;
392 struct sipe_container_member
*member
;
397 if (!sip
) return NULL
;
399 entry
= sip
->containers
;
401 container
= entry
->data
;
403 entry2
= container
->members
;
405 member
= entry2
->data
;
406 if (sipe_strcase_equal(member
->type
, "domain"))
408 res
= slist_insert_unique_sorted(res
, g_strdup(member
->value
), (GCompareFunc
)g_ascii_strcasecmp
);
410 entry2
= entry2
->next
;
417 static void sipe_send_container_members_prepare(const guint container_id
,
418 const guint container_version
,
422 char **container_xmls
)
424 gchar
*value_str
= value
? g_strdup_printf(" value=\"%s\"", value
) : g_strdup("");
427 if (!container_xmls
) return;
429 body
= g_strdup_printf(
430 "<container id=\"%d\" version=\"%d\"><member action=\"%s\" type=\"%s\"%s/></container>",
438 if ((*container_xmls
) == NULL
) {
439 *container_xmls
= body
;
441 char *tmp
= *container_xmls
;
443 *container_xmls
= g_strconcat(*container_xmls
, body
, NULL
);
449 static void sipe_send_set_container_members(struct sipe_core_private
*sipe_private
,
450 char *container_xmls
)
457 if (!container_xmls
) return;
459 self
= sip_uri_self(sipe_private
);
460 body
= g_strdup_printf(
461 "<setContainerMembers xmlns=\"http://schemas.microsoft.com/2006/09/sip/container-management\">"
463 "</setContainerMembers>",
466 contact
= get_contact(sipe_private
);
467 hdr
= g_strdup_printf("Contact: %s\r\n"
468 "Content-Type: application/msrtc-setcontainermembers+xml\r\n", contact
);
471 sip_transport_service(sipe_private
,
483 * @param container_id a new access level. If -1 then current access level
484 * is just removed (I.e. the member is removed from all containers).
485 * @param type a type of member. E.g. "user", "sameEnterprise", etc.
486 * @param value a value for member. E.g. SIP URI for "user" member type.
488 void sipe_ocs2007_change_access_level(struct sipe_core_private
*sipe_private
,
489 const int container_id
,
494 int current_container_id
= -1;
495 char *container_xmls
= NULL
;
497 /* for each container: find/delete */
498 for (i
= 0; i
< CONTAINERS_LEN
; i
++) {
499 struct sipe_container_member
*member
;
500 struct sipe_container
*container
= sipe_find_container(sipe_private
, containers
[i
]);
502 if (!container
) continue;
504 member
= sipe_find_container_member(container
, type
, value
);
506 current_container_id
= containers
[i
];
507 /* delete/publish current access level */
508 if (container_id
< 0 || container_id
!= current_container_id
) {
509 sipe_send_container_members_prepare(current_container_id
, container
->version
, "remove", type
, value
, &container_xmls
);
510 /* remove member from our cache, to be able to recalculate AL below */
511 container
->members
= g_slist_remove(container
->members
, member
);
512 current_container_id
= -1;
517 /* recalculate AL below */
518 current_container_id
= sipe_ocs2007_find_access_level(sipe_private
, type
, value
, NULL
);
520 /* assign/publish new access level */
521 if (container_id
!= current_container_id
&& container_id
>= 0) {
522 struct sipe_container
*container
= sipe_find_container(sipe_private
, container_id
);
523 guint version
= container
? container
->version
: 0;
525 sipe_send_container_members_prepare(container_id
, version
, "add", type
, value
, &container_xmls
);
528 if (container_xmls
) {
529 sipe_send_set_container_members(sipe_private
, container_xmls
);
531 g_free(container_xmls
);
534 void sipe_ocs2007_change_access_level_from_container(struct sipe_core_private
*sipe_private
,
535 struct sipe_container
*container
)
537 struct sipe_container_member
*member
;
539 if (!container
|| !container
->members
) return;
541 member
= ((struct sipe_container_member
*)container
->members
->data
);
543 if (!member
->type
) return;
545 SIPE_DEBUG_INFO("sipe_ocs2007_change_access_level_from_container: container->id=%d, member->type=%s, member->value=%s",
546 container
->id
, member
->type
, member
->value
? member
->value
: "");
548 sipe_ocs2007_change_access_level(sipe_private
,
555 void sipe_ocs2007_change_access_level_for_domain(struct sipe_core_private
*sipe_private
,
559 /* move Blocked first */
560 guint i
= (index
== 4) ? 0 : index
+ 1;
561 guint container_id
= containers
[i
];
563 SIPE_DEBUG_INFO("sipe_ocs2007_change_access_level_from_id: domain=%s, container_id=(%d)%d",
564 domain
? domain
: "", index
, container_id
);
566 sipe_ocs2007_change_access_level(sipe_private
,
574 * Schedules process of self status publish
575 * based on own calendar information.
576 * Should be scheduled to the beginning of every
577 * 15 min interval, like:
578 * 13:00, 13:15, 13:30, 13:45, etc.
581 static void schedule_publish_update(struct sipe_core_private
*sipe_private
,
582 time_t calculate_from
)
585 /** start of the beginning of closest 5 min interval. */
586 time_t next_start
= ((time_t)((int)((int)calculate_from
)/interval
+ 1)*interval
);
588 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: calculate_from time: %s",
589 asctime(localtime(&calculate_from
)));
590 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: next start time : %s",
591 asctime(localtime(&next_start
)));
593 sipe_schedule_seconds(sipe_private
,
594 "<+2007-cal-status>",
596 next_start
- time(NULL
),
597 sipe_ocs2007_presence_publish
,
602 * An availability XML entry for SIPE_PUB_XML_STATE_CALENDAR
603 * @param availability (%d) Ex.: 6500
605 #define SIPE_PUB_XML_STATE_CALENDAR_AVAIL \
606 "<availability>%d</availability>"
608 * An activity XML entry for SIPE_PUB_XML_STATE_CALENDAR
609 * @param token (%s) Ex.: in-a-meeting
610 * @param minAvailability_attr (%s) Ex.: minAvailability="6500"
611 * @param maxAvailability_attr (%s) Ex.: maxAvailability="8999" or none
613 #define SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY \
614 "<activity token=\"%s\" %s %s></activity>"
616 * Publishes 'calendarState' category.
617 * @param instance (%u) Ex.: 1339299275
618 * @param version (%u) Ex.: 1
619 * @param uri (%s) Ex.: john@contoso.com
620 * @param start_time_str (%s) Ex.: 2008-01-11T19:00:00Z
621 * @param availability (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_AVAIL
622 * @param activity (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
623 * @param meeting_subject (%s) Ex.: Customer Meeting
624 * @param meeting_location (%s) Ex.: Conf Room 100
626 * @param instance (%u) Ex.: 1339299275
627 * @param version (%u) Ex.: 1
628 * @param uri (%s) Ex.: john@contoso.com
629 * @param start_time_str (%s) Ex.: 2008-01-11T19:00:00Z
630 * @param availability (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_AVAIL
631 * @param activity (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
632 * @param meeting_subject (%s) Ex.: Customer Meeting
633 * @param meeting_location (%s) Ex.: Conf Room 100
635 #define SIPE_PUB_XML_STATE_CALENDAR \
636 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
637 "<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\">"\
640 "<endpointLocation/>"\
641 "<meetingSubject>%s</meetingSubject>"\
642 "<meetingLocation>%s</meetingLocation>"\
645 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
646 "<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\">"\
649 "<endpointLocation/>"\
650 "<meetingSubject>%s</meetingSubject>"\
651 "<meetingLocation>%s</meetingLocation>"\
655 * Publishes to clear 'calendarState' category
656 * @param instance (%u) Ex.: 1251210982
657 * @param version (%u) Ex.: 1
659 #define SIPE_PUB_XML_STATE_CALENDAR_CLEAR \
660 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"\
661 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"
664 * Publishes to clear any category
665 * @param category_name (%s) Ex.: state
666 * @param instance (%u) Ex.: 536870912
667 * @param container (%u) Ex.: 3
668 * @param version (%u) Ex.: 1
669 * @param expireType (%s) Ex.: static
671 #define SIPE_PUB_XML_PUBLICATION_CLEAR \
672 "<publication categoryName=\"%s\" instance=\"%u\" container=\"%u\" version=\"%u\" expireType=\"%s\" expires=\"0\"/>"
675 * Publishes 'note' category.
676 * @param instance (%u) Ex.: 2135971629; 0 for personal
677 * @param container (%u) Ex.: 200
678 * @param version (%u) Ex.: 2
679 * @param type (%s) Ex.: personal or OOF
680 * @param startTime_attr (%s) Ex.: startTime="2008-01-11T19:00:00Z"
681 * @param endTime_attr (%s) Ex.: endTime="2008-01-15T19:00:00Z"
682 * @param body (%s) Ex.: In the office
684 #define SIPE_PUB_XML_NOTE \
685 "<publication categoryName=\"note\" instance=\"%u\" container=\"%u\" version=\"%d\" expireType=\"static\">"\
686 "<note xmlns=\"http://schemas.microsoft.com/2006/09/sip/note\">"\
687 "<body type=\"%s\" uri=\"\"%s%s>%s</body>"\
692 * Only Busy and OOF calendar event are published.
693 * Different instances are used for that.
695 * Must be g_free'd after use.
697 static gchar
*sipe_publish_get_category_state_calendar(struct sipe_core_private
*sipe_private
,
698 struct sipe_cal_event
*event
,
702 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
703 gchar
*start_time_str
;
704 int availability
= 0;
707 guint instance
= (cal_satus
== SIPE_CAL_OOF
) ?
708 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR_OOF
) :
709 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR
);
711 /* key is <category><instance><container> */
712 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
713 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
714 struct sipe_publication
*publication_2
=
715 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "state"), key_2
);
716 struct sipe_publication
*publication_3
=
717 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "state"), key_3
);
722 if (!publication_3
&& !event
) { /* was nothing, have nothing, exiting */
723 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
724 "Exiting as no publication and no event for cal_satus:%d", cal_satus
);
730 (publication_3
->availability
== availability
) &&
731 sipe_strequal(publication_3
->cal_event_hash
, (tmp
= sipe_cal_event_hash(event
))))
734 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
735 "cal state has NOT changed for cal_satus:%d. Exiting.", cal_satus
);
736 return NULL
; /* nothing to update */
741 (event
->cal_status
== SIPE_CAL_BUSY
||
742 event
->cal_status
== SIPE_CAL_OOF
))
744 gchar
*availability_xml_str
= NULL
;
745 gchar
*activity_xml_str
= NULL
;
746 gchar
*escaped_subject
= event
->subject
? g_markup_escape_text(event
->subject
, -1) : NULL
;
747 gchar
*escaped_location
= event
->location
? g_markup_escape_text(event
->location
, -1) : NULL
;
749 if (event
->cal_status
== SIPE_CAL_BUSY
) {
750 availability_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_AVAIL
, 6500);
753 if (event
->cal_status
== SIPE_CAL_BUSY
&& event
->is_meeting
) {
754 activity_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
,
755 sipe_activity_to_token(SIPE_ACTIVITY_IN_MEETING
),
756 "minAvailability=\"6500\"",
757 "maxAvailability=\"8999\"");
758 } else if (event
->cal_status
== SIPE_CAL_OOF
) {
759 activity_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
,
760 sipe_activity_to_token(SIPE_ACTIVITY_OOF
),
761 "minAvailability=\"12000\"",
764 start_time_str
= sipe_utils_time_to_str(event
->start_time
);
766 res
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR
,
768 publication_2
? publication_2
->version
: 0,
771 availability_xml_str
? availability_xml_str
: "",
772 activity_xml_str
? activity_xml_str
: "",
773 escaped_subject
? escaped_subject
: "",
774 escaped_location
? escaped_location
: "",
777 publication_3
? publication_3
->version
: 0,
780 availability_xml_str
? availability_xml_str
: "",
781 activity_xml_str
? activity_xml_str
: "",
782 escaped_subject
? escaped_subject
: "",
783 escaped_location
? escaped_location
: ""
785 g_free(escaped_location
);
786 g_free(escaped_subject
);
787 g_free(start_time_str
);
788 g_free(availability_xml_str
);
789 g_free(activity_xml_str
);
792 else /* including !event, SIPE_CAL_FREE, SIPE_CAL_TENTATIVE */
794 res
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_CLEAR
,
796 publication_2
? publication_2
->version
: 0,
799 publication_3
? publication_3
->version
: 0
807 * Returns 'note' XML part for publication.
808 * Must be g_free'd after use.
810 * Protocol format for Note is plain text.
812 * @param note a note in Sipe internal HTML format
813 * @param note_type either personal or OOF
815 static gchar
*sipe_publish_get_category_note(struct sipe_core_private
*sipe_private
,
816 const char *note
, /* html */
817 const char *note_type
,
821 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
822 guint instance
= sipe_strequal("OOF", note_type
) ? sipe_get_pub_instance(sipe_private
, SIPE_PUB_NOTE_OOF
) : 0;
823 /* key is <category><instance><container> */
824 gchar
*key_note_200
= g_strdup_printf("<%s><%u><%u>", "note", instance
, 200);
825 gchar
*key_note_300
= g_strdup_printf("<%s><%u><%u>", "note", instance
, 300);
826 gchar
*key_note_400
= g_strdup_printf("<%s><%u><%u>", "note", instance
, 400);
828 struct sipe_publication
*publication_note_200
=
829 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "note"), key_note_200
);
830 struct sipe_publication
*publication_note_300
=
831 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "note"), key_note_300
);
832 struct sipe_publication
*publication_note_400
=
833 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "note"), key_note_400
);
835 char *tmp
= note
? sipe_backend_markup_strip_html(note
) : NULL
;
836 char *n1
= tmp
? g_markup_escape_text(tmp
, -1) : NULL
;
837 const char *n2
= publication_note_200
? publication_note_200
->note
: NULL
;
838 char *res
, *tmp1
, *tmp2
, *tmp3
;
839 char *start_time_attr
;
844 g_free(key_note_200
);
845 g_free(key_note_300
);
846 g_free(key_note_400
);
848 /* we even need to republish empty note */
849 if (sipe_strequal(n1
, n2
))
851 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_note: note has NOT changed. Exiting.");
853 return NULL
; /* nothing to update */
856 start_time_attr
= note_start
? g_strdup_printf(" startTime=\"%s\"", (tmp
= sipe_utils_time_to_str(note_start
))) : NULL
;
859 end_time_attr
= note_end
? g_strdup_printf(" endTime=\"%s\"", (tmp
= sipe_utils_time_to_str(note_end
))) : NULL
;
863 tmp1
= g_strdup_printf(SIPE_PUB_XML_NOTE
,
866 publication_note_200
? publication_note_200
->version
: 0,
868 start_time_attr
? start_time_attr
: "",
869 end_time_attr
? end_time_attr
: "",
872 tmp2
= g_strdup_printf(SIPE_PUB_XML_NOTE
,
875 publication_note_300
? publication_note_300
->version
: 0,
877 start_time_attr
? start_time_attr
: "",
878 end_time_attr
? end_time_attr
: "",
881 tmp3
= g_strdup_printf(SIPE_PUB_XML_NOTE
,
884 publication_note_400
? publication_note_400
->version
: 0,
886 start_time_attr
? start_time_attr
: "",
887 end_time_attr
? end_time_attr
: "",
890 tmp1
= g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR
,
894 publication_note_200
? publication_note_200
->version
: 0,
896 tmp2
= g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR
,
900 publication_note_200
? publication_note_200
->version
: 0,
902 tmp3
= g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR
,
906 publication_note_200
? publication_note_200
->version
: 0,
909 res
= g_strconcat(tmp1
, tmp2
, tmp3
, NULL
);
911 g_free(start_time_attr
);
912 g_free(end_time_attr
);
922 * Publishes 'calendarData' category's WorkingHours.
924 * @param version (%u) Ex.: 1
925 * @param email (%s) Ex.: alice@cosmo.local
926 * @param working_hours_xml_str (%s) Ex.: <WorkingHours xmlns=.....
928 * @param version (%u)
930 * @param version (%u)
932 * @param working_hours_xml_str (%s)
934 * @param version (%u)
936 * @param working_hours_xml_str (%s)
938 * @param version (%u)
940 * @param working_hours_xml_str (%s)
942 * @param version (%u)
944 #define SIPE_PUB_XML_WORKING_HOURS \
945 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"1\" version=\"%d\" expireType=\"static\">"\
946 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
949 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"100\" version=\"%d\" expireType=\"static\">"\
950 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
952 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"200\" version=\"%d\" expireType=\"static\">"\
953 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
956 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"300\" version=\"%d\" expireType=\"static\">"\
957 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
960 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"400\" version=\"%d\" expireType=\"static\">"\
961 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
964 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"32000\" version=\"%d\" expireType=\"static\">"\
965 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
969 * Returns 'calendarData' XML part with WorkingHours for publication.
970 * Must be g_free'd after use.
972 static gchar
*sipe_publish_get_category_cal_working_hours(struct sipe_core_private
*sipe_private
)
974 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
975 struct sipe_calendar
* cal
= sip
->cal
;
977 /* key is <category><instance><container> */
978 gchar
*key_cal_1
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1);
979 gchar
*key_cal_100
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100);
980 gchar
*key_cal_200
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200);
981 gchar
*key_cal_300
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300);
982 gchar
*key_cal_400
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400);
983 gchar
*key_cal_32000
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000);
985 struct sipe_publication
*publication_cal_1
=
986 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "calendarData"), key_cal_1
);
987 struct sipe_publication
*publication_cal_100
=
988 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "calendarData"), key_cal_100
);
989 struct sipe_publication
*publication_cal_200
=
990 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "calendarData"), key_cal_200
);
991 struct sipe_publication
*publication_cal_300
=
992 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "calendarData"), key_cal_300
);
993 struct sipe_publication
*publication_cal_400
=
994 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "calendarData"), key_cal_400
);
995 struct sipe_publication
*publication_cal_32000
=
996 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "calendarData"), key_cal_32000
);
998 const char *n1
= cal
? cal
->working_hours_xml_str
: NULL
;
999 const char *n2
= publication_cal_300
? publication_cal_300
->working_hours_xml_str
: NULL
;
1002 g_free(key_cal_100
);
1003 g_free(key_cal_200
);
1004 g_free(key_cal_300
);
1005 g_free(key_cal_400
);
1006 g_free(key_cal_32000
);
1008 if (!cal
|| is_empty(cal
->email
) || is_empty(cal
->working_hours_xml_str
)) {
1009 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_working_hours: no data to publish, exiting");
1013 if (sipe_strequal(n1
, n2
))
1015 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_working_hours: WorkingHours has NOT changed. Exiting.");
1016 return NULL
; /* nothing to update */
1019 return g_strdup_printf(SIPE_PUB_XML_WORKING_HOURS
,
1021 publication_cal_1
? publication_cal_1
->version
: 0,
1023 cal
->working_hours_xml_str
,
1025 publication_cal_100
? publication_cal_100
->version
: 0,
1027 publication_cal_200
? publication_cal_200
->version
: 0,
1029 cal
->working_hours_xml_str
,
1031 publication_cal_300
? publication_cal_300
->version
: 0,
1033 cal
->working_hours_xml_str
,
1034 /* 400 - Personal */
1035 publication_cal_400
? publication_cal_400
->version
: 0,
1037 cal
->working_hours_xml_str
,
1038 /* 32000 - Blocked */
1039 publication_cal_32000
? publication_cal_32000
->version
: 0
1044 * Publishes 'calendarData' category's FreeBusy.
1046 * @param instance (%u) Ex.: 1300372959
1047 * @param version (%u) Ex.: 1
1049 * @param instance (%u) Ex.: 1300372959
1050 * @param version (%u) Ex.: 1
1052 * @param instance (%u) Ex.: 1300372959
1053 * @param version (%u) Ex.: 1
1054 * @param email (%s) Ex.: alice@cosmo.local
1055 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1056 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1058 * @param instance (%u) Ex.: 1300372959
1059 * @param version (%u) Ex.: 1
1060 * @param email (%s) Ex.: alice@cosmo.local
1061 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1062 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1064 * @param instance (%u) Ex.: 1300372959
1065 * @param version (%u) Ex.: 1
1066 * @param email (%s) Ex.: alice@cosmo.local
1067 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1068 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1070 * @param instance (%u) Ex.: 1300372959
1071 * @param version (%u) Ex.: 1
1073 #define SIPE_PUB_XML_FREE_BUSY \
1074 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"1\" version=\"%d\" expireType=\"endpoint\">"\
1075 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1077 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"100\" version=\"%d\" expireType=\"endpoint\">"\
1078 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1080 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"200\" version=\"%d\" expireType=\"endpoint\">"\
1081 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1082 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1085 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"300\" version=\"%d\" expireType=\"endpoint\">"\
1086 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1087 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1090 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"400\" version=\"%d\" expireType=\"endpoint\">"\
1091 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1092 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1095 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"32000\" version=\"%d\" expireType=\"endpoint\">"\
1096 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1100 * Returns 'calendarData' XML part with FreeBusy for publication.
1101 * Must be g_free'd after use.
1103 static gchar
*sipe_publish_get_category_cal_free_busy(struct sipe_core_private
*sipe_private
)
1105 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
1106 struct sipe_calendar
* cal
= sip
->cal
;
1107 guint cal_data_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_CALENDAR_DATA
);
1109 char *free_busy_base64
;
1110 /* const char *st; */
1111 /* const char *fb; */
1114 /* key is <category><instance><container> */
1115 gchar
*key_cal_1
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 1);
1116 gchar
*key_cal_100
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 100);
1117 gchar
*key_cal_200
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 200);
1118 gchar
*key_cal_300
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 300);
1119 gchar
*key_cal_400
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 400);
1120 gchar
*key_cal_32000
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 32000);
1122 struct sipe_publication
*publication_cal_1
=
1123 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "calendarData"), key_cal_1
);
1124 struct sipe_publication
*publication_cal_100
=
1125 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "calendarData"), key_cal_100
);
1126 struct sipe_publication
*publication_cal_200
=
1127 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "calendarData"), key_cal_200
);
1128 struct sipe_publication
*publication_cal_300
=
1129 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "calendarData"), key_cal_300
);
1130 struct sipe_publication
*publication_cal_400
=
1131 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "calendarData"), key_cal_400
);
1132 struct sipe_publication
*publication_cal_32000
=
1133 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "calendarData"), key_cal_32000
);
1136 g_free(key_cal_100
);
1137 g_free(key_cal_200
);
1138 g_free(key_cal_300
);
1139 g_free(key_cal_400
);
1140 g_free(key_cal_32000
);
1142 if (!cal
|| is_empty(cal
->email
) || !cal
->fb_start
|| is_empty(cal
->free_busy
)) {
1143 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_free_busy: no data to publish, exiting");
1147 fb_start_str
= sipe_utils_time_to_str(cal
->fb_start
);
1148 free_busy_base64
= sipe_cal_get_freebusy_base64(cal
->free_busy
);
1150 /* we will rebuplish the same data to refresh publication time,
1151 * so if data from multiple sources, most recent will be choosen
1153 // st = publication_cal_300 ? publication_cal_300->fb_start_str : NULL;
1154 // fb = publication_cal_300 ? publication_cal_300->free_busy_base64 : NULL;
1156 //if (sipe_strequal(st, fb_start_str) && sipe_strequal(fb, free_busy_base64))
1158 // SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_free_busy: FreeBusy has NOT changed. Exiting.");
1159 // g_free(fb_start_str);
1160 // g_free(free_busy_base64);
1161 // return NULL; /* nothing to update */
1164 res
= g_strdup_printf(SIPE_PUB_XML_FREE_BUSY
,
1167 publication_cal_1
? publication_cal_1
->version
: 0,
1170 publication_cal_100
? publication_cal_100
->version
: 0,
1173 publication_cal_200
? publication_cal_200
->version
: 0,
1179 publication_cal_300
? publication_cal_300
->version
: 0,
1183 /* 400 - Personal */
1185 publication_cal_400
? publication_cal_400
->version
: 0,
1189 /* 32000 - Blocked */
1191 publication_cal_32000
? publication_cal_32000
->version
: 0
1194 g_free(fb_start_str
);
1195 g_free(free_busy_base64
);
1201 * Publishes 'device' category.
1202 * @param instance (%u) Ex.: 1938468728
1203 * @param version (%u) Ex.: 1
1204 * @param endpointId (%s) Ex.: C707E38E-1E10-5413-94D9-ECAC260A0269
1205 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1206 * @param timezone (%s) Ex.: 00:00:00+01:00
1207 * @param machineName (%s) Ex.: BOSTON-OCS07
1209 #define SIPE_PUB_XML_DEVICE \
1210 "<publication categoryName=\"device\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
1211 "<device xmlns=\"http://schemas.microsoft.com/2006/09/sip/device\" endpointId=\"%s\">"\
1212 "<capabilities preferred=\"false\" uri=\"%s\">"\
1213 "<text capture=\"true\" render=\"true\" publish=\"false\"/>"\
1214 "<gifInk capture=\"false\" render=\"true\" publish=\"false\"/>"\
1215 "<isfInk capture=\"false\" render=\"true\" publish=\"false\"/>"\
1217 "<timezone>%s</timezone>"\
1218 "<machineName>%s</machineName>"\
1223 * Returns 'device' XML part for publication.
1224 * Must be g_free'd after use.
1226 static gchar
*sipe_publish_get_category_device(struct sipe_core_private
*sipe_private
)
1228 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
1231 gchar
*uuid
= get_uuid(sipe_private
);
1232 guint device_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_DEVICE
);
1233 /* key is <category><instance><container> */
1234 gchar
*key
= g_strdup_printf("<%s><%u><%u>", "device", device_instance
, 2);
1235 struct sipe_publication
*publication
=
1236 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "device"), key
);
1240 uri
= sip_uri_self(sipe_private
);
1241 doc
= g_strdup_printf(SIPE_PUB_XML_DEVICE
,
1243 publication
? publication
->version
: 0,
1246 "00:00:00+01:00", /* @TODO make timezone real*/
1257 * Publishes 'machineState' category.
1258 * @param instance (%u) Ex.: 926460663
1259 * @param version (%u) Ex.: 22
1260 * @param availability (%d) Ex.: 3500
1261 * @param instance (%u) Ex.: 926460663
1262 * @param version (%u) Ex.: 22
1263 * @param availability (%d) Ex.: 3500
1265 #define SIPE_PUB_XML_STATE_MACHINE \
1266 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
1267 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"machineState\">"\
1268 "<availability>%d</availability>"\
1269 "<endpointLocation/>"\
1272 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
1273 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"machineState\">"\
1274 "<availability>%d</availability>"\
1275 "<endpointLocation/>"\
1280 * Publishes 'userState' category.
1281 * @param instance (%u) User. Ex.: 536870912
1282 * @param version (%u) User Container 2. Ex.: 22
1283 * @param availability (%d) User Container 2. Ex.: 15500
1284 * @param instance (%u) User. Ex.: 536870912
1285 * @param version (%u) User Container 3.Ex.: 22
1286 * @param availability (%d) User Container 3. Ex.: 15500
1288 #define SIPE_PUB_XML_STATE_USER \
1289 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"static\">"\
1290 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"true\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"userState\">"\
1291 "<availability>%d</availability>"\
1292 "<endpointLocation/>"\
1295 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"static\">"\
1296 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"true\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"userState\">"\
1297 "<availability>%d</availability>"\
1298 "<endpointLocation/>"\
1303 * A service method - use
1304 * - send_publish_get_category_state_machine and
1305 * - send_publish_get_category_state_user instead.
1306 * Must be g_free'd after use.
1308 static gchar
*sipe_publish_get_category_state(struct sipe_core_private
*sipe_private
,
1309 gboolean is_user_state
)
1311 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
1312 int availability
= sipe_get_availability_by_status(sip
->status
, NULL
);
1313 guint instance
= is_user_state
? sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_USER
) :
1314 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_MACHINE
);
1315 /* key is <category><instance><container> */
1316 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
1317 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
1318 struct sipe_publication
*publication_2
=
1319 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "state"), key_2
);
1320 struct sipe_publication
*publication_3
=
1321 g_hash_table_lookup(g_hash_table_lookup(sip
->our_publications
, "state"), key_3
);
1326 if (publication_2
&& (publication_2
->availability
== availability
))
1328 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_state: state has NOT changed. Exiting.");
1329 return NULL
; /* nothing to update */
1332 return g_strdup_printf( is_user_state
? SIPE_PUB_XML_STATE_USER
: SIPE_PUB_XML_STATE_MACHINE
,
1334 publication_2
? publication_2
->version
: 0,
1337 publication_3
? publication_3
->version
: 0,
1342 * Returns 'machineState' XML part for publication.
1343 * Must be g_free'd after use.
1345 static gchar
*sipe_publish_get_category_state_machine(struct sipe_core_private
*sipe_private
)
1347 return sipe_publish_get_category_state(sipe_private
, FALSE
);
1351 * Returns 'userState' XML part for publication.
1352 * Must be g_free'd after use.
1354 static gchar
*sipe_publish_get_category_state_user(struct sipe_core_private
*sipe_private
)
1356 return sipe_publish_get_category_state(sipe_private
, TRUE
);
1359 static void send_publish_category_initial(struct sipe_core_private
*sipe_private
)
1361 gchar
*pub_device
= sipe_publish_get_category_device(sipe_private
);
1363 gchar
*publications
;
1365 sipe_set_initial_status(sipe_private
);
1367 pub_machine
= sipe_publish_get_category_state_machine(sipe_private
);
1368 publications
= g_strdup_printf("%s%s",
1370 pub_machine
? pub_machine
: "");
1372 g_free(pub_machine
);
1374 send_presence_publish(sipe_private
, publications
);
1375 g_free(publications
);
1378 static gboolean
process_send_presence_category_publish_response(struct sipe_core_private
*sipe_private
,
1380 struct transaction
*trans
)
1382 const gchar
*contenttype
= sipmsg_find_header(msg
, "Content-Type");
1384 if (msg
->response
== 409 && g_str_has_prefix(contenttype
, "application/msrtc-fault+xml")) {
1386 const sipe_xml
*node
;
1390 gboolean has_device_publication
= FALSE
;
1392 xml
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
1394 /* test if version mismatch fault */
1395 fault_code
= sipe_xml_data(sipe_xml_child(xml
, "Faultcode"));
1396 if (!sipe_strequal(fault_code
, "Client.BadCall.WrongDelta")) {
1397 SIPE_DEBUG_INFO("process_send_presence_category_publish_response: unsupported fault code:%s returning.", fault_code
);
1404 /* accumulating information about faulty versions */
1405 faults
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
1406 for (node
= sipe_xml_child(xml
, "details/operation");
1408 node
= sipe_xml_twin(node
))
1410 const gchar
*index
= sipe_xml_attribute(node
, "index");
1411 const gchar
*curVersion
= sipe_xml_attribute(node
, "curVersion");
1413 g_hash_table_insert(faults
, g_strdup(index
), g_strdup(curVersion
));
1414 SIPE_DEBUG_INFO("fault added: index:%s curVersion:%s", index
, curVersion
);
1418 /* here we are parsing our own request to figure out what publication
1419 * referenced here only by index went wrong
1421 xml
= sipe_xml_parse(trans
->msg
->body
, trans
->msg
->bodylen
);
1424 for (node
= sipe_xml_child(xml
, "publications/publication"),
1425 index_our
= 1; /* starts with 1 - our first publication */
1427 node
= sipe_xml_twin(node
), index_our
++)
1429 gchar
*idx
= g_strdup_printf("%d", index_our
);
1430 const gchar
*curVersion
= g_hash_table_lookup(faults
, idx
);
1431 const gchar
*categoryName
= sipe_xml_attribute(node
, "categoryName");
1434 if (sipe_strequal("device", categoryName
)) {
1435 has_device_publication
= TRUE
;
1438 if (curVersion
) { /* fault exist on this index */
1439 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
1440 const gchar
*container
= sipe_xml_attribute(node
, "container");
1441 const gchar
*instance
= sipe_xml_attribute(node
, "instance");
1442 /* key is <category><instance><container> */
1443 gchar
*key
= g_strdup_printf("<%s><%s><%s>", categoryName
, instance
, container
);
1444 GHashTable
*category
= g_hash_table_lookup(sip
->our_publications
, categoryName
);
1447 struct sipe_publication
*publication
=
1448 g_hash_table_lookup(category
, key
);
1450 SIPE_DEBUG_INFO("key is %s", key
);
1453 SIPE_DEBUG_INFO("Updating %s with version %s. Was %d before.",
1454 key
, curVersion
, publication
->version
);
1455 /* updating publication's version to the correct one */
1456 publication
->version
= atoi(curVersion
);
1459 /* We somehow lost this category from our publications... */
1460 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
1461 publication
->category
= g_strdup(categoryName
);
1462 publication
->instance
= atoi(instance
);
1463 publication
->container
= atoi(container
);
1464 publication
->version
= atoi(curVersion
);
1465 category
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
1466 g_free
, (GDestroyNotify
)free_publication
);
1467 g_hash_table_insert(category
, g_strdup(key
), publication
);
1468 g_hash_table_insert(sip
->our_publications
, g_strdup(categoryName
), category
);
1469 SIPE_DEBUG_INFO("added lost category '%s' key '%s'", categoryName
, key
);
1475 g_hash_table_destroy(faults
);
1477 /* rebublishing with right versions */
1478 if (has_device_publication
) {
1479 send_publish_category_initial(sipe_private
);
1481 send_presence_status(sipe_private
, NULL
);
1488 * Publishes categories.
1489 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1490 * @param publications (%s) XML publications
1492 #define SIPE_SEND_PRESENCE \
1493 "<publish xmlns=\"http://schemas.microsoft.com/2006/09/sip/rich-presence\">"\
1494 "<publications uri=\"%s\">"\
1499 static void send_presence_publish(struct sipe_core_private
*sipe_private
,
1500 const char *publications
)
1507 uri
= sip_uri_self(sipe_private
);
1508 doc
= g_strdup_printf(SIPE_SEND_PRESENCE
,
1512 tmp
= get_contact(sipe_private
);
1513 hdr
= g_strdup_printf("Contact: %s\r\n"
1514 "Content-Type: application/msrtc-category-publish+xml\r\n", tmp
);
1516 sip_transport_service(sipe_private
,
1520 process_send_presence_category_publish_response
);
1529 * Publishes self status
1530 * based on own calendar information.
1532 void sipe_ocs2007_presence_publish(struct sipe_core_private
*sipe_private
,
1533 SIPE_UNUSED_PARAMETER
void *unused
)
1535 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
1536 struct sipe_cal_event
* event
= NULL
;
1537 gchar
*pub_cal_working_hours
= NULL
;
1538 gchar
*pub_cal_free_busy
= NULL
;
1539 gchar
*pub_calendar
= NULL
;
1540 gchar
*pub_calendar2
= NULL
;
1541 gchar
*pub_oof_note
= NULL
;
1542 const gchar
*oof_note
;
1543 time_t oof_start
= 0;
1547 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() no calendar data.");
1551 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() started.");
1552 if (sip
->cal
->cal_events
) {
1553 event
= sipe_cal_get_event(sip
->cal
->cal_events
, time(NULL
));
1557 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: current event is NULL");
1559 char *desc
= sipe_cal_event_describe(event
);
1560 SIPE_DEBUG_INFO("publish_calendar_status_self: current event is:\n%s", desc
? desc
: "");
1566 OOF publish, Busy clean
1568 OOF clean, Busy publish
1570 OOF clean, Busy clean
1572 if (event
&& event
->cal_status
== SIPE_CAL_OOF
) {
1573 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, event
, sip
->cal
->email
, SIPE_CAL_OOF
);
1574 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, sip
->cal
->email
, SIPE_CAL_BUSY
);
1575 } else if (event
&& event
->cal_status
== SIPE_CAL_BUSY
) {
1576 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, sip
->cal
->email
, SIPE_CAL_OOF
);
1577 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, event
, sip
->cal
->email
, SIPE_CAL_BUSY
);
1579 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, sip
->cal
->email
, SIPE_CAL_OOF
);
1580 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, sip
->cal
->email
, SIPE_CAL_BUSY
);
1583 oof_note
= sipe_ews_get_oof_note(sip
->cal
);
1584 if (sipe_strequal("Scheduled", sip
->cal
->oof_state
)) {
1585 oof_start
= sip
->cal
->oof_start
;
1586 oof_end
= sip
->cal
->oof_end
;
1588 pub_oof_note
= sipe_publish_get_category_note(sipe_private
, oof_note
, "OOF", oof_start
, oof_end
);
1590 pub_cal_working_hours
= sipe_publish_get_category_cal_working_hours(sipe_private
);
1591 pub_cal_free_busy
= sipe_publish_get_category_cal_free_busy(sipe_private
);
1593 if (!pub_cal_working_hours
&& !pub_cal_free_busy
&& !pub_calendar
&& !pub_calendar2
&& !pub_oof_note
) {
1594 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: nothing has changed.");
1596 gchar
*publications
= g_strdup_printf("%s%s%s%s%s",
1597 pub_cal_working_hours
? pub_cal_working_hours
: "",
1598 pub_cal_free_busy
? pub_cal_free_busy
: "",
1599 pub_calendar
? pub_calendar
: "",
1600 pub_calendar2
? pub_calendar2
: "",
1601 pub_oof_note
? pub_oof_note
: "");
1603 send_presence_publish(sipe_private
, publications
);
1604 g_free(publications
);
1607 g_free(pub_cal_working_hours
);
1608 g_free(pub_cal_free_busy
);
1609 g_free(pub_calendar
);
1610 g_free(pub_calendar2
);
1611 g_free(pub_oof_note
);
1613 /* repeat scheduling */
1614 schedule_publish_update(sipe_private
, time(NULL
));
1617 void sipe_ocs2007_category_publish(struct sipe_core_private
*sipe_private
)
1619 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
1620 gchar
*pub_state
= sipe_is_user_state(sipe_private
) ?
1621 sipe_publish_get_category_state_user(sipe_private
) :
1622 sipe_publish_get_category_state_machine(sipe_private
);
1623 gchar
*pub_note
= sipe_publish_get_category_note(sipe_private
,
1625 sip
->is_oof_note
? "OOF" : "personal",
1628 gchar
*publications
;
1630 if (!pub_state
&& !pub_note
) {
1631 SIPE_DEBUG_INFO_NOFORMAT("sipe_osc2007_category_publish: nothing has changed. Exiting.");
1635 publications
= g_strdup_printf("%s%s",
1636 pub_state
? pub_state
: "",
1637 pub_note
? pub_note
: "");
1642 send_presence_publish(sipe_private
, publications
);
1643 g_free(publications
);
1646 static void sipe_publish_get_cat_state_user_to_clear(SIPE_UNUSED_PARAMETER
const char *name
,
1650 struct sipe_publication
*publication
= value
;
1652 g_string_append_printf( str
,
1653 SIPE_PUB_XML_PUBLICATION_CLEAR
,
1654 publication
->category
,
1655 publication
->instance
,
1656 publication
->container
,
1657 publication
->version
,
1661 void sipe_ocs2007_reset_status(struct sipe_core_private
*sipe_private
)
1663 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
1665 gchar
*publications
;
1667 if (!sip
->user_state_publications
|| g_hash_table_size(sip
->user_state_publications
) == 0) {
1668 SIPE_DEBUG_INFO_NOFORMAT("sipe_reset_status: no userState publications, exiting.");
1672 str
= g_string_new(NULL
);
1673 g_hash_table_foreach(sip
->user_state_publications
, (GHFunc
)sipe_publish_get_cat_state_user_to_clear
, str
);
1674 publications
= g_string_free(str
, FALSE
);
1676 send_presence_publish(sipe_private
, publications
);
1677 g_free(publications
);
1680 /* key is <category><instance><container> */
1681 static gboolean
sipe_is_our_publication(struct sipe_core_private
*sipe_private
,
1684 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
1687 /* filling keys for our publications if not yet cached */
1688 if (!sip
->our_publication_keys
) {
1689 guint device_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_DEVICE
);
1690 guint machine_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_MACHINE
);
1691 guint user_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_USER
);
1692 guint calendar_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR
);
1693 guint cal_oof_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR_OOF
);
1694 guint cal_data_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_CALENDAR_DATA
);
1695 guint note_oof_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_NOTE_OOF
);
1697 SIPE_DEBUG_INFO_NOFORMAT("* Our Publication Instances *");
1698 SIPE_DEBUG_INFO("\tDevice : %u\t0x%08X", device_instance
, device_instance
);
1699 SIPE_DEBUG_INFO("\tMachine State : %u\t0x%08X", machine_instance
, machine_instance
);
1700 SIPE_DEBUG_INFO("\tUser Stare : %u\t0x%08X", user_instance
, user_instance
);
1701 SIPE_DEBUG_INFO("\tCalendar State : %u\t0x%08X", calendar_instance
, calendar_instance
);
1702 SIPE_DEBUG_INFO("\tCalendar OOF State : %u\t0x%08X", cal_oof_instance
, cal_oof_instance
);
1703 SIPE_DEBUG_INFO("\tCalendar FreeBusy : %u\t0x%08X", cal_data_instance
, cal_data_instance
);
1704 SIPE_DEBUG_INFO("\tOOF Note : %u\t0x%08X", note_oof_instance
, note_oof_instance
);
1705 SIPE_DEBUG_INFO("\tNote : %u", 0);
1706 SIPE_DEBUG_INFO("\tCalendar WorkingHours: %u", 0);
1709 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1710 g_strdup_printf("<%s><%u><%u>", "device", device_instance
, 2));
1712 /* state:machineState */
1713 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1714 g_strdup_printf("<%s><%u><%u>", "state", machine_instance
, 2));
1715 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1716 g_strdup_printf("<%s><%u><%u>", "state", machine_instance
, 3));
1718 /* state:userState */
1719 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1720 g_strdup_printf("<%s><%u><%u>", "state", user_instance
, 2));
1721 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1722 g_strdup_printf("<%s><%u><%u>", "state", user_instance
, 3));
1724 /* state:calendarState */
1725 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1726 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance
, 2));
1727 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1728 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance
, 3));
1730 /* state:calendarState OOF */
1731 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1732 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance
, 2));
1733 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1734 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance
, 3));
1737 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1738 g_strdup_printf("<%s><%u><%u>", "note", 0, 200));
1739 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1740 g_strdup_printf("<%s><%u><%u>", "note", 0, 300));
1741 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1742 g_strdup_printf("<%s><%u><%u>", "note", 0, 400));
1745 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1746 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 200));
1747 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1748 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 300));
1749 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1750 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 400));
1752 /* calendarData:WorkingHours */
1753 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1754 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1));
1755 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1756 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100));
1757 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1758 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200));
1759 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1760 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300));
1761 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1762 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400));
1763 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1764 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000));
1766 /* calendarData:FreeBusy */
1767 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1768 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 1));
1769 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1770 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 100));
1771 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1772 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 200));
1773 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1774 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 300));
1775 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1776 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 400));
1777 sip
->our_publication_keys
= g_slist_append(sip
->our_publication_keys
,
1778 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 32000));
1780 //SIPE_DEBUG_INFO("sipe_is_our_publication: sip->our_publication_keys length=%d",
1781 // sip->our_publication_keys ? (int) g_slist_length(sip->our_publication_keys) : -1);
1784 //SIPE_DEBUG_INFO("sipe_is_our_publication: key=%s", key);
1786 entry
= sip
->our_publication_keys
;
1788 //SIPE_DEBUG_INFO(" sipe_is_our_publication: entry->data=%s", entry->data);
1789 if (sipe_strequal(entry
->data
, key
)) {
1792 entry
= entry
->next
;
1797 static void sipe_refresh_blocked_status_cb(char *buddy_name
,
1798 SIPE_UNUSED_PARAMETER
struct sipe_buddy
*buddy
,
1799 struct sipe_core_private
*sipe_private
)
1801 int container_id
= sipe_ocs2007_find_access_level(sipe_private
, "user", buddy_name
, NULL
);
1802 gboolean blocked
= (container_id
== 32000);
1803 gboolean blocked_in_blist
= sipe_backend_buddy_is_blocked(SIPE_CORE_PUBLIC
, buddy_name
);
1805 /* SIPE_DEBUG_INFO("sipe_refresh_blocked_status_cb: buddy_name=%s, blocked=%s, blocked_in_blist=%s",
1806 buddy_name, blocked ? "T" : "F", blocked_in_blist ? "T" : "F"); */
1808 if (blocked
!= blocked_in_blist
) {
1809 sipe_backend_buddy_set_blocked_status(SIPE_CORE_PUBLIC
, buddy_name
, blocked
);
1813 static void sipe_refresh_blocked_status(struct sipe_core_private
*sipe_private
)
1815 g_hash_table_foreach(sipe_private
->buddies
,
1816 (GHFunc
) sipe_refresh_blocked_status_cb
,
1821 * When we receive some self (BE) NOTIFY with a new subscriber
1822 * we sends a setSubscribers request to him [SIP-PRES] 4.8
1825 void sipe_ocs2007_process_roaming_self(struct sipe_core_private
*sipe_private
,
1828 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
1832 const sipe_xml
*node
;
1833 const sipe_xml
*node2
;
1834 char *display_name
= NULL
;
1836 GSList
*category_names
= NULL
;
1837 int aggreg_avail
= 0;
1838 gboolean do_update_status
= FALSE
;
1839 gboolean has_note_cleaned
= FALSE
;
1840 GHashTable
*devices
;
1842 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self");
1844 xml
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
1847 contact
= get_contact(sipe_private
);
1848 to
= sip_uri_self(sipe_private
);
1851 /* set list of categories participating in this XML */
1852 for (node
= sipe_xml_child(xml
, "categories/category"); node
; node
= sipe_xml_twin(node
)) {
1853 const gchar
*name
= sipe_xml_attribute(node
, "name");
1854 category_names
= slist_insert_unique_sorted(category_names
, (gchar
*)name
, (GCompareFunc
)strcmp
);
1856 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: category_names length=%d",
1857 category_names
? (int) g_slist_length(category_names
) : -1);
1858 /* drop category information */
1859 if (category_names
) {
1860 GSList
*entry
= category_names
;
1862 GHashTable
*cat_publications
;
1863 const gchar
*category
= entry
->data
;
1864 entry
= entry
->next
;
1865 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: dropping category: %s", category
);
1866 cat_publications
= g_hash_table_lookup(sip
->our_publications
, category
);
1867 if (cat_publications
) {
1868 g_hash_table_remove(sip
->our_publications
, category
);
1869 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: dropped category: %s", category
);
1873 g_slist_free(category_names
);
1875 /* filling our categories reflected in roaming data */
1876 devices
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
1878 for (node
= sipe_xml_child(xml
, "categories/category"); node
; node
= sipe_xml_twin(node
)) {
1880 const gchar
*name
= sipe_xml_attribute(node
, "name");
1881 guint container
= sipe_xml_int_attribute(node
, "container", -1);
1882 guint instance
= sipe_xml_int_attribute(node
, "instance", -1);
1883 guint version
= sipe_xml_int_attribute(node
, "version", 0);
1884 time_t publish_time
= (tmp
= sipe_xml_attribute(node
, "publishTime")) ?
1885 sipe_utils_str_to_time(tmp
) : 0;
1887 GHashTable
*cat_publications
= g_hash_table_lookup(sip
->our_publications
, name
);
1889 /* Ex. clear note: <category name="note"/> */
1890 if (container
== (guint
)-1) {
1893 do_update_status
= TRUE
;
1897 /* Ex. clear note: <category name="note" container="200"/> */
1898 if (instance
== (guint
)-1) {
1899 if (container
== 200) {
1902 do_update_status
= TRUE
;
1904 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removing publications for: %s/%u", name
, container
);
1905 sipe_remove_category_container_publications(
1906 sip
->our_publications
, name
, container
);
1910 /* key is <category><instance><container> */
1911 key
= g_strdup_printf("<%s><%u><%u>", name
, instance
, container
);
1912 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: key=%s version=%d", key
, version
);
1914 /* capture all userState publication for later clean up if required */
1915 if (sipe_strequal(name
, "state") && (container
== 2 || container
== 3)) {
1916 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
1918 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "userState")) {
1919 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
1920 publication
->category
= g_strdup(name
);
1921 publication
->instance
= instance
;
1922 publication
->container
= container
;
1923 publication
->version
= version
;
1925 if (!sip
->user_state_publications
) {
1926 sip
->user_state_publications
= g_hash_table_new_full(
1927 g_str_hash
, g_str_equal
,
1928 g_free
, (GDestroyNotify
)free_publication
);
1930 g_hash_table_insert(sip
->user_state_publications
, g_strdup(key
), publication
);
1931 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added to user_state_publications key=%s version=%d",
1936 /* count each client instance only once */
1937 if (sipe_strequal(name
, "device"))
1938 g_hash_table_replace(devices
, g_strdup_printf("%u", instance
), NULL
);
1940 if (sipe_is_our_publication(sipe_private
, key
)) {
1941 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
1943 publication
->category
= g_strdup(name
);
1944 publication
->instance
= instance
;
1945 publication
->container
= container
;
1946 publication
->version
= version
;
1948 /* filling publication->availability */
1949 if (sipe_strequal(name
, "state")) {
1950 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
1951 const sipe_xml
*xn_avail
= sipe_xml_child(xn_state
, "availability");
1954 gchar
*avail_str
= sipe_xml_data(xn_avail
);
1956 publication
->availability
= atoi(avail_str
);
1960 /* for calendarState */
1961 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "calendarState")) {
1962 const sipe_xml
*xn_activity
= sipe_xml_child(xn_state
, "activity");
1963 struct sipe_cal_event
*event
= g_new0(struct sipe_cal_event
, 1);
1965 event
->start_time
= sipe_utils_str_to_time(sipe_xml_attribute(xn_state
, "startTime"));
1967 if (sipe_strequal(sipe_xml_attribute(xn_activity
, "token"),
1968 sipe_activity_to_token(SIPE_ACTIVITY_IN_MEETING
)))
1970 event
->is_meeting
= TRUE
;
1973 event
->subject
= sipe_xml_data(sipe_xml_child(xn_state
, "meetingSubject"));
1974 event
->location
= sipe_xml_data(sipe_xml_child(xn_state
, "meetingLocation"));
1976 publication
->cal_event_hash
= sipe_cal_event_hash(event
);
1977 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: hash=%s",
1978 publication
->cal_event_hash
);
1979 sipe_cal_event_free(event
);
1982 /* filling publication->note */
1983 if (sipe_strequal(name
, "note")) {
1984 const sipe_xml
*xn_body
= sipe_xml_child(node
, "note/body");
1986 if (!has_note_cleaned
) {
1987 has_note_cleaned
= TRUE
;
1991 sip
->note_since
= publish_time
;
1993 do_update_status
= TRUE
;
1996 g_free(publication
->note
);
1997 publication
->note
= NULL
;
2001 publication
->note
= g_markup_escape_text((tmp
= sipe_xml_data(xn_body
)), -1);
2003 if (publish_time
>= sip
->note_since
) {
2005 sip
->note
= g_strdup(publication
->note
);
2006 sip
->note_since
= publish_time
;
2007 sip
->is_oof_note
= sipe_strequal(sipe_xml_attribute(xn_body
, "type"), "OOF");
2009 do_update_status
= TRUE
;
2014 /* filling publication->fb_start_str, free_busy_base64, working_hours_xml_str */
2015 if (sipe_strequal(name
, "calendarData") && (publication
->container
== 300)) {
2016 const sipe_xml
*xn_free_busy
= sipe_xml_child(node
, "calendarData/freeBusy");
2017 const sipe_xml
*xn_working_hours
= sipe_xml_child(node
, "calendarData/WorkingHours");
2019 publication
->fb_start_str
= g_strdup(sipe_xml_attribute(xn_free_busy
, "startTime"));
2020 publication
->free_busy_base64
= sipe_xml_data(xn_free_busy
);
2022 if (xn_working_hours
) {
2023 publication
->working_hours_xml_str
= sipe_xml_stringify(xn_working_hours
);
2027 if (!cat_publications
) {
2028 cat_publications
= g_hash_table_new_full(
2029 g_str_hash
, g_str_equal
,
2030 g_free
, (GDestroyNotify
)free_publication
);
2031 g_hash_table_insert(sip
->our_publications
, g_strdup(name
), cat_publications
);
2032 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added GHashTable cat=%s", name
);
2034 g_hash_table_insert(cat_publications
, g_strdup(key
), publication
);
2035 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added key=%s version=%d", key
, version
);
2039 /* aggregateState (not an our publication) from 2-nd container */
2040 if (sipe_strequal(name
, "state") && container
== 2) {
2041 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
2043 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "aggregateState")) {
2044 const sipe_xml
*xn_avail
= sipe_xml_child(xn_state
, "availability");
2047 gchar
*avail_str
= sipe_xml_data(xn_avail
);
2049 aggreg_avail
= atoi(avail_str
);
2054 do_update_status
= TRUE
;
2058 /* userProperties published by server from AD */
2059 if (!sip
->csta
&& sipe_strequal(name
, "userProperties")) {
2060 const sipe_xml
*line
;
2061 /* line, for Remote Call Control (RCC) */
2062 for (line
= sipe_xml_child(node
, "userProperties/lines/line"); line
; line
= sipe_xml_twin(line
)) {
2063 const gchar
*line_server
= sipe_xml_attribute(line
, "lineServer");
2064 const gchar
*line_type
= sipe_xml_attribute(line
, "lineType");
2067 if (!line_server
|| !(sipe_strequal(line_type
, "Rcc") || sipe_strequal(line_type
, "Dual"))) continue;
2069 line_uri
= sipe_xml_data(line
);
2071 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: line_uri=%s server=%s", line_uri
, line_server
);
2072 sip_csta_open(sipe_private
, line_uri
, line_server
);
2080 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sip->our_publications size=%d",
2081 sip
->our_publications
? (int) g_hash_table_size(sip
->our_publications
) : -1);
2083 /* active clients for user account */
2084 if (g_hash_table_size(devices
) > 1) {
2085 SIPE_CORE_PRIVATE_FLAG_SET(MPOP
);
2086 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: multiple clients detected (%d)",
2087 g_hash_table_size(devices
));
2089 SIPE_CORE_PRIVATE_FLAG_UNSET(MPOP
);
2090 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self: single client detected");
2092 g_hash_table_destroy(devices
);
2095 for (node
= sipe_xml_child(xml
, "containers/container"); node
; node
= sipe_xml_twin(node
)) {
2096 guint id
= sipe_xml_int_attribute(node
, "id", 0);
2097 struct sipe_container
*container
= sipe_find_container(sipe_private
, id
);
2100 sip
->containers
= g_slist_remove(sip
->containers
, container
);
2101 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removed existing container id=%d v%d", container
->id
, container
->version
);
2102 sipe_ocs2007_free_container(container
);
2104 container
= g_new0(struct sipe_container
, 1);
2106 container
->version
= sipe_xml_int_attribute(node
, "version", 0);
2107 sip
->containers
= g_slist_append(sip
->containers
, container
);
2108 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container id=%d v%d", container
->id
, container
->version
);
2110 for (node2
= sipe_xml_child(node
, "member"); node2
; node2
= sipe_xml_twin(node2
)) {
2111 struct sipe_container_member
*member
= g_new0(struct sipe_container_member
, 1);
2112 member
->type
= g_strdup(sipe_xml_attribute(node2
, "type"));
2113 member
->value
= g_strdup(sipe_xml_attribute(node2
, "value"));
2114 container
->members
= g_slist_append(container
->members
, member
);
2115 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container member type=%s value=%s",
2116 member
->type
, member
->value
? member
->value
: "");
2120 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sip->access_level_set=%s", sip
->access_level_set
? "TRUE" : "FALSE");
2121 if (!sip
->access_level_set
&& sipe_xml_child(xml
, "containers")) {
2122 char *container_xmls
= NULL
;
2123 int sameEnterpriseAL
= sipe_ocs2007_find_access_level(sipe_private
, "sameEnterprise", NULL
, NULL
);
2124 int federatedAL
= sipe_ocs2007_find_access_level(sipe_private
, "federated", NULL
, NULL
);
2126 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sameEnterpriseAL=%d", sameEnterpriseAL
);
2127 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: federatedAL=%d", federatedAL
);
2128 /* initial set-up to let counterparties see your status */
2129 if (sameEnterpriseAL
< 0) {
2130 struct sipe_container
*container
= sipe_find_container(sipe_private
, 200);
2131 guint version
= container
? container
->version
: 0;
2132 sipe_send_container_members_prepare(200, version
, "add", "sameEnterprise", NULL
, &container_xmls
);
2134 if (federatedAL
< 0) {
2135 struct sipe_container
*container
= sipe_find_container(sipe_private
, 100);
2136 guint version
= container
? container
->version
: 0;
2137 sipe_send_container_members_prepare(100, version
, "add", "federated", NULL
, &container_xmls
);
2139 sip
->access_level_set
= TRUE
;
2141 if (container_xmls
) {
2142 sipe_send_set_container_members(sipe_private
, container_xmls
);
2144 g_free(container_xmls
);
2147 /* Refresh contacts' blocked status */
2148 sipe_refresh_blocked_status(sipe_private
);
2151 for (node
= sipe_xml_child(xml
, "subscribers/subscriber"); node
; node
= sipe_xml_twin(node
)) {
2153 const char *acknowledged
;
2157 user
= sipe_xml_attribute(node
, "user"); /* without 'sip:' prefix */
2158 if (!user
) continue;
2159 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user %s", user
);
2160 display_name
= g_strdup(sipe_xml_attribute(node
, "displayName"));
2161 uri
= sip_uri_from_name(user
);
2163 sipe_buddy_update_property(sipe_private
, uri
, SIPE_BUDDY_INFO_DISPLAY_NAME
, display_name
);
2165 acknowledged
= sipe_xml_attribute(node
, "acknowledged");
2166 if(sipe_strcase_equal(acknowledged
,"false")){
2167 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user added you %s", user
);
2168 if (!sipe_backend_buddy_find(SIPE_CORE_PUBLIC
, uri
, NULL
)) {
2169 sipe_backend_buddy_request_add(SIPE_CORE_PUBLIC
, uri
, display_name
);
2172 hdr
= g_strdup_printf(
2174 "Content-Type: application/msrtc-presence-setsubscriber+xml\r\n", contact
);
2176 body
= g_strdup_printf(
2177 "<setSubscribers xmlns=\"http://schemas.microsoft.com/2006/09/sip/presence-subscribers\">"
2178 "<subscriber user=\"%s\" acknowledged=\"true\"/>"
2179 "</setSubscribers>", user
);
2181 sip_transport_service(sipe_private
,
2189 g_free(display_name
);
2196 /* Publish initial state if not yet.
2197 * Assuming this happens on initial responce to subscription to roaming-self
2198 * so we've already updated our roaming data in full.
2201 if (!sip
->initial_state_published
) {
2202 send_publish_category_initial(sipe_private
);
2203 sipe_groupchat_init(sipe_private
);
2204 sip
->initial_state_published
= TRUE
;
2206 sipe_cal_delayed_calendar_update(sipe_private
);
2207 do_update_status
= FALSE
;
2208 } else if (aggreg_avail
) {
2210 if (aggreg_avail
&& aggreg_avail
< 18000) { /* not offline */
2211 g_free(sip
->status
);
2212 sip
->status
= g_strdup(sipe_get_status_by_availability(aggreg_avail
, NULL
));
2214 sipe_set_invisible_status(sipe_private
); /* not not let offline status switch us off */
2218 if (do_update_status
) {
2219 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: switch to '%s' for the account", sip
->status
);
2220 sipe_status_and_note(sipe_private
, sip
->status
);