1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2008-2011 D��vai Tam��s ( gonosztopi@amule.org )
5// Copyright (c) 2008-2011 aMule Team ( admin@amule.org / http://www.amule.org )
6//
7// Any parts of this program derived from the xMule, lMule or eMule project,
8// or contributed by third-party developers are copyrighted by their
9// respective authors.
10//
11// This program is free software; you can redistribute it and/or modify
12// it under the terms of the GNU General Public License as published by
13// the Free Software Foundation; either version 2 of the License, or
14// (at your option) any later version.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
24//
25
26#include "Print.h"
27#include <wx/datetime.h>
28#include <tags/FileTags.h>
29#include <tags/ServerTags.h>
30#include <tags/TagTypes.h>
31#include <protocol/ed2k/Client2Server/UDP.h>
32#include "../../OtherFunctions.h"
33#include "../../Friend.h"			// Needed for FF_NAME
34#include "../../KnownFile.h"		// Needed for PR_*
35#include "../../NetworkFunctions.h"	// Needed for Uint32toStringIP
36
37#include <cctype>
38#include <map>
39#include <iostream>
40
41SDMODE g_stringDecodeMode;
42
43wxString MakePrintableString(const wxString& s)
44{
45	wxString str = s;
46	unsigned c = 0;
47	for (unsigned i = 0; i < str.length(); i++) {
48		c |= (wxChar) str[i];
49	}
50
51	if (c <= 0xff && GetStringsMode() != SD_NONE) {
52		wxCharBuffer buf = str.To8BitData();
53		wxString test = UTF82unicode(buf.data());
54		if (!test.empty()) {
55			str = test;
56			c = 0;
57			for (unsigned i = 0; i < str.length(); i++) {
58				c |= (wxChar) str[i];
59			}
60		}
61	}
62
63	wxString retval = wxT("\"");
64
65	if (GetStringsMode() == SD_DISPLAY) {
66		retval += str;
67	} else if (GetStringsMode() == SD_UTF8) {
68		str = wxString::From8BitData((const char *)str.utf8_str());
69		c = 0xff;
70	}
71
72	if (GetStringsMode() != SD_DISPLAY) {
73		for (unsigned i = 0; i < str.length(); i++) {
74			if (GetStringsMode() == SD_NONE ? ((unsigned)str[i] >= ' ' && (unsigned)str[i] <= 0x7f) : std::isprint(str[i])) {
75				retval += str[i];
76			} else if (c <= 0xff) {
77				retval += wxString::Format(wxT("\\x%02x"), str[i]);
78			} else {
79				retval += wxString::Format(wxT("\\u%04x"), str[i]);
80			}
81		}
82	}
83
84	retval += wxT("\"");
85	return retval;
86}
87
88std::ostream& operator<<(std::ostream& x, const CTimeT& y)
89{
90	if ((time_t)y != 0) {
91		wxDateTime dt((time_t)y);
92		return x << (time_t)y << " (" << dt.Format(wxDefaultDateTimeFormat, wxDateTime::UTC) << " UTC)";
93	} else {
94		return x << "0 (Never)";
95	}
96}
97
98std::ostream& operator<<(std::ostream& x, const CKadIP& ip)
99{
100	return x << hex(ip) << " (" << Uint32toStringIP(wxUINT32_SWAP_ALWAYS(ip)) << ')';
101}
102
103std::ostream& operator<<(std::ostream& x, const CeD2kIP& ip)
104{
105	return x << hex(ip) << " (" << Uint32toStringIP(ip) << ')';
106}
107
108static inline wxString TagNameString(const wxString& name)
109{
110	if (name.length() == 1) {
111		return wxString::Format(wxT("\"\\x%02x\""), name[0]);
112	} else if (name.length() > 1) {
113		if (name[0] == FT_GAPSTART || name[0] == FT_GAPEND) {
114			return wxString::Format(wxT("\"\\x%02x"), name[0]) + name.substr(1) + wxT("\"");
115		}
116	}
117	return wxT("\"") + name + wxT("\"");
118}
119
120#define TEST_VALUE(VALUE)	if (value == VALUE) return #VALUE; else
121
122const char* DecodeTagNameID(uint8_t value)
123{
124	TEST_VALUE(FT_FILENAME)
125	TEST_VALUE(FT_FILESIZE)
126	TEST_VALUE(FT_FILESIZE_HI)
127	TEST_VALUE(FT_FILETYPE)
128	TEST_VALUE(FT_FILEFORMAT)
129	TEST_VALUE(FT_LASTSEENCOMPLETE)
130	TEST_VALUE(FT_TRANSFERRED)
131	TEST_VALUE(FT_GAPSTART)
132	TEST_VALUE(FT_GAPEND)
133	TEST_VALUE(FT_PARTFILENAME)
134	TEST_VALUE(FT_OLDDLPRIORITY)
135	TEST_VALUE(FT_STATUS)
136	TEST_VALUE(FT_SOURCES)
137	TEST_VALUE(FT_PERMISSIONS)
138	TEST_VALUE(FT_OLDULPRIORITY)
139	TEST_VALUE(FT_DLPRIORITY)
140	TEST_VALUE(FT_ULPRIORITY)
141	TEST_VALUE(FT_KADLASTPUBLISHKEY)
142	TEST_VALUE(FT_KADLASTPUBLISHSRC)
143	TEST_VALUE(FT_FLAGS)
144	TEST_VALUE(FT_DL_ACTIVE_TIME)
145	TEST_VALUE(FT_CORRUPTEDPARTS)
146	TEST_VALUE(FT_DL_PREVIEW)
147	TEST_VALUE(FT_KADLASTPUBLISHNOTES)
148	TEST_VALUE(FT_AICH_HASH)
149	TEST_VALUE(FT_COMPLETE_SOURCES)
150	TEST_VALUE(FT_PUBLISHINFO)
151	TEST_VALUE(FT_ATTRANSFERRED)
152	TEST_VALUE(FT_ATREQUESTED)
153	TEST_VALUE(FT_ATACCEPTED)
154	TEST_VALUE(FT_CATEGORY)
155	TEST_VALUE(FT_ATTRANSFERREDHI)
156	TEST_VALUE(FT_MEDIA_ARTIST)
157	TEST_VALUE(FT_MEDIA_ALBUM)
158	TEST_VALUE(FT_MEDIA_TITLE)
159	TEST_VALUE(FT_MEDIA_LENGTH)
160	TEST_VALUE(FT_MEDIA_BITRATE)
161	TEST_VALUE(FT_MEDIA_CODEC)
162	TEST_VALUE(FT_FILERATING)
163	return "??";
164}
165
166const char* DecodeTagName(const wxString& value)
167{
168	TEST_VALUE(TAG_FILENAME)
169	TEST_VALUE(TAG_FILESIZE)
170	TEST_VALUE(TAG_FILESIZE_HI)
171	TEST_VALUE(TAG_FILETYPE)
172	TEST_VALUE(TAG_FILEFORMAT)
173	TEST_VALUE(TAG_COLLECTION)
174	TEST_VALUE(TAG_PART_PATH)
175	TEST_VALUE(TAG_PART_HASH)
176	TEST_VALUE(TAG_COPIED)
177	TEST_VALUE(TAG_GAP_START)
178	TEST_VALUE(TAG_GAP_END)
179	TEST_VALUE(TAG_DESCRIPTION)
180	TEST_VALUE(TAG_PING)
181	TEST_VALUE(TAG_FAIL)
182	TEST_VALUE(TAG_PREFERENCE)
183	TEST_VALUE(TAG_PORT)
184	TEST_VALUE(TAG_IP_ADDRESS)
185	TEST_VALUE(TAG_VERSION)
186	TEST_VALUE(TAG_TEMPFILE)
187	TEST_VALUE(TAG_PRIORITY)
188	TEST_VALUE(TAG_STATUS)
189	TEST_VALUE(TAG_SOURCES)
190	TEST_VALUE(TAG_AVAILABILITY)
191	TEST_VALUE(TAG_PERMISSIONS)
192	TEST_VALUE(TAG_QTIME)
193	TEST_VALUE(TAG_PARTS)
194	TEST_VALUE(TAG_PUBLISHINFO)
195	TEST_VALUE(TAG_MEDIA_ARTIST)
196	TEST_VALUE(TAG_MEDIA_ALBUM)
197	TEST_VALUE(TAG_MEDIA_TITLE)
198	TEST_VALUE(TAG_MEDIA_LENGTH)
199	TEST_VALUE(TAG_MEDIA_BITRATE)
200	TEST_VALUE(TAG_MEDIA_CODEC)
201	TEST_VALUE(TAG_ENCRYPTION)
202	TEST_VALUE(TAG_FILERATING)
203	TEST_VALUE(TAG_BUDDYHASH)
204	TEST_VALUE(TAG_CLIENTLOWID)
205	TEST_VALUE(TAG_SERVERPORT)
206	TEST_VALUE(TAG_SERVERIP)
207	TEST_VALUE(TAG_SOURCEUPORT)
208	TEST_VALUE(TAG_SOURCEPORT)
209	TEST_VALUE(TAG_SOURCEIP)
210	TEST_VALUE(TAG_SOURCETYPE)
211	return "??";
212}
213
214const char* DecodeTagType(uint8_t value)
215{
216	TEST_VALUE(TAGTYPE_HASH16)
217	TEST_VALUE(TAGTYPE_STRING)
218	TEST_VALUE(TAGTYPE_UINT32)
219	TEST_VALUE(TAGTYPE_FLOAT32)
220	TEST_VALUE(TAGTYPE_BOOL)
221	TEST_VALUE(TAGTYPE_BOOLARRAY)
222	TEST_VALUE(TAGTYPE_BLOB)
223	TEST_VALUE(TAGTYPE_UINT16)
224	TEST_VALUE(TAGTYPE_UINT8)
225	TEST_VALUE(TAGTYPE_BSOB)
226	TEST_VALUE(TAGTYPE_UINT64)
227	TEST_VALUE(TAGTYPE_STR1)
228	TEST_VALUE(TAGTYPE_STR2)
229	TEST_VALUE(TAGTYPE_STR3)
230	TEST_VALUE(TAGTYPE_STR4)
231	TEST_VALUE(TAGTYPE_STR5)
232	TEST_VALUE(TAGTYPE_STR6)
233	TEST_VALUE(TAGTYPE_STR7)
234	TEST_VALUE(TAGTYPE_STR8)
235	TEST_VALUE(TAGTYPE_STR9)
236	TEST_VALUE(TAGTYPE_STR10)
237	TEST_VALUE(TAGTYPE_STR11)
238	TEST_VALUE(TAGTYPE_STR12)
239	TEST_VALUE(TAGTYPE_STR13)
240	TEST_VALUE(TAGTYPE_STR14)
241	TEST_VALUE(TAGTYPE_STR15)
242	TEST_VALUE(TAGTYPE_STR16)
243	TEST_VALUE(TAGTYPE_STR17)
244	TEST_VALUE(TAGTYPE_STR18)
245	TEST_VALUE(TAGTYPE_STR19)
246	TEST_VALUE(TAGTYPE_STR20)
247	TEST_VALUE(TAGTYPE_STR21)
248	TEST_VALUE(TAGTYPE_STR22)
249	return "??";
250}
251
252const char* DecodeServerTagNameID(uint8_t value)
253{
254	TEST_VALUE(ST_SERVERNAME)
255	TEST_VALUE(ST_DESCRIPTION)
256	TEST_VALUE(ST_PING)
257	TEST_VALUE(ST_FAIL)
258	TEST_VALUE(ST_PREFERENCE)
259	TEST_VALUE(ST_DYNIP)
260	TEST_VALUE(ST_LASTPING_DEPRECATED)
261	TEST_VALUE(ST_MAXUSERS)
262	TEST_VALUE(ST_SOFTFILES)
263	TEST_VALUE(ST_HARDFILES)
264	TEST_VALUE(ST_LASTPING)
265	TEST_VALUE(ST_VERSION)
266	TEST_VALUE(ST_UDPFLAGS)
267	TEST_VALUE(ST_AUXPORTSLIST)
268	TEST_VALUE(ST_LOWIDUSERS)
269	TEST_VALUE(ST_UDPKEY)
270	TEST_VALUE(ST_UDPKEYIP)
271	TEST_VALUE(ST_TCPPORTOBFUSCATION)
272	TEST_VALUE(ST_UDPPORTOBFUSCATION)
273	return "??";
274}
275
276const char* DecodeFriendTagNameID(uint8_t value)
277{
278	TEST_VALUE(FF_NAME)
279	return "??";
280}
281
282typedef std::map<uint32_t, const char*> FlagMap;
283
284class CFlagDecoder
285{
286      public:
287	void AddFlag(uint32_t bit, const char* name)
288	{
289		m_flags[bit] = name;
290	}
291
292	wxString DecodeFlags(uint32_t flags)
293	{
294		uint32_t cur_flag = 1;
295		wxString result;
296		while (flags) {
297			if (flags & 1) {
298				if (!result.empty()) {
299					result += wxT(" | ");
300				}
301				FlagMap::const_iterator it = m_flags.find(cur_flag);
302				if (it != m_flags.end()) {
303					result += wxString::FromAscii(it->second);
304				} else {
305					result += wxString::Format(wxT("%#x"), cur_flag);
306				}
307			}
308			cur_flag <<= 1;
309			flags >>= 1;
310		}
311		return result;
312	}
313
314      private:
315	FlagMap	m_flags;
316};
317
318#define ADD_DECODER_FLAG(decoder, FLAG)	decoder.AddFlag(FLAG, #FLAG)
319
320std::ostream& operator<<(std::ostream& out, const CTag& tag)
321{
322	out << "{ ";
323	if (tag.GetName().empty()) {
324		out << hex(tag.GetNameID()) << ' ' << DecodeTagNameID(tag.GetNameID());
325	} else {
326		out << TagNameString(tag.GetName()) << ' ';
327		bool name_decoded = false;
328		if (tag.IsInt() && tag.GetName().length() > 1) {
329			wxCharBuffer ascii_name = tag.GetName().ToAscii();
330			char gap_mark = ascii_name ? ascii_name[(size_t)0] : 0;
331			if (gap_mark == FT_GAPSTART || gap_mark == FT_GAPEND) {
332				unsigned long gapkey;
333				if (tag.GetName().Mid(1).ToULong(&gapkey)) {
334					out << DecodeTagNameID(gap_mark) << wxString::Format(wxT("[%lu]"), gapkey);
335					name_decoded = true;
336				}
337			}
338		}
339		if (!name_decoded) {
340			out << DecodeTagName(tag.GetName());
341		}
342	}
343	out << ", " << (unsigned)tag.GetType() << ' ' << DecodeTagType(tag.GetType()) << ", ";
344	if (tag.IsInt()) {
345		if (tag.GetName() == TAG_SOURCEIP) {
346			out << CKadIP(tag.GetInt());
347		} else if (tag.GetName() == TAG_SERVERIP) {
348			out << CeD2kIP(tag.GetInt());
349		} else if (tag.GetName() == TAG_ENCRYPTION) {
350			uint8_t enc = tag.GetInt();
351			out << hex(enc);
352			if (enc) {
353				CFlagDecoder decoder;
354				decoder.AddFlag(0x01, "CryptSupported");
355				decoder.AddFlag(0x02, "CryptRequested");
356				decoder.AddFlag(0x04, "CryptRequired");
357				decoder.AddFlag(0x08, "SupportsDirectCallback");
358				out << " (" << decoder.DecodeFlags(enc) << ')';
359			}
360		} else if (tag.GetNameID() == FT_LASTSEENCOMPLETE
361			   || tag.GetNameID() == FT_KADLASTPUBLISHSRC
362			   || tag.GetNameID() == FT_KADLASTPUBLISHNOTES
363			   || tag.GetNameID() == FT_KADLASTPUBLISHKEY
364			   ) {
365			out << CTimeT(tag.GetInt());
366		} else if (tag.GetName() == TAG_FILESIZE
367			   || tag.GetNameID() == FT_FILESIZE
368			   || tag.GetNameID() == FT_TRANSFERRED
369			   || tag.GetNameID() == FT_ATTRANSFERRED
370			   ) {
371			out << tag.GetInt() << " (" << CastItoXBytes(tag.GetInt()) << ')';
372		} else if (tag.GetNameID() == FT_ULPRIORITY
373			   || tag.GetNameID() == FT_DLPRIORITY
374			   || tag.GetNameID() == FT_OLDULPRIORITY
375			   || tag.GetNameID() == FT_OLDDLPRIORITY
376			   ) {
377			out << tag.GetInt() << ' ';
378			switch (tag.GetInt()) {
379				case PR_VERYLOW:	out << "PR_VERYLOW"; break;
380				case PR_LOW:		out << "PR_LOW"; break;
381				case PR_NORMAL:		out << "PR_NORMAL"; break;
382				case PR_HIGH:		out << "PR_HIGH"; break;
383				case PR_VERYHIGH:	out << "PR_VERYHIGH"; break;
384				case PR_AUTO:		out << "PR_AUTO"; break;
385				case PR_POWERSHARE:	out << "PR_POWERSHARE"; break;
386			}
387		} else {
388			out << tag.GetInt();
389		}
390	} else if (tag.IsStr()) {
391		out << MakePrintableString(tag.GetStr());
392	} else if (tag.IsFloat()) {
393		out << tag.GetFloat();
394	} else if (tag.IsHash()) {
395		out << tag.GetHash();
396	} else if (tag.IsBlob()) {
397		out << wxString::Format(wxT("(size = %u)"), tag.GetBlobSize());
398	} else if (tag.IsBsob()) {
399		out << wxString::Format(wxT("(size = %u)"), tag.GetBsobSize());
400	} else {
401		out << "(...)";
402	}
403	out << " }";
404	return out;
405}
406
407std::ostream& operator<<(std::ostream& out, const CServerTag& tag)
408{
409	out << "{ ";
410	if (tag.GetName().empty()) {
411		out << hex(tag.GetNameID()) << ' ' << DecodeServerTagNameID(tag.GetNameID());
412	} else {
413		out << TagNameString(tag.GetName());
414	}
415	out << ", " << (unsigned)tag.GetType() << ' ' << DecodeTagType(tag.GetType()) << ", ";
416	if (tag.IsInt()) {
417		if (tag.GetNameID() == ST_DYNIP || tag.GetNameID() == ST_UDPKEYIP) {
418			out << CeD2kIP(tag.GetInt());
419		} else if (tag.GetNameID() == ST_UDPKEY) {
420			out << hex((uint32_t)tag.GetInt());
421		} else if (tag.GetNameID() == ST_UDPFLAGS) {
422			uint32_t flags = tag.GetInt();
423			out << hex(flags);
424			if (flags) {
425				CFlagDecoder decoder;
426				ADD_DECODER_FLAG(decoder, SRV_UDPFLG_EXT_GETSOURCES);
427				ADD_DECODER_FLAG(decoder, SRV_UDPFLG_EXT_GETFILES);
428				ADD_DECODER_FLAG(decoder, SRV_UDPFLG_NEWTAGS);
429				ADD_DECODER_FLAG(decoder, SRV_UDPFLG_UNICODE);
430				ADD_DECODER_FLAG(decoder, SRV_UDPFLG_EXT_GETSOURCES2);
431				ADD_DECODER_FLAG(decoder, SRV_UDPFLG_LARGEFILES);
432				ADD_DECODER_FLAG(decoder, SRV_UDPFLG_UDPOBFUSCATION);
433				ADD_DECODER_FLAG(decoder, SRV_UDPFLG_TCPOBFUSCATION);
434				out << " (" << decoder.DecodeFlags(flags) << ')';
435			}
436		} else if (tag.GetNameID() == ST_PREFERENCE) {
437			out << tag.GetInt() << ' ';
438			switch (tag.GetInt()) {
439				case 0: out << "SRV_PR_NORMAL"; break;
440				case 1: out << "SRV_PR_HIGH"; break;
441				case 2: out << "SRV_PR_LOW"; break;
442				default: out << "??";
443			}
444		} else {
445			out << tag.GetInt();
446		}
447	} else if (tag.IsStr()) {
448		out << MakePrintableString(tag.GetStr());
449	} else if (tag.IsFloat()) {
450		out << tag.GetFloat();
451	} else if (tag.IsHash()) {
452		out << tag.GetHash();
453	} else if (tag.IsBlob()) {
454		out << wxString::Format(wxT("(size = %u)"), tag.GetBlobSize());
455	} else if (tag.IsBsob()) {
456		out << wxString::Format(wxT("(size = %u)"), tag.GetBsobSize());
457	} else {
458		out << "(...)";
459	}
460	out << " }";
461	return out;
462}
463
464std::ostream& operator<<(std::ostream& out, const CFriendTag& tag)
465{
466	out << "{ ";
467	if (tag.GetName().empty()) {
468		out << hex(tag.GetNameID()) << ' ' << DecodeFriendTagNameID(tag.GetNameID());
469	} else {
470		out << TagNameString(tag.GetName());
471	}
472	out << ", " << (unsigned)tag.GetType() << ' ' << DecodeTagType(tag.GetType()) << ", ";
473	if (tag.IsInt()) {
474		out << tag.GetInt();
475	} else if (tag.IsStr()) {
476		out << MakePrintableString(tag.GetStr());
477	} else if (tag.IsFloat()) {
478		out << tag.GetFloat();
479	} else if (tag.IsHash()) {
480		out << tag.GetHash();
481	} else if (tag.IsBlob()) {
482		out << wxString::Format(wxT("(size = %u)"), tag.GetBlobSize());
483	} else if (tag.IsBsob()) {
484		out << wxString::Format(wxT("(size = %u)"), tag.GetBsobSize());
485	} else {
486		out << "(...)";
487	}
488	out << " }";
489	return out;
490}
491