Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,7 @@ Indigo-specific rules:

- Required checks are `CI gate` (`.github/workflows/ci.yml`, waits on `checks`, `host` and `build-3ds`; add any new mandatory job to its `needs`) and `flow / conventions` (`.github/workflows/flow.yml`, Wolfram's reusable workflow). Never edit `.github/PULL_REQUEST_TEMPLATE.md` or the block above here; change them in Wolfram and copy them out.
- Run `scripts/check-flow.sh drift`, `scripts/check-flow.sh protocol` and `scripts/check-flow-selftest.sh` before pushing.
- Protocol guard: `scripts/check-flow.sh protocol` rejects raw `com.atproto.*`, `app.bsky.*` and `uk.ewancroft.*` method strings in `src/` unless listed with a reason in `scripts/flow-protocol-allow.txt`. Shared logic goes to Wolfram (and file persistence is `src/store/file.c`, which the session, settings and draft stores call instead of repeating it); reply gates are `wf_agent_set_reply_gate`; image attachments are `wolfram/attach.h` (type and size filter, folder scan, upload), and `src/app/social.c` and `src/atproto/session.c` only call it. The duplication with Cobalt tracked in #20 is closed (matching, time, failure kinds and pairing are all Wolfram's).
- Protocol guard: `scripts/check-flow.sh protocol` rejects raw `com.atproto.*`, `app.bsky.*` and `uk.ewancroft.*` method strings in `src/` unless listed with a reason in `scripts/flow-protocol-allow.txt`. Shared logic goes to Wolfram (and file persistence is `src/store/file.c`, which the session, settings and draft stores call instead of repeating it); reply gates are `wf_agent_set_reply_gate`; saved feeds are `wf_agent_get_saved_feeds`; image attachments are `wolfram/attach.h` (type and size filter, folder scan, upload), and `src/app/social.c` and `src/atproto/session.c` only call it. The duplication with Cobalt tracked in #20 is closed (matching, time, failure kinds and pairing are all Wolfram's).
- Doc drift: every `src/`, `scripts/`, `tools/`, `mk/`, `docs/`, `tests/` path and `make` target named in backticks in the docs must exist. Deliberate exceptions go in `scripts/flow-drift-allow.txt` with a reason.
- Never weaken a check to make it pass. A new Indigo check needs a deliberate-violation case in `scripts/check-flow-selftest.sh`.
- Update CHANGELOG under `## [Unreleased]` in the same PR as a user-visible change.
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ as the release notes.
- I can attach one picture to a post, reply or quote: SELECT, or the "Add an image" button in compose, opens a list of the JPEG and PNG files in `sdmc:/3ds/indigo/images` (under 950 KB), then asks for alt text. Wolfram does the filtering and the upload. The upload has not been run on an emulator or a 3DS. ([#58](https://github.com/ewanc26/indigo/pull/58))

### Changed
- The feed picker reads the saved feeds through Wolfram v0.35.0's `wf_agent_get_saved_feeds`; my copy of the preferences walk is deleted. ([#65](https://github.com/ewanc26/indigo/pull/65))
- Reply gates are set with Wolfram v0.34.0's `wf_agent_set_reply_gate`; my copy of the threadgate rules is deleted. ([#59](https://github.com/ewanc26/indigo/pull/59))
- What kind of failure a call was (wrong credentials, no network, a slow service, a TLS problem, a rate limit, a server fault, a reply I could not read) is Wolfram's `wf_failure_classify` and `wf_failure_tag` now, instead of a copy of them in `session.c` and `errors.c`; only the wording stays here. Nothing you would see changes ([#56](https://github.com/ewanc26/indigo/pull/56), [#20](https://github.com/ewanc26/indigo/issues/20)).
- Muted-word matching and the RFC 3339 timestamp code are Wolfram's now, not copies of Cobalt's: the matcher is `wf_muted_words_match` and the clock-free parsing and formatting are `wolfram/time.h`. A mute's expiry is checked at match time with Wolfram's parser, which also reads numeric offsets (the old one refused them). My copies, about 250 lines, are deleted. The host build now needs a Wolfram checkout and cJSON's headers ([#54](https://github.com/ewanc26/indigo/pull/54), [#20](https://github.com/ewanc26/indigo/issues/20)).
Expand Down
2 changes: 1 addition & 1 deletion mk/host.mk
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ endif
HOST_CJSON_CFLAGS ?= $(shell pkg-config --cflags libcjson 2>/dev/null)
HOST_CJSON_LIBS ?= $(shell pkg-config --libs libcjson 2>/dev/null || echo -lcjson)
HOST_WOLFRAM_INC := -I$(WOLFRAM_ROOT)/include $(HOST_CJSON_CFLAGS)
HOST_WOLFRAM_FILES := src/agent/muted_words.c src/agent/moderation.c src/failure.c src/time.c src/cdn.c src/attach.c src/update/ed25519.c \
HOST_WOLFRAM_FILES := src/agent/muted_words.c src/agent/moderation.c src/failure.c src/time.c src/cdn.c src/attach.c src/util.c src/update/ed25519.c \
src/update/signature.c src/update/update_core.c
HOST_WOLFRAM_CXX_FILES := cpp/wolfram/syntax.cpp
HOST_WOLFRAM_OBJS := $(addprefix $(HOST_OUT)/wf_,$(subst /,_,$(HOST_WOLFRAM_FILES:.c=.o))) \
Expand Down
1 change: 1 addition & 0 deletions src/atproto/session_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include <wolfram/agent.h>
#include <wolfram/attach.h>
#include <wolfram/oauth_pairing.h>
#include <wolfram/saved_feeds.h>
#include <wolfram/feed_gen_typed.h>
#include <wolfram/list_typed.h>
#include <wolfram/moderation_typed.h>
Expand Down
107 changes: 11 additions & 96 deletions src/atproto/session_lists.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,8 @@ void
indigo_session_do_feeds(const indigo_job *j)
{
indigo_session_event ev = {.kind = INDIGO_SESSION_EVENT_SEARCH_FAILED};
char *prefs_json = NULL;
const char *uris[INDIGO_SEARCH_MAX];
unsigned n = 0;
wf_saved_feed feeds[INDIGO_SEARCH_MAX];
size_t n = 0;
wf_status st;

(void) j;
Expand All @@ -162,105 +161,21 @@ indigo_session_do_feeds(const indigo_job *j)
indigo_session_publish_event(&ev);
return;
}
st = wf_agent_get_preferences(g_session.agent, &prefs_json);
if (st != WF_OK || !prefs_json) {
st = wf_agent_get_saved_feeds(g_session.agent, feeds, INDIGO_SEARCH_MAX, &n);
if (st != WF_OK) {
indigo_session_publish_failure(&ev, "preferences", st);
return;
}
{
cJSON *prefs = cJSON_Parse(prefs_json);
const cJSON *pref = NULL;

free(prefs_json);
if (!cJSON_IsArray(prefs)) {
cJSON_Delete(prefs);
ev.failure = WF_FAIL_OTHER;
indigo_log_warn("preferences: not an array");
indigo_session_publish_event(&ev);
return;
}
cJSON_ArrayForEach(pref, prefs) {
const cJSON *type = cJSON_GetObjectItemCaseSensitive(pref, "$type");

if (!cJSON_IsString(type)
|| !strstr(type->valuestring, "savedFeedsPrefV2")) {
continue;
}
{
const cJSON *items = cJSON_GetObjectItemCaseSensitive(pref, "items");
const cJSON *it = NULL;

cJSON_ArrayForEach(it, items) {
const cJSON *kind = cJSON_GetObjectItemCaseSensitive(it, "type");
const cJSON *value = cJSON_GetObjectItemCaseSensitive(it, "value");

if (n < INDIGO_SEARCH_MAX && cJSON_IsString(kind)
&& cJSON_IsString(value) && !strcmp(kind->valuestring, "feed")
&& value->valuestring[0]) {
uris[n++] = value->valuestring;
}
}
}
}
if (n == 0) {
/* Older accounts only have the V1 list. */
cJSON_ArrayForEach(pref, prefs) {
const cJSON *type = cJSON_GetObjectItemCaseSensitive(pref, "$type");

if (!cJSON_IsString(type)
|| !strstr(type->valuestring, "savedFeedsPref")) {
continue;
}
{
const cJSON *saved = cJSON_GetObjectItemCaseSensitive(pref, "saved");
const cJSON *it = NULL;

cJSON_ArrayForEach(it, saved) {
if (n < INDIGO_SEARCH_MAX && cJSON_IsString(it)
&& it->valuestring[0]) {
uris[n++] = it->valuestring;
}
}
}
}
}
cJSON_Delete(prefs);
}

g_session.feed_count = 0;
if (n > 0) {
wf_feedgen_generator_list gens;
for (size_t i = 0; i < n; i++) {
indigo_list *o = &g_session.feeds[g_session.feed_count];

memset(&gens, 0, sizeof gens);
st = wf_feedgen_get_feed_generators_typed(g_session.agent, uris, n, &gens);
if (st != WF_OK) {
/* The URIs alone still make a picker; the record key stands in
* for the name, the same fallback Cobalt uses. */
indigo_log_warn("feed generators failed: wolfram status %d", (int) st);
memset(&gens, 0, sizeof gens);
}
for (unsigned i = 0; i < n; i++) {
const char *name = NULL;
indigo_list *o = &g_session.feeds[g_session.feed_count];

for (size_t g = 0; g < gens.generator_count; g++) {
if (gens.generators[g].uri && !strcmp(gens.generators[g].uri, uris[i])) {
name = gens.generators[g].display_name;
break;
}
}
if (!name || !name[0]) {
const char *slash = strrchr(uris[i], '/');

name = slash ? slash + 1 : uris[i];
}
memset(o, 0, sizeof *o);
indigo_copy_utf8(o->uri, sizeof o->uri, uris[i]);
indigo_copy_utf8(o->name, sizeof o->name, name);
indigo_copy_utf8(o->description, sizeof o->description, "Custom feed");
g_session.feed_count++;
}
wf_feedgen_generator_list_free(&gens);
memset(o, 0, sizeof *o);
indigo_copy_utf8(o->uri, sizeof o->uri, feeds[i].uri);
indigo_copy_utf8(o->name, sizeof o->name, feeds[i].name);
indigo_copy_utf8(o->description, sizeof o->description, "Custom feed");
g_session.feed_count++;
}
ev.kind = INDIGO_SESSION_EVENT_FEEDS_PAGE;
ev.page_count = g_session.feed_count;
Expand Down
2 changes: 1 addition & 1 deletion wolfram.ref
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.34.0
v0.35.0
Loading