1 /**
2  * @file sipe-notify.c
3  *
4  * pidgin-sipe
5  *
6  * Copyright (C) 2011-2017 SIPE Project <http://sipe.sourceforge.net/>
7  *
8  *
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.
13  *
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.
18  *
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
22  *
23  *
24  * Process incoming SIP NOTIFY/BENOTIFY messages
25  *
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include <glib.h>
36 
37 #include "sipmsg.h"
38 #include "sip-csta.h"
39 #include "sip-soap.h"
40 #include "sipe-backend.h"
41 #include "sipe-buddy.h"
42 #include "sipe-cal.h"
43 #include "sipe-conf.h"
44 #include "sipe-core.h"
45 #include "sipe-core-private.h"
46 #include "sipe-group.h"
47 #include "sipe-groupchat.h"
48 #include "sipe-media.h"
49 #include "sipe-mime.h"
50 #include "sipe-nls.h"
51 #include "sipe-notify.h"
52 #include "sipe-ocs2005.h"
53 #include "sipe-ocs2007.h"
54 #include "sipe-status.h"
55 #include "sipe-subscriptions.h"
56 #include "sipe-ucs.h"
57 #include "sipe-utils.h"
58 #include "sipe-xml.h"
59 
60 /* OCS2005 */
sipe_process_provisioning(struct sipe_core_private * sipe_private,struct sipmsg * msg)61 static void sipe_process_provisioning(struct sipe_core_private *sipe_private,
62 				      struct sipmsg *msg)
63 {
64 	sipe_xml *xn_provision;
65 	const sipe_xml *node;
66 
67 	xn_provision = sipe_xml_parse(msg->body, msg->bodylen);
68 	if ((node = sipe_xml_child(xn_provision, "user"))) {
69 		SIPE_DEBUG_INFO("sipe_process_provisioning: uri=%s", sipe_xml_attribute(node, "uri"));
70 		if ((node = sipe_xml_child(node, "line"))) {
71 			const gchar *line_uri = sipe_xml_attribute(node, "uri");
72 			const gchar *server = sipe_xml_attribute(node, "server");
73 			SIPE_DEBUG_INFO("sipe_process_provisioning: line_uri=%s server=%s", line_uri, server);
74 			sip_csta_open(sipe_private, line_uri, server);
75 		}
76 	}
77 	sipe_xml_free(xn_provision);
78 }
79 
80 /* OCS2007+ */
sipe_process_provisioning_v2(struct sipe_core_private * sipe_private,struct sipmsg * msg)81 static void sipe_process_provisioning_v2(struct sipe_core_private *sipe_private,
82 					 struct sipmsg *msg)
83 {
84 #define READ_INT_FROM_NODE(node_name, field) { \
85 	gchar *s = g_strstrip(sipe_xml_data(sipe_xml_child(node, node_name))); \
86 	sipe_private->field = s ? atoi(s) : 0; \
87 	g_free(s); }
88 
89 	sipe_xml *xn_provision_group_list;
90 	const sipe_xml *node;
91 
92 	xn_provision_group_list = sipe_xml_parse(msg->body, msg->bodylen);
93 
94 	/* provisionGroup */
95 	for (node = sipe_xml_child(xn_provision_group_list, "provisionGroup");
96 	     node;
97 	     node = sipe_xml_twin(node)) {
98 		const gchar *node_name = sipe_xml_attribute(node, "name");
99 
100 		/* ServerConfiguration */
101 		if (sipe_strequal("ServerConfiguration", node_name)) {
102 			const gchar *dlx_uri_str = SIPE_CORE_PRIVATE_FLAG_IS(REMOTE_USER) ?
103 					"dlxExternalUrl" : "dlxInternalUrl";
104 			const gchar *addressbook_uri_str = SIPE_CORE_PRIVATE_FLAG_IS(REMOTE_USER) ?
105 					"absExternalServerUrl" : "absInternalServerUrl";
106 			gchar *ucPC2PCAVEncryption = NULL;
107 			gchar *ucPortRangeEnabled = NULL;
108 
109 			g_free(sipe_private->focus_factory_uri);
110 			sipe_private->focus_factory_uri = sipe_xml_data(sipe_xml_child(node, "focusFactoryUri"));
111 			SIPE_DEBUG_INFO("sipe_process_provisioning_v2: sipe_private->focus_factory_uri=%s",
112 					sipe_private->focus_factory_uri ? sipe_private->focus_factory_uri : "");
113 
114 			g_free(sipe_private->dlx_uri);
115 			sipe_private->dlx_uri = sipe_xml_data(sipe_xml_child(node, dlx_uri_str));
116 			SIPE_DEBUG_INFO("sipe_process_provisioning_v2: sipe_private->dlx_uri=%s",
117 					sipe_private->dlx_uri ? sipe_private->dlx_uri : "");
118 
119 			g_free(sipe_private->addressbook_uri);
120 			sipe_private->addressbook_uri = sipe_xml_data(sipe_xml_child(node, addressbook_uri_str));
121 			SIPE_DEBUG_INFO("sipe_process_provisioning_v2: sipe_private->addressbook_uri=%s",
122 					sipe_private->addressbook_uri ? sipe_private->addressbook_uri : "");
123 
124 #ifdef HAVE_VV
125 			g_free(sipe_private->test_call_bot_uri);
126 			sipe_private->test_call_bot_uri = sipe_xml_data(sipe_xml_child(node, "botSipUriForTestCall"));
127 			SIPE_DEBUG_INFO("sipe_process_provisioning_v2: sipe_private->test_call_bot_uri=%s",
128 					sipe_private->test_call_bot_uri ? sipe_private->test_call_bot_uri : "");
129 
130 			g_free(sipe_private->mras_uri);
131 			sipe_private->mras_uri = g_strstrip(sipe_xml_data(sipe_xml_child(node, "mrasUri")));
132 			SIPE_DEBUG_INFO("sipe_process_provisioning_v2: sipe_private->mras_uri=%s",
133 					sipe_private->mras_uri ? sipe_private->mras_uri : "");
134 
135 			if (sipe_private->mras_uri)
136 					sipe_media_get_av_edge_credentials(sipe_private);
137 #endif
138 
139 			ucPC2PCAVEncryption = g_strstrip(sipe_xml_data(sipe_xml_child(node, "ucPC2PCAVEncryption")));
140 			if (sipe_strequal(ucPC2PCAVEncryption, "SupportEncryption")) {
141 				sipe_private->server_av_encryption_policy = SIPE_ENCRYPTION_POLICY_OPTIONAL;
142 			} else if (sipe_strequal(ucPC2PCAVEncryption, "DoNotSupportEncryption")) {
143 				sipe_private->server_av_encryption_policy = SIPE_ENCRYPTION_POLICY_REJECTED;
144 			} else {
145 				// "RequireEncryption" or any unknown value.
146 				sipe_private->server_av_encryption_policy = SIPE_ENCRYPTION_POLICY_REQUIRED;
147 			}
148 			g_free(ucPC2PCAVEncryption);
149 
150 			ucPortRangeEnabled = g_strstrip(sipe_xml_data(sipe_xml_child(node, "ucPortRangeEnabled")));
151 			if (sipe_strequal(ucPortRangeEnabled, "true")) {
152 				READ_INT_FROM_NODE("ucMinMediaPort", min_media_port)
153 				READ_INT_FROM_NODE("ucMaxMediaPort", max_media_port)
154 				READ_INT_FROM_NODE("ucMinAudioPort", min_audio_port)
155 				READ_INT_FROM_NODE("ucMaxAudioPort", max_audio_port)
156 				READ_INT_FROM_NODE("ucMinVideoPort", min_video_port)
157 				READ_INT_FROM_NODE("ucMaxVideoPort", max_video_port)
158 				READ_INT_FROM_NODE("ucMinAppSharingPort", min_appsharing_port)
159 				READ_INT_FROM_NODE("ucMaxAppSharingPort", max_appsharing_port)
160 				READ_INT_FROM_NODE("ucMinFileTransferPort", min_filetransfer_port)
161 				READ_INT_FROM_NODE("ucMaxFileTransferPort", max_filetransfer_port)
162 			} else {
163 				sipe_private->min_media_port = 0;
164 				sipe_private->max_media_port = 0;
165 				sipe_private->min_audio_port = 0;
166 				sipe_private->max_audio_port = 0;
167 				sipe_private->min_video_port = 0;
168 				sipe_private->max_video_port = 0;
169 				sipe_private->min_appsharing_port = 0;
170 				sipe_private->max_appsharing_port = 0;
171 				sipe_private->min_filetransfer_port = 0;
172 				sipe_private->max_filetransfer_port = 0;
173 			}
174 			g_free(ucPortRangeEnabled);
175 
176 		/* persistentChatConfiguration */
177 		} else if (sipe_strequal("persistentChatConfiguration", node_name)) {
178 			const sipe_xml *property;
179 			gboolean enabled = FALSE;
180 			gchar *uri = NULL;
181 
182 			for (property = sipe_xml_child(node, "propertyEntryList/property");
183 			     property;
184 			     property = sipe_xml_twin(property)) {
185 				const gchar *name = sipe_xml_attribute(property, "name");
186 				gchar *value = sipe_xml_data(property);
187 
188 				if (sipe_strequal(name, "EnablePersistentChat")) {
189 					enabled = sipe_strequal(value, "true");
190 
191 				} else if (sipe_strequal(name, "DefaultPersistentChatPoolUri")) {
192 					g_free(uri);
193 					uri = value;
194 					value = NULL;
195 				}
196 				g_free(value);
197 			}
198 
199 			if (enabled) {
200 				g_free(sipe_private->persistentChatPool_uri);
201 				sipe_private->persistentChatPool_uri = g_strdup(sipe_get_no_sip_uri(uri));
202 				SIPE_DEBUG_INFO("sipe_process_provisioning_v2: sipe_private->persistentChatPool_uri=%s",
203 						sipe_private->persistentChatPool_uri ? sipe_private->persistentChatPool_uri : "");
204 			}
205 			g_free(uri);
206 		}
207 
208 	}
209 	sipe_xml_free(xn_provision_group_list);
210 
211 	if (sipe_private->dlx_uri && sipe_private->addressbook_uri) {
212 		/* Some buddies might have been added before we received this
213 		 * provisioning notify with DLX and addressbook URIs. Now we can
214 		 * trigger an update of their photos. */
215 		sipe_buddy_refresh_photos(sipe_private);
216 	}
217 
218 	if (sipe_private->focus_factory_uri) {
219 		/* Fill the list of conferencing capabilities enabled on
220 		 * the server. */
221 		sipe_conf_get_capabilities(sipe_private);
222 	}
223 
224 	if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007))
225 		/* persistentChatPool_uri has been set at this point */
226 		sipe_groupchat_init(sipe_private);
227 }
228 
process_incoming_notify_rlmi_resub(struct sipe_core_private * sipe_private,const gchar * data,unsigned len)229 static void process_incoming_notify_rlmi_resub(struct sipe_core_private *sipe_private,
230 					       const gchar *data, unsigned len)
231 {
232 	sipe_xml *xn_list;
233 	const sipe_xml *xn_resource;
234 	GHashTable *servers = g_hash_table_new_full(g_str_hash, g_str_equal,
235 						    g_free, NULL);
236 
237 	xn_list = sipe_xml_parse(data, len);
238 
239         for (xn_resource = sipe_xml_child(xn_list, "resource");
240 	     xn_resource;
241 	     xn_resource = sipe_xml_twin(xn_resource) )
242 	{
243 		const char *uri, *state;
244 		const sipe_xml *xn_instance;
245 
246 		xn_instance = sipe_xml_child(xn_resource, "instance");
247                 if (!xn_instance) continue;
248 
249                 uri = sipe_xml_attribute(xn_resource, "uri");
250                 state = sipe_xml_attribute(xn_instance, "state");
251                 SIPE_DEBUG_INFO("process_incoming_notify_rlmi_resub: uri(%s),state(%s)", uri, state);
252 
253                 if (strstr(state, "resubscribe")) {
254 			const char *poolFqdn = sipe_xml_attribute(xn_instance, "poolFqdn");
255 
256 			if (poolFqdn) { //[MS-PRES] Section 3.4.5.1.3 Processing Details
257 				gchar *user    = g_strdup(uri);
258 				gchar *host    = g_strdup(poolFqdn);
259 				GSList *server = g_hash_table_lookup(servers,
260 								     host);
261 				server = g_slist_append(server, user);
262 				g_hash_table_insert(servers, host, server);
263 			} else {
264 				sipe_subscribe_presence_single(sipe_private,
265 							       uri,
266 							       uri);
267 			}
268                 }
269 	}
270 
271 	/* Send out any deferred poolFqdn subscriptions */
272 	g_hash_table_foreach(servers, (GHFunc) sipe_subscribe_poolfqdn_resource_uri, sipe_private);
273 	g_hash_table_destroy(servers);
274 
275 	sipe_xml_free(xn_list);
276 }
277 
278 /**
279  * Update user phone
280  * Suitable for both 2005 and 2007 systems.
281  *
282  * @param uri                   buddy SIP URI with 'sip:' prefix whose info we want to change.
283  * @param phone_type
284  * @param phone                 may be modified to strip white space
285  * @param phone_display_string  may be modified to strip white space
286  */
287 static void
sipe_update_user_phone(struct sipe_core_private * sipe_private,const gchar * uri,const gchar * phone_type,gchar * phone,gchar * phone_display_string)288 sipe_update_user_phone(struct sipe_core_private *sipe_private,
289 		       const gchar *uri,
290 		       const gchar *phone_type,
291 		       gchar *phone,
292 		       gchar *phone_display_string)
293 {
294 	sipe_buddy_info_fields phone_node = SIPE_BUDDY_INFO_WORK_PHONE; /* work phone by default */
295 	sipe_buddy_info_fields phone_display_node = SIPE_BUDDY_INFO_WORK_PHONE_DISPLAY; /* work phone by default */
296 
297 	if(!phone || strlen(phone) == 0) return;
298 
299 	if ((sipe_strequal(phone_type, "mobile") ||  sipe_strequal(phone_type, "cell"))) {
300 		phone_node = SIPE_BUDDY_INFO_MOBILE_PHONE;
301 		phone_display_node = SIPE_BUDDY_INFO_MOBILE_PHONE_DISPLAY;
302 	} else if (sipe_strequal(phone_type, "home")) {
303 		phone_node = SIPE_BUDDY_INFO_HOME_PHONE;
304 		phone_display_node = SIPE_BUDDY_INFO_HOME_PHONE_DISPLAY;
305 	} else if (sipe_strequal(phone_type, "other")) {
306 		phone_node = SIPE_BUDDY_INFO_OTHER_PHONE;
307 		phone_display_node = SIPE_BUDDY_INFO_OTHER_PHONE_DISPLAY;
308 	} else if (sipe_strequal(phone_type, "custom1")) {
309 		phone_node = SIPE_BUDDY_INFO_CUSTOM1_PHONE;
310 		phone_display_node = SIPE_BUDDY_INFO_CUSTOM1_PHONE_DISPLAY;
311 	}
312 
313 	sipe_buddy_update_property(sipe_private, uri, phone_node, phone);
314 	if (phone_display_string) {
315 		sipe_buddy_update_property(sipe_private, uri, phone_display_node, phone_display_string);
316 	}
317 }
318 
process_incoming_notify_msrtc(struct sipe_core_private * sipe_private,const gchar * data,unsigned len)319 static void process_incoming_notify_msrtc(struct sipe_core_private *sipe_private,
320 					  const gchar *data,
321 					  unsigned len)
322 {
323 	char *activity = NULL;
324 	const char *epid;
325 	const char *status_id = NULL;
326 	const char *name;
327 	char *uri;
328 	char *self_uri = sip_uri_self(sipe_private);
329 	int avl;
330 	int act;
331 	const char *device_name = NULL;
332 	const char *cal_start_time = NULL;
333 	const char *cal_granularity = NULL;
334 	char *cal_free_busy_base64 = NULL;
335 	struct sipe_buddy *sbuddy;
336 	const sipe_xml *node;
337 	sipe_xml *xn_presentity;
338 	const sipe_xml *xn_availability;
339 	const sipe_xml *xn_activity;
340 	const sipe_xml *xn_display_name;
341 	const sipe_xml *xn_email;
342 	const sipe_xml *xn_phone_number;
343 	const sipe_xml *xn_userinfo;
344 	const sipe_xml *xn_note;
345 	const sipe_xml *xn_oof;
346 	const sipe_xml *xn_state;
347 	const sipe_xml *xn_contact;
348 	char *note;
349 	int user_avail;
350 	const char *user_avail_nil;
351 	int res_avail;
352 	time_t user_avail_since = 0;
353 	time_t activity_since = 0;
354 
355 	/* fix for Reuters environment on Linux */
356 	if (data && strstr(data, "encoding=\"utf-16\"")) {
357 		char *tmp_data;
358 		tmp_data = sipe_utils_str_replace(data, "encoding=\"utf-16\"", "encoding=\"utf-8\"");
359 		xn_presentity = sipe_xml_parse(tmp_data, strlen(tmp_data));
360 		g_free(tmp_data);
361 	} else {
362 		xn_presentity = sipe_xml_parse(data, len);
363 	}
364 
365 	xn_availability = sipe_xml_child(xn_presentity, "availability");
366 	xn_activity = sipe_xml_child(xn_presentity, "activity");
367 	xn_display_name = sipe_xml_child(xn_presentity, "displayName");
368 	xn_email = sipe_xml_child(xn_presentity, "email");
369 	xn_phone_number = sipe_xml_child(xn_presentity, "phoneNumber");
370 	xn_userinfo = sipe_xml_child(xn_presentity, "userInfo");
371 	xn_oof = xn_userinfo ? sipe_xml_child(xn_userinfo, "oof") : NULL;
372 	xn_state = xn_userinfo ? sipe_xml_child(xn_userinfo, "states/state"): NULL;
373 	user_avail = xn_state ? sipe_xml_int_attribute(xn_state, "avail", 0) : 0;
374 	user_avail_since = xn_state ? sipe_utils_str_to_time(sipe_xml_attribute(xn_state, "since")) : 0;
375 	user_avail_nil = xn_state ? sipe_xml_attribute(xn_state, "nil") : NULL;
376 	xn_contact = xn_userinfo ? sipe_xml_child(xn_userinfo, "contact") : NULL;
377 	xn_note = xn_userinfo ? sipe_xml_child(xn_userinfo, "note") : NULL;
378 	note = xn_note ? sipe_xml_data(xn_note) : NULL;
379 
380 	if (sipe_strequal(user_avail_nil, "true")) {	/* null-ed */
381 		user_avail = 0;
382 		user_avail_since = 0;
383 	}
384 
385 	name = sipe_xml_attribute(xn_presentity, "uri"); /* without 'sip:' prefix */
386 	uri = sip_uri_from_name(name);
387 	avl = sipe_xml_int_attribute(xn_availability, "aggregate", 0);
388 	epid = sipe_xml_attribute(xn_availability, "epid");
389 	act = sipe_xml_int_attribute(xn_activity, "aggregate", 0);
390 
391 	status_id = sipe_ocs2005_status_from_activity_availability(act, avl);
392 	activity = g_strdup(sipe_ocs2005_activity_description(act));
393 	res_avail = sipe_ocs2007_availability_from_status(status_id, NULL);
394 	if (user_avail > res_avail) {
395 		res_avail = user_avail;
396 		status_id = sipe_ocs2007_status_from_legacy_availability(user_avail, NULL);
397 	}
398 
399 	if (xn_display_name) {
400 		char *display_name = g_strdup(sipe_xml_attribute(xn_display_name, "displayName"));
401 		char *email        = xn_email ? g_strdup(sipe_xml_attribute(xn_email, "email")) : NULL;
402 		char *phone_label  = xn_phone_number ? g_strdup(sipe_xml_attribute(xn_phone_number, "label")) : NULL;
403 		char *phone_number = xn_phone_number ? g_strdup(sipe_xml_attribute(xn_phone_number, "number")) : NULL;
404 		char *tel_uri      = sip_to_tel_uri(phone_number);
405 
406 		sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_DISPLAY_NAME, display_name);
407 		sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_EMAIL, email);
408 		sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_WORK_PHONE, tel_uri);
409 		sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_WORK_PHONE_DISPLAY, !is_empty(phone_label) ? phone_label : phone_number);
410 
411 		g_free(tel_uri);
412 		g_free(phone_label);
413 		g_free(phone_number);
414 		g_free(email);
415 		g_free(display_name);
416 	}
417 
418 	if (xn_contact) {
419 		/* tel */
420 		for (node = sipe_xml_child(xn_contact, "tel"); node; node = sipe_xml_twin(node))
421 		{
422 			/* Ex.: <tel type="work">tel:+3222220000</tel> */
423 			const char *phone_type = sipe_xml_attribute(node, "type");
424 			char* phone = sipe_xml_data(node);
425 
426 			sipe_update_user_phone(sipe_private, uri, phone_type, phone, NULL);
427 
428 			g_free(phone);
429 		}
430 	}
431 
432 	if (xn_display_name || xn_contact)
433 		sipe_backend_buddy_refresh_properties(SIPE_CORE_PUBLIC, uri);
434 
435 	/* devicePresence */
436 	for (node = sipe_xml_child(xn_presentity, "devices/devicePresence"); node; node = sipe_xml_twin(node)) {
437 		const sipe_xml *xn_device_name;
438 		const sipe_xml *xn_calendar_info;
439 		const sipe_xml *xn_state;
440 		char *state;
441 
442 		/* deviceName */
443 		if (sipe_strequal(sipe_xml_attribute(node, "epid"), epid)) {
444 			xn_device_name = sipe_xml_child(node, "deviceName");
445 			device_name = xn_device_name ? sipe_xml_attribute(xn_device_name, "name") : NULL;
446 		}
447 
448 		/* calendarInfo */
449 		xn_calendar_info = sipe_xml_child(node, "calendarInfo");
450 		if (xn_calendar_info) {
451 			const char *cal_start_time_tmp = sipe_xml_attribute(xn_calendar_info, "startTime");
452 
453 			if (cal_start_time) {
454 				time_t cal_start_time_t     = sipe_utils_str_to_time(cal_start_time);
455 				time_t cal_start_time_t_tmp = sipe_utils_str_to_time(cal_start_time_tmp);
456 
457 				if (cal_start_time_t_tmp > cal_start_time_t) {
458 					cal_start_time = cal_start_time_tmp;
459 					cal_granularity = sipe_xml_attribute(xn_calendar_info, "granularity");
460 					g_free(cal_free_busy_base64);
461 					cal_free_busy_base64 = sipe_xml_data(xn_calendar_info);
462 
463 					SIPE_DEBUG_INFO("process_incoming_notify_msrtc: startTime=%s granularity=%s cal_free_busy_base64=\n%s", cal_start_time, cal_granularity, cal_free_busy_base64);
464 				}
465 			} else {
466 				cal_start_time = cal_start_time_tmp;
467 				cal_granularity = sipe_xml_attribute(xn_calendar_info, "granularity");
468 				g_free(cal_free_busy_base64);
469 				cal_free_busy_base64 = sipe_xml_data(xn_calendar_info);
470 
471 				SIPE_DEBUG_INFO("process_incoming_notify_msrtc: startTime=%s granularity=%s cal_free_busy_base64=\n%s", cal_start_time, cal_granularity, cal_free_busy_base64);
472 			}
473 		}
474 
475 		/* state */
476 		xn_state = sipe_xml_child(node, "states/state");
477 		if (xn_state) {
478 			int dev_avail = sipe_xml_int_attribute(xn_state, "avail", 0);
479 			time_t dev_avail_since = sipe_utils_str_to_time(sipe_xml_attribute(xn_state, "since"));
480 
481 			state = sipe_xml_data(xn_state);
482 			if (dev_avail_since > user_avail_since &&
483 			    dev_avail >= res_avail)
484 			{
485 				const gchar *new_desc;
486 				res_avail = dev_avail;
487 				if (!is_empty(state)) {
488 					if (sipe_strequal(state, sipe_status_activity_to_token(SIPE_ACTIVITY_ON_PHONE))) {
489 						g_free(activity);
490 						activity = g_strdup(sipe_core_activity_description(SIPE_ACTIVITY_ON_PHONE));
491 					} else if (sipe_strequal(state, "presenting")) {
492 						g_free(activity);
493 						activity = g_strdup(sipe_core_activity_description(SIPE_ACTIVITY_IN_CONF));
494 					} else {
495 						activity = state;
496 						state = NULL;
497 					}
498 					activity_since = dev_avail_since;
499 				}
500 				status_id = sipe_ocs2007_status_from_legacy_availability(res_avail, NULL);
501 				new_desc  = sipe_ocs2007_legacy_activity_description(res_avail);
502 				if (new_desc) {
503 					g_free(activity);
504 					activity = g_strdup(new_desc);
505 				}
506 			}
507 			g_free(state);
508 		}
509 	}
510 
511 	/* oof */
512 	if (xn_oof && res_avail >= 15000) { /* 12000 in 2007 */
513 		g_free(activity);
514 		activity = g_strdup(sipe_core_activity_description(SIPE_ACTIVITY_OOF));
515 		activity_since = 0;
516 	}
517 
518 	sbuddy = sipe_buddy_find_by_uri(sipe_private, uri);
519 	if (sbuddy)
520 	{
521 		g_free(sbuddy->activity);
522 		sbuddy->activity = activity;
523 		activity = NULL;
524 
525 		sbuddy->activity_since = activity_since;
526 
527 		sbuddy->user_avail = user_avail;
528 		sbuddy->user_avail_since = user_avail_since;
529 
530 		g_free(sbuddy->note);
531 		sbuddy->note = NULL;
532 		if (!is_empty(note)) { sbuddy->note = g_markup_escape_text(note, -1); }
533 
534 		sbuddy->is_oof_note = (xn_oof != NULL);
535 
536 		g_free(sbuddy->device_name);
537 		sbuddy->device_name = NULL;
538 		if (!is_empty(device_name)) { sbuddy->device_name = g_strdup(device_name); }
539 
540 		if (!is_empty(cal_free_busy_base64)) {
541 			g_free(sbuddy->cal_start_time);
542 			sbuddy->cal_start_time = g_strdup(cal_start_time);
543 
544 			sbuddy->cal_granularity = sipe_strcase_equal(cal_granularity, "PT15M") ? 15 : 0;
545 
546 			g_free(sbuddy->cal_free_busy_base64);
547 			sbuddy->cal_free_busy_base64 = cal_free_busy_base64;
548 			cal_free_busy_base64 = NULL;
549 
550 			g_free(sbuddy->cal_free_busy);
551 			sbuddy->cal_free_busy = NULL;
552 		}
553 
554 		sbuddy->last_non_cal_status_id = status_id;
555 		g_free(sbuddy->last_non_cal_activity);
556 		sbuddy->last_non_cal_activity = g_strdup(sbuddy->activity);
557 
558 		if (sipe_strcase_equal(sbuddy->name, self_uri)) {
559 			if (!sipe_strequal(sbuddy->note, sipe_private->note)) /* not same */
560 			{
561 				if (sbuddy->is_oof_note)
562 					SIPE_CORE_PRIVATE_FLAG_SET(OOF_NOTE);
563 				else
564 					SIPE_CORE_PRIVATE_FLAG_UNSET(OOF_NOTE);
565 
566 				g_free(sipe_private->note);
567 				sipe_private->note = g_strdup(sbuddy->note);
568 
569 				sipe_private->note_since = time(NULL);
570 			}
571 
572 			sipe_status_set_token(sipe_private,
573 					      sbuddy->last_non_cal_status_id);
574 		}
575 	}
576 	g_free(cal_free_busy_base64);
577 	g_free(activity);
578 
579 	SIPE_DEBUG_INFO("process_incoming_notify_msrtc: status(%s)", status_id);
580 	sipe_core_buddy_got_status(SIPE_CORE_PUBLIC, uri,
581 				   sipe_status_token_to_activity(status_id));
582 
583 	if (!SIPE_CORE_PRIVATE_FLAG_IS(OCS2007) && sipe_strcase_equal(self_uri, uri)) {
584 		sipe_ocs2005_user_info_has_updated(sipe_private, xn_userinfo);
585 	}
586 
587 	g_free(note);
588 	sipe_xml_free(xn_presentity);
589 	g_free(uri);
590 	g_free(self_uri);
591 }
592 
process_incoming_notify_rlmi(struct sipe_core_private * sipe_private,const gchar * data,unsigned len)593 static void process_incoming_notify_rlmi(struct sipe_core_private *sipe_private,
594 					 const gchar *data,
595 					 unsigned len)
596 {
597 	const char *uri;
598 	struct sipe_buddy *sbuddy = NULL;
599 	sipe_xml *xn_categories;
600 	const sipe_xml *xn_category;
601 	const char *status = NULL;
602 	gboolean do_update_status = FALSE;
603 	gboolean has_note_cleaned = FALSE;
604 	gboolean has_free_busy_cleaned = FALSE;
605 
606 	xn_categories = sipe_xml_parse(data, len);
607 	uri = sipe_xml_attribute(xn_categories, "uri"); /* with 'sip:' prefix */
608 	if (uri) {
609 		sbuddy = sipe_buddy_find_by_uri(sipe_private, uri);
610 	}
611 
612 	if (!sbuddy) {
613 		/* Got presence of a buddy not in our contact list, ignore. */
614 		sipe_xml_free(xn_categories);
615 		return;
616 	}
617 
618 	for (xn_category = sipe_xml_child(xn_categories, "category");
619 		 xn_category ;
620 		 xn_category = sipe_xml_twin(xn_category) )
621 	{
622 		const sipe_xml *xn_node;
623 		const char *tmp;
624 		const char *attrVar = sipe_xml_attribute(xn_category, "name");
625 		time_t publish_time = (tmp = sipe_xml_attribute(xn_category, "publishTime")) ?
626 			sipe_utils_str_to_time(tmp) : 0;
627 
628 		/* contactCard */
629 		if (sipe_strequal(attrVar, "contactCard"))
630 		{
631 			const sipe_xml *card = sipe_xml_child(xn_category, "contactCard");
632 
633 			if (card) {
634 				const sipe_xml *node;
635 				/* identity - Display Name and email */
636 				node = sipe_xml_child(card, "identity");
637 				if (node) {
638 					char* display_name = sipe_xml_data(
639 						sipe_xml_child(node, "name/displayName"));
640 					char* email = sipe_xml_data(
641 						sipe_xml_child(node, "email"));
642 
643 					sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_DISPLAY_NAME, display_name);
644 					sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_EMAIL, email);
645 
646 					g_free(display_name);
647 					g_free(email);
648 				}
649 				/* company */
650 				node = sipe_xml_child(card, "company");
651 				if (node) {
652 					char* company = sipe_xml_data(node);
653 					sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_COMPANY, company);
654 					g_free(company);
655 				}
656 				/* department */
657 				node = sipe_xml_child(card, "department");
658 				if (node) {
659 					char* department = sipe_xml_data(node);
660 					sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_DEPARTMENT, department);
661 					g_free(department);
662 				}
663 				/* title */
664 				node = sipe_xml_child(card, "title");
665 				if (node) {
666 					char* title = sipe_xml_data(node);
667 					sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_JOB_TITLE, title);
668 					g_free(title);
669 				}
670 				/* office */
671 				node = sipe_xml_child(card, "office");
672 				if (node) {
673 					char* office = sipe_xml_data(node);
674 					sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_OFFICE, office);
675 					g_free(office);
676 				}
677 				/* site (url) */
678 				node = sipe_xml_child(card, "url");
679 				if (node) {
680 					char* site = sipe_xml_data(node);
681 					sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_SITE, site);
682 					g_free(site);
683 				}
684 				/* phone */
685 				for (node = sipe_xml_child(card, "phone");
686 				     node;
687 				     node = sipe_xml_twin(node))
688 				{
689 					const char *phone_type = sipe_xml_attribute(node, "type");
690 					char* phone = sipe_xml_data(sipe_xml_child(node, "uri"));
691 					char* phone_display_string = sipe_xml_data(sipe_xml_child(node, "displayString"));
692 
693 					sipe_update_user_phone(sipe_private, uri, phone_type, phone, phone_display_string);
694 
695 					g_free(phone);
696 					g_free(phone_display_string);
697 				}
698 				/* address */
699 				for (node = sipe_xml_child(card, "address");
700 				     node;
701 				     node = sipe_xml_twin(node))
702 				{
703 					if (sipe_strequal(sipe_xml_attribute(node, "type"), "work")) {
704 						char* street = sipe_xml_data(sipe_xml_child(node, "street"));
705 						char* city = sipe_xml_data(sipe_xml_child(node, "city"));
706 						char* state = sipe_xml_data(sipe_xml_child(node, "state"));
707 						char* zipcode = sipe_xml_data(sipe_xml_child(node, "zipcode"));
708 						char* country_code = sipe_xml_data(sipe_xml_child(node, "countryCode"));
709 
710 						sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_STREET, street);
711 						sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_CITY, city);
712 						sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_STATE, state);
713 						sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_ZIPCODE, zipcode);
714 						sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_COUNTRY, country_code);
715 
716 						g_free(street);
717 						g_free(city);
718 						g_free(state);
719 						g_free(zipcode);
720 						g_free(country_code);
721 
722 						break;
723 					}
724 				}
725 				/* photo */
726 				for (node = sipe_xml_child(card, "photo");
727 				     node;
728 				     node = sipe_xml_twin(node)) {
729 					const gchar *type = sipe_xml_attribute(node, "type");
730 					gchar *photo_url;
731 					gchar *hash;
732 					gboolean found = FALSE;
733 
734 					if (sipe_strequal(type, "default") &&
735 					    !SIPE_CORE_PUBLIC_FLAG_IS(ALLOW_WEB_PHOTO)) {
736 						SIPE_DEBUG_INFO("process_incoming_notify_rlmi: skipping download of web profile picture for %s", uri);
737 						continue;
738 					}
739 
740 					photo_url = sipe_xml_data(sipe_xml_child(node, "uri"));
741 					hash = sipe_xml_data(sipe_xml_child(node, "hash"));
742 
743 					if (!is_empty(photo_url) && !is_empty(hash)) {
744 						sipe_buddy_update_photo(sipe_private,
745 									uri,
746 									hash,
747 									photo_url,
748 									NULL);
749 						found = TRUE;
750 					}
751 
752 					g_free(hash);
753 					g_free(photo_url);
754 
755 					if (found)
756 						break;
757 				}
758 			}
759 		}
760 		/* note */
761 		else if (sipe_strequal(attrVar, "note"))
762 		{
763 			if (!has_note_cleaned) {
764 				has_note_cleaned = TRUE;
765 
766 				g_free(sbuddy->note);
767 				sbuddy->note = NULL;
768 				sbuddy->is_oof_note = FALSE;
769 				sbuddy->note_since = publish_time;
770 
771 				do_update_status = TRUE;
772 			}
773 			if (publish_time >= sbuddy->note_since) {
774 				/* clean up in case no 'note' element is supplied
775 				 * which indicate note removal in client
776 				 */
777 				g_free(sbuddy->note);
778 				sbuddy->note = NULL;
779 				sbuddy->is_oof_note = FALSE;
780 				sbuddy->note_since = publish_time;
781 
782 				xn_node = sipe_xml_child(xn_category, "note/body");
783 				if (xn_node) {
784 					char *tmp;
785 					sbuddy->note = g_markup_escape_text((tmp = sipe_xml_data(xn_node)), -1);
786 					g_free(tmp);
787 					sbuddy->is_oof_note = sipe_strequal(sipe_xml_attribute(xn_node, "type"), "OOF");
788 					sbuddy->note_since = publish_time;
789 
790 					SIPE_DEBUG_INFO("process_incoming_notify_rlmi: uri(%s), note(%s)",
791 							uri, sbuddy->note ? sbuddy->note : "");
792 				}
793 				/* to trigger UI refresh in case no status info is supplied in this update */
794 				do_update_status = TRUE;
795 			}
796 		}
797 		/* state */
798 		else if(sipe_strequal(attrVar, "state"))
799 		{
800 			char *tmp;
801 			int availability;
802 			const sipe_xml *xn_availability;
803 			const sipe_xml *xn_activity;
804 			const sipe_xml *xn_device;
805 			const sipe_xml *xn_meeting_subject;
806 			const sipe_xml *xn_meeting_location;
807 			const gchar *legacy_activity;
808 
809 			xn_node = sipe_xml_child(xn_category, "state");
810 			if (!xn_node) continue;
811 			xn_availability = sipe_xml_child(xn_node, "availability");
812 			if (!xn_availability) continue;
813 			xn_activity = sipe_xml_child(xn_node, "activity");
814 			xn_meeting_subject = sipe_xml_child(xn_node, "meetingSubject");
815 			xn_meeting_location = sipe_xml_child(xn_node, "meetingLocation");
816 
817 			tmp = sipe_xml_data(xn_availability);
818 			availability = atoi(tmp);
819 			g_free(tmp);
820 
821 			sbuddy->is_mobile = FALSE;
822 			xn_device = sipe_xml_child(xn_node, "device");
823 			if (xn_device) {
824 				tmp = sipe_xml_data(xn_device);
825 				sbuddy->is_mobile = !g_ascii_strcasecmp(tmp, "Mobile");
826 				g_free(tmp);
827 			}
828 
829 			/* activity */
830 			g_free(sbuddy->activity);
831 			sbuddy->activity = NULL;
832 			if (xn_activity) {
833 				const char *token = sipe_xml_attribute(xn_activity, "token");
834 				const sipe_xml *xn_custom = sipe_xml_child(xn_activity, "custom");
835 
836 				/* from token */
837 				if (!is_empty(token)) {
838 					sbuddy->activity = g_strdup(sipe_core_activity_description(sipe_status_token_to_activity(token)));
839 				}
840 				/* from custom element */
841 				if (xn_custom) {
842 					char *custom = sipe_xml_data(xn_custom);
843 
844 					if (!is_empty(custom)) {
845 						g_free(sbuddy->activity);
846 						sbuddy->activity = custom;
847 						custom = NULL;
848 					}
849 					g_free(custom);
850 				}
851 			}
852 			/* meeting_subject */
853 			g_free(sbuddy->meeting_subject);
854 			sbuddy->meeting_subject = NULL;
855 			if (xn_meeting_subject) {
856 				char *meeting_subject = sipe_xml_data(xn_meeting_subject);
857 
858 				if (!is_empty(meeting_subject)) {
859 					sbuddy->meeting_subject = meeting_subject;
860 					meeting_subject = NULL;
861 				}
862 				g_free(meeting_subject);
863 			}
864 			/* meeting_location */
865 			g_free(sbuddy->meeting_location);
866 			sbuddy->meeting_location = NULL;
867 			if (xn_meeting_location) {
868 				char *meeting_location = sipe_xml_data(xn_meeting_location);
869 
870 				if (!is_empty(meeting_location)) {
871 					sbuddy->meeting_location = meeting_location;
872 					meeting_location = NULL;
873 				}
874 				g_free(meeting_location);
875 			}
876 
877 			status = sipe_ocs2007_status_from_legacy_availability(availability, NULL);
878 			legacy_activity = sipe_ocs2007_legacy_activity_description(availability);
879 			if (sbuddy->activity && legacy_activity) {
880 				gchar *tmp2 = sbuddy->activity;
881 
882 				sbuddy->activity = g_strdup_printf("%s, %s", sbuddy->activity, legacy_activity);
883 				g_free(tmp2);
884 			} else if (legacy_activity) {
885 				sbuddy->activity = g_strdup(legacy_activity);
886 			}
887 
888 			do_update_status = TRUE;
889 		}
890 		/* calendarData */
891 		else if(sipe_strequal(attrVar, "calendarData"))
892 		{
893 			const sipe_xml *xn_free_busy = sipe_xml_child(xn_category, "calendarData/freeBusy");
894 			const sipe_xml *xn_working_hours = sipe_xml_child(xn_category, "calendarData/WorkingHours");
895 
896 			if (xn_free_busy) {
897 				if (!has_free_busy_cleaned) {
898 					has_free_busy_cleaned = TRUE;
899 
900 					g_free(sbuddy->cal_start_time);
901 					sbuddy->cal_start_time = NULL;
902 
903 					g_free(sbuddy->cal_free_busy_base64);
904 					sbuddy->cal_free_busy_base64 = NULL;
905 
906 					g_free(sbuddy->cal_free_busy);
907 					sbuddy->cal_free_busy = NULL;
908 
909 					sbuddy->cal_free_busy_published = publish_time;
910 				}
911 
912 				if (publish_time >= sbuddy->cal_free_busy_published) {
913 					g_free(sbuddy->cal_start_time);
914 					sbuddy->cal_start_time = g_strdup(sipe_xml_attribute(xn_free_busy, "startTime"));
915 
916 					sbuddy->cal_granularity = sipe_strcase_equal(sipe_xml_attribute(xn_free_busy, "granularity"), "PT15M") ?
917 						15 : 0;
918 
919 					g_free(sbuddy->cal_free_busy_base64);
920 					sbuddy->cal_free_busy_base64 = sipe_xml_data(xn_free_busy);
921 
922 					g_free(sbuddy->cal_free_busy);
923 					sbuddy->cal_free_busy = NULL;
924 
925 					sbuddy->cal_free_busy_published = publish_time;
926 
927 					SIPE_DEBUG_INFO("process_incoming_notify_rlmi: startTime=%s granularity=%d cal_free_busy_base64=\n%s", sbuddy->cal_start_time, sbuddy->cal_granularity, sbuddy->cal_free_busy_base64);
928 				}
929 			}
930 
931 			if (xn_working_hours) {
932 				sipe_cal_parse_working_hours(xn_working_hours, sbuddy);
933 			}
934 		}
935 	}
936 
937 	if (do_update_status) {
938 		guint activity;
939 
940 		if (status) {
941 			SIPE_DEBUG_INFO("process_incoming_notify_rlmi: %s", status);
942 			activity = sipe_status_token_to_activity(status);
943 		} else {
944 			/* no status category in this update,
945 			   using contact's current status */
946 			activity = sipe_backend_buddy_get_status(SIPE_CORE_PUBLIC,
947 								 uri);
948 		}
949 
950 		sipe_core_buddy_got_status(SIPE_CORE_PUBLIC, uri, activity);
951 	}
952 
953 	sipe_backend_buddy_refresh_properties(SIPE_CORE_PUBLIC, uri);
954 
955 	sipe_xml_free(xn_categories);
956 }
957 
sipe_buddy_status_from_activity(struct sipe_core_private * sipe_private,const gchar * uri,const gchar * activity,gboolean is_online)958 static void sipe_buddy_status_from_activity(struct sipe_core_private *sipe_private,
959 					    const gchar *uri,
960 					    const gchar *activity,
961 					    gboolean is_online)
962 {
963 	if (is_online) {
964 		const gchar *status_id = NULL;
965 		if (activity) {
966 			if (sipe_strequal(activity,
967 					  sipe_status_activity_to_token(SIPE_ACTIVITY_BUSY))) {
968 				status_id = sipe_status_activity_to_token(SIPE_ACTIVITY_BUSY);
969 			} else if (sipe_strequal(activity,
970 						 sipe_status_activity_to_token(SIPE_ACTIVITY_AWAY))) {
971 				status_id = sipe_status_activity_to_token(SIPE_ACTIVITY_AWAY);
972 			}
973 		}
974 
975 		if (!status_id) {
976 			status_id = sipe_status_activity_to_token(SIPE_ACTIVITY_AVAILABLE);
977 		}
978 
979 		SIPE_DEBUG_INFO("sipe_buddy_status_from_activity: status_id(%s)", status_id);
980 		sipe_core_buddy_got_status(SIPE_CORE_PUBLIC, uri,
981 					   sipe_status_token_to_activity(status_id));
982 	} else {
983 		sipe_core_buddy_got_status(SIPE_CORE_PUBLIC, uri,
984 					   SIPE_ACTIVITY_OFFLINE);
985 	}
986 }
987 
process_incoming_notify_pidf(struct sipe_core_private * sipe_private,const gchar * data,unsigned len)988 static void process_incoming_notify_pidf(struct sipe_core_private *sipe_private,
989 					 const gchar *data,
990 					 unsigned len)
991 {
992 	gchar *uri;
993 	gchar *getbasic;
994 	gchar *activity = NULL;
995 	sipe_xml *pidf;
996 	const sipe_xml *basicstatus = NULL, *tuple, *status;
997 	gboolean isonline = FALSE;
998 	const sipe_xml *display_name_node;
999 
1000 	pidf = sipe_xml_parse(data, len);
1001 	if (!pidf) {
1002 		SIPE_DEBUG_INFO("process_incoming_notify_pidf: no parseable pidf:%s", data);
1003 		return;
1004 	}
1005 
1006 	if ((tuple = sipe_xml_child(pidf, "tuple")))
1007 	{
1008 		if ((status = sipe_xml_child(tuple, "status"))) {
1009 			basicstatus = sipe_xml_child(status, "basic");
1010 		}
1011 	}
1012 
1013 	if (!basicstatus) {
1014 		SIPE_DEBUG_INFO_NOFORMAT("process_incoming_notify_pidf: no basic found");
1015 		sipe_xml_free(pidf);
1016 		return;
1017 	}
1018 
1019 	getbasic = sipe_xml_data(basicstatus);
1020 	if (!getbasic) {
1021 		SIPE_DEBUG_INFO_NOFORMAT("process_incoming_notify_pidf: no basic data found");
1022 		sipe_xml_free(pidf);
1023 		return;
1024 	}
1025 
1026 	SIPE_DEBUG_INFO("process_incoming_notify_pidf: basic-status(%s)", getbasic);
1027 	if (strstr(getbasic, "open")) {
1028 		isonline = TRUE;
1029 	}
1030 	g_free(getbasic);
1031 
1032 	uri = sip_uri(sipe_xml_attribute(pidf, "entity")); /* with 'sip:' prefix */ /* AOL comes without the prefix */
1033 
1034 	display_name_node = sipe_xml_child(pidf, "display-name");
1035 	if (display_name_node) {
1036 		char * display_name = sipe_xml_data(display_name_node);
1037 
1038 		sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_DISPLAY_NAME, display_name);
1039 		g_free(display_name);
1040 
1041 		sipe_backend_buddy_refresh_properties(SIPE_CORE_PUBLIC, uri);
1042 	}
1043 
1044 	if ((tuple = sipe_xml_child(pidf, "tuple"))) {
1045 		if ((status = sipe_xml_child(tuple, "status"))) {
1046 			if ((basicstatus = sipe_xml_child(status, "activities"))) {
1047 				if ((basicstatus = sipe_xml_child(basicstatus, "activity"))) {
1048 					activity = sipe_xml_data(basicstatus);
1049 					SIPE_DEBUG_INFO("process_incoming_notify_pidf: activity(%s)", activity);
1050 				}
1051 			}
1052 		}
1053 	}
1054 
1055 	sipe_buddy_status_from_activity(sipe_private,
1056 					uri,
1057 					activity,
1058 					isonline);
1059 
1060 	g_free(activity);
1061 	g_free(uri);
1062 	sipe_xml_free(pidf);
1063 }
1064 
sipe_presence_mime_cb(gpointer user_data,const GSList * fields,const gchar * body,gsize length)1065 static void sipe_presence_mime_cb(gpointer user_data, /* sipe_core_private */
1066 				  const GSList *fields,
1067 				  const gchar *body,
1068 				  gsize length)
1069 {
1070 	const gchar *type = sipe_utils_nameval_find(fields, "Content-Type");
1071 
1072 	if (strstr(type,"application/rlmi+xml")) {
1073 		process_incoming_notify_rlmi_resub(user_data, body, length);
1074 	} else if (strstr(type, "text/xml+msrtc.pidf")) {
1075 		process_incoming_notify_msrtc(user_data, body, length);
1076 	} else {
1077 		process_incoming_notify_rlmi(user_data, body, length);
1078 	}
1079 }
1080 
sipe_process_presence(struct sipe_core_private * sipe_private,struct sipmsg * msg)1081 static void sipe_process_presence(struct sipe_core_private *sipe_private,
1082 				  struct sipmsg *msg)
1083 {
1084 	const char *ctype = sipmsg_find_header(msg, "Content-Type");
1085 
1086 	SIPE_DEBUG_INFO("sipe_process_presence: Content-Type: %s", ctype ? ctype : "");
1087 
1088 	if (ctype &&
1089 	    (strstr(ctype, "application/rlmi+xml") ||
1090 	     strstr(ctype, "application/msrtc-event-categories+xml")))
1091 	{
1092 		if (strstr(ctype, "multipart"))
1093 		{
1094 			sipe_mime_parts_foreach(ctype, msg->body, sipe_presence_mime_cb, sipe_private);
1095 		}
1096 		else if(strstr(ctype, "application/msrtc-event-categories+xml") )
1097 		{
1098 			process_incoming_notify_rlmi(sipe_private, msg->body, msg->bodylen);
1099 		}
1100 		else if(strstr(ctype, "application/rlmi+xml"))
1101 		{
1102 			process_incoming_notify_rlmi_resub(sipe_private, msg->body, msg->bodylen);
1103 		}
1104 	}
1105 	else if(ctype && strstr(ctype, "text/xml+msrtc.pidf"))
1106 	{
1107 		process_incoming_notify_msrtc(sipe_private, msg->body, msg->bodylen);
1108 	}
1109 	else
1110 	{
1111 		process_incoming_notify_pidf(sipe_private, msg->body, msg->bodylen);
1112 	}
1113 }
1114 
1115 /**
1116  * Fires on deregistration event initiated by server.
1117  * [MS-SIPREGE] SIP extension.
1118  *
1119  *	OCS2007 Example
1120  *
1121  *	Content-Type: text/registration-event
1122  *	subscription-state: terminated;expires=0
1123  *	ms-diagnostics-public: 4141;reason="User disabled"
1124  *
1125  *	deregistered;event=rejected
1126  */
sipe_process_registration_notify(struct sipe_core_private * sipe_private,struct sipmsg * msg)1127 static void sipe_process_registration_notify(struct sipe_core_private *sipe_private,
1128 					     struct sipmsg *msg)
1129 {
1130 	const gchar *contenttype = sipmsg_find_header(msg, "Content-Type");
1131 	gchar *event = NULL;
1132 	gchar *reason = NULL;
1133 	gchar *warning;
1134 
1135 	SIPE_DEBUG_INFO_NOFORMAT("sipe_process_registration_notify: deregistration received.");
1136 
1137 	if (!g_ascii_strncasecmp(contenttype, "text/registration-event", 23)) {
1138 		event = sipmsg_find_part_of_header(msg->body, "event=", NULL, NULL);
1139 		//@TODO have proper parameter extraction _by_name_ func, case insesitive.
1140 		event = event ? event : sipmsg_find_part_of_header(msg->body, "event=", ";", NULL);
1141 	} else {
1142 		SIPE_DEBUG_INFO_NOFORMAT("sipe_process_registration_notify: unknown content type, exiting.");
1143 		return;
1144 	}
1145 
1146 	reason = sipmsg_get_ms_diagnostics_reason(msg);
1147 	reason = reason ? reason : sipmsg_get_ms_diagnostics_public_reason(msg);
1148 	if (!reason) { // for LCS2005
1149 		if (event && sipe_strcase_equal(event, "unregistered")) {
1150 			//reason = g_strdup(_("User logged out")); // [MS-OCER]
1151 			reason = g_strdup(_("you are already signed in at another location"));
1152 		} else if (event && sipe_strcase_equal(event, "rejected")) {
1153 			reason = g_strdup(_("user disabled")); // [MS-OCER]
1154 		} else if (event && sipe_strcase_equal(event, "deactivated")) {
1155 			reason = g_strdup(_("user moved")); // [MS-OCER]
1156 		}
1157 	}
1158 	g_free(event);
1159 	warning = g_strdup_printf(_("You have been rejected by the server: %s"), reason ? reason : _("no reason given"));
1160 	g_free(reason);
1161 
1162 	sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1163 				      SIPE_CONNECTION_ERROR_INVALID_USERNAME,
1164 				      warning);
1165 	g_free(warning);
1166 
1167 }
1168 
1169 /* Replace "~" with localized version of "Other Contacts" */
get_group_name(const sipe_xml * node)1170 static const gchar *get_group_name(const sipe_xml *node)
1171 {
1172 	const gchar *name = sipe_xml_attribute(node, "name");
1173 	return(g_str_has_prefix(name, "~") ? _("Other Contacts") : name);
1174 }
1175 
add_new_group(struct sipe_core_private * sipe_private,const sipe_xml * node)1176 static void add_new_group(struct sipe_core_private *sipe_private,
1177 			  const sipe_xml *node)
1178 {
1179 	sipe_group_add(sipe_private,
1180 		       get_group_name(node),
1181 		       NULL,
1182 		       NULL,
1183 		       sipe_xml_int_attribute(node, "id", 0));
1184 }
1185 
add_new_buddy(struct sipe_core_private * sipe_private,const sipe_xml * node,const gchar * uri)1186 static void add_new_buddy(struct sipe_core_private *sipe_private,
1187 			  const sipe_xml *node,
1188 			  const gchar *uri)
1189 {
1190 	const gchar *name = sipe_xml_attribute(node, "name");
1191 	struct sipe_buddy *buddy = NULL;
1192 	gchar *tmp;
1193 	gchar **item_groups;
1194 	int i = 0;
1195 
1196 	/* "name" attribute is a contact alias which user can manually assign by
1197 	 * renaming the item in the contact list. Empty string means no alias
1198 	 * and the display name from the contact card should be used instead. */
1199 	if (name && strlen(name) == 0) {
1200 		name = NULL;
1201 	}
1202 
1203 	/* assign to group Other Contacts if nothing else received */
1204 	tmp = g_strdup(sipe_xml_attribute(node, "groups"));
1205 	if (is_empty(tmp)) {
1206 		struct sipe_group *group = sipe_group_find_by_name(sipe_private,
1207 								   _("Other Contacts"));
1208 		g_free(tmp);
1209 		tmp = group ? g_strdup_printf("%d", group->id) : g_strdup("1");
1210 	}
1211 	item_groups = g_strsplit(tmp, " ", 0);
1212 	g_free(tmp);
1213 
1214 	while (item_groups[i]) {
1215 		struct sipe_group *group = sipe_group_find_by_id(sipe_private,
1216 								 g_ascii_strtod(item_groups[i],
1217 										NULL));
1218 
1219 		/* If couldn't find the right group for this contact, */
1220 		/* then just put it in the first group we have	      */
1221 		if (!group)
1222 			group = sipe_group_first(sipe_private);
1223 
1224 		if (group) {
1225 			if (!buddy)
1226 				buddy = sipe_buddy_add(sipe_private,
1227 						       uri,
1228 						       NULL,
1229 						       NULL);
1230 
1231 			sipe_buddy_add_to_group(sipe_private,
1232 						buddy,
1233 						group,
1234 						name);
1235 		} else {
1236 			SIPE_DEBUG_INFO("No group found for contact %s!  Unable to add to buddy list",
1237 					uri);
1238 		}
1239 
1240 		i++;
1241 	}
1242 
1243 	g_strfreev(item_groups);
1244 }
1245 
sipe_process_roaming_contacts(struct sipe_core_private * sipe_private,struct sipmsg * msg)1246 static gboolean sipe_process_roaming_contacts(struct sipe_core_private *sipe_private,
1247 					      struct sipmsg *msg)
1248 {
1249 	int len = msg->bodylen;
1250 
1251 	const gchar *tmp = sipmsg_find_header(msg, "Event");
1252 	const sipe_xml *item;
1253 	sipe_xml *isc;
1254 	guint delta;
1255 	const sipe_xml *group_node;
1256 
1257 	if (!g_str_has_prefix(tmp, "vnd-microsoft-roaming-contacts")) {
1258 		return FALSE;
1259 	}
1260 
1261 	/* Convert the contact from XML to backend Buddies */
1262 	isc = sipe_xml_parse(msg->body, len);
1263 	if (!isc) {
1264 		return FALSE;
1265 	}
1266 
1267 	/* [MS-SIP]: deltaNum MUST be non-zero */
1268 	delta = sipe_xml_int_attribute(isc, "deltaNum", 0);
1269 	if (delta) {
1270 		sipe_private->deltanum_contacts = delta;
1271 	}
1272 
1273 	/*
1274 	 * Process whole buddy list
1275 	 *
1276 	 *  - Only sent once
1277 	 *    * up to Lync 2010
1278 	 *    * Lync 2013 (and later) with buddy list not migrated
1279 	 *
1280 	 *  - Lync 2013 with buddy list migrated to Unified Contact Store (UCS)
1281 	 *    * Notify piggy-backed on SUBSCRIBE response with empty list
1282 	 *    * NOTIFY send by server with standard list (ignored by us)
1283 	 */
1284 	if (sipe_strequal(sipe_xml_name(isc), "contactList")) {
1285 		const gchar *ucsmode = sipe_xml_attribute(isc, "ucsmode");
1286 
1287 		SIPE_CORE_PRIVATE_FLAG_UNSET(LYNC2013);
1288 		if (ucsmode) {
1289 			gboolean migrated = sipe_strcase_equal(ucsmode,
1290 							       "migrated");
1291 			SIPE_CORE_PRIVATE_FLAG_SET(LYNC2013);
1292 			SIPE_LOG_INFO_NOFORMAT("sipe_process_roaming_contacts: contact list contains 'ucsmode' attribute (indicates Lync 2013+)");
1293 
1294 			if (migrated)
1295 				SIPE_LOG_INFO_NOFORMAT("sipe_process_roaming_contacts: contact list has been migrated to Unified Contact Store (UCS)");
1296 			sipe_ucs_init(sipe_private, migrated);
1297 		}
1298 
1299 		if (!sipe_ucs_is_migrated(sipe_private)) {
1300 			/* Start processing contact list */
1301 			sipe_backend_buddy_list_processing_start(SIPE_CORE_PUBLIC);
1302 
1303 			/* Parse groups */
1304 			for (group_node = sipe_xml_child(isc, "group"); group_node; group_node = sipe_xml_twin(group_node))
1305 				add_new_group(sipe_private, group_node);
1306 
1307 			/* Make sure we have at least one group */
1308 			if (sipe_group_count(sipe_private) == 0) {
1309 				sipe_group_create(sipe_private,
1310 						  NULL,
1311 						  _("Other Contacts"),
1312 						  NULL);
1313 			}
1314 
1315 			/* Parse contacts */
1316 			for (item = sipe_xml_child(isc, "contact"); item; item = sipe_xml_twin(item)) {
1317 				const gchar *name = sipe_xml_attribute(item, "uri");
1318 				gchar *uri        = sip_uri_from_name(name);
1319 				add_new_buddy(sipe_private, item, uri);
1320 				g_free(uri);
1321 			}
1322 
1323 			sipe_buddy_cleanup_local_list(sipe_private);
1324 
1325 			/* Add self-contact if not there yet. 2005 systems. */
1326 			/* This will resemble subscription to roaming_self in 2007 systems */
1327 			if (!SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
1328 				gchar *self_uri = sip_uri_self(sipe_private);
1329 				sipe_buddy_add(sipe_private,
1330 					       self_uri,
1331 					       NULL,
1332 					       NULL);
1333 				g_free(self_uri);
1334 			}
1335 
1336 			/* Finished processing contact list */
1337 			sipe_backend_buddy_list_processing_finish(SIPE_CORE_PUBLIC);
1338 		}
1339 
1340 	/* Process buddy list updates */
1341 	} else if (sipe_strequal(sipe_xml_name(isc), "contactDelta")) {
1342 
1343 		/* Process new groups */
1344 		for (group_node = sipe_xml_child(isc, "addedGroup"); group_node; group_node = sipe_xml_twin(group_node))
1345 			add_new_group(sipe_private, group_node);
1346 
1347 		/* Process modified groups */
1348 		for (group_node = sipe_xml_child(isc, "modifiedGroup"); group_node; group_node = sipe_xml_twin(group_node)) {
1349 			struct sipe_group *group = sipe_group_find_by_id(sipe_private,
1350 									 (int)g_ascii_strtod(sipe_xml_attribute(group_node, "id"),
1351 											     NULL));
1352 			if (group) {
1353 				const gchar *name = get_group_name(group_node);
1354 
1355 				if (!(is_empty(name) ||
1356 				      sipe_strequal(group->name, name)) &&
1357 				    sipe_group_rename(sipe_private,
1358 						      group,
1359 						      name))
1360 					SIPE_DEBUG_INFO("Replaced group %d name with %s", group->id, name);
1361 			}
1362 		}
1363 
1364 		/* Process new buddies */
1365 		for (item = sipe_xml_child(isc, "addedContact"); item; item = sipe_xml_twin(item)) {
1366 			add_new_buddy(sipe_private,
1367 				      item,
1368 				      sipe_xml_attribute(item, "uri"));
1369 		}
1370 
1371 		/* Process modified buddies */
1372 		for (item = sipe_xml_child(isc, "modifiedContact"); item; item = sipe_xml_twin(item)) {
1373 			const gchar *uri = sipe_xml_attribute(item, "uri");
1374 			struct sipe_buddy *buddy = sipe_buddy_find_by_uri(sipe_private,
1375 									  uri);
1376 
1377 			if (buddy) {
1378 				gchar **item_groups = g_strsplit(sipe_xml_attribute(item,
1379 										    "groups"),
1380 								 " ", 0);
1381 
1382 				/* this should be defined. Otherwise we would get "deletedContact" */
1383 				if (item_groups) {
1384 					const gchar *name = sipe_xml_attribute(item, "name");
1385 					gboolean empty_name = is_empty(name);
1386 					GSList *found = NULL;
1387 					int i = 0;
1388 
1389 					while (item_groups[i]) {
1390 						struct sipe_group *group = sipe_group_find_by_id(sipe_private,
1391 												 g_ascii_strtod(item_groups[i],
1392 														NULL));
1393 						/* ignore unkown groups */
1394 						if (group) {
1395 							sipe_backend_buddy b = sipe_backend_buddy_find(SIPE_CORE_PUBLIC,
1396 												       uri,
1397 												       group->name);
1398 
1399 							/* add group to found list */
1400 							found = g_slist_prepend(found, group);
1401 
1402 							if (b) {
1403 								/* new alias? */
1404 								gchar *b_alias = sipe_backend_buddy_get_alias(SIPE_CORE_PUBLIC,
1405 													      b);
1406 
1407 								if (!(empty_name ||
1408 								      sipe_strequal(b_alias, name))) {
1409 									sipe_backend_buddy_set_alias(SIPE_CORE_PUBLIC,
1410 												     b,
1411 												     name);
1412 									SIPE_DEBUG_INFO("Replaced for buddy %s in group '%s' old alias '%s' with '%s'",
1413 											uri, group->name, b_alias, name);
1414 								}
1415 								g_free(b_alias);
1416 
1417 							} else {
1418 								const gchar *alias = empty_name ? uri : name;
1419 								/* buddy was not in this group */
1420 								sipe_backend_buddy_add(SIPE_CORE_PUBLIC,
1421 										       uri,
1422 										       alias,
1423 										       group->name);
1424 								sipe_buddy_insert_group(buddy, group);
1425 								SIPE_DEBUG_INFO("Added buddy %s (alias '%s' to group '%s'",
1426 										uri, alias, group->name);
1427 							}
1428 						}
1429 
1430 						/* next group */
1431 						i++;
1432 					}
1433 					g_strfreev(item_groups);
1434 
1435  					/* removed from groups? */
1436 					sipe_buddy_update_groups(sipe_private,
1437 								 buddy,
1438 								 found);
1439 					g_slist_free(found);
1440 				}
1441 			}
1442 		}
1443 
1444 		/* Process deleted buddies */
1445 		for (item = sipe_xml_child(isc, "deletedContact"); item; item = sipe_xml_twin(item)) {
1446 			const gchar *uri = sipe_xml_attribute(item, "uri");
1447 			struct sipe_buddy *buddy = sipe_buddy_find_by_uri(sipe_private,
1448 									  uri);
1449 
1450 			if (buddy) {
1451 				SIPE_DEBUG_INFO("Removing buddy %s", uri);
1452 				sipe_buddy_remove(sipe_private, buddy);
1453 			}
1454 		}
1455 
1456 		/* Process deleted groups
1457 		 *
1458 		 * NOTE: all buddies will already have been removed from the
1459 		 *       group prior to this. The log shows that OCS actually
1460 		 *       sends two separate updates when you delete a group:
1461 		 *
1462 		 *         - first one with "modifiedContact" removing buddies
1463 		 *           from the group, leaving it empty, and
1464 		 *
1465 		 *         - then one with "deletedGroup" removing the group
1466 		 */
1467 		for (group_node = sipe_xml_child(isc, "deletedGroup"); group_node; group_node = sipe_xml_twin(group_node))
1468 			sipe_group_remove(sipe_private,
1469 					  sipe_group_find_by_id(sipe_private,
1470 								(int)g_ascii_strtod(sipe_xml_attribute(group_node, "id"),
1471 										    NULL)));
1472 
1473 	}
1474 	sipe_xml_free(isc);
1475 
1476 	/* Subscribe to buddies, if contact list not migrated to UCS */
1477 	if (!sipe_ucs_is_migrated(sipe_private))
1478 		sipe_subscribe_presence_initial(sipe_private);
1479 
1480 	/* for 2005 systems schedule contacts' status update
1481 	 * based on their calendar information
1482 	 */
1483 	if (!SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
1484 		sipe_ocs2005_schedule_status_update(sipe_private, time(NULL));
1485 	}
1486 
1487 	return 0;
1488 }
1489 
sipe_process_roaming_acl(struct sipe_core_private * sipe_private,struct sipmsg * msg)1490 static void sipe_process_roaming_acl(struct sipe_core_private *sipe_private,
1491 				     struct sipmsg *msg)
1492 {
1493 	guint delta;
1494 	sipe_xml *xml;
1495 
1496 	xml = sipe_xml_parse(msg->body, msg->bodylen);
1497 	if (!xml)
1498 		return;
1499 
1500 	/* [MS-SIP]: deltaNum MUST be non-zero */
1501 	delta = sipe_xml_int_attribute(xml, "deltaNum", 0);
1502 	if (delta) {
1503 		sipe_private->deltanum_acl = delta;
1504 	}
1505 
1506 	sipe_xml_free(xml);
1507 }
1508 
1509 struct sipe_auth_job {
1510 	gchar *who;
1511 	struct sipe_core_private *sipe_private;
1512 };
1513 
sipe_core_contact_allow_deny(struct sipe_core_public * sipe_public,const gchar * who,gboolean allow)1514 void sipe_core_contact_allow_deny(struct sipe_core_public *sipe_public,
1515 				  const gchar* who,
1516 				  gboolean allow)
1517 {
1518 	struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
1519 
1520 	if (allow) {
1521 		SIPE_DEBUG_INFO("sipe_core_contact_allow_deny: authorizing contact %s", who);
1522 	} else {
1523 		SIPE_DEBUG_INFO("sipe_core_contact_allow_deny: blocking contact %s", who);
1524 	}
1525 
1526 	if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
1527 		sipe_ocs2007_change_access_level(sipe_private,
1528 						 (allow ? -1 : 32000),
1529 						 "user",
1530 						 sipe_get_no_sip_uri(who));
1531 	} else {
1532 		sip_soap_ocs2005_setacl(sipe_private, who, allow);
1533 	}
1534 }
1535 
1536 
sipe_auth_user_cb(gpointer data)1537 static void sipe_auth_user_cb(gpointer data)
1538 {
1539 	struct sipe_auth_job *job = (struct sipe_auth_job *) data;
1540 	if (!job) return;
1541 
1542 	sipe_core_contact_allow_deny((struct sipe_core_public *)job->sipe_private,
1543 				     job->who,
1544 				     TRUE);
1545 	g_free(job);
1546 }
1547 
sipe_deny_user_cb(gpointer data)1548 static void sipe_deny_user_cb(gpointer data)
1549 {
1550 	struct sipe_auth_job *job = (struct sipe_auth_job *) data;
1551 	if (!job) return;
1552 
1553 	sipe_core_contact_allow_deny((struct sipe_core_public *)job->sipe_private,
1554 				     job->who,
1555 				     FALSE);
1556 	g_free(job);
1557 }
1558 
1559 /* OCS2005- */
sipe_process_presence_wpending(struct sipe_core_private * sipe_private,struct sipmsg * msg)1560 static void sipe_process_presence_wpending (struct sipe_core_private *sipe_private,
1561 					    struct sipmsg * msg)
1562 {
1563 	sipe_xml *watchers;
1564 	const sipe_xml *watcher;
1565 	// Ensure it's either not a response (eg it's a BENOTIFY) or that it's a 200 OK response
1566 	if (msg->response != 0 && msg->response != 200) return;
1567 
1568 	if (msg->bodylen == 0 || msg->body == NULL || sipe_strequal(sipmsg_find_header(msg, "Event"), "msrtc.wpending")) return;
1569 
1570 	watchers = sipe_xml_parse(msg->body, msg->bodylen);
1571 	if (!watchers) return;
1572 
1573 	for (watcher = sipe_xml_child(watchers, "watcher"); watcher; watcher = sipe_xml_twin(watcher)) {
1574 		gchar * remote_user = g_strdup(sipe_xml_attribute(watcher, "uri"));
1575 		gchar * alias = g_strdup(sipe_xml_attribute(watcher, "displayName"));
1576 		gboolean on_list = sipe_buddy_find_by_uri(sipe_private, remote_user) != NULL;
1577 
1578 		// TODO pull out optional displayName to pass as alias
1579 		if (remote_user) {
1580 			struct sipe_auth_job * job = g_new0(struct sipe_auth_job, 1);
1581 			job->who = remote_user;
1582 			job->sipe_private = sipe_private;
1583 			sipe_backend_buddy_request_authorization(SIPE_CORE_PUBLIC,
1584 								 remote_user,
1585 								 alias,
1586 								 on_list,
1587 								 sipe_auth_user_cb,
1588 								 sipe_deny_user_cb,
1589 								 (gpointer)job);
1590 		}
1591 	}
1592 
1593 
1594 	sipe_xml_free(watchers);
1595 	return;
1596 }
1597 
1598 /**
1599  * Dispatcher for all incoming subscription information
1600  * whether it comes from NOTIFY, BENOTIFY requests or
1601  * piggy-backed to subscription's OK responce.
1602  */
process_incoming_notify(struct sipe_core_private * sipe_private,struct sipmsg * msg)1603 void process_incoming_notify(struct sipe_core_private *sipe_private,
1604 			     struct sipmsg *msg)
1605 {
1606 	const gchar *content_type = sipmsg_find_header(msg, "Content-Type");
1607 	const gchar *event = sipmsg_find_header(msg, "Event");
1608 	const gchar *subscription_state = sipmsg_find_header(msg, "subscription-state");
1609 
1610 	SIPE_DEBUG_INFO("process_incoming_notify: subscription_state: %s", subscription_state ? subscription_state : "");
1611 
1612 	/* implicit subscriptions */
1613 	if (content_type && g_str_has_prefix(content_type, "application/ms-imdn+xml")) {
1614 		sipe_process_imdn(sipe_private, msg);
1615 
1616 	/* event subscriptions */
1617 	} else if (event) {
1618 
1619 		/* One-off subscriptions - sent with "Expires: 0" */
1620 		if (sipe_strcase_equal(event, "vnd-microsoft-provisioning-v2")) {
1621 			sipe_process_provisioning_v2(sipe_private, msg);
1622 		} else if (sipe_strcase_equal(event, "vnd-microsoft-provisioning")) {
1623 			sipe_process_provisioning(sipe_private, msg);
1624 		} else if (sipe_strcase_equal(event, "presence")) {
1625 			sipe_process_presence(sipe_private, msg);
1626 		} else if (sipe_strcase_equal(event, "registration-notify")) {
1627 			sipe_process_registration_notify(sipe_private, msg);
1628 
1629 		/* Subscriptions with timeout */
1630 		} else if (!subscription_state || strstr(subscription_state, "active")) {
1631 			if (sipe_strcase_equal(event, "vnd-microsoft-roaming-contacts")) {
1632 				sipe_process_roaming_contacts(sipe_private, msg);
1633 			} else if (sipe_strcase_equal(event, "vnd-microsoft-roaming-self")) {
1634 				sipe_ocs2007_process_roaming_self(sipe_private, msg);
1635 			} else if (sipe_strcase_equal(event, "vnd-microsoft-roaming-ACL")) {
1636 				sipe_process_roaming_acl(sipe_private, msg);
1637 			} else if (sipe_strcase_equal(event, "presence.wpending")) {
1638 				sipe_process_presence_wpending(sipe_private, msg);
1639 			} else if (sipe_strcase_equal(event, "conference")) {
1640 				sipe_process_conference(sipe_private, msg);
1641 			}
1642 		}
1643 	}
1644 }
1645 
1646 /*
1647   Local Variables:
1648   mode: c
1649   c-file-style: "bsd"
1650   indent-tabs-mode: t
1651   tab-width: 8
1652   End:
1653 */
1654