core cleanup: move out [MS-PRES] fields
[siplcs.git] / src / core / sipe-ocs2007.c
blobfacad0a34c5118795011c48366b13b36157a0d01
1 /**
2 * @file sipe-ocs2007.c
4 * pidgin-sipe
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
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
32 #include <stdlib.h>
33 #include <string.h>
34 #include <time.h>
36 #include <glib.h>
38 #include "sipe-common.h"
39 #include "http-conn.h"
40 #include "sipmsg.h"
41 #include "sip-csta.h"
42 #include "sip-transport.h"
43 #include "sipe-backend.h"
44 #include "sipe-buddy.h"
45 #include "sipe-cal.h"
46 #include "sipe-core.h"
47 #include "sipe-core-private.h"
48 #include "sipe-ews.h"
49 #include "sipe-groupchat.h"
50 #include "sipe-nls.h"
51 #include "sipe-ocs2007.h"
52 #include "sipe-schedule.h"
53 #include "sipe-status.h"
54 #include "sipe-utils.h"
55 #include "sipe-xml.h"
57 #include "sipe.h"
59 /** MS-PRES publication */
60 struct sipe_publication {
61 gchar *category;
62 guint instance;
63 guint container;
64 guint version;
65 /** for 'state' category */
66 int availability;
67 /** for 'state:calendarState' category */
68 char *cal_event_hash;
69 /** for 'note' category */
70 gchar *note;
71 /** for 'calendarData' category; 300(Team) container */
72 char *working_hours_xml_str;
73 char *fb_start_str;
74 char *free_busy_base64;
77 /**
78 * 2007-style Activity and Availability.
80 * [MS-PRES] 3.7.5.5
82 * Conversion of legacyInterop elements and attributes to MSRTC elements and attributes.
84 * The values define the starting point of a range
86 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_ONLINE 3000
87 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY 4500
88 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_ON_PHONE 6000
89 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY 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_AWAY2 15000
93 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE 18000
94 const gchar *sipe_ocs2007_status_from_legacy_availability(guint availability)
96 guint type;
98 if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_ONLINE) {
99 type = SIPE_ACTIVITY_OFFLINE;
100 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY) {
101 type = SIPE_ACTIVITY_AVAILABLE;
102 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_ON_PHONE) {
103 //type = SIPE_ACTIVITY_IDLE;
104 type = SIPE_ACTIVITY_AVAILABLE;
105 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY) {
106 type = SIPE_ACTIVITY_BUSY;
107 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_DND) {
108 //type = SIPE_ACTIVITY_BUSYIDLE;
109 type = SIPE_ACTIVITY_BUSY;
110 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_BRB) {
111 type = SIPE_ACTIVITY_DND;
112 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY2) {
113 type = SIPE_ACTIVITY_BRB;
114 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE) {
115 type = SIPE_ACTIVITY_AWAY;
116 } else {
117 type = SIPE_ACTIVITY_OFFLINE;
120 return(sipe_backend_activity_to_token(type));
123 const gchar *sipe_ocs2007_legacy_activity_description(guint availability)
125 if ((availability >= SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY) &&
126 (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_ON_PHONE)) {
127 return(sipe_core_activity_description(SIPE_ACTIVITY_INACTIVE));
128 } else if ((availability >= SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY) &&
129 (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_DND)) {
130 return(sipe_core_activity_description(SIPE_ACTIVITY_BUSYIDLE));
131 } else {
132 return(NULL);
137 * @param sipe_status_id (in)
138 * @param activity_token (out) [only sipe-ocs2005.c/send_presence_soap()
139 * requests this token]
141 #define SIPE_OCS2007_AVAILABILITY_UNKNOWN 0
142 #define SIPE_OCS2007_AVAILABILITY_ONLINE 3500
143 #define SIPE_OCS2007_AVAILABILITY_BUSY 6500
144 #define SIPE_OCS2007_AVAILABILITY_DND 9500 /* do not disturb */
145 #define SIPE_OCS2007_AVAILABILITY_BRB 12500 /* be right back */
146 #define SIPE_OCS2007_AVAILABILITY_AWAY 15500
147 #define SIPE_OCS2007_AVAILABILITY_OFFLINE 18500
148 guint sipe_ocs2007_availability_from_status(const gchar *sipe_status_id,
149 const gchar **activity_token)
151 guint availability;
152 guint activity;
154 if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_AWAY))) {
155 availability = SIPE_OCS2007_AVAILABILITY_AWAY;
156 activity = SIPE_ACTIVITY_AWAY;
157 } else if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_BRB))) {
158 availability = SIPE_OCS2007_AVAILABILITY_BRB;
159 activity = SIPE_ACTIVITY_BRB;
160 } else if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_DND))) {
161 availability = SIPE_OCS2007_AVAILABILITY_DND;
162 activity = SIPE_ACTIVITY_DND;
163 } else if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_BUSY))) {
164 availability = SIPE_OCS2007_AVAILABILITY_BUSY;
165 activity = SIPE_ACTIVITY_BUSY;
166 } else if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_AVAILABLE))) {
167 availability = SIPE_OCS2007_AVAILABILITY_ONLINE;
168 activity = SIPE_ACTIVITY_ONLINE;
169 } else if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_UNSET))) {
170 availability = SIPE_OCS2007_AVAILABILITY_UNKNOWN;
171 activity = SIPE_ACTIVITY_UNSET;
172 } else {
173 /* Offline or invisible */
174 availability = SIPE_OCS2007_AVAILABILITY_OFFLINE;
175 activity = SIPE_ACTIVITY_OFFLINE;
178 if (activity_token) {
179 *activity_token = sipe_backend_activity_to_token(activity);
182 return(availability);
185 gboolean sipe_ocs2007_status_is_busy(const gchar *status_id)
187 return(SIPE_OCS2007_AVAILABILITY_BUSY >=
188 sipe_ocs2007_availability_from_status(status_id, NULL));
192 gboolean sipe_ocs2007_availability_is_away2(guint availability)
194 return(availability >= SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY2);
197 static void send_presence_publish(struct sipe_core_private *sipe_private,
198 const char *publications);
200 static void free_publication(struct sipe_publication *publication)
202 g_free(publication->category);
203 g_free(publication->cal_event_hash);
204 g_free(publication->note);
206 g_free(publication->working_hours_xml_str);
207 g_free(publication->fb_start_str);
208 g_free(publication->free_busy_base64);
210 g_free(publication);
213 struct hash_table_delete_payload {
214 GHashTable *hash_table;
215 guint container;
218 static void sipe_remove_category_container_publications_cb(const gchar *name,
219 struct sipe_publication *publication,
220 struct hash_table_delete_payload *payload)
222 if (publication->container == payload->container) {
223 g_hash_table_remove(payload->hash_table, name);
227 static void sipe_remove_category_container_publications(GHashTable *our_publications,
228 const gchar *category,
229 guint container)
231 struct hash_table_delete_payload payload;
232 payload.hash_table = g_hash_table_lookup(our_publications, category);
234 if (!payload.hash_table) return;
236 payload.container = container;
237 g_hash_table_foreach(payload.hash_table,
238 (GHFunc)sipe_remove_category_container_publications_cb,
239 &payload);
242 /** MS-PRES container */
243 struct sipe_container {
244 guint id;
245 guint version;
246 GSList *members;
249 /** MS-PRES container member */
250 struct sipe_container_member {
251 /** user, domain, sameEnterprise, federated, publicCloud; everyone */
252 gchar *type;
253 gchar *value;
256 static const guint containers[] = {32000, 400, 300, 200, 100};
257 #define CONTAINERS_LEN (sizeof(containers) / sizeof(guint))
259 guint sipe_ocs2007_containers(void)
261 return(CONTAINERS_LEN);
264 static void free_container_member(struct sipe_container_member *member)
266 if (!member) return;
268 g_free(member->type);
269 g_free(member->value);
270 g_free(member);
273 void sipe_ocs2007_free_container(struct sipe_container *container)
275 GSList *entry;
277 if (!container) return;
279 entry = container->members;
280 while (entry) {
281 void *data = entry->data;
282 entry = g_slist_remove(entry, data);
283 free_container_member((struct sipe_container_member *)data);
285 g_free(container);
288 struct sipe_container *sipe_ocs2007_create_container(guint index,
289 const gchar *member_type,
290 const gchar *member_value,
291 gboolean is_group)
293 struct sipe_container *container = g_new0(struct sipe_container, 1);
294 struct sipe_container_member *member = g_new0(struct sipe_container_member, 1);
296 container->id = is_group ? (guint) -1 : containers[index];
297 container->members = g_slist_append(container->members, member);
298 member->type = g_strdup(member_type);
299 member->value = g_strdup(member_value);
301 return(container);
304 void sipe_ocs2007_free(struct sipe_core_private *sipe_private)
306 if (sipe_private->containers) {
307 GSList *entry = sipe_private->containers;
308 while (entry) {
309 sipe_ocs2007_free_container((struct sipe_container *)entry->data);
310 entry = entry->next;
313 g_slist_free(sipe_private->containers);
317 * Finds locally stored MS-PRES container member
319 static struct sipe_container_member *
320 sipe_find_container_member(struct sipe_container *container,
321 const gchar *type,
322 const gchar *value)
324 struct sipe_container_member *member;
325 GSList *entry;
327 if (container == NULL || type == NULL) {
328 return NULL;
331 entry = container->members;
332 while (entry) {
333 member = entry->data;
334 if (sipe_strcase_equal(member->type, type) &&
335 sipe_strcase_equal(member->value, value))
337 return member;
339 entry = entry->next;
341 return NULL;
345 * Finds locally stored MS-PRES container by id
347 static struct sipe_container *sipe_find_container(struct sipe_core_private *sipe_private,
348 guint id)
350 GSList *entry = sipe_private->containers;
351 while (entry) {
352 struct sipe_container *container = entry->data;
353 if (id == container->id) {
354 return container;
356 entry = entry->next;
358 return NULL;
361 static int sipe_find_member_access_level(struct sipe_core_private *sipe_private,
362 const gchar *type,
363 const gchar *value)
365 unsigned int i = 0;
366 const gchar *value_mod = value;
368 if (!type) return -1;
370 if (sipe_strequal("user", type)) {
371 value_mod = sipe_get_no_sip_uri(value);
374 for (i = 0; i < CONTAINERS_LEN; i++) {
375 struct sipe_container_member *member;
376 struct sipe_container *container = sipe_find_container(sipe_private, containers[i]);
377 if (!container) continue;
379 member = sipe_find_container_member(container, type, value_mod);
380 if (member) return containers[i];
383 return -1;
387 * Returns pointer to domain part in provided Email URL
389 * @param email an email URL. Example: first.last@hq.company.com
390 * @return pointer to domain part of email URL. Coresponding example: hq.company.com
392 * Doesn't allocate memory
394 static const gchar *sipe_get_domain(const gchar *email)
396 gchar *tmp;
398 if (!email) return NULL;
400 tmp = strstr(email, "@");
402 if (tmp && ((tmp+1) < (email + strlen(email)))) {
403 return tmp+1;
404 } else {
405 return NULL;
409 /* @TODO: replace with binary search for faster access? */
410 /** source: http://support.microsoft.com/kb/897567 */
411 static const gchar * const public_domains[] = {
412 "aol.com", "icq.com", "love.com", "mac.com", "br.live.com",
413 "hotmail.co.il", "hotmail.co.jp", "hotmail.co.th", "hotmail.co.uk",
414 "hotmail.com", "hotmail.com.ar", "hotmail.com.tr", "hotmail.es",
415 "hotmail.de", "hotmail.fr", "hotmail.it", "live.at", "live.be",
416 "live.ca", "live.cl", "live.cn", "live.co.in", "live.co.kr",
417 "live.co.uk", "live.co.za", "live.com", "live.com.ar", "live.com.au",
418 "live.com.co", "live.com.mx", "live.com.my", "live.com.pe",
419 "live.com.ph", "live.com.pk", "live.com.pt", "live.com.sg",
420 "live.com.ve", "live.de", "live.dk", "live.fr", "live.hk", "live.ie",
421 "live.in", "live.it", "live.jp", "live.nl", "live.no", "live.ph",
422 "live.ru", "live.se", "livemail.com.br", "livemail.tw",
423 "messengeruser.com", "msn.com", "passport.com", "sympatico.ca",
424 "tw.live.com", "webtv.net", "windowslive.com", "windowslive.es",
425 "yahoo.com",
426 NULL};
428 static gboolean sipe_is_public_domain(const gchar *domain)
430 int i = 0;
431 while (public_domains[i]) {
432 if (sipe_strcase_equal(public_domains[i], domain)) {
433 return TRUE;
435 i++;
437 return FALSE;
441 * Access Levels
442 * 32000 - Blocked
443 * 400 - Personal
444 * 300 - Team
445 * 200 - Company
446 * 100 - Public
448 const gchar *sipe_ocs2007_access_level_name(guint id)
450 switch (id) {
451 case 32000: return _("Blocked");
452 case 400: return _("Personal");
453 case 300: return _("Team");
454 case 200: return _("Company");
455 case 100: return _("Public");
457 return _("Unknown");
460 int sipe_ocs2007_container_id(guint index)
462 return(containers[index]);
465 /** Member type: user, domain, sameEnterprise, federated, publicCloud; everyone */
466 int sipe_ocs2007_find_access_level(struct sipe_core_private *sipe_private,
467 const gchar *type,
468 const gchar *value,
469 gboolean *is_group_access)
471 int container_id = -1;
473 if (sipe_strequal("user", type)) {
474 const char *domain;
475 const char *no_sip_uri = sipe_get_no_sip_uri(value);
477 container_id = sipe_find_member_access_level(sipe_private, "user", no_sip_uri);
478 if (container_id >= 0) {
479 if (is_group_access) *is_group_access = FALSE;
480 return container_id;
483 domain = sipe_get_domain(no_sip_uri);
484 container_id = sipe_find_member_access_level(sipe_private, "domain", domain);
485 if (container_id >= 0) {
486 if (is_group_access) *is_group_access = TRUE;
487 return container_id;
490 container_id = sipe_find_member_access_level(sipe_private, "sameEnterprise", NULL);
491 if ((container_id >= 0) && sipe_strcase_equal(sipe_private->public.sip_domain, domain)) {
492 if (is_group_access) *is_group_access = TRUE;
493 return container_id;
496 container_id = sipe_find_member_access_level(sipe_private, "publicCloud", NULL);
497 if ((container_id >= 0) && sipe_is_public_domain(domain)) {
498 if (is_group_access) *is_group_access = TRUE;
499 return container_id;
502 container_id = sipe_find_member_access_level(sipe_private, "everyone", NULL);
503 if ((container_id >= 0)) {
504 if (is_group_access) *is_group_access = TRUE;
505 return container_id;
507 } else {
508 container_id = sipe_find_member_access_level(sipe_private, type, value);
509 if (is_group_access) *is_group_access = FALSE;
512 return container_id;
515 GSList *sipe_ocs2007_get_access_domains(struct sipe_core_private *sipe_private)
517 struct sipe_container *container;
518 struct sipe_container_member *member;
519 GSList *entry;
520 GSList *entry2;
521 GSList *res = NULL;
523 entry = sipe_private->containers;
524 while (entry) {
525 container = entry->data;
527 entry2 = container->members;
528 while (entry2) {
529 member = entry2->data;
530 if (sipe_strcase_equal(member->type, "domain"))
532 res = slist_insert_unique_sorted(res, g_strdup(member->value), (GCompareFunc)g_ascii_strcasecmp);
534 entry2 = entry2->next;
536 entry = entry->next;
538 return res;
541 static void sipe_send_container_members_prepare(const guint container_id,
542 const guint container_version,
543 const gchar *action,
544 const gchar *type,
545 const gchar *value,
546 char **container_xmls)
548 gchar *value_str = value ? g_strdup_printf(" value=\"%s\"", value) : g_strdup("");
549 gchar *body;
551 if (!container_xmls) return;
553 body = g_strdup_printf(
554 "<container id=\"%d\" version=\"%d\"><member action=\"%s\" type=\"%s\"%s/></container>",
555 container_id,
556 container_version,
557 action,
558 type,
559 value_str);
560 g_free(value_str);
562 if ((*container_xmls) == NULL) {
563 *container_xmls = body;
564 } else {
565 char *tmp = *container_xmls;
567 *container_xmls = g_strconcat(*container_xmls, body, NULL);
568 g_free(tmp);
569 g_free(body);
573 static void sipe_send_set_container_members(struct sipe_core_private *sipe_private,
574 char *container_xmls)
576 gchar *self;
577 gchar *contact;
578 gchar *hdr;
579 gchar *body;
581 if (!container_xmls) return;
583 self = sip_uri_self(sipe_private);
584 body = g_strdup_printf(
585 "<setContainerMembers xmlns=\"http://schemas.microsoft.com/2006/09/sip/container-management\">"
586 "%s"
587 "</setContainerMembers>",
588 container_xmls);
590 contact = get_contact(sipe_private);
591 hdr = g_strdup_printf("Contact: %s\r\n"
592 "Content-Type: application/msrtc-setcontainermembers+xml\r\n", contact);
593 g_free(contact);
595 sip_transport_service(sipe_private,
596 self,
597 hdr,
598 body,
599 NULL);
601 g_free(hdr);
602 g_free(body);
603 g_free(self);
607 * @param container_id a new access level. If -1 then current access level
608 * is just removed (I.e. the member is removed from all containers).
609 * @param type a type of member. E.g. "user", "sameEnterprise", etc.
610 * @param value a value for member. E.g. SIP URI for "user" member type.
612 void sipe_ocs2007_change_access_level(struct sipe_core_private *sipe_private,
613 const int container_id,
614 const gchar *type,
615 const gchar *value)
617 unsigned int i;
618 int current_container_id = -1;
619 char *container_xmls = NULL;
621 /* for each container: find/delete */
622 for (i = 0; i < CONTAINERS_LEN; i++) {
623 struct sipe_container_member *member;
624 struct sipe_container *container = sipe_find_container(sipe_private, containers[i]);
626 if (!container) continue;
628 member = sipe_find_container_member(container, type, value);
629 if (member) {
630 current_container_id = containers[i];
631 /* delete/publish current access level */
632 if (container_id < 0 || container_id != current_container_id) {
633 sipe_send_container_members_prepare(current_container_id, container->version, "remove", type, value, &container_xmls);
634 /* remove member from our cache, to be able to recalculate AL below */
635 container->members = g_slist_remove(container->members, member);
636 current_container_id = -1;
641 /* recalculate AL below */
642 current_container_id = sipe_ocs2007_find_access_level(sipe_private, type, value, NULL);
644 /* assign/publish new access level */
645 if (container_id != current_container_id && container_id >= 0) {
646 struct sipe_container *container = sipe_find_container(sipe_private, container_id);
647 guint version = container ? container->version : 0;
649 sipe_send_container_members_prepare(container_id, version, "add", type, value, &container_xmls);
652 if (container_xmls) {
653 sipe_send_set_container_members(sipe_private, container_xmls);
655 g_free(container_xmls);
658 void sipe_ocs2007_change_access_level_from_container(struct sipe_core_private *sipe_private,
659 struct sipe_container *container)
661 struct sipe_container_member *member;
663 if (!container || !container->members) return;
665 member = ((struct sipe_container_member *)container->members->data);
667 if (!member->type) return;
669 SIPE_DEBUG_INFO("sipe_ocs2007_change_access_level_from_container: container->id=%d, member->type=%s, member->value=%s",
670 container->id, member->type, member->value ? member->value : "");
672 sipe_ocs2007_change_access_level(sipe_private,
673 container->id,
674 member->type,
675 member->value);
679 void sipe_ocs2007_change_access_level_for_domain(struct sipe_core_private *sipe_private,
680 const gchar *domain,
681 guint index)
683 /* move Blocked first */
684 guint i = (index == 4) ? 0 : index + 1;
685 guint container_id = containers[i];
687 SIPE_DEBUG_INFO("sipe_ocs2007_change_access_level_from_id: domain=%s, container_id=(%d)%d",
688 domain ? domain : "", index, container_id);
690 sipe_ocs2007_change_access_level(sipe_private,
691 container_id,
692 "domain",
693 domain);
698 * Schedules process of self status publish
699 * based on own calendar information.
700 * Should be scheduled to the beginning of every
701 * 15 min interval, like:
702 * 13:00, 13:15, 13:30, 13:45, etc.
705 static void schedule_publish_update(struct sipe_core_private *sipe_private,
706 time_t calculate_from)
708 int interval = 5*60;
709 /** start of the beginning of closest 5 min interval. */
710 time_t next_start = ((time_t)((int)((int)calculate_from)/interval + 1)*interval);
712 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: calculate_from time: %s",
713 asctime(localtime(&calculate_from)));
714 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: next start time : %s",
715 asctime(localtime(&next_start)));
717 sipe_schedule_seconds(sipe_private,
718 "<+2007-cal-status>",
719 NULL,
720 next_start - time(NULL),
721 sipe_ocs2007_presence_publish,
722 NULL);
726 * An availability XML entry for SIPE_PUB_XML_STATE_CALENDAR
727 * @param availability (%d) Ex.: 6500
729 #define SIPE_PUB_XML_STATE_CALENDAR_AVAIL \
730 "<availability>%d</availability>"
732 * An activity XML entry for SIPE_PUB_XML_STATE_CALENDAR
733 * @param token (%s) Ex.: in-a-meeting
734 * @param minAvailability_attr (%s) Ex.: minAvailability="6500"
735 * @param maxAvailability_attr (%s) Ex.: maxAvailability="8999" or none
737 #define SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY \
738 "<activity token=\"%s\" %s %s></activity>"
740 * Publishes 'calendarState' category.
741 * @param instance (%u) Ex.: 1339299275
742 * @param version (%u) Ex.: 1
743 * @param uri (%s) Ex.: john@contoso.com
744 * @param start_time_str (%s) Ex.: 2008-01-11T19:00:00Z
745 * @param availability (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_AVAIL
746 * @param activity (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
747 * @param meeting_subject (%s) Ex.: Customer Meeting
748 * @param meeting_location (%s) Ex.: Conf Room 100
750 * @param instance (%u) Ex.: 1339299275
751 * @param version (%u) Ex.: 1
752 * @param uri (%s) Ex.: john@contoso.com
753 * @param start_time_str (%s) Ex.: 2008-01-11T19:00:00Z
754 * @param availability (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_AVAIL
755 * @param activity (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
756 * @param meeting_subject (%s) Ex.: Customer Meeting
757 * @param meeting_location (%s) Ex.: Conf Room 100
759 #define SIPE_PUB_XML_STATE_CALENDAR \
760 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
761 "<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\">"\
762 "%s"\
763 "%s"\
764 "<endpointLocation/>"\
765 "<meetingSubject>%s</meetingSubject>"\
766 "<meetingLocation>%s</meetingLocation>"\
767 "</state>"\
768 "</publication>"\
769 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
770 "<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\">"\
771 "%s"\
772 "%s"\
773 "<endpointLocation/>"\
774 "<meetingSubject>%s</meetingSubject>"\
775 "<meetingLocation>%s</meetingLocation>"\
776 "</state>"\
777 "</publication>"
779 * Publishes to clear 'calendarState' category
780 * @param instance (%u) Ex.: 1251210982
781 * @param version (%u) Ex.: 1
783 #define SIPE_PUB_XML_STATE_CALENDAR_CLEAR \
784 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"\
785 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"
788 * Publishes to clear any category
789 * @param category_name (%s) Ex.: state
790 * @param instance (%u) Ex.: 536870912
791 * @param container (%u) Ex.: 3
792 * @param version (%u) Ex.: 1
793 * @param expireType (%s) Ex.: static
795 #define SIPE_PUB_XML_PUBLICATION_CLEAR \
796 "<publication categoryName=\"%s\" instance=\"%u\" container=\"%u\" version=\"%u\" expireType=\"%s\" expires=\"0\"/>"
799 * Publishes 'note' category.
800 * @param instance (%u) Ex.: 2135971629; 0 for personal
801 * @param container (%u) Ex.: 200
802 * @param version (%u) Ex.: 2
803 * @param type (%s) Ex.: personal or OOF
804 * @param startTime_attr (%s) Ex.: startTime="2008-01-11T19:00:00Z"
805 * @param endTime_attr (%s) Ex.: endTime="2008-01-15T19:00:00Z"
806 * @param body (%s) Ex.: In the office
808 #define SIPE_PUB_XML_NOTE \
809 "<publication categoryName=\"note\" instance=\"%u\" container=\"%u\" version=\"%d\" expireType=\"static\">"\
810 "<note xmlns=\"http://schemas.microsoft.com/2006/09/sip/note\">"\
811 "<body type=\"%s\" uri=\"\"%s%s>%s</body>"\
812 "</note>"\
813 "</publication>"
816 * Only Busy and OOF calendar event are published.
817 * Different instances are used for that.
819 * Must be g_free'd after use.
821 static gchar *sipe_publish_get_category_state_calendar(struct sipe_core_private *sipe_private,
822 struct sipe_cal_event *event,
823 const char *uri,
824 int cal_satus)
826 gchar *start_time_str;
827 int availability = 0;
828 gchar *res;
829 gchar *tmp = NULL;
830 guint instance = (cal_satus == SIPE_CAL_OOF) ?
831 sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_CALENDAR_OOF) :
832 sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_CALENDAR);
834 /* key is <category><instance><container> */
835 gchar *key_2 = g_strdup_printf("<%s><%u><%u>", "state", instance, 2);
836 gchar *key_3 = g_strdup_printf("<%s><%u><%u>", "state", instance, 3);
837 struct sipe_publication *publication_2 =
838 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "state"), key_2);
839 struct sipe_publication *publication_3 =
840 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "state"), key_3);
842 g_free(key_2);
843 g_free(key_3);
845 if (!publication_3 && !event) { /* was nothing, have nothing, exiting */
846 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
847 "Exiting as no publication and no event for cal_satus:%d", cal_satus);
848 return NULL;
851 if (event &&
852 publication_3 &&
853 (publication_3->availability == availability) &&
854 sipe_strequal(publication_3->cal_event_hash, (tmp = sipe_cal_event_hash(event))))
856 g_free(tmp);
857 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
858 "cal state has NOT changed for cal_satus:%d. Exiting.", cal_satus);
859 return NULL; /* nothing to update */
861 g_free(tmp);
863 if (event &&
864 (event->cal_status == SIPE_CAL_BUSY ||
865 event->cal_status == SIPE_CAL_OOF))
867 gchar *availability_xml_str = NULL;
868 gchar *activity_xml_str = NULL;
869 gchar *escaped_subject = event->subject ? g_markup_escape_text(event->subject, -1) : NULL;
870 gchar *escaped_location = event->location ? g_markup_escape_text(event->location, -1) : NULL;
872 if (event->cal_status == SIPE_CAL_BUSY) {
873 availability_xml_str = g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_AVAIL,
874 SIPE_OCS2007_AVAILABILITY_BUSY);
877 if (event->cal_status == SIPE_CAL_BUSY && event->is_meeting) {
878 activity_xml_str = g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY,
879 sipe_backend_activity_to_token(SIPE_ACTIVITY_IN_MEETING),
880 "minAvailability=\"6500\"",
881 "maxAvailability=\"8999\"");
882 } else if (event->cal_status == SIPE_CAL_OOF) {
883 activity_xml_str = g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY,
884 sipe_backend_activity_to_token(SIPE_ACTIVITY_OOF),
885 "minAvailability=\"12000\"",
886 "");
888 start_time_str = sipe_utils_time_to_str(event->start_time);
890 res = g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR,
891 instance,
892 publication_2 ? publication_2->version : 0,
893 uri,
894 start_time_str,
895 availability_xml_str ? availability_xml_str : "",
896 activity_xml_str ? activity_xml_str : "",
897 escaped_subject ? escaped_subject : "",
898 escaped_location ? escaped_location : "",
900 instance,
901 publication_3 ? publication_3->version : 0,
902 uri,
903 start_time_str,
904 availability_xml_str ? availability_xml_str : "",
905 activity_xml_str ? activity_xml_str : "",
906 escaped_subject ? escaped_subject : "",
907 escaped_location ? escaped_location : ""
909 g_free(escaped_location);
910 g_free(escaped_subject);
911 g_free(start_time_str);
912 g_free(availability_xml_str);
913 g_free(activity_xml_str);
916 else /* including !event, SIPE_CAL_FREE, SIPE_CAL_TENTATIVE */
918 res = g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_CLEAR,
919 instance,
920 publication_2 ? publication_2->version : 0,
922 instance,
923 publication_3 ? publication_3->version : 0
927 return res;
931 * Returns 'note' XML part for publication.
932 * Must be g_free'd after use.
934 * Protocol format for Note is plain text.
936 * @param note a note in Sipe internal HTML format
937 * @param note_type either personal or OOF
939 static gchar *sipe_publish_get_category_note(struct sipe_core_private *sipe_private,
940 const char *note, /* html */
941 const char *note_type,
942 time_t note_start,
943 time_t note_end)
945 guint instance = sipe_strequal("OOF", note_type) ? sipe_get_pub_instance(sipe_private, SIPE_PUB_NOTE_OOF) : 0;
946 /* key is <category><instance><container> */
947 gchar *key_note_200 = g_strdup_printf("<%s><%u><%u>", "note", instance, 200);
948 gchar *key_note_300 = g_strdup_printf("<%s><%u><%u>", "note", instance, 300);
949 gchar *key_note_400 = g_strdup_printf("<%s><%u><%u>", "note", instance, 400);
951 struct sipe_publication *publication_note_200 =
952 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "note"), key_note_200);
953 struct sipe_publication *publication_note_300 =
954 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "note"), key_note_300);
955 struct sipe_publication *publication_note_400 =
956 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "note"), key_note_400);
958 char *tmp = note ? sipe_backend_markup_strip_html(note) : NULL;
959 char *n1 = tmp ? g_markup_escape_text(tmp, -1) : NULL;
960 const char *n2 = publication_note_200 ? publication_note_200->note : NULL;
961 char *res, *tmp1, *tmp2, *tmp3;
962 char *start_time_attr;
963 char *end_time_attr;
965 g_free(tmp);
966 tmp = NULL;
967 g_free(key_note_200);
968 g_free(key_note_300);
969 g_free(key_note_400);
971 /* we even need to republish empty note */
972 if (sipe_strequal(n1, n2))
974 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_note: note has NOT changed. Exiting.");
975 g_free(n1);
976 return NULL; /* nothing to update */
979 start_time_attr = note_start ? g_strdup_printf(" startTime=\"%s\"", (tmp = sipe_utils_time_to_str(note_start))) : NULL;
980 g_free(tmp);
981 tmp = NULL;
982 end_time_attr = note_end ? g_strdup_printf(" endTime=\"%s\"", (tmp = sipe_utils_time_to_str(note_end))) : NULL;
983 g_free(tmp);
985 if (n1) {
986 tmp1 = g_strdup_printf(SIPE_PUB_XML_NOTE,
987 instance,
988 200,
989 publication_note_200 ? publication_note_200->version : 0,
990 note_type,
991 start_time_attr ? start_time_attr : "",
992 end_time_attr ? end_time_attr : "",
993 n1);
995 tmp2 = g_strdup_printf(SIPE_PUB_XML_NOTE,
996 instance,
997 300,
998 publication_note_300 ? publication_note_300->version : 0,
999 note_type,
1000 start_time_attr ? start_time_attr : "",
1001 end_time_attr ? end_time_attr : "",
1002 n1);
1004 tmp3 = g_strdup_printf(SIPE_PUB_XML_NOTE,
1005 instance,
1006 400,
1007 publication_note_400 ? publication_note_400->version : 0,
1008 note_type,
1009 start_time_attr ? start_time_attr : "",
1010 end_time_attr ? end_time_attr : "",
1011 n1);
1012 } else {
1013 tmp1 = g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR,
1014 "note",
1015 instance,
1016 200,
1017 publication_note_200 ? publication_note_200->version : 0,
1018 "static");
1019 tmp2 = g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR,
1020 "note",
1021 instance,
1022 300,
1023 publication_note_200 ? publication_note_200->version : 0,
1024 "static");
1025 tmp3 = g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR,
1026 "note",
1027 instance,
1028 400,
1029 publication_note_200 ? publication_note_200->version : 0,
1030 "static");
1032 res = g_strconcat(tmp1, tmp2, tmp3, NULL);
1034 g_free(start_time_attr);
1035 g_free(end_time_attr);
1036 g_free(tmp1);
1037 g_free(tmp2);
1038 g_free(tmp3);
1039 g_free(n1);
1041 return res;
1045 * Publishes 'calendarData' category's WorkingHours.
1047 * @param version (%u) Ex.: 1
1048 * @param email (%s) Ex.: alice@cosmo.local
1049 * @param working_hours_xml_str (%s) Ex.: <WorkingHours xmlns=.....
1051 * @param version (%u)
1053 * @param version (%u)
1054 * @param email (%s)
1055 * @param working_hours_xml_str (%s)
1057 * @param version (%u)
1058 * @param email (%s)
1059 * @param working_hours_xml_str (%s)
1061 * @param version (%u)
1062 * @param email (%s)
1063 * @param working_hours_xml_str (%s)
1065 * @param version (%u)
1067 #define SIPE_PUB_XML_WORKING_HOURS \
1068 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"1\" version=\"%d\" expireType=\"static\">"\
1069 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1070 "</calendarData>"\
1071 "</publication>"\
1072 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"100\" version=\"%d\" expireType=\"static\">"\
1073 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1074 "</publication>"\
1075 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"200\" version=\"%d\" expireType=\"static\">"\
1076 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1077 "</calendarData>"\
1078 "</publication>"\
1079 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"300\" version=\"%d\" expireType=\"static\">"\
1080 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1081 "</calendarData>"\
1082 "</publication>"\
1083 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"400\" version=\"%d\" expireType=\"static\">"\
1084 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1085 "</calendarData>"\
1086 "</publication>"\
1087 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"32000\" version=\"%d\" expireType=\"static\">"\
1088 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1089 "</publication>"
1092 * Returns 'calendarData' XML part with WorkingHours for publication.
1093 * Must be g_free'd after use.
1095 static gchar *sipe_publish_get_category_cal_working_hours(struct sipe_core_private *sipe_private)
1097 struct sipe_calendar* cal = sipe_private->calendar;
1099 /* key is <category><instance><container> */
1100 gchar *key_cal_1 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1);
1101 gchar *key_cal_100 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100);
1102 gchar *key_cal_200 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200);
1103 gchar *key_cal_300 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300);
1104 gchar *key_cal_400 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400);
1105 gchar *key_cal_32000 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000);
1107 struct sipe_publication *publication_cal_1 =
1108 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_1);
1109 struct sipe_publication *publication_cal_100 =
1110 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_100);
1111 struct sipe_publication *publication_cal_200 =
1112 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_200);
1113 struct sipe_publication *publication_cal_300 =
1114 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_300);
1115 struct sipe_publication *publication_cal_400 =
1116 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_400);
1117 struct sipe_publication *publication_cal_32000 =
1118 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_32000);
1120 const char *n1 = cal ? cal->working_hours_xml_str : NULL;
1121 const char *n2 = publication_cal_300 ? publication_cal_300->working_hours_xml_str : NULL;
1123 g_free(key_cal_1);
1124 g_free(key_cal_100);
1125 g_free(key_cal_200);
1126 g_free(key_cal_300);
1127 g_free(key_cal_400);
1128 g_free(key_cal_32000);
1130 if (!cal || is_empty(cal->email) || is_empty(cal->working_hours_xml_str)) {
1131 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_working_hours: no data to publish, exiting");
1132 return NULL;
1135 if (sipe_strequal(n1, n2))
1137 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_working_hours: WorkingHours has NOT changed. Exiting.");
1138 return NULL; /* nothing to update */
1141 return g_strdup_printf(SIPE_PUB_XML_WORKING_HOURS,
1142 /* 1 */
1143 publication_cal_1 ? publication_cal_1->version : 0,
1144 cal->email,
1145 cal->working_hours_xml_str,
1146 /* 100 - Public */
1147 publication_cal_100 ? publication_cal_100->version : 0,
1148 /* 200 - Company */
1149 publication_cal_200 ? publication_cal_200->version : 0,
1150 cal->email,
1151 cal->working_hours_xml_str,
1152 /* 300 - Team */
1153 publication_cal_300 ? publication_cal_300->version : 0,
1154 cal->email,
1155 cal->working_hours_xml_str,
1156 /* 400 - Personal */
1157 publication_cal_400 ? publication_cal_400->version : 0,
1158 cal->email,
1159 cal->working_hours_xml_str,
1160 /* 32000 - Blocked */
1161 publication_cal_32000 ? publication_cal_32000->version : 0
1166 * Publishes 'calendarData' category's FreeBusy.
1168 * @param instance (%u) Ex.: 1300372959
1169 * @param version (%u) Ex.: 1
1171 * @param instance (%u) Ex.: 1300372959
1172 * @param version (%u) Ex.: 1
1174 * @param instance (%u) Ex.: 1300372959
1175 * @param version (%u) Ex.: 1
1176 * @param email (%s) Ex.: alice@cosmo.local
1177 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1178 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1180 * @param instance (%u) Ex.: 1300372959
1181 * @param version (%u) Ex.: 1
1182 * @param email (%s) Ex.: alice@cosmo.local
1183 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1184 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1186 * @param instance (%u) Ex.: 1300372959
1187 * @param version (%u) Ex.: 1
1188 * @param email (%s) Ex.: alice@cosmo.local
1189 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1190 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1192 * @param instance (%u) Ex.: 1300372959
1193 * @param version (%u) Ex.: 1
1195 #define SIPE_PUB_XML_FREE_BUSY \
1196 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"1\" version=\"%d\" expireType=\"endpoint\">"\
1197 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1198 "</publication>"\
1199 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"100\" version=\"%d\" expireType=\"endpoint\">"\
1200 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1201 "</publication>"\
1202 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"200\" version=\"%d\" expireType=\"endpoint\">"\
1203 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1204 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1205 "</calendarData>"\
1206 "</publication>"\
1207 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"300\" version=\"%d\" expireType=\"endpoint\">"\
1208 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1209 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1210 "</calendarData>"\
1211 "</publication>"\
1212 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"400\" version=\"%d\" expireType=\"endpoint\">"\
1213 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1214 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1215 "</calendarData>"\
1216 "</publication>"\
1217 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"32000\" version=\"%d\" expireType=\"endpoint\">"\
1218 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1219 "</publication>"
1222 * Returns 'calendarData' XML part with FreeBusy for publication.
1223 * Must be g_free'd after use.
1225 static gchar *sipe_publish_get_category_cal_free_busy(struct sipe_core_private *sipe_private)
1227 struct sipe_calendar* cal = sipe_private->calendar;
1228 guint cal_data_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_CALENDAR_DATA);
1229 char *fb_start_str;
1230 char *free_busy_base64;
1231 /* const char *st; */
1232 /* const char *fb; */
1233 char *res;
1235 /* key is <category><instance><container> */
1236 gchar *key_cal_1 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 1);
1237 gchar *key_cal_100 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 100);
1238 gchar *key_cal_200 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 200);
1239 gchar *key_cal_300 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 300);
1240 gchar *key_cal_400 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 400);
1241 gchar *key_cal_32000 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 32000);
1243 struct sipe_publication *publication_cal_1 =
1244 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_1);
1245 struct sipe_publication *publication_cal_100 =
1246 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_100);
1247 struct sipe_publication *publication_cal_200 =
1248 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_200);
1249 struct sipe_publication *publication_cal_300 =
1250 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_300);
1251 struct sipe_publication *publication_cal_400 =
1252 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_400);
1253 struct sipe_publication *publication_cal_32000 =
1254 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_32000);
1256 g_free(key_cal_1);
1257 g_free(key_cal_100);
1258 g_free(key_cal_200);
1259 g_free(key_cal_300);
1260 g_free(key_cal_400);
1261 g_free(key_cal_32000);
1263 if (!cal || is_empty(cal->email) || !cal->fb_start || is_empty(cal->free_busy)) {
1264 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_free_busy: no data to publish, exiting");
1265 return NULL;
1268 fb_start_str = sipe_utils_time_to_str(cal->fb_start);
1269 free_busy_base64 = sipe_cal_get_freebusy_base64(cal->free_busy);
1271 /* we will rebuplish the same data to refresh publication time,
1272 * so if data from multiple sources, most recent will be choosen
1274 // st = publication_cal_300 ? publication_cal_300->fb_start_str : NULL;
1275 // fb = publication_cal_300 ? publication_cal_300->free_busy_base64 : NULL;
1277 //if (sipe_strequal(st, fb_start_str) && sipe_strequal(fb, free_busy_base64))
1279 // SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_free_busy: FreeBusy has NOT changed. Exiting.");
1280 // g_free(fb_start_str);
1281 // g_free(free_busy_base64);
1282 // return NULL; /* nothing to update */
1285 res = g_strdup_printf(SIPE_PUB_XML_FREE_BUSY,
1286 /* 1 */
1287 cal_data_instance,
1288 publication_cal_1 ? publication_cal_1->version : 0,
1289 /* 100 - Public */
1290 cal_data_instance,
1291 publication_cal_100 ? publication_cal_100->version : 0,
1292 /* 200 - Company */
1293 cal_data_instance,
1294 publication_cal_200 ? publication_cal_200->version : 0,
1295 cal->email,
1296 fb_start_str,
1297 free_busy_base64,
1298 /* 300 - Team */
1299 cal_data_instance,
1300 publication_cal_300 ? publication_cal_300->version : 0,
1301 cal->email,
1302 fb_start_str,
1303 free_busy_base64,
1304 /* 400 - Personal */
1305 cal_data_instance,
1306 publication_cal_400 ? publication_cal_400->version : 0,
1307 cal->email,
1308 fb_start_str,
1309 free_busy_base64,
1310 /* 32000 - Blocked */
1311 cal_data_instance,
1312 publication_cal_32000 ? publication_cal_32000->version : 0
1315 g_free(fb_start_str);
1316 g_free(free_busy_base64);
1317 return res;
1322 * Publishes 'device' category.
1323 * @param instance (%u) Ex.: 1938468728
1324 * @param version (%u) Ex.: 1
1325 * @param endpointId (%s) Ex.: C707E38E-1E10-5413-94D9-ECAC260A0269
1326 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1327 * @param timezone (%s) Ex.: 00:00:00+01:00
1328 * @param machineName (%s) Ex.: BOSTON-OCS07
1330 #define SIPE_PUB_XML_DEVICE \
1331 "<publication categoryName=\"device\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
1332 "<device xmlns=\"http://schemas.microsoft.com/2006/09/sip/device\" endpointId=\"%s\">"\
1333 "<capabilities preferred=\"false\" uri=\"%s\">"\
1334 "<text capture=\"true\" render=\"true\" publish=\"false\"/>"\
1335 "<gifInk capture=\"false\" render=\"true\" publish=\"false\"/>"\
1336 "<isfInk capture=\"false\" render=\"true\" publish=\"false\"/>"\
1337 "</capabilities>"\
1338 "<timezone>%s</timezone>"\
1339 "<machineName>%s</machineName>"\
1340 "</device>"\
1341 "</publication>"
1344 * Returns 'device' XML part for publication.
1345 * Must be g_free'd after use.
1347 static gchar *sipe_publish_get_category_device(struct sipe_core_private *sipe_private)
1349 gchar *uri;
1350 gchar *doc;
1351 gchar *uuid = get_uuid(sipe_private);
1352 guint device_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_DEVICE);
1353 /* key is <category><instance><container> */
1354 gchar *key = g_strdup_printf("<%s><%u><%u>", "device", device_instance, 2);
1355 struct sipe_publication *publication =
1356 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "device"), key);
1358 g_free(key);
1360 uri = sip_uri_self(sipe_private);
1361 doc = g_strdup_printf(SIPE_PUB_XML_DEVICE,
1362 device_instance,
1363 publication ? publication->version : 0,
1364 uuid,
1365 uri,
1366 "00:00:00+01:00", /* @TODO make timezone real*/
1367 g_get_host_name()
1370 g_free(uri);
1371 g_free(uuid);
1373 return doc;
1377 * Publishes 'machineState' category.
1378 * @param instance (%u) Ex.: 926460663
1379 * @param version (%u) Ex.: 22
1380 * @param availability (%d) Ex.: 3500
1381 * @param instance (%u) Ex.: 926460663
1382 * @param version (%u) Ex.: 22
1383 * @param availability (%d) Ex.: 3500
1385 #define SIPE_PUB_XML_STATE_MACHINE \
1386 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
1387 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"machineState\">"\
1388 "<availability>%d</availability>"\
1389 "<endpointLocation/>"\
1390 "</state>"\
1391 "</publication>"\
1392 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
1393 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"machineState\">"\
1394 "<availability>%d</availability>"\
1395 "<endpointLocation/>"\
1396 "</state>"\
1397 "</publication>"
1400 * Publishes 'userState' category.
1401 * @param instance (%u) User. Ex.: 536870912
1402 * @param version (%u) User Container 2. Ex.: 22
1403 * @param availability (%d) User Container 2. Ex.: 15500
1404 * @param instance (%u) User. Ex.: 536870912
1405 * @param version (%u) User Container 3.Ex.: 22
1406 * @param availability (%d) User Container 3. Ex.: 15500
1408 #define SIPE_PUB_XML_STATE_USER \
1409 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"static\">"\
1410 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"true\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"userState\">"\
1411 "<availability>%d</availability>"\
1412 "<endpointLocation/>"\
1413 "</state>"\
1414 "</publication>"\
1415 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"static\">"\
1416 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"true\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"userState\">"\
1417 "<availability>%d</availability>"\
1418 "<endpointLocation/>"\
1419 "</state>"\
1420 "</publication>"
1423 * A service method - use
1424 * - send_publish_get_category_state_machine and
1425 * - send_publish_get_category_state_user instead.
1426 * Must be g_free'd after use.
1428 static gchar *sipe_publish_get_category_state(struct sipe_core_private *sipe_private,
1429 gboolean is_user_state)
1431 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
1432 int availability = sipe_ocs2007_availability_from_status(sip->status, NULL);
1433 guint instance = is_user_state ? sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_USER) :
1434 sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_MACHINE);
1435 /* key is <category><instance><container> */
1436 gchar *key_2 = g_strdup_printf("<%s><%u><%u>", "state", instance, 2);
1437 gchar *key_3 = g_strdup_printf("<%s><%u><%u>", "state", instance, 3);
1438 struct sipe_publication *publication_2 =
1439 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "state"), key_2);
1440 struct sipe_publication *publication_3 =
1441 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "state"), key_3);
1443 g_free(key_2);
1444 g_free(key_3);
1446 if (publication_2 && (publication_2->availability == availability))
1448 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_state: state has NOT changed. Exiting.");
1449 return NULL; /* nothing to update */
1452 return g_strdup_printf( is_user_state ? SIPE_PUB_XML_STATE_USER : SIPE_PUB_XML_STATE_MACHINE,
1453 instance,
1454 publication_2 ? publication_2->version : 0,
1455 availability,
1456 instance,
1457 publication_3 ? publication_3->version : 0,
1458 availability);
1462 * Returns 'machineState' XML part for publication.
1463 * Must be g_free'd after use.
1465 static gchar *sipe_publish_get_category_state_machine(struct sipe_core_private *sipe_private)
1467 return sipe_publish_get_category_state(sipe_private, FALSE);
1471 * Returns 'userState' XML part for publication.
1472 * Must be g_free'd after use.
1474 static gchar *sipe_publish_get_category_state_user(struct sipe_core_private *sipe_private)
1476 return sipe_publish_get_category_state(sipe_private, TRUE);
1479 static void send_publish_category_initial(struct sipe_core_private *sipe_private)
1481 gchar *pub_device = sipe_publish_get_category_device(sipe_private);
1482 gchar *pub_machine;
1483 gchar *publications;
1485 sipe_status_set_activity(sipe_private, SIPE_ACTIVITY_AVAILABLE);
1487 pub_machine = sipe_publish_get_category_state_machine(sipe_private);
1488 publications = g_strdup_printf("%s%s",
1489 pub_device,
1490 pub_machine ? pub_machine : "");
1491 g_free(pub_device);
1492 g_free(pub_machine);
1494 send_presence_publish(sipe_private, publications);
1495 g_free(publications);
1498 static gboolean process_send_presence_category_publish_response(struct sipe_core_private *sipe_private,
1499 struct sipmsg *msg,
1500 struct transaction *trans)
1502 const gchar *contenttype = sipmsg_find_header(msg, "Content-Type");
1504 if (msg->response == 409 && g_str_has_prefix(contenttype, "application/msrtc-fault+xml")) {
1505 sipe_xml *xml;
1506 const sipe_xml *node;
1507 gchar *fault_code;
1508 GHashTable *faults;
1509 int index_our;
1510 gboolean has_device_publication = FALSE;
1512 xml = sipe_xml_parse(msg->body, msg->bodylen);
1514 /* test if version mismatch fault */
1515 fault_code = sipe_xml_data(sipe_xml_child(xml, "Faultcode"));
1516 if (!sipe_strequal(fault_code, "Client.BadCall.WrongDelta")) {
1517 SIPE_DEBUG_INFO("process_send_presence_category_publish_response: unsupported fault code:%s returning.", fault_code);
1518 g_free(fault_code);
1519 sipe_xml_free(xml);
1520 return TRUE;
1522 g_free(fault_code);
1524 /* accumulating information about faulty versions */
1525 faults = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
1526 for (node = sipe_xml_child(xml, "details/operation");
1527 node;
1528 node = sipe_xml_twin(node))
1530 const gchar *index = sipe_xml_attribute(node, "index");
1531 const gchar *curVersion = sipe_xml_attribute(node, "curVersion");
1533 g_hash_table_insert(faults, g_strdup(index), g_strdup(curVersion));
1534 SIPE_DEBUG_INFO("fault added: index:%s curVersion:%s", index, curVersion);
1536 sipe_xml_free(xml);
1538 /* here we are parsing our own request to figure out what publication
1539 * referenced here only by index went wrong
1541 xml = sipe_xml_parse(trans->msg->body, trans->msg->bodylen);
1543 /* publication */
1544 for (node = sipe_xml_child(xml, "publications/publication"),
1545 index_our = 1; /* starts with 1 - our first publication */
1546 node;
1547 node = sipe_xml_twin(node), index_our++)
1549 gchar *idx = g_strdup_printf("%d", index_our);
1550 const gchar *curVersion = g_hash_table_lookup(faults, idx);
1551 const gchar *categoryName = sipe_xml_attribute(node, "categoryName");
1552 g_free(idx);
1554 if (sipe_strequal("device", categoryName)) {
1555 has_device_publication = TRUE;
1558 if (curVersion) { /* fault exist on this index */
1559 const gchar *container = sipe_xml_attribute(node, "container");
1560 const gchar *instance = sipe_xml_attribute(node, "instance");
1561 /* key is <category><instance><container> */
1562 gchar *key = g_strdup_printf("<%s><%s><%s>", categoryName, instance, container);
1563 GHashTable *category = g_hash_table_lookup(sipe_private->our_publications, categoryName);
1565 if (category) {
1566 struct sipe_publication *publication =
1567 g_hash_table_lookup(category, key);
1569 SIPE_DEBUG_INFO("key is %s", key);
1571 if (publication) {
1572 SIPE_DEBUG_INFO("Updating %s with version %s. Was %d before.",
1573 key, curVersion, publication->version);
1574 /* updating publication's version to the correct one */
1575 publication->version = atoi(curVersion);
1577 } else {
1578 /* We somehow lost this category from our publications... */
1579 struct sipe_publication *publication = g_new0(struct sipe_publication, 1);
1580 publication->category = g_strdup(categoryName);
1581 publication->instance = atoi(instance);
1582 publication->container = atoi(container);
1583 publication->version = atoi(curVersion);
1584 category = g_hash_table_new_full(g_str_hash, g_str_equal,
1585 g_free, (GDestroyNotify)free_publication);
1586 g_hash_table_insert(category, g_strdup(key), publication);
1587 g_hash_table_insert(sipe_private->our_publications, g_strdup(categoryName), category);
1588 SIPE_DEBUG_INFO("added lost category '%s' key '%s'", categoryName, key);
1590 g_free(key);
1593 sipe_xml_free(xml);
1594 g_hash_table_destroy(faults);
1596 /* rebublishing with right versions */
1597 if (has_device_publication) {
1598 send_publish_category_initial(sipe_private);
1599 } else {
1600 sipe_status_update(sipe_private, NULL);
1603 return TRUE;
1607 * Publishes categories.
1608 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1609 * @param publications (%s) XML publications
1611 #define SIPE_SEND_PRESENCE \
1612 "<publish xmlns=\"http://schemas.microsoft.com/2006/09/sip/rich-presence\">"\
1613 "<publications uri=\"%s\">"\
1614 "%s"\
1615 "</publications>"\
1616 "</publish>"
1618 static void send_presence_publish(struct sipe_core_private *sipe_private,
1619 const char *publications)
1621 gchar *uri;
1622 gchar *doc;
1623 gchar *tmp;
1624 gchar *hdr;
1626 uri = sip_uri_self(sipe_private);
1627 doc = g_strdup_printf(SIPE_SEND_PRESENCE,
1628 uri,
1629 publications);
1631 tmp = get_contact(sipe_private);
1632 hdr = g_strdup_printf("Contact: %s\r\n"
1633 "Content-Type: application/msrtc-category-publish+xml\r\n", tmp);
1635 sip_transport_service(sipe_private,
1636 uri,
1637 hdr,
1638 doc,
1639 process_send_presence_category_publish_response);
1641 g_free(tmp);
1642 g_free(hdr);
1643 g_free(uri);
1644 g_free(doc);
1648 * Publishes self status
1649 * based on own calendar information.
1651 void sipe_ocs2007_presence_publish(struct sipe_core_private *sipe_private,
1652 SIPE_UNUSED_PARAMETER void *unused)
1654 struct sipe_calendar* cal = sipe_private->calendar;
1655 struct sipe_cal_event* event = NULL;
1656 gchar *pub_cal_working_hours = NULL;
1657 gchar *pub_cal_free_busy = NULL;
1658 gchar *pub_calendar = NULL;
1659 gchar *pub_calendar2 = NULL;
1660 gchar *pub_oof_note = NULL;
1661 const gchar *oof_note;
1662 time_t oof_start = 0;
1663 time_t oof_end = 0;
1665 if (!cal) {
1666 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() no calendar data.");
1667 return;
1670 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() started.");
1671 if (cal->cal_events) {
1672 event = sipe_cal_get_event(cal->cal_events, time(NULL));
1675 if (!event) {
1676 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: current event is NULL");
1677 } else {
1678 char *desc = sipe_cal_event_describe(event);
1679 SIPE_DEBUG_INFO("publish_calendar_status_self: current event is:\n%s", desc ? desc : "");
1680 g_free(desc);
1683 /* Logic
1684 if OOF
1685 OOF publish, Busy clean
1686 ilse if Busy
1687 OOF clean, Busy publish
1688 else
1689 OOF clean, Busy clean
1691 if (event && event->cal_status == SIPE_CAL_OOF) {
1692 pub_calendar = sipe_publish_get_category_state_calendar(sipe_private, event, cal->email, SIPE_CAL_OOF);
1693 pub_calendar2 = sipe_publish_get_category_state_calendar(sipe_private, NULL, cal->email, SIPE_CAL_BUSY);
1694 } else if (event && event->cal_status == SIPE_CAL_BUSY) {
1695 pub_calendar = sipe_publish_get_category_state_calendar(sipe_private, NULL, cal->email, SIPE_CAL_OOF);
1696 pub_calendar2 = sipe_publish_get_category_state_calendar(sipe_private, event, cal->email, SIPE_CAL_BUSY);
1697 } else {
1698 pub_calendar = sipe_publish_get_category_state_calendar(sipe_private, NULL, cal->email, SIPE_CAL_OOF);
1699 pub_calendar2 = sipe_publish_get_category_state_calendar(sipe_private, NULL, cal->email, SIPE_CAL_BUSY);
1702 oof_note = sipe_ews_get_oof_note(cal);
1703 if (sipe_strequal("Scheduled", cal->oof_state)) {
1704 oof_start = cal->oof_start;
1705 oof_end = cal->oof_end;
1707 pub_oof_note = sipe_publish_get_category_note(sipe_private, oof_note, "OOF", oof_start, oof_end);
1709 pub_cal_working_hours = sipe_publish_get_category_cal_working_hours(sipe_private);
1710 pub_cal_free_busy = sipe_publish_get_category_cal_free_busy(sipe_private);
1712 if (!pub_cal_working_hours && !pub_cal_free_busy && !pub_calendar && !pub_calendar2 && !pub_oof_note) {
1713 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: nothing has changed.");
1714 } else {
1715 gchar *publications = g_strdup_printf("%s%s%s%s%s",
1716 pub_cal_working_hours ? pub_cal_working_hours : "",
1717 pub_cal_free_busy ? pub_cal_free_busy : "",
1718 pub_calendar ? pub_calendar : "",
1719 pub_calendar2 ? pub_calendar2 : "",
1720 pub_oof_note ? pub_oof_note : "");
1722 send_presence_publish(sipe_private, publications);
1723 g_free(publications);
1726 g_free(pub_cal_working_hours);
1727 g_free(pub_cal_free_busy);
1728 g_free(pub_calendar);
1729 g_free(pub_calendar2);
1730 g_free(pub_oof_note);
1732 /* repeat scheduling */
1733 schedule_publish_update(sipe_private, time(NULL));
1736 void sipe_ocs2007_category_publish(struct sipe_core_private *sipe_private)
1738 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
1739 gchar *pub_state = sipe_status_changed_by_user(sipe_private) ?
1740 sipe_publish_get_category_state_user(sipe_private) :
1741 sipe_publish_get_category_state_machine(sipe_private);
1742 gchar *pub_note = sipe_publish_get_category_note(sipe_private,
1743 sip->note,
1744 SIPE_CORE_PRIVATE_FLAG_IS(OOF_NOTE) ? "OOF" : "personal",
1747 gchar *publications;
1749 if (!pub_state && !pub_note) {
1750 SIPE_DEBUG_INFO_NOFORMAT("sipe_osc2007_category_publish: nothing has changed. Exiting.");
1751 return;
1754 publications = g_strdup_printf("%s%s",
1755 pub_state ? pub_state : "",
1756 pub_note ? pub_note : "");
1758 g_free(pub_state);
1759 g_free(pub_note);
1761 send_presence_publish(sipe_private, publications);
1762 g_free(publications);
1765 static void sipe_publish_get_cat_state_user_to_clear(SIPE_UNUSED_PARAMETER const char *name,
1766 gpointer value,
1767 GString* str)
1769 struct sipe_publication *publication = value;
1771 g_string_append_printf( str,
1772 SIPE_PUB_XML_PUBLICATION_CLEAR,
1773 publication->category,
1774 publication->instance,
1775 publication->container,
1776 publication->version,
1777 "static");
1780 void sipe_ocs2007_reset_status(struct sipe_core_private *sipe_private)
1782 GString* str;
1783 gchar *publications;
1785 if (!sipe_private->user_state_publications || g_hash_table_size(sipe_private->user_state_publications) == 0) {
1786 SIPE_DEBUG_INFO_NOFORMAT("sipe_reset_status: no userState publications, exiting.");
1787 return;
1790 str = g_string_new(NULL);
1791 g_hash_table_foreach(sipe_private->user_state_publications, (GHFunc)sipe_publish_get_cat_state_user_to_clear, str);
1792 publications = g_string_free(str, FALSE);
1794 send_presence_publish(sipe_private, publications);
1795 g_free(publications);
1798 /* key is <category><instance><container> */
1799 static gboolean sipe_is_our_publication(struct sipe_core_private *sipe_private,
1800 const gchar *key)
1802 GSList *entry;
1804 /* filling keys for our publications if not yet cached */
1805 if (!sipe_private->our_publication_keys) {
1806 guint device_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_DEVICE);
1807 guint machine_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_MACHINE);
1808 guint user_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_USER);
1809 guint calendar_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_CALENDAR);
1810 guint cal_oof_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_CALENDAR_OOF);
1811 guint cal_data_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_CALENDAR_DATA);
1812 guint note_oof_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_NOTE_OOF);
1814 SIPE_DEBUG_INFO_NOFORMAT("* Our Publication Instances *");
1815 SIPE_DEBUG_INFO("\tDevice : %u\t0x%08X", device_instance, device_instance);
1816 SIPE_DEBUG_INFO("\tMachine State : %u\t0x%08X", machine_instance, machine_instance);
1817 SIPE_DEBUG_INFO("\tUser Stare : %u\t0x%08X", user_instance, user_instance);
1818 SIPE_DEBUG_INFO("\tCalendar State : %u\t0x%08X", calendar_instance, calendar_instance);
1819 SIPE_DEBUG_INFO("\tCalendar OOF State : %u\t0x%08X", cal_oof_instance, cal_oof_instance);
1820 SIPE_DEBUG_INFO("\tCalendar FreeBusy : %u\t0x%08X", cal_data_instance, cal_data_instance);
1821 SIPE_DEBUG_INFO("\tOOF Note : %u\t0x%08X", note_oof_instance, note_oof_instance);
1822 SIPE_DEBUG_INFO("\tNote : %u", 0);
1823 SIPE_DEBUG_INFO("\tCalendar WorkingHours: %u", 0);
1825 /* device */
1826 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1827 g_strdup_printf("<%s><%u><%u>", "device", device_instance, 2));
1829 /* state:machineState */
1830 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1831 g_strdup_printf("<%s><%u><%u>", "state", machine_instance, 2));
1832 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1833 g_strdup_printf("<%s><%u><%u>", "state", machine_instance, 3));
1835 /* state:userState */
1836 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1837 g_strdup_printf("<%s><%u><%u>", "state", user_instance, 2));
1838 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1839 g_strdup_printf("<%s><%u><%u>", "state", user_instance, 3));
1841 /* state:calendarState */
1842 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1843 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance, 2));
1844 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1845 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance, 3));
1847 /* state:calendarState OOF */
1848 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1849 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance, 2));
1850 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1851 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance, 3));
1853 /* note */
1854 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1855 g_strdup_printf("<%s><%u><%u>", "note", 0, 200));
1856 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1857 g_strdup_printf("<%s><%u><%u>", "note", 0, 300));
1858 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1859 g_strdup_printf("<%s><%u><%u>", "note", 0, 400));
1861 /* note OOF */
1862 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1863 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance, 200));
1864 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1865 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance, 300));
1866 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1867 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance, 400));
1869 /* calendarData:WorkingHours */
1870 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1871 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1));
1872 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1873 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100));
1874 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1875 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200));
1876 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1877 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300));
1878 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1879 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400));
1880 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1881 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000));
1883 /* calendarData:FreeBusy */
1884 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1885 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 1));
1886 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1887 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 100));
1888 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1889 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 200));
1890 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1891 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 300));
1892 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1893 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 400));
1894 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1895 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 32000));
1897 //SIPE_DEBUG_INFO("sipe_is_our_publication: sipe_private->our_publication_keys length=%d",
1898 // sipe_private->our_publication_keys ? (int) g_slist_length(sipe_private->our_publication_keys) : -1);
1901 //SIPE_DEBUG_INFO("sipe_is_our_publication: key=%s", key);
1903 entry = sipe_private->our_publication_keys;
1904 while (entry) {
1905 //SIPE_DEBUG_INFO(" sipe_is_our_publication: entry->data=%s", entry->data);
1906 if (sipe_strequal(entry->data, key)) {
1907 return TRUE;
1909 entry = entry->next;
1911 return FALSE;
1914 static void sipe_refresh_blocked_status_cb(char *buddy_name,
1915 SIPE_UNUSED_PARAMETER struct sipe_buddy *buddy,
1916 struct sipe_core_private *sipe_private)
1918 int container_id = sipe_ocs2007_find_access_level(sipe_private, "user", buddy_name, NULL);
1919 gboolean blocked = (container_id == 32000);
1920 gboolean blocked_in_blist = sipe_backend_buddy_is_blocked(SIPE_CORE_PUBLIC, buddy_name);
1922 /* SIPE_DEBUG_INFO("sipe_refresh_blocked_status_cb: buddy_name=%s, blocked=%s, blocked_in_blist=%s",
1923 buddy_name, blocked ? "T" : "F", blocked_in_blist ? "T" : "F"); */
1925 if (blocked != blocked_in_blist) {
1926 sipe_backend_buddy_set_blocked_status(SIPE_CORE_PUBLIC, buddy_name, blocked);
1930 static void sipe_refresh_blocked_status(struct sipe_core_private *sipe_private)
1932 g_hash_table_foreach(sipe_private->buddies,
1933 (GHFunc) sipe_refresh_blocked_status_cb,
1934 sipe_private);
1938 * When we receive some self (BE) NOTIFY with a new subscriber
1939 * we sends a setSubscribers request to him [SIP-PRES] 4.8
1942 void sipe_ocs2007_process_roaming_self(struct sipe_core_private *sipe_private,
1943 struct sipmsg *msg)
1945 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
1946 gchar *contact;
1947 gchar *to;
1948 sipe_xml *xml;
1949 const sipe_xml *node;
1950 const sipe_xml *node2;
1951 char *display_name = NULL;
1952 char *uri;
1953 GSList *category_names = NULL;
1954 int aggreg_avail = 0;
1955 gboolean do_update_status = FALSE;
1956 gboolean has_note_cleaned = FALSE;
1957 GHashTable *devices;
1959 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self");
1961 xml = sipe_xml_parse(msg->body, msg->bodylen);
1962 if (!xml) return;
1964 contact = get_contact(sipe_private);
1965 to = sip_uri_self(sipe_private);
1967 /* categories */
1968 /* set list of categories participating in this XML */
1969 for (node = sipe_xml_child(xml, "categories/category"); node; node = sipe_xml_twin(node)) {
1970 const gchar *name = sipe_xml_attribute(node, "name");
1971 category_names = slist_insert_unique_sorted(category_names, (gchar *)name, (GCompareFunc)strcmp);
1973 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: category_names length=%d",
1974 category_names ? (int) g_slist_length(category_names) : -1);
1975 /* drop category information */
1976 if (category_names) {
1977 GSList *entry = category_names;
1978 while (entry) {
1979 GHashTable *cat_publications;
1980 const gchar *category = entry->data;
1981 entry = entry->next;
1982 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: dropping category: %s", category);
1983 cat_publications = g_hash_table_lookup(sipe_private->our_publications, category);
1984 if (cat_publications) {
1985 g_hash_table_remove(sipe_private->our_publications, category);
1986 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: dropped category: %s", category);
1990 g_slist_free(category_names);
1992 /* filling our categories reflected in roaming data */
1993 devices = g_hash_table_new_full(g_str_hash, g_str_equal,
1994 g_free, NULL);
1995 for (node = sipe_xml_child(xml, "categories/category"); node; node = sipe_xml_twin(node)) {
1996 const char *tmp;
1997 const gchar *name = sipe_xml_attribute(node, "name");
1998 guint container = sipe_xml_int_attribute(node, "container", -1);
1999 guint instance = sipe_xml_int_attribute(node, "instance", -1);
2000 guint version = sipe_xml_int_attribute(node, "version", 0);
2001 time_t publish_time = (tmp = sipe_xml_attribute(node, "publishTime")) ?
2002 sipe_utils_str_to_time(tmp) : 0;
2003 gchar *key;
2004 GHashTable *cat_publications = g_hash_table_lookup(sipe_private->our_publications, name);
2006 /* Ex. clear note: <category name="note"/> */
2007 if (container == (guint)-1) {
2008 g_free(sip->note);
2009 sip->note = NULL;
2010 do_update_status = TRUE;
2011 continue;
2014 /* Ex. clear note: <category name="note" container="200"/> */
2015 if (instance == (guint)-1) {
2016 if (container == 200) {
2017 g_free(sip->note);
2018 sip->note = NULL;
2019 do_update_status = TRUE;
2021 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removing publications for: %s/%u", name, container);
2022 sipe_remove_category_container_publications(
2023 sipe_private->our_publications, name, container);
2024 continue;
2027 /* key is <category><instance><container> */
2028 key = g_strdup_printf("<%s><%u><%u>", name, instance, container);
2029 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: key=%s version=%d", key, version);
2031 /* capture all userState publication for later clean up if required */
2032 if (sipe_strequal(name, "state") && (container == 2 || container == 3)) {
2033 const sipe_xml *xn_state = sipe_xml_child(node, "state");
2035 if (xn_state && sipe_strequal(sipe_xml_attribute(xn_state, "type"), "userState")) {
2036 struct sipe_publication *publication = g_new0(struct sipe_publication, 1);
2037 publication->category = g_strdup(name);
2038 publication->instance = instance;
2039 publication->container = container;
2040 publication->version = version;
2042 if (!sipe_private->user_state_publications) {
2043 sipe_private->user_state_publications = g_hash_table_new_full(
2044 g_str_hash, g_str_equal,
2045 g_free, (GDestroyNotify)free_publication);
2047 g_hash_table_insert(sipe_private->user_state_publications, g_strdup(key), publication);
2048 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added to user_state_publications key=%s version=%d",
2049 key, version);
2053 /* count each client instance only once */
2054 if (sipe_strequal(name, "device"))
2055 g_hash_table_replace(devices, g_strdup_printf("%u", instance), NULL);
2057 if (sipe_is_our_publication(sipe_private, key)) {
2058 struct sipe_publication *publication = g_new0(struct sipe_publication, 1);
2060 publication->category = g_strdup(name);
2061 publication->instance = instance;
2062 publication->container = container;
2063 publication->version = version;
2065 /* filling publication->availability */
2066 if (sipe_strequal(name, "state")) {
2067 const sipe_xml *xn_state = sipe_xml_child(node, "state");
2068 const sipe_xml *xn_avail = sipe_xml_child(xn_state, "availability");
2070 if (xn_avail) {
2071 gchar *avail_str = sipe_xml_data(xn_avail);
2072 if (avail_str) {
2073 publication->availability = atoi(avail_str);
2075 g_free(avail_str);
2077 /* for calendarState */
2078 if (xn_state && sipe_strequal(sipe_xml_attribute(xn_state, "type"), "calendarState")) {
2079 const sipe_xml *xn_activity = sipe_xml_child(xn_state, "activity");
2080 struct sipe_cal_event *event = g_new0(struct sipe_cal_event, 1);
2082 event->start_time = sipe_utils_str_to_time(sipe_xml_attribute(xn_state, "startTime"));
2083 if (xn_activity) {
2084 if (sipe_strequal(sipe_xml_attribute(xn_activity, "token"),
2085 sipe_backend_activity_to_token(SIPE_ACTIVITY_IN_MEETING)))
2087 event->is_meeting = TRUE;
2090 event->subject = sipe_xml_data(sipe_xml_child(xn_state, "meetingSubject"));
2091 event->location = sipe_xml_data(sipe_xml_child(xn_state, "meetingLocation"));
2093 publication->cal_event_hash = sipe_cal_event_hash(event);
2094 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: hash=%s",
2095 publication->cal_event_hash);
2096 sipe_cal_event_free(event);
2099 /* filling publication->note */
2100 if (sipe_strequal(name, "note")) {
2101 const sipe_xml *xn_body = sipe_xml_child(node, "note/body");
2103 if (!has_note_cleaned) {
2104 has_note_cleaned = TRUE;
2106 g_free(sip->note);
2107 sip->note = NULL;
2108 sip->note_since = publish_time;
2110 do_update_status = TRUE;
2113 g_free(publication->note);
2114 publication->note = NULL;
2115 if (xn_body) {
2116 char *tmp;
2118 publication->note = g_markup_escape_text((tmp = sipe_xml_data(xn_body)), -1);
2119 g_free(tmp);
2120 if (publish_time >= sip->note_since) {
2121 g_free(sip->note);
2122 sip->note = g_strdup(publication->note);
2123 sip->note_since = publish_time;
2124 if (sipe_strequal(sipe_xml_attribute(xn_body, "type"), "OOF"))
2125 SIPE_CORE_PRIVATE_FLAG_SET(OOF_NOTE);
2126 else
2127 SIPE_CORE_PRIVATE_FLAG_UNSET(OOF_NOTE);
2129 do_update_status = TRUE;
2134 /* filling publication->fb_start_str, free_busy_base64, working_hours_xml_str */
2135 if (sipe_strequal(name, "calendarData") && (publication->container == 300)) {
2136 const sipe_xml *xn_free_busy = sipe_xml_child(node, "calendarData/freeBusy");
2137 const sipe_xml *xn_working_hours = sipe_xml_child(node, "calendarData/WorkingHours");
2138 if (xn_free_busy) {
2139 publication->fb_start_str = g_strdup(sipe_xml_attribute(xn_free_busy, "startTime"));
2140 publication->free_busy_base64 = sipe_xml_data(xn_free_busy);
2142 if (xn_working_hours) {
2143 publication->working_hours_xml_str = sipe_xml_stringify(xn_working_hours);
2147 if (!cat_publications) {
2148 cat_publications = g_hash_table_new_full(
2149 g_str_hash, g_str_equal,
2150 g_free, (GDestroyNotify)free_publication);
2151 g_hash_table_insert(sipe_private->our_publications, g_strdup(name), cat_publications);
2152 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added GHashTable cat=%s", name);
2154 g_hash_table_insert(cat_publications, g_strdup(key), publication);
2155 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added key=%s version=%d", key, version);
2157 g_free(key);
2159 /* aggregateState (not an our publication) from 2-nd container */
2160 if (sipe_strequal(name, "state") && container == 2) {
2161 const sipe_xml *xn_state = sipe_xml_child(node, "state");
2163 if (xn_state && sipe_strequal(sipe_xml_attribute(xn_state, "type"), "aggregateState")) {
2164 const sipe_xml *xn_avail = sipe_xml_child(xn_state, "availability");
2166 if (xn_avail) {
2167 gchar *avail_str = sipe_xml_data(xn_avail);
2168 if (avail_str) {
2169 aggreg_avail = atoi(avail_str);
2171 g_free(avail_str);
2174 do_update_status = TRUE;
2178 /* userProperties published by server from AD */
2179 if (!sipe_private->csta &&
2180 sipe_strequal(name, "userProperties")) {
2181 const sipe_xml *line;
2182 /* line, for Remote Call Control (RCC) */
2183 for (line = sipe_xml_child(node, "userProperties/lines/line"); line; line = sipe_xml_twin(line)) {
2184 const gchar *line_server = sipe_xml_attribute(line, "lineServer");
2185 const gchar *line_type = sipe_xml_attribute(line, "lineType");
2186 gchar *line_uri;
2188 if (!line_server || !(sipe_strequal(line_type, "Rcc") || sipe_strequal(line_type, "Dual"))) continue;
2190 line_uri = sipe_xml_data(line);
2191 if (line_uri) {
2192 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: line_uri=%s server=%s", line_uri, line_server);
2193 sip_csta_open(sipe_private, line_uri, line_server);
2195 g_free(line_uri);
2197 break;
2201 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sipe_private->our_publications size=%d",
2202 sipe_private->our_publications ? (int) g_hash_table_size(sipe_private->our_publications) : -1);
2204 /* active clients for user account */
2205 if (g_hash_table_size(devices) > 1) {
2206 SIPE_CORE_PRIVATE_FLAG_SET(MPOP);
2207 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: multiple clients detected (%d)",
2208 g_hash_table_size(devices));
2209 } else {
2210 SIPE_CORE_PRIVATE_FLAG_UNSET(MPOP);
2211 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self: single client detected");
2213 g_hash_table_destroy(devices);
2215 /* containers */
2216 for (node = sipe_xml_child(xml, "containers/container"); node; node = sipe_xml_twin(node)) {
2217 guint id = sipe_xml_int_attribute(node, "id", 0);
2218 struct sipe_container *container = sipe_find_container(sipe_private, id);
2220 if (container) {
2221 sipe_private->containers = g_slist_remove(sipe_private->containers, container);
2222 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removed existing container id=%d v%d", container->id, container->version);
2223 sipe_ocs2007_free_container(container);
2225 container = g_new0(struct sipe_container, 1);
2226 container->id = id;
2227 container->version = sipe_xml_int_attribute(node, "version", 0);
2228 sipe_private->containers = g_slist_append(sipe_private->containers, container);
2229 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container id=%d v%d", container->id, container->version);
2231 for (node2 = sipe_xml_child(node, "member"); node2; node2 = sipe_xml_twin(node2)) {
2232 struct sipe_container_member *member = g_new0(struct sipe_container_member, 1);
2233 member->type = g_strdup(sipe_xml_attribute(node2, "type"));
2234 member->value = g_strdup(sipe_xml_attribute(node2, "value"));
2235 container->members = g_slist_append(container->members, member);
2236 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container member type=%s value=%s",
2237 member->type, member->value ? member->value : "");
2241 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sip->access_level_set=%s",
2242 SIPE_CORE_PRIVATE_FLAG_IS(ACCESS_LEVEL_SET) ? "TRUE" : "FALSE");
2243 if (!SIPE_CORE_PRIVATE_FLAG_IS(ACCESS_LEVEL_SET) && sipe_xml_child(xml, "containers")) {
2244 char *container_xmls = NULL;
2245 int sameEnterpriseAL = sipe_ocs2007_find_access_level(sipe_private, "sameEnterprise", NULL, NULL);
2246 int federatedAL = sipe_ocs2007_find_access_level(sipe_private, "federated", NULL, NULL);
2248 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sameEnterpriseAL=%d", sameEnterpriseAL);
2249 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: federatedAL=%d", federatedAL);
2250 /* initial set-up to let counterparties see your status */
2251 if (sameEnterpriseAL < 0) {
2252 struct sipe_container *container = sipe_find_container(sipe_private, 200);
2253 guint version = container ? container->version : 0;
2254 sipe_send_container_members_prepare(200, version, "add", "sameEnterprise", NULL, &container_xmls);
2256 if (federatedAL < 0) {
2257 struct sipe_container *container = sipe_find_container(sipe_private, 100);
2258 guint version = container ? container->version : 0;
2259 sipe_send_container_members_prepare(100, version, "add", "federated", NULL, &container_xmls);
2261 SIPE_CORE_PRIVATE_FLAG_SET(ACCESS_LEVEL_SET);
2263 if (container_xmls) {
2264 sipe_send_set_container_members(sipe_private, container_xmls);
2266 g_free(container_xmls);
2269 /* Refresh contacts' blocked status */
2270 sipe_refresh_blocked_status(sipe_private);
2272 /* subscribers */
2273 for (node = sipe_xml_child(xml, "subscribers/subscriber"); node; node = sipe_xml_twin(node)) {
2274 const char *user;
2275 const char *acknowledged;
2276 gchar *hdr;
2277 gchar *body;
2279 user = sipe_xml_attribute(node, "user"); /* without 'sip:' prefix */
2280 if (!user) continue;
2281 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user %s", user);
2282 display_name = g_strdup(sipe_xml_attribute(node, "displayName"));
2283 uri = sip_uri_from_name(user);
2285 sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_DISPLAY_NAME, display_name);
2287 acknowledged= sipe_xml_attribute(node, "acknowledged");
2288 if(sipe_strcase_equal(acknowledged,"false")){
2289 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user added you %s", user);
2290 if (!sipe_backend_buddy_find(SIPE_CORE_PUBLIC, uri, NULL)) {
2291 sipe_backend_buddy_request_add(SIPE_CORE_PUBLIC, uri, display_name);
2294 hdr = g_strdup_printf(
2295 "Contact: %s\r\n"
2296 "Content-Type: application/msrtc-presence-setsubscriber+xml\r\n", contact);
2298 body = g_strdup_printf(
2299 "<setSubscribers xmlns=\"http://schemas.microsoft.com/2006/09/sip/presence-subscribers\">"
2300 "<subscriber user=\"%s\" acknowledged=\"true\"/>"
2301 "</setSubscribers>", user);
2303 sip_transport_service(sipe_private,
2305 hdr,
2306 body,
2307 NULL);
2308 g_free(body);
2309 g_free(hdr);
2311 g_free(display_name);
2312 g_free(uri);
2315 g_free(contact);
2316 sipe_xml_free(xml);
2318 /* Publish initial state if not yet.
2319 * Assuming this happens on initial responce to subscription to roaming-self
2320 * so we've already updated our roaming data in full.
2321 * Only for 2007+
2323 if (!SIPE_CORE_PRIVATE_FLAG_IS(INITIAL_PUBLISH)) {
2324 send_publish_category_initial(sipe_private);
2325 sipe_groupchat_init(sipe_private);
2326 SIPE_CORE_PRIVATE_FLAG_SET(INITIAL_PUBLISH);
2327 /* dalayed run */
2328 sipe_cal_delayed_calendar_update(sipe_private);
2329 do_update_status = FALSE;
2330 } else if (aggreg_avail) {
2332 if (aggreg_avail &&
2333 (aggreg_avail < SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE)) {
2334 /* not offline */
2335 sipe_status_set_token(sipe_private,
2336 sipe_ocs2007_status_from_legacy_availability(aggreg_avail));
2337 } else {
2338 /* do not let offline status switch us off */
2339 sipe_status_set_activity(sipe_private,
2340 SIPE_ACTIVITY_INVISIBLE);
2344 if (do_update_status) {
2345 sipe_status_and_note(sipe_private, NULL);
2348 g_free(to);
2352 Local Variables:
2353 mode: c
2354 c-file-style: "bsd"
2355 indent-tabs-mode: t
2356 tab-width: 8
2357 End: