#!/bin/sh

#
# Copyright (C) 2013 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# Set the PPP username and password to be used when making connections on
# a cellular service.

PROGRAM=$(basename $0)
FLAGS_HELP="Usage:

Show current PPP username
  ${PROGRAM}

Set PPP username and/or password
  ${PROGRAM} [-u <username>] [-p <password>]

Clear PPP username and password
  ${PROGRAM} -c
"

. /usr/share/misc/shflags

DEFAULT_PROFILE_NAME=default
FLIMFLAM=org.chromium.flimflam
IMANAGER=${FLIMFLAM}.Manager
IPROFILE=${FLIMFLAM}.Profile
ISERVICE=${FLIMFLAM}.Service
PASSWORD_PROPERTY=Cellular.PPP.Password
PROFILE_PROPERTY=Profile
USERNAME_PROPERTY=Cellular.PPP.Username

usage() {
  echo "$*"
  echo
  flags_help
  exit 1
}

dbus() {
  local object="$1"
  local method="$2"
  shift 2

  dbus-send --system --print-reply --fixed --dest="${FLIMFLAM}" \
    "${object}" "${method}" "$@"
}

get_property() {
  local interface="${1:?internal error}"
  local object="${2:?internal error}"
  local property="${3:?nternal error}"

  dbus "${object}" "${interface}.GetProperties" 2>/dev/null \
    | sed -n "/\/${property}/{s/.* //p}"
}

display_username() {
  local service="$1"
  local username="$(get_property ${ISERVICE} ${service} ${USERNAME_PROPERTY})"

  if [ -n "${username}" ]; then
    echo "PPP username: " ${username}
    exit 0
  fi

  echo "No PPP username."
  exit 0
}

set_username() {
  local service="$1"
  local username="$2"

  echo "Setting PPP username \"${username}\" for service ${service}"
  dbus "${service}" "${ISERVICE}.SetProperty" \
    "string:${USERNAME_PROPERTY}" "variant:string:${username}"
}

set_password() {
  local service="$1"
  local password="$2"

  echo "Setting PPP pasword for service ${service}"
  dbus "${service}" "${ISERVICE}.SetProperty" \
    "string:${PASSWORD_PROPERTY}" "variant:string:${password}"
}

clear_property() {
  local service="$1"
  local property="$2"

  echo "Clearing ${property} for service ${service}"
  dbus "${service}" "${ISERVICE}.ClearProperty" "string:${property}"
}

get_profiles() {
  dbus / "${IMANAGER}.GetProperties" 2>/dev/null \
    | sed -n "/\/Profiles\//{s/.* //p}"
}

get_services() {
  dbus / "${IMANAGER}.GetProperties" 2>/dev/null \
    | sed -n "/\/Services\//{s/.* //p}"
}

get_default_profile() {
  local profile
  local profile_name

  for profile in $(get_profiles); do
    profile_name="$(get_property ${IPROFILE} ${profile} Name)"
    if [ ${profile_name} = ${DEFAULT_PROFILE_NAME} ]; then
      echo "${profile}"
      break
    fi
  done
}

get_first_cellular_service() {
  local service
  local service_type

  for service in $(get_services); do
    service_type="$(get_property ${ISERVICE} ${service} Type)"
    if [ "${service_type}" = "cellular" ]; then
      echo "${service}"
      break
    fi
  done
}

move_service_to_profile() {
  local service="$1"
  local profile="$2"

  if [ -z "${service}" ]; then
    return 1
  fi

  if [ -z "${profile}" ]; then
    return 1
  fi

  dbus "${service}" "${ISERVICE}.SetProperty" \
    "string:${PROFILE_PROPERTY}" "variant:string:${profile}"

  local new_profile=$(
    get_property "${ISERVICE}" "${service}" "${PROFILE_PROPERTY}")
  if [ "${new_profile}" != "${profile}" ]; then
    return 1
  else
    return 0
  fi
}

service="$(get_first_cellular_service)"
if [ -z "${service}" ]; then
  echo "No cellular service exists."
  exit 1
fi

if [ $# -lt 1 ]; then
  display_username "${service}"
fi

DEFINE_string 'username' "" 'PPP username for the Service' 'u'
DEFINE_string 'password' "" 'PPP password for the Service' 'p'
DEFINE_boolean 'clear' false \
  'clear any username and password that has been previously set' 'c'
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"

if [ "${FLAGS_clear}" -ne 0 ]; then
  if [ $# -ne 0 ]; then
    usage "Too many arguments."
  fi
  if [ -n "${FLAGS_username}" ]; then
    set_username "${service}" "${FLAGS_username}"
  fi
  if [ -n "${FLAGS_password}" ]; then
    set_password "${service}" "${FLAGS_password}"
  fi
  echo  #  newline to separate from set_username/set_password output
  if move_service_to_profile "${service}" "$(get_default_profile)"; then
    cat <<-END
	When your cellular dongle is connected to the system, its connection
	will be available to any user of this Chromebook, including guest users.

	If you want to leave the dongle connected, without sharing its
	connection with other users, you will need to clear the PPP username
	and password by running the following command:
	        ${PROGRAM} -c

	If you clear the PPP username and password, you will need to re-run
	${PROGRAM} the next time you need to connect.
END
  else
    cat <<-END
	Your cellular connection could not be configured for sharing with
	other users of this Chromebook. If you would like to share this
	connection with them, please try running this command again.
END
  fi
else
  if [ $# -ne 0 ]; then
    usage "Too many arguments."
  fi
  clear_property "${service}" "${USERNAME_PROPERTY}"
  clear_property "${service}" "${PASSWORD_PROPERTY}"
fi