#!/bin/bash
# dolphin-ftp-share - Manage FTP folder shares for Dolphin with Pure-FTPd
#
# Each user gets a personal FTP root with only their shared folders.
# Virtual FTP users (PureDB) are created automatically.
# Permissions (ro/rw) are enforced via bind mount options.
#
# Usage:
#   dolphin-ftp-share setup                             Initial Pure-FTPd setup
#   dolphin-ftp-share info                              List all shares
#   dolphin-ftp-share add <name> <path> <acl>           Add/update a share
#   dolphin-ftp-share delete <name>                     Remove a share
#   dolphin-ftp-share passwd <username> <password>      Set FTP password

set -e

SHARE_DIR="${HOME}/.local/share/dolphin-ftp-shares"
FTP_ROOT="${HOME}/.local/share/dolphin-ftp-root"
PASSWD_FILE="/etc/pure-ftpd/pureftpd.passwd"
PDB_FILE="/etc/pure-ftpd/pureftpd.pdb"

CALLER_UID=$(id -u)
CALLER_GID=$(id -g)

# Update home directory for an existing virtual FTP user.
ensure_virtual_user() {
    local username="$1"
    local user_root="$FTP_ROOT/users/$username"

    mkdir -p "$user_root"

    if sudo pure-pw show "$username" -f "$PASSWD_FILE" >/dev/null 2>&1; then
        sudo pure-pw usermod "$username" \
            -d "$user_root" \
            -f "$PASSWD_FILE" 2>/dev/null
    fi
}

rebuild_db() {
    sudo pure-pw mkdb "$PDB_FILE" -f "$PASSWD_FILE"
}

