diff --git a/Makefile b/Makefile index 8eac5cd..3b2ec92 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ SOURCES := source INCLUDES := source # Bei jedem Release erhöhen - das Auto-Update vergleicht diese Nummer -VERSION := 3.0.0 +VERSION := 3.0.1 APP_TITLE := MBMNET APP_DESCRIPTION := Dein eigenes 3DS-Netzwerk diff --git a/source/admin.c b/source/admin.c index 07fd9ee..36d4852 100644 --- a/source/admin.c +++ b/source/admin.c @@ -1,6 +1,6 @@ -// Entwickler-Werkzeuge nur für Admins: Die App fragt bei MBMNET, ob die verknüpfte NNID einem Admin -// gehört (GET /mbmnet/app-info?pid=...). Die Antwort wird auf der SD gemerkt, damit die Werkzeuge -// auch im Nintendo-Modus und ohne Verbindung da sind. +// 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 @@ -12,11 +12,12 @@ 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) { fputs(on ? "1" : "0", f); fclose(f); } + if (f) { fprintf(f, "%lu %d\n", (unsigned long)currentPid, on ? 1 : 0); fclose(f); } } static void worker(void *arg) @@ -38,9 +39,17 @@ static void worker(void *arg) 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) { isAdmin = fgetc(f) == '1'; fclose(f); } - if (!pid) return; + 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); diff --git a/source/main.c b/source/main.c index b462ab7..20deda3 100644 --- a/source/main.c +++ b/source/main.c @@ -155,7 +155,7 @@ static void draw_top(PatchState st, const char *msg, bool admin, bool isAdmin) { C2D_DrawRectangle(0, 0, 0, TOP_W, SCR_H, COL_BG2, COL_BG2, COL_BG, COL_BG); draw_update_line(admin); - const char *hint = admin ? "START: Beenden SELECT: Werkzeuge aus" : "START: Beenden SELECT: Werkzeuge"; + const char *hint = admin ? "START: Beenden SELECT: Werkzeuge aus" : isAdmin ? "START: Beenden SELECT: Werkzeuge" : "START: Beenden"; text(hint, 10, 4, 0.4f, COL_MUTED, 0); if (ftpOn) { // FTP-Adresse direkt daneben @@ -587,7 +587,17 @@ int main(int argc, char **argv) snprintf(msg, sizeof(msg), "Neuer Speicherort für die Patches!\nBitte MBMNET einmal neu antippen."); PatchState st = patch_state(); // Nur im MBMNET-Modus ist die verknüpfte NNID ein MBMNET-Konto - admin_start(server, st == STATE_MBMNET ? nnid_pid() : 0); + // Werkzeuge nur für Admins: gefragt wird mit der ID im MBMNET-Platz (auch wenn gerade Nintendo aktiv ist) + { + u8 mslot = frdswitch_slot_of(FRIEND_ACCOUNT_MBMNET); + char mid[20]; + u32 mpid = 0; + if (mslot && frdswitch_slot_linked(FRIEND_ACCOUNT_MBMNET, mid, sizeof(mid))) + ACT_GetAccountInfo(&mpid, sizeof(mpid), mslot, INFO_TYPE_PRINCIPAL_ID); + admin_start(server, mpid); + } + // Ein SpotPass-Test von früher (App mitten im Test verlassen) darf nicht weiterlaufen + spotpass_test_cancel(); // MBMNET aktiv, aber das Freundekonto hat eine fremde Kennung: darauf hinweisen if (st == STATE_MBMNET && frdswitch_current() == FRIEND_ACCOUNT_MBMNET) { @@ -621,7 +631,8 @@ int main(int argc, char **argv) u32 down = hidKeysDown(); if (--ftpCheckIn <= 0) { ftpCheckIn = 120; ftpOn = ftpctl_running(); } if (down & KEY_START && rebootIn == 0) break; // während des Umschaltens nicht abbrechen - if (down & KEY_SELECT) toolsToggled = !toolsToggled; + if (down & KEY_SELECT && admin_is()) toolsToggled = !toolsToggled; + if (!admin_is()) toolsToggled = false; // Werkzeuge nur für Admins (Server hat es bestätigt) // Werkzeuge nur mit SELECT, beim Öffnen immer aus bool admin = toolsToggled; if (!visible(selected, admin)) selected = admin || selected <= BTN_REBOOT ? BTN_ENABLE : BTN_SHOP; @@ -728,6 +739,7 @@ int main(int argc, char **argv) // schreiben sie nach dem Freigeben hinein und Luma zeigt einen Absturz (z. B. beim Neustart nach "Nintendo"). ftpctl_stop(NULL, 0); shopctl_exit(); + if (spotpassTestFrames >= 0) spotpass_test_cancel(); // App mitten im Test beendet // Update- und Admin-Abfrage nur kurz abwarten: Läuft noch etwas, beendet sich die App hart (schneller // Neustart nach dem Umschalten). Das Auffrischen schreibt Patch-Dateien - darauf warten (beim Umschalten // ist es ohnehin schon fertig, Aktionen warten darauf). diff --git a/source/spotpass.c b/source/spotpass.c index ec2ebe7..66e2a86 100644 --- a/source/spotpass.c +++ b/source/spotpass.c @@ -205,7 +205,9 @@ bool spotpass_test_start(const char *server, char *msg, size_t msglen) return false; } const char *step = ""; - rc = setup_task(server, TASK_TEST, testUrl, 60, &step); + // Abstand 24 h: Selbst wenn die Aufgabe stehen bleibt (App mitten im Test verlassen), kommt der Test + // nicht jede Minute wieder. Normalerweise löscht spotpass_test_poll/spotpass_test_cancel sie. + rc = setup_task(server, TASK_TEST, testUrl, 24 * 60 * 60, &step); if (R_SUCCEEDED(rc)) { step = "Aufgabe starten"; rc = bossStartTaskImmediate(TASK_TEST); } bossExit(); if (R_FAILED(rc)) { @@ -217,6 +219,13 @@ bool spotpass_test_start(const char *server, char *msg, size_t msglen) return true; } +void spotpass_test_cancel(void) +{ + if (R_FAILED(bossInit(0, false))) return; + bossDeleteTask(TASK_TEST, 0); + bossExit(); +} + bool spotpass_test_poll(int seconds, char *msg, size_t msglen) { if (R_FAILED(bossInit(0, false))) return true; diff --git a/source/spotpass.h b/source/spotpass.h index e58e6ad..fb91f08 100644 --- a/source/spotpass.h +++ b/source/spotpass.h @@ -3,7 +3,7 @@ #include // SpotPass (BOSS): Der 3DS holt MBMNET-Nachrichten und Ankündigungen selbst im Hintergrund ab (auch im -// Standby, ohne App) und zeigt sie als Mitteilung im HOME-Menü. Die Aufgabe ruft alle 2 Minuten +// Standby, ohne App) und zeigt sie als Mitteilung im HOME-Menü. Die Aufgabe ruft alle 15 Minuten // http:///spotpass//news.boss ab (MBMNET Accounting, spotpass.js). // Hintergrund-Aufgabe anmelden (bei aktivem MBMNET). false + msg bei Fehler. @@ -15,3 +15,6 @@ void spotpass_unregister(void); bool spotpass_test_start(const char *server, char *msg, size_t msglen); // true = Test noch nicht fertig. msg bekommt den Stand bzw. das Ergebnis. bool spotpass_test_poll(int seconds, char *msg, size_t msglen); +// Test-Aufgabe löschen (beim Start, beim Verlassen der App): Bleibt sie stehen, ruft der 3DS den Test +// immer wieder ab und zeigt jedes Mal eine neue Mitteilung. +void spotpass_test_cancel(void);