#!/bin/sh

MOD_NAME=mqttbroker
MOD_DEFAULTS=/opt/$MOD_NAME/etc/defaults
MOD_SETTINGS=/opt/$MOD_NAME/etc/settings
[ -L "$MOD_SETTINGS" ] && MOD_SETTINGS=`readlink $MOD_SETTINGS`

MODULE_CHAIN=mod_$MOD_NAME
DAEMON_NAME=mosquitto
DAEMON_BIN=/opt/$MOD_NAME/bin/$DAEMON_NAME
DAEMON_RUN=/run/$MOD_NAME
DAEMON_CFG=$DAEMON_RUN/$DAEMON_NAME.conf
DAEMON_USER=daemon
DAEMON_GROUP=daemons
PASSWD_BIN=/opt/$MOD_NAME/bin/mosquitto_passwd
BROKER_PWDFILE=$DAEMON_RUN/broker_pwd
BROKER_ACLFILE=$DAEMON_RUN/broker_acl
BROKER_PSKFILE=$DAEMON_RUN/broker_psk
BROKER_CAFILE=$DAEMON_RUN/broker_ca.pem
BROKER_CERTFILE=$DAEMON_RUN/broker_cert.pem
BROKER_KEYFILE=$DAEMON_RUN/broker_key.pem
BRIDGE_CAFILE=$DAEMON_RUN/bridge%_ca.pem
BRIDGE_CERTFILE=$DAEMON_RUN/bridge%_cert.pem
BRIDGE_KEYFILE=$DAEMON_RUN/bridge%_key.pem
STATS_SOCKET=$DAEMON_RUN/stats_sock
STATS_PWDFILE=$DAEMON_RUN/stats_pwd
STATS_ACLFILE=$DAEMON_RUN/stats_acl
STATS_USERNAME=stats
STATS_PASSWORD=stats

add_chain() {
  /sbin/iptables -N $MODULE_CHAIN || return
  /sbin/iptables -A $MODULE_CHAIN -p tcp --dport $MOD_MQTTBROKER_PORT -j ACCEPT
  /sbin/iptables -A in_mod -j $MODULE_CHAIN
}

del_chain() {
  /sbin/iptables -D in_mod -j $MODULE_CHAIN >/dev/null
  /sbin/iptables -F $MODULE_CHAIN >/dev/null
  /sbin/iptables -X $MODULE_CHAIN >/dev/null
}

[ -f "$MOD_SETTINGS" ] || cp $MOD_DEFAULTS $MOD_SETTINGS
[ -x "/sbin/hash_verify" ] && [ ! -f "$MOD_SETTINGS.hash" ] && cp $MOD_DEFAULTS.hash $MOD_SETTINGS.hash

. $MOD_SETTINGS