# Unmount a share from all user roots
unmount_share() {
    local name="$1"
    if [ -d "$FTP_ROOT/users" ]; then
        for user_dir in "$FTP_ROOT/users"/*/; do
            [ -d "$user_dir" ] || continue
            local mp="${user_dir}${name}"
            if mountpoint -q "$mp" 2>/dev/null; then
                sudo umount "$mp"
            fi
            rmdir "$mp" 2>/dev/null || true
        done
    fi
}

cmd_setup() {
    echo "Setting up Pure-FTPd for Dolphin FTP sharing..."

    mkdir -p "$FTP_ROOT/users"

    # Enable PureDB authentication
    echo "$PDB_FILE" | sudo tee /etc/pure-ftpd/conf/PureDB >/dev/null
    sudo ln -sf /etc/pure-ftpd/conf/PureDB /etc/pure-ftpd/auth/50pure

    # Chroot all users to their FTP home
    echo "yes" | sudo tee /etc/pure-ftpd/conf/ChrootEveryone >/dev/null

    # Disable anonymous access — only authenticated virtual users
    echo "yes" | sudo tee /etc/pure-ftpd/conf/NoAnonymous >/dev/null

    # Remove system auth so only PureDB users can log in
    sudo rm -f /etc/pure-ftpd/auth/65unix /etc/pure-ftpd/auth/70pam

    # Create empty password DB if needed
    sudo touch "$PASSWD_FILE"
    sudo pure-pw mkdb "$PDB_FILE" -f "$PASSWD_FILE"

    # Enable logging
    echo "yes" | sudo tee /etc/pure-ftpd/conf/VerboseLog >/dev/null

    # Create sudoers rule for passwordless mount/umount/pure-pw
    # Use SUDO_USER to get the real user (not root) when run with sudo
    local REAL_USER="${SUDO_USER:-$USER}"
    local REAL_HOME
    REAL_HOME=$(getent passwd "$REAL_USER" | cut -d: -f6)
    local REAL_FTP_ROOT="${REAL_HOME}/.local/share/dolphin-ftp-root"

    sudo tee /etc/sudoers.d/dolphin-ftp-share >/dev/null <<EOF
${REAL_USER} ALL=(root) NOPASSWD: /usr/bin/mount --bind *
${REAL_USER} ALL=(root) NOPASSWD: /usr/bin/mount -o remount?ro?bind *
${REAL_USER} ALL=(root) NOPASSWD: /usr/bin/umount ${REAL_FTP_ROOT}/*
${REAL_USER} ALL=(root) NOPASSWD: /usr/bin/pure-pw *
${REAL_USER} ALL=(root) NOPASSWD: /usr/bin/tee /etc/pure-ftpd/*
${REAL_USER} ALL=(root) NOPASSWD: /usr/bin/tee -a /etc/pure-ftpd/*
${REAL_USER} ALL=(root) NOPASSWD: /usr/bin/rm -f /etc/pure-ftpd/conf/PassivePortRange
${REAL_USER} ALL=(root) NOPASSWD: /usr/bin/sed -i *pureftpd.passwd*
${REAL_USER} ALL=(root) NOPASSWD: /usr/bin/systemctl restart pure-ftpd
EOF
    sudo chmod 440 /etc/sudoers.d/dolphin-ftp-share

    sudo systemctl restart pure-ftpd

    echo ""
    echo "Setup complete!"
    echo "Share folders via Dolphin: right-click folder → Properties → FTP tab"
    echo "Default FTP password = username. Change with:"
    echo "  dolphin-ftp-share passwd <user> <newpassword>"
}

cmd_info() {
    [ -d "$SHARE_DIR" ] || exit 0
    for conf in "$SHARE_DIR"/*.conf; do
        [ -f "$conf" ] || continue
        name=$(basename "$conf" .conf)
        echo "[$name]"
        cat "$conf"
        echo ""
    done
}

cmd_add() {
    local name="$1"
    local path="$2"
    local acl="$3"

    if [ -z "$name" ] || [ -z "$path" ]; then
        echo "Error: name and path are required" >&2
        exit 1
    fi

    mkdir -p "$SHARE_DIR" "$FTP_ROOT/users"

    # Unmount any existing mounts for this share (handles permission changes)
    unmount_share "$name"

    # Save config
    cat > "$SHARE_DIR/$name.conf" <<EOF
path=$path
user_acl=$acl
EOF

    # Process per-user ACL: "user1:ro,user2:rw"
    if [ -n "$acl" ]; then
        IFS=',' read -ra entries <<< "$acl"
        for entry in "${entries[@]}"; do
            local username="${entry%%:*}"
            local perm="${entry##*:}"
            local user_root="$FTP_ROOT/users/$username"
            local mount_point="$user_root/$name"

            ensure_virtual_user "$username"

            mkdir -p "$mount_point"

            # Bind mount the shared folder into user's personal FTP root
            sudo mount --bind "$path" "$mount_point"

            # Read-only: remount with ro flag
            if [ "$perm" = "ro" ]; then
                sudo mount -o remount,ro,bind "$mount_point"
            fi
        done
    fi

    rebuild_db
    echo "Share '$name' added: $path"
}

cmd_delete() {
    local name="$1"

    if [ -z "$name" ]; then
        echo "Error: name is required" >&2
        exit 1
    fi

    unmount_share "$name"
    rm -f "$SHARE_DIR/$name.conf"

    # Clean up
    rmdir "$SHARE_DIR" 2>/dev/null || true

    echo "Share '$name' deleted"
}

cmd_userexists() {
    local username="$1"

    if [ -z "$username" ]; then
        exit 1
    fi

    if sudo pure-pw show "$username" -f "$PASSWD_FILE" >/dev/null 2>&1; then
        exit 0
    else
        exit 1
    fi
}

cmd_passwd() {
    local username="$1"
    local password="$2"

    if [ -z "$username" ] || [ -z "$password" ]; then
        echo "Error: username and password are required" >&2
        exit 1
    fi

    local user_root="$FTP_ROOT/users/$username"
    mkdir -p "$user_root"

    # Generate MD5 password hash
    local hash
    hash=$(openssl passwd -1 "$password")

    if sudo pure-pw show "$username" -f "$PASSWD_FILE" >/dev/null 2>&1; then
        # User exists — update password in-place
        sudo sed -i "s|^${username}:[^:]*:|${username}:${hash}:|" "$PASSWD_FILE"
        echo "Password updated for '$username'"
    else
        # User doesn't exist — add entry to passwd file
        # Format: username:hash:uid:gid:gecos:home:uploadbw:downloadbw:uploadratio:downloadratio:maxconn:filesquota:sizequota:allowedlocalip:allowedclientip:timerestrictions
        echo "${username}:${hash}:${CALLER_UID}:${CALLER_GID}::${user_root}::::::::::::" | \
            sudo tee -a "$PASSWD_FILE" >/dev/null
        echo "Created FTP user '$username'"
    fi

    rebuild_db
}

cmd_deluser() {
    local username="$1"

    if [ -z "$username" ]; then
        echo "Error: username is required" >&2
        exit 1
    fi

    # Unmount all shares from this user's root first
    local user_root="$FTP_ROOT/users/$username"
    if [ -d "$user_root" ]; then
        for mp in "$user_root"/*/; do
            [ -d "$mp" ] || continue
            if mountpoint -q "$mp" 2>/dev/null; then
                sudo umount "$mp"
            fi
            rmdir "$mp" 2>/dev/null || true
        done
        rmdir "$user_root" 2>/dev/null || true
    fi

    # Remove user entry from passwd file
    if sudo pure-pw show "$username" -f "$PASSWD_FILE" >/dev/null 2>&1; then
        sudo sed -i "/^${username}:/d" "$PASSWD_FILE"
        rebuild_db
        echo "FTP user '$username' deleted"
    else
        echo "FTP user '$username' does not exist"
        exit 1
    fi
}

cmd_serverconfig() {
    local action="$1"

    case "$action" in
        show)
            # Output current mode and ports
            if [ -f /etc/pure-ftpd/conf/PassivePortRange ]; then
                local range
                range=$(cat /etc/pure-ftpd/conf/PassivePortRange)
                echo "mode=passive"
                echo "passive_start=${range%% *}"
                echo "passive_end=${range##* }"
            else
                echo "mode=active"
            fi
            ;;
        active)
            # Remove passive port range → only active mode
            sudo rm -f /etc/pure-ftpd/conf/PassivePortRange
            sudo systemctl restart pure-ftpd
            echo "Server set to active mode"
            ;;
        passive)
            local start_port="$2"
            local end_port="$3"
            if [ -z "$start_port" ] || [ -z "$end_port" ]; then
                echo "Error: start and end port required" >&2
                exit 1
            fi
            echo "${start_port} ${end_port}" | sudo tee /etc/pure-ftpd/conf/PassivePortRange >/dev/null
            sudo systemctl restart pure-ftpd
            echo "Server set to passive mode (ports ${start_port}-${end_port})"
            ;;
        *)
            echo "Usage: dolphin-ftp-share serverconfig {show|active|passive <start> <end>}" >&2
            exit 1
            ;;
    esac
}

case "${1:-}" in
    setup)        cmd_setup ;;
    info)         cmd_info ;;
    add)          cmd_add "$2" "$3" "${4:-}" ;;
    delete)       cmd_delete "$2" ;;
    userexists)   cmd_userexists "$2" ;;
    passwd)       cmd_passwd "$2" "$3" ;;
    deluser)      cmd_deluser "$2" ;;
    serverconfig) cmd_serverconfig "$2" "$3" "$4" ;;
    *)
        echo "Usage: dolphin-ftp-share {setup|info|add|delete|userexists|passwd|deluser|serverconfig}" >&2
        echo "" >&2
        echo "Commands:" >&2
        echo "  setup                             Initial Pure-FTPd setup" >&2
        echo "  info                              List all shares" >&2
        echo "  add <name> <path> <acl>           Add/update a share" >&2
        echo "  delete <name>                     Remove a share" >&2
        echo "  userexists <username>              Check if FTP user exists" >&2
        echo "  passwd <username> <password>       Set/create FTP password" >&2
        echo "  deluser <username>                 Delete FTP user (not system user)" >&2
        echo "  serverconfig show                  Show current server config" >&2
        echo "  serverconfig active                Set active mode" >&2
        echo "  serverconfig passive <start> <end> Set passive mode with port range" >&2
        exit 1
        ;;
esac
