4 *****************************************************************************
5 *** !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ***
7 *** THIS MODULE IS DEPECRATED ***
9 *** DO NOT ADD ANY NEW CODE TO THIS MODULE ***
11 *** !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ***
12 *****************************************************************************
16 * Copyright (C) 2010-11 SIPE Project <http://sipe.sourceforge.net/>
17 * Copyright (C) 2010 pier11 <pier11@operamail.com>
18 * Copyright (C) 2009 Anibal Avelar <debianmx@gmail.com>
19 * Copyright (C) 2009 pier11 <pier11@operamail.com>
20 * Copyright (C) 2008 Novell, Inc., Anibal Avelar <debianmx@gmail.com>
21 * Copyright (C) 2007 Anibal Avelar <debianmx@gmail.com>
22 * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de>
25 * Thanks to Google's Summer of Code Program and the helpful mentors
28 * Session-based SIP MESSAGE documentation:
29 * http://tools.ietf.org/html/draft-ietf-simple-im-session-00
31 * This program is free software; you can redistribute it and/or modify
32 * it under the terms of the GNU General Public License as published by
33 * the Free Software Foundation; either version 2 of the License, or
34 * (at your option) any later version.
36 * This program is distributed in the hope that it will be useful,
37 * but WITHOUT ANY WARRANTY; without even the implied warranty of
38 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39 * GNU General Public License for more details.
41 * You should have received a copy of the GNU General Public License
42 * along with this program; if not, write to the Free Software
43 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
61 #include "sipe-common.h"
65 #include "connection.h"
66 #include "conversation.h"
72 #include "savedstatuses.h"
75 #include "core-depurple.h" /* Temporary for the core de-purple transition */
77 #include "http-conn.h"
81 #include "sip-transport.h"
82 #include "sipe-backend.h"
83 #include "sipe-buddy.h"
85 #include "sipe-chat.h"
86 #include "sipe-conf.h"
87 #include "sipe-core.h"
88 #include "sipe-core-private.h"
89 #include "sipe-dialog.h"
92 #include "sipe-ocs2005.h"
93 #include "sipe-ocs2007.h"
94 #include "sipe-schedule.h"
95 #include "sipe-session.h"
96 #include "sipe-subscriptions.h"
97 #include "sipe-utils.h"
100 #define _SIPE_NEED_ACTIVITIES /* ugly hack :-( */
103 #define SIPE_IDLE_SET_DELAY 1 /* 1 sec */
105 /* Status identifiers (see also: sipe_status_types()) */
106 #define SIPE_STATUS_ID_UNKNOWN purple_primitive_get_id_from_type(PURPLE_STATUS_UNSET) /* Unset (primitive) */
107 #define SIPE_STATUS_ID_OFFLINE purple_primitive_get_id_from_type(PURPLE_STATUS_OFFLINE) /* Offline (primitive) */
108 #define SIPE_STATUS_ID_AVAILABLE purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE) /* Online */
109 /* PURPLE_STATUS_UNAVAILABLE: */
110 #define SIPE_STATUS_ID_BUSY "busy" /* Busy */
111 #define SIPE_STATUS_ID_BUSYIDLE "busyidle" /* BusyIdle */
112 #define SIPE_STATUS_ID_DND "do-not-disturb" /* Do Not Disturb */
113 #define SIPE_STATUS_ID_IN_MEETING "in-a-meeting" /* In a meeting */
114 #define SIPE_STATUS_ID_IN_CONF "in-a-conference" /* In a conference */
115 #define SIPE_STATUS_ID_ON_PHONE "on-the-phone" /* On the phone */
116 #define SIPE_STATUS_ID_INVISIBLE purple_primitive_get_id_from_type(PURPLE_STATUS_INVISIBLE) /* Appear Offline */
117 /* PURPLE_STATUS_AWAY: */
118 #define SIPE_STATUS_ID_IDLE "idle" /* Idle/Inactive */
119 #define SIPE_STATUS_ID_BRB "be-right-back" /* Be Right Back */
120 #define SIPE_STATUS_ID_AWAY purple_primitive_get_id_from_type(PURPLE_STATUS_AWAY) /* Away (primitive) */
121 /** Reuters status (user settable) */
122 #define SIPE_STATUS_ID_LUNCH "out-to-lunch" /* Out To Lunch */
123 /* ??? PURPLE_STATUS_EXTENDED_AWAY */
124 /* ??? PURPLE_STATUS_MOBILE */
125 /* ??? PURPLE_STATUS_TUNE */
127 /* Status attributes (see also sipe_status_types() */
128 #define SIPE_STATUS_ATTR_ID_MESSAGE "message"
130 static struct sipe_activity_map_struct
135 const char *status_id
;
137 } const sipe_activity_map
[] =
139 /* This has nothing to do with Availability numbers, like 3500 (online).
140 * Just a mapping of Communicator Activities to Purple statuses to be able display them in Pidgin.
142 { SIPE_ACTIVITY_UNSET
, "unset", NULL
, NULL
},
143 { SIPE_ACTIVITY_ONLINE
, "online", NULL
, NULL
},
144 { SIPE_ACTIVITY_INACTIVE
, SIPE_STATUS_ID_IDLE
, N_("Inactive") , NULL
},
145 { SIPE_ACTIVITY_BUSY
, SIPE_STATUS_ID_BUSY
, N_("Busy") , SIPE_STATUS_ID_BUSY
},
146 { SIPE_ACTIVITY_BUSYIDLE
, SIPE_STATUS_ID_BUSYIDLE
, N_("Busy-Idle") , NULL
},
147 { SIPE_ACTIVITY_DND
, SIPE_STATUS_ID_DND
, NULL
, SIPE_STATUS_ID_DND
},
148 { SIPE_ACTIVITY_BRB
, SIPE_STATUS_ID_BRB
, N_("Be right back") , SIPE_STATUS_ID_BRB
},
149 { SIPE_ACTIVITY_AWAY
, "away", NULL
, NULL
},
150 { SIPE_ACTIVITY_LUNCH
, SIPE_STATUS_ID_LUNCH
, N_("Out to lunch") , NULL
},
151 { SIPE_ACTIVITY_OFFLINE
, "offline", NULL
, NULL
},
152 { SIPE_ACTIVITY_ON_PHONE
, SIPE_STATUS_ID_ON_PHONE
, N_("In a call") , NULL
},
153 { SIPE_ACTIVITY_IN_CONF
, SIPE_STATUS_ID_IN_CONF
, N_("In a conference") , NULL
},
154 { SIPE_ACTIVITY_IN_MEETING
, SIPE_STATUS_ID_IN_MEETING
, N_("In a meeting") , NULL
},
155 { SIPE_ACTIVITY_OOF
, "out-of-office", N_("Out of office") , NULL
},
156 { SIPE_ACTIVITY_URGENT_ONLY
, "urgent-interruptions-only", N_("Urgent interruptions only") , NULL
}
158 /** @param x is sipe_activity */
159 #define SIPE_ACTIVITY_I18N(x) gettext(sipe_activity_map[x].desc)
161 const gchar
*sipe_activity_to_token(sipe_activity type
)
163 return(sipe_activity_map
[type
].token
);
166 const gchar
*sipe_activity_description(sipe_activity type
)
168 return(SIPE_ACTIVITY_I18N(type
));
171 void sipe_set_unknown_status(struct sipe_core_private
*sipe_private
)
173 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
176 sip
->status
= g_strdup(SIPE_STATUS_ID_UNKNOWN
);
179 void sipe_set_initial_status(struct sipe_core_private
*sipe_private
)
181 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
184 sip
->status
= g_strdup(SIPE_STATUS_ID_AVAILABLE
); /* our initial state */
187 void sipe_set_invisible_status(struct sipe_core_private
*sipe_private
)
189 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
192 sip
->status
= g_strdup(SIPE_STATUS_ID_INVISIBLE
);
196 sipe_get_activity_by_token(const char *token
)
200 for (i
= 0; i
< SIPE_ACTIVITY_NUM_TYPES
; i
++)
202 if (sipe_strequal(token
, sipe_activity_to_token(i
)))
203 return sipe_activity_map
[i
].type
;
206 return sipe_activity_map
[0].type
;
209 const gchar
*sipe_activity_description_from_token(const gchar
*token
)
211 if (!token
) return NULL
;
213 return sipe_activity_description(sipe_get_activity_by_token(token
));
217 sipe_apply_calendar_status(struct sipe_core_private
*sipe_private
,
218 struct sipe_buddy
*sbuddy
,
219 const char *status_id
)
221 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
222 time_t cal_avail_since
;
223 int cal_status
= sipe_cal_get_status(sbuddy
, time(NULL
), &cal_avail_since
);
229 if (cal_status
< SIPE_CAL_NO_DATA
) {
230 SIPE_DEBUG_INFO("sipe_apply_calendar_status: cal_status : %d for %s", cal_status
, sbuddy
->name
);
231 SIPE_DEBUG_INFO("sipe_apply_calendar_status: cal_avail_since : %s", asctime(localtime(&cal_avail_since
)));
234 /* scheduled Cal update call */
236 status_id
= sbuddy
->last_non_cal_status_id
;
237 g_free(sbuddy
->activity
);
238 sbuddy
->activity
= g_strdup(sbuddy
->last_non_cal_activity
);
242 SIPE_DEBUG_INFO("sipe_apply_calendar_status: status_id is NULL for %s, exiting.",
243 sbuddy
->name
? sbuddy
->name
: "" );
247 /* adjust to calendar status */
248 if (cal_status
!= SIPE_CAL_NO_DATA
) {
249 SIPE_DEBUG_INFO("sipe_apply_calendar_status: user_avail_since: %s", asctime(localtime(&sbuddy
->user_avail_since
)));
251 if (cal_status
== SIPE_CAL_BUSY
252 && cal_avail_since
> sbuddy
->user_avail_since
253 && 6500 >= sipe_get_availability_by_status(status_id
, NULL
))
255 status_id
= SIPE_STATUS_ID_BUSY
;
256 g_free(sbuddy
->activity
);
257 sbuddy
->activity
= g_strdup(sipe_activity_description(SIPE_ACTIVITY_IN_MEETING
));
259 avail
= sipe_get_availability_by_status(status_id
, NULL
);
261 SIPE_DEBUG_INFO("sipe_apply_calendar_status: activity_since : %s", asctime(localtime(&sbuddy
->activity_since
)));
262 if (cal_avail_since
> sbuddy
->activity_since
) {
263 if (cal_status
== SIPE_CAL_OOF
264 && avail
>= 15000) /* 12000 in 2007 */
266 g_free(sbuddy
->activity
);
267 sbuddy
->activity
= g_strdup(sipe_activity_description(SIPE_ACTIVITY_OOF
));
272 /* then set status_id actually */
273 SIPE_DEBUG_INFO("sipe_apply_calendar_status: to %s for %s", status_id
, sbuddy
->name
? sbuddy
->name
: "" );
274 sipe_backend_buddy_set_status(SIPE_CORE_PUBLIC
, sbuddy
->name
, status_id
);
276 /* set our account state to the one in roaming (including calendar info) */
277 self_uri
= sip_uri_self(sipe_private
);
278 if (sip
->initial_state_published
&& sipe_strcase_equal(sbuddy
->name
, self_uri
)) {
279 if (sipe_strequal(status_id
, SIPE_STATUS_ID_OFFLINE
)) {
280 status_id
= g_strdup(SIPE_STATUS_ID_INVISIBLE
); /* not not let offline status switch us off */
283 SIPE_DEBUG_INFO("sipe_apply_calendar_status: switch to '%s' for the account", sip
->status
);
284 sipe_backend_account_status_and_note(sipe_private
, status_id
);
290 sipe_core_buddy_got_status(struct sipe_core_public
*sipe_public
,
292 const gchar
*status_id
)
294 struct sipe_core_private
*sipe_private
= SIPE_CORE_PRIVATE
;
295 struct sipe_buddy
*sbuddy
= g_hash_table_lookup(sipe_private
->buddies
, uri
);
299 /* Check if on 2005 system contact's calendar,
300 * then set/preserve it.
302 if (!SIPE_CORE_PRIVATE_FLAG_IS(OCS2007
)) {
303 sipe_apply_calendar_status(sipe_private
, sbuddy
, status_id
);
305 sipe_backend_buddy_set_status(sipe_public
, uri
, status_id
);
309 void sipe_set_status(PurpleAccount
*account
, PurpleStatus
*status
)
311 SIPE_DEBUG_INFO("sipe_set_status: status=%s", purple_status_get_id(status
));
313 if (!purple_status_is_active(status
))
317 struct sipe_core_private
*sipe_private
= PURPLE_ACCOUNT_TO_SIPE_CORE_PRIVATE
;
318 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
323 time_t now
= time(NULL
);
324 const char *status_id
= purple_status_get_id(status
);
325 const char *note
= purple_status_get_attr_string(status
, SIPE_STATUS_ATTR_ID_MESSAGE
);
326 sipe_activity activity
= sipe_get_activity_by_token(status_id
);
327 gboolean do_not_publish
= ((now
- sip
->do_not_publish
[activity
]) <= 2);
329 /* when other point of presence clears note, but we are keeping
332 if (do_not_publish
&& !note
&& sip
->cal
&& sip
->cal
->oof_note
) {
333 SIPE_DEBUG_INFO_NOFORMAT("sipe_set_status: enabling publication as OOF note keepers.");
334 do_not_publish
= FALSE
;
337 SIPE_DEBUG_INFO("sipe_set_status: was: sip->do_not_publish[%s]=%d [?] now(time)=%d",
338 status_id
, (int)sip
->do_not_publish
[activity
], (int)now
);
340 sip
->do_not_publish
[activity
] = 0;
341 SIPE_DEBUG_INFO("sipe_set_status: set: sip->do_not_publish[%s]=%d [0]",
342 status_id
, (int)sip
->do_not_publish
[activity
]);
346 SIPE_DEBUG_INFO_NOFORMAT("sipe_set_status: publication was switched off, exiting.");
351 sip
->status
= g_strdup(status_id
);
353 /* hack to escape apostrof before comparison */
354 tmp
= note
? sipe_utils_str_replace(note
, "'", "'") : NULL
;
356 /* this will preserve OOF flag as well */
357 if (!sipe_strequal(tmp
, sip
->note
)) {
358 sip
->is_oof_note
= FALSE
;
360 sip
->note
= g_strdup(note
);
361 sip
->note_since
= time(NULL
);
365 /* schedule 2 sec to capture idle flag */
366 action_name
= g_strdup_printf("<%s>", "+set-status");
367 sipe_schedule_seconds(sipe_private
,
371 send_presence_status
,
379 sipe_set_idle(PurpleConnection
* gc
,
382 SIPE_DEBUG_INFO("sipe_set_idle: interval=%d", interval
);
385 struct sipe_core_private
*sipe_private
= PURPLE_GC_TO_SIPE_CORE_PRIVATE
;
386 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
389 sip
->idle_switch
= time(NULL
);
390 SIPE_DEBUG_INFO("sipe_set_idle: sip->idle_switch : %s", asctime(localtime(&(sip
->idle_switch
))));
395 const gchar
*sipe_get_buddy_status(struct sipe_core_private
*sipe_private
,
398 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
399 PurpleBuddy
*pbuddy
= purple_find_buddy((PurpleAccount
*)sip
->account
, uri
);
400 const PurplePresence
*presence
= purple_buddy_get_presence(pbuddy
);
401 const PurpleStatus
*pstatus
= purple_presence_get_active_status(presence
);
402 return(purple_status_get_id(pstatus
));
405 void sipe_buddy_status_from_activity(struct sipe_core_private
*sipe_private
,
407 const gchar
*activity
,
411 const gchar
*status_id
= NULL
;
413 if (sipe_strequal(activity
, sipe_activity_to_token(SIPE_ACTIVITY_BUSY
))) {
414 status_id
= SIPE_STATUS_ID_BUSY
;
415 } else if (sipe_strequal(activity
, sipe_activity_to_token(SIPE_ACTIVITY_AWAY
))) {
416 status_id
= SIPE_STATUS_ID_AWAY
;
421 status_id
= SIPE_STATUS_ID_AVAILABLE
;
424 SIPE_DEBUG_INFO("sipe_buddy_status_from_activity: status_id(%s)", status_id
);
425 sipe_core_buddy_got_status(SIPE_CORE_PUBLIC
, uri
, status_id
);
427 sipe_core_buddy_got_status(SIPE_CORE_PUBLIC
, uri
, SIPE_STATUS_ID_OFFLINE
);
432 * Tries to figure out user first and last name
433 * based on Display Name and email properties.
435 * Allocates memory - must be g_free()'d
439 * First Last - Company Name
442 * Last, First (C)(STP) (Company)
443 * first.last@company.com (preprocessed as "first last")
444 * first.last.company.com@reuters.net (preprocessed as "first last company com")
447 * user@company.com (preprocessed as "user")
448 * first.m.last@company.com (preprocessed as "first m last")
449 * user.company.com@reuters.net (preprocessed as "user company com")
452 sipe_get_first_last_names(struct sipe_core_private
*sipe_private
,
457 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
458 sipe_backend_buddy p_buddy
;
461 const char *first
, *last
;
464 gboolean has_comma
= FALSE
;
466 if (!sip
|| !uri
) return;
468 p_buddy
= sipe_backend_buddy_find(SIPE_CORE_PUBLIC
, uri
, NULL
);
470 if (!p_buddy
) return;
472 display_name
= sipe_backend_buddy_get_alias(SIPE_CORE_PUBLIC
, p_buddy
);
473 email
= sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC
, p_buddy
, SIPE_BUDDY_INFO_EMAIL
);
475 if (!display_name
&& !email
) return;
477 /* if no display name, make "first last anything_else" out of email */
478 if (email
&& !display_name
) {
479 display_name
= g_strndup(email
, strstr(email
, "@") - email
);
480 display_name
= sipe_utils_str_replace((tmp
= display_name
), ".", " ");
485 has_comma
= (strstr(display_name
, ",") != NULL
);
486 display_name
= sipe_utils_str_replace((tmp
= display_name
), ", ", " ");
488 display_name
= sipe_utils_str_replace((tmp
= display_name
), ",", " ");
492 parts
= g_strsplit(display_name
, " ", 0);
494 if (!parts
[0] || !parts
[1]) {
496 g_free(display_name
);
510 *first_name
= g_strstrip(g_strdup(first
));
514 *last_name
= g_strstrip(g_strdup(last
));
518 g_free(display_name
);
523 * This method motivates Purple's Host (e.g. Pidgin) to update its UI
524 * by using standard Purple's means of signals and saved statuses.
526 * Thus all UI elements get updated: Status Button with Note, docklet.
527 * This is ablolutely important as both our status and note can come
528 * inbound (roaming) or be updated programmatically (e.g. based on our
531 void sipe_backend_account_status_and_note(struct sipe_core_private
*sipe_private
,
532 const gchar
*status_id
)
534 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
535 PurpleAccount
*account
= sip
->account
;
536 PurpleStatus
*status
= purple_account_get_active_status(account
);
537 const gchar
*message
= sip
->note
;
538 time_t *do_not_publish
= sip
->do_not_publish
;
539 gboolean changed
= TRUE
;
541 if (g_str_equal(status_id
, purple_status_get_id(status
)) &&
542 sipe_strequal(message
, purple_status_get_attr_string(status
, SIPE_STATUS_ATTR_ID_MESSAGE
)))
547 if (purple_savedstatus_is_idleaway()) {
552 PurpleSavedStatus
*saved_status
;
553 const PurpleStatusType
*acct_status_type
=
554 purple_status_type_find_with_id(account
->status_types
, status_id
);
555 PurpleStatusPrimitive primitive
= purple_status_type_get_primitive(acct_status_type
);
556 sipe_activity activity
= sipe_get_activity_by_token(status_id
);
558 saved_status
= purple_savedstatus_find_transient_by_type_and_message(primitive
, message
);
560 purple_savedstatus_set_substatus(saved_status
, account
, acct_status_type
, message
);
563 /* If this type+message is unique then create a new transient saved status
564 * Ref: gtkstatusbox.c
568 GList
*active_accts
= purple_accounts_get_all_active();
570 saved_status
= purple_savedstatus_new(NULL
, primitive
);
571 purple_savedstatus_set_message(saved_status
, message
);
573 for (tmp
= active_accts
; tmp
!= NULL
; tmp
= tmp
->next
) {
574 purple_savedstatus_set_substatus(saved_status
,
575 (PurpleAccount
*)tmp
->data
, acct_status_type
, message
);
577 g_list_free(active_accts
);
580 do_not_publish
[activity
] = time(NULL
);
581 SIPE_DEBUG_INFO("sipe_set_purple_account_status_and_note: do_not_publish[%s]=%d [now]",
582 status_id
, (int)do_not_publish
[activity
]);
584 /* Set the status for each account */
585 purple_savedstatus_activate(saved_status
);
589 /* IM Session (INVITE and MESSAGE methods) */
592 process_options_response(SIPE_UNUSED_PARAMETER
struct sipe_core_private
*sipe_private
,
594 SIPE_UNUSED_PARAMETER
struct transaction
*trans
)
598 if (msg
->response
!= 200) {
599 SIPE_DEBUG_INFO("process_options_response: OPTIONS response is %d", msg
->response
);
603 SIPE_DEBUG_INFO("process_options_response: body:\n%s", msg
->body
? msg
->body
: "");
609 * Asks UA/proxy about its capabilities.
611 static void sipe_options_request(struct sipe_core_private
*sipe_private
,
614 gchar
*to
= sip_uri(who
);
615 gchar
*contact
= get_contact(sipe_private
);
616 gchar
*request
= g_strdup_printf(
617 "Accept: application/sdp\r\n"
618 "Contact: %s\r\n", contact
);
621 sip_transport_request(sipe_private
,
628 process_options_response
);
635 sipe_convo_closed(PurpleConnection
* gc
, const char *who
)
637 struct sipe_core_private
*sipe_private
= PURPLE_GC_TO_SIPE_CORE_PRIVATE
;
639 SIPE_DEBUG_INFO("conversation with %s closed", who
);
640 sipe_session_close(sipe_private
,
641 sipe_session_find_im(sipe_private
, who
));
645 * Returns 2005-style activity and Availability.
647 * @param status Sipe statis id.
649 void sipe_get_act_avail_by_status_2005(const char *status
,
653 int avail
= 300; /* online */
654 int act
= 400; /* Available */
656 if (sipe_strequal(status
, SIPE_STATUS_ID_AWAY
)) {
658 //} else if (sipe_strequal(status, SIPE_STATUS_ID_LUNCH)) {
660 } else if (sipe_strequal(status
, SIPE_STATUS_ID_BRB
)) {
662 } else if (sipe_strequal(status
, SIPE_STATUS_ID_AVAILABLE
)) {
664 //} else if (sipe_strequal(status, SIPE_STATUS_ID_ON_PHONE)) {
666 } else if (sipe_strequal(status
, SIPE_STATUS_ID_BUSY
) ||
667 sipe_strequal(status
, SIPE_STATUS_ID_DND
)) {
669 } else if (sipe_strequal(status
, SIPE_STATUS_ID_INVISIBLE
) ||
670 sipe_strequal(status
, SIPE_STATUS_ID_OFFLINE
)) {
671 avail
= 0; /* offline */
674 act
= 400; /* Available */
677 if (activity
) *activity
= act
;
678 if (availability
) *availability
= avail
;
684 * @param activity 2005 aggregated activity. Ex.: 600
685 * @param availablity 2005 aggregated availablity. Ex.: 300
688 sipe_get_status_by_act_avail_2005(const int activity
,
689 const int availablity
,
690 char **activity_desc
)
692 const char *status_id
= NULL
;
693 const char *act
= NULL
;
695 if (activity
< 150) {
696 status_id
= SIPE_STATUS_ID_AWAY
;
697 } else if (activity
< 200) {
698 //status_id = SIPE_STATUS_ID_LUNCH;
699 status_id
= SIPE_STATUS_ID_AWAY
;
700 act
= sipe_activity_description(SIPE_ACTIVITY_LUNCH
);
701 } else if (activity
< 300) {
702 //status_id = SIPE_STATUS_ID_IDLE;
703 status_id
= SIPE_STATUS_ID_AWAY
;
704 act
= sipe_activity_description(SIPE_ACTIVITY_INACTIVE
);
705 } else if (activity
< 400) {
706 status_id
= SIPE_STATUS_ID_BRB
;
707 } else if (activity
< 500) {
708 status_id
= SIPE_STATUS_ID_AVAILABLE
;
709 } else if (activity
< 600) {
710 //status_id = SIPE_STATUS_ID_ON_PHONE;
711 status_id
= SIPE_STATUS_ID_BUSY
;
712 act
= sipe_activity_description(SIPE_ACTIVITY_ON_PHONE
);
713 } else if (activity
< 700) {
714 status_id
= SIPE_STATUS_ID_BUSY
;
715 } else if (activity
< 800) {
716 status_id
= SIPE_STATUS_ID_AWAY
;
718 status_id
= SIPE_STATUS_ID_AVAILABLE
;
721 if (availablity
< 100)
722 status_id
= SIPE_STATUS_ID_OFFLINE
;
724 if (activity_desc
&& act
) {
725 g_free(*activity_desc
);
726 *activity_desc
= g_strdup(act
);
733 * [MS-PRES] Table 3: Conversion of legacyInterop elements and attributes to MSRTC elements and attributes.
736 sipe_get_status_by_availability(int avail
,
737 gchar
**activity_desc
)
740 const char *act
= NULL
;
743 status
= SIPE_STATUS_ID_OFFLINE
;
744 } else if (avail
< 4500) {
745 status
= SIPE_STATUS_ID_AVAILABLE
;
746 } else if (avail
< 6000) {
747 //status = SIPE_STATUS_ID_IDLE;
748 status
= SIPE_STATUS_ID_AVAILABLE
;
749 act
= sipe_activity_description(SIPE_ACTIVITY_INACTIVE
);
750 } else if (avail
< 7500) {
751 status
= SIPE_STATUS_ID_BUSY
;
752 } else if (avail
< 9000) {
753 //status = SIPE_STATUS_ID_BUSYIDLE;
754 status
= SIPE_STATUS_ID_BUSY
;
755 act
= sipe_activity_description(SIPE_ACTIVITY_BUSYIDLE
);
756 } else if (avail
< 12000) {
757 status
= SIPE_STATUS_ID_DND
;
758 } else if (avail
< 15000) {
759 status
= SIPE_STATUS_ID_BRB
;
760 } else if (avail
< 18000) {
761 status
= SIPE_STATUS_ID_AWAY
;
763 status
= SIPE_STATUS_ID_OFFLINE
;
766 if (activity_desc
&& act
) {
767 g_free(*activity_desc
);
768 *activity_desc
= g_strdup(act
);
775 * Returns 2007-style availability value
777 * @param sipe_status_id (in)
778 * @param activity_token (out) Must be g_free()'d after use if consumed.
781 sipe_get_availability_by_status(const char* sipe_status_id
, char** activity_token
)
784 sipe_activity activity
= SIPE_ACTIVITY_UNSET
;
786 if (sipe_strequal(sipe_status_id
, SIPE_STATUS_ID_AWAY
)) {
787 availability
= 15500;
788 if (!activity_token
|| !(*activity_token
)) {
789 activity
= SIPE_ACTIVITY_AWAY
;
791 } else if (sipe_strequal(sipe_status_id
, SIPE_STATUS_ID_BRB
)) {
792 availability
= 12500;
793 activity
= SIPE_ACTIVITY_BRB
;
794 } else if (sipe_strequal(sipe_status_id
, SIPE_STATUS_ID_DND
)) {
796 activity
= SIPE_ACTIVITY_DND
;
797 } else if (sipe_strequal(sipe_status_id
, SIPE_STATUS_ID_BUSY
)) {
799 if (!activity_token
|| !(*activity_token
)) {
800 activity
= SIPE_ACTIVITY_BUSY
;
802 } else if (sipe_strequal(sipe_status_id
, SIPE_STATUS_ID_AVAILABLE
)) {
804 activity
= SIPE_ACTIVITY_ONLINE
;
805 } else if (sipe_strequal(sipe_status_id
, SIPE_STATUS_ID_UNKNOWN
)) {
808 // Offline or invisible
809 availability
= 18500;
810 activity
= SIPE_ACTIVITY_OFFLINE
;
813 if (activity_token
) {
814 *activity_token
= g_strdup(sipe_activity_to_token(activity
));
820 * Whether user manually changed status or
821 * it was changed automatically due to user
822 * became inactive/active again
825 sipe_is_user_state(struct sipe_core_private
*sipe_private
)
827 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
829 time_t now
= time(NULL
);
831 SIPE_DEBUG_INFO("sipe_is_user_state: sip->idle_switch : %s", asctime(localtime(&(sip
->idle_switch
))));
832 SIPE_DEBUG_INFO("sipe_is_user_state: now : %s", asctime(localtime(&now
)));
834 res
= ((now
- SIPE_IDLE_SET_DELAY
* 2) >= sip
->idle_switch
);
836 SIPE_DEBUG_INFO("sipe_is_user_state: res = %s", res
? "USER" : "MACHINE");
840 gboolean
sipe_is_user_available(struct sipe_core_private
*sipe_private
)
842 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
843 return(sipe_strequal(sip
->status
, SIPE_STATUS_ID_AVAILABLE
));
846 void send_presence_status(struct sipe_core_private
*sipe_private
,
847 SIPE_UNUSED_PARAMETER gpointer unused
)
849 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
850 PurpleStatus
* status
= purple_account_get_active_status(sip
->account
);
854 SIPE_DEBUG_INFO("send_presence_status: status: %s (%s)",
855 purple_status_get_id(status
) ? purple_status_get_id(status
) : "",
856 sipe_is_user_state(sipe_private
) ? "USER" : "MACHINE");
858 sipe_cal_presence_publish(sipe_private
, FALSE
);
861 /* temporary function */
862 void sipe_purple_setup(struct sipe_core_public
*sipe_public
,
863 PurpleConnection
*gc
)
865 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA
;
867 sip
->account
= purple_connection_get_account(gc
);
870 void sipe_core_reset_status(struct sipe_core_public
*sipe_public
)
872 struct sipe_core_private
*sipe_private
= SIPE_CORE_PRIVATE
;
873 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007
))
874 sipe_ocs2007_reset_status(sipe_private
);
876 sipe_ocs2005_reset_status(sipe_private
);
879 /** for Access levels menu */
880 #define INDENT_FMT " %s"
882 /** Member is indirectly belong to access level container.
883 * For example 'sameEnterprise' is in the container and user
884 * belongs to that same enterprise.
886 #define INDENT_MARKED_INHERITED_FMT "= %s"
889 purple_blist_add_buddy_clone(PurpleGroup
* group
, PurpleBuddy
* buddy
)
891 struct sipe_core_private
*sipe_private
= PURPLE_BUDDY_TO_SIPE_CORE_PRIVATE
;
893 gchar
*server_alias
, *email
;
894 const PurpleStatus
*status
= purple_presence_get_active_status(purple_buddy_get_presence(buddy
));
896 clone
= sipe_backend_buddy_add(SIPE_CORE_PUBLIC
,
901 server_alias
= sipe_backend_buddy_get_server_alias(SIPE_CORE_PUBLIC
,
904 sipe_backend_buddy_set_server_alias(SIPE_CORE_PUBLIC
,
907 g_free(server_alias
);
910 email
= sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC
,
912 SIPE_BUDDY_INFO_EMAIL
);
914 sipe_backend_buddy_set_string(SIPE_CORE_PUBLIC
,
916 SIPE_BUDDY_INFO_EMAIL
,
921 purple_presence_set_status_active(purple_buddy_get_presence(clone
),
922 purple_status_get_id(status
),
924 /* for UI to update */
925 sipe_backend_buddy_set_status(SIPE_CORE_PUBLIC
,
927 purple_status_get_id(status
));
933 sipe_buddy_menu_copy_to_cb(PurpleBlistNode
*node
, const char *group_name
)
935 PurpleBuddy
*buddy
, *b
;
936 PurpleGroup
* group
= purple_find_group(group_name
);
938 g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node
));
940 buddy
= (PurpleBuddy
*)node
;
942 SIPE_DEBUG_INFO("sipe_buddy_menu_copy_to_cb: copying %s to %s",
943 buddy
->name
, group_name
);
945 b
= purple_find_buddy_in_group(buddy
->account
, buddy
->name
, group
);
947 b
= purple_blist_add_buddy_clone(group
, buddy
);
950 PurpleConnection
*gc
= purple_account_get_connection(b
->account
);
952 sipe_core_buddy_add(PURPLE_GC_TO_SIPE_CORE_PUBLIC
,
959 sipe_buddy_menu_chat_new_cb(PurpleBuddy
*buddy
)
961 struct sipe_core_private
*sipe_private
= PURPLE_BUDDY_TO_SIPE_CORE_PRIVATE
;
963 SIPE_DEBUG_INFO("sipe_buddy_menu_chat_new_cb: buddy->name=%s", buddy
->name
);
965 /* 2007+ conference */
966 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007
))
968 sipe_conf_add(sipe_private
, buddy
->name
);
970 else /* 2005- multiparty chat */
972 gchar
*self
= sip_uri_self(sipe_private
);
973 struct sip_session
*session
;
975 session
= sipe_session_add_chat(sipe_private
,
979 session
->chat_session
->backend
= sipe_backend_chat_create(SIPE_CORE_PUBLIC
,
980 session
->chat_session
,
981 session
->chat_session
->title
,
985 sipe_im_invite(sipe_private
, session
, buddy
->name
, NULL
, NULL
, NULL
, FALSE
);
990 * For 2007+ conference only.
993 sipe_buddy_menu_chat_make_leader_cb(PurpleBuddy
*buddy
,
994 struct sipe_chat_session
*chat_session
)
996 struct sipe_core_private
*sipe_private
= PURPLE_BUDDY_TO_SIPE_CORE_PRIVATE
;
997 struct sip_session
*session
;
999 SIPE_DEBUG_INFO("sipe_buddy_menu_chat_make_leader_cb: buddy->name=%s", buddy
->name
);
1000 SIPE_DEBUG_INFO("sipe_buddy_menu_chat_make_leader_cb: chat_title=%s", chat_session
->title
);
1002 session
= sipe_session_find_chat(sipe_private
, chat_session
);
1004 sipe_conf_modify_user_role(sipe_private
, session
, buddy
->name
);
1008 * For 2007+ conference only.
1011 sipe_buddy_menu_chat_remove_cb(PurpleBuddy
*buddy
,
1012 struct sipe_chat_session
*chat_session
)
1014 struct sipe_core_private
*sipe_private
= PURPLE_BUDDY_TO_SIPE_CORE_PRIVATE
;
1015 struct sip_session
*session
;
1017 SIPE_DEBUG_INFO("sipe_buddy_menu_chat_remove_cb: buddy->name=%s", buddy
->name
);
1018 SIPE_DEBUG_INFO("sipe_buddy_menu_chat_remove_cb: chat_title=%s", chat_session
->title
);
1020 session
= sipe_session_find_chat(sipe_private
, chat_session
);
1022 sipe_conf_delete_user(sipe_private
, session
, buddy
->name
);
1026 sipe_buddy_menu_chat_invite_cb(PurpleBuddy
*buddy
,
1027 struct sipe_chat_session
*chat_session
)
1029 struct sipe_core_private
*sipe_private
= PURPLE_BUDDY_TO_SIPE_CORE_PRIVATE
;
1031 SIPE_DEBUG_INFO("sipe_buddy_menu_chat_invite_cb: buddy->name=%s", buddy
->name
);
1032 SIPE_DEBUG_INFO("sipe_buddy_menu_chat_invite_cb: chat_title=%s", chat_session
->title
);
1034 sipe_core_chat_invite(SIPE_CORE_PUBLIC
, chat_session
, buddy
->name
);
1038 sipe_buddy_menu_make_call_cb(PurpleBuddy
*buddy
, const char *phone
)
1040 struct sipe_core_private
*sipe_private
= PURPLE_BUDDY_TO_SIPE_CORE_PRIVATE
;
1042 SIPE_DEBUG_INFO("sipe_buddy_menu_make_call_cb: buddy->name=%s", buddy
->name
);
1044 char *tel_uri
= sip_to_tel_uri(phone
);
1046 SIPE_DEBUG_INFO("sipe_buddy_menu_make_call_cb: going to call number: %s", tel_uri
? tel_uri
: "");
1047 sip_csta_make_call(sipe_private
, tel_uri
);
1054 sipe_buddy_menu_access_level_help_cb(PurpleBuddy
*buddy
)
1056 /** Translators: replace with URL to localized page
1057 * If it doesn't exist copy the original URL */
1058 purple_notify_uri(buddy
->account
->gc
, _("https://sourceforge.net/apps/mediawiki/sipe/index.php?title=Access_Levels"));
1062 sipe_buddy_menu_send_email_cb(PurpleBuddy
*buddy
)
1064 struct sipe_core_private
*sipe_private
= PURPLE_BUDDY_TO_SIPE_CORE_PRIVATE
;
1066 SIPE_DEBUG_INFO("sipe_buddy_menu_send_email_cb: buddy->name=%s", buddy
->name
);
1068 email
= sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC
,
1070 SIPE_BUDDY_INFO_EMAIL
);
1073 char *command_line
= g_strdup_printf(
1079 " mailto:%s", email
);
1080 SIPE_DEBUG_INFO("sipe_buddy_menu_send_email_cb: going to call email client: %s", command_line
);
1083 g_spawn_command_line_async(command_line
, NULL
);
1084 g_free(command_line
);
1088 SIPE_DEBUG_INFO("sipe_buddy_menu_send_email_cb: no email address stored for buddy=%s", buddy
->name
);
1093 sipe_buddy_menu_access_level_cb(PurpleBuddy
*buddy
,
1094 struct sipe_container
*container
)
1096 struct sipe_core_private
*sipe_private
= PURPLE_BUDDY_TO_SIPE_CORE_PRIVATE
;
1097 sipe_ocs2007_change_access_level_from_container(sipe_private
,
1102 sipe_get_access_control_menu(struct sipe_core_private
*sipe_private
,
1106 * A menu which appear when right-clicking on buddy in contact list.
1109 sipe_buddy_menu(PurpleBuddy
*buddy
)
1111 PurpleBlistNode
*g_node
;
1112 PurpleGroup
*gr_parent
;
1113 PurpleMenuAction
*act
;
1115 GList
*menu_groups
= NULL
;
1116 struct sipe_core_private
*sipe_private
= PURPLE_BUDDY_TO_SIPE_CORE_PRIVATE
;
1117 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
1119 gchar
*self
= sip_uri_self(sipe_private
);
1121 SIPE_SESSION_FOREACH
{
1122 if (!sipe_strcase_equal(self
, buddy
->name
) && session
->chat_session
)
1124 struct sipe_chat_session
*chat_session
= session
->chat_session
;
1125 gboolean is_conf
= (chat_session
->type
== SIPE_CHAT_TYPE_CONFERENCE
);
1127 if (sipe_backend_chat_find(chat_session
->backend
, buddy
->name
))
1129 gboolean conf_op
= sipe_backend_chat_is_operator(chat_session
->backend
, self
);
1132 && !sipe_backend_chat_is_operator(chat_session
->backend
, buddy
->name
) /* Not conf OP */
1133 && conf_op
) /* We are a conf OP */
1135 gchar
*label
= g_strdup_printf(_("Make leader of '%s'"),
1136 chat_session
->title
);
1137 act
= purple_menu_action_new(label
,
1138 PURPLE_CALLBACK(sipe_buddy_menu_chat_make_leader_cb
),
1139 chat_session
, NULL
);
1141 menu
= g_list_prepend(menu
, act
);
1145 && conf_op
) /* We are a conf OP */
1147 gchar
*label
= g_strdup_printf(_("Remove from '%s'"),
1148 chat_session
->title
);
1149 act
= purple_menu_action_new(label
,
1150 PURPLE_CALLBACK(sipe_buddy_menu_chat_remove_cb
),
1151 chat_session
, NULL
);
1153 menu
= g_list_prepend(menu
, act
);
1159 || (is_conf
&& !session
->locked
))
1161 gchar
*label
= g_strdup_printf(_("Invite to '%s'"),
1162 chat_session
->title
);
1163 act
= purple_menu_action_new(label
,
1164 PURPLE_CALLBACK(sipe_buddy_menu_chat_invite_cb
),
1165 chat_session
, NULL
);
1167 menu
= g_list_prepend(menu
, act
);
1171 } SIPE_SESSION_FOREACH_END
;
1173 act
= purple_menu_action_new(_("New chat"),
1174 PURPLE_CALLBACK(sipe_buddy_menu_chat_new_cb
),
1176 menu
= g_list_prepend(menu
, act
);
1178 if (sip
->csta
&& !sip
->csta
->line_status
) {
1180 gchar
*phone_disp_str
;
1183 phone
= sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC
,
1185 SIPE_BUDDY_INFO_WORK_PHONE
);
1186 phone_disp_str
= sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC
,
1188 SIPE_BUDDY_INFO_WORK_PHONE_DISPLAY
);
1190 gchar
*label
= g_strdup_printf(_("Work %s"),
1191 phone_disp_str
? phone_disp_str
: (tmp
= sip_tel_uri_denormalize(phone
)));
1192 act
= purple_menu_action_new(label
, PURPLE_CALLBACK(sipe_buddy_menu_make_call_cb
), (gpointer
) phone
, NULL
);
1196 menu
= g_list_prepend(menu
, act
);
1199 g_free(phone_disp_str
);
1202 phone
= sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC
,
1204 SIPE_BUDDY_INFO_MOBILE_PHONE
);
1205 phone_disp_str
= sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC
,
1207 SIPE_BUDDY_INFO_MOBILE_PHONE_DISPLAY
);
1209 gchar
*label
= g_strdup_printf(_("Mobile %s"),
1210 phone_disp_str
? phone_disp_str
: (tmp
= sip_tel_uri_denormalize(phone
)));
1211 act
= purple_menu_action_new(label
, PURPLE_CALLBACK(sipe_buddy_menu_make_call_cb
), (gpointer
) phone
, NULL
);
1215 menu
= g_list_prepend(menu
, act
);
1218 g_free(phone_disp_str
);
1221 phone
= sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC
,
1223 SIPE_BUDDY_INFO_HOME_PHONE
);
1224 phone_disp_str
= sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC
,
1226 SIPE_BUDDY_INFO_HOME_PHONE_DISPLAY
);
1228 gchar
*label
= g_strdup_printf(_("Home %s"),
1229 phone_disp_str
? phone_disp_str
: (tmp
= sip_tel_uri_denormalize(phone
)));
1230 act
= purple_menu_action_new(label
, PURPLE_CALLBACK(sipe_buddy_menu_make_call_cb
), (gpointer
) phone
, NULL
);
1234 menu
= g_list_prepend(menu
, act
);
1237 g_free(phone_disp_str
);
1240 phone
= sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC
,
1242 SIPE_BUDDY_INFO_OTHER_PHONE
);
1243 phone_disp_str
= sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC
,
1245 SIPE_BUDDY_INFO_OTHER_PHONE_DISPLAY
);
1247 gchar
*label
= g_strdup_printf(_("Other %s"),
1248 phone_disp_str
? phone_disp_str
: (tmp
= sip_tel_uri_denormalize(phone
)));
1249 act
= purple_menu_action_new(label
, PURPLE_CALLBACK(sipe_buddy_menu_make_call_cb
), (gpointer
) phone
, NULL
);
1253 menu
= g_list_prepend(menu
, act
);
1256 g_free(phone_disp_str
);
1259 phone
= sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC
,
1261 SIPE_BUDDY_INFO_CUSTOM1_PHONE
);
1262 phone_disp_str
= sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC
,
1264 SIPE_BUDDY_INFO_CUSTOM1_PHONE_DISPLAY
);
1266 gchar
*label
= g_strdup_printf(_("Custom1 %s"),
1267 phone_disp_str
? phone_disp_str
: (tmp
= sip_tel_uri_denormalize(phone
)));
1268 act
= purple_menu_action_new(label
, PURPLE_CALLBACK(sipe_buddy_menu_make_call_cb
), (gpointer
) phone
, NULL
);
1272 menu
= g_list_prepend(menu
, act
);
1275 g_free(phone_disp_str
);
1278 email
= sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC
,
1280 SIPE_BUDDY_INFO_EMAIL
);
1282 act
= purple_menu_action_new(_("Send email..."),
1283 PURPLE_CALLBACK(sipe_buddy_menu_send_email_cb
),
1285 menu
= g_list_prepend(menu
, act
);
1290 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007
)) {
1291 GList
*menu_access_levels
= sipe_get_access_control_menu(sipe_private
, buddy
->name
);
1293 act
= purple_menu_action_new(_("Access level"),
1295 NULL
, menu_access_levels
);
1296 menu
= g_list_prepend(menu
, act
);
1300 gr_parent
= purple_buddy_get_group(buddy
);
1301 for (g_node
= purple_blist_get_root(); g_node
; g_node
= g_node
->next
) {
1304 if (g_node
->type
!= PURPLE_BLIST_GROUP_NODE
)
1307 group
= (PurpleGroup
*)g_node
;
1308 if (group
== gr_parent
)
1311 if (purple_find_buddy_in_group(buddy
->account
, buddy
->name
, group
))
1314 act
= purple_menu_action_new(purple_group_get_name(group
),
1315 PURPLE_CALLBACK(sipe_buddy_menu_copy_to_cb
),
1317 menu_groups
= g_list_prepend(menu_groups
, act
);
1319 /* Coverity complains about RESOURCE_LEAK here - no idea how to fix it */
1320 menu_groups
= g_list_reverse(menu_groups
);
1322 act
= purple_menu_action_new(_("Copy to"),
1325 menu
= g_list_prepend(menu
, act
);
1327 menu
= g_list_reverse(menu
);
1334 sipe_ask_access_domain_cb(PurpleConnection
*gc
, PurpleRequestFields
*fields
)
1336 struct sipe_core_private
*sipe_private
= PURPLE_GC_TO_SIPE_CORE_PRIVATE
;
1337 const char *domain
= purple_request_fields_get_string(fields
, "access_domain");
1338 guint index
= purple_request_fields_get_choice(fields
, "container_id");
1339 sipe_ocs2007_change_access_level_for_domain(sipe_private
,
1345 sipe_ask_access_domain(struct sipe_core_private
*sipe_private
)
1347 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
1348 PurpleAccount
*account
= sip
->account
;
1349 PurpleConnection
*gc
= sip
->gc
;
1350 PurpleRequestFields
*fields
;
1351 PurpleRequestFieldGroup
*g
;
1352 PurpleRequestField
*f
;
1354 fields
= purple_request_fields_new();
1356 g
= purple_request_field_group_new(NULL
);
1357 f
= purple_request_field_string_new("access_domain", _("Domain"), "partner-company.com", FALSE
);
1358 purple_request_field_set_required(f
, TRUE
);
1359 purple_request_field_group_add_field(g
, f
);
1361 f
= purple_request_field_choice_new("container_id", _("Access level"), 0);
1362 purple_request_field_choice_add(f
, _("Personal")); /* index 0 */
1363 purple_request_field_choice_add(f
, _("Team"));
1364 purple_request_field_choice_add(f
, _("Company"));
1365 purple_request_field_choice_add(f
, _("Public"));
1366 purple_request_field_choice_add(f
, _("Blocked")); /* index 4 */
1367 purple_request_field_choice_set_default_value(f
, 3); /* index */
1368 purple_request_field_set_required(f
, TRUE
);
1369 purple_request_field_group_add_field(g
, f
);
1371 purple_request_fields_add_group(fields
, g
);
1373 purple_request_fields(gc
, _("Add new domain"),
1374 _("Add new domain"), NULL
, fields
,
1375 _("Add"), G_CALLBACK(sipe_ask_access_domain_cb
),
1377 account
, NULL
, NULL
, gc
);
1381 sipe_buddy_menu_access_level_add_domain_cb(PurpleBuddy
*buddy
)
1383 sipe_ask_access_domain(PURPLE_BUDDY_TO_SIPE_CORE_PRIVATE
);
1387 * Workaround for missing libpurple API to release resources allocated
1388 * during blist_node_menu() callback. See also:
1390 * <http://developer.pidgin.im/ticket/12597>
1392 * We remember all memory blocks in a list and deallocate them when
1394 * - the next time we enter the callback, or
1395 * - the account is disconnected
1397 * That means that after the buddy menu has been closed we have unused
1398 * resources but at least we don't leak them anymore...
1400 void sipe_blist_menu_free_containers(struct sipe_core_private
*sipe_private
)
1402 GSList
*entry
= sipe_private
->blist_menu_containers
;
1404 sipe_ocs2007_free_container(entry
->data
);
1405 entry
= entry
->next
;
1407 g_slist_free(sipe_private
->blist_menu_containers
);
1408 sipe_private
->blist_menu_containers
= NULL
;
1412 sipe_blist_menu_remember_container(struct sipe_core_private
*sipe_private
,
1413 struct sipe_container
*container
)
1415 sipe_private
->blist_menu_containers
= g_slist_prepend(sipe_private
->blist_menu_containers
,
1420 sipe_get_access_levels_menu(struct sipe_core_private
*sipe_private
,
1421 const char* member_type
,
1422 const char* member_value
,
1423 const gboolean extra_menu
)
1425 GList
*menu_access_levels
= NULL
;
1428 PurpleMenuAction
*act
;
1429 struct sipe_container
*container
;
1430 gboolean is_group_access
= FALSE
;
1431 int container_id
= sipe_ocs2007_find_access_level(sipe_private
,
1435 guint container_max
= sipe_ocs2007_containers();
1437 for (i
= 1; i
<= container_max
; i
++) {
1438 /* to put Blocked level last in menu list.
1439 * Blocked should remaim in the first place in the containers[] array.
1441 unsigned int j
= (i
== container_max
) ? 0 : i
;
1442 int container_j
= sipe_ocs2007_container_id(j
);
1443 const gchar
*acc_level_name
= sipe_ocs2007_access_level_name(container_j
);
1445 container
= sipe_ocs2007_create_container(j
,
1450 /* libpurple memory leak workaround */
1451 sipe_blist_menu_remember_container(sipe_private
, container
);
1453 /* current container/access level */
1454 if (container_j
== container_id
) {
1455 menu_name
= is_group_access
?
1456 g_strdup_printf(INDENT_MARKED_INHERITED_FMT
, acc_level_name
) :
1457 g_strdup_printf(SIPE_OCS2007_INDENT_MARKED_FMT
, acc_level_name
);
1459 menu_name
= g_strdup_printf(INDENT_FMT
, acc_level_name
);
1462 act
= purple_menu_action_new(menu_name
,
1463 PURPLE_CALLBACK(sipe_buddy_menu_access_level_cb
),
1466 menu_access_levels
= g_list_prepend(menu_access_levels
, act
);
1469 if (extra_menu
&& (container_id
>= 0)) {
1471 act
= purple_menu_action_new(" --------------", NULL
, NULL
, NULL
);
1472 menu_access_levels
= g_list_prepend(menu_access_levels
, act
);
1474 if (!is_group_access
) {
1475 container
= sipe_ocs2007_create_container(0,
1480 /* libpurple memory leak workaround */
1481 sipe_blist_menu_remember_container(sipe_private
, container
);
1483 /* Translators: remove (clear) previously assigned access level */
1484 menu_name
= g_strdup_printf(INDENT_FMT
, _("Unspecify"));
1485 act
= purple_menu_action_new(menu_name
,
1486 PURPLE_CALLBACK(sipe_buddy_menu_access_level_cb
),
1489 menu_access_levels
= g_list_prepend(menu_access_levels
, act
);
1493 menu_access_levels
= g_list_reverse(menu_access_levels
);
1494 return menu_access_levels
;
1498 sipe_get_access_groups_menu(struct sipe_core_private
*sipe_private
)
1500 GList
*menu_access_groups
= NULL
;
1501 PurpleMenuAction
*act
;
1502 GSList
*access_domains
;
1505 act
= purple_menu_action_new(_("People in my company"),
1507 NULL
, sipe_get_access_levels_menu(sipe_private
, "sameEnterprise", NULL
, FALSE
));
1508 menu_access_groups
= g_list_prepend(menu_access_groups
, act
);
1510 /* this is original name, don't edit */
1511 act
= purple_menu_action_new(_("People in domains connected with my company"),
1513 NULL
, sipe_get_access_levels_menu(sipe_private
, "federated", NULL
, FALSE
));
1514 menu_access_groups
= g_list_prepend(menu_access_groups
, act
);
1516 act
= purple_menu_action_new(_("People in public domains"),
1518 NULL
, sipe_get_access_levels_menu(sipe_private
, "publicCloud", NULL
, TRUE
));
1519 menu_access_groups
= g_list_prepend(menu_access_groups
, act
);
1521 access_domains
= sipe_ocs2007_get_access_domains(sipe_private
);
1522 entry
= access_domains
;
1524 gchar
*domain
= entry
->data
;
1525 gchar
*menu_name
= g_strdup_printf(_("People at %s"), domain
);
1527 /* takes over ownership of entry->data (= domain) */
1528 act
= purple_menu_action_new(menu_name
,
1530 NULL
, sipe_get_access_levels_menu(sipe_private
, "domain", domain
, TRUE
));
1531 menu_access_groups
= g_list_prepend(menu_access_groups
, act
);
1534 entry
= entry
->next
;
1536 g_slist_free(access_domains
);
1539 /* People in domains connected with my company */
1540 act
= purple_menu_action_new("-------------------------------------------", NULL
, NULL
, NULL
);
1541 menu_access_groups
= g_list_prepend(menu_access_groups
, act
);
1543 act
= purple_menu_action_new(_("Add new domain..."),
1544 PURPLE_CALLBACK(sipe_buddy_menu_access_level_add_domain_cb
),
1546 menu_access_groups
= g_list_prepend(menu_access_groups
, act
);
1548 menu_access_groups
= g_list_reverse(menu_access_groups
);
1550 return menu_access_groups
;
1554 sipe_get_access_control_menu(struct sipe_core_private
*sipe_private
,
1557 GList
*menu_access_levels
= NULL
;
1558 GList
*menu_access_groups
= NULL
;
1560 PurpleMenuAction
*act
;
1562 /* libpurple memory leak workaround */
1563 sipe_blist_menu_free_containers(sipe_private
);
1565 menu_access_levels
= sipe_get_access_levels_menu(sipe_private
, "user", sipe_get_no_sip_uri(uri
), TRUE
);
1567 menu_access_groups
= sipe_get_access_groups_menu(sipe_private
);
1569 menu_name
= g_strdup_printf(INDENT_FMT
, _("Access groups"));
1570 act
= purple_menu_action_new(menu_name
,
1572 NULL
, menu_access_groups
);
1574 menu_access_levels
= g_list_append(menu_access_levels
, act
);
1576 menu_name
= g_strdup_printf(INDENT_FMT
, _("Online help..."));
1577 act
= purple_menu_action_new(menu_name
,
1578 PURPLE_CALLBACK(sipe_buddy_menu_access_level_help_cb
),
1581 menu_access_levels
= g_list_append(menu_access_levels
, act
);
1583 return menu_access_levels
;
1587 process_get_info_response(struct sipe_core_private
*sipe_private
,
1588 struct sipmsg
*msg
, struct transaction
*trans
)
1590 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
1591 char *uri
= trans
->payload
->data
;
1593 PurpleNotifyUserInfo
*info
;
1594 PurpleBuddy
*pbuddy
= NULL
;
1595 struct sipe_buddy
*sbuddy
;
1596 const char *alias
= NULL
;
1597 char *device_name
= NULL
;
1598 char *server_alias
= NULL
;
1599 char *phone_number
= NULL
;
1602 char *first_name
= NULL
;
1603 char *last_name
= NULL
;
1605 if (!sip
) return FALSE
;
1607 SIPE_DEBUG_INFO("Fetching %s's user info for %s", uri
, sipe_private
->username
);
1609 pbuddy
= purple_find_buddy((PurpleAccount
*)sip
->account
, uri
);
1610 alias
= purple_buddy_get_local_alias(pbuddy
);
1612 //will query buddy UA's capabilities and send answer to log
1613 sipe_options_request(sipe_private
, uri
);
1615 sbuddy
= g_hash_table_lookup(sipe_private
->buddies
, uri
);
1617 device_name
= sbuddy
->device_name
? g_strdup(sbuddy
->device_name
) : NULL
;
1620 info
= purple_notify_user_info_new();
1622 if (msg
->response
!= 200) {
1623 SIPE_DEBUG_INFO("process_get_info_response: SERVICE response is %d", msg
->response
);
1625 sipe_xml
*searchResults
;
1626 const sipe_xml
*mrow
;
1628 SIPE_DEBUG_INFO("process_get_info_response: body:\n%s", msg
->body
? msg
->body
: "");
1629 searchResults
= sipe_xml_parse(msg
->body
, msg
->bodylen
);
1630 if (!searchResults
) {
1631 SIPE_DEBUG_INFO_NOFORMAT("process_get_info_response: no parseable searchResults");
1632 } else if ((mrow
= sipe_xml_child(searchResults
, "Body/Array/row"))) {
1634 server_alias
= g_strdup(sipe_xml_attribute(mrow
, "displayName"));
1635 email
= g_strdup(sipe_xml_attribute(mrow
, "email"));
1636 phone_number
= g_strdup(sipe_xml_attribute(mrow
, "phone"));
1638 /* For 2007 system we will take this from ContactCard -
1639 * it has cleaner tel: URIs at least
1641 if (!SIPE_CORE_PRIVATE_FLAG_IS(OCS2007
)) {
1642 char *tel_uri
= sip_to_tel_uri(phone_number
);
1643 /* trims its parameters, so call first */
1644 sipe_buddy_update_property(sipe_private
, uri
, SIPE_BUDDY_INFO_DISPLAY_NAME
, server_alias
);
1645 sipe_buddy_update_property(sipe_private
, uri
, SIPE_BUDDY_INFO_EMAIL
, email
);
1646 sipe_buddy_update_property(sipe_private
, uri
, SIPE_BUDDY_INFO_WORK_PHONE
, tel_uri
);
1647 sipe_buddy_update_property(sipe_private
, uri
, SIPE_BUDDY_INFO_WORK_PHONE_DISPLAY
, phone_number
);
1651 #if PURPLE_VERSION_CHECK(3,0,0)
1652 #define PURPLE_NOTIFY_USER_INFO_ADD_PAIR purple_notify_user_info_add_pair_html
1654 #define PURPLE_NOTIFY_USER_INFO_ADD_PAIR purple_notify_user_info_add_pair
1657 if (server_alias
&& strlen(server_alias
) > 0) {
1658 PURPLE_NOTIFY_USER_INFO_ADD_PAIR(info
, _("Display name"), server_alias
);
1660 if ((value
= sipe_xml_attribute(mrow
, "title")) && strlen(value
) > 0) {
1661 PURPLE_NOTIFY_USER_INFO_ADD_PAIR(info
, _("Job title"), value
);
1663 if ((value
= sipe_xml_attribute(mrow
, "office")) && strlen(value
) > 0) {
1664 PURPLE_NOTIFY_USER_INFO_ADD_PAIR(info
, _("Office"), value
);
1666 if (phone_number
&& strlen(phone_number
) > 0) {
1667 PURPLE_NOTIFY_USER_INFO_ADD_PAIR(info
, _("Business phone"), phone_number
);
1669 if ((value
= sipe_xml_attribute(mrow
, "company")) && strlen(value
) > 0) {
1670 PURPLE_NOTIFY_USER_INFO_ADD_PAIR(info
, _("Company"), value
);
1672 if ((value
= sipe_xml_attribute(mrow
, "city")) && strlen(value
) > 0) {
1673 PURPLE_NOTIFY_USER_INFO_ADD_PAIR(info
, _("City"), value
);
1675 if ((value
= sipe_xml_attribute(mrow
, "state")) && strlen(value
) > 0) {
1676 PURPLE_NOTIFY_USER_INFO_ADD_PAIR(info
, _("State"), value
);
1678 if ((value
= sipe_xml_attribute(mrow
, "country")) && strlen(value
) > 0) {
1679 PURPLE_NOTIFY_USER_INFO_ADD_PAIR(info
, _("Country"), value
);
1681 if (email
&& strlen(email
) > 0) {
1682 PURPLE_NOTIFY_USER_INFO_ADD_PAIR(info
, _("Email address"), email
);
1686 sipe_xml_free(searchResults
);
1689 purple_notify_user_info_add_section_break(info
);
1691 if (is_empty(server_alias
)) {
1692 g_free(server_alias
);
1693 server_alias
= sipe_backend_buddy_get_server_alias(SIPE_CORE_PUBLIC
,
1696 PURPLE_NOTIFY_USER_INFO_ADD_PAIR(info
, _("Display name"), server_alias
);
1700 /* present alias if it differs from server alias */
1701 if (alias
&& !sipe_strequal(alias
, server_alias
))
1703 PURPLE_NOTIFY_USER_INFO_ADD_PAIR(info
, _("Alias"), alias
);
1706 if (is_empty(email
)) {
1708 email
= sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC
,
1710 SIPE_BUDDY_INFO_EMAIL
);
1712 PURPLE_NOTIFY_USER_INFO_ADD_PAIR(info
, _("Email address"), email
);
1716 site
= sipe_backend_buddy_get_string(SIPE_CORE_PUBLIC
,
1718 SIPE_BUDDY_INFO_SITE
);
1720 PURPLE_NOTIFY_USER_INFO_ADD_PAIR(info
, _("Site"), site
);
1724 sipe_get_first_last_names(sipe_private
, uri
, &first_name
, &last_name
);
1725 if (first_name
&& last_name
) {
1726 char *link
= g_strconcat("http://www.linkedin.com/pub/dir/", first_name
, "/", last_name
, NULL
);
1728 PURPLE_NOTIFY_USER_INFO_ADD_PAIR(info
, _("Find on LinkedIn"), link
);
1735 PURPLE_NOTIFY_USER_INFO_ADD_PAIR(info
, _("Device"), device_name
);
1738 /* show a buddy's user info in a nice dialog box */
1739 purple_notify_userinfo(sip
->gc
, /* connection the buddy info came through */
1740 uri
, /* buddy's URI */
1742 NULL
, /* callback called when dialog closed */
1743 NULL
); /* userdata for callback */
1745 g_free(phone_number
);
1746 g_free(server_alias
);
1748 g_free(device_name
);
1753 #define SIPE_SOAP_SEARCH_ROW "<m:row m:attrib=\"%s\" m:value=\"%s\"/>"
1756 * AD search first, LDAP based
1758 void sipe_get_info(PurpleConnection
*gc
, const char *username
)
1760 struct sipe_core_private
*sipe_private
= PURPLE_GC_TO_SIPE_CORE_PRIVATE
;
1761 char *row
= g_markup_printf_escaped(SIPE_SOAP_SEARCH_ROW
, "msRTCSIP-PrimaryUserAddress", username
);
1762 struct transaction_payload
*payload
= g_new0(struct transaction_payload
, 1);
1764 payload
->destroy
= g_free
;
1765 payload
->data
= g_strdup(username
);
1767 SIPE_DEBUG_INFO("sipe_get_info: row: %s", row
? row
: "");
1768 sip_soap_directory_search(sipe_private
,
1771 process_get_info_response
,