case "$1" in

  start)
    [ -x "/sbin/hash_verify" ] && ! hash_verify $MOD_SETTINGS && exit 1
    echo -n "Starting MQTT Broker..."
    if [ "$MOD_MQTTBROKER_ENABLED" != "1" -a "$MOD_MQTTBROKER_BR1_ENABLED" != "1" -a "$MOD_MQTTBROKER_BR2_ENABLED" != "1" -a "$MOD_MQTTBROKER_BR3_ENABLED" != "1" ]; then
      echo "skipped"
      exit 0
    fi
    mkdir -p $DAEMON_RUN
    chown $DAEMON_USER:$DAEMON_GROUP $DAEMON_RUN
    # common configuration
    echo "user $DAEMON_USER" >$DAEMON_CFG
    echo "per_listener_settings true" >>$DAEMON_CFG
    case $MOD_MQTTBROKER_LOGLEV in
      error)
        echo -e "log_dest syslog\nlog_timestamp false\nlog_type error" >>$DAEMON_CFG
      ;;
      warning)
        echo -e "log_dest syslog\nlog_timestamp false\nlog_type error\nlog_type warning" >>$DAEMON_CFG
      ;;
      notice)
        echo -e "log_dest syslog\nlog_timestamp false\nlog_type error\nlog_type warning\nlog_type notice" >>$DAEMON_CFG
      ;;
      information)
        echo -e "log_dest syslog\nlog_timestamp false\nlog_type error\nlog_type warning\nlog_type notice\nlog_type information\nlog_type subscribe\nlog_type unsubscribe" >>$DAEMON_CFG
      ;;
      debug)
        echo -e "log_dest syslog\nlog_timestamp false\nlog_type all" >>$DAEMON_CFG
      ;;
    esac
    echo "" >>$DAEMON_CFG
    echo "listener 0 $STATS_SOCKET" >>$DAEMON_CFG
    echo "allow_anonymous false" >>$DAEMON_CFG
    echo "password_file $STATS_PWDFILE" >>$DAEMON_CFG
    echo "acl_file $STATS_ACLFILE" >>$DAEMON_CFG
    $PASSWD_BIN -H sha512-pbkdf2 -c -b $STATS_PWDFILE $STATS_USERNAME $STATS_PASSWORD
    echo -e "user $STATS_USERNAME\ntopic read \$SYS/#" >>$STATS_ACLFILE
    chmod 0600 $STATS_PWDFILE
    chown $DAEMON_USER:$DAEMON_GROUP $STATS_PWDFILE
    chmod 0600 $STATS_ACLFILE
    chown $DAEMON_USER:$DAEMON_GROUP $STATS_ACLFILE
    # broker listener configuration
    if [ "$MOD_MQTTBROKER_ENABLED" = "1" ]; then
      echo "" >>$DAEMON_CFG
      echo "listener $MOD_MQTTBROKER_PORT" >>$DAEMON_CFG
      case $MOD_MQTTBROKER_AUTH in
        pass)
          $PASSWD_BIN -H sha512-pbkdf2 -c -b $BROKER_PWDFILE $MOD_MQTTBROKER_USERNAME $MOD_MQTTBROKER_PASSWORD
          echo -e "user $MOD_MQTTBROKER_USERNAME\ntopic readwrite #\ntopic read \$SYS/#\ntopic readwrite \$SYS/broker/connection/+/state" >>$BROKER_ACLFILE
          chmod 0600 $BROKER_PWDFILE
          chown $DAEMON_USER:$DAEMON_GROUP $BROKER_PWDFILE
          chmod 0600 $BROKER_ACLFILE
          chown $DAEMON_USER:$DAEMON_GROUP $BROKER_ACLFILE
          echo "password_file $BROKER_PWDFILE" >>$DAEMON_CFG
          echo "acl_file $BROKER_ACLFILE" >>$DAEMON_CFG
          echo "allow_anonymous false" >>$DAEMON_CFG
        ;;
        cert)
          echo -e "user $MOD_MQTTBROKER_USERNAME\ntopic readwrite #\ntopic read \$SYS/#\ntopic readwrite \$SYS/broker/connection/+/state" >>$BROKER_ACLFILE
          chmod 0600 $BROKER_ACLFILE
          chown $DAEMON_USER:$DAEMON_GROUP $BROKER_ACLFILE
          echo "acl_file $BROKER_ACLFILE" >>$DAEMON_CFG
          echo "use_identity_as_username true" >>$DAEMON_CFG
        ;;
        *)
          echo "allow_anonymous true" >>$DAEMON_CFG
          if [ "$MOD_MQTTBROKER_TLS_SUPPORT" = "cert" ]; then
            echo "use_identity_as_username false" >>$DAEMON_CFG
          fi
        ;;
      esac
      case $MOD_MQTTBROKER_TLS_SUPPORT in
        psk)
          echo "$MOD_MQTTBROKER_PSK_IDENT:$MOD_MQTTBROKER_PSK_KEY" >$BROKER_PSKFILE
          chmod 0600 $BROKER_PSKFILE
          chown $DAEMON_USER:$DAEMON_GROUP $BROKER_PSKFILE
          echo "psk_hint router" >>$DAEMON_CFG
          echo "psk_file $BROKER_PSKFILE" >>$DAEMON_CFG
        ;;
        cert)
          decode $MOD_MQTTBROKER_CRT_BRKCRT >$BROKER_CERTFILE
          decode $MOD_MQTTBROKER_CRT_BRKKEY >$BROKER_KEYFILE
          chmod 0600 $BROKER_CERTFILE
          chown $DAEMON_USER:$DAEMON_GROUP $BROKER_CERTFILE
          chmod 0600 $BROKER_KEYFILE
          chown $DAEMON_USER:$DAEMON_GROUP $BROKER_KEYFILE
          echo "certfile $BROKER_CERTFILE" >>$DAEMON_CFG
          echo "keyfile $BROKER_KEYFILE" >>$DAEMON_CFG
          if [ -n "$MOD_MQTTBROKER_CRT_CACRT" ]; then
            decode $MOD_MQTTBROKER_CRT_CACRT >$BROKER_CAFILE
            chmod 0600 $BROKER_CAFILE
            chown $DAEMON_USER:$DAEMON_GROUP $BROKER_CAFILE
            echo "cafile $BROKER_CAFILE" >>$DAEMON_CFG
            echo "require_certificate true" >>$DAEMON_CFG
          else
            echo "require_certificate false" >>$DAEMON_CFG
          fi
        ;;
      esac
    fi
    # bridges configuration
    for BR in 1 2 3; do
      if [ "$(eval echo -n \$MOD_MQTTBROKER_BR${BR}_ENABLED)" = "1" ]; then
        echo "" >>$DAEMON_CFG
        echo "connection $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_NAME)" >>$DAEMON_CFG
        echo -n "address" >>$DAEMON_CFG
        for REMOTE in 1 2; do
          if [ -n "$(eval echo -n \$MOD_MQTTBROKER_BR${BR}_HOST${REMOTE})" ]; then
            echo -n " $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_HOST${REMOTE}):$(eval echo -n \$MOD_MQTTBROKER_BR${BR}_PORT${REMOTE})" >>$DAEMON_CFG
          fi
        done
        echo "" >>$DAEMON_CFG
        echo "local_clientid $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_NAME)" >>$DAEMON_CFG
        echo "bridge_protocol_version mqttv$(eval echo -n \$MOD_MQTTBROKER_BR${BR}_VERSION)" >>$DAEMON_CFG
        echo "keepalive_interval $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_KEEPALIVE)" >>$DAEMON_CFG
        if [ "$(eval echo -n \$MOD_MQTTBROKER_BR${BR}_CLEAN_SESSION)" = "1" ]; then
          echo "cleansession true" >>$DAEMON_CFG
        else
          echo "cleansession false" >>$DAEMON_CFG
        fi
        if [ "$(eval echo -n \$MOD_MQTTBROKER_BR${BR}_TRY_PRIVATE)" = "1" ]; then
          echo "try_private true" >>$DAEMON_CFG
        else
          echo "try_private false" >>$DAEMON_CFG
        fi
        case $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_AUTH) in
          pass)
            echo "remote_username $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_USERNAME)" >>$DAEMON_CFG
            echo "remote_password $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_PASSWORD)" >>$DAEMON_CFG
          ;;
          cert)
            echo "remote_username $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_USERNAME)" >>$DAEMON_CFG
          ;;
          *)
          ;;
        esac
        case $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_TLS_SUPPORT) in
          psk)
            echo "bridge_identity $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_PSK_IDENT)" >>$DAEMON_CFG
            echo "bridge_psk $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_PSK_KEY)" >>$DAEMON_CFG
          ;;
          cert)
            CAFILE="${BRIDGE_CAFILE/%/$BR}"
            decode $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_CRT_CACRT) >$CAFILE
            chmod 0600 $CAFILE
            chown $DAEMON_USER:$DAEMON_GROUP $CAFILE
            echo "bridge_cafile $CAFILE" >>$DAEMON_CFG
            if [ "$(eval echo -n \$MOD_MQTTBROKER_BR${BR}_CRT_VERIFY)" = "1" ]; then
              echo "bridge_insecure false" >>$DAEMON_CFG
            else
              echo "bridge_insecure true" >>$DAEMON_CFG
            fi
            if [ -n "$(eval echo -n \$MOD_MQTTBROKER_BR${BR}_CRT_CLICRT)" ]; then
              CERTFILE="${BRIDGE_CERTFILE/%/$BR}"
              decode $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_CRT_CLICRT) >$CERTFILE
              chmod 0600 $CERTFILE
              chown $DAEMON_USER:$DAEMON_GROUP $CERTFILE
              echo "bridge_certfile $CERTFILE" >>$DAEMON_CFG
            fi
            if [ -n "$(eval echo -n \$MOD_MQTTBROKER_BR${BR}_CRT_CLIKEY)" ]; then
              KEYFILE="${BRIDGE_KEYFILE/%/$BR}"
              decode $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_CRT_CLIKEY) >$KEYFILE
              chmod 0600 $KEYFILE
              chown $DAEMON_USER:$DAEMON_GROUP $KEYFILE
              echo "bridge_keyfile $KEYFILE" >>$DAEMON_CFG
            fi
          ;;
        esac
        for RULE in 1 2 3 4 5 6 7 8 9 10; do
          if [ "$(eval echo -n \$MOD_MQTTBROKER_BR${BR}_RULE${RULE}_ENABLED)" = "1" ]; then
            echo -n "topic $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_RULE${RULE}_TOPIC) $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_RULE${RULE}_DIRECTION) $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_RULE${RULE}_QOS)" >>$DAEMON_CFG
            if [ -z "$(eval echo -n \$MOD_MQTTBROKER_BR${BR}_RULE${RULE}_LPREFIX)" ]; then
              echo -n " \"\"" >>$DAEMON_CFG
            else
              echo -n " $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_RULE${RULE}_LPREFIX)" >>$DAEMON_CFG
            fi
            if [ -z "$(eval echo -n \$MOD_MQTTBROKER_BR${BR}_RULE${RULE}_RPREFIX)" ]; then
              echo -n " \"\"" >>$DAEMON_CFG
            else
              echo -n " $(eval echo -n \$MOD_MQTTBROKER_BR${BR}_RULE${RULE}_RPREFIX)" >>$DAEMON_CFG
            fi
            echo "" >>$DAEMON_CFG
          fi
        done
      fi
    done
    chmod 0600 $DAEMON_CFG
    chown $DAEMON_USER:$DAEMON_GROUP $DAEMON_CFG
    add_chain
    logger -t mosquitto "MQTT Broker service start"
    $DAEMON_BIN -d -c $DAEMON_CFG 2>/dev/null
    echo "done"
    exit 0;
  ;;

  stop)
    echo -n "Stopping MQTT Broker..."
    killall -q -SIGTERM $DAEMON_NAME
    del_chain
    rm -rf $DAEMON_RUN
    logger -t mosquitto "MQTT Broker service stop"
    echo "done"
    exit $?;
  ;;

  restart)
    $0 stop
    sleep 1
    $0 start
  ;;

  status)
    echo -n "Module $MOD_NAME is "
    killall -0 $DAEMON_NAME 2>/dev/null
    RETVAL=$?
    if [ $RETVAL = 0 ]; then echo "running"; else echo "stopped"; fi
    exit $RETVAL
  ;;

  defaults)
    cp $MOD_DEFAULTS $MOD_SETTINGS 2>/dev/null
    [ -f "$MOD_DEFAULTS.hash" ] && cp $MOD_DEFAULTS.hash $MOD_SETTINGS.hash
    exit 0
  ;;

  *)
    echo "Usage: $0 {start|stop|restart|status|defaults}"
    exit 1
  ;;

esac
