/* meow_ipc.c — MeowOS IPC 测试钩子(阶段 D · M0+M1;与 evtool 同定位)。 * * 向 meow_launcherd 的 AF_UNIX IPC(FRAMEWORK_DESIGN §1)发帧、收应答并打印。 * 静态 MIPS32r2 musl(用 zig-mipsel-cc 编译),qemu-mipsel 亦可用。 * * 子命令: * meow_ipc hello [version] [flags] → MSG_HELLO,期望 MSG_ACK * meow_ipc ping [app_id] → hello 别名(默认 meow_ipc) * meow_ipc query → MSG_ACT_QUERY,期望 MSG_ACT_RESULT * meow_ipc declare [...] → MSG_ACT_DECLARE,期望 MSG_ACK * 全局: * --sock 覆盖 socket 路径(默认可被 MEOW_IPC_SOCK 覆盖,再回退 /usr/data/meow_ipc.sock) */ #include #include #include #include #include #include #include #include #include #include #include "meow_ipc.h" static const char *g_sock = NULL; static void print_err(const m_err_t *e) { fprintf(stderr, "ERR 0x%x: %.*s\n", e->code, e->msg_len < 64 ? e->msg_len : 64, e->msg); } static int connect_path(const char *path) { int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); return -1; } struct sockaddr_un a; memset(&a, 0, sizeof a); a.sun_family = AF_UNIX; strncpy(a.sun_path, path, sizeof a.sun_path - 1); if (connect(fd, (struct sockaddr *)&a, sizeof a) < 0) { fprintf(stderr, "connect %s: %s\n", path, strerror(errno)); close(fd); return -1; } return fd; } /* 发一帧(头+负载),读回一帧(头+负载)。返回应答类型;-1=失败。 */ static int xchg(int fd, uint16_t type, uint32_t req_id, const void *payload, uint32_t len, uint8_t *rbuf, uint32_t rcap) { uint8_t hdr[MEOW_IPC_HDR_LEN]; uint32_t magic = MEOW_IPC_MAGIC; uint16_t ver = MEOW_IPC_VERSION; memcpy(hdr + 0, &magic, 4); memcpy(hdr + 4, &ver, 2); memcpy(hdr + 6, &type, 2); memcpy(hdr + 8, &req_id, 4); memcpy(hdr + 12, &len, 4); size_t off = 0; while (off < sizeof hdr) { ssize_t w = write(fd, hdr + off, sizeof hdr - off); if (w <= 0) { perror("write hdr"); return -1; } off += (size_t)w; } if (len && payload) { size_t p = 0; while (p < len) { ssize_t w = write(fd, (const uint8_t *)payload + p, len - p); if (w <= 0) { perror("write payload"); return -1; } p += (size_t)w; } } /* read response header */ uint8_t rhdr[MEOW_IPC_HDR_LEN]; off = 0; while (off < sizeof rhdr) { ssize_t r = read(fd, rhdr + off, sizeof rhdr - off); if (r <= 0) { perror("read hdr"); return -1; } off += (size_t)r; } uint32_t rmagic, rlen; uint16_t rver, rtype; memcpy(&rmagic, rhdr, 4); memcpy(&rver, rhdr + 4, 2); memcpy(&rtype, rhdr + 6, 2); memcpy(&rlen, rhdr + 12, 4); if (rmagic != MEOW_IPC_MAGIC) { fprintf(stderr, "bad resp magic %08x\n", rmagic); return -1; } if (rver != MEOW_IPC_VERSION) { fprintf(stderr, "bad resp version %u\n", rver); return -1; } if (rlen > rcap) rlen = rcap; off = 0; while (off < rlen) { ssize_t r = read(fd, rbuf + off, rlen - off); if (r <= 0) { perror("read payload"); return -1; } off += (size_t)r; } return (int)rtype; } static int cmd_hello(const char *app_id, uint32_t version, uint32_t flags) { const char *sock = g_sock; int fd = connect_path(sock); if (fd < 0) return 1; m_hello_t h; memset(&h, 0, sizeof h); strncpy(h.app_id, app_id, MEOW_APP_ID_MAX - 1); h.version = version; h.flags = flags; uint8_t rbuf[256]; int rt = xchg(fd, MSG_HELLO, 1, &h, sizeof h, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("HELLO ok: code=%d status=%u (apps registered)\n", a.code, a.status); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "HELLO: unexpected resp type 0x%04x\n", rt); return 1; } static int cmd_query(const char *app_id, const char *activity) { int fd = connect_path(g_sock); if (fd < 0) return 1; m_act_query_t q; memset(&q, 0, sizeof q); strncpy(q.app_id, app_id, MEOW_APP_ID_MAX - 1); strncpy(q.activity, activity, MEOW_ACT_MAX - 1); uint8_t rbuf[256]; int rt = xchg(fd, MSG_ACT_QUERY, 2, &q, sizeof q, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACT_RESULT) { m_act_result_t r; memcpy(&r, rbuf, sizeof r); size_t cl = r.chain_len < MEOW_CHAIN_MAX ? r.chain_len : MEOW_CHAIN_MAX - 1; char chain[MEOW_CHAIN_MAX]; memcpy(chain, r.chain, cl); chain[cl] = 0; printf("QUERY ok: app=%s act=%s depth=%u chain=%s\n", app_id, activity, r.depth, cl ? chain : "(empty)"); return r.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "QUERY: unexpected resp type 0x%04x\n", rt); return 1; } static int cmd_declare(const char *app_id, int nent, char **ents) { int fd = connect_path(g_sock); if (fd < 0) return 1; m_act_declare_t d; memset(&d, 0, sizeof d); strncpy(d.app_id, app_id, MEOW_APP_ID_MAX - 1); int n = 0; char *p = d.entries; for (int i = 0; i < nent && n < 8; i++) { size_t l = strlen(ents[i]); if (l + 1 > (size_t)(d.entries + sizeof d.entries - p)) break; memcpy(p, ents[i], l + 1); p += l + 1; n++; } d.count = (uint16_t)n; uint32_t len = (uint32_t)(sizeof d.app_id + 2 + 2 + (p - d.entries)); uint8_t rbuf[256]; int rt = xchg(fd, MSG_ACT_DECLARE, 3, &d, len, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("DECLARE ok: app=%s n=%d code=%d\n", app_id, n, a.code); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "DECLARE: unexpected resp type 0x%04x\n", rt); return 1; } static int cmd_focus(const char *app_id, const char *activity) { int fd = connect_path(g_sock); if (fd < 0) return 1; m_act_focus_t f; memset(&f, 0, sizeof f); strncpy(f.app_id, app_id, MEOW_APP_ID_MAX - 1); strncpy(f.activity, activity, MEOW_ACT_MAX - 1); uint8_t rbuf[256]; int rt = xchg(fd, MSG_ACT_FOCUS, 4, &f, sizeof f, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("FOCUS ok: app=%s act=%s code=%d\n", app_id, activity, a.code); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "FOCUS: unexpected resp type 0x%04x\n", rt); return 1; } static int cmd_back(void) { int fd = connect_path(g_sock); if (fd < 0) return 1; uint8_t rbuf[256]; int rt = xchg(fd, MSG_ACT_BACK, 5, NULL, 0, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("BACK ok: code=%d\n", a.code); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "BACK: unexpected resp type 0x%04x\n", rt); return 1; } /* M3:上报导航 → MSG_NAV,期望 MSG_ACK。 * nav report 上报栈深/顶层(MEOW_NAV_REPORT) * nav exit 请求退出(MEOW_NAV_EXIT) */ static int cmd_nav(const char *app_id, int exit_req, uint32_t depth, const char *top) { int fd = connect_path(g_sock); if (fd < 0) return 1; m_nav_t n; memset(&n, 0, sizeof n); strncpy(n.app_id, app_id, MEOW_APP_ID_MAX - 1); n.nav_type = exit_req ? MEOW_NAV_EXIT : MEOW_NAV_REPORT; n.depth = depth; if (top) strncpy(n.current, top, MEOW_ACT_MAX - 1); uint8_t rbuf[256]; int rt = xchg(fd, MSG_NAV, 10, &n, sizeof n, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("NAV ok: app=%s type=%u depth=%u top=\"%s\" code=%d\n", app_id, n.nav_type, depth, n.current, a.code); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "NAV: unexpected resp type 0x%04x\n", rt); return 1; } /* M2a:推送通知 → MSG_NOTIFY,期望 MSG_NOTIFY_ACK。 */ static int cmd_notify(const char *app_id, const char *category, const char *summary, const char *body, uint32_t replaces_id, int ongoing, int media, int progress, const char *target_activity) { int fd = connect_path(g_sock); if (fd < 0) return 1; m_notify_t n; memset(&n, 0, sizeof n); strncpy(n.app_id, app_id, MEOW_APP_ID_MAX - 1); strncpy(n.category, category, sizeof n.category - 1); strncpy(n.summary, summary, sizeof n.summary - 1); if (body) strncpy(n.body, body, sizeof n.body - 1); if (target_activity) strncpy(n.target_activity, target_activity, MEOW_ACT_MAX - 1); n.replaces_id = replaces_id; n.ongoing = ongoing ? 1 : 0; n.media = media ? 1 : 0; n.progress = progress; n.expire_timeout = ongoing ? 0xFFFFFFFFu : 0; /* ONGOING 常驻 */ uint8_t rbuf[256]; int rt = xchg(fd, MSG_NOTIFY, 6, &n, sizeof n, rbuf, sizeof rbuf); close(fd); if (rt == MSG_NOTIFY_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("NOTIFY ok: id=%u code=%d\n", a.status, a.code); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "NOTIFY: unexpected resp type 0x%04x\n", rt); return 1; } /* M2a:撤下通知 → MSG_NOTIFY_DISMISS,期望 MSG_ACK。 */ static int cmd_dismiss(uint32_t id) { int fd = connect_path(g_sock); if (fd < 0) return 1; uint8_t rbuf[256]; int rt = xchg(fd, MSG_NOTIFY_DISMISS, 7, &id, sizeof id, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("DISMISS ok: id=%u code=%d\n", id, a.code); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "DISMISS: unexpected resp type 0x%04x\n", rt); return 1; } /* 查询当前内存活跃通知集 → MSG_NOTIFY_QUERY,期望 MSG_NOTIFY_QUERY_RESULT(打印 JSON 文本)。 * 可选 过滤(缺省=全部)。 */ static int cmd_querynotif(const char *app_id) { int fd = connect_path(g_sock); if (fd < 0) return 1; uint8_t rbuf[MEOW_IPC_MAX]; int rt = xchg(fd, MSG_NOTIFY_QUERY, 8, app_id, app_id ? (uint32_t)strlen(app_id) : 0, rbuf, sizeof rbuf); close(fd); if (rt == MSG_NOTIFY_QUERY_RESULT) { m_notify_query_result_t r; memcpy(&r, rbuf, sizeof r); uint32_t tl = r.text_len < sizeof r.text ? r.text_len : sizeof r.text - 1; printf("QUERY ok: code=%d len=%u\n%s\n", r.code, (unsigned)tl, r.text); return r.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "QUERY: unexpected resp type 0x%04x\n", rt); return 1; } /* 一键清除(保留 ongoing/media/progress)→ MSG_NOTIFY_DISMISS_ALL,期望 MSG_ACK(status=清除数)。 */ static int cmd_dismissall(void) { int fd = connect_path(g_sock); if (fd < 0) return 1; uint8_t rbuf[256]; int rt = xchg(fd, MSG_NOTIFY_DISMISS_ALL, 9, NULL, 0, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("DISMISS_ALL ok: code=%d cleared=%u\n", a.code, a.status); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "DISMISS_ALL: unexpected resp type 0x%04x\n", rt); return 1; } /* 阶段 D 附录 B:媒体会话上报 → MSG_META,期望 MSG_ACK。 * meta <artist> <album> [artwork] */ static int cmd_meta(const char *app_id, uint32_t state, uint32_t pos, uint32_t dur, const char *title, const char *artist, const char *album, const char *artwork) { int fd = connect_path(g_sock); if (fd < 0) return 1; m_meta_t mm; memset(&mm, 0, sizeof mm); strncpy(mm.app_id, app_id, MEOW_APP_ID_MAX - 1); mm.state = state; mm.pos_ms = pos; mm.dur_ms = dur; snprintf(mm.title, sizeof mm.title, "%s", title); snprintf(mm.artist, sizeof mm.artist, "%s", artist); snprintf(mm.album, sizeof mm.album, "%s", album); if (artwork) snprintf(mm.artwork, sizeof mm.artwork, "%s", artwork); uint8_t rbuf[256]; int rt = xchg(fd, MSG_META, 11, &mm, sizeof mm, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("META ok: app=%s state=%u code=%d\n", app_id, state, a.code); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "META: unexpected resp type 0x%04x\n", rt); return 1; } /* 控制转发 → MSG_PLAYCTL(launcher 转发到最近活跃媒体会话),期望 MSG_ACK。 * playctl <cmd> [seek_ms] (cmd 1=播放 2=暂停 3=上一首 4=下一首 5=seek) */ static int cmd_playctl(uint32_t cmd, int64_t seek_ms) { int fd = connect_path(g_sock); if (fd < 0) return 1; m_playctl_t c; memset(&c, 0, sizeof c); c.cmd = cmd; c.seek_ms = seek_ms; uint8_t rbuf[256]; int rt = xchg(fd, MSG_PLAYCTL, 12, &c, sizeof c, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("PLAYCTL ok: cmd=%u seek=%lld code=%d (status=%d)\n", cmd, (long long)seek_ms, a.code, (int)a.status); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "PLAYCTL: unexpected resp type 0x%04x\n", rt); return 1; } /* 读一帧(头+负载)→ 返回负载长;-1=连接断/坏帧。type/req_id 输出。 */ static int read_frame(int fd, uint16_t *type, uint32_t *req_id, uint8_t *rbuf, uint32_t rcap) { uint8_t rhdr[MEOW_IPC_HDR_LEN]; size_t off = 0; while (off < sizeof rhdr) { ssize_t r = read(fd, rhdr + off, sizeof rhdr - off); if (r <= 0) return -1; off += (size_t)r; } uint32_t magic, len; uint16_t ver; memcpy(&magic, rhdr, 4); memcpy(&ver, rhdr + 4, 2); memcpy(type, rhdr + 6, 2); memcpy(req_id, rhdr + 8, 4); memcpy(&len, rhdr + 12, 4); if (magic != MEOW_IPC_MAGIC || ver != MEOW_IPC_VERSION) return -1; if (len > rcap) len = rcap; off = 0; while (off < len) { ssize_t r = read(fd, rbuf + off, len - off); if (r <= 0) return -1; off += (size_t)r; } return (int)len; } /* §10.5:App 前台顶部下滑 → 请求展开通知中心叠加会话 → MSG_NOTIF_OPEN,期望 MSG_ACK。 * notifopen <app_id> [origin_y] [hotzone] */ static int cmd_notifopen(const char *app_id, uint16_t origin_y, uint16_t hotzone) { int fd = connect_path(g_sock); if (fd < 0) return 1; m_notif_open_t o; memset(&o, 0, sizeof o); strncpy(o.app_id, app_id, MEOW_APP_ID_MAX - 1); o.event_seq = 1; o.origin_x = 0; o.origin_y = origin_y; o.hotzone = hotzone; uint8_t rbuf[256]; int rt = xchg(fd, MSG_NOTIF_OPEN, 20, &o, sizeof o, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("NOTIF_OPEN ok: app=%s oy=%u hz=%u code=%d status=%u\n", app_id, origin_y, hotzone, a.code, a.status); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "NOTIF_OPEN: unexpected resp type 0x%04x\n", rt); return 1; } /* §10.5:App 告知结束/退出 → MSG_NOTIF_CLOSE(launcher 收尾兜底),期望 MSG_ACK。 * notifclose <app_id> <reason> */ static int cmd_notifclose(const char *app_id, uint32_t reason) { int fd = connect_path(g_sock); if (fd < 0) return 1; m_notif_close_t o; memset(&o, 0, sizeof o); strncpy(o.app_id, app_id, MEOW_APP_ID_MAX - 1); o.reason = reason; uint8_t rbuf[256]; int rt = xchg(fd, MSG_NOTIF_CLOSE, 21, &o, sizeof o, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("NOTIF_CLOSE ok: app=%s reason=%u code=%d\n", app_id, reason, a.code); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "NOTIF_CLOSE: unexpected resp type 0x%04x\n", rt); return 1; } /* 媒体源监听:HELLO(MF_PLAYBACK) + META → 保持连接等待 launcher 下发 MSG_PLAYCTL。 * listen <app_id> <state> <pos_ms> <dur_ms> <title> <artist> <album> [artwork] */ static int cmd_listen(const char *app_id, uint32_t state, uint32_t pos, uint32_t dur, const char *title, const char *artist, const char *album, const char *artwork) { int fd = connect_path(g_sock); if (fd < 0) return 1; m_hello_t h; memset(&h, 0, sizeof h); strncpy(h.app_id, app_id, MEOW_APP_ID_MAX - 1); h.version = 1; h.flags = MF_PLAYBACK; uint8_t rbuf[256]; int rt = xchg(fd, MSG_HELLO, 1, &h, sizeof h, rbuf, sizeof rbuf); if (rt != MSG_ACK) { fprintf(stderr, "listen: HELLO resp 0x%04x\n", rt); close(fd); return 1; } m_meta_t mm; memset(&mm, 0, sizeof mm); strncpy(mm.app_id, app_id, MEOW_APP_ID_MAX - 1); mm.state = state; mm.pos_ms = pos; mm.dur_ms = dur; snprintf(mm.title, sizeof mm.title, "%s", title); snprintf(mm.artist, sizeof mm.artist, "%s", artist); snprintf(mm.album, sizeof mm.album, "%s", album); if (artwork) snprintf(mm.artwork, sizeof mm.artwork, "%s", artwork); rt = xchg(fd, MSG_META, 2, &mm, sizeof mm, rbuf, sizeof rbuf); if (rt != MSG_ACK) { fprintf(stderr, "listen: META resp 0x%04x\n", rt); close(fd); return 1; } printf("listen: source=%s registered (state=%u) — awaiting PLAYCTL...\n", app_id, state); fflush(stdout); /* 阻塞读:等待 launcher 下发 MSG_PLAYCTL(同一连接)。 */ for (;;) { uint16_t type; uint32_t req_id; int n = read_frame(fd, &type, &req_id, rbuf, sizeof rbuf); if (n < 0) { fprintf(stderr, "listen: conn closed\n"); close(fd); return 0; } if (type == MSG_PLAYCTL && n >= (int)sizeof(m_playctl_t)) { m_playctl_t c; memcpy(&c, rbuf, sizeof c); printf("RECV PLAYCTL: cmd=%u seek=%lld\n", c.cmd, (long long)c.seek_ms); fflush(stdout); } else { printf("RECV frame type=0x%04x len=%d\n", type, n); } } } int main(int argc, char **argv) { const char *env = getenv("MEOW_IPC_SOCK"); g_sock = (env && env[0]) ? env : MEOW_IPC_PATH; /* parse leading global options */ int i = 1; for (; i < argc; i++) { if (!strcmp(argv[i], "--sock") && i + 1 < argc) { g_sock = argv[++i]; } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { fprintf(stderr, "usage: meow_ipc [--sock <path>] hello|ping|query|declare ...\n"); return 0; } else break; } if (i >= argc) { fprintf(stderr, "bad args; try --help\n"); return 1; } const char *cmd = argv[i]; if (!strcmp(cmd, "hello")) { if (i + 1 >= argc) { fprintf(stderr, "hello needs <app_id>\n"); return 1; } uint32_t ver = (i + 2 < argc) ? (uint32_t)strtoul(argv[i + 2], NULL, 0) : 1; uint32_t flg = (i + 3 < argc) ? (uint32_t)strtoul(argv[i + 3], NULL, 0) : 0; return cmd_hello(argv[i + 1], ver, flg); } if (!strcmp(cmd, "ping")) { const char *app = (i + 1 < argc) ? argv[i + 1] : "meow_ipc"; return cmd_hello(app, 1, 0); } if (!strcmp(cmd, "query")) { if (i + 2 >= argc) { fprintf(stderr, "query needs <app_id> <activity>\n"); return 1; } return cmd_query(argv[i + 1], argv[i + 2]); } if (!strcmp(cmd, "declare")) { if (i + 2 >= argc) { fprintf(stderr, "declare needs <app_id> <route_id=chain> [...]\n"); return 1; } return cmd_declare(argv[i + 1], argc - i - 2, argv + i + 2); } if (!strcmp(cmd, "focus")) { if (i + 2 >= argc) { fprintf(stderr, "focus needs <app_id> <activity>\n"); return 1; } return cmd_focus(argv[i + 1], argv[i + 2]); } if (!strcmp(cmd, "back")) { return cmd_back(); } if (!strcmp(cmd, "notify")) { /* notify <app_id> <category> <summary> [body] [replaces_id] [ongoing] [media] [progress] [target_activity] */ if (i + 2 >= argc) { fprintf(stderr, "notify needs <app_id> <category> <summary>\n"); return 1; } const char *body = (i + 4 < argc) ? argv[i + 4] : ""; uint32_t rid = (i + 5 < argc) ? (uint32_t)strtoul(argv[i + 5], NULL, 0) : 0; int ongoing = (i + 6 < argc) ? atoi(argv[i + 6]) : 0; int media = (i + 7 < argc) ? atoi(argv[i + 7]) : 0; int progress = (i + 8 < argc) ? atoi(argv[i + 8]) : -1; const char *tgt = (i + 9 < argc) ? argv[i + 9] : ""; return cmd_notify(argv[i + 1], argv[i + 2], argv[i + 3], body, rid, ongoing, media, progress, tgt); } if (!strcmp(cmd, "dismiss")) { if (i + 1 >= argc) { fprintf(stderr, "dismiss needs <id>\n"); return 1; } return cmd_dismiss((uint32_t)strtoul(argv[i + 1], NULL, 0)); } if (!strcmp(cmd, "querynotif")) { const char *app = (i + 1 < argc) ? argv[i + 1] : NULL; return cmd_querynotif(app); } if (!strcmp(cmd, "dismissall")) { return cmd_dismissall(); } if (!strcmp(cmd, "meta")) { /* meta <app_id> <state> <pos_ms> <dur_ms> <title> <artist> <album> [artwork] */ if (i + 7 >= argc) { fprintf(stderr, "meta needs <app_id> <state> <pos_ms> <dur_ms> <title> <artist> <album>\n"); return 1; } uint32_t st = (uint32_t)strtoul(argv[i + 2], NULL, 0); uint32_t pos = (uint32_t)strtoul(argv[i + 3], NULL, 0); uint32_t dur = (uint32_t)strtoul(argv[i + 4], NULL, 0); const char *aw = (i + 8 < argc) ? argv[i + 8] : NULL; return cmd_meta(argv[i + 1], st, pos, dur, argv[i + 5], argv[i + 6], argv[i + 7], aw); } if (!strcmp(cmd, "listen")) { /* listen <app_id> <state> <pos_ms> <dur_ms> <title> <artist> <album> [artwork] */ if (i + 7 >= argc) { fprintf(stderr, "listen needs <app_id> <state> <pos_ms> <dur_ms> <title> <artist> <album>\n"); return 1; } uint32_t st = (uint32_t)strtoul(argv[i + 2], NULL, 0); uint32_t pos = (uint32_t)strtoul(argv[i + 3], NULL, 0); uint32_t dur = (uint32_t)strtoul(argv[i + 4], NULL, 0); const char *aw = (i + 8 < argc) ? argv[i + 8] : NULL; return cmd_listen(argv[i + 1], st, pos, dur, argv[i + 5], argv[i + 6], argv[i + 7], aw); } if (!strcmp(cmd, "playctl")) { if (i + 1 >= argc) { fprintf(stderr, "playctl needs <cmd> [seek_ms]\n"); return 1; } uint32_t cmd2 = (uint32_t)strtoul(argv[i + 1], NULL, 0); int64_t seek = (i + 2 < argc) ? (int64_t)strtoll(argv[i + 2], NULL, 0) : 0; return cmd_playctl(cmd2, seek); } if (!strcmp(cmd, "notifopen")) { /* notifopen <app_id> [origin_y] [hotzone] */ if (i + 1 >= argc) { fprintf(stderr, "notifopen needs <app_id>\n"); return 1; } uint16_t oy = (i + 2 < argc) ? (uint16_t)strtoul(argv[i + 2], NULL, 0) : 0; uint16_t hz = (i + 3 < argc) ? (uint16_t)strtoul(argv[i + 3], NULL, 0) : 28; return cmd_notifopen(argv[i + 1], oy, hz); } if (!strcmp(cmd, "notifclose")) { /* notifclose <app_id> <reason> */ if (i + 1 >= argc) { fprintf(stderr, "notifclose needs <app_id>\n"); return 1; } uint32_t r2 = (i + 2 < argc) ? (uint32_t)strtoul(argv[i + 2], NULL, 0) : 0; return cmd_notifclose(argv[i + 1], r2); } if (!strcmp(cmd, "nav")) { /* nav report <app_id> <depth> <top> | nav exit <app_id> */ if (i + 1 >= argc) { fprintf(stderr, "nav needs <app_id> and report|exit\n"); return 1; } int exit_req = (!strcmp(argv[i + 1], "exit") || !strcmp(argv[i + 1], "EXIT")); if (i + 2 >= argc) { fprintf(stderr, "nav needs <app_id>\n"); return 1; } uint32_t depth = (i + 3 < argc) ? (uint32_t)strtoul(argv[i + 3], NULL, 0) : 0; const char *top = (i + 4 < argc) ? argv[i + 4] : ""; return cmd_nav(argv[i + 2], exit_req, depth, top); } fprintf(stderr, "unknown cmd %s; try --help\n", cmd); return 1; }