ms-dlx: request web ticket for service
[siplcs.git] / src / core / sipe-buddy.c
blob03f5d354d0457b54afe67bb4e35a0dd756bb2580
1 /**
2 * @file sipe-buddy.c
4 * pidgin-sipe
6 * Copyright (C) 2010-11 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
27 #include <string.h>
28 #include <time.h>
30 #include <glib.h>
32 #include "sipe-common.h"
33 #include "sipmsg.h"
34 #include "sip-csta.h"
35 #include "sip-soap.h"
36 #include "sip-transport.h"
37 #include "sipe-backend.h"
38 #include "sipe-buddy.h"
39 #include "sipe-cal.h"
40 #include "sipe-chat.h"
41 #include "sipe-conf.h"
42 #include "sipe-core.h"
43 #include "sipe-core-private.h"
44 #include "sipe-group.h"
45 #include "sipe-im.h"
46 #include "sipe-nls.h"
47 #include "sipe-ocs2005.h"
48 #include "sipe-ocs2007.h"
49 #include "sipe-schedule.h"
50 #include "sipe-session.h"
51 #include "sipe-subscriptions.h"
52 #include "sipe-utils.h"
53 #include "sipe-webticket.h"
54 #include "sipe-xml.h"
56 static void buddy_free(struct sipe_buddy *buddy)
58 #ifndef _WIN32
60 * We are calling g_hash_table_foreach_steal(). That means that no
61 * key/value deallocation functions are called. Therefore the glib
62 * hash code does not touch the key (buddy->name) or value (buddy)
63 * of the to-be-deleted hash node at all. It follows that we
65 * - MUST free the memory for the key ourselves and
66 * - ARE allowed to do it in this function
68 * Conclusion: glib must be broken on the Windows platform if sipe
69 * crashes with SIGTRAP when closing. You'll have to live
70 * with the memory leak until this is fixed.
72 g_free(buddy->name);
73 #endif
74 g_free(buddy->activity);
75 g_free(buddy->meeting_subject);
76 g_free(buddy->meeting_location);
77 g_free(buddy->note);
79 g_free(buddy->cal_start_time);
80 g_free(buddy->cal_free_busy_base64);
81 g_free(buddy->cal_free_busy);
82 g_free(buddy->last_non_cal_activity);
84 sipe_cal_free_working_hours(buddy->cal_working_hours);
86 g_free(buddy->device_name);
87 g_slist_free(buddy->groups);
88 g_free(buddy);
91 static gboolean buddy_free_cb(SIPE_UNUSED_PARAMETER gpointer key,
92 gpointer buddy,
93 SIPE_UNUSED_PARAMETER gpointer user_data)
95 buddy_free(buddy);
96 /* We must return TRUE as the key/value have already been deleted */
97 return(TRUE);
100 void sipe_buddy_free_all(struct sipe_core_private *sipe_private)
102 g_hash_table_foreach_steal(sipe_private->buddies,
103 buddy_free_cb,
104 NULL);
107 gchar *sipe_core_buddy_status(struct sipe_core_public *sipe_public,
108 const gchar *uri,
109 guint activity,
110 const gchar *status_text)
112 struct sipe_buddy *sbuddy;
113 const char *activity_str;
115 if (!sipe_public) return NULL; /* happens on pidgin exit */
117 sbuddy = g_hash_table_lookup(SIPE_CORE_PRIVATE->buddies, uri);
118 if (!sbuddy) return NULL;
120 activity_str = sbuddy->activity ? sbuddy->activity :
121 (activity == SIPE_ACTIVITY_BUSY) || (activity == SIPE_ACTIVITY_BRB) ?
122 status_text : NULL;
124 if (activity_str && sbuddy->note) {
125 return g_strdup_printf("%s - <i>%s</i>", activity_str, sbuddy->note);
126 } else if (activity_str) {
127 return g_strdup(activity_str);
128 } else if (sbuddy->note) {
129 return g_strdup_printf("<i>%s</i>", sbuddy->note);
130 } else {
131 return NULL;
135 gchar *sipe_buddy_get_alias(struct sipe_core_private *sipe_private,
136 const gchar *with)
138 sipe_backend_buddy pbuddy;
139 gchar *alias = NULL;
140 if ((pbuddy = sipe_backend_buddy_find(SIPE_CORE_PUBLIC, with, NULL))) {
141 alias = sipe_backend_buddy_get_alias(SIPE_CORE_PUBLIC, pbuddy);
143 return alias;
146 void sipe_core_buddy_group(struct sipe_core_public *sipe_public,
147 const gchar *who,
148 const gchar *old_group_name,
149 const gchar *new_group_name)
151 struct sipe_buddy * buddy = g_hash_table_lookup(SIPE_CORE_PRIVATE->buddies, who);
152 struct sipe_group * old_group = NULL;
153 struct sipe_group * new_group;
155 SIPE_DEBUG_INFO("sipe_core_buddy_group: who:%s old_group_name:%s new_group_name:%s",
156 who ? who : "", old_group_name ? old_group_name : "", new_group_name ? new_group_name : "");
158 if(!buddy) { // buddy not in roaming list
159 return;
162 if (old_group_name) {
163 old_group = sipe_group_find_by_name(SIPE_CORE_PRIVATE, old_group_name);
165 new_group = sipe_group_find_by_name(SIPE_CORE_PRIVATE, new_group_name);
167 if (old_group) {
168 buddy->groups = g_slist_remove(buddy->groups, old_group);
169 SIPE_DEBUG_INFO("sipe_core_buddy_group: buddy %s removed from old group %s", who, old_group_name);
172 if (!new_group) {
173 sipe_group_create(SIPE_CORE_PRIVATE, new_group_name, who);
174 } else {
175 buddy->groups = slist_insert_unique_sorted(buddy->groups, new_group, (GCompareFunc)sipe_group_compare);
176 sipe_core_group_set_user(sipe_public, who);
180 void sipe_core_buddy_add(struct sipe_core_public *sipe_public,
181 const gchar *uri,
182 const gchar *group_name)
184 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
186 if (!g_hash_table_lookup(sipe_private->buddies, uri)) {
187 struct sipe_buddy *b = g_new0(struct sipe_buddy, 1);
189 SIPE_DEBUG_INFO("sipe_core_buddy_add: %s", uri);
191 b->name = g_strdup(uri);
192 b->just_added = TRUE;
193 g_hash_table_insert(sipe_private->buddies, b->name, b);
195 /* @TODO should go to callback */
196 sipe_subscribe_presence_single(sipe_private, b->name);
198 } else {
199 SIPE_DEBUG_INFO("sipe_core_buddy_add: buddy %s already in internal list",
200 uri);
203 sipe_core_buddy_group(sipe_public,
204 uri,
205 NULL,
206 group_name);
210 * Unassociates buddy from group first.
211 * Then see if no groups left, removes buddy completely.
212 * Otherwise updates buddy groups on server.
214 void sipe_core_buddy_remove(struct sipe_core_public *sipe_public,
215 const gchar *uri,
216 const gchar *group_name)
218 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
219 struct sipe_buddy *b = g_hash_table_lookup(sipe_private->buddies,
220 uri);
222 if (!b) return;
224 if (group_name) {
225 struct sipe_group *g = sipe_group_find_by_name(sipe_private,
226 group_name);
227 if (g) {
228 b->groups = g_slist_remove(b->groups, g);
229 SIPE_DEBUG_INFO("sipe_core_buddy_remove: buddy %s removed from group %s",
230 uri, g->name);
234 if (g_slist_length(b->groups) < 1) {
235 gchar *action_name = sipe_utils_presence_key(uri);
236 sipe_schedule_cancel(sipe_private, action_name);
237 g_free(action_name);
239 g_hash_table_remove(sipe_private->buddies, uri);
241 if (b->name) {
242 gchar *request = g_strdup_printf("<m:URI>%s</m:URI>",
243 b->name);
244 sip_soap_request(sipe_private,
245 "deleteContact",
246 request);
247 g_free(request);
250 buddy_free(b);
251 } else {
252 /* updates groups on server */
253 sipe_core_group_set_user(sipe_public, b->name);
258 void sipe_core_buddy_got_status(struct sipe_core_public *sipe_public,
259 const gchar *uri,
260 const gchar *status_id)
262 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
263 struct sipe_buddy *sbuddy = g_hash_table_lookup(sipe_private->buddies,
264 uri);
266 if (!sbuddy) return;
268 /* Check if on 2005 system contact's calendar,
269 * then set/preserve it.
271 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
272 sipe_backend_buddy_set_status(sipe_public, uri, status_id);
273 } else {
274 sipe_ocs2005_apply_calendar_status(sipe_private,
275 sbuddy,
276 status_id);
280 void sipe_core_buddy_tooltip_info(struct sipe_core_public *sipe_public,
281 const gchar *uri,
282 const gchar *status_name,
283 gboolean is_online,
284 struct sipe_backend_buddy_tooltip *tooltip)
286 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
287 gchar *note = NULL;
288 gboolean is_oof_note = FALSE;
289 const gchar *activity = NULL;
290 gchar *calendar = NULL;
291 const gchar *meeting_subject = NULL;
292 const gchar *meeting_location = NULL;
293 gchar *access_text = NULL;
295 #define SIPE_ADD_BUDDY_INFO(l, t) \
297 gchar *tmp = g_markup_escape_text((t), -1); \
298 sipe_backend_buddy_tooltip_add(sipe_public, tooltip, (l), tmp); \
299 g_free(tmp); \
301 #define SIPE_ADD_BUDDY_INFO_NOESCAPE(l, t) \
302 sipe_backend_buddy_tooltip_add(sipe_public, tooltip, (l), (t))
304 if (sipe_public) { /* happens on pidgin exit */
305 struct sipe_buddy *sbuddy = g_hash_table_lookup(sipe_private->buddies, uri);
306 if (sbuddy) {
307 note = sbuddy->note;
308 is_oof_note = sbuddy->is_oof_note;
309 activity = sbuddy->activity;
310 calendar = sipe_cal_get_description(sbuddy);
311 meeting_subject = sbuddy->meeting_subject;
312 meeting_location = sbuddy->meeting_location;
314 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
315 gboolean is_group_access = FALSE;
316 const int container_id = sipe_ocs2007_find_access_level(sipe_private,
317 "user",
318 sipe_get_no_sip_uri(uri),
319 &is_group_access);
320 const char *access_level = sipe_ocs2007_access_level_name(container_id);
321 access_text = is_group_access ?
322 g_strdup(access_level) :
323 g_strdup_printf(SIPE_OCS2007_INDENT_MARKED_FMT,
324 access_level);
328 if (is_online) {
329 const gchar *status_str = activity ? activity : status_name;
331 SIPE_ADD_BUDDY_INFO(_("Status"), status_str);
333 if (is_online && !is_empty(calendar)) {
334 SIPE_ADD_BUDDY_INFO(_("Calendar"), calendar);
336 g_free(calendar);
337 if (!is_empty(meeting_location)) {
338 SIPE_DEBUG_INFO("sipe_tooltip_text: %s meeting location: '%s'", uri, meeting_location);
339 SIPE_ADD_BUDDY_INFO(_("Meeting in"), meeting_location);
341 if (!is_empty(meeting_subject)) {
342 SIPE_DEBUG_INFO("sipe_tooltip_text: %s meeting subject: '%s'", uri, meeting_subject);
343 SIPE_ADD_BUDDY_INFO(_("Meeting about"), meeting_subject);
345 if (note) {
346 SIPE_DEBUG_INFO("sipe_tooltip_text: %s note: '%s'", uri, note);
347 SIPE_ADD_BUDDY_INFO_NOESCAPE(is_oof_note ? _("Out of office note") : _("Note"),
348 g_strdup_printf("<i>%s</i>", note));
350 if (access_text) {
351 SIPE_ADD_BUDDY_INFO(_("Access level"), access_text);
352 g_free(access_text);
356 void sipe_buddy_update_property(struct sipe_core_private *sipe_private,
357 const char *uri,
358 sipe_buddy_info_fields propkey,
359 char *property_value)
361 GSList *buddies, *entry;
363 if (property_value)
364 property_value = g_strstrip(property_value);
366 entry = buddies = sipe_backend_buddy_find_all(SIPE_CORE_PUBLIC, uri, NULL); /* all buddies in different groups */
367 while (entry) {
368 gchar *prop_str;
369 gchar *server_alias;
370 gchar *alias;
371 sipe_backend_buddy p_buddy = entry->data;
373 /* for Display Name */
374 if (propkey == SIPE_BUDDY_INFO_DISPLAY_NAME) {
375 alias = sipe_backend_buddy_get_alias(SIPE_CORE_PUBLIC, p_buddy);
376 if (property_value && sipe_is_bad_alias(uri, alias)) {
377 SIPE_DEBUG_INFO("Replacing alias for %s with %s", uri, property_value);
378 sipe_backend_buddy_set_alias(SIPE_CORE_PUBLIC, p_buddy, property_value);
380 g_free(alias);
382 server_alias = sipe_backend_buddy_get_server_alias(SIPE_CORE_PUBLIC, p_buddy);
383 if (!is_empty(property_value) &&
384 (!sipe_strequal(property_value, server_alias) || is_empty(server_alias)) )
386 SIPE_DEBUG_INFO("Replacing service alias for %s with %s", uri, property_value);
387 sipe_backend_buddy_set_server_alias(SIPE_CORE_PUBLIC, p_buddy, property_value);
389 g_free(server_alias);
391 /* for other properties */
392 else {
393 if (!is_empty(property_value)) {
394 prop_str = sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC, p_buddy, propkey);
395 if (!prop_str || !sipe_strcase_equal(prop_str, property_value)) {
396 sipe_backend_buddy_set_string(SIPE_CORE_PUBLIC, p_buddy, propkey, property_value);
398 g_free(prop_str);
402 entry = entry->next;
404 g_slist_free(buddies);
407 static gboolean process_search_contact_response(struct sipe_core_private *sipe_private,
408 struct sipmsg *msg,
409 SIPE_UNUSED_PARAMETER struct transaction *trans)
411 struct sipe_backend_search_results *results;
412 sipe_xml *searchResults;
413 const sipe_xml *mrow;
414 guint match_count = 0;
415 gboolean more = FALSE;
416 gchar *secondary;
418 /* valid response? */
419 if (msg->response != 200) {
420 SIPE_DEBUG_ERROR("process_search_contact_response: request failed (%d)",
421 msg->response);
422 sipe_backend_notify_error(SIPE_CORE_PUBLIC,
423 _("Contact search failed"),
424 NULL);
425 return(FALSE);
428 SIPE_DEBUG_INFO("process_search_contact_response: body:\n%s", msg->body ? msg->body : "");
430 /* valid XML? */
431 searchResults = sipe_xml_parse(msg->body, msg->bodylen);
432 if (!searchResults) {
433 SIPE_DEBUG_INFO_NOFORMAT("process_search_contact_response: no parseable searchResults");
434 sipe_backend_notify_error(SIPE_CORE_PUBLIC,
435 _("Contact search failed"),
436 NULL);
437 return(FALSE);
440 /* any matches? */
441 mrow = sipe_xml_child(searchResults, "Body/Array/row");
442 if (!mrow) {
443 SIPE_DEBUG_ERROR_NOFORMAT("process_search_contact_response: no matches");
444 sipe_backend_notify_error(SIPE_CORE_PUBLIC,
445 _("No contacts found"),
446 NULL);
448 sipe_xml_free(searchResults);
449 return(FALSE);
452 /* OK, we found something - show the results to the user */
453 results = sipe_backend_search_results_start(SIPE_CORE_PUBLIC);
454 if (!results) {
455 SIPE_DEBUG_ERROR_NOFORMAT("process_search_contact_response: Unable to display the search results.");
456 sipe_backend_notify_error(SIPE_CORE_PUBLIC,
457 _("Unable to display the search results"),
458 NULL);
460 sipe_xml_free(searchResults);
461 return FALSE;
464 for (/* initialized above */ ; mrow; mrow = sipe_xml_twin(mrow)) {
465 gchar **uri_parts = g_strsplit(sipe_xml_attribute(mrow, "uri"), ":", 2);
466 sipe_backend_search_results_add(SIPE_CORE_PUBLIC,
467 results,
468 uri_parts[1],
469 sipe_xml_attribute(mrow, "displayName"),
470 sipe_xml_attribute(mrow, "company"),
471 sipe_xml_attribute(mrow, "country"),
472 sipe_xml_attribute(mrow, "email"));
473 g_strfreev(uri_parts);
474 match_count++;
477 if ((mrow = sipe_xml_child(searchResults, "Body/directorySearch/moreAvailable")) != NULL) {
478 char *data = sipe_xml_data(mrow);
479 more = (g_strcasecmp(data, "true") == 0);
480 g_free(data);
483 secondary = g_strdup_printf(
484 dngettext(PACKAGE_NAME,
485 "Found %d contact%s:",
486 "Found %d contacts%s:", match_count),
487 match_count, more ? _(" (more matched your query)") : "");
489 sipe_backend_search_results_finalize(SIPE_CORE_PUBLIC,
490 results,
491 secondary,
492 more);
493 g_free(secondary);
494 sipe_xml_free(searchResults);
496 return(TRUE);
499 #define SIPE_SOAP_SEARCH_ROW "<m:row m:attrib=\"%s\" m:value=\"%s\"/>"
501 void sipe_core_buddy_search(struct sipe_core_public *sipe_public,
502 const gchar *given_name,
503 const gchar *surname,
504 const gchar *company,
505 const gchar *country)
507 gchar **attrs = g_new(gchar *, 5);
508 guint i = 0;
510 if (!attrs) return;
512 #define ADD_QUERY_ROW(a, v) \
513 if (v) attrs[i++] = g_markup_printf_escaped(SIPE_SOAP_SEARCH_ROW, a, v)
515 ADD_QUERY_ROW("givenName", given_name);
516 ADD_QUERY_ROW("sn", surname);
517 ADD_QUERY_ROW("company", company);
518 ADD_QUERY_ROW("c", country);
520 if (i) {
521 gchar *query;
523 attrs[i] = NULL;
524 query = g_strjoinv(NULL, attrs);
525 SIPE_DEBUG_INFO("sipe_core_buddy_search: rows:\n%s",
526 query ? query : "");
527 sip_soap_directory_search(SIPE_CORE_PRIVATE,
528 100,
529 query,
530 process_search_contact_response,
531 NULL);
532 g_free(query);
535 g_strfreev(attrs);
538 static gboolean process_options_response(SIPE_UNUSED_PARAMETER struct sipe_core_private *sipe_private,
539 struct sipmsg *msg,
540 SIPE_UNUSED_PARAMETER struct transaction *trans)
542 if (msg->response != 200) {
543 SIPE_DEBUG_INFO("process_options_response: OPTIONS response is %d",
544 msg->response);
545 return(FALSE);
546 } else {
547 SIPE_DEBUG_INFO("process_options_response: body:\n%s",
548 msg->body ? msg->body : "");
549 return(TRUE);
553 /* Asks UA/proxy about its capabilities */
554 static void sipe_options_request(struct sipe_core_private *sipe_private,
555 const char *who)
557 gchar *to = sip_uri(who);
558 gchar *contact = get_contact(sipe_private);
559 gchar *request = g_strdup_printf("Accept: application/sdp\r\n"
560 "Contact: %s\r\n",
561 contact);
562 g_free(contact);
564 sip_transport_request(sipe_private,
565 "OPTIONS",
568 request,
569 NULL,
570 NULL,
571 process_options_response);
573 g_free(to);
574 g_free(request);
577 static void get_info_finalize(struct sipe_core_private *sipe_private,
578 struct sipe_backend_buddy_info *info,
579 const gchar *uri,
580 const gchar *server_alias,
581 const gchar *email)
583 sipe_backend_buddy bbuddy;
584 struct sipe_buddy *sbuddy;
585 gchar *alias;
586 gchar *value;
588 if (!info) {
589 info = sipe_backend_buddy_info_start(SIPE_CORE_PUBLIC);
590 } else {
591 sipe_backend_buddy_info_break(SIPE_CORE_PUBLIC, info);
593 if (!info)
594 return;
596 bbuddy = sipe_backend_buddy_find(SIPE_CORE_PUBLIC, uri, NULL);
598 if (is_empty(server_alias)) {
599 value = sipe_backend_buddy_get_server_alias(SIPE_CORE_PUBLIC,
600 bbuddy);
601 if (value) {
602 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
603 info,
604 _("Display name"),
605 value);
607 } else {
608 value = g_strdup(server_alias);
611 /* present alias if it differs from server alias */
612 alias = sipe_backend_buddy_get_local_alias(SIPE_CORE_PUBLIC, bbuddy);
613 if (alias && !sipe_strequal(alias, value))
615 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
616 info,
617 _("Alias"),
618 alias);
620 g_free(alias);
621 g_free(value);
623 if (is_empty(email)) {
624 value = sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC,
625 bbuddy,
626 SIPE_BUDDY_INFO_EMAIL);
627 if (value) {
628 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
629 info,
630 _("Email address"),
631 value);
632 g_free(value);
636 value = sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC,
637 bbuddy,
638 SIPE_BUDDY_INFO_SITE);
639 if (value) {
640 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
641 info,
642 _("Site"),
643 value);
644 g_free(value);
647 sbuddy = g_hash_table_lookup(sipe_private->buddies, uri);
648 if (sbuddy && sbuddy->device_name) {
649 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
650 info,
651 _("Device"),
652 sbuddy->device_name);
655 sipe_backend_buddy_info_finalize(SIPE_CORE_PUBLIC, info, uri);
658 static void ms_dlx_webticket(struct sipe_core_private *sipe_private,
659 const gchar *base_uri,
660 const gchar *auth_uri,
661 const gchar *wsse_security,
662 gpointer callback_data)
664 gchar *who = callback_data;
666 if (wsse_security) {
668 SIPE_DEBUG_INFO("ms_dlx_webticket: got ticket for %s",
669 base_uri);
671 /* TBD... MS-DLX request to auth_uri */
672 (void) auth_uri;
673 get_info_finalize(sipe_private,
674 NULL,
675 who,
676 NULL,
677 NULL);
679 } else {
680 /* no ticket: this will show the minmum information */
681 SIPE_DEBUG_ERROR("ms_dlx_webticket: no web ticket for %s",
682 base_uri);
683 get_info_finalize(sipe_private,
684 NULL,
685 who,
686 NULL,
687 NULL);
690 g_free(who);
693 static gboolean process_get_info_response(struct sipe_core_private *sipe_private,
694 struct sipmsg *msg,
695 struct transaction *trans)
697 const gchar *uri = trans->payload->data;
698 struct sipe_backend_buddy_info *info = NULL;
699 gchar *server_alias = NULL;
700 gchar *email = NULL;
702 SIPE_DEBUG_INFO("Fetching %s's user info for %s",
703 uri, sipe_private->username);
705 /* will query buddy UA's capabilities and send answer to log */
706 if (sipe_backend_debug_enabled())
707 sipe_options_request(sipe_private, uri);
709 if (msg->response != 200) {
710 SIPE_DEBUG_INFO("process_get_info_response: SERVICE response is %d", msg->response);
711 } else {
712 sipe_xml *searchResults;
713 const sipe_xml *mrow;
715 SIPE_DEBUG_INFO("process_get_info_response: body:\n%s",
716 msg->body ? msg->body : "");
718 searchResults = sipe_xml_parse(msg->body, msg->bodylen);
719 if (!searchResults) {
721 SIPE_DEBUG_INFO_NOFORMAT("process_get_info_response: no parseable searchResults");
723 } else if ((mrow = sipe_xml_child(searchResults, "Body/Array/row"))) {
724 const gchar *value;
725 gchar *phone_number;
727 info = sipe_backend_buddy_info_start(SIPE_CORE_PUBLIC);
729 server_alias = g_strdup(sipe_xml_attribute(mrow, "displayName"));
730 email = g_strdup(sipe_xml_attribute(mrow, "email"));
731 phone_number = g_strdup(sipe_xml_attribute(mrow, "phone"));
734 * For 2007 system we will take this from ContactCard -
735 * it has cleaner tel: URIs at least
737 if (!SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
738 char *tel_uri = sip_to_tel_uri(phone_number);
739 /* trims its parameters, so call first */
740 sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_DISPLAY_NAME, server_alias);
741 sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_EMAIL, email);
742 sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_WORK_PHONE, tel_uri);
743 sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_WORK_PHONE_DISPLAY, phone_number);
744 g_free(tel_uri);
747 if (!is_empty(server_alias)) {
748 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
749 info,
750 _("Display name"),
751 server_alias);
753 if ((value = sipe_xml_attribute(mrow, "title")) && strlen(value) > 0) {
754 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
755 info,
756 _("Job title"),
757 value);
759 if ((value = sipe_xml_attribute(mrow, "office")) && strlen(value) > 0) {
760 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
761 info,
762 _("Office"),
763 value);
765 if (!is_empty(phone_number)) {
766 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
767 info,
768 _("Business phone"),
769 phone_number);
771 g_free(phone_number);
772 if ((value = sipe_xml_attribute(mrow, "company")) && strlen(value) > 0) {
773 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
774 info,
775 _("Company"),
776 value);
778 if ((value = sipe_xml_attribute(mrow, "city")) && strlen(value) > 0) {
779 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
780 info,
781 _("City"),
782 value);
784 if ((value = sipe_xml_attribute(mrow, "state")) && strlen(value) > 0) {
785 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
786 info,
787 _("State"),
788 value);
790 if ((value = sipe_xml_attribute(mrow, "country")) && strlen(value) > 0) {
791 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
792 info,
793 _("Country"),
794 value);
796 if (!is_empty(email)) {
797 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
798 info,
799 _("Email address"),
800 email);
803 sipe_xml_free(searchResults);
806 /* this will show the minmum information */
807 get_info_finalize(sipe_private,
808 info,
809 uri,
810 server_alias,
811 email);
813 g_free(server_alias);
814 g_free(email);
816 return TRUE;
819 void sipe_core_buddy_get_info(struct sipe_core_public *sipe_public,
820 const gchar *who)
822 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
824 if (sipe_private->dlx_uri) {
825 gchar *payload = g_strdup(who);
827 if (!sipe_webticket_request(sipe_private,
828 sipe_private->dlx_uri,
829 "AddressBookWebTicketBearer",
830 ms_dlx_webticket,
831 payload)) {
832 SIPE_DEBUG_ERROR("sipe_core_buddy_get_info: couldn't request webticket for %s",
833 sipe_private->dlx_uri);
835 /* this will show the minmum information */
836 get_info_finalize(sipe_private,
837 NULL,
838 payload,
839 NULL,
840 NULL);
842 g_free(payload);
844 } else {
845 /* no [MS-DLX] server, use Active Directory search instead */
846 gchar *row = g_markup_printf_escaped(SIPE_SOAP_SEARCH_ROW,
847 "msRTCSIP-PrimaryUserAddress",
848 who);
849 struct transaction_payload *payload = g_new0(struct transaction_payload, 1);
851 SIPE_DEBUG_INFO("sipe_core_buddy_get_info: row: %s",
852 row ? row : "");
854 payload->destroy = g_free;
855 payload->data = g_strdup(who);
857 sip_soap_directory_search(sipe_private,
859 row,
860 process_get_info_response,
861 payload);
862 g_free(row);
866 /* Buddy menu callbacks*/
868 void sipe_core_buddy_new_chat(struct sipe_core_public *sipe_public,
869 const gchar *who)
871 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
873 /* 2007+ conference */
874 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
875 sipe_conf_add(sipe_private, who);
877 /* 2005- multiparty chat */
878 } else {
879 gchar *self = sip_uri_self(sipe_private);
880 struct sip_session *session;
882 session = sipe_session_add_chat(sipe_private,
883 NULL,
884 TRUE,
885 self);
886 session->chat_session->backend = sipe_backend_chat_create(SIPE_CORE_PUBLIC,
887 session->chat_session,
888 session->chat_session->title,
889 self);
890 g_free(self);
892 sipe_im_invite(sipe_private, session, who,
893 NULL, NULL, NULL, FALSE);
897 void sipe_core_buddy_send_email(struct sipe_core_public *sipe_public,
898 const gchar *who)
900 sipe_backend_buddy buddy = sipe_backend_buddy_find(sipe_public,
901 who,
902 NULL);
903 gchar *email = sipe_backend_buddy_get_string(sipe_public,
904 buddy,
905 SIPE_BUDDY_INFO_EMAIL);
907 if (email) {
908 gchar *command_line = g_strdup_printf(
909 #ifdef _WIN32
910 "cmd /c start"
911 #else
912 "xdg-email"
913 #endif
914 " mailto:%s", email);
915 g_free(email);
917 SIPE_DEBUG_INFO("sipe_core_buddy_send_email: going to call email client: %s",
918 command_line);
919 g_spawn_command_line_async(command_line, NULL);
920 g_free(command_line);
922 } else {
923 SIPE_DEBUG_INFO("sipe_core_buddy_send_email: no email address stored for buddy=%s",
924 who);
928 /* Buddy menu */
930 static struct sipe_backend_buddy_menu *buddy_menu_phone(struct sipe_core_public *sipe_public,
931 struct sipe_backend_buddy_menu *menu,
932 sipe_backend_buddy buddy,
933 sipe_buddy_info_fields id_phone,
934 sipe_buddy_info_fields id_display,
935 const gchar *type)
937 gchar *phone = sipe_backend_buddy_get_string(sipe_public,
938 buddy,
939 id_phone);
940 if (phone) {
941 gchar *display = sipe_backend_buddy_get_string(sipe_public,
942 buddy,
943 id_display);
944 gchar *tmp = NULL;
945 gchar *label = g_strdup_printf("%s %s",
946 type,
947 display ? display :
948 (tmp = sip_tel_uri_denormalize(phone)));
949 menu = sipe_backend_buddy_menu_add(sipe_public,
950 menu,
951 label,
952 SIPE_BUDDY_MENU_MAKE_CALL,
953 phone);
954 g_free(tmp);
955 g_free(label);
956 g_free(display);
957 g_free(phone);
960 return(menu);
963 struct sipe_backend_buddy_menu *sipe_core_buddy_create_menu(struct sipe_core_public *sipe_public,
964 const gchar *buddy_name,
965 struct sipe_backend_buddy_menu *menu)
967 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
968 sipe_backend_buddy buddy = sipe_backend_buddy_find(sipe_public,
969 buddy_name,
970 NULL);
971 gchar *self = sip_uri_self(sipe_private);
973 SIPE_SESSION_FOREACH {
974 if (!sipe_strcase_equal(self, buddy_name) && session->chat_session)
976 struct sipe_chat_session *chat_session = session->chat_session;
977 gboolean is_conf = (chat_session->type == SIPE_CHAT_TYPE_CONFERENCE);
979 if (sipe_backend_chat_find(chat_session->backend, buddy_name))
981 gboolean conf_op = sipe_backend_chat_is_operator(chat_session->backend, self);
983 if (is_conf &&
984 /* Not conf OP */
985 !sipe_backend_chat_is_operator(chat_session->backend, buddy_name) &&
986 /* We are a conf OP */
987 conf_op) {
988 gchar *label = g_strdup_printf(_("Make leader of '%s'"),
989 chat_session->title);
990 menu = sipe_backend_buddy_menu_add(sipe_public,
991 menu,
992 label,
993 SIPE_BUDDY_MENU_MAKE_CHAT_LEADER,
994 chat_session);
995 g_free(label);
998 if (is_conf &&
999 /* We are a conf OP */
1000 conf_op) {
1001 gchar *label = g_strdup_printf(_("Remove from '%s'"),
1002 chat_session->title);
1003 menu = sipe_backend_buddy_menu_add(sipe_public,
1004 menu,
1005 label,
1006 SIPE_BUDDY_MENU_REMOVE_FROM_CHAT,
1007 chat_session);
1008 g_free(label);
1011 else
1013 if (!is_conf ||
1014 (is_conf && !session->locked)) {
1015 gchar *label = g_strdup_printf(_("Invite to '%s'"),
1016 chat_session->title);
1017 menu = sipe_backend_buddy_menu_add(sipe_public,
1018 menu,
1019 label,
1020 SIPE_BUDDY_MENU_INVITE_TO_CHAT,
1021 chat_session);
1022 g_free(label);
1026 } SIPE_SESSION_FOREACH_END;
1027 g_free(self);
1029 menu = sipe_backend_buddy_menu_add(sipe_public,
1030 menu,
1031 _("New chat"),
1032 SIPE_BUDDY_MENU_NEW_CHAT,
1033 NULL);
1035 /* add buddy's phone numbers if we have call control */
1036 if (sip_csta_is_idle(sipe_private)) {
1038 /* work phone */
1039 menu = buddy_menu_phone(sipe_public,
1040 menu,
1041 buddy,
1042 SIPE_BUDDY_INFO_WORK_PHONE,
1043 SIPE_BUDDY_INFO_WORK_PHONE_DISPLAY,
1044 _("Work"));
1045 /* mobile phone */
1046 menu = buddy_menu_phone(sipe_public,
1047 menu,
1048 buddy,
1049 SIPE_BUDDY_INFO_MOBILE_PHONE,
1050 SIPE_BUDDY_INFO_MOBILE_PHONE_DISPLAY,
1051 _("Mobile"));
1053 /* home phone */
1054 menu = buddy_menu_phone(sipe_public,
1055 menu,
1056 buddy,
1057 SIPE_BUDDY_INFO_HOME_PHONE,
1058 SIPE_BUDDY_INFO_HOME_PHONE_DISPLAY,
1059 _("Home"));
1061 /* other phone */
1062 menu = buddy_menu_phone(sipe_public,
1063 menu,
1064 buddy,
1065 SIPE_BUDDY_INFO_OTHER_PHONE,
1066 SIPE_BUDDY_INFO_OTHER_PHONE_DISPLAY,
1067 _("Other"));
1069 /* custom1 phone */
1070 menu = buddy_menu_phone(sipe_public,
1071 menu,
1072 buddy,
1073 SIPE_BUDDY_INFO_CUSTOM1_PHONE,
1074 SIPE_BUDDY_INFO_CUSTOM1_PHONE_DISPLAY,
1075 _("Custom1"));
1079 gchar *email = sipe_backend_buddy_get_string(sipe_public,
1080 buddy,
1081 SIPE_BUDDY_INFO_EMAIL);
1082 if (email) {
1083 menu = sipe_backend_buddy_menu_add(sipe_public,
1084 menu,
1085 _("Send email..."),
1086 SIPE_BUDDY_MENU_SEND_EMAIL,
1087 NULL);
1088 g_free(email);
1092 /* access level control */
1093 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007))
1094 menu = sipe_backend_buddy_sub_menu_add(sipe_public,
1095 menu,
1096 _("Access level"),
1097 sipe_ocs2007_access_control_menu(sipe_private,
1098 buddy_name));
1100 return(menu);
1104 Local Variables:
1105 mode: c
1106 c-file-style: "bsd"
1107 indent-tabs-mode: t
1108 tab-width: 8
1109 End: