1 /**
2  * @file sipe-ocs2005.c
3  *
4  * pidgin-sipe
5  *
6  * Copyright (C) 2011-2016 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  * OCS2005 specific code
25  *
26  */
27 
28 #include <time.h>
29 
30 #include <glib.h>
31 
32 #include "sipe-common.h"
33 #include "sip-soap.h"
34 #include "sip-transport.h"
35 #include "sipe-backend.h"
36 #include "sipe-buddy.h"
37 #include "sipe-cal.h"
38 #include "sipe-core.h"
39 #include "sipe-core-private.h"
40 #include "sipe-ews.h"
41 #include "sipe-ocs2005.h"
42 #include "sipe-ocs2007.h"
43 #include "sipe-schedule.h"
44 #include "sipe-status.h"
45 #include "sipe-utils.h"
46 #include "sipe-xml.h"
47 
48 /**
49  * 2005-style Activity and Availability.
50  *
51  * [MS-SIP] 2.2.1
52  *
53  * @param activity	2005 aggregated activity.    Ex.: 600
54  * @param availablity	2005 aggregated availablity. Ex.: 300
55  *
56  * The values define the starting point of a range
57  */
58 #define SIPE_OCS2005_ACTIVITY_UNKNOWN       0
59 #define SIPE_OCS2005_ACTIVITY_AWAY        100
60 #define SIPE_OCS2005_ACTIVITY_LUNCH       150
61 #define SIPE_OCS2005_ACTIVITY_IDLE        200
62 #define SIPE_OCS2005_ACTIVITY_BRB         300
63 #define SIPE_OCS2005_ACTIVITY_AVAILABLE   400 /* user is active */
64 #define SIPE_OCS2005_ACTIVITY_ON_PHONE    500 /* user is participating in a communcation session */
65 #define SIPE_OCS2005_ACTIVITY_BUSY        600
66 #define SIPE_OCS2005_ACTIVITY_AWAY2       700
67 #define SIPE_OCS2005_ACTIVITY_AVAILABLE2  800
68 
69 #define SIPE_OCS2005_AVAILABILITY_OFFLINE   0
70 #define SIPE_OCS2005_AVAILABILITY_MAYBE   100
71 #define SIPE_OCS2005_AVAILABILITY_ONLINE  300
sipe_ocs2005_activity_from_status(struct sipe_core_private * sipe_private)72 static guint sipe_ocs2005_activity_from_status(struct sipe_core_private *sipe_private)
73 {
74 	const gchar *status = sipe_private->status;
75 
76 	if (sipe_strequal(status, sipe_status_activity_to_token(SIPE_ACTIVITY_AWAY))) {
77 		return(SIPE_OCS2005_ACTIVITY_AWAY);
78 	/*} else if (sipe_strequal(status, sipe_status_activity_to_token(SIPE_ACTIVITY_LUNCH))) {
79 		return(SIPE_OCS2005_ACTIVITY_LUNCH); */
80 	} else if (sipe_strequal(status, sipe_status_activity_to_token(SIPE_ACTIVITY_BRB))) {
81 		return(SIPE_OCS2005_ACTIVITY_BRB);
82 	} else if (sipe_strequal(status, sipe_status_activity_to_token(SIPE_ACTIVITY_AVAILABLE))) {
83 		return(SIPE_OCS2005_ACTIVITY_AVAILABLE);
84 	/*} else if (sipe_strequal(status, sipe_status_activity_to_token(SIPE_ACTIVITY_ON_PHONE))) {
85 		return(SIPE_OCS2005_ACTIVITY_ON_PHONE); */
86 	} else if (sipe_strequal(status, sipe_status_activity_to_token(SIPE_ACTIVITY_BUSY)) ||
87 		   sipe_strequal(status, sipe_status_activity_to_token(SIPE_ACTIVITY_DND))) {
88 		return(SIPE_OCS2005_ACTIVITY_BUSY);
89 	} else if (sipe_strequal(status, sipe_status_activity_to_token(SIPE_ACTIVITY_INVISIBLE)) ||
90 		   sipe_strequal(status, sipe_status_activity_to_token(SIPE_ACTIVITY_OFFLINE))) {
91 		return(SIPE_OCS2005_ACTIVITY_AWAY);
92 	} else {
93 		return(SIPE_OCS2005_ACTIVITY_AVAILABLE);
94 	}
95 }
96 
sipe_ocs2005_availability_from_status(struct sipe_core_private * sipe_private)97 static guint sipe_ocs2005_availability_from_status(struct sipe_core_private *sipe_private)
98 {
99 	const gchar *status = sipe_private->status;
100 
101 	if (sipe_strequal(status, sipe_status_activity_to_token(SIPE_ACTIVITY_INVISIBLE)) ||
102 	    sipe_strequal(status, sipe_status_activity_to_token(SIPE_ACTIVITY_OFFLINE)))
103 		return(SIPE_OCS2005_AVAILABILITY_OFFLINE);
104 	else
105 		return(SIPE_OCS2005_AVAILABILITY_ONLINE);
106 }
107 
sipe_ocs2005_status_from_activity_availability(guint activity,guint availability)108 const gchar *sipe_ocs2005_status_from_activity_availability(guint activity,
109 							    guint availability)
110 {
111 	guint type;
112 
113 	if (availability < SIPE_OCS2005_AVAILABILITY_MAYBE) {
114 		type = SIPE_ACTIVITY_OFFLINE;
115 	} else if (activity < SIPE_OCS2005_ACTIVITY_LUNCH) {
116 		type = SIPE_ACTIVITY_AWAY;
117 	} else if (activity < SIPE_OCS2005_ACTIVITY_IDLE) {
118 		//type = SIPE_ACTIVITY_LUNCH;
119 		type = SIPE_ACTIVITY_AWAY;
120 	} else if (activity < SIPE_OCS2005_ACTIVITY_BRB) {
121 		//type = SIPE_ACTIVITY_IDLE;
122 		type = SIPE_ACTIVITY_AWAY;
123 	} else if (activity < SIPE_OCS2005_ACTIVITY_AVAILABLE) {
124 		type = SIPE_ACTIVITY_BRB;
125 	} else if (activity < SIPE_OCS2005_ACTIVITY_ON_PHONE) {
126 		type = SIPE_ACTIVITY_AVAILABLE;
127 	} else if (activity < SIPE_OCS2005_ACTIVITY_BUSY) {
128 		//type = SIPE_ACTIVITY_ON_PHONE;
129 		type = SIPE_ACTIVITY_BUSY;
130 	} else if (activity < SIPE_OCS2005_ACTIVITY_AWAY2) {
131 		type = SIPE_ACTIVITY_BUSY;
132 	} else if (activity < SIPE_OCS2005_ACTIVITY_AVAILABLE2) {
133 		type = SIPE_ACTIVITY_AWAY;
134 	} else {
135 		type = SIPE_ACTIVITY_AVAILABLE;
136 	}
137 
138 	return(sipe_status_activity_to_token(type));
139 }
140 
sipe_ocs2005_activity_description(guint activity)141 const gchar *sipe_ocs2005_activity_description(guint activity)
142 {
143 	if ((activity >= SIPE_OCS2005_ACTIVITY_LUNCH) &&
144 	    (activity <  SIPE_OCS2005_ACTIVITY_IDLE)) {
145 		return(sipe_core_activity_description(SIPE_ACTIVITY_LUNCH));
146 	} else if ((activity >= SIPE_OCS2005_ACTIVITY_IDLE) &&
147 		   (activity <  SIPE_OCS2005_ACTIVITY_BRB)) {
148 		return(sipe_core_activity_description(SIPE_ACTIVITY_INACTIVE));
149 	} else if ((activity >= SIPE_OCS2005_ACTIVITY_ON_PHONE) &&
150 		   (activity <  SIPE_OCS2005_ACTIVITY_BUSY)) {
151 		return(sipe_core_activity_description(SIPE_ACTIVITY_ON_PHONE));
152 	} else {
153 		return(NULL);
154 	}
155 }
156 
sipe_ocs2005_user_info_has_updated(struct sipe_core_private * sipe_private,const sipe_xml * xn_userinfo)157 void sipe_ocs2005_user_info_has_updated(struct sipe_core_private *sipe_private,
158 					const sipe_xml *xn_userinfo)
159 {
160 	const sipe_xml *xn_states;
161 
162 	g_free(sipe_private->ocs2005_user_states);
163 	sipe_private->ocs2005_user_states = NULL;
164 	if ((xn_states = sipe_xml_child(xn_userinfo, "states")) != NULL) {
165 		gchar *orig = sipe_private->ocs2005_user_states = sipe_xml_stringify(xn_states);
166 
167 		/* this is a hack-around to remove added newline after inner element,
168 		 * state in this case, where it shouldn't be.
169 		 * After several use of sipe_xml_stringify, amount of added newlines
170 		 * grows significantly.
171 		 */
172 		if (orig) {
173 			gchar c, *stripped = orig;
174 			while ((c = *orig++)) {
175 				if ((c != '\n') /* && (c != '\r') */) {
176 					*stripped++ = c;
177 				}
178 			}
179 			*stripped = '\0';
180 		}
181 	}
182 
183 	/* Publish initial state if not yet.
184 	 * Assuming this happens on initial responce to self subscription
185 	 * so we've already updated our UserInfo.
186 	 */
187 	if (!SIPE_CORE_PRIVATE_FLAG_IS(INITIAL_PUBLISH)) {
188 		sipe_ocs2005_presence_publish(sipe_private, FALSE);
189 		/* dalayed run */
190 		sipe_cal_delayed_calendar_update(sipe_private);
191 	}
192 }
193 
sipe_is_user_available(struct sipe_core_private * sipe_private)194 static gboolean sipe_is_user_available(struct sipe_core_private *sipe_private)
195 {
196 	return(sipe_strequal(sipe_private->status,
197 			     sipe_status_activity_to_token(SIPE_ACTIVITY_AVAILABLE)));
198 }
199 
200 
201 /**
202  * OCS2005 presence XML messages
203  *
204  * Calendar publication entry
205  *
206  * @param legacy_dn		(%s) Ex.: /o=EXCHANGE/ou=BTUK02/cn=Recipients/cn=AHHBTT
207  * @param fb_start_time_str	(%s) Ex.: 2009-12-06T17:15:00Z
208  * @param free_busy_base64	(%s) Ex.: AAAAAAAAAAAAAAAAA......
209  */
210 #define SIPE_SOAP_SET_PRESENCE_CALENDAR \
211 "<calendarInfo xmlns=\"http://schemas.microsoft.com/2002/09/sip/presence\" mailboxId=\"%s\" startTime=\"%s\" granularity=\"PT15M\">%s</calendarInfo>"
212 
213 /**
214  * Note publication entry
215  *
216  * @param note	(%s) Ex.: Working from home
217  */
218 #define SIPE_SOAP_SET_PRESENCE_NOTE_XML  "<note>%s</note>"
219 
220 /**
221  * Note's OOF publication entry
222  */
223 #define SIPE_SOAP_SET_PRESENCE_OOF_XML  "<oof></oof>"
224 
225 /**
226  * States publication entry for User State
227  *
228  * @param avail			(%d) Availability 2007-style. Ex.: 9500
229  * @param since_time_str	(%s) Ex.: 2010-01-13T10:30:05Z
230  * @param device_id		(%s) epid. Ex.: 4c77e6ec72
231  * @param activity_token	(%s) Ex.: do-not-disturb
232  */
233 #define SIPE_SOAP_SET_PRESENCE_STATES \
234           "<states>"\
235             "<state avail=\"%d\" since=\"%s\" validWith=\"any-device\" deviceId=\"%s\" set=\"manual\" xsi:type=\"userState\">%s</state>"\
236           "</states>"
237 
238 /**
239  * Presentity publication entry.
240  *
241  * @param uri			(%s) SIP URI without 'sip:' prefix. Ex.: fox@atlanta.local
242  * @param aggr_availability	(%d) Ex.: 300
243  * @param aggr_activity		(%d) Ex.: 600
244  * @param host_name		(%s) Uppercased. Ex.: ATLANTA
245  * @param note_xml_str		(%s) XML string as SIPE_SOAP_SET_PRESENCE_NOTE_XML
246  * @param oof_xml_str		(%s) XML string as SIPE_SOAP_SET_PRESENCE_OOF_XML
247  * @param states_xml_str	(%s) XML string as SIPE_SOAP_SET_PRESENCE_STATES
248  * @param calendar_info_xml_str	(%s) XML string as SIPE_SOAP_SET_PRESENCE_CALENDAR
249  * @param device_id		(%s) epid. Ex.: 4c77e6ec72
250  * @param since_time_str	(%s) Ex.: 2010-01-13T10:30:05Z
251  * @param since_time_str	(%s) Ex.: 2010-01-13T10:30:05Z
252  * @param user_input		(%s) active, idle
253  */
254 #define SIPE_SOAP_SET_PRESENCE \
255 	"<s:Envelope" \
256         " xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"" \
257 	" xmlns:m=\"http://schemas.microsoft.com/winrtc/2002/11/sip\"" \
258 	">" \
259 	"<s:Body>" \
260 	"<m:setPresence>" \
261 	"<m:presentity xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" m:uri=\"sip:%s\">"\
262 	"<m:availability m:aggregate=\"%d\"/>"\
263 	"<m:activity m:aggregate=\"%d\"/>"\
264 	"<deviceName xmlns=\"http://schemas.microsoft.com/2002/09/sip/presence\" name=\"%s\"/>"\
265 	"<rtc:devicedata xmlns:rtc=\"http://schemas.microsoft.com/winrtc/2002/11/sip\" namespace=\"rtcService\">"\
266 	"<![CDATA[<caps><renders_gif/><renders_isf/></caps>]]></rtc:devicedata>"\
267 	"<userInfo xmlns=\"http://schemas.microsoft.com/2002/09/sip/presence\">"\
268 	"%s%s" \
269 	"%s" \
270         "</userInfo>"\
271 	"%s" \
272 	"<device xmlns=\"http://schemas.microsoft.com/2002/09/sip/presence\" deviceId=\"%s\" since=\"%s\" >"\
273 		"<userInput since=\"%s\" >%s</userInput>"\
274 	"</device>"\
275 	"</m:presentity>" \
276 	"</m:setPresence>"\
277 	"</s:Body>" \
278 	"</s:Envelope>"
279 
send_presence_soap(struct sipe_core_private * sipe_private,gboolean do_publish_calendar,gboolean do_reset_status)280 static void send_presence_soap(struct sipe_core_private *sipe_private,
281 			       gboolean do_publish_calendar,
282 			       gboolean do_reset_status)
283 {
284 	struct sipe_calendar* cal = sipe_private->calendar;
285 	gchar *body;
286 	gchar *tmp;
287 	gchar *tmp2 = NULL;
288 	gchar *res_note = NULL;
289 	gchar *res_oof = NULL;
290 	const gchar *note_pub = NULL;
291 	gchar *states = NULL;
292 	gchar *calendar_data = NULL;
293 	const gchar *epid = sip_transport_epid(sipe_private);
294 	gchar *from = sip_uri_self(sipe_private);
295 	time_t now = time(NULL);
296 	gchar *since_time_str = sipe_utils_time_to_str(now);
297 	const gchar *oof_note = cal ? sipe_ews_get_oof_note(cal) : NULL;
298 	const char *user_input;
299 	gboolean pub_oof = cal && oof_note && (!sipe_private->note || cal->updated > sipe_private->note_since);
300 
301 	if (oof_note && sipe_private->note) {
302 		SIPE_DEBUG_INFO("cal->oof_start           : %s", sipe_utils_time_to_debug_str(localtime(&(cal->oof_start))));
303 		SIPE_DEBUG_INFO("sipe_private->note_since : %s", sipe_utils_time_to_debug_str(localtime(&(sipe_private->note_since))));
304 	}
305 
306 	SIPE_DEBUG_INFO("sipe_private->note  : %s", sipe_private->note ? sipe_private->note : "");
307 
308 	if (!SIPE_CORE_PRIVATE_FLAG_IS(INITIAL_PUBLISH) ||
309 	    do_reset_status)
310 		sipe_status_set_activity(sipe_private, SIPE_ACTIVITY_AVAILABLE);
311 
312 	/* Note */
313 	if (pub_oof) {
314 		note_pub = oof_note;
315 		res_oof = SIPE_SOAP_SET_PRESENCE_OOF_XML;
316 		cal->published = TRUE;
317 	} else if (sipe_private->note) {
318 		if (SIPE_CORE_PRIVATE_FLAG_IS(OOF_NOTE) &&
319 		    !oof_note) { /* stale OOF note, as it's not present in cal already */
320 			g_free(sipe_private->note);
321 			sipe_private->note = NULL;
322 			SIPE_CORE_PRIVATE_FLAG_UNSET(OOF_NOTE);
323 			sipe_private->note_since = 0;
324 		} else {
325 			note_pub = sipe_private->note;
326 			res_oof = SIPE_CORE_PRIVATE_FLAG_IS(OOF_NOTE) ? SIPE_SOAP_SET_PRESENCE_OOF_XML : "";
327 		}
328 	}
329 
330 	if (note_pub)
331 	{
332 		/* to protocol internal plain text format */
333 		tmp = sipe_backend_markup_strip_html(note_pub);
334 		res_note = g_markup_printf_escaped(SIPE_SOAP_SET_PRESENCE_NOTE_XML, tmp);
335 		g_free(tmp);
336 	}
337 
338 	/* User State */
339 	if (!do_reset_status) {
340 		if (sipe_private->status_set_by_user &&
341 		    !do_publish_calendar &&
342 		    SIPE_CORE_PRIVATE_FLAG_IS(INITIAL_PUBLISH)) {
343 			const gchar *activity_token;
344 			int avail_2007 = sipe_ocs2007_availability_from_status(sipe_private->status,
345 									       &activity_token);
346 
347 			states = g_strdup_printf(SIPE_SOAP_SET_PRESENCE_STATES,
348 						avail_2007,
349 						since_time_str,
350 						epid,
351 						activity_token);
352 		}
353 		else /* preserve existing publication */
354 		{
355 			if (sipe_private->ocs2005_user_states) {
356 				states = g_strdup(sipe_private->ocs2005_user_states);
357 			}
358 		}
359 	} else {
360 		/* do nothing - then User state will be erased */
361 	}
362 	SIPE_CORE_PRIVATE_FLAG_SET(INITIAL_PUBLISH);
363 
364 	/* CalendarInfo */
365 	if (cal && (!is_empty(cal->legacy_dn) || !is_empty(cal->email)) && cal->fb_start && !is_empty(cal->free_busy))
366 	{
367 		char *fb_start_str = sipe_utils_time_to_str(cal->fb_start);
368 		char *free_busy_base64 = sipe_cal_get_freebusy_base64(cal->free_busy);
369 		calendar_data = g_strdup_printf(SIPE_SOAP_SET_PRESENCE_CALENDAR,
370 						!is_empty(cal->legacy_dn) ? cal->legacy_dn : cal->email,
371 						fb_start_str,
372 						free_busy_base64);
373 		g_free(fb_start_str);
374 		g_free(free_busy_base64);
375 	}
376 
377 	user_input = (sipe_private->status_set_by_user ||
378 		      sipe_is_user_available(sipe_private)) ?
379 		"active" : "idle";
380 
381 	/* generate XML */
382 	body = g_strdup_printf(SIPE_SOAP_SET_PRESENCE,
383 			       sipe_private->username,
384 			       sipe_ocs2005_availability_from_status(sipe_private),
385 			       sipe_ocs2005_activity_from_status(sipe_private),
386 			       (tmp = g_ascii_strup(g_get_host_name(), -1)),
387 			       res_note ? res_note : "",
388 			       res_oof ? res_oof : "",
389 			       states ? states : "",
390 			       calendar_data ? calendar_data : "",
391 			       epid,
392 			       since_time_str,
393 			       since_time_str,
394 			       user_input);
395 	g_free(tmp);
396 	g_free(tmp2);
397 	g_free(res_note);
398 	g_free(states);
399 	g_free(calendar_data);
400 	g_free(since_time_str);
401 
402 	sip_soap_raw_request_cb(sipe_private, from, body, NULL, NULL);
403 
404 	g_free(body);
405 }
406 
sipe_ocs2005_presence_publish(struct sipe_core_private * sipe_private,gboolean do_publish_calendar)407 void sipe_ocs2005_presence_publish(struct sipe_core_private *sipe_private,
408 				   gboolean do_publish_calendar)
409 {
410 	send_presence_soap(sipe_private, do_publish_calendar, FALSE);
411 }
412 
sipe_ocs2005_reset_status(struct sipe_core_private * sipe_private)413 void sipe_ocs2005_reset_status(struct sipe_core_private *sipe_private)
414 {
415 	send_presence_soap(sipe_private, FALSE, TRUE);
416 }
417 
sipe_ocs2005_apply_calendar_status(struct sipe_core_private * sipe_private,struct sipe_buddy * sbuddy,const char * status_id)418 void sipe_ocs2005_apply_calendar_status(struct sipe_core_private *sipe_private,
419 					struct sipe_buddy *sbuddy,
420 					const char *status_id)
421 {
422 	time_t cal_avail_since;
423 	int cal_status = sipe_cal_get_status(sbuddy, time(NULL), &cal_avail_since);
424 	int avail;
425 	gchar *self_uri;
426 
427 	if (!sbuddy) return;
428 
429 	if (cal_status < SIPE_CAL_NO_DATA) {
430 		SIPE_DEBUG_INFO("sipe_apply_calendar_status: cal_status      : %d for %s", cal_status, sbuddy->name);
431 		SIPE_DEBUG_INFO("sipe_apply_calendar_status: cal_avail_since : %s", sipe_utils_time_to_debug_str(localtime(&cal_avail_since)));
432 	}
433 
434 	/* scheduled Cal update call */
435 	if (!status_id) {
436 		status_id = sbuddy->last_non_cal_status_id;
437 		g_free(sbuddy->activity);
438 		sbuddy->activity = g_strdup(sbuddy->last_non_cal_activity);
439 	}
440 
441 	if (!status_id) {
442 		SIPE_DEBUG_INFO("sipe_apply_calendar_status: status_id is NULL for %s, exiting.",
443 				sbuddy->name ? sbuddy->name : "" );
444 		return;
445 	}
446 
447 	/* adjust to calendar status */
448 	if (cal_status != SIPE_CAL_NO_DATA) {
449 		SIPE_DEBUG_INFO("sipe_apply_calendar_status: user_avail_since: %s", sipe_utils_time_to_debug_str(localtime(&sbuddy->user_avail_since)));
450 
451 		if ((cal_status == SIPE_CAL_BUSY) &&
452 		    (cal_avail_since > sbuddy->user_avail_since) &&
453 		    sipe_ocs2007_status_is_busy(status_id)) {
454 			status_id = sipe_status_activity_to_token(SIPE_ACTIVITY_BUSY);
455 			g_free(sbuddy->activity);
456 			sbuddy->activity = g_strdup(sipe_core_activity_description(SIPE_ACTIVITY_IN_MEETING));
457 		}
458 		avail = sipe_ocs2007_availability_from_status(status_id, NULL);
459 
460 		SIPE_DEBUG_INFO("sipe_apply_calendar_status: activity_since  : %s", sipe_utils_time_to_debug_str(localtime(&sbuddy->activity_since)));
461 		if (cal_avail_since > sbuddy->activity_since) {
462 			if ((cal_status == SIPE_CAL_OOF) &&
463 			    sipe_ocs2007_availability_is_away(avail)) {
464 				g_free(sbuddy->activity);
465 				sbuddy->activity = g_strdup(sipe_core_activity_description(SIPE_ACTIVITY_OOF));
466 			}
467 		}
468 	}
469 
470 	/* then set status_id actually */
471 	SIPE_DEBUG_INFO("sipe_apply_calendar_status: to %s for %s", status_id, sbuddy->name ? sbuddy->name : "" );
472 	sipe_backend_buddy_set_status(SIPE_CORE_PUBLIC, sbuddy->name,
473 				      sipe_status_token_to_activity(status_id));
474 
475 	/* set our account state to the one in roaming (including calendar info) */
476 	self_uri = sip_uri_self(sipe_private);
477 	if (SIPE_CORE_PRIVATE_FLAG_IS(INITIAL_PUBLISH) &&
478 	    sipe_strcase_equal(sbuddy->name, self_uri)) {
479 		if (sipe_strequal(status_id, sipe_status_activity_to_token(SIPE_ACTIVITY_OFFLINE))) {
480 			/* do not let offline status switch us off */
481 			status_id = sipe_status_activity_to_token(SIPE_ACTIVITY_INVISIBLE);
482 		}
483 
484 		sipe_status_and_note(sipe_private, status_id);
485 	}
486 	g_free(self_uri);
487 }
488 
update_calendar_status_cb(SIPE_UNUSED_PARAMETER char * name,struct sipe_buddy * sbuddy,struct sipe_core_private * sipe_private)489 static void update_calendar_status_cb(SIPE_UNUSED_PARAMETER char *name,
490 				      struct sipe_buddy *sbuddy,
491 				      struct sipe_core_private *sipe_private)
492 {
493 	sipe_ocs2005_apply_calendar_status(sipe_private, sbuddy, NULL);
494 }
495 
496 /**
497  * Updates contact's status
498  * based on their calendar information.
499  */
update_calendar_status(struct sipe_core_private * sipe_private,SIPE_UNUSED_PARAMETER void * unused)500 static void update_calendar_status(struct sipe_core_private *sipe_private,
501 				   SIPE_UNUSED_PARAMETER void *unused)
502 {
503 	SIPE_DEBUG_INFO_NOFORMAT("update_calendar_status() started.");
504 	sipe_buddy_foreach(sipe_private,
505 			   (GHFunc) update_calendar_status_cb,
506 			   sipe_private);
507 
508 	/* repeat scheduling */
509 	sipe_ocs2005_schedule_status_update(sipe_private,
510 					    time(NULL) + 3 * 60 /* 3 min */);
511 }
512 
513 /**
514  * Schedules process of contacts' status update
515  * based on their calendar information.
516  * Should be scheduled to the beginning of every
517  * 15 min interval, like:
518  * 13:00, 13:15, 13:30, 13:45, etc.
519  */
sipe_ocs2005_schedule_status_update(struct sipe_core_private * sipe_private,time_t calculate_from)520 void sipe_ocs2005_schedule_status_update(struct sipe_core_private *sipe_private,
521 					 time_t calculate_from)
522 {
523 #define SCHEDULE_INTERVAL 15 * 60 /* 15 min */
524 
525 	/* start of the beginning of closest 15 min interval. */
526 	time_t next_start = (calculate_from / SCHEDULE_INTERVAL + 1) * SCHEDULE_INTERVAL;
527 
528 	SIPE_DEBUG_INFO("sipe_ocs2005_schedule_status_update: calculate_from time: %s",
529 			sipe_utils_time_to_debug_str(localtime(&calculate_from)));
530 	SIPE_DEBUG_INFO("sipe_ocs2005_schedule_status_update: next start time    : %s",
531 			sipe_utils_time_to_debug_str(localtime(&next_start)));
532 
533 	sipe_schedule_seconds(sipe_private,
534 			      "<+2005-cal-status>",
535 			      NULL,
536 			      next_start - time(NULL),
537 			      update_calendar_status,
538 			      NULL);
539 }
540 
541 /*
542   Local Variables:
543   mode: c
544   c-file-style: "bsd"
545   indent-tabs-mode: t
546   tab-width: 8
547   End:
548 */
549