Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ffe07ff48 | ||
|
|
52e0270c80 |
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user