subscriptions: use events_table for initialization
[siplcs.git] / src / core / sipe-subscriptions.c
bloba072170fa5b2ac5944219688c328665f6e986767
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 static struct sip_dialog *sipe_subscribe_dialog(struct sipe_core_private *sipe_private,
135 const gchar *key)
137 struct sip_dialog *dialog = g_hash_table_lookup(sipe_private->subscriptions,
138 key);
139 SIPE_DEBUG_INFO("sipe_subscribe_dialog: dialog for '%s' is %s", key, dialog ? "not NULL" : "NULL");
140 return(dialog);
143 static void sipe_subscription_expiration(struct sipe_core_private *sipe_private,
144 struct sipmsg *msg,
145 const gchar *event);
146 static gboolean process_subscribe_response(struct sipe_core_private *sipe_private,
147 struct sipmsg *msg,
148 struct transaction *trans)
150 gchar *with = parse_from(sipmsg_find_header(msg, "To"));
151 const gchar *event = sipmsg_find_header(msg, "Event");
153 /* The case with 2005 Public IM Connectivity (PIC) - no Event header */
154 if (!event) {
155 struct sipmsg *request_msg = trans->msg;
156 event = sipmsg_find_header(request_msg, "Event");
159 if (event) {
160 const gchar *subscription_state = sipmsg_find_header(msg, "subscription-state");
161 gboolean terminated = subscription_state && strstr(subscription_state, "terminated");
162 gchar *key = sipe_subscription_key(event, with);
165 * @TODO: does the server send this only for one-off
166 * subscriptions, i.e. the ones which anyway
167 * have "Expires: 0"?
169 if (terminated)
170 SIPE_DEBUG_INFO("process_subscribe_response: subscription '%s' to '%s' was terminated",
171 event, with);
173 /* 481 Call Leg Does Not Exist */
174 if ((msg->response == 481) || terminated) {
175 sipe_subscription_remove(sipe_private, key);
177 /* create/store subscription dialog if not yet */
178 } else if (msg->response == 200) {
179 struct sip_dialog *dialog = sipe_subscribe_dialog(sipe_private, key);
181 if (!dialog) {
182 struct sip_subscription *subscription = g_new0(struct sip_subscription, 1);
184 SIPE_DEBUG_INFO("process_subscribe_response: subscription dialog added for event '%s'",
185 key);
187 g_hash_table_insert(sipe_private->subscriptions,
188 key,
189 subscription);
190 key = NULL; /* table takes ownership of key */
192 subscription->dialog.callid = g_strdup(sipmsg_find_header(msg, "Call-ID"));
193 subscription->dialog.cseq = sipmsg_parse_cseq(msg);
194 subscription->dialog.with = g_strdup(with);
195 subscription->event = g_strdup(event);
197 dialog = &subscription->dialog;
200 sipe_dialog_parse(dialog, msg, TRUE);
202 sipe_subscription_expiration(sipe_private, msg, event);
204 g_free(key);
206 g_free(with);
208 if (sipmsg_find_header(msg, "ms-piggyback-cseq"))
209 process_incoming_notify(sipe_private, msg);
211 return(TRUE);
215 * common subscription code
217 static void sipe_subscribe(struct sipe_core_private *sipe_private,
218 const gchar *uri,
219 const gchar *event,
220 const gchar *accept,
221 const gchar *addheaders,
222 const gchar *body,
223 struct sip_dialog *dialog)
225 gchar *contact = get_contact(sipe_private);
226 gchar *hdr = g_strdup_printf(
227 "Event: %s\r\n"
228 "Accept: %s\r\n"
229 "Supported: com.microsoft.autoextend\r\n"
230 "Supported: ms-benotify\r\n"
231 "Proxy-Require: ms-benotify\r\n"
232 "Supported: ms-piggyback-first-notify\r\n"
233 "%s"
234 "Contact: %s\r\n",
235 event,
236 accept,
237 addheaders ? addheaders : "",
238 contact);
239 g_free(contact);
241 sip_transport_subscribe(sipe_private,
242 uri,
243 hdr,
244 body,
245 dialog,
246 process_subscribe_response);
247 g_free(hdr);
251 * common subscription code for self-subscriptions
253 static void sipe_subscribe_self(struct sipe_core_private *sipe_private,
254 const gchar *event,
255 const gchar *accept,
256 const gchar *addheaders,
257 const gchar *body)
259 gchar *self = sip_uri_self(sipe_private);
260 gchar *key = sipe_subscription_key(event, self);
261 struct sip_dialog *dialog = sipe_subscribe_dialog(sipe_private, key);
263 sipe_subscribe(sipe_private,
264 self,
265 event,
266 accept,
267 addheaders,
268 body,
269 dialog);
270 g_free(key);
271 g_free(self);
274 static void sipe_subscribe_presence_wpending(struct sipe_core_private *sipe_private,
275 SIPE_UNUSED_PARAMETER void *unused)
277 sipe_subscribe_self(sipe_private,
278 "presence.wpending",
279 "text/xml+msrtc.wpending",
280 NULL,
281 NULL);
285 * Subscribe roaming ACL
287 static void sipe_subscribe_roaming_acl(struct sipe_core_private *sipe_private,
288 SIPE_UNUSED_PARAMETER void *unused)
290 sipe_subscribe_self(sipe_private,
291 "vnd-microsoft-roaming-ACL",
292 "application/vnd-microsoft-roaming-acls+xml",
293 NULL,
294 NULL);
298 * Subscribe roaming contacts
300 static void sipe_subscribe_roaming_contacts(struct sipe_core_private *sipe_private,
301 SIPE_UNUSED_PARAMETER void *unused)
303 sipe_subscribe_self(sipe_private,
304 "vnd-microsoft-roaming-contacts",
305 "application/vnd-microsoft-roaming-contacts+xml",
306 NULL,
307 NULL);
311 * OCS 2005 version
313 static void sipe_subscribe_roaming_provisioning(struct sipe_core_private *sipe_private,
314 SIPE_UNUSED_PARAMETER void *unused)
316 sipe_subscribe_self(sipe_private,
317 "vnd-microsoft-provisioning",
318 "application/vnd-microsoft-roaming-provisioning+xml",
319 "Expires: 0\r\n",
320 NULL);
324 * Subscription for provisioning information to help with initial
325 * configuration. This subscription is a one-time query (denoted by the
326 * Expires header, which asks for 0 seconds for the subscription lifetime).
327 * This subscription asks for server configuration, meeting policies, and
328 * policy settings that Communicator must enforce.
330 static void sipe_subscribe_roaming_provisioning_v2(struct sipe_core_private *sipe_private,
331 SIPE_UNUSED_PARAMETER void *unused)
333 sipe_subscribe_self(sipe_private,
334 "vnd-microsoft-provisioning-v2",
335 "application/vnd-microsoft-roaming-provisioning-v2+xml",
336 "Expires: 0\r\n"
337 "Content-Type: application/vnd-microsoft-roaming-provisioning-v2+xml\r\n",
338 "<provisioningGroupList xmlns=\"http://schemas.microsoft.com/2006/09/sip/provisioninggrouplist\">"
339 "<provisioningGroup name=\"ServerConfiguration\"/><provisioningGroup name=\"meetingPolicy\"/>"
340 "<provisioningGroup name=\"ucPolicy\"/>"
341 "</provisioningGroupList>");
345 * To request for presence information about the user, access level settings
346 * that have already been configured by the user to control who has access to
347 * what information, and the list of contacts who currently have outstanding
348 * subscriptions.
350 * We wait for (BE)NOTIFY messages with some info change (categories,
351 * containers, subscribers)
353 static void sipe_subscribe_roaming_self(struct sipe_core_private *sipe_private,
354 SIPE_UNUSED_PARAMETER void *unused)
356 sipe_subscribe_self(sipe_private,
357 "vnd-microsoft-roaming-self",
358 "application/vnd-microsoft-roaming-self+xml",
359 "Content-Type: application/vnd-microsoft-roaming-self+xml\r\n",
360 "<roamingList xmlns=\"http://schemas.microsoft.com/2006/09/sip/roaming-self\">"
361 "<roaming type=\"categories\"/>"
362 "<roaming type=\"containers\"/>"
363 "<roaming type=\"subscribers\"/></roamingList>");
366 static void sipe_presence_timeout_mime_cb(gpointer user_data,
367 SIPE_UNUSED_PARAMETER const GSList *fields,
368 const gchar *body,
369 gsize length)
371 GSList **buddies = user_data;
372 sipe_xml *xml = sipe_xml_parse(body, length);
374 if (xml && !sipe_strequal(sipe_xml_name(xml), "list")) {
375 const gchar *uri = sipe_xml_attribute(xml, "uri");
376 const sipe_xml *xn_category;
379 * automaton: presence is never expected to change
381 * see: http://msdn.microsoft.com/en-us/library/ee354295(office.13).aspx
383 for (xn_category = sipe_xml_child(xml, "category");
384 xn_category;
385 xn_category = sipe_xml_twin(xn_category)) {
386 if (sipe_strequal(sipe_xml_attribute(xn_category, "name"),
387 "contactCard")) {
388 const sipe_xml *node = sipe_xml_child(xn_category, "contactCard/automaton");
389 if (node) {
390 char *boolean = sipe_xml_data(node);
391 if (sipe_strequal(boolean, "true")) {
392 SIPE_DEBUG_INFO("sipe_process_presence_timeout: %s is an automaton: - not subscribing to presence updates",
393 uri);
394 uri = NULL;
396 g_free(boolean);
398 break;
402 if (uri) {
403 *buddies = g_slist_append(*buddies, sip_uri(uri));
407 sipe_xml_free(xml);
410 static void sipe_process_presence_timeout(struct sipe_core_private *sipe_private,
411 struct sipmsg *msg,
412 const gchar *who,
413 int timeout)
415 const char *ctype = sipmsg_find_header(msg, "Content-Type");
416 gchar *action_name = sipe_utils_presence_key(who);
418 SIPE_DEBUG_INFO("sipe_process_presence_timeout: Content-Type: %s", ctype ? ctype : "");
420 if (ctype &&
421 strstr(ctype, "multipart") &&
422 (strstr(ctype, "application/rlmi+xml") ||
423 strstr(ctype, "application/msrtc-event-categories+xml"))) {
424 GSList *buddies = NULL;
426 sipe_mime_parts_foreach(ctype, msg->body, sipe_presence_timeout_mime_cb, &buddies);
428 if (buddies)
429 sipe_subscribe_presence_batched_schedule(sipe_private,
430 action_name,
431 who,
432 buddies,
433 timeout);
435 } else {
436 sipe_schedule_seconds(sipe_private,
437 action_name,
438 g_strdup(who),
439 timeout,
440 sipe_subscribe_presence_single,
441 g_free);
442 SIPE_DEBUG_INFO("Resubscription single contact with batched support(%s) in %d seconds", who, timeout);
444 g_free(action_name);
448 * @param expires not respected if set to negative value (E.g. -1)
450 void sipe_subscribe_conference(struct sipe_core_private *sipe_private,
451 const gchar *id,
452 gboolean expires)
454 sipe_subscribe(sipe_private,
456 "conference",
457 "application/conference-info+xml",
458 expires ? "Expires: 0\r\n" : NULL,
459 NULL,
460 NULL);
464 * code for presence subscription
466 static void sipe_subscribe_presence_buddy(struct sipe_core_private *sipe_private,
467 const gchar *uri,
468 const gchar *request,
469 const gchar *body)
471 gchar *key = sipe_utils_presence_key(uri);
473 sip_transport_subscribe(sipe_private,
474 uri,
475 request,
476 body,
477 sipe_subscribe_dialog(sipe_private, key),
478 process_subscribe_response);
480 g_free(key);
484 * Single Category SUBSCRIBE [MS-PRES] ; To send when the server returns a 200 OK message with state="resubscribe" in response.
485 * The user sends a single SUBSCRIBE request to the subscribed contact.
486 * The To-URI and the URI listed in the resource list MUST be the same for a single category SUBSCRIBE request.
489 void sipe_subscribe_presence_single(struct sipe_core_private *sipe_private,
490 gpointer buddy_name)
492 gchar *to = sip_uri((gchar *)buddy_name);
493 gchar *tmp = get_contact(sipe_private);
494 gchar *request;
495 gchar *content = NULL;
496 gchar *autoextend = "";
497 gchar *content_type = "";
498 struct sipe_buddy *sbuddy = g_hash_table_lookup(sipe_private->buddies, to);
499 gchar *context = sbuddy && sbuddy->just_added ? "><context/></resource>" : "/>";
501 if (sbuddy) sbuddy->just_added = FALSE;
503 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
504 content_type = "Content-Type: application/msrtc-adrl-categorylist+xml\r\n";
505 } else {
506 autoextend = "Supported: com.microsoft.autoextend\r\n";
509 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"
510 "Supported: ms-piggyback-first-notify\r\n"
511 "%s%sSupported: ms-benotify\r\n"
512 "Proxy-Require: ms-benotify\r\n"
513 "Event: presence\r\n"
514 "Contact: %s\r\n",
515 autoextend,
516 content_type,
517 tmp);
519 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
520 content = g_strdup_printf("<batchSub xmlns=\"http://schemas.microsoft.com/2006/01/sip/batch-subscribe\" uri=\"sip:%s\" name=\"\">\n"
521 "<action name=\"subscribe\" id=\"63792024\"><adhocList>\n"
522 "<resource uri=\"%s\"%s\n"
523 "</adhocList>\n"
524 "<categoryList xmlns=\"http://schemas.microsoft.com/2006/09/sip/categorylist\">\n"
525 "<category name=\"calendarData\"/>\n"
526 "<category name=\"contactCard\"/>\n"
527 "<category name=\"note\"/>\n"
528 "<category name=\"state\"/>\n"
529 "</categoryList>\n"
530 "</action>\n"
531 "</batchSub>",
532 sipe_private->username,
534 context);
537 g_free(tmp);
539 sipe_subscribe_presence_buddy(sipe_private, to, request, content);
541 g_free(content);
542 g_free(to);
543 g_free(request);
547 * Support for Batch Category SUBSCRIBE [MS-PRES] - msrtc-event-categories+xml OCS 2007
548 * Support for Batch Category SUBSCRIBE [MS-SIP] - adrl+xml LCS 2005
549 * The user sends an initial batched category SUBSCRIBE request against all contacts on his roaming list in only a request
550 * A batch category SUBSCRIBE request MUST have the same To-URI and From-URI.
551 * This header will be send only if adhoclist there is a "Supported: adhoclist" in REGISTER answer else will be send a Single Category SUBSCRIBE
553 static void sipe_subscribe_presence_batched_to(struct sipe_core_private *sipe_private,
554 gchar *resources_uri,
555 gchar *to)
557 gchar *contact = get_contact(sipe_private);
558 gchar *request;
559 gchar *content;
560 gchar *require = "";
561 gchar *accept = "";
562 gchar *autoextend = "";
563 gchar *content_type;
565 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
566 require = ", categoryList";
567 accept = ", application/msrtc-event-categories+xml, application/xpidf+xml, application/pidf+xml";
568 content_type = "application/msrtc-adrl-categorylist+xml";
569 content = g_strdup_printf("<batchSub xmlns=\"http://schemas.microsoft.com/2006/01/sip/batch-subscribe\" uri=\"sip:%s\" name=\"\">\n"
570 "<action name=\"subscribe\" id=\"63792024\">\n"
571 "<adhocList>\n%s</adhocList>\n"
572 "<categoryList xmlns=\"http://schemas.microsoft.com/2006/09/sip/categorylist\">\n"
573 "<category name=\"calendarData\"/>\n"
574 "<category name=\"contactCard\"/>\n"
575 "<category name=\"note\"/>\n"
576 "<category name=\"state\"/>\n"
577 "</categoryList>\n"
578 "</action>\n"
579 "</batchSub>",
580 sipe_private->username,
581 resources_uri);
582 } else {
583 autoextend = "Supported: com.microsoft.autoextend\r\n";
584 content_type = "application/adrl+xml";
585 content = g_strdup_printf("<adhoclist xmlns=\"urn:ietf:params:xml:ns:adrl\" uri=\"sip:%s\" name=\"sip:%s\">\n"
586 "<create xmlns=\"\">\n%s</create>\n"
587 "</adhoclist>\n",
588 sipe_private->username,
589 sipe_private->username,
590 resources_uri);
592 g_free(resources_uri);
594 request = g_strdup_printf("Require: adhoclist%s\r\n"
595 "Supported: eventlist\r\n"
596 "Accept: application/rlmi+xml, multipart/related, text/xml+msrtc.pidf%s\r\n"
597 "Supported: ms-piggyback-first-notify\r\n"
598 "%sSupported: ms-benotify\r\n"
599 "Proxy-Require: ms-benotify\r\n"
600 "Event: presence\r\n"
601 "Content-Type: %s\r\n"
602 "Contact: %s\r\n",
603 require,
604 accept,
605 autoextend,
606 content_type,
607 contact);
608 g_free(contact);
610 sipe_subscribe_presence_buddy(sipe_private, to, request, content);
612 g_free(content);
613 g_free(to);
614 g_free(request);
617 struct presence_batched_routed {
618 gchar *host;
619 GSList *buddies;
622 static void sipe_subscribe_presence_batched_routed_free(gpointer payload)
624 struct presence_batched_routed *data = payload;
625 GSList *buddies = data->buddies;
626 while (buddies) {
627 g_free(buddies->data);
628 buddies = buddies->next;
630 g_slist_free(data->buddies);
631 g_free(data->host);
632 g_free(payload);
635 static void sipe_subscribe_presence_batched_routed(struct sipe_core_private *sipe_private,
636 gpointer payload)
638 struct presence_batched_routed *data = payload;
639 GSList *buddies = data->buddies;
640 gchar *resources_uri = g_strdup("");
641 while (buddies) {
642 gchar *tmp = resources_uri;
643 resources_uri = g_strdup_printf("%s<resource uri=\"%s\"/>\n", tmp, (char *) buddies->data);
644 g_free(tmp);
645 buddies = buddies->next;
647 sipe_subscribe_presence_batched_to(sipe_private, resources_uri,
648 g_strdup(data->host));
651 void sipe_subscribe_presence_batched_schedule(struct sipe_core_private *sipe_private,
652 const gchar *action_name,
653 const gchar *who,
654 GSList *buddies,
655 int timeout)
657 struct presence_batched_routed *payload = g_malloc(sizeof(struct presence_batched_routed));
658 payload->host = g_strdup(who);
659 payload->buddies = buddies;
660 sipe_schedule_seconds(sipe_private,
661 action_name,
662 payload,
663 timeout,
664 sipe_subscribe_presence_batched_routed,
665 sipe_subscribe_presence_batched_routed_free);
666 SIPE_DEBUG_INFO("Resubscription multiple contacts with batched support & route(%s) in %d", who, timeout);
669 static void sipe_subscribe_resource_uri_with_context(const gchar *name,
670 gpointer value,
671 gchar **resources_uri)
673 struct sipe_buddy *sbuddy = (struct sipe_buddy *)value;
674 gchar *context = sbuddy && sbuddy->just_added ? "><context/></resource>" : "/>";
675 gchar *tmp = *resources_uri;
677 if (sbuddy) sbuddy->just_added = FALSE; /* should be enought to include context one time */
679 *resources_uri = g_strdup_printf("%s<resource uri=\"%s\"%s\n", tmp, name, context);
680 g_free(tmp);
683 static void sipe_subscribe_resource_uri(const char *name,
684 SIPE_UNUSED_PARAMETER gpointer value,
685 gchar **resources_uri)
687 gchar *tmp = *resources_uri;
688 *resources_uri = g_strdup_printf("%s<resource uri=\"%s\"/>\n", tmp, name);
689 g_free(tmp);
692 void sipe_subscribe_presence_batched(struct sipe_core_private *sipe_private)
694 gchar *to = sip_uri_self(sipe_private);
695 gchar *resources_uri = g_strdup("");
696 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
697 g_hash_table_foreach(sipe_private->buddies, (GHFunc) sipe_subscribe_resource_uri_with_context , &resources_uri);
698 } else {
699 g_hash_table_foreach(sipe_private->buddies, (GHFunc) sipe_subscribe_resource_uri, &resources_uri);
702 sipe_subscribe_presence_batched_to(sipe_private, resources_uri, to);
705 void sipe_subscribe_poolfqdn_resource_uri(const char *host,
706 GSList *server,
707 struct sipe_core_private *sipe_private)
709 struct presence_batched_routed *payload = g_malloc(sizeof(struct presence_batched_routed));
710 SIPE_DEBUG_INFO("process_incoming_notify_rlmi_resub: pool(%s)", host);
711 payload->host = g_strdup(host);
712 payload->buddies = server;
713 sipe_subscribe_presence_batched_routed(sipe_private,
714 payload);
715 sipe_subscribe_presence_batched_routed_free(payload);
720 * subscription expiration handling
722 struct event_subscription_data {
723 const gchar *event;
724 sipe_schedule_action callback;
725 guint flags;
728 #define EVENT_OCS2005 0x00000001
729 #define EVENT_OCS2007 0x00000002
731 static const struct event_subscription_data events_table[] =
734 * For 2007+ it does not make sence to subscribe to:
736 * presence.wpending
737 * vnd-microsoft-roaming-ACL
738 * vnd-microsoft-provisioning (not v2)
740 * These are only needed as backward compatibility for older clients
742 * For 2005- we publish our initial statuses only after we received
743 * our existing UserInfo data in response to self subscription.
744 * Only in this case we won't override existing UserInfo data
745 * set earlier or by other client on our behalf.
747 * For 2007+ we publish our initial statuses and calendar data only
748 * after we received our existing publications in roaming_self.
749 * Only in this case we know versions of current publications made
750 * on our behalf.
752 { "presence.wpending", sipe_subscribe_presence_wpending,
753 EVENT_OCS2005 },
754 { "vnd-microsoft-roaming-ACL", sipe_subscribe_roaming_acl,
755 EVENT_OCS2005 },
756 { "vnd-microsoft-roaming-contacts", sipe_subscribe_roaming_contacts,
757 EVENT_OCS2005 | EVENT_OCS2007 },
758 { "vnd-microsoft-provisioning", sipe_subscribe_roaming_provisioning,
759 EVENT_OCS2007 },
760 { "vnd-microsoft-provisioning-v2", sipe_subscribe_roaming_provisioning_v2,
761 EVENT_OCS2007 },
762 { "vnd-microsoft-roaming-self", sipe_subscribe_roaming_self,
763 EVENT_OCS2007 },
764 { NULL, NULL, 0 }
767 static void sipe_subscription_expiration(struct sipe_core_private *sipe_private,
768 struct sipmsg *msg,
769 const gchar *event)
771 const gchar *expires_header = sipmsg_find_header(msg, "Expires");
772 guint timeout = expires_header ? strtol(expires_header, NULL, 10) : 0;
774 if (timeout) {
775 /* 2 min ahead of expiration */
776 if (timeout > 240) timeout -= 120;
778 if (sipe_strcase_equal(event, "presence")) {
779 gchar *who = parse_from(sipmsg_find_header(msg, "To"));
781 if (SIPE_CORE_PRIVATE_FLAG_IS(BATCHED_SUPPORT)) {
782 sipe_process_presence_timeout(sipe_private, msg, who, timeout);
783 } else {
784 gchar *action_name = sipe_utils_presence_key(who);
785 sipe_schedule_seconds(sipe_private,
786 action_name,
787 g_strdup(who),
788 timeout,
789 sipe_subscribe_presence_single,
790 g_free);
791 g_free(action_name);
792 SIPE_DEBUG_INFO("Resubscription single contact '%s' in %d seconds", who, timeout);
794 g_free(who);
796 } else {
797 const struct event_subscription_data *esd;
799 for (esd = events_table; esd->event; esd++) {
800 if (sipe_strcase_equal(event, esd->event)) {
801 gchar *action_name = g_strdup_printf("<%s>", event);
802 sipe_schedule_seconds(sipe_private,
803 action_name,
804 NULL,
805 timeout,
806 esd->callback,
807 NULL);
808 g_free(action_name);
809 SIPE_DEBUG_INFO("Resubscription to event '%s' in %d seconds", event, timeout);
810 break;
818 * Initial event subscription
820 void sipe_subscription_self_events(struct sipe_core_private *sipe_private)
822 const guint mask = SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) ? EVENT_OCS2007 : EVENT_OCS2005;
823 const struct event_subscription_data *esd;
825 /* subscribe to those events which are selected for
826 * this version and are allowed by the server */
827 for (esd = events_table; esd->event; esd++)
828 if ((esd->flags & mask) &&
829 (g_slist_find_custom(sipe_private->allowed_events,
830 esd->event,
831 (GCompareFunc) g_ascii_strcasecmp) != NULL))
832 (*esd->callback)(sipe_private, NULL);
836 Local Variables:
837 mode: c
838 c-file-style: "bsd"
839 indent-tabs-mode: t
840 tab-width: 8
841 End: