6 * Copyright (C) 2011 SIPE Project <http://sipe.sourceforge.net/>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * OCS2007+ specific code
38 #include "sipe-common.h"
41 #include "sip-transport.h"
42 #include "sipe-backend.h"
43 #include "sipe-buddy.h"
45 #include "sipe-core.h"
46 #include "sipe-core-private.h"
48 #include "sipe-groupchat.h"
50 #include "sipe-ocs2007.h"
51 #include "sipe-schedule.h"
52 #include "sipe-status.h"
53 #include "sipe-utils.h"
56 /** MS-PRES publication */
57 struct sipe_publication
{
62 /** for 'state' category */
64 /** for 'state:calendarState' category */
66 /** for 'note' category */
68 /** for 'calendarData' category; 300(Team) container */
69 char *working_hours_xml_str
;
71 char *free_busy_base64
;
75 * 2007-style Activity and Availability.
79 * Conversion of legacyInterop availability ranges and activity tokens into
80 * SIPE activity tokens. The descriptions of availability ranges are defined at:
82 * http://msdn.microsoft.com/en-us/library/lync/dd941370%28v=office.13%29.aspx
84 * The values define the starting point of a range.
86 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_AVAILABLE 3000
87 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_AVAILABLE_IDLE 4500
88 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY 6000
89 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSYIDLE 7500
90 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_DND 9000 /* do not disturb */
91 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_BRB 12000 /* be right back */
92 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY 15000
93 #define SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE 18000
95 #define SIPE_OCS2007_ACTIVITY_ON_PHONE "on-the-phone"
97 const gchar
*sipe_ocs2007_status_from_legacy_availability(guint availability
,
98 const gchar
*activity
)
102 if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_AVAILABLE
) {
103 type
= SIPE_ACTIVITY_OFFLINE
;
104 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_AVAILABLE_IDLE
) {
105 type
= SIPE_ACTIVITY_AVAILABLE
;
106 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY
) {
107 type
= SIPE_ACTIVITY_INACTIVE
;
108 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSYIDLE
) {
109 if (sipe_strequal(activity
, SIPE_OCS2007_ACTIVITY_ON_PHONE
)) {
110 type
= SIPE_ACTIVITY_ON_PHONE
;
112 type
= SIPE_ACTIVITY_BUSY
;
114 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_DND
) {
115 type
= SIPE_ACTIVITY_BUSYIDLE
;
116 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_BRB
) {
117 type
= SIPE_ACTIVITY_DND
;
118 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY
) {
119 type
= SIPE_ACTIVITY_BRB
;
120 } else if (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE
) {
121 type
= SIPE_ACTIVITY_AWAY
;
123 type
= SIPE_ACTIVITY_OFFLINE
;
126 return sipe_status_activity_to_token(type
);
129 const gchar
*sipe_ocs2007_legacy_activity_description(guint availability
)
131 if ((availability
>= SIPE_OCS2007_LEGACY_AVAILIBILITY_AVAILABLE_IDLE
) &&
132 (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSY
)) {
133 return(sipe_core_activity_description(SIPE_ACTIVITY_INACTIVE
));
134 } else if ((availability
>= SIPE_OCS2007_LEGACY_AVAILIBILITY_BUSYIDLE
) &&
135 (availability
< SIPE_OCS2007_LEGACY_AVAILIBILITY_DND
)) {
136 return(sipe_core_activity_description(SIPE_ACTIVITY_BUSYIDLE
));
143 * @param sipe_status_id (in)
144 * @param activity_token (out) [only sipe-ocs2005.c/send_presence_soap()
145 * requests this token]
147 #define SIPE_OCS2007_AVAILABILITY_UNKNOWN 0
148 #define SIPE_OCS2007_AVAILABILITY_ONLINE 3500
149 #define SIPE_OCS2007_AVAILABILITY_BUSY 6500
150 #define SIPE_OCS2007_AVAILABILITY_DND 9500 /* do not disturb */
151 #define SIPE_OCS2007_AVAILABILITY_BRB 12500 /* be right back */
152 #define SIPE_OCS2007_AVAILABILITY_AWAY 15500
153 #define SIPE_OCS2007_AVAILABILITY_OFFLINE 18500
154 guint
sipe_ocs2007_availability_from_status(const gchar
*sipe_status_id
,
155 const gchar
**activity_token
)
160 if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_AWAY
))) {
161 availability
= SIPE_OCS2007_AVAILABILITY_AWAY
;
162 activity
= SIPE_ACTIVITY_AWAY
;
163 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_BRB
))) {
164 availability
= SIPE_OCS2007_AVAILABILITY_BRB
;
165 activity
= SIPE_ACTIVITY_BRB
;
166 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_DND
))) {
167 availability
= SIPE_OCS2007_AVAILABILITY_DND
;
168 activity
= SIPE_ACTIVITY_DND
;
169 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_BUSY
))) {
170 availability
= SIPE_OCS2007_AVAILABILITY_BUSY
;
171 activity
= SIPE_ACTIVITY_BUSY
;
172 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_AVAILABLE
))) {
173 availability
= SIPE_OCS2007_AVAILABILITY_ONLINE
;
174 activity
= SIPE_ACTIVITY_ONLINE
;
175 } else if (sipe_strequal(sipe_status_id
, sipe_status_activity_to_token(SIPE_ACTIVITY_UNSET
))) {
176 availability
= SIPE_OCS2007_AVAILABILITY_UNKNOWN
;
177 activity
= SIPE_ACTIVITY_UNSET
;
179 /* Offline or invisible */
180 availability
= SIPE_OCS2007_AVAILABILITY_OFFLINE
;
181 activity
= SIPE_ACTIVITY_OFFLINE
;
184 if (activity_token
) {
185 *activity_token
= sipe_status_activity_to_token(activity
);
188 return(availability
);
191 gboolean
sipe_ocs2007_status_is_busy(const gchar
*status_id
)
193 return(SIPE_OCS2007_AVAILABILITY_BUSY
>=
194 sipe_ocs2007_availability_from_status(status_id
, NULL
));
198 gboolean
sipe_ocs2007_availability_is_away(guint availability
)
200 return(availability
>= SIPE_OCS2007_LEGACY_AVAILIBILITY_AWAY
);
203 static void send_presence_publish(struct sipe_core_private
*sipe_private
,
204 const char *publications
);
206 static void free_publication(struct sipe_publication
*publication
)
208 g_free(publication
->category
);
209 g_free(publication
->cal_event_hash
);
210 g_free(publication
->note
);
212 g_free(publication
->working_hours_xml_str
);
213 g_free(publication
->fb_start_str
);
214 g_free(publication
->free_busy_base64
);
219 struct hash_table_delete_payload
{
220 GHashTable
*hash_table
;
224 static void sipe_remove_category_container_publications_cb(const gchar
*name
,
225 struct sipe_publication
*publication
,
226 struct hash_table_delete_payload
*payload
)
228 if (publication
->container
== payload
->container
) {
229 g_hash_table_remove(payload
->hash_table
, name
);
233 static void sipe_remove_category_container_publications(GHashTable
*our_publications
,
234 const gchar
*category
,
237 struct hash_table_delete_payload payload
;
238 payload
.hash_table
= g_hash_table_lookup(our_publications
, category
);
240 if (!payload
.hash_table
) return;
242 payload
.container
= container
;
243 g_hash_table_foreach(payload
.hash_table
,
244 (GHFunc
)sipe_remove_category_container_publications_cb
,
248 /** MS-PRES container */
249 struct sipe_container
{
255 /** MS-PRES container member */
256 struct sipe_container_member
{
257 /** user, domain, sameEnterprise, federated, publicCloud; everyone */
262 static const guint containers
[] = {32000, 400, 300, 200, 100};
263 #define CONTAINERS_LEN (sizeof(containers) / sizeof(guint))
265 static void free_container_member(struct sipe_container_member
*member
)
269 g_free(member
->type
);
270 g_free(member
->value
);
274 static void sipe_ocs2007_free_container(struct sipe_container
*container
)
278 if (!container
) return;
280 entry
= container
->members
;
282 void *data
= entry
->data
;
283 entry
= g_slist_remove(entry
, data
);
284 free_container_member((struct sipe_container_member
*)data
);
289 void sipe_core_buddy_menu_free(struct sipe_core_public
*sipe_public
)
291 struct sipe_core_private
*sipe_private
= SIPE_CORE_PRIVATE
;
292 GSList
*entry
= sipe_private
->blist_menu_containers
;
294 sipe_ocs2007_free_container(entry
->data
);
297 g_slist_free(sipe_private
->blist_menu_containers
);
298 sipe_private
->blist_menu_containers
= NULL
;
301 static void blist_menu_remember_container(struct sipe_core_private
*sipe_private
,
302 struct sipe_container
*container
)
304 sipe_private
->blist_menu_containers
= g_slist_prepend(sipe_private
->blist_menu_containers
,
308 static struct sipe_container
*create_container(guint index
,
309 const gchar
*member_type
,
310 const gchar
*member_value
,
313 struct sipe_container
*container
= g_new0(struct sipe_container
, 1);
314 struct sipe_container_member
*member
= g_new0(struct sipe_container_member
, 1);
316 container
->id
= is_group
? (guint
) -1 : containers
[index
];
317 container
->members
= g_slist_append(container
->members
, member
);
318 member
->type
= g_strdup(member_type
);
319 member
->value
= g_strdup(member_value
);
324 void sipe_ocs2007_free(struct sipe_core_private
*sipe_private
)
326 if (sipe_private
->containers
) {
327 GSList
*entry
= sipe_private
->containers
;
329 sipe_ocs2007_free_container((struct sipe_container
*)entry
->data
);
333 g_slist_free(sipe_private
->containers
);
337 * Finds locally stored MS-PRES container member
339 static struct sipe_container_member
*
340 sipe_find_container_member(struct sipe_container
*container
,
344 struct sipe_container_member
*member
;
347 if (container
== NULL
|| type
== NULL
) {
351 entry
= container
->members
;
353 member
= entry
->data
;
354 if (sipe_strcase_equal(member
->type
, type
) &&
355 sipe_strcase_equal(member
->value
, value
))
365 * Finds locally stored MS-PRES container by id
367 static struct sipe_container
*sipe_find_container(struct sipe_core_private
*sipe_private
,
370 GSList
*entry
= sipe_private
->containers
;
372 struct sipe_container
*container
= entry
->data
;
373 if (id
== container
->id
) {
381 static int sipe_find_member_access_level(struct sipe_core_private
*sipe_private
,
386 const gchar
*value_mod
= value
;
388 if (!type
) return -1;
390 if (sipe_strequal("user", type
)) {
391 value_mod
= sipe_get_no_sip_uri(value
);
394 for (i
= 0; i
< CONTAINERS_LEN
; i
++) {
395 struct sipe_container_member
*member
;
396 struct sipe_container
*container
= sipe_find_container(sipe_private
, containers
[i
]);
397 if (!container
) continue;
399 member
= sipe_find_container_member(container
, type
, value_mod
);
400 if (member
) return containers
[i
];
407 * Returns pointer to domain part in provided Email URL
409 * @param email an email URL. Example: first.last@hq.company.com
410 * @return pointer to domain part of email URL. Coresponding example: hq.company.com
412 * Doesn't allocate memory
414 static const gchar
*sipe_get_domain(const gchar
*email
)
418 if (!email
) return NULL
;
420 tmp
= strstr(email
, "@");
422 if (tmp
&& ((tmp
+1) < (email
+ strlen(email
)))) {
429 /* @TODO: replace with binary search for faster access? */
430 /** source: http://support.microsoft.com/kb/897567 */
431 static const gchar
* const public_domains
[] = {
432 "aol.com", "icq.com", "love.com", "mac.com", "br.live.com",
433 "hotmail.co.il", "hotmail.co.jp", "hotmail.co.th", "hotmail.co.uk",
434 "hotmail.com", "hotmail.com.ar", "hotmail.com.tr", "hotmail.es",
435 "hotmail.de", "hotmail.fr", "hotmail.it", "live.at", "live.be",
436 "live.ca", "live.cl", "live.cn", "live.co.in", "live.co.kr",
437 "live.co.uk", "live.co.za", "live.com", "live.com.ar", "live.com.au",
438 "live.com.co", "live.com.mx", "live.com.my", "live.com.pe",
439 "live.com.ph", "live.com.pk", "live.com.pt", "live.com.sg",
440 "live.com.ve", "live.de", "live.dk", "live.fr", "live.hk", "live.ie",
441 "live.in", "live.it", "live.jp", "live.nl", "live.no", "live.ph",
442 "live.ru", "live.se", "livemail.com.br", "livemail.tw",
443 "messengeruser.com", "msn.com", "passport.com", "sympatico.ca",
444 "tw.live.com", "webtv.net", "windowslive.com", "windowslive.es",
448 static gboolean
sipe_is_public_domain(const gchar
*domain
)
451 while (public_domains
[i
]) {
452 if (sipe_strcase_equal(public_domains
[i
], domain
)) {
468 const gchar
*sipe_ocs2007_access_level_name(guint id
)
471 case 32000: return _("Blocked");
472 case 400: return _("Personal");
473 case 300: return _("Team");
474 case 200: return _("Company");
475 case 100: return _("Public");
480 /** Member type: user, domain, sameEnterprise, federated, publicCloud; everyone */
481 int sipe_ocs2007_find_access_level(struct sipe_core_private
*sipe_private
,
484 gboolean
*is_group_access
)
486 int container_id
= -1;
488 if (sipe_strequal("user", type
)) {
490 const char *no_sip_uri
= sipe_get_no_sip_uri(value
);
492 container_id
= sipe_find_member_access_level(sipe_private
, "user", no_sip_uri
);
493 if (container_id
>= 0) {
494 if (is_group_access
) *is_group_access
= FALSE
;
498 domain
= sipe_get_domain(no_sip_uri
);
499 container_id
= sipe_find_member_access_level(sipe_private
, "domain", domain
);
500 if (container_id
>= 0) {
501 if (is_group_access
) *is_group_access
= TRUE
;
505 container_id
= sipe_find_member_access_level(sipe_private
, "sameEnterprise", NULL
);
506 if ((container_id
>= 0) && sipe_strcase_equal(sipe_private
->public.sip_domain
, domain
)) {
507 if (is_group_access
) *is_group_access
= TRUE
;
511 container_id
= sipe_find_member_access_level(sipe_private
, "publicCloud", NULL
);
512 if ((container_id
>= 0) && sipe_is_public_domain(domain
)) {
513 if (is_group_access
) *is_group_access
= TRUE
;
517 container_id
= sipe_find_member_access_level(sipe_private
, "everyone", NULL
);
518 if ((container_id
>= 0)) {
519 if (is_group_access
) *is_group_access
= TRUE
;
523 container_id
= sipe_find_member_access_level(sipe_private
, type
, value
);
524 if (is_group_access
) *is_group_access
= FALSE
;
530 static GSList
*get_access_domains(struct sipe_core_private
*sipe_private
)
532 struct sipe_container
*container
;
533 struct sipe_container_member
*member
;
538 entry
= sipe_private
->containers
;
540 container
= entry
->data
;
542 entry2
= container
->members
;
544 member
= entry2
->data
;
545 if (sipe_strcase_equal(member
->type
, "domain"))
547 res
= slist_insert_unique_sorted(res
, g_strdup(member
->value
), (GCompareFunc
)g_ascii_strcasecmp
);
549 entry2
= entry2
->next
;
556 static void sipe_send_container_members_prepare(const guint container_id
,
557 const guint container_version
,
561 char **container_xmls
)
563 gchar
*value_str
= value
? g_strdup_printf(" value=\"%s\"", value
) : g_strdup("");
566 if (!container_xmls
) return;
568 body
= g_strdup_printf(
569 "<container id=\"%d\" version=\"%d\"><member action=\"%s\" type=\"%s\"%s/></container>",
577 if ((*container_xmls
) == NULL
) {
578 *container_xmls
= body
;
580 char *tmp
= *container_xmls
;
582 *container_xmls
= g_strconcat(*container_xmls
, body
, NULL
);
588 static void sipe_send_set_container_members(struct sipe_core_private
*sipe_private
,
589 char *container_xmls
)
596 if (!container_xmls
) return;
598 self
= sip_uri_self(sipe_private
);
599 body
= g_strdup_printf(
600 "<setContainerMembers xmlns=\"http://schemas.microsoft.com/2006/09/sip/container-management\">"
602 "</setContainerMembers>",
605 contact
= get_contact(sipe_private
);
606 hdr
= g_strdup_printf("Contact: %s\r\n"
607 "Content-Type: application/msrtc-setcontainermembers+xml\r\n", contact
);
610 sip_transport_service(sipe_private
,
622 * @param container_id a new access level. If -1 then current access level
623 * is just removed (I.e. the member is removed from all containers).
624 * @param type a type of member. E.g. "user", "sameEnterprise", etc.
625 * @param value a value for member. E.g. SIP URI for "user" member type.
627 void sipe_ocs2007_change_access_level(struct sipe_core_private
*sipe_private
,
628 const int container_id
,
633 int current_container_id
= -1;
634 char *container_xmls
= NULL
;
636 /* for each container: find/delete */
637 for (i
= 0; i
< CONTAINERS_LEN
; i
++) {
638 struct sipe_container_member
*member
;
639 struct sipe_container
*container
= sipe_find_container(sipe_private
, containers
[i
]);
641 if (!container
) continue;
643 member
= sipe_find_container_member(container
, type
, value
);
645 current_container_id
= containers
[i
];
646 /* delete/publish current access level */
647 if (container_id
< 0 || container_id
!= current_container_id
) {
648 sipe_send_container_members_prepare(current_container_id
, container
->version
, "remove", type
, value
, &container_xmls
);
649 /* remove member from our cache, to be able to recalculate AL below */
650 container
->members
= g_slist_remove(container
->members
, member
);
651 current_container_id
= -1;
656 /* recalculate AL below */
657 current_container_id
= sipe_ocs2007_find_access_level(sipe_private
, type
, value
, NULL
);
659 /* assign/publish new access level */
660 if (container_id
!= current_container_id
&& container_id
>= 0) {
661 struct sipe_container
*container
= sipe_find_container(sipe_private
, container_id
);
662 guint version
= container
? container
->version
: 0;
664 sipe_send_container_members_prepare(container_id
, version
, "add", type
, value
, &container_xmls
);
667 if (container_xmls
) {
668 sipe_send_set_container_members(sipe_private
, container_xmls
);
670 g_free(container_xmls
);
673 void sipe_core_change_access_level_from_container(struct sipe_core_public
*sipe_public
,
676 struct sipe_container
*container
= parameter
;
677 struct sipe_container_member
*member
;
679 if (!container
|| !container
->members
) return;
681 member
= ((struct sipe_container_member
*)container
->members
->data
);
683 if (!member
->type
) return;
685 SIPE_DEBUG_INFO("sipe_ocs2007_change_access_level_from_container: container->id=%d, member->type=%s, member->value=%s",
686 container
->id
, member
->type
, member
->value
? member
->value
: "");
688 sipe_ocs2007_change_access_level(SIPE_CORE_PRIVATE
,
695 void sipe_core_change_access_level_for_domain(struct sipe_core_public
*sipe_public
,
699 /* move Blocked first */
700 guint i
= (index
== 4) ? 0 : index
+ 1;
701 guint container_id
= containers
[i
];
703 SIPE_DEBUG_INFO("sipe_core_change_access_level_from_id: domain=%s, container_id=(%d)%d",
704 domain
? domain
: "", index
, container_id
);
706 sipe_ocs2007_change_access_level(SIPE_CORE_PRIVATE
,
713 * Schedules process of self status publish
714 * based on own calendar information.
715 * Should be scheduled to the beginning of every
716 * 15 min interval, like:
717 * 13:00, 13:15, 13:30, 13:45, etc.
720 static void schedule_publish_update(struct sipe_core_private
*sipe_private
,
721 time_t calculate_from
)
724 /** start of the beginning of closest 5 min interval. */
725 time_t next_start
= ((time_t)((int)((int)calculate_from
)/interval
+ 1)*interval
);
727 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: calculate_from time: %s",
728 asctime(localtime(&calculate_from
)));
729 SIPE_DEBUG_INFO("sipe_sched_calendar_status_self_publish: next start time : %s",
730 asctime(localtime(&next_start
)));
732 sipe_schedule_seconds(sipe_private
,
733 "<+2007-cal-status>",
735 next_start
- time(NULL
),
736 sipe_ocs2007_presence_publish
,
741 * An availability XML entry for SIPE_PUB_XML_STATE_CALENDAR
742 * @param availability (%d) Ex.: 6500
744 #define SIPE_PUB_XML_STATE_CALENDAR_AVAIL \
745 "<availability>%d</availability>"
747 * An activity XML entry for SIPE_PUB_XML_STATE_CALENDAR
748 * @param token (%s) Ex.: in-a-meeting
749 * @param minAvailability_attr (%s) Ex.: minAvailability="6500"
750 * @param maxAvailability_attr (%s) Ex.: maxAvailability="8999" or none
752 #define SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY \
753 "<activity token=\"%s\" %s %s></activity>"
755 * Publishes 'calendarState' category.
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 * @param instance (%u) Ex.: 1339299275
766 * @param version (%u) Ex.: 1
767 * @param uri (%s) Ex.: john@contoso.com
768 * @param start_time_str (%s) Ex.: 2008-01-11T19:00:00Z
769 * @param availability (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_AVAIL
770 * @param activity (%s) XML string as SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
771 * @param meeting_subject (%s) Ex.: Customer Meeting
772 * @param meeting_location (%s) Ex.: Conf Room 100
774 #define SIPE_PUB_XML_STATE_CALENDAR \
775 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" 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\">"\
779 "<endpointLocation/>"\
780 "<meetingSubject>%s</meetingSubject>"\
781 "<meetingLocation>%s</meetingLocation>"\
784 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
785 "<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\">"\
788 "<endpointLocation/>"\
789 "<meetingSubject>%s</meetingSubject>"\
790 "<meetingLocation>%s</meetingLocation>"\
794 * Publishes to clear 'calendarState' and 'phoneState' category
795 * @param instance (%u) Ex.: 1251210982
796 * @param version (%u) Ex.: 1
798 #define SIPE_PUB_XML_STATE_CALENDAR_PHONE_CLEAR \
799 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"\
800 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\" expires=\"0\"/>"
803 * Publishes to clear any category
804 * @param category_name (%s) Ex.: state
805 * @param instance (%u) Ex.: 536870912
806 * @param container (%u) Ex.: 3
807 * @param version (%u) Ex.: 1
808 * @param expireType (%s) Ex.: static
810 #define SIPE_PUB_XML_PUBLICATION_CLEAR \
811 "<publication categoryName=\"%s\" instance=\"%u\" container=\"%u\" version=\"%u\" expireType=\"%s\" expires=\"0\"/>"
814 * Publishes 'note' category.
815 * @param instance (%u) Ex.: 2135971629; 0 for personal
816 * @param container (%u) Ex.: 200
817 * @param version (%u) Ex.: 2
818 * @param type (%s) Ex.: personal or OOF
819 * @param startTime_attr (%s) Ex.: startTime="2008-01-11T19:00:00Z"
820 * @param endTime_attr (%s) Ex.: endTime="2008-01-15T19:00:00Z"
821 * @param body (%s) Ex.: In the office
823 #define SIPE_PUB_XML_NOTE \
824 "<publication categoryName=\"note\" instance=\"%u\" container=\"%u\" version=\"%d\" expireType=\"static\">"\
825 "<note xmlns=\"http://schemas.microsoft.com/2006/09/sip/note\">"\
826 "<body type=\"%s\" uri=\"\"%s%s>%s</body>"\
830 * Publishes 'phoneState' category.
831 * @param instance (%u) Ex.: 1339299275
832 * @param version (%u) Ex.: 1
834 * @param instance (%u) Ex.: 1339299275
835 * @param version (%u) Ex.: 1
837 #define SIPE_PUB_XML_STATE_PHONE \
838 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
839 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"phoneState\">"\
840 "<availability>6500</availability>"\
841 "<activity token=\"on-the-phone\" minAvailability=\"6500\" maxAvailability=\"8999\"/>"\
844 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
845 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"phoneState\">"\
846 "<availability>6500</availability>"\
847 "<activity token=\"on-the-phone\" minAvailability=\"6500\" maxAvailability=\"8999\"/>"\
852 * Only Busy and OOF calendar event are published.
853 * Different instances are used for that.
855 * Must be g_free'd after use.
857 static gchar
*sipe_publish_get_category_state_calendar(struct sipe_core_private
*sipe_private
,
858 struct sipe_cal_event
*event
,
862 gchar
*start_time_str
;
863 int availability
= 0;
866 guint instance
= (cal_satus
== SIPE_CAL_OOF
) ?
867 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR_OOF
) :
868 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR
);
870 /* key is <category><instance><container> */
871 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
872 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
873 struct sipe_publication
*publication_2
=
874 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_2
);
875 struct sipe_publication
*publication_3
=
876 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_3
);
881 if (!publication_3
&& !event
) { /* was nothing, have nothing, exiting */
882 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
883 "Exiting as no publication and no event for cal_satus:%d", cal_satus
);
889 (publication_3
->availability
== availability
) &&
890 sipe_strequal(publication_3
->cal_event_hash
, (tmp
= sipe_cal_event_hash(event
))))
893 SIPE_DEBUG_INFO("sipe_publish_get_category_state_calendar: "
894 "cal state has NOT changed for cal_satus:%d. Exiting.", cal_satus
);
895 return NULL
; /* nothing to update */
900 (event
->cal_status
== SIPE_CAL_BUSY
||
901 event
->cal_status
== SIPE_CAL_OOF
))
903 gchar
*availability_xml_str
= NULL
;
904 gchar
*activity_xml_str
= NULL
;
905 gchar
*escaped_subject
= event
->subject
? g_markup_escape_text(event
->subject
, -1) : NULL
;
906 gchar
*escaped_location
= event
->location
? g_markup_escape_text(event
->location
, -1) : NULL
;
908 if (event
->cal_status
== SIPE_CAL_BUSY
) {
909 availability_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_AVAIL
,
910 SIPE_OCS2007_AVAILABILITY_BUSY
);
913 if (event
->cal_status
== SIPE_CAL_BUSY
&& event
->is_meeting
) {
914 activity_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
,
915 sipe_status_activity_to_token(SIPE_ACTIVITY_IN_MEETING
),
916 "minAvailability=\"6500\"",
917 "maxAvailability=\"8999\"");
918 } else if (event
->cal_status
== SIPE_CAL_OOF
) {
919 activity_xml_str
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_ACTIVITY
,
920 sipe_status_activity_to_token(SIPE_ACTIVITY_OOF
),
921 "minAvailability=\"12000\"",
924 start_time_str
= sipe_utils_time_to_str(event
->start_time
);
926 res
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR
,
928 publication_2
? publication_2
->version
: 0,
931 availability_xml_str
? availability_xml_str
: "",
932 activity_xml_str
? activity_xml_str
: "",
933 escaped_subject
? escaped_subject
: "",
934 escaped_location
? escaped_location
: "",
937 publication_3
? publication_3
->version
: 0,
940 availability_xml_str
? availability_xml_str
: "",
941 activity_xml_str
? activity_xml_str
: "",
942 escaped_subject
? escaped_subject
: "",
943 escaped_location
? escaped_location
: ""
945 g_free(escaped_location
);
946 g_free(escaped_subject
);
947 g_free(start_time_str
);
948 g_free(availability_xml_str
);
949 g_free(activity_xml_str
);
952 else /* including !event, SIPE_CAL_FREE, SIPE_CAL_TENTATIVE */
954 res
= g_strdup_printf(SIPE_PUB_XML_STATE_CALENDAR_PHONE_CLEAR
,
956 publication_2
? publication_2
->version
: 0,
959 publication_3
? publication_3
->version
: 0
967 * Returns 'note' XML part for publication.
968 * Must be g_free'd after use.
970 * Protocol format for Note is plain text.
972 * @param note a note in Sipe internal HTML format
973 * @param note_type either personal or OOF
975 static gchar
*sipe_publish_get_category_note(struct sipe_core_private
*sipe_private
,
976 const char *note
, /* html */
977 const char *note_type
,
981 guint instance
= sipe_strequal("OOF", note_type
) ? sipe_get_pub_instance(sipe_private
, SIPE_PUB_NOTE_OOF
) : 0;
982 /* key is <category><instance><container> */
983 gchar
*key_note_200
= g_strdup_printf("<%s><%u><%u>", "note", instance
, 200);
984 gchar
*key_note_300
= g_strdup_printf("<%s><%u><%u>", "note", instance
, 300);
985 gchar
*key_note_400
= g_strdup_printf("<%s><%u><%u>", "note", instance
, 400);
987 struct sipe_publication
*publication_note_200
=
988 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "note"), key_note_200
);
989 struct sipe_publication
*publication_note_300
=
990 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "note"), key_note_300
);
991 struct sipe_publication
*publication_note_400
=
992 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "note"), key_note_400
);
994 char *tmp
= note
? sipe_backend_markup_strip_html(note
) : NULL
;
995 char *n1
= tmp
? g_markup_escape_text(tmp
, -1) : NULL
;
996 const char *n2
= publication_note_200
? publication_note_200
->note
: NULL
;
997 char *res
, *tmp1
, *tmp2
, *tmp3
;
998 char *start_time_attr
;
1003 g_free(key_note_200
);
1004 g_free(key_note_300
);
1005 g_free(key_note_400
);
1007 /* we even need to republish empty note */
1008 if (sipe_strequal(n1
, n2
))
1010 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_note: note has NOT changed. Exiting.");
1012 return NULL
; /* nothing to update */
1015 start_time_attr
= note_start
? g_strdup_printf(" startTime=\"%s\"", (tmp
= sipe_utils_time_to_str(note_start
))) : NULL
;
1018 end_time_attr
= note_end
? g_strdup_printf(" endTime=\"%s\"", (tmp
= sipe_utils_time_to_str(note_end
))) : NULL
;
1022 tmp1
= g_strdup_printf(SIPE_PUB_XML_NOTE
,
1025 publication_note_200
? publication_note_200
->version
: 0,
1027 start_time_attr
? start_time_attr
: "",
1028 end_time_attr
? end_time_attr
: "",
1031 tmp2
= g_strdup_printf(SIPE_PUB_XML_NOTE
,
1034 publication_note_300
? publication_note_300
->version
: 0,
1036 start_time_attr
? start_time_attr
: "",
1037 end_time_attr
? end_time_attr
: "",
1040 tmp3
= g_strdup_printf(SIPE_PUB_XML_NOTE
,
1043 publication_note_400
? publication_note_400
->version
: 0,
1045 start_time_attr
? start_time_attr
: "",
1046 end_time_attr
? end_time_attr
: "",
1049 tmp1
= g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR
,
1053 publication_note_200
? publication_note_200
->version
: 0,
1055 tmp2
= g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR
,
1059 publication_note_200
? publication_note_200
->version
: 0,
1061 tmp3
= g_strdup_printf( SIPE_PUB_XML_PUBLICATION_CLEAR
,
1065 publication_note_200
? publication_note_200
->version
: 0,
1068 res
= g_strconcat(tmp1
, tmp2
, tmp3
, NULL
);
1070 g_free(start_time_attr
);
1071 g_free(end_time_attr
);
1081 * Publishes 'calendarData' category's WorkingHours.
1083 * @param version (%u) Ex.: 1
1084 * @param email (%s) Ex.: alice@cosmo.local
1085 * @param working_hours_xml_str (%s) Ex.: <WorkingHours xmlns=.....
1087 * @param version (%u)
1089 * @param version (%u)
1091 * @param working_hours_xml_str (%s)
1093 * @param version (%u)
1095 * @param working_hours_xml_str (%s)
1097 * @param version (%u)
1099 * @param working_hours_xml_str (%s)
1101 * @param version (%u)
1103 #define SIPE_PUB_XML_WORKING_HOURS \
1104 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"1\" version=\"%d\" expireType=\"static\">"\
1105 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1108 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"100\" version=\"%d\" expireType=\"static\">"\
1109 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1111 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"200\" version=\"%d\" expireType=\"static\">"\
1112 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1115 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"300\" version=\"%d\" expireType=\"static\">"\
1116 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1119 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"400\" version=\"%d\" expireType=\"static\">"\
1120 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">%s"\
1123 "<publication categoryName=\"calendarData\" instance=\"0\" container=\"32000\" version=\"%d\" expireType=\"static\">"\
1124 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1128 * Returns 'calendarData' XML part with WorkingHours for publication.
1129 * Must be g_free'd after use.
1131 static gchar
*sipe_publish_get_category_cal_working_hours(struct sipe_core_private
*sipe_private
)
1133 struct sipe_calendar
* cal
= sipe_private
->calendar
;
1135 /* key is <category><instance><container> */
1136 gchar
*key_cal_1
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1);
1137 gchar
*key_cal_100
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100);
1138 gchar
*key_cal_200
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200);
1139 gchar
*key_cal_300
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300);
1140 gchar
*key_cal_400
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400);
1141 gchar
*key_cal_32000
= g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000);
1143 struct sipe_publication
*publication_cal_1
=
1144 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_1
);
1145 struct sipe_publication
*publication_cal_100
=
1146 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_100
);
1147 struct sipe_publication
*publication_cal_200
=
1148 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_200
);
1149 struct sipe_publication
*publication_cal_300
=
1150 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_300
);
1151 struct sipe_publication
*publication_cal_400
=
1152 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_400
);
1153 struct sipe_publication
*publication_cal_32000
=
1154 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_32000
);
1156 const char *n1
= cal
? cal
->working_hours_xml_str
: NULL
;
1157 const char *n2
= publication_cal_300
? publication_cal_300
->working_hours_xml_str
: NULL
;
1160 g_free(key_cal_100
);
1161 g_free(key_cal_200
);
1162 g_free(key_cal_300
);
1163 g_free(key_cal_400
);
1164 g_free(key_cal_32000
);
1166 if (!cal
|| is_empty(cal
->email
) || is_empty(cal
->working_hours_xml_str
)) {
1167 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_working_hours: no data to publish, exiting");
1171 if (sipe_strequal(n1
, n2
))
1173 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_working_hours: WorkingHours has NOT changed. Exiting.");
1174 return NULL
; /* nothing to update */
1177 return g_strdup_printf(SIPE_PUB_XML_WORKING_HOURS
,
1179 publication_cal_1
? publication_cal_1
->version
: 0,
1181 cal
->working_hours_xml_str
,
1183 publication_cal_100
? publication_cal_100
->version
: 0,
1185 publication_cal_200
? publication_cal_200
->version
: 0,
1187 cal
->working_hours_xml_str
,
1189 publication_cal_300
? publication_cal_300
->version
: 0,
1191 cal
->working_hours_xml_str
,
1192 /* 400 - Personal */
1193 publication_cal_400
? publication_cal_400
->version
: 0,
1195 cal
->working_hours_xml_str
,
1196 /* 32000 - Blocked */
1197 publication_cal_32000
? publication_cal_32000
->version
: 0
1202 * Publishes 'calendarData' category's FreeBusy.
1204 * @param instance (%u) Ex.: 1300372959
1205 * @param version (%u) Ex.: 1
1207 * @param instance (%u) Ex.: 1300372959
1208 * @param version (%u) Ex.: 1
1210 * @param instance (%u) Ex.: 1300372959
1211 * @param version (%u) Ex.: 1
1212 * @param email (%s) Ex.: alice@cosmo.local
1213 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1214 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1216 * @param instance (%u) Ex.: 1300372959
1217 * @param version (%u) Ex.: 1
1218 * @param email (%s) Ex.: alice@cosmo.local
1219 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1220 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1222 * @param instance (%u) Ex.: 1300372959
1223 * @param version (%u) Ex.: 1
1224 * @param email (%s) Ex.: alice@cosmo.local
1225 * @param fb_start_time_str (%s) Ex.: 2009-12-03T00:00:00Z
1226 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAAAAAA.....
1228 * @param instance (%u) Ex.: 1300372959
1229 * @param version (%u) Ex.: 1
1231 #define SIPE_PUB_XML_FREE_BUSY \
1232 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"1\" version=\"%d\" expireType=\"endpoint\">"\
1233 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1235 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"100\" version=\"%d\" expireType=\"endpoint\">"\
1236 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1238 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"200\" version=\"%d\" expireType=\"endpoint\">"\
1239 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1240 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1243 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"300\" version=\"%d\" expireType=\"endpoint\">"\
1244 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1245 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1248 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"400\" version=\"%d\" expireType=\"endpoint\">"\
1249 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\" mailboxID=\"%s\">"\
1250 "<freeBusy startTime=\"%s\" granularity=\"PT15M\" encodingVersion=\"1\">%s</freeBusy>"\
1253 "<publication categoryName=\"calendarData\" instance=\"%u\" container=\"32000\" version=\"%d\" expireType=\"endpoint\">"\
1254 "<calendarData xmlns=\"http://schemas.microsoft.com/2006/09/sip/calendarData\"/>"\
1258 * Returns 'calendarData' XML part with FreeBusy for publication.
1259 * Must be g_free'd after use.
1261 static gchar
*sipe_publish_get_category_cal_free_busy(struct sipe_core_private
*sipe_private
)
1263 struct sipe_calendar
* cal
= sipe_private
->calendar
;
1264 guint cal_data_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_CALENDAR_DATA
);
1266 char *free_busy_base64
;
1267 /* const char *st; */
1268 /* const char *fb; */
1271 /* key is <category><instance><container> */
1272 gchar
*key_cal_1
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 1);
1273 gchar
*key_cal_100
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 100);
1274 gchar
*key_cal_200
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 200);
1275 gchar
*key_cal_300
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 300);
1276 gchar
*key_cal_400
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 400);
1277 gchar
*key_cal_32000
= g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 32000);
1279 struct sipe_publication
*publication_cal_1
=
1280 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_1
);
1281 struct sipe_publication
*publication_cal_100
=
1282 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_100
);
1283 struct sipe_publication
*publication_cal_200
=
1284 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_200
);
1285 struct sipe_publication
*publication_cal_300
=
1286 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_300
);
1287 struct sipe_publication
*publication_cal_400
=
1288 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_400
);
1289 struct sipe_publication
*publication_cal_32000
=
1290 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "calendarData"), key_cal_32000
);
1293 g_free(key_cal_100
);
1294 g_free(key_cal_200
);
1295 g_free(key_cal_300
);
1296 g_free(key_cal_400
);
1297 g_free(key_cal_32000
);
1299 if (!cal
|| is_empty(cal
->email
) || !cal
->fb_start
|| is_empty(cal
->free_busy
)) {
1300 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_free_busy: no data to publish, exiting");
1304 fb_start_str
= sipe_utils_time_to_str(cal
->fb_start
);
1305 free_busy_base64
= sipe_cal_get_freebusy_base64(cal
->free_busy
);
1307 /* we will rebuplish the same data to refresh publication time,
1308 * so if data from multiple sources, most recent will be choosen
1310 // st = publication_cal_300 ? publication_cal_300->fb_start_str : NULL;
1311 // fb = publication_cal_300 ? publication_cal_300->free_busy_base64 : NULL;
1313 //if (sipe_strequal(st, fb_start_str) && sipe_strequal(fb, free_busy_base64))
1315 // SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_cal_free_busy: FreeBusy has NOT changed. Exiting.");
1316 // g_free(fb_start_str);
1317 // g_free(free_busy_base64);
1318 // return NULL; /* nothing to update */
1321 res
= g_strdup_printf(SIPE_PUB_XML_FREE_BUSY
,
1324 publication_cal_1
? publication_cal_1
->version
: 0,
1327 publication_cal_100
? publication_cal_100
->version
: 0,
1330 publication_cal_200
? publication_cal_200
->version
: 0,
1336 publication_cal_300
? publication_cal_300
->version
: 0,
1340 /* 400 - Personal */
1342 publication_cal_400
? publication_cal_400
->version
: 0,
1346 /* 32000 - Blocked */
1348 publication_cal_32000
? publication_cal_32000
->version
: 0
1351 g_free(fb_start_str
);
1352 g_free(free_busy_base64
);
1358 * Publishes 'device' category.
1359 * @param instance (%u) Ex.: 1938468728
1360 * @param version (%u) Ex.: 1
1361 * @param endpointId (%s) Ex.: C707E38E-1E10-5413-94D9-ECAC260A0269
1362 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1363 * @param timezone (%s) Ex.: 00:00:00+01:00
1364 * @param machineName (%s) Ex.: BOSTON-OCS07
1366 #define SIPE_PUB_XML_DEVICE \
1367 "<publication categoryName=\"device\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
1368 "<device xmlns=\"http://schemas.microsoft.com/2006/09/sip/device\" endpointId=\"%s\">"\
1369 "<capabilities preferred=\"false\" uri=\"%s\">"\
1370 "<text capture=\"true\" render=\"true\" publish=\"false\"/>"\
1371 "<gifInk capture=\"false\" render=\"true\" publish=\"false\"/>"\
1372 "<isfInk capture=\"false\" render=\"true\" publish=\"false\"/>"\
1374 "<timezone>%s</timezone>"\
1375 "<machineName>%s</machineName>"\
1380 * Returns 'device' XML part for publication.
1381 * Must be g_free'd after use.
1383 static gchar
*sipe_publish_get_category_device(struct sipe_core_private
*sipe_private
)
1387 gchar
*uuid
= get_uuid(sipe_private
);
1388 guint device_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_DEVICE
);
1389 /* key is <category><instance><container> */
1390 gchar
*key
= g_strdup_printf("<%s><%u><%u>", "device", device_instance
, 2);
1391 struct sipe_publication
*publication
=
1392 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "device"), key
);
1396 uri
= sip_uri_self(sipe_private
);
1397 doc
= g_strdup_printf(SIPE_PUB_XML_DEVICE
,
1399 publication
? publication
->version
: 0,
1402 "00:00:00+01:00", /* @TODO make timezone real*/
1413 * Publishes 'machineState' category.
1414 * @param instance (%u) Ex.: 926460663
1415 * @param version (%u) Ex.: 22
1416 * @param availability (%d) Ex.: 3500
1417 * @param instance (%u) Ex.: 926460663
1418 * @param version (%u) Ex.: 22
1419 * @param availability (%d) Ex.: 3500
1421 #define SIPE_PUB_XML_STATE_MACHINE \
1422 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"endpoint\">"\
1423 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"machineState\">"\
1424 "<availability>%d</availability>"\
1425 "<endpointLocation/>"\
1428 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"endpoint\">"\
1429 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"false\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"machineState\">"\
1430 "<availability>%d</availability>"\
1431 "<endpointLocation/>"\
1436 * Publishes 'userState' category.
1437 * @param instance (%u) User. Ex.: 536870912
1438 * @param version (%u) User Container 2. Ex.: 22
1439 * @param availability (%d) User Container 2. Ex.: 15500
1440 * @param instance (%u) User. Ex.: 536870912
1441 * @param version (%u) User Container 3.Ex.: 22
1442 * @param availability (%d) User Container 3. Ex.: 15500
1444 #define SIPE_PUB_XML_STATE_USER \
1445 "<publication categoryName=\"state\" instance=\"%u\" container=\"2\" version=\"%u\" expireType=\"static\">"\
1446 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"true\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"userState\">"\
1447 "<availability>%d</availability>"\
1448 "<endpointLocation/>"\
1451 "<publication categoryName=\"state\" instance=\"%u\" container=\"3\" version=\"%u\" expireType=\"static\">"\
1452 "<state xmlns=\"http://schemas.microsoft.com/2006/09/sip/state\" manual=\"true\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"userState\">"\
1453 "<availability>%d</availability>"\
1454 "<endpointLocation/>"\
1459 * A service method - use
1460 * - send_publish_get_category_state_machine and
1461 * - send_publish_get_category_state_user instead.
1462 * Must be g_free'd after use.
1464 static gchar
*sipe_publish_get_category_state(struct sipe_core_private
*sipe_private
,
1465 gboolean is_user_state
)
1467 int availability
= sipe_ocs2007_availability_from_status(sipe_private
->status
, NULL
);
1468 guint instance
= is_user_state
? sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_USER
) :
1469 sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_MACHINE
);
1470 /* key is <category><instance><container> */
1471 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
1472 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
1473 struct sipe_publication
*publication_2
=
1474 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_2
);
1475 struct sipe_publication
*publication_3
=
1476 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_3
);
1481 if (publication_2
&& (publication_2
->availability
== availability
))
1483 SIPE_DEBUG_INFO_NOFORMAT("sipe_publish_get_category_state: state has NOT changed. Exiting.");
1484 return NULL
; /* nothing to update */
1487 return g_strdup_printf( is_user_state
? SIPE_PUB_XML_STATE_USER
: SIPE_PUB_XML_STATE_MACHINE
,
1489 publication_2
? publication_2
->version
: 0,
1492 publication_3
? publication_3
->version
: 0,
1497 * Returns 'machineState' XML part for publication.
1498 * Must be g_free'd after use.
1500 static gchar
*sipe_publish_get_category_state_machine(struct sipe_core_private
*sipe_private
)
1502 return sipe_publish_get_category_state(sipe_private
, FALSE
);
1506 * Returns 'userState' XML part for publication.
1507 * Must be g_free'd after use.
1509 static gchar
*sipe_publish_get_category_state_user(struct sipe_core_private
*sipe_private
)
1511 return sipe_publish_get_category_state(sipe_private
, TRUE
);
1514 static void send_publish_category_initial(struct sipe_core_private
*sipe_private
)
1516 gchar
*pub_device
= sipe_publish_get_category_device(sipe_private
);
1518 gchar
*publications
;
1520 sipe_status_set_activity(sipe_private
, SIPE_ACTIVITY_AVAILABLE
);
1522 pub_machine
= sipe_publish_get_category_state_machine(sipe_private
);
1523 publications
= g_strdup_printf("%s%s",
1525 pub_machine
? pub_machine
: "");
1527 g_free(pub_machine
);
1529 send_presence_publish(sipe_private
, publications
);
1530 g_free(publications
);
1533 static gboolean
process_send_presence_category_publish_response(struct sipe_core_private
*sipe_private
,
1535 struct transaction
*trans
)
1537 const gchar
*contenttype
= sipmsg_find_header(msg
, "Content-Type");
1539 if (msg
->response
== 409 && g_str_has_prefix(contenttype
, "application/msrtc-fault+xml")) {
1541 const sipe_xml
*node
;
1545 gboolean has_device_publication
= FALSE
;
1547 xml
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
1549 /* test if version mismatch fault */
1550 fault_code
= sipe_xml_data(sipe_xml_child(xml
, "Faultcode"));
1551 if (!sipe_strequal(fault_code
, "Client.BadCall.WrongDelta")) {
1552 SIPE_DEBUG_INFO("process_send_presence_category_publish_response: unsupported fault code:%s returning.", fault_code
);
1559 /* accumulating information about faulty versions */
1560 faults
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
1561 for (node
= sipe_xml_child(xml
, "details/operation");
1563 node
= sipe_xml_twin(node
))
1565 const gchar
*index
= sipe_xml_attribute(node
, "index");
1566 const gchar
*curVersion
= sipe_xml_attribute(node
, "curVersion");
1568 g_hash_table_insert(faults
, g_strdup(index
), g_strdup(curVersion
));
1569 SIPE_DEBUG_INFO("fault added: index:%s curVersion:%s", index
, curVersion
);
1573 /* here we are parsing our own request to figure out what publication
1574 * referenced here only by index went wrong
1576 xml
= sipe_xml_parse(trans
->msg
->body
, trans
->msg
->bodylen
);
1579 for (node
= sipe_xml_child(xml
, "publications/publication"),
1580 index_our
= 1; /* starts with 1 - our first publication */
1582 node
= sipe_xml_twin(node
), index_our
++)
1584 gchar
*idx
= g_strdup_printf("%d", index_our
);
1585 const gchar
*curVersion
= g_hash_table_lookup(faults
, idx
);
1586 const gchar
*categoryName
= sipe_xml_attribute(node
, "categoryName");
1589 if (sipe_strequal("device", categoryName
)) {
1590 has_device_publication
= TRUE
;
1593 if (curVersion
) { /* fault exist on this index */
1594 const gchar
*container
= sipe_xml_attribute(node
, "container");
1595 const gchar
*instance
= sipe_xml_attribute(node
, "instance");
1596 /* key is <category><instance><container> */
1597 gchar
*key
= g_strdup_printf("<%s><%s><%s>", categoryName
, instance
, container
);
1598 GHashTable
*category
= g_hash_table_lookup(sipe_private
->our_publications
, categoryName
);
1601 struct sipe_publication
*publication
=
1602 g_hash_table_lookup(category
, key
);
1604 SIPE_DEBUG_INFO("key is %s", key
);
1607 SIPE_DEBUG_INFO("Updating %s with version %s. Was %d before.",
1608 key
, curVersion
, publication
->version
);
1609 /* updating publication's version to the correct one */
1610 publication
->version
= atoi(curVersion
);
1613 /* We somehow lost this category from our publications... */
1614 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
1615 publication
->category
= g_strdup(categoryName
);
1616 publication
->instance
= atoi(instance
);
1617 publication
->container
= atoi(container
);
1618 publication
->version
= atoi(curVersion
);
1619 category
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
1620 g_free
, (GDestroyNotify
)free_publication
);
1621 g_hash_table_insert(category
, g_strdup(key
), publication
);
1622 g_hash_table_insert(sipe_private
->our_publications
, g_strdup(categoryName
), category
);
1623 SIPE_DEBUG_INFO("added lost category '%s' key '%s'", categoryName
, key
);
1629 g_hash_table_destroy(faults
);
1631 /* rebublishing with right versions */
1632 if (has_device_publication
) {
1633 send_publish_category_initial(sipe_private
);
1635 sipe_status_update(sipe_private
, NULL
);
1642 * Publishes categories.
1643 * @param uri (%s) Self URI. Ex.: sip:alice7@boston.local
1644 * @param publications (%s) XML publications
1646 #define SIPE_SEND_PRESENCE \
1647 "<publish xmlns=\"http://schemas.microsoft.com/2006/09/sip/rich-presence\">"\
1648 "<publications uri=\"%s\">"\
1653 static void send_presence_publish(struct sipe_core_private
*sipe_private
,
1654 const char *publications
)
1661 uri
= sip_uri_self(sipe_private
);
1662 doc
= g_strdup_printf(SIPE_SEND_PRESENCE
,
1666 tmp
= get_contact(sipe_private
);
1667 hdr
= g_strdup_printf("Contact: %s\r\n"
1668 "Content-Type: application/msrtc-category-publish+xml\r\n", tmp
);
1670 sip_transport_service(sipe_private
,
1674 process_send_presence_category_publish_response
);
1683 * Publishes self status
1684 * based on own calendar information.
1686 void sipe_ocs2007_presence_publish(struct sipe_core_private
*sipe_private
,
1687 SIPE_UNUSED_PARAMETER
void *unused
)
1689 struct sipe_calendar
* cal
= sipe_private
->calendar
;
1690 struct sipe_cal_event
* event
= NULL
;
1691 gchar
*pub_cal_working_hours
= NULL
;
1692 gchar
*pub_cal_free_busy
= NULL
;
1693 gchar
*pub_calendar
= NULL
;
1694 gchar
*pub_calendar2
= NULL
;
1695 gchar
*pub_oof_note
= NULL
;
1696 const gchar
*oof_note
;
1697 time_t oof_start
= 0;
1701 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() no calendar data.");
1705 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self() started.");
1706 if (cal
->cal_events
) {
1707 event
= sipe_cal_get_event(cal
->cal_events
, time(NULL
));
1711 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: current event is NULL");
1713 char *desc
= sipe_cal_event_describe(event
);
1714 SIPE_DEBUG_INFO("publish_calendar_status_self: current event is:\n%s", desc
? desc
: "");
1720 OOF publish, Busy clean
1722 OOF clean, Busy publish
1724 OOF clean, Busy clean
1726 if (event
&& event
->cal_status
== SIPE_CAL_OOF
) {
1727 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, event
, cal
->email
, SIPE_CAL_OOF
);
1728 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_BUSY
);
1729 } else if (event
&& event
->cal_status
== SIPE_CAL_BUSY
) {
1730 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_OOF
);
1731 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, event
, cal
->email
, SIPE_CAL_BUSY
);
1733 pub_calendar
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_OOF
);
1734 pub_calendar2
= sipe_publish_get_category_state_calendar(sipe_private
, NULL
, cal
->email
, SIPE_CAL_BUSY
);
1737 oof_note
= sipe_ews_get_oof_note(cal
);
1738 if (sipe_strequal("Scheduled", cal
->oof_state
)) {
1739 oof_start
= cal
->oof_start
;
1740 oof_end
= cal
->oof_end
;
1742 pub_oof_note
= sipe_publish_get_category_note(sipe_private
, oof_note
, "OOF", oof_start
, oof_end
);
1744 pub_cal_working_hours
= sipe_publish_get_category_cal_working_hours(sipe_private
);
1745 pub_cal_free_busy
= sipe_publish_get_category_cal_free_busy(sipe_private
);
1747 if (!pub_cal_working_hours
&& !pub_cal_free_busy
&& !pub_calendar
&& !pub_calendar2
&& !pub_oof_note
) {
1748 SIPE_DEBUG_INFO_NOFORMAT("publish_calendar_status_self: nothing has changed.");
1750 gchar
*publications
= g_strdup_printf("%s%s%s%s%s",
1751 pub_cal_working_hours
? pub_cal_working_hours
: "",
1752 pub_cal_free_busy
? pub_cal_free_busy
: "",
1753 pub_calendar
? pub_calendar
: "",
1754 pub_calendar2
? pub_calendar2
: "",
1755 pub_oof_note
? pub_oof_note
: "");
1757 send_presence_publish(sipe_private
, publications
);
1758 g_free(publications
);
1761 g_free(pub_cal_working_hours
);
1762 g_free(pub_cal_free_busy
);
1763 g_free(pub_calendar
);
1764 g_free(pub_calendar2
);
1765 g_free(pub_oof_note
);
1767 /* repeat scheduling */
1768 schedule_publish_update(sipe_private
, time(NULL
));
1771 void sipe_ocs2007_category_publish(struct sipe_core_private
*sipe_private
)
1773 gchar
*pub_state
= sipe_status_changed_by_user(sipe_private
) ?
1774 sipe_publish_get_category_state_user(sipe_private
) :
1775 sipe_publish_get_category_state_machine(sipe_private
);
1776 gchar
*pub_note
= sipe_publish_get_category_note(sipe_private
,
1778 SIPE_CORE_PRIVATE_FLAG_IS(OOF_NOTE
) ? "OOF" : "personal",
1781 gchar
*publications
;
1783 if (!pub_state
&& !pub_note
) {
1784 SIPE_DEBUG_INFO_NOFORMAT("sipe_osc2007_category_publish: nothing has changed. Exiting.");
1788 publications
= g_strdup_printf("%s%s",
1789 pub_state
? pub_state
: "",
1790 pub_note
? pub_note
: "");
1795 send_presence_publish(sipe_private
, publications
);
1796 g_free(publications
);
1799 void sipe_ocs2007_phone_state_publish(struct sipe_core_private
*sipe_private
)
1801 gchar
*publications
= NULL
;
1802 guint instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_PHONE_VOIP
);
1804 /* key is <category><instance><container> */
1805 gchar
*key_2
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 2);
1806 gchar
*key_3
= g_strdup_printf("<%s><%u><%u>", "state", instance
, 3);
1807 struct sipe_publication
*publication_2
=
1808 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_2
);
1809 struct sipe_publication
*publication_3
=
1810 g_hash_table_lookup(g_hash_table_lookup(sipe_private
->our_publications
, "state"), key_3
);
1814 publications
= g_strdup_printf((sipe_private
->media_call
) ?
1815 SIPE_PUB_XML_STATE_PHONE
: SIPE_PUB_XML_STATE_CALENDAR_PHONE_CLEAR
,
1816 instance
, publication_2
? publication_2
->version
: 0,
1817 instance
, publication_3
? publication_3
->version
: 0);
1819 send_presence_publish(sipe_private
, publications
);
1820 g_free(publications
);
1823 static void sipe_publish_get_cat_state_user_to_clear(SIPE_UNUSED_PARAMETER
const char *name
,
1827 struct sipe_publication
*publication
= value
;
1829 g_string_append_printf( str
,
1830 SIPE_PUB_XML_PUBLICATION_CLEAR
,
1831 publication
->category
,
1832 publication
->instance
,
1833 publication
->container
,
1834 publication
->version
,
1838 void sipe_ocs2007_reset_status(struct sipe_core_private
*sipe_private
)
1841 gchar
*publications
;
1843 if (!sipe_private
->user_state_publications
|| g_hash_table_size(sipe_private
->user_state_publications
) == 0) {
1844 SIPE_DEBUG_INFO_NOFORMAT("sipe_reset_status: no userState publications, exiting.");
1848 str
= g_string_new(NULL
);
1849 g_hash_table_foreach(sipe_private
->user_state_publications
, (GHFunc
)sipe_publish_get_cat_state_user_to_clear
, str
);
1850 publications
= g_string_free(str
, FALSE
);
1852 send_presence_publish(sipe_private
, publications
);
1853 g_free(publications
);
1856 /* key is <category><instance><container> */
1857 static gboolean
sipe_is_our_publication(struct sipe_core_private
*sipe_private
,
1862 /* filling keys for our publications if not yet cached */
1863 if (!sipe_private
->our_publication_keys
) {
1864 guint device_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_DEVICE
);
1865 guint machine_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_MACHINE
);
1866 guint user_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_USER
);
1867 guint calendar_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR
);
1868 guint cal_oof_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_CALENDAR_OOF
);
1869 guint phone_voip_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_STATE_PHONE_VOIP
);
1870 guint cal_data_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_CALENDAR_DATA
);
1871 guint note_oof_instance
= sipe_get_pub_instance(sipe_private
, SIPE_PUB_NOTE_OOF
);
1873 SIPE_DEBUG_INFO_NOFORMAT("* Our Publication Instances *");
1874 SIPE_DEBUG_INFO("\tDevice : %u\t0x%08X", device_instance
, device_instance
);
1875 SIPE_DEBUG_INFO("\tMachine State : %u\t0x%08X", machine_instance
, machine_instance
);
1876 SIPE_DEBUG_INFO("\tUser Stare : %u\t0x%08X", user_instance
, user_instance
);
1877 SIPE_DEBUG_INFO("\tCalendar State : %u\t0x%08X", calendar_instance
, calendar_instance
);
1878 SIPE_DEBUG_INFO("\tCalendar OOF State : %u\t0x%08X", cal_oof_instance
, cal_oof_instance
);
1879 SIPE_DEBUG_INFO("\tVOIP Phone State : %u\t0x%08X", phone_voip_instance
, phone_voip_instance
);
1880 SIPE_DEBUG_INFO("\tCalendar FreeBusy : %u\t0x%08X", cal_data_instance
, cal_data_instance
);
1881 SIPE_DEBUG_INFO("\tOOF Note : %u\t0x%08X", note_oof_instance
, note_oof_instance
);
1882 SIPE_DEBUG_INFO("\tNote : %u", 0);
1883 SIPE_DEBUG_INFO("\tCalendar WorkingHours: %u", 0);
1886 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1887 g_strdup_printf("<%s><%u><%u>", "device", device_instance
, 2));
1889 /* state:machineState */
1890 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1891 g_strdup_printf("<%s><%u><%u>", "state", machine_instance
, 2));
1892 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1893 g_strdup_printf("<%s><%u><%u>", "state", machine_instance
, 3));
1895 /* state:userState */
1896 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1897 g_strdup_printf("<%s><%u><%u>", "state", user_instance
, 2));
1898 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1899 g_strdup_printf("<%s><%u><%u>", "state", user_instance
, 3));
1901 /* state:calendarState */
1902 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1903 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance
, 2));
1904 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1905 g_strdup_printf("<%s><%u><%u>", "state", calendar_instance
, 3));
1907 /* state:calendarState OOF */
1908 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1909 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance
, 2));
1910 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1911 g_strdup_printf("<%s><%u><%u>", "state", cal_oof_instance
, 3));
1913 /* state:phoneState */
1914 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1915 g_strdup_printf("<%s><%u><%u>", "state", phone_voip_instance
, 2));
1916 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1917 g_strdup_printf("<%s><%u><%u>", "state", phone_voip_instance
, 3));
1920 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1921 g_strdup_printf("<%s><%u><%u>", "note", 0, 200));
1922 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1923 g_strdup_printf("<%s><%u><%u>", "note", 0, 300));
1924 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1925 g_strdup_printf("<%s><%u><%u>", "note", 0, 400));
1928 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1929 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 200));
1930 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1931 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 300));
1932 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1933 g_strdup_printf("<%s><%u><%u>", "note", note_oof_instance
, 400));
1935 /* calendarData:WorkingHours */
1936 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1937 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 1));
1938 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1939 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 100));
1940 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1941 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 200));
1942 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1943 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 300));
1944 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1945 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 400));
1946 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1947 g_strdup_printf("<%s><%u><%u>", "calendarData", 0, 32000));
1949 /* calendarData:FreeBusy */
1950 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1951 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 1));
1952 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1953 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 100));
1954 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1955 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 200));
1956 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1957 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 300));
1958 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1959 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 400));
1960 sipe_private
->our_publication_keys
= g_slist_append(sipe_private
->our_publication_keys
,
1961 g_strdup_printf("<%s><%u><%u>", "calendarData", cal_data_instance
, 32000));
1963 //SIPE_DEBUG_INFO("sipe_is_our_publication: sipe_private->our_publication_keys length=%d",
1964 // sipe_private->our_publication_keys ? (int) g_slist_length(sipe_private->our_publication_keys) : -1);
1967 //SIPE_DEBUG_INFO("sipe_is_our_publication: key=%s", key);
1969 entry
= sipe_private
->our_publication_keys
;
1971 //SIPE_DEBUG_INFO(" sipe_is_our_publication: entry->data=%s", entry->data);
1972 if (sipe_strequal(entry
->data
, key
)) {
1975 entry
= entry
->next
;
1980 static void sipe_refresh_blocked_status_cb(char *buddy_name
,
1981 SIPE_UNUSED_PARAMETER
struct sipe_buddy
*buddy
,
1982 struct sipe_core_private
*sipe_private
)
1984 int container_id
= sipe_ocs2007_find_access_level(sipe_private
, "user", buddy_name
, NULL
);
1985 gboolean blocked
= (container_id
== 32000);
1986 gboolean blocked_in_blist
= sipe_backend_buddy_is_blocked(SIPE_CORE_PUBLIC
, buddy_name
);
1988 /* SIPE_DEBUG_INFO("sipe_refresh_blocked_status_cb: buddy_name=%s, blocked=%s, blocked_in_blist=%s",
1989 buddy_name, blocked ? "T" : "F", blocked_in_blist ? "T" : "F"); */
1991 if (blocked
!= blocked_in_blist
) {
1992 sipe_backend_buddy_set_blocked_status(SIPE_CORE_PUBLIC
, buddy_name
, blocked
);
1996 static void sipe_refresh_blocked_status(struct sipe_core_private
*sipe_private
)
1998 g_hash_table_foreach(sipe_private
->buddies
,
1999 (GHFunc
) sipe_refresh_blocked_status_cb
,
2004 * When we receive some self (BE) NOTIFY with a new subscriber
2005 * we sends a setSubscribers request to him [SIP-PRES] 4.8
2008 void sipe_ocs2007_process_roaming_self(struct sipe_core_private
*sipe_private
,
2014 const sipe_xml
*node
;
2015 const sipe_xml
*node2
;
2016 char *display_name
= NULL
;
2018 GSList
*category_names
= NULL
;
2019 int aggreg_avail
= 0;
2020 gchar
*activity_token
= NULL
;
2021 gboolean do_update_status
= FALSE
;
2022 gboolean has_note_cleaned
= FALSE
;
2023 GHashTable
*devices
;
2025 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self");
2027 xml
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
2030 contact
= get_contact(sipe_private
);
2031 to
= sip_uri_self(sipe_private
);
2034 /* set list of categories participating in this XML */
2035 for (node
= sipe_xml_child(xml
, "categories/category"); node
; node
= sipe_xml_twin(node
)) {
2036 const gchar
*name
= sipe_xml_attribute(node
, "name");
2037 category_names
= slist_insert_unique_sorted(category_names
, (gchar
*)name
, (GCompareFunc
)strcmp
);
2039 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: category_names length=%d",
2040 category_names
? (int) g_slist_length(category_names
) : -1);
2041 /* drop category information */
2042 if (category_names
) {
2043 GSList
*entry
= category_names
;
2045 GHashTable
*cat_publications
;
2046 const gchar
*category
= entry
->data
;
2047 entry
= entry
->next
;
2048 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: dropping category: %s", category
);
2049 cat_publications
= g_hash_table_lookup(sipe_private
->our_publications
, category
);
2050 if (cat_publications
) {
2051 g_hash_table_remove(sipe_private
->our_publications
, category
);
2052 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: dropped category: %s", category
);
2056 g_slist_free(category_names
);
2058 /* filling our categories reflected in roaming data */
2059 devices
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
2061 for (node
= sipe_xml_child(xml
, "categories/category"); node
; node
= sipe_xml_twin(node
)) {
2063 const gchar
*name
= sipe_xml_attribute(node
, "name");
2064 guint container
= sipe_xml_int_attribute(node
, "container", -1);
2065 guint instance
= sipe_xml_int_attribute(node
, "instance", -1);
2066 guint version
= sipe_xml_int_attribute(node
, "version", 0);
2067 time_t publish_time
= (tmp
= sipe_xml_attribute(node
, "publishTime")) ?
2068 sipe_utils_str_to_time(tmp
) : 0;
2070 GHashTable
*cat_publications
= g_hash_table_lookup(sipe_private
->our_publications
, name
);
2072 /* Ex. clear note: <category name="note"/> */
2073 if (container
== (guint
)-1) {
2074 g_free(sipe_private
->note
);
2075 sipe_private
->note
= NULL
;
2076 do_update_status
= TRUE
;
2080 /* Ex. clear note: <category name="note" container="200"/> */
2081 if (instance
== (guint
)-1) {
2082 if (container
== 200) {
2083 g_free(sipe_private
->note
);
2084 sipe_private
->note
= NULL
;
2085 do_update_status
= TRUE
;
2087 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removing publications for: %s/%u", name
, container
);
2088 sipe_remove_category_container_publications(
2089 sipe_private
->our_publications
, name
, container
);
2093 /* key is <category><instance><container> */
2094 key
= g_strdup_printf("<%s><%u><%u>", name
, instance
, container
);
2095 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: key=%s version=%d", key
, version
);
2097 /* capture all userState publication for later clean up if required */
2098 if (sipe_strequal(name
, "state") && (container
== 2 || container
== 3)) {
2099 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
2101 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "userState")) {
2102 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
2103 publication
->category
= g_strdup(name
);
2104 publication
->instance
= instance
;
2105 publication
->container
= container
;
2106 publication
->version
= version
;
2108 if (!sipe_private
->user_state_publications
) {
2109 sipe_private
->user_state_publications
= g_hash_table_new_full(
2110 g_str_hash
, g_str_equal
,
2111 g_free
, (GDestroyNotify
)free_publication
);
2113 g_hash_table_insert(sipe_private
->user_state_publications
, g_strdup(key
), publication
);
2114 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added to user_state_publications key=%s version=%d",
2119 /* count each client instance only once */
2120 if (sipe_strequal(name
, "device"))
2121 g_hash_table_replace(devices
, g_strdup_printf("%u", instance
), NULL
);
2123 if (sipe_is_our_publication(sipe_private
, key
)) {
2124 struct sipe_publication
*publication
= g_new0(struct sipe_publication
, 1);
2126 publication
->category
= g_strdup(name
);
2127 publication
->instance
= instance
;
2128 publication
->container
= container
;
2129 publication
->version
= version
;
2131 /* filling publication->availability */
2132 if (sipe_strequal(name
, "state")) {
2133 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
2134 const sipe_xml
*xn_avail
= sipe_xml_child(xn_state
, "availability");
2137 gchar
*avail_str
= sipe_xml_data(xn_avail
);
2139 publication
->availability
= atoi(avail_str
);
2143 /* for calendarState */
2144 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "calendarState")) {
2145 const sipe_xml
*xn_activity
= sipe_xml_child(xn_state
, "activity");
2146 struct sipe_cal_event
*event
= g_new0(struct sipe_cal_event
, 1);
2148 event
->start_time
= sipe_utils_str_to_time(sipe_xml_attribute(xn_state
, "startTime"));
2150 if (sipe_strequal(sipe_xml_attribute(xn_activity
, "token"),
2151 sipe_status_activity_to_token(SIPE_ACTIVITY_IN_MEETING
)))
2153 event
->is_meeting
= TRUE
;
2156 event
->subject
= sipe_xml_data(sipe_xml_child(xn_state
, "meetingSubject"));
2157 event
->location
= sipe_xml_data(sipe_xml_child(xn_state
, "meetingLocation"));
2159 publication
->cal_event_hash
= sipe_cal_event_hash(event
);
2160 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: hash=%s",
2161 publication
->cal_event_hash
);
2162 sipe_cal_event_free(event
);
2165 /* filling publication->note */
2166 if (sipe_strequal(name
, "note")) {
2167 const sipe_xml
*xn_body
= sipe_xml_child(node
, "note/body");
2169 if (!has_note_cleaned
) {
2170 has_note_cleaned
= TRUE
;
2172 g_free(sipe_private
->note
);
2173 sipe_private
->note
= NULL
;
2174 sipe_private
->note_since
= publish_time
;
2176 do_update_status
= TRUE
;
2179 g_free(publication
->note
);
2180 publication
->note
= NULL
;
2184 publication
->note
= g_markup_escape_text((tmp
= sipe_xml_data(xn_body
)), -1);
2186 if (publish_time
>= sipe_private
->note_since
) {
2187 g_free(sipe_private
->note
);
2188 sipe_private
->note
= g_strdup(publication
->note
);
2189 sipe_private
->note_since
= publish_time
;
2190 if (sipe_strequal(sipe_xml_attribute(xn_body
, "type"), "OOF"))
2191 SIPE_CORE_PRIVATE_FLAG_SET(OOF_NOTE
);
2193 SIPE_CORE_PRIVATE_FLAG_UNSET(OOF_NOTE
);
2195 do_update_status
= TRUE
;
2200 /* filling publication->fb_start_str, free_busy_base64, working_hours_xml_str */
2201 if (sipe_strequal(name
, "calendarData") && (publication
->container
== 300)) {
2202 const sipe_xml
*xn_free_busy
= sipe_xml_child(node
, "calendarData/freeBusy");
2203 const sipe_xml
*xn_working_hours
= sipe_xml_child(node
, "calendarData/WorkingHours");
2205 publication
->fb_start_str
= g_strdup(sipe_xml_attribute(xn_free_busy
, "startTime"));
2206 publication
->free_busy_base64
= sipe_xml_data(xn_free_busy
);
2208 if (xn_working_hours
) {
2209 publication
->working_hours_xml_str
= sipe_xml_stringify(xn_working_hours
);
2213 if (!cat_publications
) {
2214 cat_publications
= g_hash_table_new_full(
2215 g_str_hash
, g_str_equal
,
2216 g_free
, (GDestroyNotify
)free_publication
);
2217 g_hash_table_insert(sipe_private
->our_publications
, g_strdup(name
), cat_publications
);
2218 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added GHashTable cat=%s", name
);
2220 g_hash_table_insert(cat_publications
, g_strdup(key
), publication
);
2221 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added key=%s version=%d", key
, version
);
2225 /* aggregateState (not an our publication) from 2-nd container */
2226 if (sipe_strequal(name
, "state") && container
== 2) {
2227 const sipe_xml
*xn_state
= sipe_xml_child(node
, "state");
2228 const sipe_xml
*xn_activity
= sipe_xml_child(xn_state
, "activity");
2230 if (xn_state
&& sipe_strequal(sipe_xml_attribute(xn_state
, "type"), "aggregateState")) {
2231 const sipe_xml
*xn_avail
= sipe_xml_child(xn_state
, "availability");
2234 gchar
*avail_str
= sipe_xml_data(xn_avail
);
2236 aggreg_avail
= atoi(avail_str
);
2241 do_update_status
= TRUE
;
2245 activity_token
= g_strdup(sipe_xml_attribute(xn_activity
, "token"));
2249 /* userProperties published by server from AD */
2250 if (!sipe_private
->csta
&&
2251 sipe_strequal(name
, "userProperties")) {
2252 const sipe_xml
*line
;
2253 /* line, for Remote Call Control (RCC) */
2254 for (line
= sipe_xml_child(node
, "userProperties/lines/line"); line
; line
= sipe_xml_twin(line
)) {
2255 const gchar
*line_server
= sipe_xml_attribute(line
, "lineServer");
2256 const gchar
*line_type
= sipe_xml_attribute(line
, "lineType");
2259 if (!line_server
|| !(sipe_strequal(line_type
, "Rcc") || sipe_strequal(line_type
, "Dual"))) continue;
2261 line_uri
= sipe_xml_data(line
);
2263 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: line_uri=%s server=%s", line_uri
, line_server
);
2264 sip_csta_open(sipe_private
, line_uri
, line_server
);
2272 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sipe_private->our_publications size=%d",
2273 sipe_private
->our_publications
? (int) g_hash_table_size(sipe_private
->our_publications
) : -1);
2275 /* active clients for user account */
2276 if (g_hash_table_size(devices
) > 1) {
2277 SIPE_CORE_PRIVATE_FLAG_SET(MPOP
);
2278 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: multiple clients detected (%d)",
2279 g_hash_table_size(devices
));
2281 SIPE_CORE_PRIVATE_FLAG_UNSET(MPOP
);
2282 SIPE_DEBUG_INFO_NOFORMAT("sipe_ocs2007_process_roaming_self: single client detected");
2284 g_hash_table_destroy(devices
);
2287 for (node
= sipe_xml_child(xml
, "containers/container"); node
; node
= sipe_xml_twin(node
)) {
2288 guint id
= sipe_xml_int_attribute(node
, "id", 0);
2289 struct sipe_container
*container
= sipe_find_container(sipe_private
, id
);
2292 sipe_private
->containers
= g_slist_remove(sipe_private
->containers
, container
);
2293 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: removed existing container id=%d v%d", container
->id
, container
->version
);
2294 sipe_ocs2007_free_container(container
);
2296 container
= g_new0(struct sipe_container
, 1);
2298 container
->version
= sipe_xml_int_attribute(node
, "version", 0);
2299 sipe_private
->containers
= g_slist_append(sipe_private
->containers
, container
);
2300 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container id=%d v%d", container
->id
, container
->version
);
2302 for (node2
= sipe_xml_child(node
, "member"); node2
; node2
= sipe_xml_twin(node2
)) {
2303 struct sipe_container_member
*member
= g_new0(struct sipe_container_member
, 1);
2304 member
->type
= g_strdup(sipe_xml_attribute(node2
, "type"));
2305 member
->value
= g_strdup(sipe_xml_attribute(node2
, "value"));
2306 container
->members
= g_slist_append(container
->members
, member
);
2307 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: added container member type=%s value=%s",
2308 member
->type
, member
->value
? member
->value
: "");
2312 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: access_level_set=%s",
2313 SIPE_CORE_PRIVATE_FLAG_IS(ACCESS_LEVEL_SET
) ? "TRUE" : "FALSE");
2314 if (!SIPE_CORE_PRIVATE_FLAG_IS(ACCESS_LEVEL_SET
) && sipe_xml_child(xml
, "containers")) {
2315 char *container_xmls
= NULL
;
2316 int sameEnterpriseAL
= sipe_ocs2007_find_access_level(sipe_private
, "sameEnterprise", NULL
, NULL
);
2317 int federatedAL
= sipe_ocs2007_find_access_level(sipe_private
, "federated", NULL
, NULL
);
2319 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: sameEnterpriseAL=%d", sameEnterpriseAL
);
2320 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: federatedAL=%d", federatedAL
);
2321 /* initial set-up to let counterparties see your status */
2322 if (sameEnterpriseAL
< 0) {
2323 struct sipe_container
*container
= sipe_find_container(sipe_private
, 200);
2324 guint version
= container
? container
->version
: 0;
2325 sipe_send_container_members_prepare(200, version
, "add", "sameEnterprise", NULL
, &container_xmls
);
2327 if (federatedAL
< 0) {
2328 struct sipe_container
*container
= sipe_find_container(sipe_private
, 100);
2329 guint version
= container
? container
->version
: 0;
2330 sipe_send_container_members_prepare(100, version
, "add", "federated", NULL
, &container_xmls
);
2332 SIPE_CORE_PRIVATE_FLAG_SET(ACCESS_LEVEL_SET
);
2334 if (container_xmls
) {
2335 sipe_send_set_container_members(sipe_private
, container_xmls
);
2337 g_free(container_xmls
);
2340 /* Refresh contacts' blocked status */
2341 sipe_refresh_blocked_status(sipe_private
);
2344 for (node
= sipe_xml_child(xml
, "subscribers/subscriber"); node
; node
= sipe_xml_twin(node
)) {
2346 const char *acknowledged
;
2350 user
= sipe_xml_attribute(node
, "user"); /* without 'sip:' prefix */
2351 if (!user
) continue;
2352 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user %s", user
);
2353 display_name
= g_strdup(sipe_xml_attribute(node
, "displayName"));
2354 uri
= sip_uri_from_name(user
);
2356 sipe_buddy_update_property(sipe_private
, uri
, SIPE_BUDDY_INFO_DISPLAY_NAME
, display_name
);
2358 acknowledged
= sipe_xml_attribute(node
, "acknowledged");
2359 if(sipe_strcase_equal(acknowledged
,"false")){
2360 SIPE_DEBUG_INFO("sipe_ocs2007_process_roaming_self: user added you %s", user
);
2361 if (!sipe_backend_buddy_find(SIPE_CORE_PUBLIC
, uri
, NULL
)) {
2362 sipe_backend_buddy_request_add(SIPE_CORE_PUBLIC
, uri
, display_name
);
2365 hdr
= g_strdup_printf(
2367 "Content-Type: application/msrtc-presence-setsubscriber+xml\r\n", contact
);
2369 body
= g_strdup_printf(
2370 "<setSubscribers xmlns=\"http://schemas.microsoft.com/2006/09/sip/presence-subscribers\">"
2371 "<subscriber user=\"%s\" acknowledged=\"true\"/>"
2372 "</setSubscribers>", user
);
2374 sip_transport_service(sipe_private
,
2382 g_free(display_name
);
2389 /* Publish initial state if not yet.
2390 * Assuming this happens on initial responce to subscription to roaming-self
2391 * so we've already updated our roaming data in full.
2394 if (!SIPE_CORE_PRIVATE_FLAG_IS(INITIAL_PUBLISH
)) {
2395 send_publish_category_initial(sipe_private
);
2396 sipe_groupchat_init(sipe_private
);
2397 SIPE_CORE_PRIVATE_FLAG_SET(INITIAL_PUBLISH
);
2399 sipe_cal_delayed_calendar_update(sipe_private
);
2400 do_update_status
= FALSE
;
2401 } else if (aggreg_avail
) {
2404 (aggreg_avail
< SIPE_OCS2007_LEGACY_AVAILIBILITY_OFFLINE
)) {
2406 sipe_status_set_token(sipe_private
,
2407 sipe_ocs2007_status_from_legacy_availability(aggreg_avail
, activity_token
));
2409 /* do not let offline status switch us off */
2410 sipe_status_set_activity(sipe_private
,
2411 SIPE_ACTIVITY_INVISIBLE
);
2415 if (do_update_status
) {
2416 sipe_status_and_note(sipe_private
, NULL
);
2420 g_free(activity_token
);
2424 * for Access levels menu
2426 #define INDENT_FMT " %s"
2429 * Member is indirectly belong to access level container.
2430 * For example 'sameEnterprise' is in the container and user
2431 * belongs to that same enterprise.
2433 #define INDENT_MARKED_INHERITED_FMT "= %s"
2435 static struct sipe_backend_buddy_menu
*access_levels_menu(struct sipe_core_private
*sipe_private
,
2436 struct sipe_backend_buddy_menu
*menu
,
2437 const gchar
*member_type
,
2438 const gchar
*member_value
,
2439 const gboolean extra_menu
)
2442 gboolean is_group_access
= FALSE
;
2446 menu
= sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC
);
2448 container_id
= sipe_ocs2007_find_access_level(sipe_private
,
2453 for (i
= 1; i
<= CONTAINERS_LEN
; i
++) {
2455 * Blocked should remain in the first place
2456 * in the containers[] array.
2458 unsigned int j
= (i
== CONTAINERS_LEN
) ? 0 : i
;
2459 int container_j
= containers
[j
];
2460 const gchar
*acc_level_name
= sipe_ocs2007_access_level_name(container_j
);
2461 struct sipe_container
*container
= create_container(j
,
2467 /* libpurple memory leak workaround */
2468 blist_menu_remember_container(sipe_private
, container
);
2470 /* current container/access level */
2471 if (container_j
== container_id
) {
2472 label
= is_group_access
?
2473 g_strdup_printf(INDENT_MARKED_INHERITED_FMT
, acc_level_name
) :
2474 g_strdup_printf(SIPE_OCS2007_INDENT_MARKED_FMT
, acc_level_name
);
2476 label
= g_strdup_printf(INDENT_FMT
, acc_level_name
);
2479 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2482 SIPE_BUDDY_MENU_CHANGE_ACCESS_LEVEL
,
2487 if (extra_menu
&& (container_id
>= 0) && !is_group_access
) {
2488 struct sipe_container
*container
= create_container(0,
2495 menu
= sipe_backend_buddy_menu_separator(SIPE_CORE_PUBLIC
,
2500 /* libpurple memory leak workaround */
2501 blist_menu_remember_container(sipe_private
, container
);
2503 /* Translators: remove (clear) previously assigned access level */
2504 label
= g_strdup_printf(INDENT_FMT
, _("Unspecify"));
2505 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2508 SIPE_BUDDY_MENU_CHANGE_ACCESS_LEVEL
,
2516 static struct sipe_backend_buddy_menu
*access_groups_menu(struct sipe_core_private
*sipe_private
)
2518 struct sipe_backend_buddy_menu
*menu
= sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC
);
2519 GSList
*access_domains
, *entry
;
2521 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2523 _("People in my company"),
2524 access_levels_menu(sipe_private
,
2530 /* this is original name, don't edit */
2531 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2533 _("People in domains connected with my company"),
2534 access_levels_menu(sipe_private
,
2540 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2542 _("People in public domains"),
2543 access_levels_menu(sipe_private
,
2549 entry
= access_domains
= get_access_domains(sipe_private
);
2551 gchar
*domain
= entry
->data
;
2552 gchar
*menu_name
= g_strdup_printf(_("People at %s"), domain
);
2554 /* takes over ownership of entry->data (= domain) */
2555 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2558 access_levels_menu(sipe_private
,
2565 entry
= entry
->next
;
2567 g_slist_free(access_domains
);
2570 /* People in domains connected with my company */
2571 menu
= sipe_backend_buddy_menu_separator(SIPE_CORE_PUBLIC
,
2573 "-------------------------------------------");
2575 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2577 _("Add new domain..."),
2578 SIPE_BUDDY_MENU_ADD_NEW_DOMAIN
,
2584 struct sipe_backend_buddy_menu
*sipe_ocs2007_access_control_menu(struct sipe_core_private
*sipe_private
,
2585 const gchar
*buddy_name
)
2587 struct sipe_backend_buddy_menu
*menu
= sipe_backend_buddy_menu_start(SIPE_CORE_PUBLIC
);
2591 * Workaround for missing libpurple API to release resources allocated
2592 * during blist_node_menu() callback. See also:
2594 * <http://developer.pidgin.im/ticket/12597>
2596 * We remember all memory blocks in a list and deallocate them when
2598 * - the next time we enter the callback, or
2599 * - the account is disconnected
2601 * That means that after the buddy menu has been closed we have unused
2602 * resources but at least we don't leak them anymore...
2604 sipe_core_buddy_menu_free(SIPE_CORE_PUBLIC
);
2606 label
= g_strdup_printf(INDENT_FMT
, _("Online help..."));
2607 menu
= sipe_backend_buddy_menu_add(SIPE_CORE_PUBLIC
,
2610 SIPE_BUDDY_MENU_ACCESS_LEVEL_HELP
,
2614 label
= g_strdup_printf(INDENT_FMT
, _("Access groups"));
2615 menu
= sipe_backend_buddy_sub_menu_add(SIPE_CORE_PUBLIC
,
2618 access_groups_menu(sipe_private
));
2621 menu
= access_levels_menu(sipe_private
,
2624 sipe_get_no_sip_uri(buddy_name
),