新增IRC协议相关的全套工具模块,包括: - 核心协议解析与CTCP处理 - 消息发送缓存与文本 sanitize - 账号配置管理与运行时状态 - 命令处理与权限控制 - 服务发现与诊断工具 - 多账号网关与配置加载
77 lines
2.2 KiB
Python
77 lines
2.2 KiB
Python
from __future__ import annotations
|
|
|
|
from fnmatch import fnmatchcase
|
|
|
|
|
|
def build_allowlist_candidates(
|
|
sender_nick: str,
|
|
sender_user: str | None = None,
|
|
sender_host: str | None = None,
|
|
) -> list[str]:
|
|
candidates = [sender_nick]
|
|
|
|
if sender_user:
|
|
candidates.append(f"{sender_nick}!{sender_user}")
|
|
if sender_host:
|
|
candidates.append(f"{sender_nick}@{sender_host}")
|
|
if sender_user and sender_host:
|
|
candidates.append(f"{sender_nick}!{sender_user}@{sender_host}")
|
|
|
|
return candidates
|
|
|
|
|
|
def resolve_allowlist_match(
|
|
candidates: list[str],
|
|
allowlist: list[str],
|
|
) -> str | None:
|
|
for candidate in candidates:
|
|
if candidate in allowlist:
|
|
return candidate
|
|
for candidate in candidates:
|
|
for entry in allowlist:
|
|
if fnmatchcase(candidate, entry) or fnmatchcase(entry, candidate):
|
|
return entry
|
|
if "*" in allowlist:
|
|
return "*"
|
|
return None
|
|
|
|
|
|
def normalize_allow_entry(entry: str) -> str:
|
|
for prefix in ("irc:", "irc:user:", "user:"):
|
|
if entry.startswith(prefix):
|
|
entry = entry[len(prefix) :]
|
|
return entry
|
|
|
|
|
|
def looks_like_irc_target_id(target: str) -> bool:
|
|
if target.startswith("irc:channel:") or target.startswith("irc:user:"):
|
|
return True
|
|
if "!" in target and "@" in target:
|
|
return True
|
|
return False
|
|
|
|
|
|
def normalize_irc_messaging_target(target: str) -> tuple[str, str]:
|
|
if target.startswith("irc:channel:"):
|
|
return "group", target.removeprefix("irc:channel:")
|
|
if target.startswith("irc:user:"):
|
|
return "direct", target.removeprefix("irc:user:")
|
|
if target.startswith("#") or target.startswith("&"):
|
|
return "group", target
|
|
return "direct", normalize_allow_entry(target)
|
|
|
|
|
|
def resolve_targets(target: str) -> dict:
|
|
kind, resolved = normalize_irc_messaging_target(target)
|
|
return {"kind": kind, "id": resolved, "display_name": resolved}
|
|
|
|
|
|
def format_irc_sender_id(nick: str, user: str | None = None, host: str | None = None) -> str:
|
|
if user and host:
|
|
return f"{nick}!{user}@{host}"
|
|
if user:
|
|
return f"{nick}!{user}"
|
|
if host:
|
|
return f"{nick}@{host}"
|
|
return nick
|