core cleanup: separate code for send email menu entry
[siplcs.git] / src / core / sipe-buddy.c
blobaa81844e6b100257b82c995110db505d6b96b531
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 "http-conn.h" /* sipe-cal.h requires this */
34 #include "sipmsg.h"
35 #include "sip-csta.h"
36 #include "sip-soap.h"
37 #include "sip-transport.h"
38 #include "sipe-backend.h"
39 #include "sipe-buddy.h"
40 #include "sipe-cal.h"
41 #include "sipe-chat.h"
42 #include "sipe-conf.h"
43 #include "sipe-core.h"
44 #include "sipe-core-private.h"
45 #include "sipe-group.h"
46 #include "sipe-im.h"
47 #include "sipe-nls.h"
48 #include "sipe-ocs2005.h"
49 #include "sipe-ocs2007.h"
50 #include "sipe-schedule.h"
51 #include "sipe-session.h"
52 #include "sipe-subscriptions.h"
53 #include "sipe-utils.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 gboolean process_get_info_response(struct sipe_core_private *sipe_private,
578 struct sipmsg *msg,
579 struct transaction *trans)
581 const gchar *uri = trans->payload->data;
582 sipe_backend_buddy bbuddy;
583 struct sipe_backend_buddy_info *info;
584 struct sipe_buddy *sbuddy;
585 gchar *alias = NULL;
586 gchar *device_name = NULL;
587 gchar *server_alias = NULL;
588 gchar *phone_number = NULL;
589 gchar *email = NULL;
590 gchar *site;
592 SIPE_DEBUG_INFO("Fetching %s's user info for %s",
593 uri, sipe_private->username);
595 info = sipe_backend_buddy_info_start(SIPE_CORE_PUBLIC);
596 if (!info) return(FALSE);
598 bbuddy = sipe_backend_buddy_find(SIPE_CORE_PUBLIC, uri, NULL);
599 alias = sipe_backend_buddy_get_local_alias(SIPE_CORE_PUBLIC, bbuddy);
601 /* will query buddy UA's capabilities and send answer to log */
602 if (sipe_backend_debug_enabled())
603 sipe_options_request(sipe_private, uri);
605 sbuddy = g_hash_table_lookup(sipe_private->buddies, uri);
606 if (sbuddy) {
607 device_name = sbuddy->device_name ? g_strdup(sbuddy->device_name) : NULL;
610 if (msg->response != 200) {
611 SIPE_DEBUG_INFO("process_get_info_response: SERVICE response is %d", msg->response);
612 } else {
613 sipe_xml *searchResults;
614 const sipe_xml *mrow;
616 SIPE_DEBUG_INFO("process_get_info_response: body:\n%s",
617 msg->body ? msg->body : "");
619 searchResults = sipe_xml_parse(msg->body, msg->bodylen);
620 if (!searchResults) {
622 SIPE_DEBUG_INFO_NOFORMAT("process_get_info_response: no parseable searchResults");
624 } else if ((mrow = sipe_xml_child(searchResults, "Body/Array/row"))) {
625 const gchar *value;
627 server_alias = g_strdup(sipe_xml_attribute(mrow, "displayName"));
628 email = g_strdup(sipe_xml_attribute(mrow, "email"));
629 phone_number = g_strdup(sipe_xml_attribute(mrow, "phone"));
632 * For 2007 system we will take this from ContactCard -
633 * it has cleaner tel: URIs at least
635 if (!SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
636 char *tel_uri = sip_to_tel_uri(phone_number);
637 /* trims its parameters, so call first */
638 sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_DISPLAY_NAME, server_alias);
639 sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_EMAIL, email);
640 sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_WORK_PHONE, tel_uri);
641 sipe_buddy_update_property(sipe_private, uri, SIPE_BUDDY_INFO_WORK_PHONE_DISPLAY, phone_number);
642 g_free(tel_uri);
645 if (server_alias && strlen(server_alias) > 0) {
646 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
647 info,
648 _("Display name"),
649 server_alias);
651 if ((value = sipe_xml_attribute(mrow, "title")) && strlen(value) > 0) {
652 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
653 info,
654 _("Job title"),
655 value);
657 if ((value = sipe_xml_attribute(mrow, "office")) && strlen(value) > 0) {
658 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
659 info,
660 _("Office"),
661 value);
663 if (phone_number && strlen(phone_number) > 0) {
664 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
665 info,
666 _("Business phone"),
667 phone_number);
669 if ((value = sipe_xml_attribute(mrow, "company")) && strlen(value) > 0) {
670 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
671 info,
672 _("Company"),
673 value);
675 if ((value = sipe_xml_attribute(mrow, "city")) && strlen(value) > 0) {
676 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
677 info,
678 _("City"),
679 value);
681 if ((value = sipe_xml_attribute(mrow, "state")) && strlen(value) > 0) {
682 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
683 info,
684 _("State"),
685 value);
687 if ((value = sipe_xml_attribute(mrow, "country")) && strlen(value) > 0) {
688 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
689 info,
690 _("Country"),
691 value);
693 if (email && strlen(email) > 0) {
694 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
695 info,
696 _("Email address"),
697 email);
701 sipe_xml_free(searchResults);
704 sipe_backend_buddy_info_break(SIPE_CORE_PUBLIC, info);
706 if (is_empty(server_alias)) {
707 g_free(server_alias);
708 server_alias = sipe_backend_buddy_get_server_alias(SIPE_CORE_PUBLIC,
709 bbuddy);
710 if (server_alias) {
711 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
712 info,
713 _("Display name"),
714 server_alias);
718 /* present alias if it differs from server alias */
719 if (alias && !sipe_strequal(alias, server_alias))
721 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
722 info,
723 _("Alias"),
724 alias);
727 if (is_empty(email)) {
728 g_free(email);
729 email = sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC,
730 bbuddy,
731 SIPE_BUDDY_INFO_EMAIL);
732 if (email) {
733 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
734 info,
735 _("Email address"),
736 email);
740 site = sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC,
741 bbuddy,
742 SIPE_BUDDY_INFO_SITE);
743 if (site) {
744 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
745 info,
746 _("Site"),
747 site);
748 g_free(site);
751 if (device_name) {
752 sipe_backend_buddy_info_add(SIPE_CORE_PUBLIC,
753 info,
754 _("Device"),
755 device_name);
758 sipe_backend_buddy_info_finalize(SIPE_CORE_PUBLIC, info, uri);
760 g_free(phone_number);
761 g_free(server_alias);
762 g_free(email);
763 g_free(device_name);
764 g_free(alias);
766 return TRUE;
770 * AD search first, LDAP based
772 void sipe_core_buddy_get_info(struct sipe_core_public *sipe_public,
773 const gchar *who)
775 char *row = g_markup_printf_escaped(SIPE_SOAP_SEARCH_ROW,
776 "msRTCSIP-PrimaryUserAddress",
777 who);
778 struct transaction_payload *payload = g_new0(struct transaction_payload, 1);
780 SIPE_DEBUG_INFO("sipe_core_buddy_get_info: row: %s", row ? row : "");
782 payload->destroy = g_free;
783 payload->data = g_strdup(who);
785 sip_soap_directory_search(SIPE_CORE_PRIVATE,
787 row,
788 process_get_info_response,
789 payload);
790 g_free(row);
793 /* Buddy menu callbacks*/
795 void sipe_core_buddy_new_chat(struct sipe_core_public *sipe_public,
796 const gchar *who)
798 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
800 /* 2007+ conference */
801 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007)) {
802 sipe_conf_add(sipe_private, who);
804 /* 2005- multiparty chat */
805 } else {
806 gchar *self = sip_uri_self(sipe_private);
807 struct sip_session *session;
809 session = sipe_session_add_chat(sipe_private,
810 NULL,
811 TRUE,
812 self);
813 session->chat_session->backend = sipe_backend_chat_create(SIPE_CORE_PUBLIC,
814 session->chat_session,
815 session->chat_session->title,
816 self);
817 g_free(self);
819 sipe_im_invite(sipe_private, session, who,
820 NULL, NULL, NULL, FALSE);
824 void sipe_core_buddy_send_email(struct sipe_core_public *sipe_public,
825 const gchar *who)
827 sipe_backend_buddy buddy = sipe_backend_buddy_find(sipe_public,
828 who,
829 NULL);
830 gchar *email = sipe_backend_buddy_get_string(sipe_public,
831 buddy,
832 SIPE_BUDDY_INFO_EMAIL);
834 if (email) {
835 gchar *command_line = g_strdup_printf(
836 #ifdef _WIN32
837 "cmd /c start"
838 #else
839 "xdg-email"
840 #endif
841 " mailto:%s", email);
842 g_free(email);
844 SIPE_DEBUG_INFO("sipe_core_buddy_send_email: going to call email client: %s",
845 command_line);
846 g_spawn_command_line_async(command_line, NULL);
847 g_free(command_line);
849 } else {
850 SIPE_DEBUG_INFO("sipe_core_buddy_send_email: no email address stored for buddy=%s",
851 who);
855 /* Buddy menu */
857 static struct sipe_backend_buddy_menu *buddy_menu_phone(struct sipe_core_public *sipe_public,
858 struct sipe_backend_buddy_menu *menu,
859 sipe_backend_buddy buddy,
860 sipe_buddy_info_fields id_phone,
861 sipe_buddy_info_fields id_display,
862 const gchar *type)
864 gchar *phone = sipe_backend_buddy_get_string(sipe_public,
865 buddy,
866 id_phone);
867 if (phone) {
868 gchar *display = sipe_backend_buddy_get_string(sipe_public,
869 buddy,
870 id_display);
871 gchar *tmp = NULL;
872 gchar *label = g_strdup_printf("%s %s",
873 type,
874 display ? display :
875 (tmp = sip_tel_uri_denormalize(phone)));
876 menu = sipe_backend_buddy_menu_add(sipe_public,
877 menu,
878 label,
879 SIPE_BUDDY_MENU_MAKE_CALL,
880 phone);
881 g_free(tmp);
882 g_free(label);
883 g_free(display);
884 g_free(phone);
887 return(menu);
890 struct sipe_backend_buddy_menu *sipe_core_buddy_create_menu(struct sipe_core_public *sipe_public,
891 const gchar *buddy_name,
892 struct sipe_backend_buddy_menu *menu)
894 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
895 sipe_backend_buddy buddy = sipe_backend_buddy_find(sipe_public,
896 buddy_name,
897 NULL);
898 gchar *self = sip_uri_self(sipe_private);
900 SIPE_SESSION_FOREACH {
901 if (!sipe_strcase_equal(self, buddy_name) && session->chat_session)
903 struct sipe_chat_session *chat_session = session->chat_session;
904 gboolean is_conf = (chat_session->type == SIPE_CHAT_TYPE_CONFERENCE);
906 if (sipe_backend_chat_find(chat_session->backend, buddy_name))
908 gboolean conf_op = sipe_backend_chat_is_operator(chat_session->backend, self);
910 if (is_conf &&
911 /* Not conf OP */
912 !sipe_backend_chat_is_operator(chat_session->backend, buddy_name) &&
913 /* We are a conf OP */
914 conf_op) {
915 gchar *label = g_strdup_printf(_("Make leader of '%s'"),
916 chat_session->title);
917 menu = sipe_backend_buddy_menu_add(sipe_public,
918 menu,
919 label,
920 SIPE_BUDDY_MENU_MAKE_CHAT_LEADER,
921 chat_session);
922 g_free(label);
925 if (is_conf &&
926 /* We are a conf OP */
927 conf_op) {
928 gchar *label = g_strdup_printf(_("Remove from '%s'"),
929 chat_session->title);
930 menu = sipe_backend_buddy_menu_add(sipe_public,
931 menu,
932 label,
933 SIPE_BUDDY_MENU_REMOVE_FROM_CHAT,
934 chat_session);
935 g_free(label);
938 else
940 if (!is_conf ||
941 (is_conf && !session->locked)) {
942 gchar *label = g_strdup_printf(_("Invite to '%s'"),
943 chat_session->title);
944 menu = sipe_backend_buddy_menu_add(sipe_public,
945 menu,
946 label,
947 SIPE_BUDDY_MENU_INVITE_TO_CHAT,
948 chat_session);
949 g_free(label);
953 } SIPE_SESSION_FOREACH_END;
954 g_free(self);
956 menu = sipe_backend_buddy_menu_add(sipe_public,
957 menu,
958 _("New chat"),
959 SIPE_BUDDY_MENU_NEW_CHAT,
960 NULL);
962 /* add buddy's phone numbers if we have call control */
963 if (sip_csta_is_idle(sipe_private)) {
965 /* work phone */
966 menu = buddy_menu_phone(sipe_public,
967 menu,
968 buddy,
969 SIPE_BUDDY_INFO_WORK_PHONE,
970 SIPE_BUDDY_INFO_WORK_PHONE_DISPLAY,
971 _("Work"));
972 /* mobile phone */
973 menu = buddy_menu_phone(sipe_public,
974 menu,
975 buddy,
976 SIPE_BUDDY_INFO_MOBILE_PHONE,
977 SIPE_BUDDY_INFO_MOBILE_PHONE_DISPLAY,
978 _("Mobile"));
980 /* home phone */
981 menu = buddy_menu_phone(sipe_public,
982 menu,
983 buddy,
984 SIPE_BUDDY_INFO_HOME_PHONE,
985 SIPE_BUDDY_INFO_HOME_PHONE_DISPLAY,
986 _("Home"));
988 /* other phone */
989 menu = buddy_menu_phone(sipe_public,
990 menu,
991 buddy,
992 SIPE_BUDDY_INFO_OTHER_PHONE,
993 SIPE_BUDDY_INFO_OTHER_PHONE_DISPLAY,
994 _("Other"));
996 /* custom1 phone */
997 menu = buddy_menu_phone(sipe_public,
998 menu,
999 buddy,
1000 SIPE_BUDDY_INFO_CUSTOM1_PHONE,
1001 SIPE_BUDDY_INFO_CUSTOM1_PHONE_DISPLAY,
1002 _("Custom1"));
1006 gchar *email = sipe_backend_buddy_get_string(sipe_public,
1007 buddy,
1008 SIPE_BUDDY_INFO_EMAIL);
1009 if (email) {
1010 menu = sipe_backend_buddy_menu_add(sipe_public,
1011 menu,
1012 _("Send email..."),
1013 SIPE_BUDDY_MENU_SEND_EMAIL,
1014 NULL);
1015 g_free(email);
1019 /*--------------------- START WIP ------------------------------*/
1021 return(menu);
1025 Local Variables:
1026 mode: c
1027 c-file-style: "bsd"
1028 indent-tabs-mode: t
1029 tab-width: 8
1030 End: