wow_world_messages/world/vanilla/
cmsg_send_mail.rs

1use std::io::{Read, Write};
2
3use crate::Guid;
4use crate::shared::gold_vanilla_tbc_wrath::Gold;
5
6/// Auto generated from the original `wowm` in file [`wow_message_parser/wowm/world/mail/cmsg_send_mail.wowm:1`](https://github.com/gtker/wow_messages/tree/main/wow_message_parser/wowm/world/mail/cmsg_send_mail.wowm#L1):
7/// ```text
8/// cmsg CMSG_SEND_MAIL = 0x0238 {
9///     Guid mailbox;
10///     CString receiver;
11///     CString subject;
12///     CString body;
13///     u32 unknown1;
14///     u32 unknown2;
15///     Guid item;
16///     Gold money;
17///     u32 cash_on_delivery_amount;
18///     u32 unknown3;
19///     u32 unknown4;
20/// }
21/// ```
22#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
23pub struct CMSG_SEND_MAIL {
24    pub mailbox: Guid,
25    pub receiver: String,
26    pub subject: String,
27    pub body: String,
28    /// cmangos: stationery?
29    pub unknown1: u32,
30    /// cmangos: 0x00000000
31    pub unknown2: u32,
32    pub item: Guid,
33    pub money: Gold,
34    pub cash_on_delivery_amount: u32,
35    /// cmangos: const 0
36    pub unknown3: u32,
37    /// cmangos: const 0
38    pub unknown4: u32,
39}
40
41impl crate::private::Sealed for CMSG_SEND_MAIL {}
42impl CMSG_SEND_MAIL {
43    fn read_inner(mut r: &mut &[u8], body_size: u32) -> Result<Self, crate::errors::ParseErrorKind> {
44        if !(43..=808).contains(&body_size) {
45            return Err(crate::errors::ParseErrorKind::InvalidSize);
46        }
47
48        // mailbox: Guid
49        let mailbox = crate::util::read_guid(&mut r)?;
50
51        // receiver: CString
52        let receiver = {
53            let receiver = crate::util::read_c_string_to_vec(&mut r)?;
54            String::from_utf8(receiver)?
55        };
56
57        // subject: CString
58        let subject = {
59            let subject = crate::util::read_c_string_to_vec(&mut r)?;
60            String::from_utf8(subject)?
61        };
62
63        // body: CString
64        let body = {
65            let body = crate::util::read_c_string_to_vec(&mut r)?;
66            String::from_utf8(body)?
67        };
68
69        // unknown1: u32
70        let unknown1 = crate::util::read_u32_le(&mut r)?;
71
72        // unknown2: u32
73        let unknown2 = crate::util::read_u32_le(&mut r)?;
74
75        // item: Guid
76        let item = crate::util::read_guid(&mut r)?;
77
78        // money: Gold
79        let money = Gold::new(crate::util::read_u32_le(&mut r)?);
80
81        // cash_on_delivery_amount: u32
82        let cash_on_delivery_amount = crate::util::read_u32_le(&mut r)?;
83
84        // unknown3: u32
85        let unknown3 = crate::util::read_u32_le(&mut r)?;
86
87        // unknown4: u32
88        let unknown4 = crate::util::read_u32_le(&mut r)?;
89
90        Ok(Self {
91            mailbox,
92            receiver,
93            subject,
94            body,
95            unknown1,
96            unknown2,
97            item,
98            money,
99            cash_on_delivery_amount,
100            unknown3,
101            unknown4,
102        })
103    }
104
105}
106
107impl crate::Message for CMSG_SEND_MAIL {
108    const OPCODE: u32 = 0x0238;
109
110    #[cfg(feature = "print-testcase")]
111    fn message_name(&self) -> &'static str {
112        "CMSG_SEND_MAIL"
113    }
114
115    #[cfg(feature = "print-testcase")]
116    fn to_test_case_string(&self) -> Option<String> {
117        use std::fmt::Write;
118        use crate::traits::Message;
119
120        let mut s = String::new();
121
122        writeln!(s, "test CMSG_SEND_MAIL {{").unwrap();
123        // Members
124        writeln!(s, "    mailbox = {};", self.mailbox.guid()).unwrap();
125        writeln!(s, "    receiver = \"{}\";", self.receiver).unwrap();
126        writeln!(s, "    subject = \"{}\";", self.subject).unwrap();
127        writeln!(s, "    body = \"{}\";", self.body).unwrap();
128        writeln!(s, "    unknown1 = {};", self.unknown1).unwrap();
129        writeln!(s, "    unknown2 = {};", self.unknown2).unwrap();
130        writeln!(s, "    item = {};", self.item.guid()).unwrap();
131        writeln!(s, "    money = {};", self.money.as_int()).unwrap();
132        writeln!(s, "    cash_on_delivery_amount = {};", self.cash_on_delivery_amount).unwrap();
133        writeln!(s, "    unknown3 = {};", self.unknown3).unwrap();
134        writeln!(s, "    unknown4 = {};", self.unknown4).unwrap();
135
136        writeln!(s, "}} [").unwrap();
137
138        let [a, b] = (u16::try_from(self.size() + 4).unwrap()).to_be_bytes();
139        writeln!(s, "    {a:#04X}, {b:#04X}, /* size */").unwrap();
140        let [a, b, c, d] = 568_u32.to_le_bytes();
141        writeln!(s, "    {a:#04X}, {b:#04X}, {c:#04X}, {d:#04X}, /* opcode */").unwrap();
142        let mut bytes: Vec<u8> = Vec::new();
143        self.write_into_vec(&mut bytes).unwrap();
144        let mut bytes = bytes.into_iter();
145
146        crate::util::write_bytes(&mut s, &mut bytes, 8, "mailbox", "    ");
147        crate::util::write_bytes(&mut s, &mut bytes, self.receiver.len() + 1, "receiver", "    ");
148        crate::util::write_bytes(&mut s, &mut bytes, self.subject.len() + 1, "subject", "    ");
149        crate::util::write_bytes(&mut s, &mut bytes, self.body.len() + 1, "body", "    ");
150        crate::util::write_bytes(&mut s, &mut bytes, 4, "unknown1", "    ");
151        crate::util::write_bytes(&mut s, &mut bytes, 4, "unknown2", "    ");
152        crate::util::write_bytes(&mut s, &mut bytes, 8, "item", "    ");
153        crate::util::write_bytes(&mut s, &mut bytes, 4, "money", "    ");
154        crate::util::write_bytes(&mut s, &mut bytes, 4, "cash_on_delivery_amount", "    ");
155        crate::util::write_bytes(&mut s, &mut bytes, 4, "unknown3", "    ");
156        crate::util::write_bytes(&mut s, &mut bytes, 4, "unknown4", "    ");
157
158
159        writeln!(s, "] {{").unwrap();
160        writeln!(s, "    versions = \"{}\";", std::env::var("WOWM_TEST_CASE_WORLD_VERSION").unwrap_or("1".to_string())).unwrap();
161        writeln!(s, "}}\n").unwrap();
162
163        Some(s)
164    }
165
166    fn size_without_header(&self) -> u32 {
167        self.size() as u32
168    }
169
170    fn write_into_vec(&self, mut w: impl Write) -> Result<(), std::io::Error> {
171        // mailbox: Guid
172        w.write_all(&self.mailbox.guid().to_le_bytes())?;
173
174        // receiver: CString
175        // TODO: Guard against strings that are already null-terminated
176        assert_ne!(self.receiver.as_bytes().iter().next_back(), Some(&0_u8), "String `receiver` must not be null-terminated.");
177        w.write_all(self.receiver.as_bytes())?;
178        // Null terminator
179        w.write_all(&[0])?;
180
181        // subject: CString
182        // TODO: Guard against strings that are already null-terminated
183        assert_ne!(self.subject.as_bytes().iter().next_back(), Some(&0_u8), "String `subject` must not be null-terminated.");
184        w.write_all(self.subject.as_bytes())?;
185        // Null terminator
186        w.write_all(&[0])?;
187
188        // body: CString
189        // TODO: Guard against strings that are already null-terminated
190        assert_ne!(self.body.as_bytes().iter().next_back(), Some(&0_u8), "String `body` must not be null-terminated.");
191        w.write_all(self.body.as_bytes())?;
192        // Null terminator
193        w.write_all(&[0])?;
194
195        // unknown1: u32
196        w.write_all(&self.unknown1.to_le_bytes())?;
197
198        // unknown2: u32
199        w.write_all(&self.unknown2.to_le_bytes())?;
200
201        // item: Guid
202        w.write_all(&self.item.guid().to_le_bytes())?;
203
204        // money: Gold
205        w.write_all((self.money.as_int()).to_le_bytes().as_slice())?;
206
207        // cash_on_delivery_amount: u32
208        w.write_all(&self.cash_on_delivery_amount.to_le_bytes())?;
209
210        // unknown3: u32
211        w.write_all(&self.unknown3.to_le_bytes())?;
212
213        // unknown4: u32
214        w.write_all(&self.unknown4.to_le_bytes())?;
215
216        Ok(())
217    }
218
219    fn read_body<S: crate::private::Sealed>(r: &mut &[u8], body_size: u32) -> Result<Self, crate::errors::ParseError> {
220        Self::read_inner(r, body_size).map_err(|a| crate::errors::ParseError::new(568, "CMSG_SEND_MAIL", body_size, a))
221    }
222
223}
224
225#[cfg(feature = "vanilla")]
226impl crate::vanilla::ClientMessage for CMSG_SEND_MAIL {}
227
228impl CMSG_SEND_MAIL {
229    pub(crate) fn size(&self) -> usize {
230        8 // mailbox: Guid
231        + self.receiver.len() + 1 // receiver: CString
232        + self.subject.len() + 1 // subject: CString
233        + self.body.len() + 1 // body: CString
234        + 4 // unknown1: u32
235        + 4 // unknown2: u32
236        + 8 // item: Guid
237        + 4 // money: Gold
238        + 4 // cash_on_delivery_amount: u32
239        + 4 // unknown3: u32
240        + 4 // unknown4: u32
241    }
242}
243