core cleanup: move out is_oof_note flag
[siplcs.git] / src / core / sipe-ocs2007.c
blob05f53217cbee222641a0c3b21438c1e0f23eac53
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 /**
60 * 2007-style Activity and Availability.
62 * [MS-PRES] 3.7.5.5
64 * Conversion of legacyInterop elements and attributes to MSRTC elements and attributes.
66 * The values define the starting point of a range
68 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_ONLINE 3000
69 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY 4500
70 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_ON_PHONE 6000
71 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY 7500
72 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_DND 9000 /* do not disturb */
73 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_BRB 12000 /* be right back */
74 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY2 15000
75 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE 18000
76 const gchar *sipe_ocs2007_status_from_legacy_availability(guint availability)
78 guint type;
80 if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_ONLINE) {
81 type = SIPE_ACTIVITY_OFFLINE;
82 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY) {
83 type = SIPE_ACTIVITY_AVAILABLE;
84 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_ON_PHONE) {
85 //type = SIPE_ACTIVITY_IDLE;
86 type = SIPE_ACTIVITY_AVAILABLE;
87 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY) {
88 type = SIPE_ACTIVITY_BUSY;
89 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_DND) {
90 //type = SIPE_ACTIVITY_BUSYIDLE;
91 type = SIPE_ACTIVITY_BUSY;
92 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_BRB) {
93 type = SIPE_ACTIVITY_DND;
94 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY2) {
95 type = SIPE_ACTIVITY_BRB;
96 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE) {
97 type = SIPE_ACTIVITY_AWAY;
98 } else {
99 type = SIPE_ACTIVITY_OFFLINE;
102 return(sipe_backend_activity_to_token(type));
105 const gchar *sipe_ocs2007_legacy_activity_description(guint availability)
107 if ((availability >= SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY) &&
108 (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_ON_PHONE)) {
109 return(sipe_core_activity_description(SIPE_ACTIVITY_INACTIVE));
110 } else if ((availability >= SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY) &&
111 (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_DND)) {
112 return(sipe_core_activity_description(SIPE_ACTIVITY_BUSYIDLE));
113 } else {
114 return(NULL);
119 * @param sipe_status_id (in)
120 * @param activity_token (out) [only sipe-ocs2005.c/send_presence_soap()
121 * requests this token]
123 #define SIPE_OCS2007_AVAILABILITY_UNKNOWN 0
124 #define SIPE_OCS2007_AVAILABILITY_ONLINE 3500
125 #define SIPE_OCS2007_AVAILABILITY_BUSY 6500
126 #define SIPE_OCS2007_AVAILABILITY_DND 9500 /* do not disturb */
127 #define SIPE_OCS2007_AVAILABILITY_BRB 12500 /* be right back */
128 #define SIPE_OCS2007_AVAILABILITY_AWAY 15500
129 #define SIPE_OCS2007_AVAILABILITY_OFFLINE 18500
130 guint sipe_ocs2007_availability_from_status(const gchar *sipe_status_id,
131 const gchar **activity_token)
133 guint availability;
134 guint activity;
136 if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_AWAY))) {
137 availability = SIPE_OCS2007_AVAILABILITY_AWAY;
138 activity = SIPE_ACTIVITY_AWAY;
139 } else if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_BRB))) {
140 availability = SIPE_OCS2007_AVAILABILITY_BRB;
141 activity = SIPE_ACTIVITY_BRB;
142 } else if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_DND))) {
143 availability = SIPE_OCS2007_AVAILABILITY_DND;
144 activity = SIPE_ACTIVITY_DND;
145 } else if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_BUSY))) {
146 availability = SIPE_OCS2007_AVAILABILITY_BUSY;
147 activity = SIPE_ACTIVITY_BUSY;
148 } else if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_AVAILABLE))) {
149 availability = SIPE_OCS2007_AVAILABILITY_ONLINE;
150 activity = SIPE_ACTIVITY_ONLINE;
151 } else if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_UNSET))) {
152 availability = SIPE_OCS2007_AVAILABILITY_UNKNOWN;
153 activity = SIPE_ACTIVITY_UNSET;
154 } else {
155 /* Offline or invisible */
156 availability = SIPE_OCS2007_AVAILABILITY_OFFLINE;
157 activity = SIPE_ACTIVITY_OFFLINE;
160 if (activity_token) {
161 *activity_token = sipe_backend_activity_to_token(activity);
164 return(availability);
167 gboolean sipe_ocs2007_status_is_busy(const gchar *status_id)
169 return(SIPE_OCS2007_AVAILABILITY_BUSY >=
170 sipe_ocs2007_availability_from_status(status_id, NULL));
174 gboolean sipe_ocs2007_availability_is_away2(guint availability)
176 return(availability >= SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY2);
179 static void send_presence_publish(struct sipe_core_private *sipe_private,
180 const char *publications);
182 static void free_publication(struct sipe_publication *publication)
184 g_free(publication->category);
185 g_free(publication->cal_event_hash);
186 g_free(publication->note);
188 g_free(publication->working_hours_xml_str);
189 g_free(publication->fb_start_str);
190 g_free(publication->free_busy_base64);
192 g_free(publication);
195 struct hash_table_delete_payload {
196 GHashTable *hash_table;
197 guint container;
200 static void sipe_remove_category_container_publications_cb(const gchar *name,
201 struct sipe_publication *publication,
202 struct hash_table_delete_payload *payload)
204 if (publication->container == payload->container) {
205 g_hash_table_remove(payload->hash_table, name);
209 static void sipe_remove_category_container_publications(GHashTable *our_publications,
210 const gchar *category,
211 guint container)
213 struct hash_table_delete_payload payload;
214 payload.hash_table = g_hash_table_lookup(our_publications, category);
216 if (!payload.hash_table) return;
218 payload.container = container;
219 g_hash_table_foreach(payload.hash_table,
220 (GHFunc)sipe_remove_category_container_publications_cb,
221 &payload);
224 /** MS-PRES container */
225 struct sipe_container {
226 guint id;
227 guint version;
228 GSList *members;
231 /** MS-PRES container member */
232 struct sipe_container_member {
233 /** user, domain, sameEnterprise, federated, publicCloud; everyone */
234 gchar *type;
235 gchar *value;
238 static const guint containers[] = {32000, 400, 300, 200, 100};
239 #define CONTAINERS_LEN (sizeof(containers) / sizeof(guint))
241 guint sipe_ocs2007_containers(void)
243 return(CONTAINERS_LEN);
246 static void free_container_member(struct sipe_container_member *member)
248 if (!member) return;
250 g_free(member->type);
251 g_free(member->value);
252 g_free(member);
255 void sipe_ocs2007_free_container(struct sipe_container *container)
257 GSList *entry;
259 if (!container) return;
261 entry = container->members;
262 while (entry) {
263 void *data = entry->data;
264 entry = g_slist_remove(entry, data);
265 free_container_member((struct sipe_container_member *)data);
267 g_free(container);
270 struct sipe_container *sipe_ocs2007_create_container(guint index,
271 const gchar *member_type,
272 const gchar *member_value,
273 gboolean is_group)
275 struct sipe_container *container = g_new0(struct sipe_container, 1);
276 struct sipe_container_member *member = g_new0(struct sipe_container_member, 1);
278 container->id = is_group ? (guint) -1 : containers[index];
279 container->members = g_slist_append(container->members, member);
280 member->type = g_strdup(member_type);
281 member->value = g_strdup(member_value);
283 return(container);
286 void sipe_ocs2007_free(struct sipe_core_private *sipe_private)
288 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
290 if (sip->containers) {
291 GSList *entry = sip->containers;
292 while (entry) {
293 sipe_ocs2007_free_container((struct sipe_container *)entry->data);
294 entry = entry->next;
297 g_slist_free(sip->containers);
301 * Finds locally stored MS-PRES container member
303 static struct sipe_container_member *
304 sipe_find_container_member(struct sipe_container *container,
305 const gchar *type,
306 const gchar *value)
308 struct sipe_container_member *member;
309 GSList *entry;
311 if (container == NULL || type == NULL) {
312 return NULL;
315 entry = container->members;
316 while (entry) {
317 member = entry->data;
318 if (sipe_strcase_equal(member->type, type) &&
319 sipe_strcase_equal(member->value, value))
321 return member;
323 entry = entry->next;
325 return NULL;
329 * Finds locally stored MS-PRES container by id
331 static struct sipe_container *sipe_find_container(struct sipe_core_private *sipe_private,
332 guint id)
334 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
335 struct sipe_container *container;
336 GSList *entry;
338 if (sip == NULL) {
339 return NULL;
342 entry = sip->containers;
343 while (entry) {
344 container = entry->data;
345 if (id == container->id) {
346 return container;
348 entry = entry->next;
350 return NULL;
353 static int sipe_find_member_access_level(struct sipe_core_private *sipe_private,
354 const gchar *type,
355 const gchar *value)
357 unsigned int i = 0;
358 const gchar *value_mod = value;
360 if (!type) return -1;
362 if (sipe_strequal("user", type)) {
363 value_mod = sipe_get_no_sip_uri(value);
366 for (i = 0; i < CONTAINERS_LEN; i++) {
367 struct sipe_container_member *member;
368 struct sipe_container *container = sipe_find_container(sipe_private, containers[i]);
369 if (!container) continue;
371 member = sipe_find_container_member(container, type, value_mod);
372 if (member) return containers[i];
375 return -1;
379 * Returns pointer to domain part in provided Email URL
381 * @param email an email URL. Example: first.last@hq.company.com
382 * @return pointer to domain part of email URL. Coresponding example: hq.company.com
384 * Doesn't allocate memory
386 static const gchar *sipe_get_domain(const gchar *email)
388 gchar *tmp;
390 if (!email) return NULL;
392 tmp = strstr(email, "@");
394 if (tmp && ((tmp+1) < (email + strlen(email)))) {
395 return tmp+1;
396 } else {
397 return NULL;
401 /* @TODO: replace with binary search for faster access? */
402 /** source: http://support.microsoft.com/kb/897567 */
403 static const gchar * const public_domains[] = {
404 "aol.com", "icq.com", "love.com", "mac.com", "br.live.com",
405 "hotmail.co.il", "hotmail.co.jp", "hotmail.co.th", "hotmail.co.uk",
406 "hotmail.com", "hotmail.com.ar", "hotmail.com.tr", "hotmail.es",
407 "hotmail.de", "hotmail.fr", "hotmail.it", "live.at", "live.be",
408 "live.ca", "live.cl", "live.cn", "live.co.in", "live.co.kr",
409 "live.co.uk", "live.co.za", "live.com", "live.com.ar", "live.com.au",
410 "live.com.co", "live.com.mx", "live.com.my", "live.com.pe",
411 "live.com.ph", "live.com.pk", "live.com.pt", "live.com.sg",
412 "live.com.ve", "live.de", "live.dk", "live.fr", "live.hk", "live.ie",
413 "live.in", "live.it", "live.jp", "live.nl", "live.no", "live.ph",
414 "live.ru", "live.se", "livemail.com.br", "livemail.tw",
415 "messengeruser.com", "msn.com", "passport.com", "sympatico.ca",
416 "tw.live.com", "webtv.net", "windowslive.com", "windowslive.es",
417 "yahoo.com",
418 NULL};
420 static gboolean sipe_is_public_domain(const gchar *domain)
422 int i = 0;
423 while (public_domains[i]) {
424 if (sipe_strcase_equal(public_domains[i], domain)) {
425 return TRUE;
427 i++;
429 return FALSE;
433 * Access Levels
434 * 32000 - Blocked
435 * 400 - Personal
436 * 300 - Team
437 * 200 - Company
438 * 100 - Public
440 const gchar *sipe_ocs2007_access_level_name(guint id)
442 switch (id) {
443 case 32000: return _("Blocked");
444 case 400: return _("Personal");
445 case 300: return _("Team");
446 case 200: return _("Company");
447 case 100: return _("Public");
449 return _("Unknown");
452 int sipe_ocs2007_container_id(guint index)
454 return(containers[index]);
457 /** Member type: user, domain, sameEnterprise, federated, publicCloud; everyone */
458 int sipe_ocs2007_find_access_level(struct sipe_core_private *sipe_private,
459 const gchar *type,
460 const gchar *value,
461 gboolean *is_group_access)
463 int container_id = -1;
465 if (sipe_strequal("user", type)) {
466 const char *domain;
467 const char *no_sip_uri = sipe_get_no_sip_uri(value);
469 container_id = sipe_find_member_access_level(sipe_private, "user", no_sip_uri);
470 if (container_id >= 0) {
471 if (is_group_access) *is_group_access = FALSE;
472 return container_id;
475 domain = sipe_get_domain(no_sip_uri);
476 container_id = sipe_find_member_access_level(sipe_private, "domain", domain);
477 if (container_id >= 0) {
478 if (is_group_access) *is_group_access = TRUE;
479 return container_id;
482 container_id = sipe_find_member_access_level(sipe_private, "sameEnterprise", NULL);
483 if ((container_id >= 0) && sipe_strcase_equal(sipe_private->public.sip_domain, domain)) {
484 if (is_group_access) *is_group_access = TRUE;
485 return container_id;
488 container_id = sipe_find_member_access_level(sipe_private, "publicCloud", NULL);
489 if ((container_id >= 0) && sipe_is_public_domain(domain)) {
490 if (is_group_access) *is_group_access = TRUE;
491 return container_id;
494 container_id = sipe_find_member_access_level(sipe_private, "everyone", NULL);
495 if ((container_id >= 0)) {
496 if (is_group_access) *is_group_access = TRUE;
497 return container_id;
499 } else {
500 container_id = sipe_find_member_access_level(sipe_private, type, value);
501 if (is_group_access) *is_group_access = FALSE;
504 return container_id;
507 GSList *sipe_ocs2007_get_access_domains(struct sipe_core_private *sipe_private)
509 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
510 struct sipe_container *container;
511 struct sipe_container_member *member;
512 GSList *entry;
513 GSList *entry2;
514 GSList *res = NULL;
516 if (!sip) return NULL;
518 entry = sip->containers;
519 while (entry) {
520 container = entry->data;
522 entry2 = container->members;
523 while (entry2) {
524 member = entry2->data;
525 if (sipe_strcase_equal(member->type, "domain"))
527 res = slist_insert_unique_sorted(res, g_strdup(member->value), (GCompareFunc)g_ascii_strcasecmp);
529 entry2 = entry2->next;
531 entry = entry->next;
533 return res;
536 static void sipe_send_container_members_prepare(const guint container_id,
537 const guint container_version,
538 const gchar *action,
539 const gchar *type,
540 const gchar *value,
541 char **container_xmls)
543 gchar *value_str = value ? g_strdup_printf(" value=\"%s\"", value) : g_strdup("");
544 gchar *body;
546 if (!container_xmls) return;
548 body = g_strdup_printf(
549 "<container id=\"%d\" version=\"%d\"><member action=\"%s\" type=\"%s\"%s/></container>",
550 container_id,
551 container_version,
552 action,
553 type,
554 value_str);
555 g_free(value_str);
557 if ((*container_xmls) == NULL) {
558 *container_xmls = body;
559 } else {
560 char *tmp = *container_xmls;
562 *container_xmls = g_strconcat(*container_xmls, body, NULL);
563 g_free(tmp);
564 g_free(body);
568 static void sipe_send_set_container_members(struct sipe_core_private *sipe_private,
569 char *container_xmls)
571 gchar *self;
572 gchar *contact;
573 gchar *hdr;
574 gchar *body;
576 if (!container_xmls) return;
578 self = sip_uri_self(sipe_private);
579 body = g_strdup_printf(
580 "<setContainerMembers xmlns=\"http://schemas.microsoft.com/2006/09/sip/container-management\">"
581 "%s"
582 "</setContainerMembers>",
583 container_xmls);
585 contact = get_contact(sipe_private);
586 hdr = g_strdup_printf("Contact: %s\r\n"
587 "Content-Type: application/msrtc-setcontainermembers+xml\r\n", contact);
588 g_free(contact);
590 sip_transport_service(sipe_private,
591 self,
592 hdr,
593 body,
594 NULL);
596 g_free(hdr);
597 g_free(body);
598 g_free(self);
602 * @param container_id a new access level. If -1 then current access level
603 * is just removed (I.e. the member is removed from all containers).
604 * @param type a type of member. E.g. "user", "sameEnterprise", etc.
605 * @param value a value for member. E.g. SIP URI for "user" member type.
607 void sipe_ocs2007_change_access_level(struct sipe_core_private *sipe_private,
608 const int container_id,
609 const gchar *type,
610 const gchar *value)
612 unsigned int i;
613 int current_container_id = -1;
614 char *container_xmls = NULL;
616 /* for each container: find/delete */
617 for (i = 0; i < CONTAINERS_LEN; i++) {
618 struct sipe_container_member *member;
619 struct sipe_container *container = sipe_find_container(sipe_private, containers[i]);
621 if (!container) continue;
623 member = sipe_find_container_member(container, type, value);
624 if (member) {
625 current_container_id = containers[i];
626 /* delete/publish current access level */
627 if (container_id < 0 || container_id != current_container_id) {
628 sipe_send_container_members_prepare(current_container_id, container->version, "remove", type, value, &container_xmls);
629 /* remove member from our cache, to be able to recalculate AL below */
630 container->members = g_slist_remove(container->members, member);
631 current_container_id = -1;
636 /* recalculate AL below */
637 current_container_id = sipe_ocs2007_find_access_level(sipe_private, type, value, NULL);
639 /* assign/publish new access level */
640 if (container_id != current_container_id && container_id >= 0) {
641 struct sipe_container *container = sipe_find_container(sipe_private, container_id);
642 guint version = container ? container->version : 0;
644 sipe_send_container_members_prepare(container_id, version, "add", type, value, &container_xmls);
647 if (container_xmls) {
648 sipe_send_set_container_members(sipe_private, container_xmls);
650 g_free(container_xmls);
653 void sipe_ocs2007_change_access_level_from_container(struct sipe_core_private *sipe_private,
654 struct sipe_container *container)
656 struct sipe_container_member *member;
658 if (!container || !container->members) return;
660 member = ((struct sipe_container_member *)container->members->data);
662 if (!member->type) return;
664 SIPE_DEBUG_INFO("sipe_ocs2007_change_access_level_from_container: container->id=%d, member->type=%s, member->value=%s",
665 container->id, member->type, member->value ? member->value : "");
667 sipe_ocs2007_change_access_level(sipe_private,
668 container->id,
669 member->type,
670 member->value);
674 void sipe_ocs2007_change_access_level_for_domain(struct sipe_core_private *sipe_private,
675 const gchar *domain,
676 guint index)
678 /* move Blocked first */
679 guint i = (index == 4) ? 0 : index + 1;
680 guint container_id = containers[i];
682 SIPE_DEBUG_INFO("sipe_ocs2007_change_access_level_from_id: domain=%s, container_id=(%d)%d",
683 domain ? domain : "", index, container_id);
685 sipe_ocs2007_change_access_level(sipe_private,
686 container_id,
687 "domain",
688 domain);
693 * Schedules process of self status publish
694 * based on own calendar information.
695 * Should be scheduled to the beginning of every
696 * 15 min interval, like:
697 * 13:00, 13:15, 13:30, 13:45, etc.
700 static void schedule_publish_update(struct sipe_core_private *sipe_private,
701 time_t calculate_from)
703 int interval = 5*60;
704 /** start of the beginning of closest 5 min interval. */
705 time_t next_start = ((time_t)((int)((int)calculate_from)/interval + 1)*interval);
707 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: calculate_from time: %s",
708 asctime(localtime(&calculate_from)));
709 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: next start time : %s",
710 asctime(localtime(&next_start)));
712 sipe_schedule_seconds(sipe_private,
713 "<+2007-cal-status>",
714 NULL,
715 next_start - time(NULL),
716 sipe_ocs2007_presence_publish,
717 NULL);
721 * An availability XML entry for SIPE_PUB_XML_STATE_CALENDAR
722 * @param availability (%d) Ex.: 6500
724 #define SIPE_PUB_XML_STATE_CALENDAR_AVAIL \
725 "<availability>%d</availability>"
727 * An activity XML entry for SIPE_PUB_XML_STATE_CALENDAR
728 * @param token (%s) Ex.: in-a-meeting
729 * @param minAvailability_attr (%s) Ex.: minAvailability="6500"
730 * @param maxAvailability_attr (%s) Ex.: maxAvailability="8999" or none
732 #define SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY \
733 "<activity token=\"%s\" %s %s></activity>"
735 * Publishes 'calendarState' category.
736 * @param instance (%u) Ex.: 1339299275
737 * @param version (%u) Ex.: 1
738 * @param uri (%s) Ex.: john@contoso.com
739 * @param start_time_str (%s) Ex.: 2008-01-11T19:00:00Z
740 * @param availability (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_AVAIL
741 * @param activity (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
742 * @param meeting_subject (%s) Ex.: Customer Meeting
743 * @param meeting_location (%s) Ex.: Conf Room 100
745 * @param instance (%u) Ex.: 1339299275
746 * @param version (%u) Ex.: 1
747 * @param uri (%s) Ex.: john@contoso.com
748 * @param start_time_str (%s) Ex.: 2008-01-11T19:00:00Z
749 * @param availability (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_AVAIL
750 * @param activity (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
751 * @param meeting_subject (%s) Ex.: Customer Meeting
752 * @param meeting_location (%s) Ex.: Conf Room 100
754 #define SIPE_PUB_XML_STATE_CALENDAR \
755 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
756 "<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\">"\
757 "%s"\
758 "%s"\
759 "<endpointLocation/>"\
760 "<meetingSubject>%s</meetingSubject>"\
761 "<meetingLocation>%s</meetingLocation>"\
762 "</state>"\
763 "</publication>"\
764 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
765 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" uri=\"%s\" startTime=\"%s\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"calendarState\">"\
766 "%s"\
767 "%s"\
768 "<endpointLocation/>"\
769 "<meetingSubject>%s</meetingSubject>"\
770 "<meetingLocation>%s</meetingLocation>"\
771 "</state>"\
772 "</publication>"
774 * Publishes to clear 'calendarState' category
775 * @param instance (%u) Ex.: 1251210982
776 * @param version (%u) Ex.: 1
778 #define SIPE_PUB_XML_STATE_CALENDAR_CLEAR \
779 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"\
780 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"
783 * Publishes to clear any category
784 * @param category_name (%s) Ex.: state
785 * @param instance (%u) Ex.: 536870912
786 * @param container (%u) Ex.: 3
787 * @param version (%u) Ex.: 1
788 * @param expireType (%s) Ex.: static
790 #define SIPE_PUB_XML_PUBLICATION_CLEAR \
791 "<publication categoryName=\"%s\" instance=\"%u\" container=\"%u\" version=\"%u\" expireType=\"%s\" expires=\"0\"/>"
794 * Publishes 'note' category.
795 * @param instance (%u) Ex.: 2135971629; 0 for personal
796 * @param container (%u) Ex.: 200
797 * @param version (%u) Ex.: 2
798 * @param type (%s) Ex.: personal or OOF
799 * @param startTime_attr (%s) Ex.: startTime="2008-01-11T19:00:00Z"
800 * @param endTime_attr (%s) Ex.: endTime="2008-01-15T19:00:00Z"
801 * @param body (%s) Ex.: In the office
803 #define SIPE_PUB_XML_NOTE \
804 "<publication categoryName=\"note\" instance=\"%u\" container=\"%u\" version=\"%d\" expireType=\"static\">"\
805 "<note xmlns=\"http://schemas.microsoft.com/2006/09/sip/note\">"\
806 "<body type=\"%s\" uri=\"\"%s%s>%s</body>"\
807 "</note>"\
808 "</publication>"
811 * Only Busy and OOF calendar event are published.
812 * Different instances are used for that.
814 * Must be g_free'd after use.
816 static gchar *sipe_publish_get_category_state_calendar(struct sipe_core_private *sipe_private,
817 struct sipe_cal_event *event,
818 const char *uri,
819 int cal_satus)
821 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
822 gchar *start_time_str;
823 int availability = 0;
824 gchar *res;
825 gchar *tmp = NULL;
826 guint instance = (cal_satus == SIPE_CAL_OOF) ?
827 sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_CALENDAR_OOF) :
828 sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_CALENDAR);
830 /* key is <category><instance><container> */
831 gchar *key_2 = g_strdup_printf("<%s><%u><%u>", "state", instance, 2);
832 gchar *key_3 = g_strdup_printf("<%s><%u><%u>", "state", instance, 3);
833 struct sipe_publication *publication_2 =
834 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "state"), key_2);
835 struct sipe_publication *publication_3 =
836 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "state"), key_3);
838 g_free(key_2);
839 g_free(key_3);
841 if (!publication_3 && !event) { /* was nothing, have nothing, exiting */
842 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
843 "Exiting as no publication and no event for cal_satus:%d", cal_satus);
844 return NULL;
847 if (event &&
848 publication_3 &&
849 (publication_3->availability == availability) &&
850 sipe_strequal(publication_3->cal_event_hash, (tmp = sipe_cal_event_hash(event))))
852 g_free(tmp);
853 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
854 "cal state has NOT changed for cal_satus:%d. Exiting.", cal_satus);
855 return NULL; /* nothing to update */
857 g_free(tmp);
859 if (event &&
860 (event->cal_status == SIPE_CAL_BUSY ||
861 event->cal_status == SIPE_CAL_OOF))
863 gchar *availability_xml_str = NULL;
864 gchar *activity_xml_str = NULL;
865 gchar *escaped_subject = event->subject ? g_markup_escape_text(event->subject, -1) : NULL;
866 gchar *escaped_location = event->location ? g_markup_escape_text(event->location, -1) : NULL;
868 if (event->cal_status == SIPE_CAL_BUSY) {
869 availability_xml_str = g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_AVAIL,
870 SIPE_OCS2007_AVAILABILITY_BUSY);
873 if (event->cal_status == SIPE_CAL_BUSY && event->is_meeting) {
874 activity_xml_str = g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY,
875 sipe_backend_activity_to_token(SIPE_ACTIVITY_IN_MEETING),
876 "minAvailability=\"6500\"",
877 "maxAvailability=\"8999\"");
878 } else if (event->cal_status == SIPE_CAL_OOF) {
879 activity_xml_str = g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY,
880 sipe_backend_activity_to_token(SIPE_ACTIVITY_OOF),
881 "minAvailability=\"12000\"",
882 "");
884 start_time_str = sipe_utils_time_to_str(event->start_time);
886 res = g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR,
887 instance,
888 publication_2 ? publication_2->version : 0,
889 uri,
890 start_time_str,
891 availability_xml_str ? availability_xml_str : "",
892 activity_xml_str ? activity_xml_str : "",
893 escaped_subject ? escaped_subject : "",
894 escaped_location ? escaped_location : "",
896 instance,
897 publication_3 ? publication_3->version : 0,
898 uri,
899 start_time_str,
900 availability_xml_str ? availability_xml_str : "",
901 activity_xml_str ? activity_xml_str : "",
902 escaped_subject ? escaped_subject : "",
903 escaped_location ? escaped_location : ""
905 g_free(escaped_location);
906 g_free(escaped_subject);
907 g_free(start_time_str);
908 g_free(availability_xml_str);
909 g_free(activity_xml_str);
912 else /* including !event, SIPE_CAL_FREE, SIPE_CAL_TENTATIVE */
914 res = g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_CLEAR,
915 instance,
916 publication_2 ? publication_2->version : 0,
918 instance,
919 publication_3 ? publication_3->version : 0
923 return res;
927 * Returns 'note' XML part for publication.
928 * Must be g_free'd after use.
930 * Protocol format for Note is plain text.
932 * @param note a note in Sipe internal HTML format
933 * @param note_type either personal or OOF
935 static gchar *sipe_publish_get_category_note(struct sipe_core_private *sipe_private,
936 const char *note, /* html */
937 const char *note_type,
938 time_t note_start,
939 time_t note_end)
941 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
942 guint instance = sipe_strequal("OOF", note_type) ? sipe_get_pub_instance(sipe_private, SIPE_PUB_NOTE_OOF) : 0;
943 /* key is <category><instance><container> */
944 gchar *key_note_200 = g_strdup_printf("<%s><%u><%u>", "note", instance, 200);
945 gchar *key_note_300 = g_strdup_printf("<%s><%u><%u>", "note", instance, 300);
946 gchar *key_note_400 = g_strdup_printf("<%s><%u><%u>", "note", instance, 400);
948 struct sipe_publication *publication_note_200 =
949 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "note"), key_note_200);
950 struct sipe_publication *publication_note_300 =
951 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "note"), key_note_300);
952 struct sipe_publication *publication_note_400 =
953 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "note"), key_note_400);
955 char *tmp = note ? sipe_backend_markup_strip_html(note) : NULL;
956 char *n1 = tmp ? g_markup_escape_text(tmp, -1) : NULL;
957 const char *n2 = publication_note_200 ? publication_note_200->note : NULL;
958 char *res, *tmp1, *tmp2, *tmp3;
959 char *start_time_attr;
960 char *end_time_attr;
962 g_free(tmp);
963 tmp = NULL;
964 g_free(key_note_200);
965 g_free(key_note_300);
966 g_free(key_note_400);
968 /* we even need to republish empty note */
969 if (sipe_strequal(n1, n2))
971 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_note: note has NOT changed. Exiting.");
972 g_free(n1);
973 return NULL; /* nothing to update */
976 start_time_attr = note_start ? g_strdup_printf(" startTime=\"%s\"", (tmp = sipe_utils_time_to_str(note_start))) : NULL;
977 g_free(tmp);
978 tmp = NULL;
979 end_time_attr = note_end ? g_strdup_printf(" endTime=\"%s\"", (tmp = sipe_utils_time_to_str(note_end))) : NULL;
980 g_free(tmp);
982 if (n1) {
983 tmp1 = g_strdup_printf(SIPE_PUB_XML_NOTE,
984 instance,
985 200,
986 publication_note_200 ? publication_note_200->version : 0,
987 note_type,
988 start_time_attr ? start_time_attr : "",
989 end_time_attr ? end_time_attr : "",
990 n1);
992 tmp2 = g_strdup_printf(SIPE_PUB_XML_NOTE,
993 instance,
994 300,
995 publication_note_300 ? publication_note_300->version : 0,
996 note_type,
997 start_time_attr ? start_time_attr : "",
998 end_time_attr ? end_time_attr : "",
999 n1);
1001 tmp3 = g_strdup_printf(SIPE_PUB_XML_NOTE,
1002 instance,
1003 400,
1004 publication_note_400 ? publication_note_400->version : 0,
1005 note_type,
1006 start_time_attr ? start_time_attr : "",
1007 end_time_attr ? end_time_attr : "",
1008 n1);
1009 } else {
1010 tmp1 = g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR,
1011 "note",
1012 instance,
1013 200,
1014 publication_note_200 ? publication_note_200->version : 0,
1015 "static");
1016 tmp2 = g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR,
1017 "note",
1018 instance,
1019 300,
1020 publication_note_200 ? publication_note_200->version : 0,
1021 "static");
1022 tmp3 = g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR,
1023 "note",
1024 instance,
1025 400,
1026 publication_note_200 ? publication_note_200->version : 0,
1027 "static");
1029 res = g_strconcat(tmp1, tmp2, tmp3, NULL);
1031 g_free(start_time_attr);
1032 g_free(end_time_attr);
1033 g_free(tmp1);
1034 g_free(tmp2);
1035 g_free(tmp3);
1036 g_free(n1);
1038 return res;
1042 * Publishes 'calendarData' category's WorkingHours.
1044 * @param version (%u) Ex.: 1
1045 * @param email (%s) Ex.: alice@cosmo.local
1046 * @param working_hours_xml_str (%s) Ex.: <WorkingHours xmlns=.....
1048 * @param version (%u)
1050 * @param version (%u)
1051 * @param email (%s)
1052 * @param working_hours_xml_str (%s)
1054 * @param version (%u)
1055 * @param email (%s)
1056 * @param working_hours_xml_str (%s)
1058 * @param version (%u)
1059 * @param email (%s)
1060 * @param working_hours_xml_str (%s)
1062 * @param version (%u)
1064 #define SIPE_PUB_XML_WORKING_HOURS \
1065 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"1\" version=\"%d\" expireType=\"static\">"\
1066 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1067 "</calendarData>"\
1068 "</publication>"\
1069 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"100\" version=\"%d\" expireType=\"static\">"\
1070 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1071 "</publication>"\
1072 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"200\" version=\"%d\" expireType=\"static\">"\
1073 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1074 "</calendarData>"\
1075 "</publication>"\
1076 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"300\" version=\"%d\" expireType=\"static\">"\
1077 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1078 "</calendarData>"\
1079 "</publication>"\
1080 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"400\" version=\"%d\" expireType=\"static\">"\
1081 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1082 "</calendarData>"\
1083 "</publication>"\
1084 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"32000\" version=\"%d\" expireType=\"static\">"\
1085 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1086 "</publication>"
1089 * Returns 'calendarData' XML part with WorkingHours for publication.
1090 * Must be g_free'd after use.
1092 static gchar *sipe_publish_get_category_cal_working_hours(struct sipe_core_private *sipe_private)
1094 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
1095 struct sipe_calendar* cal = sip->cal;
1097 /* key is <category><instance><container> */
1098 gchar *key_cal_1 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1);
1099 gchar *key_cal_100 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100);
1100 gchar *key_cal_200 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200);
1101 gchar *key_cal_300 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300);
1102 gchar *key_cal_400 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400);
1103 gchar *key_cal_32000 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000);
1105 struct sipe_publication *publication_cal_1 =
1106 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "calendarData"), key_cal_1);
1107 struct sipe_publication *publication_cal_100 =
1108 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "calendarData"), key_cal_100);
1109 struct sipe_publication *publication_cal_200 =
1110 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "calendarData"), key_cal_200);
1111 struct sipe_publication *publication_cal_300 =
1112 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "calendarData"), key_cal_300);
1113 struct sipe_publication *publication_cal_400 =
1114 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "calendarData"), key_cal_400);
1115 struct sipe_publication *publication_cal_32000 =
1116 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "calendarData"), key_cal_32000);
1118 const char *n1 = cal ? cal->working_hours_xml_str : NULL;
1119 const char *n2 = publication_cal_300 ? publication_cal_300->working_hours_xml_str : NULL;
1121 g_free(key_cal_1);
1122 g_free(key_cal_100);
1123 g_free(key_cal_200);
1124 g_free(key_cal_300);
1125 g_free(key_cal_400);
1126 g_free(key_cal_32000);
1128 if (!cal || is_empty(cal->email) || is_empty(cal->working_hours_xml_str)) {
1129 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_working_hours: no data to publish, exiting");
1130 return NULL;
1133 if (sipe_strequal(n1, n2))
1135 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_working_hours: WorkingHours has NOT changed. Exiting.");
1136 return NULL; /* nothing to update */
1139 return g_strdup_printf(SIPE_PUB_XML_WORKING_HOURS,
1140 /* 1 */
1141 publication_cal_1 ? publication_cal_1->version : 0,
1142 cal->email,
1143 cal->working_hours_xml_str,
1144 /* 100 - Public */
1145 publication_cal_100 ? publication_cal_100->version : 0,
1146 /* 200 - Company */
1147 publication_cal_200 ? publication_cal_200->version : 0,
1148 cal->email,
1149 cal->working_hours_xml_str,
1150 /* 300 - Team */
1151 publication_cal_300 ? publication_cal_300->version : 0,
1152 cal->email,
1153 cal->working_hours_xml_str,
1154 /* 400 - Personal */
1155 publication_cal_400 ? publication_cal_400->version : 0,
1156 cal->email,
1157 cal->working_hours_xml_str,
1158 /* 32000 - Blocked */
1159 publication_cal_32000 ? publication_cal_32000->version : 0
1164 * Publishes 'calendarData' category's FreeBusy.
1166 * @param instance (%u) Ex.: 1300372959
1167 * @param version (%u) Ex.: 1
1169 * @param instance (%u) Ex.: 1300372959
1170 * @param version (%u) Ex.: 1
1172 * @param instance (%u) Ex.: 1300372959
1173 * @param version (%u) Ex.: 1
1174 * @param email (%s) Ex.: alice@cosmo.local
1175 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1176 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1178 * @param instance (%u) Ex.: 1300372959
1179 * @param version (%u) Ex.: 1
1180 * @param email (%s) Ex.: alice@cosmo.local
1181 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1182 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1184 * @param instance (%u) Ex.: 1300372959
1185 * @param version (%u) Ex.: 1
1186 * @param email (%s) Ex.: alice@cosmo.local
1187 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1188 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1190 * @param instance (%u) Ex.: 1300372959
1191 * @param version (%u) Ex.: 1
1193 #define SIPE_PUB_XML_FREE_BUSY \
1194 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"1\" version=\"%d\" expireType=\"endpoint\">"\
1195 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1196 "</publication>"\
1197 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"100\" version=\"%d\" expireType=\"endpoint\">"\
1198 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1199 "</publication>"\
1200 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"200\" version=\"%d\" expireType=\"endpoint\">"\
1201 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1202 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1203 "</calendarData>"\
1204 "</publication>"\
1205 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"300\" version=\"%d\" expireType=\"endpoint\">"\
1206 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1207 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1208 "</calendarData>"\
1209 "</publication>"\
1210 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"400\" version=\"%d\" expireType=\"endpoint\">"\
1211 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1212 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1213 "</calendarData>"\
1214 "</publication>"\
1215 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"32000\" version=\"%d\" expireType=\"endpoint\">"\
1216 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1217 "</publication>"
1220 * Returns 'calendarData' XML part with FreeBusy for publication.
1221 * Must be g_free'd after use.
1223 static gchar *sipe_publish_get_category_cal_free_busy(struct sipe_core_private *sipe_private)
1225 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
1226 struct sipe_calendar* cal = sip->cal;
1227 guint cal_data_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_CALENDAR_DATA);
1228 char *fb_start_str;
1229 char *free_busy_base64;
1230 /* const char *st; */
1231 /* const char *fb; */
1232 char *res;
1234 /* key is <category><instance><container> */
1235 gchar *key_cal_1 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 1);
1236 gchar *key_cal_100 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 100);
1237 gchar *key_cal_200 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 200);
1238 gchar *key_cal_300 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 300);
1239 gchar *key_cal_400 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 400);
1240 gchar *key_cal_32000 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 32000);
1242 struct sipe_publication *publication_cal_1 =
1243 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "calendarData"), key_cal_1);
1244 struct sipe_publication *publication_cal_100 =
1245 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "calendarData"), key_cal_100);
1246 struct sipe_publication *publication_cal_200 =
1247 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "calendarData"), key_cal_200);
1248 struct sipe_publication *publication_cal_300 =
1249 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "calendarData"), key_cal_300);
1250 struct sipe_publication *publication_cal_400 =
1251 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "calendarData"), key_cal_400);
1252 struct sipe_publication *publication_cal_32000 =
1253 g_hash_table_lookup(g_hash_table_lookup(sip->our_publications, "calendarData"), key_cal_32000);
1255 g_free(key_cal_1);
1256 g_free(key_cal_100);
1257 g_free(key_cal_200);
1258 g_free(key_cal_300);
1259 g_free(key_cal_400);
1260 g_free(key_cal_32000);
1262 if (!cal || is_empty(cal->email) || !cal->fb_start || is_empty(cal->free_busy)) {
1263 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_free_busy: no data to publish, exiting");
1264 return NULL;
1267 fb_start_str = sipe_utils_time_to_str(cal->fb_start);
1268 free_busy_base64 = sipe_cal_get_freebusy_base64(cal->free_busy);
1270 /* we will rebuplish the same data to refresh publication time,
1271 * so if data from multiple sources, most recent will be choosen
1273 // st = publication_cal_300 ? publication_cal_300->fb_start_str : NULL;
1274 // fb = publication_cal_300 ? publication_cal_300->free_busy_base64 : NULL;
1276 //if (sipe_strequal(st, fb_start_str) && sipe_strequal(fb, free_busy_base64))
1278 // SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_free_busy: FreeBusy has NOT changed. Exiting.");
1279 // g_free(fb_start_str);
1280 // g_free(free_busy_base64);
1281 // return NULL; /* nothing to update */
1284 res = g_strdup_printf(SIPE_PUB_XML_FREE_BUSY,
1285 /* 1 */
1286 cal_data_instance,
1287 publication_cal_1 ? publication_cal_1->version : 0,
1288 /* 100 - Public */
1289 cal_data_instance,
1290 publication_cal_100 ? publication_cal_100->version : 0,
1291 /* 200 - Company */
1292 cal_data_instance,
1293 publication_cal_200 ? publication_cal_200->version : 0,
1294 cal->email,
1295 fb_start_str,
1296 free_busy_base64,
1297 /* 300 - Team */
1298 cal_data_instance,
1299 publication_cal_300 ? publication_cal_300->version : 0,
1300 cal->email,
1301 fb_start_str,
1302 free_busy_base64,
1303 /* 400 - Personal */
1304 cal_data_instance,
1305 publication_cal_400 ? publication_cal_400->version : 0,
1306 cal->email,
1307 fb_start_str,
1308 free_busy_base64,
1309 /* 32000 - Blocked */
1310 cal_data_instance,
1311 publication_cal_32000 ? publication_cal_32000->version : 0
1314 g_free(fb_start_str);
1315 g_free(free_busy_base64);
1316 return res;
1321 * Publishes 'device' category.
1322 * @param instance (%u) Ex.: 1938468728
1323 * @param version (%u) Ex.: 1
1324 * @param endpointId (%s) Ex.: C707E38E-1E10-5413-94D9-ECAC260A0269
1325 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1326 * @param timezone (%s) Ex.: 00:00:00+01:00
1327 * @param machineName (%s) Ex.: BOSTON-OCS07
1329 #define SIPE_PUB_XML_DEVICE \
1330 "<publication categoryName=\"device\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
1331 "<device xmlns=\"http://schemas.microsoft.com/2006/09/sip/device\" endpointId=\"%s\">"\
1332 "<capabilities preferred=\"false\" uri=\"%s\">"\
1333 "<text capture=\"true\" render=\"true\" publish=\"false\"/>"\
1334 "<gifInk capture=\"false\" render=\"true\" publish=\"false\"/>"\
1335 "<isfInk capture=\"false\" render=\"true\" publish=\"false\"/>"\
1336 "</capabilities>"\
1337 "<timezone>%s</timezone>"\
1338 "<machineName>%s</machineName>"\
1339 "</device>"\
1340 "</publication>"
1343 * Returns 'device' XML part for publication.
1344 * Must be g_free'd after use.
1346 static gchar *sipe_publish_get_category_device(struct sipe_core_private *sipe_private)
1348 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_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(sip->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(sip->our_publications, "state"), key_2);
1440 struct sipe_publication *publication_3 =
1441 g_hash_table_lookup(g_hash_table_lookup(sip->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 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
1560 const gchar *container = sipe_xml_attribute(node, "container");
1561 const gchar *instance = sipe_xml_attribute(node, "instance");
1562 /* key is <category><instance><container> */
1563 gchar *key = g_strdup_printf("<%s><%s><%s>", categoryName, instance, container);
1564 GHashTable *category = g_hash_table_lookup(sip->our_publications, categoryName);
1566 if (category) {
1567 struct sipe_publication *publication =
1568 g_hash_table_lookup(category, key);
1570 SIPE_DEBUG_INFO("key is %s", key);
1572 if (publication) {
1573 SIPE_DEBUG_INFO("Updating %s with version %s. Was %d before.",
1574 key, curVersion, publication->version);
1575 /* updating publication's version to the correct one */
1576 publication->version = atoi(curVersion);
1578 } else {
1579 /* We somehow lost this category from our publications... */
1580 struct sipe_publication *publication = g_new0(struct sipe_publication, 1);
1581 publication->category = g_strdup(categoryName);
1582 publication->instance = atoi(instance);
1583 publication->container = atoi(container);
1584 publication->version = atoi(curVersion);
1585 category = g_hash_table_new_full(g_str_hash, g_str_equal,
1586 g_free, (GDestroyNotify)free_publication);
1587 g_hash_table_insert(category, g_strdup(key), publication);
1588 g_hash_table_insert(sip->our_publications, g_strdup(categoryName), category);
1589 SIPE_DEBUG_INFO("added lost category '%s' key '%s'", categoryName, key);
1591 g_free(key);
1594 sipe_xml_free(xml);
1595 g_hash_table_destroy(faults);
1597 /* rebublishing with right versions */
1598 if (has_device_publication) {
1599 send_publish_category_initial(sipe_private);
1600 } else {
1601 sipe_status_update(sipe_private, NULL);
1604 return TRUE;
1608 * Publishes categories.
1609 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1610 * @param publications (%s) XML publications
1612 #define SIPE_SEND_PRESENCE \
1613 "<publish xmlns=\"http://schemas.microsoft.com/2006/09/sip/rich-presence\">"\
1614 "<publications uri=\"%s\">"\
1615 "%s"\
1616 "</publications>"\
1617 "</publish>"
1619 static void send_presence_publish(struct sipe_core_private *sipe_private,
1620 const char *publications)
1622 gchar *uri;
1623 gchar *doc;
1624 gchar *tmp;
1625 gchar *hdr;
1627 uri = sip_uri_self(sipe_private);
1628 doc = g_strdup_printf(SIPE_SEND_PRESENCE,
1629 uri,
1630 publications);
1632 tmp = get_contact(sipe_private);
1633 hdr = g_strdup_printf("Contact: %s\r\n"
1634 "Content-Type: application/msrtc-category-publish+xml\r\n", tmp);
1636 sip_transport_service(sipe_private,
1637 uri,
1638 hdr,
1639 doc,
1640 process_send_presence_category_publish_response);
1642 g_free(tmp);
1643 g_free(hdr);
1644 g_free(uri);
1645 g_free(doc);
1649 * Publishes self status
1650 * based on own calendar information.
1652 void sipe_ocs2007_presence_publish(struct sipe_core_private *sipe_private,
1653 SIPE_UNUSED_PARAMETER void *unused)
1655 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
1656 struct sipe_cal_event* event = NULL;
1657 gchar *pub_cal_working_hours = NULL;
1658 gchar *pub_cal_free_busy = NULL;
1659 gchar *pub_calendar = NULL;
1660 gchar *pub_calendar2 = NULL;
1661 gchar *pub_oof_note = NULL;
1662 const gchar *oof_note;
1663 time_t oof_start = 0;
1664 time_t oof_end = 0;
1666 if (!sip->cal) {
1667 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() no calendar data.");
1668 return;
1671 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() started.");
1672 if (sip->cal->cal_events) {
1673 event = sipe_cal_get_event(sip->cal->cal_events, time(NULL));
1676 if (!event) {
1677 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: current event is NULL");
1678 } else {
1679 char *desc = sipe_cal_event_describe(event);
1680 SIPE_DEBUG_INFO("publish_calendar_status_self: current event is:\n%s", desc ? desc : "");
1681 g_free(desc);
1684 /* Logic
1685 if OOF
1686 OOF publish, Busy clean
1687 ilse if Busy
1688 OOF clean, Busy publish
1689 else
1690 OOF clean, Busy clean
1692 if (event && event->cal_status == SIPE_CAL_OOF) {
1693 pub_calendar = sipe_publish_get_category_state_calendar(sipe_private, event, sip->cal->email, SIPE_CAL_OOF);
1694 pub_calendar2 = sipe_publish_get_category_state_calendar(sipe_private, NULL, sip->cal->email, SIPE_CAL_BUSY);
1695 } else if (event && event->cal_status == SIPE_CAL_BUSY) {
1696 pub_calendar = sipe_publish_get_category_state_calendar(sipe_private, NULL, sip->cal->email, SIPE_CAL_OOF);
1697 pub_calendar2 = sipe_publish_get_category_state_calendar(sipe_private, event, sip->cal->email, SIPE_CAL_BUSY);
1698 } else {
1699 pub_calendar = sipe_publish_get_category_state_calendar(sipe_private, NULL, sip->cal->email, SIPE_CAL_OOF);
1700 pub_calendar2 = sipe_publish_get_category_state_calendar(sipe_private, NULL, sip->cal->email, SIPE_CAL_BUSY);
1703 oof_note = sipe_ews_get_oof_note(sip->cal);
1704 if (sipe_strequal("Scheduled", sip->cal->oof_state)) {
1705 oof_start = sip->cal->oof_start;
1706 oof_end = sip->cal->oof_end;
1708 pub_oof_note = sipe_publish_get_category_note(sipe_private, oof_note, "OOF", oof_start, oof_end);
1710 pub_cal_working_hours = sipe_publish_get_category_cal_working_hours(sipe_private);
1711 pub_cal_free_busy = sipe_publish_get_category_cal_free_busy(sipe_private);
1713 if (!pub_cal_working_hours && !pub_cal_free_busy && !pub_calendar && !pub_calendar2 && !pub_oof_note) {
1714 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: nothing has changed.");
1715 } else {
1716 gchar *publications = g_strdup_printf("%s%s%s%s%s",
1717 pub_cal_working_hours ? pub_cal_working_hours : "",
1718 pub_cal_free_busy ? pub_cal_free_busy : "",
1719 pub_calendar ? pub_calendar : "",
1720 pub_calendar2 ? pub_calendar2 : "",
1721 pub_oof_note ? pub_oof_note : "");
1723 send_presence_publish(sipe_private, publications);
1724 g_free(publications);
1727 g_free(pub_cal_working_hours);
1728 g_free(pub_cal_free_busy);
1729 g_free(pub_calendar);
1730 g_free(pub_calendar2);
1731 g_free(pub_oof_note);
1733 /* repeat scheduling */
1734 schedule_publish_update(sipe_private, time(NULL));
1737 void sipe_ocs2007_category_publish(struct sipe_core_private *sipe_private)
1739 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
1740 gchar *pub_state = sipe_status_changed_by_user(sipe_private) ?
1741 sipe_publish_get_category_state_user(sipe_private) :
1742 sipe_publish_get_category_state_machine(sipe_private);
1743 gchar *pub_note = sipe_publish_get_category_note(sipe_private,
1744 sip->note,
1745 SIPE_CORE_PRIVATE_FLAG_IS(OOF_NOTE) ? "OOF" : "personal",
1748 gchar *publications;
1750 if (!pub_state && !pub_note) {
1751 SIPE_DEBUG_INFO_NOFORMAT("sipe_osc2007_category_publish: nothing has changed. Exiting.");
1752 return;
1755 publications = g_strdup_printf("%s%s",
1756 pub_state ? pub_state : "",
1757 pub_note ? pub_note : "");
1759 g_free(pub_state);
1760 g_free(pub_note);
1762 send_presence_publish(sipe_private, publications);
1763 g_free(publications);
1766 static void sipe_publish_get_cat_state_user_to_clear(SIPE_UNUSED_PARAMETER const char *name,
1767 gpointer value,
1768 GString* str)
1770 struct sipe_publication *publication = value;
1772 g_string_append_printf( str,
1773 SIPE_PUB_XML_PUBLICATION_CLEAR,
1774 publication->category,
1775 publication->instance,
1776 publication->container,
1777 publication->version,
1778 "static");
1781 void sipe_ocs2007_reset_status(struct sipe_core_private *sipe_private)
1783 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
1784 GString* str;
1785 gchar *publications;
1787 if (!sip->user_state_publications || g_hash_table_size(sip->user_state_publications) == 0) {
1788 SIPE_DEBUG_INFO_NOFORMAT("sipe_reset_status: no userState publications, exiting.");
1789 return;
1792 str = g_string_new(NULL);
1793 g_hash_table_foreach(sip->user_state_publications, (GHFunc)sipe_publish_get_cat_state_user_to_clear, str);
1794 publications = g_string_free(str, FALSE);
1796 send_presence_publish(sipe_private, publications);
1797 g_free(publications);
1800 /* key is <category><instance><container> */
1801 static gboolean sipe_is_our_publication(struct sipe_core_private *sipe_private,
1802 const gchar *key)
1804 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
1805 GSList *entry;
1807 /* filling keys for our publications if not yet cached */
1808 if (!sip->our_publication_keys) {
1809 guint device_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_DEVICE);
1810 guint machine_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_MACHINE);
1811 guint user_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_USER);
1812 guint calendar_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_CALENDAR);
1813 guint cal_oof_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_CALENDAR_OOF);
1814 guint cal_data_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_CALENDAR_DATA);
1815 guint note_oof_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_NOTE_OOF);
1817 SIPE_DEBUG_INFO_NOFORMAT("* Our Publication Instances *");
1818 SIPE_DEBUG_INFO("\tDevice : %u\t0x%08X", device_instance, device_instance);
1819 SIPE_DEBUG_INFO("\tMachine State : %u\t0x%08X", machine_instance, machine_instance);
1820 SIPE_DEBUG_INFO("\tUser Stare : %u\t0x%08X", user_instance, user_instance);
1821 SIPE_DEBUG_INFO("\tCalendar State : %u\t0x%08X", calendar_instance, calendar_instance);
1822 SIPE_DEBUG_INFO("\tCalendar OOF State : %u\t0x%08X", cal_oof_instance, cal_oof_instance);
1823 SIPE_DEBUG_INFO("\tCalendar FreeBusy : %u\t0x%08X", cal_data_instance, cal_data_instance);
1824 SIPE_DEBUG_INFO("\tOOF Note : %u\t0x%08X", note_oof_instance, note_oof_instance);
1825 SIPE_DEBUG_INFO("\tNote : %u", 0);
1826 SIPE_DEBUG_INFO("\tCalendar WorkingHours: %u", 0);
1828 /* device */
1829 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1830 g_strdup_printf("<%s><%u><%u>", "device", device_instance, 2));
1832 /* state:machineState */
1833 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1834 g_strdup_printf("<%s><%u><%u>", "state", machine_instance, 2));
1835 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1836 g_strdup_printf("<%s><%u><%u>", "state", machine_instance, 3));
1838 /* state:userState */
1839 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1840 g_strdup_printf("<%s><%u><%u>", "state", user_instance, 2));
1841 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1842 g_strdup_printf("<%s><%u><%u>", "state", user_instance, 3));
1844 /* state:calendarState */
1845 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1846 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance, 2));
1847 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1848 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance, 3));
1850 /* state:calendarState OOF */
1851 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1852 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance, 2));
1853 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1854 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance, 3));
1856 /* note */
1857 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1858 g_strdup_printf("<%s><%u><%u>", "note", 0, 200));
1859 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1860 g_strdup_printf("<%s><%u><%u>", "note", 0, 300));
1861 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1862 g_strdup_printf("<%s><%u><%u>", "note", 0, 400));
1864 /* note OOF */
1865 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1866 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance, 200));
1867 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1868 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance, 300));
1869 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1870 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance, 400));
1872 /* calendarData:WorkingHours */
1873 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1874 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1));
1875 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1876 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100));
1877 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1878 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200));
1879 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1880 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300));
1881 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1882 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400));
1883 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1884 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000));
1886 /* calendarData:FreeBusy */
1887 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1888 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 1));
1889 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1890 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 100));
1891 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1892 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 200));
1893 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1894 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 300));
1895 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1896 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 400));
1897 sip->our_publication_keys = g_slist_append(sip->our_publication_keys,
1898 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 32000));
1900 //SIPE_DEBUG_INFO("sipe_is_our_publication: sip->our_publication_keys length=%d",
1901 // sip->our_publication_keys ? (int) g_slist_length(sip->our_publication_keys) : -1);
1904 //SIPE_DEBUG_INFO("sipe_is_our_publication: key=%s", key);
1906 entry = sip->our_publication_keys;
1907 while (entry) {
1908 //SIPE_DEBUG_INFO(" sipe_is_our_publication: entry->data=%s", entry->data);
1909 if (sipe_strequal(entry->data, key)) {
1910 return TRUE;
1912 entry = entry->next;
1914 return FALSE;
1917 static void sipe_refresh_blocked_status_cb(char *buddy_name,
1918 SIPE_UNUSED_PARAMETER struct sipe_buddy *buddy,
1919 struct sipe_core_private *sipe_private)
1921 int container_id = sipe_ocs2007_find_access_level(sipe_private, "user", buddy_name, NULL);
1922 gboolean blocked = (container_id == 32000);
1923 gboolean blocked_in_blist = sipe_backend_buddy_is_blocked(SIPE_CORE_PUBLIC, buddy_name);
1925 /* SIPE_DEBUG_INFO("sipe_refresh_blocked_status_cb: buddy_name=%s, blocked=%s, blocked_in_blist=%s",
1926 buddy_name, blocked ? "T" : "F", blocked_in_blist ? "T" : "F"); */
1928 if (blocked != blocked_in_blist) {
1929 sipe_backend_buddy_set_blocked_status(SIPE_CORE_PUBLIC, buddy_name, blocked);
1933 static void sipe_refresh_blocked_status(struct sipe_core_private *sipe_private)
1935 g_hash_table_foreach(sipe_private->buddies,
1936 (GHFunc) sipe_refresh_blocked_status_cb,
1937 sipe_private);
1941 * When we receive some self (BE) NOTIFY with a new subscriber
1942 * we sends a setSubscribers request to him [SIP-PRES] 4.8
1945 void sipe_ocs2007_process_roaming_self(struct sipe_core_private *sipe_private,
1946 struct sipmsg *msg)
1948 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
1949 gchar *contact;
1950 gchar *to;
1951 sipe_xml *xml;
1952 const sipe_xml *node;
1953 const sipe_xml *node2;
1954 char *display_name = NULL;
1955 char *uri;
1956 GSList *category_names = NULL;
1957 int aggreg_avail = 0;
1958 gboolean do_update_status = FALSE;
1959 gboolean has_note_cleaned = FALSE;
1960 GHashTable *devices;
1962 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self");
1964 xml = sipe_xml_parse(msg->body, msg->bodylen);
1965 if (!xml) return;
1967 contact = get_contact(sipe_private);
1968 to = sip_uri_self(sipe_private);
1970 /* categories */
1971 /* set list of categories participating in this XML */
1972 for (node = sipe_xml_child(xml, "categories/category"); node; node = sipe_xml_twin(node)) {
1973 const gchar *name = sipe_xml_attribute(node, "name");
1974 category_names = slist_insert_unique_sorted(category_names, (gchar *)name, (GCompareFunc)strcmp);
1976 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: category_names length=%d",
1977 category_names ? (int) g_slist_length(category_names) : -1);
1978 /* drop category information */
1979 if (category_names) {
1980 GSList *entry = category_names;
1981 while (entry) {
1982 GHashTable *cat_publications;
1983 const gchar *category = entry->data;
1984 entry = entry->next;
1985 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: dropping category: %s", category);
1986 cat_publications = g_hash_table_lookup(sip->our_publications, category);
1987 if (cat_publications) {
1988 g_hash_table_remove(sip->our_publications, category);
1989 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: dropped category: %s", category);
1993 g_slist_free(category_names);
1995 /* filling our categories reflected in roaming data */
1996 devices = g_hash_table_new_full(g_str_hash, g_str_equal,
1997 g_free, NULL);
1998 for (node = sipe_xml_child(xml, "categories/category"); node; node = sipe_xml_twin(node)) {
1999 const char *tmp;
2000 const gchar *name = sipe_xml_attribute(node, "name");
2001 guint container = sipe_xml_int_attribute(node, "container", -1);
2002 guint instance = sipe_xml_int_attribute(node, "instance", -1);
2003 guint version = sipe_xml_int_attribute(node, "version", 0);
2004 time_t publish_time = (tmp = sipe_xml_attribute(node, "publishTime")) ?
2005 sipe_utils_str_to_time(tmp) : 0;
2006 gchar *key;
2007 GHashTable *cat_publications = g_hash_table_lookup(sip->our_publications, name);
2009 /* Ex. clear note: <category name="note"/> */
2010 if (container == (guint)-1) {
2011 g_free(sip->note);
2012 sip->note = NULL;
2013 do_update_status = TRUE;
2014 continue;
2017 /* Ex. clear note: <category name="note" container="200"/> */
2018 if (instance == (guint)-1) {
2019 if (container == 200) {
2020 g_free(sip->note);
2021 sip->note = NULL;
2022 do_update_status = TRUE;
2024 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removing publications for: %s/%u", name, container);
2025 sipe_remove_category_container_publications(
2026 sip->our_publications, name, container);
2027 continue;
2030 /* key is <category><instance><container> */
2031 key = g_strdup_printf("<%s><%u><%u>", name, instance, container);
2032 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: key=%s version=%d", key, version);
2034 /* capture all userState publication for later clean up if required */
2035 if (sipe_strequal(name, "state") && (container == 2 || container == 3)) {
2036 const sipe_xml *xn_state = sipe_xml_child(node, "state");
2038 if (xn_state && sipe_strequal(sipe_xml_attribute(xn_state, "type"), "userState")) {
2039 struct sipe_publication *publication = g_new0(struct sipe_publication, 1);
2040 publication->category = g_strdup(name);
2041 publication->instance = instance;
2042 publication->container = container;
2043 publication->version = version;
2045 if (!sip->user_state_publications) {
2046 sip->user_state_publications = g_hash_table_new_full(
2047 g_str_hash, g_str_equal,
2048 g_free, (GDestroyNotify)free_publication);
2050 g_hash_table_insert(sip->user_state_publications, g_strdup(key), publication);
2051 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added to user_state_publications key=%s version=%d",
2052 key, version);
2056 /* count each client instance only once */
2057 if (sipe_strequal(name, "device"))
2058 g_hash_table_replace(devices, g_strdup_printf("%u", instance), NULL);
2060 if (sipe_is_our_publication(sipe_private, key)) {
2061 struct sipe_publication *publication = g_new0(struct sipe_publication, 1);
2063 publication->category = g_strdup(name);
2064 publication->instance = instance;
2065 publication->container = container;
2066 publication->version = version;
2068 /* filling publication->availability */
2069 if (sipe_strequal(name, "state")) {
2070 const sipe_xml *xn_state = sipe_xml_child(node, "state");
2071 const sipe_xml *xn_avail = sipe_xml_child(xn_state, "availability");
2073 if (xn_avail) {
2074 gchar *avail_str = sipe_xml_data(xn_avail);
2075 if (avail_str) {
2076 publication->availability = atoi(avail_str);
2078 g_free(avail_str);
2080 /* for calendarState */
2081 if (xn_state && sipe_strequal(sipe_xml_attribute(xn_state, "type"), "calendarState")) {
2082 const sipe_xml *xn_activity = sipe_xml_child(xn_state, "activity");
2083 struct sipe_cal_event *event = g_new0(struct sipe_cal_event, 1);
2085 event->start_time = sipe_utils_str_to_time(sipe_xml_attribute(xn_state, "startTime"));
2086 if (xn_activity) {
2087 if (sipe_strequal(sipe_xml_attribute(xn_activity, "token"),
2088 sipe_backend_activity_to_token(SIPE_ACTIVITY_IN_MEETING)))
2090 event->is_meeting = TRUE;
2093 event->subject = sipe_xml_data(sipe_xml_child(xn_state, "meetingSubject"));
2094 event->location = sipe_xml_data(sipe_xml_child(xn_state, "meetingLocation"));
2096 publication->cal_event_hash = sipe_cal_event_hash(event);
2097 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: hash=%s",
2098 publication->cal_event_hash);
2099 sipe_cal_event_free(event);
2102 /* filling publication->note */
2103 if (sipe_strequal(name, "note")) {
2104 const sipe_xml *xn_body = sipe_xml_child(node, "note/body");
2106 if (!has_note_cleaned) {
2107 has_note_cleaned = TRUE;
2109 g_free(sip->note);
2110 sip->note = NULL;
2111 sip->note_since = publish_time;
2113 do_update_status = TRUE;
2116 g_free(publication->note);
2117 publication->note = NULL;
2118 if (xn_body) {
2119 char *tmp;
2121 publication->note = g_markup_escape_text((tmp = sipe_xml_data(xn_body)), -1);
2122 g_free(tmp);
2123 if (publish_time >= sip->note_since) {
2124 g_free(sip->note);
2125 sip->note = g_strdup(publication->note);
2126 sip->note_since = publish_time;
2127 if (sipe_strequal(sipe_xml_attribute(xn_body, "type"), "OOF"))
2128 SIPE_CORE_PRIVATE_FLAG_SET(OOF_NOTE);
2129 else
2130 SIPE_CORE_PRIVATE_FLAG_UNSET(OOF_NOTE);
2132 do_update_status = TRUE;
2137 /* filling publication->fb_start_str, free_busy_base64, working_hours_xml_str */
2138 if (sipe_strequal(name, "calendarData") && (publication->container == 300)) {
2139 const sipe_xml *xn_free_busy = sipe_xml_child(node, "calendarData/freeBusy");
2140 const sipe_xml *xn_working_hours = sipe_xml_child(node, "calendarData/WorkingHours");
2141 if (xn_free_busy) {
2142 publication->fb_start_str = g_strdup(sipe_xml_attribute(xn_free_busy, "startTime"));
2143 publication->free_busy_base64 = sipe_xml_data(xn_free_busy);
2145 if (xn_working_hours) {
2146 publication->working_hours_xml_str = sipe_xml_stringify(xn_working_hours);
2150 if (!cat_publications) {
2151 cat_publications = g_hash_table_new_full(
2152 g_str_hash, g_str_equal,
2153 g_free, (GDestroyNotify)free_publication);
2154 g_hash_table_insert(sip->our_publications, g_strdup(name), cat_publications);
2155 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added GHashTable cat=%s", name);
2157 g_hash_table_insert(cat_publications, g_strdup(key), publication);
2158 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added key=%s version=%d", key, version);
2160 g_free(key);
2162 /* aggregateState (not an our publication) from 2-nd container */
2163 if (sipe_strequal(name, "state") && container == 2) {
2164 const sipe_xml *xn_state = sipe_xml_child(node, "state");
2166 if (xn_state && sipe_strequal(sipe_xml_attribute(xn_state, "type"), "aggregateState")) {
2167 const sipe_xml *xn_avail = sipe_xml_child(xn_state, "availability");
2169 if (xn_avail) {
2170 gchar *avail_str = sipe_xml_data(xn_avail);
2171 if (avail_str) {
2172 aggreg_avail = atoi(avail_str);
2174 g_free(avail_str);
2177 do_update_status = TRUE;
2181 /* userProperties published by server from AD */
2182 if (!sip->csta && sipe_strequal(name, "userProperties")) {
2183 const sipe_xml *line;
2184 /* line, for Remote Call Control (RCC) */
2185 for (line = sipe_xml_child(node, "userProperties/lines/line"); line; line = sipe_xml_twin(line)) {
2186 const gchar *line_server = sipe_xml_attribute(line, "lineServer");
2187 const gchar *line_type = sipe_xml_attribute(line, "lineType");
2188 gchar *line_uri;
2190 if (!line_server || !(sipe_strequal(line_type, "Rcc") || sipe_strequal(line_type, "Dual"))) continue;
2192 line_uri = sipe_xml_data(line);
2193 if (line_uri) {
2194 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: line_uri=%s server=%s", line_uri, line_server);
2195 sip_csta_open(sipe_private, line_uri, line_server);
2197 g_free(line_uri);
2199 break;
2203 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sip->our_publications size=%d",
2204 sip->our_publications ? (int) g_hash_table_size(sip->our_publications) : -1);
2206 /* active clients for user account */
2207 if (g_hash_table_size(devices) > 1) {
2208 SIPE_CORE_PRIVATE_FLAG_SET(MPOP);
2209 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: multiple clients detected (%d)",
2210 g_hash_table_size(devices));
2211 } else {
2212 SIPE_CORE_PRIVATE_FLAG_UNSET(MPOP);
2213 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self: single client detected");
2215 g_hash_table_destroy(devices);
2217 /* containers */
2218 for (node = sipe_xml_child(xml, "containers/container"); node; node = sipe_xml_twin(node)) {
2219 guint id = sipe_xml_int_attribute(node, "id", 0);
2220 struct sipe_container *container = sipe_find_container(sipe_private, id);
2222 if (container) {
2223 sip->containers = g_slist_remove(sip->containers, container);
2224 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removed existing container id=%d v%d", container->id, container->version);
2225 sipe_ocs2007_free_container(container);
2227 container = g_new0(struct sipe_container, 1);
2228 container->id = id;
2229 container->version = sipe_xml_int_attribute(node, "version", 0);
2230 sip->containers = g_slist_append(sip->containers, container);
2231 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container id=%d v%d", container->id, container->version);
2233 for (node2 = sipe_xml_child(node, "member"); node2; node2 = sipe_xml_twin(node2)) {
2234 struct sipe_container_member *member = g_new0(struct sipe_container_member, 1);
2235 member->type = g_strdup(sipe_xml_attribute(node2, "type"));
2236 member->value = g_strdup(sipe_xml_attribute(node2, "value"));
2237 container->members = g_slist_append(container->members, member);
2238 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container member type=%s value=%s",
2239 member->type, member->value ? member->value : "");
2243 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sip->access_level_set=%s", sip->access_level_set ? "TRUE" : "FALSE");
2244 if (!sip->access_level_set && sipe_xml_child(xml, "containers")) {
2245 char *container_xmls = NULL;
2246 int sameEnterpriseAL = sipe_ocs2007_find_access_level(sipe_private, "sameEnterprise", NULL, NULL);
2247 int federatedAL = sipe_ocs2007_find_access_level(sipe_private, "federated", NULL, NULL);
2249 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sameEnterpriseAL=%d", sameEnterpriseAL);
2250 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: federatedAL=%d", federatedAL);
2251 /* initial set-up to let counterparties see your status */
2252 if (sameEnterpriseAL < 0) {
2253 struct sipe_container *container = sipe_find_container(sipe_private, 200);
2254 guint version = container ? container->version : 0;
2255 sipe_send_container_members_prepare(200, version, "add", "sameEnterprise", NULL, &container_xmls);
2257 if (federatedAL < 0) {
2258 struct sipe_container *container = sipe_find_container(sipe_private, 100);
2259 guint version = container ? container->version : 0;
2260 sipe_send_container_members_prepare(100, version, "add", "federated", NULL, &container_xmls);
2262 sip->access_level_set = TRUE;
2264 if (container_xmls) {
2265 sipe_send_set_container_members(sipe_private, container_xmls);
2267 g_free(container_xmls);
2270 /* Refresh contacts' blocked status */
2271 sipe_refresh_blocked_status(sipe_private);
2273 /* subscribers */
2274 for (node = sipe_xml_child(xml, "subscribers/subscriber"); node; node = sipe_xml_twin(node)) {
2275 const char *user;
2276 const char *acknowledged;
2277 gchar *hdr;
2278 gchar *body;
2280 user = sipe_xml_attribute(node, "user"); /* without 'sip:' prefix */
2281 if (!user) continue;
2282 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user %s", user);
2283 display_name = g_strdup(sipe_xml_attribute(node, "displayName"));
2284 uri = sip_uri_from_name(user);
2286 sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_DISPLAY_NAME, display_name);
2288 acknowledged= sipe_xml_attribute(node, "acknowledged");
2289 if(sipe_strcase_equal(acknowledged,"false")){
2290 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user added you %s", user);
2291 if (!sipe_backend_buddy_find(SIPE_CORE_PUBLIC, uri, NULL)) {
2292 sipe_backend_buddy_request_add(SIPE_CORE_PUBLIC, uri, display_name);
2295 hdr = g_strdup_printf(
2296 "Contact: %s\r\n"
2297 "Content-Type: application/msrtc-presence-setsubscriber+xml\r\n", contact);
2299 body = g_strdup_printf(
2300 "<setSubscribers xmlns=\"http://schemas.microsoft.com/2006/09/sip/presence-subscribers\">"
2301 "<subscriber user=\"%s\" acknowledged=\"true\"/>"
2302 "</setSubscribers>", user);
2304 sip_transport_service(sipe_private,
2306 hdr,
2307 body,
2308 NULL);
2309 g_free(body);
2310 g_free(hdr);
2312 g_free(display_name);
2313 g_free(uri);
2316 g_free(contact);
2317 sipe_xml_free(xml);
2319 /* Publish initial state if not yet.
2320 * Assuming this happens on initial responce to subscription to roaming-self
2321 * so we've already updated our roaming data in full.
2322 * Only for 2007+
2324 if (!sip->initial_state_published) {
2325 send_publish_category_initial(sipe_private);
2326 sipe_groupchat_init(sipe_private);
2327 sip->initial_state_published = TRUE;
2328 /* dalayed run */
2329 sipe_cal_delayed_calendar_update(sipe_private);
2330 do_update_status = FALSE;
2331 } else if (aggreg_avail) {
2333 if (aggreg_avail &&
2334 (aggreg_avail < SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE)) {
2335 /* not offline */
2336 sipe_status_set_token(sipe_private,
2337 sipe_ocs2007_status_from_legacy_availability(aggreg_avail));
2338 } else {
2339 /* do not let offline status switch us off */
2340 sipe_status_set_activity(sipe_private,
2341 SIPE_ACTIVITY_INVISIBLE);
2345 if (do_update_status) {
2346 sipe_status_and_note(sipe_private, NULL);
2349 g_free(to);
2353 Local Variables:
2354 mode: c
2355 c-file-style: "bsd"
2356 indent-tabs-mode: t
2357 tab-width: 8
2358 End: