// Entwickler-Werkzeuge nur für Admins: Die App fragt bei MBMNET, ob die im MBMNET-Platz verknüpfte ID einem // Admin gehört (GET /mbmnet/app-info?pid=...). Ohne verknüpfte MBMNET-ID gibt es keine Werkzeuge. // Die Antwort wird mit der Kennung (PID) auf der SD gemerkt: Ohne Verbindung gilt sie nur für dasselbe Konto. #include <3ds.h> #include #include #include "admin.h" #define CACHE_FILE "sdmc:/3ds/mbmnet/admin" static volatile bool isAdmin; static Thread thread; static char url[128]; static u32 currentPid; static void remember(bool on) { FILE *f = fopen(CACHE_FILE, "w"); if (f) { fprintf(f, "%lu %d\n", (unsigned long)currentPid, on ? 1 : 0); fclose(f); } } static void worker(void *arg) { (void)arg; httpcContext ctx; if (R_FAILED(httpcOpenContext(&ctx, HTTPC_METHOD_GET, url, 1))) return; httpcAddRequestHeaderField(&ctx, "User-Agent", "MBMNET-Switcher/" APP_VERSION); u32 status = 0, got = 0; char body[32] = { 0 }; Result rc = httpcBeginRequest(&ctx); if (R_SUCCEEDED(rc)) rc = httpcGetResponseStatusCodeTimeout(&ctx, &status, 8ULL * 1000 * 1000 * 1000); if (R_SUCCEEDED(rc) && status == 200) httpcDownloadData(&ctx, (u8 *)body, sizeof(body) - 1, &got); httpcCloseContext(&ctx); if (status != 200 || strncmp(body, "admin=", 6) != 0) return; // keine Antwort: gemerkte gilt weiter isAdmin = body[6] == '1'; remember(isAdmin); } void admin_start(const char *server, u32 pid) { currentPid = pid; isAdmin = false; if (!pid) { remove(CACHE_FILE); return; } // keine MBMNET-ID verknüpft: keine Werkzeuge // Gemerkte Antwort nur, wenn sie zu genau diesem Konto gehört (alte Dateien ohne PID zählen nicht) FILE *f = fopen(CACHE_FILE, "r"); if (f) { unsigned long cachedPid = 0; int on = 0; if (fscanf(f, "%lu %d", &cachedPid, &on) == 2 && cachedPid == pid) isAdmin = on == 1; fclose(f); } snprintf(url, sizeof(url), "http://%s/mbmnet/app-info?pid=%lu", server, (unsigned long)pid); s32 prio = 0x30; svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); thread = threadCreate(worker, NULL, 16 * 1024, prio + 1, -2, false); } bool admin_is(void) { return isAdmin; } bool admin_finish(void) { if (!thread) return true; if (R_FAILED(threadJoin(thread, 100ULL * 1000 * 1000))) return false; // läuft noch threadFree(thread); thread = NULL; return true; }