From 5a9ab28e4197a0c9a4b860ac7460272316c430b6 Mon Sep 17 00:00:00 2001 From: Alex9303 Date: Wed, 18 Feb 2026 10:34:10 -0500 Subject: [PATCH 1/4] Match rest of NWC24 --- include/revolution/NWC24/NWC24DateParser.h | 9 + include/revolution/NWC24/NWC24MBoxCtrl.h | 55 + include/revolution/NWC24/NWC24Manage.h | 2 +- include/revolution/NWC24/NWC24Mime.h | 2 +- include/revolution/NWC24/NWC24MsgCommit.h | 8 + include/revolution/NWC24/NWC24MsgObj.h | 11 +- include/revolution/NWC24/NWC24Utils.h | 12 + src/revolution/NWC24/NWC24DateParser.c | 176 +++ src/revolution/NWC24/NWC24MBoxCtrl.c | 1064 ++++++++++++++++ src/revolution/NWC24/NWC24Mime.c | 191 +++ src/revolution/NWC24/NWC24MsgCommit.c | 1333 ++++++++++++++++++++ src/revolution/NWC24/NWC24MsgObj.c | 6 +- src/revolution/NWC24/NWC24StdApi.c | 296 +++++ 13 files changed, 3155 insertions(+), 10 deletions(-) create mode 100644 src/revolution/NWC24/NWC24DateParser.c create mode 100644 src/revolution/NWC24/NWC24MBoxCtrl.c create mode 100644 src/revolution/NWC24/NWC24Mime.c create mode 100644 src/revolution/NWC24/NWC24MsgCommit.c create mode 100644 src/revolution/NWC24/NWC24StdApi.c diff --git a/include/revolution/NWC24/NWC24DateParser.h b/include/revolution/NWC24/NWC24DateParser.h index 8bdfc699..c6855c60 100644 --- a/include/revolution/NWC24/NWC24DateParser.h +++ b/include/revolution/NWC24/NWC24DateParser.h @@ -9,6 +9,15 @@ extern "C" { NWC24Err NWC24iIsValidDate(u16 year, u8 month, u8 day); +typedef struct NWC24iDate { + u16 year; + u8 month; + u8 day; + u8 hour; + u8 min; + u8 sec; +} NWC24iDate; + #ifdef __cplusplus } #endif diff --git a/include/revolution/NWC24/NWC24MBoxCtrl.h b/include/revolution/NWC24/NWC24MBoxCtrl.h index f226a154..3c011147 100644 --- a/include/revolution/NWC24/NWC24MBoxCtrl.h +++ b/include/revolution/NWC24/NWC24MBoxCtrl.h @@ -9,6 +9,61 @@ extern "C" { NWC24Err NWC24iOpenMBox(void); +typedef struct MountInfoStruct { + u32 count; // 0x00 + s32 type; // 0x04 +} MountInfoStruct; + +typedef struct MBoxControlHeader { + u32 magic; // 0x00 + u32 version; // 0x04 + u32 msgCount; // 0x08 + u32 capacity; // 0x0C + u32 totalMsgSize; // 0x10 + u32 mailDataOffset; // 0x14 + u32 nextMsgId; // 0x18 + u32 nextFreeEntry; // 0x1C + u32 oldestMsgId; // 0x20 + u32 freeSpace; // 0x24 + char padding[0x58]; // to 0x80 +} MBoxControlHeader; + +typedef struct MBoxControlEntry { + u32 id; // 0x00 + u32 flags; // 0x04 + u32 length; // 0x08 + u32 appId; // 0x0C + u32 UNK_0x10; // 0x10 + u32 tag; // 0x14 + u32 ledPattern; // 0x18 + u32 nextFreeOrCreationMs; // 0x1C + u64 fromId; // 0x20 + u32 createTime; // 0x28 + u32 UNK_0x2C; // 0x2C + u8 numTo; // 0x30 + u8 numAttached; // 0x31 + u16 groupId; // 0x32 + u32 packedSubjectText; // 0x34 + u32 packedTextSubjectSize; // 0x38 + u32 packedSubjectTextSize; // 0x3C + u32 packedTextSizeContentType; // 0x40 + u32 packedContentTypeTransferEnc; // 0x44 + u32 textPtr; // 0x48 + u32 textSize; // 0x4C + u32 attached0Ptr; // 0x50 + u32 attached0Size; // 0x54 + u32 attached1Ptr; // 0x58 + u32 attached1Size; // 0x5C + u32 attached0OrigSize; // 0x60 + u32 attached1OrigSize; // 0x64 + u32 attached0_type; // 0x68 + u32 attached1_type; // 0x6C + u32 textOrigSize; // 0x70 + u32 UNK_0x74; // 0x74 + u32 UNK_0x78; // 0x78 + u32 UNK_0x7C; // 0x7C +} MBoxControlEntry; + #ifdef __cplusplus } #endif diff --git a/include/revolution/NWC24/NWC24Manage.h b/include/revolution/NWC24/NWC24Manage.h index 9a7b3b5e..977b6ad1 100644 --- a/include/revolution/NWC24/NWC24Manage.h +++ b/include/revolution/NWC24/NWC24Manage.h @@ -26,7 +26,7 @@ typedef struct NWC24Work { char WORK_0x1180[128]; char WORK_0x1200[128]; char WORK_0x1280[128]; - u8 base64Work[256]; // at 0x1300 + s8 base64Work[256]; // at 0x1300 char WORK_0x1400[0x2400 - 0x1400]; u8 flHeader[WORK_SIZE(NWC24FLHeader)]; // at 0x2800 u8 secretFlHeader[WORK_SIZE(NWC24SecretFLHeader)]; // at 0x2800 diff --git a/include/revolution/NWC24/NWC24Mime.h b/include/revolution/NWC24/NWC24Mime.h index dbbc3bd6..ec581e2e 100644 --- a/include/revolution/NWC24/NWC24Mime.h +++ b/include/revolution/NWC24/NWC24Mime.h @@ -5,7 +5,7 @@ extern "C" { #endif -void NWC24InitBase64Table(u8* table); +void NWC24InitBase64Table(s8* table); #ifdef __cplusplus } diff --git a/include/revolution/NWC24/NWC24MsgCommit.h b/include/revolution/NWC24/NWC24MsgCommit.h index 200908d9..61076619 100644 --- a/include/revolution/NWC24/NWC24MsgCommit.h +++ b/include/revolution/NWC24/NWC24MsgCommit.h @@ -3,15 +3,23 @@ #include #include +#include #ifdef __cplusplus extern "C" { #endif +#define NWC24_WORK_BUFFER_SIZE 1024 + // Forward declarations typedef struct NWC24MsgObj NWC24MsgObj; NWC24Err NWC24CommitMsg(NWC24MsgObj*); +typedef union { + u64 id; + NWC24Data data; +} NWC24AddrId; + #ifdef __cplusplus } #endif diff --git a/include/revolution/NWC24/NWC24MsgObj.h b/include/revolution/NWC24/NWC24MsgObj.h index a49cfd96..6d3fc115 100644 --- a/include/revolution/NWC24/NWC24MsgObj.h +++ b/include/revolution/NWC24/NWC24MsgObj.h @@ -33,18 +33,18 @@ typedef struct NWC24MsgObj { u32 flags; // at 0x4 u32 length; // at 0x8 u32 appId; // at 0xC - char UNK_0x10[0x4]; + s32 UNK_0x10; u32 tag; // at 0x14 u32 ledPattern; // at 0x18 u64 fromId; // at 0x20 - u32 WORD_0x28; + u32 createTime; // at 0x28 u32 WORD_0x2C; NWC24Data DATA_0x30; NWC24Data DATA_0x38; NWC24Data subject; // at 0x40 NWC24Data text; // at 0x48 - NWC24Data DATA_0x50; - NWC24Data DATA_0x58; + NWC24Data contentType; // at 0x50 + NWC24Data transferEncoding; // at 0x58 NWC24Charset charset; // at 0x60 NWC24Encoding encoding; // at 0x64 NWC24Data attached[NWC24_MSG_ATTACHMENT_MAX]; // at 0x68 @@ -70,7 +70,8 @@ typedef struct NWC24MsgObj { NWC24Data DATA_0xD0; NWC24Data face; // at 0xD8 NWC24Data alt; // at 0xE0 - char UNK_0xE8[0x100 - 0xE8]; + NWC24Data altMeta; + char UNK_0xF0[0x100 - 0xF0]; } NWC24MsgObj; NWC24Err NWC24InitMsgObj(NWC24MsgObj* msg, NWC24MsgType type); diff --git a/include/revolution/NWC24/NWC24Utils.h b/include/revolution/NWC24/NWC24Utils.h index bfaad363..2f9781c6 100644 --- a/include/revolution/NWC24/NWC24Utils.h +++ b/include/revolution/NWC24/NWC24Utils.h @@ -20,6 +20,18 @@ typedef struct NWC24Date { u8 BYTE_0x7; } NWC24Date; +typedef struct NWC24Calendar { + /* 0x00 */ u32 sec; + /* 0x04 */ u32 min; + /* 0x08 */ u32 hour; + /* 0x0C */ u32 day; + /* 0x10 */ u32 month; + /* 0x14 */ u32 year; + /* 0x18 */ u32 UNK_0x18; + /* 0x1C */ u32 UNK_0x1C; + /* 0x20 */ u32 UNK_0x20; +} NWC24Calendar; + void NWC24Data_Init(NWC24Data* data); void NWC24Data_SetDataP(NWC24Data* data, const void* ptr, u32 size); void NWC24Date_Init(NWC24Date* date); diff --git a/src/revolution/NWC24/NWC24DateParser.c b/src/revolution/NWC24/NWC24DateParser.c new file mode 100644 index 00000000..bb632b55 --- /dev/null +++ b/src/revolution/NWC24/NWC24DateParser.c @@ -0,0 +1,176 @@ +#include + +const u8 DAYS_OF_MONTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0, 0, 0, 0}; +const u16 DAYS_OF_YEAR[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + +s32 ConvertDateToDays(u16 year, u16 month, u16 day); +void ConvertDaysToDate(u16 *year, u8 *month, u8 *day, s32 days); + +inline BOOL IsLeapYear(u16 year) { + return (((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) != 0); +} + +NWC24Err NWC24iDateToMinutes(s32 *outMinutes, const NWC24iDate *date) { + s32 days; + s32 minutes; + u8 seconds; + + days = ConvertDateToDays(date->year, date->month, date->day); + + if (days == -1) { + return NWC24_ERR_FAILED; + } + + seconds = date->sec; + if (date->hour > 23 || seconds > 59) { + minutes = -1; + } else { + minutes = seconds + (date->hour * 60); + } + + if (minutes == -1 || date->min > 60) { + return NWC24_ERR_FAILED; + } + + *outMinutes = days * (24 * 60) + minutes; + return NWC24_OK; +} + +NWC24Err NWC24iEpochSecondsToDate(NWC24iDate *date, s64 timestamp) { + s64 adjusted = -0x7c558180U; + s32 minutes; + u32 days; + + if (0 > (timestamp + adjusted)) { + timestamp = -adjusted; + } + + timestamp += adjusted; + date->min = (u8)(timestamp % 60); + minutes = timestamp / 60; + if (minutes < 0) { + minutes = 0; + } + + days = minutes / (24 * 60); + minutes %= (24 * 60); + date->hour = (u8)(minutes / 60); + date->sec = (u8)(minutes % 60); + ConvertDaysToDate(&date->year, &date->month, &date->day, days); + return NWC24_OK; +} + +NWC24Err NWC24iDateToOSCalendarTime(OSCalendarTime *time, const NWC24iDate *date) { + s32 daysSinceEpoch; + + time->year = date->year; + time->month = date->month - 1; + time->mday = date->day; + time->hour = date->hour; + // TODO(Alex9303) Why are minutes and seconds swapped here? Is this a decompilation error or is it actually swapped in the original code? + time->min = date->sec; // Swapped? + time->sec = date->min; // Swapped? + time->msec = 0; + time->usec = 0; + time->yday = (DAYS_OF_YEAR[time->month] + date->day) - 1; + + if (IsLeapYear(date->year) && date->month > 2) { + time->yday++; + } + + daysSinceEpoch = ConvertDateToDays(date->year, date->month, date->day); + time->wday = (daysSinceEpoch + 1) % 7; + return NWC24_OK; +} + +NWC24Err NWC24iIsValidDate(u16 year, u8 month, u8 day) { + s32 days = ConvertDateToDays(year, month, day); + s32 result = NWC24_OK; + + if (days == -1) { + result = NWC24_ERR_INVALID_VALUE; + } + + return result; +} + +s32 ConvertDateToDays(u16 year, u16 month, u16 day) { + s32 dayOfYear; + s32 yearsSince1900; + s32 days; + s32 leapDays; + s32 gregorianCorrection; + + if (year < 1900 || month < 1 || month > 12) { + return -1; + } + + if (month == 2 && IsLeapYear(year)) { + if (day < 1 || day > 29) { + return -1; + } + } else { + if (day < 1 || (u16)DAYS_OF_MONTH[month - 1] < day) { + return -1; + } + } + + dayOfYear = day - 1; + dayOfYear += DAYS_OF_YEAR[month - 1]; + + if (month >= 3 && IsLeapYear(year)) { + dayOfYear++; + } + + yearsSince1900 = year - 1900; + + leapDays = (yearsSince1900 - 1) / 4 - (yearsSince1900 - 1) / 100; + gregorianCorrection = (yearsSince1900 + 299) / 400; + + days = yearsSince1900 * 365 + dayOfYear; + days += leapDays + gregorianCorrection; + + return days; +} + +void ConvertDaysToDate(u16 *year, u8 *month, u8 *day, s32 days) { + s32 remaining; + + *year = 1900; + *month = 1; + *day = 1; + + if (days < 0) { + return; + } + + while (1) { + remaining = days; + days -= IsLeapYear(*year) ? 366 : 365; + + if (days < 0) { + days = remaining; + break; + } + + (*year)++; + } + + while (1) { + remaining = days; + + if (*month == 2 && IsLeapYear(*year)) { + days -= 29; + } else { + days -= DAYS_OF_MONTH[*month - 1]; + } + + if (days < 0) { + break; + } + + (*month)++; + } + + *day += remaining; +} diff --git a/src/revolution/NWC24/NWC24MBoxCtrl.c b/src/revolution/NWC24/NWC24MBoxCtrl.c new file mode 100644 index 00000000..1a95b8d7 --- /dev/null +++ b/src/revolution/NWC24/NWC24MBoxCtrl.c @@ -0,0 +1,1064 @@ +#include + +MountInfoStruct MountInfo; + +int Mail_sprintf(char* buffer, const char* format, ...); + +NWC24Err DuplicationCheck(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC24File* file, s32 mboxType); +NWC24Err DeleteMsg(s32 mboxType, u32 msgId, u32 flags); +NWC24Err GetCachedMBCHeader(s32 mboxType, MBoxControlHeader** headerOut); +NWC24Err AddMBCEntry(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC24File* file); +NWC24Err MountVFMBox(s32 mboxType); +NWC24Err CopyMsgObjToMBCFmt(const NWC24MsgObj* src, MBoxControlEntry* dst); + +inline static NWC24Err UnmountVFMBox(void) { + s32 count; + u32 freeSize; + NWC24Err err; + NWC24Err unmountErr; + MBoxControlHeader* header; + + count = MountInfo.count; + if (count == 0) { + unmountErr = NWC24_OK; + } else { + count--; + MountInfo.count = count; + if (count > 0) { + unmountErr = NWC24_OK; + } else { + err = GetCachedMBCHeader(MountInfo.type, &header); + if (err != NWC24_OK) { + unmountErr = err; + } else { + err = NWC24CheckSizeVF("@24", &freeSize); + if (err != NWC24_OK) { + unmountErr = err; + } else { + header->freeSpace = freeSize; + unmountErr = NWC24UnmountVF("@24"); + } + } + } + } + return unmountErr; +} + +NWC24Err NWC24iOpenMBox(void) { + NWC24Err err; + MBoxControlHeader* header; + NWC24File recvFile; + NWC24File sendFile; + char* pathWork; + const char* mboxDir; + + pathWork = NWC24WorkP->pathWork; + + Mail_memset(NWC24WorkP->WORK_0x1100, 0, sizeof(MBoxControlHeader)); + err = GetCachedMBCHeader(0, &header); + if (err != NWC24_OK) { + return err; + } + + Mail_memset(NWC24WorkP->WORK_0x1180, 0, sizeof(MBoxControlHeader)); + err = GetCachedMBCHeader(1, &header); + if (err != NWC24_OK) { + return err; + } + + mboxDir = NWC24GetMBoxDir(); + if (STD_strnlen(mboxDir, 0x40) + 14 > 0x100) { + err = NWC24_ERR_NOMEM; + } else { + Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24send.ctl"); + err = NWC24_OK; + } + + if (err != NWC24_OK) { + return err; + } + + err = NWC24FOpen(&recvFile, pathWork, 2); + if (err == NWC24_OK) { + err = NWC24FClose(&recvFile); + } + + if (err != NWC24_OK) { + return err; + } + + mboxDir = NWC24GetMBoxDir(); + if (STD_strnlen(mboxDir, 0x40) + 14 > 0x100) { + err = NWC24_ERR_NOMEM; + } else { + Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24recv.ctl"); + err = NWC24_OK; + } + + if (err != NWC24_OK) { + return err; + } + + err = NWC24FOpen(&sendFile, pathWork, 2); + if (err == NWC24_OK) { + err = NWC24FClose(&sendFile); + } + + if (err != NWC24_OK) { + return err; + } + + MountInfo.count = 0; + MountInfo.type = 0; + return NWC24_OK; +} + +NWC24Err NWC24iMBoxOpenNewMsg(s32 mboxType, NWC24File* file, u32* msgId) { + NWC24Err err; + MBoxControlHeader* header; + MBoxControlHeader* footer; + char* path; + u32 id; + + err = GetCachedMBCHeader(mboxType, &header); + if (err != NWC24_OK) { + return err; + } + + footer = header; + + if (footer->magic != 0x57635466) { + err = NWC24_ERR_INVALID_VALUE; + } else { + if (footer->nextMsgId > 1000000) { + footer->nextMsgId = 1; + } + err = NWC24_OK; + *msgId = footer->nextMsgId; + footer->nextMsgId++; + } + + if (err != NWC24_OK) { + return err; + } + + err = MountVFMBox(mboxType); + if (err != NWC24_OK) { + return err; + } + + id = *msgId; + path = NWC24WorkP->pathWork; + + switch (mboxType) { + case 0: + Mail_sprintf(path, "@24:/mb/s%07d.msg", id); + break; + case 1: + Mail_sprintf(path, "@24:/mb/r%07d.msg", id); + break; + default: + err = NWC24_ERR_INVALID_VALUE; + goto check_mbox; + } + + err = NWC24_OK; + +check_mbox: + if (err != NWC24_OK) { + return err; + } + + err = NWC24FOpen(file, path, 0x109); + return err; +} + +NWC24Err NWC24iMBoxCloseMsg(NWC24File* file) { + NWC24Err err; + u32 freeSize; + MBoxControlHeader* header; + s32 count; + NWC24Err unmountErr; + NWC24Err closeErr; + + closeErr = NWC24FClose(file); + // unmountErr = UnmountVFMBox(); + // This code could be replaced with a call to UnmountVFMBox but that causes issues with the assembly matching. + + count = MountInfo.count; + if (count == 0) { + unmountErr = NWC24_OK; + } else { + count--; + MountInfo.count = count; + if (count > 0) { + unmountErr = NWC24_OK; + } else { + err = GetCachedMBCHeader(MountInfo.type, &header); + if (err != NWC24_OK) { + unmountErr = err; + } else { + err = NWC24CheckSizeVF("@24", &freeSize); + if (err != NWC24_OK) { + unmountErr = err; + } else { + header->freeSpace = freeSize; + unmountErr = NWC24UnmountVF("@24"); + } + } + } + } + + if (closeErr != NWC24_OK && unmountErr != NWC24_OK) { + return unmountErr; + } + return closeErr; +} + +NWC24Err NWC24iMBoxCancelMsg(NWC24File* file, s32 mboxType, u32 msgId) { + s32 result = (s32)msgId; + char* pathWork; + unsigned int tempErr; + NWC24Err deleteErr; + NWC24Err closeErr; + NWC24Err unmountErr; + + closeErr = NWC24FClose(file); + unmountErr = MountVFMBox(mboxType); + + if (unmountErr != NWC24_OK) { + result = unmountErr; + } else { + pathWork = NWC24WorkP->pathWork; + switch (mboxType) { + case 0: + Mail_sprintf(pathWork, "@24:/mb/s%07d.msg", result); + break; + + case 1: + Mail_sprintf(pathWork, "@24:/mb/r%07d.msg", result); + break; + + default: + result = NWC24_ERR_INVALID_VALUE; + goto check_result; + } + + result = NWC24_OK; + + check_result: + // TODO(Alex9303) Permuter fake(?)match + deleteErr = result; + if (deleteErr != NWC24_OK) { + result = deleteErr; + } else { + deleteErr = NWC24FDeleteVF(pathWork); + tempErr = deleteErr; + unmountErr = UnmountVFMBox(); + if (tempErr != NWC24_OK) { + result = tempErr; + } else { + result = unmountErr; + } + } + } + + MountInfo.count = 1; + + unmountErr = UnmountVFMBox(); + if (closeErr != NWC24_OK) { + return closeErr; + } + if (result != NWC24_OK) { + return result; + } + if (unmountErr != NWC24_OK) { + return unmountErr; + } + return NWC24_OK; +} + +NWC24Err NWC24iMBoxAddMsgObj(s32 mboxType, NWC24MsgObj* msg) { + NWC24Err err; + NWC24Err closeErr; + MBoxControlHeader* header; + MBoxControlHeader* header2; + const char* mboxDir; + char* pathWork; + NWC24File file; + + err = GetCachedMBCHeader(mboxType, &header); + if (err != NWC24_OK) { + return err; + } + + if (header->msgCount == header->capacity) { + return NWC24_ERR_FULL; + } + + pathWork = NWC24WorkP->pathWork; + + mboxDir = NWC24GetMBoxDir(); + + if (STD_strnlen(mboxDir, 0x40) + 14 > 0x100) { + err = NWC24_ERR_NOMEM; + } else { + switch (mboxType) { + case 0: + Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24send.ctl"); + break; + case 1: + Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24recv.ctl"); + break; + default: + err = NWC24_ERR_INVALID_VALUE; + goto check_result; + } + err = NWC24_OK; + } +check_result: + if (err != NWC24_OK) { + return err; + } + + err = NWC24FOpen(&file, pathWork, 4); + if (err != NWC24_OK) { + return err; + } + + err = AddMBCEntry(header, msg, &file); + if (err == NWC24_OK) { + err = DuplicationCheck(header, msg, &file, mboxType); + if (err == NWC24_OK) { + // TODO(Alex9303) Fakematch: (possibly) Missing inline function + header2 = header; + NWC24FSeek(&file, 0, NWC24_SEEK_BEG); + err = NWC24FWrite(header2, sizeof(MBoxControlHeader), &file); + } + } + + closeErr = NWC24FClose(&file); + if (err != NWC24_OK) { + return err; + } + + return closeErr; +} + +NWC24Err NWC24iMBoxFlushHeader(s32 mboxType) { + NWC24Err err; + NWC24Err closeErr; + MBoxControlHeader* header; + MBoxControlHeader* header2; + const char* mboxDir; + char* pathWork; + NWC24File file; + + err = GetCachedMBCHeader(mboxType, &header); + if (err != NWC24_OK) { + return err; + } + + pathWork = NWC24WorkP->pathWork; + mboxDir = NWC24GetMBoxDir(); + + if (STD_strnlen(mboxDir, 0x40) + 14 > 0x100) { + err = NWC24_ERR_NOMEM; + } else { + switch (mboxType) { + case 0: + err = Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24send.ctl"); + break; + case 1: + err = Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24recv.ctl"); + break; + default: + err = NWC24_ERR_INVALID_VALUE; + goto check_result; + } + err = NWC24_OK; + } +check_result: + if (err != NWC24_OK) { + return err; + } + + err = NWC24FOpen(&file, pathWork, 4); + if (err != NWC24_OK) { + return err; + } + + // TODO(Alex9303) Fakematch: (possibly) Missing inline function + header2 = header; + NWC24FSeek(&file, 0, 0); + err = NWC24FWrite(header2, 0x80, &file); + closeErr = NWC24FClose(&file); + + if (err != NWC24_OK) { + return err; + } + + return closeErr; +} + +NWC24Err NWC24iMBoxCheck(s32 mboxType, u32 requiredSize) { + NWC24Err err; + MBoxControlHeader* header; + volatile long oldestMsgId; + u32 spaceWithBuffer; + + if (requiredSize >= 0x31C00) { + return NWC24_ERR_OVERFLOW; + } + + spaceWithBuffer = requiredSize + 0x4000; + + err = GetCachedMBCHeader(mboxType, &header); + if (err != NWC24_OK) { + return err; + } + + if (mboxType == 0) { + if (header->msgCount >= header->capacity) { + return NWC24_ERR_FULL; + } + if (header->freeSpace <= spaceWithBuffer) { + return NWC24_ERR_FULL; + } + } else if (mboxType == 1) { + while (header->msgCount >= header->capacity || header->freeSpace <= spaceWithBuffer) { + oldestMsgId = header->oldestMsgId; + err = DeleteMsg(mboxType, oldestMsgId, 0); + if (err != NWC24_OK) { + return err; + } + + err = GetCachedMBCHeader(mboxType, &header); + if (err != NWC24_OK) { + return err; + } + } + } else { + return NWC24_ERR_INVALID_VALUE; + } + return NWC24_OK; +} + +NWC24Err DeleteMsg(s32 mboxType, u32 msgId, u32 flags) { + NWC24Err err; + const char* mboxDir; + MBoxControlHeader* header; + u32 entryOffsetToDelete = 0; + MBoxControlHeader* header3; + NWC24File file; + s32 pathLen; + u32 offset; + char* pathWorkCopy; + MBoxControlHeader* header2; + int cmp; + MBoxControlEntry* entry2; + u32 checkedCount = 0; + u32 oldestMsgId = 0; + MBoxControlEntry* entry; + NWC24Err mountErr = NWC24_OK; + NWC24Err writeErr = NWC24_OK; + NWC24Err deleteErr = NWC24_OK; + char* pathWork; + + if (!NWC24IsMsgLibOpened() && !NWC24IsMsgLibOpenedByTool()) { + return NWC24_ERR_LIB_NOT_OPENED; + } + entry = (MBoxControlEntry*)((char*)NWC24WorkP + 0x1200); + + err = GetCachedMBCHeader(mboxType, &header); + if (err != NWC24_OK) { + return err; + } + + pathWorkCopy = NWC24WorkP->pathWork; + pathWork = pathWorkCopy; + mboxDir = NWC24GetMBoxDir(); + + pathLen = STD_strnlen(mboxDir, 64); + + if (pathLen + 14 > 256) { + err = NWC24_ERR_NOMEM; + } else { + switch (mboxType) { + case 0: + Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24recv.ctl"); + break; + case 1: + Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24send.ctl"); + break; + default: + err = NWC24_ERR_INVALID_VALUE; + goto check_result1; + } + + err = NWC24_OK; + } +check_result1: + if (err != NWC24_OK) { + return err; + } + + err = NWC24FOpen(&file, pathWork, 4); + if (err != NWC24_OK) { + return err; + } + + err = NWC24_ERR_NOT_FOUND; + + for (offset = 0x80; offset < header->mailDataOffset; offset += 0x80) { + NWC24Err readErr; + NWC24FSeek(&file, offset, NWC24_SEEK_BEG); + readErr = NWC24FRead(entry, 0x80, &file); + if (readErr != NWC24_OK) { + err = readErr; + break; + } + + if (entry->id == 0) { + continue; + } + + entryOffsetToDelete++; + + if (entry->id == msgId) { + if (flags != 0) { + if ((entry->flags & 0x2) != 0) { + if (NWC24GetAppId() - 0x48410000 != 0x4541) { + err = NWC24_ERR_PROTECTED; + break; + } + } else { + if ((entry->appId & 0xFFFFFF00) != (NWC24GetAppId() & 0xFFFFFF00)) { + if ((entry->flags & 0x8) != 0) { + if (NWC24GetAppId() - 0x48410000 == 0x4541) { + goto permission_ok; + } + } + err = NWC24_ERR_PROTECTED; + break; + } + } + } + permission_ok: + + checkedCount = offset; + err = NWC24_OK; + continue; + } + + if (oldestMsgId != 0) { + if (oldestMsgId == entry->id) { + cmp = 0; + } else if (oldestMsgId > 900000 && entry->id < 100000) { + cmp = -1; + } else if (oldestMsgId < 100000 && entry->id > 900000) { + cmp = 1; + } else if (oldestMsgId > entry->id) { + cmp = 1; + } else { + cmp = -1; + } + if (cmp <= 0) { + continue; + } + } + + oldestMsgId = entry->id; + } + + if (err == NWC24_ERR_NOT_FOUND) { + if (header->msgCount != entryOffsetToDelete) { + header->msgCount = entryOffsetToDelete; + + // TODO(Alex9303) Fakematch: (possibly) Missing inline function + header3 = header; + NWC24FSeek(&file, 0, NWC24_SEEK_BEG); + NWC24FWrite(header3, 0x80, &file); + } + } + + if (err != NWC24_OK) { + NWC24FClose(&file); + + if (msgId == 0) { + err = NWC24_ERR_INVALID_VALUE; + } + + return err; + } + + header->oldestMsgId = oldestMsgId; + + // TODO(Alex9303) Fakematch: (possibly) Missing inline function + header2 = header; + + // TODO(Alex9303) Fakematch: (possibly) Missing inline function + entry2 = (MBoxControlEntry*)(((char*)NWC24WorkP) + 0x1200); + entry = entry2; + NWC24FSeek(&file, checkedCount, NWC24_SEEK_BEG); + NWC24FRead(entry, 0x80, &file); + + header2->msgCount--; + header2->totalMsgSize -= entry->length; + + memset(entry, 0, 0x80); + entry->appId = header2->nextFreeEntry; + header2->nextFreeEntry = checkedCount; + + NWC24FSeek(&file, checkedCount, NWC24_SEEK_BEG); + writeErr = NWC24FWrite(entry, 0x80, &file); + + mountErr = MountVFMBox(mboxType); + switch (mountErr) { + case NWC24_OK: + pathWork = NWC24WorkP->pathWork; + switch (mboxType) { + case 0: + Mail_sprintf(pathWork, "@24:/mb/r%07d.msg", msgId); + break; + case 1: + Mail_sprintf(pathWork, "/shared2/wc24/mbox/s%07d.msg", msgId); + + break; + default: + mountErr = NWC24_ERR_INVALID_VALUE; + goto check_result2; + } + mountErr = NWC24_OK; + + check_result2: + switch (mountErr) { + case NWC24_OK: + deleteErr = NWC24FDeleteVF(pathWork); + mountErr = UnmountVFMBox(); + if (deleteErr != NWC24_OK) { + mountErr = deleteErr; + } + break; + } + break; + } + + // TODO(Alex9303) Fakematch: Reusing arguments msgId/mboxType as error variables to match r23/r22 + msgId = mountErr; + if (writeErr != NWC24_OK) { + msgId = writeErr; + } + + // TODO(Alex9303) Fakematch: (possibly) Missing inline function + header2 = header; + NWC24FSeek(&file, 0, NWC24_SEEK_BEG); + + mboxType = NWC24FWrite(header2, 0x80, &file); + if (msgId != NWC24_OK) { + mboxType = msgId; + } + + err = NWC24FClose(&file); + if (mboxType != NWC24_OK) { + err = mboxType; + } + + return err; +} + +NWC24Err DuplicationCheck(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC24File* file, s32 mboxType) { + NWC24Err err; + u32 offset; + u32 checkedCount; + u32 bestMsgId; + u32 bestOffset; + u32 oldestMsgId; + MBoxControlEntry* entry; + char* pathWork; + char** pathWorkPtr; + + err = NWC24_OK; + checkedCount = 0; + bestMsgId = 0; + bestOffset = 0; + oldestMsgId = 0; + + pathWorkPtr = &pathWork; + + if (mboxType == 0) { + return NWC24_OK; + } + + entry = (MBoxControlEntry*)((char*)NWC24WorkP + 0x1200); + + for (offset = 0x80; offset < header->mailDataOffset; offset += 0x80) { + int isDuplicate; + int cmp; + + if (checkedCount >= header->msgCount) { + break; + } + + err = NWC24FSeek(file, offset, NWC24_SEEK_BEG); + err = NWC24FRead(entry, 0x80, file); + if (err != NWC24_OK) { + break; + } + + if (entry->id == 0) { + continue; + } + + checkedCount++; + isDuplicate = 1; + + if (entry->id == msg->id) { + isDuplicate = 0; + } + + if ((entry->flags & msg->flags & 1) != 0) { + if (entry->appId != msg->appId) { + isDuplicate = 0; + } + if (entry->fromId != msg->fromId) { + isDuplicate = 0; + } + } + + if (isDuplicate) { + u32 msgTag = msg->tag & 0xFFFF; + u32 msgCreationMs; + + if (msgTag != 0) { + if ((entry->tag & 0xFFFF) == msgTag) { + bestMsgId = entry->id; + bestOffset = offset; + continue; + } + } + + msgCreationMs = ((const u32*)msg)[7]; + if (msgCreationMs != 0 && entry->nextFreeOrCreationMs == msgCreationMs && entry->flags == msg->flags && entry->length == msg->length && entry->UNK_0x10 == ((const u32*)msg)[4] && (s32)entry->createTime == (s32)((const u32*)msg)[10]) { + bestMsgId = entry->id; + bestOffset = offset; + continue; + } + } + + if (oldestMsgId != 0) { + if (oldestMsgId == entry->id) { + cmp = 0; + } else if (oldestMsgId > 900000 && entry->id < 100000) { + cmp = -1; + } else if (oldestMsgId < 100000 && entry->id > 900000) { + cmp = 1; + } else if (oldestMsgId > entry->id) { + cmp = 1; + } else { + cmp = -1; + } + + if (cmp <= 0) { + continue; + } + } + + oldestMsgId = entry->id; + } + + if (err != NWC24_OK) { + return err; + } + + header->oldestMsgId = oldestMsgId; + + if (bestMsgId != 0) { + NWC24Err writeErr; + NWC24Err result; + + entry = (MBoxControlEntry*)(((char*)NWC24WorkP) + 0x1200); + pathWork = NWC24WorkP->WORK_0x1200; + + err = NWC24FSeek(file, bestOffset, NWC24_SEEK_BEG); + err = NWC24FRead(*pathWorkPtr, 0x80, file); + + header->msgCount--; + header->totalMsgSize -= entry->length; + + memset(entry, 0, 0x80); + entry->appId = header->nextFreeEntry; + header->nextFreeEntry = bestOffset; + + err = NWC24FSeek(file, bestOffset, NWC24_SEEK_BEG); + writeErr = NWC24FWrite(entry, 0x80, file); + + err = MountVFMBox(mboxType); + if (err != NWC24_OK) { + result = err; + } else { + pathWork = NWC24WorkP->pathWork; + + switch (mboxType) { + case 0: + Mail_sprintf(pathWork, "/wc24recv.mbx", bestMsgId); + break; + + case 1: + Mail_sprintf(pathWork, "/wc24send.mbx", bestMsgId); + break; + + default: + err = NWC24_ERR_INVALID_VALUE; + goto check_result; + } + + err = NWC24_OK; + check_result: + if (err != NWC24_OK) { + result = err; + } else { + NWC24Err deleteErr = NWC24FDeleteVF(pathWork); + + result = UnmountVFMBox(); + if (deleteErr != NWC24_OK) { + result = deleteErr; + } + } + } + + if (writeErr != NWC24_OK) { + result = writeErr; + } + + return result; + } + + return err; +} + +NWC24Err GetCachedMBCHeader(s32 mboxType, MBoxControlHeader** headerOut) { + NWC24Err err; + const char* mboxDir; + NWC24File file; + MBoxControlHeader* header; + NWC24Err result = NWC24_OK; + char* pathWork; + + if (mboxType == 0) { + *headerOut = (MBoxControlHeader*)NWC24WorkP->WORK_0x1100; + } else if (mboxType == 1) { + *headerOut = (MBoxControlHeader*)NWC24WorkP->WORK_0x1180; + } else { + *headerOut = 0; + return NWC24_ERR_INVALID_VALUE; + } + + if ((*headerOut)->magic != 0x57635466) { + pathWork = NWC24WorkP->pathWork; + mboxDir = NWC24GetMBoxDir(); + + if (STD_strnlen(mboxDir, 0x40) + 14 > 0x100) { + err = NWC24_ERR_NOMEM; + } else { + switch (mboxType) { + case 0: + Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24send.ctl"); + break; + case 1: + Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24recv.ctl"); + break; + default: + err = NWC24_ERR_INVALID_VALUE; + goto check_result; + } + err = NWC24_OK; + } + check_result: + if (err != NWC24_OK) { + return err; + } + + err = NWC24FOpen(&file, pathWork, 2); + if (err != NWC24_OK) { + return err; + } + + header = *headerOut; + NWC24FSeek(&file, 0, 0); + err = NWC24FRead(header, 0x80, &file); + if (err != NWC24_OK) { + result = err; + + } else { + result = NWC24_OK; + if ((header)->magic != 0x57635466) { + result = NWC24_ERR_BROKEN; + } + } + err = NWC24FClose(&file); + if (result == NWC24_OK) { + if (err != NWC24_OK) { + result = err; + } + } + } + + if ((*headerOut)->version != 4) { + result = NWC24_ERR_VER_MISMATCH; + } + return result; +} + +NWC24Err AddMBCEntry(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC24File* file) { + s32 entryOffset = header->nextFreeEntry; + MBoxControlEntry* entryBuffer; + s32 nextEntryOffset; + NWC24Err err; + + entryBuffer = (MBoxControlEntry*)NWC24WorkP->WORK_0x1200; + + if (entryOffset == 0) { + return NWC24_ERR_FULL; + } + + if ((u32)entryOffset >= header->mailDataOffset || ((entryOffset - 0x80) & 0x7F) != 0) { + return NWC24_ERR_BROKEN; + } + + NWC24FSeek(file, entryOffset, NWC24_SEEK_BEG); + + err = NWC24FRead(entryBuffer, sizeof(MBoxControlEntry), file); + if (err != NWC24_OK) { + return err; + } + + nextEntryOffset = entryBuffer->appId; + + if ((u32)nextEntryOffset >= header->mailDataOffset || ((nextEntryOffset - 0x80) & 0x7F) != 0) { + return NWC24_ERR_BROKEN; + } + + header->nextFreeEntry = nextEntryOffset; + CopyMsgObjToMBCFmt(msg, entryBuffer); + + NWC24FSeek(file, entryOffset, NWC24_SEEK_BEG); + + err = NWC24FWrite(entryBuffer, sizeof(MBoxControlEntry), file); + if (err != NWC24_OK) { + return err; + } + + if (header->msgCount == 0) { + header->oldestMsgId = msg->id; + } + + header->msgCount++; + header->totalMsgSize += msg->length; + return NWC24_OK; +} + +NWC24Err MountVFMBox(s32 mboxType) { + s32 result; + NWC24Err err; + const char* mboxDir; + char* pathWork; + + if (MountInfo.count != 0 && MountInfo.type != mboxType) { + MountInfo.count = 1; + UnmountVFMBox(); + return NWC24_ERR_FATAL; + } + + if ((s32)(++MountInfo.count) > 1) { + return NWC24_OK; + } + + pathWork = NWC24WorkP->pathWork; + mboxDir = NWC24GetMBoxDir(); + if (STD_strnlen(mboxDir, 0x40) + 14 > 0x100) { + result = NWC24_ERR_NOMEM; + } else { + switch (mboxType) { + case 0: + Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24recv.mbx"); + break; + + case 1: + Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24send.mbx"); + break; + + default: + result = NWC24_ERR_INVALID_VALUE; + goto check_result; + } + + result = NWC24_OK; + } + +check_result: + if (result != NWC24_OK) { + return result; + } + + result = NWC24_OK; + err = NWC24MountVF("@24", pathWork); + if (err != result) { + return err; + } else { + err = result; + MountInfo.type = mboxType; + } + + return err; +} + +NWC24Err CopyMsgObjToMBCFmt(const NWC24MsgObj* src, MBoxControlEntry* dst) { + u32 packData30 = (((u32)src->DATA_0x30.ptr) & 0xFFFFF) | (src->DATA_0x30.size << 20); + u32 packData38 = (((u32)src->DATA_0x38.ptr) & 0xFFFFF) | (src->DATA_0x38.size << 20); + u32 packSubject = (((u32)src->subject.ptr) & 0xFFFFF) | (src->subject.size << 20); + u32 packContent = (((u32)src->contentType.ptr) & 0xFFFFF) | (src->contentType.size << 20); + u32 packTransfer = (((u32)src->transferEncoding.ptr) & 0xFFFFF) | (src->transferEncoding.size << 20); + + dst->id = src->id; + dst->flags = src->flags; + dst->length = src->length; + dst->appId = src->appId; + *(u32*)&dst->UNK_0x10 = src->UNK_0x10; + dst->tag = src->tag; + dst->ledPattern = src->ledPattern; + dst->nextFreeOrCreationMs = *(const u32*)((const u8*)src + 0x1C); + ((u32*)&dst->fromId)[0] = ((u32*)&src->fromId)[0]; + + ((u32*)&dst->fromId)[1] = ((u32*)&src->fromId)[1]; + + dst->createTime = src->createTime; + dst->UNK_0x2C = src->WORD_0x2C; + + *(u8*)&dst->numTo = src->numTo; + *(u8*)((u8*)dst + 0x31) = src->numAttached; + *(u16*)((u8*)dst + 0x32) = src->groupId; + + dst->packedSubjectText = packData30; + dst->packedTextSubjectSize = packData38; + dst->packedSubjectTextSize = packSubject; + dst->packedTextSizeContentType = packContent; + dst->packedContentTypeTransferEnc = packTransfer; + + dst->textPtr = (u32)src->text.ptr; + dst->textSize = src->text.size; + dst->textOrigSize = *(const u32*)((const u8*)src + 0xE8); + dst->UNK_0x74 = *(const u32*)((const u8*)src + 0xEC); + + dst->attached0Ptr = (u32)src->attached[0].ptr; + dst->attached0Size = src->attached[0].size; + dst->attached0OrigSize = src->attachedSize[0]; + dst->attached0_type = src->attachedType[0]; + + dst->attached1Ptr = (u32)src->attached[1].ptr; + dst->attached1Size = src->attached[1].size; + dst->attached1OrigSize = src->attachedSize[1]; + dst->attached1_type = src->attachedType[1]; + + return NWC24_OK; +} diff --git a/src/revolution/NWC24/NWC24Mime.c b/src/revolution/NWC24/NWC24Mime.c new file mode 100644 index 00000000..2ee48857 --- /dev/null +++ b/src/revolution/NWC24/NWC24Mime.c @@ -0,0 +1,191 @@ +#include + +static char *MIMEEncStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + +NWC24Err Base64Encode(char *inputBuffer, s32 inputLength, u32 *inBytesConsumed, char *outBuffer, s32 outBufferSize, u32 *outBytesWritten) { + s32 result = NWC24_OK; + s32 outputIndex; + s32 inputIndex = 0; + BOOL hasThird; + BOOL hasSecond; + u32 combined; + + for (outputIndex = 0; inputIndex < inputLength; inputIndex += 3) { + if ((outputIndex + 3) >= outBufferSize) { + result = NWC24_ERR_OVERFLOW; + break; + } + + hasThird = FALSE; + hasSecond = FALSE; + + combined = ((unsigned char)inputBuffer[inputIndex]); + combined <<= 8; + + if ((inputIndex + 1) < inputLength) { + hasSecond = TRUE; + combined |= ((unsigned char)inputBuffer[inputIndex + 1]); + } + + combined <<= 8; + + if ((inputIndex + 2) < inputLength) { + hasThird = TRUE; + combined |= ((unsigned char)inputBuffer[inputIndex + 2]); + } + + outBuffer[outputIndex + 0] = MIMEEncStr[(combined >> 18) & 0x3F]; + outBuffer[outputIndex + 1] = MIMEEncStr[(combined >> 12) & 0x3F]; + outBuffer[outputIndex + 2] = MIMEEncStr[(hasSecond) ? ((combined >> 6) & 0x3F) : (0x40)]; + outBuffer[outputIndex + 3] = MIMEEncStr[(hasThird) ? (combined & 0x3F) : (0x40)]; + + outputIndex += 4; + } + + *outBytesWritten = outputIndex; + + if (inBytesConsumed != 0) { + outputIndex = inputLength; + if (inputLength < inputIndex) { + inputIndex = inputLength; + } + *inBytesConsumed = inputIndex; + } + return result; +} + +void NWC24Base64Encode(char *inputBuffer, s32 inputLength, char *outBuffer, s32 outBufferSize, u32 *outBytesWritten) { + Base64Encode(inputBuffer, inputLength, 0, outBuffer, outBufferSize, outBytesWritten); +} + +void NWC24InitBase64Table(signed char *codes) { + int i; + for (i = 0; i < 256; i++) { + codes[i] = (char)0xFF; + } + + for (i = 'A'; i <= 'Z'; i++) { + codes[i] = (char)(i - 'A'); + } + + for (i = 'a'; i <= 'z'; i++) { + codes[i] = (char)(26 + i - 'a'); + } + + for (i = '0'; i <= '9'; i++) { + codes[i] = (char)(52 + i - '0'); + } + + codes['+'] = 62; + codes['/'] = 63; + + return; +} + +NWC24Err QEncode(u8 *outBuffer, u32 outBufferSize, u32 *outBytesWritten, u8 *inputBuffer, u32 inputLength, u32 *inBytesConsumed, s32 maxLineLength) { + u8 *outputPtr; + u32 outBytesUsed; + u32 inputIndex; + s32 result; + s32 lineLength; + u8 encodeBuffer[8]; + s32 bufferIndex; + BOOL needsSoftBreak; + s32 emitCount; + s32 bytesRead; + s16 currentByte; + + result = NWC24_OK; + + if (outBuffer == 0) { + return NWC24_ERR_INVALID_VALUE; + } + if (inputBuffer == 0) { + return NWC24_ERR_INVALID_VALUE; + } + if (inputLength == 0) { + return NWC24_ERR_OVERFLOW; + } + if (inBytesConsumed) { + *inBytesConsumed = 0; + } + if (outBytesWritten) { + *outBytesWritten = 0; + } + outputPtr = outBuffer; + lineLength = 0; + outBytesUsed = 0; + inputIndex = 0; + while (inputIndex < inputLength) { + currentByte = *inputBuffer; + needsSoftBreak = FALSE; + + if (((((char)currentByte) >= '!') && (((char)currentByte) <= '~')) && (((char)currentByte) != '=')) { + bytesRead = 1; + emitCount = 1; + encodeBuffer[0] = *inputBuffer; + } else { + if ((((inputIndex + 1) < inputLength) && (((char)currentByte) == '\r')) && (((long)inputBuffer[1]) == '\n')) { + bytesRead = 2; + encodeBuffer[0] = *inputBuffer; + emitCount = 1; + encodeBuffer[1] = inputBuffer[1]; + } else { + encodeBuffer[0] = '='; + if (((*inputBuffer) >> 4) >= 10) { + encodeBuffer[1] = (((*inputBuffer) >> 4) % 10) + 'A'; + } else { + encodeBuffer[1] = (((*inputBuffer) >> 4) % 10) + '0'; + } + if (((*inputBuffer) & 0xf) >= 10) { + encodeBuffer[2] = (((*inputBuffer) & 0xf) % 10) + 'A'; + } else { + encodeBuffer[2] = (((*inputBuffer) & 0xf) % 10) + '0'; + } + + bytesRead = 1; + emitCount = 3; + } + } + if ((maxLineLength == 0) && ((lineLength + emitCount) >= 75)) { + needsSoftBreak = TRUE; + emitCount = emitCount + 3; + } + if (((u32)(outBytesUsed + emitCount)) >= outBufferSize) { + result = NWC24_ERR_OVERFLOW; + break; + } + outBytesUsed = emitCount + outBytesUsed; + if (needsSoftBreak) { + *outputPtr = '='; + outputPtr[1] = '\r'; + outputPtr[2] = '\n'; + outputPtr = outputPtr + 3; + lineLength = 0; + emitCount = emitCount - 3; + } + lineLength = emitCount + lineLength; + bufferIndex = 0; + while (bufferIndex < emitCount) { + *(outputPtr++) = encodeBuffer[bufferIndex]; + bufferIndex++; + } + + inputIndex = inputIndex + bytesRead; + inputBuffer = inputBuffer + bytesRead; + } + + if (inBytesConsumed) { + *inBytesConsumed = inputIndex; + } + + if (outBytesWritten) { + *outBytesWritten = outBytesUsed; + } + + return result; +} + +s32 NWC24EncodeQuotedPrintable(u8 *outBuffer, u32 outBufferSize, u32 *outBytesWritten, u8 *inputBuffer, u32 inputLength, u32 *inBytesConsumed) { + return QEncode(outBuffer, outBufferSize, outBytesWritten, inputBuffer, inputLength, inBytesConsumed, 0); +} diff --git a/src/revolution/NWC24/NWC24MsgCommit.c b/src/revolution/NWC24/NWC24MsgCommit.c new file mode 100644 index 00000000..7408f33e --- /dev/null +++ b/src/revolution/NWC24/NWC24MsgCommit.c @@ -0,0 +1,1333 @@ +#include + +extern char MultiPartDivider[40]; +static const char* LoopBackEnable = (const char[]){0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}; +static char* MonthStr[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + +extern NWC24Work* NWC24WorkP; + +extern void* m_pFile; +extern const char* ContentTypeA; +extern const char* ContentTxEncA; +extern const char* ContentDispA; +extern const char* ContentTypeTP; +extern const char* ContentTxEncT; + +int Mail_sprintf(char *buffer, const char *format, ...); + +NWC24Err NWC24CommitMsgInternal(NWC24MsgObj* msg, s32 flagLocal); +NWC24Err WriteBase64Data(const void* data, u32 size, u32* bytesWritten); +NWC24Err WriteQPData(const void* data, u32 size, u32* bytesWritten); +NWC24Err CheckMsgBoxSpace(NWC24MsgObj* msg, u32 requiredSize); +NWC24Err WriteSMTP_MAILFROM(NWC24MsgObj* msg); +NWC24Err WriteSMTP_RCPTTO(NWC24MsgObj* msg); +NWC24Err WriteFromField(NWC24MsgObj* msg); +NWC24Err WriteToField(NWC24MsgObj* msg); +NWC24Err WriteDateField(NWC24MsgObj* msg); +NWC24Err WriteXWiiAppIdField(NWC24MsgObj* msg); +NWC24Err WriteXWiiFaceField(NWC24MsgObj* msg); +NWC24Err WriteXWiiAltNameField(NWC24MsgObj* msg); +NWC24Err WriteMIMEAttachHeader(NWC24MsgObj* msg, u32 attachIndex); +NWC24Err WriteContentTypeField(NWC24MsgObj* msg); +NWC24Err WritePlainText(NWC24MsgObj* msg); +NWC24Err CheckMsgObject(const NWC24MsgObj* msg); + +NWC24Err NWC24FClose(NWC24File* file); +NWC24Err NWC24FWrite(const void* src, s32 size, NWC24File* file); +NWC24Err NWC24GetMyUserId(u64* idOut); +NWC24Err NWC24iMBoxAddMsgObj(s32 mboxType, NWC24MsgObj* msg); +NWC24Err NWC24iMBoxCancelMsg(NWC24File* file, s32 mboxType, u32 msgId); +NWC24Err NWC24iMBoxCloseMsg(NWC24File* file); +NWC24Err NWC24iMBoxFlushHeader(s32 mboxType); +NWC24Err NWC24iMBoxOpenNewMsg(s32 mboxType, NWC24File* file, u32* msgId); +NWC24Err NWC24iSetNewMsgArrived(u32 flags); +const char* NWC24GetAccountDomain(void); +u32 STD_strnlen(const char* str, u32 maxLen); +void NWC24Data_Init(NWC24Data* data); + +NWC24Err NWC24CommitMsg(NWC24MsgObj *msg) { + s32 flagLocal; + u32 flags; + u64 myUserId; + u64 targetUserId; + + flagLocal = 0; + + if (NWC24IsMsgLibOpened() == 0 && NWC24IsMsgLibOpenedByTool() == 0) { + return -9; + } + + flags = msg->flags; + + if ((flags & 0x100) == 0 || (flags & 0x200) != 0) { + return -7; + } + + if (LoopBackEnable != 0 && (flags & 0x1) != 0) { + NWC24GetMyUserId(&myUserId); + if (msg->numTo == 1) { + targetUserId = msg->toIds[0]; + if ((targetUserId ^ myUserId) == 0) { + flagLocal = 1; + } + } + } + + return NWC24CommitMsgInternal(msg, flagLocal); +} + +static inline NWC24Err WriteDataCommand(NWC24MsgObj* msg) { + NWC24Err result; + char* stringWork = NWC24WorkP->stringWork; + Mail_strcpy(stringWork, "DATA\r\n"); + result = NWC24FWrite(stringWork, Mail_strlen(stringWork), m_pFile); + if (result == NWC24_OK) { + msg->length += 6; + } + return result; +} + +static inline NWC24Err WriteMessageIdField(NWC24MsgObj* msg) { + u64 myUserId; + char stackBuffer[32]; + NWC24Err result; + u32 writeSize; + char* stringWork = NWC24WorkP->stringWork; + const char* domain = NWC24GetAccountDomain(); + NWC24GetMyUserId(&myUserId); + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_strcpy(stringWork, "Message-ID: <"); + Mail_memset(stackBuffer, 0, 32); + Mail_sprintf(stackBuffer, "%08x%08x%08x%08x", msg->id, (u32)(myUserId >> 32), (u32)myUserId, msg->createTime); + Mail_strcat(stringWork, stackBuffer); + Mail_strcat(stringWork, domain); + Mail_strcat(stringWork, ">\r\n"); + writeSize = Mail_strlen(stringWork); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + return result; +} + +static inline NWC24Err WriteSubjectField(NWC24MsgObj* msg) { + char* stringWork = NWC24WorkP->stringWork; + NWC24Err result; + u32 writeSize; + if (msg->subject.size == 0) { + result = NWC24_ERR_NULL; + } else { + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_strcpy(stringWork, "Subject: "); + Mail_strncat(stringWork, (const char*)msg->subject.ptr, 1021); + Mail_strncat(stringWork, "\r\n", NWC24_WORK_BUFFER_SIZE); + writeSize = STD_strnlen(stringWork, NWC24_WORK_BUFFER_SIZE); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + } + return result; +} + +static inline NWC24Err WriteXWiiLedField(NWC24MsgObj* msg) { + NWC24Err result; + u32 writeSize; + if (msg->ledPattern == 0) { + return NWC24_OK; + } else { + char* stringWork = NWC24WorkP->stringWork; + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_sprintf(stringWork, "X-Wii-Led: %08x\r\n", msg->ledPattern); + writeSize = Mail_strlen(stringWork); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + } + return result; +} + +static inline NWC24Err WriteXWiiTagField(NWC24MsgObj* msg) { + NWC24Err result; + u32 writeSize; + if (msg->tag == 0) { + return NWC24_OK; + } else { + char* stringWork = NWC24WorkP->stringWork; + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_sprintf(stringWork, "X-Wii-Tag: %08x\r\n", msg->tag); + writeSize = Mail_strlen(stringWork); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + } + return result; +} + +static inline NWC24Err WriteXWiiAltField(NWC24MsgObj* msg) { + NWC24Err result; + u32 writeSize; + if (!(msg->flags & 0x2000)) { + return NWC24_OK; + } else { + char* stringWork = NWC24WorkP->stringWork; + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_sprintf(stringWork, "X-Wii-Alt: %08x\r\n", (u32)msg->altMeta.size); + writeSize = Mail_strlen(stringWork); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + } + return result; +} + +static inline NWC24Err WriteXWiiMBParameterField(NWC24MsgObj* msg) { + NWC24Err result; + if (!(msg->mb.raw & 0x80000000)) { + return NWC24_OK; + } else { + char* stringWork = NWC24WorkP->stringWork; + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_strcpy(stringWork, "X-Wii-MB-Parameter:\r\n"); + result = NWC24FWrite(stringWork, 21, m_pFile); + if (result == NWC24_OK) { + msg->length += 21; + } + } + return result; +} + +static inline NWC24Err WriteXWiiMBRegDateField(NWC24MsgObj* msg) { + u32 writeSize; + NWC24Err result; + u32 regdate = msg->mb.regdate; + if (regdate == 0) { + return NWC24_OK; + } else { + char* stringWork = NWC24WorkP->stringWork; + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_sprintf(stringWork, "X-Wii-MB-RegDate: %04x\r\n", regdate); + writeSize = STD_strnlen(stringWork, NWC24_WORK_BUFFER_SIZE); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + } + return result; +} + +static inline NWC24Err WriteXWiiMBDelayField(NWC24MsgObj* msg) { + NWC24Err result; + u32 writeSize; + u32 delay = msg->mb.raw & 0x00FF0000; + if (delay == 0) { + return NWC24_OK; + } else { + char* stringWork = NWC24WorkP->stringWork; + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_sprintf(stringWork, "X-Wii-MB-Delay: %02x\r\n", delay >> 16); + writeSize = STD_strnlen(stringWork, NWC24_WORK_BUFFER_SIZE); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + } + return result; +} + +static inline NWC24Err WriteCustomHeader(NWC24MsgObj* msg) { + NWC24Err result; + if (msg->DATA_0xD0.size == 0) { + return NWC24_OK; + } else { + result = NWC24FWrite(msg->DATA_0xD0.ptr, msg->DATA_0xD0.size, m_pFile); + if (result == NWC24_OK) { + msg->length += msg->DATA_0xD0.size; + } + } + return result; +} + +static inline NWC24Err WriteMimeHeader(NWC24MsgObj* msg) { + char* stringWork = NWC24WorkP->stringWork; + NWC24Err result; + u32 writeSize; + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_strcpy(stringWork, "MIME-Version: 1.0\r\n"); + if (msg->flags & 0x10000) { + Mail_strcat(stringWork, "Content-Type: multipart/mixed; boundary=\""); + Mail_strcat(stringWork, MultiPartDivider); + Mail_strcat(stringWork, "\"\r\n"); + } + writeSize = Mail_strlen(stringWork); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + return result; +} + +static inline NWC24Err WriteMimeBoundary(NWC24MsgObj* msg) { + char* stringWork = NWC24WorkP->stringWork; + NWC24Err result; + u32 writeSize; + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_sprintf(stringWork, "\r\n--%s", MultiPartDivider); + Mail_strcat(stringWork, "\r\n"); + writeSize = Mail_strlen(stringWork); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + return result; +} + +static inline NWC24Err WritePlainTextWrapper(NWC24MsgObj* msg) { + NWC24Err result; + result = WritePlainText(msg); + if (result == NWC24_ERR_NULL) { + return NWC24_OK; + } + return result; +} + +static inline NWC24Err WriteAttachedBase64(NWC24MsgObj* msg, s32 i) { + NWC24Err result; + u32 writeSize; + result = WriteBase64Data(msg->attached[i].ptr, msg->attached[i].size, &writeSize); + if (result == NWC24_OK) { + msg->length += writeSize; + } + return result; +} + +static inline NWC24Err WriteMimeBoundaryEnd(NWC24MsgObj* msg) { + char* stringWork = NWC24WorkP->stringWork; + NWC24Err result; + u32 writeSize; + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_sprintf(stringWork, "\r\n--%s", MultiPartDivider); + Mail_strcat(stringWork, "--\r\n"); + writeSize = Mail_strlen(stringWork); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + return result; +} + +NWC24Err NWC24CommitMsgInternal(NWC24MsgObj* msg, s32 mboxType) { + NWC24File file; + s32 i = 0; + u32 msgId; + NWC24Data data1; + NWC24Data data2; + NWC24Data attachedData[2]; + NWC24Err result; + NWC24Err err; + + NWC24Data_Init(&data1); + NWC24Data_Init(&data2); + + for (i = 0; i < 2; i++) { + NWC24Data_Init(&attachedData[i]); + } + + NWC24iSetErrorCode(NWC24_OK); + err = CheckMsgObject(msg); + if (err != NWC24_OK) { + goto exit_error; + } + err = CheckMsgBoxSpace(msg, mboxType); + if (err != NWC24_OK) { + goto exit_error; + } + result = NWC24iMBoxOpenNewMsg(mboxType, &file, &msgId); + if (result != NWC24_OK) { + err = result; + goto error_break; + } + msg->id = msgId; + msg->length = 0; + m_pFile = &file; + + if (mboxType == 0) { + result = WriteSMTP_MAILFROM(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + result = WriteSMTP_RCPTTO(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + result = WriteDataCommand(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + } + + result = WriteDateField(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + result = WriteFromField(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + result = WriteToField(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + + result = WriteMessageIdField(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + + data1.ptr = (void*)(msg->length + 9); + result = WriteSubjectField(msg); + if (result == NWC24_OK) { + data1.size = (msg->length - ((u32)data1.ptr)) - 2; + } else if (result == NWC24_ERR_NULL) { + result = NWC24_OK; + data1.ptr = 0; + } + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + + if (msg->flags & 1) { + result = WriteXWiiAppIdField(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + + result = WriteXWiiLedField(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + + result = WriteXWiiTagField(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + + result = WriteXWiiAltField(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + + result = WriteXWiiAltNameField(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + + result = WriteXWiiFaceField(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + + if (msg->mb.raw != 0) { + result = WriteXWiiMBParameterField(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + + result = WriteXWiiMBRegDateField(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + + result = WriteXWiiMBDelayField(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + } + } + + result = WriteCustomHeader(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + + Mail_memset(MultiPartDivider, 0, 40); + // TODO(Alex9303) Replace string with correct string + Mail_sprintf(MultiPartDivider, "----_%08x%08x__________", msg->createTime, msg->id); + + result = WriteMimeHeader(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + + if (msg->flags & 0x10000ULL) { + msg->UNK_0x10 = msg->length; + result = WriteMimeBoundary(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + } + + result = WriteContentTypeField(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + if (!(msg->flags & 0x10000)) { + msg->UNK_0x10 = msg->length; + } + data2.ptr = (void*)msg->length; + result = WritePlainTextWrapper(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + data2.size = msg->length - ((u32)data2.ptr); + + for (i = 0; i < ((u32)msg->numAttached); i++) { + result = WriteMimeBoundary(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + + result = WriteMIMEAttachHeader(msg, i); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + + attachedData[i].ptr = (void*)msg->length; + result = WriteAttachedBase64(msg, i); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + + attachedData[i].size = msg->length - ((u32)attachedData[i].ptr); + + if (i == (msg->numAttached - 1)) { + result = WriteMimeBoundaryEnd(msg); + if (result != NWC24_OK) { + NWC24FClose(&file); + err = result; + goto error_break; + } + } + } + +error_break: + if (err == NWC24_OK) { + NWC24iMBoxCloseMsg(&file); + } else { + NWC24iMBoxCancelMsg(&file, mboxType, msgId); + NWC24iMBoxFlushHeader(mboxType); + goto exit_error; + } + + msg->subject = data1; + msg->text = data2; + msg->attached[0] = attachedData[0]; + msg->attached[1] = *(attachedData + 1); + msg->flags |= 0x200; + + if (mboxType == 1) { + msg->flags |= 0x20; + } else if (mboxType == 0) { + msg->flags |= 0x10; + } + + result = NWC24iMBoxAddMsgObj(mboxType, msg); + if (err != NWC24_OK) { + result = err; + } + err = result; + + if (mboxType == 1) { + int arrivedFlags = 1; + if (msg->flags & 8) { + arrivedFlags |= 2; + } + NWC24iSetNewMsgArrived(arrivedFlags); + } + +exit_error: + if ((((((err == (NWC24_ERR_FULL)) || ((err <= (NWC24_ERR_FILE_OPEN)) && (err >= (NWC24_ERR_FILE_OTHER)))) || (err == (NWC24_ERR_NAND_CORRUPT))) || (err == (NWC24_ERR_FILE_EXISTS))) || (err == (NWC24_ERR_INTERNAL_VF))) || (err == (NWC24_ERR_FILE_BROKEN))) { + NWC24iSetErrorCode((NWC24Err)((err - 0x20000) + 21772)); + } + + return err; +} + +NWC24Err CheckMsgObject(const NWC24MsgObj* msg) { + const char* subject; + + u8 numTo = msg->numTo; + if (numTo == 0) { + return NWC24_ERR_NULL; + } + if (numTo > NWC24_MSG_RECIPIENT_MAX) { + return NWC24_ERR_INVALID_VALUE; + } + + subject = (const char*)msg->subject.ptr; + if (subject != NULL) { + const char* p = subject; + + while (*p != '\0') { + if ((p[0] == '\r' && p[1] != '\n')) { + return NWC24_ERR_FORMAT; + } + + if (p[0] == '\n' && p[1] != ' ') { + return NWC24_ERR_FORMAT; + } + + p++; + } + } + + if (msg->numAttached > NWC24_MSG_ATTACHMENT_MAX) { + return NWC24_ERR_INVALID_VALUE; + } + + return NWC24_OK; +} + +NWC24Err CheckMsgBoxSpace(NWC24MsgObj* msg, u32 requiredSize) { + u32 textSize; + u32 totalSize = 0; + int i; + NWC24Err result; + NWC24Err err; + + for (i = 0; i < (int)msg->numAttached; i++) { + totalSize += ((((msg->attachedSize[i] * 4) + 2) / 3) + ((msg->attachedSize[i] / 57) * 2)) + 4; + } + + switch (msg->encoding) { + case NWC24_ENC_7BIT: + case NWC24_ENC_8BIT: + textSize = msg->text.size; + break; + + case NWC24_ENC_BASE64: + textSize = ((((msg->text.size * 4) + 2) / 3) + ((msg->text.size / 57) * 2)) + 4; + break; + + case NWC24_ENC_QUOTED_PRINTABLE: + textSize = (msg->text.size * 4) / 3; + break; + + default: + textSize = 0; + break; + } + + totalSize += textSize; + + if (totalSize >= 0x31c00) { + return -8; + } + + err = NWC24iMBoxCheck(requiredSize, totalSize + NWC24_WORK_BUFFER_SIZE); + + result = 0; + if (err != 0) { + result = err; + } + + return result; +} + +NWC24Err SynthesizeAddrStr(NWC24AddrId* id_pair, u32 flags, char* out_buffer, int buffer_size, u32* out_length) { + s32 domain_len; + char id_str[20]; + NWC24Err result = 0; + const char* domain; + + if ((flags & 1) != 0) { + domain = NWC24GetAccountDomain(); + domain_len = Mail_strlen(domain); + + if (domain_len <= 0) { + result = NWC24_ERR_CONFIG; + goto cleanup; + } + + if ((domain_len + 0x12) >= buffer_size) { + result = NWC24_ERR_NOMEM; + goto cleanup; + } + + NWC24iConvIdToStr(id_pair->id, id_str); + domain_len = Mail_sprintf(out_buffer, "%c%s%s", 0x77, id_str, domain); + + if (domain_len == 0) { + result = NWC24_ERR_FATAL; + goto cleanup; + } + + *out_length = domain_len; + + } else if ((flags & 2) != 0) { + if ((id_pair->data.size + 3) >= buffer_size) { + result = NWC24_ERR_NOMEM; + goto cleanup; + } + + domain_len = Mail_sprintf(out_buffer, "%s", id_pair->data.ptr); + + if (domain_len == 0) { + result = NWC24_ERR_FATAL; + goto cleanup; + } + + *out_length = domain_len; + + } else { + result = NWC24_ERR_INVALID_VALUE; + } + +cleanup: + return result; +} + +NWC24Err WriteSMTP_MAILFROM(NWC24MsgObj* msg) { + NWC24Err err; + char* workp; + u32 addrType; + u32 addrLen; + int totalLen; + + workp = NWC24WorkP->stringWork; + + Mail_memset(workp, 0, NWC24_WORK_BUFFER_SIZE); + Mail_strncat(workp, "MAIL FROM:<", 0x3fe); + + workp += 11; + + addrType = 1; + if (msg->flags & 0x100000ULL) { + addrType = 2; + } + + err = SynthesizeAddrStr((NWC24AddrId*)&msg->fromId, addrType, workp, 0x3fe, &addrLen); + if (err != NWC24_OK) { + return err; + } + + workp += addrLen; + *workp++ = '\r'; + *workp++ = '\n'; + + totalLen = addrLen + 13; + + if ((0x3fe - totalLen) <= 0) { + return NWC24_ERR_NOMEM; + } + + if (err == NWC24_OK) { + err = NWC24FWrite(NWC24WorkP->stringWork, totalLen, m_pFile); + if (err == NWC24_OK) { + msg->length += totalLen; + } + } + + return err; +} + +NWC24Err WriteSMTP_RCPTTO(NWC24MsgObj* msg) { + char* workp; + u32 i; + u32 totalLen; + int remainSize; + NWC24Err err; + + workp = NWC24WorkP->stringWork; + totalLen = 0; + err = NWC24_OK; + + Mail_memset(workp, 0, NWC24_WORK_BUFFER_SIZE); + remainSize = 0x3fe; + + for (i = 0; i < msg->numTo; i++) { + u32 addrLen; + + Mail_strncat(workp, "RCPT TO:<", remainSize); + workp += 9; + + err = SynthesizeAddrStr((NWC24AddrId*)&msg->toIds[i], msg->flags, workp, remainSize, &addrLen); + if (err != NWC24_OK) { + break; + } + + workp += addrLen; + *workp++ = '\r'; + *workp++ = '\n'; + + remainSize -= (addrLen + 11); + totalLen += (addrLen + 11); + + if (remainSize <= 0) { + err = NWC24_ERR_NOMEM; + break; + } + } + + if (err == NWC24_OK) { + err = NWC24FWrite(NWC24WorkP->stringWork, totalLen, m_pFile); + if (err == NWC24_OK) { + msg->length += totalLen; + } + } + + return err; +} + +NWC24Err WriteFromField(NWC24MsgObj* msg) { + char* workp; + u32 addrType; + u32 addrLen; + NWC24Err err; + int totalLen; + + workp = NWC24WorkP->stringWork; + + Mail_memset(workp, 0, NWC24_WORK_BUFFER_SIZE); + Mail_strncat(workp, "From: ", 0x3fe); + + workp += 6; + msg->DATA_0x30.ptr = (void*)(msg->length + 6); + + addrType = 1; + if (msg->flags & 0x100000ULL) { + addrType = 2; + } + + err = SynthesizeAddrStr((NWC24AddrId*)&msg->fromId, addrType, workp, 0x3fe, &addrLen); + if (err != NWC24_OK) { + return err; + } + + workp += addrLen; + *workp++ = '\r'; + *workp++ = '\n'; + + totalLen = addrLen + 8; + + if (0x3fe - totalLen <= 0) { + return NWC24_ERR_NOMEM; + } + + if (err == NWC24_OK) { + err = NWC24FWrite(NWC24WorkP->stringWork, totalLen, m_pFile); + if (err == NWC24_OK) { + msg->length += totalLen; + msg->DATA_0x30.size = ((int)(msg->length - (u32)msg->DATA_0x30.ptr)) - 2; + } + } + + return err; +} + +NWC24Err WriteToField(NWC24MsgObj* msg) { + NWC24AddrId* toId; + char* workp; + int i; + int totalLen; + int remainSize; + u32 len; + NWC24Err err; + + workp = NWC24WorkP->stringWork; + err = NWC24_OK; + + Mail_memset(workp, 0, NWC24_WORK_BUFFER_SIZE); + Mail_strncat(workp, "To: ", NWC24_WORK_BUFFER_SIZE); + + workp += 4; + toId = (NWC24AddrId*)&msg->toIds[0]; + i = 0; + totalLen = 4; + remainSize = 0x3FC; + + *(u32*)&msg->DATA_0x38.ptr = msg->length + 4; + + while (i < msg->numTo) { + err = SynthesizeAddrStr(toId, msg->flags, workp, remainSize, &len); + if (err != NWC24_OK) { + break; + } + + remainSize -= len; + workp += len; + totalLen += len; + + if (remainSize <= 4) { + err = -11; + break; + } + + if (i < msg->numTo - 1) { + *workp++ = ','; + *workp++ = '\r'; + *workp++ = '\n'; + *workp++ = ' '; + totalLen += 4; + remainSize -= 4; + } + + toId++; + i++; + } + + *workp++ = '\r'; + *workp++ = '\n'; + totalLen += 2; + + if (err == NWC24_OK) { + err = NWC24FWrite(NWC24WorkP, totalLen, m_pFile); + if (err == NWC24_OK) { + msg->length += totalLen; + msg->DATA_0x38.size = ((int) (msg->length - (*((u32 *) (&msg->DATA_0x38.ptr))))) - 2; + } + } + + return err; +} + +NWC24Err WriteDateField(NWC24MsgObj* msg) { + char* workp; + NWC24Date date; + u32 len; + NWC24Err err; + NWC24Calendar cal; + + NWC24Date_Init(&date); + NETGetUniversalCalendar((u8*)&cal); + + date.year = cal.year; + date.month = cal.month + 1; + date.day = cal.day; + date.hour = cal.hour; + date.min = cal.min; + date.sec = cal.sec; + + if (date.month > 12) { + return NWC24_ERR_FORMAT; + } + + workp = NWC24WorkP->stringWork; + Mail_memset(workp, 0, NWC24_WORK_BUFFER_SIZE); + + len = Mail_sprintf(workp, "Date: %02d %s %d %02d:%02d:%02d +0000\r\n", date.day, MonthStr[date.month - 1], date.year, date.hour, date.min, date.sec); + + NWC24iDateToMinutes(&msg->createTime, &date); + len = Mail_strlen(workp); + + err = NWC24FWrite(workp, len, m_pFile); + if (err == NWC24_OK) { + msg->length += len; + } + + return err; +} + +NWC24Err WriteXWiiAppIdField(NWC24MsgObj* msg) { + char* workp = NWC24WorkP->stringWork; + char tempbuf[16]; + u32 flags = 0; + u32 len; + + Mail_memset(workp, 0, NWC24_WORK_BUFFER_SIZE); + Mail_strcpy(workp, "X-Wii-AppId: "); + + if (NWC24IsMsgLibOpenedByTool() == 0) { + if (NWC24GetAppId() != 0x48414541) { + msg->appId = NWC24GetAppId(); + } + } + + if (msg->flags & 0x4) { + flags |= 1; + } + if (msg->flags & 0x8) { + flags |= 2; + } + + Mail_memset(tempbuf, 0, 0x10); + Mail_sprintf(tempbuf, "%d-%08x-%04x", flags, msg->appId, msg->groupId); + Mail_strcat(workp, tempbuf); + + len = Mail_strlen(workp); + if (NWC24FWrite(workp, len, m_pFile) == NWC24_OK) { + msg->length += len; + } +} + +NWC24Err WriteXWiiFaceField(NWC24MsgObj* msg) { + char* workp; + const u8* dataPtr; + u32 currentOffset = 0; + NWC24Err err = NWC24_OK; + u32 encodedLen; + s32 remainSize; + s32 chunkSize; + + if (msg->face.size == 0) { + return NWC24_OK; + } + + workp = NWC24WorkP->stringWork; + + Mail_memset(workp, 0, NWC24_WORK_BUFFER_SIZE); + Mail_strcpy(workp, "X-Wii-Face:"); + currentOffset = 10; + dataPtr = (const u8*)msg->face.ptr; + remainSize = msg->face.size; + + while (remainSize > 0) { + workp[currentOffset++] = ' '; + chunkSize = remainSize; + if (remainSize > 42) { + chunkSize = 42; + } + + err = NWC24Base64Encode((char*)dataPtr, chunkSize, workp + currentOffset, 76, &encodedLen); + + dataPtr += chunkSize; + remainSize -= chunkSize; + currentOffset += encodedLen; + + workp[currentOffset++] = '\r'; + workp[currentOffset++] = '\n'; + } + + err = NWC24FWrite(workp, currentOffset, m_pFile); + if (err == NWC24_OK) { + msg->length += currentOffset; + } + + return err; +} + +NWC24Err WriteXWiiAltNameField(NWC24MsgObj* msg) { + char* workp; + const u8* dataPtr; + u32 currentOffset = 0; + NWC24Err err = NWC24_OK; + u32 encodedLen; + s32 remainSize; + s32 chunkSize; + + if (msg->alt.size == 0) { + return NWC24_OK; + } + + workp = NWC24WorkP->stringWork; + + Mail_memset(workp, 0, NWC24_WORK_BUFFER_SIZE); + Mail_strcpy(workp, "X-Wii-AltName:"); + currentOffset = 14; + dataPtr = (const u8*)msg->alt.ptr; + remainSize = msg->alt.size; + + while (remainSize > 0) { + workp[currentOffset++] = ' '; + chunkSize = remainSize; + if (remainSize > 42) { + chunkSize = 42; + } + + err = NWC24Base64Encode((char*)dataPtr, chunkSize, workp + currentOffset, 76, &encodedLen); + + dataPtr += chunkSize; + remainSize -= chunkSize; + currentOffset += encodedLen; + + workp[currentOffset++] = '\r'; + workp[currentOffset++] = '\n'; + } + + err = NWC24FWrite(workp, currentOffset, m_pFile); + if (err == NWC24_OK) { + msg->length += currentOffset; + } + + return err; +} + +NWC24Err WriteMIMEAttachHeader(NWC24MsgObj* msg, u32 attachIndex) { + char* workp; + const char* mimeTypeStr; + const char* mimeSuffix; + s32 written; + s32 totalWritten = 0; + NWC24Err err; + + Mail_memset(NWC24WorkP->stringWork, 0, NWC24_WORK_BUFFER_SIZE); + workp = NWC24WorkP->stringWork; + + mimeTypeStr = NWC24GetMIMETypeStr(msg->attachedType[attachIndex]); + mimeSuffix = NWC24iGetMIMETypeSuffix(msg->attachedType[attachIndex]); + + written = Mail_strlen(ContentTypeA) + Mail_strlen(ContentTxEncA) + Mail_strlen(ContentDispA) + Mail_strlen(mimeTypeStr) + 4; + + if (written >= NWC24_WORK_BUFFER_SIZE) { + return NWC24_ERR_NOMEM; + } + + written = Mail_sprintf(workp, ContentTypeA, mimeTypeStr, (char)('a' + attachIndex), msg->id, mimeSuffix);; + if (written <= 0) { + return NWC24_ERR_FAILED; + } + workp += written; + totalWritten += written; + + written = Mail_sprintf(workp, ContentTxEncA); + if (written <= 0) { + return NWC24_ERR_FAILED; + } + workp += written; + totalWritten += written; + + written = Mail_sprintf(workp, ContentDispA, (char)('a' + attachIndex), msg->id, mimeSuffix); + if (written <= 0) { + return NWC24_ERR_FAILED; + } + workp += written; + totalWritten += written; + + err = NWC24FWrite(NWC24WorkP->stringWork, totalWritten, m_pFile); + if (err == NWC24_OK) { + msg->length += totalWritten; + } + + return err; +} + +NWC24Err WriteContentTypeField(NWC24MsgObj* msg) { + char* work = NWC24WorkP->stringWork; + const char* charset; + const char* encoding; + u32 total = 0; + NWC24Err err = NWC24_OK; + + Mail_memset(work, 0, NWC24_WORK_BUFFER_SIZE); + + charset = NWC24GetCharsetStr(msg->charset); + if (charset != NULL) { + int clen = 0; + + Mail_sprintf(work, ContentTypeTP, charset); + + msg->contentType.ptr = (void*)(msg->length + 0x22); + + clen = Mail_strlen(charset); + msg->contentType.size = clen + 1; + + clen = Mail_strlen(work); + total += clen; + work += clen; + } + + encoding = NWC24GetEncodingStr(msg->encoding); + if (encoding != NULL) { + int elen = 0; + + Mail_sprintf(work, ContentTxEncT, encoding); + + msg->transferEncoding.ptr = (void*)(msg->length + total + 0x1b); + + elen = Mail_strlen(encoding); + msg->transferEncoding.size = elen + 1; + + elen = Mail_strlen(work); + total += elen; + } + + if (total == 0) { + err = NWC24_OK; + } else { + err = NWC24FWrite(NWC24WorkP->stringWork, total, m_pFile); + if (err == NWC24_OK) { + msg->length += total; + } + } + + return err; +} + +NWC24Err WritePlainText(NWC24MsgObj* msg) { + NWC24Err err = NWC24_OK; + u32 bytesWritten; + + if (msg->text.size == 0) { + return NWC24_ERR_NULL; + } + + switch (msg->encoding) { + case NWC24_ENC_7BIT: + case NWC24_ENC_8BIT: + err = NWC24FWrite(msg->text.ptr, msg->text.size, m_pFile); + bytesWritten = msg->text.size; + break; + case NWC24_ENC_BASE64: + err = WriteBase64Data(msg->text.ptr, msg->text.size, &bytesWritten); + break; + case NWC24_ENC_QUOTED_PRINTABLE: + err = WriteQPData(msg->text.ptr, msg->text.size, &bytesWritten); + break; + default: + err = NWC24_ERR_INVALID_VALUE; + break; + } + + if (err == NWC24_OK) { + msg->altMeta.ptr = (const void *)msg->text.size; + msg->length += bytesWritten; + } + + return err; +} + +NWC24Err WriteBase64Data(const void* data, u32 size, u32* bytesWritten) { + char* workp = NWC24WorkP->stringWork; + const u8* dataPtr = (const u8*)data; + int remainSize = size; + int totalWritten = 0; + NWC24Err err = NWC24_OK; + u32 encodedLen; + + while (remainSize >= 57) { + Mail_memset(workp, 0, NWC24_WORK_BUFFER_SIZE); + err = NWC24Base64Encode((char*)dataPtr, 57, workp, 76, &encodedLen); + if (err != NWC24_OK) { + break; + } + + workp[encodedLen++] = '\r'; + workp[encodedLen++] = '\n'; + workp[encodedLen] = '\0'; + + err = NWC24FWrite(workp, encodedLen, m_pFile); + if (err != NWC24_OK) { + break; + } + + dataPtr += 57; + remainSize -= 57; + totalWritten += encodedLen; + } + + if (err == NWC24_OK) { + Mail_memset(workp, 0, NWC24_WORK_BUFFER_SIZE); + err = NWC24Base64Encode((char*)dataPtr, remainSize, workp, 76, &encodedLen); + if (err == NWC24_OK) { + workp[encodedLen++] = '\r'; + workp[encodedLen++] = '\n'; + workp[encodedLen++] = '\r'; + workp[encodedLen++] = '\n'; + workp[encodedLen] = '\0'; + + err = NWC24FWrite(workp, encodedLen, m_pFile); + if (err == NWC24_OK) { + totalWritten += encodedLen; + } + } + } + + *bytesWritten = totalWritten; + return err; +} + +NWC24Err WriteQPData(const void* data, u32 size, u32* bytesWritten) { + char* workp = NWC24WorkP->stringWork; + const u8* dataPtr = (const u8*)data; + int remainSize = size; + int totalWritten = 0; + NWC24Err err = NWC24_OK; + + while (remainSize > 0) { + u32 consumed; + u32 written; + + if (totalWritten > 0) { + Mail_memcpy(workp, "=\r\n", 3); + err = NWC24FWrite(workp, 3, m_pFile); + if (err != NWC24_OK) { + break; + } + totalWritten += 3; + } + + Mail_memset(workp, 0, NWC24_WORK_BUFFER_SIZE); + err = NWC24EncodeQuotedPrintable((u8*)workp, NWC24_WORK_BUFFER_SIZE, &written, (u8*)dataPtr, remainSize, &consumed); + + if (err != NWC24_OK) { + if (err != NWC24_ERR_OVERFLOW) { + break; + } + } + + err = NWC24FWrite(workp, written, m_pFile); + if (err != NWC24_OK) { + break; + } + + dataPtr += consumed; + remainSize -= consumed; + totalWritten += written; + } + + *bytesWritten = totalWritten; + return err; +} diff --git a/src/revolution/NWC24/NWC24MsgObj.c b/src/revolution/NWC24/NWC24MsgObj.c index 95810c88..b2b78ada 100644 --- a/src/revolution/NWC24/NWC24MsgObj.c +++ b/src/revolution/NWC24/NWC24MsgObj.c @@ -52,7 +52,7 @@ NWC24Err NWC24InitMsgObj(NWC24MsgObj* msg, NWC24MsgType type) { return NWC24_ERR_INVALID_VALUE; } - _msg->WORD_0x28 = 0; + _msg->createTime = 0; _msg->WORD_0x2C = 0; NWC24GetMyUserId(&_msg->fromId); _msg->numTo = 0; @@ -79,8 +79,8 @@ NWC24Err NWC24InitMsgObj(NWC24MsgObj* msg, NWC24MsgType type) { NWC24Data_Init(&_msg->DATA_0x30); NWC24Data_Init(&_msg->DATA_0x38); - NWC24Data_Init(&_msg->DATA_0x50); - NWC24Data_Init(&_msg->DATA_0x58); + NWC24Data_Init(&_msg->contentType); + NWC24Data_Init(&_msg->transferEncoding); NWC24Data_Init(&_msg->DATA_0xD0); NWC24Data_Init(&_msg->face); NWC24Data_Init(&_msg->alt); diff --git a/src/revolution/NWC24/NWC24StdApi.c b/src/revolution/NWC24/NWC24StdApi.c new file mode 100644 index 00000000..b5ace858 --- /dev/null +++ b/src/revolution/NWC24/NWC24StdApi.c @@ -0,0 +1,296 @@ +#include + +char* Mail_strcpy(char* dst, const char* src) { + char* backup = dst; + + while (*src != '\0') { + *dst++ = *src++; + }; + + *dst = '\0'; + return backup; +} + +size_t Mail_strlen(const char* str) { + size_t len = 0; + + while (str[len] != '\0') { + len++; + } + + return len; +} + +size_t STD_strnlen(const char* str, size_t n) { + size_t len = 0; + int i; + + for (i = 0; i < n; i++) { + if (str[len] == '\0') { + break; + } + + len++; + } + + return len; +} + +void* Mail_memcpy(void* dst, const void* src, size_t n) { + size_t i; + + for (i = 0; i < n; i++) { + ((u8*)dst)[i] = ((u8*)src)[i]; + } + + return dst; +} + +void* Mail_memset(void* dst, int ch, size_t n) { + size_t i; + + for (i = 0; i < n; i++) { + ((u8*)dst)[i] = ch; + } + + return dst; +} + +char* Mail_strcat(char* dst, const char* src) { + Mail_strcpy(dst + Mail_strlen(dst), src); + return dst; +} + +char* Mail_strncat(char* dst, const char* src, size_t n) { + const size_t len = Mail_strlen(dst); + size_t i; + + for (i = 0; i < n && src[i] != '\0'; i++) { + dst[i + len] = src[i]; + }; + + dst[(int)len + (int)i] = '\0'; + return dst; +} + +// Not really sure how get non-inlined Mail_strlen() to inline naturally. +inline static int Mail_strlen_inline(const char *str) { + int len = 0; + while (str[len] != '\0') { + len++; + } + return len; +} + +inline static void set_to_head(char *str, char c) { + // TODO(Alex9303) Figure out how to get Mail_strlen to inline naturally here. + int len = Mail_strlen_inline(str); + int i; + for (i = len; i >= 0; i--) { + str[i + 1] = str[i]; + } + *str = c; +} + +inline static void set_to_tail(char *str, char c) { + int len; + len = Mail_strlen(str); + str[len++] = c; + str[len] = '\0'; +} + +int convNum(char *dst, int number, int numberBase, char charBase, int signedFlag, int width, char specifierChar, char justifyChar) { + unsigned int workingValue; + int charsWritten; + int digitcharsWritten; + char remainder; + char digitCharBase; + char finalPadChar; + BOOL isNegative; + + if ((signedFlag != 0) && (number & 0x80000000)) { + isNegative = 1; + workingValue = -number; + } else { + isNegative = 0; + workingValue = number; + } + + digitcharsWritten = 0; + charsWritten = 0; + + while (workingValue != 0) { + remainder = workingValue % numberBase; + + workingValue /= numberBase; + digitCharBase = charBase; + set_to_head(dst, remainder + ((char)((remainder <= 9) ? (0x30) : (digitCharBase)))); + digitcharsWritten++; + charsWritten++; + } + + if ((*dst) == '\0') { + set_to_head(dst, '0'); + digitcharsWritten++; + charsWritten++; + } + + finalPadChar = specifierChar; + if (finalPadChar != '0') { + finalPadChar = ' '; + } + + digitcharsWritten += isNegative; + + while (digitcharsWritten < width) { + if (justifyChar == 'L') { + set_to_tail(dst, ' '); + charsWritten++; + } else { + set_to_head(dst, finalPadChar); + charsWritten++; + } + digitcharsWritten++; + } + + if (isNegative) { + set_to_head(dst, '-'); + } + + return charsWritten; +} + +int Mail_sprintf(char *buffer, const char *format, ...) +{ + va_list args; + int ret; + + va_start(args, format); + ret = Mail_vsprintf(buffer, format, args); + va_end(args); + + return ret; +} + +int Mail_vsprintf(char *str, char *format, va_list arg) { + s32 charsWritten; + BOOL isNumberFormat; + BOOL signedFlag; + s32 stringLength; + s32 numberBase; + s32 width; + char formatChar; + char justifyChar; + char specifierChar; + char charBase; + char *stringArg; + char longFlag; + u32 number; + + *str = 0; + charsWritten = 0; + + while ((formatChar = *format++) != 0) { + while (*str) { + str++; + } + + if (formatChar == '%') { + (formatChar = *format++); + if (formatChar == '%') { + set_to_tail(str++, formatChar); + charsWritten++; + } else { + justifyChar = formatChar; + if (formatChar == '-') { + formatChar = *format++; + } + + specifierChar = formatChar; + signedFlag = FALSE; + numberBase = 10; + charBase = '0'; + isNumberFormat = FALSE; + + if (formatChar == '*') { + width = va_arg(arg, int); + formatChar = *format++; + } else { + width = 0; + while ((formatChar >= '0') && (formatChar <= '9')) { + width = width * 10 + formatChar - '0'; + formatChar = *format++; + } + } + + longFlag = formatChar & 0xDF; + if (longFlag == 'L') { + formatChar = *format++; + } + + switch (formatChar) { + case 'd': + isNumberFormat = TRUE; + signedFlag = TRUE; + break; + case 'o': + isNumberFormat = TRUE; + numberBase = 8; + break; + case 'u': + isNumberFormat = TRUE; + break; + case 'x': + isNumberFormat = TRUE; + numberBase = 16; + charBase = 'a' - 10; + break; + case 'X': + isNumberFormat = TRUE; + numberBase = 16; + charBase = 'A' - 10; + break; + case 'c': + formatChar = va_arg(arg, s32); + set_to_tail(str++, formatChar); + charsWritten++; + break; + case 's': + stringArg = va_arg(arg, char *); + if (stringArg) { + stringLength = Mail_strlen(stringArg); + Mail_strcat(str, stringArg); + } else { + stringLength = 0; + } + charsWritten += stringLength; + while (stringLength < width) { + charsWritten++; + if (justifyChar == '-') { + set_to_tail(str, ' '); + } else { + set_to_head(str, ' '); + } + stringLength++; + } + break; + } + + if (isNumberFormat) { + if (longFlag == 'L') { + number = va_arg(arg, u32); + } else if (signedFlag) { + number = va_arg(arg, s32); + } else { + number = va_arg(arg, u32); + } + charsWritten += convNum(str, number, numberBase, charBase, signedFlag, width, specifierChar, justifyChar); + } + } + } else { + set_to_tail(str++, formatChar); + charsWritten++; + } + } + return charsWritten; +} From 89b90fedda3902a763d402a2b14a9f2d30ce74e9 Mon Sep 17 00:00:00 2001 From: Alex9303 Date: Fri, 20 Feb 2026 06:58:46 -0500 Subject: [PATCH 2/4] clean up DateDarser --- include/revolution/NWC24/NWC24DateParser.h | 9 ---- src/revolution/NWC24/NWC24DateParser.c | 63 ++++++++++++++-------- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/include/revolution/NWC24/NWC24DateParser.h b/include/revolution/NWC24/NWC24DateParser.h index c6855c60..8bdfc699 100644 --- a/include/revolution/NWC24/NWC24DateParser.h +++ b/include/revolution/NWC24/NWC24DateParser.h @@ -9,15 +9,6 @@ extern "C" { NWC24Err NWC24iIsValidDate(u16 year, u8 month, u8 day); -typedef struct NWC24iDate { - u16 year; - u8 month; - u8 day; - u8 hour; - u8 min; - u8 sec; -} NWC24iDate; - #ifdef __cplusplus } #endif diff --git a/src/revolution/NWC24/NWC24DateParser.c b/src/revolution/NWC24/NWC24DateParser.c index bb632b55..ae81f8c6 100644 --- a/src/revolution/NWC24/NWC24DateParser.c +++ b/src/revolution/NWC24/NWC24DateParser.c @@ -3,17 +3,20 @@ const u8 DAYS_OF_MONTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0, 0, 0, 0}; const u16 DAYS_OF_YEAR[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; +NWC24Err NWC24iDateToMinutes(s32 *outMinutes, const NWC24Date *date); +NWC24Err NWC24iEpochSecondsToDate(NWC24Date *date, s64 timestamp); +NWC24Err NWC24iDateToOSCalendarTime(OSCalendarTime *time, const NWC24Date *date); +NWC24Err NWC24iIsValidDate(u16 year, u8 month, u8 day); +static BOOL IsLeapYear(u16 year); s32 ConvertDateToDays(u16 year, u16 month, u16 day); void ConvertDaysToDate(u16 *year, u8 *month, u8 *day, s32 days); +static s32 ConvertTimeToMinutes(u8 hour, u8 sec); +static s32 ConvertDaysToMinutes(s32 days); +static s32 ConvertMinutesToDays(s32 minutes); -inline BOOL IsLeapYear(u16 year) { - return (((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) != 0); -} - -NWC24Err NWC24iDateToMinutes(s32 *outMinutes, const NWC24iDate *date) { +NWC24Err NWC24iDateToMinutes(s32 *outMinutes, const NWC24Date *date) { s32 days; s32 minutes; - u8 seconds; days = ConvertDateToDays(date->year, date->month, date->day); @@ -21,22 +24,16 @@ NWC24Err NWC24iDateToMinutes(s32 *outMinutes, const NWC24iDate *date) { return NWC24_ERR_FAILED; } - seconds = date->sec; - if (date->hour > 23 || seconds > 59) { - minutes = -1; - } else { - minutes = seconds + (date->hour * 60); - } - - if (minutes == -1 || date->min > 60) { + minutes = ConvertTimeToMinutes(date->hour, date->min); + if (minutes == -1 || date->sec > 60) { return NWC24_ERR_FAILED; } - *outMinutes = days * (24 * 60) + minutes; + *outMinutes = ConvertDaysToMinutes(days) + minutes; return NWC24_OK; } -NWC24Err NWC24iEpochSecondsToDate(NWC24iDate *date, s64 timestamp) { +NWC24Err NWC24iEpochSecondsToDate(NWC24Date *date, s64 timestamp) { s64 adjusted = -0x7c558180U; s32 minutes; u32 days; @@ -46,30 +43,30 @@ NWC24Err NWC24iEpochSecondsToDate(NWC24iDate *date, s64 timestamp) { } timestamp += adjusted; - date->min = (u8)(timestamp % 60); + date->sec = (u8)(timestamp % 60); minutes = timestamp / 60; if (minutes < 0) { minutes = 0; } - days = minutes / (24 * 60); + days = ConvertMinutesToDays(minutes); minutes %= (24 * 60); + date->hour = (u8)(minutes / 60); - date->sec = (u8)(minutes % 60); + date->min = (u8)(minutes % 60); ConvertDaysToDate(&date->year, &date->month, &date->day, days); return NWC24_OK; } -NWC24Err NWC24iDateToOSCalendarTime(OSCalendarTime *time, const NWC24iDate *date) { +NWC24Err NWC24iDateToOSCalendarTime(OSCalendarTime *time, const NWC24Date *date) { s32 daysSinceEpoch; time->year = date->year; time->month = date->month - 1; time->mday = date->day; time->hour = date->hour; - // TODO(Alex9303) Why are minutes and seconds swapped here? Is this a decompilation error or is it actually swapped in the original code? - time->min = date->sec; // Swapped? - time->sec = date->min; // Swapped? + time->min = date->min; + time->sec = date->sec; time->msec = 0; time->usec = 0; time->yday = (DAYS_OF_YEAR[time->month] + date->day) - 1; @@ -79,6 +76,7 @@ NWC24Err NWC24iDateToOSCalendarTime(OSCalendarTime *time, const NWC24iDate *date } daysSinceEpoch = ConvertDateToDays(date->year, date->month, date->day); + // Possibly NWC24iGetDayOfWeek(daysSinceEpoch)? time->wday = (daysSinceEpoch + 1) % 7; return NWC24_OK; } @@ -94,6 +92,10 @@ NWC24Err NWC24iIsValidDate(u16 year, u8 month, u8 day) { return result; } +static BOOL IsLeapYear(u16 year) { + return (((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) != 0); +} + s32 ConvertDateToDays(u16 year, u16 month, u16 day) { s32 dayOfYear; s32 yearsSince1900; @@ -174,3 +176,18 @@ void ConvertDaysToDate(u16 *year, u8 *month, u8 *day, s32 days) { *day += remaining; } + +static s32 ConvertTimeToMinutes(u8 hour, u8 sec) { + if (hour > 23 || sec > 59) { + return -1; + } + return (sec + (hour * 60)); +} + +static s32 ConvertDaysToMinutes(s32 days) { + return days * (24 * 60); +} + +static s32 ConvertMinutesToDays(s32 minutes) { + return minutes / (24 * 60); +} From 50d797c767dde1c587f3e1bf6ef11484574c57ee Mon Sep 17 00:00:00 2001 From: Alex9303 Date: Fri, 20 Feb 2026 13:48:27 -0500 Subject: [PATCH 3/4] Clean up MBoxCtrl and StdApi --- src/revolution/NWC24/NWC24MBoxCtrl.c | 458 ++++++++++----------------- src/revolution/NWC24/NWC24StdApi.c | 29 +- 2 files changed, 196 insertions(+), 291 deletions(-) diff --git a/src/revolution/NWC24/NWC24MBoxCtrl.c b/src/revolution/NWC24/NWC24MBoxCtrl.c index 1a95b8d7..ecac7e23 100644 --- a/src/revolution/NWC24/NWC24MBoxCtrl.c +++ b/src/revolution/NWC24/NWC24MBoxCtrl.c @@ -4,11 +4,27 @@ MountInfoStruct MountInfo; int Mail_sprintf(char* buffer, const char* format, ...); -NWC24Err DuplicationCheck(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC24File* file, s32 mboxType); +NWC24Err NWC24iOpenMBox(void); +NWC24Err NWC24iMBoxOpenNewMsg(s32 mboxType, NWC24File* file, u32* msgId); +NWC24Err NWC24iMBoxCloseMsg(NWC24File* file); +NWC24Err NWC24iMBoxCancelMsg(NWC24File* file, s32 mboxType, u32 msgId); +NWC24Err NWC24iMBoxAddMsgObj(s32 mboxType, NWC24MsgObj* msg); +NWC24Err NWC24iMBoxFlushHeader(s32 mboxType); +NWC24Err NWC24iMBoxCheck(s32 mboxType, u32 requiredSize); +static NWC24Err GetMBoxFilePath(char* buffer, s32 mboxType, u32 msgId); +static NWC24Err MakeMailPath(char* buffer, s32 mboxType); +static BOOL IsFileThere(const char* path); NWC24Err DeleteMsg(s32 mboxType, u32 msgId, u32 flags); +NWC24Err DuplicationCheck(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC24File* file, s32 mboxType); NWC24Err GetCachedMBCHeader(s32 mboxType, MBoxControlHeader** headerOut); +static NWC24Err LoadMBCHeader(NWC24File* file, MBoxControlHeader* header); +static NWC24Err SaveMBCHeader(NWC24File* file, MBoxControlHeader* header); NWC24Err AddMBCEntry(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC24File* file); +static NWC24Err ClearMBCEntry(MBoxControlHeader* header, u32 offset, NWC24File* file); +static NWC24Err GetNewMsgId(MBoxControlHeader* header, u32* msgIdOut); +inline static s32 CompareMsgId(u32 id1, u32 id2); NWC24Err MountVFMBox(s32 mboxType); +inline static NWC24Err UnmountVFMBox(void); NWC24Err CopyMsgObjToMBCFmt(const NWC24MsgObj* src, MBoxControlEntry* dst); inline static NWC24Err UnmountVFMBox(void) { @@ -47,8 +63,6 @@ inline static NWC24Err UnmountVFMBox(void) { NWC24Err NWC24iOpenMBox(void) { NWC24Err err; MBoxControlHeader* header; - NWC24File recvFile; - NWC24File sendFile; char* pathWork; const char* mboxDir; @@ -70,7 +84,7 @@ NWC24Err NWC24iOpenMBox(void) { if (STD_strnlen(mboxDir, 0x40) + 14 > 0x100) { err = NWC24_ERR_NOMEM; } else { - Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24send.ctl"); + Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24recv.mbx"); err = NWC24_OK; } @@ -78,11 +92,7 @@ NWC24Err NWC24iOpenMBox(void) { return err; } - err = NWC24FOpen(&recvFile, pathWork, 2); - if (err == NWC24_OK) { - err = NWC24FClose(&recvFile); - } - + err = IsFileThere(pathWork); if (err != NWC24_OK) { return err; } @@ -91,7 +101,7 @@ NWC24Err NWC24iOpenMBox(void) { if (STD_strnlen(mboxDir, 0x40) + 14 > 0x100) { err = NWC24_ERR_NOMEM; } else { - Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24recv.ctl"); + Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24send.mbx"); err = NWC24_OK; } @@ -99,11 +109,7 @@ NWC24Err NWC24iOpenMBox(void) { return err; } - err = NWC24FOpen(&sendFile, pathWork, 2); - if (err == NWC24_OK) { - err = NWC24FClose(&sendFile); - } - + err = IsFileThere(pathWork); if (err != NWC24_OK) { return err; } @@ -113,31 +119,17 @@ NWC24Err NWC24iOpenMBox(void) { return NWC24_OK; } -NWC24Err NWC24iMBoxOpenNewMsg(s32 mboxType, NWC24File* file, u32* msgId) { +NWC24Err NWC24iMBoxOpenNewMsg(s32 mboxType, NWC24File *file, u32 *msgId) { NWC24Err err; - MBoxControlHeader* header; - MBoxControlHeader* footer; - char* path; - u32 id; + MBoxControlHeader *header; + char *path; err = GetCachedMBCHeader(mboxType, &header); if (err != NWC24_OK) { return err; } - footer = header; - - if (footer->magic != 0x57635466) { - err = NWC24_ERR_INVALID_VALUE; - } else { - if (footer->nextMsgId > 1000000) { - footer->nextMsgId = 1; - } - err = NWC24_OK; - *msgId = footer->nextMsgId; - footer->nextMsgId++; - } - + err = GetNewMsgId(header, msgId); if (err != NWC24_OK) { return err; } @@ -147,24 +139,9 @@ NWC24Err NWC24iMBoxOpenNewMsg(s32 mboxType, NWC24File* file, u32* msgId) { return err; } - id = *msgId; path = NWC24WorkP->pathWork; - - switch (mboxType) { - case 0: - Mail_sprintf(path, "@24:/mb/s%07d.msg", id); - break; - case 1: - Mail_sprintf(path, "@24:/mb/r%07d.msg", id); - break; - default: - err = NWC24_ERR_INVALID_VALUE; - goto check_mbox; - } - - err = NWC24_OK; - -check_mbox: + + err = GetMBoxFilePath(path, mboxType, *msgId); if (err != NWC24_OK) { return err; } @@ -216,9 +193,9 @@ NWC24Err NWC24iMBoxCloseMsg(NWC24File* file) { } NWC24Err NWC24iMBoxCancelMsg(NWC24File* file, s32 mboxType, u32 msgId) { - s32 result = (s32)msgId; + s32 result; char* pathWork; - unsigned int tempErr; + NWC24Err tempErr; NWC24Err deleteErr; NWC24Err closeErr; NWC24Err unmountErr; @@ -230,26 +207,9 @@ NWC24Err NWC24iMBoxCancelMsg(NWC24File* file, s32 mboxType, u32 msgId) { result = unmountErr; } else { pathWork = NWC24WorkP->pathWork; - switch (mboxType) { - case 0: - Mail_sprintf(pathWork, "@24:/mb/s%07d.msg", result); - break; - - case 1: - Mail_sprintf(pathWork, "@24:/mb/r%07d.msg", result); - break; - - default: - result = NWC24_ERR_INVALID_VALUE; - goto check_result; - } - - result = NWC24_OK; - - check_result: + deleteErr = GetMBoxFilePath(pathWork, mboxType, msgId); // TODO(Alex9303) Permuter fake(?)match - deleteErr = result; - if (deleteErr != NWC24_OK) { + if ((deleteErr) != NWC24_OK) { result = deleteErr; } else { deleteErr = NWC24FDeleteVF(pathWork); @@ -283,7 +243,6 @@ NWC24Err NWC24iMBoxAddMsgObj(s32 mboxType, NWC24MsgObj* msg) { NWC24Err closeErr; MBoxControlHeader* header; MBoxControlHeader* header2; - const char* mboxDir; char* pathWork; NWC24File file; @@ -297,26 +256,7 @@ NWC24Err NWC24iMBoxAddMsgObj(s32 mboxType, NWC24MsgObj* msg) { } pathWork = NWC24WorkP->pathWork; - - mboxDir = NWC24GetMBoxDir(); - - if (STD_strnlen(mboxDir, 0x40) + 14 > 0x100) { - err = NWC24_ERR_NOMEM; - } else { - switch (mboxType) { - case 0: - Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24send.ctl"); - break; - case 1: - Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24recv.ctl"); - break; - default: - err = NWC24_ERR_INVALID_VALUE; - goto check_result; - } - err = NWC24_OK; - } -check_result: + err = MakeMailPath(pathWork, mboxType); if (err != NWC24_OK) { return err; } @@ -349,8 +289,6 @@ NWC24Err NWC24iMBoxFlushHeader(s32 mboxType) { NWC24Err err; NWC24Err closeErr; MBoxControlHeader* header; - MBoxControlHeader* header2; - const char* mboxDir; char* pathWork; NWC24File file; @@ -360,25 +298,7 @@ NWC24Err NWC24iMBoxFlushHeader(s32 mboxType) { } pathWork = NWC24WorkP->pathWork; - mboxDir = NWC24GetMBoxDir(); - - if (STD_strnlen(mboxDir, 0x40) + 14 > 0x100) { - err = NWC24_ERR_NOMEM; - } else { - switch (mboxType) { - case 0: - err = Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24send.ctl"); - break; - case 1: - err = Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24recv.ctl"); - break; - default: - err = NWC24_ERR_INVALID_VALUE; - goto check_result; - } - err = NWC24_OK; - } -check_result: + err = MakeMailPath(pathWork, mboxType); if (err != NWC24_OK) { return err; } @@ -388,10 +308,7 @@ NWC24Err NWC24iMBoxFlushHeader(s32 mboxType) { return err; } - // TODO(Alex9303) Fakematch: (possibly) Missing inline function - header2 = header; - NWC24FSeek(&file, 0, 0); - err = NWC24FWrite(header2, 0x80, &file); + err = SaveMBCHeader(&file, header); closeErr = NWC24FClose(&file); if (err != NWC24_OK) { @@ -444,6 +361,55 @@ NWC24Err NWC24iMBoxCheck(s32 mboxType, u32 requiredSize) { return NWC24_OK; } +static NWC24Err GetMBoxFilePath(char* buffer, s32 mboxType, u32 msgId) { + const char* workDir; + NWC24Err err; + + switch (mboxType) { + case 0: + Mail_sprintf(buffer, "@24:/mb/s%07d.msg", msgId); + break; + case 1: + Mail_sprintf(buffer, "@24:/mb/r%07d.msg", msgId); + break; + default: + return NWC24_ERR_INVALID_VALUE; + } + return NWC24_OK; +} + +static NWC24Err MakeMailPath(char* buffer, s32 mboxType) { + const char* mboxDir = NWC24GetMBoxDir(); + s32 pathLen = STD_strnlen(mboxDir, 0x40); + + if (pathLen + 14 > 0x100) { + return NWC24_ERR_NOMEM; + } else { + switch (mboxType) { + case 0: + Mail_sprintf(buffer, "%s%s", mboxDir, "/wc24send.ctl"); + break; + case 1: + Mail_sprintf(buffer, "%s%s", mboxDir, "/wc24recv.ctl"); + break; + default: + return NWC24_ERR_INVALID_VALUE; + } + return NWC24_OK; + } +} + +static BOOL IsFileThere(const char* path) { + NWC24File file; + NWC24Err err; + + err = NWC24FOpen(&file, path, NWC24_SEEK_END); + if (err == NWC24_OK) { + return NWC24FClose(&file); + } + return err; +} + NWC24Err DeleteMsg(s32 mboxType, u32 msgId, u32 flags) { NWC24Err err; const char* mboxDir; @@ -456,7 +422,6 @@ NWC24Err DeleteMsg(s32 mboxType, u32 msgId, u32 flags) { char* pathWorkCopy; MBoxControlHeader* header2; int cmp; - MBoxControlEntry* entry2; u32 checkedCount = 0; u32 oldestMsgId = 0; MBoxControlEntry* entry; @@ -477,28 +442,8 @@ NWC24Err DeleteMsg(s32 mboxType, u32 msgId, u32 flags) { pathWorkCopy = NWC24WorkP->pathWork; pathWork = pathWorkCopy; - mboxDir = NWC24GetMBoxDir(); - - pathLen = STD_strnlen(mboxDir, 64); - - if (pathLen + 14 > 256) { - err = NWC24_ERR_NOMEM; - } else { - switch (mboxType) { - case 0: - Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24recv.ctl"); - break; - case 1: - Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24send.ctl"); - break; - default: - err = NWC24_ERR_INVALID_VALUE; - goto check_result1; - } - err = NWC24_OK; - } -check_result1: + err = MakeMailPath(pathWork, mboxType); if (err != NWC24_OK) { return err; } @@ -510,10 +455,10 @@ NWC24Err DeleteMsg(s32 mboxType, u32 msgId, u32 flags) { err = NWC24_ERR_NOT_FOUND; - for (offset = 0x80; offset < header->mailDataOffset; offset += 0x80) { + for (offset = sizeof(MBoxControlHeader); offset < header->mailDataOffset; offset += sizeof(MBoxControlHeader)) { NWC24Err readErr; NWC24FSeek(&file, offset, NWC24_SEEK_BEG); - readErr = NWC24FRead(entry, 0x80, &file); + readErr = NWC24FRead(entry, sizeof(MBoxControlHeader), &file); if (readErr != NWC24_OK) { err = readErr; break; @@ -552,22 +497,10 @@ NWC24Err DeleteMsg(s32 mboxType, u32 msgId, u32 flags) { } if (oldestMsgId != 0) { - if (oldestMsgId == entry->id) { - cmp = 0; - } else if (oldestMsgId > 900000 && entry->id < 100000) { - cmp = -1; - } else if (oldestMsgId < 100000 && entry->id > 900000) { - cmp = 1; - } else if (oldestMsgId > entry->id) { - cmp = 1; - } else { - cmp = -1; - } - if (cmp <= 0) { - continue; + if (CompareMsgId(oldestMsgId, entry->id) <= 0) { + continue; } } - oldestMsgId = entry->id; } @@ -578,7 +511,7 @@ NWC24Err DeleteMsg(s32 mboxType, u32 msgId, u32 flags) { // TODO(Alex9303) Fakematch: (possibly) Missing inline function header3 = header; NWC24FSeek(&file, 0, NWC24_SEEK_BEG); - NWC24FWrite(header3, 0x80, &file); + NWC24FWrite(header3, sizeof(MBoxControlHeader), &file); } } @@ -594,44 +527,13 @@ NWC24Err DeleteMsg(s32 mboxType, u32 msgId, u32 flags) { header->oldestMsgId = oldestMsgId; - // TODO(Alex9303) Fakematch: (possibly) Missing inline function - header2 = header; - - // TODO(Alex9303) Fakematch: (possibly) Missing inline function - entry2 = (MBoxControlEntry*)(((char*)NWC24WorkP) + 0x1200); - entry = entry2; - NWC24FSeek(&file, checkedCount, NWC24_SEEK_BEG); - NWC24FRead(entry, 0x80, &file); - - header2->msgCount--; - header2->totalMsgSize -= entry->length; - - memset(entry, 0, 0x80); - entry->appId = header2->nextFreeEntry; - header2->nextFreeEntry = checkedCount; - - NWC24FSeek(&file, checkedCount, NWC24_SEEK_BEG); - writeErr = NWC24FWrite(entry, 0x80, &file); + writeErr = ClearMBCEntry(header, checkedCount, &file); mountErr = MountVFMBox(mboxType); switch (mountErr) { case NWC24_OK: pathWork = NWC24WorkP->pathWork; - switch (mboxType) { - case 0: - Mail_sprintf(pathWork, "@24:/mb/r%07d.msg", msgId); - break; - case 1: - Mail_sprintf(pathWork, "/shared2/wc24/mbox/s%07d.msg", msgId); - - break; - default: - mountErr = NWC24_ERR_INVALID_VALUE; - goto check_result2; - } - mountErr = NWC24_OK; - - check_result2: + mountErr = GetMBoxFilePath(pathWork, mboxType, msgId); switch (mountErr) { case NWC24_OK: deleteErr = NWC24FDeleteVF(pathWork); @@ -654,7 +556,7 @@ NWC24Err DeleteMsg(s32 mboxType, u32 msgId, u32 flags) { header2 = header; NWC24FSeek(&file, 0, NWC24_SEEK_BEG); - mboxType = NWC24FWrite(header2, 0x80, &file); + mboxType = NWC24FWrite(header2, sizeof(MBoxControlHeader), &file); if (msgId != NWC24_OK) { mboxType = msgId; } @@ -692,7 +594,7 @@ NWC24Err DuplicationCheck(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC entry = (MBoxControlEntry*)((char*)NWC24WorkP + 0x1200); - for (offset = 0x80; offset < header->mailDataOffset; offset += 0x80) { + for (offset = sizeof(MBoxControlHeader); offset < header->mailDataOffset; offset += sizeof(MBoxControlHeader)) { int isDuplicate; int cmp; @@ -700,8 +602,8 @@ NWC24Err DuplicationCheck(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC break; } - err = NWC24FSeek(file, offset, NWC24_SEEK_BEG); - err = NWC24FRead(entry, 0x80, file); + NWC24FSeek(file, offset, NWC24_SEEK_BEG); + err = NWC24FRead(entry, sizeof(MBoxControlHeader), file); if (err != NWC24_OK) { break; } @@ -747,23 +649,10 @@ NWC24Err DuplicationCheck(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC } if (oldestMsgId != 0) { - if (oldestMsgId == entry->id) { - cmp = 0; - } else if (oldestMsgId > 900000 && entry->id < 100000) { - cmp = -1; - } else if (oldestMsgId < 100000 && entry->id > 900000) { - cmp = 1; - } else if (oldestMsgId > entry->id) { - cmp = 1; - } else { - cmp = -1; - } - - if (cmp <= 0) { - continue; + if (CompareMsgId(oldestMsgId, entry->id) <= 0) { + continue; } } - oldestMsgId = entry->id; } @@ -781,40 +670,24 @@ NWC24Err DuplicationCheck(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC pathWork = NWC24WorkP->WORK_0x1200; err = NWC24FSeek(file, bestOffset, NWC24_SEEK_BEG); - err = NWC24FRead(*pathWorkPtr, 0x80, file); + err = NWC24FRead(*pathWorkPtr, sizeof(MBoxControlHeader), file); header->msgCount--; header->totalMsgSize -= entry->length; - memset(entry, 0, 0x80); + memset(entry, 0, sizeof(MBoxControlHeader)); entry->appId = header->nextFreeEntry; header->nextFreeEntry = bestOffset; err = NWC24FSeek(file, bestOffset, NWC24_SEEK_BEG); - writeErr = NWC24FWrite(entry, 0x80, file); + writeErr = NWC24FWrite(entry, sizeof(MBoxControlHeader), file); err = MountVFMBox(mboxType); if (err != NWC24_OK) { result = err; } else { pathWork = NWC24WorkP->pathWork; - - switch (mboxType) { - case 0: - Mail_sprintf(pathWork, "/wc24recv.mbx", bestMsgId); - break; - - case 1: - Mail_sprintf(pathWork, "/wc24send.mbx", bestMsgId); - break; - - default: - err = NWC24_ERR_INVALID_VALUE; - goto check_result; - } - - err = NWC24_OK; - check_result: + err = GetMBoxFilePath(pathWork, mboxType, bestMsgId); if (err != NWC24_OK) { result = err; } else { @@ -841,7 +714,6 @@ NWC24Err GetCachedMBCHeader(s32 mboxType, MBoxControlHeader** headerOut) { NWC24Err err; const char* mboxDir; NWC24File file; - MBoxControlHeader* header; NWC24Err result = NWC24_OK; char* pathWork; @@ -856,25 +728,7 @@ NWC24Err GetCachedMBCHeader(s32 mboxType, MBoxControlHeader** headerOut) { if ((*headerOut)->magic != 0x57635466) { pathWork = NWC24WorkP->pathWork; - mboxDir = NWC24GetMBoxDir(); - - if (STD_strnlen(mboxDir, 0x40) + 14 > 0x100) { - err = NWC24_ERR_NOMEM; - } else { - switch (mboxType) { - case 0: - Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24send.ctl"); - break; - case 1: - Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24recv.ctl"); - break; - default: - err = NWC24_ERR_INVALID_VALUE; - goto check_result; - } - err = NWC24_OK; - } - check_result: + err = MakeMailPath(pathWork, mboxType); if (err != NWC24_OK) { return err; } @@ -884,18 +738,7 @@ NWC24Err GetCachedMBCHeader(s32 mboxType, MBoxControlHeader** headerOut) { return err; } - header = *headerOut; - NWC24FSeek(&file, 0, 0); - err = NWC24FRead(header, 0x80, &file); - if (err != NWC24_OK) { - result = err; - - } else { - result = NWC24_OK; - if ((header)->magic != 0x57635466) { - result = NWC24_ERR_BROKEN; - } - } + result = LoadMBCHeader(&file, *headerOut); err = NWC24FClose(&file); if (result == NWC24_OK) { if (err != NWC24_OK) { @@ -910,6 +753,27 @@ NWC24Err GetCachedMBCHeader(s32 mboxType, MBoxControlHeader** headerOut) { return result; } +static NWC24Err LoadMBCHeader(NWC24File* file, MBoxControlHeader* header) { + NWC24Err err; + + NWC24FSeek(file, 0, NWC24_SEEK_BEG); + err = NWC24FRead(header, sizeof(MBoxControlHeader), file); + if (err != NWC24_OK) { + return err; + } + + if (header->magic != 0x57635466) { + return NWC24_ERR_BROKEN; + } + + return NWC24_OK; +} + +static NWC24Err SaveMBCHeader(NWC24File* file, MBoxControlHeader* header) { + NWC24FSeek(file, 0, NWC24_SEEK_BEG); + return NWC24FWrite(header, sizeof(MBoxControlHeader), file); +} + NWC24Err AddMBCEntry(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC24File* file) { s32 entryOffset = header->nextFreeEntry; MBoxControlEntry* entryBuffer; @@ -922,7 +786,7 @@ NWC24Err AddMBCEntry(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC24Fil return NWC24_ERR_FULL; } - if ((u32)entryOffset >= header->mailDataOffset || ((entryOffset - 0x80) & 0x7F) != 0) { + if ((u32)entryOffset >= header->mailDataOffset || ((entryOffset - sizeof(MBoxControlHeader)) & 0x7F) != 0) { return NWC24_ERR_BROKEN; } @@ -935,7 +799,7 @@ NWC24Err AddMBCEntry(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC24Fil nextEntryOffset = entryBuffer->appId; - if ((u32)nextEntryOffset >= header->mailDataOffset || ((nextEntryOffset - 0x80) & 0x7F) != 0) { + if ((u32)nextEntryOffset >= header->mailDataOffset || ((nextEntryOffset - sizeof(MBoxControlHeader)) & 0x7F) != 0) { return NWC24_ERR_BROKEN; } @@ -958,6 +822,53 @@ NWC24Err AddMBCEntry(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC24Fil return NWC24_OK; } +static NWC24Err ClearMBCEntry(MBoxControlHeader* header, u32 offset, NWC24File* file) { + MBoxControlEntry* entryBuffer; + + entryBuffer = (MBoxControlEntry*)NWC24WorkP->WORK_0x1200; + NWC24FSeek(file, offset, NWC24_SEEK_BEG); + NWC24FRead(entryBuffer, sizeof(MBoxControlEntry), file); + + header->msgCount--; + header->totalMsgSize -= entryBuffer->length; + + memset(entryBuffer, 0, sizeof(MBoxControlEntry)); + entryBuffer->appId = header->nextFreeEntry; + header->nextFreeEntry = offset; + + NWC24FSeek(file, offset, NWC24_SEEK_BEG); + return NWC24FWrite(entryBuffer, sizeof(MBoxControlEntry), file); +} + +NWC24Err GetNewMsgId(MBoxControlHeader* header, u32* msgIdOut) { + if (header->magic != 0x57635466) { + return NWC24_ERR_INVALID_VALUE; + } + + if (header->nextMsgId > 1000000) { + header->nextMsgId = 1; + } + + *msgIdOut = header->nextMsgId; + header->nextMsgId++; + + return NWC24_OK; +} + +static s32 CompareMsgId(u32 id1, u32 id2) { + if (id1 == id2) { + return 0; + } else if (id1 > 900000 && id2 < 100000) { + return -1; + } else if (id1 < 100000 && id2 > 900000) { + return 1; + } else if (id1 > id2) { + return 1; + } else { + return -1; + } +} + NWC24Err MountVFMBox(s32 mboxType) { s32 result; NWC24Err err; @@ -975,28 +886,7 @@ NWC24Err MountVFMBox(s32 mboxType) { } pathWork = NWC24WorkP->pathWork; - mboxDir = NWC24GetMBoxDir(); - if (STD_strnlen(mboxDir, 0x40) + 14 > 0x100) { - result = NWC24_ERR_NOMEM; - } else { - switch (mboxType) { - case 0: - Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24recv.mbx"); - break; - - case 1: - Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24send.mbx"); - break; - - default: - result = NWC24_ERR_INVALID_VALUE; - goto check_result; - } - - result = NWC24_OK; - } - -check_result: + result = MakeMailPath(pathWork, mboxType); if (result != NWC24_OK) { return result; } diff --git a/src/revolution/NWC24/NWC24StdApi.c b/src/revolution/NWC24/NWC24StdApi.c index b5ace858..ba5a1022 100644 --- a/src/revolution/NWC24/NWC24StdApi.c +++ b/src/revolution/NWC24/NWC24StdApi.c @@ -1,5 +1,19 @@ #include +char* Mail_strcpy(char* dst, const char* src); +size_t Mail_strlen(const char* str); +size_t STD_strnlen(const char* str, size_t n); +void* Mail_memcpy(void* dst, const void* src, size_t n); +void* Mail_memset(void* dst, int ch, size_t n); +char* Mail_strcat(char* dst, const char* src); +char* Mail_strncat(char* dst, const char* src, size_t n); +static int Mail_toupper(int c); +static void set_to_head(char *str, char c); +static void set_to_tail(char *str, char c); +int convNum(char *dst, int number, int numberBase, char charBase, int signedFlag, int width, char specifierChar, char justifyChar); +int Mail_sprintf(char *buffer, char *format, ...); +int Mail_vsprintf(char *str, char *format, va_list arg); + char* Mail_strcpy(char* dst, const char* src) { char* backup = dst; @@ -29,7 +43,6 @@ size_t STD_strnlen(const char* str, size_t n) { if (str[len] == '\0') { break; } - len++; } @@ -48,7 +61,6 @@ void* Mail_memcpy(void* dst, const void* src, size_t n) { void* Mail_memset(void* dst, int ch, size_t n) { size_t i; - for (i = 0; i < n; i++) { ((u8*)dst)[i] = ch; } @@ -73,6 +85,10 @@ char* Mail_strncat(char* dst, const char* src, size_t n) { return dst; } +static int Mail_toupper(int c) { + return c & 0xDF; +} + // Not really sure how get non-inlined Mail_strlen() to inline naturally. inline static int Mail_strlen_inline(const char *str) { int len = 0; @@ -82,7 +98,7 @@ inline static int Mail_strlen_inline(const char *str) { return len; } -inline static void set_to_head(char *str, char c) { +static void set_to_head(char *str, char c) { // TODO(Alex9303) Figure out how to get Mail_strlen to inline naturally here. int len = Mail_strlen_inline(str); int i; @@ -92,7 +108,7 @@ inline static void set_to_head(char *str, char c) { *str = c; } -inline static void set_to_tail(char *str, char c) { +static void set_to_tail(char *str, char c) { int len; len = Mail_strlen(str); str[len++] = c; @@ -160,8 +176,7 @@ int convNum(char *dst, int number, int numberBase, char charBase, int signedFlag return charsWritten; } -int Mail_sprintf(char *buffer, const char *format, ...) -{ +int Mail_sprintf(char *buffer, char *format, ...) { va_list args; int ret; @@ -223,7 +238,7 @@ int Mail_vsprintf(char *str, char *format, va_list arg) { } } - longFlag = formatChar & 0xDF; + longFlag = Mail_toupper(formatChar); if (longFlag == 'L') { formatChar = *format++; } From 1150c32099e36fc51afb22b652a0ce1497cdbe80 Mon Sep 17 00:00:00 2001 From: Alex9303 Date: Fri, 20 Feb 2026 16:18:29 -0500 Subject: [PATCH 4/4] Clean up MsgCommit --- src/revolution/NWC24/NWC24MBoxCtrl.c | 8 +- src/revolution/NWC24/NWC24Mime.c | 14 +- src/revolution/NWC24/NWC24MsgCommit.c | 594 ++++++++++++++------------ src/revolution/NWC24/NWC24StdApi.c | 4 +- 4 files changed, 322 insertions(+), 298 deletions(-) diff --git a/src/revolution/NWC24/NWC24MBoxCtrl.c b/src/revolution/NWC24/NWC24MBoxCtrl.c index ecac7e23..7790acc6 100644 --- a/src/revolution/NWC24/NWC24MBoxCtrl.c +++ b/src/revolution/NWC24/NWC24MBoxCtrl.c @@ -140,7 +140,7 @@ NWC24Err NWC24iMBoxOpenNewMsg(s32 mboxType, NWC24File *file, u32 *msgId) { } path = NWC24WorkP->pathWork; - + err = GetMBoxFilePath(path, mboxType, *msgId); if (err != NWC24_OK) { return err; @@ -498,7 +498,7 @@ NWC24Err DeleteMsg(s32 mboxType, u32 msgId, u32 flags) { if (oldestMsgId != 0) { if (CompareMsgId(oldestMsgId, entry->id) <= 0) { - continue; + continue; } } oldestMsgId = entry->id; @@ -650,7 +650,7 @@ NWC24Err DuplicationCheck(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC if (oldestMsgId != 0) { if (CompareMsgId(oldestMsgId, entry->id) <= 0) { - continue; + continue; } } oldestMsgId = entry->id; @@ -851,7 +851,7 @@ NWC24Err GetNewMsgId(MBoxControlHeader* header, u32* msgIdOut) { *msgIdOut = header->nextMsgId; header->nextMsgId++; - + return NWC24_OK; } diff --git a/src/revolution/NWC24/NWC24Mime.c b/src/revolution/NWC24/NWC24Mime.c index 2ee48857..36bc8c6a 100644 --- a/src/revolution/NWC24/NWC24Mime.c +++ b/src/revolution/NWC24/NWC24Mime.c @@ -15,30 +15,30 @@ NWC24Err Base64Encode(char *inputBuffer, s32 inputLength, u32 *inBytesConsumed, result = NWC24_ERR_OVERFLOW; break; } - + hasThird = FALSE; hasSecond = FALSE; - + combined = ((unsigned char)inputBuffer[inputIndex]); combined <<= 8; - + if ((inputIndex + 1) < inputLength) { hasSecond = TRUE; combined |= ((unsigned char)inputBuffer[inputIndex + 1]); } - + combined <<= 8; - + if ((inputIndex + 2) < inputLength) { hasThird = TRUE; combined |= ((unsigned char)inputBuffer[inputIndex + 2]); } - + outBuffer[outputIndex + 0] = MIMEEncStr[(combined >> 18) & 0x3F]; outBuffer[outputIndex + 1] = MIMEEncStr[(combined >> 12) & 0x3F]; outBuffer[outputIndex + 2] = MIMEEncStr[(hasSecond) ? ((combined >> 6) & 0x3F) : (0x40)]; outBuffer[outputIndex + 3] = MIMEEncStr[(hasThird) ? (combined & 0x3F) : (0x40)]; - + outputIndex += 4; } diff --git a/src/revolution/NWC24/NWC24MsgCommit.c b/src/revolution/NWC24/NWC24MsgCommit.c index 7408f33e..96b2bc4d 100644 --- a/src/revolution/NWC24/NWC24MsgCommit.c +++ b/src/revolution/NWC24/NWC24MsgCommit.c @@ -13,160 +13,61 @@ extern const char* ContentDispA; extern const char* ContentTypeTP; extern const char* ContentTxEncT; +// STD API +u32 STD_strnlen(const char* str, u32 maxLen); int Mail_sprintf(char *buffer, const char *format, ...); +// Other NWC24 functions from other files +void NWC24Data_Init(NWC24Data* data); +NWC24Err NWC24FClose(NWC24File* file); +NWC24Err NWC24FWrite(const void* src, s32 size, NWC24File* file); +NWC24Err NWC24GetMyUserId(u64* idOut); +NWC24Err NWC24iMBoxCloseMsg(NWC24File* file); +NWC24Err NWC24iMBoxAddMsgObj(s32 mboxType, NWC24MsgObj* msg); +NWC24Err NWC24iMBoxCancelMsg(NWC24File* file, s32 mboxType, u32 msgId); +NWC24Err NWC24iMBoxOpenNewMsg(s32 mboxType, NWC24File* file, u32* msgId); +NWC24Err NWC24iMBoxFlushHeader(s32 mboxType); +NWC24Err NWC24iSetNewMsgArrived(u32 flags); +const char* NWC24GetAccountDomain(void); + +// Functions not present in RevoYawarakaD.MAP +static NWC24Err WriteXWiiAltField(NWC24MsgObj* msg); +static NWC24Err WriteTextBody(NWC24MsgObj* msg); +static NWC24Err WriteMIMEPartBoundaryEnd(NWC24MsgObj* msg); + +NWC24Err NWC24CommitMsg(NWC24MsgObj *msg); NWC24Err NWC24CommitMsgInternal(NWC24MsgObj* msg, s32 flagLocal); -NWC24Err WriteBase64Data(const void* data, u32 size, u32* bytesWritten); -NWC24Err WriteQPData(const void* data, u32 size, u32* bytesWritten); +NWC24Err CheckMsgObject(const NWC24MsgObj* msg); NWC24Err CheckMsgBoxSpace(NWC24MsgObj* msg, u32 requiredSize); +NWC24Err SynthesizeAddrStr(NWC24AddrId* addrId, u32 flags, char* outBuffer, int bufferSize, u32* outLength); NWC24Err WriteSMTP_MAILFROM(NWC24MsgObj* msg); NWC24Err WriteSMTP_RCPTTO(NWC24MsgObj* msg); +static NWC24Err WriteSMTP_DATA(NWC24MsgObj* msg); NWC24Err WriteFromField(NWC24MsgObj* msg); NWC24Err WriteToField(NWC24MsgObj* msg); +static NWC24Err WriteSubjectField(NWC24MsgObj* msg); NWC24Err WriteDateField(NWC24MsgObj* msg); +static NWC24Err WriteMessageIdField(NWC24MsgObj* msg); NWC24Err WriteXWiiAppIdField(NWC24MsgObj* msg); +static NWC24Err WriteXWiiTagField(NWC24MsgObj* msg); +static NWC24Err WriteXWiiCmdField(NWC24MsgObj* msg); NWC24Err WriteXWiiFaceField(NWC24MsgObj* msg); NWC24Err WriteXWiiAltNameField(NWC24MsgObj* msg); +static NWC24Err WriteXWiiMBNoReplyField(NWC24MsgObj* msg); +static NWC24Err WriteXWiiMBRegDateField(NWC24MsgObj* msg); +static NWC24Err WriteXWiiMBDelayField(NWC24MsgObj* msg); +static NWC24Err WriteMIMETopHeader(NWC24MsgObj* msg); +static NWC24Err WriteMIMEPartBoundary(NWC24MsgObj* msg); NWC24Err WriteMIMEAttachHeader(NWC24MsgObj* msg, u32 attachIndex); NWC24Err WriteContentTypeField(NWC24MsgObj* msg); +static NWC24Err WriteUserField(NWC24MsgObj* msg); NWC24Err WritePlainText(NWC24MsgObj* msg); -NWC24Err CheckMsgObject(const NWC24MsgObj* msg); - -NWC24Err NWC24FClose(NWC24File* file); -NWC24Err NWC24FWrite(const void* src, s32 size, NWC24File* file); -NWC24Err NWC24GetMyUserId(u64* idOut); -NWC24Err NWC24iMBoxAddMsgObj(s32 mboxType, NWC24MsgObj* msg); -NWC24Err NWC24iMBoxCancelMsg(NWC24File* file, s32 mboxType, u32 msgId); -NWC24Err NWC24iMBoxCloseMsg(NWC24File* file); -NWC24Err NWC24iMBoxFlushHeader(s32 mboxType); -NWC24Err NWC24iMBoxOpenNewMsg(s32 mboxType, NWC24File* file, u32* msgId); -NWC24Err NWC24iSetNewMsgArrived(u32 flags); -const char* NWC24GetAccountDomain(void); -u32 STD_strnlen(const char* str, u32 maxLen); -void NWC24Data_Init(NWC24Data* data); - -NWC24Err NWC24CommitMsg(NWC24MsgObj *msg) { - s32 flagLocal; - u32 flags; - u64 myUserId; - u64 targetUserId; - - flagLocal = 0; - - if (NWC24IsMsgLibOpened() == 0 && NWC24IsMsgLibOpenedByTool() == 0) { - return -9; - } - - flags = msg->flags; - - if ((flags & 0x100) == 0 || (flags & 0x200) != 0) { - return -7; - } - - if (LoopBackEnable != 0 && (flags & 0x1) != 0) { - NWC24GetMyUserId(&myUserId); - if (msg->numTo == 1) { - targetUserId = msg->toIds[0]; - if ((targetUserId ^ myUserId) == 0) { - flagLocal = 1; - } - } - } - - return NWC24CommitMsgInternal(msg, flagLocal); -} - -static inline NWC24Err WriteDataCommand(NWC24MsgObj* msg) { - NWC24Err result; - char* stringWork = NWC24WorkP->stringWork; - Mail_strcpy(stringWork, "DATA\r\n"); - result = NWC24FWrite(stringWork, Mail_strlen(stringWork), m_pFile); - if (result == NWC24_OK) { - msg->length += 6; - } - return result; -} - -static inline NWC24Err WriteMessageIdField(NWC24MsgObj* msg) { - u64 myUserId; - char stackBuffer[32]; - NWC24Err result; - u32 writeSize; - char* stringWork = NWC24WorkP->stringWork; - const char* domain = NWC24GetAccountDomain(); - NWC24GetMyUserId(&myUserId); - Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); - Mail_strcpy(stringWork, "Message-ID: <"); - Mail_memset(stackBuffer, 0, 32); - Mail_sprintf(stackBuffer, "%08x%08x%08x%08x", msg->id, (u32)(myUserId >> 32), (u32)myUserId, msg->createTime); - Mail_strcat(stringWork, stackBuffer); - Mail_strcat(stringWork, domain); - Mail_strcat(stringWork, ">\r\n"); - writeSize = Mail_strlen(stringWork); - result = NWC24FWrite(stringWork, writeSize, m_pFile); - if (result == NWC24_OK) { - msg->length += writeSize; - } - return result; -} - -static inline NWC24Err WriteSubjectField(NWC24MsgObj* msg) { - char* stringWork = NWC24WorkP->stringWork; - NWC24Err result; - u32 writeSize; - if (msg->subject.size == 0) { - result = NWC24_ERR_NULL; - } else { - Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); - Mail_strcpy(stringWork, "Subject: "); - Mail_strncat(stringWork, (const char*)msg->subject.ptr, 1021); - Mail_strncat(stringWork, "\r\n", NWC24_WORK_BUFFER_SIZE); - writeSize = STD_strnlen(stringWork, NWC24_WORK_BUFFER_SIZE); - result = NWC24FWrite(stringWork, writeSize, m_pFile); - if (result == NWC24_OK) { - msg->length += writeSize; - } - } - return result; -} - -static inline NWC24Err WriteXWiiLedField(NWC24MsgObj* msg) { - NWC24Err result; - u32 writeSize; - if (msg->ledPattern == 0) { - return NWC24_OK; - } else { - char* stringWork = NWC24WorkP->stringWork; - Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); - Mail_sprintf(stringWork, "X-Wii-Led: %08x\r\n", msg->ledPattern); - writeSize = Mail_strlen(stringWork); - result = NWC24FWrite(stringWork, writeSize, m_pFile); - if (result == NWC24_OK) { - msg->length += writeSize; - } - } - return result; -} - -static inline NWC24Err WriteXWiiTagField(NWC24MsgObj* msg) { - NWC24Err result; - u32 writeSize; - if (msg->tag == 0) { - return NWC24_OK; - } else { - char* stringWork = NWC24WorkP->stringWork; - Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); - Mail_sprintf(stringWork, "X-Wii-Tag: %08x\r\n", msg->tag); - writeSize = Mail_strlen(stringWork); - result = NWC24FWrite(stringWork, writeSize, m_pFile); - if (result == NWC24_OK) { - msg->length += writeSize; - } - } - return result; -} +static NWC24Err WriteAttachData(NWC24MsgObj* msg, s32 i); +NWC24Err WriteBase64Data(const void* data, u32 size, u32* bytesWritten); +NWC24Err WriteQPData(const void* data, u32 size, u32* bytesWritten); -static inline NWC24Err WriteXWiiAltField(NWC24MsgObj* msg) { +static NWC24Err WriteXWiiAltField(NWC24MsgObj* msg) { + // TODO(Alex9303) Function missing from RevoYawarakaD.MAP. Keeping so NWC24CommitMsgInternal can be somewhat readable. NWC24Err result; u32 writeSize; if (!(msg->flags & 0x2000)) { @@ -184,99 +85,24 @@ static inline NWC24Err WriteXWiiAltField(NWC24MsgObj* msg) { return result; } -static inline NWC24Err WriteXWiiMBParameterField(NWC24MsgObj* msg) { +static NWC24Err WriteTextBody(NWC24MsgObj* msg) { + // TODO(Alex9303) Function missing from RevoYawarakaD.MAP. Keeping so NWC24CommitMsgInternal can be somewhat readable. NWC24Err result; - if (!(msg->mb.raw & 0x80000000)) { - return NWC24_OK; - } else { - char* stringWork = NWC24WorkP->stringWork; - Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); - Mail_strcpy(stringWork, "X-Wii-MB-Parameter:\r\n"); - result = NWC24FWrite(stringWork, 21, m_pFile); - if (result == NWC24_OK) { - msg->length += 21; - } - } - return result; -} - -static inline NWC24Err WriteXWiiMBRegDateField(NWC24MsgObj* msg) { - u32 writeSize; - NWC24Err result; - u32 regdate = msg->mb.regdate; - if (regdate == 0) { - return NWC24_OK; - } else { - char* stringWork = NWC24WorkP->stringWork; - Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); - Mail_sprintf(stringWork, "X-Wii-MB-RegDate: %04x\r\n", regdate); - writeSize = STD_strnlen(stringWork, NWC24_WORK_BUFFER_SIZE); - result = NWC24FWrite(stringWork, writeSize, m_pFile); - if (result == NWC24_OK) { - msg->length += writeSize; - } - } - return result; -} - -static inline NWC24Err WriteXWiiMBDelayField(NWC24MsgObj* msg) { - NWC24Err result; - u32 writeSize; - u32 delay = msg->mb.raw & 0x00FF0000; - if (delay == 0) { - return NWC24_OK; - } else { - char* stringWork = NWC24WorkP->stringWork; - Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); - Mail_sprintf(stringWork, "X-Wii-MB-Delay: %02x\r\n", delay >> 16); - writeSize = STD_strnlen(stringWork, NWC24_WORK_BUFFER_SIZE); - result = NWC24FWrite(stringWork, writeSize, m_pFile); - if (result == NWC24_OK) { - msg->length += writeSize; - } - } - return result; -} - -static inline NWC24Err WriteCustomHeader(NWC24MsgObj* msg) { - NWC24Err result; - if (msg->DATA_0xD0.size == 0) { + result = WritePlainText(msg); + if (result == NWC24_ERR_NULL) { return NWC24_OK; - } else { - result = NWC24FWrite(msg->DATA_0xD0.ptr, msg->DATA_0xD0.size, m_pFile); - if (result == NWC24_OK) { - msg->length += msg->DATA_0xD0.size; - } } return result; } -static inline NWC24Err WriteMimeHeader(NWC24MsgObj* msg) { - char* stringWork = NWC24WorkP->stringWork; - NWC24Err result; - u32 writeSize; - Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); - Mail_strcpy(stringWork, "MIME-Version: 1.0\r\n"); - if (msg->flags & 0x10000) { - Mail_strcat(stringWork, "Content-Type: multipart/mixed; boundary=\""); - Mail_strcat(stringWork, MultiPartDivider); - Mail_strcat(stringWork, "\"\r\n"); - } - writeSize = Mail_strlen(stringWork); - result = NWC24FWrite(stringWork, writeSize, m_pFile); - if (result == NWC24_OK) { - msg->length += writeSize; - } - return result; -} - -static inline NWC24Err WriteMimeBoundary(NWC24MsgObj* msg) { +static NWC24Err WriteMIMEPartBoundaryEnd(NWC24MsgObj* msg) { + // TODO(Alex9303) Function missing from RevoYawarakaD.MAP. Keeping so NWC24CommitMsgInternal can be somewhat readable. char* stringWork = NWC24WorkP->stringWork; NWC24Err result; u32 writeSize; Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); Mail_sprintf(stringWork, "\r\n--%s", MultiPartDivider); - Mail_strcat(stringWork, "\r\n"); + Mail_strcat(stringWork, "--\r\n"); writeSize = Mail_strlen(stringWork); result = NWC24FWrite(stringWork, writeSize, m_pFile); if (result == NWC24_OK) { @@ -285,38 +111,35 @@ static inline NWC24Err WriteMimeBoundary(NWC24MsgObj* msg) { return result; } -static inline NWC24Err WritePlainTextWrapper(NWC24MsgObj* msg) { - NWC24Err result; - result = WritePlainText(msg); - if (result == NWC24_ERR_NULL) { - return NWC24_OK; +NWC24Err NWC24CommitMsg(NWC24MsgObj *msg) { + s32 flagLocal; + u32 flags; + u64 myUserId; + u64 targetUserId; + + flagLocal = 0; + + if (NWC24IsMsgLibOpened() == 0 && NWC24IsMsgLibOpenedByTool() == 0) { + return NWC24_ERR_LIB_NOT_OPENED; } - return result; -} -static inline NWC24Err WriteAttachedBase64(NWC24MsgObj* msg, s32 i) { - NWC24Err result; - u32 writeSize; - result = WriteBase64Data(msg->attached[i].ptr, msg->attached[i].size, &writeSize); - if (result == NWC24_OK) { - msg->length += writeSize; + flags = msg->flags; + + if ((flags & 0x100) == 0 || (flags & 0x200) != 0) { + return NWC24_ERR_PROTECTED; } - return result; -} -static inline NWC24Err WriteMimeBoundaryEnd(NWC24MsgObj* msg) { - char* stringWork = NWC24WorkP->stringWork; - NWC24Err result; - u32 writeSize; - Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); - Mail_sprintf(stringWork, "\r\n--%s", MultiPartDivider); - Mail_strcat(stringWork, "--\r\n"); - writeSize = Mail_strlen(stringWork); - result = NWC24FWrite(stringWork, writeSize, m_pFile); - if (result == NWC24_OK) { - msg->length += writeSize; + if (LoopBackEnable != 0 && (flags & 0x1) != 0) { + NWC24GetMyUserId(&myUserId); + if (msg->numTo == 1) { + targetUserId = msg->toIds[0]; + if ((targetUserId ^ myUserId) == 0) { + flagLocal = 1; + } + } } - return result; + + return NWC24CommitMsgInternal(msg, flagLocal); } NWC24Err NWC24CommitMsgInternal(NWC24MsgObj* msg, s32 mboxType) { @@ -355,6 +178,7 @@ NWC24Err NWC24CommitMsgInternal(NWC24MsgObj* msg, s32 mboxType) { m_pFile = &file; if (mboxType == 0) { + // Regswap happens inside of this code block. result = WriteSMTP_MAILFROM(msg); if (result != NWC24_OK) { NWC24FClose(&file); @@ -367,7 +191,7 @@ NWC24Err NWC24CommitMsgInternal(NWC24MsgObj* msg, s32 mboxType) { err = result; goto error_break; } - result = WriteDataCommand(msg); + result = WriteSMTP_DATA(msg); if (result != NWC24_OK) { NWC24FClose(&file); err = result; @@ -423,7 +247,7 @@ NWC24Err NWC24CommitMsgInternal(NWC24MsgObj* msg, s32 mboxType) { goto error_break; } - result = WriteXWiiLedField(msg); + result = WriteXWiiCmdField(msg); if (result != NWC24_OK) { NWC24FClose(&file); err = result; @@ -459,7 +283,7 @@ NWC24Err NWC24CommitMsgInternal(NWC24MsgObj* msg, s32 mboxType) { } if (msg->mb.raw != 0) { - result = WriteXWiiMBParameterField(msg); + result = WriteXWiiMBNoReplyField(msg); if (result != NWC24_OK) { NWC24FClose(&file); err = result; @@ -482,7 +306,7 @@ NWC24Err NWC24CommitMsgInternal(NWC24MsgObj* msg, s32 mboxType) { } } - result = WriteCustomHeader(msg); + result = WriteUserField(msg); if (result != NWC24_OK) { NWC24FClose(&file); err = result; @@ -490,10 +314,9 @@ NWC24Err NWC24CommitMsgInternal(NWC24MsgObj* msg, s32 mboxType) { } Mail_memset(MultiPartDivider, 0, 40); - // TODO(Alex9303) Replace string with correct string Mail_sprintf(MultiPartDivider, "----_%08x%08x__________", msg->createTime, msg->id); - result = WriteMimeHeader(msg); + result = WriteMIMETopHeader(msg); if (result != NWC24_OK) { NWC24FClose(&file); err = result; @@ -502,7 +325,7 @@ NWC24Err NWC24CommitMsgInternal(NWC24MsgObj* msg, s32 mboxType) { if (msg->flags & 0x10000ULL) { msg->UNK_0x10 = msg->length; - result = WriteMimeBoundary(msg); + result = WriteMIMEPartBoundary(msg); if (result != NWC24_OK) { NWC24FClose(&file); err = result; @@ -520,7 +343,7 @@ NWC24Err NWC24CommitMsgInternal(NWC24MsgObj* msg, s32 mboxType) { msg->UNK_0x10 = msg->length; } data2.ptr = (void*)msg->length; - result = WritePlainTextWrapper(msg); + result = WriteTextBody(msg); if (result != NWC24_OK) { NWC24FClose(&file); err = result; @@ -529,7 +352,7 @@ NWC24Err NWC24CommitMsgInternal(NWC24MsgObj* msg, s32 mboxType) { data2.size = msg->length - ((u32)data2.ptr); for (i = 0; i < ((u32)msg->numAttached); i++) { - result = WriteMimeBoundary(msg); + result = WriteMIMEPartBoundary(msg); if (result != NWC24_OK) { NWC24FClose(&file); err = result; @@ -544,7 +367,7 @@ NWC24Err NWC24CommitMsgInternal(NWC24MsgObj* msg, s32 mboxType) { } attachedData[i].ptr = (void*)msg->length; - result = WriteAttachedBase64(msg, i); + result = WriteAttachData(msg, i); if (result != NWC24_OK) { NWC24FClose(&file); err = result; @@ -554,7 +377,7 @@ NWC24Err NWC24CommitMsgInternal(NWC24MsgObj* msg, s32 mboxType) { attachedData[i].size = msg->length - ((u32)attachedData[i].ptr); if (i == (msg->numAttached - 1)) { - result = WriteMimeBoundaryEnd(msg); + result = WriteMIMEPartBoundaryEnd(msg); if (result != NWC24_OK) { NWC24FClose(&file); err = result; @@ -674,7 +497,7 @@ NWC24Err CheckMsgBoxSpace(NWC24MsgObj* msg, u32 requiredSize) { totalSize += textSize; if (totalSize >= 0x31c00) { - return -8; + return NWC24_ERR_OVERFLOW; } err = NWC24iMBoxCheck(requiredSize, totalSize + NWC24_WORK_BUFFER_SIZE); @@ -687,57 +510,57 @@ NWC24Err CheckMsgBoxSpace(NWC24MsgObj* msg, u32 requiredSize) { return result; } -NWC24Err SynthesizeAddrStr(NWC24AddrId* id_pair, u32 flags, char* out_buffer, int buffer_size, u32* out_length) { - s32 domain_len; - char id_str[20]; - NWC24Err result = 0; - const char* domain; +NWC24Err SynthesizeAddrStr(NWC24AddrId* addrId, u32 flags, char* outBuffer, int bufferSize, u32* outLength) { + s32 domainLength; + char addrIdString[20]; + NWC24Err err = NWC24_OK; + const char* accountDomain; if ((flags & 1) != 0) { - domain = NWC24GetAccountDomain(); - domain_len = Mail_strlen(domain); + accountDomain = NWC24GetAccountDomain(); + domainLength = Mail_strlen(accountDomain); - if (domain_len <= 0) { - result = NWC24_ERR_CONFIG; + if (domainLength <= 0) { + err = NWC24_ERR_CONFIG; goto cleanup; } - if ((domain_len + 0x12) >= buffer_size) { - result = NWC24_ERR_NOMEM; + if ((domainLength + 0x12) >= bufferSize) { + err = NWC24_ERR_NOMEM; goto cleanup; } - NWC24iConvIdToStr(id_pair->id, id_str); - domain_len = Mail_sprintf(out_buffer, "%c%s%s", 0x77, id_str, domain); + NWC24iConvIdToStr(addrId->id, addrIdString); + domainLength = Mail_sprintf(outBuffer, "%c%s%s", 0x77, addrIdString, accountDomain); - if (domain_len == 0) { - result = NWC24_ERR_FATAL; + if (domainLength == 0) { + err = NWC24_ERR_FATAL; goto cleanup; } - *out_length = domain_len; + *outLength = domainLength; } else if ((flags & 2) != 0) { - if ((id_pair->data.size + 3) >= buffer_size) { - result = NWC24_ERR_NOMEM; + if ((addrId->data.size + 3) >= bufferSize) { + err = NWC24_ERR_NOMEM; goto cleanup; } - domain_len = Mail_sprintf(out_buffer, "%s", id_pair->data.ptr); + domainLength = Mail_sprintf(outBuffer, "%s", addrId->data.ptr); - if (domain_len == 0) { - result = NWC24_ERR_FATAL; + if (domainLength == 0) { + err = NWC24_ERR_FATAL; goto cleanup; } - *out_length = domain_len; + *outLength = domainLength; } else { - result = NWC24_ERR_INVALID_VALUE; + err = NWC24_ERR_INVALID_VALUE; } cleanup: - return result; + return err; } NWC24Err WriteSMTP_MAILFROM(NWC24MsgObj* msg) { @@ -832,6 +655,17 @@ NWC24Err WriteSMTP_RCPTTO(NWC24MsgObj* msg) { return err; } +static NWC24Err WriteSMTP_DATA(NWC24MsgObj* msg) { + NWC24Err result; + char* stringWork = NWC24WorkP->stringWork; + Mail_strcpy(stringWork, "DATA\r\n"); + result = NWC24FWrite(stringWork, Mail_strlen(stringWork), m_pFile); + if (result == NWC24_OK) { + msg->length += 6; + } + return result; +} + NWC24Err WriteFromField(NWC24MsgObj* msg) { char* workp; u32 addrType; @@ -944,6 +778,26 @@ NWC24Err WriteToField(NWC24MsgObj* msg) { return err; } +static NWC24Err WriteSubjectField(NWC24MsgObj* msg) { + char* stringWork = NWC24WorkP->stringWork; + NWC24Err result; + u32 writeSize; + if (msg->subject.size == 0) { + result = NWC24_ERR_NULL; + } else { + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_strcpy(stringWork, "Subject: "); + Mail_strncat(stringWork, (const char*)msg->subject.ptr, 1021); + Mail_strncat(stringWork, "\r\n", NWC24_WORK_BUFFER_SIZE); + writeSize = STD_strnlen(stringWork, NWC24_WORK_BUFFER_SIZE); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + } + return result; +} + NWC24Err WriteDateField(NWC24MsgObj* msg) { char* workp; NWC24Date date; @@ -981,6 +835,29 @@ NWC24Err WriteDateField(NWC24MsgObj* msg) { return err; } +static NWC24Err WriteMessageIdField(NWC24MsgObj* msg) { + u64 myUserId; + char stackBuffer[32]; + NWC24Err result; + u32 writeSize; + char* stringWork = NWC24WorkP->stringWork; + const char* domain = NWC24GetAccountDomain(); + NWC24GetMyUserId(&myUserId); + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_strcpy(stringWork, "Message-ID: <"); + Mail_memset(stackBuffer, 0, 32); + Mail_sprintf(stackBuffer, "%08x%08x%08x%08x", msg->id, (u32)(myUserId >> 32), (u32)myUserId, msg->createTime); + Mail_strcat(stringWork, stackBuffer); + Mail_strcat(stringWork, domain); + Mail_strcat(stringWork, ">\r\n"); + writeSize = Mail_strlen(stringWork); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + return result; +} + NWC24Err WriteXWiiAppIdField(NWC24MsgObj* msg) { char* workp = NWC24WorkP->stringWork; char tempbuf[16]; @@ -1013,6 +890,42 @@ NWC24Err WriteXWiiAppIdField(NWC24MsgObj* msg) { } } +static NWC24Err WriteXWiiTagField(NWC24MsgObj* msg) { + NWC24Err result; + u32 writeSize; + if (msg->tag == 0) { + return NWC24_OK; + } else { + char* stringWork = NWC24WorkP->stringWork; + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_sprintf(stringWork, "X-Wii-Tag: %08x\r\n", msg->tag); + writeSize = Mail_strlen(stringWork); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + } + return result; +} + +static NWC24Err WriteXWiiCmdField(NWC24MsgObj* msg) { + NWC24Err result; + u32 writeSize; + if (msg->ledPattern == 0) { + return NWC24_OK; + } else { + char* stringWork = NWC24WorkP->stringWork; + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_sprintf(stringWork, "X-Wii-Led: %08x\r\n", msg->ledPattern); + writeSize = Mail_strlen(stringWork); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + } + return result; +} + NWC24Err WriteXWiiFaceField(NWC24MsgObj* msg) { char* workp; const u8* dataPtr; @@ -1105,6 +1018,94 @@ NWC24Err WriteXWiiAltNameField(NWC24MsgObj* msg) { return err; } +static NWC24Err WriteXWiiMBNoReplyField(NWC24MsgObj* msg) { + NWC24Err result; + if (!(msg->mb.raw & 0x80000000)) { + return NWC24_OK; + } else { + char* stringWork = NWC24WorkP->stringWork; + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_strcpy(stringWork, "X-Wii-MB-Parameter:\r\n"); + result = NWC24FWrite(stringWork, 21, m_pFile); + if (result == NWC24_OK) { + msg->length += 21; + } + } + return result; +} + +static NWC24Err WriteXWiiMBRegDateField(NWC24MsgObj* msg) { + u32 writeSize; + NWC24Err result; + u32 regdate = msg->mb.regdate; + if (regdate == 0) { + return NWC24_OK; + } else { + char* stringWork = NWC24WorkP->stringWork; + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_sprintf(stringWork, "X-Wii-MB-RegDate: %04x\r\n", regdate); + writeSize = STD_strnlen(stringWork, NWC24_WORK_BUFFER_SIZE); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + } + return result; +} + +static NWC24Err WriteXWiiMBDelayField(NWC24MsgObj* msg) { + NWC24Err result; + u32 writeSize; + u32 delay = msg->mb.raw & 0x00FF0000; + if (delay == 0) { + return NWC24_OK; + } else { + char* stringWork = NWC24WorkP->stringWork; + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_sprintf(stringWork, "X-Wii-MB-Delay: %02x\r\n", delay >> 16); + writeSize = STD_strnlen(stringWork, NWC24_WORK_BUFFER_SIZE); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + } + return result; +} + +static NWC24Err WriteMIMETopHeader(NWC24MsgObj* msg) { + char* stringWork = NWC24WorkP->stringWork; + NWC24Err result; + u32 writeSize; + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_strcpy(stringWork, "MIME-Version: 1.0\r\n"); + if (msg->flags & 0x10000) { + Mail_strcat(stringWork, "Content-Type: multipart/mixed; boundary=\""); + Mail_strcat(stringWork, MultiPartDivider); + Mail_strcat(stringWork, "\"\r\n"); + } + writeSize = Mail_strlen(stringWork); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + return result; +} + +static NWC24Err WriteMIMEPartBoundary(NWC24MsgObj* msg) { + char* stringWork = NWC24WorkP->stringWork; + NWC24Err result; + u32 writeSize; + Mail_memset(stringWork, 0, NWC24_WORK_BUFFER_SIZE); + Mail_sprintf(stringWork, "\r\n--%s", MultiPartDivider); + Mail_strcat(stringWork, "\r\n"); + writeSize = Mail_strlen(stringWork); + result = NWC24FWrite(stringWork, writeSize, m_pFile); + if (result == NWC24_OK) { + msg->length += writeSize; + } + return result; +} + NWC24Err WriteMIMEAttachHeader(NWC24MsgObj* msg, u32 attachIndex) { char* workp; const char* mimeTypeStr; @@ -1206,6 +1207,19 @@ NWC24Err WriteContentTypeField(NWC24MsgObj* msg) { return err; } +static NWC24Err WriteUserField(NWC24MsgObj* msg) { + NWC24Err result; + if (msg->DATA_0xD0.size == 0) { + return NWC24_OK; + } else { + result = NWC24FWrite(msg->DATA_0xD0.ptr, msg->DATA_0xD0.size, m_pFile); + if (result == NWC24_OK) { + msg->length += msg->DATA_0xD0.size; + } + } + return result; +} + NWC24Err WritePlainText(NWC24MsgObj* msg) { NWC24Err err = NWC24_OK; u32 bytesWritten; @@ -1239,6 +1253,16 @@ NWC24Err WritePlainText(NWC24MsgObj* msg) { return err; } +static NWC24Err WriteAttachData(NWC24MsgObj* msg, s32 i) { + NWC24Err result; + u32 writeSize; + result = WriteBase64Data(msg->attached[i].ptr, msg->attached[i].size, &writeSize); + if (result == NWC24_OK) { + msg->length += writeSize; + } + return result; +} + NWC24Err WriteBase64Data(const void* data, u32 size, u32* bytesWritten) { char* workp = NWC24WorkP->stringWork; const u8* dataPtr = (const u8*)data; @@ -1311,13 +1335,13 @@ NWC24Err WriteQPData(const void* data, u32 size, u32* bytesWritten) { Mail_memset(workp, 0, NWC24_WORK_BUFFER_SIZE); err = NWC24EncodeQuotedPrintable((u8*)workp, NWC24_WORK_BUFFER_SIZE, &written, (u8*)dataPtr, remainSize, &consumed); - + if (err != NWC24_OK) { if (err != NWC24_ERR_OVERFLOW) { break; } } - + err = NWC24FWrite(workp, written, m_pFile); if (err != NWC24_OK) { break; diff --git a/src/revolution/NWC24/NWC24StdApi.c b/src/revolution/NWC24/NWC24StdApi.c index ba5a1022..2c3fc908 100644 --- a/src/revolution/NWC24/NWC24StdApi.c +++ b/src/revolution/NWC24/NWC24StdApi.c @@ -123,7 +123,7 @@ int convNum(char *dst, int number, int numberBase, char charBase, int signedFlag char digitCharBase; char finalPadChar; BOOL isNegative; - + if ((signedFlag != 0) && (number & 0x80000000)) { isNegative = 1; workingValue = -number; @@ -131,7 +131,7 @@ int convNum(char *dst, int number, int numberBase, char charBase, int signedFlag isNegative = 0; workingValue = number; } - + digitcharsWritten = 0; charsWritten = 0;