chore(license): add SPDX license identifiers to various files, standardizing licensing terms across the project

This commit is contained in:
Ivan 2026-04-16 18:12:14 -05:00
parent ca8b2a9fe0
commit 6fb4ccc79a
No known key found for this signature in database
GPG key ID: B84314E2D9332AE0
307 changed files with 739 additions and 24 deletions

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import os
import signal
import sys

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import os
import sys
from pathlib import Path

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
"""Reticulum MeshChatX - A mesh network communications app."""
__version__ = "4.5.0"

View file

@ -1,4 +1,5 @@
#!/usr/bin/env python
# SPDX-License-Identifier: 0BSD AND MIT
import argparse
import asyncio
@ -226,7 +227,9 @@ class ReticulumMeshChat:
rns_loglevel: str | None = None,
):
self.running = True
self.reticulum_config_dir = reticulum_config_dir
self.reticulum_config_dir = self._normalize_reticulum_config_dir(
reticulum_config_dir,
)
self.storage_dir = storage_dir or os.path.join("storage")
self.ssl_cert_path = ssl_cert_path
self.ssl_key_path = ssl_key_path
@ -525,6 +528,30 @@ class ReticulumMeshChat:
return os.path.join(self.public_dir_override, filename)
return get_file_path(os.path.join("public", filename))
@staticmethod
def _normalize_reticulum_config_dir(config_candidate: str | None) -> str:
"""Normalize Reticulum config candidate to a config directory path."""
candidate = config_candidate
if not candidate:
candidate = (
getattr(RNS.Reticulum, "configdir", None)
or os.path.dirname(getattr(RNS.Reticulum, "configpath", "") or "")
or os.path.expanduser("~/.reticulum")
)
candidate = os.path.expanduser(str(candidate))
# Reticulum's config file is plaintext named "config" (no extension).
# If a file path is provided, convert it to its parent directory.
if os.path.basename(candidate) == "config" and not os.path.isdir(candidate):
return os.path.dirname(candidate) or os.path.expanduser("~/.reticulum")
return candidate
def _reticulum_config_file_path(self) -> str:
return os.path.join(
self._normalize_reticulum_config_dir(self.reticulum_config_dir),
"config",
)
def backup_database(self, backup_path=None):
if not self.database:
raise RuntimeError("Database not initialized")
@ -540,12 +567,9 @@ class ReticulumMeshChat:
If the config is missing or invalid, create a sane default.
"""
config_dir = (
self.reticulum_config_dir
or RNS.Reticulum.configpath
or os.path.expanduser("~/.reticulum")
)
config_file = os.path.join(config_dir, "config")
config_dir = self._normalize_reticulum_config_dir(self.reticulum_config_dir)
self.reticulum_config_dir = config_dir
config_file = self._reticulum_config_file_path()
should_recreate = False
@ -1060,13 +1084,9 @@ class ReticulumMeshChat:
# Also check the config file for ports
try:
config_dir = getattr(self, "reticulum_config_dir", None)
if not config_dir:
if hasattr(RNS.Reticulum, "configdir") and RNS.Reticulum.configdir:
config_dir = RNS.Reticulum.configdir
else:
config_dir = os.path.expanduser("~/.reticulum")
config_dir = self._normalize_reticulum_config_dir(
getattr(self, "reticulum_config_dir", None),
)
config_path = os.path.join(config_dir, "config")
if os.path.isfile(config_path):
cp = configparser.ConfigParser()
@ -1101,8 +1121,6 @@ class ReticulumMeshChat:
# Defaults
rpc_addrs.append((("127.0.0.1", 37429), "AF_INET"))
rpc_addrs.append((("127.0.0.1", 37428), "AF_INET"))
if platform.system() == "Linux":
rpc_addrs.append(("\0rns/default/rpc", "AF_UNIX"))
for i in range(15):
all_free = True
@ -1134,6 +1152,19 @@ class ReticulumMeshChat:
f"RPC addr {addr_display} still in use... (attempt {i + 1}/15)",
)
s.close()
is_abstract_unix_addr = (
family == socket.AF_UNIX
and isinstance(addr, str)
and addr.startswith("\0")
)
if is_abstract_unix_addr:
# Another local shared-instance daemon may own this address.
# Do not block reload on abstract UNIX sockets.
print(
f"Abstract RPC addr {addr_display} is occupied by another process; continuing reload.",
)
continue
all_free = False
# If we are stuck, try to force close the connection manually
@ -1528,7 +1559,9 @@ class ReticulumMeshChat:
p = getattr(r, "configpath", None)
if p:
return str(p)
rd = getattr(self, "reticulum_config_dir", None)
rd = self._normalize_reticulum_config_dir(
getattr(self, "reticulum_config_dir", None),
)
if rd:
return os.path.join(rd, "config")
return None
@ -4461,13 +4494,9 @@ class ReticulumMeshChat:
# Fallback to reading config if not found via connections
if not shared_instance_address:
try:
config_dir = getattr(self, "reticulum_config_dir", None)
if not config_dir:
config_dir = getattr(
RNS.Reticulum,
"configdir",
os.path.expanduser("~/.reticulum"),
)
config_dir = self._normalize_reticulum_config_dir(
getattr(self, "reticulum_config_dir", None),
)
config_path = os.path.join(config_dir, "config")
if os.path.isfile(config_path):

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: MIT
import sys
# NOTE: this class is required to be able to use print/log commands and have them flush to stdout and stderr immediately

View file

@ -1 +1,3 @@
# SPDX-License-Identifier: 0BSD
"""Backend utilities shared by the Reticulum MeshChatX CLI."""

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD AND MIT
# an announce handler that forwards announces to a provided callback for the provided aspect filter
# this handler exists so we can have access to the original aspect, as this is not provided in the announce itself
class AnnounceHandler:

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import base64
from .database import Database

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import hashlib
from .database import Database

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD AND MIT
import asyncio
import sys
import threading

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import asyncio
import time

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import contextlib
import json
import logging

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import argparse
import contextlib
import os

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import re
import time
from datetime import datetime, timedelta

View file

@ -1,3 +1,6 @@
# SPDX-License-Identifier: 0BSD AND MIT
class ColourUtils:
@staticmethod
def hex_colour_to_byte_array(hex_colour):

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import json
from pathlib import Path
from typing import Any

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
"""Convert directory.rns.recipes listing rows into MeshChat interface preset dicts."""
from __future__ import annotations

View file

@ -1,3 +1,6 @@
# SPDX-License-Identifier: 0BSD
class ConfigManager:
def __init__(self, db):
self.db = db

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import json
import logging
import os

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
from __future__ import annotations
import hashlib

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
from datetime import UTC, datetime
from .provider import DatabaseProvider

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
from datetime import UTC, datetime
from .provider import DatabaseProvider

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
from .provider import DatabaseProvider

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import json
from .provider import DatabaseProvider

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
from datetime import UTC, datetime
from .provider import DatabaseProvider

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import os
import re

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
from datetime import UTC, datetime
from .provider import DatabaseProvider

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import json
from datetime import UTC, datetime

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
from datetime import UTC, datetime
from .provider import DatabaseProvider

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import sqlite3
import threading
import weakref

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
from datetime import UTC, datetime
from .provider import DatabaseProvider

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import re
from .provider import DatabaseProvider

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import base64
import sqlite3
import time

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import json
from datetime import UTC, datetime

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
from .provider import DatabaseProvider

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
from .provider import DatabaseProvider

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import asyncio
import html
import io

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import base64
import contextlib
import os

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import asyncio
import contextlib
import os

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import base64
import contextlib
import json

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import fnmatch
import hashlib
import json

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD AND MIT
import RNS.vendor.configobj

View file

@ -1,3 +1,6 @@
# SPDX-License-Identifier: 0BSD AND MIT
class InterfaceEditor:
@staticmethod
def update_value(interface_details: dict, data: dict, key: str):

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD AND MIT
import threading
import time

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD AND MIT
import threading
import time

View file

@ -1 +1,3 @@
# SPDX-License-Identifier: 0BSD
"""Shared transport interfaces for MeshChatX."""

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
"""Collect third-party license metadata for Python (backend) and Node (frontend)."""
from __future__ import annotations

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: MIT
# helper class for passing around an lxmf audio field
class LxmfAudioField:
def __init__(self, audio_mode: int, audio_bytes: bytes):

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import base64
import json

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import asyncio
import base64
import math

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import html
import re

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import base64
import contextlib
import json

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
from .database import Database

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import asyncio
import io
import os

View file

@ -1,3 +1,6 @@
# SPDX-License-Identifier: 0BSD
def convert_nomadnet_string_data_to_map(path_data: str | None):
data = {}
if path_data is not None:

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
"""PageNode: Serves Micron pages and files over RNS.
Each PageNode owns an RNS Destination (SINGLE, IN) with the aspect

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
"""PageNodeManager: Manages the lifecycle of multiple PageNode instances.
Handles creation, deletion, persistence, start/stop, and announce

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import collections
import logging
import math

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
from .crash_recovery import CrashRecovery
from .health_monitor import HealthMonitor

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
"""Crash recovery and adaptive diagnostics for MeshChatX.
Uses entropy, KL-divergence, and Bayesian weight learning. Crash history is

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
"""Lightweight predictive health monitor.
Runs as a daemon thread on a 5-minute interval, reading in-memory

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import os
import shutil
import subprocess

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import asyncio
import contextlib
import os

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import RNS

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import asyncio
import time
import traceback

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import asyncio
import os
import time

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import contextlib
import time
from typing import Any

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: MIT
# https://github.com/markqvist/Sideband/blob/e515889e210037f881c201e0d627a7b09a48eb69/sbapp/sideband/sense.py#L11
class SidebandCommands:
TELEMETRY_REQUEST = 0x01

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
"""Validation and hashing for user sticker images stored per identity."""
from __future__ import annotations

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import struct
import time

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import asyncio
import base64
import contextlib

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import asyncio
import concurrent.futures
import os

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import contextlib
import os
import platform

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
import asyncio
import contextlib
import json

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: 0BSD
"""Environment variable parsing helpers."""
import os

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD AND MIT -->
<template>
<div
:class="{ dark: config?.theme === 'dark' }"

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD -->
<template>
<div class="card-stack-wrapper flex-1 flex flex-col min-h-0" :class="{ 'is-expanded': isExpanded }">
<div

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD -->
<template>
<v-dialog
v-if="!isPage"

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD AND MIT -->
<template>
<div
v-click-outside="{ handler: onClickOutsideMenu, capture: true }"

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD -->
<template>
<transition name="slide-down">
<div

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD -->
<template>
<Transition name="confirm-dialog">
<div v-if="pendingConfirm" class="fixed inset-0 z-[9999] flex items-center justify-center p-4">

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD AND MIT -->
<template>
<div
v-click-outside="{ handler: onClickOutsideMenu, capture: true }"

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD AND MIT -->
<template>
<div
class="cursor-pointer flex p-3 space-x-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-zinc-700"

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD AND MIT -->
<template>
<button
type="button"

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD -->
<template>
<v-dialog v-model="visible" persistent max-width="500">
<v-card color="warning" class="pa-4">

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD -->
<template>
<div class="relative">
<button

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD AND MIT -->
<template>
<div
v-if="customImage"

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD AND MIT -->
<template>
<svg
xmlns="http://www.w3.org/2000/svg"

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD -->
<template>
<div class="relative">
<button

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD AND MIT -->
<template>
<RouterLink v-slot="{ href, navigate, isActive }" :to="to" custom>
<a

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD -->
<template>
<div class="fixed bottom-4 right-4 z-[100] flex flex-col gap-2 pointer-events-none">
<TransitionGroup name="toast">

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD -->
<template>
<v-dialog
v-if="!isPage"

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD AND MIT -->
<template>
<div class="flex flex-col flex-1 overflow-hidden min-w-0 bg-slate-50 dark:bg-zinc-950">
<div

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD -->
<template>
<div
class="flex h-full shrink-0 flex-col overflow-hidden border-r border-gray-200 bg-white dark:border-zinc-800 dark:bg-zinc-950"

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD -->
<template>
<!-- eslint-disable vue/no-v-html -->
<div class="flex h-full overflow-hidden bg-white dark:bg-zinc-950">

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD -->
<template>
<div class="h-screen w-full flex items-center justify-center bg-slate-50 dark:bg-zinc-950">
<div class="w-full max-w-md p-8">

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD -->
<template>
<div class="flex flex-col flex-1 h-full overflow-hidden bg-slate-50 dark:bg-zinc-950">
<div

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD -->
<template>
<div
v-if="activeCall || initiationStatus || isEnded || wasDeclined"

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD -->
<template>
<div class="flex flex-col w-full h-full bg-gray-100 dark:bg-zinc-950">
<div class="w-full h-full overflow-y-auto">

View file

@ -1,3 +1,5 @@
<!-- SPDX-License-Identifier: 0BSD -->
<template>
<div class="space-y-6">
<!-- Header -->

Some files were not shown because too many files have changed in this diff Show more