core cleanup: add second level of access levels menu
[siplcs.git] / src / core / sipe-ocs2007.c
blob274a779260256217a3c92b379934aa5111bad23c
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 "sipmsg.h"
40 #include "sip-csta.h"
41 #include "sip-transport.h"
42 #include "sipe-backend.h"
43 #include "sipe-buddy.h"
44 #include "sipe-cal.h"
45 #include "sipe-core.h"
46 #include "sipe-core-private.h"
47 #include "sipe-ews.h"
48 #include "sipe-groupchat.h"
49 #include "sipe-nls.h"
50 #include "sipe-ocs2007.h"
51 #include "sipe-schedule.h"
52 #include "sipe-status.h"
53 #include "sipe-utils.h"
54 #include "sipe-xml.h"
56 /** MS-PRES publication */
57 struct sipe_publication {
58 gchar *category;
59 guint instance;
60 guint container;
61 guint version;
62 /** for 'state' category */
63 int availability;
64 /** for 'state:calendarState' category */
65 char *cal_event_hash;
66 /** for 'note' category */
67 gchar *note;
68 /** for 'calendarData' category; 300(Team) container */
69 char *working_hours_xml_str;
70 char *fb_start_str;
71 char *free_busy_base64;
74 /**
75 * 2007-style Activity and Availability.
77 * [MS-PRES] 3.7.5.5
79 * Conversion of legacyInterop elements and attributes to MSRTC elements and attributes.
81 * The values define the starting point of a range
83 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_ONLINE 3000
84 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY 4500
85 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_ON_PHONE 6000
86 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY 7500
87 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_DND 9000 /* do not disturb */
88 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_BRB 12000 /* be right back */
89 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY2 15000
90 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE 18000
91 const gchar *sipe_ocs2007_status_from_legacy_availability(guint availability)
93 guint type;
95 if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_ONLINE) {
96 type = SIPE_ACTIVITY_OFFLINE;
97 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY) {
98 type = SIPE_ACTIVITY_AVAILABLE;
99 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_ON_PHONE) {
100 //type = SIPE_ACTIVITY_IDLE;
101 type = SIPE_ACTIVITY_AVAILABLE;
102 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY) {
103 type = SIPE_ACTIVITY_BUSY;
104 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_DND) {
105 //type = SIPE_ACTIVITY_BUSYIDLE;
106 type = SIPE_ACTIVITY_BUSY;
107 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_BRB) {
108 type = SIPE_ACTIVITY_DND;
109 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY2) {
110 type = SIPE_ACTIVITY_BRB;
111 } else if (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE) {
112 type = SIPE_ACTIVITY_AWAY;
113 } else {
114 type = SIPE_ACTIVITY_OFFLINE;
117 return(sipe_backend_activity_to_token(type));
120 const gchar *sipe_ocs2007_legacy_activity_description(guint availability)
122 if ((availability >= SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY) &&
123 (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_ON_PHONE)) {
124 return(sipe_core_activity_description(SIPE_ACTIVITY_INACTIVE));
125 } else if ((availability >= SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY) &&
126 (availability < SIPE_OCS2007_LEGACY_AVAILIBILITY_DND)) {
127 return(sipe_core_activity_description(SIPE_ACTIVITY_BUSYIDLE));
128 } else {
129 return(NULL);
134 * @param sipe_status_id (in)
135 * @param activity_token (out) [only sipe-ocs2005.c/send_presence_soap()
136 * requests this token]
138 #define SIPE_OCS2007_AVAILABILITY_UNKNOWN 0
139 #define SIPE_OCS2007_AVAILABILITY_ONLINE 3500
140 #define SIPE_OCS2007_AVAILABILITY_BUSY 6500
141 #define SIPE_OCS2007_AVAILABILITY_DND 9500 /* do not disturb */
142 #define SIPE_OCS2007_AVAILABILITY_BRB 12500 /* be right back */
143 #define SIPE_OCS2007_AVAILABILITY_AWAY 15500
144 #define SIPE_OCS2007_AVAILABILITY_OFFLINE 18500
145 guint sipe_ocs2007_availability_from_status(const gchar *sipe_status_id,
146 const gchar **activity_token)
148 guint availability;
149 guint activity;
151 if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_AWAY))) {
152 availability = SIPE_OCS2007_AVAILABILITY_AWAY;
153 activity = SIPE_ACTIVITY_AWAY;
154 } else if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_BRB))) {
155 availability = SIPE_OCS2007_AVAILABILITY_BRB;
156 activity = SIPE_ACTIVITY_BRB;
157 } else if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_DND))) {
158 availability = SIPE_OCS2007_AVAILABILITY_DND;
159 activity = SIPE_ACTIVITY_DND;
160 } else if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_BUSY))) {
161 availability = SIPE_OCS2007_AVAILABILITY_BUSY;
162 activity = SIPE_ACTIVITY_BUSY;
163 } else if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_AVAILABLE))) {
164 availability = SIPE_OCS2007_AVAILABILITY_ONLINE;
165 activity = SIPE_ACTIVITY_ONLINE;
166 } else if (sipe_strequal(sipe_status_id, sipe_backend_activity_to_token(SIPE_ACTIVITY_UNSET))) {
167 availability = SIPE_OCS2007_AVAILABILITY_UNKNOWN;
168 activity = SIPE_ACTIVITY_UNSET;
169 } else {
170 /* Offline or invisible */
171 availability = SIPE_OCS2007_AVAILABILITY_OFFLINE;
172 activity = SIPE_ACTIVITY_OFFLINE;
175 if (activity_token) {
176 *activity_token = sipe_backend_activity_to_token(activity);
179 return(availability);
182 gboolean sipe_ocs2007_status_is_busy(const gchar *status_id)
184 return(SIPE_OCS2007_AVAILABILITY_BUSY >=
185 sipe_ocs2007_availability_from_status(status_id, NULL));
189 gboolean sipe_ocs2007_availability_is_away2(guint availability)
191 return(availability >= SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY2);
194 static void send_presence_publish(struct sipe_core_private *sipe_private,
195 const char *publications);
197 static void free_publication(struct sipe_publication *publication)
199 g_free(publication->category);
200 g_free(publication->cal_event_hash);
201 g_free(publication->note);
203 g_free(publication->working_hours_xml_str);
204 g_free(publication->fb_start_str);
205 g_free(publication->free_busy_base64);
207 g_free(publication);
210 struct hash_table_delete_payload {
211 GHashTable *hash_table;
212 guint container;
215 static void sipe_remove_category_container_publications_cb(const gchar *name,
216 struct sipe_publication *publication,
217 struct hash_table_delete_payload *payload)
219 if (publication->container == payload->container) {
220 g_hash_table_remove(payload->hash_table, name);
224 static void sipe_remove_category_container_publications(GHashTable *our_publications,
225 const gchar *category,
226 guint container)
228 struct hash_table_delete_payload payload;
229 payload.hash_table = g_hash_table_lookup(our_publications, category);
231 if (!payload.hash_table) return;
233 payload.container = container;
234 g_hash_table_foreach(payload.hash_table,
235 (GHFunc)sipe_remove_category_container_publications_cb,
236 &payload);
239 /** MS-PRES container */
240 struct sipe_container {
241 guint id;
242 guint version;
243 GSList *members;
246 /** MS-PRES container member */
247 struct sipe_container_member {
248 /** user, domain, sameEnterprise, federated, publicCloud; everyone */
249 gchar *type;
250 gchar *value;
253 static const guint containers[] = {32000, 400, 300, 200, 100};
254 #define CONTAINERS_LEN (sizeof(containers) / sizeof(guint))
256 static void free_container_member(struct sipe_container_member *member)
258 if (!member) return;
260 g_free(member->type);
261 g_free(member->value);
262 g_free(member);
265 static void sipe_ocs2007_free_container(struct sipe_container *container)
267 GSList *entry;
269 if (!container) return;
271 entry = container->members;
272 while (entry) {
273 void *data = entry->data;
274 entry = g_slist_remove(entry, data);
275 free_container_member((struct sipe_container_member *)data);
277 g_free(container);
280 void sipe_core_buddy_menu_free(struct sipe_core_public *sipe_public)
282 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
283 GSList *entry = sipe_private->blist_menu_containers;
284 while (entry) {
285 sipe_ocs2007_free_container(entry->data);
286 entry = entry->next;
288 g_slist_free(sipe_private->blist_menu_containers);
289 sipe_private->blist_menu_containers = NULL;
292 static void blist_menu_remember_container(struct sipe_core_private *sipe_private,
293 struct sipe_container *container)
295 sipe_private->blist_menu_containers = g_slist_prepend(sipe_private->blist_menu_containers,
296 container);
299 static struct sipe_container *create_container(guint index,
300 const gchar *member_type,
301 const gchar *member_value,
302 gboolean is_group)
304 struct sipe_container *container = g_new0(struct sipe_container, 1);
305 struct sipe_container_member *member = g_new0(struct sipe_container_member, 1);
307 container->id = is_group ? (guint) -1 : containers[index];
308 container->members = g_slist_append(container->members, member);
309 member->type = g_strdup(member_type);
310 member->value = g_strdup(member_value);
312 return(container);
315 void sipe_ocs2007_free(struct sipe_core_private *sipe_private)
317 if (sipe_private->containers) {
318 GSList *entry = sipe_private->containers;
319 while (entry) {
320 sipe_ocs2007_free_container((struct sipe_container *)entry->data);
321 entry = entry->next;
324 g_slist_free(sipe_private->containers);
328 * Finds locally stored MS-PRES container member
330 static struct sipe_container_member *
331 sipe_find_container_member(struct sipe_container *container,
332 const gchar *type,
333 const gchar *value)
335 struct sipe_container_member *member;
336 GSList *entry;
338 if (container == NULL || type == NULL) {
339 return NULL;
342 entry = container->members;
343 while (entry) {
344 member = entry->data;
345 if (sipe_strcase_equal(member->type, type) &&
346 sipe_strcase_equal(member->value, value))
348 return member;
350 entry = entry->next;
352 return NULL;
356 * Finds locally stored MS-PRES container by id
358 static struct sipe_container *sipe_find_container(struct sipe_core_private *sipe_private,
359 guint id)
361 GSList *entry = sipe_private->containers;
362 while (entry) {
363 struct sipe_container *container = entry->data;
364 if (id == container->id) {
365 return container;
367 entry = entry->next;
369 return NULL;
372 static int sipe_find_member_access_level(struct sipe_core_private *sipe_private,
373 const gchar *type,
374 const gchar *value)
376 unsigned int i = 0;
377 const gchar *value_mod = value;
379 if (!type) return -1;
381 if (sipe_strequal("user", type)) {
382 value_mod = sipe_get_no_sip_uri(value);
385 for (i = 0; i < CONTAINERS_LEN; i++) {
386 struct sipe_container_member *member;
387 struct sipe_container *container = sipe_find_container(sipe_private, containers[i]);
388 if (!container) continue;
390 member = sipe_find_container_member(container, type, value_mod);
391 if (member) return containers[i];
394 return -1;
398 * Returns pointer to domain part in provided Email URL
400 * @param email an email URL. Example: first.last@hq.company.com
401 * @return pointer to domain part of email URL. Coresponding example: hq.company.com
403 * Doesn't allocate memory
405 static const gchar *sipe_get_domain(const gchar *email)
407 gchar *tmp;
409 if (!email) return NULL;
411 tmp = strstr(email, "@");
413 if (tmp && ((tmp+1) < (email + strlen(email)))) {
414 return tmp+1;
415 } else {
416 return NULL;
420 /* @TODO: replace with binary search for faster access? */
421 /** source: http://support.microsoft.com/kb/897567 */
422 static const gchar * const public_domains[] = {
423 "aol.com", "icq.com", "love.com", "mac.com", "br.live.com",
424 "hotmail.co.il", "hotmail.co.jp", "hotmail.co.th", "hotmail.co.uk",
425 "hotmail.com", "hotmail.com.ar", "hotmail.com.tr", "hotmail.es",
426 "hotmail.de", "hotmail.fr", "hotmail.it", "live.at", "live.be",
427 "live.ca", "live.cl", "live.cn", "live.co.in", "live.co.kr",
428 "live.co.uk", "live.co.za", "live.com", "live.com.ar", "live.com.au",
429 "live.com.co", "live.com.mx", "live.com.my", "live.com.pe",
430 "live.com.ph", "live.com.pk", "live.com.pt", "live.com.sg",
431 "live.com.ve", "live.de", "live.dk", "live.fr", "live.hk", "live.ie",
432 "live.in", "live.it", "live.jp", "live.nl", "live.no", "live.ph",
433 "live.ru", "live.se", "livemail.com.br", "livemail.tw",
434 "messengeruser.com", "msn.com", "passport.com", "sympatico.ca",
435 "tw.live.com", "webtv.net", "windowslive.com", "windowslive.es",
436 "yahoo.com",
437 NULL};
439 static gboolean sipe_is_public_domain(const gchar *domain)
441 int i = 0;
442 while (public_domains[i]) {
443 if (sipe_strcase_equal(public_domains[i], domain)) {
444 return TRUE;
446 i++;
448 return FALSE;
452 * Access Levels
453 * 32000 - Blocked
454 * 400 - Personal
455 * 300 - Team
456 * 200 - Company
457 * 100 - Public
459 const gchar *sipe_ocs2007_access_level_name(guint id)
461 switch (id) {
462 case 32000: return _("Blocked");
463 case 400: return _("Personal");
464 case 300: return _("Team");
465 case 200: return _("Company");
466 case 100: return _("Public");
468 return _("Unknown");
471 /** Member type: user, domain, sameEnterprise, federated, publicCloud; everyone */
472 int sipe_ocs2007_find_access_level(struct sipe_core_private *sipe_private,
473 const gchar *type,
474 const gchar *value,
475 gboolean *is_group_access)
477 int container_id = -1;
479 if (sipe_strequal("user", type)) {
480 const char *domain;
481 const char *no_sip_uri = sipe_get_no_sip_uri(value);
483 container_id = sipe_find_member_access_level(sipe_private, "user", no_sip_uri);
484 if (container_id >= 0) {
485 if (is_group_access) *is_group_access = FALSE;
486 return container_id;
489 domain = sipe_get_domain(no_sip_uri);
490 container_id = sipe_find_member_access_level(sipe_private, "domain", domain);
491 if (container_id >= 0) {
492 if (is_group_access) *is_group_access = TRUE;
493 return container_id;
496 container_id = sipe_find_member_access_level(sipe_private, "sameEnterprise", NULL);
497 if ((container_id >= 0) && sipe_strcase_equal(sipe_private->public.sip_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, "publicCloud", NULL);
503 if ((container_id >= 0) && sipe_is_public_domain(domain)) {
504 if (is_group_access) *is_group_access = TRUE;
505 return container_id;
508 container_id = sipe_find_member_access_level(sipe_private, "everyone", NULL);
509 if ((container_id >= 0)) {
510 if (is_group_access) *is_group_access = TRUE;
511 return container_id;
513 } else {
514 container_id = sipe_find_member_access_level(sipe_private, type, value);
515 if (is_group_access) *is_group_access = FALSE;
518 return container_id;
521 static GSList *get_access_domains(struct sipe_core_private *sipe_private)
523 struct sipe_container *container;
524 struct sipe_container_member *member;
525 GSList *entry;
526 GSList *entry2;
527 GSList *res = NULL;
529 entry = sipe_private->containers;
530 while (entry) {
531 container = entry->data;
533 entry2 = container->members;
534 while (entry2) {
535 member = entry2->data;
536 if (sipe_strcase_equal(member->type, "domain"))
538 res = slist_insert_unique_sorted(res, g_strdup(member->value), (GCompareFunc)g_ascii_strcasecmp);
540 entry2 = entry2->next;
542 entry = entry->next;
544 return res;
547 static void sipe_send_container_members_prepare(const guint container_id,
548 const guint container_version,
549 const gchar *action,
550 const gchar *type,
551 const gchar *value,
552 char **container_xmls)
554 gchar *value_str = value ? g_strdup_printf(" value=\"%s\"", value) : g_strdup("");
555 gchar *body;
557 if (!container_xmls) return;
559 body = g_strdup_printf(
560 "<container id=\"%d\" version=\"%d\"><member action=\"%s\" type=\"%s\"%s/></container>",
561 container_id,
562 container_version,
563 action,
564 type,
565 value_str);
566 g_free(value_str);
568 if ((*container_xmls) == NULL) {
569 *container_xmls = body;
570 } else {
571 char *tmp = *container_xmls;
573 *container_xmls = g_strconcat(*container_xmls, body, NULL);
574 g_free(tmp);
575 g_free(body);
579 static void sipe_send_set_container_members(struct sipe_core_private *sipe_private,
580 char *container_xmls)
582 gchar *self;
583 gchar *contact;
584 gchar *hdr;
585 gchar *body;
587 if (!container_xmls) return;
589 self = sip_uri_self(sipe_private);
590 body = g_strdup_printf(
591 "<setContainerMembers xmlns=\"http://schemas.microsoft.com/2006/09/sip/container-management\">"
592 "%s"
593 "</setContainerMembers>",
594 container_xmls);
596 contact = get_contact(sipe_private);
597 hdr = g_strdup_printf("Contact: %s\r\n"
598 "Content-Type: application/msrtc-setcontainermembers+xml\r\n", contact);
599 g_free(contact);
601 sip_transport_service(sipe_private,
602 self,
603 hdr,
604 body,
605 NULL);
607 g_free(hdr);
608 g_free(body);
609 g_free(self);
613 * @param container_id a new access level. If -1 then current access level
614 * is just removed (I.e. the member is removed from all containers).
615 * @param type a type of member. E.g. "user", "sameEnterprise", etc.
616 * @param value a value for member. E.g. SIP URI for "user" member type.
618 void sipe_ocs2007_change_access_level(struct sipe_core_private *sipe_private,
619 const int container_id,
620 const gchar *type,
621 const gchar *value)
623 unsigned int i;
624 int current_container_id = -1;
625 char *container_xmls = NULL;
627 /* for each container: find/delete */
628 for (i = 0; i < CONTAINERS_LEN; i++) {
629 struct sipe_container_member *member;
630 struct sipe_container *container = sipe_find_container(sipe_private, containers[i]);
632 if (!container) continue;
634 member = sipe_find_container_member(container, type, value);
635 if (member) {
636 current_container_id = containers[i];
637 /* delete/publish current access level */
638 if (container_id < 0 || container_id != current_container_id) {
639 sipe_send_container_members_prepare(current_container_id, container->version, "remove", type, value, &container_xmls);
640 /* remove member from our cache, to be able to recalculate AL below */
641 container->members = g_slist_remove(container->members, member);
642 current_container_id = -1;
647 /* recalculate AL below */
648 current_container_id = sipe_ocs2007_find_access_level(sipe_private, type, value, NULL);
650 /* assign/publish new access level */
651 if (container_id != current_container_id && container_id >= 0) {
652 struct sipe_container *container = sipe_find_container(sipe_private, container_id);
653 guint version = container ? container->version : 0;
655 sipe_send_container_members_prepare(container_id, version, "add", type, value, &container_xmls);
658 if (container_xmls) {
659 sipe_send_set_container_members(sipe_private, container_xmls);
661 g_free(container_xmls);
664 void sipe_core_change_access_level_from_container(struct sipe_core_public *sipe_public,
665 gpointer parameter)
667 struct sipe_container *container = parameter;
668 struct sipe_container_member *member;
670 if (!container || !container->members) return;
672 member = ((struct sipe_container_member *)container->members->data);
674 if (!member->type) return;
676 SIPE_DEBUG_INFO("sipe_ocs2007_change_access_level_from_container: container->id=%d, member->type=%s, member->value=%s",
677 container->id, member->type, member->value ? member->value : "");
679 sipe_ocs2007_change_access_level(SIPE_CORE_PRIVATE,
680 container->id,
681 member->type,
682 member->value);
686 void sipe_core_change_access_level_for_domain(struct sipe_core_public *sipe_public,
687 const gchar *domain,
688 guint index)
690 /* move Blocked first */
691 guint i = (index == 4) ? 0 : index + 1;
692 guint container_id = containers[i];
694 SIPE_DEBUG_INFO("sipe_core_change_access_level_from_id: domain=%s, container_id=(%d)%d",
695 domain ? domain : "", index, container_id);
697 sipe_ocs2007_change_access_level(SIPE_CORE_PRIVATE,
698 container_id,
699 "domain",
700 domain);
704 * Schedules process of self status publish
705 * based on own calendar information.
706 * Should be scheduled to the beginning of every
707 * 15 min interval, like:
708 * 13:00, 13:15, 13:30, 13:45, etc.
711 static void schedule_publish_update(struct sipe_core_private *sipe_private,
712 time_t calculate_from)
714 int interval = 5*60;
715 /** start of the beginning of closest 5 min interval. */
716 time_t next_start = ((time_t)((int)((int)calculate_from)/interval + 1)*interval);
718 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: calculate_from time: %s",
719 asctime(localtime(&calculate_from)));
720 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: next start time : %s",
721 asctime(localtime(&next_start)));
723 sipe_schedule_seconds(sipe_private,
724 "<+2007-cal-status>",
725 NULL,
726 next_start - time(NULL),
727 sipe_ocs2007_presence_publish,
728 NULL);
732 * An availability XML entry for SIPE_PUB_XML_STATE_CALENDAR
733 * @param availability (%d) Ex.: 6500
735 #define SIPE_PUB_XML_STATE_CALENDAR_AVAIL \
736 "<availability>%d</availability>"
738 * An activity XML entry for SIPE_PUB_XML_STATE_CALENDAR
739 * @param token (%s) Ex.: in-a-meeting
740 * @param minAvailability_attr (%s) Ex.: minAvailability="6500"
741 * @param maxAvailability_attr (%s) Ex.: maxAvailability="8999" or none
743 #define SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY \
744 "<activity token=\"%s\" %s %s></activity>"
746 * Publishes 'calendarState' category.
747 * @param instance (%u) Ex.: 1339299275
748 * @param version (%u) Ex.: 1
749 * @param uri (%s) Ex.: john@contoso.com
750 * @param start_time_str (%s) Ex.: 2008-01-11T19:00:00Z
751 * @param availability (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_AVAIL
752 * @param activity (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
753 * @param meeting_subject (%s) Ex.: Customer Meeting
754 * @param meeting_location (%s) Ex.: Conf Room 100
756 * @param instance (%u) Ex.: 1339299275
757 * @param version (%u) Ex.: 1
758 * @param uri (%s) Ex.: john@contoso.com
759 * @param start_time_str (%s) Ex.: 2008-01-11T19:00:00Z
760 * @param availability (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_AVAIL
761 * @param activity (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
762 * @param meeting_subject (%s) Ex.: Customer Meeting
763 * @param meeting_location (%s) Ex.: Conf Room 100
765 #define SIPE_PUB_XML_STATE_CALENDAR \
766 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
767 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" uri=\"%s\" startTime=\"%s\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"calendarState\">"\
768 "%s"\
769 "%s"\
770 "<endpointLocation/>"\
771 "<meetingSubject>%s</meetingSubject>"\
772 "<meetingLocation>%s</meetingLocation>"\
773 "</state>"\
774 "</publication>"\
775 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
776 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" uri=\"%s\" startTime=\"%s\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"calendarState\">"\
777 "%s"\
778 "%s"\
779 "<endpointLocation/>"\
780 "<meetingSubject>%s</meetingSubject>"\
781 "<meetingLocation>%s</meetingLocation>"\
782 "</state>"\
783 "</publication>"
785 * Publishes to clear 'calendarState' category
786 * @param instance (%u) Ex.: 1251210982
787 * @param version (%u) Ex.: 1
789 #define SIPE_PUB_XML_STATE_CALENDAR_CLEAR \
790 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"\
791 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"
794 * Publishes to clear any category
795 * @param category_name (%s) Ex.: state
796 * @param instance (%u) Ex.: 536870912
797 * @param container (%u) Ex.: 3
798 * @param version (%u) Ex.: 1
799 * @param expireType (%s) Ex.: static
801 #define SIPE_PUB_XML_PUBLICATION_CLEAR \
802 "<publication categoryName=\"%s\" instance=\"%u\" container=\"%u\" version=\"%u\" expireType=\"%s\" expires=\"0\"/>"
805 * Publishes 'note' category.
806 * @param instance (%u) Ex.: 2135971629; 0 for personal
807 * @param container (%u) Ex.: 200
808 * @param version (%u) Ex.: 2
809 * @param type (%s) Ex.: personal or OOF
810 * @param startTime_attr (%s) Ex.: startTime="2008-01-11T19:00:00Z"
811 * @param endTime_attr (%s) Ex.: endTime="2008-01-15T19:00:00Z"
812 * @param body (%s) Ex.: In the office
814 #define SIPE_PUB_XML_NOTE \
815 "<publication categoryName=\"note\" instance=\"%u\" container=\"%u\" version=\"%d\" expireType=\"static\">"\
816 "<note xmlns=\"http://schemas.microsoft.com/2006/09/sip/note\">"\
817 "<body type=\"%s\" uri=\"\"%s%s>%s</body>"\
818 "</note>"\
819 "</publication>"
822 * Only Busy and OOF calendar event are published.
823 * Different instances are used for that.
825 * Must be g_free'd after use.
827 static gchar *sipe_publish_get_category_state_calendar(struct sipe_core_private *sipe_private,
828 struct sipe_cal_event *event,
829 const char *uri,
830 int cal_satus)
832 gchar *start_time_str;
833 int availability = 0;
834 gchar *res;
835 gchar *tmp = NULL;
836 guint instance = (cal_satus == SIPE_CAL_OOF) ?
837 sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_CALENDAR_OOF) :
838 sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_CALENDAR);
840 /* key is <category><instance><container> */
841 gchar *key_2 = g_strdup_printf("<%s><%u><%u>", "state", instance, 2);
842 gchar *key_3 = g_strdup_printf("<%s><%u><%u>", "state", instance, 3);
843 struct sipe_publication *publication_2 =
844 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "state"), key_2);
845 struct sipe_publication *publication_3 =
846 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "state"), key_3);
848 g_free(key_2);
849 g_free(key_3);
851 if (!publication_3 && !event) { /* was nothing, have nothing, exiting */
852 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
853 "Exiting as no publication and no event for cal_satus:%d", cal_satus);
854 return NULL;
857 if (event &&
858 publication_3 &&
859 (publication_3->availability == availability) &&
860 sipe_strequal(publication_3->cal_event_hash, (tmp = sipe_cal_event_hash(event))))
862 g_free(tmp);
863 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
864 "cal state has NOT changed for cal_satus:%d. Exiting.", cal_satus);
865 return NULL; /* nothing to update */
867 g_free(tmp);
869 if (event &&
870 (event->cal_status == SIPE_CAL_BUSY ||
871 event->cal_status == SIPE_CAL_OOF))
873 gchar *availability_xml_str = NULL;
874 gchar *activity_xml_str = NULL;
875 gchar *escaped_subject = event->subject ? g_markup_escape_text(event->subject, -1) : NULL;
876 gchar *escaped_location = event->location ? g_markup_escape_text(event->location, -1) : NULL;
878 if (event->cal_status == SIPE_CAL_BUSY) {
879 availability_xml_str = g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_AVAIL,
880 SIPE_OCS2007_AVAILABILITY_BUSY);
883 if (event->cal_status == SIPE_CAL_BUSY && event->is_meeting) {
884 activity_xml_str = g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY,
885 sipe_backend_activity_to_token(SIPE_ACTIVITY_IN_MEETING),
886 "minAvailability=\"6500\"",
887 "maxAvailability=\"8999\"");
888 } else if (event->cal_status == SIPE_CAL_OOF) {
889 activity_xml_str = g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY,
890 sipe_backend_activity_to_token(SIPE_ACTIVITY_OOF),
891 "minAvailability=\"12000\"",
892 "");
894 start_time_str = sipe_utils_time_to_str(event->start_time);
896 res = g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR,
897 instance,
898 publication_2 ? publication_2->version : 0,
899 uri,
900 start_time_str,
901 availability_xml_str ? availability_xml_str : "",
902 activity_xml_str ? activity_xml_str : "",
903 escaped_subject ? escaped_subject : "",
904 escaped_location ? escaped_location : "",
906 instance,
907 publication_3 ? publication_3->version : 0,
908 uri,
909 start_time_str,
910 availability_xml_str ? availability_xml_str : "",
911 activity_xml_str ? activity_xml_str : "",
912 escaped_subject ? escaped_subject : "",
913 escaped_location ? escaped_location : ""
915 g_free(escaped_location);
916 g_free(escaped_subject);
917 g_free(start_time_str);
918 g_free(availability_xml_str);
919 g_free(activity_xml_str);
922 else /* including !event, SIPE_CAL_FREE, SIPE_CAL_TENTATIVE */
924 res = g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_CLEAR,
925 instance,
926 publication_2 ? publication_2->version : 0,
928 instance,
929 publication_3 ? publication_3->version : 0
933 return res;
937 * Returns 'note' XML part for publication.
938 * Must be g_free'd after use.
940 * Protocol format for Note is plain text.
942 * @param note a note in Sipe internal HTML format
943 * @param note_type either personal or OOF
945 static gchar *sipe_publish_get_category_note(struct sipe_core_private *sipe_private,
946 const char *note, /* html */
947 const char *note_type,
948 time_t note_start,
949 time_t note_end)
951 guint instance = sipe_strequal("OOF", note_type) ? sipe_get_pub_instance(sipe_private, SIPE_PUB_NOTE_OOF) : 0;
952 /* key is <category><instance><container> */
953 gchar *key_note_200 = g_strdup_printf("<%s><%u><%u>", "note", instance, 200);
954 gchar *key_note_300 = g_strdup_printf("<%s><%u><%u>", "note", instance, 300);
955 gchar *key_note_400 = g_strdup_printf("<%s><%u><%u>", "note", instance, 400);
957 struct sipe_publication *publication_note_200 =
958 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "note"), key_note_200);
959 struct sipe_publication *publication_note_300 =
960 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "note"), key_note_300);
961 struct sipe_publication *publication_note_400 =
962 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "note"), key_note_400);
964 char *tmp = note ? sipe_backend_markup_strip_html(note) : NULL;
965 char *n1 = tmp ? g_markup_escape_text(tmp, -1) : NULL;
966 const char *n2 = publication_note_200 ? publication_note_200->note : NULL;
967 char *res, *tmp1, *tmp2, *tmp3;
968 char *start_time_attr;
969 char *end_time_attr;
971 g_free(tmp);
972 tmp = NULL;
973 g_free(key_note_200);
974 g_free(key_note_300);
975 g_free(key_note_400);
977 /* we even need to republish empty note */
978 if (sipe_strequal(n1, n2))
980 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_note: note has NOT changed. Exiting.");
981 g_free(n1);
982 return NULL; /* nothing to update */
985 start_time_attr = note_start ? g_strdup_printf(" startTime=\"%s\"", (tmp = sipe_utils_time_to_str(note_start))) : NULL;
986 g_free(tmp);
987 tmp = NULL;
988 end_time_attr = note_end ? g_strdup_printf(" endTime=\"%s\"", (tmp = sipe_utils_time_to_str(note_end))) : NULL;
989 g_free(tmp);
991 if (n1) {
992 tmp1 = g_strdup_printf(SIPE_PUB_XML_NOTE,
993 instance,
994 200,
995 publication_note_200 ? publication_note_200->version : 0,
996 note_type,
997 start_time_attr ? start_time_attr : "",
998 end_time_attr ? end_time_attr : "",
999 n1);
1001 tmp2 = g_strdup_printf(SIPE_PUB_XML_NOTE,
1002 instance,
1003 300,
1004 publication_note_300 ? publication_note_300->version : 0,
1005 note_type,
1006 start_time_attr ? start_time_attr : "",
1007 end_time_attr ? end_time_attr : "",
1008 n1);
1010 tmp3 = g_strdup_printf(SIPE_PUB_XML_NOTE,
1011 instance,
1012 400,
1013 publication_note_400 ? publication_note_400->version : 0,
1014 note_type,
1015 start_time_attr ? start_time_attr : "",
1016 end_time_attr ? end_time_attr : "",
1017 n1);
1018 } else {
1019 tmp1 = g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR,
1020 "note",
1021 instance,
1022 200,
1023 publication_note_200 ? publication_note_200->version : 0,
1024 "static");
1025 tmp2 = g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR,
1026 "note",
1027 instance,
1028 300,
1029 publication_note_200 ? publication_note_200->version : 0,
1030 "static");
1031 tmp3 = g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR,
1032 "note",
1033 instance,
1034 400,
1035 publication_note_200 ? publication_note_200->version : 0,
1036 "static");
1038 res = g_strconcat(tmp1, tmp2, tmp3, NULL);
1040 g_free(start_time_attr);
1041 g_free(end_time_attr);
1042 g_free(tmp1);
1043 g_free(tmp2);
1044 g_free(tmp3);
1045 g_free(n1);
1047 return res;
1051 * Publishes 'calendarData' category's WorkingHours.
1053 * @param version (%u) Ex.: 1
1054 * @param email (%s) Ex.: alice@cosmo.local
1055 * @param working_hours_xml_str (%s) Ex.: <WorkingHours xmlns=.....
1057 * @param version (%u)
1059 * @param version (%u)
1060 * @param email (%s)
1061 * @param working_hours_xml_str (%s)
1063 * @param version (%u)
1064 * @param email (%s)
1065 * @param working_hours_xml_str (%s)
1067 * @param version (%u)
1068 * @param email (%s)
1069 * @param working_hours_xml_str (%s)
1071 * @param version (%u)
1073 #define SIPE_PUB_XML_WORKING_HOURS \
1074 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"1\" version=\"%d\" expireType=\"static\">"\
1075 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1076 "</calendarData>"\
1077 "</publication>"\
1078 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"100\" version=\"%d\" expireType=\"static\">"\
1079 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1080 "</publication>"\
1081 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"200\" version=\"%d\" expireType=\"static\">"\
1082 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1083 "</calendarData>"\
1084 "</publication>"\
1085 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"300\" version=\"%d\" expireType=\"static\">"\
1086 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1087 "</calendarData>"\
1088 "</publication>"\
1089 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"400\" version=\"%d\" expireType=\"static\">"\
1090 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1091 "</calendarData>"\
1092 "</publication>"\
1093 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"32000\" version=\"%d\" expireType=\"static\">"\
1094 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1095 "</publication>"
1098 * Returns 'calendarData' XML part with WorkingHours for publication.
1099 * Must be g_free'd after use.
1101 static gchar *sipe_publish_get_category_cal_working_hours(struct sipe_core_private *sipe_private)
1103 struct sipe_calendar* cal = sipe_private->calendar;
1105 /* key is <category><instance><container> */
1106 gchar *key_cal_1 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1);
1107 gchar *key_cal_100 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100);
1108 gchar *key_cal_200 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200);
1109 gchar *key_cal_300 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300);
1110 gchar *key_cal_400 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400);
1111 gchar *key_cal_32000 = g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000);
1113 struct sipe_publication *publication_cal_1 =
1114 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_1);
1115 struct sipe_publication *publication_cal_100 =
1116 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_100);
1117 struct sipe_publication *publication_cal_200 =
1118 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_200);
1119 struct sipe_publication *publication_cal_300 =
1120 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_300);
1121 struct sipe_publication *publication_cal_400 =
1122 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_400);
1123 struct sipe_publication *publication_cal_32000 =
1124 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_32000);
1126 const char *n1 = cal ? cal->working_hours_xml_str : NULL;
1127 const char *n2 = publication_cal_300 ? publication_cal_300->working_hours_xml_str : NULL;
1129 g_free(key_cal_1);
1130 g_free(key_cal_100);
1131 g_free(key_cal_200);
1132 g_free(key_cal_300);
1133 g_free(key_cal_400);
1134 g_free(key_cal_32000);
1136 if (!cal || is_empty(cal->email) || is_empty(cal->working_hours_xml_str)) {
1137 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_working_hours: no data to publish, exiting");
1138 return NULL;
1141 if (sipe_strequal(n1, n2))
1143 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_working_hours: WorkingHours has NOT changed. Exiting.");
1144 return NULL; /* nothing to update */
1147 return g_strdup_printf(SIPE_PUB_XML_WORKING_HOURS,
1148 /* 1 */
1149 publication_cal_1 ? publication_cal_1->version : 0,
1150 cal->email,
1151 cal->working_hours_xml_str,
1152 /* 100 - Public */
1153 publication_cal_100 ? publication_cal_100->version : 0,
1154 /* 200 - Company */
1155 publication_cal_200 ? publication_cal_200->version : 0,
1156 cal->email,
1157 cal->working_hours_xml_str,
1158 /* 300 - Team */
1159 publication_cal_300 ? publication_cal_300->version : 0,
1160 cal->email,
1161 cal->working_hours_xml_str,
1162 /* 400 - Personal */
1163 publication_cal_400 ? publication_cal_400->version : 0,
1164 cal->email,
1165 cal->working_hours_xml_str,
1166 /* 32000 - Blocked */
1167 publication_cal_32000 ? publication_cal_32000->version : 0
1172 * Publishes 'calendarData' category's FreeBusy.
1174 * @param instance (%u) Ex.: 1300372959
1175 * @param version (%u) Ex.: 1
1177 * @param instance (%u) Ex.: 1300372959
1178 * @param version (%u) Ex.: 1
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
1194 * @param email (%s) Ex.: alice@cosmo.local
1195 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1196 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1198 * @param instance (%u) Ex.: 1300372959
1199 * @param version (%u) Ex.: 1
1201 #define SIPE_PUB_XML_FREE_BUSY \
1202 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"1\" version=\"%d\" expireType=\"endpoint\">"\
1203 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1204 "</publication>"\
1205 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"100\" version=\"%d\" expireType=\"endpoint\">"\
1206 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1207 "</publication>"\
1208 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"200\" version=\"%d\" expireType=\"endpoint\">"\
1209 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1210 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1211 "</calendarData>"\
1212 "</publication>"\
1213 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"300\" version=\"%d\" expireType=\"endpoint\">"\
1214 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1215 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1216 "</calendarData>"\
1217 "</publication>"\
1218 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"400\" version=\"%d\" expireType=\"endpoint\">"\
1219 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1220 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1221 "</calendarData>"\
1222 "</publication>"\
1223 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"32000\" version=\"%d\" expireType=\"endpoint\">"\
1224 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1225 "</publication>"
1228 * Returns 'calendarData' XML part with FreeBusy for publication.
1229 * Must be g_free'd after use.
1231 static gchar *sipe_publish_get_category_cal_free_busy(struct sipe_core_private *sipe_private)
1233 struct sipe_calendar* cal = sipe_private->calendar;
1234 guint cal_data_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_CALENDAR_DATA);
1235 char *fb_start_str;
1236 char *free_busy_base64;
1237 /* const char *st; */
1238 /* const char *fb; */
1239 char *res;
1241 /* key is <category><instance><container> */
1242 gchar *key_cal_1 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 1);
1243 gchar *key_cal_100 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 100);
1244 gchar *key_cal_200 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 200);
1245 gchar *key_cal_300 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 300);
1246 gchar *key_cal_400 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 400);
1247 gchar *key_cal_32000 = g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 32000);
1249 struct sipe_publication *publication_cal_1 =
1250 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_1);
1251 struct sipe_publication *publication_cal_100 =
1252 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_100);
1253 struct sipe_publication *publication_cal_200 =
1254 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_200);
1255 struct sipe_publication *publication_cal_300 =
1256 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_300);
1257 struct sipe_publication *publication_cal_400 =
1258 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_400);
1259 struct sipe_publication *publication_cal_32000 =
1260 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "calendarData"), key_cal_32000);
1262 g_free(key_cal_1);
1263 g_free(key_cal_100);
1264 g_free(key_cal_200);
1265 g_free(key_cal_300);
1266 g_free(key_cal_400);
1267 g_free(key_cal_32000);
1269 if (!cal || is_empty(cal->email) || !cal->fb_start || is_empty(cal->free_busy)) {
1270 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_free_busy: no data to publish, exiting");
1271 return NULL;
1274 fb_start_str = sipe_utils_time_to_str(cal->fb_start);
1275 free_busy_base64 = sipe_cal_get_freebusy_base64(cal->free_busy);
1277 /* we will rebuplish the same data to refresh publication time,
1278 * so if data from multiple sources, most recent will be choosen
1280 // st = publication_cal_300 ? publication_cal_300->fb_start_str : NULL;
1281 // fb = publication_cal_300 ? publication_cal_300->free_busy_base64 : NULL;
1283 //if (sipe_strequal(st, fb_start_str) && sipe_strequal(fb, free_busy_base64))
1285 // SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_free_busy: FreeBusy has NOT changed. Exiting.");
1286 // g_free(fb_start_str);
1287 // g_free(free_busy_base64);
1288 // return NULL; /* nothing to update */
1291 res = g_strdup_printf(SIPE_PUB_XML_FREE_BUSY,
1292 /* 1 */
1293 cal_data_instance,
1294 publication_cal_1 ? publication_cal_1->version : 0,
1295 /* 100 - Public */
1296 cal_data_instance,
1297 publication_cal_100 ? publication_cal_100->version : 0,
1298 /* 200 - Company */
1299 cal_data_instance,
1300 publication_cal_200 ? publication_cal_200->version : 0,
1301 cal->email,
1302 fb_start_str,
1303 free_busy_base64,
1304 /* 300 - Team */
1305 cal_data_instance,
1306 publication_cal_300 ? publication_cal_300->version : 0,
1307 cal->email,
1308 fb_start_str,
1309 free_busy_base64,
1310 /* 400 - Personal */
1311 cal_data_instance,
1312 publication_cal_400 ? publication_cal_400->version : 0,
1313 cal->email,
1314 fb_start_str,
1315 free_busy_base64,
1316 /* 32000 - Blocked */
1317 cal_data_instance,
1318 publication_cal_32000 ? publication_cal_32000->version : 0
1321 g_free(fb_start_str);
1322 g_free(free_busy_base64);
1323 return res;
1328 * Publishes 'device' category.
1329 * @param instance (%u) Ex.: 1938468728
1330 * @param version (%u) Ex.: 1
1331 * @param endpointId (%s) Ex.: C707E38E-1E10-5413-94D9-ECAC260A0269
1332 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1333 * @param timezone (%s) Ex.: 00:00:00+01:00
1334 * @param machineName (%s) Ex.: BOSTON-OCS07
1336 #define SIPE_PUB_XML_DEVICE \
1337 "<publication categoryName=\"device\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
1338 "<device xmlns=\"http://schemas.microsoft.com/2006/09/sip/device\" endpointId=\"%s\">"\
1339 "<capabilities preferred=\"false\" uri=\"%s\">"\
1340 "<text capture=\"true\" render=\"true\" publish=\"false\"/>"\
1341 "<gifInk capture=\"false\" render=\"true\" publish=\"false\"/>"\
1342 "<isfInk capture=\"false\" render=\"true\" publish=\"false\"/>"\
1343 "</capabilities>"\
1344 "<timezone>%s</timezone>"\
1345 "<machineName>%s</machineName>"\
1346 "</device>"\
1347 "</publication>"
1350 * Returns 'device' XML part for publication.
1351 * Must be g_free'd after use.
1353 static gchar *sipe_publish_get_category_device(struct sipe_core_private *sipe_private)
1355 gchar *uri;
1356 gchar *doc;
1357 gchar *uuid = get_uuid(sipe_private);
1358 guint device_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_DEVICE);
1359 /* key is <category><instance><container> */
1360 gchar *key = g_strdup_printf("<%s><%u><%u>", "device", device_instance, 2);
1361 struct sipe_publication *publication =
1362 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "device"), key);
1364 g_free(key);
1366 uri = sip_uri_self(sipe_private);
1367 doc = g_strdup_printf(SIPE_PUB_XML_DEVICE,
1368 device_instance,
1369 publication ? publication->version : 0,
1370 uuid,
1371 uri,
1372 "00:00:00+01:00", /* @TODO make timezone real*/
1373 g_get_host_name()
1376 g_free(uri);
1377 g_free(uuid);
1379 return doc;
1383 * Publishes 'machineState' category.
1384 * @param instance (%u) Ex.: 926460663
1385 * @param version (%u) Ex.: 22
1386 * @param availability (%d) Ex.: 3500
1387 * @param instance (%u) Ex.: 926460663
1388 * @param version (%u) Ex.: 22
1389 * @param availability (%d) Ex.: 3500
1391 #define SIPE_PUB_XML_STATE_MACHINE \
1392 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" 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>"\
1398 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
1399 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"machineState\">"\
1400 "<availability>%d</availability>"\
1401 "<endpointLocation/>"\
1402 "</state>"\
1403 "</publication>"
1406 * Publishes 'userState' category.
1407 * @param instance (%u) User. Ex.: 536870912
1408 * @param version (%u) User Container 2. Ex.: 22
1409 * @param availability (%d) User Container 2. Ex.: 15500
1410 * @param instance (%u) User. Ex.: 536870912
1411 * @param version (%u) User Container 3.Ex.: 22
1412 * @param availability (%d) User Container 3. Ex.: 15500
1414 #define SIPE_PUB_XML_STATE_USER \
1415 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" 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>"\
1421 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"static\">"\
1422 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"true\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"userState\">"\
1423 "<availability>%d</availability>"\
1424 "<endpointLocation/>"\
1425 "</state>"\
1426 "</publication>"
1429 * A service method - use
1430 * - send_publish_get_category_state_machine and
1431 * - send_publish_get_category_state_user instead.
1432 * Must be g_free'd after use.
1434 static gchar *sipe_publish_get_category_state(struct sipe_core_private *sipe_private,
1435 gboolean is_user_state)
1437 int availability = sipe_ocs2007_availability_from_status(sipe_private->status, NULL);
1438 guint instance = is_user_state ? sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_USER) :
1439 sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_MACHINE);
1440 /* key is <category><instance><container> */
1441 gchar *key_2 = g_strdup_printf("<%s><%u><%u>", "state", instance, 2);
1442 gchar *key_3 = g_strdup_printf("<%s><%u><%u>", "state", instance, 3);
1443 struct sipe_publication *publication_2 =
1444 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "state"), key_2);
1445 struct sipe_publication *publication_3 =
1446 g_hash_table_lookup(g_hash_table_lookup(sipe_private->our_publications, "state"), key_3);
1448 g_free(key_2);
1449 g_free(key_3);
1451 if (publication_2 && (publication_2->availability == availability))
1453 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_state: state has NOT changed. Exiting.");
1454 return NULL; /* nothing to update */
1457 return g_strdup_printf( is_user_state ? SIPE_PUB_XML_STATE_USER : SIPE_PUB_XML_STATE_MACHINE,
1458 instance,
1459 publication_2 ? publication_2->version : 0,
1460 availability,
1461 instance,
1462 publication_3 ? publication_3->version : 0,
1463 availability);
1467 * Returns 'machineState' XML part for publication.
1468 * Must be g_free'd after use.
1470 static gchar *sipe_publish_get_category_state_machine(struct sipe_core_private *sipe_private)
1472 return sipe_publish_get_category_state(sipe_private, FALSE);
1476 * Returns 'userState' XML part for publication.
1477 * Must be g_free'd after use.
1479 static gchar *sipe_publish_get_category_state_user(struct sipe_core_private *sipe_private)
1481 return sipe_publish_get_category_state(sipe_private, TRUE);
1484 static void send_publish_category_initial(struct sipe_core_private *sipe_private)
1486 gchar *pub_device = sipe_publish_get_category_device(sipe_private);
1487 gchar *pub_machine;
1488 gchar *publications;
1490 sipe_status_set_activity(sipe_private, SIPE_ACTIVITY_AVAILABLE);
1492 pub_machine = sipe_publish_get_category_state_machine(sipe_private);
1493 publications = g_strdup_printf("%s%s",
1494 pub_device,
1495 pub_machine ? pub_machine : "");
1496 g_free(pub_device);
1497 g_free(pub_machine);
1499 send_presence_publish(sipe_private, publications);
1500 g_free(publications);
1503 static gboolean process_send_presence_category_publish_response(struct sipe_core_private *sipe_private,
1504 struct sipmsg *msg,
1505 struct transaction *trans)
1507 const gchar *contenttype = sipmsg_find_header(msg, "Content-Type");
1509 if (msg->response == 409 && g_str_has_prefix(contenttype, "application/msrtc-fault+xml")) {
1510 sipe_xml *xml;
1511 const sipe_xml *node;
1512 gchar *fault_code;
1513 GHashTable *faults;
1514 int index_our;
1515 gboolean has_device_publication = FALSE;
1517 xml = sipe_xml_parse(msg->body, msg->bodylen);
1519 /* test if version mismatch fault */
1520 fault_code = sipe_xml_data(sipe_xml_child(xml, "Faultcode"));
1521 if (!sipe_strequal(fault_code, "Client.BadCall.WrongDelta")) {
1522 SIPE_DEBUG_INFO("process_send_presence_category_publish_response: unsupported fault code:%s returning.", fault_code);
1523 g_free(fault_code);
1524 sipe_xml_free(xml);
1525 return TRUE;
1527 g_free(fault_code);
1529 /* accumulating information about faulty versions */
1530 faults = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
1531 for (node = sipe_xml_child(xml, "details/operation");
1532 node;
1533 node = sipe_xml_twin(node))
1535 const gchar *index = sipe_xml_attribute(node, "index");
1536 const gchar *curVersion = sipe_xml_attribute(node, "curVersion");
1538 g_hash_table_insert(faults, g_strdup(index), g_strdup(curVersion));
1539 SIPE_DEBUG_INFO("fault added: index:%s curVersion:%s", index, curVersion);
1541 sipe_xml_free(xml);
1543 /* here we are parsing our own request to figure out what publication
1544 * referenced here only by index went wrong
1546 xml = sipe_xml_parse(trans->msg->body, trans->msg->bodylen);
1548 /* publication */
1549 for (node = sipe_xml_child(xml, "publications/publication"),
1550 index_our = 1; /* starts with 1 - our first publication */
1551 node;
1552 node = sipe_xml_twin(node), index_our++)
1554 gchar *idx = g_strdup_printf("%d", index_our);
1555 const gchar *curVersion = g_hash_table_lookup(faults, idx);
1556 const gchar *categoryName = sipe_xml_attribute(node, "categoryName");
1557 g_free(idx);
1559 if (sipe_strequal("device", categoryName)) {
1560 has_device_publication = TRUE;
1563 if (curVersion) { /* fault exist on this index */
1564 const gchar *container = sipe_xml_attribute(node, "container");
1565 const gchar *instance = sipe_xml_attribute(node, "instance");
1566 /* key is <category><instance><container> */
1567 gchar *key = g_strdup_printf("<%s><%s><%s>", categoryName, instance, container);
1568 GHashTable *category = g_hash_table_lookup(sipe_private->our_publications, categoryName);
1570 if (category) {
1571 struct sipe_publication *publication =
1572 g_hash_table_lookup(category, key);
1574 SIPE_DEBUG_INFO("key is %s", key);
1576 if (publication) {
1577 SIPE_DEBUG_INFO("Updating %s with version %s. Was %d before.",
1578 key, curVersion, publication->version);
1579 /* updating publication's version to the correct one */
1580 publication->version = atoi(curVersion);
1582 } else {
1583 /* We somehow lost this category from our publications... */
1584 struct sipe_publication *publication = g_new0(struct sipe_publication, 1);
1585 publication->category = g_strdup(categoryName);
1586 publication->instance = atoi(instance);
1587 publication->container = atoi(container);
1588 publication->version = atoi(curVersion);
1589 category = g_hash_table_new_full(g_str_hash, g_str_equal,
1590 g_free, (GDestroyNotify)free_publication);
1591 g_hash_table_insert(category, g_strdup(key), publication);
1592 g_hash_table_insert(sipe_private->our_publications, g_strdup(categoryName), category);
1593 SIPE_DEBUG_INFO("added lost category '%s' key '%s'", categoryName, key);
1595 g_free(key);
1598 sipe_xml_free(xml);
1599 g_hash_table_destroy(faults);
1601 /* rebublishing with right versions */
1602 if (has_device_publication) {
1603 send_publish_category_initial(sipe_private);
1604 } else {
1605 sipe_status_update(sipe_private, NULL);
1608 return TRUE;
1612 * Publishes categories.
1613 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1614 * @param publications (%s) XML publications
1616 #define SIPE_SEND_PRESENCE \
1617 "<publish xmlns=\"http://schemas.microsoft.com/2006/09/sip/rich-presence\">"\
1618 "<publications uri=\"%s\">"\
1619 "%s"\
1620 "</publications>"\
1621 "</publish>"
1623 static void send_presence_publish(struct sipe_core_private *sipe_private,
1624 const char *publications)
1626 gchar *uri;
1627 gchar *doc;
1628 gchar *tmp;
1629 gchar *hdr;
1631 uri = sip_uri_self(sipe_private);
1632 doc = g_strdup_printf(SIPE_SEND_PRESENCE,
1633 uri,
1634 publications);
1636 tmp = get_contact(sipe_private);
1637 hdr = g_strdup_printf("Contact: %s\r\n"
1638 "Content-Type: application/msrtc-category-publish+xml\r\n", tmp);
1640 sip_transport_service(sipe_private,
1641 uri,
1642 hdr,
1643 doc,
1644 process_send_presence_category_publish_response);
1646 g_free(tmp);
1647 g_free(hdr);
1648 g_free(uri);
1649 g_free(doc);
1653 * Publishes self status
1654 * based on own calendar information.
1656 void sipe_ocs2007_presence_publish(struct sipe_core_private *sipe_private,
1657 SIPE_UNUSED_PARAMETER void *unused)
1659 struct sipe_calendar* cal = sipe_private->calendar;
1660 struct sipe_cal_event* event = NULL;
1661 gchar *pub_cal_working_hours = NULL;
1662 gchar *pub_cal_free_busy = NULL;
1663 gchar *pub_calendar = NULL;
1664 gchar *pub_calendar2 = NULL;
1665 gchar *pub_oof_note = NULL;
1666 const gchar *oof_note;
1667 time_t oof_start = 0;
1668 time_t oof_end = 0;
1670 if (!cal) {
1671 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() no calendar data.");
1672 return;
1675 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() started.");
1676 if (cal->cal_events) {
1677 event = sipe_cal_get_event(cal->cal_events, time(NULL));
1680 if (!event) {
1681 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: current event is NULL");
1682 } else {
1683 char *desc = sipe_cal_event_describe(event);
1684 SIPE_DEBUG_INFO("publish_calendar_status_self: current event is:\n%s", desc ? desc : "");
1685 g_free(desc);
1688 /* Logic
1689 if OOF
1690 OOF publish, Busy clean
1691 ilse if Busy
1692 OOF clean, Busy publish
1693 else
1694 OOF clean, Busy clean
1696 if (event && event->cal_status == SIPE_CAL_OOF) {
1697 pub_calendar = sipe_publish_get_category_state_calendar(sipe_private, event, cal->email, SIPE_CAL_OOF);
1698 pub_calendar2 = sipe_publish_get_category_state_calendar(sipe_private, NULL, cal->email, SIPE_CAL_BUSY);
1699 } else if (event && event->cal_status == SIPE_CAL_BUSY) {
1700 pub_calendar = sipe_publish_get_category_state_calendar(sipe_private, NULL, cal->email, SIPE_CAL_OOF);
1701 pub_calendar2 = sipe_publish_get_category_state_calendar(sipe_private, event, cal->email, SIPE_CAL_BUSY);
1702 } else {
1703 pub_calendar = sipe_publish_get_category_state_calendar(sipe_private, NULL, cal->email, SIPE_CAL_OOF);
1704 pub_calendar2 = sipe_publish_get_category_state_calendar(sipe_private, NULL, cal->email, SIPE_CAL_BUSY);
1707 oof_note = sipe_ews_get_oof_note(cal);
1708 if (sipe_strequal("Scheduled", cal->oof_state)) {
1709 oof_start = cal->oof_start;
1710 oof_end = cal->oof_end;
1712 pub_oof_note = sipe_publish_get_category_note(sipe_private, oof_note, "OOF", oof_start, oof_end);
1714 pub_cal_working_hours = sipe_publish_get_category_cal_working_hours(sipe_private);
1715 pub_cal_free_busy = sipe_publish_get_category_cal_free_busy(sipe_private);
1717 if (!pub_cal_working_hours && !pub_cal_free_busy && !pub_calendar && !pub_calendar2 && !pub_oof_note) {
1718 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: nothing has changed.");
1719 } else {
1720 gchar *publications = g_strdup_printf("%s%s%s%s%s",
1721 pub_cal_working_hours ? pub_cal_working_hours : "",
1722 pub_cal_free_busy ? pub_cal_free_busy : "",
1723 pub_calendar ? pub_calendar : "",
1724 pub_calendar2 ? pub_calendar2 : "",
1725 pub_oof_note ? pub_oof_note : "");
1727 send_presence_publish(sipe_private, publications);
1728 g_free(publications);
1731 g_free(pub_cal_working_hours);
1732 g_free(pub_cal_free_busy);
1733 g_free(pub_calendar);
1734 g_free(pub_calendar2);
1735 g_free(pub_oof_note);
1737 /* repeat scheduling */
1738 schedule_publish_update(sipe_private, time(NULL));
1741 void sipe_ocs2007_category_publish(struct sipe_core_private *sipe_private)
1743 gchar *pub_state = sipe_status_changed_by_user(sipe_private) ?
1744 sipe_publish_get_category_state_user(sipe_private) :
1745 sipe_publish_get_category_state_machine(sipe_private);
1746 gchar *pub_note = sipe_publish_get_category_note(sipe_private,
1747 sipe_private->note,
1748 SIPE_CORE_PRIVATE_FLAG_IS(OOF_NOTE) ? "OOF" : "personal",
1751 gchar *publications;
1753 if (!pub_state && !pub_note) {
1754 SIPE_DEBUG_INFO_NOFORMAT("sipe_osc2007_category_publish: nothing has changed. Exiting.");
1755 return;
1758 publications = g_strdup_printf("%s%s",
1759 pub_state ? pub_state : "",
1760 pub_note ? pub_note : "");
1762 g_free(pub_state);
1763 g_free(pub_note);
1765 send_presence_publish(sipe_private, publications);
1766 g_free(publications);
1769 static void sipe_publish_get_cat_state_user_to_clear(SIPE_UNUSED_PARAMETER const char *name,
1770 gpointer value,
1771 GString* str)
1773 struct sipe_publication *publication = value;
1775 g_string_append_printf( str,
1776 SIPE_PUB_XML_PUBLICATION_CLEAR,
1777 publication->category,
1778 publication->instance,
1779 publication->container,
1780 publication->version,
1781 "static");
1784 void sipe_ocs2007_reset_status(struct sipe_core_private *sipe_private)
1786 GString* str;
1787 gchar *publications;
1789 if (!sipe_private->user_state_publications || g_hash_table_size(sipe_private->user_state_publications) == 0) {
1790 SIPE_DEBUG_INFO_NOFORMAT("sipe_reset_status: no userState publications, exiting.");
1791 return;
1794 str = g_string_new(NULL);
1795 g_hash_table_foreach(sipe_private->user_state_publications, (GHFunc)sipe_publish_get_cat_state_user_to_clear, str);
1796 publications = g_string_free(str, FALSE);
1798 send_presence_publish(sipe_private, publications);
1799 g_free(publications);
1802 /* key is <category><instance><container> */
1803 static gboolean sipe_is_our_publication(struct sipe_core_private *sipe_private,
1804 const gchar *key)
1806 GSList *entry;
1808 /* filling keys for our publications if not yet cached */
1809 if (!sipe_private->our_publication_keys) {
1810 guint device_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_DEVICE);
1811 guint machine_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_MACHINE);
1812 guint user_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_USER);
1813 guint calendar_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_CALENDAR);
1814 guint cal_oof_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_STATE_CALENDAR_OOF);
1815 guint cal_data_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_CALENDAR_DATA);
1816 guint note_oof_instance = sipe_get_pub_instance(sipe_private, SIPE_PUB_NOTE_OOF);
1818 SIPE_DEBUG_INFO_NOFORMAT("* Our Publication Instances *");
1819 SIPE_DEBUG_INFO("\tDevice : %u\t0x%08X", device_instance, device_instance);
1820 SIPE_DEBUG_INFO("\tMachine State : %u\t0x%08X", machine_instance, machine_instance);
1821 SIPE_DEBUG_INFO("\tUser Stare : %u\t0x%08X", user_instance, user_instance);
1822 SIPE_DEBUG_INFO("\tCalendar State : %u\t0x%08X", calendar_instance, calendar_instance);
1823 SIPE_DEBUG_INFO("\tCalendar OOF State : %u\t0x%08X", cal_oof_instance, cal_oof_instance);
1824 SIPE_DEBUG_INFO("\tCalendar FreeBusy : %u\t0x%08X", cal_data_instance, cal_data_instance);
1825 SIPE_DEBUG_INFO("\tOOF Note : %u\t0x%08X", note_oof_instance, note_oof_instance);
1826 SIPE_DEBUG_INFO("\tNote : %u", 0);
1827 SIPE_DEBUG_INFO("\tCalendar WorkingHours: %u", 0);
1829 /* device */
1830 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1831 g_strdup_printf("<%s><%u><%u>", "device", device_instance, 2));
1833 /* state:machineState */
1834 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1835 g_strdup_printf("<%s><%u><%u>", "state", machine_instance, 2));
1836 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1837 g_strdup_printf("<%s><%u><%u>", "state", machine_instance, 3));
1839 /* state:userState */
1840 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1841 g_strdup_printf("<%s><%u><%u>", "state", user_instance, 2));
1842 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1843 g_strdup_printf("<%s><%u><%u>", "state", user_instance, 3));
1845 /* state:calendarState */
1846 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1847 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance, 2));
1848 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1849 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance, 3));
1851 /* state:calendarState OOF */
1852 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1853 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance, 2));
1854 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1855 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance, 3));
1857 /* note */
1858 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1859 g_strdup_printf("<%s><%u><%u>", "note", 0, 200));
1860 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1861 g_strdup_printf("<%s><%u><%u>", "note", 0, 300));
1862 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1863 g_strdup_printf("<%s><%u><%u>", "note", 0, 400));
1865 /* note OOF */
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, 200));
1868 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1869 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance, 300));
1870 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1871 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance, 400));
1873 /* calendarData:WorkingHours */
1874 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1875 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1));
1876 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1877 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100));
1878 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1879 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200));
1880 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1881 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300));
1882 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1883 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400));
1884 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1885 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000));
1887 /* calendarData:FreeBusy */
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, 1));
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, 100));
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, 200));
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, 300));
1896 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1897 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 400));
1898 sipe_private->our_publication_keys = g_slist_append(sipe_private->our_publication_keys,
1899 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance, 32000));
1901 //SIPE_DEBUG_INFO("sipe_is_our_publication: sipe_private->our_publication_keys length=%d",
1902 // sipe_private->our_publication_keys ? (int) g_slist_length(sipe_private->our_publication_keys) : -1);
1905 //SIPE_DEBUG_INFO("sipe_is_our_publication: key=%s", key);
1907 entry = sipe_private->our_publication_keys;
1908 while (entry) {
1909 //SIPE_DEBUG_INFO(" sipe_is_our_publication: entry->data=%s", entry->data);
1910 if (sipe_strequal(entry->data, key)) {
1911 return TRUE;
1913 entry = entry->next;
1915 return FALSE;
1918 static void sipe_refresh_blocked_status_cb(char *buddy_name,
1919 SIPE_UNUSED_PARAMETER struct sipe_buddy *buddy,
1920 struct sipe_core_private *sipe_private)
1922 int container_id = sipe_ocs2007_find_access_level(sipe_private, "user", buddy_name, NULL);
1923 gboolean blocked = (container_id == 32000);
1924 gboolean blocked_in_blist = sipe_backend_buddy_is_blocked(SIPE_CORE_PUBLIC, buddy_name);
1926 /* SIPE_DEBUG_INFO("sipe_refresh_blocked_status_cb: buddy_name=%s, blocked=%s, blocked_in_blist=%s",
1927 buddy_name, blocked ? "T" : "F", blocked_in_blist ? "T" : "F"); */
1929 if (blocked != blocked_in_blist) {
1930 sipe_backend_buddy_set_blocked_status(SIPE_CORE_PUBLIC, buddy_name, blocked);
1934 static void sipe_refresh_blocked_status(struct sipe_core_private *sipe_private)
1936 g_hash_table_foreach(sipe_private->buddies,
1937 (GHFunc) sipe_refresh_blocked_status_cb,
1938 sipe_private);
1942 * When we receive some self (BE) NOTIFY with a new subscriber
1943 * we sends a setSubscribers request to him [SIP-PRES] 4.8
1946 void sipe_ocs2007_process_roaming_self(struct sipe_core_private *sipe_private,
1947 struct sipmsg *msg)
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(sipe_private->our_publications, category);
1987 if (cat_publications) {
1988 g_hash_table_remove(sipe_private->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(sipe_private->our_publications, name);
2009 /* Ex. clear note: <category name="note"/> */
2010 if (container == (guint)-1) {
2011 g_free(sipe_private->note);
2012 sipe_private->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(sipe_private->note);
2021 sipe_private->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 sipe_private->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 (!sipe_private->user_state_publications) {
2046 sipe_private->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(sipe_private->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(sipe_private->note);
2110 sipe_private->note = NULL;
2111 sipe_private->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 >= sipe_private->note_since) {
2124 g_free(sipe_private->note);
2125 sipe_private->note = g_strdup(publication->note);
2126 sipe_private->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(sipe_private->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 (!sipe_private->csta &&
2183 sipe_strequal(name, "userProperties")) {
2184 const sipe_xml *line;
2185 /* line, for Remote Call Control (RCC) */
2186 for (line = sipe_xml_child(node, "userProperties/lines/line"); line; line = sipe_xml_twin(line)) {
2187 const gchar *line_server = sipe_xml_attribute(line, "lineServer");
2188 const gchar *line_type = sipe_xml_attribute(line, "lineType");
2189 gchar *line_uri;
2191 if (!line_server || !(sipe_strequal(line_type, "Rcc") || sipe_strequal(line_type, "Dual"))) continue;
2193 line_uri = sipe_xml_data(line);
2194 if (line_uri) {
2195 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: line_uri=%s server=%s", line_uri, line_server);
2196 sip_csta_open(sipe_private, line_uri, line_server);
2198 g_free(line_uri);
2200 break;
2204 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sipe_private->our_publications size=%d",
2205 sipe_private->our_publications ? (int) g_hash_table_size(sipe_private->our_publications) : -1);
2207 /* active clients for user account */
2208 if (g_hash_table_size(devices) > 1) {
2209 SIPE_CORE_PRIVATE_FLAG_SET(MPOP);
2210 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: multiple clients detected (%d)",
2211 g_hash_table_size(devices));
2212 } else {
2213 SIPE_CORE_PRIVATE_FLAG_UNSET(MPOP);
2214 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self: single client detected");
2216 g_hash_table_destroy(devices);
2218 /* containers */
2219 for (node = sipe_xml_child(xml, "containers/container"); node; node = sipe_xml_twin(node)) {
2220 guint id = sipe_xml_int_attribute(node, "id", 0);
2221 struct sipe_container *container = sipe_find_container(sipe_private, id);
2223 if (container) {
2224 sipe_private->containers = g_slist_remove(sipe_private->containers, container);
2225 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removed existing container id=%d v%d", container->id, container->version);
2226 sipe_ocs2007_free_container(container);
2228 container = g_new0(struct sipe_container, 1);
2229 container->id = id;
2230 container->version = sipe_xml_int_attribute(node, "version", 0);
2231 sipe_private->containers = g_slist_append(sipe_private->containers, container);
2232 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container id=%d v%d", container->id, container->version);
2234 for (node2 = sipe_xml_child(node, "member"); node2; node2 = sipe_xml_twin(node2)) {
2235 struct sipe_container_member *member = g_new0(struct sipe_container_member, 1);
2236 member->type = g_strdup(sipe_xml_attribute(node2, "type"));
2237 member->value = g_strdup(sipe_xml_attribute(node2, "value"));
2238 container->members = g_slist_append(container->members, member);
2239 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container member type=%s value=%s",
2240 member->type, member->value ? member->value : "");
2244 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: access_level_set=%s",
2245 SIPE_CORE_PRIVATE_FLAG_IS(ACCESS_LEVEL_SET) ? "TRUE" : "FALSE");
2246 if (!SIPE_CORE_PRIVATE_FLAG_IS(ACCESS_LEVEL_SET) && sipe_xml_child(xml, "containers")) {
2247 char *container_xmls = NULL;
2248 int sameEnterpriseAL = sipe_ocs2007_find_access_level(sipe_private, "sameEnterprise", NULL, NULL);
2249 int federatedAL = sipe_ocs2007_find_access_level(sipe_private, "federated", NULL, NULL);
2251 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sameEnterpriseAL=%d", sameEnterpriseAL);
2252 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: federatedAL=%d", federatedAL);
2253 /* initial set-up to let counterparties see your status */
2254 if (sameEnterpriseAL < 0) {
2255 struct sipe_container *container = sipe_find_container(sipe_private, 200);
2256 guint version = container ? container->version : 0;
2257 sipe_send_container_members_prepare(200, version, "add", "sameEnterprise", NULL, &container_xmls);
2259 if (federatedAL < 0) {
2260 struct sipe_container *container = sipe_find_container(sipe_private, 100);
2261 guint version = container ? container->version : 0;
2262 sipe_send_container_members_prepare(100, version, "add", "federated", NULL, &container_xmls);
2264 SIPE_CORE_PRIVATE_FLAG_SET(ACCESS_LEVEL_SET);
2266 if (container_xmls) {
2267 sipe_send_set_container_members(sipe_private, container_xmls);
2269 g_free(container_xmls);
2272 /* Refresh contacts' blocked status */
2273 sipe_refresh_blocked_status(sipe_private);
2275 /* subscribers */
2276 for (node = sipe_xml_child(xml, "subscribers/subscriber"); node; node = sipe_xml_twin(node)) {
2277 const char *user;
2278 const char *acknowledged;
2279 gchar *hdr;
2280 gchar *body;
2282 user = sipe_xml_attribute(node, "user"); /* without 'sip:' prefix */
2283 if (!user) continue;
2284 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user %s", user);
2285 display_name = g_strdup(sipe_xml_attribute(node, "displayName"));
2286 uri = sip_uri_from_name(user);
2288 sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_DISPLAY_NAME, display_name);
2290 acknowledged= sipe_xml_attribute(node, "acknowledged");
2291 if(sipe_strcase_equal(acknowledged,"false")){
2292 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user added you %s", user);
2293 if (!sipe_backend_buddy_find(SIPE_CORE_PUBLIC, uri, NULL)) {
2294 sipe_backend_buddy_request_add(SIPE_CORE_PUBLIC, uri, display_name);
2297 hdr = g_strdup_printf(
2298 "Contact: %s\r\n"
2299 "Content-Type: application/msrtc-presence-setsubscriber+xml\r\n", contact);
2301 body = g_strdup_printf(
2302 "<setSubscribers xmlns=\"http://schemas.microsoft.com/2006/09/sip/presence-subscribers\">"
2303 "<subscriber user=\"%s\" acknowledged=\"true\"/>"
2304 "</setSubscribers>", user);
2306 sip_transport_service(sipe_private,
2308 hdr,
2309 body,
2310 NULL);
2311 g_free(body);
2312 g_free(hdr);
2314 g_free(display_name);
2315 g_free(uri);
2318 g_free(contact);
2319 sipe_xml_free(xml);
2321 /* Publish initial state if not yet.
2322 * Assuming this happens on initial responce to subscription to roaming-self
2323 * so we've already updated our roaming data in full.
2324 * Only for 2007+
2326 if (!SIPE_CORE_PRIVATE_FLAG_IS(INITIAL_PUBLISH)) {
2327 send_publish_category_initial(sipe_private);
2328 sipe_groupchat_init(sipe_private);
2329 SIPE_CORE_PRIVATE_FLAG_SET(INITIAL_PUBLISH);
2330 /* dalayed run */
2331 sipe_cal_delayed_calendar_update(sipe_private);
2332 do_update_status = FALSE;
2333 } else if (aggreg_avail) {
2335 if (aggreg_avail &&
2336 (aggreg_avail < SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE)) {
2337 /* not offline */
2338 sipe_status_set_token(sipe_private,
2339 sipe_ocs2007_status_from_legacy_availability(aggreg_avail));
2340 } else {
2341 /* do not let offline status switch us off */
2342 sipe_status_set_activity(sipe_private,
2343 SIPE_ACTIVITY_INVISIBLE);
2347 if (do_update_status) {
2348 sipe_status_and_note(sipe_private, NULL);
2351 g_free(to);
2355 * for Access levels menu
2357 #define INDENT_FMT " %s"
2360 * Member is indirectly belong to access level container.
2361 * For example 'sameEnterprise' is in the container and user
2362 * belongs to that same enterprise.
2364 #define INDENT_MARKED_INHERITED_FMT "= %s"
2366 static struct sipe_backend_buddy_menu *access_levels_menu(struct sipe_core_private *sipe_private,
2367 struct sipe_backend_buddy_menu *menu,
2368 const gchar *member_type,
2369 const gchar *member_value,
2370 const gboolean extra_menu)
2372 if (!menu)
2373 menu = sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC);
2375 (void) member_type;
2376 (void) member_value;
2377 (void) extra_menu;
2378 (void) blist_menu_remember_container;
2379 (void) create_container;
2380 return(menu);
2383 static struct sipe_backend_buddy_menu *access_groups_menu(struct sipe_core_private *sipe_private)
2385 struct sipe_backend_buddy_menu *menu = sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC);
2386 GSList *access_domains, *entry;
2388 menu = sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC,
2389 menu,
2390 _("People in my company"),
2391 access_levels_menu(sipe_private,
2392 NULL,
2393 "sameEnterprise",
2394 NULL,
2395 FALSE));
2397 /* this is original name, don't edit */
2398 menu = sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC,
2399 menu,
2400 _("People in domains connected with my company"),
2401 access_levels_menu(sipe_private,
2402 NULL,
2403 "federated",
2404 NULL,
2405 FALSE));
2407 menu = sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC,
2408 menu,
2409 _("People in public domains"),
2410 access_levels_menu(sipe_private,
2411 NULL,
2412 "publicCloud",
2413 NULL,
2414 TRUE));
2416 entry = access_domains = get_access_domains(sipe_private);
2417 while (entry) {
2418 gchar *domain = entry->data;
2419 gchar *menu_name = g_strdup_printf(_("People at %s"), domain);
2421 /* takes over ownership of entry->data (= domain) */
2422 menu = sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC,
2423 menu,
2424 menu_name,
2425 access_levels_menu(sipe_private,
2426 NULL,
2427 "domain",
2428 domain,
2429 TRUE));
2430 g_free(menu_name);
2432 entry = entry->next;
2434 g_slist_free(access_domains);
2436 /* separator */
2437 /* People in domains connected with my company */
2438 menu = sipe_backend_buddy_menu_separator(SIPE_CORE_PUBLIC,
2439 menu,
2440 "-------------------------------------------");
2442 menu = sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC,
2443 menu,
2444 _("Add new domain..."),
2445 SIPE_BUDDY_MENU_ADD_NEW_DOMAIN,
2446 NULL);
2448 return(menu);
2451 struct sipe_backend_buddy_menu *sipe_ocs2007_access_control_menu(struct sipe_core_private *sipe_private,
2452 const gchar *buddy_name)
2454 struct sipe_backend_buddy_menu *menu = sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC);
2455 gchar *label;
2458 * Workaround for missing libpurple API to release resources allocated
2459 * during blist_node_menu() callback. See also:
2461 * <http://developer.pidgin.im/ticket/12597>
2463 * We remember all memory blocks in a list and deallocate them when
2465 * - the next time we enter the callback, or
2466 * - the account is disconnected
2468 * That means that after the buddy menu has been closed we have unused
2469 * resources but at least we don't leak them anymore...
2471 sipe_core_buddy_menu_free(SIPE_CORE_PUBLIC);
2473 label = g_strdup_printf(INDENT_FMT, _("Online help..."));
2474 menu = sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC,
2475 menu,
2476 label,
2477 SIPE_BUDDY_MENU_ACCESS_LEVEL_HELP,
2478 NULL);
2479 g_free(label);
2481 label = g_strdup_printf(INDENT_FMT, _("Access groups"));
2482 menu = sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC,
2483 menu,
2484 label,
2485 access_groups_menu(sipe_private));
2486 g_free(label);
2488 menu = access_levels_menu(sipe_private,
2489 menu,
2490 "user",
2491 sipe_get_no_sip_uri(buddy_name),
2492 TRUE);
2494 return(menu);
2498 Local Variables:
2499 mode: c
2500 c-file-style: "bsd"
2501 indent-tabs-mode: t
2502 tab-width: 8
2503 End: