[Pkg-voip-commits] [ring] 01/03: Imported Upstream version 20160712.1.66bea8b~dfsg1
Alexandre Viau
aviau at moszumanska.debian.org
Wed Jul 13 13:58:54 UTC 2016
This is an automated email from the git hooks/post-receive script.
aviau pushed a commit to branch master
in repository ring.
commit 5cae43c541576a96d56520bbb9b6c4eacf76cd2c
Author: aviau <alexandre at alexandreviau.net>
Date: Wed Jul 13 09:55:29 2016 -0400
Imported Upstream version 20160712.1.66bea8b~dfsg1
---
.gitmodules | 3 +
client-gnome/CMakeLists.txt | 2 +
client-gnome/po/ar.po | 2 +-
client-gnome/po/bg.po | 6 +-
client-gnome/po/ca.po | 269 +++++++-------
client-gnome/po/{ca.po => el.po} | 39 +-
client-gnome/po/es.po | 7 +-
client-gnome/po/{nl.po => fi.po} | 32 +-
client-gnome/po/he.po | 20 +-
client-gnome/po/hr.po | 167 ++++-----
client-gnome/po/nl.po | 331 ++++++++---------
client-gnome/po/{ca.po => nl_NL.po} | 45 ++-
client-gnome/po/pt_BR.po | 7 +-
client-gnome/src/accountimportexportview.cpp | 411 +++++++++++++++++++++
client-gnome/src/accountimportexportview.h | 40 ++
client-gnome/src/accountview.cpp | 138 +++++--
client-gnome/src/ring_client.cpp | 22 +-
client-gnome/ui/accountimportexportview.ui | 211 +++++++++++
client-gnome/ui/accountview.ui | 28 +-
client-gnome/ui/ringiconmenu.ui | 18 -
client-gnome/ui/ui.gresource.xml | 2 +-
daemon/configure.ac | 56 +--
daemon/contrib/src/ffmpeg/rules.mak | 15 +-
daemon/contrib/src/gmp/rules.mak | 2 +-
daemon/contrib/src/gnutls/SHA512SUMS | 2 +-
.../src/gnutls/dtls-packet-reordering.patch | 5 -
daemon/contrib/src/gnutls/format-security.patch | 6 -
daemon/contrib/src/gnutls/rules.mak | 8 +-
daemon/contrib/src/gsm/include_ios.patch | 11 +
daemon/contrib/src/gsm/rules.mak | 1 +
daemon/contrib/src/jsoncpp/SHA512SUMS | 2 +-
daemon/contrib/src/jsoncpp/rules.mak | 2 +-
daemon/contrib/src/natpmp/SHA512SUMS | 1 +
daemon/contrib/src/natpmp/rules.mak | 21 ++
daemon/contrib/src/nettle/rules.mak | 13 +-
daemon/contrib/src/opus/rules.mak | 4 -
daemon/contrib/src/pjproject/gnutls.patch | 8 +-
daemon/contrib/src/speexdsp/rules.mak | 2 +-
daemon/contrib/src/uuid/rules.mak | 4 +
daemon/contrib/src/vpx/rules.mak | 18 +-
daemon/contrib/src/x264/rules.mak | 2 +
daemon/src/Makefile.am | 37 +-
daemon/src/account.cpp | 4 -
daemon/src/account_factory.cpp | 4 -
daemon/src/call.h | 2 -
daemon/src/client/callmanager.cpp | 2 -
daemon/src/client/configurationmanager.cpp | 26 --
daemon/src/manager.cpp | 12 -
daemon/src/manager.h | 4 -
daemon/src/media/audio/Makefile.am | 8 +
daemon/src/media/audio/coreaudio/Makefile.am | 4 +
daemon/src/media/audio/coreaudio/audiodevice.cpp | 4 +
daemon/src/media/audio/coreaudio/audiodevice.h | 6 +
daemon/src/media/audio/coreaudio/corelayer.cpp | 18 +-
daemon/src/media/audio/coreaudio/corelayer.h | 2 +
daemon/src/media/video/Makefile.am | 3 +-
daemon/src/ringdht/Makefile.am | 4 -
daemon/src/ringdht/ringaccount.cpp | 11 +
daemon/src/sip/sdp.cpp | 4 -
daemon/src/sip/sipaccount.cpp | 28 +-
daemon/src/sip/sipaccount.h | 4 -
daemon/src/sip/sipcall.cpp | 8 -
daemon/src/sip/sipcall.h | 2 -
daemon/src/sip/siptransport.cpp | 12 +-
daemon/src/sip/siptransport.h | 6 -
daemon/src/sip/sipvoiplink.cpp | 10 -
daemon/src/upnp/upnp_context.cpp | 407 +++++++++++++++-----
daemon/src/upnp/upnp_context.h | 124 ++++---
daemon/src/upnp/upnp_control.cpp | 18 +-
daemon/src/upnp/upnp_igd.h | 93 ++++-
docs/source/dev/releasing.rst | 2 +-
lrc/src/macromodel.cpp | 7 +-
lrc/src/private/videorenderermanager.cpp | 113 +++---
lrc/src/recentmodel.cpp | 4 +-
lrc/src/tlsmethodmodel.cpp | 17 +-
lrc/src/tlsmethodmodel.h | 3 +-
make-ring.py | 28 +-
77 files changed, 1999 insertions(+), 1025 deletions(-)
diff --git a/.gitmodules b/.gitmodules
index 002160e..83252bf 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -16,3 +16,6 @@
[submodule "client-macosx"]
path = client-macosx
url = https://gerrit-ring.savoirfairelinux.com/ring-client-macosx
+[submodule "client-ios"]
+ path = client-ios
+ url = https://gerrit-ring.savoirfairelinux.com/ring-client-ios
diff --git a/client-gnome/CMakeLists.txt b/client-gnome/CMakeLists.txt
index 0622c8e..1549826 100644
--- a/client-gnome/CMakeLists.txt
+++ b/client-gnome/CMakeLists.txt
@@ -310,6 +310,8 @@ SET( SRC_FILES
src/chatview.cpp
src/avatarmanipulation.h
src/avatarmanipulation.cpp
+ src/accountimportexportview.h
+ src/accountimportexportview.cpp
)
# compile glib resource files to c code
diff --git a/client-gnome/po/ar.po b/client-gnome/po/ar.po
index 4376275..0a34126 100644
--- a/client-gnome/po/ar.po
+++ b/client-gnome/po/ar.po
@@ -11,7 +11,7 @@ msgstr ""
"Project-Id-Version: Ring\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-13 09:43-0500\n"
-"PO-Revision-Date: 2016-04-14 15:25+0000\n"
+"PO-Revision-Date: 2016-05-12 17:43+0000\n"
"Last-Translator: Omar Mohamed <om_80_m at yahoo.com>\n"
"Language-Team: Arabic (http://www.transifex.com/savoirfairelinux/ring/language/ar/)\n"
"MIME-Version: 1.0\n"
diff --git a/client-gnome/po/bg.po b/client-gnome/po/bg.po
index 639b928..8a4e844 100644
--- a/client-gnome/po/bg.po
+++ b/client-gnome/po/bg.po
@@ -9,7 +9,7 @@ msgstr ""
"Project-Id-Version: Ring\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-13 09:43-0500\n"
-"PO-Revision-Date: 2016-03-28 16:48+0000\n"
+"PO-Revision-Date: 2016-06-06 19:35+0000\n"
"Last-Translator: Любомир Василев\n"
"Language-Team: Bulgarian (http://www.transifex.com/savoirfairelinux/ring/language/bg/)\n"
"MIME-Version: 1.0\n"
@@ -347,11 +347,11 @@ msgstr ""
#: ui/accountadvancedtab.ui:558 ui/accountadvancedtab.ui:632
msgid "Min"
-msgstr ""
+msgstr "Минимум"
#: ui/accountadvancedtab.ui:581 ui/accountadvancedtab.ui:655
msgid "Max"
-msgstr ""
+msgstr "Максимум"
#: ui/accountadvancedtab.ui:605
msgid "<b>Audio RTP Port Range</b>"
diff --git a/client-gnome/po/ca.po b/client-gnome/po/ca.po
index 280e138..ed302b4 100644
--- a/client-gnome/po/ca.po
+++ b/client-gnome/po/ca.po
@@ -4,13 +4,14 @@
#
# Translators:
# David <stakewinner00 at mykolab.com>, 2015
+# Jaume <retrasado.man at gmail.com>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Ring\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-13 09:43-0500\n"
-"PO-Revision-Date: 2016-03-24 20:09+0000\n"
-"Last-Translator: Guillaume Roguez\n"
+"PO-Revision-Date: 2016-05-26 12:59+0000\n"
+"Last-Translator: Jaume <retrasado.man at gmail.com>\n"
"Language-Team: Catalan (http://www.transifex.com/savoirfairelinux/ring/language/ca/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -29,47 +30,47 @@ msgstr "Nom"
#: src/accountaudiotab.cpp:195 src/accountvideotab.cpp:204
msgid "Bitrate"
-msgstr ""
+msgstr "Taxa de bits"
#: src/accountaudiotab.cpp:199
msgid "Samplerate"
-msgstr ""
+msgstr "Freqüència de mostreig"
#: src/accountgeneraltab.cpp:210
msgid "Alias"
-msgstr ""
+msgstr "Àlies"
#: src/accountgeneraltab.cpp:221
msgid "Type"
-msgstr ""
+msgstr "Tipus"
#: src/accountgeneraltab.cpp:250
msgid "auto-generating..."
-msgstr ""
+msgstr "autogenerant..."
#: src/accountgeneraltab.cpp:269
msgid "Hostname"
-msgstr ""
+msgstr "Nom d'amfitrió"
#: src/accountgeneraltab.cpp:279
msgid "Username"
-msgstr ""
+msgstr "Nom d'usuari"
#: src/accountgeneraltab.cpp:289
msgid "Password"
-msgstr ""
+msgstr "Contrasenya"
#: src/accountgeneraltab.cpp:302
msgid "Show password"
-msgstr ""
+msgstr "Mostra la contrasenya"
#: src/accountgeneraltab.cpp:308
msgid "Proxy"
-msgstr ""
+msgstr "Intermediari"
#: src/accountgeneraltab.cpp:318
msgid "Voicemail number"
-msgstr ""
+msgstr "Nombre de correu de veu"
#: src/accountgeneraltab.cpp:330
msgctxt "The DHT bootstrap server url"
@@ -78,15 +79,15 @@ msgstr ""
#: src/accountgeneraltab.cpp:342
msgid "Auto-answer calls"
-msgstr ""
+msgstr "Autorespondre trucades"
#: src/accountgeneraltab.cpp:350
msgid "UPnP enabled"
-msgstr ""
+msgstr "UPnP habitlitat"
#: src/accountgeneraltab.cpp:358
msgid "DTMF tone type:"
-msgstr ""
+msgstr "Tipus de to DTMF"
#: src/accountvideotab.cpp:200
msgctxt "The name of the codec"
@@ -96,22 +97,22 @@ msgstr "Nom"
#: src/accountview.cpp:159
msgctxt "Account settings"
msgid "General"
-msgstr ""
+msgstr "General"
#: src/accountview.cpp:163
msgctxt "Account settings"
msgid "Audio"
-msgstr ""
+msgstr "Àudio"
#: src/accountview.cpp:167
msgctxt "Account settings"
msgid "Video"
-msgstr ""
+msgstr "Vídeo"
#: src/accountview.cpp:171
msgctxt "Account settings"
msgid "Advanced"
-msgstr ""
+msgstr "Avançat"
#: src/accountview.cpp:175
msgctxt "Account settings"
@@ -121,11 +122,11 @@ msgstr "Seguretat"
#: src/accountview.cpp:229
#, c-format
msgid "Are you sure you want to delete account \"%s\"?"
-msgstr ""
+msgstr "Esteu segur que voleu esborrar el compte \"%s\"?"
#: src/accountview.cpp:313 src/accountview.cpp:315
msgid "New Account"
-msgstr ""
+msgstr "Compte Nou"
#: src/accountview.cpp:399
msgctxt "Account state column"
@@ -135,24 +136,24 @@ msgstr "Habilitat"
#: src/accountview.cpp:405
msgctxt "Account alias (name) column"
msgid "Alias"
-msgstr ""
+msgstr "Àlies"
#: src/accountview.cpp:409
msgctxt "Account status column"
msgid "Status"
-msgstr ""
+msgstr "Estat"
#: src/contactsview.cpp:305
msgid "_Copy name"
-msgstr ""
+msgstr "_Copia nom"
#: src/contactsview.cpp:316 src/contactsview.cpp:331
msgid "_Copy number"
-msgstr ""
+msgstr "_Copia telèfon"
#: src/dialogs.c:53
msgid "Working..."
-msgstr ""
+msgstr "Treballant..."
#: src/dialogs.c:84
#, c-format
@@ -166,170 +167,170 @@ msgstr ""
msgid ""
"The GNOME client for Ring.\n"
"Ring is a secured and distributed communication software."
-msgstr ""
+msgstr "El client de GNOME per a Ring.\nRing és un programari de comunicació segur i distribuït."
#: src/editcontactview.cpp:196
msgctxt "Phone number category"
msgid "home"
-msgstr ""
+msgstr "casa"
#: src/generalsettingsview.cpp:94
msgid ""
"Are you sure you want to clear all your history?\n"
"This operation will also reset the Frequent Contacts list"
-msgstr ""
+msgstr "Esteu segura que voleu esborrar tot el vostre historial?\nAquesta operació també esborrarà la llista de Contactes Freqüents."
#: src/historyview.cpp:184
msgid "_Copy"
-msgstr ""
+msgstr "_Copia"
#: src/historyview.cpp:402
msgctxt "Call history"
msgid "Call"
-msgstr ""
+msgstr "Trucada"
#: src/historyview.cpp:447
msgctxt "Call history"
msgid "Date"
-msgstr ""
+msgstr "Data"
#: src/ringnotify.cpp:86
msgid "Incoming call"
-msgstr ""
+msgstr "Trucada entrant"
#: src/ringnotify.cpp:169
#, c-format
msgctxt "Text message notification"
msgid "%s says:"
-msgstr ""
+msgstr "%s diu:"
#: src/ring_client_options.c:65
msgid "Enable debug"
-msgstr ""
+msgstr "Habilitar depuració"
#: src/ring_client_options.c:67
msgid ""
"Restores the hidden state of the main window (only applicable to the primary"
" instance)"
-msgstr ""
+msgstr "Restaura l'estat ocult de la finestra principal (només s'aplica a la instància principal)"
#: src/ring_client_options.c:84
msgid "- GNOME client for Ring"
-msgstr ""
+msgstr "- Client de GNOME per a Ring"
#: src/backends/edscontactbackend.cpp:201
msgid "Unknown EDS addressbook"
-msgstr ""
+msgstr "Llibreta d'adreces EDS desconeguda"
#: src/backends/edscontactbackend.cpp:221
msgctxt "Backend type"
msgid "Contacts"
-msgstr ""
+msgstr "Contactes"
#: src/utils/menus.cpp:67
msgid "_Add to contact"
-msgstr ""
+msgstr "_Afegir al contacte"
#: src/ringmainwindow.cpp:944
msgctxt ""
"Please try to make the translation 50 chars or less so that it fits into the"
" layout"
msgid "Search contacts or enter number"
-msgstr ""
+msgstr "Busqueu contactes o introduïu el nombre"
#: src/ringwelcomeview.cpp:61
msgid "fetching RingID..."
-msgstr ""
+msgstr "buscant RingID"
#: src/ringwelcomeview.cpp:92
msgid ""
"Ring is a secure and distributed voice, video, and chat communication "
"platform that requires no centralized server and leaves the power of privacy"
" in the hands of the user."
-msgstr ""
+msgstr "Ring és una plataforma de veu, vídeo i xat segura i distribuïda que no requereix un servidor central i deixa en mans de l'usuari el poder de la privacitat."
#: src/ringwelcomeview.cpp:102
msgctxt "Do not translate \"RingID\""
msgid ""
"This is your RingID.\n"
"Copy and share it with your friends!"
-msgstr ""
+msgstr "Aquest és el vostre RingID.\nCopieu i compartiu amb les vostres amistats!"
#: src/video/video_widget.cpp:478
msgid "Share screen area"
-msgstr ""
+msgstr "Compartir pantalla"
#: src/video/video_widget.cpp:484
msgid "Share file"
-msgstr ""
+msgstr "Compartir arxiu"
#: ui/accountadvancedtab.ui:81
msgid "Registration expire timeout (seconds):"
-msgstr ""
+msgstr "Temps d'expiració del registre (segons):"
#: ui/accountadvancedtab.ui:103
msgid "Allow calls from unknown peers"
-msgstr ""
+msgstr "Permetre trucades de nodes desconeguts"
#: ui/accountadvancedtab.ui:117
msgid "Allow calls from peers in your call history"
-msgstr ""
+msgstr "Permetre trucades de nodes del vostre historial de trucades"
#: ui/accountadvancedtab.ui:131
msgid "Allow calls from peers in your contacts list"
-msgstr ""
+msgstr "Permetre trucades de nodes de la vostra llista de contactes"
#: ui/accountadvancedtab.ui:149
msgid "<b>Registration</b>"
-msgstr ""
+msgstr "<b>Registre</b>"
#: ui/accountadvancedtab.ui:176
msgid "Use random port"
-msgstr ""
+msgstr "Fer servir un port aleatori"
#: ui/accountadvancedtab.ui:197
msgid "Local port:"
-msgstr ""
+msgstr "Port local:"
#: ui/accountadvancedtab.ui:223
msgid "<b>Network Interface</b>"
-msgstr ""
+msgstr "<b>Interfície de xarxa</b>"
#: ui/accountadvancedtab.ui:249
msgid "Same as local parameters"
-msgstr ""
+msgstr "Igual que els paràmetres locals"
#: ui/accountadvancedtab.ui:264
msgid "Set published address and port:"
-msgstr ""
+msgstr "Establir port i adreça publicats:"
#: ui/accountadvancedtab.ui:288
msgid "Address"
-msgstr ""
+msgstr "Adreça"
#: ui/accountadvancedtab.ui:310
msgid "Port"
-msgstr ""
+msgstr "Port"
#: ui/accountadvancedtab.ui:336
msgid "Use STUN"
-msgstr ""
+msgstr "Utilitza STUN"
#: ui/accountadvancedtab.ui:359 ui/accountadvancedtab.ui:408
msgid "server URL"
-msgstr ""
+msgstr "URl del servidor"
#: ui/accountadvancedtab.ui:385
msgid "Use TURN"
-msgstr ""
+msgstr "Utilitza TURN"
#: ui/accountadvancedtab.ui:430
msgid "username"
-msgstr ""
+msgstr "nom d'usuari"
#: ui/accountadvancedtab.ui:451
msgid "password"
-msgstr ""
+msgstr "contrasenya"
#: ui/accountadvancedtab.ui:475
msgid "realm"
@@ -337,7 +338,7 @@ msgstr ""
#: ui/accountadvancedtab.ui:504
msgid "<b>Published Address</b>"
-msgstr ""
+msgstr "<b>Adreça publicada</b>"
#: ui/accountadvancedtab.ui:533
msgid ""
@@ -347,19 +348,19 @@ msgstr ""
#: ui/accountadvancedtab.ui:558 ui/accountadvancedtab.ui:632
msgid "Min"
-msgstr ""
+msgstr "Mín"
#: ui/accountadvancedtab.ui:581 ui/accountadvancedtab.ui:655
msgid "Max"
-msgstr ""
+msgstr "Màx"
#: ui/accountadvancedtab.ui:605
msgid "<b>Audio RTP Port Range</b>"
-msgstr ""
+msgstr "<b>Interval de Ports d'Àudio RTP</b>"
#: ui/accountadvancedtab.ui:679
msgid "<b>Video RTP Port Range</b>"
-msgstr ""
+msgstr "<b>Interval de Ports de Vídeo RTP</b>"
#: ui/accountadvancedtab.ui:695
msgid "<b>SDP Session Negotiation (ICE Fallback)</b>"
@@ -367,31 +368,31 @@ msgstr ""
#: ui/accountaudiotab.ui:59 ui/accountvideotab.ui:59
msgid "Up"
-msgstr ""
+msgstr "Amunt"
#: ui/accountaudiotab.ui:66 ui/accountvideotab.ui:66
msgid "Down"
-msgstr ""
+msgstr "Avall"
#: ui/accountaudiotab.ui:77 ui/accountvideotab.ui:77
msgid "<b>Codecs</b>"
-msgstr ""
+msgstr "<b>Còdecs</b>"
#: ui/accountgeneraltab.ui:42
msgid "<b>Account</b>"
-msgstr ""
+msgstr "<b>Comptes</b>"
#: ui/accountgeneraltab.ui:80
msgid "<b>Parameters</b>"
-msgstr ""
+msgstr "<b>Paràmetres</b>"
#: ui/accountsecuritytab.ui:37
msgid "Encrypt media streams (SRTP)"
-msgstr ""
+msgstr "Xifra el flux de mitjans (SRTP)"
#: ui/accountsecuritytab.ui:58
msgid "Key exchange protocol"
-msgstr ""
+msgstr "Protocol d'intercanvi de claus"
#: ui/accountsecuritytab.ui:76
msgid "Fallback on RTP on encryption failure"
@@ -399,19 +400,19 @@ msgstr ""
#: ui/accountsecuritytab.ui:94
msgid "<b>Media Stream Encryption</b>"
-msgstr ""
+msgstr "<b>Xifratge del Flux de Mitjans</b>"
#: ui/accountsecuritytab.ui:121
msgid "Encrypt negotiation (TLS)"
-msgstr ""
+msgstr "Negociació de xifrat (TLS)"
#: ui/accountsecuritytab.ui:146
msgid "CA certificate"
-msgstr ""
+msgstr "Certificat CA"
#: ui/accountsecuritytab.ui:183
msgid "User certificate"
-msgstr ""
+msgstr "Certificat d'usuari"
#: ui/accountsecuritytab.ui:220
msgid "Private key"
@@ -419,27 +420,27 @@ msgstr "Clau privada"
#: ui/accountsecuritytab.ui:243
msgid "Private key password"
-msgstr ""
+msgstr "Contrasenya de la clau privada"
#: ui/accountsecuritytab.ui:290
msgid "TLS protocol method"
-msgstr ""
+msgstr "Mètode del protocol TLS"
#: ui/accountsecuritytab.ui:313
msgid "Outgoing TLS server name"
-msgstr ""
+msgstr "Servidor TLS sortint"
#: ui/accountsecuritytab.ui:335
msgid "Negotiation timeout (seconds)"
-msgstr ""
+msgstr "Temps d'espera de la negociació (segons)"
#: ui/accountsecuritytab.ui:369
msgid "Use default ciphers"
-msgstr ""
+msgstr "Utilitza xifrats per defecte"
#: ui/accountsecuritytab.ui:385
msgid "Use custom cipher list"
-msgstr ""
+msgstr "Utilitza llista de xifrats personalitzats"
#: ui/accountsecuritytab.ui:442
msgid "Verify incoming certificates (server side)"
@@ -459,7 +460,7 @@ msgstr ""
#: ui/accountvideotab.ui:90
msgid "Enable Video"
-msgstr ""
+msgstr "Habilita el vídeo"
#: ui/accountview.ui:59
msgid "<b>−</b>"
@@ -471,7 +472,7 @@ msgstr ""
#: ui/choosecontactview.ui:34
msgid "Create New"
-msgstr ""
+msgstr "Crea Nou"
#: ui/currentcallview.ui:73
msgid "Send"
@@ -479,56 +480,56 @@ msgstr "Enviar"
#: ui/currentcallview.ui:191
msgid "End this call"
-msgstr ""
+msgstr "Finalitza aquesta trucada"
#: ui/currentcallview.ui:195 ui/currentcallview.ui:356
msgid "End call"
-msgstr ""
+msgstr "Finalitza la trucada"
#: ui/currentcallview.ui:213
msgid "Toggle hold"
-msgstr ""
+msgstr "Mantenir en espera"
#: ui/currentcallview.ui:217 ui/currentcallview.ui:239
#: ui/currentcallview.ui:347
msgid "Hold"
-msgstr ""
+msgstr "En espera"
#: ui/currentcallview.ui:235
msgid "Toggle mute audio"
-msgstr ""
+msgstr "Activa silenci d'àudio"
#: ui/currentcallview.ui:257
msgid "Toggle mute video"
-msgstr ""
+msgstr "Activa silenci de vídeo"
#: ui/currentcallview.ui:261 ui/currentcallview.ui:338
msgid "Mute video"
-msgstr ""
+msgstr "Silencia el vídeo"
#: ui/currentcallview.ui:280
msgid "Toggle record audio"
-msgstr ""
+msgstr "Activa silenci"
#: ui/currentcallview.ui:283
msgid "Record audio"
-msgstr ""
+msgstr "Grava l'àudio"
#: ui/currentcallview.ui:299
msgid "Toggle show chat"
-msgstr ""
+msgstr "Mostra el xat"
#: ui/currentcallview.ui:303 ui/currentcallview.ui:320
msgid "Chat"
-msgstr ""
+msgstr "Xat"
#: ui/currentcallview.ui:329
msgid "Mute audio"
-msgstr ""
+msgstr "Silencia l'àudio"
#: ui/currentcallview.ui:365
msgid "Record"
-msgstr ""
+msgstr "Grava"
#: ui/editcontactview.ui:12
msgid "Select addressbook"
@@ -536,7 +537,7 @@ msgstr ""
#: ui/editcontactview.ui:15
msgid "Addressbook"
-msgstr ""
+msgstr "Llibreta d'adreces"
#: ui/editcontactview.ui:29
msgid "Name"
@@ -544,7 +545,7 @@ msgstr "Nom"
#: ui/editcontactview.ui:32
msgid "Contact name"
-msgstr ""
+msgstr "Nom de contacte"
#: ui/editcontactview.ui:47
msgid "Select how this number will be categorized"
@@ -560,19 +561,19 @@ msgstr ""
#: ui/editcontactview.ui:72
msgid "Number or Ring ID"
-msgstr ""
+msgstr "Nombre o Ring ID"
#: ui/editcontactview.ui:83
msgid "Save"
-msgstr ""
+msgstr "Desa"
#: ui/generalsettingsview.ui:32
msgid "<b>Ring Settings</b>"
-msgstr ""
+msgstr "<b>Opcions de Ring</b>"
#: ui/generalsettingsview.ui:46
msgid "Start Ring on login"
-msgstr ""
+msgstr "Obre Ring a l'inici"
#: ui/generalsettingsview.ui:55
msgid "Hide Ring on close instead of quitting."
@@ -604,23 +605,23 @@ msgstr ""
#: ui/generalsettingsview.ui:160
msgid "Clear all history"
-msgstr ""
+msgstr "Neteja l'historial"
#: ui/incomingcallview.ui:88
msgid "Incoming..."
-msgstr ""
+msgstr "Entrant..."
#: ui/incomingcallview.ui:122
msgid " Accept"
-msgstr ""
+msgstr "Accepta"
#: ui/incomingcallview.ui:137
msgid " Reject"
-msgstr ""
+msgstr "Rebutja"
#: ui/incomingcallview.ui:152
msgid " Hang-up"
-msgstr ""
+msgstr "Penja"
#: ui/mediasettingsview.ui:36
msgid "Audio manager:"
@@ -644,88 +645,88 @@ msgstr ""
#: ui/mediasettingsview.ui:163
msgid "Device:"
-msgstr ""
+msgstr "Dispositiu"
#: ui/mediasettingsview.ui:175
msgid "Channel:"
-msgstr ""
+msgstr "Canal:"
#: ui/mediasettingsview.ui:187
msgid "Resolution:"
-msgstr ""
+msgstr "Resolució"
#: ui/mediasettingsview.ui:199
msgid "Frame rate:"
-msgstr ""
+msgstr "Velocitat de fotogrames"
#: ui/mediasettingsview.ui:258
msgid "<b>Camera Settings</b>"
-msgstr ""
+msgstr "<b>Opcions de Càmera</b>"
#: ui/ringgearsmenu.ui:13
msgid "_About"
-msgstr ""
+msgstr "_Sobre"
#: ui/ringgearsmenu.ui:19
msgid "_Quit"
-msgstr ""
+msgstr "_Tanca"
#: ui/ringmainwindow.ui:20
msgid "Menu"
-msgstr ""
+msgstr "Menú"
#: ui/ringmainwindow.ui:54
msgid "General"
-msgstr ""
+msgstr "General"
#: ui/ringmainwindow.ui:64
msgid "Media"
-msgstr ""
+msgstr "Mitjans"
#: ui/ringmainwindow.ui:75
msgid "Accounts"
-msgstr ""
+msgstr "Comptes"
#: ui/ringmainwindow.ui:93
msgid "Settings"
-msgstr ""
+msgstr "Opcions"
#: ui/ringmainwindow.ui:192
msgid "Conversations"
-msgstr ""
+msgstr "Converses"
#: ui/ringmainwindow.ui:211
msgid "Contacts"
-msgstr ""
+msgstr "Contactes"
#: ui/ringmainwindow.ui:230
msgid "History"
-msgstr ""
+msgstr "Historial"
#: ui/ringmainwindow.ui:290
msgid "Welcome to "
-msgstr ""
+msgstr "Benvingut a"
#: ui/ringmainwindow.ui:307
msgid "Enter your alias to get started:"
-msgstr ""
+msgstr "Introduïu el vostre àlies per començar:"
#: ui/ringmainwindow.ui:324
msgid "Generating your Ring account..."
-msgstr ""
+msgstr "Generant el vostre compte de Ring..."
#: ui/ringmainwindow.ui:338
msgid "Next"
-msgstr ""
+msgstr "Següent"
#: ui/ringmainwindow.ui:360
msgid "Your Ring account has been created with the following Ring ID:"
-msgstr ""
+msgstr "El vostre compte de Ring ha sigut creat amb el següent Ring ID:"
#: ui/ringmainwindow.ui:375
msgid "Share it with your friends so they can contact you via Ring!"
-msgstr ""
+msgstr "Compartiu amb els vostres amics per que puguen contactar-vos a través de Ring!"
#: ui/ringmainwindow.ui:380
msgid "Done"
-msgstr ""
+msgstr "Fet"
diff --git a/client-gnome/po/ca.po b/client-gnome/po/el.po
similarity index 97%
copy from client-gnome/po/ca.po
copy to client-gnome/po/el.po
index 280e138..55c6052 100644
--- a/client-gnome/po/ca.po
+++ b/client-gnome/po/el.po
@@ -3,29 +3,28 @@
# This file is distributed under the same license as the Ring package.
#
# Translators:
-# David <stakewinner00 at mykolab.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: Ring\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-13 09:43-0500\n"
-"PO-Revision-Date: 2016-03-24 20:09+0000\n"
+"PO-Revision-Date: 2016-06-06 20:47+0000\n"
"Last-Translator: Guillaume Roguez\n"
-"Language-Team: Catalan (http://www.transifex.com/savoirfairelinux/ring/language/ca/)\n"
+"Language-Team: Greek (http://www.transifex.com/savoirfairelinux/ring/language/el/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Language: ca\n"
+"Language: el\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: src/accountaudiotab.cpp:185 src/accountvideotab.cpp:194
msgid "Enabled"
-msgstr "Habilitat"
+msgstr ""
#: src/accountaudiotab.cpp:191
msgctxt "Name of the codec"
msgid "Name"
-msgstr "Nom"
+msgstr "Όνομα"
#: src/accountaudiotab.cpp:195 src/accountvideotab.cpp:204
msgid "Bitrate"
@@ -41,7 +40,7 @@ msgstr ""
#: src/accountgeneraltab.cpp:221
msgid "Type"
-msgstr ""
+msgstr "Τύπος"
#: src/accountgeneraltab.cpp:250
msgid "auto-generating..."
@@ -49,7 +48,7 @@ msgstr ""
#: src/accountgeneraltab.cpp:269
msgid "Hostname"
-msgstr ""
+msgstr "Hostname"
#: src/accountgeneraltab.cpp:279
msgid "Username"
@@ -91,7 +90,7 @@ msgstr ""
#: src/accountvideotab.cpp:200
msgctxt "The name of the codec"
msgid "Name"
-msgstr "Nom"
+msgstr "Όνομα"
#: src/accountview.cpp:159
msgctxt "Account settings"
@@ -116,7 +115,7 @@ msgstr ""
#: src/accountview.cpp:175
msgctxt "Account settings"
msgid "Security"
-msgstr "Seguretat"
+msgstr ""
#: src/accountview.cpp:229
#, c-format
@@ -130,7 +129,7 @@ msgstr ""
#: src/accountview.cpp:399
msgctxt "Account state column"
msgid "Enabled"
-msgstr "Habilitat"
+msgstr ""
#: src/accountview.cpp:405
msgctxt "Account alias (name) column"
@@ -191,7 +190,7 @@ msgstr ""
#: src/historyview.cpp:447
msgctxt "Call history"
msgid "Date"
-msgstr ""
+msgstr "Ημερομηνία"
#: src/ringnotify.cpp:86
msgid "Incoming call"
@@ -224,7 +223,7 @@ msgstr ""
#: src/backends/edscontactbackend.cpp:221
msgctxt "Backend type"
msgid "Contacts"
-msgstr ""
+msgstr "Επαφές"
#: src/utils/menus.cpp:67
msgid "_Add to contact"
@@ -309,7 +308,7 @@ msgstr ""
#: ui/accountadvancedtab.ui:310
msgid "Port"
-msgstr ""
+msgstr "Port"
#: ui/accountadvancedtab.ui:336
msgid "Use STUN"
@@ -415,7 +414,7 @@ msgstr ""
#: ui/accountsecuritytab.ui:220
msgid "Private key"
-msgstr "Clau privada"
+msgstr ""
#: ui/accountsecuritytab.ui:243
msgid "Private key password"
@@ -475,7 +474,7 @@ msgstr ""
#: ui/currentcallview.ui:73
msgid "Send"
-msgstr "Enviar"
+msgstr ""
#: ui/currentcallview.ui:191
msgid "End this call"
@@ -492,7 +491,7 @@ msgstr ""
#: ui/currentcallview.ui:217 ui/currentcallview.ui:239
#: ui/currentcallview.ui:347
msgid "Hold"
-msgstr ""
+msgstr "Αναμονή"
#: ui/currentcallview.ui:235
msgid "Toggle mute audio"
@@ -540,7 +539,7 @@ msgstr ""
#: ui/editcontactview.ui:29
msgid "Name"
-msgstr "Nom"
+msgstr "Όνομα"
#: ui/editcontactview.ui:32
msgid "Contact name"
@@ -696,11 +695,11 @@ msgstr ""
#: ui/ringmainwindow.ui:211
msgid "Contacts"
-msgstr ""
+msgstr "Επαφές"
#: ui/ringmainwindow.ui:230
msgid "History"
-msgstr ""
+msgstr "Ιστορικό"
#: ui/ringmainwindow.ui:290
msgid "Welcome to "
diff --git a/client-gnome/po/es.po b/client-gnome/po/es.po
index f4a97db..2073bad 100644
--- a/client-gnome/po/es.po
+++ b/client-gnome/po/es.po
@@ -6,6 +6,7 @@
# David <stakewinner00 at mykolab.com>, 2015
# Emiliano Ariel Vazquez <emilianovazquez at gmail.com>, 2015
# Ernesto Rodriguez Ortiz <ernesto.rodriguezortiz at savoirfairelinux.com>, 2015-2016
+# Juanjo Faico <juanjofaico22 at openmailbox.org>, 2016
# Jusore Mondos <jusore at gmail.com>, 2016
# Stepan Salenikovich, 2015
msgid ""
@@ -13,8 +14,8 @@ msgstr ""
"Project-Id-Version: Ring\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-13 09:43-0500\n"
-"PO-Revision-Date: 2016-03-29 03:06+0000\n"
-"Last-Translator: Ernesto Rodriguez Ortiz <ernesto.rodriguezortiz at savoirfairelinux.com>\n"
+"PO-Revision-Date: 2016-04-29 17:51+0000\n"
+"Last-Translator: Juanjo Faico <juanjofaico22 at openmailbox.org>\n"
"Language-Team: Spanish (http://www.transifex.com/savoirfairelinux/ring/language/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -668,7 +669,7 @@ msgstr "<b>Configuración de la cámara</b>"
#: ui/ringgearsmenu.ui:13
msgid "_About"
-msgstr "_Sobre"
+msgstr "_Acerca de"
#: ui/ringgearsmenu.ui:19
msgid "_Quit"
diff --git a/client-gnome/po/nl.po b/client-gnome/po/fi.po
similarity index 97%
copy from client-gnome/po/nl.po
copy to client-gnome/po/fi.po
index 3cdd9e3..0348a73 100644
--- a/client-gnome/po/nl.po
+++ b/client-gnome/po/fi.po
@@ -8,13 +8,13 @@ msgstr ""
"Project-Id-Version: Ring\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-13 09:43-0500\n"
-"PO-Revision-Date: 2016-03-24 20:09+0000\n"
-"Last-Translator: Guillaume Roguez\n"
-"Language-Team: Dutch (http://www.transifex.com/savoirfairelinux/ring/language/nl/)\n"
+"PO-Revision-Date: 2015-09-10 22:02+0000\n"
+"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
+"Language-Team: Finnish (http://www.transifex.com/savoirfairelinux/ring/language/fi/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Language: nl\n"
+"Language: fi\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: src/accountaudiotab.cpp:185 src/accountvideotab.cpp:194
@@ -24,7 +24,7 @@ msgstr ""
#: src/accountaudiotab.cpp:191
msgctxt "Name of the codec"
msgid "Name"
-msgstr ""
+msgstr "Nimi"
#: src/accountaudiotab.cpp:195 src/accountvideotab.cpp:204
msgid "Bitrate"
@@ -36,7 +36,7 @@ msgstr ""
#: src/accountgeneraltab.cpp:210
msgid "Alias"
-msgstr "Alias"
+msgstr ""
#: src/accountgeneraltab.cpp:221
msgid "Type"
@@ -48,15 +48,15 @@ msgstr ""
#: src/accountgeneraltab.cpp:269
msgid "Hostname"
-msgstr "Hostnaam"
+msgstr ""
#: src/accountgeneraltab.cpp:279
msgid "Username"
-msgstr "Gebruikersnaam"
+msgstr ""
#: src/accountgeneraltab.cpp:289
msgid "Password"
-msgstr "Wachtwoord"
+msgstr ""
#: src/accountgeneraltab.cpp:302
msgid "Show password"
@@ -90,7 +90,7 @@ msgstr ""
#: src/accountvideotab.cpp:200
msgctxt "The name of the codec"
msgid "Name"
-msgstr ""
+msgstr "Nimi"
#: src/accountview.cpp:159
msgctxt "Account settings"
@@ -100,12 +100,12 @@ msgstr ""
#: src/accountview.cpp:163
msgctxt "Account settings"
msgid "Audio"
-msgstr ""
+msgstr "Ääni"
#: src/accountview.cpp:167
msgctxt "Account settings"
msgid "Video"
-msgstr ""
+msgstr "Video"
#: src/accountview.cpp:171
msgctxt "Account settings"
@@ -134,7 +134,7 @@ msgstr ""
#: src/accountview.cpp:405
msgctxt "Account alias (name) column"
msgid "Alias"
-msgstr "Alias"
+msgstr ""
#: src/accountview.cpp:409
msgctxt "Account status column"
@@ -366,11 +366,11 @@ msgstr ""
#: ui/accountaudiotab.ui:59 ui/accountvideotab.ui:59
msgid "Up"
-msgstr ""
+msgstr "Ylös"
#: ui/accountaudiotab.ui:66 ui/accountvideotab.ui:66
msgid "Down"
-msgstr ""
+msgstr "Alas"
#: ui/accountaudiotab.ui:77 ui/accountvideotab.ui:77
msgid "<b>Codecs</b>"
@@ -539,7 +539,7 @@ msgstr ""
#: ui/editcontactview.ui:29
msgid "Name"
-msgstr ""
+msgstr "Nimi"
#: ui/editcontactview.ui:32
msgid "Contact name"
diff --git a/client-gnome/po/he.po b/client-gnome/po/he.po
index 3a07d50..6b0ef81 100644
--- a/client-gnome/po/he.po
+++ b/client-gnome/po/he.po
@@ -4,14 +4,14 @@
#
# Translators:
# FIRST AUTHOR <EMAIL at ADDRESS>, 2014
-# GenghisKhan <genghiskhan at gmx.ca>, 2015
+# GenghisKhan <genghiskhan at gmx.ca>, 2015-2016
msgid ""
msgstr ""
"Project-Id-Version: Ring\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-13 09:43-0500\n"
-"PO-Revision-Date: 2016-03-24 20:09+0000\n"
-"Last-Translator: Guillaume Roguez\n"
+"PO-Revision-Date: 2016-05-23 00:25+0000\n"
+"Last-Translator: GenghisKhan <genghiskhan at gmx.ca>\n"
"Language-Team: Hebrew (http://www.transifex.com/savoirfairelinux/ring/language/he/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -236,7 +236,7 @@ msgctxt ""
"Please try to make the translation 50 chars or less so that it fits into the"
" layout"
msgid "Search contacts or enter number"
-msgstr ""
+msgstr "חפש אנשי קשר או הזן מספר"
#: src/ringwelcomeview.cpp:61
msgid "fetching RingID..."
@@ -258,11 +258,11 @@ msgstr ""
#: src/video/video_widget.cpp:478
msgid "Share screen area"
-msgstr ""
+msgstr "שתף אזור מסך"
#: src/video/video_widget.cpp:484
msgid "Share file"
-msgstr ""
+msgstr "שתף קובץ"
#: ui/accountadvancedtab.ui:81
msgid "Registration expire timeout (seconds):"
@@ -388,7 +388,7 @@ msgstr "<b>פרמטרים</b>"
#: ui/accountsecuritytab.ui:37
msgid "Encrypt media streams (SRTP)"
-msgstr ""
+msgstr "הצפן זרמי מדיה (SRTP)"
#: ui/accountsecuritytab.ui:58
msgid "Key exchange protocol"
@@ -605,11 +605,11 @@ msgstr ""
#: ui/generalsettingsview.ui:160
msgid "Clear all history"
-msgstr ""
+msgstr "טהר היסטוריה"
#: ui/incomingcallview.ui:88
msgid "Incoming..."
-msgstr ""
+msgstr "קריאה נכנסת..."
#: ui/incomingcallview.ui:122
msgid " Accept"
@@ -693,7 +693,7 @@ msgstr "הגדרות"
#: ui/ringmainwindow.ui:192
msgid "Conversations"
-msgstr ""
+msgstr "דיונים"
#: ui/ringmainwindow.ui:211
msgid "Contacts"
diff --git a/client-gnome/po/hr.po b/client-gnome/po/hr.po
index 52f2c06..1f443af 100644
--- a/client-gnome/po/hr.po
+++ b/client-gnome/po/hr.po
@@ -3,13 +3,14 @@
# This file is distributed under the same license as the Ring package.
#
# Translators:
+# Ivica Kolić <ikoli at yahoo.com>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Ring\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-13 09:43-0500\n"
-"PO-Revision-Date: 2016-03-24 20:09+0000\n"
-"Last-Translator: Guillaume Roguez\n"
+"PO-Revision-Date: 2016-06-05 22:50+0000\n"
+"Last-Translator: Ivica Kolić <ikoli at yahoo.com>\n"
"Language-Team: Croatian (http://www.transifex.com/savoirfairelinux/ring/language/hr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -24,7 +25,7 @@ msgstr "Uključeno"
#: src/accountaudiotab.cpp:191
msgctxt "Name of the codec"
msgid "Name"
-msgstr ""
+msgstr "Ime"
#: src/accountaudiotab.cpp:195 src/accountvideotab.cpp:204
msgid "Bitrate"
@@ -40,7 +41,7 @@ msgstr "Alias"
#: src/accountgeneraltab.cpp:221
msgid "Type"
-msgstr ""
+msgstr "Vrsta"
#: src/accountgeneraltab.cpp:250
msgid "auto-generating..."
@@ -56,7 +57,7 @@ msgstr "Korisničko ime"
#: src/accountgeneraltab.cpp:289
msgid "Password"
-msgstr ""
+msgstr "Lozinka"
#: src/accountgeneraltab.cpp:302
msgid "Show password"
@@ -64,11 +65,11 @@ msgstr "Prikaži lozinku"
#: src/accountgeneraltab.cpp:308
msgid "Proxy"
-msgstr ""
+msgstr "Proxy"
#: src/accountgeneraltab.cpp:318
msgid "Voicemail number"
-msgstr ""
+msgstr "Broj govorne pošte"
#: src/accountgeneraltab.cpp:330
msgctxt "The DHT bootstrap server url"
@@ -81,7 +82,7 @@ msgstr "Automatski primi pozive"
#: src/accountgeneraltab.cpp:350
msgid "UPnP enabled"
-msgstr ""
+msgstr "UPnP omogućen"
#: src/accountgeneraltab.cpp:358
msgid "DTMF tone type:"
@@ -90,7 +91,7 @@ msgstr ""
#: src/accountvideotab.cpp:200
msgctxt "The name of the codec"
msgid "Name"
-msgstr ""
+msgstr "Ime"
#: src/accountview.cpp:159
msgctxt "Account settings"
@@ -115,16 +116,16 @@ msgstr "Napredno"
#: src/accountview.cpp:175
msgctxt "Account settings"
msgid "Security"
-msgstr ""
+msgstr "Sigurnost"
#: src/accountview.cpp:229
#, c-format
msgid "Are you sure you want to delete account \"%s\"?"
-msgstr ""
+msgstr "Jeste li sigurni da želite izbrisati račun \"%s\"?"
#: src/accountview.cpp:313 src/accountview.cpp:315
msgid "New Account"
-msgstr ""
+msgstr "Novi račun"
#: src/accountview.cpp:399
msgctxt "Account state column"
@@ -139,15 +140,15 @@ msgstr "Alias"
#: src/accountview.cpp:409
msgctxt "Account status column"
msgid "Status"
-msgstr ""
+msgstr "Status"
#: src/contactsview.cpp:305
msgid "_Copy name"
-msgstr ""
+msgstr "_Kopiraj ime"
#: src/contactsview.cpp:316 src/contactsview.cpp:331
msgid "_Copy number"
-msgstr ""
+msgstr "_Kopiraj broj"
#: src/dialogs.c:53
msgid "Working..."
@@ -180,7 +181,7 @@ msgstr ""
#: src/historyview.cpp:184
msgid "_Copy"
-msgstr ""
+msgstr "_Kopiraj"
#: src/historyview.cpp:402
msgctxt "Call history"
@@ -190,17 +191,17 @@ msgstr "Nazovi"
#: src/historyview.cpp:447
msgctxt "Call history"
msgid "Date"
-msgstr ""
+msgstr "Datum"
#: src/ringnotify.cpp:86
msgid "Incoming call"
-msgstr ""
+msgstr "Dolazni poziv"
#: src/ringnotify.cpp:169
#, c-format
msgctxt "Text message notification"
msgid "%s says:"
-msgstr ""
+msgstr "%s kaže:"
#: src/ring_client_options.c:65
msgid "Enable debug"
@@ -214,27 +215,27 @@ msgstr ""
#: src/ring_client_options.c:84
msgid "- GNOME client for Ring"
-msgstr ""
+msgstr "- GNOME klijent za Ring"
#: src/backends/edscontactbackend.cpp:201
msgid "Unknown EDS addressbook"
-msgstr ""
+msgstr "Nepoznati EDS adresar"
#: src/backends/edscontactbackend.cpp:221
msgctxt "Backend type"
msgid "Contacts"
-msgstr ""
+msgstr "Kontakti"
#: src/utils/menus.cpp:67
msgid "_Add to contact"
-msgstr ""
+msgstr "_Dodaj u kontakt"
#: src/ringmainwindow.cpp:944
msgctxt ""
"Please try to make the translation 50 chars or less so that it fits into the"
" layout"
msgid "Search contacts or enter number"
-msgstr ""
+msgstr "Traži kontakt ili unesi broj"
#: src/ringwelcomeview.cpp:61
msgid "fetching RingID..."
@@ -256,11 +257,11 @@ msgstr ""
#: src/video/video_widget.cpp:478
msgid "Share screen area"
-msgstr ""
+msgstr "Dijelite područje zaslona"
#: src/video/video_widget.cpp:484
msgid "Share file"
-msgstr ""
+msgstr "Dijeli datoteku"
#: ui/accountadvancedtab.ui:81
msgid "Registration expire timeout (seconds):"
@@ -280,23 +281,23 @@ msgstr ""
#: ui/accountadvancedtab.ui:149
msgid "<b>Registration</b>"
-msgstr ""
+msgstr "<b>Registracija</b>"
#: ui/accountadvancedtab.ui:176
msgid "Use random port"
-msgstr ""
+msgstr "Koristi nasumični port"
#: ui/accountadvancedtab.ui:197
msgid "Local port:"
-msgstr ""
+msgstr "Lokalni port:"
#: ui/accountadvancedtab.ui:223
msgid "<b>Network Interface</b>"
-msgstr ""
+msgstr "<b>Mrežno sučelje</b>"
#: ui/accountadvancedtab.ui:249
msgid "Same as local parameters"
-msgstr ""
+msgstr "Isto kao i lokalni parametri"
#: ui/accountadvancedtab.ui:264
msgid "Set published address and port:"
@@ -312,23 +313,23 @@ msgstr "Port"
#: ui/accountadvancedtab.ui:336
msgid "Use STUN"
-msgstr ""
+msgstr "Koristi STUN"
#: ui/accountadvancedtab.ui:359 ui/accountadvancedtab.ui:408
msgid "server URL"
-msgstr ""
+msgstr "URL poslužitelja"
#: ui/accountadvancedtab.ui:385
msgid "Use TURN"
-msgstr ""
+msgstr "Koristi TURN"
#: ui/accountadvancedtab.ui:430
msgid "username"
-msgstr ""
+msgstr "korisničko ime"
#: ui/accountadvancedtab.ui:451
msgid "password"
-msgstr ""
+msgstr "lozinka"
#: ui/accountadvancedtab.ui:475
msgid "realm"
@@ -374,15 +375,15 @@ msgstr "Dolje"
#: ui/accountaudiotab.ui:77 ui/accountvideotab.ui:77
msgid "<b>Codecs</b>"
-msgstr ""
+msgstr "<b>Kodeci</b>"
#: ui/accountgeneraltab.ui:42
msgid "<b>Account</b>"
-msgstr ""
+msgstr "<b>Račun</b>"
#: ui/accountgeneraltab.ui:80
msgid "<b>Parameters</b>"
-msgstr ""
+msgstr "<b>Parametri</b>"
#: ui/accountsecuritytab.ui:37
msgid "Encrypt media streams (SRTP)"
@@ -414,19 +415,19 @@ msgstr ""
#: ui/accountsecuritytab.ui:220
msgid "Private key"
-msgstr ""
+msgstr "Privatni ključ"
#: ui/accountsecuritytab.ui:243
msgid "Private key password"
-msgstr ""
+msgstr "Lozinka privatnog ključa"
#: ui/accountsecuritytab.ui:290
msgid "TLS protocol method"
-msgstr ""
+msgstr "Metoda TSL protokola"
#: ui/accountsecuritytab.ui:313
msgid "Outgoing TLS server name"
-msgstr ""
+msgstr "Ime odlaznoga TSL poslužitelja"
#: ui/accountsecuritytab.ui:335
msgid "Negotiation timeout (seconds)"
@@ -458,31 +459,31 @@ msgstr ""
#: ui/accountvideotab.ui:90
msgid "Enable Video"
-msgstr ""
+msgstr "Omogući video"
#: ui/accountview.ui:59
msgid "<b>−</b>"
-msgstr ""
+msgstr "<b>−</b>"
#: ui/accountview.ui:83
msgid "<b>+</b>"
-msgstr ""
+msgstr "<b>+</b>"
#: ui/choosecontactview.ui:34
msgid "Create New"
-msgstr ""
+msgstr "Napravi novi"
#: ui/currentcallview.ui:73
msgid "Send"
-msgstr ""
+msgstr "Pošalji"
#: ui/currentcallview.ui:191
msgid "End this call"
-msgstr ""
+msgstr "Završi ovaj poziv"
#: ui/currentcallview.ui:195 ui/currentcallview.ui:356
msgid "End call"
-msgstr ""
+msgstr "Završi poziv"
#: ui/currentcallview.ui:213
msgid "Toggle hold"
@@ -511,7 +512,7 @@ msgstr ""
#: ui/currentcallview.ui:283
msgid "Record audio"
-msgstr ""
+msgstr "Snimaj audio"
#: ui/currentcallview.ui:299
msgid "Toggle show chat"
@@ -519,7 +520,7 @@ msgstr ""
#: ui/currentcallview.ui:303 ui/currentcallview.ui:320
msgid "Chat"
-msgstr ""
+msgstr "Čavrljanje"
#: ui/currentcallview.ui:329
msgid "Mute audio"
@@ -527,27 +528,27 @@ msgstr ""
#: ui/currentcallview.ui:365
msgid "Record"
-msgstr ""
+msgstr "Snimaj"
#: ui/editcontactview.ui:12
msgid "Select addressbook"
-msgstr ""
+msgstr "Odaberi adresar"
#: ui/editcontactview.ui:15
msgid "Addressbook"
-msgstr ""
+msgstr "Adresar"
#: ui/editcontactview.ui:29
msgid "Name"
-msgstr ""
+msgstr "Ime"
#: ui/editcontactview.ui:32
msgid "Contact name"
-msgstr ""
+msgstr "Ime kontakta"
#: ui/editcontactview.ui:47
msgid "Select how this number will be categorized"
-msgstr ""
+msgstr "Odaberite kako će ovaj broj biti kategoriziran"
#: ui/editcontactview.ui:50
msgid "Number category"
@@ -563,11 +564,11 @@ msgstr ""
#: ui/editcontactview.ui:83
msgid "Save"
-msgstr ""
+msgstr "Spremi"
#: ui/generalsettingsview.ui:32
msgid "<b>Ring Settings</b>"
-msgstr ""
+msgstr "<b>Ring postavke</b>"
#: ui/generalsettingsview.ui:46
msgid "Start Ring on login"
@@ -591,19 +592,19 @@ msgstr ""
#: ui/generalsettingsview.ui:110
msgid "<b>History Settings</b>"
-msgstr ""
+msgstr "<b>Postavke povijesti</b>"
#: ui/generalsettingsview.ui:128
msgid "Keep history for (days):"
-msgstr ""
+msgstr "Zadrži povijest (dana):"
#: ui/generalsettingsview.ui:151
msgid "(set to 0 for unlimited history)"
-msgstr ""
+msgstr "(postavi na 0 za neograničenu povijest)"
#: ui/generalsettingsview.ui:160
msgid "Clear all history"
-msgstr ""
+msgstr "Očisti svu povijest"
#: ui/incomingcallview.ui:88
msgid "Incoming..."
@@ -611,11 +612,11 @@ msgstr ""
#: ui/incomingcallview.ui:122
msgid " Accept"
-msgstr ""
+msgstr "Prihvati"
#: ui/incomingcallview.ui:137
msgid " Reject"
-msgstr ""
+msgstr "Odbij"
#: ui/incomingcallview.ui:152
msgid " Hang-up"
@@ -627,11 +628,11 @@ msgstr ""
#: ui/mediasettingsview.ui:48
msgid "Ringtone device:"
-msgstr ""
+msgstr "Uređaj melodija zvona:"
#: ui/mediasettingsview.ui:60
msgid "Output device:"
-msgstr ""
+msgstr "Izlazni uređaj:"
#: ui/mediasettingsview.ui:72
msgid "Input device:"
@@ -639,19 +640,19 @@ msgstr ""
#: ui/mediasettingsview.ui:127
msgid "<b>Audio Settings</b>"
-msgstr ""
+msgstr "<b>Audio postavke</b>"
#: ui/mediasettingsview.ui:163
msgid "Device:"
-msgstr ""
+msgstr "Uređaj:"
#: ui/mediasettingsview.ui:175
msgid "Channel:"
-msgstr ""
+msgstr "Kanal:"
#: ui/mediasettingsview.ui:187
msgid "Resolution:"
-msgstr ""
+msgstr "Razlučivost:"
#: ui/mediasettingsview.ui:199
msgid "Frame rate:"
@@ -659,19 +660,19 @@ msgstr ""
#: ui/mediasettingsview.ui:258
msgid "<b>Camera Settings</b>"
-msgstr ""
+msgstr "<b>Postavke kamere</b>"
#: ui/ringgearsmenu.ui:13
msgid "_About"
-msgstr ""
+msgstr "_O programu"
#: ui/ringgearsmenu.ui:19
msgid "_Quit"
-msgstr ""
+msgstr "_Prekini"
#: ui/ringmainwindow.ui:20
msgid "Menu"
-msgstr ""
+msgstr "Izbornik"
#: ui/ringmainwindow.ui:54
msgid "General"
@@ -679,7 +680,7 @@ msgstr "Opće"
#: ui/ringmainwindow.ui:64
msgid "Media"
-msgstr ""
+msgstr "Medij"
#: ui/ringmainwindow.ui:75
msgid "Accounts"
@@ -691,11 +692,11 @@ msgstr "Postavke"
#: ui/ringmainwindow.ui:192
msgid "Conversations"
-msgstr ""
+msgstr "Razgovori"
#: ui/ringmainwindow.ui:211
msgid "Contacts"
-msgstr ""
+msgstr "Kontakti"
#: ui/ringmainwindow.ui:230
msgid "History"
@@ -703,7 +704,7 @@ msgstr "Povijest"
#: ui/ringmainwindow.ui:290
msgid "Welcome to "
-msgstr ""
+msgstr "Dobrodošli u"
#: ui/ringmainwindow.ui:307
msgid "Enter your alias to get started:"
@@ -715,7 +716,7 @@ msgstr ""
#: ui/ringmainwindow.ui:338
msgid "Next"
-msgstr ""
+msgstr "Slijedeće"
#: ui/ringmainwindow.ui:360
msgid "Your Ring account has been created with the following Ring ID:"
@@ -723,8 +724,8 @@ msgstr ""
#: ui/ringmainwindow.ui:375
msgid "Share it with your friends so they can contact you via Ring!"
-msgstr ""
+msgstr "Podijelite sa vašim prijateljima da vas mogu kontaktirati putem Ringa!"
#: ui/ringmainwindow.ui:380
msgid "Done"
-msgstr ""
+msgstr "Učinjeno"
diff --git a/client-gnome/po/nl.po b/client-gnome/po/nl.po
index 3cdd9e3..3e0d85f 100644
--- a/client-gnome/po/nl.po
+++ b/client-gnome/po/nl.po
@@ -3,13 +3,14 @@
# This file is distributed under the same license as the Ring package.
#
# Translators:
+# Niels van Duijkeren <nielsvanduijkeren at gmail.com>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Ring\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-13 09:43-0500\n"
-"PO-Revision-Date: 2016-03-24 20:09+0000\n"
-"Last-Translator: Guillaume Roguez\n"
+"PO-Revision-Date: 2016-05-30 14:33+0000\n"
+"Last-Translator: Niels van Duijkeren <nielsvanduijkeren at gmail.com>\n"
"Language-Team: Dutch (http://www.transifex.com/savoirfairelinux/ring/language/nl/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -19,20 +20,20 @@ msgstr ""
#: src/accountaudiotab.cpp:185 src/accountvideotab.cpp:194
msgid "Enabled"
-msgstr ""
+msgstr "Ingeschakeld"
#: src/accountaudiotab.cpp:191
msgctxt "Name of the codec"
msgid "Name"
-msgstr ""
+msgstr "Naam"
#: src/accountaudiotab.cpp:195 src/accountvideotab.cpp:204
msgid "Bitrate"
-msgstr ""
+msgstr "Bitrate"
#: src/accountaudiotab.cpp:199
msgid "Samplerate"
-msgstr ""
+msgstr "Samplerate"
#: src/accountgeneraltab.cpp:210
msgid "Alias"
@@ -40,11 +41,11 @@ msgstr "Alias"
#: src/accountgeneraltab.cpp:221
msgid "Type"
-msgstr ""
+msgstr "Type"
#: src/accountgeneraltab.cpp:250
msgid "auto-generating..."
-msgstr ""
+msgstr "automatisch genereren..."
#: src/accountgeneraltab.cpp:269
msgid "Hostname"
@@ -60,76 +61,76 @@ msgstr "Wachtwoord"
#: src/accountgeneraltab.cpp:302
msgid "Show password"
-msgstr ""
+msgstr "Wachtwoord tonen"
#: src/accountgeneraltab.cpp:308
msgid "Proxy"
-msgstr ""
+msgstr "Proxy"
#: src/accountgeneraltab.cpp:318
msgid "Voicemail number"
-msgstr ""
+msgstr "Voicemail nummer"
#: src/accountgeneraltab.cpp:330
msgctxt "The DHT bootstrap server url"
msgid "Bootstrap"
-msgstr ""
+msgstr "Bootstrap"
#: src/accountgeneraltab.cpp:342
msgid "Auto-answer calls"
-msgstr ""
+msgstr "Oproepen automatisch beantwoorden"
#: src/accountgeneraltab.cpp:350
msgid "UPnP enabled"
-msgstr ""
+msgstr "UPnP ingeschakeld"
#: src/accountgeneraltab.cpp:358
msgid "DTMF tone type:"
-msgstr ""
+msgstr "Type kiestoon (DTMF):"
#: src/accountvideotab.cpp:200
msgctxt "The name of the codec"
msgid "Name"
-msgstr ""
+msgstr "Naam"
#: src/accountview.cpp:159
msgctxt "Account settings"
msgid "General"
-msgstr ""
+msgstr "Algemeen"
#: src/accountview.cpp:163
msgctxt "Account settings"
msgid "Audio"
-msgstr ""
+msgstr "Geluid"
#: src/accountview.cpp:167
msgctxt "Account settings"
msgid "Video"
-msgstr ""
+msgstr "Video"
#: src/accountview.cpp:171
msgctxt "Account settings"
msgid "Advanced"
-msgstr ""
+msgstr "Geavanceerd"
#: src/accountview.cpp:175
msgctxt "Account settings"
msgid "Security"
-msgstr ""
+msgstr "Beveiliging"
#: src/accountview.cpp:229
#, c-format
msgid "Are you sure you want to delete account \"%s\"?"
-msgstr ""
+msgstr "Weet u zeker dat u het account \"%s\" wilt verwijderen?"
#: src/accountview.cpp:313 src/accountview.cpp:315
msgid "New Account"
-msgstr ""
+msgstr "Account aanmaken"
#: src/accountview.cpp:399
msgctxt "Account state column"
msgid "Enabled"
-msgstr ""
+msgstr "Ingeschakeld"
#: src/accountview.cpp:405
msgctxt "Account alias (name) column"
@@ -139,19 +140,19 @@ msgstr "Alias"
#: src/accountview.cpp:409
msgctxt "Account status column"
msgid "Status"
-msgstr ""
+msgstr "Status"
#: src/contactsview.cpp:305
msgid "_Copy name"
-msgstr ""
+msgstr "_Naam kopiëren"
#: src/contactsview.cpp:316 src/contactsview.cpp:331
msgid "_Copy number"
-msgstr ""
+msgstr "_Nummer kopiëren"
#: src/dialogs.c:53
msgid "Working..."
-msgstr ""
+msgstr "Bezig..."
#: src/dialogs.c:84
#, c-format
@@ -159,572 +160,572 @@ msgctxt "Do not translate the release name"
msgid ""
"release: Louis-Joseph Papineau\n"
"v%d.%d.%d - %.10s"
-msgstr ""
+msgstr "release: Louis-Joseph Papineau\nv%d.%d.%d - %.10s"
#: src/dialogs.c:111
msgid ""
"The GNOME client for Ring.\n"
"Ring is a secured and distributed communication software."
-msgstr ""
+msgstr "De GNOME client voor Ring.\nRing is software voor beveiligde en gedistribueerde communicatie."
#: src/editcontactview.cpp:196
msgctxt "Phone number category"
msgid "home"
-msgstr ""
+msgstr "thuis"
#: src/generalsettingsview.cpp:94
msgid ""
"Are you sure you want to clear all your history?\n"
"This operation will also reset the Frequent Contacts list"
-msgstr ""
+msgstr "Weet u zeker dat u de geschiedenis wilt wissen?\nDeze actie zal ook de Frequente Contacten lijst resetten."
#: src/historyview.cpp:184
msgid "_Copy"
-msgstr ""
+msgstr "_Kopiëren"
#: src/historyview.cpp:402
msgctxt "Call history"
msgid "Call"
-msgstr ""
+msgstr "Oproep"
#: src/historyview.cpp:447
msgctxt "Call history"
msgid "Date"
-msgstr ""
+msgstr "Datum"
#: src/ringnotify.cpp:86
msgid "Incoming call"
-msgstr ""
+msgstr "Binnenkomende oproep"
#: src/ringnotify.cpp:169
#, c-format
msgctxt "Text message notification"
msgid "%s says:"
-msgstr ""
+msgstr "%s schrijft:"
#: src/ring_client_options.c:65
msgid "Enable debug"
-msgstr ""
+msgstr "Foutopsporing inschakelen"
#: src/ring_client_options.c:67
msgid ""
"Restores the hidden state of the main window (only applicable to the primary"
" instance)"
-msgstr ""
+msgstr "Herstelt de verborgen status van het hoofdscherm (alleen van toepassing op het primaire proces)"
#: src/ring_client_options.c:84
msgid "- GNOME client for Ring"
-msgstr ""
+msgstr "- GNOME client voor Ring"
#: src/backends/edscontactbackend.cpp:201
msgid "Unknown EDS addressbook"
-msgstr ""
+msgstr "Onbekend EDS adresboek"
#: src/backends/edscontactbackend.cpp:221
msgctxt "Backend type"
msgid "Contacts"
-msgstr ""
+msgstr "Contacten"
#: src/utils/menus.cpp:67
msgid "_Add to contact"
-msgstr ""
+msgstr "_Aan contact toevoegen"
#: src/ringmainwindow.cpp:944
msgctxt ""
"Please try to make the translation 50 chars or less so that it fits into the"
" layout"
msgid "Search contacts or enter number"
-msgstr ""
+msgstr "Zoek contacten of geef nummer in"
#: src/ringwelcomeview.cpp:61
msgid "fetching RingID..."
-msgstr ""
+msgstr "RingID ophalen..."
#: src/ringwelcomeview.cpp:92
msgid ""
"Ring is a secure and distributed voice, video, and chat communication "
"platform that requires no centralized server and leaves the power of privacy"
" in the hands of the user."
-msgstr ""
+msgstr "Ring is een veilige en gedistribueerde spraak, video en chat communicatie platform dat geen centrale server vereist en laat de kracht van privacy in handen van de gebruiker."
#: src/ringwelcomeview.cpp:102
msgctxt "Do not translate \"RingID\""
msgid ""
"This is your RingID.\n"
"Copy and share it with your friends!"
-msgstr ""
+msgstr "Dit is uw RingID.\nDeel hem met uw vrienden!"
#: src/video/video_widget.cpp:478
msgid "Share screen area"
-msgstr ""
+msgstr "Schermruimte delen"
#: src/video/video_widget.cpp:484
msgid "Share file"
-msgstr ""
+msgstr "Bestand delen"
#: ui/accountadvancedtab.ui:81
msgid "Registration expire timeout (seconds):"
-msgstr ""
+msgstr "Registratie verval time-out (seconden):"
#: ui/accountadvancedtab.ui:103
msgid "Allow calls from unknown peers"
-msgstr ""
+msgstr "Oproepen accepteren van onbekende gebruikers"
#: ui/accountadvancedtab.ui:117
msgid "Allow calls from peers in your call history"
-msgstr ""
+msgstr "Oproepen accepteren van gebruikers in de oproepgeschiedenis"
#: ui/accountadvancedtab.ui:131
msgid "Allow calls from peers in your contacts list"
-msgstr ""
+msgstr "Oproepen accepteren van gebruikers in de contactenlijst"
#: ui/accountadvancedtab.ui:149
msgid "<b>Registration</b>"
-msgstr ""
+msgstr "<b>Registratie</b>"
#: ui/accountadvancedtab.ui:176
msgid "Use random port"
-msgstr ""
+msgstr "Willekeurige poort gebruiken"
#: ui/accountadvancedtab.ui:197
msgid "Local port:"
-msgstr ""
+msgstr "Lokale poort:"
#: ui/accountadvancedtab.ui:223
msgid "<b>Network Interface</b>"
-msgstr ""
+msgstr "<b>Netwerkinterface</b>"
#: ui/accountadvancedtab.ui:249
msgid "Same as local parameters"
-msgstr ""
+msgstr "Gelijk aan lokale parameters"
#: ui/accountadvancedtab.ui:264
msgid "Set published address and port:"
-msgstr ""
+msgstr "Gepubliceerde adres en poort:"
#: ui/accountadvancedtab.ui:288
msgid "Address"
-msgstr ""
+msgstr "Adres"
#: ui/accountadvancedtab.ui:310
msgid "Port"
-msgstr ""
+msgstr "Poort"
#: ui/accountadvancedtab.ui:336
msgid "Use STUN"
-msgstr ""
+msgstr "STUN gebruiken"
#: ui/accountadvancedtab.ui:359 ui/accountadvancedtab.ui:408
msgid "server URL"
-msgstr ""
+msgstr "server URL"
#: ui/accountadvancedtab.ui:385
msgid "Use TURN"
-msgstr ""
+msgstr "TURN gebruiken"
#: ui/accountadvancedtab.ui:430
msgid "username"
-msgstr ""
+msgstr "gebruikersnaam"
#: ui/accountadvancedtab.ui:451
msgid "password"
-msgstr ""
+msgstr "wachtwoord"
#: ui/accountadvancedtab.ui:475
msgid "realm"
-msgstr ""
+msgstr "realm"
#: ui/accountadvancedtab.ui:504
msgid "<b>Published Address</b>"
-msgstr ""
+msgstr "<b>Gepubliceerd Adres</b>"
#: ui/accountadvancedtab.ui:533
msgid ""
"These settings are only used during SDP session negotiation in case ICE is "
"not supported by the server or peer."
-msgstr ""
+msgstr "Deze instellingen worden enkel gebruikt tijdens SDP sessie onderhandelingen in geval ICE niet ondersteund wordt door de server of de gebruiker."
#: ui/accountadvancedtab.ui:558 ui/accountadvancedtab.ui:632
msgid "Min"
-msgstr ""
+msgstr "Min"
#: ui/accountadvancedtab.ui:581 ui/accountadvancedtab.ui:655
msgid "Max"
-msgstr ""
+msgstr "Max"
#: ui/accountadvancedtab.ui:605
msgid "<b>Audio RTP Port Range</b>"
-msgstr ""
+msgstr "<b>Audio RTP Poortenreeks</b>"
#: ui/accountadvancedtab.ui:679
msgid "<b>Video RTP Port Range</b>"
-msgstr ""
+msgstr "<b>Video RTP Poortenreeks</b>"
#: ui/accountadvancedtab.ui:695
msgid "<b>SDP Session Negotiation (ICE Fallback)</b>"
-msgstr ""
+msgstr "<b>SDP Sessie Onderhandeling (ICE Terugvaloptie)</b>"
#: ui/accountaudiotab.ui:59 ui/accountvideotab.ui:59
msgid "Up"
-msgstr ""
+msgstr "Hoger"
#: ui/accountaudiotab.ui:66 ui/accountvideotab.ui:66
msgid "Down"
-msgstr ""
+msgstr "Lager"
#: ui/accountaudiotab.ui:77 ui/accountvideotab.ui:77
msgid "<b>Codecs</b>"
-msgstr ""
+msgstr "<b>Codecs</b>"
#: ui/accountgeneraltab.ui:42
msgid "<b>Account</b>"
-msgstr ""
+msgstr "<b>Account</b>"
#: ui/accountgeneraltab.ui:80
msgid "<b>Parameters</b>"
-msgstr ""
+msgstr "<b>Parameters</b>"
#: ui/accountsecuritytab.ui:37
msgid "Encrypt media streams (SRTP)"
-msgstr ""
+msgstr "Mediastreams versleutelen (SRTP)"
#: ui/accountsecuritytab.ui:58
msgid "Key exchange protocol"
-msgstr ""
+msgstr "Sleuteluitwisselingsprotocol"
#: ui/accountsecuritytab.ui:76
msgid "Fallback on RTP on encryption failure"
-msgstr ""
+msgstr "RTP gebruiken bij mislukte versleuteling"
#: ui/accountsecuritytab.ui:94
msgid "<b>Media Stream Encryption</b>"
-msgstr ""
+msgstr "<b>Mediastream Versleuteling</b>"
#: ui/accountsecuritytab.ui:121
msgid "Encrypt negotiation (TLS)"
-msgstr ""
+msgstr "Onderhandeling versleutelen (TLS)"
#: ui/accountsecuritytab.ui:146
msgid "CA certificate"
-msgstr ""
+msgstr "CA certificaat"
#: ui/accountsecuritytab.ui:183
msgid "User certificate"
-msgstr ""
+msgstr "Gebruikerscertificaat"
#: ui/accountsecuritytab.ui:220
msgid "Private key"
-msgstr ""
+msgstr "Persoonlijke sleutel"
#: ui/accountsecuritytab.ui:243
msgid "Private key password"
-msgstr ""
+msgstr "Wachtwoord persoonlijke sleutel"
#: ui/accountsecuritytab.ui:290
msgid "TLS protocol method"
-msgstr ""
+msgstr "TLS protocol methode"
#: ui/accountsecuritytab.ui:313
msgid "Outgoing TLS server name"
-msgstr ""
+msgstr "Uitgaande TLS servernaam"
#: ui/accountsecuritytab.ui:335
msgid "Negotiation timeout (seconds)"
-msgstr ""
+msgstr "Tijdslimiet onderhandeling (seconden)"
#: ui/accountsecuritytab.ui:369
msgid "Use default ciphers"
-msgstr ""
+msgstr "Standaard codering gebruiken"
#: ui/accountsecuritytab.ui:385
msgid "Use custom cipher list"
-msgstr ""
+msgstr "Aangepaste codering gebruiken"
#: ui/accountsecuritytab.ui:442
msgid "Verify incoming certificates (server side)"
-msgstr ""
+msgstr "Binnenkomende certificaten verifiëren (serverzijde)"
#: ui/accountsecuritytab.ui:457
msgid "Verify answer certificates (client side)"
-msgstr ""
+msgstr "Uitgaande certificaten verifiëren (clientzijde)"
#: ui/accountsecuritytab.ui:472
msgid "Require a certificate for incoming TLS connections"
-msgstr ""
+msgstr "Certificaat voor binnenkomende TLS verbindingen vereisen"
#: ui/accountsecuritytab.ui:491
msgid "<b>Negotiation Encryption</b>"
-msgstr ""
+msgstr "<b>Onderhandeling Versleuteling</b>"
#: ui/accountvideotab.ui:90
msgid "Enable Video"
-msgstr ""
+msgstr "Video inschakelen"
#: ui/accountview.ui:59
msgid "<b>−</b>"
-msgstr ""
+msgstr "<b>−</b>"
#: ui/accountview.ui:83
msgid "<b>+</b>"
-msgstr ""
+msgstr "<b>+</b>"
#: ui/choosecontactview.ui:34
msgid "Create New"
-msgstr ""
+msgstr "Nieuw Aanmaken"
#: ui/currentcallview.ui:73
msgid "Send"
-msgstr ""
+msgstr "Versturen"
#: ui/currentcallview.ui:191
msgid "End this call"
-msgstr ""
+msgstr "Deze oproep beëindigen "
#: ui/currentcallview.ui:195 ui/currentcallview.ui:356
msgid "End call"
-msgstr ""
+msgstr "Oproep beëindigen"
#: ui/currentcallview.ui:213
msgid "Toggle hold"
-msgstr ""
+msgstr "Wacht in/uitschakelen"
#: ui/currentcallview.ui:217 ui/currentcallview.ui:239
#: ui/currentcallview.ui:347
msgid "Hold"
-msgstr ""
+msgstr "In wacht zetten"
#: ui/currentcallview.ui:235
msgid "Toggle mute audio"
-msgstr ""
+msgstr "Geluid in/uitschakelen"
#: ui/currentcallview.ui:257
msgid "Toggle mute video"
-msgstr ""
+msgstr "Video in/uitschakelen"
#: ui/currentcallview.ui:261 ui/currentcallview.ui:338
msgid "Mute video"
-msgstr ""
+msgstr "Video uitschakelen"
#: ui/currentcallview.ui:280
msgid "Toggle record audio"
-msgstr ""
+msgstr "Geluid opname in/uitschakelen"
#: ui/currentcallview.ui:283
msgid "Record audio"
-msgstr ""
+msgstr "Geluid opnemen"
#: ui/currentcallview.ui:299
msgid "Toggle show chat"
-msgstr ""
+msgstr "Chat tonen/verbergen"
#: ui/currentcallview.ui:303 ui/currentcallview.ui:320
msgid "Chat"
-msgstr ""
+msgstr "Chat"
#: ui/currentcallview.ui:329
msgid "Mute audio"
-msgstr ""
+msgstr "Geluid dempen"
#: ui/currentcallview.ui:365
msgid "Record"
-msgstr ""
+msgstr "Opnemen"
#: ui/editcontactview.ui:12
msgid "Select addressbook"
-msgstr ""
+msgstr "Adresboek selecteren"
#: ui/editcontactview.ui:15
msgid "Addressbook"
-msgstr ""
+msgstr "Adresboek"
#: ui/editcontactview.ui:29
msgid "Name"
-msgstr ""
+msgstr "Naam"
#: ui/editcontactview.ui:32
msgid "Contact name"
-msgstr ""
+msgstr "Contactnaam"
#: ui/editcontactview.ui:47
msgid "Select how this number will be categorized"
-msgstr ""
+msgstr "Wijze van categorisatie voor dit nummer selecteren"
#: ui/editcontactview.ui:50
msgid "Number category"
-msgstr ""
+msgstr "Nummer categorie"
#: ui/editcontactview.ui:66
msgid "Number or Ring ID to be added"
-msgstr ""
+msgstr "Toe te voegen nummer of Ring ID"
#: ui/editcontactview.ui:72
msgid "Number or Ring ID"
-msgstr ""
+msgstr "Nummer of Ring ID"
#: ui/editcontactview.ui:83
msgid "Save"
-msgstr ""
+msgstr "Opslaan"
#: ui/generalsettingsview.ui:32
msgid "<b>Ring Settings</b>"
-msgstr ""
+msgstr "<b>Ring-instellingen</b>"
#: ui/generalsettingsview.ui:46
msgid "Start Ring on login"
-msgstr ""
+msgstr "Ring opstarten bij het aanmelden"
#: ui/generalsettingsview.ui:55
msgid "Hide Ring on close instead of quitting."
-msgstr ""
+msgstr "Ring verbergen in plaats van afsluiten."
#: ui/generalsettingsview.ui:64
msgid "Bring Ring to the foreground on incoming calls."
-msgstr ""
+msgstr "Ring naar voorgrond brengen bij binnenkomende oproepen."
#: ui/generalsettingsview.ui:79
msgid "Show chat on the right."
-msgstr ""
+msgstr "Chat rechts weergeven"
#: ui/generalsettingsview.ui:86
msgid "Show chat on the bottom."
-msgstr ""
+msgstr "Chat onderaan weergeven"
#: ui/generalsettingsview.ui:110
msgid "<b>History Settings</b>"
-msgstr ""
+msgstr "<b>Geschiedenisinstellingen</b>"
#: ui/generalsettingsview.ui:128
msgid "Keep history for (days):"
-msgstr ""
+msgstr "Geschiedenis bewaren voor (dagen):"
#: ui/generalsettingsview.ui:151
msgid "(set to 0 for unlimited history)"
-msgstr ""
+msgstr "(kies 0 voor onbeperkte geschiedenis)"
#: ui/generalsettingsview.ui:160
msgid "Clear all history"
-msgstr ""
+msgstr "Geschiedenis wissen"
#: ui/incomingcallview.ui:88
msgid "Incoming..."
-msgstr ""
+msgstr "Binnenkomend..."
#: ui/incomingcallview.ui:122
msgid " Accept"
-msgstr ""
+msgstr "Accepteren"
#: ui/incomingcallview.ui:137
msgid " Reject"
-msgstr ""
+msgstr "Afwijzen"
#: ui/incomingcallview.ui:152
msgid " Hang-up"
-msgstr ""
+msgstr "Ophangen"
#: ui/mediasettingsview.ui:36
msgid "Audio manager:"
-msgstr ""
+msgstr "Geluidsbeheerder:"
#: ui/mediasettingsview.ui:48
msgid "Ringtone device:"
-msgstr ""
+msgstr "Beltoonapparaat:"
#: ui/mediasettingsview.ui:60
msgid "Output device:"
-msgstr ""
+msgstr "Uitvoerapparaat:"
#: ui/mediasettingsview.ui:72
msgid "Input device:"
-msgstr ""
+msgstr "Invoerapparaat:"
#: ui/mediasettingsview.ui:127
msgid "<b>Audio Settings</b>"
-msgstr ""
+msgstr "<b>Geluidinstellingen</b>"
#: ui/mediasettingsview.ui:163
msgid "Device:"
-msgstr ""
+msgstr "Apparaat:"
#: ui/mediasettingsview.ui:175
msgid "Channel:"
-msgstr ""
+msgstr "Kanaal:"
#: ui/mediasettingsview.ui:187
msgid "Resolution:"
-msgstr ""
+msgstr "Resolutie:"
#: ui/mediasettingsview.ui:199
msgid "Frame rate:"
-msgstr ""
+msgstr "Framesnelheid:"
#: ui/mediasettingsview.ui:258
msgid "<b>Camera Settings</b>"
-msgstr ""
+msgstr "<b>Camera-instellingen</b>"
#: ui/ringgearsmenu.ui:13
msgid "_About"
-msgstr ""
+msgstr "_Over"
#: ui/ringgearsmenu.ui:19
msgid "_Quit"
-msgstr ""
+msgstr "_Afsluiten"
#: ui/ringmainwindow.ui:20
msgid "Menu"
-msgstr ""
+msgstr "Menu"
#: ui/ringmainwindow.ui:54
msgid "General"
-msgstr ""
+msgstr "Algemeen"
#: ui/ringmainwindow.ui:64
msgid "Media"
-msgstr ""
+msgstr "Media"
#: ui/ringmainwindow.ui:75
msgid "Accounts"
-msgstr ""
+msgstr "Accounts"
#: ui/ringmainwindow.ui:93
msgid "Settings"
-msgstr ""
+msgstr "Instellingen"
#: ui/ringmainwindow.ui:192
msgid "Conversations"
-msgstr ""
+msgstr "Conversaties"
#: ui/ringmainwindow.ui:211
msgid "Contacts"
-msgstr ""
+msgstr "Contacten"
#: ui/ringmainwindow.ui:230
msgid "History"
-msgstr ""
+msgstr "Geschiedenis"
#: ui/ringmainwindow.ui:290
msgid "Welcome to "
-msgstr ""
+msgstr "Welkom bij"
#: ui/ringmainwindow.ui:307
msgid "Enter your alias to get started:"
-msgstr ""
+msgstr "Kies een alias om te beginnen:"
#: ui/ringmainwindow.ui:324
msgid "Generating your Ring account..."
-msgstr ""
+msgstr "Uw Ring account wordt gegenereerd..."
#: ui/ringmainwindow.ui:338
msgid "Next"
-msgstr ""
+msgstr "Volgende"
#: ui/ringmainwindow.ui:360
msgid "Your Ring account has been created with the following Ring ID:"
-msgstr ""
+msgstr "Uw Ring account is aangemaakt met het volgende Ring ID:"
#: ui/ringmainwindow.ui:375
msgid "Share it with your friends so they can contact you via Ring!"
-msgstr ""
+msgstr "Deel deze met uw vrienden zodat zij u kunnen bereiken via Ring!"
#: ui/ringmainwindow.ui:380
msgid "Done"
-msgstr ""
+msgstr "Klaar"
diff --git a/client-gnome/po/ca.po b/client-gnome/po/nl_NL.po
similarity index 96%
copy from client-gnome/po/ca.po
copy to client-gnome/po/nl_NL.po
index 280e138..e31789d 100644
--- a/client-gnome/po/ca.po
+++ b/client-gnome/po/nl_NL.po
@@ -3,29 +3,28 @@
# This file is distributed under the same license as the Ring package.
#
# Translators:
-# David <stakewinner00 at mykolab.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: Ring\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-13 09:43-0500\n"
-"PO-Revision-Date: 2016-03-24 20:09+0000\n"
+"PO-Revision-Date: 2016-06-02 13:45+0000\n"
"Last-Translator: Guillaume Roguez\n"
-"Language-Team: Catalan (http://www.transifex.com/savoirfairelinux/ring/language/ca/)\n"
+"Language-Team: Dutch (Netherlands) (http://www.transifex.com/savoirfairelinux/ring/language/nl_NL/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Language: ca\n"
+"Language: nl_NL\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: src/accountaudiotab.cpp:185 src/accountvideotab.cpp:194
msgid "Enabled"
-msgstr "Habilitat"
+msgstr ""
#: src/accountaudiotab.cpp:191
msgctxt "Name of the codec"
msgid "Name"
-msgstr "Nom"
+msgstr "Naam"
#: src/accountaudiotab.cpp:195 src/accountvideotab.cpp:204
msgid "Bitrate"
@@ -41,7 +40,7 @@ msgstr ""
#: src/accountgeneraltab.cpp:221
msgid "Type"
-msgstr ""
+msgstr "Type"
#: src/accountgeneraltab.cpp:250
msgid "auto-generating..."
@@ -91,32 +90,32 @@ msgstr ""
#: src/accountvideotab.cpp:200
msgctxt "The name of the codec"
msgid "Name"
-msgstr "Nom"
+msgstr "Naam"
#: src/accountview.cpp:159
msgctxt "Account settings"
msgid "General"
-msgstr ""
+msgstr "Algemeen"
#: src/accountview.cpp:163
msgctxt "Account settings"
msgid "Audio"
-msgstr ""
+msgstr "Geluid"
#: src/accountview.cpp:167
msgctxt "Account settings"
msgid "Video"
-msgstr ""
+msgstr "Video"
#: src/accountview.cpp:171
msgctxt "Account settings"
msgid "Advanced"
-msgstr ""
+msgstr "Gevorderd"
#: src/accountview.cpp:175
msgctxt "Account settings"
msgid "Security"
-msgstr "Seguretat"
+msgstr "Beveiliging"
#: src/accountview.cpp:229
#, c-format
@@ -130,7 +129,7 @@ msgstr ""
#: src/accountview.cpp:399
msgctxt "Account state column"
msgid "Enabled"
-msgstr "Habilitat"
+msgstr ""
#: src/accountview.cpp:405
msgctxt "Account alias (name) column"
@@ -140,7 +139,7 @@ msgstr ""
#: src/accountview.cpp:409
msgctxt "Account status column"
msgid "Status"
-msgstr ""
+msgstr "Staat"
#: src/contactsview.cpp:305
msgid "_Copy name"
@@ -367,11 +366,11 @@ msgstr ""
#: ui/accountaudiotab.ui:59 ui/accountvideotab.ui:59
msgid "Up"
-msgstr ""
+msgstr "Omhoog"
#: ui/accountaudiotab.ui:66 ui/accountvideotab.ui:66
msgid "Down"
-msgstr ""
+msgstr "Beneden"
#: ui/accountaudiotab.ui:77 ui/accountvideotab.ui:77
msgid "<b>Codecs</b>"
@@ -415,7 +414,7 @@ msgstr ""
#: ui/accountsecuritytab.ui:220
msgid "Private key"
-msgstr "Clau privada"
+msgstr ""
#: ui/accountsecuritytab.ui:243
msgid "Private key password"
@@ -475,7 +474,7 @@ msgstr ""
#: ui/currentcallview.ui:73
msgid "Send"
-msgstr "Enviar"
+msgstr ""
#: ui/currentcallview.ui:191
msgid "End this call"
@@ -540,7 +539,7 @@ msgstr ""
#: ui/editcontactview.ui:29
msgid "Name"
-msgstr "Nom"
+msgstr "Naam"
#: ui/editcontactview.ui:32
msgid "Contact name"
@@ -676,15 +675,15 @@ msgstr ""
#: ui/ringmainwindow.ui:54
msgid "General"
-msgstr ""
+msgstr "Algemeen"
#: ui/ringmainwindow.ui:64
msgid "Media"
-msgstr ""
+msgstr "Media"
#: ui/ringmainwindow.ui:75
msgid "Accounts"
-msgstr ""
+msgstr "Accounts"
#: ui/ringmainwindow.ui:93
msgid "Settings"
diff --git a/client-gnome/po/pt_BR.po b/client-gnome/po/pt_BR.po
index 8054af3..2d38bd5 100644
--- a/client-gnome/po/pt_BR.po
+++ b/client-gnome/po/pt_BR.po
@@ -3,6 +3,7 @@
# This file is distributed under the same license as the Ring package.
#
# Translators:
+# Cleiton Floss, 2016
# Keven de Oliveira <keven at zenbackup.com.br>, 2015
# Nícolas Wildner <nicolasgaucho at gmail.com>, 2015
# Raul Dipeas <rauldipeas at outlook.com>, 2015
@@ -11,8 +12,8 @@ msgstr ""
"Project-Id-Version: Ring\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-13 09:43-0500\n"
-"PO-Revision-Date: 2016-03-24 20:09+0000\n"
-"Last-Translator: Guillaume Roguez\n"
+"PO-Revision-Date: 2016-05-26 04:33+0000\n"
+"Last-Translator: Cleiton Floss\n"
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/savoirfairelinux/ring/language/pt_BR/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -162,7 +163,7 @@ msgctxt "Do not translate the release name"
msgid ""
"release: Louis-Joseph Papineau\n"
"v%d.%d.%d - %.10s"
-msgstr ""
+msgstr "Versão: Louis-Joseph Papineau\nv%d.%d.%d - %.10s"
#: src/dialogs.c:111
msgid ""
diff --git a/client-gnome/src/accountimportexportview.cpp b/client-gnome/src/accountimportexportview.cpp
new file mode 100644
index 0000000..2523e53
--- /dev/null
+++ b/client-gnome/src/accountimportexportview.cpp
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2016 Savoir-faire Linux Inc.
+ * Author: Stepan Salenikovich <stepan.salenikovich at savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "accountimportexportview.h"
+
+#include <gtk/gtk.h>
+#include <account.h>
+#include <accountmodel.h>
+
+#include <glib/gi18n.h>
+
+struct _AccountImportExportView
+{
+ GtkBox parent;
+};
+
+struct _AccountImportExportViewClass
+{
+ GtkBoxClass parent_class;
+};
+
+typedef struct _AccountImportExportViewPrivate AccountImportExportViewPrivate;
+
+struct _AccountImportExportViewPrivate
+{
+ Account *account;
+
+ GtkWidget *label_export;
+ GtkWidget *label_import;
+ GtkWidget *hbox_export_location;
+ GtkWidget *label_export_location;
+ GtkWidget *button_export_location;
+ GtkWidget *filechooserbutton_import;
+ GtkWidget *button_export;
+ GtkWidget *button_import;
+ GtkWidget *button_cancel;
+ GtkWidget *entry_password;
+ GtkWidget *label_error;
+
+ GList *export_accounts_list;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(AccountImportExportView, account_importexport_view, GTK_TYPE_BOX);
+
+#define ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ACCOUNT_IMPORTEXPORT_VIEW_TYPE, AccountImportExportViewPrivate))
+
+/* signals */
+enum {
+ IMPORT_EXPORT_CANCELED,
+ IMPORT_EXPORT_COMPLETED,
+ LAST_SIGNAL
+};
+
+static guint account_importexport_view_signals[LAST_SIGNAL] = { 0 };
+
+static void
+account_importexport_view_dispose(GObject *object)
+{
+ G_OBJECT_CLASS(account_importexport_view_parent_class)->dispose(object);
+}
+
+static void
+account_importexport_view_finalize(GObject *object)
+{
+ AccountImportExportView *view = ACCOUNT_IMPORTEXPORT_VIEW(object);
+ AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(view);
+
+ if (priv->export_accounts_list)
+ g_list_free(priv->export_accounts_list);
+
+ G_OBJECT_CLASS(account_importexport_view_parent_class)->finalize(object);
+}
+
+static void
+choose_export_location(AccountImportExportView *self)
+{
+ AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
+
+ // clear any existing error
+ gtk_label_set_text(GTK_LABEL(priv->label_error), "");
+
+ // create filechooser dialog and get export location
+ auto dialog = gtk_file_chooser_dialog_new(_("Select account export location"),
+ GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(self))),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ _("Cancel"),
+ GTK_RESPONSE_CANCEL,
+ _("Select"),
+ GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
+ gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dialog), TRUE);
+
+ if (!priv->export_accounts_list->next) {
+ auto name = g_strconcat(static_cast<Account *>(priv->export_accounts_list->data)->alias().toUtf8().constData(), ".ring", NULL);
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), name);
+ g_free(name);
+ } else {
+ // TODO: handle multiple account export
+ }
+
+ /* start the file chooser */
+ if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
+ if (auto filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog))) {
+ gtk_label_set_text(GTK_LABEL(priv->label_export_location), filename);
+
+ // if accounts and password are set then we're ready for export
+ auto password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
+ if (priv->export_accounts_list && priv->export_accounts_list->data && strlen(password) > 0) {
+ gtk_widget_set_sensitive(priv->button_export, TRUE);
+ }
+ g_free (filename);
+ }
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+
+static void
+import_file_set(AccountImportExportView *self)
+{
+ AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
+
+ // clear any existing error
+ gtk_label_set_text(GTK_LABEL(priv->label_error), "");
+
+ // if password is set then we're ready for import
+ auto password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
+ if (strlen(password) > 0) {
+ gtk_widget_set_sensitive(priv->button_import, TRUE);
+ }
+}
+
+static void
+password_changed(AccountImportExportView *self)
+{
+ AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
+
+ // clear any existing error
+ gtk_label_set_text(GTK_LABEL(priv->label_error), "");
+
+ // if the password and other requirements are met then enable import/export
+ auto password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
+ if (strlen(password) > 0) {
+
+ // import
+ if (auto filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->filechooserbutton_import))) {
+ gtk_widget_set_sensitive(priv->button_import, TRUE);
+ g_free(filename);
+ }
+
+ // export
+ const auto filename = gtk_label_get_text(GTK_LABEL(priv->label_export_location));
+ if (strlen(filename) > 0) {
+ if (priv->export_accounts_list && priv->export_accounts_list->data) {
+ gtk_widget_set_sensitive(priv->button_export, TRUE);
+ }
+ }
+
+ } else {
+ gtk_widget_set_sensitive(priv->button_export, FALSE);
+ gtk_widget_set_sensitive(priv->button_import, FALSE);
+ }
+}
+
+static void
+cancel_clicked(AccountImportExportView *self)
+{
+ g_signal_emit(G_OBJECT(self), account_importexport_view_signals[IMPORT_EXPORT_CANCELED], 0);
+}
+
+static void
+import_account(AccountImportExportView *self)
+{
+ g_return_if_fail(IS_ACCOUNT_IMPORTEXPORT_VIEW(self));
+
+ AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
+
+ // clear any existing error
+ gtk_label_set_text(GTK_LABEL(priv->label_error), "");
+
+ if (auto filepath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->filechooserbutton_import))) {
+ const auto password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
+ if (strlen(password) > 0) {
+ auto ret = AccountModel::instance().importAccounts(filepath, password);
+ switch(ret) {
+ case 0:
+ // done
+ g_signal_emit(G_OBJECT(self), account_importexport_view_signals[IMPORT_EXPORT_COMPLETED], 0);
+ break;
+ default:
+ //failed
+ gtk_label_set_text(GTK_LABEL(priv->label_error), _("Error importing account(s)"));
+ g_warning("failed to import account(s), err: %d", ret);
+ break;
+ }
+ } else {
+ g_warning("no password set for account import");
+ }
+ g_free(filepath);
+ } else {
+ g_warning("no file selected for account import");
+ }
+}
+
+static void
+export_account(AccountImportExportView *self)
+{
+ g_return_if_fail(IS_ACCOUNT_IMPORTEXPORT_VIEW(self));
+
+ AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
+
+ // clear any existing error
+ gtk_label_set_text(GTK_LABEL(priv->label_error), "");
+
+ // check that we have some accounts to export
+ if ( !(priv->export_accounts_list && priv->export_accounts_list->data)) {
+ g_warning("no accounts are selected for export");
+ return;
+ }
+
+ const auto filepath = gtk_label_get_text(GTK_LABEL(priv->label_export_location));
+ // validate filepath
+ if (strlen(filepath)) {
+ const auto password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
+ if (strlen(password) > 0) {
+
+ // get account id strings
+ auto account_ids = QStringList();
+ auto list = priv->export_accounts_list;
+ while (list != nullptr) {
+ auto account = static_cast<Account *>(list->data);
+ account_ids << account->id();
+ list = g_list_next(list);
+ }
+
+ auto ret = AccountModel::instance().exportAccounts(account_ids, filepath, password);
+ switch (ret) {
+ case 0:
+ // done
+ g_signal_emit(G_OBJECT(self), account_importexport_view_signals[IMPORT_EXPORT_COMPLETED], 0);
+ break;
+ default:
+ //failed
+ gtk_label_set_text(GTK_LABEL(priv->label_error), _("Error exporting account(s)"));
+ g_warning("failed to export account(s), err: %d", ret);
+ break;
+ }
+ } else {
+ g_warning("no password set for account export");
+ }
+ } else {
+ g_warning("no file selected for account export");
+ }
+}
+
+static void
+account_importexport_view_init(AccountImportExportView *self)
+{
+ gtk_widget_init_template(GTK_WIDGET(self));
+
+ AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
+
+ g_signal_connect_swapped(priv->button_export_location, "clicked", G_CALLBACK(choose_export_location), self);
+ g_signal_connect_swapped(priv->filechooserbutton_import, "file-set", G_CALLBACK(import_file_set), self);
+ g_signal_connect_swapped(priv->entry_password, "changed", G_CALLBACK(password_changed), self);
+ g_signal_connect_swapped(priv->button_cancel, "clicked", G_CALLBACK(cancel_clicked), self);
+ g_signal_connect_swapped(priv->button_import, "clicked", G_CALLBACK(import_account), self);
+ g_signal_connect_swapped(priv->button_export, "clicked", G_CALLBACK(export_account), self);
+}
+
+static void
+account_importexport_view_class_init(AccountImportExportViewClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+
+ gobject_class->dispose = account_importexport_view_dispose;
+ gobject_class->finalize = account_importexport_view_finalize;
+
+ gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
+ "/cx/ring/RingGnome/accountimportexportview.ui");
+
+ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, label_export);
+ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, label_import);
+ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, hbox_export_location);
+ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, label_export_location);
+ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, button_export_location);
+ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, filechooserbutton_import);
+ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, button_export);
+ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, button_import);
+ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, button_cancel);
+ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, entry_password);
+ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountImportExportView, label_error);
+
+ /* add signals */
+ account_importexport_view_signals[IMPORT_EXPORT_CANCELED] = g_signal_new("import-export-canceled",
+ G_TYPE_FROM_CLASS(klass),
+ (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
+ 0,
+ nullptr,
+ nullptr,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ account_importexport_view_signals[IMPORT_EXPORT_COMPLETED] = g_signal_new("import-export-completed",
+ G_TYPE_FROM_CLASS(klass),
+ (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
+ 0,
+ nullptr,
+ nullptr,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+build_import_view(AccountImportExportView *self)
+{
+ g_return_if_fail(self);
+
+ AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
+
+ gtk_widget_hide(priv->label_export);
+ gtk_widget_hide(priv->hbox_export_location);
+ gtk_widget_hide(priv->button_export);
+
+ gtk_widget_show(priv->label_import);
+ gtk_widget_show(priv->filechooserbutton_import);
+ gtk_widget_show(priv->button_import);
+}
+
+static void
+build_export_view(AccountImportExportView *self)
+{
+ g_return_if_fail(self);
+
+ AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
+
+ gtk_widget_show(priv->label_export);
+ gtk_widget_show(priv->hbox_export_location);
+ gtk_widget_show(priv->button_export);
+
+ gtk_widget_hide(priv->label_import);
+ gtk_widget_hide(priv->filechooserbutton_import);
+ gtk_widget_hide(priv->button_import);
+}
+
+GtkWidget *
+account_import_view_new()
+{
+ gpointer view = g_object_new(ACCOUNT_IMPORTEXPORT_VIEW_TYPE, NULL);
+
+ build_import_view(ACCOUNT_IMPORTEXPORT_VIEW(view));
+
+ return (GtkWidget *)view;
+}
+
+GtkWidget *
+account_export_view_new()
+{
+ gpointer view = g_object_new(ACCOUNT_IMPORTEXPORT_VIEW_TYPE, NULL);
+
+ build_export_view(ACCOUNT_IMPORTEXPORT_VIEW(view));
+
+ return (GtkWidget *)view;
+}
+
+void
+account_export_view_set_accounts(AccountImportExportView *self, GList *accounts)
+{
+ g_return_if_fail(self);
+ AccountImportExportViewPrivate *priv = ACCOUNT_IMPORTEXPORT_VIEW_GET_PRIVATE(self);
+
+ // replace current list
+ if (priv->export_accounts_list) {
+ g_list_free(priv->export_accounts_list);
+ priv->export_accounts_list = nullptr;
+ }
+
+ // make sure the new list isn't empty
+ if (accounts && accounts->data) {
+ priv->export_accounts_list = g_list_copy(accounts);
+
+ if (!accounts->next) {
+ auto location = g_strconcat(g_get_home_dir(), "/", static_cast<Account *>(priv->export_accounts_list->data)->alias().toUtf8().constData(), ".ring", NULL);
+ gtk_label_set_text(GTK_LABEL(priv->label_export_location), location);
+ g_free(location);
+ } else {
+ // TODO: handle multiple account export
+ }
+ } else {
+ // no accounts are selected... this case should not normally be ever displayed
+ }
+}
diff --git a/client-gnome/src/accountimportexportview.h b/client-gnome/src/accountimportexportview.h
new file mode 100644
index 0000000..f2b9324
--- /dev/null
+++ b/client-gnome/src/accountimportexportview.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 Savoir-faire Linux Inc.
+ * Author: Stepan Salenikovich <stepan.salenikovich at savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define ACCOUNT_IMPORTEXPORT_VIEW_TYPE (account_importexport_view_get_type ())
+#define ACCOUNT_IMPORTEXPORT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ACCOUNT_IMPORTEXPORT_VIEW_TYPE, AccountImportExportView))
+#define ACCOUNT_IMPORTEXPORT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), ACCOUNT_IMPORTEXPORT_VIEW_TYPE, AccountImportExportViewClass))
+#define IS_ACCOUNT_IMPORTEXPORT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), ACCOUNT_IMPORTEXPORT_VIEW_TYPE))
+#define IS_ACCOUNT_IMPORTEXPORT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), ACCOUNT_IMPORTEXPORT_VIEW_TYPE))
+
+typedef struct _AccountImportExportView AccountImportExportView;
+typedef struct _AccountImportExportViewClass AccountImportExportViewClass;
+
+GType account_importexport_view_get_type (void) G_GNUC_CONST;
+GtkWidget *account_import_view_new (void);
+GtkWidget *account_export_view_new (void);
+void account_export_view_set_accounts (AccountImportExportView* self, GList *accounts);
+
+G_END_DECLS
diff --git a/client-gnome/src/accountview.cpp b/client-gnome/src/accountview.cpp
index 5ca2fa9..30ef947 100644
--- a/client-gnome/src/accountview.cpp
+++ b/client-gnome/src/accountview.cpp
@@ -36,6 +36,7 @@
#include "dialogs.h"
#include <glib/gprintf.h>
#include "utils/models.h"
+#include "accountimportexportview.h"
struct _AccountView
{
@@ -52,11 +53,14 @@ typedef struct _AccountViewPrivate AccountViewPrivate;
struct _AccountViewPrivate
{
GtkWidget *treeview_account_list;
+ GtkWidget *account_import_view;
+ GtkWidget *account_export_view;
GtkWidget *stack_account;
- GtkWidget *current_account_notebook;
GtkWidget *button_remove_account;
GtkWidget *button_add_account;
GtkWidget *combobox_account_type;
+ GtkWidget *button_import_account;
+ GtkWidget *button_export_account;
gint current_page; /* keeps track of current notebook page displayed */
@@ -109,19 +113,24 @@ create_scrolled_account_view(GtkWidget *account_view)
}
static void
-account_selection_changed(GtkTreeSelection *selection, AccountView *view)
+tab_selection_changed(G_GNUC_UNUSED GtkNotebook *notebook,
+ G_GNUC_UNUSED GtkWidget *page,
+ guint page_num,
+ AccountView *self)
{
- g_return_if_fail(IS_ACCOUNT_VIEW(view));
- AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(view);
+ g_return_if_fail(IS_ACCOUNT_VIEW(self));
+ AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(self);
- GtkWidget *old_account_view = gtk_stack_get_visible_child(GTK_STACK(priv->stack_account));
+ priv->current_page = page_num;
+}
- /* keep track of the last tab displayed */
- if (priv->current_account_notebook)
- priv->current_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(priv->current_account_notebook));
+static void
+account_selection_changed(GtkTreeSelection *selection, AccountView *self)
+{
+ g_return_if_fail(IS_ACCOUNT_VIEW(self));
+ AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(self);
- if (priv->current_page < 0)
- priv->current_page = 0;
+ auto old_view = gtk_stack_get_visible_child(GTK_STACK(priv->stack_account));
QModelIndex account_idx = get_index_from_selection(selection);
if (!account_idx.isValid()) {
@@ -130,7 +139,10 @@ account_selection_changed(GtkTreeSelection *selection, AccountView *view)
gtk_widget_show(empty_box);
gtk_stack_add_named(GTK_STACK(priv->stack_account), empty_box, "placeholder");
gtk_stack_set_visible_child(GTK_STACK(priv->stack_account), empty_box);
- priv->current_account_notebook = NULL;
+
+ /* cannot delete nor export accounts */
+ gtk_widget_set_sensitive(priv->button_remove_account, FALSE);
+ gtk_widget_set_sensitive(priv->button_export_account, FALSE);
} else {
Account *account = AccountModel::instance().getAccountByModelIndex(account_idx);
@@ -138,48 +150,53 @@ account_selection_changed(GtkTreeSelection *selection, AccountView *view)
GtkWidget *hbox_account = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
/* create account notebook */
- priv->current_account_notebook = gtk_notebook_new();
- gtk_notebook_set_scrollable(GTK_NOTEBOOK(priv->current_account_notebook), TRUE);
- gtk_notebook_set_show_border(GTK_NOTEBOOK(priv->current_account_notebook), FALSE);
- gtk_box_pack_start(GTK_BOX(hbox_account), priv->current_account_notebook, TRUE, TRUE, 0);
+ auto account_notebook = gtk_notebook_new();
+ gtk_notebook_set_scrollable(GTK_NOTEBOOK(account_notebook), TRUE);
+ gtk_notebook_set_show_border(GTK_NOTEBOOK(account_notebook), FALSE);
+ gtk_box_pack_start(GTK_BOX(hbox_account), account_notebook, TRUE, TRUE, 0);
/* customize account view based on account */
auto general_tab = create_scrolled_account_view(account_general_tab_new(account));
- gtk_notebook_append_page(GTK_NOTEBOOK(priv->current_account_notebook),
+ gtk_notebook_append_page(GTK_NOTEBOOK(account_notebook),
general_tab,
gtk_label_new(C_("Account settings", "General")));
auto audio_tab = create_scrolled_account_view(account_audio_tab_new(account));
- gtk_notebook_append_page(GTK_NOTEBOOK(priv->current_account_notebook),
+ gtk_notebook_append_page(GTK_NOTEBOOK(account_notebook),
audio_tab,
gtk_label_new(C_("Account settings", "Audio")));
auto video_tab = create_scrolled_account_view(account_video_tab_new(account));
- gtk_notebook_append_page(GTK_NOTEBOOK(priv->current_account_notebook),
+ gtk_notebook_append_page(GTK_NOTEBOOK(account_notebook),
video_tab,
gtk_label_new(C_("Account settings", "Video")));
auto advanced_tab = create_scrolled_account_view(account_advanced_tab_new(account));
- gtk_notebook_append_page(GTK_NOTEBOOK(priv->current_account_notebook),
+ gtk_notebook_append_page(GTK_NOTEBOOK(account_notebook),
advanced_tab,
gtk_label_new(C_("Account settings", "Advanced")));
auto security_tab = create_scrolled_account_view(account_security_tab_new(account));
- gtk_notebook_append_page(GTK_NOTEBOOK(priv->current_account_notebook),
+ gtk_notebook_append_page(GTK_NOTEBOOK(account_notebook),
security_tab,
gtk_label_new(C_("Account settings", "Security")));
- /* set the tab displayed to the same as the prev account selected */
- gtk_notebook_set_current_page(GTK_NOTEBOOK(priv->current_account_notebook), priv->current_page);
-
gtk_widget_show_all(hbox_account);
+ /* set the tab displayed to the same as the prev account selected */
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(account_notebook), priv->current_page);
+ /* now connect to the tab changed signal */
+ g_signal_connect(account_notebook, "switch-page", G_CALLBACK(tab_selection_changed), self);
/* set the new account view as visible */
char *account_view_name = g_strdup_printf("%p_account", account);
gtk_stack_add_named(GTK_STACK(priv->stack_account), hbox_account, account_view_name);
gtk_stack_set_visible_child(GTK_STACK(priv->stack_account), hbox_account);
g_free(account_view_name);
+
+ /* can delete and export accounts */
+ gtk_widget_set_sensitive(priv->button_remove_account, TRUE);
+ gtk_widget_set_sensitive(priv->button_export_account, TRUE);
}
- /* remove the old account view */
- if (old_account_view)
- gtk_container_remove(GTK_CONTAINER(priv->stack_account), old_account_view);
+ /* remove the old view */
+ if (old_view)
+ gtk_container_remove(GTK_CONTAINER(priv->stack_account), old_view);
}
static void
@@ -367,6 +384,69 @@ state_to_string(G_GNUC_UNUSED GtkTreeViewColumn *tree_column,
}
static void
+close_import_export_view(AccountView *self)
+{
+ g_return_if_fail(IS_ACCOUNT_VIEW(self));
+ AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(self);
+
+ auto selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_account_list));
+ account_selection_changed(selection, self);
+}
+
+static void
+import_account(AccountView* self)
+{
+ g_return_if_fail(IS_ACCOUNT_VIEW(self));
+ AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(self);
+
+ auto old_view = gtk_stack_get_visible_child(GTK_STACK(priv->stack_account));
+
+ auto import_account = account_import_view_new();
+ g_signal_connect_swapped(import_account, "import-export-canceled", G_CALLBACK(close_import_export_view), self);
+ g_signal_connect_swapped(import_account, "import-export-completed", G_CALLBACK(close_import_export_view), self);
+ auto scrolled_view = create_scrolled_account_view(import_account);
+ gtk_widget_show_all(scrolled_view);
+ gtk_stack_add_named(GTK_STACK(priv->stack_account), scrolled_view, "import_account");
+ gtk_stack_set_visible_child(GTK_STACK(priv->stack_account), scrolled_view);
+
+ /* remove the old view */
+ if (old_view)
+ gtk_container_remove(GTK_CONTAINER(priv->stack_account), old_view);
+}
+
+static void
+export_account(AccountView* self)
+{
+ g_return_if_fail(IS_ACCOUNT_VIEW(self));
+ AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(self);
+
+ auto selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_account_list));
+ auto idx = get_index_from_selection(selection);
+ if (idx.isValid()) {
+ auto old_view = gtk_stack_get_visible_child(GTK_STACK(priv->stack_account));
+
+ auto account = AccountModel::instance().getAccountByModelIndex(idx);
+ auto export_account = account_export_view_new();
+ g_signal_connect_swapped(export_account, "import-export-canceled", G_CALLBACK(close_import_export_view), self);
+ g_signal_connect_swapped(export_account, "import-export-completed", G_CALLBACK(close_import_export_view), self);
+ GList *account_list = nullptr;
+ account_list = g_list_append(account_list, account);
+ account_export_view_set_accounts(ACCOUNT_IMPORTEXPORT_VIEW(export_account), account_list);
+ g_list_free(account_list);
+ auto scrolled_view = create_scrolled_account_view(export_account);
+ gtk_widget_show_all(scrolled_view);
+ gtk_stack_add_named(GTK_STACK(priv->stack_account), scrolled_view, "export_account");
+ gtk_stack_set_visible_child(GTK_STACK(priv->stack_account), scrolled_view);
+
+ /* remove the old view */
+ if (old_view)
+ gtk_container_remove(GTK_CONTAINER(priv->stack_account), old_view);
+
+ }
+
+}
+
+static void
account_view_init(AccountView *view)
{
gtk_widget_init_template(GTK_WIDGET(view));
@@ -475,6 +555,10 @@ account_view_init(AccountView *view)
/* connect signals to add/remove accounts */
g_signal_connect(priv->button_remove_account, "clicked", G_CALLBACK(remove_account), view);
g_signal_connect(priv->button_add_account, "clicked", G_CALLBACK(add_account), view);
+
+ /* signals to import/export acounts */
+ g_signal_connect_swapped(priv->button_import_account, "clicked", G_CALLBACK(import_account), view);
+ g_signal_connect_swapped(priv->button_export_account, "clicked", G_CALLBACK(export_account), view);
}
static void
@@ -491,6 +575,8 @@ account_view_class_init(AccountViewClass *klass)
gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountView, button_remove_account);
gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountView, button_add_account);
gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountView, combobox_account_type);
+ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountView, button_import_account);
+ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountView, button_export_account);
}
GtkWidget *
diff --git a/client-gnome/src/ring_client.cpp b/client-gnome/src/ring_client.cpp
index 15c5a5d..fb6c3be 100644
--- a/client-gnome/src/ring_client.cpp
+++ b/client-gnome/src/ring_client.cpp
@@ -258,15 +258,23 @@ init_systray(RingClient *client)
// init menu
if (!priv->icon_menu) {
- auto builder = gtk_builder_new_from_resource("/cx/ring/RingGnome/ringiconmenu.ui");
- auto menu_model = G_MENU_MODEL(gtk_builder_get_object(builder, "menu"));
- priv->icon_menu = gtk_menu_new_from_model(menu_model);
- /* enable the menu actions */
- gtk_widget_insert_action_group(priv->icon_menu, "app", G_ACTION_GROUP(client));
- g_object_unref(builder);
- g_object_unref(menu_model);
+ /* for some reason AppIndicator doesn't like the menu being built from a GMenuModel and/or
+ * the GMenuModel being built from an xml resource. So we build the menu in code.
+ */
+ priv->icon_menu = gtk_menu_new();
g_object_ref_sink(priv->icon_menu);
+
+ auto item = gtk_check_menu_item_new_with_label(C_("In the status icon menu, toggle action to show or hide the Ring main window", "Show Ring"));
+ gtk_actionable_set_action_name(GTK_ACTIONABLE(item), "app.show-main-window");
+ gtk_menu_shell_append(GTK_MENU_SHELL(priv->icon_menu), item);
+
+ item = gtk_menu_item_new_with_label(_("Quit"));
+ gtk_actionable_set_action_name(GTK_ACTIONABLE(item), "app.quit");
+ gtk_menu_shell_append(GTK_MENU_SHELL(priv->icon_menu), item);
+
+ gtk_widget_insert_action_group(priv->icon_menu, "app", G_ACTION_GROUP(client));
+ gtk_widget_show_all(priv->icon_menu);
}
#if USE_APPINDICATOR
diff --git a/client-gnome/ui/accountimportexportview.ui b/client-gnome/ui/accountimportexportview.ui
new file mode 100644
index 0000000..1a7f4db
--- /dev/null
+++ b/client-gnome/ui/accountimportexportview.ui
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.10"/>
+ <template class="AccountImportExportView" parent="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">10</property>
+ <property name="border-width">10</property>
+
+ <!-- export or import label, depending on whats being done -->
+ <child>
+ <object class="GtkLabel" id="label_export">
+ <property name="visible">False</property>
+ <property name="label" translatable="yes">Export selected account</property>
+ <property name="halign">center</property>
+ <property name="valign">start</property>
+ <property name="no-show-all">True</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_import">
+ <property name="visible">False</property>
+ <property name="label" translatable="yes">Import accounts</property>
+ <property name="halign">center</property>
+ <property name="valign">start</property>
+ <property name="no-show-all">True</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ <!-- end import/export label -->
+
+ <child>
+ <object class="GtkGrid" id="grid_ipmort_export">
+ <property name="visible">True</property>
+ <property name="column-spacing">10</property>
+ <property name="row-spacing">10</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+
+ <!-- location selection row -->
+ <child>
+ <object class="GtkLabel" id="label_location">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Location:</property>
+ <property name="halign">end</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+
+ <!-- filechooser for export -->
+ <child>
+ <object class="GtkBox" id="hbox_export_location">
+ <property name="visible">False</property>
+ <property name="orientation">horizontal</property>
+ <property name="spacing">5</property>
+ <property name="no-show-all">True</property>
+ <child>
+ <object class="GtkLabel" id="label_export_location">
+ <property name="visible">True</property>
+ <property name="ellipsize">start</property>
+ <property name="selectable">True</property>
+ <property name="label" translatable="yes">choose location</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_export_location">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes">Choose export location</property>
+ <property name="image">image_choose_file</property>
+ <property name="halign">end</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <!-- end filechooser for export -->
+
+ <!-- filechooser for import -->
+ <child>
+ <object class="GtkFileChooserButton" id="filechooserbutton_import">
+ <property name="visible">False</property>
+ <property name="create_folders">False</property>
+ <property name="action">open</property>
+ <property name="tooltip-text" translatable="yes">Choose archive location</property>
+ <property name="no-show-all">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <!-- end filechooser for import -->
+
+ <!-- end location selection row -->
+
+ <!-- password row -->
+ <child>
+ <object class="GtkLabel" id="label_password">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Password (required):</property>
+ <property name="halign">end</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+
+ <child>
+ <object class="GtkEntry" id="entry_password">
+ <property name="visible">True</property>
+ <property name="visibility">False</property>
+ <property name="primary_icon_stock">gtk-dialog-authentication</property>
+ <property name="input_purpose">password</property>
+ <property name="tooltip-text" translatable="yes">Enter archive password</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <!-- end password row -->
+
+ <!-- error message label -->
+ <child>
+ <object class="GtkLabel" id="label_error">
+ <property name="visible">True</property>
+ <attributes>
+ <attribute name="foreground" value="red"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <!-- end error message label -->
+
+ <child>
+ <object class="GtkButtonBox" id="buttonbox_confirm">
+ <property name="visible">True</property>
+ <property name="layout-style">spread</property>
+ <!-- <property name="valign">end</property> -->
+ <property name="spacing">10</property>
+
+ <child>
+ <object class="GtkButton" id="button_cancel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Cancel</property>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkButton" id="button_export">
+ <property name="visible">False</property>
+ <property name="sensitive">False</property>
+ <property name="label" translatable="yes">Export</property>
+ <property name="no-show-all">True</property>
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkButton" id="button_import">
+ <property name="visible">False</property>
+ <property name="sensitive">False</property>
+ <property name="label" translatable="yes">Import</property>
+ <property name="no-show-all">True</property>
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ </child>
+
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+
+ </object>
+ <packing>
+ <property name="fill">True</property>
+ <property name="expand">True</property>
+ </packing>
+ </child>
+
+ </template>
+
+ <object class="GtkImage" id="image_choose_file">
+ <property name="visible">True</property>
+ <property name="icon-name">list-add-symbolic</property>
+ </object>
+
+</interface>
diff --git a/client-gnome/ui/accountview.ui b/client-gnome/ui/accountview.ui
index d2641c4..f3c15c9 100644
--- a/client-gnome/ui/accountview.ui
+++ b/client-gnome/ui/accountview.ui
@@ -30,7 +30,7 @@
<child>
<object class="GtkBox" id="hbox_addremove_account">
<property name="visible">True</property>
-s <property name="orientation">horizontal</property>
+ <property name="orientation">horizontal</property>
<property name="spacing">5</property>
<property name="halign">GTK_ALIGN_CENTER</property>
<!-- remove account -->
@@ -38,6 +38,7 @@ s <property name="orientation">horizontal</property>
<object class="GtkButton" id="button_remove_account">
<property name="visible">True</property>
<property name="image">image_remove</property>
+ <property name="sensitive">False</property>
<property name="tooltip-text" translatable="yes">Remove selected account</property>
<child internal-child="accessible">
<object class="AtkObject" id="button_remove_account-atkobject">
@@ -85,6 +86,31 @@ s <property name="orientation">horizontal</property>
</object>
</child>
<!-- end add remove accounts -->
+
+ <!-- import/export account -->
+ <child>
+ <object class="GtkButtonBox" id="buttonbox_import_export">
+ <property name="visible">True</property>
+ <property name="orientation">horizontal</property>
+ <property name="layout-style">spread</property>
+ <property name="margin-top">5</property>
+ <child>
+ <object class="GtkButton" id="button_import_account">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Import</property>
+ <property name="tooltip-text" translatable="yes">Import archived account(s)</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_export_account">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Export</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip-text" translatable="yes">Export selected account(s)</property>
+ </object>
+ </child>
+ </object>
+ </child>
</object>
<!-- <packing>
</packing> -->
diff --git a/client-gnome/ui/ringiconmenu.ui b/client-gnome/ui/ringiconmenu.ui
deleted file mode 100644
index a5b439d..0000000
--- a/client-gnome/ui/ringiconmenu.ui
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0"?>
-<interface>
- <!-- interface-requires gtk+ 3.0 -->
- <menu id="menu">
- <section>
- <item>
- <attribute name="label" translatable="yes">Show Ring</attribute>
- <attribute name="action">app.show-main-window</attribute>
- </item>
- </section>
- <section>
- <item>
- <attribute name="label" translatable="yes">Quit</attribute>
- <attribute name="action">app.quit</attribute>
- </item>
- </section>
- </menu>
-</interface>
diff --git a/client-gnome/ui/ui.gresource.xml b/client-gnome/ui/ui.gresource.xml
index 59fb41a..aded6f6 100644
--- a/client-gnome/ui/ui.gresource.xml
+++ b/client-gnome/ui/ui.gresource.xml
@@ -17,6 +17,6 @@
<file preprocess="xml-stripblanks">choosecontactview.ui</file>
<file preprocess="xml-stripblanks">chatview.ui</file>
<file preprocess="xml-stripblanks">avatarmanipulation.ui</file>
- <file preprocess="xml-stripblanks">ringiconmenu.ui</file>
+ <file preprocess="xml-stripblanks">accountimportexportview.ui</file>
</gresource>
</gresources>
diff --git a/daemon/configure.ac b/daemon/configure.ac
index 3e2381d..ab744a1 100644
--- a/daemon/configure.ac
+++ b/daemon/configure.ac
@@ -102,7 +102,7 @@ AM_CONDITIONAL(HAVE_IOS, test "${HAVE_IOS}" = "1")
dnl FIXME this should be deduced automatically
AC_DEFINE_UNQUOTED([HAVE_COREAUDIO],
- `if test "${HAVE_OSX}" = "1"; then echo 1; else echo 0; fi`,
+ `if test "${HAVE_OSX}" = "1" || test "${HAVE_IOS}" = "1"; then echo 1; else echo 0; fi`,
[Define if you have CoreAudio])
dnl Android is linux, but a bit different
@@ -413,28 +413,8 @@ AS_IF([test "x$enable_video" != "xno"],
AM_CONDITIONAL(RING_VIDEO, false)
]);
-dnl TLS support is enabled if it's installed and up to date
-AC_ARG_WITH([tls],
- [AS_HELP_STRING([--with-tls],
- [support tls @<:@default=check@:>@])],
- [],
- [with_tls=check])
-AS_CASE(["$with_tls"],
- [yes], [PKG_CHECK_MODULES([GNUTLS], [gnutls >= 3.3], [HAVE_GNUTLS=1])],
- [no], [HAVE_GNUTLS=0],
- [PKG_CHECK_MODULES([GNUTLS], [gnutls >= 3.3], [HAVE_GNUTLS=1], [HAVE_GNUTLS=0])])
-
-AC_DEFINE_UNQUOTED([HAVE_TLS], `if test $HAVE_GNUTLS -eq 1; then echo 1; else echo 0; fi`, [Define if you have tls support])
-AM_CONDITIONAL(BUILD_TLS, test "$HAVE_GNUTLS" -eq 1)
-
-# Instant Messaging
-AC_ARG_WITH([instant_messaging],
- [AS_HELP_STRING([--without-instant_messaging], [disable support for instant-messaging])],
- [],
- [with_instant_messaging=yes])
-
-AC_DEFINE_UNQUOTED([HAVE_INSTANT_MESSAGING], `if test "x$with_instant_messaging" = "xyes"; then echo 1; else echo 0; fi`, [Define if you have instant messaging support])
-AM_CONDITIONAL(BUILD_INSTANT_MESSAGING, test "x$with_instant_messaging" = "xyes" )
+dnl check for GnuTLS
+PKG_CHECK_MODULES([GNUTLS], [gnutls >= 3.4.14], [HAVE_GNUTLS=1], [HAVE_GNUTLS=0])
# PTHREAD
@@ -530,20 +510,8 @@ AS_CASE(["$with_opus"],
[PKG_CHECK_MODULES([opus], [opus], [HAVE_OPUS=1], [HAVE_OPUS=0])])
AM_CONDITIONAL([BUILD_OPUS], [test "$HAVE_OPUS" -eq 1])
-# dht is default-enabled, but requires gnutls
-AC_ARG_ENABLE([dht],
- AS_HELP_STRING([--disable-dht], [disable support for dht]))
-
-AS_IF([test "x$enable_dht" != "xno" -a "$HAVE_GNUTLS" -eq 1],
- [AC_DEFINE([HAVE_DHT], 1, [Define to enable dht])
- PKG_CHECK_MODULES([OPENDHT], opendht,
- AC_DEFINE([HAVE_DHT], 1, [Define to enable dht])
- AM_CONDITIONAL(USE_DHT, true),
- AC_DEFINE([HAVE_DHT], 0, [Define to enable dht])
- AM_CONDITIONAL(USE_DHT, false)
- AC_MSG_WARN([Missing OpenDHT]))],
- [AC_DEFINE([HAVE_DHT], 0, [Define to enable dht])
- AM_CONDITIONAL(USE_DHT, false)])
+dnl check for openDHT
+PKG_CHECK_MODULES([OPENDHT], [opendht >= 0.6.1],, AC_MSG_WARN([Missing OpenDHT]))
dnl IPv6 mode is default-disabled
AC_ARG_ENABLE([ipv6], AS_HELP_STRING([--enable-ipv6], [Enable IPv6 support]))
@@ -563,6 +531,20 @@ AS_IF([test "x$with_upnp" = "xyes"],
AC_DEFINE([HAVE_LIBUPNP], 0, [Define if you have libupnp])])
])
+# LIBNATPMP
+dnl check for libnatpmp
+AC_ARG_WITH([natpmp], [AS_HELP_STRING([--without-natpmp],
+ [disable support for NAT-PMP])], [], [with_natpmp=yes])
+
+AS_IF([test "x$with_natpmp" != xno],
+ [AC_CHECK_HEADER([natpmp.h],
+ AC_CHECK_LIB([natpmp], [initnatpmp], [], [with_natpmp=no]),
+ [AC_MSG_WARN([Unable to find the libnatpmp headers (you may need to install the dev package). You may use --without-natpmp to compile without NAT-PMP support.]);
+ with_natpmp=no])
+ ],[])
+
+AC_DEFINE_UNQUOTED([HAVE_LIBNATPMP], `if test "x$with_natpmp" != xno; then echo 1; else echo 0; fi`, [Define if you have libnatpmp])
+
AC_DEFINE_UNQUOTED([HAVE_SHM], `if test -z "${HAVE_LINUX_TRUE}" && test -z "${HAVE_ANDROID_FALSE}" ; then echo 1; else echo 0; fi`,
[Define if you have shared memory support])
diff --git a/daemon/contrib/src/ffmpeg/rules.mak b/daemon/contrib/src/ffmpeg/rules.mak
index 34d0263..7b53ed7 100644
--- a/daemon/contrib/src/ffmpeg/rules.mak
+++ b/daemon/contrib/src/ffmpeg/rules.mak
@@ -19,7 +19,6 @@ FFMPEGCONF += \
--disable-programs \
--disable-sdl
-
#enable muxers/demuxers
FFMPEGCONF += \
--enable-demuxers \
@@ -83,13 +82,24 @@ FFMPEGCONF += \
--enable-encoder=tiff \
--enable-decoder=tiff
+ifdef HAVE_WIN32
FFMPEGCONF += \
--enable-indev=dshow \
--enable-indev=gdigrab \
--enable-dxva2
+endif
DEPS_ffmpeg = iconv zlib x264 vpx opus speex $(DEPS_vpx)
+ifdef HAVE_IOS
+FFMPEGCONF += \
+ --target-os=darwin \
+ --enable-cross-compile \
+ --arch=$(ARCH) \
+ --enable-pic \
+ --enable-indev=avfoundation
+endif
+
# Linux
ifdef HAVE_LINUX
FFMPEGCONF += --target-os=linux --enable-pic
@@ -102,9 +112,11 @@ FFMPEGCONF += --disable-asm
endif
endif
+ifndef HAVE_IOS
ifdef HAVE_CROSS_COMPILE
FFMPEGCONF += --cross-prefix=$(HOST)-
endif
+endif
# x86 stuff
ifeq ($(ARCH),i386)
@@ -160,6 +172,7 @@ ffmpeg: ffmpeg-$(FFMPEG_HASH).tar.xz .sum-ffmpeg
.ffmpeg: ffmpeg
cd $< && $(HOSTVARS) ./configure \
+ --extra-cflags="$(CFLAGS)" \
--extra-ldflags="$(LDFLAGS)" $(FFMPEGCONF) \
--prefix="$(PREFIX)" --enable-static --disable-shared
cd $< && $(MAKE) install-libs install-headers
diff --git a/daemon/contrib/src/gmp/rules.mak b/daemon/contrib/src/gmp/rules.mak
index 4309a73..96c7980 100644
--- a/daemon/contrib/src/gmp/rules.mak
+++ b/daemon/contrib/src/gmp/rules.mak
@@ -14,7 +14,7 @@ gmp: gmp-$(GMP_VERSION).tar.bz2 .sum-gmp
.gmp: gmp
ifdef HAVE_IOS
- cd $< && $(HOSTVARS) ./configure --disable-assembly $(HOSTCONF)
+ cd $< && $(HOSTVARS) CFLAGS="$(CFLAGS) -O3" ./configure --disable-assembly $(HOSTCONF)
else
cd $< && $(HOSTVARS) ./configure $(HOSTCONF)
endif
diff --git a/daemon/contrib/src/gnutls/SHA512SUMS b/daemon/contrib/src/gnutls/SHA512SUMS
index 5c13629..7292832 100644
--- a/daemon/contrib/src/gnutls/SHA512SUMS
+++ b/daemon/contrib/src/gnutls/SHA512SUMS
@@ -1 +1 @@
-e5cd60240ebbcac9d8f7c28fdbf023a499e3c58a352a43c24d075b248a0a903161b1745641bf263519293c0014424cc23dbb67274c8934aaf273a523ad0a2925 gnutls-3.4.10.tar.xz
+d75f6b4dea2dc742cd7f60ee0ee540d41b69991aaa937ca0138cfdf4a1e0dfaaa3863464303bfa5799e14ee02de252f71c59a7a9e57b96ff8af653e419edfd4e gnutls-3.4.14.tar.xz
diff --git a/daemon/contrib/src/gnutls/dtls-packet-reordering.patch b/daemon/contrib/src/gnutls/dtls-packet-reordering.patch
deleted file mode 100644
index 24a474a..0000000
--- a/daemon/contrib/src/gnutls/dtls-packet-reordering.patch
+++ /dev/null
@@ -1,5 +0,0 @@
---- a/lib/gnutls_buffers.c
-+++ b/lib/gnutls_buffers.c
-@@ -1033 +1033 @@
-- && hsk->end_offset >=
-+ && hsk->end_offset + 1 >=
diff --git a/daemon/contrib/src/gnutls/format-security.patch b/daemon/contrib/src/gnutls/format-security.patch
deleted file mode 100644
index b0b4f32..0000000
--- a/daemon/contrib/src/gnutls/format-security.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-diff -rU0 gnutls-old/lib/x509/ocsp_output.c gnutls/lib/x509/ocsp_output.c
---- gnutls-old/lib/x509/ocsp_output.c
-+++ gnutls/lib/x509/ocsp_output.c
-@@ -289 +289 @@
-- addf(str, _("\tResponder Key ID: "));
-+ adds(str, _("\tResponder Key ID: "));
diff --git a/daemon/contrib/src/gnutls/rules.mak b/daemon/contrib/src/gnutls/rules.mak
index 58fbd75..e7c2280 100644
--- a/daemon/contrib/src/gnutls/rules.mak
+++ b/daemon/contrib/src/gnutls/rules.mak
@@ -1,11 +1,10 @@
# GnuTLS
-GNUTLS_VERSION := 3.4.10
+GNUTLS_VERSION := 3.4.14
GNUTLS_URL := ftp://ftp.gnutls.org/gcrypt/gnutls/v3.4/gnutls-$(GNUTLS_VERSION).tar.xz
PKGS += gnutls
-# We need at least the 3.4.10, but DTLS handshake re-ordered packet fix is only available since 3.4.14
-# So we patch the 3.4.10 until official release of 3.4.14
+
ifeq ($(call need_pkg,"gnutls >= 3.4.14"),)
PKGS_FOUND += gnutls
endif
@@ -33,8 +32,6 @@ endif
ifndef HAVE_IOS
$(APPLY) $(SRC)/gnutls/mac-keychain-lookup.patch
endif
- $(APPLY) $(SRC)/gnutls/format-security.patch
- $(APPLY) $(SRC)/gnutls/dtls-packet-reordering.patch
$(call pkg_static,"lib/gnutls.pc.in")
$(UPDATE_AUTOCONFIG)
$(MOVE)
@@ -52,6 +49,7 @@ GNUTLS_CONF := \
--disable-nls \
--disable-dtls-srtp-support \
--without-libintl-prefix \
+ --disable-non-suiteb-curves \
$(HOSTCONF)
ifdef HAVE_ANDROID
diff --git a/daemon/contrib/src/gsm/include_ios.patch b/daemon/contrib/src/gsm/include_ios.patch
new file mode 100644
index 0000000..80db687
--- /dev/null
+++ b/daemon/contrib/src/gsm/include_ios.patch
@@ -0,0 +1,11 @@
+--- a/src/code.c 2016-06-13 10:49:31.000000000 -0400
++++ b/src/code.c 2016-06-13 10:49:22.000000000 -0400
+@@ -16,6 +16,8 @@
+ extern char * memcpy P((char *, char *, int));
+ #endif
+
++#include <string.h>
++
+ #include "private.h"
+ #include "gsm.h"
+ #include "proto.h"
diff --git a/daemon/contrib/src/gsm/rules.mak b/daemon/contrib/src/gsm/rules.mak
index 2ca2b44..c080287 100644
--- a/daemon/contrib/src/gsm/rules.mak
+++ b/daemon/contrib/src/gsm/rules.mak
@@ -12,6 +12,7 @@ $(TARBALLS)/libgsm_$(GSM_VERSION).tar.gz:
gsm: libgsm_$(GSM_VERSION).tar.gz .sum-gsm
$(UNPACK)
mv gsm-1.0-* libgsm_$(GSM_VERSION)
+ $(APPLY) $(SRC)/gsm/include_ios.patch
$(APPLY) $(SRC)/gsm/gsm-cross.patch
sed -e 's/^CFLAGS.*=/CFLAGS+=/' -i.orig libgsm_$(GSM_VERSION)/Makefile
$(MOVE)
diff --git a/daemon/contrib/src/jsoncpp/SHA512SUMS b/daemon/contrib/src/jsoncpp/SHA512SUMS
index 614157b..e42d7f8 100644
--- a/daemon/contrib/src/jsoncpp/SHA512SUMS
+++ b/daemon/contrib/src/jsoncpp/SHA512SUMS
@@ -1 +1 @@
-589153d525ffde15e10f1ef6907c6b5d0f62a41c8cebdc12fe2bc4d989bcd861cdac79526de2f51872c0a17e574bf0fd8c913f0aa301c184efa1e3f2fb2b1955 jsoncpp-1.6.5.tar.gz
+32702147229ea7a3679654325572c38f4188f258ab6ac21f9e04059d53ef2a7cd0542ec4ec3b0e7b9089acd2b7bce389f16b9ff24b2e63e0ba2a5bcd46bab766 jsoncpp-1.7.2.tar.gz
diff --git a/daemon/contrib/src/jsoncpp/rules.mak b/daemon/contrib/src/jsoncpp/rules.mak
index b23b0e6..5be14e8 100644
--- a/daemon/contrib/src/jsoncpp/rules.mak
+++ b/daemon/contrib/src/jsoncpp/rules.mak
@@ -1,5 +1,5 @@
# JSONCPP
-JSONCPP_VERSION := 1.6.5
+JSONCPP_VERSION := 1.7.2
JSONCPP_URL := https://github.com/open-source-parsers/jsoncpp/archive/$(JSONCPP_VERSION).tar.gz
PKGS += jsoncpp
diff --git a/daemon/contrib/src/natpmp/SHA512SUMS b/daemon/contrib/src/natpmp/SHA512SUMS
new file mode 100644
index 0000000..956a4e3
--- /dev/null
+++ b/daemon/contrib/src/natpmp/SHA512SUMS
@@ -0,0 +1 @@
+e50b1f68ce9254bb2f068ddc37417a3c417b80f7b3fb3d84e3e9af4a144d89e204ab993b54c01657335e855d0124a8fcbbf96ce78db7b9ae0b03b6eb79de2e09 libnatpmp-20150609.tar.gz
diff --git a/daemon/contrib/src/natpmp/rules.mak b/daemon/contrib/src/natpmp/rules.mak
new file mode 100644
index 0000000..49ddcb0
--- /dev/null
+++ b/daemon/contrib/src/natpmp/rules.mak
@@ -0,0 +1,21 @@
+# libnatpmp
+NATPMP_VERSION := 20150609
+NATPMP_URL := http://miniupnp.free.fr/files/download.php?file=libnatpmp-$(NATPMP_VERSION).tar.gz
+
+PKGS += natpmp
+ifeq ($(call need_pkg,'libnatpmp'),)
+PKGS_FOUND += natpmp
+endif
+
+$(TARBALLS)/libnatpmp-$(NATPMP_VERSION).tar.gz:
+ $(call download,$(NATPMP_URL))
+
+.sum-natpmp: libnatpmp-$(NATPMP_VERSION).tar.gz
+
+natpmp: libnatpmp-$(NATPMP_VERSION).tar.gz .sum-natpmp
+ $(UNPACK)
+ $(MOVE)
+
+.natpmp: natpmp
+ cd $< && $(MAKE) INSTALLPREFIX="$(PREFIX)" install
+ touch $@
diff --git a/daemon/contrib/src/nettle/rules.mak b/daemon/contrib/src/nettle/rules.mak
index 888570e..b245cca 100644
--- a/daemon/contrib/src/nettle/rules.mak
+++ b/daemon/contrib/src/nettle/rules.mak
@@ -5,12 +5,9 @@ NETTLE_URL := $(GNU)/nettle/nettle-$(NETTLE_VERSION).tar.gz
PKGS += nettle
-# TEMPORARY DISABLED
-# Force nettle contrib until gnutls major patches are upstream and released
-# See gnutls rules.mak for more information
-#ifeq ($(call need_pkg,"nettle >= 3.1"),)
-#PKGS_FOUND += nettle
-#endif
+ifeq ($(call need_pkg,"nettle >= 3.1"),)
+PKGS_FOUND += nettle
+endif
$(TARBALLS)/nettle-$(NETTLE_VERSION).tar.gz:
$(call download,$(NETTLE_URL))
@@ -26,7 +23,9 @@ DEPS_nettle = gmp $(DEPS_gmp)
.nettle: nettle
ifdef HAVE_IOS
- cd $< && $(HOSTVARS) ./configure --disable-assembler $(HOSTCONF)
+ cd $< && sed -i.orig s/-ggdb3//g configure.ac
+ cd $< && autoreconf
+ cd $< && $(HOSTVARS) CFLAGS="$(CFLAGS) -O3" ./configure $(HOSTCONF)
else
cd $< && $(HOSTVARS) ./configure $(HOSTCONF)
endif
diff --git a/daemon/contrib/src/opus/rules.mak b/daemon/contrib/src/opus/rules.mak
index 52f3cbe..bba61a7 100644
--- a/daemon/contrib/src/opus/rules.mak
+++ b/daemon/contrib/src/opus/rules.mak
@@ -25,10 +25,6 @@ ifndef HAVE_FPU
OPUS_CONF += --enable-fixed-point
endif
-ifdef HAVE_IOS
-OPUS_CONF += --disable-asm
-endif
-
.opus: opus
cd $< && $(HOSTVARS) ./configure $(HOSTCONF) $(OPUS_CONF)
cd $< && $(MAKE) install
diff --git a/daemon/contrib/src/pjproject/gnutls.patch b/daemon/contrib/src/pjproject/gnutls.patch
index 778baf5..4d2123a 100644
--- a/daemon/contrib/src/pjproject/gnutls.patch
+++ b/daemon/contrib/src/pjproject/gnutls.patch
@@ -460,7 +460,7 @@ new file mode 100644
index 0000000..6864740
--- /dev/null
+++ b/pjlib/src/pj/ssl_sock_gtls.c
-@@ -0,0 +1,2869 @@
+@@ -0,0 +1,2865 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2014-2015 Savoir-faire Linux. (http://www.savoirfairelinux.com)
@@ -1155,11 +1155,7 @@ index 0000000..6864740
+ if (ssock->param.proto & PJ_SSL_SOCK_PROTO_TLS1) {
+ pj_strcat2(&priority, "+VERS-TLS1.0:");
+ }
-+ if (ssock->param.proto & PJ_SSL_SOCK_PROTO_SSL3) {
-+ pj_strcat2(&priority, "+VERS-SSL3.0:");
-+ } else {
-+ pj_strcat2(&priority, "-VERS-SSL3.0:");
-+ }
++ pj_strcat2(&priority, "-VERS-SSL3.0:");
+ pj_strcat2(&priority, "%LATEST_RECORD_VERSION");
+
+ pj_strcat(&cipher_list, &priority);
diff --git a/daemon/contrib/src/speexdsp/rules.mak b/daemon/contrib/src/speexdsp/rules.mak
index 997ea48..05f88a4 100644
--- a/daemon/contrib/src/speexdsp/rules.mak
+++ b/daemon/contrib/src/speexdsp/rules.mak
@@ -1,7 +1,7 @@
# speexdsp
SPEEXDSP_VERSION := git
-SPEEXDSP_HASH := HEAD
+SPEEXDSP_HASH := 83b63852e0e4755a8c04a1f9c87dd73b5aa6293f
SPEEXDSP_GITURL := http://git.xiph.org/?p=speexdsp.git;a=snapshot;h=$(SPEEXDSP_HASH);sf=tgz
PKGS += speexdsp
diff --git a/daemon/contrib/src/uuid/rules.mak b/daemon/contrib/src/uuid/rules.mak
index fa620f9..63f3296 100644
--- a/daemon/contrib/src/uuid/rules.mak
+++ b/daemon/contrib/src/uuid/rules.mak
@@ -3,9 +3,13 @@
UUID_VERSION := 1.0.2
UUID_URL := $(SF)/libuuid/libuuid-$(UUID_VERSION).tar.gz
+ifndef HAVE_IOS
ifeq ($(call need_pkg,"uuid >= 2.0.0"),)
PKGS_FOUND += uuid
endif
+else
+PKGS_FOUND += uuid
+endif
$(TARBALLS)/libuuid-$(UUID_VERSION).tar.gz:
$(call download,$(UUID_URL))
diff --git a/daemon/contrib/src/vpx/rules.mak b/daemon/contrib/src/vpx/rules.mak
index 10b6cf4..0d09bd0 100644
--- a/daemon/contrib/src/vpx/rules.mak
+++ b/daemon/contrib/src/vpx/rules.mak
@@ -1,6 +1,11 @@
# libvpx
+#Libav doesnt support new vpx version
+ifdef HAVE_IOS
+VPX_HASH := cbecf57f3e0d85a7b7f97f3ab7c507f6fe640a93
+else
VPX_HASH := c74bf6d889992c3cabe017ec353ca85c323107cd
+endif
VPX_URL := https://github.com/webmproject/libvpx/archive/$(VPX_HASH).tar.gz
#VPX_GITURL := https://code.google.com/p/webm.libvpx
@@ -20,13 +25,18 @@ libvpx: libvpx-$(VPX_HASH).tar.gz .sum-vpx
DEPS_vpx =
ifdef HAVE_CROSS_COMPILE
+ifndef HAVE_IOS
VPX_CROSS := $(CROSS_COMPILE)
+endif
else
VPX_CROSS :=
endif
+
ifeq ($(ARCH),arm)
VPX_ARCH := armv7
+else ifeq ($(ARCH),arm64)
+VPX_ARCH := arm64
else ifeq ($(ARCH),i386)
VPX_ARCH := x86
else ifeq ($(ARCH),mips)
@@ -46,7 +56,11 @@ VPX_OS := android
else ifdef HAVE_LINUX
VPX_OS := linux
else ifdef HAVE_DARWIN_OS
-ifeq ($(ARCH),arm)
+ifeq ($(IOS_TARGET_PLATFORM),iPhoneSimulator)
+VPX_OS := iphonesimulator
+else ifeq ($(ARCH),armv7)
+VPX_OS := darwin
+else ifeq ($(ARCH),arm64)
VPX_OS := darwin
else
ifeq ($(OSX_VERSION),10.5)
@@ -95,7 +109,7 @@ ifdef HAVE_MACOSX
VPX_CONF += --sdk-path=$(MACOSX_SDK)
endif
ifdef HAVE_IOS
-VPX_CONF += --sdk-path=$(SDKROOT)
+VPX_CONF += --sdk-path=$(IOS_SDK)
endif
LOCAL_HOSTVARS=
ifdef HAVE_ANDROID
diff --git a/daemon/contrib/src/x264/rules.mak b/daemon/contrib/src/x264/rules.mak
index 9ad7c95..cf5f4d6 100644
--- a/daemon/contrib/src/x264/rules.mak
+++ b/daemon/contrib/src/x264/rules.mak
@@ -22,9 +22,11 @@ X264CONF += --enable-pic
else
X264CONF += --enable-win32thread
endif
+ifndef HAVE_IOS
ifdef HAVE_CROSS_COMPILE
X264CONF += --cross-prefix="$(CROSS_COMPILE)"
endif
+endif
$(TARBALLS)/x264-$(X264_HASH).tar.xz:
$(call download_git,$(X264_GITURL),master,$(X264_HASH))
diff --git a/daemon/src/Makefile.am b/daemon/src/Makefile.am
index e76ec02..ffbca3f 100644
--- a/daemon/src/Makefile.am
+++ b/daemon/src/Makefile.am
@@ -23,23 +23,7 @@ RING_VIDEO_LIBS+= \
endif
endif
-if BUILD_INSTANT_MESSAGING
-INSTANT_MESSAGING_SUBDIR = im
-IM_LIBA=./im/libim.la
-endif
-
-if USE_DHT
-RINGACC_SUBDIR=ringdht
-RINGACC_CXXFLAG=-DUSE_DHT
-RINGACC_LIBA=./ringdht/libringacc.la
-endif
-
-if BUILD_TLS
-TLS_LIB = @GNUTLS_LIBS@
-TLS_CFLAGS = @GNUTLS_CFLAGS@
-endif
-
-SUBDIRS = client media config hooks sip upnp security $(RINGACC_SUBDIR) $(INSTANT_MESSAGING_SUBDIR) $(RING_VIDEO_SUBDIR)
+SUBDIRS = client media config hooks sip upnp security ringdht im $(RING_VIDEO_SUBDIR)
# libring
@@ -53,8 +37,8 @@ libring_la_LIBADD = \
./hooks/libhooks.la \
./security/libsecurity.la \
./upnp/libupnpcontrol.la \
- $(RINGACC_LIBA) \
- $(IM_LIBA) \
+ ./ringdht/libringacc.la \
+ ./im/libim.la \
$(RING_VIDEO_LIBS)
libring_la_LDFLAGS = \
@@ -68,14 +52,10 @@ libring_la_LDFLAGS = \
@SPEEXDSP_LIBS@ \
@LIBUPNP_LIBS@ \
@PORTAUDIO_LIBS@ \
- $(TLS_LIB) \
- $(IM_LIB) \
+ @GNUTLS_LIBS@ \
+ @OPENDHT_LIBS@ \
$(PCRE_LIBS)
-if USE_DHT
-libring_la_LDFLAGS += $(OPENDHT_LIBS)
-endif
-
if HAVE_OSX
#FIXME necessary for -lintl
libring_la_LDFLAGS += -L/usr/local/opt/gettext/lib
@@ -89,14 +69,11 @@ libring_la_CFLAGS = \
@LIBUPNP_CFLAGS@ \
@SPEEXDSP_CFLAGS@ \
@PORTAUDIO_CFLAGS@ \
- $(TLS_CFLAGS)
+ @GNUTLS_CFLAGS@ \
+ @OPENDHT_CFLAGS@
libring_la_CXXFLAGS = @JSONCPP_CFLAGS@
-if USE_DHT
-libring_la_CFLAGS += $(OPENDHT_CFLAGS)
-endif
-
libring_la_SOURCES = \
buildinfo.cpp \
conference.cpp \
diff --git a/daemon/src/account.cpp b/daemon/src/account.cpp
index b1cdbcb..f7cd8fa 100644
--- a/daemon/src/account.cpp
+++ b/daemon/src/account.cpp
@@ -36,12 +36,8 @@
#include "logger.h"
#include "manager.h"
-#if HAVE_DHT
#include <opendht/rng.h>
using random_device = dht::crypto::random_device;
-#else
-using random_device = std::random_device;
-#endif
#include "client/ring_signal.h"
#include "account_schema.h"
diff --git a/daemon/src/account_factory.cpp b/daemon/src/account_factory.cpp
index 3feb736..5123372 100644
--- a/daemon/src/account_factory.cpp
+++ b/daemon/src/account_factory.cpp
@@ -25,9 +25,7 @@
#include "account_factory.h"
#include "sip/sipaccount.h"
-#if HAVE_DHT
#include "ringdht/ringaccount.h"
-#endif
#include <stdexcept>
@@ -40,11 +38,9 @@ AccountFactory::AccountFactory()
auto sipfunc = [](const std::string& id){ return std::make_shared<SIPAccount>(id, true); };
generators_.insert(std::make_pair(SIPAccount::ACCOUNT_TYPE, sipfunc));
RING_DBG("registered %s account", SIPAccount::ACCOUNT_TYPE);
-#if HAVE_DHT
auto dhtfunc = [](const std::string& id){ return std::make_shared<RingAccount>(id, false); };
generators_.insert(std::make_pair(RingAccount::ACCOUNT_TYPE, dhtfunc));
RING_DBG("registered %s account", RingAccount::ACCOUNT_TYPE);
-#endif
}
std::shared_ptr<Account>
diff --git a/daemon/src/call.h b/daemon/src/call.h
index e5c3329..54c264a 100644
--- a/daemon/src/call.h
+++ b/daemon/src/call.h
@@ -299,7 +299,6 @@ class Call : public Recordable, public std::enable_shared_from_this<Call> {
*/
virtual void carryingDTMFdigits(char code) = 0;
-#if HAVE_INSTANT_MESSAGING
/**
* Send a message to a call identified by its callid
*
@@ -308,7 +307,6 @@ class Call : public Recordable, public std::enable_shared_from_this<Call> {
*/
virtual void sendTextMessage(const std::map<std::string, std::string>& messages,
const std::string &from) = 0;
-#endif
void removeCall();
diff --git a/daemon/src/client/callmanager.cpp b/daemon/src/client/callmanager.cpp
index b190d9d..9882973 100644
--- a/daemon/src/client/callmanager.cpp
+++ b/daemon/src/client/callmanager.cpp
@@ -324,9 +324,7 @@ acceptEnrollment(const std::string& /*callID*/, bool /*accepted*/)
void
sendTextMessage(const std::string& callID, const std::map<std::string, std::string>& messages, const std::string& from, bool isMixed)
{
-#if HAVE_INSTANT_MESSAGING
ring::Manager::instance().sendCallTextMessage(callID, messages, from, isMixed);
-#endif
}
} // namespace DRing
diff --git a/daemon/src/client/configurationmanager.cpp b/daemon/src/client/configurationmanager.cpp
index b1338c1..233e335 100644
--- a/daemon/src/client/configurationmanager.cpp
+++ b/daemon/src/client/configurationmanager.cpp
@@ -28,10 +28,8 @@
#include "configurationmanager_interface.h"
#include "account_schema.h"
#include "manager.h"
-#if HAVE_TLS && HAVE_DHT
#include "security/tlsvalidator.h"
#include "security/certstore.h"
-#endif
#include "logger.h"
#include "fileutils.h"
#include "archiver.h"
@@ -119,17 +117,12 @@ std::map<std::string, std::string>
validateCertificate(const std::string&,
const std::string& certificate)
{
-#if HAVE_TLS && HAVE_DHT
try {
return TlsValidator{CertificateStore::instance().getCertificate(certificate)}.getSerializedChecks();
} catch(const std::runtime_error& e) {
RING_WARN("Certificate loading failed: %s", e.what());
return {{Certificate::ChecksNames::EXIST, Certificate::CheckValuesNames::FAILED}};
}
-#else
- RING_WARN("TLS not supported");
- return {};
-#endif
}
std::map<std::string, std::string>
@@ -139,38 +132,28 @@ validateCertificatePath(const std::string&,
const std::string& privateKeyPass,
const std::string& caList)
{
-#if HAVE_TLS && HAVE_DHT
try {
return TlsValidator{certificate, privateKey, privateKeyPass, caList}.getSerializedChecks();
} catch(const std::runtime_error& e) {
RING_WARN("Certificate loading failed: %s", e.what());
return {{Certificate::ChecksNames::EXIST, Certificate::CheckValuesNames::FAILED}};
}
-#else
- RING_WARN("TLS not supported");
- return {};
-#endif
}
std::map<std::string, std::string>
getCertificateDetails(const std::string& certificate)
{
-#if HAVE_TLS && HAVE_DHT
try {
return TlsValidator{CertificateStore::instance().getCertificate(certificate)}.getSerializedDetails();
} catch(const std::runtime_error& e) {
RING_WARN("Certificate loading failed: %s", e.what());
}
-#else
- RING_WARN("TLS not supported");
-#endif
return {};
}
std::map<std::string, std::string>
getCertificateDetailsPath(const std::string& certificate, const std::string& privateKey, const std::string& privateKeyPassword)
{
-#if HAVE_TLS && HAVE_DHT
try {
auto crt = std::make_shared<dht::crypto::Certificate>(ring::fileutils::loadFile(certificate));
TlsValidator validator {certificate, privateKey, privateKeyPassword};
@@ -179,20 +162,13 @@ getCertificateDetailsPath(const std::string& certificate, const std::string& pri
} catch(const std::runtime_error& e) {
RING_WARN("Certificate loading failed: %s", e.what());
}
-#else
- RING_WARN("TLS not supported");
-#endif
return {};
}
std::vector<std::string>
getPinnedCertificates()
{
-#if HAVE_TLS && HAVE_DHT
return ring::tls::CertificateStore::instance().getPinnedCertificates();
-#else
- RING_WARN("TLS not supported");
-#endif
return {};
}
@@ -390,11 +366,9 @@ getSupportedTlsMethod()
std::vector<std::string>
getSupportedCiphers(const std::string& accountID)
{
-#if HAVE_TLS
if (auto sipaccount = ring::Manager::instance().getAccount<SIPAccount>(accountID))
return SIPAccount::getSupportedTlsCiphers();
RING_ERR("SIP account %s doesn't exist", accountID.c_str());
-#endif
return {};
}
diff --git a/daemon/src/manager.cpp b/daemon/src/manager.cpp
index 6d26387..91d1b74 100644
--- a/daemon/src/manager.cpp
+++ b/daemon/src/manager.cpp
@@ -39,13 +39,9 @@
#include "map_utils.h"
#include "account.h"
#include "string_utils.h"
-#if HAVE_DHT
#include "ringdht/ringaccount.h"
#include <opendht/rng.h>
using random_device = dht::crypto::random_device;
-#else
-using random_device = std::random_device;
-#endif
#include "call_factory.h"
@@ -149,7 +145,6 @@ setSipLogLevel()
pj_log_set_level(level);
}
-#if HAVE_TLS
/**
* Set gnutls's log level based on the RING_TLS_LOGLEVEL environment variable.
* RING_TLS_LOGLEVEL = 0 minimum logging (default)
@@ -182,7 +177,6 @@ setGnuTlsLogLevel()
gnutls_global_set_log_level(level);
gnutls_global_set_log_function(tls_print_logs);
}
-#endif // HAVE_TLS
Manager&
Manager::instance()
@@ -276,10 +270,8 @@ Manager::init(const std::string &config_file)
RING_DBG("pjsip version %s for %s initialized",
pj_get_version(), PJ_OS_NAME);
-#if HAVE_TLS
setGnuTlsLogLevel();
RING_DBG("GNU TLS version %s initialized", gnutls_check_version(nullptr));
-#endif
ice_tf_.reset(new IceTransportFactory());
@@ -1637,7 +1629,6 @@ Manager::incomingCall(Call &call, const std::string& accountId)
}
//THREAD=VoIP
-#if HAVE_INSTANT_MESSAGING
void
Manager::sendTextMessageToConference(const Conference& conf,
const std::map<std::string, std::string>& messages,
@@ -1718,7 +1709,6 @@ Manager::sendCallTextMessage(const std::string& callID,
}
}
}
-#endif // HAVE_INSTANT_MESSAGING
//THREAD=VoIP CALL=Outgoing
void
@@ -2825,7 +2815,6 @@ Manager::newOutgoingCall(const std::string& toUrl,
{
auto preferred = getAccount(preferredAccountId);
-#if HAVE_DHT
if (toUrl.find("ring:") != std::string::npos) {
if (preferred && preferred->getAccountType() == RingAccount::ACCOUNT_TYPE)
return preferred->newOutgoingCall(toUrl);
@@ -2834,7 +2823,6 @@ Manager::newOutgoingCall(const std::string& toUrl,
if (acc->isEnabled())
return acc->newOutgoingCall(toUrl);
}
-#endif
// If peer url is an IP, and the preferred account is not an "IP2IP like",
// we try to find a suitable one in all SIPAccount's.
auto strippedToUrl = toUrl;
diff --git a/daemon/src/manager.h b/daemon/src/manager.h
index a3dde6c..8867184 100644
--- a/daemon/src/manager.h
+++ b/daemon/src/manager.h
@@ -377,7 +377,6 @@ class Manager {
*/
void peerHungupCall(Call& call);
-#if HAVE_INSTANT_MESSAGING
/**
* Notify the client with an incoming message
* @param accountId The account identifier
@@ -396,7 +395,6 @@ class Manager {
void sendCallTextMessage(const std::string& callID,
const std::map<std::string, std::string>& messages,
const std::string& from, bool isMixed);
-#endif // HAVE_INSTANT_MESSAGING
/**
* Notify the client he has voice mails
@@ -1041,11 +1039,9 @@ class Manager {
/* Sink ID mapping */
std::map<std::string, std::weak_ptr<video::SinkClient>> sinkMap_;
-#if HAVE_INSTANT_MESSAGING
void sendTextMessageToConference(const Conference& conf,
const std::map<std::string, std::string>& messages,
const std::string& from) const noexcept;
-#endif
#ifdef RING_VIDEO
std::unique_ptr<VideoManager> videoManager_;
diff --git a/daemon/src/media/audio/Makefile.am b/daemon/src/media/audio/Makefile.am
index 0b4a8de..b26233d 100644
--- a/daemon/src/media/audio/Makefile.am
+++ b/daemon/src/media/audio/Makefile.am
@@ -24,6 +24,10 @@ if HAVE_OSX
SUBDIRS += coreaudio
endif
+if HAVE_IOS
+SUBDIRS += coreaudio
+endif
+
if HAVE_PORTAUDIO
SUBDIRS += portaudio
endif
@@ -89,6 +93,10 @@ if HAVE_OSX
libaudio_la_LIBADD += ./coreaudio/libcoreaudiolayer.la
endif
+if HAVE_IOS
+libaudio_la_LIBADD += ./coreaudio/libcoreaudiolayer.la
+endif
+
if BUILD_OPENSL
libaudio_la_LIBADD += ./opensl/libopensl.la
libaudio_la_LDFLAGS += -lOpenSLES
diff --git a/daemon/src/media/audio/coreaudio/Makefile.am b/daemon/src/media/audio/coreaudio/Makefile.am
index 1969b70..be060ee 100644
--- a/daemon/src/media/audio/coreaudio/Makefile.am
+++ b/daemon/src/media/audio/coreaudio/Makefile.am
@@ -4,5 +4,9 @@ if HAVE_OSX
noinst_LTLIBRARIES = libcoreaudiolayer.la
endif
+if HAVE_IOS
+noinst_LTLIBRARIES = libcoreaudiolayer.la
+endif
+
libcoreaudiolayer_la_SOURCES = corelayer.cpp corelayer.h audiodevice.cpp audiodevice.h
libcoreaudiolayer_la_CXXFLAGS = -I$(top_srcdir)/src
diff --git a/daemon/src/media/audio/coreaudio/audiodevice.cpp b/daemon/src/media/audio/coreaudio/audiodevice.cpp
index 2241aca..7389c60 100644
--- a/daemon/src/media/audio/coreaudio/audiodevice.cpp
+++ b/daemon/src/media/audio/coreaudio/audiodevice.cpp
@@ -20,6 +20,8 @@
#include "audiodevice.h"
+#if !TARGET_OS_IPHONE
+
namespace ring {
AudioDevice::AudioDevice(AudioDeviceID devid, bool isInput)
@@ -168,3 +170,5 @@ std::string AudioDevice::getName() const
}
} // namespace ring
+
+#endif // TARGET_OS_IPHONE
diff --git a/daemon/src/media/audio/coreaudio/audiodevice.h b/daemon/src/media/audio/coreaudio/audiodevice.h
index ba24605..f309bbc 100644
--- a/daemon/src/media/audio/coreaudio/audiodevice.h
+++ b/daemon/src/media/audio/coreaudio/audiodevice.h
@@ -21,14 +21,19 @@
#ifndef AUDIO_DEVICE_H
#define AUDIO_DEVICE_H
+#import <TargetConditionals.h>
+
+#if !TARGET_OS_IPHONE
#include <CoreServices/CoreServices.h>
#include <CoreAudio/CoreAudio.h>
+#endif
#include <string>
namespace ring {
class AudioDevice {
+#if !TARGET_OS_IPHONE
public:
AudioDevice() : id_(kAudioDeviceUnknown) { }
AudioDevice(AudioDeviceID devid, bool isInput);
@@ -48,6 +53,7 @@ public:
private:
int countChannels() const;
std::string getName() const;
+#endif
};
}
diff --git a/daemon/src/media/audio/coreaudio/corelayer.cpp b/daemon/src/media/audio/coreaudio/corelayer.cpp
index c07f70f..5912bba 100644
--- a/daemon/src/media/audio/coreaudio/corelayer.cpp
+++ b/daemon/src/media/audio/coreaudio/corelayer.cpp
@@ -57,8 +57,10 @@ std::vector<std::string> CoreLayer::getCaptureDeviceList() const
{
std::vector<std::string> ret;
+#if !TARGET_OS_IPHONE
for (auto x : getDeviceList(true))
ret.push_back(x.name_);
+#endif
return ret;
}
@@ -67,10 +69,10 @@ std::vector<std::string> CoreLayer::getPlaybackDeviceList() const
{
std::vector<std::string> ret;
+#if !TARGET_OS_IPHONE
for (auto x : getDeviceList(false))
- {
ret.push_back(x.name_);
- }
+#endif
return ret;
}
@@ -175,6 +177,7 @@ void CoreLayer::initAudioLayerIO()
// Input buffer setup. Note that ioData is empty and we have to store data
// in another buffer.
+#if !TARGET_OS_IPHONE
UInt32 bufferSizeFrames = 0;
size = sizeof(UInt32);
checkErr(AudioUnitGetProperty(ioUnit_,
@@ -183,6 +186,14 @@ void CoreLayer::initAudioLayerIO()
outputBus,
&bufferSizeFrames,
&size));
+#else
+ Float32 bufferDuration;
+ UInt32 propSize = sizeof(Float32);
+ AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration,
+ &propSize,
+ &bufferDuration);
+ UInt32 bufferSizeFrames = audioInputFormat_.sample_rate * bufferDuration;
+#endif
UInt32 bufferSizeBytes = bufferSizeFrames * sizeof(Float32);
size = offsetof(AudioBufferList, mBuffers[0]) +
@@ -392,6 +403,7 @@ void CoreLayer::updatePreference(AudioPreference &preference, int index, DeviceT
std::vector<AudioDevice> CoreLayer::getDeviceList(bool getCapture) const
{
std::vector<AudioDevice> ret;
+#if !TARGET_OS_IPHONE
UInt32 propsize;
AudioObjectPropertyAddress theAddress = {
@@ -422,7 +434,7 @@ std::vector<AudioDevice> CoreLayer::getDeviceList(bool getCapture) const
}
}
delete[] devids;
-
+#endif
return ret;
}
diff --git a/daemon/src/media/audio/coreaudio/corelayer.h b/daemon/src/media/audio/coreaudio/corelayer.h
index 51afd5a..b0a00b8 100644
--- a/daemon/src/media/audio/coreaudio/corelayer.h
+++ b/daemon/src/media/audio/coreaudio/corelayer.h
@@ -25,7 +25,9 @@
#include "noncopyable.h"
#include <CoreFoundation/CoreFoundation.h>
#include <AudioToolbox/AudioToolbox.h>
+#if !TARGET_OS_IPHONE
#include <CoreAudio/AudioHardware.h>
+#endif
#define checkErr( err) \
if(err) {\
diff --git a/daemon/src/media/video/Makefile.am b/daemon/src/media/video/Makefile.am
index 7e94139..80e8469 100644
--- a/daemon/src/media/video/Makefile.am
+++ b/daemon/src/media/video/Makefile.am
@@ -33,8 +33,7 @@ libvideo_la_SOURCES = \
video_receive_thread.cpp video_receive_thread.h \
video_sender.cpp video_sender.h \
video_rtp_session.cpp video_rtp_session.h \
- sinkclient.cpp sinkclient.h \
- video_provider.h
+ sinkclient.cpp sinkclient.h
libvideo_la_LIBADD = @LIBAVCODEC_LIBS@ @LIBAVFORMAT_LIBS@ @LIBAVDEVICE_LIBS@ @LIBSWSCALE_LIBS@ @LIBAVUTIL_LIBS@
diff --git a/daemon/src/ringdht/Makefile.am b/daemon/src/ringdht/Makefile.am
index 1ee66dc..1b9219f 100644
--- a/daemon/src/ringdht/Makefile.am
+++ b/daemon/src/ringdht/Makefile.am
@@ -1,7 +1,5 @@
include $(top_srcdir)/globals.mak
-if USE_DHT
-
noinst_LTLIBRARIES = libringacc.la
libringacc_la_CXXFLAGS = @CXXFLAGS@
@@ -14,5 +12,3 @@ libringacc_la_SOURCES = \
sip_transport_ice.h \
sips_transport_ice.cpp \
sips_transport_ice.h
-
-endif
diff --git a/daemon/src/ringdht/ringaccount.cpp b/daemon/src/ringdht/ringaccount.cpp
index 43aac58..7c91778 100644
--- a/daemon/src/ringdht/ringaccount.cpp
+++ b/daemon/src/ringdht/ringaccount.cpp
@@ -459,8 +459,14 @@ RingAccount::loadIdentity()
dht::crypto::PrivateKey dht_key;
try {
+#if TARGET_OS_IPHONE
+ const auto path = fileutils::get_data_dir() + DIR_SEPARATOR_STR + getAccountID() + DIR_SEPARATOR_STR;
+ dht_cert = dht::crypto::Certificate(fileutils::loadFile(path + tlsCertificateFile_));
+ dht_key = dht::crypto::PrivateKey(fileutils::loadFile(path + tlsPrivateKeyFile_), tlsPassword_);
+#else
dht_cert = dht::crypto::Certificate(fileutils::loadFile(tlsCertificateFile_));
dht_key = dht::crypto::PrivateKey(fileutils::loadFile(tlsPrivateKeyFile_), tlsPassword_);
+#endif
}
catch (const std::exception& e) {
RING_ERR("Error loading identity: %s", e.what());
@@ -479,8 +485,13 @@ RingAccount::loadIdentity()
// save the chain including CA
saveIdentity(id, idPath_ + DIR_SEPARATOR_STR "dht");
+#if TARGET_OS_IPHONE
+ tlsCertificateFile_ = "dht.crt";
+ tlsPrivateKeyFile_ = "dht.key";
+#else
tlsCertificateFile_ = idPath_ + DIR_SEPARATOR_STR "dht.crt";
tlsPrivateKeyFile_ = idPath_ + DIR_SEPARATOR_STR "dht.key";
+#endif
tlsPassword_ = {};
username_ = RING_URI_PREFIX+id.second->getId().toString();
diff --git a/daemon/src/sip/sdp.cpp b/daemon/src/sip/sdp.cpp
index baf675a..8e5299b 100644
--- a/daemon/src/sip/sdp.cpp
+++ b/daemon/src/sip/sdp.cpp
@@ -41,12 +41,8 @@
#include "system_codec_container.h"
#include "intrin.h" // for UNUSED
-#if HAVE_DHT
#include <opendht/rng.h>
using random_device = dht::crypto::random_device;
-#else
-using random_device = std::random_device;
-#endif
#include <algorithm>
#include <cassert>
diff --git a/daemon/src/sip/sipaccount.cpp b/daemon/src/sip/sipaccount.cpp
index 0fab6b8..85e6ad1 100644
--- a/daemon/src/sip/sipaccount.cpp
+++ b/daemon/src/sip/sipaccount.cpp
@@ -86,7 +86,7 @@ static constexpr int MIN_REGISTRATION_TIME = 60; // seconds
static constexpr unsigned DEFAULT_REGISTRATION_TIME = 3600; // seconds
static constexpr unsigned REGISTRATION_FIRST_RETRY_INTERVAL = 60; // seconds
static constexpr unsigned REGISTRATION_RETRY_INTERVAL = 300; // seconds
-static const char *const VALID_TLS_PROTOS[] = {"Default", "TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3"};
+static const char *const VALID_TLS_PROTOS[] = {"Default", "TLSv1.2", "TLSv1.1", "TLSv1"};
constexpr const char * const SIPAccount::ACCOUNT_TYPE;
@@ -185,10 +185,8 @@ SIPAccount::newOutgoingCall(const std::string& toUrl)
family = ipv6 ? pj_AF_INET6() : pj_AF_INET();
// TODO: resolve remote host using SIPVoIPLink::resolveSrvName
- std::shared_ptr<SipTransport> t =
-#if HAVE_TLS
- isTlsEnabled() ? link_->sipTransportBroker->getTlsTransport(tlsListener_, IpAddr(sip_utils::getHostFromUri(to))) :
-#endif
+ std::shared_ptr<SipTransport> t = isTlsEnabled() ?
+ link_->sipTransportBroker->getTlsTransport(tlsListener_, IpAddr(sip_utils::getHostFromUri(to))) :
transport_;
setTransport(t);
call->setTransport(t);
@@ -655,7 +653,6 @@ SIPAccount::getVolatileAccountDetails() const
a.emplace(Conf::CONFIG_PRESENCE_NOTE, presence_->getNote());
}
-#if HAVE_TLS
if (transport_ and transport_->isSecure() and transport_->isConnected()) {
const auto& tlsInfos = transport_->getTlsInfos();
auto cipher = pj_ssl_cipher_name(tlsInfos.cipher);
@@ -673,7 +670,6 @@ SIPAccount::getVolatileAccountDetails() const
}
a.emplace(DRing::TlsTransport::TLS_PEER_CA_NUM, ring::to_string(n));
}
-#endif
return a;
}
@@ -788,7 +784,6 @@ void SIPAccount::doRegister2_()
ipv6 = hostIp_.isIpv6();
#endif
-#if HAVE_TLS
// Init TLS settings if the user wants to use TLS
if (tlsEnable_) {
RING_DBG("TLS is enabled for account %s", accountID_.c_str());
@@ -810,9 +805,7 @@ void SIPAccount::doRegister2_()
return;
}
}
- } else
-#endif
- {
+ } else {
tlsListener_.reset();
transportType_ = ipv6 ? PJSIP_TRANSPORT_UDP6 : PJSIP_TRANSPORT_UDP;
}
@@ -837,12 +830,9 @@ void SIPAccount::doRegister2_()
try {
RING_WARN("Creating transport");
transport_.reset();
-#if HAVE_TLS
if (isTlsEnabled()) {
setTransport(link_->sipTransportBroker->getTlsTransport(tlsListener_, hostIp_, tlsServerName_.empty() ? hostname_ : tlsServerName_));
- } else
-#endif
- {
+ } else {
setTransport(link_->sipTransportBroker->getUdpTransport(
SipTransportDescr { getTransportType(), getLocalPort(), getLocalInterface() }
));
@@ -1143,7 +1133,6 @@ SIPAccount::sendUnregister()
}
}
-#if HAVE_TLS
pj_uint32_t
SIPAccount::tlsProtocolFromString(const std::string& method)
{
@@ -1155,8 +1144,6 @@ SIPAccount::tlsProtocolFromString(const std::string& method)
return PJ_SSL_SOCK_PROTO_TLS1_2 | PJ_SSL_SOCK_PROTO_TLS1_1;
if (method == "TLSv1")
return PJ_SSL_SOCK_PROTO_TLS1_2 | PJ_SSL_SOCK_PROTO_TLS1_1 | PJ_SSL_SOCK_PROTO_TLS1;
- if (method == "SSLv3")
- return PJ_SSL_SOCK_PROTO_SSL3;
return PJSIP_SSL_DEFAULT_PROTO;
}
@@ -1231,8 +1218,6 @@ void SIPAccount::initTlsConfiguration()
tlsSetting_.qos_ignore_error = PJ_TRUE;
}
-#endif
-
void SIPAccount::initStunConfiguration()
{
size_t pos;
@@ -1260,13 +1245,10 @@ void SIPAccount::loadConfig()
if (registrationExpire_ == 0)
registrationExpire_ = DEFAULT_REGISTRATION_TIME; /** Default expire value for registration */
-#if HAVE_TLS
-
if (tlsEnable_) {
initTlsConfiguration();
transportType_ = PJSIP_TRANSPORT_TLS;
} else
-#endif
transportType_ = PJSIP_TRANSPORT_UDP;
}
diff --git a/daemon/src/sip/sipaccount.h b/daemon/src/sip/sipaccount.h
index 7a63bf4..5ad7e29 100644
--- a/daemon/src/sip/sipaccount.h
+++ b/daemon/src/sip/sipaccount.h
@@ -571,8 +571,6 @@ class SIPAccount : public SIPAccountBase {
*/
pjsip_transport_type_e transportType_ {PJSIP_TRANSPORT_UNSPECIFIED};
-#if HAVE_TLS
-
/**
* Maps a string description of the SSL method
* to the corresponding enum value in pjsip_ssl_method.
@@ -592,8 +590,6 @@ class SIPAccount : public SIPAccountBase {
*/
void trimCiphers();
-#endif
-
/**
* Initializes STUN config from the config file
*/
diff --git a/daemon/src/sip/sipcall.cpp b/daemon/src/sip/sipcall.cpp
index df972e9..4114a7e 100644
--- a/daemon/src/sip/sipcall.cpp
+++ b/daemon/src/sip/sipcall.cpp
@@ -34,15 +34,9 @@
#include "string_utils.h"
#include "upnp/upnp_control.h"
#include "sip_utils.h"
-
#include "audio/audio_rtp_session.h"
-
#include "system_codec_container.h"
-
-#if HAVE_INSTANT_MESSAGING
#include "im/instant_messaging.h"
-#endif
-
#include "dring/call_const.h"
#include "dring/media_const.h"
#include "client/ring_signal.h"
@@ -666,7 +660,6 @@ SIPCall::carryingDTMFdigits(char code)
dtmfSend(*this, code, getSIPAccount().getDtmfType());
}
-#if HAVE_INSTANT_MESSAGING
void
SIPCall::sendTextMessage(const std::map<std::string, std::string>& messages,
const std::string& /* from */)
@@ -680,7 +673,6 @@ SIPCall::sendTextMessage(const std::map<std::string, std::string>& messages,
im::sendSipMessage(inv.get(), messages);
}
-#endif // HAVE_INSTANT_MESSAGING
void
SIPCall::onFailure(signed cause)
diff --git a/daemon/src/sip/sipcall.h b/daemon/src/sip/sipcall.h
index 4c25206..74f35b1 100644
--- a/daemon/src/sip/sipcall.h
+++ b/daemon/src/sip/sipcall.h
@@ -156,10 +156,8 @@ class SIPCall : public Call
void carryingDTMFdigits(char code) override;
-#if HAVE_INSTANT_MESSAGING
void sendTextMessage(const std::map<std::string, std::string>& messages,
const std::string& from) override;
-#endif
SIPAccountBase& getSIPAccount() const;
diff --git a/daemon/src/sip/siptransport.cpp b/daemon/src/sip/siptransport.cpp
index 7119f92..a9f4f28 100644
--- a/daemon/src/sip/siptransport.cpp
+++ b/daemon/src/sip/siptransport.cpp
@@ -32,10 +32,8 @@
#include <pjsip.h>
#include <pjsip/sip_types.h>
-#if HAVE_TLS
#include <pjsip/sip_transport_tls.h>
#include <pj/ssl_sock.h>
-#endif
#include <pjnath.h>
#include <pjnath/stun_config.h>
#include <pjlib.h>
@@ -123,7 +121,6 @@ SipTransport::stateCallback(pjsip_transport_state state,
{
connected_ = state == PJSIP_TP_STATE_CONNECTED;
-#if HAVE_TLS
auto extInfo = static_cast<const pjsip_tls_state_info*>(info->ext_info);
if (isSecure() && extInfo && extInfo->ssl_sock_info && extInfo->ssl_sock_info->established) {
auto tlsInfo = extInfo->ssl_sock_info;
@@ -142,7 +139,6 @@ SipTransport::stateCallback(pjsip_transport_state state,
} else {
tlsInfos_ = {};
}
-#endif
std::vector<SipTransportStateCallback> cbs;
{
@@ -180,11 +176,11 @@ SipTransportBroker::SipTransportBroker(pjsip_endpoint *endpt,
pj_caching_pool& cp, pj_pool_t& pool) :
cp_(cp), pool_(pool), endpt_(endpt)
{
-/*#if HAVE_DHT
+/*
pjsip_transport_register_type(PJSIP_TRANSPORT_DATAGRAM, "ICE",
pjsip_transport_get_default_port_for_type(PJSIP_TRANSPORT_UDP),
&ice_pj_transport_type_);
-#endif*/
+*/
RING_DBG("SipTransportBroker@%p", this);
}
@@ -353,7 +349,6 @@ SipTransportBroker::createUdpTransport(const SipTransportDescr& d)
return ret;
}
-#if HAVE_TLS
std::shared_ptr<TlsListener>
SipTransportBroker::getTlsListener(const SipTransportDescr& d, const pjsip_tls_setting* settings)
{
@@ -423,9 +418,7 @@ SipTransportBroker::getTlsTransport(const std::shared_ptr<TlsListener>& l, const
}
return ret;
}
-#endif
-#if HAVE_DHT
std::shared_ptr<SipTransport>
SipTransportBroker::getIceTransport(const std::shared_ptr<IceTransport> ice,
unsigned comp_id)
@@ -464,6 +457,5 @@ SipTransportBroker::getTlsIceTransport(const std::shared_ptr<ring::IceTransport>
}
return sip_tr;
}
-#endif
} // namespace ring
diff --git a/daemon/src/sip/siptransport.h b/daemon/src/sip/siptransport.h
index 9a636b3..b12a094 100644
--- a/daemon/src/sip/siptransport.h
+++ b/daemon/src/sip/siptransport.h
@@ -169,22 +169,18 @@ public:
std::shared_ptr<SipTransport> getUdpTransport(const SipTransportDescr&);
-#if HAVE_TLS
std::shared_ptr<TlsListener>
getTlsListener(const SipTransportDescr&, const pjsip_tls_setting*);
std::shared_ptr<SipTransport>
getTlsTransport(const std::shared_ptr<TlsListener>&, const IpAddr& remote, const std::string& remote_name = {});
-#endif
-#if HAVE_DHT
std::shared_ptr<SipTransport>
getIceTransport(const std::shared_ptr<IceTransport>, unsigned comp_id);
std::shared_ptr<SipTransport>
getTlsIceTransport(const std::shared_ptr<IceTransport>, unsigned comp_id,
const tls::TlsParams&);
-#endif
std::shared_ptr<SipTransport> addTransport(pjsip_transport*);
@@ -221,9 +217,7 @@ private:
/**
* Storage for SIP/ICE transport instances.
*/
-#if HAVE_DHT
int ice_pj_transport_type_ {PJSIP_TRANSPORT_START_OTHER};
-#endif
pj_caching_pool& cp_;
pj_pool_t& pool_;
diff --git a/daemon/src/sip/sipvoiplink.cpp b/daemon/src/sip/sipvoiplink.cpp
index 0457584..8874521 100644
--- a/daemon/src/sip/sipvoiplink.cpp
+++ b/daemon/src/sip/sipvoiplink.cpp
@@ -32,19 +32,14 @@
#include "sipcall.h"
#include "sipaccount.h"
-#if HAVE_DHT
#include "ringdht/ringaccount.h"
-#endif
#include "manager.h"
#if HAVE_SDES
#include "sdes_negotiator.h"
#endif
-#if HAVE_INSTANT_MESSAGING
#include "im/instant_messaging.h"
-#endif
-
#include "system_codec_container.h"
#include "audio/audio_rtp_session.h"
@@ -637,7 +632,6 @@ SIPVoIPLink::guessAccount(const std::string& userName,
std::shared_ptr<SIPAccountBase> IP2IPAccount;
MatchRank best = MatchRank::NONE;
-#if HAVE_DHT
// DHT accounts
for (const auto& account : Manager::instance().getAllAccounts<RingAccount>()) {
if (!account)
@@ -652,7 +646,6 @@ SIPVoIPLink::guessAccount(const std::string& userName,
result = account;
}
}
-#endif
// SIP accounts
for (const auto& account : Manager::instance().getAllAccounts<SIPAccount>()) {
@@ -1113,7 +1106,6 @@ static void
onRequestMessage(pjsip_inv_session* /*inv*/, pjsip_rx_data* /*rdata*/, pjsip_msg* msg,
SIPCall& call)
{
-#if HAVE_INSTANT_MESSAGING
if (!msg->body)
return;
@@ -1122,8 +1114,6 @@ onRequestMessage(pjsip_inv_session* /*inv*/, pjsip_rx_data* /*rdata*/, pjsip_msg
// in the future
Manager::instance().incomingMessage(call.getCallId(), call.getPeerNumber(),
im::parseSipMessage(msg));
-
-#endif // HAVE_INSTANT_MESSAGING
}
static void
diff --git a/daemon/src/upnp/upnp_context.cpp b/daemon/src/upnp/upnp_context.cpp
index a994dd8..ace784f 100644
--- a/daemon/src/upnp/upnp_context.cpp
+++ b/daemon/src/upnp/upnp_context.cpp
@@ -38,17 +38,17 @@
#include <upnp/upnptools.h>
#endif
+#if HAVE_LIBNATPMP
+#include <natpmp.h>
+#endif
+
#include "logger.h"
#include "ip_utils.h"
#include "upnp_igd.h"
#include "intrin.h"
-#if HAVE_DHT
#include <opendht/rng.h>
using random_device = dht::crypto::random_device;
-#else
-using random_device = std::random_device;
-#endif
namespace ring { namespace upnp {
@@ -65,6 +65,20 @@ getUPnPContext()
return context;
}
+/* UPnP error codes */
+constexpr static int INVALID_ARGS = 402;
+constexpr static int ARRAY_IDX_INVALID = 713;
+constexpr static int CONFLICT_IN_MAPPING = 718;
+
+/* max number of times to retry mapping if it fails due to conflict;
+ * there isn't much logic in picking this number... ideally not many ports should
+ * be mapped in a system, so a few number of random port retries should work;
+ * a high number of retries would indicate there might be some kind of bug or else
+ * incompatibility with the router; we use it to prevent an infinite loop of
+ * retrying to map the entry
+ */
+constexpr static unsigned MAX_RETRIES = 20;
+
#if HAVE_LIBUPNP
/* UPnP IGD definitions */
@@ -75,23 +89,10 @@ constexpr static const char * UPNP_WANCON_DEVICE = "urn:schemas-upnp-org:device:
constexpr static const char * UPNP_WANIP_SERVICE = "urn:schemas-upnp-org:service:WANIPConnection:1";
constexpr static const char * UPNP_WANPPP_SERVICE = "urn:schemas-upnp-org:service:WANPPPConnection:1";
-/* UPnP error codes */
-constexpr static int INVALID_ARGS = 402;
constexpr static const char * INVALID_ARGS_STR = "402";
-constexpr static int ARRAY_IDX_INVALID = 713;
constexpr static const char * ARRAY_IDX_INVALID_STR = "713";
-constexpr static int CONFLICT_IN_MAPPING = 718;
constexpr static const char * CONFLICT_IN_MAPPING_STR = "718";
-/* max number of times to retry mapping if it fails due to conflict;
- * there isn't much logic in picking this number... ideally not many ports should
- * be mapped in a system, so a few number of random port retries should work;
- * a high number of retries would indicate there might be some kind of bug or else
- * incompatibility with the router; we use it to prevent an infinite loop of
- * retrying to map the entry
- */
-constexpr static unsigned MAX_RETRIES = 20;
-
/*
* Local prototypes
*/
@@ -100,18 +101,68 @@ static std::string get_first_doc_item(IXML_Document*, const char*);
static std::string get_first_element_item(IXML_Element*, const char*);
static void checkResponseError(IXML_Document*);
-static int
-cp_callback(Upnp_EventType event_type, void* event, void* user_data)
-{
- if (auto upnpContext = static_cast<UPnPContext*>(user_data))
- return upnpContext->handleUPnPEvents(event_type, event);
+#else
- RING_WARN("UPnP callback without UPnPContext");
- return 0;
-}
+constexpr static int UPNP_E_SUCCESS = 0;
+
+#endif // HAVE_LIBUPNP
UPnPContext::UPnPContext()
{
+#if HAVE_LIBNATPMP
+ pmpThread_ = std::thread([this]() {
+ PMPIGD* pmp_igd = new PMPIGD();
+ natpmp_t natpmp;
+ bool found {false};
+
+ while (pmpRun_) {
+ if (initnatpmp(&natpmp, 0, 0) < 0) {
+ RING_ERR("NAT-PMP: can't initialize libnatpmp");
+ std::unique_lock<std::mutex> lk(pmpMutex_);
+ pmpCv_.wait_for(lk, std::chrono::minutes(1));
+ } else {
+ RING_DBG("NAT-PMP: initialized");
+ break;
+ }
+ }
+
+ while (pmpRun_) {
+ std::unique_lock<std::mutex> lk(pmpMutex_);
+ pmpCv_.wait_until(lk, pmp_igd->getRenewalTime(), [&] {
+ return not pmpRun_ or pmp_igd->getRenewalTime() <= clock::now();
+ });
+ if (not pmpRun_) break;
+
+ auto now = clock::now();
+
+ if (pmp_igd->renewal_ < now) {
+ PMPsearchForIGD(pmp_igd, natpmp, found);
+ }
+ if (found) {
+ if (pmp_igd->clearAll_) {
+ PMPdeleteAllPortMapping(*pmp_igd, natpmp, NATPMP_PROTOCOL_UDP);
+ PMPdeleteAllPortMapping(*pmp_igd, natpmp, NATPMP_PROTOCOL_TCP);
+ pmp_igd->clearAll_ = false;
+ pmp_igd->toRemove_.clear();
+ } else if (not pmp_igd->toRemove_.empty()) {
+ for (auto& m : pmp_igd->toRemove_)
+ PMPaddPortMapping(*pmp_igd, natpmp, m, true);
+ pmp_igd->toRemove_.clear();
+ }
+ auto mapping = pmp_igd->getNextMappingToRenew();
+ if (mapping and mapping->renewal_ < now)
+ PMPaddPortMapping(*pmp_igd, natpmp, *mapping);
+ }
+ }
+ if (not found) delete pmp_igd;
+ closenatpmp(&natpmp);
+ RING_DBG("NAT-PMP: ended");
+ });
+ clientRegistered_ = true;
+#endif
+
+#if HAVE_LIBUPNP
+
int upnp_err;
char* ip_address = nullptr;
unsigned short port = 0;
@@ -159,19 +210,39 @@ UPnPContext::UPnPContext()
* we will probably receive their advertisements either way
*/
searchForIGD();
+#endif
}
UPnPContext::~UPnPContext()
{
/* make sure everything is unregistered, freed, and UpnpFinish() is called */
-
{
std::lock_guard<std::mutex> lock(validIGDMutex_);
for( auto const &it : validIGDs_) {
- removeMappingsByLocalIPAndDescription(it.second.get(), Mapping::UPNP_DEFAULT_MAPPING_DESCRIPTION);
+#if HAVE_LIBUPNP
+ if (auto igd = dynamic_cast<UPnPIGD*>(it.second.get()))
+ removeMappingsByLocalIPAndDescription(*igd, Mapping::UPNP_DEFAULT_MAPPING_DESCRIPTION);
+#endif
+#if HAVE_LIBNATPMP
+ if (auto pmp = dynamic_cast<PMPIGD*>(it.second.get())) {
+ {
+ std::lock_guard<std::mutex> lk(pmpMutex_);
+ pmp->clearAll();
+ }
+ pmpCv_.notify_all();
+ }
+#endif
}
}
+#if HAVE_LIBNATPMP
+ pmpRun_ = false;
+ pmpCv_.notify_all();
+ if (pmpThread_.joinable())
+ pmpThread_.join();
+#endif
+
+#if HAVE_LIBUPNP
if (clientRegistered_)
UpnpUnRegisterClient( ctrlptHandle_ );
@@ -181,21 +252,7 @@ UPnPContext::~UPnPContext()
#ifndef _WIN32
UpnpFinish();
#endif
-}
-
-void
-UPnPContext::searchForIGD()
-{
- if (not clientRegistered_) {
- RING_WARN("UPnP: Control Point not registered");
- return;
- }
-
- /* send out search for both types, as some routers may possibly only reply to one */
- UpnpSearchAsync(ctrlptHandle_, SEARCH_TIMEOUT, UPNP_ROOT_DEVICE, this);
- UpnpSearchAsync(ctrlptHandle_, SEARCH_TIMEOUT, UPNP_IGD_DEVICE, this);
- UpnpSearchAsync(ctrlptHandle_, SEARCH_TIMEOUT, UPNP_WANIP_SERVICE, this);
- UpnpSearchAsync(ctrlptHandle_, SEARCH_TIMEOUT, UPNP_WANPPP_SERVICE, this);
+#endif
}
bool
@@ -243,7 +300,11 @@ UPnPContext::chooseIGD_unlocked() const
{
if (validIGDs_.empty())
return nullptr;
- return validIGDs_.begin()->second.get();
+ auto natpmp = validIGDs_.find("NATPMP");
+ if (natpmp == validIGDs_.end())
+ return validIGDs_.begin()->second.get();
+ else
+ return natpmp->second.get();
}
/**
@@ -288,11 +349,21 @@ UPnPContext::addMapping(IGD* igd,
}
/* mapping doesn't exist, so try to add it */
- RING_DBG("UPnP: adding port mapping : %s", mapping.toString().c_str());
+ RING_DBG("adding port mapping : %s", mapping.toString().c_str());
- if(addPortMapping(igd, mapping, upnp_error)) {
+#if HAVE_LIBUPNP
+ auto upnp = dynamic_cast<const UPnPIGD*>(igd);
+ if (not upnp or addPortMapping(*upnp, mapping, upnp_error))
+#endif
+ {
/* success; add it to global list */
globalMappings->emplace(port_external, std::move(GlobalMapping{mapping}));
+#if HAVE_LIBNATPMP
+#if HAVE_LIBUPNP
+ if (not upnp)
+#endif
+ pmpCv_.notify_all();
+#endif
return mapping;
}
return {};
@@ -308,17 +379,17 @@ generateRandomPort()
/* define the range */
static std::uniform_int_distribution<uint16_t> dist(Mapping::UPNP_PORT_MIN, Mapping::UPNP_PORT_MAX);
- return dist(gen);;
+ return dist(gen);
}
/**
* chooses a random port that is not yet used by the daemon for UPnP
*/
uint16_t
-UPnPContext::chooseRandomPort(const IGD* igd, PortType type)
+UPnPContext::chooseRandomPort(const IGD& igd, PortType type)
{
auto globalMappings = type == PortType::UDP ?
- &igd->udpMappings : &igd->tcpMappings;
+ &igd.udpMappings : &igd.tcpMappings;
uint16_t port = generateRandomPort();
@@ -367,7 +438,7 @@ UPnPContext::addAnyMapping(uint16_t port_desired,
auto iter = globalMappings->find(port_desired);
if (iter != globalMappings->end()) {
/* port already used, we need a unique port */
- port_desired = chooseRandomPort(igd, type);
+ port_desired = chooseRandomPort(*igd, type);
}
}
@@ -392,7 +463,7 @@ UPnPContext::addAnyMapping(uint16_t port_desired,
RING_DBG("UPnP: mapping failed (conflicting entry? err = %d), trying with a different port.",
upnp_error);
/* TODO: make sure we don't try sellecting the same random port twice if it fails ? */
- port_desired = chooseRandomPort(igd, type);
+ port_desired = chooseRandomPort(*igd, type);
if (use_same_port)
port_local = port_desired;
mapping = addMapping(igd, port_desired, port_local, type, &upnp_error);
@@ -427,21 +498,33 @@ UPnPContext::removeMapping(const Mapping& mapping)
auto iter = globalMappings->find(mapping.getPortExternal());
if ( iter != globalMappings->end() ) {
/* make sure its the same mapping */
- GlobalMapping *global_mapping = &iter->second;
- if (mapping == *global_mapping ) {
+ GlobalMapping& global_mapping = iter->second;
+ if (mapping == global_mapping ) {
/* now check the users */
- if (global_mapping->users > 1) {
+ if (global_mapping.users > 1) {
/* more than one user, simply decrement the number */
- --(global_mapping->users);
+ --(global_mapping.users);
RING_DBG("UPnP: decrementing users of mapping: %s, %d users remaining",
- mapping.toString().c_str(), global_mapping->users);
+ mapping.toString().c_str(), global_mapping.users);
} else {
/* no other users, can delete */
RING_DBG("UPnP: removing port mapping : %s",
mapping.toString().c_str());
- deletePortMapping(igd,
- mapping.getPortExternalStr(),
- mapping.getTypeStr());
+#if HAVE_LIBUPNP
+ if (auto upnp = dynamic_cast<UPnPIGD*>(igd))
+ deletePortMapping(*upnp,
+ mapping.getPortExternalStr(),
+ mapping.getTypeStr());
+#endif
+#if HAVE_LIBNATPMP
+ if (auto pmp = dynamic_cast<PMPIGD*>(igd)) {
+ {
+ std::lock_guard<std::mutex> lk(pmpMutex_);
+ pmp->toRemove_.emplace_back(std::move(global_mapping));
+ }
+ pmpCv_.notify_all();
+ }
+#endif
globalMappings->erase(iter);
}
} else {
@@ -482,6 +565,117 @@ UPnPContext::getExternalIP() const
return {};
}
+#if HAVE_LIBNATPMP
+
+void
+UPnPContext::PMPsearchForIGD(PMPIGD* pmp_igd, natpmp_t& natpmp, bool& found)
+{
+ if (sendpublicaddressrequest(&natpmp) < 0) {
+ RING_ERR("NAT-PMP: can't send request");
+ pmp_igd->renewal_ = clock::now() + std::chrono::minutes(1);
+ return;
+ }
+
+ while (pmpRun_) {
+ natpmpresp_t response;
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ auto r = readnatpmpresponseorretry(&natpmp, &response);
+ if (r < 0 && r != NATPMP_TRYAGAIN) {
+ RING_WARN("NAT-PMP: can't find device");
+ pmp_igd->renewal_ = clock::now() + std::chrono::minutes(5);
+ break;
+ }
+ else if (r != NATPMP_TRYAGAIN) {
+ pmp_igd->localIp = ip_utils::getLocalAddr(AF_INET);
+ pmp_igd->publicIp = IpAddr(response.pnu.publicaddress.addr);
+ if (not found) {
+ found = true;
+ RING_DBG("NAT-PMP: found new device");
+ RING_DBG("NAT-PMP: got external IP: %s", pmp_igd->publicIp.toString().c_str());
+ {
+ std::lock_guard<std::mutex> lock(validIGDMutex_);
+ validIGDs_.emplace("NATPMP", std::unique_ptr<IGD>(pmp_igd));
+ validIGDCondVar_.notify_all();
+ for (const auto& l : igdListeners_)
+ l.second();
+ }
+ }
+ pmp_igd->renewal_ = clock::now() + std::chrono::minutes(1);
+ break;
+ }
+ }
+}
+
+void
+UPnPContext::PMPaddPortMapping(const PMPIGD& /*pmp_igd*/, natpmp_t& natpmp, GlobalMapping& mapping, bool remove) const
+{
+ if (sendnewportmappingrequest(&natpmp,
+ mapping.getType() == PortType::UDP ? NATPMP_PROTOCOL_UDP : NATPMP_PROTOCOL_TCP,
+ mapping.getPortInternal(),
+ mapping.getPortExternal(), remove ? 0 : 3600) < 0) {
+ RING_ERR("NAT-PMP: can't send port mapping request");
+ mapping.renewal_ = clock::now() + std::chrono::minutes(1);
+ return;
+ }
+ RING_DBG("NAT-PMP: sent port mapping %srequest", remove ? "removal " : "");
+ while (pmpRun_) {
+ natpmpresp_t response;
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ auto r = readnatpmpresponseorretry(&natpmp, &response);
+ if (r < 0 && r != NATPMP_TRYAGAIN) {
+ RING_ERR("NAT-PMP: can't %sregister port mapping", remove ? "un" : "");
+ break;
+ }
+ else if (r != NATPMP_TRYAGAIN) {
+ mapping.renewal_ = clock::now()
+ + std::chrono::seconds(response.pnu.newportmapping.lifetime/2);
+ break;
+ }
+ }
+}
+
+void
+UPnPContext::PMPdeleteAllPortMapping(const PMPIGD& /*pmp_igd*/, natpmp_t& natpmp, int proto) const
+{
+ if (sendnewportmappingrequest(&natpmp, proto, 0, 0, 0) < 0) {
+ RING_ERR("NAT-PMP: can't send all port mapping removal request");
+ return;
+ }
+ RING_DBG("NAT-PMP: sent all port mapping removal request");
+ while (pmpRun_) {
+ natpmpresp_t response;
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ auto r = readnatpmpresponseorretry(&natpmp, &response);
+ if (r < 0 && r != NATPMP_TRYAGAIN) {
+ RING_ERR("NAT-PMP: can't remove all port mappings");
+ break;
+ }
+ else if (r != NATPMP_TRYAGAIN) {
+ break;
+ }
+ }
+}
+
+#endif /* HAVE_LIBNATPMP */
+
+
+#if HAVE_LIBUPNP
+
+void
+UPnPContext::searchForIGD()
+{
+ if (not clientRegistered_) {
+ RING_WARN("UPnP: Control Point not registered");
+ return;
+ }
+
+ /* send out search for both types, as some routers may possibly only reply to one */
+ UpnpSearchAsync(ctrlptHandle_, SEARCH_TIMEOUT, UPNP_ROOT_DEVICE, this);
+ UpnpSearchAsync(ctrlptHandle_, SEARCH_TIMEOUT, UPNP_IGD_DEVICE, this);
+ UpnpSearchAsync(ctrlptHandle_, SEARCH_TIMEOUT, UPNP_WANIP_SERVICE, this);
+ UpnpSearchAsync(ctrlptHandle_, SEARCH_TIMEOUT, UPNP_WANPPP_SERVICE, this);
+}
+
/**
* Parses the device description and adds desired devices to
* relevant lists
@@ -532,7 +726,7 @@ UPnPContext::parseIGD(IXML_Document* doc, const Upnp_Discovery* d_event)
}
}
- std::unique_ptr<IGD> new_igd;
+ std::unique_ptr<UPnPIGD> new_igd;
int upnp_err;
std::string friendlyName = get_first_doc_item(doc, "friendlyName");
@@ -620,9 +814,9 @@ UPnPContext::parseIGD(IXML_Document* doc, const Upnp_Discovery* d_event)
if (not (serviceId.empty() and controlURL.empty() and eventSubURL.empty()) ) {
/* RING_DBG("UPnP: got service info from device:\n\tserviceType: %s\n\tserviceID: %s\n\tcontrolURL: %s\n\teventSubURL: %s",
serviceType.c_str(), serviceId.c_str(), controlURL.c_str(), eventSubURL.c_str()); */
- new_igd.reset(new IGD(UDN, baseURL, friendlyName, serviceType, serviceId, controlURL, eventSubURL));
- if (isIGDConnected(new_igd.get())) {
- new_igd->publicIp = getExternalIP(new_igd.get());
+ new_igd.reset(new UPnPIGD(UDN, baseURL, friendlyName, serviceType, serviceId, controlURL, eventSubURL));
+ if (isIGDConnected(*new_igd)) {
+ new_igd->publicIp = getExternalIP(*new_igd);
if (new_igd->publicIp) {
RING_DBG("UPnP: got external IP: %s", new_igd->publicIp.toString().c_str());
new_igd->localIp = ip_utils::getLocalAddr(pj_AF_INET());
@@ -650,7 +844,7 @@ UPnPContext::parseIGD(IXML_Document* doc, const Upnp_Discovery* d_event)
{
std::lock_guard<std::mutex> lock(validIGDMutex_);
/* delete all RING mappings first */
- removeMappingsByLocalIPAndDescription(new_igd.get(), Mapping::UPNP_DEFAULT_MAPPING_DESCRIPTION);
+ removeMappingsByLocalIPAndDescription(*new_igd, Mapping::UPNP_DEFAULT_MAPPING_DESCRIPTION);
validIGDs_.emplace(UDN, std::move(new_igd));
validIGDCondVar_.notify_all();
for (const auto& l : igdListeners_)
@@ -701,6 +895,17 @@ get_first_element_item(IXML_Element* element, const char* item)
}
return ret;
}
+
+int
+UPnPContext::cp_callback(Upnp_EventType event_type, void* event, void* user_data)
+{
+ if (auto upnpContext = static_cast<UPnPContext*>(user_data))
+ return upnpContext->handleUPnPEvents(event_type, event);
+
+ RING_WARN("UPnP callback without UPnPContext");
+ return 0;
+}
+
int
UPnPContext::handleUPnPEvents(Upnp_EventType event_type, void* event)
{
@@ -870,22 +1075,22 @@ checkResponseError(IXML_Document* doc)
}
bool
-UPnPContext::isIGDConnected(const IGD* igd)
+UPnPContext::isIGDConnected(const UPnPIGD& igd)
{
bool connected = false;
std::unique_ptr<IXML_Document, decltype(ixmlDocument_free)&> action(nullptr, ixmlDocument_free);
- action.reset(UpnpMakeAction("GetStatusInfo", igd->getServiceType().c_str(), 0, nullptr));
+ action.reset(UpnpMakeAction("GetStatusInfo", igd.getServiceType().c_str(), 0, nullptr));
std::unique_ptr<IXML_Document, decltype(ixmlDocument_free)&> response(nullptr, ixmlDocument_free);
IXML_Document* response_ptr = nullptr;
- int upnp_err = UpnpSendAction(ctrlptHandle_, igd->getControlURL().c_str(),
- igd->getServiceType().c_str(), nullptr, action.get(), &response_ptr);
+ int upnp_err = UpnpSendAction(ctrlptHandle_, igd.getControlURL().c_str(),
+ igd.getServiceType().c_str(), nullptr, action.get(), &response_ptr);
response.reset(response_ptr);
checkResponseError(response.get());
if( upnp_err != UPNP_E_SUCCESS) {
/* TODO: if failed, should we chck if the igd is disconnected? */
RING_WARN("UPnP: Failed to get GetStatusInfo from: %s, %d: %s",
- igd->getServiceType().c_str(), upnp_err, UpnpGetErrorMessage(upnp_err));
+ igd.getServiceType().c_str(), upnp_err, UpnpGetErrorMessage(upnp_err));
return false;
}
@@ -903,21 +1108,21 @@ UPnPContext::isIGDConnected(const IGD* igd)
}
IpAddr
-UPnPContext::getExternalIP(const IGD* igd)
+UPnPContext::getExternalIP(const UPnPIGD& igd)
{
std::unique_ptr<IXML_Document, decltype(ixmlDocument_free)&> action(nullptr, ixmlDocument_free);
- action.reset(UpnpMakeAction("GetExternalIPAddress", igd->getServiceType().c_str(), 0, nullptr));
+ action.reset(UpnpMakeAction("GetExternalIPAddress", igd.getServiceType().c_str(), 0, nullptr));
std::unique_ptr<IXML_Document, decltype(ixmlDocument_free)&> response(nullptr, ixmlDocument_free);
IXML_Document* response_ptr = nullptr;
- int upnp_err = UpnpSendAction(ctrlptHandle_, igd->getControlURL().c_str(),
- igd->getServiceType().c_str(), nullptr, action.get(), &response_ptr);
+ int upnp_err = UpnpSendAction(ctrlptHandle_, igd.getControlURL().c_str(),
+ igd.getServiceType().c_str(), nullptr, action.get(), &response_ptr);
response.reset(response_ptr);
checkResponseError(response.get());
if( upnp_err != UPNP_E_SUCCESS) {
/* TODO: if failed, should we chck if the igd is disconnected? */
RING_WARN("UPnP: Failed to get GetExternalIPAddress from: %s, %d: %s",
- igd->getServiceType().c_str(), upnp_err, UpnpGetErrorMessage(upnp_err));
+ igd.getServiceType().c_str(), upnp_err, UpnpGetErrorMessage(upnp_err));
return {};
}
@@ -926,15 +1131,15 @@ UPnPContext::getExternalIP(const IGD* igd)
}
void
-UPnPContext::removeMappingsByLocalIPAndDescription(const IGD* igd, const std::string& description)
+UPnPContext::removeMappingsByLocalIPAndDescription(const UPnPIGD& igd, const std::string& description)
{
- if (!igd->localIp) {
+ if (!igd.localIp) {
RING_DBG("UPnP: cannot determine local IP in function removeMappingsByLocalIPAndDescription()");
return;
}
RING_DBG("UPnP: removing all port mappings with description: \"%s\" and local ip: %s",
- description.c_str(), igd->localIp.toString().c_str());
+ description.c_str(), igd.localIp.toString().c_str());
int entry_idx = 0;
bool done = false;
@@ -942,19 +1147,19 @@ UPnPContext::removeMappingsByLocalIPAndDescription(const IGD* igd, const std::st
do {
std::unique_ptr<IXML_Document, decltype(ixmlDocument_free)&> action(nullptr, ixmlDocument_free);
IXML_Document* action_ptr = nullptr;
- UpnpAddToAction(&action_ptr, "GetGenericPortMappingEntry", igd->getServiceType().c_str(),
+ UpnpAddToAction(&action_ptr, "GetGenericPortMappingEntry", igd.getServiceType().c_str(),
"NewPortMappingIndex", ring::to_string(entry_idx).c_str());
action.reset(action_ptr);
std::unique_ptr<IXML_Document, decltype(ixmlDocument_free)&> response(nullptr, ixmlDocument_free);
IXML_Document* response_ptr = nullptr;
- int upnp_err = UpnpSendAction(ctrlptHandle_, igd->getControlURL().c_str(),
- igd->getServiceType().c_str(), nullptr, action.get(), &response_ptr);
+ int upnp_err = UpnpSendAction(ctrlptHandle_, igd.getControlURL().c_str(),
+ igd.getServiceType().c_str(), nullptr, action.get(), &response_ptr);
response.reset(response_ptr);
if( not response and upnp_err != UPNP_E_SUCCESS) {
/* TODO: if failed, should we chck if the igd is disconnected? */
RING_WARN("UPnP: Failed to get GetGenericPortMappingEntry from: %s, %d: %s",
- igd->getServiceType().c_str(), upnp_err, UpnpGetErrorMessage(upnp_err));
+ igd.getServiceType().c_str(), upnp_err, UpnpGetErrorMessage(upnp_err));
return;
}
@@ -967,7 +1172,7 @@ UPnPContext::removeMappingsByLocalIPAndDescription(const IGD* igd, const std::st
std::string client_ip = get_first_doc_item(response.get(), "NewInternalClient");
/* check if same IP and description */
- if (IpAddr(client_ip) == igd->localIp and desc_actual.compare(description) == 0) {
+ if (IpAddr(client_ip) == igd.localIp and desc_actual.compare(description) == 0) {
/* get the rest of the needed parameters */
std::string port_internal = get_first_doc_item(response.get(), "NewInternalPort");
std::string port_external = get_first_doc_item(response.get(), "NewExternalPort");
@@ -1000,28 +1205,28 @@ UPnPContext::removeMappingsByLocalIPAndDescription(const IGD* igd, const std::st
}
bool
-UPnPContext::deletePortMapping(const IGD* igd, const std::string& port_external, const std::string& protocol)
+UPnPContext::deletePortMapping(const UPnPIGD& igd, const std::string& port_external, const std::string& protocol)
{
std::string action_name{"DeletePortMapping"};
std::unique_ptr<IXML_Document, decltype(ixmlDocument_free)&> action(nullptr, ixmlDocument_free);
IXML_Document* action_ptr = nullptr;
- UpnpAddToAction(&action_ptr, action_name.c_str(), igd->getServiceType().c_str(),
+ UpnpAddToAction(&action_ptr, action_name.c_str(), igd.getServiceType().c_str(),
"NewRemoteHost", "");
- UpnpAddToAction(&action_ptr, action_name.c_str(), igd->getServiceType().c_str(),
+ UpnpAddToAction(&action_ptr, action_name.c_str(), igd.getServiceType().c_str(),
"NewExternalPort", port_external.c_str());
- UpnpAddToAction(&action_ptr, action_name.c_str(), igd->getServiceType().c_str(),
+ UpnpAddToAction(&action_ptr, action_name.c_str(), igd.getServiceType().c_str(),
"NewProtocol", protocol.c_str());
action.reset(action_ptr);
std::unique_ptr<IXML_Document, decltype(ixmlDocument_free)&> response(nullptr, ixmlDocument_free);
IXML_Document* response_ptr = nullptr;
- int upnp_err = UpnpSendAction(ctrlptHandle_, igd->getControlURL().c_str(),
- igd->getServiceType().c_str(), nullptr, action.get(), &response_ptr);
+ int upnp_err = UpnpSendAction(ctrlptHandle_, igd.getControlURL().c_str(),
+ igd.getServiceType().c_str(), nullptr, action.get(), &response_ptr);
response.reset(response_ptr);
if( upnp_err != UPNP_E_SUCCESS) {
/* TODO: if failed, should we check if the igd is disconnected? */
RING_WARN("UPnP: Failed to get %s from: %s, %d: %s", action_name.c_str(),
- igd->getServiceType().c_str(), upnp_err, UpnpGetErrorMessage(upnp_err));
+ igd.getServiceType().c_str(), upnp_err, UpnpGetErrorMessage(upnp_err));
return false;
}
/* check if there is an error code */
@@ -1036,41 +1241,41 @@ UPnPContext::deletePortMapping(const IGD* igd, const std::string& port_external,
}
bool
-UPnPContext::addPortMapping(const IGD* igd, const Mapping& mapping, int* error_code)
+UPnPContext::addPortMapping(const UPnPIGD& igd, const Mapping& mapping, int* error_code)
{
*error_code = UPNP_E_SUCCESS;
std::string action_name{"AddPortMapping"};
std::unique_ptr<IXML_Document, decltype(ixmlDocument_free)&> action(nullptr, ixmlDocument_free);
IXML_Document* action_ptr = nullptr;
- UpnpAddToAction(&action_ptr, action_name.c_str(), igd->getServiceType().c_str(),
+ UpnpAddToAction(&action_ptr, action_name.c_str(), igd.getServiceType().c_str(),
"NewRemoteHost", "");
- UpnpAddToAction(&action_ptr, action_name.c_str(), igd->getServiceType().c_str(),
+ UpnpAddToAction(&action_ptr, action_name.c_str(), igd.getServiceType().c_str(),
"NewExternalPort", mapping.getPortExternalStr().c_str());
- UpnpAddToAction(&action_ptr, action_name.c_str(), igd->getServiceType().c_str(),
+ UpnpAddToAction(&action_ptr, action_name.c_str(), igd.getServiceType().c_str(),
"NewProtocol", mapping.getTypeStr().c_str());
- UpnpAddToAction(&action_ptr, action_name.c_str(), igd->getServiceType().c_str(),
+ UpnpAddToAction(&action_ptr, action_name.c_str(), igd.getServiceType().c_str(),
"NewInternalPort", mapping.getPortInternalStr().c_str());
- UpnpAddToAction(&action_ptr, action_name.c_str(), igd->getServiceType().c_str(),
- "NewInternalClient", igd->localIp.toString().c_str());
- UpnpAddToAction(&action_ptr, action_name.c_str(), igd->getServiceType().c_str(),
+ UpnpAddToAction(&action_ptr, action_name.c_str(), igd.getServiceType().c_str(),
+ "NewInternalClient", igd.localIp.toString().c_str());
+ UpnpAddToAction(&action_ptr, action_name.c_str(), igd.getServiceType().c_str(),
"NewEnabled", "1");
- UpnpAddToAction(&action_ptr, action_name.c_str(), igd->getServiceType().c_str(),
+ UpnpAddToAction(&action_ptr, action_name.c_str(), igd.getServiceType().c_str(),
"NewPortMappingDescription", mapping.getDescription().c_str());
/* for now assume lease duration is always infinite */
- UpnpAddToAction(&action_ptr, action_name.c_str(), igd->getServiceType().c_str(),
+ UpnpAddToAction(&action_ptr, action_name.c_str(), igd.getServiceType().c_str(),
"NewLeaseDuration", "0");
action.reset(action_ptr);
std::unique_ptr<IXML_Document, decltype(ixmlDocument_free)&> response(nullptr, ixmlDocument_free);
IXML_Document* response_ptr = nullptr;
- int upnp_err = UpnpSendAction(ctrlptHandle_, igd->getControlURL().c_str(),
- igd->getServiceType().c_str(), nullptr, action.get(), &response_ptr);
+ int upnp_err = UpnpSendAction(ctrlptHandle_, igd.getControlURL().c_str(),
+ igd.getServiceType().c_str(), nullptr, action.get(), &response_ptr);
response.reset(response_ptr);
if( not response and upnp_err != UPNP_E_SUCCESS) {
/* TODO: if failed, should we chck if the igd is disconnected? */
RING_WARN("UPnP: Failed to %s from: %s, %d: %s", action_name.c_str(),
- igd->getServiceType().c_str(), upnp_err, UpnpGetErrorMessage(upnp_err));
+ igd.getServiceType().c_str(), upnp_err, UpnpGetErrorMessage(upnp_err));
*error_code = -1; /* make sure to -1 since we didn't get a response */
return false;
}
diff --git a/daemon/src/upnp/upnp_context.h b/daemon/src/upnp/upnp_context.h
index 72d06b7..3ad8285 100644
--- a/daemon/src/upnp/upnp_context.h
+++ b/daemon/src/upnp/upnp_context.h
@@ -18,8 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef UPNP_CONTEXT_H_
-#define UPNP_CONTEXT_H_
+#pragma once
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -32,6 +31,7 @@
#include <condition_variable>
#include <chrono>
#include <atomic>
+#include <thread>
#if HAVE_LIBUPNP
#ifdef _WIN32
@@ -43,6 +43,10 @@
#include <upnp/upnptools.h>
#endif
+#if HAVE_LIBNATPMP
+#include <natpmp.h>
+#endif
+
#include "noncopyable.h"
#include "upnp_igd.h"
@@ -56,7 +60,6 @@ class UPnPContext {
public:
constexpr static unsigned SEARCH_TIMEOUT {30};
-#if HAVE_LIBUPNP
UPnPContext();
~UPnPContext();
@@ -104,20 +107,62 @@ public:
*/
IpAddr getLocalIP() const;
+private:
+ NON_COPYABLE(UPnPContext);
+
+ std::atomic_bool clientRegistered_ {false};
+
/**
- * callback function for the UPnP client (control point)
- * all UPnP events received by the client are processed here
+ * map of valid IGDs - IGDs which have the correct services and are connected
+ * to some external network (have an external IP)
+ *
+ * the UDN string is used to uniquely identify the IGD
+ *
+ * the mutex is used to access these lists and IGDs in a thread-safe manner
*/
- int handleUPnPEvents(Upnp_EventType event_type, void* event);
+ std::map<std::string, std::unique_ptr<IGD>> validIGDs_;
+ mutable std::mutex validIGDMutex_;
+ std::condition_variable validIGDCondVar_;
-#else
- /* use default constructor and destructor */
- UPnPContext() = default;
- ~UPnPContext() = default;
-#endif
+ /**
+ * Map of valid IGD listeners.
+ */
+ std::map<size_t, IGDFoundCallback> igdListeners_;
+
+ /**
+ * Last provided token for valid IGD listeners.
+ * 0 is the invalid token.
+ */
+ size_t listenerToken_ {0};
+
+ /**
+ * chooses the IGD to use (currently selects the first one in the map)
+ * assumes you already have a lock on igd_mutex_
+ */
+ IGD* chooseIGD_unlocked() const;
-private:
- NON_COPYABLE(UPnPContext);
+
+ /* tries to add mapping, assumes you alreayd have lock on igd_mutex_ */
+ Mapping addMapping(IGD* igd,
+ uint16_t port_external,
+ uint16_t port_internal,
+ PortType type,
+ int *upnp_error);
+
+ uint16_t chooseRandomPort(const IGD& igd, PortType type);
+
+#if HAVE_LIBNATPMP
+
+ std::thread pmpThread_;
+ std::mutex pmpMutex_;
+ std::condition_variable pmpCv_;
+ std::atomic_bool pmpRun_ {true};
+
+ void PMPsearchForIGD(PMPIGD* pmp_igd, natpmp_t& natpmp, bool& found);
+ void PMPaddPortMapping(const PMPIGD& pmp_igd, natpmp_t& natpmp, GlobalMapping& mapping, bool remove=false) const;
+ void PMPdeleteAllPortMapping(const PMPIGD& pmp_igd, natpmp_t& natpmp, int proto) const;
+
+#endif
#if HAVE_LIBUPNP
@@ -150,40 +195,18 @@ private:
UpnpDevice_Handle deviceHandle_ {-1};
/**
- * keep track if we've successfully registered
- * a client and/ore device
+ * keep track if we've successfully registered a device
*/
- std::atomic_bool clientRegistered_ {false};
bool deviceRegistered_ {false};
- /**
- * map of valid IGDs - IGDs which have the correct services and are connected
- * to some external network (have an external IP)
- *
- * the UDN string is used to uniquely identify the IGD
- *
- * the mutex is used to access these lists and IGDs in a thread-safe manner
- */
- std::map<std::string, std::unique_ptr<IGD>> validIGDs_;
- mutable std::mutex validIGDMutex_;
- std::condition_variable validIGDCondVar_;
-
- /**
- * Map of valid IGD listeners.
- */
- std::map<size_t, IGDFoundCallback> igdListeners_;
+ static int cp_callback(Upnp_EventType event_type, void* event, void* user_data);
/**
- * Last provided token for valid IGD listeners.
- * 0 is the invalid token.
+ * callback function for the UPnP client (control point)
+ * all UPnP events received by the client are processed here
*/
- size_t listenerToken_ {0};
+ int handleUPnPEvents(Upnp_EventType event_type, void* event);
- /**
- * chooses the IGD to use (currently selects the first one in the map)
- * assumes you already have a lock on igd_mutex_
- */
- IGD* chooseIGD_unlocked() const;
/* sends out async search for IGD */
void searchForIGD();
@@ -196,33 +219,24 @@ private:
void parseIGD(IXML_Document* doc, const Upnp_Discovery* d_event);
- /* tries to add mapping, assumes you alreayd have lock on igd_mutex_ */
- Mapping addMapping(IGD* igd,
- uint16_t port_external,
- uint16_t port_internal,
- PortType type,
- int *upnp_error);
-
- uint16_t chooseRandomPort(const IGD* igd, PortType type);
/* these functions directly create UPnP actions
* and make synchronous UPnP control point calls
* they assume you have a lock on the igd_mutex_ */
- bool isIGDConnected(const IGD* igd);
+ bool isIGDConnected(const UPnPIGD& igd);
- IpAddr getExternalIP(const IGD* igd);
+ IpAddr getExternalIP(const UPnPIGD& igd);
- void removeMappingsByLocalIPAndDescription(const IGD* igd,
+ void removeMappingsByLocalIPAndDescription(const UPnPIGD& igd,
const std::string& description);
- bool deletePortMapping(const IGD* igd,
+ bool deletePortMapping(const UPnPIGD& igd,
const std::string& port_external,
const std::string& protocol);
- bool addPortMapping(const IGD* igd,
+ bool addPortMapping(const UPnPIGD& igd,
const Mapping& mapping,
int* error_code);
-
#endif /* HAVE_LIBUPNP */
};
@@ -236,5 +250,3 @@ private:
std::shared_ptr<UPnPContext> getUPnPContext();
}} // namespace ring::upnp
-
-#endif /* UPNP_CONTEXT_H_ */
diff --git a/daemon/src/upnp/upnp_control.cpp b/daemon/src/upnp/upnp_control.cpp
index 4e3be9d..d6b06f3 100644
--- a/daemon/src/upnp/upnp_control.cpp
+++ b/daemon/src/upnp/upnp_control.cpp
@@ -46,19 +46,14 @@ Controller::~Controller()
{
/* remove all mappings */
removeMappings();
-#if HAVE_LIBUPNP
if (listToken_ and upnpContext_)
upnpContext_->removeIGDListener(listToken_);
-#endif
}
bool
Controller::hasValidIGD(std::chrono::seconds timeout)
{
-#if HAVE_LIBUPNP
return upnpContext_ and upnpContext_->hasValidIGD(timeout);
-#endif
- return false;
}
void
@@ -66,11 +61,9 @@ Controller::setIGDListener(IGDFoundCallback&& cb)
{
if (not upnpContext_)
return;
-#if HAVE_LIBUPNP
if (listToken_)
upnpContext_->removeIGDListener(listToken_);
listToken_ = cb ? upnpContext_->addIGDListener(std::move(cb)) : 0;
-#endif
}
bool
@@ -81,7 +74,6 @@ Controller::addAnyMapping(uint16_t port_desired,
bool unique,
uint16_t *port_used)
{
-#if HAVE_LIBUPNP
if (not upnpContext_)
return false;
@@ -97,7 +89,6 @@ Controller::addAnyMapping(uint16_t port_desired,
instanceMappings.emplace(usedPort, std::move(mapping));
return true;
}
-#endif
return false;
}
@@ -113,7 +104,6 @@ Controller::addAnyMapping(uint16_t port_desired,
void
Controller::removeMappings(PortType type) {
-#if HAVE_LIBUPNP
if (not upnpContext_)
return;
@@ -123,34 +113,28 @@ Controller::removeMappings(PortType type) {
upnpContext_->removeMapping(mapping);
iter = instanceMappings.erase(iter);
}
-#endif
}
+
void
Controller::removeMappings()
{
-#if HAVE_LIBUPNP
removeMappings(PortType::UDP);
removeMappings(PortType::TCP);
-#endif
}
IpAddr
Controller::getLocalIP() const
{
-#if HAVE_LIBUPNP
if (upnpContext_)
return upnpContext_->getLocalIP();
-#endif
return {}; // empty address
}
IpAddr
Controller::getExternalIP() const
{
-#if HAVE_LIBUPNP
if (upnpContext_)
return upnpContext_->getExternalIP();
-#endif
return {}; // empty address
}
diff --git a/daemon/src/upnp/upnp_igd.h b/daemon/src/upnp/upnp_igd.h
index 3fdce01..6a65de3 100644
--- a/daemon/src/upnp/upnp_igd.h
+++ b/daemon/src/upnp/upnp_igd.h
@@ -18,12 +18,16 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef UPNP_IGD_H_
-#define UPNP_IGD_H_
+#pragma once
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
#include <string>
#include <map>
#include <functional>
+#include <chrono>
#include "noncopyable.h"
#include "ip_utils.h"
@@ -63,13 +67,13 @@ public:
friend bool operator== (const Mapping& cRedir1, const Mapping& cRedir2);
friend bool operator!= (const Mapping& cRedir1, const Mapping& cRedir2);
- uint16_t getPortExternal() const { return port_external_; };
- std::string getPortExternalStr() const { return ring::to_string(port_external_); };
- uint16_t getPortInternal() const { return port_internal_; };
- std::string getPortInternalStr() const { return ring::to_string(port_internal_); };
- PortType getType() const { return type_; };
+ uint16_t getPortExternal() const { return port_external_; }
+ std::string getPortExternalStr() const { return ring::to_string(port_external_); }
+ uint16_t getPortInternal() const { return port_internal_; }
+ std::string getPortInternalStr() const { return ring::to_string(port_internal_); }
+ PortType getType() const { return type_; }
std::string getTypeStr() const { return type_ == PortType::UDP ? "UDP" : "TCP"; }
- std::string getDescription() const { return description_; };
+ std::string getDescription() const { return description_; }
std::string toString() const {
return getPortExternalStr() + ":" + getPortInternalStr() + ", " + getTypeStr();
@@ -83,6 +87,11 @@ public:
return isValid();
}
+#if HAVE_LIBNATPMP
+ std::chrono::system_clock::time_point renewal_ {std::chrono::system_clock::time_point::min()};
+ bool remove {false};
+#endif
+
private:
NON_COPYABLE(Mapping);
@@ -123,7 +132,6 @@ using IGDFoundCallback = std::function<void()>;
/* defines a UPnP capable Internet Gateway Device (a router) */
class IGD {
public:
-
/* device address seen by IGD */
IpAddr localIp;
@@ -136,7 +144,22 @@ public:
/* constructors */
IGD() {}
- IGD(std::string UDN,
+
+ /* move constructor and operator */
+ IGD(IGD&&) = default;
+ IGD& operator=(IGD&&) = default;
+
+ virtual ~IGD() = default;
+
+private:
+ NON_COPYABLE(IGD);
+};
+
+#if HAVE_LIBUPNP
+
+class UPnPIGD : public IGD {
+public:
+ UPnPIGD(std::string UDN,
std::string baseURL,
std::string friendlyName,
std::string serviceType,
@@ -152,12 +175,6 @@ public:
, eventSubURL_(eventSubURL)
{}
- /* move constructor and operator */
- IGD(IGD&&) = default;
- IGD& operator=(IGD&&) = default;
-
- ~IGD() = default;
-
const std::string& getUDN() const { return UDN_; };
const std::string& getBaseURL() const { return baseURL_; };
const std::string& getFriendlyName() const { return friendlyName_; };
@@ -167,8 +184,6 @@ public:
const std::string& getEventSubURL() const { return eventSubURL_; };
private:
- NON_COPYABLE(IGD);
-
/* root device info */
std::string UDN_ {}; /* used to uniquely identify this UPnP device */
std::string baseURL_ {};
@@ -179,9 +194,47 @@ private:
std::string serviceId_ {};
std::string controlURL_ {};
std::string eventSubURL_ {};
+};
+
+#endif
+
+#if HAVE_LIBNATPMP
+
+using clock = std::chrono::system_clock;
+using time_point = clock::time_point;
+
+class PMPIGD : public IGD {
+public:
+
+ void clearAll() {
+ toRemove_.clear();
+ udpMappings.clear();
+ tcpMappings.clear();
+ clearAll_ = true;
+ }
+
+ GlobalMapping* getNextMappingToRenew() const {
+ const GlobalMapping* mapping {nullptr};
+ for (const auto& m : udpMappings)
+ if (!mapping or m.second.renewal_ < mapping->renewal_)
+ mapping = &m.second;
+ for (const auto& m : tcpMappings)
+ if (!mapping or m.second.renewal_ < mapping->renewal_)
+ mapping = &m.second;
+ return (GlobalMapping*)mapping;
+ }
+ time_point getRenewalTime() const {
+ const auto next = getNextMappingToRenew();
+ auto nextTime = std::min(renewal_, next ? next->renewal_ : time_point::max());
+ return toRemove_.empty() ? nextTime : std::min(nextTime, time_point::min());
+ }
+
+ time_point renewal_ {time_point::min()};
+ std::vector<GlobalMapping> toRemove_ {};
+ bool clearAll_ {false};
};
-}} // namespace ring::upnp
+#endif
-#endif /* UPNP_IGD_H_ */
+}} // namespace ring::upnp
diff --git a/docs/source/dev/releasing.rst b/docs/source/dev/releasing.rst
index 17bc36f..defcc5d 100644
--- a/docs/source/dev/releasing.rst
+++ b/docs/source/dev/releasing.rst
@@ -8,7 +8,7 @@ Release tarball
Ring is released in the form of a tarball. They are hosted here:
- - https://gpl.savoirfairelinux.net/ring-download/ring-release/tarballs/
+ - https://dl.ring.cx/ring-release/tarballs/
Tarballs are generated from the integration branch of the `ring-project <https://github.com/savoirfairelinux/ring-project>`_ repository with a job on our `Jenkins server <https://test.savoirfairelinux.com/>`_. They include a copy of all contrib libraries configured in ``daemon/contrib/src``. If you are a Savoir-faire Linux employee, you may trigger the job from `this page <https://test.savoirfairelinux.com/job/ring-release/>`_.
diff --git a/lrc/src/macromodel.cpp b/lrc/src/macromodel.cpp
index e52fc7d..566aec4 100644
--- a/lrc/src/macromodel.cpp
+++ b/lrc/src/macromodel.cpp
@@ -198,10 +198,13 @@ QModelIndex MacroModel::parent( const QModelIndex& index) const
QModelIndex MacroModel::index( int row, int column, const QModelIndex& parent) const
{
- if (!parent.isValid() && d_ptr->m_lCategories.size() > row) {
+ if (column != 0 || parent.parent().isValid())
+ return QModelIndex();
+
+ if ((!parent.isValid()) && d_ptr->m_lCategories.size() > row && row >= 0) {
return createIndex(row,column,d_ptr->m_lCategories[row]->m_pPointer);
}
- else if (parent.isValid() && d_ptr->m_lCategories[parent.row()]->m_lContent.size() > row) {
+ else if (parent.isValid() && d_ptr->m_lCategories[parent.row()]->m_lContent.size() > row && row >= 0) {
return createIndex(row,column,d_ptr->m_lCategories[parent.row()]->m_lContent[row]->d_ptr->m_pPointer);
}
return QModelIndex();
diff --git a/lrc/src/private/videorenderermanager.cpp b/lrc/src/private/videorenderermanager.cpp
index 75e67de..d1523d6 100644
--- a/lrc/src/private/videorenderermanager.cpp
+++ b/lrc/src/private/videorenderermanager.cpp
@@ -62,13 +62,13 @@ public:
//Helper
void removeRenderer(Video::Renderer* r);
-
private:
VideoRendererManager* q_ptr;
public Q_SLOTS:
void startedDecoding(const QString& id, const QString& shmPath, int width, int height);
void stoppedDecoding(const QString& id, const QString& shmPath);
+ void callIsOver();
};
@@ -227,9 +227,9 @@ void VideoRendererManagerPrivate::startedDecoding(const QString& id, const QStri
}
else {
- r = m_hRenderers[rid];
+ r = m_hRenderers.value(rid);
- QThread* t = m_hThreads[r];
+ QThread* t = m_hThreads.value(r);
if (t && !t->isRunning())
t->start();
@@ -280,72 +280,87 @@ void VideoRendererManagerPrivate::startedDecoding(const QString& id, const QStri
}
}
-/**
- * @warning This method can be called multiple time for the same renderer
- */
+/// Deletes the renderer and related resources
void VideoRendererManagerPrivate::removeRenderer(Video::Renderer* r)
{
- if (!r || !m_hRenderers.contains(m_hRendererIds[r]))
- return;
+ const auto id = m_hRendererIds.value(r);
+ auto t = m_hThreads.value(r);
- const QByteArray id = m_hRendererIds[r];
+ m_hRendererIds.remove(r);
+ m_hRenderers.remove(id);
+ m_hThreads.remove(r);
- //Quit if for some reasons the renderer is not found
- if ( !r ) {
- qWarning() << "Cannot stop rendering, renderer" << id << "not found";
- return;
- }
+ if (t) {
+ t->deleteLater();
+ }
- Call* c = CallModel::instance().getCall(id);
+ r->deleteLater();
+}
- if (c && c->lifeCycleState() == Call::LifeCycleState::FINISHED) {
- c->d_ptr->removeRenderer(r);
- }
+/**
+ * A video stopped being rendered
+ *
+ * @warning This method can be called multiple time for the same renderer
+ */
+void VideoRendererManagerPrivate::stoppedDecoding(const QString& id, const QString& shmPath)
+{
+ Q_UNUSED(shmPath)
- r->stopRendering();
+ if (!m_hRenderers.contains(id.toLatin1()) || !m_hRenderers.contains(id.toLatin1())) {
+ qWarning() << "Cannot stop decoding, renderer" << id << "not found";
+ return; // nothing to do
+ }
- qDebug() << "Video stopped for call" << id << "Renderer found:" << m_hRenderers.contains(id);
+ auto r = m_hRenderers.value(id.toLatin1());
- Video::Device* dev = Video::DeviceModel::instance().getDevice(id);
+ Call* c = CallModel::instance().getCall(id);
- if (dev)
- emit dev->renderingStopped(r);
+ // TODO: the current implementeation of CallPrivate::removeRenderer() does nothing
+ if (c && c->lifeCycleState() == Call::LifeCycleState::FINISHED) {
+ c->d_ptr->removeRenderer(r);
+ }
- if (id == PREVIEW_RENDERER_ID) {
- m_PreviewState = false;
- emit q_ptr->previewStateChanged(false);
- emit q_ptr->previewStopped(r);
- }
+ r->stopRendering();
- QThread* t = m_hThreads[r];
+ qDebug() << "Video stopped for call" << id << "Renderer found:" << m_hRenderers.contains(id.toLatin1());
- if (t) {
- t->quit();
- t->wait();
- }
+ Video::Device* dev = Video::DeviceModel::instance().getDevice(id);
- if (c && c->lifeCycleState() == Call::LifeCycleState::FINISHED) {
+ if (dev)
+ emit dev->renderingStopped(r);
- m_hRendererIds.remove(r);
- m_hRenderers.remove(id);
+ if (id == PREVIEW_RENDERER_ID) {
+ m_PreviewState = false;
+ emit q_ptr->previewStateChanged(false);
+ emit q_ptr->previewStopped(r);
+ }
- m_hThreads[r] = nullptr;
- if (t) {
- t->deleteLater();
- }
+ QThread* t = m_hThreads.value(r);
- r->deleteLater();
- }
+ if (t) {
+ t->quit();
+ t->wait();
+ }
+
+ // decoding stopped; remove the renderer, if/when call is over
+ if (c && c->lifeCycleState() == Call::LifeCycleState::FINISHED) {
+ removeRenderer(r);
+ } else if (c) {
+ connect(c, &Call::isOver, this, &VideoRendererManagerPrivate::callIsOver);
+ }
}
-///A video stopped being rendered
-void VideoRendererManagerPrivate::stoppedDecoding(const QString& id, const QString& shmPath)
+void VideoRendererManagerPrivate::callIsOver()
{
- Q_UNUSED(shmPath)
-
- if (m_hRenderers.contains(id.toLatin1())) {
- removeRenderer(m_hRenderers[id.toLatin1()]);
- }
+ if (auto call = qobject_cast<Call *>(sender())) {
+ if (auto r = m_hRenderers.value(call->dringId().toLatin1()))
+ removeRenderer(r);
+ else
+ qDebug() << "Could not delete renderer, it might have already been removed:" << call->dringId();
+
+ // remove the connection from this call to this
+ disconnect(call, &Call::isOver, this, 0);
+ }
}
void VideoRendererManager::switchDevice(const Video::Device* device) const
diff --git a/lrc/src/recentmodel.cpp b/lrc/src/recentmodel.cpp
index ff3d0ea..e3645bf 100644
--- a/lrc/src/recentmodel.cpp
+++ b/lrc/src/recentmodel.cpp
@@ -196,7 +196,7 @@ RecentModel::getParticipantNumber(Call *call) const
void RecentModelPrivate::selectNode(RecentViewNode* node) const
{
- const auto idx = q_ptr->createIndex(node->m_Index, 0, node->m_pParent);
+ const auto idx = q_ptr->createIndex(node->m_Index, 0, node);
q_ptr->selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
}
@@ -748,7 +748,7 @@ void RecentModelPrivate::slotContactChanged(ContactMethod* cm, Person* np, Perso
removeNode(n);
if (newParentNode && newParentNode->m_lChildren.size()) {
- q_ptr->selectionModel()->select(q_ptr->getIndex(const_cast<Person*>(newParentNode->m_uContent.m_pPerson)), QItemSelectionModel::ClearAndSelect);
+ selectNode(newParentNode);
}
}
}
diff --git a/lrc/src/tlsmethodmodel.cpp b/lrc/src/tlsmethodmodel.cpp
index 609a7be..59c69d5 100644
--- a/lrc/src/tlsmethodmodel.cpp
+++ b/lrc/src/tlsmethodmodel.cpp
@@ -40,7 +40,6 @@ public:
constexpr static const char* TLSv1 = "TLSv1" ;
constexpr static const char* TLSv1_1 = "TLSv1.1";
constexpr static const char* TLSv1_2 = "TLSv1.2";
- constexpr static const char* SSLv3 = "SSLv3" ;
};
@@ -50,7 +49,6 @@ public:
constexpr static const char* TLSv1 = "TLSv1" ;
constexpr static const char* TLSv1_1 = "TLSv1.1";
constexpr static const char* TLSv1_2 = "TLSv1.2";
- constexpr static const char* SSLv3 = "SSLv3" ;
};
static const char* toDaemonName(TlsMethodModel::Type type);
@@ -112,16 +110,18 @@ QVariant TlsMethodModel::data( const QModelIndex& index, int role) const
return TlsMethodModelPrivate::Name::TLSv1_1;
case TlsMethodModel::Type::TLSv1_2:
return TlsMethodModelPrivate::Name::TLSv1_2;
- case TlsMethodModel::Type::SSLv3:
- return TlsMethodModelPrivate::Name::SSLv3;
+ case TlsMethodModel::Type::COUNT__:
+ break;
};
}
return QVariant();
}
int TlsMethodModel::rowCount( const QModelIndex& parent ) const
+
{
- return parent.isValid()?0: d_ptr->isRing ? 1 : 4;
+ // In the RING case, only the "default" encryption type can be used
+ return parent.isValid() ? 0 : d_ptr->isRing ? 1 : static_cast<int>(TlsMethodModel::Type::COUNT__);
}
Qt::ItemFlags TlsMethodModel::flags( const QModelIndex& index ) const
@@ -181,8 +181,9 @@ const char* TlsMethodModelPrivate::toDaemonName(TlsMethodModel::Type type)
return TlsMethodModelPrivate::DaemonName::TLSv1_1;
case TlsMethodModel::Type::TLSv1_2:
return TlsMethodModelPrivate::DaemonName::TLSv1_2;
- case TlsMethodModel::Type::SSLv3:
- return TlsMethodModelPrivate::DaemonName::SSLv3;
+ case TlsMethodModel::Type::COUNT__:
+ // default
+ break;
};
return TlsMethodModelPrivate::DaemonName::DEFAULT;
}
@@ -198,8 +199,6 @@ TlsMethodModel::Type TlsMethodModelPrivate::fromDaemonName(const QString& name)
return TlsMethodModel::Type::TLSv1_1;
else if (name == TlsMethodModelPrivate::DaemonName::TLSv1_2)
return TlsMethodModel::Type::TLSv1_2;
- else if (name == TlsMethodModelPrivate::DaemonName::SSLv3)
- return TlsMethodModel::Type::SSLv3;
qDebug() << "Unknown TLS method" << name;
return TlsMethodModel::Type::DEFAULT;
}
diff --git a/lrc/src/tlsmethodmodel.h b/lrc/src/tlsmethodmodel.h
index 94e5116..be5747d 100644
--- a/lrc/src/tlsmethodmodel.h
+++ b/lrc/src/tlsmethodmodel.h
@@ -46,7 +46,7 @@ public:
TLSv1_0 = 1,
TLSv1_1 = 2,
TLSv1_2 = 3,
- SSLv3 = 4,
+ COUNT__
};
//Private constructor, can only be called by 'Account'
@@ -70,4 +70,3 @@ private:
};
Q_DECLARE_METATYPE(TlsMethodModel*)
-
diff --git a/make-ring.py b/make-ring.py
index 41ed474..f75a63a 100755
--- a/make-ring.py
+++ b/make-ring.py
@@ -53,11 +53,13 @@ FEDORA_DEPENDENCIES = [
'autoconf', 'automake', 'cmake', 'speexdsp-devel', 'pulseaudio-libs-devel',
'libsamplerate-devel', 'libtool', 'dbus-devel', 'expat-devel', 'pcre-devel',
'yaml-cpp-devel', 'boost-devel', 'dbus-c++-devel', 'dbus-devel',
- 'libsndfile-devel', 'libsrtp-devel', 'libXext-devel', 'libXfixes-devel', 'yasm',
- 'speex-devel', 'chrpath', 'check', 'astyle', 'uuid-c++-devel', 'gettext-devel',
+ 'libsndfile-devel', 'libXext-devel', 'libXfixes-devel', 'yasm',
+ 'speex-devel', 'chrpath', 'check', 'astyle', 'uuid-c++-devel', 'gettext',
'gcc-c++', 'which', 'alsa-lib-devel', 'systemd-devel', 'libuuid-devel',
'uuid-devel', 'gnutls-devel', 'nettle-devel', 'opus-devel', 'speexdsp-devel',
- 'yaml-cpp-devel', 'qt5-qtbase-devel', 'swig', 'qrencode-devel'
+ 'yaml-cpp-devel', 'qt5-qtbase-devel', 'swig', 'qrencode-devel', 'jsoncpp-devel',
+ 'gtk3-devel', 'clutter-devel', 'clutter-gtk-devel', 'evolution-data-server-devel',
+ 'libnotify-devel', 'libappindicator-gtk3-devel', 'patch'
]
UBUNTU_DEPENDENCIES = [
@@ -68,24 +70,22 @@ UBUNTU_DEPENDENCIES = [
'libdbus-c++-dev', 'libebook1.2-dev', 'libexpat1-dev', 'libgnutls-dev',
'libgsm1-dev', 'libgtk-3-dev', 'libjack-dev', 'libnotify-dev',
'libopus-dev', 'libpcre3-dev', 'libpulse-dev', 'libsamplerate0-dev',
- 'libsndfile1-dev', 'libspeex-dev', 'libspeexdsp-dev', 'libsrtp-dev',
- 'libswscale-dev', 'libtool', 'libudev-dev', 'libupnp-dev',
- 'libyaml-cpp-dev', 'qtbase5-dev', 'sip-tester', 'swig',
- 'uuid-dev', 'yasm', 'libqrencode-dev'
+ 'libsndfile1-dev', 'libspeex-dev', 'libspeexdsp-dev', 'libswscale-dev', 'libtool',
+ 'libudev-dev', 'libupnp-dev', 'libyaml-cpp-dev', 'qtbase5-dev', 'sip-tester', 'swig',
+ 'uuid-dev', 'yasm', 'libqrencode-dev', 'libjsoncpp-dev', 'libappindicator3-dev'
]
-
DEBIAN_DEPENDENCIES = [
'autoconf', 'autopoint', 'cmake', 'dbus', 'doxygen', 'g++', 'gettext',
'gnome-icon-theme-symbolic', 'libasound2-dev', 'libavcodec-dev',
'libavcodec-extra', 'libavdevice-dev', 'libavformat-dev', 'libboost-dev',
'libclutter-gtk-1.0-dev', 'libcppunit-dev', 'libdbus-1-dev',
- 'libdbus-c++-dev', 'libebook1.2-dev', 'libexpat1-dev', 'libgsm1-dev',
- 'libgtk-3-dev', 'libjack-dev', 'libnotify-dev', 'libopus-dev',
- 'libpcre3-dev', 'libpulse-dev', 'libsamplerate0-dev', 'libsndfile1-dev',
- 'libspeex-dev', 'libspeexdsp-dev', 'libswscale-dev', 'libtool',
- 'libudev-dev', 'libupnp-dev', 'libyaml-cpp-dev',
- 'qtbase5-dev', 'sip-tester', 'swig', 'uuid-dev', 'yasm', 'libqrencode-dev'
+ 'libdbus-c++-dev', 'libebook1.2-dev', 'libexpat1-dev', 'libgnutls-dev',
+ 'libgsm1-dev', 'libgtk-3-dev', 'libjack-dev', 'libnotify-dev',
+ 'libopus-dev', 'libpcre3-dev', 'libpulse-dev', 'libsamplerate0-dev',
+ 'libsndfile1-dev', 'libspeex-dev', 'libspeexdsp-dev', 'libswscale-dev', 'libtool',
+ 'libudev-dev', 'libupnp-dev', 'libyaml-cpp-dev', 'qtbase5-dev', 'sip-tester', 'swig',
+ 'uuid-dev', 'yasm', 'libqrencode-dev', 'libjsoncpp-dev', 'libappindicator3-dev'
]
ARCH_LINUX_DEPENDENCIES = [
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-voip/ring.git
More information about the Pkg-voip-commits
mailing list