Compare commits

...
2 Commits
8 changed files with 83 additions and 15 deletions
+1 -1
View File
@@ -17,7 +17,7 @@ SOURCES := source
INCLUDES := source INCLUDES := source
# Bei jedem Release erhöhen - das Auto-Update vergleicht diese Nummer # Bei jedem Release erhöhen - das Auto-Update vergleicht diese Nummer
VERSION := 2.9.3 VERSION := 2.9.4
APP_TITLE := MBMNET APP_TITLE := MBMNET
APP_DESCRIPTION := Dein eigenes 3DS-Netzwerk APP_DESCRIPTION := Dein eigenes 3DS-Netzwerk
+5 -3
View File
@@ -49,9 +49,11 @@ void admin_start(const char *server, u32 pid)
bool admin_is(void) { return isAdmin; } bool admin_is(void) { return isAdmin; }
void admin_finish(void) bool admin_finish(void)
{ {
if (!thread) return; if (!thread) return true;
if (R_SUCCEEDED(threadJoin(thread, 3ULL * 1000 * 1000 * 1000))) threadFree(thread); if (R_FAILED(threadJoin(thread, 15ULL * 1000 * 1000 * 1000))) return false; // läuft noch
threadFree(thread);
thread = NULL; thread = NULL;
return true;
} }
+1 -1
View File
@@ -6,4 +6,4 @@
void admin_start(const char *server, u32 pid); void admin_start(const char *server, u32 pid);
// Admin? (gemerkte Antwort, bis der Server geantwortet hat) // Admin? (gemerkte Antwort, bis der Server geantwortet hat)
bool admin_is(void); bool admin_is(void);
void admin_finish(void); bool admin_finish(void); // wartet höchstens 15 s, false = läuft noch
+46 -5
View File
@@ -6,6 +6,8 @@
#include <citro2d.h> #include <citro2d.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <strings.h>
#include <sys/stat.h>
#include "patcher.h" #include "patcher.h"
#include "update.h" #include "update.h"
@@ -394,14 +396,40 @@ static bool enable(bool confirmed, char *msg, size_t msglen)
return true; return true;
} }
// Umstellung auf den Zweitnamen (einmalig): Steht im MBMNET-Platz noch die ID unter dem echten Namen, blockiert
// sie eine gleichnamige Pretendo-ID (022-2571). Dann wird sie EINMAL gelöst; beim nächsten Wechsel zu MBMNET
// meldet man sich mit "<Name>.m" an, und ab dann bleibt alles verknüpft. note bekommt den Hinweis.
#define ALIAS_DONE_MARKER "sdmc:/3ds/mbmnet/zweitname-umgestellt"
static bool free_mbmnet_name(char *note, size_t len)
{
note[0] = 0;
FILE *m = fopen(ALIAS_DONE_MARKER, "r");
if (m) { fclose(m); return false; }
char id[20];
u8 slot = frdswitch_slot_of(FRIEND_ACCOUNT_MBMNET);
if (!slot || !frdswitch_slot_linked(FRIEND_ACCOUNT_MBMNET, id, sizeof(id))) return false;
size_t n = strlen(id);
if (n >= 2 && !strcasecmp(id + n - 2, ".m")) return false; // schon der Zweitname
remember_mbmnet_id(id);
if (!nnid_unlink_slot(slot, note, len)) return false;
mkdir("sdmc:/3ds/mbmnet", 0777);
m = fopen(ALIAS_DONE_MARKER, "w");
if (m) { fputs(id, m); fclose(m); }
snprintf(note, len, "\"%s\" ist jetzt frei für Pretendo.\nZurück bei MBMNET einmal mit \"%.14s.m\" anmelden,\ndanach nie wieder.", id, id);
return true;
}
// Zurück zu Nintendo. true = der 3DS muss jetzt neu starten. // Zurück zu Nintendo. true = der 3DS muss jetzt neu starten.
static bool disable(bool confirmed, char *msg, size_t msglen) static bool disable(bool confirmed, char *msg, size_t msglen)
{ {
(void)confirmed; (void)confirmed;
char detail[160] = ""; char detail[160] = "";
PatchState st = patch_state(); PatchState st = patch_state();
char note[200];
if (st == STATE_ORIGINAL && frdswitch_current() == FRIEND_ACCOUNT_NINTENDO) { if (st == STATE_ORIGINAL && frdswitch_current() == FRIEND_ACCOUNT_NINTENDO) {
snprintf(msg, msglen, "Nintendo ist schon aktiv."); if (free_mbmnet_name(note, sizeof(note))) snprintf(msg, msglen, "Nintendo ist schon aktiv.\n%s", note);
else if (note[0]) snprintf(msg, msglen, "%s", note);
else snprintf(msg, msglen, "Nintendo ist schon aktiv.");
return false; return false;
} }
if (st == STATE_FOREIGN) { if (st == STATE_FOREIGN) {
@@ -412,11 +440,13 @@ static bool disable(bool confirmed, char *msg, size_t msglen)
// anmelden). Den Namen merken, für den Hinweis auf den Zweitnamen. // anmelden). Den Namen merken, für den Hinweis auf den Zweitnamen.
char id[20] = ""; char id[20] = "";
if (frdswitch_current() == FRIEND_ACCOUNT_MBMNET && nnid_linked(id, sizeof(id))) remember_mbmnet_id(id); if (frdswitch_current() == FRIEND_ACCOUNT_MBMNET && nnid_linked(id, sizeof(id))) remember_mbmnet_id(id);
bool freed = free_mbmnet_name(note, sizeof(note));
bool created = false; bool created = false;
if (frdswitch_current() != FRIEND_ACCOUNT_NINTENDO && !frdswitch_to(FRIEND_ACCOUNT_NINTENDO, &created, msg, msglen)) return false; if (frdswitch_current() != FRIEND_ACCOUNT_NINTENDO && !frdswitch_to(FRIEND_ACCOUNT_NINTENDO, &created, msg, msglen)) return false;
patch_disable(detail, sizeof(detail)); patch_disable(detail, sizeof(detail));
spotpass_unregister(); spotpass_unregister();
snprintf(msg, msglen, "Nintendo aktiv! Der 3DS startet neu.\nDeine Nintendo-Freundesliste ist wieder da."); if (freed) snprintf(msg, msglen, "Nintendo aktiv! Der 3DS startet neu.\n%s", note);
else snprintf(msg, msglen, "Nintendo aktiv! Der 3DS startet neu.\nDeine Nintendo-Freundesliste ist wieder da.");
return true; return true;
} }
@@ -651,11 +681,22 @@ int main(int argc, char **argv)
C3D_FrameEnd(0); C3D_FrameEnd(0);
} }
// Hintergrund-Threads, die noch auf den Server warten, dürfen ihren Speicher nicht verlieren: Sonst
// schreiben sie nach dem Freigeben hinein und Luma zeigt einen Absturz (z. B. beim Neustart nach "Nintendo").
ftpctl_stop(NULL, 0); ftpctl_stop(NULL, 0);
shopctl_exit(); shopctl_exit();
if (maintenanceThread) { threadJoin(maintenanceThread, U64_MAX); threadFree(maintenanceThread); } bool clean = true;
admin_finish(); if (maintenanceThread) {
update_finish(); if (R_SUCCEEDED(threadJoin(maintenanceThread, 20ULL * 1000 * 1000 * 1000))) threadFree(maintenanceThread);
else clean = false;
}
clean = admin_finish() && clean;
clean = update_finish() && clean;
if (!clean) {
// Hart beenden, ohne Speicher freizugeben (der Kernel räumt alles auf)
aptExit();
svcExitProcess();
}
frdswitch_exit(); frdswitch_exit();
nnid_exit(); nnid_exit();
httpcExit(); httpcExit();
+19
View File
@@ -193,6 +193,25 @@ bool nnid_name_elsewhere(const char *name, u8 exceptSlot)
return false; return false;
} }
bool nnid_unlink_slot(u8 slot, char *msg, size_t msglen)
{
if (!ready) return false;
AccountId id = { 0 };
ACT_GetAccountInfo(id, sizeof(id), slot, INFO_TYPE_ACCOUNT_ID);
if (!id[0]) return true;
FILE *log = fopen(LOG_FILE, "a");
Result rc = ACTA_UnbindServerAccount(slot, true);
if (log) fprintf(log, "Platz %u (%s) lösen %08lX\n", slot, id, (unsigned long)rc);
if (R_FAILED(rc)) {
Result u = ACTA_UnloadConsoleAccount();
rc = ACTA_UnbindServerAccount(slot, true);
if (log) fprintf(log, " nach Abmelden (%08lX): %08lX\n", (unsigned long)u, (unsigned long)rc);
}
if (log) fclose(log);
if (R_FAILED(rc)) snprintf(msg, msglen, "\"%s\" (Platz %u) ließ sich nicht lösen (Fehler %08lX).", id, slot, (unsigned long)rc);
return R_SUCCEEDED(rc);
}
// Löst die ID "name" in allen Konto-Plätzen außer exceptSlot (nur auf dem 3DS). false + msg bei Fehler. // Löst die ID "name" in allen Konto-Plätzen außer exceptSlot (nur auf dem 3DS). false + msg bei Fehler.
bool nnid_unlink_named(const char *name, u8 exceptSlot, char *msg, size_t msglen) bool nnid_unlink_named(const char *name, u8 exceptSlot, char *msg, size_t msglen)
{ {
+2
View File
@@ -18,6 +18,8 @@ bool nnid_unlink(char *msg, size_t msglen);
// Gibt es die ID "name" in einem Konto-Platz außer exceptSlot? // Gibt es die ID "name" in einem Konto-Platz außer exceptSlot?
bool nnid_name_elsewhere(const char *name, u8 exceptSlot); bool nnid_name_elsewhere(const char *name, u8 exceptSlot);
// Löst die ID "name" in allen Konto-Plätzen außer exceptSlot (nur auf dem 3DS) // Löst die ID "name" in allen Konto-Plätzen außer exceptSlot (nur auf dem 3DS)
// Löst die ID in einem bestimmten Konto-Platz (nur auf dem 3DS). false + msg bei Fehler.
bool nnid_unlink_slot(u8 slot, char *msg, size_t msglen);
bool nnid_unlink_named(const char *name, u8 exceptSlot, char *msg, size_t msglen); bool nnid_unlink_named(const char *name, u8 exceptSlot, char *msg, size_t msglen);
// Schreibt alle Konto-Plätze in die Diagnose // Schreibt alle Konto-Plätze in die Diagnose
void nnid_dump(FILE *f); void nnid_dump(FILE *f);
+7 -4
View File
@@ -268,10 +268,13 @@ bool update_pending(void)
return state == UPD_AVAILABLE || state == UPD_DOWNLOADING || state == UPD_INSTALLED; return state == UPD_AVAILABLE || state == UPD_DOWNLOADING || state == UPD_INSTALLED;
} }
void update_finish(void) bool update_finish(void)
{ {
if (!thread) return; if (!thread) return true;
// Läuft der Download noch, nicht freigeben: Die App beendet sich ohnehin. // Läuft die Abfrage noch, nicht freigeben (sonst schreibt der Thread in freigegebenen Speicher).
if (R_SUCCEEDED(threadJoin(thread, 3ULL * 1000 * 1000 * 1000))) threadFree(thread); // false = läuft noch, die App muss sich hart beenden (main.c).
if (R_FAILED(threadJoin(thread, 15ULL * 1000 * 1000 * 1000))) return false;
threadFree(thread);
thread = NULL; thread = NULL;
return true;
} }
+2 -1
View File
@@ -21,7 +21,8 @@ void update_download(void);
bool update_pending(void); bool update_pending(void);
UpdateState update_state(void); UpdateState update_state(void);
const char *update_new_version(void); const char *update_new_version(void);
void update_finish(void); // Wartet auf den Hintergrund-Thread (höchstens 15 s). false = läuft noch.
bool update_finish(void);
// Laufender Download-Versuch (1-3) // Laufender Download-Versuch (1-3)
int update_attempt(void); int update_attempt(void);
// Beschreibung des letzten Fehlers (Schritt und Code) // Beschreibung des letzten Fehlers (Schritt und Code)