url = git://git.linphone.org/ortp.git
[submodule "mediastreamer2"]
path = mediastreamer2
- url = gitosis@git.linphone.org:mediastreamer2-private.git
+ url = git://git.linphone.org/mediastreamer2.git
#a zip containing win32 binaries, suitable to generate an installer
+if BUILD_ZRTP
+WINBINDIST_FILES+=./bin/libzrtpcpp.dll ./bin/msys-1.0.dll ./bin/msys-crypto-1.0.0.dll
+endif
+
other-cherrypick:
cd $(GTK_PREFIX) && \
for file in $(WINBINDIST_FILES) ; do \
/mingw/bin/libstdc++-6.dll \
/mingw/bin/libintl-8.dll \
/mingw/bin/libiconv-2.dll \
- /mingw/bin/libpthread-2.dll \
+ /mingw/bin/pthreadGC2.dll \
$(INSTALLDIR_WITH_PREFIX)/bin/.
make install DESTDIR=$(INSTALLDIR)
LINPHONE_INSTALL_PREFIX=$(INSTALLDIR_WITH_PREFIX) \
LIBLINPHONE_INSTALL_PREFIX=$(INSTALLDIR_WITH_PREFIX) \
- ige-mac-bundler $(PACKAGE_BUNDLE_FILE)
+ gtk-mac-bundler $(PACKAGE_BUNDLE_FILE)
printf "[Pango]\nModuleFiles=./etc/pango/pango.modules\n" \
> $(BUNDLEDIR)/Contents/Resources/etc/pango/pangorc
cp -f $(LIBICONV_HACK) $(BUNDLEDIR)/Contents/Resources/lib/.
$ sudo make install
When this version will be integrated into macports, only this will be necessary:
- $ port install sdl-devel
+ $ port install libsdl-devel
- Install gtk. It is recommended to use the quartz backend for better integration.
$ port install cairo +quartz +no_x11
Done.
-If you want to generate a portable bundle, then install ige-mac-bundler.
-The macport package of ige-mac-bundler doesn't work at all.
+If you want to generate a portable bundle, then install gtk-mac-bundler.
Use git:
- $ git clone https://github.com/jralls/ige-mac-bundler.git
- $ cd ige-mac-bundler && make install
+ $ git clone https://github.com/jralls/gtk-mac-bundler.git
+ $ cd gtk-mac-bundler && make install
$ export PATH=$PATH:~/.local/bin
Then run, inside linphone source tree:
mingw-get install msys-zip
mingw-get install msys-unzip
mingw-get install msys-wget
+mingw-get install msys-libopenssl
mkdir -p /opt/perl/bin
cp /bin/perl /opt/perl/bin/.
rm /lib/libintl.dll.a
rm /lib/libintl.la
rm /lib/libintl.a
-rm /include/intl.h
+rm /include/libintl.h
* Download and install Inno Setup Compiler (required only if you run 'make setup.exe'). Add it to your windows Path environment variable.
LOCAL_CFLAGS += -DHAVE_X264
endif
endif
+
LOCAL_C_INCLUDES += \
$(LOCAL_PATH) \
$(LOCAL_PATH)/include \
libopencoreamr
endif
+ifeq ($(BUILD_SILK),1)
+LOCAL_CFLAGS += -DHAVE_SILK
+LOCAL_STATIC_LIBRARIES += libmssilk
+endif
+
ifeq ($(LINPHONE_VIDEO),1)
LOCAL_LDLIBS += -lGLESv2
LOCAL_STATIC_LIBRARIES += libvpx
dnl Process this file with autoconf to produce a configure script.
-AC_INIT([linphone],[3.4.99.2],[linphone-developers@nongnu.org])
+AC_INIT([linphone],[3.4.99.4],[linphone-developers@nongnu.org])
AC_CANONICAL_SYSTEM
AC_CONFIG_SRCDIR([coreapi/linphonecore.c])
*) AC_MSG_ERROR(bad value ${enableval} for --enable-alsa) ;;
esac],[alsa=true])
-AC_ARG_ENABLE(artsc,
- [ --enable-artsc Turn on artsc (kde) sound input/output (auto) ],
+AC_ARG_ENABLE(zrtp,
+ [ --enable-zrtp Turn on zrtp support - UNFINISHED],
[case "${enableval}" in
- yes) artsc=true ;;
- no) artsc=false ;;
- *) AC_MSG_ERROR(bad value ${enableval} for --enable-artsc) ;;
- esac],[artsc=false])
+ yes) zrtp=true ;;
+ no) zrtp=false ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-zrtp) ;;
+ esac],[zrtp=false])
+
AC_ARG_ENABLE(portaudio,
[ --enable-portaudio Turn on portaudio native support compiling],
dnl compilation of gtk user interface
AM_CONDITIONAL(BUILD_GTK_UI, [test x$gtk_ui = xtrue ] )
AM_CONDITIONAL(BUILD_WIN32, test x$mingw_found = xyes )
+AM_CONDITIONAL(BUILD_ZRTP, test x$zrtp = xtrue)
dnl check getenv
AH_TEMPLATE([HAVE_GETENV])
static int lpc_cmd_identify(LinphoneCore *lc, char *args);
static int lpc_cmd_ringback(LinphoneCore *lc, char *args);
static int lpc_cmd_conference(LinphoneCore *lc, char *args);
+static int lpc_cmd_zrtp_verified(LinphoneCore *lc, char *args);
/* Command handler helpers */
static void linphonec_proxy_add(LinphoneCore *lc);
{ "redirect", lpc_cmd_redirect, "Redirect an incoming call",
"'redirect <redirect-uri>'\t: Redirect all pending incoming calls to the <redirect-uri>\n"
},
+ { "zrtp-set-verified", lpc_cmd_zrtp_verified,"Set ZRTP SAS verified.",
+ "'Set ZRTP SAS verified'\n"
+ },
{ NULL,NULL,NULL,NULL}
};
return 1;
}
+static int lpc_cmd_zrtp_verified(LinphoneCore *lc, char *args){
+ LinphoneCall *call=linphone_core_get_current_call(lc);
+ if (linphone_call_params_get_media_encryption(linphone_call_get_current_params(call))==LinphoneMediaEncryptionZRTP){
+ linphone_call_set_authentication_token_verified(call,TRUE);
+ }
+ return 1;
+}
+
/***************************************************************************
*
* Command table management funx
static int trace_level = 0;
static char *logfile_name = NULL;
static char configfile_name[PATH_MAX];
+static char zrtpsecrets[PATH_MAX];
static const char *factory_configfile_name=NULL;
static char *sip_addr_to_call = NULL; /* for autocall */
static int window_id = 0; /* 0=standalone window, or window id for embedding video */
#ifndef _WIN32
snprintf(configfile_name, PATH_MAX, "%s/.linphonerc",
getenv("HOME"));
+ snprintf(zrtpsecrets, PATH_MAX, "%s/.linphone-zidcache",
+ getenv("HOME"));
#elif defined(_WIN32_WCE)
strncpy(configfile_name,PACKAGE_DIR "\\linphonerc",PATH_MAX);
mylogfile=fopen(PACKAGE_DIR "\\" "linphonec.log","w");
#else
snprintf(configfile_name, PATH_MAX, "%s/Linphone/linphonerc",
getenv("APPDATA"));
+ snprintf(zrtpsecrets, PATH_MAX, "%s/Linphone/linphone-zidcache",
+ getenv("APPDATA"));
#endif
/* Handle configuration filename changes */
switch (handle_configfile_migration())
* Initialize linphone core
*/
linphonec=linphone_core_new (&linphonec_vtable, configfile_name, factory_configfile_name, NULL);
+ linphone_core_set_zrtp_secrets_file(linphonec,zrtpsecrets);
linphone_core_enable_video(linphonec,vcap_enabled,display_enabled);
if (display_enabled && window_id != 0)
{
}
#endif
+static bool_t already_a_call_with_remote_address(const LinphoneCore *lc, const LinphoneAddress *remote) {
+ ms_warning(" searching for already_a_call_with_remote_address.");
+
+ MSList *elem;
+ for(elem=lc->calls;elem!=NULL;elem=elem->next){
+ const LinphoneCall *call=(LinphoneCall*)elem->data;
+ const LinphoneAddress *cRemote=linphone_call_get_remote_address(call);
+ if (linphone_address_weak_equal(cRemote,remote)) {
+ ms_warning("already_a_call_with_remote_address found.");
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
static bool_t already_a_call_pending(LinphoneCore *lc){
MSList *elem;
for(elem=lc->calls;elem!=NULL;elem=elem->next){
LinphoneAddress *from_addr, *to_addr;
SalMediaDescription *md;
bool_t propose_early_media=lp_config_get_int(lc->config,"sip","incoming_calls_early_media",FALSE);
+ bool_t prevent_colliding_calls=lp_config_get_int(lc->config,"sip","prevent_colliding_calls",TRUE);
const char *ringback_tone=linphone_core_get_remote_ringback_tone (lc);
/* first check if we can answer successfully to this invite */
from_addr=linphone_address_new(from);
to_addr=linphone_address_new(to);
- if (already_a_call_pending(lc)){
+ if ((already_a_call_with_remote_address(lc,from_addr) && prevent_colliding_calls) || already_a_call_pending(lc)){
ms_warning("Receiving another call while one is ringing or initiated, refusing this one with busy message.");
sal_call_decline(h,SalReasonBusy,NULL);
sal_op_release(h);
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
LinphoneCallState prevstate=LinphoneCallIdle;
SalMediaDescription *md;
+ SalMediaDescription *old_md=call->resultdesc;
+
+ sal_media_description_ref(old_md);
md=sal_call_get_final_media_description(op);
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We are being paused..."));
linphone_call_set_state (call,LinphoneCallPausedByRemote,"Call paused by remote");
- }else if (!sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv) && sal_media_description_has_dir(md,SalStreamSendRecv)){
+ }else if (!sal_media_description_has_dir(old_md,SalStreamSendRecv) && sal_media_description_has_dir(md,SalStreamSendRecv)){
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We have been resumed..."));
linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
- if (!call->current_params.in_conference)
- lc->current_call=call;
}else{
prevstate=call->state;
if(lc->vtable.display_status)
linphone_call_set_state (call,prevstate,"Connected (streams running)");
}
}
+ sal_media_description_unref(old_md);
}
static void call_terminated(SalOp *op, const char *from){
lc->vtable.display_status(lc,msg600);
break;
case SalReasonMedia:
+ //media_encryption_mandatory
+ if (call->params.media_encryption == LinphoneMediaEncryptionSRTP &&
+ !linphone_core_is_media_encryption_mandatory(lc)) {
+ int i;
+ ms_message("Outgoing call failed with SRTP (SAVP) enabled - retrying with AVP");
+ linphone_call_stop_media_streams(call);
+ /* clear SRTP local params */
+ call->params.media_encryption = LinphoneMediaEncryptionNone;
+ for(i=0; i<call->localdesc->nstreams; i++) {
+ call->localdesc->streams[i].proto = SalProtoRtpAvp;
+ memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
+ }
+ linphone_core_start_invite(lc, call, NULL);
+ return;
+ }
msg=_("No common codecs");
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg);
conference_check_init(&lc->conf_ctx);
call->params.in_conference=TRUE;
call->params.has_video=FALSE;
+ call->params.media_encryption=LinphoneMediaEncryptionNone;
params=call->params;
if (call->state==LinphoneCallPaused)
linphone_core_resume_call(lc,call);
int linphone_core_enter_conference(LinphoneCore *lc){
+ if (linphone_core_sound_resources_locked(lc)) {
+ return -1;
+ }
LinphoneConference *conf=&lc->conf_ctx;
if (conf->local_participant==NULL) add_local_endpoint(conf,lc);
return 0;
}
username=linphone_address_get_username(puri);
domain=linphone_address_get_domain(puri);
+ if (domain==NULL) {
+ linphone_address_destroy(puri);
+ return NULL;
+ }
for(elem=lc->friends;elem!=NULL;elem=ms_list_next(elem)){
lf=(LinphoneFriend*)elem->data;
const char *it_username=linphone_address_get_username(lf->uri);
#include "lpconfig.h"
#include "private.h"
#include <ortp/event.h>
+#include <ortp/b64.h>
#include "mediastreamer2/mediastream.h"
}
#endif
+static bool_t generate_b64_crypto_key(int key_length, char* key_out) {
+ int b64_size;
+ uint8_t* tmp = (uint8_t*) malloc(key_length);
+ if (ortp_crypto_get_random(tmp, key_length)!=0) {
+ ms_error("Failed to generate random key");
+ free(tmp);
+ return FALSE;
+ }
+
+ b64_size = b64_encode((const char*)tmp, key_length, NULL, 0);
+ if (b64_size == 0) {
+ ms_error("Failed to b64 encode key");
+ free(tmp);
+ return FALSE;
+ }
+ key_out[b64_size] = '\0';
+ b64_encode((const char*)tmp, key_length, key_out, 40);
+ free(tmp);
+ return TRUE;
+}
+
LinphoneCore *linphone_call_get_core(const LinphoneCall *call){
return call->core;
}
bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){
return call->auth_token_verified;
}
-bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call) {
+
+static bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call) {
// Check ZRTP encryption in audiostream
if (!call->audiostream_encrypted) {
return FALSE;
}
void propagate_encryption_changed(LinphoneCall *call){
- if (call->core->vtable.call_encryption_changed == NULL) return;
-
+ LinphoneCore *lc=call->core;
if (!linphone_call_are_all_streams_encrypted(call)) {
ms_message("Some streams are not encrypted");
- call->core->vtable.call_encryption_changed(call->core, call, FALSE, call->auth_token);
+ call->current_params.media_encryption=LinphoneMediaEncryptionNone;
+ if (lc->vtable.call_encryption_changed)
+ lc->vtable.call_encryption_changed(call->core, call, FALSE, call->auth_token);
} else {
ms_message("All streams are encrypted");
- call->core->vtable.call_encryption_changed(call->core, call, TRUE, call->auth_token);
+ call->current_params.media_encryption=LinphoneMediaEncryptionZRTP;
+ if (lc->vtable.call_encryption_changed)
+ lc->vtable.call_encryption_changed(call->core, call, TRUE, call->auth_token);
}
}
LinphoneCall *call = (LinphoneCall *)data;
call->audiostream_encrypted=encrypted;
-
+
if (encrypted && call->core->vtable.display_status != NULL) {
snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token);
call->core->vtable.display_status(call->core, status);
ms_message("Authentication token is %s (%s)", auth_token, verified?"verified":"unverified");
}
+void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified){
+ if (call->audiostream==NULL){
+ ms_error("linphone_call_set_authentication_token_verified(): No audio stream");
+ }
+ if (call->audiostream->ortpZrtpContext==NULL){
+ ms_error("linphone_call_set_authentication_token_verified(): No zrtp context.");
+ }
+ if (!call->auth_token_verified && verified){
+ ortp_zrtp_sas_verified(call->audiostream->ortpZrtpContext);
+ }else if (call->auth_token_verified && !verified){
+ ortp_zrtp_sas_reset_verified(call->audiostream->ortpZrtpContext);
+ }
+ call->auth_token_verified=verified;
+ propagate_encryption_changed(call);
+}
static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit){
MSList *l=NULL;
static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, LinphoneCall *call, unsigned int session_id, unsigned int session_ver){
MSList *l;
PayloadType *pt;
+ int i;
const char *me=linphone_core_get_identity(lc);
LinphoneAddress *addr=linphone_address_new(me);
const char *username=linphone_address_get_username (addr);
/*set audio capabilities */
strncpy(md->streams[0].addr,call->localip,sizeof(md->streams[0].addr));
md->streams[0].port=call->audio_port;
- md->streams[0].proto=SalProtoRtpAvp;
+ md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ?
+ SalProtoRtpSavp : SalProtoRtpAvp;
md->streams[0].type=SalAudio;
md->streams[0].ptime=lc->net_conf.down_ptime;
l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw);
if (call->params.has_video){
md->nstreams++;
md->streams[1].port=call->video_port;
- md->streams[1].proto=SalProtoRtpAvp;
+ md->streams[1].proto=md->streams[0].proto;
md->streams[1].type=SalVideo;
l=make_codec_list(lc,lc->codecs_conf.video_codecs,0);
md->streams[1].payloads=l;
}
+
+ for(i=0; i<md->nstreams; i++) {
+ if (md->streams[i].proto == SalProtoRtpSavp) {
+ md->streams[i].crypto[0].tag = 1;
+ md->streams[i].crypto[0].algo = AES_128_SHA1_80;
+ if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key))
+ md->streams[i].crypto[0].algo = 0;
+ md->streams[i].crypto[1].tag = 2;
+ md->streams[i].crypto[1].algo = AES_128_SHA1_32;
+ if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key))
+ md->streams[i].crypto[1].algo = 0;
+ md->streams[i].crypto[2].algo = 0;
+ }
+ }
+
linphone_address_destroy(addr);
return md;
}
linphone_core_run_stun_tests(call->core,call);
discover_mtu(lc,linphone_address_get_domain (to));
if (params->referer){
- sal_call_set_referer (call->op,params->referer->op);
+ sal_call_set_referer(call->op,params->referer->op);
}
return call;
}
linphone_address_clean(from);
linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
linphone_call_init_common(call, from, to);
- call->params.has_video=linphone_core_video_enabled(lc);
+ linphone_core_init_default_params(lc, &call->params);
call->localdesc=create_local_media_description (lc,call);
call->camera_active=call->params.has_video;
if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseStun)
if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
if (cstate!=LinphoneCallReleased){
ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
- linphone_call_state_to_string(cstate));
+ linphone_call_state_to_string(cstate));
return;
}
}
}
if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
if (call->reason==LinphoneReasonDeclined){
- call->log->status=LinphoneCallDeclined;
- }
- linphone_call_set_terminated (call);
+ call->log->status=LinphoneCallDeclined;
+ }
+ linphone_call_set_terminated (call);
+ }
+ if (cstate == LinphoneCallConnected) {
+ call->log->status=LinphoneCallSuccess;
+ call->media_start_time=time(NULL);
}
- if (cstate == LinphoneCallConnected) {
- call->log->status=LinphoneCallSuccess;
- }
if (lc->vtable.call_state_changed)
lc->vtable.call_state_changed(lc,call,cstate,message);
return cp->has_video;
}
+enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
+ return cp->media_encryption;
+}
+
+void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
+ cp->media_encryption = e;
+}
+
+
/**
* Enable sending of real early media (during outgoing calls).
**/
LinphoneCore *lc=call->core;
int jitt_comp=lc->rtp_conf.audio_jitt_comp;
int used_pt=-1;
+ /* look for savp stream first */
const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
+ SalProtoRtpSavp,SalAudio);
+ /* no savp audio stream, use avp */
+ if (!stream)
+ stream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpAvp,SalAudio);
if (stream && stream->dir!=SalStreamInactive && stream->port!=0){
/*transform the graph to connect it to the conference filter */
linphone_call_add_to_conf(call);
}
+
+ if (stream->proto == SalProtoRtpSavp) {
+ const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
+ SalProtoRtpSavp,SalAudio);
+
+ audio_stream_enable_strp(
+ call->audiostream,
+ stream->crypto[0].algo,
+ local_st_desc->crypto[0].master_key,
+ stream->crypto[0].master_key);
+ }
}else ms_warning("No audio stream accepted ?");
}
}
#ifdef VIDEO_ENABLED
LinphoneCore *lc=call->core;
int used_pt=-1;
+ /* look for savp stream first */
const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
- SalProtoRtpAvp,SalVideo);
+ SalProtoRtpSavp,SalVideo);
+ /* no savp audio stream, use avp */
+ if (!vstream)
+ vstream=sal_media_description_find_stream(call->resultdesc,
+ SalProtoRtpAvp,SalVideo);
+
/* shutdown preview */
if (lc->previewstream!=NULL) {
video_preview_stop(lc->previewstream);
used_pt, lc->rtp_conf.audio_jitt_comp, cam);
video_stream_set_rtcp_information(call->videostream, cname,LINPHONE_RTCP_SDES_TOOL);
}
+
+ if (vstream->proto == SalProtoRtpSavp) {
+ const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
+ SalProtoRtpSavp,SalVideo);
+
+ video_stream_enable_strp(
+ call->videostream,
+ vstream->crypto[0].algo,
+ local_st_desc->crypto[0].master_key,
+ vstream->crypto[0].master_key
+ );
+ }
}else ms_warning("No video stream accepted.");
}else{
ms_warning("No valid video stream defined.");
return;
}
call->current_params = call->params;
- if (call->media_start_time==0) call->media_start_time=time(NULL);
cname=linphone_address_as_string_uri_only(me);
#if defined(VIDEO_ENABLED)
call->playing_ringbacktone=send_ringbacktone;
call->up_bw=linphone_core_get_upload_bandwidth(lc);
- if (ortp_zrtp_available()) {
+ if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
OrtpZrtpParams params;
+ /*will be set later when zrtp is activated*/
+ call->current_params.media_encryption=LinphoneMediaEncryptionNone;
+
params.zid=get_hexa_zrtp_identifier(lc);
params.zid_file=lc->zrtp_secrets_cache;
audio_stream_enable_zrtp(call->audiostream,¶ms);
#include "private.h"
#include <ortp/telephonyevents.h>
+#include <ortp/zrtp.h>
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/mseventqueue.h"
#include "mediastreamer2/msvolume.h"
#endif
#endif
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
/*#define UNSTANDART_GSM_11K 1*/
#define ROOT_CA_FILE PACKAGE_DATA_DIR "/linphone/rootca.pem"
#else
sal_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE));
#endif
-
+
tmp=lp_config_get_int(lc->config,"sip","guess_hostname",1);
linphone_core_set_guess_hostname(lc,tmp);
break;
}
}
+ /*this is to filter out unsupported encryption schemes*/
+ linphone_core_set_media_encryption(lc,linphone_core_get_media_encryption(lc));
/*for tuning or test*/
lc->sip_conf.sdp_200_ack=lp_config_get_int(lc->config,"sip","sdp_200_ack",0);
LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc){
LinphoneCallParams *p=ms_new0(LinphoneCallParams,1);
- p->has_video=linphone_core_video_enabled(lc);
+ linphone_core_init_default_params(lc, p);
return p;
}
int linphone_core_get_max_calls(LinphoneCore *lc) {
return lc->max_calls;
}
-
+void linphone_core_set_max_calls(LinphoneCore *lc, int max) {
+ lc->max_calls=max;
+}
typedef struct Hook{
LinphoneCoreIterateHook fun;
lc->zrtp_secrets_cache=file ? ms_strdup(file) : NULL;
}
-// if (stringUri.equals(call.getRemoteAddress().asStringUriOnly())) {
const LinphoneCall* linphone_core_find_call_from_uri(LinphoneCore *lc, const char *uri) {
if (uri == NULL) return NULL;
MSList *calls=lc->calls;
}
return NULL;
}
+
+
+/**
+ * Check if a call will need the sound resources.
+ *
+ * @ingroup call_control
+ * @param lc The LinphoneCore
+**/
+bool_t linphone_core_sound_resources_locked(LinphoneCore *lc){
+ MSList *calls=lc->calls;
+ while(calls) {
+ LinphoneCall *c=(LinphoneCall*)calls->data;
+ calls=calls->next;
+ switch (c->state) {
+ case LinphoneCallOutgoingInit:
+ case LinphoneCallOutgoingProgress:
+ case LinphoneCallOutgoingRinging:
+ case LinphoneCallOutgoingEarlyMedia:
+ case LinphoneCallConnected:
+ case LinphoneCallRefered:
+ case LinphoneCallIncomingEarlyMedia:
+ case LinphoneCallUpdated:
+ return TRUE;
+ default:
+ break;
+ }
+ }
+ return FALSE;
+}
+
+void linphone_core_set_srtp_enabled(LinphoneCore *lc, bool_t enabled) {
+ lp_config_set_int(lc->config,"sip","srtp",(int)enabled);
+}
+
+/**
+ * Returns whether a media encryption scheme is supported by the LinphoneCore engine
+**/
+bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, LinphoneMediaEncryption menc){
+ switch(menc){
+ case LinphoneMediaEncryptionSRTP:
+ return ortp_srtp_supported();
+ case LinphoneMediaEncryptionZRTP:
+ return ortp_zrtp_available();
+ case LinphoneMediaEncryptionNone:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int linphone_core_set_media_encryption(LinphoneCore *lc, enum LinphoneMediaEncryption menc) {
+ const char *type="none";
+ int ret=0;
+ if (menc == LinphoneMediaEncryptionSRTP){
+ if (!ortp_srtp_supported()){
+ ms_warning("SRTP not supported by library.");
+ type="none";
+ ret=-1;
+ }else type="srtp";
+ }else if (menc == LinphoneMediaEncryptionZRTP){
+ if (!ortp_zrtp_available()){
+ ms_warning("ZRTP not supported by library.");
+ type="none";
+ ret=-1;
+ }else type="zrtp";
+ }
+ lp_config_set_string(lc->config,"sip","media_encryption",type);
+ return ret;
+}
+
+LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc) {
+ const char* menc = lp_config_get_string(lc->config, "sip", "media_encryption", NULL);
+
+ if (menc == NULL)
+ return LinphoneMediaEncryptionNone;
+ else if (strcmp(menc, "srtp")==0)
+ return LinphoneMediaEncryptionSRTP;
+ else if (strcmp(menc, "zrtp")==0)
+ return LinphoneMediaEncryptionZRTP;
+ else
+ return LinphoneMediaEncryptionNone;
+}
+
+bool_t linphone_core_is_media_encryption_mandatory(LinphoneCore *lc) {
+ return (bool_t)lp_config_get_int(lc->config, "sip", "media_encryption_mandatory", 0);
+}
+
+void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m) {
+ lp_config_set_int(lc->config, "sip", "media_encryption_mandatory", (int)m);
+}
+
+void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params) {
+ params->has_video=linphone_core_video_enabled(lc);
+ params->media_encryption=linphone_core_get_media_encryption(lc);
+ params->in_conference=FALSE;
+}
+
struct _LinphoneCore *lc;
} LinphoneCallLog;
+enum LinphoneMediaEncryption {
+ LinphoneMediaEncryptionNone,
+ LinphoneMediaEncryptionSRTP,
+ LinphoneMediaEncryptionZRTP
+};
+typedef enum LinphoneMediaEncryption LinphoneMediaEncryption;
/*public: */
void linphone_call_log_set_user_pointer(LinphoneCallLog *cl, void *up);
LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp);
void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled);
bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp);
+LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp);
+void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, LinphoneMediaEncryption e);
void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled);
bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp);
bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp);
float linphone_call_get_record_volume(LinphoneCall *call);
float linphone_call_get_current_quality(LinphoneCall *call);
float linphone_call_get_average_quality(LinphoneCall *call);
+const char* linphone_call_get_authentication_token(LinphoneCall *call);
+bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call);
+void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified);
+void linphone_call_send_vfu_request(LinphoneCall *call);
void *linphone_call_get_user_pointer(LinphoneCall *call);
void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer);
/**
*/
void linphone_core_refresh_registers(LinphoneCore* lc);
-
-void linphone_call_send_vfu_request(LinphoneCall *call);
-
/* Path to the file storing secrets cache */
void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file);
-bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call);
-const char* linphone_call_get_authentication_token(LinphoneCall *call);
-bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call);
const LinphoneCall* linphone_core_find_call_from_uri(LinphoneCore *lc, const char *uri);
int linphone_core_get_conference_size(LinphoneCore *lc);
int linphone_core_get_max_calls(LinphoneCore *lc);
+void linphone_core_set_max_calls(LinphoneCore *lc, int max);
+
+bool_t linphone_core_sound_resources_locked(LinphoneCore *lc);
+
+bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, LinphoneMediaEncryption menc);
+
+/**
+ * Choose media encryption policy to be used for RTP packets
+ */
+int linphone_core_set_media_encryption(LinphoneCore *lc, enum LinphoneMediaEncryption menc);
+LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc);
+
+bool_t linphone_core_is_media_encryption_mandatory(LinphoneCore *lc);
+/**
+ * Defines Linphone behaviour when encryption parameters negociation fails on outoing call.
+ * If set to TRUE call will fail; if set to FALSE will resend an INVITE with encryption disabled
+ */
+void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m);
+
+/**
+ * Init call params using LinphoneCore's current configuration
+ */
+void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params);
#ifdef __cplusplus
}
#ifdef HAVE_AMR
extern "C" void libmsamr_init();
#endif
+#ifdef HAVE_SILK
+extern "C" void libmssilk_init();
+#endif
#endif /*ANDROID*/
static JavaVM *jvm=0;
#endif
#ifdef HAVE_AMR
libmsamr_init();
+#endif
+#ifdef HAVE_SILK
+ libmssilk_init();
#endif
jlong nativePtr = (jlong)linphone_core_new( &ldata->vTable
,userConfig
}
+static enum LinphoneMediaEncryption media_encryption_string_to_enum(const char* menc) {
+ if (menc==NULL)
+ return LinphoneMediaEncryptionNone;
+ else if (strcasecmp(menc, "none")==0)
+ return LinphoneMediaEncryptionNone;
+ else if (strcasecmp(menc, "srtp")==0)
+ return LinphoneMediaEncryptionSRTP;
+ else if (strcasecmp(menc, "zrtp")==0)
+ return LinphoneMediaEncryptionZRTP;
+ else
+ return LinphoneMediaEncryptionNone;
+}
+
+static jstring media_encryption_enum_to_jstring(JNIEnv* env, enum LinphoneMediaEncryption enc) {
+ switch (enc) {
+ case LinphoneMediaEncryptionSRTP:
+ return env->NewStringUTF("srtp");
+ case LinphoneMediaEncryptionZRTP:
+ return env->NewStringUTF("zrtp");
+ case LinphoneMediaEncryptionNone:
+ return env->NewStringUTF("none");
+ default:
+ return NULL;
+ }
+}
+extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getMediaEncryption(JNIEnv* env
+ ,jobject thiz
+ ,jlong lc
+ ) {
+ return media_encryption_enum_to_jstring(env,
+ linphone_core_get_media_encryption((LinphoneCore*)lc));
+}
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setMediaEncryption(JNIEnv* env
+ ,jobject thiz
+ ,jlong lc
+ ,jstring jmenc) {
+ const char* menc = jmenc?env->GetStringUTFChars(jmenc, NULL):NULL;
+
+ linphone_core_set_media_encryption((LinphoneCore*)lc,
+ media_encryption_string_to_enum(menc));
+
+ if (menc) env->ReleaseStringUTFChars(jmenc, menc);
+}
+
+extern "C" jstring Java_org_linphone_core_LinphoneCallParamsImpl_getMediaEncryption(JNIEnv* env
+ ,jobject thiz
+ ,jlong lc
+ ) {
+ return media_encryption_enum_to_jstring(env,
+ linphone_call_params_get_media_encryption((LinphoneCallParams*)lc));
+}
+extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setMediaEncryption(JNIEnv* env
+ ,jobject thiz
+ ,jlong lc
+ ,jstring jmenc) {
+ const char* menc = jmenc?env->GetStringUTFChars(jmenc, NULL):NULL;
+ linphone_call_params_set_media_encryption((LinphoneCallParams*)lc,
+ media_encryption_string_to_enum(menc));
+ if (menc) env->ReleaseStringUTFChars(jmenc, menc);
+}
+
+extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_getMediaEncryptionMandatory(JNIEnv* env
+ ,jobject thiz
+ ,jlong lc
+ ) {
+ return linphone_core_is_media_encryption_mandatory((LinphoneCore*)lc);
+}
+
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setMediaEncryptionMandatory(JNIEnv* env
+ ,jobject thiz
+ ,jlong lc
+ , jboolean yesno
+ ) {
+ linphone_core_set_media_encryption_mandatory((LinphoneCore*)lc, yesno);
+}
//ProxyConfig
LinphoneCall *call = (LinphoneCall *) ptr;
return linphone_call_get_authentication_token_verified(call);
}
-extern "C" jboolean Java_org_linphone_core_LinphoneCallImpl_areStreamsEncrypted(JNIEnv* env,jobject thiz,jlong ptr) {
- return linphone_call_are_all_streams_encrypted((LinphoneCall *) ptr);
+
+extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_soundResourcesLocked(JNIEnv* env,jobject thiz,jlong ptr){
+ return linphone_core_sound_resources_locked((LinphoneCore *) ptr);
}
// Needed by Galaxy S (can't switch to/from speaker while playing and still keep mic working)
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getMaxCalls(JNIEnv *env,jobject thiz,jlong pCore) {
return (jint) linphone_core_get_max_calls((LinphoneCore *) pCore);
}
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setMaxCalls(JNIEnv *env,jobject thiz,jlong pCore, jint max) {
+ linphone_core_set_max_calls((LinphoneCore *) pCore, (int) max);
+}
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#define MAX_LEN 32768
+#define MAX_LEN 16384
#include "linphonecore.h"
}
void lp_config_parse(LpConfig *lpconfig, FILE *file){
- char tmp[MAX_LEN];
+ char tmp[MAX_LEN]= {'\0'};
LpSection *cur=NULL;
if (file==NULL) return;
while(fgets(tmp,MAX_LEN,file)!=NULL){
+ tmp[sizeof(tmp) -1] = '\0';
char *pos1,*pos2;
pos1=strchr(tmp,'[');
if (pos1!=NULL && is_first_char(tmp,pos1) ){
return res;
}
+static bool_t match_crypto_algo(const SalSrtpCryptoAlgo* local, const SalSrtpCryptoAlgo* remote,
+ SalSrtpCryptoAlgo* result, bool_t use_local_key) {
+ int i,j;
+ for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
+ if (remote[i].algo == 0)
+ break;
+
+ for(j=0; j<SAL_CRYPTO_ALGO_MAX; j++) {
+ if (remote[i].algo == local[j].algo) {
+ result->algo = remote[i].algo;
+ if (use_local_key) {
+ strncpy(result->master_key, local[j].master_key, 41);
+ result->tag = local[j].tag;
+ } else {
+ strncpy(result->master_key, remote[j].master_key, 41);
+ result->tag = remote[j].tag;
+ }
+ result->master_key[40] = '\0';
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
static SalStreamDir compute_dir_outgoing(SalStreamDir local, SalStreamDir answered){
SalStreamDescription *result){
if (remote_answer->port!=0)
result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads,TRUE,FALSE);
- result->proto=local_offer->proto;
+ result->proto=remote_answer->proto;
result->type=local_offer->type;
result->dir=compute_dir_outgoing(local_offer->dir,remote_answer->dir);
}else{
result->port=0;
}
+ if (result->proto == SalProtoRtpSavp) {
+ /* verify crypto algo */
+ memset(result->crypto, 0, sizeof(result->crypto));
+ if (!match_crypto_algo(local_offer->crypto, remote_answer->crypto, &result->crypto[0], FALSE))
+ result->port = 0;
+ }
}
const SalStreamDescription *remote_offer,
SalStreamDescription *result, bool_t one_matching_codec){
result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads, FALSE, one_matching_codec);
- result->proto=local_cap->proto;
+ result->proto=remote_offer->proto;
result->type=local_cap->type;
result->dir=compute_dir_incoming(local_cap->dir,remote_offer->dir);
if (result->payloads && !only_telephone_event(result->payloads)){
}else{
result->port=0;
}
+ if (result->proto == SalProtoRtpSavp) {
+ /* select crypto algo */
+ memset(result->crypto, 0, sizeof(result->crypto));
+ if (!match_crypto_algo(local_cap->crypto, remote_offer->crypto, &result->crypto[0], TRUE))
+ result->port = 0;
+
+ }
}
/**
const SalMediaDescription *remote_answer,
SalMediaDescription *result){
int i,j;
+
const SalStreamDescription *ls,*rs;
for(i=0,j=0;i<local_offer->nstreams;++i){
ms_message("Processing for stream %i",i);
for(i=0;i<remote_offer->nstreams;++i){
rs=&remote_offer->streams[i];
ms_message("Processing for stream %i",i);
+
ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type);
+ ms_message("remote proto: %s => %p", (rs->proto == SalProtoRtpAvp)?"AVP":"SAVP", ls);
+ /* if matching failed, and remote proposes Avp only, ask for local Savp streams */
+ if (!ls && rs->proto == SalProtoRtpAvp) {
+ ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,SalProtoRtpSavp,rs->type);
+ ms_message("retry with AVP => %p", ls);
+ }
if (ls){
initiate_incoming(ls,rs,&result->streams[i],one_matching_codec);
- } else {
+ }
+ else {
/* create an inactive stream for the answer, as there where no matching stream a local capability */
result->streams[i].dir=SalStreamInactive;
result->streams[i].port=0;
#endif
#endif
-
struct _LinphoneCallParams{
LinphoneCall *referer; /*in case this call creation is consecutive to an incoming transfer, this points to the original call */
int audio_bw; /* bandwidth limit for audio stream */
+ LinphoneMediaEncryption media_encryption;
bool_t has_video;
bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/
bool_t in_conference; /*in conference mode */
bool_t pad;
+
};
struct _LinphoneCall
#define SAL_ENDPOINT_CANDIDATE_MAX 2
+typedef struct SalSrtpCryptoAlgo {
+ unsigned int tag;
+ enum ortp_srtp_crypto_suite_t algo;
+ /* 41= 40 max(key_length for all algo) + '\0' */
+ char master_key[41];
+} SalSrtpCryptoAlgo;
+
+#define SAL_CRYPTO_ALGO_MAX 4
+
typedef struct SalStreamDescription{
SalMediaProto proto;
SalStreamType type;
int ptime;
SalEndpointCandidate candidates[SAL_ENDPOINT_CANDIDATE_MAX];
SalStreamDir dir;
+ SalSrtpCryptoAlgo crypto[SAL_CRYPTO_ALGO_MAX];
} SalStreamDescription;
#define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4
It should contains media parameters constraint from the remote offer, not our response*/
strcpy(h->result->addr,h->base.remote_media->addr);
h->result->bandwidth=h->base.remote_media->bandwidth;
+
for(i=0;i<h->result->nstreams;++i){
if (h->result->streams[i].port>0){
strcpy(h->result->streams[i].addr,h->base.remote_media->streams[i].addr);
h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime;
h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth;
h->result->streams[i].port=h->base.remote_media->streams[i].port;
+
+ if (h->result->streams[i].proto == SalProtoRtpSavp) {
+ h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0];
+ }
}
}
}
sal_op_set_from(h,from);
sal_op_set_to(h,to);
sal_exosip_fix_route(h);
+
+ h->terminated = FALSE;
+
route = sal_op_get_route(h);
err=eXosip_call_build_initial_invite(&invite,to,from,route,"Phone call");
if (err!=0){
osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"),
osip_strdup (addr), NULL, NULL);
}
- sdp_message_m_media_add (msg, osip_strdup (mt),
- int_2char (port), NULL,
- osip_strdup ("RTP/AVP"));
+
+ if (desc->proto == SalProtoRtpSavp) {
+ int i;
+
+ sdp_message_m_media_add (msg, osip_strdup (mt),
+ int_2char (port), NULL,
+ osip_strdup ("RTP/SAVP"));
+
+ /* add crypto lines */
+ for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
+ char buffer[1024];
+ switch (desc->crypto[i].algo) {
+ case AES_128_SHA1_80:
+ snprintf(buffer, 1024, "%d %s inline:%s",
+ desc->crypto[i].tag, "AES_CM_128_HMAC_SHA1_80", desc->crypto[i].master_key);
+ sdp_message_a_attribute_add(msg, lineno, osip_strdup("crypto"),
+ osip_strdup(buffer));
+ break;
+ case AES_128_SHA1_32:
+ snprintf(buffer, 1024, "%d %s inline:%s",
+ desc->crypto[i].tag, "AES_CM_128_HMAC_SHA1_32", desc->crypto[i].master_key);
+ sdp_message_a_attribute_add(msg, lineno, osip_strdup("crypto"),
+ osip_strdup(buffer));
+ break;
+ case AES_128_NO_AUTH:
+ ms_warning("Unsupported crypto suite: AES_128_NO_AUTH");
+ break;
+ case NO_CIPHER_SHA1_80:
+ ms_warning("Unsupported crypto suite: NO_CIPHER_SHA1_80");
+ break;
+ default:
+ i = SAL_CRYPTO_ALGO_MAX;
+ }
+ }
+
+ } else {
+ sdp_message_m_media_add (msg, osip_strdup (mt),
+ int_2char (port), NULL,
+ osip_strdup ("RTP/AVP"));
+
+ }
if (desc->bandwidth>0) sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"),
int_2char(desc->bandwidth));
if (desc->ptime>0) sdp_message_a_attribute_add(msg,lineno,osip_strdup("ptime"),
for(j=0;(sbw=sdp_message_bandwidth_get(msg,i,j))!=NULL;++j){
if (strcasecmp(sbw->b_bwtype,"AS")==0) stream->bandwidth=atoi(sbw->b_bandwidth);
}
- stream->dir=_sdp_message_get_mline_dir(msg,i);
+ stream->dir=_sdp_message_get_mline_dir(msg,i);
/* for each payload type */
for (j=0;((number=sdp_message_m_payload_get (msg, i,j)) != NULL); j++){
const char *rtpmap,*fmtp;
pt->send_fmtp ? pt->send_fmtp : "");
}
}
+
+ /* read crypto lines if any */
+ if (stream->proto == SalProtoRtpSavp) {
+ int k, valid_count = 0;
+ sdp_attribute_t *attr;
+
+ memset(&stream->crypto, 0, sizeof(stream->crypto));
+ for (k=0;valid_count < SAL_CRYPTO_ALGO_MAX && (attr=sdp_message_attribute_get(msg,i,k))!=NULL;k++){
+ char tmp[256], tmp2[256];
+ if (keywordcmp("crypto",attr->a_att_field)==0 && attr->a_att_value!=NULL){
+ int nb = sscanf(attr->a_att_value, "%d %256s inline:%256s",
+ &stream->crypto[valid_count].tag,
+ tmp,
+ tmp2);
+ ms_message("Found valid crypto line (tag:%d algo:'%s' key:'%s'",
+ stream->crypto[valid_count].tag,
+ tmp,
+ tmp2);
+ if (nb == 3) {
+ if (strcmp(tmp, "AES_CM_128_HMAC_SHA1_80") == 0)
+ stream->crypto[valid_count].algo = AES_128_SHA1_80;
+ else if (strcmp(tmp, "AES_CM_128_HMAC_SHA1_32") == 0)
+ stream->crypto[valid_count].algo = AES_128_SHA1_32;
+ else {
+ ms_warning("Failed to parse crypto-algo: '%s'", tmp);
+ stream->crypto[valid_count].algo = 0;
+ }
+ if (stream->crypto[valid_count].algo) {
+ strncpy(stream->crypto[valid_count].master_key, tmp2, 41);
+ stream->crypto[valid_count].master_key[40] = '\0';
+ ms_message("Found valid crypto line (tag:%d algo:'%s' key:'%s'",
+ stream->crypto[valid_count].tag,
+ tmp,
+ stream->crypto[valid_count].master_key);
+ valid_count++;
+ }
+ } else {
+ ms_warning("sdp has a strange a= line (%s) nb=%i",attr->a_att_value,nb);
+ }
+ }
+ }
+ ms_message("Found: %d valid crypto lines", valid_count);
+ }
}
desc->nstreams=i;
return 0;
GtkWidget *container=linphone_gtk_get_widget(callview,"in_call_animation");
GList *elem=gtk_container_get_children(GTK_CONTAINER(container));
GtkWidget *image;
- if (!is_stock)
+
+ if (!is_stock){
+ if (image_name==NULL){
+ gtk_widget_hide(container);
+ }
image=create_pixmap(image_name);
- else
+ }else
image=gtk_image_new_from_stock(image_name,GTK_ICON_SIZE_DIALOG);
if (elem)
gtk_widget_destroy((GtkWidget*)elem->data);
gtk_widget_show(image);
gtk_container_add(GTK_CONTAINER(container),image);
-
+ gtk_widget_show_all(container);
}
static void linphone_gtk_in_call_set_animation_spinner(GtkWidget *callview){
gtk_widget_destroy((GtkWidget*)elem->data);
gtk_widget_show(spinner);
gtk_container_add(GTK_CONTAINER(container),spinner);
+ gtk_widget_set_size_request(spinner, 20,20);
gtk_spinner_start(GTK_SPINNER(spinner));
}
}
}
+void linphone_gtk_auth_token_verified_clicked(GtkButton *button){
+ LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
+ if (call){
+ linphone_call_set_authentication_token_verified(call,!linphone_call_get_authentication_token_verified(call));
+ }
+}
+
+void linphone_gtk_in_call_view_show_encryption(LinphoneCall *call){
+ GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
+ GtkWidget *encryption_box=linphone_gtk_get_widget(callview,"encryption_box");
+ GtkWidget *label=linphone_gtk_get_widget(callview,"encryption_label");
+ GtkWidget *status_icon=linphone_gtk_get_widget(callview,"encryption_status_icon");
+ GtkWidget *verify_button=linphone_gtk_get_widget(callview,"encryption_verify_button");
+ LinphoneMediaEncryption me=linphone_call_params_get_media_encryption(linphone_call_get_current_params(call));
+ bool_t verified=linphone_call_get_authentication_token_verified(call);
+ switch(me){
+ case LinphoneMediaEncryptionSRTP:
+ gtk_label_set_markup(GTK_LABEL(label),_("Secured by SRTP"));
+ gtk_widget_hide(status_icon);
+ gtk_widget_hide(verify_button);
+ gtk_widget_show_all(encryption_box);
+ break;
+ case LinphoneMediaEncryptionZRTP:
+ {
+ gchar *text=g_strdup_printf(_("Secured by ZRTP - [auth token: %s]"),linphone_call_get_authentication_token(call));
+ gtk_label_set_markup(GTK_LABEL(label),text);
+ g_free(text);
+ gtk_image_set_from_stock(GTK_IMAGE(status_icon),
+ verified ? GTK_STOCK_APPLY : GTK_STOCK_DIALOG_WARNING,GTK_ICON_SIZE_MENU);
+ gtk_button_set_label(GTK_BUTTON(verify_button),
+ verified ? _("Set unverified") : _("Set verified"));
+ gtk_widget_show_all(encryption_box);
+ }
+ break;
+ default:
+ gtk_widget_hide(encryption_box);
+ }
+}
+
void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status");
g_object_set_data(G_OBJECT(callview),"taskid",GINT_TO_POINTER(taskid));
}
linphone_gtk_in_call_view_enable_audio_view(call, !in_conf);
+ linphone_gtk_in_call_view_show_encryption(call);
if (in_conf) linphone_gtk_set_in_conference(call);
}
void linphone_gtk_set_in_conference(LinphoneCall *call);
void linphone_gtk_unset_from_conference(LinphoneCall *call);
void linphone_gtk_terminate_conference_participant(LinphoneCall *call);
+void linphone_gtk_in_call_view_show_encryption(LinphoneCall *call);
typedef float (*get_volume_t)(void *data);
void linphone_gtk_init_audio_meter(GtkWidget *w, get_volume_t get_volume, void *data);
static GtkWidget *the_ui=NULL;
static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg);
-static void linphone_gtk_show(LinphoneCore *lc);
static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid);
static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username);
static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url);
static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl);
static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg);
+static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token);
static gboolean linphone_gtk_auto_answer(LinphoneCall *call);
static void linphone_gtk_status_icon_set_blinking(gboolean val);
#ifndef WIN32
#define CONFIG_FILE ".linphonerc"
+#define SECRETS_FILE ".linphone-zidcache"
#else
#define CONFIG_FILE "linphonerc"
+#define SECRETS_FILE "linphone-zidcache"
#endif
-
-static char _config_file[1024];
-
-
-const char *linphone_gtk_get_config_file(){
+char *linphone_gtk_get_config_file(const char *filename){
+ const int path_max=1024;
+ char *config_file=g_malloc0(path_max);
+ if (filename==NULL) filename=CONFIG_FILE;
/*try accessing a local file first if exists*/
if (access(CONFIG_FILE,F_OK)==0){
- snprintf(_config_file,sizeof(_config_file),"%s",CONFIG_FILE);
+ snprintf(config_file,path_max,"%s",CONFIG_FILE);
}else{
#ifdef WIN32
const char *appdata=getenv("APPDATA");
if (appdata){
- snprintf(_config_file,sizeof(_config_file),"%s\\%s",appdata,LINPHONE_CONFIG_DIR);
- CreateDirectory(_config_file,NULL);
- snprintf(_config_file,sizeof(_config_file),"%s\\%s",appdata,LINPHONE_CONFIG_DIR "\\" CONFIG_FILE);
+ snprintf(config_file,path_max,"%s\\%s",appdata,LINPHONE_CONFIG_DIR);
+ CreateDirectory(config_file,NULL);
+ snprintf(config_file,path_max,"%s\\%s\\%s",appdata,LINPHONE_CONFIG_DIR,filename);
}
#else
const char *home=getenv("HOME");
if (home==NULL) home=".";
- snprintf(_config_file,sizeof(_config_file),"%s/%s",home,CONFIG_FILE);
+ snprintf(config_file,path_max,"%s/%s",home,filename);
#endif
}
- return _config_file;
+ return config_file;
}
static void linphone_gtk_init_liblinphone(const char *config_file,
const char *factory_config_file) {
LinphoneCoreVTable vtable={0};
+ gchar *secrets_file=linphone_gtk_get_config_file(SECRETS_FILE);
vtable.call_state_changed=linphone_gtk_call_state_changed;
vtable.registration_state_changed=linphone_gtk_registration_state_changed;
- vtable.show=linphone_gtk_show;
vtable.notify_presence_recv=linphone_gtk_notify_recv;
vtable.new_subscription_request=linphone_gtk_new_unknown_subscriber;
vtable.auth_info_requested=linphone_gtk_auth_info_requested;
vtable.text_received=linphone_gtk_text_received;
vtable.refer_received=linphone_gtk_refer_received;
vtable.buddy_info_updated=linphone_gtk_buddy_info_updated;
+ vtable.call_encryption_changed=linphone_gtk_call_encryption_changed;
linphone_core_set_user_agent("Linphone", LINPHONE_VERSION);
the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
+ linphone_core_set_zrtp_secrets_file(the_core,secrets_file);
+ g_free(secrets_file);
}
gtk_window_present(GTK_WINDOW(w));
}
-static void linphone_gtk_show(LinphoneCore *lc){
-#ifndef HAVE_NOTIFY
- linphone_gtk_show_main_window();
-#endif
-}
-
void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){
GtkWidget *mw=linphone_gtk_get_main_window();
if (linphone_core_get_calls(linphone_gtk_get_core())==NULL){
linphone_gtk_status_icon_set_blinking(FALSE);
break;
case LinphoneCallIncomingReceived:
- linphone_gtk_create_in_call_view (call);
+ linphone_gtk_create_in_call_view(call);
linphone_gtk_in_call_view_set_incoming(call);
linphone_gtk_status_icon_set_blinking(TRUE);
if (auto_answer) {
linphone_gtk_update_call_buttons (call);
}
+static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token){
+ linphone_gtk_in_call_view_show_encryption(call);
+}
+
static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){
GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
GtkTreeModel *model=gtk_combo_box_get_model(box);
update_registration_status(cfg,rs);
}
-
-static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
- GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
- gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
-}
-
void linphone_gtk_open_browser(const char *url){
/*in gtk 2.16, gtk_show_uri does not work...*/
#ifndef WIN32
linphone_gtk_open_browser(home);
}
+#ifndef HAVE_GTK_OSX
+
+static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
+ GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
+ gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
+}
+
static GtkWidget *create_icon_menu(){
GtkWidget *menu=gtk_menu_new();
GtkWidget *menu_item;
return TRUE;
}
+#endif
+
static void linphone_gtk_status_icon_set_blinking(gboolean val){
- guint tout;
- tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout"));
- if (val && tout==0){
- tout=g_timeout_add(500,(GSourceFunc)do_icon_blink,icon);
- g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout));
- }else if (!val && tout!=0){
- GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon");
- g_source_remove(tout);
- g_object_set_data(G_OBJECT(icon),"timeout",NULL);
- gtk_status_icon_set_from_pixbuf(icon,normal_icon);
+#ifdef HAVE_GTK_OSX
+ static gint attention_id;
+ GtkOSXApplication *theMacApp=(GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
+ if (val)
+ attention_id=gtk_osxapplication_attention_request(theMacApp,CRITICAL_REQUEST);
+ else gtk_osxapplication_cancel_attention_request(theMacApp,attention_id);
+#else
+ if (icon!=NULL){
+ guint tout;
+ tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout"));
+ if (val && tout==0){
+ tout=g_timeout_add(500,(GSourceFunc)do_icon_blink,icon);
+ g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout));
+ }else if (!val && tout!=0){
+ GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon");
+ g_source_remove(tout);
+ g_object_set_data(G_OBJECT(icon),"timeout",NULL);
+ gtk_status_icon_set_from_pixbuf(icon,normal_icon);
+ }
}
+#endif
}
static void init_identity_combo(GtkComboBox *box){
#ifdef ENABLE_NLS
void *p;
#endif
- const char *config_file;
+ char *config_file;
const char *factory_config_file;
const char *lang;
GtkSettings *settings;
progpath = strdup(argv[0]);
- config_file=linphone_gtk_get_config_file();
+ config_file=linphone_gtk_get_config_file(NULL);
#ifdef WIN32
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <requires lib="gtk+" version="2.16"/>
- <!-- interface-naming-policy toplevel-contextual -->
+ <requires lib="gtk+" version="2.22"/>
<object class="GtkWindow" id="dummy_conf_window">
<property name="can_focus">False</property>
<child>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
- <object class="GtkHBox" id="incall_hbox1">
+ <object class="GtkVBox" id="in_call_animation">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
- <object class="GtkVBox" id="in_call_animation">
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="in_call_uri">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">label</property>
+ <property name="justify">center</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="encryption_box">
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkImage" id="image12">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <child>
- <placeholder/>
- </child>
+ <property name="stock">gtk-dialog-authentication</property>
+ <property name="icon-size">1</property>
</object>
<packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="in_call_uri">
+ <object class="GtkImage" id="encryption_status_icon">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="stock">gtk-apply</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="encryption_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">label</property>
- <property name="justify">center</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
- <property name="position">1</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="encryption_verify_button">
+ <property name="label" translatable="yes">Set verified</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <signal name="clicked" handler="linphone_gtk_auth_token_verified_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
</packing>
</child>
</object>
<packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
</packing>
</child>
<child>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">1</property>
+ <property name="position">3</property>
</packing>
</child>
<child>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">2</property>
+ <property name="position">4</property>
</packing>
</child>
<child>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">3</property>
+ <property name="position">5</property>
</packing>
</child>
</object>
<property name="invisible_char">●</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
- <property name="primary_icon_sensitive">True</property>
- <property name="secondary_icon_sensitive">True</property>
<signal name="activate" handler="linphone_gtk_uri_bar_activate" swapped="no"/>
</object>
<packing>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
- <property name="primary_icon_sensitive">True</property>
- <property name="secondary_icon_sensitive">True</property>
<signal name="changed" handler="linphone_gtk_show_friends" swapped="no"/>
</object>
<packing>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="hscrollbar_policy">automatic</property>
- <property name="vscrollbar_policy">automatic</property>
<child>
<object class="GtkTreeView" id="contact_list">
<property name="visible">True</property>
<signal name="cursor-changed" handler="linphone_gtk_contact_clicked" swapped="no"/>
<signal name="row-activated" handler="linphone_gtk_contact_activated" swapped="no"/>
<signal name="popup-menu" handler="linphone_gtk_popup_contact_menu" swapped="no"/>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeview-selection1"/>
+ </child>
</object>
</child>
</object>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
- <property name="primary_icon_sensitive">True</property>
- <property name="secondary_icon_sensitive">True</property>
<signal name="activate" handler="linphone_gtk_directory_search_activate" swapped="no"/>
<signal name="icon-press" handler="linphone_gtk_directory_search_activate" swapped="no"/>
<signal name="focus-in-event" handler="linphone_gtk_directory_search_focus_in" swapped="no"/>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
- <property name="vscrollbar_policy">automatic</property>
<child>
<object class="GtkTreeView" id="logs_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
<signal name="row-activated" handler="linphone_gtk_history_row_activated" swapped="no"/>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeview-selection2"/>
+ </child>
</object>
</child>
</object>
<property name="invisible_char">●</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
- <property name="primary_icon_sensitive">True</property>
- <property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="invisible_char">●</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
- <property name="primary_icon_sensitive">True</property>
- <property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <requires lib="gtk+" version="2.16"/>
+ <requires lib="gtk+" version="2.22"/>
<object class="GtkAdjustment" id="adjustment1">
<property name="lower">500</property>
<property name="upper">3001</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
+ <object class="GtkListStore" id="liststore1"/>
<object class="GtkListStore" id="model1">
<columns>
<!-- column-name gchararray -->
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="left_padding">12</property>
<child>
- <object class="GtkVBox" id="vbox6">
+ <object class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">2</property>
<child>
- <placeholder/>
+ <object class="GtkComboBox" id="proto_combo">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="model">model8</property>
+ <child>
+ <object class="GtkCellRendererText" id="renderer1"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="proto_port">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="invisible_char_set">True</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="adjustment">adjustment7</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="video_rtp_port">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="invisible_char">•</property>
+ <property name="invisible_char_set">True</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="adjustment">adjustment2</property>
+ <signal name="value-changed" handler="linphone_gtk_video_port_changed" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
</child>
<child>
- <object class="GtkTable" id="table1">
+ <object class="GtkSpinButton" id="audio_rtp_port">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="invisible_char">•</property>
+ <property name="invisible_char_set">True</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="adjustment">adjustment3</property>
+ <signal name="value-changed" handler="linphone_gtk_audio_port_changed" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="n_rows">3</property>
- <property name="n_columns">2</property>
- <child>
- <object class="GtkComboBox" id="proto_combo">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="model">model8</property>
- <signal name="changed" handler="linphone_gtk_proto_changed" swapped="no"/>
- <child>
- <object class="GtkCellRendererText" id="renderer1"/>
- <attributes>
- <attribute name="text">0</attribute>
- </attributes>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkSpinButton" id="proto_port">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="invisible_char">•</property>
- <property name="invisible_char_set">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
- <property name="adjustment">adjustment7</property>
- <signal name="value-changed" handler="linphone_gtk_update_my_port" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkSpinButton" id="video_rtp_port">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="invisible_char">•</property>
- <property name="invisible_char_set">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
- <property name="adjustment">adjustment2</property>
- <signal name="value-changed" handler="linphone_gtk_video_port_changed" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkSpinButton" id="audio_rtp_port">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="invisible_char">•</property>
- <property name="invisible_char_set">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
- <property name="adjustment">adjustment3</property>
- <signal name="value-changed" handler="linphone_gtk_audio_port_changed" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label7">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="label" translatable="yes">Video RTP/UDP:</property>
- <property name="justify">right</property>
- </object>
- <packing>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label6">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="label" translatable="yes">Audio RTP/UDP:</property>
- <property name="justify">right</property>
- </object>
- <packing>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- </packing>
- </child>
+ <property name="label" translatable="yes">Video RTP/UDP:</property>
+ <property name="justify">right</property>
</object>
<packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Audio RTP/UDP:</property>
+ <property name="justify">right</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="media_encryption_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Media encryption type</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="media_encryption_combo">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="active">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
</packing>
</child>
</object>
linphone_gtk_ui_level_adapt(top);
}
+static void linphone_gtk_media_encryption_changed(GtkWidget *combo){
+ char *selected=gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo));
+ LinphoneCore *lc=linphone_gtk_get_core();
+ if (selected!=NULL){
+ if (strcasecmp(selected,"SRTP")==0)
+ linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionSRTP);
+ else if (strcasecmp(selected,"ZRTP")==0)
+ linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionZRTP);
+ else linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionNone);
+ g_free(selected);
+ }else g_warning("gtk_combo_box_get_active_text() returned NULL");
+}
+
+static void linphone_gtk_show_media_encryption(GtkWidget *pb){
+ LinphoneCore *lc=linphone_gtk_get_core();
+ GtkWidget *combo=linphone_gtk_get_widget(pb,"media_encryption_combo");
+ bool_t no_enc=TRUE;
+ int srtp_id=-1,zrtp_id=-1;
+ GtkTreeModel *model;
+ GtkListStore *store;
+ GtkTreeIter iter;
+ GtkCellRenderer *renderer=gtk_cell_renderer_text_new();
+
+ model=GTK_TREE_MODEL((store=gtk_list_store_new(1,G_TYPE_STRING)));
+ gtk_combo_box_set_model(GTK_COMBO_BOX(combo),model);
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),renderer,TRUE);
+ gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),renderer,"text",0,NULL);
+
+ gtk_list_store_append(store,&iter);
+ gtk_list_store_set(store,&iter,0,_("None"),-1);
+
+ if (linphone_core_media_encryption_supported(lc,LinphoneMediaEncryptionSRTP)){
+ gtk_list_store_append(store,&iter);
+ gtk_list_store_set(store,&iter,0,_("SRTP"),-1);
+ srtp_id=1;
+ no_enc=FALSE;
+ }
+ if (linphone_core_media_encryption_supported(lc,LinphoneMediaEncryptionZRTP)){
+ gtk_list_store_append(store,&iter);
+ gtk_list_store_set(store,&iter,0,_("ZRTP"),-1);
+ no_enc=FALSE;
+ if (srtp_id!=-1) zrtp_id=2;
+ else zrtp_id=1;
+ }
+ if (no_enc){
+ /*hide this setting*/
+ gtk_widget_hide(combo);
+ gtk_widget_hide(linphone_gtk_get_widget(pb,"media_encryption_label"));
+ }else{
+ LinphoneMediaEncryption menc=linphone_core_get_media_encryption(lc);
+ switch(menc){
+ case LinphoneMediaEncryptionNone:
+ gtk_combo_box_set_active(GTK_COMBO_BOX(combo),0);
+ break;
+ case LinphoneMediaEncryptionSRTP:
+ if (srtp_id!=-1) gtk_combo_box_set_active(GTK_COMBO_BOX(combo),srtp_id);
+ break;
+ case LinphoneMediaEncryptionZRTP:
+ if (zrtp_id!=-1) gtk_combo_box_set_active(GTK_COMBO_BOX(combo),zrtp_id);
+ break;
+ }
+ g_signal_connect(G_OBJECT(combo),"changed",(GCallback)linphone_gtk_media_encryption_changed,NULL);
+ }
+ g_object_unref(G_OBJECT(model));
+}
+
void linphone_gtk_show_parameters(void){
GtkWidget *pb=linphone_gtk_create_window("parameters");
LinphoneCore *lc=linphone_gtk_get_core();
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"video_rtp_port")),
linphone_core_get_video_port(lc));
+ linphone_gtk_show_media_encryption(pb);
+
tmp=linphone_core_get_nat_address(lc);
if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"nat_address")),tmp);
tmp=linphone_core_get_stun_server(lc);
ui_advanced);
linphone_gtk_ui_level_adapt(pb);
+ g_signal_connect(G_OBJECT(linphone_gtk_get_widget(pb,"proto_port")),"value-changed",(GCallback)linphone_gtk_update_my_port,NULL);
+ g_signal_connect(G_OBJECT(linphone_gtk_get_widget(pb,"proto_combo")),"changed",(GCallback)linphone_gtk_proto_changed,NULL);
gtk_widget_show(pb);
}
String getAuthenticationToken();
boolean isAuthenticationTokenVerified();
- boolean areStreamsEncrypted();
boolean isInConference();
}
*/
void setAudioBandwidth(int value);
+ /**
+ * return selected media encryption
+ * @return 'none', 'srtp' or 'zrtp'
+ */
+ String getMediaEncryption();
+ /**
+ * set media encryption (rtp) to use
+ * @params menc: 'none', 'srtp' or 'zrtp'
+ */
+ void setMediaEnctyption(String menc);
+
}
LinphoneCall findCallFromUri(String uri);
int getMaxCalls();
+ void setMaxCalls(int max);
+ boolean isMyself(String uri);
+ /**
+ * Use this method to check the calls state and forbid proposing actions
+ * which could result in an active call.
+ * Eg: don't start a new call if one is in outgoing ringing.
+ * Eg: don't merge to conference either as it could result
+ * in two active calls (conference and accepted call).
+ * @return
+ */
+ boolean soundResourcesLocked();
+ /**
+ * set media encryption (rtp) to use
+ * @params menc: 'none', 'srtp' or 'zrtp'
+ */
+ void setMediaEncryption(String menc);
+ /**
+ * return selected media encryption
+ * @return 'none', 'srtp' or 'zrtp'
+ */
+ String getMediaEncryption();
+/**
+ * Set media encryption required for outgoing calls
+ */
+ void setMediaEncryptionMandatory(boolean yesno);
+ /**
+ * @return if media encryption is required for ougtoing calls
+ */
+ boolean isMediaEncryptionMandatory();
}
./bin/avcodec-53.dll
./bin/avutil-51.dll
-./bin/libeXosip2-6.dll
+./bin/libeay32.dll
+./bin/ssleay32.dll
+./bin/libeXosip2-7.dll
./bin/libogg-0.dll
./bin/libtheora-0.dll
./bin/libxml2-2.dll
-./bin/libosip2-6.dll
-./bin/libosipparser2-6.dll
+./bin/libosip2-7.dll
+./bin/libosipparser2-7.dll
./bin/swscale-2.dll
-Subproject commit 7e80b7c99175ff4165814eaa90d13a7b1bd7a869
+Subproject commit 4ee916b3fcae0aba38a0d595079298242c9ac2cd
-Subproject commit 7606207905bd3dc661e68576097adce471916697
+Subproject commit de8ecee12b217f5e63e12fdfe1e3462e248ad46d
msgstr "Rechercher:"
#: ../gtk/main.ui.h:43
-msgid "My current identity:"
-msgstr "Mon identité sip :"
+msgid "My current default identity:"
+msgstr "Mon identité sip par défaut :"
#: ../gtk/main.ui.h:44
msgid "Online users"