diff --git a/.travis.yml b/.travis.yml
index 0fa7e72..e5cd093 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -27,6 +27,7 @@ script:
- testing/run_integration_case.sh run_without_reconnection
- testing/run_integration_case.sh run_with_route_discovery
- testing/run_integration_case.sh run_without_route_discovery
+ - testing/run_integration_case.sh xaval
branches:
only:
diff --git a/README.md b/README.md
index 9062a93..2badb4e 100644
--- a/README.md
+++ b/README.md
@@ -39,5 +39,8 @@ As long as your routes do not overlap, you can run as many `xiringuito` tunnels
+## Xaval: connection manager
+**NB!** To ease xiringuito configuration `xaval` connection manager script (is inside the project) could be used.
+
## Future?
-Before, due to lack of testing, we had some complications with adding new features and changing `xiringuito` behavior, but since **[this PR](https://github.com/ivanilves/xiringuito/pull/32)** was merged, we are covered and will bravely proceed with addressing **[issues](https://github.com/ivanilves/xiringuito/issues)** and any challenges on our way.
+Before, due to lack of testing, we had some complications with adding new features and changing `xiringuito` behavior, but since **[this PR](https://github.com/ivanilves/xiringuito/pull/32)** was merged, we are covered and will bravely proceed with addressing **[issues](https://github.com/ivanilves/xiringuito/issues)** and any challenges on our way.
diff --git a/testing/integration/cases/xaval.sh b/testing/integration/cases/xaval.sh
new file mode 100644
index 0000000..e881e40
--- /dev/null
+++ b/testing/integration/cases/xaval.sh
@@ -0,0 +1,64 @@
+export EXIT_AFTER_CONNECT=1
+
+local PROFILE_DIR=~/.xiringuito/profiles
+local PROFILE=xiri-${DIST}
+
+trap "rm -f ${PROFILE_DIR}/${PROFILE}*; teardown" EXIT
+
+${WD}/xaval create ${PROFILE} ${SSH_USER}@${REMOTE_IP}
+warn "$(cat ${PROFILE_DIR}/${PROFILE})"
+if [[ "$(cat ${PROFILE_DIR}/${PROFILE})" != "${SSH_USER}@${REMOTE_IP}" ]]; then
+ complain "Xaval has not created profile file with valid content: ${PROFILE}"
+ exit 1
+fi
+
+set +e
+${WD}/xaval create ${PROFILE} ${SSH_USER}@${REMOTE_IP}
+if [[ ${?} -eq 0 ]]; then
+ complain "Xaval has created profile, even when it was already created :-/"
+ exit 1
+fi
+set -e
+
+${WD}/xaval rename ${PROFILE} ${PROFILE}.new
+if [[ -f "${PROFILE_DIR}/${PROFILE}" ]]; then
+ complain "Xaval [renaming] has not removed old profile file: ${PROFILE_DIR}/${PROFILE}"
+ exit 1
+fi
+if [[ ! -f "${PROFILE_DIR}/${PROFILE}.new" ]]; then
+ complain "Xaval [renaming] has not created new profile file: ${PROFILE_DIR}/${PROFILE}"
+ exit 1
+fi
+
+set +e
+${WD}/xaval rename ${PROFILE} ${PROFILE}.new
+if [[ ${?} -eq 0 ]]; then
+ complain "Xaval has renamed non-existing profile :-/"
+ exit 1
+fi
+set -e
+
+${WD}/xaval rename ${PROFILE}.new ${PROFILE}
+
+${WD}/xaval update ${PROFILE} -X ${SSH_USER}@${REMOTE_IP}
+warn "$(cat ${PROFILE_DIR}/${PROFILE})"
+if [[ "$(cat ${PROFILE_DIR}/${PROFILE})" != "-X ${SSH_USER}@${REMOTE_IP}" ]]; then
+ complain "Xaval has not updated profile file with valid content: ${PROFILE}"
+ exit 1
+fi
+
+${WD}/xaval connect ${PROFILE}
+
+${WD}/xaval delete ${PROFILE}
+if [[ -f "${PROFILE_DIR}/${PROFILE}" ]]; then
+ complain "Xaval has not deleted profile file: ${PROFILE_DIR}/${PROFILE}"
+ exit 1
+fi
+
+set +e
+${WD}/xaval delete ${PROFILE}
+if [[ ${?} -eq 0 ]]; then
+ complain "Xaval has deleted already deleted profile :-/"
+ exit 1
+fi
+set -e
diff --git a/xaval b/xaval
new file mode 100755
index 0000000..64ac68b
--- /dev/null
+++ b/xaval
@@ -0,0 +1,186 @@
+#!/usr/bin/env bash
+#
+# xaval - xiringuito connection manager
+#
+set -u
+set -e
+set -o pipefail
+
+declare -r DIR=${HOME}/.xiringuito/profiles; mkdir -p ${DIR}
+
+function print_help(){
+ cat <" PROFILE_NUMBER
+
+ if [[ ${PROFILE_NUMBER} =~ "^[0-9]+$" ]]; then
+ commit_suicide "Should be a natural number!"
+ fi
+
+ if [[ ${PROFILE_NUMBER} -lt ${START_NUMBER} ]]; then
+ commit_suicide "Should be >= ${START_NUMBER}"
+ fi
+
+ if [[ ${PROFILE_NUMBER} -gt ${PROFILE_COUNT} ]]; then
+ commit_suicide "Should be <= ${PROFILE_COUNT}"
+ fi
+
+ local PROFILE=$(list_profiles | head -n${PROFILE_NUMBER} | tail -n1 | cut -d' ' -f1)
+
+ connect_profile ${PROFILE}
+}
+
+function list_profiles(){
+ local FILTER_EXPR="${@}"
+ if [[ -z "${FILTER_EXPR}" ]]; then
+ FILTER_EXPR=".*"
+ fi
+ for PROFILE in $(find ${DIR} -type f -printf "%f\n" | egrep "${FILTER_EXPR}" | sort); do
+ printf "%-20s = %s\n" ${PROFILE} "$(cat ${DIR}/${PROFILE})"
+ done
+}
+
+function create_profile(){
+ local PROFILE=${1}; shift
+
+ suicide_on_existing_profile ${PROFILE}
+
+ echo "${@}" >${DIR}/${PROFILE}
+}
+
+function update_profile(){
+ local PROFILE=${1}; shift
+
+ suicide_on_absent_profile ${PROFILE}
+
+ echo "${@}" >${DIR}/${PROFILE}
+}
+
+function upsert_profile(){
+ local PROFILE=${1}; shift
+
+ echo "${@}" >${DIR}/${PROFILE}
+}
+
+function delete_profile(){
+ local PROFILE=${1}
+
+ suicide_on_absent_profile ${PROFILE}
+
+ rm ${DIR}/${PROFILE}
+}
+
+function connect_profile(){
+ local PROFILE=${1}
+
+ suicide_on_absent_profile ${PROFILE}
+
+ exec $(dirname ${0})/xiringuito $(cat ${DIR}/${PROFILE})
+}
+
+function rename_profile(){
+ local OLD_PROFILE=${1}
+ local NEW_PROFILE=${2}
+
+ suicide_on_absent_profile ${OLD_PROFILE}
+ suicide_on_existing_profile ${NEW_PROFILE}
+
+ mv ${DIR}/${OLD_PROFILE} ${DIR}/${NEW_PROFILE}
+}
+
+if [[ $(echo "${@}" | egrep "((^|(^| )-{1,2})help|^-h)($| )") ]]; then
+ print_help
+ exit 0
+fi
+
+if [[ ${#} -eq 0 ]]; then
+ select_profile
+fi
+
+declare -r CMD=${1}; shift
+
+if [[ ! $(validate_command ${CMD}) ]]; then
+ print_help_and_commit_suicide "Illegal command: ${CMD}"
+fi
+
+if [[ "${CMD}" == "list" ]]; then
+ list_profiles "${@}"
+ exit 0
+fi
+
+if [[ "${CMD}" == "connect" || "${CMD}" == "delete" ]]; then
+ if [[ ${#} -ne 1 ]]; then
+ print_help_and_commit_suicide "Command requires exactly 1 parameter: ${CMD}"
+ fi
+elif [[ ${CMD} == "rename" ]]; then
+ if [[ ${#} -ne 2 ]]; then
+ print_help_and_commit_suicide "Command requires exactly 2 parameters: ${CMD}"
+ fi
+else
+ if [[ ${#} -lt 2 ]]; then
+ print_help_and_commit_suicide "Not enough parameters for the command: ${CMD}"
+ fi
+fi
+
+eval ${CMD}_profile ${@}