From bde27ebfb10d9bdedc6d6cbd4782474482322608 Mon Sep 17 00:00:00 2001 From: TrudeEH Date: Fri, 14 Mar 2025 09:13:55 +0000 Subject: [PATCH] Add new scripts for system monitoring and remove deprecated scripts --- install.sh | 1 + scripts/battery-health.sh | 1 - scripts/{colors.sh => colors} | 0 scripts/{sb-cpu => cpu} | 0 scripts/dm-bluetooth | 412 ------------ scripts/dm-kill | 23 - scripts/dm-mansearch | 18 - scripts/dm-mpd | 76 --- scripts/dm-pass | 60 -- scripts/dm-todo | 28 - scripts/dm-usb-mount | 4 - scripts/dm-usb-poweroff | 3 - scripts/dm-usb-unmount | 3 - scripts/dm-web | 28 - scripts/dm-wifi | 1038 ------------------------------- scripts/{sb-network => neticon} | 8 +- scripts/network.sh | 11 - scripts/{sb-memory => ram} | 0 scripts/sb-battery | 25 - scripts/{sb-volume => volume} | 8 +- 20 files changed, 7 insertions(+), 1740 deletions(-) delete mode 100755 scripts/battery-health.sh rename scripts/{colors.sh => colors} (100%) rename scripts/{sb-cpu => cpu} (100%) delete mode 100755 scripts/dm-bluetooth delete mode 100755 scripts/dm-kill delete mode 100755 scripts/dm-mansearch delete mode 100755 scripts/dm-mpd delete mode 100755 scripts/dm-pass delete mode 100755 scripts/dm-todo delete mode 100755 scripts/dm-usb-mount delete mode 100755 scripts/dm-usb-poweroff delete mode 100755 scripts/dm-usb-unmount delete mode 100755 scripts/dm-web delete mode 100755 scripts/dm-wifi rename scripts/{sb-network => neticon} (62%) delete mode 100755 scripts/network.sh rename scripts/{sb-memory => ram} (100%) delete mode 100755 scripts/sb-battery rename scripts/{sb-volume => volume} (76%) diff --git a/install.sh b/install.sh index 322d9d82..0876fbaf 100755 --- a/install.sh +++ b/install.sh @@ -111,6 +111,7 @@ if [[ "$OSTYPE" != "darwin"* ]]; then sudo ufw limit 22/tcp fi sudo ufw enable + sudo ss -tupln | tee "$HOME/dotfiles/logs/open_ports.log" sudo ufw status numbered | tee "$HOME/dotfiles/logs/ufw_status.log" if [ $? -ne 0 ]; then printf "${RED}Error setting up UFW.${NC}\n" diff --git a/scripts/battery-health.sh b/scripts/battery-health.sh deleted file mode 100755 index 1a89954b..00000000 --- a/scripts/battery-health.sh +++ /dev/null @@ -1 +0,0 @@ -upower -i /org/freedesktop/UPower/devices/* | grep "capacity:" diff --git a/scripts/colors.sh b/scripts/colors similarity index 100% rename from scripts/colors.sh rename to scripts/colors diff --git a/scripts/sb-cpu b/scripts/cpu similarity index 100% rename from scripts/sb-cpu rename to scripts/cpu diff --git a/scripts/dm-bluetooth b/scripts/dm-bluetooth deleted file mode 100755 index 1084403a..00000000 --- a/scripts/dm-bluetooth +++ /dev/null @@ -1,412 +0,0 @@ -#!/usr/bin/env bash -# _ _ _ _ _ _ -# __| |_ __ ___ ___ _ __ _ _ | |__ | |_ _ ___| |_ ___ ___ | |_ | |__ -# / _` | '_ ` _ \ / _ \ '_ \| | | |_____| '_ \| | | | |/ _ \ __/ _ \ / _ \| __|| '_ \ -# | (_| | | | | | | __/ | | | |_| |_____| |_) | | |_| | __/ || (_) | (_) | |_ | | | | -# \__,_|_| |_| |_|\___|_| |_|\__,_| |_.__/|_|\__,_|\___|\__\___/ \___/ \__||_| |_| -# -# Author: Nick Clyde (clydedroid) -# dmenu support by: Layerex -# Original script: https://github.com/nickclyde/rofi-bluetooth -# -# A script that generates a dmenu menu that uses bluetoothctl to -# connect to bluetooth devices and display status info. -# -# Inspired by networkmanager-dmenu (https://github.com/firecat53/networkmanager-dmenu) -# Thanks to x70b1 (https://github.com/polybar/polybar-scripts/tree/master/polybar-scripts/system-bluetooth-bluetoothctl) -# -# Depends on: -# Arch repositories: dmenu, bluez-utils (contains bluetoothctl) - -# Constants -divider="---------" -goback="Back" -exit="Exit" -connected_icon="" - -# Checks if bluetooth controller is powered on -power_on() { - if bluetoothctl show | grep -F -q "Powered: yes"; then - return 0 - else - return 1 - fi -} - -# Toggles power state -toggle_power() { - if power_on; then - bluetoothctl power off - show_menu - else - if rfkill list bluetooth | grep -F -q 'blocked: yes'; then - rfkill unblock bluetooth && sleep 3 - fi - bluetoothctl power on - show_menu - fi -} - -# Checks if controller is scanning for new devices -scan_on() { - if bluetoothctl show | grep -F -q "Discovering: yes"; then - echo "Scan: on" - return 0 - else - echo "Scan: off" - return 1 - fi -} - -# Toggles scanning state -toggle_scan() { - if scan_on; then - kill "$(pgrep -f "bluetoothctl scan on")" - bluetoothctl scan off - show_menu - else - bluetoothctl scan on & - echo "Scanning..." - sleep 5 - show_menu - fi -} - -# Checks if controller is able to pair to devices -pairable_on() { - if bluetoothctl show | grep -F -q "Pairable: yes"; then - echo "Pairable: on" - return 0 - else - echo "Pairable: off" - return 1 - fi -} - -# Toggles pairable state -toggle_pairable() { - if pairable_on; then - bluetoothctl pairable off - show_menu - else - bluetoothctl pairable on - show_menu - fi -} - -# Checks if controller is discoverable by other devices -discoverable_on() { - if bluetoothctl show | grep -F -q "Discoverable: yes"; then - echo "Discoverable: on" - return 0 - else - echo "Discoverable: off" - return 1 - fi -} - -# Toggles discoverable state -toggle_discoverable() { - if discoverable_on; then - bluetoothctl discoverable off - show_menu - else - bluetoothctl discoverable on - show_menu - fi -} - -# Checks if a device is connected -device_connected() { - if bluetoothctl info "$1" | grep -F -q "Connected: yes"; then - return 0 - else - return 1 - fi -} - -# Toggles device connection -toggle_connection() { - if device_connected "$1"; then - bluetoothctl disconnect "$1" - # device_menu "$device" - else - bluetoothctl connect "$1" - # device_menu "$device" - fi -} - -# Checks if a device is paired -device_paired() { - if bluetoothctl info "$1" | grep -F -q "Paired: yes"; then - echo "Paired: yes" - return 0 - else - echo "Paired: no" - return 1 - fi -} - -# Toggles device paired state -toggle_paired() { - if device_paired "$1"; then - bluetoothctl remove "$1" - device_menu "$device" - else - bluetoothctl pair "$1" - device_menu "$device" - fi -} - -# Checks if a device is trusted -device_trusted() { - if bluetoothctl info "$1" | grep -F -q "Trusted: yes"; then - echo "Trusted: yes" - return 0 - else - echo "Trusted: no" - return 1 - fi -} - -# Toggles device connection -toggle_trust() { - if device_trusted "$1"; then - bluetoothctl untrust "$1" - device_menu "$device" - else - bluetoothctl trust "$1" - device_menu "$device" - fi -} - -# Prints a short string with the current bluetooth status -# Useful for status bars like polybar, etc. -print_status() { - if power_on; then - printf '' - - mapfile -t paired_devices < <(bluetoothctl paired-devices | grep -F Device | cut -d ' ' -f 2) - counter=0 - - for device in "${paired_devices[@]}"; do - if device_connected "$device"; then - device_alias="$(bluetoothctl info "$device" | grep -F "Alias" | cut -d ' ' -f 2-)" - - if [ $counter -gt 0 ]; then - printf ", %s" "$device_alias" - else - printf " %s" "$device_alias" - fi - - ((counter++)) - fi - done - printf "\n" - else - echo "" - fi -} - -# A submenu for a specific device that allows connecting, pairing, and trusting -device_menu() { - device="$1" - - # Get device name and mac address - device_name="$(echo "$device" | cut -d ' ' -f 3-)" - mac="$(echo "$device" | cut -d ' ' -f 2)" - - # Build options - if device_connected "$mac"; then - connected="Connected: yes" - else - connected="Connected: no" - fi - paired="$(device_paired "$mac")" - trusted="$(device_trusted "$mac")" - options="$connected\n$paired\n$trusted\n$divider\n$goback\n$exit" - - # Open dmenu menu, read chosen option - chosen="$(echo -e "$options" | run_dmenu "$device_name")" - - # Match chosen option to command - case $chosen in - "" | "$divider") - echo "No option chosen." - ;; - "$connected") - toggle_connection "$mac" - ;; - "$paired") - toggle_paired "$mac" - ;; - "$trusted") - toggle_trust "$mac" - ;; - "$goback") - show_menu - ;; - esac -} - -# Opens a dmenu menu with current bluetooth status and options to connect -show_menu() { - # Get menu options - if power_on; then - power="Power: on" - - # Human-readable names of devices, one per line - # If scan is off, will only list paired devices - if [[ -n "$connected_icon" ]]; then - devices="$(bluetoothctl devices | grep -F Device | while read -r device; do - device_name="$(echo "$device" | cut -d ' ' -f 3-)" - mac="$(echo "$device" | cut -d ' ' -f 2)" - icon="" - - if device_connected "$mac" && [[ -n $connected_icon ]]; then - icon=" $connected_icon" - fi - - echo "$device_name${icon}" - done)" - else - devices="$(bluetoothctl devices | grep -F Device | cut -d ' ' -f 3-)" - fi - - # Get controller flags - scan="$(scan_on)" - pairable="$(pairable_on)" - discoverable="$(discoverable_on)" - - # Options passed to dmenu - [[ -n $devices ]] && devices_part="$devices\n$divider\n" - options="$devices_part$power\n$scan\n$pairable\n$discoverable\n$exit" - else - power="Power: off" - options="$power\n$exit" - fi - - # Open dmenu menu, read chosen option - chosen="$(echo -e "$options" | run_dmenu "Bluetooth")" - - # Match chosen option to command - case $chosen in - "" | "$divider") - echo "No option chosen." - ;; - "$power") - toggle_power - ;; - "$scan") - toggle_scan - ;; - "$discoverable") - toggle_discoverable - ;; - "$pairable") - toggle_pairable - ;; - *) - if [[ -n "$connected_icon" ]]; then - chosen="${chosen%% ${connected_icon}}" - fi - device="$(bluetoothctl devices | grep -F "$chosen")" - # Open a submenu if a device is selected - if [[ -n "$device" ]]; then device_menu "$device"; fi - ;; - esac -} - -# dmenu command to pipe into. Extra arguments to dmenu-bluetooth are passed through to dmenu. This -# allows the user to set fonts, sizes, colours, etc. -DMENU_BLUETOOTH_LAUNCHER="${DMENU_BLUETOOTH_LAUNCHER:-dmenu}" -run_dmenu() { - case "$DMENU_BLUETOOTH_LAUNCHER" in - rofi) - DMENU_BLUETOOTH_LAUNCHER="rofi -dmenu" - ;; - fuzzel) - DMENU_BLUETOOTH_LAUNCHER="fuzzel --dmenu" - ;; - esac - $DMENU_BLUETOOTH_LAUNCHER -i -p "$DMENU_BLUETOOTH_PROMPT" "-l" "20" "${dmenu_args[@]}" -} - -print_help() { - echo "usage: $0 [--help] [--status] [--connected-icon [ICON]] [PROMPT] DMENU_ARGS..." - echo "" - echo "A script that generates a dmenu menu that uses bluetoothctl to connect to bluetooth devices and display status info." - echo "" - echo "positional arguments:" - echo " PROMPT dmenu prompt" - echo " DMENU_ARGS... arguments passed to dmenu" - echo "" - echo "options:" - echo "--help show this help message and exit" - echo "--status print a short string about current bluetooth status and exit" - echo "--connected-icon [ICON] add icon on device list next to connected devices" - echo "" - echo "environment variables:" - echo " DMENU_BLUETOOTH_PROMPT dmenu prompt" - echo " DMENU_BLUETOOTH_LAUNCHER command to use instead of 'dmenu'" - echo "" - echo "Positional arguments have to be placed after all other arguments." - echo "A PROMPT positional argument will be interpreted as part of DMENU_ARGS if it starts with '-'. It won't be parsed if the DMENU_BLUETOOTH_PROMPT environment variable is set." - echo "Use the DMENU_BLUETOOTH_LAUNCHER environment variable to use launchers other than dmenu. Rofi, fuzzel, and any dmenu-compatible launchers are supported." -} - -command_present() { - command -v "$1" >/dev/null 2>&1 -} - -error() { - echo "$1. $2." >&2 - command_present notify-send && notify-send "$1" "$2." -} - -# Check if bluetooth daemon is running. Start it if possible. -if command_present systemctl; then - systemctl is-active --quiet bluetooth - case $? in - 3) - error "Bluetooth daemon is not running" "Start it to use this script" - systemctl start bluetooth || exit 3 - ;; - 4) - error "Bluetooth daemon is not present" "On Arch Linux install bluez and bluez-utils packages" - exit 4 - ;; - esac -fi - -dmenu_args=("$@") -case "$1" in - --help) - print_help - exit - ;; - --status) - print_status - exit - ;; - --connected-icon) - if [[ "$2" == "--" ]]; then - connected_icon="" - else - connected_icon="$2" - fi - dmenu_args=("${dmenu_args[@]:2}") - ;; -esac -case "${dmenu_args[0]}" in - -*) - ;; - *) - if [[ -z "$DMENU_BLUETOOTH_PROMPT" ]]; then - DMENU_BLUETOOTH_PROMPT="${dmenu_args[0]}" - dmenu_args=("${dmenu_args[@]:1}") - fi - ;; -esac - -show_menu diff --git a/scripts/dm-kill b/scripts/dm-kill deleted file mode 100755 index eb47e813..00000000 --- a/scripts/dm-kill +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -# dmenu theming -lines="-l 20" - -selected="$(ps -a -u $USER | \ - dmenu -i -p "Type to search and select process to kill" \ - $lines | \ - awk '{print $1" "$4}')"; - -if [[ ! -z $selected ]]; then - - answer="$(echo -e "Yes\nNo" | \ - dmenu -i -p "$selected will be killed, are you sure?" \ - $lines )" - - if [[ $answer == "Yes" ]]; then - selpid="$(awk '{print $1}' <<< $selected)"; - kill -9 $selpid - fi -fi - -exit 0 diff --git a/scripts/dm-mansearch b/scripts/dm-mansearch deleted file mode 100755 index c65bfd61..00000000 --- a/scripts/dm-mansearch +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -prompt="-p Manual:" - -# terminal to open manual -terminal="st" - -# list all manuals -manual="$(man -k . | dmenu $prompt | awk '{print $1}')" - -# open selected manual with terminal -if [[ ! -z "$manual" ]]; then - eval "$($terminal -e man $manual)" -fi - -exit 0 - - diff --git a/scripts/dm-mpd b/scripts/dm-mpd deleted file mode 100755 index d32d9576..00000000 --- a/scripts/dm-mpd +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/bash - -all_name='[ALL]' -mode=library - -d_artist() { - mpc list artist | sort -f | dmenu -p artist "${dmenu_args[@]}" -} - -d_album() { - local artist="$1" - local albums - - mapfile -t albums < <(mpc list album artist "$artist") - if (( ${#albums[@]} > 1 )) ; then - { - printf '%s\n' "$all_name" - printf '%s\n' "${albums[@]}" | sort -f - } | dmenu -p album "${dmenu_args[@]}" - else - # We only have one album, so just use that. - printf '%s\n' "${albums[0]}" - fi -} - -d_playlist() { - local format="%position% %title%" - local extra_format="(%artist% - %album%)" - local track - local num_extras - - # If all tracks are from the same artist and album, no need to display that - num_extras=$(mpc playlist -f "$extra_format" | sort | uniq | wc -l) - (( num_extras == 1 )) || format+=" $extra_format" - - track=$(mpc playlist -f "$format" | dmenu -p track "${dmenu_args[@]}") - printf '%s' "${track%% *}" -} - -i=2 - -for arg do - if [[ $arg == :: ]]; then - dmenu_args=( "${@:$i}" ) - break - fi - - case "$arg" in - -l) mode=library ;; - -p) mode=playlist ;; - esac - - let i++ -done - -case "$mode" in - library) - artist=$(d_artist) - [[ $artist ]] || exit 1 - - album=$(d_album "$artist") - [[ $album ]] || exit 2 - - mpc clear - if [[ $album == "$all_name" ]]; then - mpc find artist "$artist" | sort | mpc add - else - mpc find artist "$artist" album "$album" | sort | mpc add - fi - - mpc play >/dev/null - ;; - playlist) - mpc play "$(d_playlist)" >/dev/null - ;; -esac diff --git a/scripts/dm-pass b/scripts/dm-pass deleted file mode 100755 index 38472199..00000000 --- a/scripts/dm-pass +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env bash - -shopt -s nullglob globstar - -typeit=0 -if [[ $1 == "--type" ]]; then - typeit=1 - shift -fi - - -STARTDIR=${PASSWORD_STORE_DIR-~/.password-store} -BASEDIR=$STARTDIR -DONE=0 -LEVEL=0 -PREVSELECTION="" -SELECTION="" - -while [ "$DONE" -eq 0 ] ; do - password_files=( "$STARTDIR"/* ) - password_files=( "${password_files[@]#"$STARTDIR"/}" ) - password_files=( "${password_files[@]%.gpg}" ) - - if [ "$LEVEL" -ne 0 ] ; then - password_files=(".." "${password_files[@]}") - fi - entry=$(printf '%s\n' "${password_files[@]}" | dmenu "$@" -l 15) - - echo "entry: $entry" - if [ -z "$entry" ] ; then - DONE=1 - exit - fi - - if [ "$entry" != ".." ] ; then - PREVSELECTION=$SELECTION - SELECTION="$SELECTION/$entry" - - # check if another dir - if [ -d "$STARTDIR/$entry" ] ; then - STARTDIR="$STARTDIR/$entry" - LEVEL=$((LEVEL+1)) - else - # not a directory so it must be a real password entry - - if [[ $typeit -eq 0 ]]; then - pass show -c "$SELECTION" 2>/dev/null - else - xdotool - <<<"type --clearmodifiers -- $(pass show "$SELECTION" | head -n 1)" - fi - DONE=1 - fi - - else - LEVEL=$((LEVEL-1)) - SELECTION=$PREVSELECTION - STARTDIR="$BASEDIR/$SELECTION" - fi -done - diff --git a/scripts/dm-todo b/scripts/dm-todo deleted file mode 100755 index 17d74153..00000000 --- a/scripts/dm-todo +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Write/remove a task to do later. -# -# Select an existing entry to remove it from the file, or type a new entry to -# add it. -# - -file="$HOME/.todo" -touch "$file" -height=$(wc -l "$file" | awk '{print $1}') -prompt="Add/delete a task: " - -cmd=$(dmenu -l "$height" -p "$prompt" "$@" < "$file") -while [ -n "$cmd" ]; do - if grep -q "^$cmd\$" "$file"; then - grep -v "^$cmd\$" "$file" > "$file.$$" - mv "$file.$$" "$file" - height=$(( height - 1 )) - else - echo "$cmd" >> "$file" - height=$(( height + 1 )) - fi - - cmd=$(dmenu -l "$height" -p "$prompt" "$@" < "$file") -done - -exit 0 diff --git a/scripts/dm-usb-mount b/scripts/dm-usb-mount deleted file mode 100755 index c59eb86c..00000000 --- a/scripts/dm-usb-mount +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -udisksctl mount -b $(lsblk -lp | awk '/part/ {print $1, "(" $4 ")"}' | dmenu -p mount) - diff --git a/scripts/dm-usb-poweroff b/scripts/dm-usb-poweroff deleted file mode 100755 index 4e626ae5..00000000 --- a/scripts/dm-usb-poweroff +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -udisksctl power-off -b $(lsblk -lp | awk '/part/ {print $1, "(" $4 ")"}' | dmenu -p poweroff) diff --git a/scripts/dm-usb-unmount b/scripts/dm-usb-unmount deleted file mode 100755 index 1fc47e87..00000000 --- a/scripts/dm-usb-unmount +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -udisksctl unmount -b $(lsblk -lp | awk '/part/ {print $1, "(" $4 ")"}' | dmenu -p unmount) diff --git a/scripts/dm-web b/scripts/dm-web deleted file mode 100755 index 10cda6e5..00000000 --- a/scripts/dm-web +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -engine="https://www.google.com/search?q=" - -declare -A bookmarks=( - ["YouTube"]="https://www.youtube.com/" - ["GitHub"]="https://github.com/TrudeEH/dotfiles" - ["TrudeWeb"]="https://trudeeh.github.io/web/" - ["Gemini"]="https://gemini.google.com/app" - ["Element"]="https://app.element.io/#/home" - ["Gmail"]="https://mail.google.com/mail/u/0/#inbox" - ["Google Messages"]="https://messages.google.com/web/conversations" - ["WOL"]="https://wol.jw.org/pt-PT/" - ["Discord"]="https://discord.com/app" -) - -choice=$(printf "%s\n" "${!bookmarks[@]}" | dmenu -i -p "Search:") - -if [[ -n "$choice" ]]; then - # Find the matching URL - url=${bookmarks[$choice]} - - if [[ -n "$url" ]]; then - xdg-open $url - else - xdg-open $engine$choice - fi -fi diff --git a/scripts/dm-wifi b/scripts/dm-wifi deleted file mode 100755 index 9ae652d2..00000000 --- a/scripts/dm-wifi +++ /dev/null @@ -1,1038 +0,0 @@ -#!/usr/bin/env python3 -# encoding:utf8 -"""NetworkManager command line dmenu script. - -To add new connections or enable/disable networking requires policykit -permissions setup per: -https://wiki.archlinux.org/index.php/NetworkManager#Set_up_PolicyKit_permissions - -OR running the script as root - -Add dmenu options and default terminal if desired to -~/.config/networkmanager-dmenu/config.ini - -""" -import pathlib -import struct -import configparser -import locale -import os -from os.path import basename, expanduser -import shlex -from shutil import which -import sys -from time import sleep -import uuid -import subprocess - -# pylint: disable=import-error -import gi -gi.require_version('NM', '1.0') -from gi.repository import GLib, NM # noqa pylint: disable=wrong-import-position -# pylint: enable=import-error - -ENV = os.environ.copy() -ENC = locale.getpreferredencoding() - -CONF = configparser.ConfigParser() -CONF.read(expanduser("~/.config/networkmanager-dmenu/config.ini")) - - -def cli_args(): - """ Don't override dmenu_cmd function arguments with CLI args. Removes -l - and -p if those are passed on the command line. - - Exception: if -l is passed and dmenu_command is not defined, assume that the - user wants to switch dmenu to the vertical layout and include -l. - - Returns: List of additional CLI arguments - - """ - args = sys.argv[1:] - cmd = CONF.get('dmenu', 'dmenu_command', fallback=False) - if "-l" in args or "-p" in args: - for nope in ['-l', '-p'] if cmd is not False else ['-p']: - try: - nope_idx = args.index(nope) - del args[nope_idx] - del args[nope_idx] - except ValueError: - pass - return args - - -def dmenu_pass(command, color): - """Check if dmenu passphrase patch is applied and return the correct command - line arg list - - Args: command - string - color - obscure color string - Returns: list or None - - """ - if command != 'dmenu': - return None - try: - # Check for dmenu password patch - dm_patch = b'P' in subprocess.run(["dmenu", "-h"], - capture_output=True, - check=False).stderr - except FileNotFoundError: - dm_patch = False - return ["-P"] if dm_patch else ["-nb", color, "-nf", color] - - -def dmenu_cmd(num_lines, prompt="Networks", active_lines=None): - """Parse config.ini for menu options - - Args: args - num_lines: number of lines to display - prompt: prompt to show - active_lines: list of line numbers to tag as active - Returns: command invocation (as a list of strings) for example - ["dmenu", "-l", "", "-p", "", "-i"] - - """ - # Create command string - commands = {"dmenu": ["-l", "20", "-p", str(prompt)], - "rofi": ["-dmenu", "-p", str(prompt)], - "bemenu": ["-p", str(prompt)], - "wofi": ["-p", str(prompt)], - "fuzzel": ["-p", str(prompt), "--log-level", "none"]} - command = shlex.split(CONF.get('dmenu', 'dmenu_command', fallback="dmenu")) - cmd_base = basename(command[0]) - command.extend(cli_args()) - command.extend(commands.get(cmd_base, [])) - # Highlighting - highlight = CONF.getboolean('dmenu', 'highlight', fallback=False) - if highlight is True: - # Rofi - if cmd_base == "rofi" and active_lines: - command.extend(["-a", ",".join([str(num) for num in active_lines])]) - # Wofi - if cmd_base == "wofi" and active_lines: - # add '-q' to prevent tag name and properties of pango markup from searchable - command.extend(["-m", "-q"]) - # Passphrase prompts - obscure = CONF.getboolean('dmenu_passphrase', 'obscure', fallback=False) - if prompt == "Passphrase" and obscure is True: - obscure_color = CONF.get('dmenu_passphrase', 'obscure_color', fallback='#222222') - pass_prompts = {"dmenu": dmenu_pass(cmd_base, obscure_color), - "rofi": ['-password'], - "bemenu": ['-x'], - "wofi": ['-P'], - "fuzzel": ['--password']} - command.extend(pass_prompts.get(cmd_base, [])) - return command - - -def choose_adapter(client): - """If there is more than one wifi adapter installed, ask which one to use - - """ - devices = client.get_devices() - devices = [i for i in devices if i.get_device_type() == NM.DeviceType.WIFI] - if not devices: - return None - if len(devices) == 1: - return devices[0] - device_names = "\n".join([d.get_iface() for d in devices]) - sel = subprocess.run(dmenu_cmd(len(devices), "CHOOSE ADAPTER:"), - capture_output=True, - check=False, - env=ENV, - input=device_names, - encoding=ENC).stdout - if not sel.strip(): - sys.exit() - devices = [i for i in devices if i.get_iface() == sel.strip()] - if len(devices) != 1: - raise ValueError(f"Selection was ambiguous: '{str(sel.strip())}'") - return devices[0] - - -def is_installed(cmd): - """Check if a utility is installed""" - return which(cmd) is not None - - -def is_running(cmd): - try: - subprocess.check_output(["pidof", cmd]) - except subprocess.CalledProcessError: - return False - else: - return True - - -def bluetooth_get_enabled(): - """Check if bluetooth is enabled. Try bluetoothctl first, then rfkill. - - Returns None if no bluetooth device was found. - """ - if is_installed('bluetoothctl') and is_running('bluetoothd'): - # Times out in 2 seconds, otherwise bluetoothctl will hang if bluetooth - # service isn't running. - try: - res = subprocess.run(['bluetoothctl', 'show'], - timeout=2, - capture_output=True, - text=True) - return "Powered: yes" in res.stdout - except subprocess.TimeoutExpired: - pass - # See https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-rfkill - for path in pathlib.Path('/sys/class/rfkill/').glob('rfkill*'): - if (path / 'type').read_text().strip() == 'bluetooth': - return (path / 'soft').read_text().strip() == '0' - return None - - -def create_other_actions(client): - """Return list of other actions that can be taken - - """ - networking_enabled = client.networking_get_enabled() - networking_action = "Disable" if networking_enabled else "Enable" - - wifi_enabled = client.wireless_get_enabled() - wifi_action = "Disable" if wifi_enabled else "Enable" - - bluetooth_enabled = bluetooth_get_enabled() - bluetooth_action = "Disable" if bluetooth_enabled else "Enable" - - actions = [Action(f"{wifi_action} Wifi", toggle_wifi, - not wifi_enabled), - Action(f"{networking_action} Networking", - toggle_networking, not networking_enabled)] - if bluetooth_enabled is not None: - actions.append(Action(f"{bluetooth_action} Bluetooth", - toggle_bluetooth, not bluetooth_enabled)) - actions += [Action("Launch Connection Manager", launch_connection_editor), - Action("Delete a Connection", delete_connection)] - if wifi_enabled: - actions.append(Action("Rescan Wifi Networks", rescan_wifi)) - return actions - - -def rescan_wifi(): - """ - Rescan Wifi Access Points - """ - delay = CONF.getint('nmdm', 'rescan_delay', fallback=5) - for dev in CLIENT.get_devices(): - if gi.repository.NM.DeviceWifi == type(dev): - try: - dev.request_scan_async(None, rescan_cb, None) - LOOP.run() - sleep(delay) - notify("Wifi scan complete") - main() - except gi.repository.GLib.Error as err: - # Too frequent rescan error - notify("Wifi rescan failed", urgency="critical") - if not err.code == 6: # pylint: disable=no-member - raise err - - -def rescan_cb(dev, res, data): - """Callback for rescan_wifi. Just for notifications - - """ - if dev.request_scan_finish(res) is True: - notify("Wifi scan running...") - else: - notify("Wifi scan failed", urgency="critical") - LOOP.quit() - - -def ssid_to_utf8(nm_ap): - """ Convert binary ssid to utf-8 """ - ssid = nm_ap.get_ssid() - if not ssid: - return "" - ret = NM.utils_ssid_to_utf8(ssid.get_data()) - return ret - - -def prompt_saved(saved_cons): - """Prompt for a saved connection.""" - actions = create_saved_actions(saved_cons) - sel = get_selection(actions) - sel() - - -def ap_security(nm_ap): - """Parse the security flags to return a string with 'WPA2', etc. """ - flags = nm_ap.get_flags() - wpa_flags = nm_ap.get_wpa_flags() - rsn_flags = nm_ap.get_rsn_flags() - sec_str = "" - if ((flags & getattr(NM, '80211ApFlags').PRIVACY) and - (wpa_flags == 0) and (rsn_flags == 0)): - sec_str = " WEP" - if wpa_flags: - sec_str = " WPA1" - if rsn_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_PSK: - sec_str += " WPA2" - if rsn_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_SAE: - sec_str += " WPA3" - if ((wpa_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_802_1X) or - (rsn_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_802_1X)): - sec_str += " 802.1X" - if ((wpa_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_OWE) or - (rsn_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_OWE)): - sec_str += " OWE" - - # If there is no security use "--" - if sec_str == "": - sec_str = "--" - return sec_str.lstrip() - - -class Action(): # pylint: disable=too-few-public-methods - """Helper class to execute functions from a string variable""" - def __init__(self, - name, - func, - args=None, - active=False): - self.name = name - self.func = func - self.is_active = active - if args is None: - self.args = None - elif isinstance(args, list): - self.args = args - else: - self.args = [args] - - def __str__(self): - return self.name - - def __call__(self): - if self.args is None: - self.func() - else: - self.func(*self.args) - - -def conn_matches_adapter(conn, adapter): - """Return True if the connection is applicable for the given adapter. - - There seem to be two ways for a connection specify what interface it belongs - to: - - - By setting 'mac-address' in [wifi] to the adapter's MAC - - By setting 'interface-name` in [connection] to the adapter's name. - - Depending on how the connection was added, it seems like either - 'mac-address', 'interface-name' or neither of both is set. - """ - # [wifi] mac-address - setting_wireless = conn.get_setting_wireless() - mac = setting_wireless.get_mac_address() - if mac is not None: - return mac == adapter.get_permanent_hw_address() - - # [connection] interface-name - setting_connection = conn.get_setting_connection() - interface = setting_connection.get_interface_name() - if interface is not None: - return interface == adapter.get_iface() - - # Neither is set, let's assume this connection is for multiple/all adapters. - return True - - -def process_ap(nm_ap, is_active, adapter): - """Activate/Deactivate a connection and get password if required""" - if is_active: - CLIENT.deactivate_connection_async(nm_ap, None, deactivate_cb, nm_ap) - LOOP.run() - else: - conns_cur = [i for i in CONNS if - i.get_setting_wireless() is not None and - conn_matches_adapter(i, adapter)] - con = nm_ap.filter_connections(conns_cur) - if len(con) > 1: - raise ValueError("There are multiple connections possible") - - if len(con) == 1: - CLIENT.activate_connection_async(con[0], adapter, nm_ap.get_path(), - None, activate_cb, nm_ap) - LOOP.run() - else: - if ap_security(nm_ap) != "--": - password = get_passphrase() - else: - password = "" - set_new_connection(nm_ap, password, adapter) - - -def activate_cb(dev, res, data): - """Notification if activate connection completed successfully - - """ - try: - conn = dev.activate_connection_finish(res) - except GLib.Error: - conn = None - if conn is not None: - notify(f"Activated {conn.get_id()}") - else: - notify(f"Problem activating {data.get_id()}", urgency="critical") - LOOP.quit() - - -def deactivate_cb(dev, res, data): - """Notification if deactivate connection completed successfully - - """ - if dev.deactivate_connection_finish(res) is True: - notify(f"Deactivated {data.get_id()}") - else: - notify(f"Problem deactivating {data.get_id()}", urgency="critical") - LOOP.quit() - - -def process_vpngsm(con, activate): - """Activate/deactive VPN or GSM connections""" - if activate: - CLIENT.activate_connection_async(con, None, None, - None, activate_cb, con) - else: - CLIENT.deactivate_connection_async(con, None, deactivate_cb, con) - LOOP.run() - -def strength_bars(signal_strength): - bars = NM.utils_wifi_strength_bars(signal_strength) - wifi_chars = CONF.get("dmenu", "wifi_chars", fallback=False) - if wifi_chars: - bars = "".join([wifi_chars[i] for i, j in enumerate(bars) if j == '*']) - return bars - - -def strength_icon(signal_strength): - wifi_icons = CONF.get("dmenu", "wifi_icons", fallback=False) - if wifi_icons: - return wifi_icons[round(signal_strength / 100 * (len(wifi_icons) - 1))] - return "" - - -def create_ap_actions(aps, active_ap, active_connection, adapter): # noqa pylint: disable=too-many-locals,line-too-long - """For each AP in a list, create the string and its attached function - (activate/deactivate) - - """ - active_ap_bssid = active_ap.get_bssid() if active_ap is not None else "" - - names = [ssid_to_utf8(ap) for ap in aps] - max_len_name = max([len(name) for name in names]) if names else 0 - secs = [ap_security(ap) for ap in aps] - max_len_sec = max([len(sec) for sec in secs]) if secs else 0 - - ap_actions = [] - - if CONF.getboolean("dmenu", "compact", fallback=False): - format = CONF.get("dmenu", "format", fallback="{name} {sec} {bars}") - else: - format = CONF.get("dmenu", "format", fallback="{name:<{max_len_name}s} {sec:<{max_len_sec}s} {bars:>4}") - - for nm_ap, name, sec in zip(aps, names, secs): - is_active = nm_ap.get_bssid() == active_ap_bssid - signal_strength = nm_ap.get_strength() - bars = strength_bars(signal_strength) - icon = strength_icon(signal_strength) - action_name = format.format(name=name, sec=sec, signal=signal_strength, bars=bars, icon=icon, - max_len_name=max_len_name, max_len_sec=max_len_sec) - if is_active: - ap_actions.append(Action(action_name, process_ap, - [active_connection, True, adapter], - active=True)) - else: - ap_actions.append(Action(action_name, process_ap, - [nm_ap, False, adapter])) - return ap_actions - - -def create_vpn_actions(vpns, active): - """Create the list of strings to display with associated function - (activate/deactivate) for VPN connections. - - """ - active_vpns = [i for i in active if i.get_vpn()] - return _create_vpngsm_actions(vpns, active_vpns, "VPN") - - -def create_vlan_actions(vlans, active): - """Create the list of strings to display with associated function - (activate/deactivate) for VLAN connections. - - """ - active_vlans = [i for i in active if "vlan" == i.get_connection_type()] - return _create_vpngsm_actions(vlans, active_vlans, "VLAN") - - -def create_wireguard_actions(wgs, active): - """Create the list of strings to display with associated function - (activate/deactivate) for Wireguard connections. - - """ - active_wgs = [i for i in active if i.get_connection_type() == "wireguard"] - return _create_vpngsm_actions(wgs, active_wgs, "Wireguard") - - -def create_eth_actions(eths, active): - """Create the list of strings to display with associated function - (activate/deactivate) for Ethernet connections. - - """ - active_eths = [i for i in active if 'ethernet' in i.get_connection_type()] - return _create_vpngsm_actions(eths, active_eths, "Eth") - - -def create_gsm_actions(gsms, active): - """Create the list of strings to display with associated function - (activate/deactivate) GSM connections.""" - active_gsms = [i for i in active if - i.get_connection() is not None and - i.get_connection().is_type(NM.SETTING_GSM_SETTING_NAME)] - return _create_vpngsm_actions(gsms, active_gsms, "GSM") - - -def create_blue_actions(blues, active): - """Create the list of strings to display with associated function - (activate/deactivate) Bluetooth connections.""" - active_blues = [i for i in active if - i.get_connection() is not None and - i.get_connection().is_type(NM.SETTING_BLUETOOTH_SETTING_NAME)] - return _create_vpngsm_actions(blues, active_blues, "Bluetooth") - - -def create_saved_actions(saved): - """Create the list of strings to display with associated function - (activate/deactivate) for VPN connections. - - """ - return _create_vpngsm_actions(saved, [], "SAVED") - - -def _create_vpngsm_actions(cons, active_cons, label): - active_con_ids = [a.get_id() for a in active_cons] - actions = [] - for con in cons: - is_active = con.get_id() in active_con_ids - action_name = f"{con.get_id()}:{label}" - if is_active: - active_connection = [a for a in active_cons - if a.get_id() == con.get_id()] - if len(active_connection) != 1: - raise ValueError(f"Multiple active connections match {con.get_id()}") - active_connection = active_connection[0] - - actions.append(Action(action_name, process_vpngsm, - [active_connection, False], active=True)) - else: - actions.append(Action(action_name, process_vpngsm, - [con, True])) - return actions - - -def create_wwan_actions(client): - """Create WWWAN actions - - """ - wwan_enabled = client.wwan_get_enabled() - wwan_action = "Disable" if wwan_enabled else "Enable" - return [Action(f"{wwan_action} WWAN", toggle_wwan, not wwan_enabled)] - - -def combine_actions(eths, aps, vlans, vpns, wgs, gsms, blues, wwan, others, saved): - # pylint: disable=too-many-arguments - """Combine all given actions into a list of actions. - - Args: args - eths: list of Actions - aps: list of Actions - vpns: list of Actions - gsms: list of Actions - blues: list of Actions - wwan: list of Actions - others: list of Actions - """ - compact = CONF.getboolean("dmenu", "compact", fallback=False) - empty_action = [Action('', None)] if not compact else [] - all_actions = [] - all_actions += eths + empty_action if eths else [] - all_actions += aps + empty_action if aps else [] - all_actions += vlans + empty_action if vlans else [] - all_actions += vpns + empty_action if vpns else [] - all_actions += wgs + empty_action if wgs else [] - all_actions += gsms + empty_action if (gsms and wwan) else [] - all_actions += blues + empty_action if blues else [] - all_actions += wwan + empty_action if wwan else [] - all_actions += others + empty_action if others else [] - all_actions += saved + empty_action if saved else [] - return all_actions - - -def get_wofi_highlight_markup(action): - highlight_fg = CONF.get('dmenu', 'highlight_fg', fallback=None) - highlight_bg = CONF.get('dmenu', 'highlight_bg', fallback=None) - highlight_bold = CONF.getboolean('dmenu', 'highlight_bold', fallback=True) - - style = "" - if highlight_fg: - style += f'foreground="{highlight_fg}" ' - if highlight_bg: - style += f'background="{highlight_bg}" ' - if highlight_bold: - style += 'weight="bold" ' - - return f"" + str(action) + "" - - -def get_selection(all_actions): - """Spawn dmenu for selection and execute the associated action.""" - command = shlex.split(CONF.get("dmenu", "dmenu_command", fallback="dmenu")) - cmd_base = basename(command[0]) - active_chars = CONF.get("dmenu", "active_chars", fallback="==") - highlight = CONF.getboolean("dmenu", "highlight", fallback=False) - inp = [] - - if highlight is True and cmd_base == "rofi": - inp = [str(action) for action in all_actions] - elif highlight is True and cmd_base == "wofi": - inp = [get_wofi_highlight_markup(action) if action.is_active else str(action) - for action in all_actions] - else: - inp = [(active_chars if action.is_active else " " * len(active_chars)) + " " + str(action) - for action in all_actions] - active_lines = [index for index, action in enumerate(all_actions) - if action.is_active] - - command = dmenu_cmd(len(inp), active_lines=active_lines) - sel = subprocess.run(command, - capture_output=True, - check=False, - input="\n".join(inp), - encoding=ENC, - env=ENV).stdout - - if not sel.rstrip(): - sys.exit() - - if highlight is True and cmd_base == "rofi": - action = [i for i in all_actions if str(i).strip() == sel.strip()] - elif highlight is True and cmd_base == "wofi": - action = [i for i in all_actions - if str(i).strip() == sel.strip() or - get_wofi_highlight_markup(i) == sel.strip()] - else: - action = [i for i in all_actions - if ((str(i).strip() == str(sel.strip()) - and not i.is_active) or - (active_chars + " " + str(i) == str(sel.rstrip('\n')) - and i.is_active))] - if len(action) != 1: - raise ValueError(f"Selection was ambiguous: '{str(sel.strip())}'") - return action[0] - - -def toggle_networking(enable): - """Enable/disable networking - - Args: enable - boolean - - """ - toggle = GLib.Variant.new_tuple(GLib.Variant.new_boolean(enable)) - try: - CLIENT.dbus_call(NM.DBUS_PATH, NM.DBUS_INTERFACE, "Enable", toggle, - None, -1, None, None, None) - except AttributeError: - # Workaround for older versions of python-gobject - CLIENT.networking_set_enabled(enable) - notify(f"Networking {'enabled' if enable is True else 'disabled'}") - - -def toggle_wifi(enable): - """Enable/disable Wifi - - Args: enable - boolean - - """ - toggle = GLib.Variant.new_boolean(enable) - try: - CLIENT.dbus_set_property(NM.DBUS_PATH, NM.DBUS_INTERFACE, "WirelessEnabled", toggle, - -1, None, None, None) - except AttributeError: - # Workaround for older versions of python-gobject - CLIENT.wireless_set_enabled(enable) - notify(f"Wifi {'enabled' if enable is True else 'disabled'}") - - -def toggle_wwan(enable): - """Enable/disable WWAN - - Args: enable - boolean - - """ - toggle = GLib.Variant.new_boolean(enable) - try: - CLIENT.dbus_set_property(NM.DBUS_PATH, NM.DBUS_INTERFACE, "WwanEnabled", toggle, - -1, None, None, None) - except AttributeError: - # Workaround for older versions of python-gobject - CLIENT.wwan_set_enabled(enable) - notify(f"Wwan {'enabled' if enable is True else 'disabled'}") - - -def toggle_bluetooth(enable): - """Enable/disable Bluetooth - - Try bluetoothctl first, then drop to rfkill if it's not installed or - bluetooth service isn't running. - - Args: enable - boolean - - References: - https://github.com/blueman-project/blueman/blob/master/blueman/plugins/mechanism/RfKill.py - https://www.kernel.org/doc/html/latest/driver-api/rfkill.html - https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/uapi/linux/rfkill.h?h=v5.8.9 - - """ - if is_installed('bluetoothctl') and is_running('bluetoothd'): - # Times out in 2 seconds, otherwise bluetoothctl will hang if bluetooth - # service isn't running. - try: - res = subprocess.run(['bluetoothctl', 'power', 'on' if enable is True else 'off'], - timeout=2, - capture_output=True) - except subprocess.TimeoutExpired: - pass - try: - res = subprocess.run(['bluetoothctl', 'show'], - timeout=2, - capture_output=True, - text=True) - if "Powered: yes" in res.stdout: - notify("Bluetooth enabled") - return - except subprocess.TimeoutExpired: - pass - # Now try using rfkill - type_bluetooth = 2 - op_change_all = 3 - idx = 0 - soft_state = 0 if enable else 1 - hard_state = 0 - - data = struct.pack("IBBBB", idx, type_bluetooth, op_change_all, - soft_state, hard_state) - - try: - with open('/dev/rfkill', 'r+b', buffering=0) as rff: - rff.write(data) - except PermissionError: - notify("Lacking permission to write to /dev/rfkill.", - "Check README for configuration options.", - urgency="critical") - else: - notify(f"Bluetooth {'enabled' if enable else 'disabled'}") - - -def launch_connection_editor(): - """Launch nmtui or the gui nm-connection-editor - - """ - terminal = CONF.get("editor", "terminal", fallback="xterm") - gui_if_available = CONF.getboolean("editor", "gui_if_available", fallback=True) - gui = CONF.get("editor", "gui", fallback="nm-connection-editor") - if gui_if_available is True: - if is_installed(gui): - subprocess.run(gui, check=False) - return - if is_installed("nmtui"): - subprocess.run([terminal, "-e", "nmtui"], check=False) - return - notify("No network connection editor installed", urgency="critical") - - -def get_passphrase(): - """Get a password - - Returns: string - - """ - pinentry = CONF.get("dmenu", "pinentry", fallback=None) - if pinentry: - description = CONF.get("pinentry", "description", fallback="Get network password") - prompt = CONF.get("pinentry", "prompt", fallback="Password: ") - pin = "" - out = subprocess.run(pinentry, - capture_output=True, - check=False, - encoding=ENC, - input=f"setdesc {description}\nsetprompt {prompt}\ngetpin\n").stdout - if out: - res = [i for i in out.split("\n") if i.startswith("D ")] - if res and res[0].startswith("D "): - pin = res[0].split("D ")[1] - return pin - return subprocess.run(dmenu_cmd(0, "Passphrase"), - stdin=subprocess.DEVNULL, - capture_output=True, - check=False, - encoding=ENC).stdout - - -def delete_connection(): - """Display list of NM connections and delete the selected one - - """ - conn_acts = [Action(i.get_id(), i.delete_async, args=[None, delete_cb, None]) for i in CONNS] - conn_names = "\n".join([str(i) for i in conn_acts]) - sel = subprocess.run(dmenu_cmd(len(conn_acts), "CHOOSE CONNECTION TO DELETE:"), - capture_output=True, - check=False, - input=conn_names, - encoding=ENC, - env=ENV).stdout - if not sel.strip(): - sys.exit() - action = [i for i in conn_acts if str(i) == sel.rstrip("\n")] - if len(action) != 1: - raise ValueError(f"Selection was ambiguous: {str(sel)}") - action[0]() - LOOP.run() - - -def delete_cb(dev, res, data): - """Notification if delete completed successfully - - """ - if dev.delete_finish(res) is True: - notify(f"Deleted {dev.get_id()}") - else: - notify(f"Problem deleting {dev.get_id()}", urgency="critical") - LOOP.quit() - - -def set_new_connection(nm_ap, nm_pw, adapter): - """Setup a new NetworkManager connection - - Args: ap - NM.AccessPoint - pw - string - - """ - nm_pw = str(nm_pw).strip() - profile = create_wifi_profile(nm_ap, nm_pw, adapter) - CLIENT.add_and_activate_connection_async(profile, adapter, nm_ap.get_path(), - None, verify_conn, profile) - LOOP.run() - - -def create_wifi_profile(nm_ap, password, adapter): - # pylint: disable=line-too-long - # noqa From https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/examples/python/gi/add_connection.py - # noqa and https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/examples/python/dbus/add-wifi-psk-connection.py - # pylint: enable=line-too-long - """Create the NM profile given the AP and passphrase""" - ap_sec = ap_security(nm_ap) - profile = NM.SimpleConnection.new() - - s_con = NM.SettingConnection.new() - s_con.set_property(NM.SETTING_CONNECTION_ID, ssid_to_utf8(nm_ap)) - s_con.set_property(NM.SETTING_CONNECTION_UUID, str(uuid.uuid4())) - s_con.set_property(NM.SETTING_CONNECTION_TYPE, "802-11-wireless") - profile.add_setting(s_con) - - s_wifi = NM.SettingWireless.new() - s_wifi.set_property(NM.SETTING_WIRELESS_SSID, nm_ap.get_ssid()) - s_wifi.set_property(NM.SETTING_WIRELESS_MODE, 'infrastructure') - s_wifi.set_property(NM.SETTING_WIRELESS_MAC_ADDRESS, adapter.get_permanent_hw_address()) - profile.add_setting(s_wifi) - - s_ip4 = NM.SettingIP4Config.new() - s_ip4.set_property(NM.SETTING_IP_CONFIG_METHOD, "auto") - profile.add_setting(s_ip4) - - s_ip6 = NM.SettingIP6Config.new() - s_ip6.set_property(NM.SETTING_IP_CONFIG_METHOD, "auto") - profile.add_setting(s_ip6) - - if ap_sec != "--": - s_wifi_sec = NM.SettingWirelessSecurity.new() - if "WPA" in ap_sec: - if "WPA3" in ap_sec: - s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_KEY_MGMT, - "sae") - else: - s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_KEY_MGMT, - "wpa-psk") - s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_AUTH_ALG, - "open") - s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_PSK, password) - elif "WEP" in ap_sec: - s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_KEY_MGMT, - "None") - s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, - NM.WepKeyType.PASSPHRASE) - s_wifi_sec.set_wep_key(0, password) - profile.add_setting(s_wifi_sec) - - return profile - - -def verify_conn(client, result, data): - """Callback function for add_and_activate_connection_async - - Check if connection completes successfully. Delete the connection if there - is an error. - - """ - try: - act_conn = client.add_and_activate_connection_finish(result) - conn = act_conn.get_connection() - if not all([conn.verify(), - conn.verify_secrets(), - data.verify(), - data.verify_secrets()]): - raise GLib.Error - notify(f"Added {conn.get_id()}") - except GLib.Error: - try: - notify(f"Connection to {conn.get_id()} failed", - urgency="critical") - conn.delete_async(None, None, None) - except UnboundLocalError: - pass - finally: - LOOP.quit() - - -def create_ap_list(adapter, active_connections): - """Generate list of access points. Remove duplicate APs , keeping strongest - ones and the active AP - - Args: adapter - active_connections - list of all active connections - Returns: aps - list of access points - active_ap - active AP - active_ap_con - active Connection - adapter - - """ - aps = [] - ap_names = [] - active_ap = adapter.get_active_access_point() - aps_all = sorted(adapter.get_access_points(), - key=lambda a: a.get_strength(), reverse=True) - conns_cur = [i for i in CONNS if - i.get_setting_wireless() is not None and - conn_matches_adapter(i, adapter)] - try: - ap_conns = active_ap.filter_connections(conns_cur) - active_ap_name = ssid_to_utf8(active_ap) - active_ap_con = [active_conn for active_conn in active_connections - if active_conn.get_connection() in ap_conns] - except AttributeError: - active_ap_name = None - active_ap_con = [] - if len(active_ap_con) > 1: - raise ValueError("Multiple connection profiles match" - " the wireless AP") - active_ap_con = active_ap_con[0] if active_ap_con else None - for nm_ap in aps_all: - ap_name = ssid_to_utf8(nm_ap) - if nm_ap != active_ap and ap_name == active_ap_name: - # Skip adding AP if it's not active but same name as active AP - continue - if ap_name not in ap_names: - ap_names.append(ap_name) - aps.append(nm_ap) - return aps, active_ap, active_ap_con, adapter - - -def notify(message, details=None, urgency="low"): - """Use notify-send if available for notifications - - """ - delay = CONF.getint('nmdm', 'rescan_delay', fallback=5) - args = ["-u", urgency, "-a", "networkmanager-dmenu", - "-t", str(delay * 1000), message] - if details is not None: - args.append(details) - if is_installed("notify-send"): - subprocess.run(["notify-send"] + args, check=False) - - -def run(): # pylint: disable=too-many-locals - """Main script entrypoint""" - try: - subprocess.check_output(["pidof", "NetworkManager"]) - except subprocess.CalledProcessError: - notify("WARNING: NetworkManager don't seems to be running") - print("WARNING: NetworkManager don't seems to be running") - active = CLIENT.get_active_connections() - adapter = choose_adapter(CLIENT) - if adapter: - ap_actions = create_ap_actions(*create_ap_list(adapter, active)) - else: - ap_actions = [] - - vpns = [i for i in CONNS if i.is_type(NM.SETTING_VPN_SETTING_NAME)] - try: - wgs = [i for i in CONNS if i.is_type(NM.SETTING_WIREGUARD_SETTING_NAME)] - except AttributeError: - # Workaround for older versions of python-gobject with no wireguard support - wgs = [] - eths = [i for i in CONNS if i.is_type(NM.SETTING_WIRED_SETTING_NAME)] - vlans = [i for i in CONNS if i.is_type(NM.SETTING_VLAN_SETTING_NAME)] - blues = [i for i in CONNS if i.is_type(NM.SETTING_BLUETOOTH_SETTING_NAME)] - - vpn_actions = create_vpn_actions(vpns, active) - wg_actions = create_wireguard_actions(wgs, active) - eth_actions = create_eth_actions(eths, active) - vlan_actions = create_vlan_actions(vlans, active) - blue_actions = create_blue_actions(blues, active) - other_actions = create_other_actions(CLIENT) - wwan_installed = is_installed("ModemManager") - if wwan_installed: - gsms = [i for i in CONNS if i.is_type(NM.SETTING_GSM_SETTING_NAME)] - gsm_actions = create_gsm_actions(gsms, active) - wwan_actions = create_wwan_actions(CLIENT) - else: - gsm_actions = [] - wwan_actions = [] - - list_saved = CONF.getboolean('dmenu', 'list_saved', fallback=False) - saved_cons = [i for i in CONNS if i not in vpns + wgs + eths + blues] - if list_saved: - saved_actions = create_saved_actions(saved_cons) - else: - saved_actions = [Action("Saved connections", prompt_saved, [saved_cons])] - - - actions = combine_actions(eth_actions, ap_actions, vlan_actions, vpn_actions, - wg_actions, gsm_actions, blue_actions, wwan_actions, - other_actions, saved_actions) - sel = get_selection(actions) - sel() - - -def main(): - """Main. Enables script to be re-run after a wifi rescan - - """ - global CLIENT, CONNS, LOOP # noqa pylint: disable=global-variable-undefined - CLIENT = NM.Client.new(None) - LOOP = GLib.MainLoop() - CONNS = CLIENT.get_connections() - - run() - - -if __name__ == '__main__': - main() - -# vim: set et ts=4 sw=4 : diff --git a/scripts/sb-network b/scripts/neticon similarity index 62% rename from scripts/sb-network rename to scripts/neticon index c62238b6..a116c6f5 100755 --- a/scripts/sb-network +++ b/scripts/neticon @@ -1,13 +1,9 @@ #!/bin/sh -# Show wifi 📶 and percent strength or 📡 if none. -# Show 🌐 if connected to ethernet or ❎ if none. -# Show 🔒 if a vpn connection is active - # Wifi -if [ "$(cat /sys/class/net/w*/operstate 2>/dev/null)" = 'up' ] ; then +if [ "$(cat /sys/class/net/w*/operstate 2>/dev/null)" = 'up' ]; then wifiicon="$(awk '/^[[:space:]]*w/ { gsub(/[[:space:]]+/, " "); print " ", int($3 * 100 / 70) "% " }' /proc/net/wireless)" -elif [ "$(cat /sys/class/net/w*/operstate 2>/dev/null)" = 'down' ] ; then +elif [ "$(cat /sys/class/net/w*/operstate 2>/dev/null)" = 'down' ]; then wifiicon=" " fi diff --git a/scripts/network.sh b/scripts/network.sh deleted file mode 100755 index 850e16d5..00000000 --- a/scripts/network.sh +++ /dev/null @@ -1,11 +0,0 @@ -echo "PUBLIC IP:" -wget -qO - https://api.ipify.org -echo -echo - -# echo "TOR PUBLIC IP:" -# torsocks wget -qO - https://api.ipify.org; echo -# echo - -echo "OPEN PORTS:" -sudo ss -tupln diff --git a/scripts/sb-memory b/scripts/ram similarity index 100% rename from scripts/sb-memory rename to scripts/ram diff --git a/scripts/sb-battery b/scripts/sb-battery deleted file mode 100755 index 11b2a7ff..00000000 --- a/scripts/sb-battery +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -# Prints all batteries, their percentage remaining and an emoji corresponding -# to charge status (🔌 for plugged up, 🔋 for discharging on battery, etc.). - -# Loop through all attached batteries and format the info -# for battery in /sys/class/power_supply/BAT?*; do # For standard devices, use this line instead. -for battery in /sys/class/power_supply/?*; do - # If non-first battery, print a space separator. - [ -n "${capacity+x}" ] && [ -f "$battery/status" ] && printf " " - # Sets up the status and capacity - case "$(cat "$battery/status" 2>&1)" in - "Full") status="󰁹 " ;; - "Discharging") status="󰂌 " ;; - "Charging") status="󰂄 " ;; - "Not charging") status="󰂃 " ;; - "Unknown") status="󰂑 " ;; - *) exit 1 ;; - esac - capacity="$(cat "$battery/capacity" 2>&1)" - # Will make a warn variable if discharging and low - [ "$status" = "󰂌 " ] && [ "$capacity" -le 25 ] && warn=" " - # Prints the info - printf "%s%s%d%%" "$status" "$warn" "$capacity"; unset warn -done && printf "\\n" diff --git a/scripts/sb-volume b/scripts/volume similarity index 76% rename from scripts/sb-volume rename to scripts/volume index 97ca5d21..78f7a726 100755 --- a/scripts/sb-volume +++ b/scripts/volume @@ -19,10 +19,10 @@ split() { vol="$(printf "%.0f" "$(split "$vol" ".")")" case 1 in - $((vol >= 70)) ) icon=" " ;; - $((vol >= 30)) ) icon=" " ;; - $((vol >= 1)) ) icon=" " ;; - * ) echo " " && exit ;; +$((vol >= 70))) icon=" " ;; +$((vol >= 30))) icon=" " ;; +$((vol >= 1))) icon=" " ;; +*) echo " " && exit ;; esac echo "$icon$vol%"