core cleanup: separate code for sipe_backend_account_status_and_note()
[siplcs.git] / src / core / sipe-ocs2005.c
blob38f6e7d559be3ffc6fab8bf0d4084ca0528cb33b
1 /**
2 * @file sipe-ocs2005.c
4 * pidgin-sipe
6 * Copyright (C) 2011 SIPE Project <http://sipe.sourceforge.net/>
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.
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.
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
24 * OCS2005 specific code
28 #include <time.h>
30 #include <glib.h>
32 #include "sipe-common.h"
33 #include "http-conn.h" /* sipe-cal.h requires this */
34 #include "sip-soap.h"
35 #include "sipe-backend.h"
36 #include "sipe-cal.h"
37 #include "sipe-core.h"
38 #include "sipe-core-private.h"
39 #include "sipe-ews.h"
40 #include "sipe-ocs2005.h"
41 #include "sipe-schedule.h"
42 #include "sipe-utils.h"
43 #include "sipe-xml.h"
44 #include "sipe.h"
46 void sipe_ocs2005_user_info_has_updated(struct sipe_core_private *sipe_private,
47 const sipe_xml *xn_userinfo)
49 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
50 const sipe_xml *xn_states;
52 g_free(sip->user_states);
53 sip->user_states = NULL;
54 if ((xn_states = sipe_xml_child(xn_userinfo, "states")) != NULL) {
55 gchar *orig = sip->user_states = sipe_xml_stringify(xn_states);
57 /* this is a hack-around to remove added newline after inner element,
58 * state in this case, where it shouldn't be.
59 * After several use of sipe_xml_stringify, amount of added newlines
60 * grows significantly.
62 if (orig) {
63 gchar c, *stripped = orig;
64 while ((c = *orig++)) {
65 if ((c != '\n') /* && (c != '\r') */) {
66 *stripped++ = c;
69 *stripped = '\0';
73 /* Publish initial state if not yet.
74 * Assuming this happens on initial responce to self subscription
75 * so we've already updated our UserInfo.
77 if (!sip->initial_state_published) {
78 sipe_ocs2005_presence_publish(sipe_private, FALSE);
79 /* dalayed run */
80 sipe_cal_delayed_calendar_update(sipe_private);
84 /**
85 * OCS2005 presence XML messages
87 * Calendar publication entry
89 * @param legacy_dn (%s) Ex.: /o=EXCHANGE/ou=BTUK02/cn=Recipients/cn=AHHBTT
90 * @param fb_start_time_str (%s) Ex.: 2009-12-06T17:15:00Z
91 * @param free_busy_base64 (%s) Ex.: AAAAAAAAAAAAAAAAA......
93 #define SIPE_SOAP_SET_PRESENCE_CALENDAR \
94 "<calendarInfo xmlns=\"http://schemas.microsoft.com/2002/09/sip/presence\" mailboxId=\"%s\" startTime=\"%s\" granularity=\"PT15M\">%s</calendarInfo>"
96 /**
97 * Note publication entry
99 * @param note (%s) Ex.: Working from home
101 #define SIPE_SOAP_SET_PRESENCE_NOTE_XML "<note>%s</note>"
104 * Note's OOF publication entry
106 #define SIPE_SOAP_SET_PRESENCE_OOF_XML "<oof></oof>"
109 * States publication entry for User State
111 * @param avail (%d) Availability 2007-style. Ex.: 9500
112 * @param since_time_str (%s) Ex.: 2010-01-13T10:30:05Z
113 * @param device_id (%s) epid. Ex.: 4c77e6ec72
114 * @param activity_token (%s) Ex.: do-not-disturb
116 #define SIPE_SOAP_SET_PRESENCE_STATES \
117 "<states>"\
118 "<state avail=\"%d\" since=\"%s\" validWith=\"any-device\" deviceId=\"%s\" set=\"manual\" xsi:type=\"userState\">%s</state>"\
119 "</states>"
122 * Presentity publication entry.
124 * @param uri (%s) SIP URI without 'sip:' prefix. Ex.: fox@atlanta.local
125 * @param aggr_availability (%d) Ex.: 300
126 * @param aggr_activity (%d) Ex.: 600
127 * @param host_name (%s) Uppercased. Ex.: ATLANTA
128 * @param note_xml_str (%s) XML string as SIPE_SOAP_SET_PRESENCE_NOTE_XML
129 * @param oof_xml_str (%s) XML string as SIPE_SOAP_SET_PRESENCE_OOF_XML
130 * @param states_xml_str (%s) XML string as SIPE_SOAP_SET_PRESENCE_STATES
131 * @param calendar_info_xml_str (%s) XML string as SIPE_SOAP_SET_PRESENCE_CALENDAR
132 * @param device_id (%s) epid. Ex.: 4c77e6ec72
133 * @param since_time_str (%s) Ex.: 2010-01-13T10:30:05Z
134 * @param since_time_str (%s) Ex.: 2010-01-13T10:30:05Z
135 * @param user_input (%s) active, idle
137 #define SIPE_SOAP_SET_PRESENCE \
138 "<s:Envelope" \
139 " xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"" \
140 " xmlns:m=\"http://schemas.microsoft.com/winrtc/2002/11/sip\"" \
141 ">" \
142 "<s:Body>" \
143 "<m:setPresence>" \
144 "<m:presentity xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" m:uri=\"sip:%s\">"\
145 "<m:availability m:aggregate=\"%d\"/>"\
146 "<m:activity m:aggregate=\"%d\"/>"\
147 "<deviceName xmlns=\"http://schemas.microsoft.com/2002/09/sip/presence\" name=\"%s\"/>"\
148 "<rtc:devicedata xmlns:rtc=\"http://schemas.microsoft.com/winrtc/2002/11/sip\" namespace=\"rtcService\">"\
149 "<![CDATA[<caps><renders_gif/><renders_isf/></caps>]]></rtc:devicedata>"\
150 "<userInfo xmlns=\"http://schemas.microsoft.com/2002/09/sip/presence\">"\
151 "%s%s" \
152 "%s" \
153 "</userInfo>"\
154 "%s" \
155 "<device xmlns=\"http://schemas.microsoft.com/2002/09/sip/presence\" deviceId=\"%s\" since=\"%s\" >"\
156 "<userInput since=\"%s\" >%s</userInput>"\
157 "</device>"\
158 "</m:presentity>" \
159 "</m:setPresence>"\
160 "</s:Body>" \
161 "</s:Envelope>"
163 static void send_presence_soap(struct sipe_core_private *sipe_private,
164 gboolean do_publish_calendar,
165 gboolean do_reset_status)
167 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
168 struct sipe_calendar* cal = sip->cal;
169 int availability = 0;
170 int activity = 0;
171 gchar *body;
172 gchar *tmp;
173 gchar *tmp2 = NULL;
174 gchar *res_note = NULL;
175 gchar *res_oof = NULL;
176 const gchar *note_pub = NULL;
177 gchar *states = NULL;
178 gchar *calendar_data = NULL;
179 gchar *epid = get_epid(sipe_private);
180 gchar *from = sip_uri_self(sipe_private);
181 time_t now = time(NULL);
182 gchar *since_time_str = sipe_utils_time_to_str(now);
183 const gchar *oof_note = cal ? sipe_ews_get_oof_note(cal) : NULL;
184 const char *user_input;
185 gboolean pub_oof = cal && oof_note && (!sip->note || cal->updated > sip->note_since);
187 if (oof_note && sip->note) {
188 SIPE_DEBUG_INFO("cal->oof_start : %s", asctime(localtime(&(cal->oof_start))));
189 SIPE_DEBUG_INFO("sip->note_since : %s", asctime(localtime(&(sip->note_since))));
192 SIPE_DEBUG_INFO("sip->note : %s", sip->note ? sip->note : "");
194 if (!sip->initial_state_published ||
195 do_reset_status)
196 sipe_set_initial_status(sipe_private);
198 sipe_get_act_avail_by_status_2005(sip->status, &activity, &availability);
200 /* Note */
201 if (pub_oof) {
202 note_pub = oof_note;
203 res_oof = SIPE_SOAP_SET_PRESENCE_OOF_XML;
204 cal->published = TRUE;
205 } else if (sip->note) {
206 if (sip->is_oof_note && !oof_note) { /* stale OOF note, as it's not present in cal already */
207 g_free(sip->note);
208 sip->note = NULL;
209 sip->is_oof_note = FALSE;
210 sip->note_since = 0;
211 } else {
212 note_pub = sip->note;
213 res_oof = sip->is_oof_note ? SIPE_SOAP_SET_PRESENCE_OOF_XML : "";
217 if (note_pub)
219 /* to protocol internal plain text format */
220 tmp = sipe_backend_markup_strip_html(note_pub);
221 res_note = g_markup_printf_escaped(SIPE_SOAP_SET_PRESENCE_NOTE_XML, tmp);
222 g_free(tmp);
225 /* User State */
226 if (!do_reset_status) {
227 if (sipe_is_user_state(sipe_private) && !do_publish_calendar && sip->initial_state_published)
229 gchar *activity_token = NULL;
230 int avail_2007 = sipe_get_availability_by_status(sip->status, &activity_token);
232 states = g_strdup_printf(SIPE_SOAP_SET_PRESENCE_STATES,
233 avail_2007,
234 since_time_str,
235 epid,
236 activity_token);
237 g_free(activity_token);
239 else /* preserve existing publication */
241 if (sip->user_states) {
242 states = g_strdup(sip->user_states);
245 } else {
246 /* do nothing - then User state will be erased */
248 sip->initial_state_published = TRUE;
250 /* CalendarInfo */
251 if (cal && (!is_empty(cal->legacy_dn) || !is_empty(cal->email)) && cal->fb_start && !is_empty(cal->free_busy))
253 char *fb_start_str = sipe_utils_time_to_str(cal->fb_start);
254 char *free_busy_base64 = sipe_cal_get_freebusy_base64(cal->free_busy);
255 calendar_data = g_strdup_printf(SIPE_SOAP_SET_PRESENCE_CALENDAR,
256 !is_empty(cal->legacy_dn) ? cal->legacy_dn : cal->email,
257 fb_start_str,
258 free_busy_base64);
259 g_free(fb_start_str);
260 g_free(free_busy_base64);
263 user_input = (sipe_is_user_state(sipe_private) ||
264 sipe_is_user_available(sipe_private)) ?
265 "active" : "idle";
267 /* forming resulting XML */
268 body = g_strdup_printf(SIPE_SOAP_SET_PRESENCE,
269 sipe_private->username,
270 availability,
271 activity,
272 (tmp = g_ascii_strup(g_get_host_name(), -1)),
273 res_note ? res_note : "",
274 res_oof ? res_oof : "",
275 states ? states : "",
276 calendar_data ? calendar_data : "",
277 epid,
278 since_time_str,
279 since_time_str,
280 user_input);
281 g_free(tmp);
282 g_free(tmp2);
283 g_free(res_note);
284 g_free(states);
285 g_free(calendar_data);
286 g_free(since_time_str);
287 g_free(epid);
289 sip_soap_raw_request_cb(sipe_private, from, body, NULL, NULL);
291 g_free(body);
294 void sipe_ocs2005_presence_publish(struct sipe_core_private *sipe_private,
295 gboolean do_publish_calendar)
297 return send_presence_soap(sipe_private, do_publish_calendar, FALSE);
300 void sipe_ocs2005_reset_status(struct sipe_core_private *sipe_private)
302 return send_presence_soap(sipe_private, FALSE, TRUE);
305 static void update_calendar_status_cb(SIPE_UNUSED_PARAMETER char *name,
306 struct sipe_buddy *sbuddy,
307 struct sipe_core_private *sipe_private)
309 sipe_apply_calendar_status(sipe_private, sbuddy, NULL);
313 * Updates contact's status
314 * based on their calendar information.
316 static void update_calendar_status(struct sipe_core_private *sipe_private,
317 SIPE_UNUSED_PARAMETER void *unused)
319 SIPE_DEBUG_INFO_NOFORMAT("update_calendar_status() started.");
320 g_hash_table_foreach(sipe_private->buddies,
321 (GHFunc)update_calendar_status_cb,
322 sipe_private);
324 /* repeat scheduling */
325 sipe_ocs2005_schedule_status_update(sipe_private,
326 time(NULL) + 3 * 60 /* 3 min */);
330 * Schedules process of contacts' status update
331 * based on their calendar information.
332 * Should be scheduled to the beginning of every
333 * 15 min interval, like:
334 * 13:00, 13:15, 13:30, 13:45, etc.
336 void sipe_ocs2005_schedule_status_update(struct sipe_core_private *sipe_private,
337 time_t calculate_from)
339 #define SCHEDULE_INTERVAL 15 * 60 /* 15 min */
341 /* start of the beginning of closest 15 min interval. */
342 time_t next_start = (calculate_from / SCHEDULE_INTERVAL + 1) * SCHEDULE_INTERVAL;
344 SIPE_DEBUG_INFO("sipe_ocs2005_schedule_status_update: calculate_from time: %s",
345 asctime(localtime(&calculate_from)));
346 SIPE_DEBUG_INFO("sipe_ocs2005_schedule_status_update: next start time : %s",
347 asctime(localtime(&next_start)));
349 sipe_schedule_seconds(sipe_private,
350 "<+2005-cal-status>",
351 NULL,
352 next_start - time(NULL),
353 update_calendar_status,
354 NULL);
358 Local Variables:
359 mode: c
360 c-file-style: "bsd"
361 indent-tabs-mode: t
362 tab-width: 8
363 End: