subscriptions: dead code path removal for non-NULL event
[siplcs.git] / src / core / sipe-subscriptions.c
bloba974bbe9b88c5da76206d00ba2eaa032a034864a
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>
25 #include <glib.h>
27 #include "sipe-common.h"
28 #include "sipmsg.h"
29 #include "sip-transport.h"
30 #include "sipe-backend.h"
31 #include "sipe-buddy.h"
32 #include "sipe-core.h"
33 #include "sipe-core-private.h"
34 #include "sipe-dialog.h"
35 #include "sipe-notify.h"
36 #include "sipe-schedule.h"
37 #include "sipe-subscriptions.h"
38 #include "sipe-utils.h"
40 /* RFC3265 subscription */
41 struct sip_subscription {
42 struct sip_dialog dialog;
43 gchar *event;
46 static void sipe_subscription_free(struct sip_subscription *subscription)
48 if (!subscription) return;
50 g_free(subscription->event);
51 /* NOTE: use cast to prevent BAD_FREE warning from Coverity */
52 sipe_dialog_free((struct sip_dialog *) subscription);
55 void sipe_subscriptions_init(struct sipe_core_private *sipe_private)
57 sipe_private->subscriptions = g_hash_table_new_full(g_str_hash,
58 g_str_equal,
59 g_free,
60 (GDestroyNotify)sipe_subscription_free);
63 static void sipe_unsubscribe_cb(SIPE_UNUSED_PARAMETER gpointer key,
64 gpointer value, gpointer user_data)
66 struct sip_subscription *subscription = value;
67 struct sip_dialog *dialog = &subscription->dialog;
68 struct sipe_core_private *sipe_private = user_data;
69 gchar *contact = get_contact(sipe_private);
70 gchar *hdr = g_strdup_printf(
71 "Event: %s\r\n"
72 "Expires: 0\r\n"
73 "Contact: %s\r\n", subscription->event, contact);
74 g_free(contact);
76 /* Rate limit to max. 25 requests per seconds */
77 g_usleep(1000000 / 25);
79 sip_transport_subscribe(sipe_private,
80 dialog->with,
81 hdr,
82 NULL,
83 dialog,
84 NULL);
86 g_free(hdr);
89 void sipe_subscriptions_unsubscribe(struct sipe_core_private *sipe_private)
91 /* unsubscribe all */
92 g_hash_table_foreach(sipe_private->subscriptions,
93 sipe_unsubscribe_cb,
94 sipe_private);
98 void sipe_subscriptions_destroy(struct sipe_core_private *sipe_private)
100 g_hash_table_destroy(sipe_private->subscriptions);
103 static void sipe_subscription_remove(struct sipe_core_private *sipe_private,
104 const gchar *key)
106 if (g_hash_table_lookup(sipe_private->subscriptions, key)) {
107 g_hash_table_remove(sipe_private->subscriptions, key);
108 SIPE_DEBUG_INFO("sipe_subscription_remove: %s", key);
113 * Generate subscription key
115 * @param event event name (must not by @c NULL)
116 * @param uri presence URI (ignored if @c event != "presence")
118 * @return key string. Must be g_free()'d after use.
120 static gchar *sipe_subscription_key(const gchar *event,
121 const gchar *uri)
123 if (!g_ascii_strcasecmp(event, "presence"))
124 /* Subscription is identified by <presence><uri> key */
125 return(sipe_utils_presence_key(uri));
126 else
127 /* Subscription is identified by <event> key */
128 return(g_strdup_printf("<%s>", event));
131 void sipe_subscription_terminate(struct sipe_core_private *sipe_private,
132 const gchar *event,
133 const gchar *who)
135 gchar *key = sipe_subscription_key(event, who);
136 sipe_subscription_remove(sipe_private, key);
137 g_free(key);
140 static gboolean process_subscribe_response(struct sipe_core_private *sipe_private,
141 struct sipmsg *msg,
142 struct transaction *trans)
144 gchar *with = parse_from(sipmsg_find_header(msg, "To"));
145 const gchar *event = sipmsg_find_header(msg, "Event");
147 /* The case with 2005 Public IM Connectivity (PIC) - no Event header */
148 if (!event) {
149 struct sipmsg *request_msg = trans->msg;
150 event = sipmsg_find_header(request_msg, "Event");
153 if (event) {
154 gchar *key = sipe_subscription_key(event, with);
156 /* 200 OK; 481 Call Leg Does Not Exist */
157 if (msg->response == 200 || msg->response == 481)
158 sipe_subscription_remove(sipe_private, key);
160 /* create/store subscription dialog if not yet */
161 if (msg->response == 200) {
162 struct sip_subscription *subscription = g_new0(struct sip_subscription, 1);
163 g_hash_table_insert(sipe_private->subscriptions,
164 g_strdup(key),
165 subscription);
167 subscription->dialog.callid = g_strdup(sipmsg_find_header(msg, "Call-ID"));
168 subscription->dialog.cseq = sipmsg_parse_cseq(msg);
169 subscription->dialog.with = g_strdup(with);
170 subscription->event = g_strdup(event);
171 sipe_dialog_parse(&subscription->dialog, msg, TRUE);
173 SIPE_DEBUG_INFO("process_subscribe_response: subscription dialog added for: %s",
174 key);
177 g_free(key);
179 g_free(with);
181 if (sipmsg_find_header(msg, "ms-piggyback-cseq"))
182 process_incoming_notify(sipe_private, msg, FALSE, FALSE);
184 return(TRUE);
188 * common subscription code
190 void sipe_subscribe(struct sipe_core_private *sipe_private,
191 const gchar *uri,
192 const gchar *event,
193 const gchar *accept,
194 const gchar *addheaders,
195 const gchar *body,
196 struct sip_dialog *dialog)
198 gchar *contact = get_contact(sipe_private);
199 gchar *hdr = g_strdup_printf(
200 "Event: %s\r\n"
201 "Accept: %s\r\n"
202 "Supported: com.microsoft.autoextend\r\n"
203 "Supported: ms-benotify\r\n"
204 "Proxy-Require: ms-benotify\r\n"
205 "Supported: ms-piggyback-first-notify\r\n"
206 "%s"
207 "Contact: %s\r\n",
208 event,
209 accept,
210 addheaders ? addheaders : "",
211 contact);
212 g_free(contact);
215 sip_transport_subscribe(sipe_private,
216 uri,
217 hdr,
218 body,
219 dialog,
220 process_subscribe_response);
222 g_free(hdr);
226 * common subscription code for self-subscriptions
228 static void sipe_subscribe_self(struct sipe_core_private *sipe_private,
229 const gchar *event,
230 const gchar *accept,
231 const gchar *addheaders,
232 const gchar *body,
233 struct sip_dialog *dialog)
235 gchar *self = sip_uri_self(sipe_private);
237 sipe_subscribe(sipe_private,
238 self,
239 event,
240 accept,
241 addheaders,
242 body,
243 dialog);
245 g_free(self);
248 static struct sip_dialog *sipe_subscribe_dialog(struct sipe_core_private *sipe_private,
249 const gchar *key)
251 struct sip_dialog *dialog = g_hash_table_lookup(sipe_private->subscriptions,
252 key);
253 SIPE_DEBUG_INFO("sipe_subscribe_dialog: dialog for '%s' is %s", key, dialog ? "not NULL" : "NULL");
254 return dialog;
257 static void sipe_subscribe_presence_buddy(struct sipe_core_private *sipe_private,
258 const gchar *uri,
259 const gchar *request,
260 const gchar *body)
262 gchar *key = sipe_utils_presence_key(uri);
264 sip_transport_subscribe(sipe_private,
265 uri,
266 request,
267 body,
268 sipe_subscribe_dialog(sipe_private, key),
269 process_subscribe_response);
271 g_free(key);
274 void sipe_subscribe_presence_wpending(struct sipe_core_private *sipe_private,
275 SIPE_UNUSED_PARAMETER void *unused)
277 gchar *key = sipe_subscription_key("presence.wpending", NULL);
279 sipe_subscribe_self(sipe_private,
280 "presence.wpending",
281 "text/xml+msrtc.wpending",
282 NULL,
283 NULL,
284 sipe_subscribe_dialog(sipe_private, key));
286 g_free(key);
290 * Subscribe roaming ACL
292 void sipe_subscribe_roaming_acl(struct sipe_core_private *sipe_private)
294 sipe_subscribe_self(sipe_private,
295 "vnd-microsoft-roaming-ACL",
296 "application/vnd-microsoft-roaming-acls+xml",
297 NULL,
298 NULL,
299 NULL);
303 * Subscribe roaming contacts
305 void sipe_subscribe_roaming_contacts(struct sipe_core_private *sipe_private)
307 sipe_subscribe_self(sipe_private,
308 "vnd-microsoft-roaming-contacts",
309 "application/vnd-microsoft-roaming-contacts+xml",
310 NULL,
311 NULL,
312 NULL);
316 * OCS 2005 version
318 void sipe_subscribe_roaming_provisioning(struct sipe_core_private *sipe_private)
320 sipe_subscribe_self(sipe_private,
321 "vnd-microsoft-provisioning",
322 "application/vnd-microsoft-roaming-provisioning+xml",
323 "Expires: 0\r\n",
324 NULL,
325 NULL);
329 * Subscription for provisioning information to help with initial
330 * configuration. This subscription is a one-time query (denoted by the
331 * Expires header, which asks for 0 seconds for the subscription lifetime).
332 * This subscription asks for server configuration, meeting policies, and
333 * policy settings that Communicator must enforce.
335 void sipe_subscribe_roaming_provisioning_v2(struct sipe_core_private *sipe_private)
337 sipe_subscribe_self(sipe_private,
338 "vnd-microsoft-provisioning-v2",
339 "application/vnd-microsoft-roaming-provisioning-v2+xml",
340 "Expires: 0\r\n"
341 "Content-Type: application/vnd-microsoft-roaming-provisioning-v2+xml\r\n",
342 "<provisioningGroupList xmlns=\"http://schemas.microsoft.com/2006/09/sip/provisioninggrouplist\">"
343 "<provisioningGroup name=\"ServerConfiguration\"/><provisioningGroup name=\"meetingPolicy\"/>"
344 "<provisioningGroup name=\"ucPolicy\"/>"
345 "</provisioningGroupList>",
346 NULL);
350 * To request for presence information about the user, access level settings
351 * that have already been configured by the user to control who has access to
352 * what information, and the list of contacts who currently have outstanding
353 * subscriptions.
355 * We wait for (BE)NOTIFY messages with some info change (categories,
356 * containers, subscribers)
358 void sipe_subscribe_roaming_self(struct sipe_core_private *sipe_private)
360 sipe_subscribe_self(sipe_private,
361 "vnd-microsoft-roaming-self",
362 "application/vnd-microsoft-roaming-self+xml",
363 "Content-Type: application/vnd-microsoft-roaming-self+xml\r\n",
364 "<roamingList xmlns=\"http://schemas.microsoft.com/2006/09/sip/roaming-self\">"
365 "<roaming type=\"categories\"/>"
366 "<roaming type=\"containers\"/>"
367 "<roaming type=\"subscribers\"/></roamingList>",
368 NULL);
372 * Single Category SUBSCRIBE [MS-PRES] ; To send when the server returns a 200 OK message with state="resubscribe" in response.
373 * The user sends a single SUBSCRIBE request to the subscribed contact.
374 * The To-URI and the URI listed in the resource list MUST be the same for a single category SUBSCRIBE request.
377 void sipe_subscribe_presence_single(struct sipe_core_private *sipe_private,
378 gpointer buddy_name)
380 gchar *to = sip_uri((gchar *)buddy_name);
381 gchar *tmp = get_contact(sipe_private);
382 gchar *request;
383 gchar *content = NULL;
384 gchar *autoextend = "";
385 gchar *content_type = "";
386 struct sipe_buddy *sbuddy = g_hash_table_lookup(sipe_private->buddies, to);
387 gchar *context = sbuddy && sbuddy->just_added ? "><context/></resource>" : "/>";
389 if (sbuddy) sbuddy->just_added = FALSE;
391 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
392 content_type = "Content-Type: application/msrtc-adrl-categorylist+xml\r\n";
393 } else {
394 autoextend = "Supported: com.microsoft.autoextend\r\n";
397 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"
398 "Supported: ms-piggyback-first-notify\r\n"
399 "%s%sSupported: ms-benotify\r\n"
400 "Proxy-Require: ms-benotify\r\n"
401 "Event: presence\r\n"
402 "Contact: %s\r\n",
403 autoextend,
404 content_type,
405 tmp);
407 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
408 content = g_strdup_printf("<batchSub xmlns=\"http://schemas.microsoft.com/2006/01/sip/batch-subscribe\" uri=\"sip:%s\" name=\"\">\n"
409 "<action name=\"subscribe\" id=\"63792024\"><adhocList>\n"
410 "<resource uri=\"%s\"%s\n"
411 "</adhocList>\n"
412 "<categoryList xmlns=\"http://schemas.microsoft.com/2006/09/sip/categorylist\">\n"
413 "<category name=\"calendarData\"/>\n"
414 "<category name=\"contactCard\"/>\n"
415 "<category name=\"note\"/>\n"
416 "<category name=\"state\"/>\n"
417 "</categoryList>\n"
418 "</action>\n"
419 "</batchSub>",
420 sipe_private->username,
422 context);
425 g_free(tmp);
427 sipe_subscribe_presence_buddy(sipe_private, to, request, content);
429 g_free(content);
430 g_free(to);
431 g_free(request);
435 * Support for Batch Category SUBSCRIBE [MS-PRES] - msrtc-event-categories+xml OCS 2007
436 * Support for Batch Category SUBSCRIBE [MS-SIP] - adrl+xml LCS 2005
437 * The user sends an initial batched category SUBSCRIBE request against all contacts on his roaming list in only a request
438 * A batch category SUBSCRIBE request MUST have the same To-URI and From-URI.
439 * This header will be send only if adhoclist there is a "Supported: adhoclist" in REGISTER answer else will be send a Single Category SUBSCRIBE
441 static void sipe_subscribe_presence_batched_to(struct sipe_core_private *sipe_private,
442 gchar *resources_uri,
443 gchar *to)
445 gchar *contact = get_contact(sipe_private);
446 gchar *request;
447 gchar *content;
448 gchar *require = "";
449 gchar *accept = "";
450 gchar *autoextend = "";
451 gchar *content_type;
453 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
454 require = ", categoryList";
455 accept = ", application/msrtc-event-categories+xml, application/xpidf+xml, application/pidf+xml";
456 content_type = "application/msrtc-adrl-categorylist+xml";
457 content = g_strdup_printf("<batchSub xmlns=\"http://schemas.microsoft.com/2006/01/sip/batch-subscribe\" uri=\"sip:%s\" name=\"\">\n"
458 "<action name=\"subscribe\" id=\"63792024\">\n"
459 "<adhocList>\n%s</adhocList>\n"
460 "<categoryList xmlns=\"http://schemas.microsoft.com/2006/09/sip/categorylist\">\n"
461 "<category name=\"calendarData\"/>\n"
462 "<category name=\"contactCard\"/>\n"
463 "<category name=\"note\"/>\n"
464 "<category name=\"state\"/>\n"
465 "</categoryList>\n"
466 "</action>\n"
467 "</batchSub>",
468 sipe_private->username,
469 resources_uri);
470 } else {
471 autoextend = "Supported: com.microsoft.autoextend\r\n";
472 content_type = "application/adrl+xml";
473 content = g_strdup_printf("<adhoclist xmlns=\"urn:ietf:params:xml:ns:adrl\" uri=\"sip:%s\" name=\"sip:%s\">\n"
474 "<create xmlns=\"\">\n%s</create>\n"
475 "</adhoclist>\n",
476 sipe_private->username,
477 sipe_private->username,
478 resources_uri);
480 g_free(resources_uri);
482 request = g_strdup_printf("Require: adhoclist%s\r\n"
483 "Supported: eventlist\r\n"
484 "Accept: application/rlmi+xml, multipart/related, text/xml+msrtc.pidf%s\r\n"
485 "Supported: ms-piggyback-first-notify\r\n"
486 "%sSupported: ms-benotify\r\n"
487 "Proxy-Require: ms-benotify\r\n"
488 "Event: presence\r\n"
489 "Content-Type: %s\r\n"
490 "Contact: %s\r\n",
491 require,
492 accept,
493 autoextend,
494 content_type,
495 contact);
496 g_free(contact);
498 sipe_subscribe_presence_buddy(sipe_private, to, request, content);
500 g_free(content);
501 g_free(to);
502 g_free(request);
505 struct presence_batched_routed {
506 gchar *host;
507 GSList *buddies;
510 static void sipe_subscribe_presence_batched_routed_free(gpointer payload)
512 struct presence_batched_routed *data = payload;
513 GSList *buddies = data->buddies;
514 while (buddies) {
515 g_free(buddies->data);
516 buddies = buddies->next;
518 g_slist_free(data->buddies);
519 g_free(data->host);
520 g_free(payload);
523 static void sipe_subscribe_presence_batched_routed(struct sipe_core_private *sipe_private,
524 gpointer payload)
526 struct presence_batched_routed *data = payload;
527 GSList *buddies = data->buddies;
528 gchar *resources_uri = g_strdup("");
529 while (buddies) {
530 gchar *tmp = resources_uri;
531 resources_uri = g_strdup_printf("%s<resource uri=\"%s\"/>\n", tmp, (char *) buddies->data);
532 g_free(tmp);
533 buddies = buddies->next;
535 sipe_subscribe_presence_batched_to(sipe_private, resources_uri,
536 g_strdup(data->host));
539 void sipe_subscribe_presence_batched_schedule(struct sipe_core_private *sipe_private,
540 const gchar *action_name,
541 const gchar *who,
542 GSList *buddies,
543 int timeout)
545 struct presence_batched_routed *payload = g_malloc(sizeof(struct presence_batched_routed));
546 payload->host = g_strdup(who);
547 payload->buddies = buddies;
548 sipe_schedule_seconds(sipe_private,
549 action_name,
550 payload,
551 timeout,
552 sipe_subscribe_presence_batched_routed,
553 sipe_subscribe_presence_batched_routed_free);
554 SIPE_DEBUG_INFO("Resubscription multiple contacts with batched support & route(%s) in %d", who, timeout);
557 static void sipe_subscribe_resource_uri_with_context(const gchar *name,
558 gpointer value,
559 gchar **resources_uri)
561 struct sipe_buddy *sbuddy = (struct sipe_buddy *)value;
562 gchar *context = sbuddy && sbuddy->just_added ? "><context/></resource>" : "/>";
563 gchar *tmp = *resources_uri;
565 if (sbuddy) sbuddy->just_added = FALSE; /* should be enought to include context one time */
567 *resources_uri = g_strdup_printf("%s<resource uri=\"%s\"%s\n", tmp, name, context);
568 g_free(tmp);
571 static void sipe_subscribe_resource_uri(const char *name,
572 SIPE_UNUSED_PARAMETER gpointer value,
573 gchar **resources_uri)
575 gchar *tmp = *resources_uri;
576 *resources_uri = g_strdup_printf("%s<resource uri=\"%s\"/>\n", tmp, name);
577 g_free(tmp);
580 void sipe_subscribe_presence_batched(struct sipe_core_private *sipe_private)
582 gchar *to = sip_uri_self(sipe_private);
583 gchar *resources_uri = g_strdup("");
584 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
585 g_hash_table_foreach(sipe_private->buddies, (GHFunc) sipe_subscribe_resource_uri_with_context , &resources_uri);
586 } else {
587 g_hash_table_foreach(sipe_private->buddies, (GHFunc) sipe_subscribe_resource_uri, &resources_uri);
590 sipe_subscribe_presence_batched_to(sipe_private, resources_uri, to);
593 void sipe_subscribe_poolfqdn_resource_uri(const char *host,
594 GSList *server,
595 struct sipe_core_private *sipe_private)
597 struct presence_batched_routed *payload = g_malloc(sizeof(struct presence_batched_routed));
598 SIPE_DEBUG_INFO("process_incoming_notify_rlmi_resub: pool(%s)", host);
599 payload->host = g_strdup(host);
600 payload->buddies = server;
601 sipe_subscribe_presence_batched_routed(sipe_private,
602 payload);
603 sipe_subscribe_presence_batched_routed_free(payload);
607 Local Variables:
608 mode: c
609 c-file-style: "bsd"
610 indent-tabs-mode: t
611 tab-width: 8
612 End: