Updated media patches README
[siplcs.git] / src / core / sipe-subscriptions.c
blobed44e9d22d13a9dd52e69701537bdd3e49d24001
1 /**
2 * @file sipe-subscriptions.c
4 * pidgin-sipe
6 * Copyright (C) 2010-11 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-core.h"
32 #include "sipe-core-private.h"
33 #include "sipe-dialog.h"
34 #include "sipe-subscriptions.h"
35 #include "sipe-utils.h"
36 #include "sipe.h"
38 /* RFC3265 subscription */
39 struct sip_subscription {
40 struct sip_dialog dialog;
41 gchar *event;
44 static void sipe_subscription_free(struct sip_subscription *subscription)
46 if (!subscription) return;
48 g_free(subscription->event);
49 /* NOTE: use cast to prevent BAD_FREE warning from Coverity */
50 sipe_dialog_free((struct sip_dialog *) subscription);
53 void sipe_subscriptions_init(struct sipe_core_private *sipe_private)
55 sipe_private->subscriptions = g_hash_table_new_full(g_str_hash,
56 g_str_equal,
57 g_free,
58 (GDestroyNotify)sipe_subscription_free);
61 static void sipe_unsubscribe_cb(SIPE_UNUSED_PARAMETER gpointer key,
62 gpointer value, gpointer user_data)
64 struct sip_subscription *subscription = value;
65 struct sip_dialog *dialog = &subscription->dialog;
66 struct sipe_core_private *sipe_private = user_data;
67 gchar *contact = get_contact(sipe_private);
68 gchar *hdr = g_strdup_printf(
69 "Event: %s\r\n"
70 "Expires: 0\r\n"
71 "Contact: %s\r\n", subscription->event, contact);
72 g_free(contact);
74 /* Rate limit to max. 25 requests per seconds */
75 g_usleep(1000000 / 25);
77 sip_transport_subscribe(sipe_private,
78 dialog->with,
79 hdr,
80 NULL,
81 dialog,
82 NULL);
84 g_free(hdr);
87 void sipe_subscriptions_unsubscribe(struct sipe_core_private *sipe_private)
89 /* unsubscribe all */
90 g_hash_table_foreach(sipe_private->subscriptions,
91 sipe_unsubscribe_cb,
92 sipe_private);
96 void sipe_subscriptions_destroy(struct sipe_core_private *sipe_private)
98 g_hash_table_destroy(sipe_private->subscriptions);
101 void sipe_subscriptions_remove(struct sipe_core_private *sipe_private,
102 const gchar *key)
104 if (g_hash_table_lookup(sipe_private->subscriptions, key)) {
105 g_hash_table_remove(sipe_private->subscriptions, key);
106 SIPE_DEBUG_INFO("sipe_subscriptions_remove: %s", key);
110 static gboolean process_subscribe_response(struct sipe_core_private *sipe_private,
111 struct sipmsg *msg,
112 struct transaction *trans)
114 gchar *with = parse_from(sipmsg_find_header(msg, "To"));
115 const gchar *event = sipmsg_find_header(msg, "Event");
116 gchar *key;
118 /* The case with 2005 Public IM Connectivity (PIC) - no Event header */
119 if (!event) {
120 struct sipmsg *request_msg = trans->msg;
121 event = sipmsg_find_header(request_msg, "Event");
124 key = sipe_utils_subscription_key(event, with);
126 /* 200 OK; 481 Call Leg Does Not Exist */
127 if (key && (msg->response == 200 || msg->response == 481)) {
128 sipe_subscriptions_remove(sipe_private, key);
131 /* create/store subscription dialog if not yet */
132 if (key && (msg->response == 200)) {
133 struct sip_subscription *subscription = g_new0(struct sip_subscription, 1);
134 g_hash_table_insert(sipe_private->subscriptions,
135 g_strdup(key),
136 subscription);
138 subscription->dialog.callid = g_strdup(sipmsg_find_header(msg, "Call-ID"));
139 subscription->dialog.cseq = sipmsg_parse_cseq(msg);
140 subscription->dialog.with = g_strdup(with);
141 subscription->event = g_strdup(event);
142 sipe_dialog_parse(&subscription->dialog, msg, TRUE);
144 SIPE_DEBUG_INFO("process_subscribe_response: subscription dialog added for: %s", key);
147 g_free(key);
148 g_free(with);
150 if (sipmsg_find_header(msg, "ms-piggyback-cseq"))
152 process_incoming_notify(sipe_private, msg, FALSE, FALSE);
154 return TRUE;
158 * common subscription code
160 void sipe_subscribe(struct sipe_core_private *sipe_private,
161 const gchar *uri,
162 const gchar *event,
163 const gchar *accept,
164 const gchar *addheaders,
165 const gchar *body,
166 struct sip_dialog *dialog)
168 gchar *contact = get_contact(sipe_private);
169 gchar *hdr = g_strdup_printf(
170 "Event: %s\r\n"
171 "Accept: %s\r\n"
172 "Supported: com.microsoft.autoextend\r\n"
173 "Supported: ms-benotify\r\n"
174 "Proxy-Require: ms-benotify\r\n"
175 "Supported: ms-piggyback-first-notify\r\n"
176 "%s"
177 "Contact: %s\r\n",
178 event,
179 accept,
180 addheaders ? addheaders : "",
181 contact);
182 g_free(contact);
185 sip_transport_subscribe(sipe_private,
186 uri,
187 hdr,
188 body,
189 dialog,
190 process_subscribe_response);
192 g_free(hdr);
196 * common subscription code for self-subscriptions
198 static void sipe_subscribe_self(struct sipe_core_private *sipe_private,
199 const gchar *event,
200 const gchar *accept,
201 const gchar *addheaders,
202 const gchar *body,
203 struct sip_dialog *dialog)
205 gchar *self = sip_uri_self(sipe_private);
207 sipe_subscribe(sipe_private,
208 self,
209 event,
210 accept,
211 addheaders,
212 body,
213 dialog);
215 g_free(self);
218 static struct sip_dialog *sipe_subscribe_dialog(struct sipe_core_private *sipe_private,
219 const gchar *key)
221 struct sip_dialog *dialog = g_hash_table_lookup(sipe_private->subscriptions,
222 key);
223 SIPE_DEBUG_INFO("sipe_subscribe_dialog: dialog for '%s' is %s", key, dialog ? "not NULL" : "NULL");
224 return dialog;
227 void sipe_subscribe_presence_buddy(struct sipe_core_private *sipe_private,
228 const gchar *uri,
229 const gchar *request,
230 const gchar *body)
232 gchar *key = sipe_utils_presence_key(uri);
234 sip_transport_subscribe(sipe_private,
235 uri,
236 request,
237 body,
238 sipe_subscribe_dialog(sipe_private, key),
239 process_subscribe_response);
241 g_free(key);
244 void sipe_subscribe_presence_wpending(struct sipe_core_private *sipe_private,
245 SIPE_UNUSED_PARAMETER void *unused)
247 gchar *key = sipe_utils_subscription_key("presence.wpending", NULL);
249 sipe_subscribe_self(sipe_private,
250 "presence.wpending",
251 "text/xml+msrtc.wpending",
252 NULL,
253 NULL,
254 sipe_subscribe_dialog(sipe_private, key));
256 g_free(key);
260 * Subscribe roaming ACL
262 void sipe_subscribe_roaming_acl(struct sipe_core_private *sipe_private)
264 sipe_subscribe_self(sipe_private,
265 "vnd-microsoft-roaming-ACL",
266 "application/vnd-microsoft-roaming-acls+xml",
267 NULL,
268 NULL,
269 NULL);
273 * Subscribe roaming contacts
275 void sipe_subscribe_roaming_contacts(struct sipe_core_private *sipe_private)
277 sipe_subscribe_self(sipe_private,
278 "vnd-microsoft-roaming-contacts",
279 "application/vnd-microsoft-roaming-contacts+xml",
280 NULL,
281 NULL,
282 NULL);
286 * OCS 2005 version
288 void sipe_subscribe_roaming_provisioning(struct sipe_core_private *sipe_private)
290 sipe_subscribe_self(sipe_private,
291 "vnd-microsoft-provisioning",
292 "application/vnd-microsoft-roaming-provisioning+xml",
293 "Expires: 0\r\n",
294 NULL,
295 NULL);
299 * Subscription for provisioning information to help with initial
300 * configuration. This subscription is a one-time query (denoted by the
301 * Expires header, which asks for 0 seconds for the subscription lifetime).
302 * This subscription asks for server configuration, meeting policies, and
303 * policy settings that Communicator must enforce.
305 * @TODO: for what do we need this information?
307 void sipe_subscribe_roaming_provisioning_v2(struct sipe_core_private *sipe_private)
309 sipe_subscribe_self(sipe_private,
310 "vnd-microsoft-provisioning-v2",
311 "application/vnd-microsoft-roaming-provisioning-v2+xml",
312 "Expires: 0\r\n"
313 "Content-Type: application/vnd-microsoft-roaming-provisioning-v2+xml\r\n",
314 "<provisioningGroupList xmlns=\"http://schemas.microsoft.com/2006/09/sip/provisioninggrouplist\">"
315 "<provisioningGroup name=\"ServerConfiguration\"/><provisioningGroup name=\"meetingPolicy\"/>"
316 "<provisioningGroup name=\"ucPolicy\"/>"
317 "</provisioningGroupList>",
318 NULL);
322 * To request for presence information about the user, access level settings
323 * that have already been configured by the user to control who has access to
324 * what information, and the list of contacts who currently have outstanding
325 * subscriptions.
327 * We wait for (BE)NOTIFY messages with some info change (categories,
328 * containers, subscribers)
330 void sipe_subscribe_roaming_self(struct sipe_core_private *sipe_private)
332 sipe_subscribe_self(sipe_private,
333 "vnd-microsoft-roaming-self",
334 "application/vnd-microsoft-roaming-self+xml",
335 "Content-Type: application/vnd-microsoft-roaming-self+xml\r\n",
336 "<roamingList xmlns=\"http://schemas.microsoft.com/2006/09/sip/roaming-self\">"
337 "<roaming type=\"categories\"/>"
338 "<roaming type=\"containers\"/>"
339 "<roaming type=\"subscribers\"/></roamingList>",
340 NULL);
344 Local Variables:
345 mode: c
346 c-file-style: "bsd"
347 indent-tabs-mode: t
348 tab-width: 8
349 End: