/* 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 #include #include #include /* strcasecmp/strncasecmp */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* 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 ) */ char x_meow_token[256]; /* X-MeowToken 头 */ char cookie[512]; /* Cookie 头(meow_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 */