Files
MeowOS-For-R3P2/patch_v2/meowpanel/src/mp.h
T
AskaEth 7c7d891570 feat: M6.44+M6.45 收编 — 真机 0.8.45 现场保全(reader章节/key_router按键路由/WiFi连接修复/ncm bench+IME修复)
脏工作区现场收编:devdocs/local/m6_44_45_dirty_tracked.patch(46 个已跟踪文本文件,
+3090/-585, 已对 M6.43 基线干净适配) + m6_44_45_untracked_src.tar.gz 中 patch_v2/ 下
13 个新增源文件, 合成单个提交, 内容与容器工作树(R3ProII/patch_v2)逐字节一致。

- reader 章节: 新增 core/rdchapter.{h,c} — TXT 章节规范解析器, 扫描 512KB 码位对齐段文件
  逐段流式识别标题行(行首缩进≤4/显示宽≤40/行内标点≤1 三重约束防误判), 输出标题+全书字符
  偏移+段号/段内偏移+阿拉伯章号(中文数字归一), 首章前内容归"卷首"; book/reader/rdenc/
  rdlayout/settings 接入章节跳转与进度锚点, 附 chapter_smoke/turn_repro/build_turn_repro.sh
- key_router 按键路由: 新增 meow_launcherd/key_router.{h,c} — launcher-UI 页物理键统一路由
  (P1 仅音量键), 把读取边沿+防抖+长按 held+ramp 推进从 5 个会话收敛为进程内单开;
  各页每圈 key_router_pump() 取防抖后边沿, 动作(调音量/光标导航)仍由调用页决定,
  保留 run_menu 的 meow_mode 分支; App 前台 volume_page 武装时边沿抑制;
  main_menu/now_playing/notif_center/settings_page/subpage 接入, 附 test_key_router_vol/test_np_keys
- WiFi 连接修复: meow_netmgrd connect 有界等待 wpa_state=COMPLETED(普通 10s/隐藏网络 15s,
  env 可调)修设置页连接无响应; list_networks/scan_results 的 \xNN 转义还原始字节, 修中文 SSID
  永不命中致新建同名 open 记录顶影; launcher netmgr_ipc 配读超时; 附 test_wifi_connect(桩
  wpa_cli 驱动 static wifi_connect_ex), test_netmgrd.sh 补用例; wifi_page 同步
- ncm bench: 新增 bench/lyric_sim.c、bench/plpage_sim.c, vol_sync_sim 与 ncm core/app 同步
- SDK IME 修复: shift 大小写、K_ENTER 只提交不关、阻塞 IME 循环喂 on_tick 不被遮挡、
  IME 打开 ~200ms TAP 冷却窗吞 stray-TAP; 附 sdk/test_ime_fix.c
- 同期: meow_audiod 音量异步 ACK 线程(代际防 fd/槽复用竞态)、watchdog 音量收编(首选 audiod
  权威, settings.conf 覆盖路径)、panel 文件搜索(F1-④)与蓝牙只读详情(F1-③)、各类 build 脚本同步

范围红线: third_party/legado-E-main 原开发者未跟踪, 本次不入库(保留 devdocs/local tar 参考);
二进制不入库(后续重编); devdocs/ 不入库。59 文件全部在 patch_v2/ 下, 无 third_party/devdocs。
验证: git apply --check 干净; 59 文件 md5 与容器 patch_v2 逐一比对 59/59 一致(含
key_router.c/rdchapter.c/meow_ui_ime.c/test_wifi_connect.c 抽查); 可执行位保守
(check_lgpl_release.sh 100755, build_turn_repro.sh 100644 与容器一致)。
2026-11-04 20:02:28 +08:00

466 lines
24 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* mp.h — MeowPanel 后端共享内部头(模块化拆分后各 .c 共同包含)。
* 定位(MEOWPANEL_DESIGN §1/§2):外置于 TF 卡 `MeowOS/opt/MeowPanel/` 的系统组件
* (HTTP/JSON 后端 + 前端静态托管),由 meow_svcd 读 TF 卡 services.d 启动。**不进固件**。
* 这是拆分后的单一共享内部头:共享常量/类型/外部全局 + 所有跨模块函数原型。
* 各 api_* 域 / store / ipc / util / json / server 均以 `#include "mp.h"` 起步。
* 编译(mipsel 静态):build_meowpanel.sh;宿主编译 build_meowpanel.sh host。 */
#ifndef MP_H
#define MP_H
#define _GNU_SOURCE /* gethostname/strcasestr/strnlen 等 GNU/musl 扩展 */
/* meowpanel.c — MeowOS Web 面板后端(MeowPanel)。
*
* 定位(MEOWPANEL_DESIGN §1/§2):外置于 TF 卡 `MeowOS/opt/MeowPanel/` 的系统组件
* (HTTP/JSON 后端 + 前端静态托管),由 meow_svcd 读 TF 卡 `MeowOS/services.d/meowpanel.conf`
* 启动、meow_sysui 监管。**不进固件**;无卡时系统核心绝不对它有任何依赖。
*
* 架构(MEOWPANEL_PROTOCOL §1/§2 + SYSTEM_FRAMEWORK_SERVICES §4):
* - 单进程单线程 + poll 串行处理(面板访问量极小);内嵌 HTTP server。
* - 读侧(/api/status,/api/perf,/api/system)经 meow_svc_perf IPC(MSG_PERF_QUERY→RESULT)
* 聚合,**绝不各自爬 /proc**(单一权威源)。
* - 动作侧(/api/system/{reboot,shutdown,ota})经 meow_svc_power IPC(MSG_POWER_ACTION→STATUS),
* 不再直连 poweroff/写 mtd5。
* - 设置镜像(/api/settings*,/api/theme*)直接读写板载 /usr/data/meow/settings.conf——
* **与 meow_ui_vol_read / meow_svc_power settings_get_int_trim 同款解析**('=' 切分 +
* key 去首尾空白精确匹配;写用 "key = value\n")。后端是独立进程,无法链接 launcher 内的
* meow_settings_*(那是 launcher 进程内存表),故直接镜像文件,保持同一存储契约。
* - 文件/应用/日志/通知:白名单根 /usr/data/mnt/sd_0 下 MeowOS/Music/MeowData/MeowAPPs/book。
*
* 编译(mipsel 静态):build_meowpanel.sh;宿主编译 build_meowpanel.sh host。
* 依赖:仅 POSIX + libc(含 linux/input.h 内核头),零第三方库(mp_jpeg.c 自研最小 JPEG;
* 字体库导入/导出走 busybox `gzip -dc | tar` 管道——与 nyai .mpk 同构,设备必带 tar/gzip)。
* 设备无 python3/lua。
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h> /* strcasecmp/strncasecmp */
#include <stdarg.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <poll.h>
#include <time.h>
#include <ctype.h>
#include <dirent.h>
#include <limits.h>
#include <math.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/utsname.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/input.h> /* KEY_* / EV_KEY / EV_SYN / struct input_event(按键注入) */
#include "meow_ipc.h" /* 帧格式/消息号 + m_perf_query_t/m_perf_result_t + POWER_* 枚举 */
#include "mp_jpeg.h" /* 实时画面:RGB565 → 最小 baseline JPEG(自包含,零依赖) */
/* 实时画面 / 触摸注入(阶段 C)。fb ioctl 常量按 launcher fb_compositor 同款手工定义
* (避免 libc/kernel struct ABI 差异,读入裸字节缓冲再按偏移取字段)。 */
#ifndef FBIOGET_VSCREENINFO
#define FBIOGET_VSCREENINFO 0x4600
#define FBIOGET_FSCREENINFO 0x4602
#endif
#ifndef FB_DEV
#define FB_DEV "/dev/fb0" /* 16bpp RGB565,480x720,双层虚拟缓冲 */
#endif
#ifndef TOUCH_DEV
#define TOUCH_DEV "/dev/input/event1" /* goodix-ts:接收 write() 注入(本机实测可投递) */
#endif
/* ---------------- 常量 ---------------- */
#define PANEL_VERSION "0.1"
#define DEFAULT_PORT 8080
#define SETTINGS_FILE "/usr/data/meow/settings.conf"
#define SETTINGS_HDR "# meow-settings 1"
#define TF_ROOT g_tf_root_buf
#define TF_CARD_DIR g_tf_card
#define MEOWAPPS_DIR g_apps_dir
#define LOGS_DIR g_logs_dir
#define PERF_SOCK "/usr/data/meow_perf.sock"
#define POWER_SOCK "/usr/data/meow_power.sock"
#define LAUNCHER_SOCK "/usr/data/meow_ipc.sock" /* launcher 主 IPC(通知活跃集查询/撤清) */
#define AUDIO_SOCK "/usr/data/meow_audio.sock" /* meow_audiod 状态快照(MSG_AUDIO_QUERY→STATE) */
#define NET_SOCK "/usr/data/meow_net.sock" /* meow_netmgrd 网络管理(MSG_NET_*,期2 观测层/DNS 代理) */
#define PM_SOCK "/usr/data/meow_pm.sock" /* meow_powermgr 功耗管理(MSG_PM_QUERY→RESULT) */
#define NYAI_PATH "/usr/bin/nyai" /* 固件内置(权威) */
#define NYAI_PATH_CARD "/usr/data/mnt/sd_0/MeowOS/opt/bin/nyai" /* 旧卡上路径(回退) */
#define AMS_BIN "/usr/bin/am" /* 固件内置 amsd 用户侧 CLI(权威) */
#define AMS_BIN_CARD "/usr/data/mnt/sd_0/MeowOS/opt/bin/am" /* 旧卡上路径(回退) */
#define SVCD_BIN "/usr/bin/meow_svcd" /* 固件内置 svcd 服务表 CLI(权威) */
#define SVCD_BIN_CARD "/usr/data/mnt/sd_0/MeowOS/opt/bin/meow_svcd" /* 旧卡上路径(回退) */
#define BOOT_DEFAULT_FILE "/data/meow_boot_default"
#define VERSION_FILE "/etc/meowos_version"
#define HOSTNAME_FILE ""
#define IPC_TIMEOUT_MS 2000
#define MAX_HTTP_HEADER (64 * 1024)
#define MAX_HTTP_BODY (16 * 1024 * 1024) /* 通用 body 上限(JSON/小件) */
#define MAX_UPLOAD_BODY (8 * 1024 * 1024) /* multipart 上传上限(14MB 内存约束:不整读超 8MB) */
#define MAX_FONT_UPLOAD (32 * 1024 * 1024) /* 字体库 tar.gz 上传上限(gbk 字库 png+idx 可能 10-20MB) */
#define MAX_JSON_IN 65536 /* JSON body 解析上限 */
#define MAX_STATIC_FREEBUF (2 * 1024 * 1024)
#define LOG_MAX_LINES 1000
#define NOTIF_PREVIEW_MAX 200 /* 通知列表返回上限(每条约 0.2KB,总 <50KB) */
#define TEXT_PREVIEW_MAX (1024 * 1024) /* 文本预览上限(超出截断,truncated=true;14MB 约束下 1MB 缓冲安全) */
#define PANEL_VOL_MAX_DEFAULT 100 /* 音频音量上限默认(对齐 meow_launcher MEOW_VOL_MAX_DEFAULT;设备可经 settings.conf audio.volume_max 覆盖) */
#define ALLOWED_COUNT ((int)(sizeof g_allowed_dirs / sizeof g_allowed_dirs[0]))
#define SENSITIVE_COUNT ((int)(sizeof g_sensitive_names / sizeof g_sensitive_names[0]))
#define SCREEN_BLOCK 8 /* 比对块边长(像素) */
#ifndef MSG_PM_POLICY_GET
#define MSG_PM_POLICY_GET 0x00D2 /* ↑ 策略读(空负载 → MSG_PM_RESULT policy JSON;读级任意调用者) */
#define MSG_PM_POLICY_SET 0x00D3 /* ↑ 策略写(req: m_pm_policy_set_t;动作级=root+系统身份) */
#define MSG_PM_HISTORY 0x00D4 /* ↑ 历史采样查询(req: u32 count,0=默认) */
#define MSG_PM_HISTORY_RESULT 0x00D5 /* ↓ 历史 JSON */
#define MSG_PM_EVENTS 0x00D6 /* ↑ 事件流查询(req: u32 count,0=默认) */
#define MSG_PM_EVENTS_RESULT 0x00D7 /* ↓ 事件 JSON */
#define MSG_PM_CALIB_START 0x00D8 /* ↑ 标定启动(动作级;本期面板不暴露,预留) */
#define MSG_PM_CALIB_STOP 0x00D9 /* ↑ 标定停止(动作级;预留) */
#endif
#define AUTH_TOKEN_BYTES 16 /* 128bit → 32 hex */
#define AUTH_TOKEN_TTL (3 * 86400) /* 3 天(固定,不滑动续期) */
#define AUTH_MAX_SESS 8 /* 内存最多保存的并发会话数 */
#define AUTH_HASH_LEN 64 /* sha256 hex 长度 */
/* ---------------- 有界动态字符串(sbuf) ---------------- */
typedef struct { char *b; size_t n; size_t cap; } sbuf_t;
/* ---------------- 最简 JSON 解析器(无第三方库) ----------------
* 只覆盖 MeowPanel 实际用到的:对象 / 数组 / 字符串(含转义) / 数字 / bool / null。
* value 树:J_OBJ 的 child 为键值对链(str=key,child=value,next=下个 pair);
* J_ARR 的 child 为元素链(next=下个元素)。
*/
enum { J_NULL, J_BOOL, J_NUM, J_STR, J_ARR, J_OBJ };
typedef struct jv {
int type;
int bval; /* J_BOOL */
long long inum; /* J_NUM 整数值 */
double dnum; /* J_NUM 浮点值 */
char *str; /* J_STR: 值; J_OBJ: key */
struct jv *child; /* J_ARR: 头; J_OBJ: 头 pair */
struct jv *next; /* 链 */
} jv_t;
typedef struct { const char *p; const char *end; int err; } jvp_t;
enum { ST_INT, ST_STR, ST_ENUM, ST_BOOL };
typedef struct setdef {
const char *key;
int type;
const char *def;
int min, max; /* ST_INT 取值域;max<=0 表示无上界 */
const char *enum_names; /* ST_ENUM 逗号名 */
const char *enum_labels; /* 对应中文 */
const char *group; /* 分组标签(协议 groups 用) */
} setdef_t;
/* 期 3 · 策略写负载(item="profile"/"low-pct"/"crit-pct"/"bri-cap"/"scr-cap")。 */
typedef struct m_pm_policy_set { char item[16]; char val[32]; } m_pm_policy_set_t; /* 48 B */
struct fent { char name[256]; int isdir; long long size, mtime; };
/* ---------------- HTTP 请求读取 ---------------- */
typedef struct {
char method[8];
char path[512]; /* 解码后的路径(不含 query) */
char query[1024]; /* 原始 query(key=value&…,未解码;取值时用 qparam) */
char *body;
size_t body_len;
char content_type[128]; /* 请求 Content-Type(若非空) */
char authorization[256]; /* Authorization 头(Bearer <token>) */
char x_meow_token[256]; /* X-MeowToken 头 */
char cookie[512]; /* Cookie 头(meow_token=<token> 等) */
} req_t;
typedef struct { char path[1400]; char filename[320]; } upfile_t;
typedef struct {
long long ms; /* created_ms(epoch ms) */
unsigned id;
char app_id[40];
char app_icon[64];
char category[40];
int urgency;
int progress; /* -1=无 */
char summary[96];
char body[128];
char target[64];
int ongoing, media, dismissed;
} notif_rec_t;
typedef struct { uint32_t state[8]; uint64_t count; uint8_t buf[64]; size_t buflen; } mp_sha256_ctx;
/* ---- 会话(**纯内存**:重启自然失效,无卡上持久化) ---- */
typedef struct { char token[65]; time_t expires; } auth_sess_t;
/* ---------------- 跨模块全局(extern;定义见各拥有模块 .c) ---------------- */
extern const char *g_settings_file;
extern char g_tf_root_buf[1024];
extern char g_tf_card_buf[2048], g_apps_dir_buf[2048], g_logs_dir_buf[2048], g_notif_log_buf[2048];
extern const char *g_tf_card, *g_apps_dir, *g_logs_dir, *g_notif_log;
extern const char *g_allowed_dirs[];
extern const char *g_sensitive_names[];
extern const char *g_sock_perf, *g_sock_power, *g_sock_launcher, *g_sock_audio, *g_sock_net, *g_sock_pm;
extern time_t g_auth_ttl;
/* ---------------- 函数原型(全部跨模块;无 static,避免 -Wunused-function) ---------------- */
void init_tf_paths(void);
int sb_reserve(sbuf_t *s, size_t extra);
void sA(sbuf_t *s, const char *fmt, ...);
int utf8_seq_len(unsigned char lead);
int json_strict_balanced(const char *b, size_t n);
int utf8_seq_ok(const char *p, int len);
int utf8_valid_n(const char *s, size_t n);
int utf8_sanitize(char *dst, const char *src, size_t n);
void sA_str_n(sbuf_t *s, const char *v, size_t n);
void sA_str(sbuf_t *s, const char *v);
void sA_append(sbuf_t *s, const char *b, size_t n);
void sbuf_free(sbuf_t *s);
jv_t *jv_alloc(int type);
void jv_free(jv_t *v);
void jvp_skip_ws(jvp_t *t);
char *jv_parse_string(jvp_t *t);
jv_t *jv_parse_object(jvp_t *t);
jv_t *jv_parse_array(jvp_t *t);
jv_t *jv_parse_value(jvp_t *t);
jv_t *jv_parse(const char *text, int len);
jv_t *jv_obj_get(const jv_t *obj, const char *key);
void jv_to_json(sbuf_t *s, const jv_t *v);
const setdef_t *setdef_find(const char *key);
void settings_mkdir_p(void);
char *settings_get_value(const char *key);
int settings_get_int(const char *key, int defv);
int brightness_clamp(int v);
int settings_write_one(const char *key, const char *val);
int settings_coerce(const setdef_t *d, const char *input, char *out, size_t outcap);
int settings_reset_all(void);
int x_read_full(int fd, uint8_t *buf, size_t n);
int x_write_full(int fd, const uint8_t *buf, size_t n);
int send_frame(int fd, uint16_t type, uint32_t req_id, const void *payload, uint32_t len);
int recv_frame(int fd, uint16_t *type, uint32_t *req_id, uint8_t *buf, uint32_t cap);
int ipc_connect_tmo(const char *sock, int tmo_ms);
int ipc_hello(int fd);
const char *perf_code_str(int code);
int perf_subset_for_path(const char *path);
int ipc_perf_query(int subset, char *out, int cap);
const char *power_code_str(int code);
int ipc_power_action(uint32_t cmd, uint32_t flag, const char *arg, m_power_status_t *out_st);
void svc_msg_kv(const char *msg, const char *key, char *out, size_t cap);
const char *audio_kv(const char *txt, const char *key, char *out, size_t cap);
long long audio_kv_ll(const char *txt, const char *key, long long defv);
int audio_vol_max(void);
void audio_fill(sbuf_t *s);
int api_audio(int sock);
int audio_write_cmd(uint16_t type, const void *pl, uint32_t len, m_ack_t *out);
int api_audio_route(int sock, const char *body, size_t body_len);
int api_audio_volume(int sock, const char *body, size_t body_len);
int api_audio_monitor(int sock, const char *query);
int ipc_pm_query(uint32_t subset, char *out, int cap);
int api_power(int sock);
int ipc_pm_send(uint16_t req_type, const void *pl, uint32_t plen, uint16_t *rtype, char *out, int cap);
int api_power_policy_get(int sock);
int api_power_policy_set(int sock, const char *body, size_t body_len);
int api_power_window(int sock, uint16_t req_type, uint16_t want_type, const char *unavail);
int power_policy_append_flag(sbuf_t *out, const char *obj); /* 拼 guard③ policy_write_enabled 顶层键(自校验) */
int api_power_history(int sock);
int api_power_events(int sock);
const char *ams_bin(void);
const char *svcd_bin(void);
int net_ipc(uint16_t req_type, const void *req, uint32_t req_len, uint16_t *ret_type, uint32_t *code, uint16_t *meta, char *out, size_t cap);
int api_net_status(int sock);
int net_conns_parse_body(sbuf_t *s, const char *txt);
int api_net_conns(int sock, const char *query);
int net_dns_obj_fill(sbuf_t *s);
int api_net_dns(int sock);
int net_block_fill(sbuf_t *s);
int api_net_dns_flush(int sock);
int api_net_log(int sock);
int api_net_ifaces(int sock);
void net_policy_parse(const char *txt, sbuf_t *s);
int api_net_policy_get(int sock);
int api_net_policy_set(int sock, const char *body, size_t body_len);
int net_locked_entity(const char *entity); /* 防自锁:系统关键网络/服务组件(dropbear/wpa_supplicant/udhcpc/netmgrd/svcd/sysui/init) */
int net_bt_aggregate(const char *st, const char *paired, const char *connected, const char *a2dp, const char *devices, sbuf_t *s); /* F1-③ 0xE6 五读文本聚合(selftest 可测) */
int api_net_bt(int sock); /* F1-③ GET /api/net/bt 蓝牙只读详情 */
int panel_policy_write_enabled(void); /* policy 默认关 gate:settings.conf `panel.policy_enabled`,缺省 0=关(只读透传) */
void panel_strip_ansi(char *s);
int txt_tokens(char *buf, char **toks, int maxtoks);
void join_tokens(char **toks, int from, int to, char *out, size_t cap);
void ams_fill(sbuf_t *s);
void ams_fg_fill(sbuf_t *s);
void ams_bg_fill(sbuf_t *s);
void ams_bg_parse(char *list_text, sbuf_t *s); /* 已 strip 的 am list 文本 → bg 列表 JSON(含 /proc 采样) */
int api_ams(int sock);
int api_ams_bg(int sock);
int ams_pkg_ok(const char *pkg);
void ams_history_parse(char *out, sbuf_t *s, const char *pkg);
void ams_history_fill(sbuf_t *s, const char *pkg);
int api_ams_history(int sock, const char *pkg);
int api_ams_ctl(int sock, const char *pkg, int kill);
int api_ams_kill_fg(int sock, const char *pkg); /* 前台强制终止(救命):am kill 优先,launcher 拒→直接 pid 信号 */
void svcd_fill(sbuf_t *s);
int api_svcd(int sock);
int api_overview(int sock);
int tf_present(void);
int path_in_whitelist(const char *abs);
int is_sensitive_name(const char *base);
int normalize_path(const char *in, char *buf, size_t buflen);
void make_rel(const char *abs, char *buf, size_t buflen);
int open_safe_for_read(const char *abs, int follow_rel);
void fmt_json_item(sbuf_t *s, const char *name, int isdir, long long size, long long mtime);
int nat_strcmp(const char *a, const char *b);
int fent_cmp(const void *a, const void *b);
int files_list(int sock, const char *relpath);
char *read_text_file_limited(const char *abs, long long *size, int *truncated);
int keycode_to_device(int code, const char **dev);
int inject_key_event(const char *dev, int code, int down);
int inject_key_release(int code, int press_ms);
int read_small_file(const char *path, char *buf, int cap);
int apps_scan_dir(const char *appdir, const char *name, sbuf_t *out, int want_detail);
void req_free(req_t *r);
int is_hex(char c);
int hexval(char c);
void url_decode(const char *in, char *buf, int buflen);
int qparam(const char *query, const char *key, char *out, int outcap);
int path_segment(const char *prefix, const char *full, char *out, int outcap);
void split_path_query(const char *src, char *path, int plc, char *query, int qlc);
ptrdiff_t find_header_end(const char *buf, size_t n);
int read_request(int sock, req_t *r);
void mp_sha256_init(mp_sha256_ctx *c);
void mp_sha256_block(mp_sha256_ctx *c, const uint8_t *p);
void mp_sha256_update(mp_sha256_ctx *c, const uint8_t *data, size_t len);
void mp_sha256_final(mp_sha256_ctx *c, uint8_t out[32]);
int auth_read_random(unsigned char *buf, size_t n);
void auth_hex(const unsigned char *raw, size_t n, char *out);
int auth_token_gen(char *out, int outcap);
int auth_make_salt(char *out, int outcap);
int auth_pass_hash(const char *salt, const char *password, char *out, int outcap);
int auth_make_hash(const char *password, char *out, int outcap);
int hash_matches(const char *stored, const char *password);
int pin_set(void);
int auth_pass_set(void);
int auth_verify(const char *password);
int pin_verify(const char *pin);
int pin_validate(const char *pin);
long long pin_lock_remaining(void);
void pin_lock_reset(void);
void pin_record_fail(void);
int sess_find(const char *token);
int sess_valid(const char *token);
void sess_add(const char *token, time_t expires);
void sess_remove(const char *token);
void auth_cp(char *dst, int dcap, const char *src);
int extract_token(const req_t *r, char *out, int outcap);
int require_auth(int sock, const req_t *r);
int api_auth_status(int sock, const req_t *r);
int api_auth_login(int sock, const req_t *r);
int api_auth_setup(int sock, const req_t *r);
int api_auth_logout(int sock, const req_t *r);
int write_full(int sock, const void *b, size_t n);
int send_head(int sock, int status, const char *ctype, long long clen, const char *extra);
int send_raw(int sock, int status, const char *ctype, const void *body, size_t bodylen);
int send_ok(int sock, const char *data);
int send_err(int sock, int status, const char *code, const char *msg);
int send_json(int sock, int status, const char *data);
int send_file(int sock, int status, const char *ctype, const char *abspath, const char *filename);
const char *mem_find(const void *hay, size_t hlen, const char *needle);
int safe_filename(const char *name, char *out, size_t cap);
int parse_multipart(const req_t *r, upfile_t *files, int maxfiles);
void panel_log(const char *fmt, ...);
int str_truthy(const char *v);
int int_meta_max(const setdef_t *d);
const char *csv_at(const char *s, int idx, char *buf, int buflen);
int csv_count(const char *s);
void enum_options_json(sbuf_t *s, const char *names, const char *labels);
void settings_item_json(sbuf_t *s, const setdef_t *d, const char *val);
char *settings_current_value(const setdef_t *d);
int api_settings_get_any(int sock, const char *key);
int api_settings_get_all(int sock);
int api_settings_put(int sock, const char *key, const req_t *r);
int api_settings_batch(int sock, const req_t *r);
int api_settings_restore(int sock);
void theme_json(sbuf_t *s);
int api_theme_get(int sock);
int api_theme_put(int sock, const req_t *r);
int api_perf(int sock, const char *path);
int perf_extract_network(const char *json, char *out, int cap);
int api_system(int sock);
int api_pin_unlock_once(int sock);
int api_system_action(int sock, const char *which, const req_t *r);
int api_key_single(int sock, int code, const req_t *r);
int api_key_batch(int sock, const req_t *r);
const char *log_group(const char *name);
int api_logs_list(int sock);
int api_logs_read(int sock, const req_t *r);
int api_logs_crash(int sock);
int notif_csv_field(const char **pp, char *out, int outcap);
int notif_parse_line(const char *line, notif_rec_t *r);
int notif_load_list(notif_rec_t *recs, int maxrec);
const char *notif_app_name(const char *app_id);
void notif_emit_item(sbuf_t *out, const notif_rec_t *r);
int notif_ipc_query(notif_rec_t *recs, int maxrec);
int notif_ipc_dismiss(unsigned id);
int notif_ipc_dismiss_all(int *out_count);
int api_notifications(int sock);
int notif_rewrite(int mode, unsigned del_id);
int api_notification_delete(int sock, unsigned id);
int api_notification_dismiss_all(int sock);
int api_files_list(int sock, const req_t *r);
int api_files_read(int sock, const req_t *r);
int api_files_download(int sock, const req_t *r);
int files_search_json(const char *abs_start, const char *name, const char *typef, int max, sbuf_t *out); /* F1-④ 搜索核心(selftest 可测) */
int api_files_search(int sock, const req_t *r); /* F1-④ GET /api/files/search(只读) */
int api_files_upload(int sock, const req_t *r);
int rm_recursive(const char *path);
int api_files_mkdir(int sock, const req_t *r);
int api_files_rename(int sock, const req_t *r);
int api_files_delete(int sock, const req_t *r);
void fonts_root(char *buf, size_t cap);
int safe_dir_segment(const char *s, char *out, size_t cap);
int unsafe_path(const char *s);
int has_dotdot_comp(const char *p);
int sanitize_member(const char *in, char *out, int n);
int mkdir_p(const char *path);
const jv_t *font_json_str(const jv_t *root, const char *key);
int api_fonts_list(int sock);
int sha256_file_hex(const char *path, char out[65]);
int api_fonts_import(int sock, const req_t *r);
int api_fonts_export(int sock, const req_t *r);
int run_cmd(const char *cmd, char *out, int outcap);
int api_apps_list(int sock);
int api_apps_info(int sock, const char *pkg);
int multipart_extract_file(const req_t *r, const char *outpath);
const char *nyai_bin(void);
int api_apps_install(int sock, const req_t *r);
int api_apps_export(int sock, const char *pkg);
int api_apps_remove(int sock, const char *pkg, const req_t *r);
int screen_read_frame(const char *dev, uint8_t **out, int *w, int *h);
int fb_dims(const char *dev, int *w, int *h);
void screen_prev_store(const uint8_t *frame, int w, int h);
int screen_diff_blocks(const uint8_t *cur, const uint8_t *prev, int w, int h, int *bx, int *by, int *bw, int *bh, int *total_blocks);
int api_screen_jpeg(int sock, const req_t *r);
int64_t now_mono_ms(void);
int64_t touch_last_local_ms(const char *dev);
int inject_tap(const char *dev, int x, int y);
int inject_swipe(const char *dev, int x0, int y0, int x1, int y1);
int api_input_tap(int sock, const req_t *r);
int api_input_gesture(int sock, const req_t *r);
const char *web_root(void);
const char *mime_for(const char *path);
int serve_static(int sock, const char *path);
int handle(int sock, req_t *r);
int read_port_config(void);
void handle_conn(int sock);
int panel_selftest(void);
int main(int argc, char **argv);
#endif /* MP_H */