subscriptions: DRY removal for allowed event check
[siplcs.git] / src / core / sipe-subscriptions.c
blobdccca1e1b6c6838d7d6d03ce28dac6a6d59d6412
1 /**
2 * @file sipe-subscriptions.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2013 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <stdlib.h>
24 #include <string.h>
26 #include <glib.h>
28 #include "sipe-common.h"
29 #include "sipmsg.h"
30 #include "sip-transport.h"
31 #include "sipe-backend.h"
32 #include "sipe-buddy.h"
33 #include "sipe-core.h"
34 #include "sipe-core-private.h"
35 #include "sipe-dialog.h"
36 #include "sipe-mime.h"
37 #include "sipe-notify.h"
38 #include "sipe-schedule.h"
39 #include "sipe-subscriptions.h"
40 #include "sipe-utils.h"
41 #include "sipe-xml.h"
43 /* RFC3265 subscription */
44 struct sip_subscription {
45 struct sip_dialog dialog;
46 gchar *event;
49 static void sipe_subscription_free(struct sip_subscription *subscription)
51 if (!subscription) return;
53 g_free(subscription->event);
54 /* NOTE: use cast to prevent BAD_FREE warning from Coverity */
55 sipe_dialog_free((struct sip_dialog *) subscription);
58 void sipe_subscriptions_init(struct sipe_core_private *sipe_private)
60 sipe_private->subscriptions = g_hash_table_new_full(g_str_hash,
61 g_str_equal,
62 g_free,
63 (GDestroyNotify)sipe_subscription_free);
66 static void sipe_unsubscribe_cb(SIPE_UNUSED_PARAMETER gpointer key,
67 gpointer value, gpointer user_data)
69 struct sip_subscription *subscription = value;
70 struct sip_dialog *dialog = &subscription->dialog;
71 struct sipe_core_private *sipe_private = user_data;
72 gchar *contact = get_contact(sipe_private);
73 gchar *hdr = g_strdup_printf(
74 "Event: %s\r\n"
75 "Expires: 0\r\n"
76 "Contact: %s\r\n", subscription->event, contact);
77 g_free(contact);
79 /* Rate limit to max. 25 requests per seconds */
80 g_usleep(1000000 / 25);
82 sip_transport_subscribe(sipe_private,
83 dialog->with,
84 hdr,
85 NULL,
86 dialog,
87 NULL);
89 g_free(hdr);
92 void sipe_subscriptions_unsubscribe(struct sipe_core_private *sipe_private)
94 /* unsubscribe all */
95 g_hash_table_foreach(sipe_private->subscriptions,
96 sipe_unsubscribe_cb,
97 sipe_private);
101 void sipe_subscriptions_destroy(struct sipe_core_private *sipe_private)
103 g_hash_table_destroy(sipe_private->subscriptions);
106 static void sipe_subscription_remove(struct sipe_core_private *sipe_private,
107 const gchar *key)
109 if (g_hash_table_lookup(sipe_private->subscriptions, key)) {
110 g_hash_table_remove(sipe_private->subscriptions, key);
111 SIPE_DEBUG_INFO("sipe_subscription_remove: %s", key);
116 * Generate subscription key
118 * @param event event name (must not by @c NULL)
119 * @param uri presence URI (ignored if @c event != "presence")
121 * @return key string. Must be g_free()'d after use.
123 static gchar *sipe_subscription_key(const gchar *event,
124 const gchar *uri)
126 if (!g_ascii_strcasecmp(event, "presence"))
127 /* Subscription is identified by <presence><uri> key */
128 return(sipe_utils_presence_key(uri));
129 else
130 /* Subscription is identified by <event> key */
131 return(g_strdup_printf("<%s>", event));
134 void sipe_subscription_terminate(struct sipe_core_private *sipe_private,
135 const gchar *event,
136 const gchar *who)
138 gchar *key = sipe_subscription_key(event, who);
139 sipe_subscription_remove(sipe_private, key);
140 g_free(key);
143 gboolean sipe_subscription_is_allowed(struct sipe_core_private *sipe_private,
144 const gchar *event)
146 return(g_slist_find_custom(sipe_private->allowed_events,
147 event,
148 (GCompareFunc) g_ascii_strcasecmp) != NULL);
151 static void sipe_presence_timeout_mime_cb(gpointer user_data,
152 SIPE_UNUSED_PARAMETER const GSList *fields,
153 const gchar *body,
154 gsize length)
156 GSList **buddies = user_data;
157 sipe_xml *xml = sipe_xml_parse(body, length);
159 if (xml && !sipe_strequal(sipe_xml_name(xml), "list")) {
160 const gchar *uri = sipe_xml_attribute(xml, "uri");
161 const sipe_xml *xn_category;
164 * automaton: presence is never expected to change
166 * see: http://msdn.microsoft.com/en-us/library/ee354295(office.13).aspx
168 for (xn_category = sipe_xml_child(xml, "category");
169 xn_category;
170 xn_category = sipe_xml_twin(xn_category)) {
171 if (sipe_strequal(sipe_xml_attribute(xn_category, "name"),
172 "contactCard")) {
173 const sipe_xml *node = sipe_xml_child(xn_category, "contactCard/automaton");
174 if (node) {
175 char *boolean = sipe_xml_data(node);
176 if (sipe_strequal(boolean, "true")) {
177 SIPE_DEBUG_INFO("sipe_process_presence_timeout: %s is an automaton: - not subscribing to presence updates",
178 uri);
179 uri = NULL;
181 g_free(boolean);
183 break;
187 if (uri) {
188 *buddies = g_slist_append(*buddies, sip_uri(uri));
192 sipe_xml_free(xml);
195 static void sipe_process_presence_timeout(struct sipe_core_private *sipe_private,
196 struct sipmsg *msg,
197 const gchar *who,
198 int timeout)
200 const char *ctype = sipmsg_find_header(msg, "Content-Type");
201 gchar *action_name = sipe_utils_presence_key(who);
203 SIPE_DEBUG_INFO("sipe_process_presence_timeout: Content-Type: %s", ctype ? ctype : "");
205 if (ctype &&
206 strstr(ctype, "multipart") &&
207 (strstr(ctype, "application/rlmi+xml") ||
208 strstr(ctype, "application/msrtc-event-categories+xml"))) {
209 GSList *buddies = NULL;
211 sipe_mime_parts_foreach(ctype, msg->body, sipe_presence_timeout_mime_cb, &buddies);
213 if (buddies)
214 sipe_subscribe_presence_batched_schedule(sipe_private,
215 action_name,
216 who,
217 buddies,
218 timeout);
220 } else {
221 sipe_schedule_seconds(sipe_private,
222 action_name,
223 g_strdup(who),
224 timeout,
225 sipe_subscribe_presence_single,
226 g_free);
227 SIPE_DEBUG_INFO("Resubscription single contact with batched support(%s) in %d", who, timeout);
229 g_free(action_name);
232 static void sipe_subscription_expiration(struct sipe_core_private *sipe_private,
233 struct sipmsg *msg,
234 const gchar *event)
236 const gchar *expires_header = sipmsg_find_header(msg, "Expires");
237 guint timeout = expires_header ? strtol(expires_header, NULL, 10) : 0;
239 SIPE_DEBUG_INFO("sipe_subscription_expiration: subscription '%s' expires in %d seconds",
240 event, timeout);
242 if (timeout) {
243 /* 2 min ahead of expiration */
244 if (timeout > 240) timeout -= 120;
246 if (sipe_strcase_equal(event, "presence.wpending") &&
247 sipe_subscription_is_allowed(sipe_private,
248 "presence.wpending")) {
249 gchar *action_name = g_strdup_printf("<%s>", "presence.wpending");
250 sipe_schedule_seconds(sipe_private,
251 action_name,
252 NULL,
253 timeout,
254 sipe_subscribe_presence_wpending,
255 NULL);
256 g_free(action_name);
258 } else if (sipe_strcase_equal(event, "presence") &&
259 sipe_subscription_is_allowed(sipe_private,
260 "presence")) {
261 gchar *who = parse_from(sipmsg_find_header(msg, "To"));
262 gchar *action_name = sipe_utils_presence_key(who);
264 if (SIPE_CORE_PRIVATE_FLAG_IS(BATCHED_SUPPORT)) {
265 sipe_process_presence_timeout(sipe_private, msg, who, timeout);
266 } else {
267 sipe_schedule_seconds(sipe_private,
268 action_name,
269 g_strdup(who),
270 timeout,
271 sipe_subscribe_presence_single,
272 g_free);
273 SIPE_DEBUG_INFO("Resubscription single contact (%s) in %d", who, timeout);
275 g_free(action_name);
276 g_free(who);
281 static gboolean process_subscribe_response(struct sipe_core_private *sipe_private,
282 struct sipmsg *msg,
283 struct transaction *trans)
285 gchar *with = parse_from(sipmsg_find_header(msg, "To"));
286 const gchar *event = sipmsg_find_header(msg, "Event");
288 /* The case with 2005 Public IM Connectivity (PIC) - no Event header */
289 if (!event) {
290 struct sipmsg *request_msg = trans->msg;
291 event = sipmsg_find_header(request_msg, "Event");
294 if (event) {
295 gchar *key = sipe_subscription_key(event, with);
297 /* 200 OK; 481 Call Leg Does Not Exist */
298 if (msg->response == 200 || msg->response == 481)
299 sipe_subscription_remove(sipe_private, key);
301 /* create/store subscription dialog if not yet */
302 if (msg->response == 200) {
303 struct sip_subscription *subscription = g_new0(struct sip_subscription, 1);
304 g_hash_table_insert(sipe_private->subscriptions,
305 g_strdup(key),
306 subscription);
308 subscription->dialog.callid = g_strdup(sipmsg_find_header(msg, "Call-ID"));
309 subscription->dialog.cseq = sipmsg_parse_cseq(msg);
310 subscription->dialog.with = g_strdup(with);
311 subscription->event = g_strdup(event);
312 sipe_dialog_parse(&subscription->dialog, msg, TRUE);
314 SIPE_DEBUG_INFO("process_subscribe_response: subscription dialog added for: %s",
315 key);
318 g_free(key);
320 g_free(with);
322 if (sipmsg_find_header(msg, "ms-piggyback-cseq")) {
323 process_incoming_notify(sipe_private, msg, FALSE);
324 if (event)
325 sipe_subscription_expiration(sipe_private, msg, event);
328 return(TRUE);
332 * common subscription code
334 void sipe_subscribe(struct sipe_core_private *sipe_private,
335 const gchar *uri,
336 const gchar *event,
337 const gchar *accept,
338 const gchar *addheaders,
339 const gchar *body,
340 struct sip_dialog *dialog)
342 gchar *contact = get_contact(sipe_private);
343 gchar *hdr = g_strdup_printf(
344 "Event: %s\r\n"
345 "Accept: %s\r\n"
346 "Supported: com.microsoft.autoextend\r\n"
347 "Supported: ms-benotify\r\n"
348 "Proxy-Require: ms-benotify\r\n"
349 "Supported: ms-piggyback-first-notify\r\n"
350 "%s"
351 "Contact: %s\r\n",
352 event,
353 accept,
354 addheaders ? addheaders : "",
355 contact);
356 g_free(contact);
359 sip_transport_subscribe(sipe_private,
360 uri,
361 hdr,
362 body,
363 dialog,
364 process_subscribe_response);
366 g_free(hdr);
370 * common subscription code for self-subscriptions
372 static void sipe_subscribe_self(struct sipe_core_private *sipe_private,
373 const gchar *event,
374 const gchar *accept,
375 const gchar *addheaders,
376 const gchar *body,
377 struct sip_dialog *dialog)
379 gchar *self = sip_uri_self(sipe_private);
381 sipe_subscribe(sipe_private,
382 self,
383 event,
384 accept,
385 addheaders,
386 body,
387 dialog);
389 g_free(self);
392 static struct sip_dialog *sipe_subscribe_dialog(struct sipe_core_private *sipe_private,
393 const gchar *key)
395 struct sip_dialog *dialog = g_hash_table_lookup(sipe_private->subscriptions,
396 key);
397 SIPE_DEBUG_INFO("sipe_subscribe_dialog: dialog for '%s' is %s", key, dialog ? "not NULL" : "NULL");
398 return dialog;
401 static void sipe_subscribe_presence_buddy(struct sipe_core_private *sipe_private,
402 const gchar *uri,
403 const gchar *request,
404 const gchar *body)
406 gchar *key = sipe_utils_presence_key(uri);
408 sip_transport_subscribe(sipe_private,
409 uri,
410 request,
411 body,
412 sipe_subscribe_dialog(sipe_private, key),
413 process_subscribe_response);
415 g_free(key);
418 void sipe_subscribe_presence_wpending(struct sipe_core_private *sipe_private,
419 SIPE_UNUSED_PARAMETER void *unused)
421 gchar *key = sipe_subscription_key("presence.wpending", NULL);
423 sipe_subscribe_self(sipe_private,
424 "presence.wpending",
425 "text/xml+msrtc.wpending",
426 NULL,
427 NULL,
428 sipe_subscribe_dialog(sipe_private, key));
430 g_free(key);
434 * Subscribe roaming ACL
436 void sipe_subscribe_roaming_acl(struct sipe_core_private *sipe_private)
438 sipe_subscribe_self(sipe_private,
439 "vnd-microsoft-roaming-ACL",
440 "application/vnd-microsoft-roaming-acls+xml",
441 NULL,
442 NULL,
443 NULL);
447 * Subscribe roaming contacts
449 void sipe_subscribe_roaming_contacts(struct sipe_core_private *sipe_private)
451 sipe_subscribe_self(sipe_private,
452 "vnd-microsoft-roaming-contacts",
453 "application/vnd-microsoft-roaming-contacts+xml",
454 NULL,
455 NULL,
456 NULL);
460 * OCS 2005 version
462 void sipe_subscribe_roaming_provisioning(struct sipe_core_private *sipe_private)
464 sipe_subscribe_self(sipe_private,
465 "vnd-microsoft-provisioning",
466 "application/vnd-microsoft-roaming-provisioning+xml",
467 "Expires: 0\r\n",
468 NULL,
469 NULL);
473 * Subscription for provisioning information to help with initial
474 * configuration. This subscription is a one-time query (denoted by the
475 * Expires header, which asks for 0 seconds for the subscription lifetime).
476 * This subscription asks for server configuration, meeting policies, and
477 * policy settings that Communicator must enforce.
479 void sipe_subscribe_roaming_provisioning_v2(struct sipe_core_private *sipe_private)
481 sipe_subscribe_self(sipe_private,
482 "vnd-microsoft-provisioning-v2",
483 "application/vnd-microsoft-roaming-provisioning-v2+xml",
484 "Expires: 0\r\n"
485 "Content-Type: application/vnd-microsoft-roaming-provisioning-v2+xml\r\n",
486 "<provisioningGroupList xmlns=\"http://schemas.microsoft.com/2006/09/sip/provisioninggrouplist\">"
487 "<provisioningGroup name=\"ServerConfiguration\"/><provisioningGroup name=\"meetingPolicy\"/>"
488 "<provisioningGroup name=\"ucPolicy\"/>"
489 "</provisioningGroupList>",
490 NULL);
494 * To request for presence information about the user, access level settings
495 * that have already been configured by the user to control who has access to
496 * what information, and the list of contacts who currently have outstanding
497 * subscriptions.
499 * We wait for (BE)NOTIFY messages with some info change (categories,
500 * containers, subscribers)
502 void sipe_subscribe_roaming_self(struct sipe_core_private *sipe_private)
504 sipe_subscribe_self(sipe_private,
505 "vnd-microsoft-roaming-self",
506 "application/vnd-microsoft-roaming-self+xml",
507 "Content-Type: application/vnd-microsoft-roaming-self+xml\r\n",
508 "<roamingList xmlns=\"http://schemas.microsoft.com/2006/09/sip/roaming-self\">"
509 "<roaming type=\"categories\"/>"
510 "<roaming type=\"containers\"/>"
511 "<roaming type=\"subscribers\"/></roamingList>",
512 NULL);
516 * Single Category SUBSCRIBE [MS-PRES] ; To send when the server returns a 200 OK message with state="resubscribe" in response.
517 * The user sends a single SUBSCRIBE request to the subscribed contact.
518 * The To-URI and the URI listed in the resource list MUST be the same for a single category SUBSCRIBE request.
521 void sipe_subscribe_presence_single(struct sipe_core_private *sipe_private,
522 gpointer buddy_name)
524 gchar *to = sip_uri((gchar *)buddy_name);
525 gchar *tmp = get_contact(sipe_private);
526 gchar *request;
527 gchar *content = NULL;
528 gchar *autoextend = "";
529 gchar *content_type = "";
530 struct sipe_buddy *sbuddy = g_hash_table_lookup(sipe_private->buddies, to);
531 gchar *context = sbuddy && sbuddy->just_added ? "><context/></resource>" : "/>";
533 if (sbuddy) sbuddy->just_added = FALSE;
535 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
536 content_type = "Content-Type: application/msrtc-adrl-categorylist+xml\r\n";
537 } else {
538 autoextend = "Supported: com.microsoft.autoextend\r\n";
541 request = g_strdup_printf("Accept: application/msrtc-event-categories+xml, text/xml+msrtc.pidf, application/xpidf+xml, application/pidf+xml, application/rlmi+xml, multipart/related\r\n"
542 "Supported: ms-piggyback-first-notify\r\n"
543 "%s%sSupported: ms-benotify\r\n"
544 "Proxy-Require: ms-benotify\r\n"
545 "Event: presence\r\n"
546 "Contact: %s\r\n",
547 autoextend,
548 content_type,
549 tmp);
551 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
552 content = g_strdup_printf("<batchSub xmlns=\"http://schemas.microsoft.com/2006/01/sip/batch-subscribe\" uri=\"sip:%s\" name=\"\">\n"
553 "<action name=\"subscribe\" id=\"63792024\"><adhocList>\n"
554 "<resource uri=\"%s\"%s\n"
555 "</adhocList>\n"
556 "<categoryList xmlns=\"http://schemas.microsoft.com/2006/09/sip/categorylist\">\n"
557 "<category name=\"calendarData\"/>\n"
558 "<category name=\"contactCard\"/>\n"
559 "<category name=\"note\"/>\n"
560 "<category name=\"state\"/>\n"
561 "</categoryList>\n"
562 "</action>\n"
563 "</batchSub>",
564 sipe_private->username,
566 context);
569 g_free(tmp);
571 sipe_subscribe_presence_buddy(sipe_private, to, request, content);
573 g_free(content);
574 g_free(to);
575 g_free(request);
579 * Support for Batch Category SUBSCRIBE [MS-PRES] - msrtc-event-categories+xml OCS 2007
580 * Support for Batch Category SUBSCRIBE [MS-SIP] - adrl+xml LCS 2005
581 * The user sends an initial batched category SUBSCRIBE request against all contacts on his roaming list in only a request
582 * A batch category SUBSCRIBE request MUST have the same To-URI and From-URI.
583 * This header will be send only if adhoclist there is a "Supported: adhoclist" in REGISTER answer else will be send a Single Category SUBSCRIBE
585 static void sipe_subscribe_presence_batched_to(struct sipe_core_private *sipe_private,
586 gchar *resources_uri,
587 gchar *to)
589 gchar *contact = get_contact(sipe_private);
590 gchar *request;
591 gchar *content;
592 gchar *require = "";
593 gchar *accept = "";
594 gchar *autoextend = "";
595 gchar *content_type;
597 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
598 require = ", categoryList";
599 accept = ", application/msrtc-event-categories+xml, application/xpidf+xml, application/pidf+xml";
600 content_type = "application/msrtc-adrl-categorylist+xml";
601 content = g_strdup_printf("<batchSub xmlns=\"http://schemas.microsoft.com/2006/01/sip/batch-subscribe\" uri=\"sip:%s\" name=\"\">\n"
602 "<action name=\"subscribe\" id=\"63792024\">\n"
603 "<adhocList>\n%s</adhocList>\n"
604 "<categoryList xmlns=\"http://schemas.microsoft.com/2006/09/sip/categorylist\">\n"
605 "<category name=\"calendarData\"/>\n"
606 "<category name=\"contactCard\"/>\n"
607 "<category name=\"note\"/>\n"
608 "<category name=\"state\"/>\n"
609 "</categoryList>\n"
610 "</action>\n"
611 "</batchSub>",
612 sipe_private->username,
613 resources_uri);
614 } else {
615 autoextend = "Supported: com.microsoft.autoextend\r\n";
616 content_type = "application/adrl+xml";
617 content = g_strdup_printf("<adhoclist xmlns=\"urn:ietf:params:xml:ns:adrl\" uri=\"sip:%s\" name=\"sip:%s\">\n"
618 "<create xmlns=\"\">\n%s</create>\n"
619 "</adhoclist>\n",
620 sipe_private->username,
621 sipe_private->username,
622 resources_uri);
624 g_free(resources_uri);
626 request = g_strdup_printf("Require: adhoclist%s\r\n"
627 "Supported: eventlist\r\n"
628 "Accept: application/rlmi+xml, multipart/related, text/xml+msrtc.pidf%s\r\n"
629 "Supported: ms-piggyback-first-notify\r\n"
630 "%sSupported: ms-benotify\r\n"
631 "Proxy-Require: ms-benotify\r\n"
632 "Event: presence\r\n"
633 "Content-Type: %s\r\n"
634 "Contact: %s\r\n",
635 require,
636 accept,
637 autoextend,
638 content_type,
639 contact);
640 g_free(contact);
642 sipe_subscribe_presence_buddy(sipe_private, to, request, content);
644 g_free(content);
645 g_free(to);
646 g_free(request);
649 struct presence_batched_routed {
650 gchar *host;
651 GSList *buddies;
654 static void sipe_subscribe_presence_batched_routed_free(gpointer payload)
656 struct presence_batched_routed *data = payload;
657 GSList *buddies = data->buddies;
658 while (buddies) {
659 g_free(buddies->data);
660 buddies = buddies->next;
662 g_slist_free(data->buddies);
663 g_free(data->host);
664 g_free(payload);
667 static void sipe_subscribe_presence_batched_routed(struct sipe_core_private *sipe_private,
668 gpointer payload)
670 struct presence_batched_routed *data = payload;
671 GSList *buddies = data->buddies;
672 gchar *resources_uri = g_strdup("");
673 while (buddies) {
674 gchar *tmp = resources_uri;
675 resources_uri = g_strdup_printf("%s<resource uri=\"%s\"/>\n", tmp, (char *) buddies->data);
676 g_free(tmp);
677 buddies = buddies->next;
679 sipe_subscribe_presence_batched_to(sipe_private, resources_uri,
680 g_strdup(data->host));
683 void sipe_subscribe_presence_batched_schedule(struct sipe_core_private *sipe_private,
684 const gchar *action_name,
685 const gchar *who,
686 GSList *buddies,
687 int timeout)
689 struct presence_batched_routed *payload = g_malloc(sizeof(struct presence_batched_routed));
690 payload->host = g_strdup(who);
691 payload->buddies = buddies;
692 sipe_schedule_seconds(sipe_private,
693 action_name,
694 payload,
695 timeout,
696 sipe_subscribe_presence_batched_routed,
697 sipe_subscribe_presence_batched_routed_free);
698 SIPE_DEBUG_INFO("Resubscription multiple contacts with batched support & route(%s) in %d", who, timeout);
701 static void sipe_subscribe_resource_uri_with_context(const gchar *name,
702 gpointer value,
703 gchar **resources_uri)
705 struct sipe_buddy *sbuddy = (struct sipe_buddy *)value;
706 gchar *context = sbuddy && sbuddy->just_added ? "><context/></resource>" : "/>";
707 gchar *tmp = *resources_uri;
709 if (sbuddy) sbuddy->just_added = FALSE; /* should be enought to include context one time */
711 *resources_uri = g_strdup_printf("%s<resource uri=\"%s\"%s\n", tmp, name, context);
712 g_free(tmp);
715 static void sipe_subscribe_resource_uri(const char *name,
716 SIPE_UNUSED_PARAMETER gpointer value,
717 gchar **resources_uri)
719 gchar *tmp = *resources_uri;
720 *resources_uri = g_strdup_printf("%s<resource uri=\"%s\"/>\n", tmp, name);
721 g_free(tmp);
724 void sipe_subscribe_presence_batched(struct sipe_core_private *sipe_private)
726 gchar *to = sip_uri_self(sipe_private);
727 gchar *resources_uri = g_strdup("");
728 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
729 g_hash_table_foreach(sipe_private->buddies, (GHFunc) sipe_subscribe_resource_uri_with_context , &resources_uri);
730 } else {
731 g_hash_table_foreach(sipe_private->buddies, (GHFunc) sipe_subscribe_resource_uri, &resources_uri);
734 sipe_subscribe_presence_batched_to(sipe_private, resources_uri, to);
737 void sipe_subscribe_poolfqdn_resource_uri(const char *host,
738 GSList *server,
739 struct sipe_core_private *sipe_private)
741 struct presence_batched_routed *payload = g_malloc(sizeof(struct presence_batched_routed));
742 SIPE_DEBUG_INFO("process_incoming_notify_rlmi_resub: pool(%s)", host);
743 payload->host = g_strdup(host);
744 payload->buddies = server;
745 sipe_subscribe_presence_batched_routed(sipe_private,
746 payload);
747 sipe_subscribe_presence_batched_routed_free(payload);
751 Local Variables:
752 mode: c
753 c-file-style: "bsd"
754 indent-tabs-mode: t
755 tab-width: 8
756 End: