IOS/KD: Implement friend registration
This commit is contained in:
parent
60f0ad501a
commit
015fbe4b5f
|
@ -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;
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
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;
|
||||
|
@ -63,6 +63,7 @@ public:
|
|||
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){};
|
||||
|
@ -93,8 +94,9 @@ private:
|
|||
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{};
|
||||
|
|
|
@ -27,6 +27,15 @@ 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();
|
||||
|
@ -34,7 +43,9 @@ public:
|
|||
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
|
||||
|
@ -59,14 +70,6 @@ private:
|
|||
Email
|
||||
};
|
||||
|
||||
enum class FriendStatus : u32
|
||||
{
|
||||
None,
|
||||
Unconfirmed,
|
||||
Confirmed,
|
||||
Declined
|
||||
};
|
||||
|
||||
struct FriendListEntry final
|
||||
{
|
||||
u32 friend_type;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -38,6 +38,7 @@ public:
|
|||
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);
|
||||
|
|
|
@ -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.
|
||||
|
@ -222,7 +223,7 @@ 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);
|
||||
|
@ -230,7 +231,7 @@ ErrorCode WC24SendList::AddRegistrationMessages(const WC24FriendList& friend_lis
|
|||
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);
|
||||
|
@ -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
|
||||
|
|
|
@ -50,7 +50,8 @@ public:
|
|||
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;
|
||||
|
@ -62,12 +63,12 @@ private:
|
|||
// 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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -94,7 +94,7 @@ public:
|
|||
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;
|
||||
|
|
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
@ -764,6 +765,37 @@ 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)
|
||||
{
|
||||
|
@ -771,6 +803,30 @@ NWC24::ErrorCode NetKDRequestDevice::KDSaveMail()
|
|||
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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue