Skip to content

Commit

Permalink
IOS/KD: Implement friend registration
Browse files Browse the repository at this point in the history
  • Loading branch information
noahpistilli committed Apr 30, 2024
1 parent cce6dff commit 3d95099
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 74 deletions.
28 changes: 16 additions & 12 deletions Source/Core/Core/IOS/Network/KD/Mail/MailParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,20 @@ MailParser::MailParser(const std::string& boundary, const u32 num_of_mail,
m_parser.onPartBegin = EmptyCallback;
m_parser.onHeaderField = [&](const char* buf, size_t start, size_t end, void* user_data) {
const Header header_key = std::make_pair(std::string(buf + start, end - start), std::string());
m_headers[current_index].push_back(header_key);
m_headers[m_current_index].push_back(header_key);
};
m_parser.onHeaderValue = [&](const char* buf, size_t start, size_t end, void* user_data) {
m_headers[current_index][current_header].second = std::string(buf + start, end - start);
m_headers[m_current_index][m_current_header].second = std::string(buf + start, end - start);
};
m_parser.onHeaderEnd = [&](const char* buf, size_t start, size_t end, void* user_data) {
current_header++;
m_current_header++;
};
m_parser.onPartData = [&](const char* buf, size_t start, size_t end, void* user_data) {
m_message_data[current_index].append(std::string(buf + start, end - start));
m_message_data[m_current_index].append(std::string(buf + start, end - start));
};
m_parser.onPartEnd = [&](const char* buf, size_t start, size_t end, void* user_data) {
current_index++;
current_header = 0;
m_current_index++;
m_current_header = 0;
};
m_parser.onEnd = EmptyCallback;
}
Expand Down Expand Up @@ -363,9 +363,8 @@ void MailParser::ParseDate(u32 index, u32 receive_index) const
m_receive_list->SetTime(receive_index, static_cast<u32>(std::floor(seconds_since_1900 / 60)));
}

ErrorCode MailParser::ParseFrom(u32 index, u32 receive_index, WC24FriendList& friend_list) const
ErrorCode MailParser::ParseFrom(u32 index, u32 receive_index, WC24FriendList& friend_list)
{
u64 friend_code{};
u64 value{};
const std::string str_friend = GetHeaderValue(index, "From");
if (str_friend.empty())
Expand All @@ -374,17 +373,17 @@ ErrorCode MailParser::ParseFrom(u32 index, u32 receive_index, WC24FriendList& fr
// Determine if this is a Wii sender or email.
if (std::regex_search(str_friend, m_wii_number_regex))
{
friend_code = std::stoull(str_friend.substr(1, 16), nullptr, 10);
value = friend_code;
m_sender = std::stoull(str_friend.substr(1, 16), nullptr, 10);
value = m_sender;
}
else
{
// For emails, the friend code stored in the nwc24fl.bin differs from the value we need to set.
friend_code = WC24FriendList::ConvertEmailToFriendCode(str_friend);
m_sender = WC24FriendList::ConvertEmailToFriendCode(str_friend);
value = u64{GetFullMessage(index).find("From") + 2} << 32 | static_cast<u64>(str_friend.size());
}

if (!friend_list.IsFriend(Common::swap64(friend_code)) && friend_code != NINTENDO_FRIEND_CODE)
if (!friend_list.IsFriend(Common::swap64(m_sender)) && m_sender != NINTENDO_FRIEND_CODE)
{
WARN_LOG_FMT(IOS_WC24, "Received message from someone who is not a friend, discarding.");
return WC24_ERR_NOT_FOUND;
Expand Down Expand Up @@ -470,4 +469,9 @@ ErrorCode MailParser::ParseWiiCmd(u32 index, u32 receive_index) const

return WC24_OK;
}

u64 MailParser::GetSender() const
{
return m_sender;
}
} // namespace IOS::HLE::NWC24::Mail
8 changes: 5 additions & 3 deletions Source/Core/Core/IOS/Network/KD/Mail/MailParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class MailParser final
ErrorCode ParseContentType(u32 index, u32 receive_index,
IsMultipart is_multipart = IsMultipart{false});
void ParseDate(u32 index, u32 receive_index) const;
ErrorCode ParseFrom(u32 index, u32 receive_index, WC24FriendList& friend_list) const;
ErrorCode ParseFrom(u32 index, u32 receive_index, WC24FriendList& friend_list);
void ParseSubject(u32 index, u32 receive_index) const;
ErrorCode ParseTo(u32 index, u32 receive_index) const;
ErrorCode ParseWiiAppId(u32 index, u32 receive_index) const;
Expand All @@ -63,6 +63,7 @@ class MailParser final
std::string GetHeaderValue(u32 index, std::string_view key,
IsMultipart is_multipart = IsMultipart{false}) const;
u32 GetHeaderLength(u32 index) const;
u64 GetSender() const;

private:
static void EmptyCallback(const char* buffer, size_t start, size_t end, void* user_data){};
Expand Down Expand Up @@ -93,8 +94,9 @@ class MailParser final
std::vector<std::string> m_message_data;
std::vector<Headers> m_headers;
std::regex m_wii_number_regex{"w\\d{16}"};
u32 current_index{};
u32 current_header{};
u32 m_current_index{};
u32 m_current_header{};
u64 m_sender{};
std::string m_charset{};
std::string m_content_type_str{};
ContentType m_content_type{};
Expand Down
19 changes: 11 additions & 8 deletions Source/Core/Core/IOS/Network/KD/Mail/WC24FriendList.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,25 @@ class WC24FriendList final
{
public:
explicit WC24FriendList(std::shared_ptr<FS::FileSystem> fs);

enum class FriendStatus : u32
{
None,
Unconfirmed,
Confirmed,
Declined
};

static u64 ConvertEmailToFriendCode(std::string_view email);

void ReadFriendList();
bool CheckFriendList() const;
void WriteFriendList() const;

bool IsFriend(u64 friend_id) const;
bool IsFriendEstablished(u64 code) const;
std::vector<u64> GetUnconfirmedFriends() const;
void SetFriendStatus(u64 code, FriendStatus status);

private:
static constexpr u32 FRIEND_LIST_MAGIC = 0x5763466C; // WcFl
Expand All @@ -59,14 +70,6 @@ class WC24FriendList final
Email
};

enum class FriendStatus : u32
{
None,
Unconfirmed,
Confirmed,
Declined
};

struct FriendListEntry final
{
u32 friend_type;
Expand Down
6 changes: 6 additions & 0 deletions Source/Core/Core/IOS/Network/KD/Mail/WC24Receive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@ u16 WC24ReceiveList::GetAppGroup(u32 index) const
return Common::swap16(m_data.entries[index].app_group);
}

u32 WC24ReceiveList::GetWiiCmd(u32 index) const
{
ASSERT(!IsDisabled());
return Common::swap32(m_data.entries[index].wii_cmd);
}

void WC24ReceiveList::UpdateFlag(u32 index, u32 value, FlagOP op)
{
ASSERT(!IsDisabled());
Expand Down
1 change: 1 addition & 0 deletions Source/Core/Core/IOS/Network/KD/Mail/WC24Receive.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class WC24ReceiveList final
u32 GetNextEntryIndex() const;
u32 GetAppID(u32 index) const;
u16 GetAppGroup(u32 index) const;
u32 GetWiiCmd(u32 index) const;

void FinalizeEntry(u32 index);
void ClearEntry(u32 index);
Expand Down
8 changes: 4 additions & 4 deletions Source/Core/Core/IOS/Network/KD/Mail/WC24Send.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ std::optional<u32> WC24SendList::GetNextFreeEntryIndex() const
return std::nullopt;
}

ErrorCode WC24SendList::AddRegistrationMessages(const WC24FriendList& friend_list, u64 sender)
void WC24SendList::AddRegistrationMessages(const WC24FriendList& friend_list, u64 sender,
std::string_view email)
{
ASSERT(!IsDisabled());
// It is possible that the user composed a message before SendMail was called.
Expand All @@ -222,15 +223,15 @@ ErrorCode WC24SendList::AddRegistrationMessages(const WC24FriendList& friend_lis
const std::time_t t = std::time(nullptr);

const std::string formatted_message =
fmt::format(MAIL_REGISTRATION_STRING, sender, code, fmt::gmtime(t));
fmt::format(MAIL_REGISTRATION_STRING, sender, code, email, fmt::gmtime(t));
const std::span message{reinterpret_cast<const u8*>(formatted_message.data()),
formatted_message.size()};
const ErrorCode reply = WriteToVFF(SEND_BOX_PATH, GetMailPath(entry_index), m_fs, message);

if (reply != WC24_OK)
{
ERROR_LOG_FMT(IOS_WC24, "Error writing registration message to VFF");
return reply;
return;
}

NOTICE_LOG_FMT(IOS_WC24, "Issued registration message for Wii Friend: {}", code);
Expand All @@ -256,7 +257,6 @@ ErrorCode WC24SendList::AddRegistrationMessages(const WC24FriendList& friend_lis

// Only flush on success.
WriteSendList();
return WC24_OK;
}

std::string_view WC24SendList::GetMailFlag() const
Expand Down
13 changes: 7 additions & 6 deletions Source/Core/Core/IOS/Network/KD/Mail/WC24Send.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ class WC24SendList final
u32 GetNextEntryIndex() const;
std::optional<u32> GetNextFreeEntryIndex() const;

ErrorCode AddRegistrationMessages(const WC24FriendList& friend_list, u64 sender);
void AddRegistrationMessages(const WC24FriendList& friend_list, u64 sender,
std::string_view email);

private:
static constexpr u32 MAX_ENTRIES = 127;
Expand All @@ -62,12 +63,12 @@ class WC24SendList final
// just 128 bytes of base64 encoded 0 bytes. That file is supposed to be friend profile data which
// is written to nwc24fl.bin, although it has been observed to always be 0.
static constexpr char MAIL_REGISTRATION_STRING[] =
"MAIL FROM: {0:016d}@wii.com\r\n"
"RCPT TO: {1:016d}wii.com\r\n"
"MAIL FROM: w{0:016d}{2}\r\n"
"RCPT TO: w{1:016d}{2}\r\n"
"DATA\r\n"
"Date: {2:%a, %d %b %Y %X} GMT\r\n"
"From: {0:016d}@wii.com\r\n"
"To: {1:016d}@wii.com\r\n"
"Date: {3:%a, %d %b %Y %X} GMT\r\n"
"From: w{0:016d}{2}\r\n"
"To: w{1:016d}{2}\r\n"
"Message-Id: <00002000B0DF6BB47FE0303E0DB0D@wii.com>\r\n"
"Subject: WC24 Cmd Message\r\n"
"X-Wii-AppId: 0-00000001-0001\r\n"
Expand Down
5 changes: 3 additions & 2 deletions Source/Core/Core/IOS/Network/KD/NWC24Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,10 @@ void NWC24Config::SetId(u64 nwc24_id)
m_data.nwc24_id = Common::swap64(nwc24_id);
}

const char* NWC24Config::Email() const
std::string_view NWC24Config::GetEmail() const
{
return m_data.email;
const size_t size = strnlen(m_data.email, MAX_EMAIL_LENGTH);
return {m_data.email, size};
}

void NWC24Config::SetEmail(const char* email)
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/IOS/Network/KD/NWC24Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class NWC24Config final
u64 Id() const;
void SetId(u64 nwc24_id);

const char* Email() const;
std::string_view GetEmail() const;
void SetEmail(const char* email);

std::string GetAccountURL() const;
Expand Down
102 changes: 64 additions & 38 deletions Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,13 @@ void NetKDRequestDevice::SchedulerWorker(const SchedulerEvent event)
u32 mail_flag{};
u32 interval{};

NWC24::ErrorCode code = KDCheckMail(&mail_flag, &interval);
NWC24::ErrorCode code = KDSendMail();
if (code != NWC24::WC24_OK)
{
LogError(ErrorType::SendMail, code);
}

code = KDCheckMail(&mail_flag, &interval);
if (code != NWC24::WC24_OK)
{
LogError(ErrorType::CheckMail, code);
Expand All @@ -290,12 +296,6 @@ void NetKDRequestDevice::SchedulerWorker(const SchedulerEvent event)
if (code != NWC24::WC24_OK)
LogError(ErrorType::ReceiveMail, code);
}

code = KDSendMail();
if (code != NWC24::WC24_OK)
{
LogError(ErrorType::SendMail, code);
}
}
}

Expand Down Expand Up @@ -545,6 +545,7 @@ NWC24::ErrorCode NetKDRequestDevice::KDSendMail()
m_scheduler_buffer[4] = Common::swap32(static_cast<u32>(CurrentFunction::Send));
}

m_send_list.AddRegistrationMessages(m_friend_list, m_config.Id(), m_config.GetEmail());
m_send_list.ReadSendList();
const std::string auth =
fmt::format("mlid=w{}\r\npasswd={}", m_config.Id(), m_config.GetPassword());
Expand Down Expand Up @@ -764,13 +765,68 @@ NWC24::ErrorCode NetKDRequestDevice::KDSaveMail()
m_receive_list.SetHeaderLength(entry_index, header_len);
m_receive_list.SetMessageOffset(entry_index, header_len);

reply = parser.ParseWiiAppId(i, entry_index);
if (reply != NWC24::WC24_OK)
{
ERROR_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_SAVE_MAIL_NOW: Failed to parse Wii App ID.");
continue;
}

if (m_receive_list.GetAppID(entry_index) == 0 || m_receive_list.GetAppGroup(entry_index) == 0)
{
if (m_receive_list.GetAppID(entry_index) == 0)
{
m_receive_list.SetWiiCmd(entry_index, 0x44001);
}
else
{
m_receive_list.SetWiiCmd(entry_index, 0x80000);
}
m_receive_list.UpdateFlag(entry_index, 2, NWC24::Mail::FlagOP::Or);
}
else
{
m_receive_list.UpdateFlag(entry_index, 1, NWC24::Mail::FlagOP::Or);
}

reply = parser.ParseWiiCmd(i, entry_index);
if (reply != NWC24::WC24_OK)
{
ERROR_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_SAVE_MAIL_NOW: Failed to parse command.");
continue;
}

reply = parser.ParseFrom(i, entry_index, m_friend_list);
if (reply != NWC24::WC24_OK)
{
ERROR_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_SAVE_MAIL_NOW: Failed to parse From field.");
continue;
}

// Handle registration is needed.
if (!m_friend_list.IsFriendEstablished(Common::swap64(parser.GetSender())))
{
// We use the parsed Wii Command to determine if this is a registration message.
const u32 wii_cmd = m_receive_list.GetWiiCmd(entry_index);
if (wii_cmd == 0x80010001 || wii_cmd == 0x80010002)
{
// Set the Wii as a registered friend.
m_friend_list.SetFriendStatus(parser.GetSender(),
NWC24::Mail::WC24FriendList::FriendStatus::Confirmed);
NOTICE_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_SAVE_MAIL_NOW: Registered friend {}",
parser.GetSender());
}
else if (wii_cmd == 0x80010003)
{
// Wii declined the friend request
m_friend_list.SetFriendStatus(parser.GetSender(),
NWC24::Mail::WC24FriendList::FriendStatus::Declined);
WARN_LOG_FMT(IOS_WC24,
"NET_KD_REQ: IOCTL_NWC24_SAVE_MAIL_NOW: Wii declined a friend request.");
}
continue;
}

reply = parser.ParseContentTransferEncoding(i, entry_index);
if (reply != NWC24::WC24_OK && reply != NWC24::WC24_ERR_NOT_FOUND)
{
Expand Down Expand Up @@ -800,37 +856,6 @@ NWC24::ErrorCode NetKDRequestDevice::KDSaveMail()
continue;
}

reply = parser.ParseWiiAppId(i, entry_index);
if (reply != NWC24::WC24_OK)
{
ERROR_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_SAVE_MAIL_NOW: Failed to parse Wii App ID.");
continue;
}

if (m_receive_list.GetAppID(entry_index) == 0 || m_receive_list.GetAppGroup(entry_index) == 0)
{
if (m_receive_list.GetAppID(entry_index) == 0)
{
m_receive_list.SetWiiCmd(entry_index, 0x44001);
}
else
{
m_receive_list.SetWiiCmd(entry_index, 0x80000);
}
m_receive_list.UpdateFlag(entry_index, 2, NWC24::Mail::FlagOP::Or);
}
else
{
m_receive_list.UpdateFlag(entry_index, 1, NWC24::Mail::FlagOP::Or);
}

reply = parser.ParseWiiCmd(i, entry_index);
if (reply != NWC24::WC24_OK)
{
ERROR_LOG_FMT(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_SAVE_MAIL_NOW: Failed to parse command.");
continue;
}

reply =
NWC24::WriteToVFF(NWC24::Mail::RECEIVE_BOX_PATH,
NWC24::Mail::WC24ReceiveList::GetMailPath(msg_id), m_ios.GetFS(), data);
Expand All @@ -846,6 +871,7 @@ NWC24::ErrorCode NetKDRequestDevice::KDSaveMail()
}

m_receive_list.WriteReceiveList();
m_friend_list.WriteFriendList();
m_scheduler_buffer[13] = Common::swap32(Common::swap32(m_scheduler_buffer[13]) + 1);
m_scheduler_buffer[4] = 0;
return NWC24::WC24_OK;
Expand Down

0 comments on commit 3d95099

Please sign in to comment.