From 310a2c101b32a5e71a616027b6a1b788a341bc02 Mon Sep 17 00:00:00 2001 From: manuel Date: Tue, 5 Mar 2013 17:39:48 +0100 Subject: initial GPLv2 release --- .gitignore | 3 + COPYING | 352 +++++++++++ Makefile | 173 ++++++ base64.cpp | 126 ++++ base64.h | 27 + crc32.cpp | 166 ++++++ crc32.h | 108 ++++ tsapp.cpp | 617 ++++++++++++++++++++ tsapp.h | 77 +++ tschannel.cpp | 199 +++++++ tschannel.h | 371 ++++++++++++ tsclient.cfg | 52 ++ tsclient.cpp | 760 ++++++++++++++++++++++++ tsclient.h | 489 ++++++++++++++++ tsclient.sh | 108 ++++ tscommand.cpp | 1519 ++++++++++++++++++++++++++++++++++++++++++++++++ tscommand.h | 524 +++++++++++++++++ tsconnectionthread.cpp | 728 +++++++++++++++++++++++ tsconnectionthread.h | 176 ++++++ tsheaders.h | 62 ++ tsplayer.cpp | 200 +++++++ tsplayer.h | 339 +++++++++++ tsquerythread.cpp | 1105 +++++++++++++++++++++++++++++++++++ tsquerythread.h | 184 ++++++ tsserver.cpp | 168 ++++++ tsserver.h | 243 ++++++++ wxbufferex.cpp | 80 +++ wxbufferex.h | 42 ++ wxstreamex.cpp | 108 ++++ wxstreamex.h | 85 +++ 30 files changed, 9191 insertions(+) create mode 100644 .gitignore create mode 100644 COPYING create mode 100644 Makefile create mode 100644 base64.cpp create mode 100644 base64.h create mode 100644 crc32.cpp create mode 100644 crc32.h create mode 100644 tsapp.cpp create mode 100644 tsapp.h create mode 100644 tschannel.cpp create mode 100644 tschannel.h create mode 100644 tsclient.cfg create mode 100644 tsclient.cpp create mode 100644 tsclient.h create mode 100755 tsclient.sh create mode 100644 tscommand.cpp create mode 100644 tscommand.h create mode 100644 tsconnectionthread.cpp create mode 100644 tsconnectionthread.h create mode 100644 tsheaders.h create mode 100644 tsplayer.cpp create mode 100644 tsplayer.h create mode 100644 tsquerythread.cpp create mode 100644 tsquerythread.h create mode 100644 tsserver.cpp create mode 100644 tsserver.h create mode 100644 wxbufferex.cpp create mode 100644 wxbufferex.h create mode 100644 wxstreamex.cpp create mode 100644 wxstreamex.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c23c9ca --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +tsclient.log +.libs/* +.deps/* diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..2cf6990 --- /dev/null +++ b/COPYING @@ -0,0 +1,352 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble +======== + +The licenses for most software are designed to take away your freedom +to share and change it. By contrast, the GNU General Public License is +intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. +Our General Public Licenses are designed to make sure that you have +the freedom to distribute copies of free software (and charge for this +service if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone +to deny you these rights or to ask you to surrender the rights. These +restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis +or for a fee, you must give the recipients all the rights that you +have. You must make sure that they, too, receive or can get the source +code. And you must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + +Finally, any free program is threatened constantly by software patents. +We wish to avoid the danger that redistributors of a free program will +individually obtain patent licenses, in effect making the program +proprietary. To prevent this, we have made it clear that any patent +must be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + 0. This License applies to any program or other work which contains a + notice placed by the copyright holder saying it may be distributed + under the terms of this General Public License. The "Program", + below, refers to any such program or work, and a "work based on + the Program" means either the Program or any derivative work under + copyright law: that is to say, a work containing the Program or a + portion of it, either verbatim or with modifications and/or + translated into another language. (Hereinafter, translation is + included without limitation in the term "modification".) Each + licensee is addressed as "you". + + Activities other than copying, distribution and modification are + not covered by this License; they are outside its scope. The act + of running the Program is not restricted, and the output from the + Program is covered only if its contents constitute a work based on + the Program (independent of having been made by running the + Program). Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an appropriate + copyright notice and disclaimer of warranty; keep intact all the + notices that refer to this License and to the absence of any + warranty; and give any other recipients of the Program a copy of + this License along with the Program. + + You may charge a fee for the physical act of transferring a copy, + and you may at your option offer warranty protection in exchange + for a fee. + + 2. You may modify your copy or copies of the Program or any portion + of it, thus forming a work based on the Program, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a. You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b. You must cause any work that you distribute or publish, that + in whole or in part contains or is derived from the Program + or any part thereof, to be licensed as a whole at no charge + to all third parties under the terms of this License. + + c. If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display + an announcement including an appropriate copyright notice and + a notice that there is no warranty (or else, saying that you + provide a warranty) and that users may redistribute the + program under these conditions, and telling the user how to + view a copy of this License. (Exception: if the Program + itself is interactive but does not normally print such an + announcement, your work based on the Program is not required + to print an announcement.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the + Program, and can be reasonably considered independent and separate + works in themselves, then this License, and its terms, do not + apply to those sections when you distribute them as separate + works. But when you distribute the same sections as part of a + whole which is a work based on the Program, the distribution of + the whole must be on the terms of this License, whose permissions + for other licensees extend to the entire whole, and thus to each + and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or + contest your rights to work written entirely by you; rather, the + intent is to exercise the right to control the distribution of + derivative or collective works based on the Program. + + In addition, mere aggregation of another work not based on the + Program with the Program (or with a work based on the Program) on + a volume of a storage or distribution medium does not bring the + other work under the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, + under Section 2) in object code or executable form under the terms + of Sections 1 and 2 above provided that you also do one of the + following: + + a. Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Sections 1 and 2 above on a medium customarily used for + software interchange; or, + + b. Accompany it with a written offer, valid for at least three + years, to give any third-party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a + medium customarily used for software interchange; or, + + c. Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with + such an offer, in accord with Subsection b above.) + + The source code for a work means the preferred form of the work for + making modifications to it. For an executable work, complete + source code means all the source code for all modules it contains, + plus any associated interface definition files, plus the scripts + used to control compilation and installation of the executable. + However, as a special exception, the source code distributed need + not include anything that is normally distributed (in either + source or binary form) with the major components (compiler, + kernel, and so on) of the operating system on which the executable + runs, unless that component itself accompanies the executable. + + If distribution of executable or object code is made by offering + access to copy from a designated place, then offering equivalent + access to copy the source code from the same place counts as + distribution of the source code, even though third parties are not + compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program + except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense or distribute the Program is + void, and will automatically terminate your rights under this + License. However, parties who have received copies, or rights, + from you under this License will not have their licenses + terminated so long as such parties remain in full compliance. + + 5. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify + or distribute the Program or its derivative works. These actions + are prohibited by law if you do not accept this License. + Therefore, by modifying or distributing the Program (or any work + based on the Program), you indicate your acceptance of this + License to do so, and all its terms and conditions for copying, + distributing or modifying the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the + Program), the recipient automatically receives a license from the + original licensor to copy, distribute or modify the Program + subject to these terms and conditions. You may not impose any + further restrictions on the recipients' exercise of the rights + granted herein. You are not responsible for enforcing compliance + by third parties to this License. + + 7. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent + issues), conditions are imposed on you (whether by court order, + agreement or otherwise) that contradict the conditions of this + License, they do not excuse you from the conditions of this + License. If you cannot distribute so as to satisfy simultaneously + your obligations under this License and any other pertinent + obligations, then as a consequence you may not distribute the + Program at all. For example, if a patent license would not permit + royalty-free redistribution of the Program by all those who + receive copies directly or indirectly through you, then the only + way you could satisfy both it and this License would be to refrain + entirely from distribution of the Program. + + If any portion of this section is held invalid or unenforceable + under any particular circumstance, the balance of the section is + intended to apply and the section as a whole is intended to apply + in other circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of + any such claims; this section has the sole purpose of protecting + the integrity of the free software distribution system, which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is + willing to distribute software through any other system and a + licensee cannot impose that choice. + + This section is intended to make thoroughly clear what is believed + to be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in + certain countries either by patents or by copyrighted interfaces, + the original copyright holder who places the Program under this + License may add an explicit geographical distribution limitation + excluding those countries, so that distribution is permitted only + in or among countries not thus excluded. In such case, this + License incorporates the limitation as if written in the body of + this License. + + 9. The Free Software Foundation may publish revised and/or new + versions of the General Public License from time to time. Such + new versions will be similar in spirit to the present version, but + may differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the + Program specifies a version number of this License which applies + to it and "any later version", you have the option of following + the terms and conditions either of that version or of any later + version published by the Free Software Foundation. If the Program + does not specify a version number of this License, you may choose + any version ever published by the Free Software Foundation. + + 10. If you wish to incorporate parts of the Program into other free + programs whose distribution conditions are different, write to the + author to ask for permission. For software which is copyrighted + by the Free Software Foundation, write to the Free Software + Foundation; we sometimes make exceptions for this. Our decision + will be guided by the two goals of preserving the free status of + all derivatives of our free software and of promoting the sharing + and reuse of software generally. + + NO WARRANTY + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO + WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE + LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT + HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT + WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT + NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE + QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE + PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY + SERVICING, REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN + WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY + MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE + LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, + INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR + INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF + DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU + OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY + OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS +How to Apply These Terms to Your New Programs +============================================= + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + +To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively convey +the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES. + Copyright (C) YYYY NAME OF AUTHOR + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19YY NAME OF AUTHOR + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and `show +c'; they could even be mouse-clicks or menu items--whatever suits your +program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + SIGNATURE OF TY COON, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, +you may consider it more useful to permit linking proprietary +applications with the library. If this is what you want to do, use the +GNU Library General Public License instead of this License. + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..592d265 --- /dev/null +++ b/Makefile @@ -0,0 +1,173 @@ +######################################################## +# Makefile automatically generated by Code::Blocks IDE # +######################################################## + +wxWidgetsPath=$(shell dirname `pwd`)/wxBase-2.8.12 +wxXml2Path=$(shell dirname `pwd`)/wxxml2 +wxXml2Lib=$(shell $(wxWidgetsPath)/wx-config --basename | sed 's/wx\_/wxcode_/')_wxxml2-$(shell $(wxWidgetsPath)/wx-config --release) + +### Variables used in this Makefile +default_CC=$(shell $(wxWidgetsPath)/wx-config --cc) +default_CPP=$(shell $(wxWidgetsPath)/wx-config --cxx) +default_LD=$(shell $(wxWidgetsPath)/wx-config --ld | sed 's/-shared//') +default_LIB= + +### Compiler/linker options +default_GLOBAL_CFLAGS=-g +default_PROJECT_CFLAGS=$(shell $(wxWidgetsPath)/wx-config --cppflags) +default_PROJECT_CFLAGS+= -Wall -Wextra -pipe -fno-pcc-struct-return -fno-rtti -fno-exceptions -DwxUSE_UNICODE=1 -D_X86_ +default_GLOBAL_LDFLAGS= +default_PROJECT_LDFLAGS= +default_GLOBAL_INCS= -I$(wxXml2Path)/include -I/usr/include -I/usr/include/libxml2 +default_PROJECT_INCS= +default_GLOBAL_LIBDIRS= +default_PROJECT_LIBDIRS= +default_GLOBAL_LIBS= +default_PROJECT_LIBS=$(shell $(wxWidgetsPath)/wx-config --libs) -L$(wxXml2Path)/lib -Wl,-rpath,$(wxXml2Path)/lib -l:lib$(wxXml2Lib).so.0 -lxml2 + +### Targets compiler flags +default_CFLAGS= $(default_PROJECT_CFLAGS) $(default_GLOBAL_CFLAGS) + +### Targets linker flags +default_LDFLAGS= $(default_PROJECT_LDFLAGS) $(default_GLOBAL_LDFLAGS) + +### Targets include directories +default_INCS= $(default_PROJECT_INCS) $(default_GLOBAL_INCS) + +### Targets library directories +default_LIBDIRS= $(default_PROJECT_LIBDIRS) $(default_GLOBAL_LIBDIRS) + +### Targets libraries +default_LIBS= $(default_PROJECT_LIBS) $(default_GLOBAL_LIBS) + +############################################################################### +# You shouldn't need to modify anything beyond this point # +############################################################################### + +### Resources used in this Makefile +default_RESOURCE= + +### Objects used in this Makefile +default_OBJS=.objs/crc32.o .objs/base64.o .objs/tsapp.o .objs/tschannel.o \ + .objs/tsclient.o .objs/tscommand.o .objs/tsconnectionthread.o \ + .objs/tsquerythread.o .objs/tsplayer.o .objs/tsserver.o \ + .objs/wxstreamex.o .objs/wxbufferex.o +default_LINKOBJS=$(default_OBJS) +default_DEPS=.deps/crc32.d .deps/base64.d .deps/tsapp.d .deps/tschannel.d \ + .deps/tsclient.d .deps/tscommand.d .deps/tsconnectionthread.d \ + .deps/tsquerythread.d .deps/tsplayer.d .deps/tsserver.d \ + .deps/wxstreamex.d .deps/wxbufferex.d + +### The targets of this project +default_BIN=tsclient + +.PHONY: all all-before all-custom all-after clean clean-custom distclean distclean-custom depend_default default-before default-after + +all: all-before default all-after + + +dist: + @zip tsclient.zip Makefile crc32.cpp crc32.h base64.c base64.h tsapp.cpp \ + tsapp.h tschannel.cpp tschannel.h tsclient.cpp tsclient.h tscommand.cpp \ + tscommand.h tsconnectionthread.cpp tsconnectionthread.h tsplayer.cpp \ + tsplayer.h tsserver.cpp tsserver.h wxstreamex.cpp wxstreamex.h + +clean_default: + $(RM) $(default_BIN) $(default_OBJS) $(default_RESOURCE) + +distclean_default: + $(RM) $(default_BIN) $(default_OBJS) $(default_DEPS) $(default_RESOURCE) + +clean: clean_default + +distclean: distclean_default + +depend_default_DIRS: + -@if [ ! -e .deps ]; then mkdir .deps; fi + +depend_default: depend_default_DIRS $(default_DEPS) + +depend: depend_default + +default_DIRS: + -@if [ ! -e .objs ]; then mkdir .objs; fi + +default: depend_default default_DIRS default-before $(default_BIN) default-after + +$(default_BIN): $(default_LINKOBJS) $(default_RESOURCE) + $(default_LD) $(default_LIBDIRS) $(default_BIN) $(default_LINKOBJS) $(default_RESOURCE) $(default_LDFLAGS) $(default_LIBS) + +tsheaders=tschannel.h tsclient.h tscommand.h tsconnectionthread.h tsheaders.h \ + tsplayer.h tsserver.h + +.deps/crc32.d: crc32.cpp crc32.h + $(default_CPP) -MM $(default_CFLAGS) -MF .deps/crc32.d -MT .objs/crc32.o $(default_INCS) crc32.cpp + +.objs/crc32.o: .deps/crc32.d + $(default_CPP) $(default_CFLAGS) $(default_INCS) -c crc32.cpp -o .objs/crc32.o + +.deps/base64.d: base64.cpp base64.h + $(default_CPP) -MM $(default_CFLAGS) -MF .deps/base64.d -MT .objs/base64.o $(default_INCS) base64.cpp + +.objs/base64.o: .deps/base64.d + $(default_CPP) $(default_CFLAGS) $(default_INCS) -c base64.cpp -o .objs/base64.o + +.deps/tsapp.d: tsapp.cpp tsapp.h $(tsheaders) tsquerythread.h + $(default_CPP) -MM $(default_CFLAGS) -MF .deps/tsapp.d -MT .objs/tsapp.o $(default_INCS) tsapp.cpp + +.objs/tsapp.o: .deps/tsapp.d + $(default_CPP) $(default_CFLAGS) $(default_INCS) -c tsapp.cpp -o .objs/tsapp.o + +.deps/tschannel.d: tschannel.cpp $(tsheaders) + $(default_CPP) -MM $(default_CFLAGS) -MF .deps/tschannel.d -MT .objs/tschannel.o $(default_INCS) tschannel.cpp + +.objs/tschannel.o: .deps/tschannel.d + $(default_CPP) $(default_CFLAGS) $(default_INCS) -c tschannel.cpp -o .objs/tschannel.o + +.deps/tsclient.d: tsclient.cpp $(tsheaders) tsserver.h + $(default_CPP) -MM $(default_CFLAGS) -MF .deps/tsclient.d -MT .objs/tsclient.o $(default_INCS) tsclient.cpp + +.objs/tsclient.o: .deps/tsclient.d + $(default_CPP) $(default_CFLAGS) $(default_INCS) -c tsclient.cpp -o .objs/tsclient.o + +.deps/tscommand.d: tscommand.cpp $(tsheaders) crc32.h wxbufferex.h wxstreamex.h + $(default_CPP) -MM $(default_CFLAGS) -MF .deps/tscommand.d -MT .objs/tscommand.o $(default_INCS) tscommand.cpp + +.objs/tscommand.o: .deps/tscommand.d + $(default_CPP) $(default_CFLAGS) $(default_INCS) -c tscommand.cpp -o .objs/tscommand.o + +.deps/tsconnectionthread.d: tsconnectionthread.cpp $(tsheaders) wxbufferex.h + $(default_CPP) -MM $(default_CFLAGS) -MF .deps/tsconnectionthread.d -MT .objs/tsconnectionthread.o $(default_INCS) tsconnectionthread.cpp + +.objs/tsconnectionthread.o: .deps/tsconnectionthread.d + $(default_CPP) $(default_CFLAGS) $(default_INCS) -c tsconnectionthread.cpp -o .objs/tsconnectionthread.o + +.deps/tsquerythread.d: tsquerythread.cpp tsquerythread.h $(tsheaders) base64.h wxbufferex.h + $(default_CPP) -MM $(default_CFLAGS) -MF .deps/tsquerythread.d -MT .objs/tsquerythread.o $(default_INCS) tsquerythread.cpp + +.objs/tsquerythread.o: .deps/tsquerythread.d + $(default_CPP) $(default_CFLAGS) $(default_INCS) -c tsquerythread.cpp -o .objs/tsquerythread.o + +.deps/tsplayer.d: tsplayer.cpp $(tsheaders) + $(default_CPP) -MM $(default_CFLAGS) -MF .deps/tsplayer.d -MT .objs/tsplayer.o $(default_INCS) tsplayer.cpp + +.objs/tsplayer.o: .deps/tsplayer.d + $(default_CPP) $(default_CFLAGS) $(default_INCS) -c tsplayer.cpp -o .objs/tsplayer.o + +.deps/tsserver.d: tsserver.cpp tsserver.h + $(default_CPP) -MM $(default_CFLAGS) -MF .deps/tsserver.d -MT .objs/tsserver.o $(default_INCS) tsserver.cpp + +.objs/tsserver.o: .deps/tsserver.d + $(default_CPP) $(default_CFLAGS) $(default_INCS) -c tsserver.cpp -o .objs/tsserver.o + +.deps/wxstreamex.d: wxstreamex.cpp wxbufferex.h + $(default_CPP) -MM $(default_CFLAGS) -MF .deps/wxstreamex.d -MT .objs/wxstreamex.o $(default_INCS) wxstreamex.cpp + +.objs/wxstreamex.o: .deps/wxstreamex.d + $(default_CPP) $(default_CFLAGS) $(default_INCS) -c wxstreamex.cpp -o .objs/wxstreamex.o + +.deps/wxbufferex.d: wxbufferex.cpp wxstreamex.h + $(default_CPP) -MM $(default_CFLAGS) -MF .deps/wxbufferex.d -MT .objs/wxbufferex.o $(default_INCS) wxbufferex.cpp + +.objs/wxbufferex.o: .deps/wxbufferex.d + $(default_CPP) $(default_CFLAGS) $(default_INCS) -c wxbufferex.cpp -o .objs/wxbufferex.o diff --git a/base64.cpp b/base64.cpp new file mode 100644 index 0000000..38837fe --- /dev/null +++ b/base64.cpp @@ -0,0 +1,126 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +//Header +#include "base64.h" + +//Libraries +#include + +static const wxString base64_chars = + _T("ABCDEFGHIJKLMNOPQRSTUVWXYZ") + _T("abcdefghijklmnopqrstuvwxyz") + _T("0123456789+/"); + + +static inline bool is_base64(unsigned char c) +{ + return (isalnum(c) || (c == '+') || (c == '/')); +} + +wxString Base64Encode(char const* bytes_to_encode, unsigned int in_len) +{ + wxString ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) + { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; i < 4; i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) + { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; j < i + 1; j++) + ret += base64_chars[char_array_4[j]]; + + while(i++ < 3) + ret += '='; + } + + return ret; + +} + +wxString Base64Decode(wxString const& encoded_string) +{ + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + wxString ret; + + while (in_len-- && encoded_string[in_] != '=' && is_base64(encoded_string[in_])) + { + char_array_4[i++] = encoded_string[in_]; + in_++; + if (i ==4) + { + for (i = 0; i < 4; i++) + char_array_4[i] = base64_chars.find(char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; i < 3; i++) + ret += char_array_3[i]; + i = 0; + } + } + + if (i) + { + for (j = i; j < 4; j++) + char_array_4[j] = 0; + + for (j = 0; j < 4; j++) + char_array_4[j] = base64_chars.find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; j < i - 1; j++) + ret += char_array_3[j]; + } + + return ret; +} + diff --git a/base64.h b/base64.h new file mode 100644 index 0000000..15a34a0 --- /dev/null +++ b/base64.h @@ -0,0 +1,27 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +#ifndef BASE64_H +#define BASE64_H + +#include + +wxString Base64Encode(char const* , unsigned int len); +wxString Base64Decode(wxString const& s); + +#endif diff --git a/crc32.cpp b/crc32.cpp new file mode 100644 index 0000000..fa4423c --- /dev/null +++ b/crc32.cpp @@ -0,0 +1,166 @@ +/* + * CRC32 + * Written by Julien Couot. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/** + * \file crc32.cpp + * Compute crc32. + */ + +//--------------------------------------------------------------------------- +// For compilers that support precompilation, includes "wx.h". +#include + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +// Include your minimal set of headers here, or wx.h +#include +#endif + +#include "crc32.h" + +//--------------------------------------------------------------------------- + +// Table used to compute the CRC32 value. +const wxUint32 CRC32::crc_table[256] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d +}; +//--------------------------------------------------------------------------- + +/* + * Default constructor. + */ +CRC32::CRC32() +{ + reset(); +} + +//--------------------------------------------------------------------------- + +/* + * Resets the CRC32 to initial value. + */ +void CRC32::reset() +{ + crc32 = 0xffffffff; +} + +//--------------------------------------------------------------------------- + +/* + * Returns the CRC32 value. + */ +wxUint32 CRC32::getUint32Value() const +{ + return crc32 ^ 0xffffffff; +} + +//--------------------------------------------------------------------------- + +/* + * Returns the checksum value in a string. + * + * @param hexInUpperCase If true the hexadecimal letters will + * be in uppercase. + * @return The current checksum value. + */ +wxString CRC32::getValue(const bool hexInUpperCase) const +{ + wxString h; + if(hexInUpperCase) + h = wxString(_T("%08X")); + else + h = wxString(_T("%08x")); + + return wxString::Format(h, getUint32Value()); +} + +//--------------------------------------------------------------------------- + +/* + * Updates the CRC32 with specified array of bytes. + */ +void CRC32::update(const wxByte *buf, unsigned int len) +{ + if(buf == NULL || len == 0) + return; + + do + { + crc32 = crc_table[(crc32 ^ (*buf++)) & 0xff] ^ (crc32 >> 8); + } + while(--len); +} + +//--------------------------------------------------------------------------- + diff --git a/crc32.h b/crc32.h new file mode 100644 index 0000000..6114d96 --- /dev/null +++ b/crc32.h @@ -0,0 +1,108 @@ +/* + * CRC32 + * Written by Julien Couot. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/** + * \file crc32.h + * Compute crc32. + */ + +#ifndef CRC32_H +#define CRC32_H + +//--------------------------------------------------------------------------- +// For compilers that support precompilation, includes "wx.h". +#include + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +// Include your minimal set of headers here, or wx.h +#include +#endif + +//--------------------------------------------------------------------------- + + +/** + * Computes the CRC-32 from a byte stream. + * + * This class is writen with the code found in + * cksfv and + * zlib code. + * + * Using this class in very simple:
+ * Use the @link update(const wxByte* buf, unsigned int len) update @endlink + * method to provide to the class the bytes for computing the checksum. + * + * The CRC-32 checksum value can be gotten by the @link getValue(const bool) const + * getValue @endlink method which puts the CRC32 checksum value in a + * unsigned 32 bits integer. + * + * The CRC32 checksum computing can be reseted by the @link reset() reset + * @endlink method. + */ +class CRC32 +{ + protected: + /// Table used to compute the CRC32 value. + static const wxUint32 crc_table[256]; + + /// The current CRC32 value. + wxUint32 crc32; + + public: + /** + * Default constructor. + */ + CRC32(); + + /** + * Resets the CRC32 to initial value. + */ + void reset(); + + /** + * Returns the CRC32 value. + * + * @return The current checksum value. + */ + wxUint32 getUint32Value() const; + + /** + * Returns the CRC32 value in a string. + * + * @param hexInUpperCase If true the hexadecimal letters will + * be in uppercase. + * @return The current CRC32 value. + */ + wxString getValue(const bool hexInUpperCase = false) const; + + /** + * Updates the CRC32 with specified array of bytes. + * + * @param buf The byte array to update the CRC32 with. + * @param len The number of bytes to use for the update. + */ + void update(const wxByte *buf, unsigned int len); +}; +//--------------------------------------------------------------------------- + +#endif diff --git a/tsapp.cpp b/tsapp.cpp new file mode 100644 index 0000000..3818b4c --- /dev/null +++ b/tsapp.cpp @@ -0,0 +1,617 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +//Header +#include "tsapp.h" +#include "tsheaders.h" + +//Libraries +#include +#include +#include +#include +#include +#if defined(__UNIX__) +# include +#endif + +//------------------------------------------------------------------------------ +// OnInit +bool TSApp::OnInit() +{ + m_pLog = NULL; + m_pLogFile = NULL; + m_pConfig = NULL; + m_pClient = NULL; + m_pQuery = NULL; + m_ConfigFileName = CONFIG_FILE_NAME; + + if (!wxAppConsole::OnInit()) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +// OnExit +int TSApp::OnExit() +{ + //cleanup + wxAppConsole::OnExit(); + + if(m_pLogFile != NULL && m_pLogFile->IsOpened()) + m_pLogFile->Close(); + + if(m_pLogFile != NULL) + delete m_pLogFile; + m_pLogFile = NULL; + + if(m_pQuery != NULL) + delete m_pQuery; + m_pQuery = NULL; + + if(m_pClient != NULL) + delete m_pClient; + m_pClient = NULL; + + if(m_pConfig != NULL) + delete m_pConfig; + m_pConfig = NULL; + + if(m_pLog != NULL) + delete m_pLog; + m_pLog = NULL; + + if(m_pQuery != NULL) + delete m_pQuery; + m_pQuery = NULL; + + return true; +} + +//------------------------------------------------------------------------------ +// Program entry point, replacment for main() +int TSApp::OnRun() +{ + wxStringOutputStream out; + + //UNIX stuff + #if defined(__UNIX__) + if(!m_Foreground && !m_Interactive) + { + int pid = fork(); + if(pid < 0) + { + wxLogError(_T("can't fork")); + return EXIT_FAILURE; + } + else if(pid != 0) + return EXIT_SUCCESS; + + //detach from tty + if (!m_Logtostderr) + { + //close existing file descriptors + for (int fd = getdtablesize() - 1; fd >= 0; fd--) + close(fd); + + //open stdin on /dev/null + open("/dev/null", O_RDWR); + } + } + #endif + + //welcome message + wxPrintf(_T("TeamSpeak Client v0.3 (c)2006-2013 Clan-Server.at\n")); + + m_pLog->SetTimestamp(_T("[%x %X]")); + wxLog::SetActiveTarget(m_pLog); + wxSocketBase::Initialize(); + + m_pClient = new TSClient; + m_pQuery = new TSQueryThread(m_pClient); + + //load config + if(!LoadConfig(m_ConfigFileName)) + { + wxLogError(_T("can't open config file %s"), m_ConfigFileName.c_str()); + return EXIT_FAILURE; + } + + //open logfile + if(m_pLogFileStr.Length() > 0 && !m_Logtostderr && (m_pLogFile == NULL || !m_pLogFile->IsOpened())) + { + m_pLogFile = new wxFFile(m_pLogFileStr.c_str(), _T("a+")); + if(!m_pLogFile->IsOpened()) + { + wxLogError(_T("can't open logfile '%s'."), m_pLogFileStr.c_str()); + return false; + } + if (m_pLog != NULL) + delete m_pLog; + m_pLog = new wxLogStderr((FILE *)m_pLogFile->fp()); + } + + //start query thread + m_pQuery->Start(); + + //check for interactive mode + if(m_Interactive) + Interactive(); + else + { + while(m_pClient->IsReconnectActive()) + { + if(!m_pClient->IsConnected()) + { + m_pClient->Disconnect(); + //some status info + wxLogMessage(_T("TSServer: connecting to %s:%d..."), + m_pClient->GetServer()->GetServerAddress().c_str(), + m_pClient->GetServer()->GetPort()); + + //connect + if(!m_pClient->Connect()) + { + wxLogError(_T("%s, error connecting."), m_pClient->GetLastError().c_str()); + wxSleep(RECONNECT_TIMEOUT); + } + else + wxLogMessage(_T("TSServer: connection established...")); + } + wxSleep(1); + } + } + + wxLogMessage(_T("TSServer: disconnecting...")); + m_pClient->Disconnect(); + m_pQuery->Stop(); + wxSocketBase::Shutdown(); + wxLogMessage(_T("TSServer: shutting down successful.")); + wxLog::SetActiveTarget(NULL); + return EXIT_SUCCESS; +} + +//------------------------------------------------------------------------------ +// Load config +bool TSApp::LoadConfig(wxString const &filename) +{ + wxString str; + if(!wxFileExists(filename)) + return false; + + m_pConfig = new wxFileConfig(_T("TSDaemon"), + wxEmptyString, + filename, + filename, + wxCONFIG_USE_RELATIVE_PATH); + + m_pConfig->Read(_T("LogFile"), &str, _T("")); + if(m_pLogFileStr.Length() <= 0) + m_pLogFileStr = str; + + //TSClient + m_pConfig->Read(_T("TSPlatform"), &str, _T("Windows XP")); + m_pClient->SetPlatform(str); + + m_pConfig->Read(_T("TSVersionNumber"), &str, _T("2.0.32.60")); + m_pClient->SetVersionNumber(str); + + TSPlayer *pTSP = new TSPlayer; + m_pConfig->Read(_T("TSLoginName"), &str, _T("")); + pTSP->SetLoginName(str); + m_pConfig->Read(_T("TSLoginPassword"), &str, _T("")); + pTSP->SetLoginPassword(str); + m_pConfig->Read(_T("TSNickname"), &str, _T("")); + pTSP->SetNickname(str); + //now the TSClient takes care of the pointer. + m_pClient->SetPlayer(pTSP); + + TSServer *pTSS = new TSServer; + m_pConfig->Read(_T("TSServerAddress"), &str, _T("")); + pTSS->SetServerAddress(str); + long l; + m_pConfig->Read(_T("TSPort"), &l, 0); + if(!pTSS->SetPort(l)) + wxLogError(_T("port, %s"), pTSS->GetLastError().c_str()); + + //now the TSClient takes care of the pointer. + m_pClient->SetServer(pTSS); + + m_pConfig->Read(_T("ServerAddress"), &str, _T("")); + m_pQuery->SetServerAddress(str); + + m_pConfig->Read(_T("AllowedAddresses"), &str, _T("")); + m_pQuery->SetAllowedAddresses(str); + + m_pConfig->Read(_T("Port"), &l, 0); + if(!m_pQuery->SetPort(l)) + wxLogError(_T("port, %s"), m_pQuery->GetLastError().c_str()); + + m_pConfig->Read(_T("Password"), &str, _T("")); + if(!m_pQuery->SetPassword(str)) + wxLogError(_T("password, %s"), m_pQuery->GetLastError().c_str()); + + return true; +} + +//------------------------------------------------------------------------------ +// Set parser line description +void TSApp::OnInitCmdLine(wxCmdLineParser &parser) +{ + //declare CmdLineParser + static const wxCmdLineEntryDesc cmdLineDesc[] = + { + { wxCMD_LINE_SWITCH, _T("h"), _T("help"), _T("show this help message"), + wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP }, + { wxCMD_LINE_SWITCH, _T("i"), _T("interactive"), _T("interactive mode"), + wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, + { wxCMD_LINE_SWITCH, _T("v"), _T("verbose"), _T("be verbose") , + wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL}, + { wxCMD_LINE_SWITCH, _T("q"), _T("quiet"), _T("be quiet") , + wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL}, + #if defined(__UNIX__) + { wxCMD_LINE_SWITCH, _T("f"), _T("foreground"), _T("run in foreground mode"), + wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL}, + #endif + { wxCMD_LINE_SWITCH, _T("g"), _T("logtostderr"), _T("log everything to stderr"), + wxCMD_LINE_VAL_NONE,wxCMD_LINE_PARAM_OPTIONAL}, + { wxCMD_LINE_OPTION, _T("c"), _T("config"), _T("path to config file"), + wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, + { wxCMD_LINE_OPTION, _T("l"), _T("logfile"), _T("path to log file"), + wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, + { wxCMD_LINE_NONE, NULL, NULL, NULL, (wxCmdLineParamType)0, 0 } //ends list + }; + parser.SetDesc(cmdLineDesc); + + //no long options on windows + #ifdef __WINDOWS__ + parser.DisableLongOptions(); + #endif +} + +//------------------------------------------------------------------------------ +// Process command line options +bool TSApp::OnCmdLineParsed(wxCmdLineParser &parser) +{ + m_Interactive = false; + m_Foreground = false; + m_Logtostderr = false; + + /* Create and hook logtarget in */ + if (m_pLog != NULL) + delete m_pLog; + m_pLog = new wxLogStderr(stdout); + + #if defined __UNIX__ + if(parser.Found(_T("f"))) + m_Foreground = true; + else + m_Foreground = false; + #endif + + if(parser.Found(_T("i"))) + { + m_Interactive = true; + #if defined __UNIX__ + m_Foreground = true; + #endif + } + + if(parser.Found(_T("g"))) + { + if (m_pLog != NULL) + delete m_pLog; + m_pLog = new wxLogStderr(stderr); + m_Logtostderr = true; + } + + if(parser.Found(_T("q"))) + m_pLog->SetLogLevel(wxLOG_FatalError); + + if(parser.Found(_T("v"))) + m_pLog->SetVerbose(true); + + wxString str; + if(parser.Found(_T("c"), &str)) + m_ConfigFileName = str; + + if(parser.Found(_T("l"), &str) && m_pLogFileStr.Length() <= 0) + m_pLogFileStr = str; + + return true; +} + +//------------------------------------------------------------------------------ +// Process help (-h) command line option +bool TSApp::OnCmdLineHelp(wxCmdLineParser &parser) +{ + parser.Usage(); + return false; +} + +//------------------------------------------------------------------------------ +// Process command line options errors +bool TSApp::OnCmdLineError(wxCmdLineParser &parser) +{ + parser.Usage(); + return false; +} + +//------------------------------------------------------------------------------ +// ReadString +wxString TSApp::ReadString(wxString const &str) +{ + wxChar cstr[80]; + wxString s; + wxPrintf(_T("%s: "), str.c_str()); + wxScanf(_T("%s"), cstr); + s = cstr; + return s; +} + +//------------------------------------------------------------------------------ +// Interactive mode +bool TSApp::Interactive() +{ + wxStringOutputStream out; + wxChar cstr[80]; + wxString str; + + wxPrintf(_T("Type \"help\" for all commands.\n")); + do + { + wxPrintf(_T(">")); + wxScanf(_T("%s"), cstr); + str = cstr; + //-------------------------------------------------------- + if(str == _T("cl")) + { + wxPrintf(wxString(_T("-"), 40).c_str()); + wxPrintf(_T("\ndumping channels...\n")); + wxPrintf(_T(" total: %d\n"), m_pClient->GetChannels()->GetCount()); + + for(size_t i = 0; i < m_pClient->GetChannels()->GetCount(); i++) + wxPrintf(_T("%.3d %s\n"), i, m_pClient->GetChannels()->Item(i)->GetName().c_str()); + wxPrintf(_T(" total: %d channels\n"), m_pClient->GetChannels()->GetCount()); + } + //-------------------------------------------------------- + else if(str == _T("pl")) + { + wxPrintf(wxString(_T("-"), 40).c_str()); + wxPrintf(_T("\ndumping players...\n")); + wxPrintf(_T(" total: %d\n"), m_pClient->GetPlayers()->GetCount()); + + for(size_t i = 0; i < m_pClient->GetPlayers()->GetCount(); i++) + wxPrintf(_T("%.3d %s\n"), i, m_pClient->GetPlayers()->Item(i)->GetNickname().c_str()); + wxPrintf(_T(" total: %d players\n"), m_pClient->GetPlayers()->GetCount()); + } + //-------------------------------------------------------- + else if(str == _T("pcl")) + { + wxPrintf(wxString(_T("-"), 40).c_str()); + wxPrintf(_T("\ndumping players with channels...\n")); + wxPrintf(_T(" total: %d\n"), m_pClient->GetPlayers()->GetCount()); + + for(size_t i = 0; i < m_pClient->GetPlayers()->GetCount(); i++) + { + wxUint32 chid = m_pClient->GetPlayers()->Item(i)->GetChannelId(); + wxString nick = m_pClient->GetPlayers()->Item(i)->GetNickname(); + wxString chl = _T("error"); + + for(size_t j = 0; j < m_pClient->GetChannels()->GetCount(); j++) + { + if(m_pClient->GetChannels()->Item(j)->GetId() == chid) + { + chl = m_pClient->GetChannels()->Item(j)->GetName(); + break; + } + } + wxPrintf(_T("%.3d %s \t\t %s\n"), i, nick.c_str(), chl.c_str()); + } + wxPrintf(_T(" total: %d players\n"), m_pClient->GetPlayers()->GetCount()); + } + //-------------------------------------------------------- + else if(str == _T("cc")) + { + TSChannel ch; + wxString str; + + wxPrintf(_T("create channel...\n")); + ch.SetName(ReadString(_T("Name"))); + ch.SetTopic(ReadString(_T("Topic"))); + ch.SetDescription(ReadString(_T("Description"))); + str = ReadString(_T("Password ('.' no pass)")); + if(str != _T(".")) + ch.SetPassword(str); + ch.SetFlags(ReadString(_T("Flags"))); + + if(m_pClient->CreateChannel(&ch)) + wxPrintf(_T("channel created\n")); + else + wxLogError(_T("%s"),m_pClient->GetLastError().c_str()); + } + //-------------------------------------------------------- + else if(str == _T("mc")) + { + TSChannel ch; + TSChannel *pChl; + wxString s,str; + wxPrintf(_T("modify channel...\n")); + + s = ReadString(_T("Name")); + pChl = m_pClient->FindChannel(s); + if(pChl == NULL) + { + wxPrintf(_T("channel not found\n")); + } + else + { + wxPrintf(_T("edit channel\n")); + ch.SetId(pChl->GetId()); + ch.SetName(ReadString(_T("Name"))); + ch.SetTopic(ReadString(_T("Topic"))); + ch.SetDescription(ReadString(_T("Description"))); + str = ReadString(_T("Password ('.' no pass)")); + if(str != _T(".")) + ch.SetPassword(str); + ch.SetFlags(ReadString(_T("Flags"))); + + if(m_pClient->ModifyChannel(&ch)) + wxPrintf(_T("channel modified\n")); + else + wxLogError(_T("%s"),m_pClient->GetLastError().c_str()); + } + } + //-------------------------------------------------------- + else if(str == _T("dc")) + { + wxString s; + TSChannel *pChl; + + wxPrintf(_T("delete channel...\n")); + s = ReadString(_T("Name")); + + pChl = m_pClient->FindChannel(s); + if(pChl == NULL) + { + wxPrintf(_T("channel not found\n")); + } + else + { + if(m_pClient->DeleteChannel(pChl)) + wxPrintf(_T("channel deleted\n")); + else + wxLogError(_T("%s"),m_pClient->GetLastError().c_str()); + } + } + //-------------------------------------------------------- + else if(str == _T("mv")) + { + wxString s; + TSPlayer ply; + TSPlayer *pPly; + TSChannel *pChl; + + wxPrintf(_T("move player...\n")); + s = ReadString(_T("Name")); + + pPly = m_pClient->FindPlayer(s); + if(pPly == NULL) + { + wxPrintf(_T("player not found\n")); + } + else + { + s = ReadString(_T("Channel")); + pChl = m_pClient->FindChannel(s); + if(pChl == NULL) + { + wxPrintf(_T("channel not found\n")); + } + else + { + ply.SetId(pPly->GetId()); + ply.SetChannelId(pChl->GetId()); + + if(m_pClient->MovePlayer(&ply)) + wxPrintf(_T("player moved\n")); + else + wxLogError(_T("%s"),m_pClient->GetLastError().c_str()); + } + } + } + //-------------------------------------------------------- + else if(str == _T("kick")) + { + wxString s; + TSPlayer ply; + TSPlayer *pPly; + + wxPrintf(_T("kick player...\n")); + s = ReadString(_T("Name")); + + pPly = m_pClient->FindPlayer(s); + if(pPly == NULL) + { + wxPrintf(_T("player not found\n")); + } + else + { + s = ReadString(_T("Message")); + + ply.SetId(pPly->GetId()); + + if(m_pClient->KickPlayer(&ply,s)) + wxPrintf(_T("player kicked\n")); + else + wxLogError(_T("%s"),m_pClient->GetLastError().c_str()); + } + + } + //-------------------------------------------------------- + else if(str == _T("exit")) + break; + //-------------------------------------------------------- + else if(str == _T("dump")) + { + m_pClient->Dump(out); + wxPrintf(_T("%s"), out.GetString().c_str()); + } + //-------------------------------------------------------- + else if(str == _T("connect")) + { + m_pClient->Disconnect(); + wxPrintf(_T("connecting...\n")); + if(!m_pClient->Connect()) + wxLogError(_T("%s, terminating."), m_pClient->GetLastError().c_str()); + else + wxPrintf(_T("connected\n")); + } + //-------------------------------------------------------- + else if(str == _T("disconnect")) + { + if(!m_pClient->Disconnect()) + wxLogError(_T("%s, terminating."), m_pClient->GetLastError().c_str()); + else + wxPrintf(_T("disconnected\n")); + } + //-------------------------------------------------------- + else if(str == _T("help")) + { + wxPrintf(_T("pl show player list\n")); + wxPrintf(_T("cl show channel list\n")); + wxPrintf(_T("pcl player with channel list\n")); + wxPrintf(_T("cc create channel\n")); + wxPrintf(_T("dc delete channel\n")); + wxPrintf(_T("mv move player\n")); + wxPrintf(_T("kick kick player\n")); + wxPrintf(_T("mc modify channel\n")); + wxPrintf(_T("connect connect to server\n")); + wxPrintf(_T("disconnect disconnect from server\n")); + wxPrintf(_T("dump full object dump\n")); + wxPrintf(_T("exit exit application\n")); + } + } while(1); + + return true; +} + +//makes the application class known to wxWidgets for dynamic construction +IMPLEMENT_APP_CONSOLE(TSApp) + diff --git a/tsapp.h b/tsapp.h new file mode 100644 index 0000000..57de48c --- /dev/null +++ b/tsapp.h @@ -0,0 +1,77 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +#ifndef TSAPP_H +#define TSAPP_H + +//libraries +#include "tsclient.h" +#include "tsquerythread.h" + +#include +#include +#include + + +//config file name +#define CONFIG_FILE_NAME _T("tsclient.cfg") +//! Timeout for reconnect sec +#define RECONNECT_TIMEOUT 10 + +//Main application class +class TSApp : public wxAppConsole +{ + public: + //main() replacment + virtual int OnRun(); + //app cleanup + virtual int OnExit(); + //app init + virtual bool OnInit(); + //Command line parser + virtual void OnInitCmdLine(wxCmdLineParser &parser); + virtual bool OnCmdLineParsed(wxCmdLineParser &parser); + virtual bool OnCmdLineHelp(wxCmdLineParser &parser); + virtual bool OnCmdLineError(wxCmdLineParser &parser); + //interactive mode + bool Interactive(); + //load config + bool LoadConfig(wxString const &filename); + + private: + wxString ReadString(wxString const &str); + + wxLogStderr *m_pLog; + wxFFile *m_pLogFile; + wxString m_pLogFileStr; + TSClient *m_pClient; + TSQueryThread*m_pQuery; + wxFileConfig *m_pConfig; + bool m_Interactive; + bool m_Logtostderr; + #if defined __UNIX__ + bool m_Foreground; + #endif + wxString m_ConfigFileName; +}; + +//create a forward declaration of the wxGetApp +//function implemented by IMPLEMENT_APP +DECLARE_APP(TSApp) + +#endif diff --git a/tschannel.cpp b/tschannel.cpp new file mode 100644 index 0000000..d5530d1 --- /dev/null +++ b/tschannel.cpp @@ -0,0 +1,199 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +// Header +#include "tschannel.h" + +//Libraries +#include + +IMPLEMENT_CLASS(TSChannel, wxObject) + +//------------------------------------------------------------------------------ +// Default CTor, Initializes the object. +TSChannel::TSChannel() +{ + m_Id = 0; + m_Parent = TS_NO_PARENT; + m_Codec = 0; + m_Order = 3200; + m_Flags = 1; + m_MaxUsers = 4; + m_Users = 0; +} + +//------------------------------------------------------------------------------ +// Default DTor. +TSChannel::~TSChannel() +{ +} + +//------------------------------------------------------------------------------ +// Sets the channel Id. +bool TSChannel::SetId(wxUint32 const id) +{ + m_Id = id; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the channel name. +bool TSChannel::SetName(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("empty string")); + return false; + } + + m_Name = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the channel topic. +bool TSChannel::SetTopic(wxString const &str) +{ + m_Topic = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the channel description. +bool TSChannel::SetDescription(wxString const &str) +{ + m_Description = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the channel password. +bool TSChannel::SetPassword(wxString const &str) +{ + if(str.Length() != 0) + m_Flags |= TS_PASSWORD; + else + m_Flags &= ~TS_PASSWORD; + + m_Password = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the channel parent. +bool TSChannel::SetParent(wxUint32 const parent) +{ + m_Parent = parent; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the channel codec. +bool TSChannel::SetCodec(wxUint16 const codec) +{ + m_Codec = codec; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the channel order. +bool TSChannel::SetOrder(wxUint16 const order) +{ + m_Order = order; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the channel flags. +bool TSChannel::SetFlags(wxString const &str) +{ + wxUint16 flags = 1; + + if(str.Find(wxChar('R')) != wxNOT_FOUND) + flags &= ~TS_UNREGISTRED; + else + flags |= TS_UNREGISTRED; + + if(str.Find(wxChar('M')) != wxNOT_FOUND) + flags |= TS_MODERATE; + else + flags &= ~TS_MODERATE; + + if(str.Find(wxChar('S')) != wxNOT_FOUND) + flags |= TS_HIERARCHICAL; + else + flags &= ~TS_HIERARCHICAL; + + if(str.Find(wxChar('D')) != wxNOT_FOUND) + flags |= TS_DEFAULT; + else + flags &= ~TS_DEFAULT; + + if(str.Find(wxChar('P')) != wxNOT_FOUND || m_Password.Length() != 0) + flags |= TS_PASSWORD; + else + flags &= ~TS_PASSWORD; + + m_Flags = flags; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the channel flags. +bool TSChannel::SetFlags(wxUint16 const flags) +{ + m_Flags = flags; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the channels maximum users count. +bool TSChannel::SetMaxUsers(wxUint16 const users) +{ + m_MaxUsers = users; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the channels users count. +bool TSChannel::SetUsers(wxUint16 const users) +{ + m_Users = users; + return true; +} + +//------------------------------------------------------------------------------ +// Dumps object. +void TSChannel::Dump(wxOutputStream &ostrm) const +{ + wxTextOutputStream out(ostrm); + out << _T("Object: TSChannel (") << wxString::Format(_T("0x%X"), this) << _T(")") << endl; + out << _T("-wxUint32 m_Id: ") << wxString::Format(_T("0x%X"), m_Id) << endl; + out << _T("-wxString m_Name: ") << m_Name << endl; + out << _T("-wxString m_Topic: ") << m_Topic << endl; + out << _T("-wxString m_Description: ") << m_Description << endl; + out << _T("-wxString m_Password: ") << m_Password << endl; + out << _T("-wxUint32 m_Parent: ") << wxString::Format(_T("0x%X"), m_Parent) << endl; + out << _T("-wxUint16 m_Codec: ") << wxString::Format(_T("0x%X"), m_Codec) << endl; + out << _T("-wxUint16 m_Order: ") << wxString::Format(_T("0x%X"), m_Order) << endl; + out << _T("-wxUint16 m_Flags: ") << wxString::Format(_T("0x%X"), m_Flags) << endl; + out << _T("-wxUint16 m_MaxUsers: ") << wxString::Format(_T("0x%X"), m_MaxUsers) << endl; + out << _T("-wxUint16 m_Users: ") << wxString::Format(_T("0x%X"), m_Users) << endl; + out << _T("-wxString m_LastError: ") << m_LastError << endl; +} + diff --git a/tschannel.h b/tschannel.h new file mode 100644 index 0000000..a1b3855 --- /dev/null +++ b/tschannel.h @@ -0,0 +1,371 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +#ifndef TSCHANNEL_H +#define TSCHANNEL_H + +#include "tsheaders.h" + +// Libraries +#include + +//------------------------------------------------------------------------------ +//! Channel flags +//! Unregistered: +#define TS_UNREGISTRED 1 +//! Moderated: +#define TS_MODERATE 2 +//! Password: +#define TS_PASSWORD 4 +//! Hierarchical aka Subchannels: +#define TS_HIERARCHICAL 8 +//! Default: +#define TS_DEFAULT 16 + +//------------------------------------------------------------------------------ +//! Channel Codecs +//! CELP 5.2 +#define TS_CELP_5_2 0 +//! CELP 6.3 +#define TS_CELP_6_3 1 +//! GSM 14.8 +#define TS_GSM_14_8 2 +//! GSM 16.4 +#define TS_GSM_16_4 3 +//! Windows CELP 5.2 +#define TS_WINDOWS_CELP_5_2 4 +//! Speex 3.4 +#define TS_SPEEX_3_4 5 +//! Speex 5.2 +#define TS_SPEEX_5_2 6 +//! Speex 7.2 +#define TS_SPEEX_7_2 7 +//! Speex 9.3 +#define TS_SPEEX_9_3 8 +//! Speex 12.3 +#define TS_SPEEX_12_3 9 +//! Speex 16.3 +#define TS_SPEEX_16_3 10 +//! Speex 19.5 +#define TS_SPEEX_19_5 11 +//! Speex 25.9 +#define TS_SPEEX_25_9 12 + +//!no parent channel +#define TS_NO_PARENT 0xffffffff + +//! TeamSpeak channel. +/*! TSChanel is used to hold all channel informations. + * After calling TSClient::Connect(), you can read + * out all the channel attributes. These stepps are + * necessary to connect to a server and read all information + * out. + * - Create a TSServer object,edit and link it to the TSClient object + * (For more information see TSClient) + * - Call TSClient::Connect() + * - Call TSClient::GetChannel() or GetChannels() + * - Now the class is filled up with the player information + */ +class TSChannel : public wxObject +{ + DECLARE_CLASS(TSChannel) + public: + + /*! Default CTor, Initializes the object. + */ + TSChannel(); + + /*! Default DTor. + */ + ~TSChannel(); + + /*! Sets the channel Id. + * \param id channel Id. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetId(wxUint32 const id); + + /*! Sets the channel name. + * \param str Channel name. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetName(wxString const &str); + + /*! Sets the channel topic. + * \param str Channel topic. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetTopic(wxString const &str); + + /*! Sets the channel description. + * \param str Channel description. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetDescription(wxString const &str); + + /*! Sets the channel password. + * \param str Channel password. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetPassword(wxString const &str); + + /*! Sets the channel parent. + * \param parent Channel parent. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetParent(wxUint32 const parent); + + /*! Sets the channel codec. + * - CELP 5.2: 0 + * - CELP 6.3: 1 + * - GSM 14.8: 2 + * - GSM 16.4: 3 + * - Windows CELP 5.2: 4 + * - Speex 3.4: 5 + * - Speex 5.2: 6 + * - Speex 7.2: 7 + * - Speex 9.3: 8 + * - Speex 12.3: 9 + * - Speex 16.3: 10 + * - Speex 19.5: 11 + * - Speex 25.9: 12 + * \param codec Channel codec. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetCodec(wxUint16 const codec); + + /*! Sets the channel order. + * \param order Channel order. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetOrder(wxUint16 const order); + + /*! Sets the channel flags. + * - Unregistered: 1 + * - Moderated: 2 + * - Password: 4 + * - Hierarchical: 8 + * - Default: 16 + * \param flags Channel flags. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetFlags(wxUint16 const flags); + + /*! Sets the channel flags. + * - Registered: R + * - Moderated: M + * - Password: P + * - Hierarchical: S + * - Default: D + * \param flags Channel flags. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetFlags(wxString const &str); + + /*! Sets the channels maximum users count. + * \param users Channel maximum users count. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetMaxUsers(wxUint16 const users); + + /*! Sets the channels users count. + * \param users Channel maximum users count. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetUsers(wxUint16 const users); + + /*! Gets the channel id. + * \return Channel Id. + */ + wxUint32 GetId() const + { + return m_Id; + } + + /*! Gets the channel name. + * \return Channel name. + */ + wxString const &GetName() const + { + return m_Name; + } + + /*! Gets the channel topic. + * \return Channel topic. + */ + wxString const &GetTopic() const + { + return m_Topic; + } + + /*! Gets the channel description. + * \return Channel description. + */ + wxString const &GetDescription() const + { + return m_Description; + } + + /*! Gets the channel password. + * \return Channel password. + */ + wxString const &GetPassword() const + { + return m_Password; + } + + /*! Gets the channel parent. + * \return Channel parent. + */ + wxUint32 GetParent() const + { + return m_Parent; + } + + /*! Gets the channel codec. + * - CELP 5.2: 0 + * - CELP 6.3: 1 + * - GSM 14.8: 2 + * - GSM 16.4: 3 + * - Windows CELP 5.2: 4 + * - Speex 3.4: 5 + * - Speex 5.2: 6 + * - Speex 7.2: 7 + * - Speex 9.3: 8 + * - Speex 12.3: 9 + * - Speex 16.3: 10 + * - Speex 19.5: 11 + * - Speex 25.9: 12 + * \return Channel codec. + */ + wxUint16 GetCodec() const + { + return m_Codec; + } + + /*! Gets the channel order. + * \return Channel order. + */ + wxUint16 GetOrder() const + { + return m_Order; + } + + /*! Gets the channel flags. + * - Unregistered: 1 + * - Moderated: 2 + * - Password: 4 + * - Hierarchical: 8 + * - Default: 16 + * \return Channel flags. + */ + wxUint16 GetFlags() const + { + return m_Flags; + } + + /*! Gets the channel flags. + * - Unregistered: 1 + * - Moderated: 2 + * - Password: 4 + * - Hierarchical: 8 + * - Default: 16 + * \return Channel flags. + */ + wxString const GetFlagsString() const + { + wxString str; + if((m_Flags &TS_MODERATE)) + str += _T("M"); + if((m_Flags &TS_DEFAULT)) + str += _T("D"); + if((m_Flags &TS_HIERARCHICAL)) + str += _T("S"); + if((m_Flags &TS_PASSWORD)) + str += _T("P"); + if(!(m_Flags &TS_UNREGISTRED)) + str += _T("R"); + return str; + } + /*! Gets the channel max users. + * \return Channel max users. + */ + wxUint16 GetMaxUsers() const + { + return m_MaxUsers; + } + + /*! Gets the channel user count. + * \return Channel user count. + */ + wxUint16 GetUsers() const + { + return m_Users; + } + + /*! Gets the LastError message, call this method + * to get more information for an error. + * \return LastError message. + */ + wxString const &GetLastError() const + { + return m_LastError; + } + + /*! Dumps object. + * \param ostrm Stream to write. + */ + void Dump(wxOutputStream &ostrm) const; + + + private: + + //Sets the LastError message. + void SetLastError(wxString const &str) + { + m_LastError = str; + } + + //members + wxUint32 m_Id; + wxString m_Name; + wxString m_Topic; + wxString m_Description; + wxString m_Password; + wxUint32 m_Parent; + wxUint16 m_Codec; + wxUint16 m_Order; + wxUint16 m_Flags; + wxUint16 m_MaxUsers; + wxUint16 m_Users; + wxString m_LastError; +}; + +#endif diff --git a/tsclient.cfg b/tsclient.cfg new file mode 100644 index 0000000..218756f --- /dev/null +++ b/tsclient.cfg @@ -0,0 +1,52 @@ +#******************************************* +# TeamSpeak daemon +# (c)2005 clan-server.at +#******************************************* + +#------------------------------------------- +# TeamSpeak client scecific settings +#------------------------------------------- + +# TeamSpeak client Platform description +TSPlatform = Windows XP + +# TeamSpeak client version number (e.g. "2.0.32.60") +TSVersionNumber = 2.0.32.60 + +# TeamSpeak player login name +# If string is empty, login as anonymous. +TSLoginName = username + +# TeamSpeak player password +TSLoginPassword = password + +# TeamSpeak player nickname +TSNickname = tsdaemon + +# TeamSpeak server IP address or URL +TSServerAddress = localhost + +# TeamSpeak server port +TSPort = 8767 + +#------------------------------------------- +# TeamSpeak daemon scecific settings +#------------------------------------------- + +#Daemon logfile +#if string is empty, no logfile. +LogFile = tsclient.log + +# Daemon host address, can be IP or URL +# If string is empty or 0.0.0.0, bind to any interfaces. +ServerAddress = 0.0.0.0 + +# Daemon allowed IP-Addresses +# Separate with ',' +AllowedAddresses = 127.0.0.1 + +# Daemon listening port +Port = 54321 + +# Daemon password +Password = daemon_password diff --git a/tsclient.cpp b/tsclient.cpp new file mode 100644 index 0000000..95f7e53 --- /dev/null +++ b/tsclient.cpp @@ -0,0 +1,760 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +// Header +#include "tsclient.h" + +//Libraries +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +IMPLEMENT_CLASS(TSClient, wxObject) +IMPLEMENT_CLASS(TSCmd, wxObject) + +//------------------------------------------------------------------------------ +// Default CTor, Initializes the object. +TSClient::TSClient() +{ + //create all objects + m_pMutex = new wxMutex; + m_pPlayer = new TSPlayer; + m_ppPlayers = new TSpPlayerArray; + m_pChannel = new TSChannel; + m_ppChannels = new TSpChannelArray; + m_pConnection = NULL; + m_pServer = new TSServer; + m_pSync = NULL; + m_VersionNumber = _T("0.0.0.0"); + m_Platform = _T("na"); + m_LastError = _T(""); + m_SessionId = 0; + m_pReconnectAct = true; +} + +//------------------------------------------------------------------------------ +// Default DTor. +TSClient::~TSClient() +{ + //do the necessary cleanup + wxASSERT(m_pPlayer != NULL); + delete m_pPlayer; + m_pPlayer = NULL; + + for(size_t i = 0; i < m_ppPlayers->GetCount(); i++) + { + wxASSERT(m_ppPlayers != NULL); + delete m_ppPlayers->Item(i); + } + + for(size_t i = 0; i < m_ppChannels->GetCount(); i++) + { + wxASSERT(m_ppChannels != NULL); + delete m_ppChannels->Item(i); + } + + wxASSERT(m_ppPlayers != NULL); + delete m_ppPlayers; + m_ppPlayers = NULL; + + wxASSERT(m_pChannel != NULL); + delete m_pChannel; + m_pChannel = NULL; + + wxASSERT(m_ppChannels != NULL); + delete m_ppChannels; + m_ppChannels = NULL; + + wxASSERT(m_pServer != NULL); + delete m_pServer; + m_pServer = NULL; + + if(m_pConnection != NULL) + { + delete m_pConnection; + m_pConnection = NULL; + } +} + +//------------------------------------------------------------------------------ +// Send a command to a Teasmpeak server. +bool TSClient::SendCommand(wxUint32 cmd) +{ + TSCmd sync; + sync.id = cmd; + sync.error = false; + sync.client = this; + return SendCommand(&sync); +} + +//------------------------------------------------------------------------------ +// Send a command to a Teamspeak server. +bool TSClient::SendCommand(TSCmd *cmd) +{ + if(!m_pConnection->IsAlive()) + { + SetLastError(_T("thread not running")); + return false; + } + + m_pMutex->Lock(); + + m_Lock = true; + m_pSync = cmd; + + m_pMutex->Unlock(); + + bool error = true; + for(int i=0;iLock(); + if (!m_Lock) + { + error = false; + break; + } + m_pMutex->Unlock(); + wxMilliSleep(1); + } + + if(error) + { + SetLastError(_T("thread not responding")); + m_pMutex->Unlock(); + return false; + } + + cmd = m_pSync; + m_pSync = NULL; + + if(cmd == NULL) + { + SetLastError(_T("command is NULL")); + m_pMutex->Unlock(); + return false; + } + + if(cmd->error) + { + SetLastError(cmd->lasterror); + m_pMutex->Unlock(); + return false; + } + + if(!cmd->executed) + { + SetLastError(_T("command not executed")); + m_pMutex->Unlock(); + return false; + } + + m_pMutex->Unlock(); + return true; +} + +//------------------------------------------------------------------------------ +// Connects to a Teasmpeak server. +bool TSClient::Connect() +{ + if(m_pPlayer == NULL) + { + SetLastError(_T("no player object")); + return false; + } + + if(m_pServer == NULL) + { + SetLastError(_T("no server object")); + return false; + } + + if(m_pConnection == NULL) + { + //m_pMutex->Lock(); + m_pConnection = new TSConnectionThread(this, m_pMutex); + //Start thread + m_pConnection->Run(); + } + + if(!m_pConnection->IsAlive()) + { + SetLastError(_T("can't create thread")); + return false; + } + + if(!SendCommand(TS_CMD_SEND_LOGIN)) + return false; + + if(!SendCommand(TS_CMD_SEND_DEFAULT)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +// Disconnects from a Teasmpeak server. +bool TSClient::Disconnect(bool reconnect) +{ + if(IsConnected()) + if(!SendCommand(TS_CMD_SEND_LOGOUT)) + return false; + + wxSleep(1); + if(m_pConnection != NULL) + { + m_pConnection->Delete(); + delete m_pConnection; + m_pConnection = NULL; + } + + for(size_t i = 0; i < m_ppPlayers->GetCount(); i++) + { + wxASSERT(m_ppPlayers != NULL); + delete m_ppPlayers->Item(i); + } + m_ppPlayers->Empty(); + + for(size_t i = 0; i < m_ppChannels->GetCount(); i++) + { + wxASSERT(m_ppChannels != NULL); + delete m_ppChannels->Item(i); + } + m_ppChannels->Empty(); + + m_pReconnectAct = reconnect; + + return true; +} + +//------------------------------------------------------------------------------ +// Sets the platform string (e.g. Windows XP, Linux). +bool TSClient::SetPlatform(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("empty string")); + return false; + } + + m_Platform = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the TeamSpeak player. +bool TSClient::SetPlayer(TSPlayer *pPlayer) +{ + if(pPlayer == NULL) + { + SetLastError(_T("invalid pointer")); + return false; + } + + wxASSERT(m_pPlayer != NULL); + delete m_pPlayer; + m_pPlayer = pPlayer; + + return true; +} + +//------------------------------------------------------------------------------ +// Sets the TeamSpeak player channel. +bool TSClient::SetChannel(TSChannel *pChannel) +{ + if(pChannel == NULL) + { + SetLastError(_T("invalid pointer")); + return false; + } + + if(m_pChannel != NULL) + delete m_pChannel; + m_pChannel = pChannel; + + return true; +} + +//------------------------------------------------------------------------------ +// Sets the TeamSpeak server. +bool TSClient::SetServer(TSServer *pServer) +{ + if(pServer == NULL) + { + SetLastError(_T("invalid pointer")); + return false; + } + + if(m_pServer != NULL) + delete m_pServer; + m_pServer = pServer; + + return true; +} + +//------------------------------------------------------------------------------ +// Sets the TeamSpeak connection. +bool TSClient::SetConnection(TSConnectionThread *pConnection) +{ + if(pConnection == NULL) + { + SetLastError(_T("invalid pointer")); + return false; + } + + if(m_pConnection != NULL) + delete m_pConnection; + m_pConnection = pConnection; + + return true; +} + +//------------------------------------------------------------------------------ +// Sets the TeamSpeak client version number +bool TSClient::SetVersionNumber(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("empty string")); + return false; + } + + m_VersionNumber = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the session id. +bool TSClient::SetSessionId(wxUint32 const id) +{ + m_SessionId = id; + return true; +} + +//------------------------------------------------------------------------------ +// Sets Sync onject, for thread sync. +bool TSClient::SetSync(TSCmd *sync) +{ + m_pSync = sync; + return true; +} + +//------------------------------------------------------------------------------ +// FindPlayer. +TSPlayer *TSClient::FindPlayer(wxUint32 id) +{ + for(size_t i = 0; i < m_ppPlayers->GetCount(); i++) + { + if(m_ppPlayers->Item(i)->GetId() == id) + return m_ppPlayers->Item(i); + } + + SetLastError(_T("player not found")); + return NULL; +} + +//------------------------------------------------------------------------------ +// FindPlayer. +TSPlayer *TSClient::FindPlayer(wxString const &str) +{ + for(size_t i = 0; i < m_ppPlayers->GetCount(); i++) + { + if(m_ppPlayers->Item(i)->GetNickname() == str) + return m_ppPlayers->Item(i); + } + + SetLastError(_T("player not found")); + return NULL; +} + +//------------------------------------------------------------------------------ +// FindChannel. +TSChannel *TSClient::FindChannel(wxUint32 id) +{ + for(size_t i = 0; i < m_ppChannels->GetCount(); i++) + { + if(m_ppChannels->Item(i)->GetId() == id) + return m_ppChannels->Item(i); + } + + SetLastError(_T("channel not found")); + return NULL; +} + +//------------------------------------------------------------------------------ +// FindChannel. +TSChannel *TSClient::FindChannel(wxString const &str) +{ + for(size_t i = 0; i < m_ppChannels->GetCount(); i++) + { + if(m_ppChannels->Item(i)->GetName() == str) + return m_ppChannels->Item(i); + } + + SetLastError(_T("channel not found")); + return NULL; +} + +//------------------------------------------------------------------------------ +// Finds default channel +TSChannel *TSClient::FindDefaultChannel() +{ + for(size_t i = 0; i < m_ppChannels->GetCount(); i++) + { + if((m_ppChannels->Item(i)->GetFlags() &TS_DEFAULT)) + + return m_ppChannels->Item(i); + } + + SetLastError(_T("channel not found")); + return NULL; +} + +//------------------------------------------------------------------------------ +// FindChannelsByParent. +bool TSClient::FindChannelsByParent(wxUint32 id, TSpChannelArray *channels) +{ + for(size_t i = 0; i < m_ppChannels->GetCount(); i++) + { + if(m_ppChannels->Item(i)->GetParent() == id) + channels->Add(m_ppChannels->Item(i)); + } + + if(channels->GetCount() == 0) + { + SetLastError(_T("no channels found")); + return false; + } + + return true; +} + +//------------------------------------------------------------------------------ +// FindChannelsByName. +bool TSClient::FindChannelsByName(wxString const &str, TSpChannelArray *channels) +{ + wxRegEx regex; + regex.Compile(str); + if(!regex.IsValid()) + { + SetLastError(_T("regular expressions pattern error")); + return false; + } + + for(size_t i = 0; i < m_ppChannels->GetCount(); i++) + { + if(regex.Matches(m_ppChannels->Item(i)->GetName())) + channels->Add(m_ppChannels->Item(i)); + } + + if(channels->GetCount() == 0) + { + SetLastError(_T("no channels found")); + return false; + } + + return true; +} + +//------------------------------------------------------------------------------ +// FindPlayersByName. +bool TSClient::FindPlayersByName(wxString const &str, TSpPlayerArray *players) +{ + wxRegEx regex; + regex.Compile(str); + if(!regex.IsValid()) + { + SetLastError(_T("regular expressions pattern error")); + return false; + } + + for(size_t i = 0; i < m_ppPlayers->GetCount(); i++) + { + if(regex.Matches(m_ppPlayers->Item(i)->GetNickname())) + players->Add(m_ppPlayers->Item(i)); + } + + if(players->GetCount() == 0) + { + SetLastError(_T("no player found")); + return false; + } + + return true; +} + +//------------------------------------------------------------------------------ +// Finds all players in channel. +bool TSClient::FindPlayersByChannel(TSChannel *channel, TSpPlayerArray *players) +{ + if(channel == NULL) + { + SetLastError(_T("invalid pointer")); + return false; + } + + for(size_t i = 0; i < m_ppPlayers->GetCount(); i++) + { + if(m_ppPlayers->Item(i)->GetChannelId() == channel->GetId()) + players->Add(m_ppPlayers->Item(i)); + } + + if(players->GetCount() == 0) + { + SetLastError(_T("no player found")); + return false; + } + return true; +} + +//------------------------------------------------------------------------------ +// Creates a channel. +bool TSClient::CreateChannel(TSChannel *channel) +{ + if(channel == NULL) + { + SetLastError(_T("invalid pointer")); + return false; + } + + TSCmd sync; + sync.id = TS_CMD_SEND_ADD_CHANNEL; + sync.client = this; + sync.param1.pChannel = channel; + + if(!SendCommand(&sync)) + return false; + return true; +} + +//------------------------------------------------------------------------------ +// Deletes a channel. +bool TSClient::DeleteChannel(TSChannel *channel) +{ + if(channel == NULL) + { + SetLastError(_T("invalid pointer")); + return false; + } + + TSCmd sync; + sync.id = TS_CMD_SEND_DEL_CHANNEL; + sync.client = this; + sync.param1.pChannel = channel; + + if(!SendCommand(&sync)) + return false; + return true; +} + +//------------------------------------------------------------------------------ +// Moves a Player. +bool TSClient::MovePlayer(TSPlayer *player) +{ + if(player == NULL) + { + SetLastError(_T("invalid pointer")); + return false; + } + + TSCmd sync; + sync.id = TS_CMD_SEND_MOVE_PLAYER; + sync.client = this; + sync.param1.pPlayer = player; + + if(!SendCommand(&sync)) + return false; + return true; +} + +//------------------------------------------------------------------------------ +// Modify Channel. +bool TSClient::ModifyChannel(TSChannel *channel) +{ + if(channel == NULL) + { + SetLastError(_T("invalid pointer")); + return false; + } + + if(channel->GetPassword().Length()!= 0) + { + TSCmd sync; + sync.id = TS_CMD_SEND_SET_CHANNEL_PASSWORD; + sync.client = this; + sync.param1.pChannel = channel; + + if(!SendCommand(&sync)) + return false; + } + + { + TSCmd sync; + sync.id = TS_CMD_SEND_SET_CHANNEL_FLAGSCODEC; + sync.client = this; + sync.param1.pChannel = channel; + + if(!SendCommand(&sync)) + return false; + } + + { + TSCmd sync; + sync.id = TS_CMD_SEND_SET_CHANNEL_NAME; + sync.client = this; + sync.param1.pChannel = channel; + + if(!SendCommand(&sync)) + return false; + } + + { + TSCmd sync; + sync.id = TS_CMD_SEND_SET_CHANNEL_TOPIC; + sync.client = this; + sync.param1.pChannel = channel; + + if(!SendCommand(&sync)) + return false; + } + + { + TSCmd sync; + sync.id = TS_CMD_SEND_SET_CHANNEL_DESCRIPTION; + sync.client = this; + sync.param1.pChannel = channel; + + if(!SendCommand(&sync)) + return false; + } + + { + TSCmd sync; + sync.id = TS_CMD_SEND_SET_CHANNEL_MAXPLAYERS; + sync.client = this; + sync.param1.pChannel = channel; + + if(!SendCommand(&sync)) + return false; + } + +#if 0 + { + TSCmd sync; + sync.id = TS_CMD_SEND_SET_CHANNEL_ORDER; + sync.client = this; + sync.param1.pChannel = channel; + + if(!SendCommand(&sync)) + return false; + } +#endif + + return true; +} + +//------------------------------------------------------------------------------ +// Check if connected. +bool TSClient::IsConnected() +{ + if(m_pConnection != NULL) + return m_pConnection->m_Connected; + return false; +} + +//------------------------------------------------------------------------------ +// Kick a Player. +bool TSClient::KickPlayer(TSPlayer *player, wxString msg) +{ + if(player == NULL) + { + SetLastError(_T("invalid pointer")); + return false; + } + + TSCmd sync; + sync.id = TS_CMD_SEND_KICK_PLAYER; + sync.client = this; + sync.param1.pPlayer = player; + sync.param2.pString = &msg; + + if(!SendCommand(&sync)) + return false; + return true; +} + +//------------------------------------------------------------------------------ +// Dumps object. +void TSClient::Dump(wxOutputStream &ostrm) const +{ + wxTextOutputStream out(ostrm); + out << wxString(_T("-"), 60) << endl; + out << _T("Object: TSClient (") << wxString::Format(_T("0x%X"), this) << _T(")") << endl; + out << wxString(_T("-"), 60) << endl; + out << _T("-TSPlayer *m_pPlayer:") << endl; + m_pPlayer->Dump(ostrm); + out << endl; + + //TSpPlayerArray + out << wxString(_T("-"), 60) << endl; + out << _T("-TSpPlayerArray *m_ppPlayers:") << endl; + out << _T(" total objects: ") << wxUint32(m_ppPlayers->GetCount()) << endl; + for(size_t i = 0; i < m_ppPlayers->GetCount(); i++) + { + out << _T("\n*Item: ") << wxUint32(i) << endl; + m_ppPlayers->Item(i)->Dump(ostrm); + } + out << endl; + + out << wxString(_T("-"), 60) << endl; + out << _T("-TSChannel *m_pChannel:") << endl; + m_pChannel->Dump(ostrm); + out << endl; + + //TSpChannelArray + out << wxString(_T("-"), 60) << endl; + out << _T("-TSpChannelArray *m_ppChannels:") << endl; + out << _T(" total objects: ") << wxUint32(m_ppChannels->GetCount()) << endl; + for(size_t i = 0; i < m_ppChannels->GetCount(); i++) + { + out << _T("\n*Item: ") << wxUint32(i) << endl; + m_ppChannels->Item(i)->Dump(ostrm); + } + out << endl; + + //TSServer + out << wxString(_T("-"), 60) << endl; + out << _T("-TSServer *m_pServer:") << endl; + m_pServer->Dump(ostrm); + out << endl; + + //remaining members + out << wxString(_T("-"), 60) << endl; + out << _T("-wxString m_VersionNumber: ") << m_VersionNumber << endl; + out << _T("-wxString m_Platform: ") << m_Platform << endl; + out << _T("-wxUint32 m_SessionId: ") << wxString::Format(_T("0x%X"), m_SessionId) << endl; + out << _T("-wxString m_LastError: ") << m_LastError << endl; +} + diff --git a/tsclient.h b/tsclient.h new file mode 100644 index 0000000..ccc32b0 --- /dev/null +++ b/tsclient.h @@ -0,0 +1,489 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +//Header guard +#ifndef TSCLIENT_H +#define TSCLIENT_H + +//Libraries +#include +#include + +#include "tsheaders.h" +#include "tsserver.h" + +//! Thread response timeout +#define THREAD_TIMEOUT 4000 + +//! Maximum time to leave +#define MAX_TTL 5 + +// better than void * +union TSPtr +{ + TSPlayer *pPlayer; + TSChannel *pChannel; + TSServer *pServer; + TSClient *pClient; + wxString *pString; +}; + +//! Only for internal use +struct TSCmd : wxObject +{ + DECLARE_CLASS(TSCmd) + //CTor + TSCmd() + { + id = 0; + executed = false; + error = false; + ttl = MAX_TTL; + pktid = 0; + oldid = 0; + client = NULL; + param1.pPlayer = NULL; + param1.pPlayer = NULL; + } + + TSCmd(wxUint32 c) + { + TSCmd(); + id = c; + } + + TSCmd(wxUint32 c, TSCmd *old) + { + TSCmd(); + id = c; + pktid = old->pktid; + oldid = old->id; + client = old->client; + } + + TSCmd(const TSCmd &cmd) + : wxObject() + { + id = cmd.id; + oldid = cmd.oldid; + executed = cmd.executed; + error = cmd.error; + ttl = cmd.ttl; + pktid = cmd.pktid; + client = cmd.client; + param1 = cmd.param1; + param2 = cmd.param2; + lasterror = cmd.lasterror; + } + + wxUint32 id; + wxUint32 oldid; + bool executed; + bool error; + wxUint32 ttl; + wxUint32 pktid; + TSClient *client; + TSPtr param1; + TSPtr param2; + wxString lasterror; +}; + +//! TeamSpeak client, main class. +/*! TSClient is the main class to connect to a + * TeamSpeak server. These stepps are necessary + * to create and use a TSClient object. + * - Create a TSClient object. + * - Change the attributes. + * - Create a TSPlayer object. + * - Change the attributes. + * - Link it to the TSClient object. + * - Create a TSServer object. + * - Change the attributes. + * - Link it to the TSClient object. + * - Call Connect(). + * + * Example: + * \code + * + * TSClient *pTSC = new TSClient; + * pTSC->SetPlatform(_T("Windows XP")); + * pTSC->SetVersionNumber(_T("2.0.32.60")); + * + * TSPlayer *pTSP = new TSPlayer; + * pTSP->SetLoginName(_T("admin")); + * pTSP->SetLoginPassword(_T("testpassword")); + * pTSP->SetNickname(_T("penner")); + * //now the TSClient takes care of the pointer. + * pTSC->SetPlayer(pTSP); + * + * TSServer *pTSS = new TSServer; + * pTSS->SetServerAddress(_T("game3.clan-server.at")); + * pTSS->SetPort(8767); + * //now the TSClient takes care of the pointer. + * pTSC->SetServer(pTSS); + * + * if(!pTSC->Connect()) + * { + * wxLogError(_T("%s, terminating.\n"), pTSC->GetLastError().c_str()); + * return EXIT_FAILURE; + * } + * + * pTSC->Disconnect(); + * delete pTSC; + * \endcode + */ +class TSClient : public wxObject +{ + DECLARE_CLASS(TSClient) + + public: + + /*! Default CTor, Initializes the object. + * Creates all necessary member objects. + */ + TSClient(); + + /*! Default DTor. + */ + ~TSClient(); + + /*! Connects to a Teasmpeak server. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool Connect(); + + /*! Disconnects from a Teasmpeak server. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool Disconnect(bool reconnect = true); + + /*! Sets the platform string (e.g. Windows XP, Linux). + * \param str Platform string. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetPlatform(wxString const &str); + + /*! Sets the TeamSpeak player. + * The class takes care of the pointer, no delete call. + * \param pPlayer TeamSpeak Player. + * \return Returns false if fails, check GetLastError for details. + * \sa TSPlayer GetLastError() + */ + bool SetPlayer(TSPlayer *pPlayer); + + /*! Sets the TeamSpeak player channel. + * The class takes care of the pointer, no delete call. + * \param pChannel player channel. + * \return Returns false if fails, check GetLastError for details. + * \sa TSChannel GetLastError() + */ + bool SetChannel(TSChannel *pChannel); + + /*! Sets the TeamSpeak server. + * The class takes care of the pointer, no delete call. + * \param pServer Server to use for connection. + * \return Returns false if fails, check GetLastError for details. + * \sa TSServer GetLastError() + */ + bool SetServer(TSServer *pServer); + + /*! Sets the TeamSpeak connection. + * The class takes care of the pointer, no delete call. + * \param pConnection Connection object. + * \return Returns false if fails, check GetLastError for details. + * \sa TSConnection GetLastError() + */ + bool SetConnection(TSConnectionThread *pConnection); + + /*! Sets the TeamSpeak client version number (e.g. "2.0.32.60"). + * \param str Client version number. + * \return Returns false if fails, check GetLastError for details. + * \sa TSConnection GetLastError() + */ + bool SetVersionNumber(wxString const &str); + + /*! Sets the session id. + * \param id Session id. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetSessionId(wxUint32 const id); + + /*! Check if connected. + * \return Returns true if connected. + * \sa GetLastError() + */ + bool IsConnected(); + + /*! Returns the state of the reconnectflag + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool IsReconnectActive() + { + return m_pReconnectAct; + } + + /*! Sets Sync onject, for thread sync. + * \param sync Sync onject. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetSync(TSCmd *sync); + + /*! Gets the TeamSpeak client Platform string. + * \return Client Platform string. + */ + wxString const &GetPlatform() const + { + return m_Platform; + } + + /*! Gets the LastError message, call this method + * to get more information for an error. + * \return LastError message. + */ + wxString const &GetLastError() const + { + return m_LastError; + } + + /*! Gets the version number + * \return Version number. + */ + wxString const &GetVersionNumber() const + { + return m_VersionNumber; + } + + /*! Gets the TeamSpeak player. + * \return TeamSpeak player. + * \sa TSPlayer + */ + TSPlayer *GetPlayer() const + { + return m_pPlayer; + } + + /*! Gets all TeamSpeak players on the server. + * \return TeamSpeak players. + * \sa TSPlayer + */ + TSpPlayerArray *GetPlayers() const + { + return m_ppPlayers; + } + + /*! Gets the TeamSpeak channel. + * \return TeamSpeak channel. + * \sa TSChannel + */ + TSChannel *GetChannel() const + { + return m_pChannel; + } + + /*! Gets all TeamSpeak channels on the server. + * \return TeamSpeak channels. + * \sa TSChannel + */ + TSpChannelArray *GetChannels() const + { + return m_ppChannels; + } + + /*! Gets the TeamSpeak server. + * \return TeamSpeak server. + * \sa TSServer + */ + TSServer *GetServer() const + { + return m_pServer; + } + + /*! Gets the TeamSpeak connection. + * \return TeamSpeak connection. + * \sa TSConnection + */ + TSConnectionThread *GetConnection() const + { + return m_pConnection; + } + + /*! Gets the session id. + * \return Session id. + */ + wxUint32 GetSessionId() const + { + return m_SessionId; + } + + /*! Gets Sync object, for thread sync + * \return Sync object. + */ + TSCmd *GetSync() const + { + return m_pSync; + } + + /*! Send a command to a Teasmpeak server. + * \param cmd Command to send. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() TSCommand for commands + */ + bool SendCommand(wxUint32 cmd); + + /*! Send a command to a Teasmpeak server. + * \param cmd Command to send. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() TSCommand for commands + */ + bool SendCommand(TSCmd *cmd); + + /*! Finds a player + * \param id Player id. + * \return Returns NULL if fails, check GetLastError for details. + * \sa GetLastError() + */ + TSPlayer *FindPlayer(wxUint32 id); + + /*! Finds a player + * \param str Player nick. + * \return Returns NULL if fails, check GetLastError for details. + * \sa GetLastError() + */ + TSPlayer *FindPlayer(wxString const &str); + + /*! Finds a channel + * \param id Channel id. + * \return Returns NULL if fails, check GetLastError for details. + * \sa GetLastError() + */ + TSChannel *FindChannel(wxUint32 id); + + /*! Finds a channel + * \param id Channel id. + * \return Returns NULL if fails, check GetLastError for details. + * \sa GetLastError() + */ + TSChannel *FindChannel(wxString const &str); + + /*! Finds default channel + * \return Returns NULL if fails, check GetLastError for details. + * \sa GetLastError() + */ + TSChannel *FindDefaultChannel(); + + /*! Finds all channel with this parent id. + * \param id Channel id. + * \param channels Channel array + * \sa TSpChannelArray + */ + bool FindChannelsByParent(wxUint32 id, TSpChannelArray *channels); + + /*! Finds all channels per name, regex. + * \param str Channel name. + * \param channels Channel array + * \sa TSpChannelArray + */ + bool FindChannelsByName(wxString const &str, TSpChannelArray *channels); + + /*! Finds all players per name, regex. + * \param str Player name. + * \param players Player array + * \sa TSpPlayerArray + */ + bool FindPlayersByName(wxString const &str, TSpPlayerArray *players); + + /*! Finds all players in channel. + * \param channel Channel. + * \param players Player array + * \sa TSpPlayerArray + */ + bool FindPlayersByChannel(TSChannel *channel, TSpPlayerArray *players); + + /*! Creates a channel. + * \param channel Channel object. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() TSChannel + */ + bool CreateChannel(TSChannel *channel); + + /*! Deletes a channel. + * \param channel Channel object. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() TSChannel + */ + bool DeleteChannel(TSChannel *channel); + + /*! Modify a channel. + * \param channel Channel object. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() TSChannel + */ + bool ModifyChannel(TSChannel *channel); + + /*! Moves a Player. + * \param player Player object. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() TSChannel + */ + bool MovePlayer(TSPlayer *player); + + /*! Kick a Player. + * \param player Player object. + * \param msg Kick message. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() TSChannel + */ + bool KickPlayer(TSPlayer *player, wxString msg = _T("")); + + /*! Dumps object. + * \param ostrm Stream to write. + */ + void Dump(wxOutputStream &ostrm) const; + + private: + //Sets the LastError message. + void SetLastError(wxString const &str) + { + m_LastError = str; + } + + //Members + TSPlayer *m_pPlayer; + TSpPlayerArray *m_ppPlayers; + TSChannel *m_pChannel; + TSpChannelArray *m_ppChannels; + TSServer *m_pServer; + TSConnectionThread *m_pConnection; + wxString m_LastError; + wxString m_VersionNumber; + wxString m_Platform; + wxUint32 m_SessionId; + wxMutex *m_pMutex; + TSCmd *m_pSync; + bool m_pReconnectAct; + public: + bool m_Lock; +}; + +#endif diff --git a/tsclient.sh b/tsclient.sh new file mode 100755 index 0000000..7a24c8d --- /dev/null +++ b/tsclient.sh @@ -0,0 +1,108 @@ +#!/bin/bash + +binary="tsclient" +arguments="" +cd "$(dirname $0)" +#export LD_LIBRARY_PATH="../wxBase-2.8.12/lib:../wxxml2/lib" + +#------------------------------------------------------------------------------- + +CHILDS=() +process_running() +{ + CHILDS=`pgrep -d" " -x ${binary}` + if [ ! -z "${CHILDS}" ]; then + return 1 + fi + return 0 +} + +#------------------------------------------------------------------------------- + +start() +{ + local retval=0 + + process_running + local state=$? + if [ ${state} -eq 0 ]; then + retval=1 + ./${binary} ${arguments} + + sleep 1 + process_running + state=$? + if [ ${state} -eq 1 ]; then + ${OUTPUT} && echo "Process started..." + retval=1 + else + ${OUTPUT} && echo "Couldn't start the process" + fi + else + ${OUTPUT} && echo "Process already running" + fi + + return ${retval} +} + +#------------------------------------------------------------------------------- + +stop() +{ + local retval=0 + + process_running + local state=$? + if [ ${state} -eq 1 ]; then + pkill -TERM -x ${binary} + + sleep 1 + process_running + state=$? + if [ ${state} -eq 1 ]; then + pkill -9 -x ${binary} + fi + + ${OUTPUT} && echo "Process stopped" + retval=1 + else + ${OUTPUT} && echo "Process not running" + fi + + return ${retval} +} + +#------------------------------------------------------------------------------- + +RETVAL=0 +OUTPUT=true +if [ ! -z "$2" -a "$2" = "quiet" ]; then + OUTPUT=false +fi + +case "$1" in + start) + start + RETVAL=$? + ;; + stop) + stop + RETVAL=$? + ;; + restart) + stop + start + RETVAL=$? + ;; + status) + process_running + state=$? + if [ ${state} -eq 1 ]; then + ${OUTPUT} && echo "Process is running (${CHILDS})..." + else + ${OUTPUT} && echo "Process is stopped" + fi + ;; +esac + +exit ${RETVAL} diff --git a/tscommand.cpp b/tscommand.cpp new file mode 100644 index 0000000..881ce70 --- /dev/null +++ b/tscommand.cpp @@ -0,0 +1,1519 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +// Header +#include "tscommand.h" +#include "wxstreamex.h" +#include "wxbufferex.h" +#include "crc32.h" + +//Libraries +#include +#include +#include +#include + +IMPLEMENT_CLASS(TSCommand, wxObject) + +//class variable +wxUint32 TSCommand::m_Cnt = 0; + +//------------------------------------------------------------------------------ +// Send User +bool TSCmdSendLogin::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxByte buf[1024]; + wxUint32 len = 0; + wxMemoryOutputStream tmpstrm; + wxDataOutputStreamEx out(tmpstrm); + + TSCommand::m_Cnt = 0; + + out.Write32(m_Id); + out.Write32(0); //SessionId + out.Write32(0); //PlayerId + out.Write32(m_Cnt++); //Counter + out.Write32(0); //CRC + out.WriteFixedString(_T("TeamSpeak")); //TeamSpeak + out.WriteFixedString(client->GetPlatform()); //Platform + + //Write version number + wxStringTokenizer tkz(client->GetVersionNumber(), _T(".")); + if(tkz.CountTokens() != 4) + { + SetLastError(_T("invalid version number, check format")); + return false; + } + + //some conversions + long i; + tkz.GetNextToken().ToLong(&i); + out.Write16(wxUint16(i)); + tkz.GetNextToken().ToLong(&i); + out.Write16(wxUint16(i)); + tkz.GetNextToken().ToLong(&i); + out.Write16(wxUint16(i)); + tkz.GetNextToken().ToLong(&i); + out.Write16(wxUint16(i)); + + out.Write8(client->GetPlayer()->GetServerAssingnsNickname()); //Allow server assing nick + + out.Write8(client->GetPlayer()->GetAnonymous()); //Anonymous login + out.WriteFixedString(client->GetPlayer()->GetLoginName()); //Login name + out.WriteFixedString(client->GetPlayer()->GetLoginPassword()); //Login password + out.WriteFixedString(client->GetPlayer()->GetNickname()); //Nickname + + len = tmpstrm.CopyTo(buf, 1024); + CRC32 myCRC32; + myCRC32.update(buf, len); + + tmpstrm.SeekO(16); + out.Write32(myCRC32.getUint32Value()); + len = tmpstrm.CopyTo(buf, len); + + ostrm.Write(buf, len); + + //only for reducing warnings + wxUnusedVar(istrm); + return true; +} + +//------------------------------------------------------------------------------ +// Recv Server +bool TSCmdRecvServer::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxString str; + wxUint32 crc = 0; + wxUint32 id; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + client->GetPlayer()->SetId(in.Read32()); //Player id + in.Read32(); //Packet count + crc = in.Read32(); //CRC + in.ReadFixedString(str); + client->GetServer()->SetServerMessage(str); //Server message + str.Clear(); + in.ReadFixedString(str); + client->GetServer()->SetPlatform(str); //Platform string + str.Clear(); + str.Append(wxString::Format(_T("%d."), in.Read16())); + str.Append(wxString::Format(_T("%d."), in.Read16())); + str.Append(wxString::Format(_T("%d."), in.Read16())); + str.Append(wxString::Format(_T("%d"), in.Read16())); + client->GetServer()->SetVersionNumber(str); + id = in.Read32(); + if(id == 0xffffffff) + { + SetLastError(_T("Bad Login (name and/or password wrong)")); + return false; + } + if(id == 0xfffffff9) + { + SetLastError(_T("This user is already logged in on the server")); + return false; + } + if(id > 100) + { + SetLastError(_T("Undefined user login error, check user data/permission")); + return false; + } + client->GetServer()->SetId(id); + + in.Read32(); //unknown + in.Read32(); //unknown + client->GetServer()->SetServerType(in.Read16()); // servertype + + //more unknown data + for(int i = 0; i < 70; i++) + in.Read8(); + + client->SetSessionId(in.Read32()); //Session id + client->GetPlayer()->SetId(in.Read32()); //Player id + str.Clear(); + in.ReadFixedString(str, 255); + client->GetServer()->SetWelcomeMessage(str); //Welcome message + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + return true; +} + +//------------------------------------------------------------------------------ +// Send default channel +bool TSCmdSendDefault::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxByte buf[1024]; + wxUint32 len = 0; + wxMemoryOutputStream tmpstrm; + wxDataOutputStreamEx out(tmpstrm); + + out.Write32(m_Id); + out.Write32(client->GetSessionId()); //SessionId + out.Write32(client->GetPlayer()->GetId()); //PlayerId + out.Write32(m_Cnt++); //Counter + out.Write32(0); //unknown + out.Write32(0); //CRC + out.Write16(1); + out.WriteFixedString(client->GetPlayer()->GetDefaultChannel()); + out.WriteFixedString(client->GetPlayer()->GetDefaultSubchannel()); + out.WriteFixedString(client->GetPlayer()->GetDefaultChannelPassword()); + out.Write32(0); //unknown + + len = tmpstrm.CopyTo(buf, 1024); + CRC32 myCRC32; + myCRC32.update(buf, len); + + tmpstrm.SeekO(20); + out.Write32(myCRC32.getUint32Value()); + len = tmpstrm.CopyTo(buf, len); + + ostrm.Write(buf, len); + + //only for reducing warnings + wxUnusedVar(istrm); + return true; +} + +//------------------------------------------------------------------------------ +// TSRecvChannel +bool TSCmdRecvChannel::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxString str; + wxUint32 crc = 0; + wxUint32 channels = 0; + TSChannel *chl = NULL; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); //read unknown + crc = in.Read32(); //CRC + channels = in.Read32(); //read channel count + + for(size_t i = 0; i < channels; i++) + { + wxUint32 chlid = in.Read32(); + chl = client->FindChannel(chlid); + if(chl == NULL) + { + chl = new TSChannel; + client->GetChannels()->Add(chl); + } + + chl->SetId(chlid); + chl->SetFlags(in.Read16()); + chl->SetCodec(in.Read16()); + chl->SetParent(in.Read32()); + chl->SetOrder(in.Read16()); + chl->SetMaxUsers(in.Read16()); + str.Clear(); + in.ReadZeroString(str); + chl->SetName(str); + str.Clear(); + in.ReadZeroString(str); + chl->SetTopic(str); + str.Clear(); + in.ReadZeroString(str); + chl->SetDescription(str); + } + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + return true; +} + +//------------------------------------------------------------------------------ +// TSRecvUser +bool TSCmdRecvUser::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxString str; + wxUint32 crc = 0; + wxUint32 players = 0; + TSPlayer *ply = NULL; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); //read unknown + crc = in.Read32(); //CRC + players = in.Read32(); + + for(size_t i = 0; i < players; i++) + { + wxUint32 plyid = in.Read32(); + ply = client->FindPlayer(plyid); + if(ply == NULL) + { + ply = new TSPlayer; + client->GetPlayers()->Add(ply); + } + + ply->SetId(plyid); + ply->SetChannelId(in.Read32()); + ply->SetChannelPrivileges(in.Read16()); + ply->SetPrivileges(in.Read16()); + ply->SetFlags(in.Read16()); + str.Clear(); + in.ReadFixedString(str); + ply->SetNickname(str); + } + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + return true; +} + +//------------------------------------------------------------------------------ +// TSRecvAck +bool TSCmdRecvAck::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + wxUint32 crc = 0; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + crc = in.Read32(); //CRC + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + return true; +} + + +//------------------------------------------------------------------------------ +// TSSendAck + +bool TSCmdSendAck::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxByte buf[1024]; + wxUint32 len = 0; + wxMemoryOutputStream tmpstrm; + wxDataOutputStreamEx out(tmpstrm); + + out.Write32(TS_CMD_RECV_ACK); //same id as recv + out.Write32(client->GetSessionId()); //SessionId + out.Write32(client->GetPlayer()->GetId()); //PlayerId + out.Write32(cmd->pktid); //Counter + len = tmpstrm.CopyTo(buf, 1024); + ostrm.Write(buf, len); + + //only for reducing warnings + wxUnusedVar(istrm); + return true; +} + +//------------------------------------------------------------------------------ +// TSRecvUrl +bool TSCmdRecvUrl::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + wxUint32 crc = 0; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + crc = in.Read32(); //CRC + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + return true; +} + +//------------------------------------------------------------------------------ +// TSSendPing +bool TSCmdSendPing::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxByte buf[1024]; + wxUint32 len = 0; + static wxUint32 cnt = 2; + wxMemoryOutputStream tmpstrm; + wxDataOutputStreamEx out(tmpstrm); + + out.Write32(m_Id); + out.Write32(client->GetSessionId()); //SessionId + out.Write32(client->GetPlayer()->GetId()); //PlayerId + out.Write32(cnt++); //Counter + out.Write32(0); + + len = tmpstrm.CopyTo(buf, 1024); + CRC32 myCRC32; + myCRC32.update(buf, len); + + tmpstrm.SeekO(16); + out.Write32(myCRC32.getUint32Value()); + len = tmpstrm.CopyTo(buf, len); + + ostrm.Write(buf, len); + + //only for reducing warnings + wxUnusedVar(istrm); + return true; +} + +//------------------------------------------------------------------------------ +// TSRecvPing +bool TSCmdRecvPing::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + //only for reducing warnings + wxUnusedVar(istrm); + wxUnusedVar(ostrm); + wxUnusedVar(cmd); + return true; +} + +//------------------------------------------------------------------------------ +// SendLogout +bool TSCmdSendLogout::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxByte buf[1024]; + wxUint32 len = 0; + wxMemoryOutputStream tmpstrm; + wxDataOutputStreamEx out(tmpstrm); + + out.Write32(m_Id); + out.Write32(client->GetSessionId()); //SessionId + out.Write32(client->GetPlayer()->GetId()); //PlayerId + out.Write32(m_Cnt++); //Counter + out.Write32(0); + out.Write32(0); + + len = tmpstrm.CopyTo(buf, 1024); + CRC32 myCRC32; + myCRC32.update(buf, len); + + tmpstrm.SeekO(20); + out.Write32(myCRC32.getUint32Value()); + len = tmpstrm.CopyTo(buf, len); + + ostrm.Write(buf, len); + + //only for reducing warnings + wxUnusedVar(istrm); + return true; +} + +//------------------------------------------------------------------------------ +// RecvLogoutInfo +bool TSCmdRecvLogout::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxUint32 crc = 0; + wxUint32 id; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); + crc = in.Read32(); //CRC + id = in.Read32(); + + for(size_t i = 0; i < client->GetPlayers()->GetCount(); i++) + { + if(id == client->GetPlayers()->Item(i)->GetId()) + { + delete client->GetPlayers()->Item(i); + client->GetPlayers()->RemoveAt(i); + return true; + } + } + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + + SetLastError(_T("unknown player, not found in list, can't remove")); + return false; +} + +//------------------------------------------------------------------------------ +// TSCmdRecvAddPlayer +bool TSCmdRecvAddPlayer::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxString str; + wxUint32 crc = 0; + wxUint32 id = 0; + TSPlayer *ply = NULL; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); //read unknown + crc = in.Read32(); //CRC + id = in.Read32(); //Player id + ply = client->FindPlayer(id); + + if(ply == NULL) + { + ply = new TSPlayer; + client->GetPlayers()->Add(ply); + } + + ply->SetId(id); + ply->SetChannelId(in.Read32()); + ply->SetChannelPrivileges(in.Read16()); + ply->SetPrivileges(in.Read16()); + ply->SetFlags(in.Read16()); + str.Clear(); + in.ReadFixedString(str); + ply->SetNickname(str); + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdRecvPlayerFlags +bool TSCmdRecvPlayerFlags::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + TSPlayer *ply = NULL; + wxUint32 crc = 0; + wxUint32 plyid = 0; + wxUint32 plyflags = 0; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); //read unknown + crc = in.Read32(); //CRC + plyid = in.Read32(); + plyflags = in.Read16(); + + ply = client->FindPlayer(plyid); + if(ply != NULL) + { + ply->SetFlags(plyflags); + return true; + } + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + + SetLastError(_T("unknown player, not found in list, flags not set")); + return false; +} + +//------------------------------------------------------------------------------ +// TSCmdRecvAddChannel +bool TSCmdRecvAddChannel::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + TSChannel *chl = NULL; + wxString str; + wxUint32 crc = 0; + wxUint32 chlid = 0; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); //read unknown + crc = in.Read32(); //CRC + in.Read32(); //user + chlid = in.Read32(); + chl = client->FindChannel(chlid); + if(chl == NULL) + { + chl = new TSChannel; + client->GetChannels()->Add(chl); + } + + chl->SetId(chlid); + chl->SetFlags(in.Read16()); + chl->SetCodec(in.Read16()); + chl->SetParent(in.Read32()); + chl->SetOrder(in.Read16()); + chl->SetMaxUsers(in.Read16()); + str.Clear(); + in.ReadZeroString(str); + chl->SetName(str); + str.Clear(); + in.ReadZeroString(str); + chl->SetTopic(str); + str.Clear(); + in.ReadZeroString(str); + chl->SetDescription(str); + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdRecvMovePlayer +bool TSCmdRecvMovePlayer::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + TSPlayer *ply = NULL; + wxUint32 crc = 0; + wxUint32 plyid = 0; + wxUint32 chlid = 0; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); //read unknown + crc = in.Read32(); //CRC + plyid = in.Read32(); + in.Read32(); //old channel + chlid = in.Read32(); //new channel + in.Read16(); //unknown + + ply = client->FindPlayer(plyid); + if(ply != NULL) + { + ply->SetChannelId(chlid); + return true; + } + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + + SetLastError(_T("unknown player, not found in list, channel not set")); + return false; +} + +//------------------------------------------------------------------------------ +// TSCmdRecvMovePlayer +bool TSCmdRecvMovePlayer2::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + TSPlayer *ply = NULL; + wxUint32 crc = 0; + wxUint32 plyid = 0; + wxUint32 chlid = 0; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); //read unknown + crc = in.Read32(); //CRC + plyid = in.Read32(); + in.Read32(); //old channel + chlid = in.Read32(); //new channel + in.Read16(); //unknown + + ply = client->FindPlayer(plyid); + if(ply != NULL) + { + ply->SetChannelId(chlid); + return true; + } + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + + SetLastError(_T("unknown player, not found in list, channel not set")); + return false; +} + +//------------------------------------------------------------------------------ +// TSCmdRecvDelChannel +bool TSCmdRecvDelChannel::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxUint32 crc = 0; + wxUint32 plyid = 0; + wxUint16 chlid = 0; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); //read unknown + crc = in.Read32(); //CRC + chlid = in.Read16(); // channel + plyid = in.Read32(); + + for(size_t i = 0; i < client->GetChannels()->GetCount(); i++) + { + if(chlid == client->GetChannels()->Item(i)->GetId()) + { + delete client->GetChannels()->Item(i); + client->GetChannels()->RemoveAt(i); + return true; + } + } + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + wxUnusedVar(plyid); + + SetLastError(_T("unknown channel, not found in list")); + return false; +} + +//------------------------------------------------------------------------------ +// TSCmdRecvServerUpdate +bool TSCmdRecvServerUpdate::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + wxUint32 crc = 0; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); //read unknown + crc = in.Read32(); //CRC + + // in.Read32(); //unknown + // in.Read32(); //unknown + // servertype = in.Read16(); //clan=05, public=06 + // more unknown data + // all over 80 byte (so 62 left or so) + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdSendAddChannel +bool TSCmdSendAddChannel::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxByte buf[1024]; + wxUint32 len = 0; + wxMemoryOutputStream tmpstrm; + wxDataOutputStreamEx out(tmpstrm); + + out.Write32(m_Id); + out.Write32(client->GetSessionId()); //SessionId + out.Write32(client->GetPlayer()->GetId()); //PlayerId + out.Write32(m_Cnt++); //Counter + out.Write32(0); //unknown + out.Write32(0); //crc + + out.Write32(0); //must be null + + out.Write16(cmd->param1.pChannel->GetFlags()); + out.Write16(cmd->param1.pChannel->GetCodec()); + out.Write32(cmd->param1.pChannel->GetParent()); + out.Write16(cmd->param1.pChannel->GetOrder()); + out.Write16(cmd->param1.pChannel->GetMaxUsers()); + out.WriteZeroString(cmd->param1.pChannel->GetName()); + out.WriteZeroString(cmd->param1.pChannel->GetTopic()); + out.WriteZeroString(cmd->param1.pChannel->GetDescription()); + if (cmd->param1.pChannel->GetPassword().Length() > 0) + out.WriteZeroString(cmd->param1.pChannel->GetPassword()); + else + out.Write8(0); + + len = tmpstrm.CopyTo(buf, 1024); + CRC32 myCRC32; + myCRC32.update(buf, len); + + tmpstrm.SeekO(20); + out.Write32(myCRC32.getUint32Value()); + len = tmpstrm.CopyTo(buf, len); + + ostrm.Write(buf, len); + + //only for reducing warnings + wxUnusedVar(istrm); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdSendDelChannel +bool TSCmdSendDelChannel::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxByte buf[1024]; + wxUint32 len = 0; + wxMemoryOutputStream tmpstrm; + wxDataOutputStreamEx out(tmpstrm); + + out.Write32(m_Id); + out.Write32(client->GetSessionId()); //SessionId + out.Write32(client->GetPlayer()->GetId()); //PlayerId + out.Write32(m_Cnt++); //Counter + out.Write32(0); //unknown + out.Write32(0); //crc + + out.Write32(cmd->param1.pChannel->GetId()); + + len = tmpstrm.CopyTo(buf, 1024); + CRC32 myCRC32; + myCRC32.update(buf, len); + + tmpstrm.SeekO(20); + out.Write32(myCRC32.getUint32Value()); + len = tmpstrm.CopyTo(buf, len); + + ostrm.Write(buf, len); + + //only for reducing warnings + wxUnusedVar(istrm); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdSendMovePlayer +bool TSCmdSendMovePlayer::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxByte buf[1024]; + wxUint32 len = 0; + wxMemoryOutputStream tmpstrm; + wxDataOutputStreamEx out(tmpstrm); + + out.Write32(m_Id); + out.Write32(client->GetSessionId()); //SessionId + out.Write32(client->GetPlayer()->GetId()); //PlayerId + out.Write32(m_Cnt++); //Counter + out.Write32(0); //unknown + out.Write32(0); //crc + + out.Write32(cmd->param1.pPlayer->GetId()); + out.Write32(cmd->param1.pPlayer->GetChannelId()); + + len = tmpstrm.CopyTo(buf, 1024); + CRC32 myCRC32; + myCRC32.update(buf, len); + + tmpstrm.SeekO(20); + out.Write32(myCRC32.getUint32Value()); + len = tmpstrm.CopyTo(buf, len); + + ostrm.Write(buf, len); + + //only for reducing warnings + wxUnusedVar(istrm); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdSendSetChannelPassword +bool TSCmdSendSetChannelPassword::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxByte buf[1024]; + wxUint32 len = 0; + wxMemoryOutputStream tmpstrm; + wxDataOutputStreamEx out(tmpstrm); + + out.Write32(m_Id); + out.Write32(client->GetSessionId()); //SessionId + out.Write32(client->GetPlayer()->GetId()); //PlayerId + out.Write32(m_Cnt++); //Counter + out.Write32(0); //unknown + out.Write32(0); //crc + + out.Write32(cmd->param1.pChannel->GetId()); + out.WriteFixedString(cmd->param1.pChannel->GetPassword()); + + len = tmpstrm.CopyTo(buf, 1024); + CRC32 myCRC32; + myCRC32.update(buf, len); + + tmpstrm.SeekO(20); + out.Write32(myCRC32.getUint32Value()); + len = tmpstrm.CopyTo(buf, len); + + ostrm.Write(buf, len); + + //only for reducing warnings + wxUnusedVar(istrm); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdSendSetChannelName +bool TSCmdSendSetChannelName::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxByte buf[1024]; + wxUint32 len = 0; + wxMemoryOutputStream tmpstrm; + wxDataOutputStreamEx out(tmpstrm); + + out.Write32(m_Id); + out.Write32(client->GetSessionId()); //SessionId + out.Write32(client->GetPlayer()->GetId()); //PlayerId + out.Write32(m_Cnt++); //Counter + out.Write32(0); //unknown + out.Write32(0); //crc + + out.Write32(cmd->param1.pChannel->GetId()); + out.WriteZeroString(cmd->param1.pChannel->GetName()); + + len = tmpstrm.CopyTo(buf, 1024); + CRC32 myCRC32; + myCRC32.update(buf, len); + + tmpstrm.SeekO(20); + out.Write32(myCRC32.getUint32Value()); + len = tmpstrm.CopyTo(buf, len); + + ostrm.Write(buf, len); + + //only for reducing warnings + wxUnusedVar(istrm); + wxUnusedVar(ostrm); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdSendSetChannelTopic +bool TSCmdSendSetChannelTopic::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxByte buf[1024]; + wxUint32 len = 0; + wxMemoryOutputStream tmpstrm; + wxDataOutputStreamEx out(tmpstrm); + + out.Write32(m_Id); + out.Write32(client->GetSessionId()); //SessionId + out.Write32(client->GetPlayer()->GetId()); //PlayerId + out.Write32(m_Cnt++); //Counter + out.Write32(0); //unknown + out.Write32(0); //crc + + out.Write32(cmd->param1.pChannel->GetId()); + out.WriteZeroString(cmd->param1.pChannel->GetTopic()); + + len = tmpstrm.CopyTo(buf, 1024); + CRC32 myCRC32; + myCRC32.update(buf, len); + + tmpstrm.SeekO(20); + out.Write32(myCRC32.getUint32Value()); + len = tmpstrm.CopyTo(buf, len); + + ostrm.Write(buf, len); + + //only for reducing warnings + wxUnusedVar(istrm); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdSendSetChannelDescription +bool TSCmdSendSetChannelDescription::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxByte buf[1024]; + wxUint32 len = 0; + wxMemoryOutputStream tmpstrm; + wxDataOutputStreamEx out(tmpstrm); + + out.Write32(m_Id); + out.Write32(client->GetSessionId()); //SessionId + out.Write32(client->GetPlayer()->GetId()); //PlayerId + out.Write32(m_Cnt++); //Counter + out.Write32(0); //unknown + out.Write32(0); //crc + + out.Write32(cmd->param1.pChannel->GetId()); + out.WriteZeroString(cmd->param1.pChannel->GetDescription()); + + len = tmpstrm.CopyTo(buf, 1024); + CRC32 myCRC32; + myCRC32.update(buf, len); + + tmpstrm.SeekO(20); + out.Write32(myCRC32.getUint32Value()); + len = tmpstrm.CopyTo(buf, len); + + ostrm.Write(buf, len); + + //only for reducing warnings + wxUnusedVar(istrm); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdSendSetChannelMaxPlayers +bool TSCmdSendSetChannelMaxPlayers::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxByte buf[1024]; + wxUint32 len = 0; + wxMemoryOutputStream tmpstrm; + wxDataOutputStreamEx out(tmpstrm); + + out.Write32(m_Id); + out.Write32(client->GetSessionId()); //SessionId + out.Write32(client->GetPlayer()->GetId()); //PlayerId + out.Write32(m_Cnt++); //Counter + out.Write32(0); //unknown + out.Write32(0); //crc + + out.Write32(cmd->param1.pChannel->GetId()); + out.Write16(cmd->param1.pChannel->GetMaxUsers()); + + len = tmpstrm.CopyTo(buf, 1024); + CRC32 myCRC32; + myCRC32.update(buf, len); + + tmpstrm.SeekO(20); + out.Write32(myCRC32.getUint32Value()); + len = tmpstrm.CopyTo(buf, len); + + ostrm.Write(buf, len); + + //only for reducing warnings + wxUnusedVar(istrm); + wxUnusedVar(ostrm); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdSendSetChannelFlagsCodec +bool TSCmdSendSetChannelFlagsCodec::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxByte buf[1024]; + wxUint32 len = 0; + wxMemoryOutputStream tmpstrm; + wxDataOutputStreamEx out(tmpstrm); + + out.Write32(m_Id); + out.Write32(client->GetSessionId()); //SessionId + out.Write32(client->GetPlayer()->GetId()); //PlayerId + out.Write32(m_Cnt++); //Counter + out.Write32(0); //unknown + out.Write32(0); //crc + + out.Write32(cmd->param1.pChannel->GetId()); + out.Write16(cmd->param1.pChannel->GetFlags()); + out.Write16(cmd->param1.pChannel->GetCodec()); + + len = tmpstrm.CopyTo(buf, 1024); + CRC32 myCRC32; + myCRC32.update(buf, len); + + tmpstrm.SeekO(20); + out.Write32(myCRC32.getUint32Value()); + len = tmpstrm.CopyTo(buf, len); + + ostrm.Write(buf, len); + + //only for reducing warnings + wxUnusedVar(istrm); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdSendSetChannelOrder +bool TSCmdSendSetChannelOrder::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxByte buf[1024]; + wxUint32 len = 0; + wxMemoryOutputStream tmpstrm; + wxDataOutputStreamEx out(tmpstrm); + + out.Write32(m_Id); + out.Write32(client->GetSessionId()); //SessionId + out.Write32(client->GetPlayer()->GetId()); //PlayerId + out.Write32(m_Cnt++); //Counter + out.Write32(0); //unknown + out.Write32(0); //crc + + out.Write32(cmd->param1.pChannel->GetId()); + out.Write16(cmd->param1.pChannel->GetOrder()); + + len = tmpstrm.CopyTo(buf, 1024); + CRC32 myCRC32; + myCRC32.update(buf, len); + + tmpstrm.SeekO(20); + out.Write32(myCRC32.getUint32Value()); + len = tmpstrm.CopyTo(buf, len); + + ostrm.Write(buf, len); + + //only for reducing warnings + wxUnusedVar(istrm); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdRecvSetChannelName +bool TSCmdRecvSetChannelName::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + TSChannel *chl = NULL; + wxString str; + wxUint32 crc = 0; + wxUint32 chlid = 0; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); //read unknown + crc = in.Read32(); //CRC + chlid = in.Read32(); + + chl = client->FindChannel(chlid); + if(chl == NULL) + { + SetLastError(_T("can't find channel")); + return false; + } + + in.Read32(); //user id + + str.Clear(); + in.ReadZeroString(str); + chl->SetName(str); + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdRecvSetChannelTopic +bool TSCmdRecvSetChannelTopic::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + TSChannel *chl = NULL; + wxString str; + wxUint32 crc = 0; + wxUint32 chlid = 0; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); //read unknown + crc = in.Read32(); //CRC + chlid = in.Read32(); + + chl = client->FindChannel(chlid); + if(chl == NULL) + { + SetLastError(_T("can't find channel")); + return false; + } + + in.Read32(); //user id + + str.Clear(); + in.ReadZeroString(str); + chl->SetTopic(str); + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdRecvSetChannelDescription +bool TSCmdRecvSetChannelDescription::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + TSChannel *chl = NULL; + wxString str; + wxUint32 crc = 0; + wxUint32 chlid = 0; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); //read unknown + crc = in.Read32(); //CRC + chlid = in.Read32(); + + chl = client->FindChannel(chlid); + if(chl == NULL) + { + SetLastError(_T("can't find channel")); + return false; + } + + in.Read32(); //user id + + str.Clear(); + in.ReadZeroString(str); + chl->SetDescription(str); + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdRecvSetChannelMaxPlayers +bool TSCmdRecvSetChannelMaxPlayers::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + TSChannel *chl = NULL; + wxUint32 crc = 0; + wxUint32 chlid = 0; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); //read unknown + crc = in.Read32(); //CRC + chlid = in.Read32(); + + chl = client->FindChannel(chlid); + if(chl == NULL) + { + SetLastError(_T("can't find channel")); + return false; + } + + chl->SetMaxUsers(in.Read16()); + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdRecvSetChannelFlagsCodec +bool TSCmdRecvSetChannelFlagsCodec::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + TSChannel *chl = NULL; + wxUint32 crc = 0; + wxUint32 chlid = 0; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); //read unknown + crc = in.Read32(); //CRC + chlid = in.Read32(); + + chl = client->FindChannel(chlid); + if(chl == NULL) + { + SetLastError(_T("can't find channel")); + return false; + } + + chl->SetFlags(in.Read16()); + chl->SetCodec(in.Read16()); + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdRecvSetChannelOrder +bool TSCmdRecvSetChannelOrder::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + TSChannel *chl = NULL; + wxUint32 crc = 0; + wxUint32 chlid = 0; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); //read unknown + crc = in.Read32(); //CRC + chlid = in.Read32(); + + chl = client->FindChannel(chlid); + if(chl == NULL) + { + SetLastError(_T("can't find channel")); + return false; + } + + chl->SetOrder(in.Read32()); + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdSendKickPlayer +bool TSCmdSendKickPlayer::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + TSClient *client = cmd->client; + wxByte buf[1024]; + wxUint32 len = 0; + wxMemoryOutputStream tmpstrm; + wxDataOutputStreamEx out(tmpstrm); + + out.Write32(m_Id); + out.Write32(client->GetSessionId()); //SessionId + out.Write32(client->GetPlayer()->GetId()); //PlayerId + out.Write32(m_Cnt++); //Counter + out.Write32(0); //unknown + out.Write32(0); //crc + + out.Write32(cmd->param1.pPlayer->GetId()); + out.WriteFixedString(*cmd->param2.pString); + + + len = tmpstrm.CopyTo(buf, 1024); + CRC32 myCRC32; + myCRC32.update(buf, len); + + tmpstrm.SeekO(20); + out.Write32(myCRC32.getUint32Value()); + len = tmpstrm.CopyTo(buf, len); + + ostrm.Write(buf, len); + + //only for reducing warnings + wxUnusedVar(istrm); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdRecvChannelPasswordChanged +bool TSCmdRecvChannelPasswordChanged::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + wxUint32 crc = 0; + wxDataInputStreamEx in(istrm); + + //read id + if(in.Read32() != m_Id) + { + SetLastError(_T("invalid command")); + return false; + } + + in.Read32(); //Session id + in.Read32(); //Player id + cmd->pktid = in.Read32(); //Packet count + in.Read32(); //read unknown + crc = in.Read32(); //CRC + + //do nothing + + //only for reducing warnings + wxUnusedVar(ostrm); + wxUnusedVar(crc); + return true; +} + +//------------------------------------------------------------------------------ +// TSCmdRecvUnknown +bool TSCmdRecvUnknown::ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd) +{ + wxMemoryBufferEx buf(1024); + wxUint32 cnt = 0; + + while(!istrm.Eof()) + { + cnt++; + buf.AppendByte(istrm.GetC()); + } + buf.SetDataLen(cnt); + wxMemoryInputStream tmp(buf.GetData(), buf.GetDataLen()); + wxDataInputStreamEx in(tmp); + + wxLogVerbose(_T("dumping unknown command...")); + + wxLogVerbose(_T("Id: %#x"), in.Read32()); //read id + wxLogVerbose(_T("SessionId: %#x"), in.Read32()); //Session id + wxLogVerbose(_T("PlayerId: %#x"), in.Read32()); //Player id + + cmd->pktid = in.Read32(); //Packet count + wxLogVerbose(_T("PacketId: %#x"), cmd->pktid); + + wxStringOutputStream so; + buf.HexDump(so); + wxLogVerbose(_T("Hex dump:\n%s"), so.GetString().c_str()); + + //only for reducing warnings + wxUnusedVar(ostrm); + return true; +} + diff --git a/tscommand.h b/tscommand.h new file mode 100644 index 0000000..d7774a2 --- /dev/null +++ b/tscommand.h @@ -0,0 +1,524 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +#ifndef TSCOMMAND_H +#define TSCOMMAND_H + +#include "tsheaders.h" + +#include +#include +#include +#include +#include + +//Commands +#define TS_CMD_RECV_UNKNOWN 0xffffffff //!< Recv unknown command +#define TS_CMD_SEND_LOGIN 0x0003bef4 //!< Send user, login +#define TS_CMD_RECV_SERVER 0x0004bef4 //!< Recv server Information +#define TS_CMD_SEND_DEFAULT 0x0005bef0 //!< Send default channel +#define TS_CMD_RECV_CHANNEL 0x0006bef0 //!< Recv channels +#define TS_CMD_RECV_USER 0x0007bef0 //!< Recv users +#define TS_CMD_RECV_ACK 0x0000bef1 //!< Recv acknowledge +#define TS_CMD_SEND_ACK 0xff00bef1 //!< pseudo command, send recv same id +#define TS_CMD_RECV_URL 0x0008bef0 //!< Recv ISP Url +#define TS_CMD_SEND_PING 0x0001bef4 //!< Send ping +#define TS_CMD_RECV_PING 0x0002bef4 //!< Recv ping +#define TS_CMD_SEND_LOGOUT 0x012cbef0 //!< Send logout user +#define TS_CMD_RECV_LOGOUT 0x0065bef0 //!< Recv logout information +#define TS_CMD_RECV_ADD_PLAYER 0x0064bef0 //!< Recv player login +#define TS_CMD_RECV_PLAYER_FLAGS 0x0068bef0 //!< Recv player flags +#define TS_CMD_RECV_ADD_CHANNEL 0x006ebef0 //!< Recv add channel +#define TS_CMD_RECV_MOVE_PLAYER 0x0067bef0 //!< Recv move player +#define TS_CMD_RECV_MOVE_PLAYER2 0x006dbef0 //!< Recv move player +#define TS_CMD_RECV_DEL_CHANNEL 0x0073bef0 //!< Recv delete channel +#define TS_CMD_RECV_SERVER_UPDATE 0x008cbef0 //!< Recv update server +#define TS_CMD_SEND_ADD_CHANNEL 0x00c9bef0 //!< Send create channel +#define TS_CMD_SEND_DEL_CHANNEL 0x00d1bef0 //!< Send delete channel +#define TS_CMD_SEND_MOVE_PLAYER 0x014abef0 //!< Send move player +#define TS_CMD_SEND_KICK_PLAYER 0x012dbef0 //!< Send kick player + +#define TS_CMD_SEND_SET_CHANNEL_PASSWORD 0x00cbbef0 //!< Send change channel +#define TS_CMD_SEND_SET_CHANNEL_NAME 0x00cebef0 //!< Send change channel +#define TS_CMD_SEND_SET_CHANNEL_TOPIC 0x00cfbef0 //!< Send change channel +#define TS_CMD_SEND_SET_CHANNEL_DESCRIPTION 0x00d0bef0 //!< Send change channel +#define TS_CMD_SEND_SET_CHANNEL_MAXPLAYERS 0x00d2bef0 //!< Send change channel +#define TS_CMD_SEND_SET_CHANNEL_FLAGSCODEC 0x00cdbef0 //!< Send change channel +#define TS_CMD_SEND_SET_CHANNEL_ORDER 0x00d4bef0 //!< Send change channel + +#define TS_CMD_RECV_SET_CHANNEL_NAME 0x006fbef0 //!< Recv change channel +#define TS_CMD_RECV_SET_CHANNEL_TOPIC 0x0070bef0 //!< Recv change channel +#define TS_CMD_RECV_SET_CHANNEL_DESCRIPTION 0x0072bef0 //!< Recv change channel +#define TS_CMD_RECV_SET_CHANNEL_MAXPLAYERS 0x0074bef0 //!< Recv change channel +#define TS_CMD_RECV_SET_CHANNEL_FLAGSCODEC 0x0071bef0 //!< Recv change channel +#define TS_CMD_RECV_SET_CHANNEL_ORDER 0x0075bef0 //!< Recv change channel + +#define TS_CMD_RECV_CHANNEL_PASSWORD_CHANGED 0x00ccbef0 //!< Recv channel password changed + +//------------------------------------------------------------------------------ +//! ABC TeamSpeak command. +/*! Abstract base class for processing commands + */ +class TSCommand : public wxObject +{ + DECLARE_CLASS(TSCommand) + public: + /*! CTor + */ + TSCommand(wxUint32 const &id) : m_Id(id) + { + } + + /*! DTor + */ + virtual ~TSCommand() + { + } + + /*! Check if this is the right class. + * \param id Command id. + * \return True if successful. + */ + virtual bool IsCommand(wxUint32 const &id) + { + if(m_Id == id) return true; + else return false; + } + + /*! Precess a command. + * \param istrm Input stream. + * \param ostrm Output stream. + * \param cmd TSCmd object. + * \return True if successful. + */ + virtual bool ProcessCommand(wxInputStream &istrm, + wxOutputStream &ostrm, + TSCmd *cmd) = 0; + + /*! Gets the LastError message, call this method + * to get more information for an error. + * \return LastError message. + */ + wxString const &GetLastError() const + { + return m_LastError; + } + + /*! Get command id. + * \return Command id. + */ + wxUint32 GetId() const + { + return m_Id; + } + + protected: + //Sets the LastError message. + void SetLastError(wxString const &str) + { + m_LastError = str; + } + + const wxUint32 m_Id; + wxString m_LastError; + //class variable + static wxUint32 m_Cnt; +}; + + +//------------------------------------------------------------------------------ +//! TSCmdSendUser +class TSCmdSendLogin : public TSCommand +{ + public: + TSCmdSendLogin():TSCommand(TS_CMD_SEND_LOGIN){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvServer +class TSCmdRecvServer : public TSCommand +{ + public: + TSCmdRecvServer():TSCommand(TS_CMD_RECV_SERVER){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdSendDefault +class TSCmdSendDefault : public TSCommand +{ + public: + TSCmdSendDefault():TSCommand(TS_CMD_SEND_DEFAULT){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvChannel +class TSCmdRecvChannel : public TSCommand +{ + public: + TSCmdRecvChannel():TSCommand(TS_CMD_RECV_CHANNEL){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvUser +class TSCmdRecvUser : public TSCommand +{ + public: + TSCmdRecvUser():TSCommand(TS_CMD_RECV_USER){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdSendAck +class TSCmdSendAck : public TSCommand +{ + public: + TSCmdSendAck():TSCommand(TS_CMD_SEND_ACK){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvAck +class TSCmdRecvAck : public TSCommand +{ + public: + TSCmdRecvAck():TSCommand(TS_CMD_RECV_ACK){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvUrl +class TSCmdRecvUrl : public TSCommand +{ + public: + TSCmdRecvUrl():TSCommand(TS_CMD_RECV_URL){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdSendPing +class TSCmdSendPing : public TSCommand +{ + public: + TSCmdSendPing():TSCommand(TS_CMD_SEND_PING){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvPing +class TSCmdRecvPing : public TSCommand +{ + public: + TSCmdRecvPing():TSCommand(TS_CMD_RECV_PING){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdSendLogout +class TSCmdSendLogout : public TSCommand +{ + public: + TSCmdSendLogout():TSCommand(TS_CMD_SEND_LOGOUT){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvLogoutInfo +class TSCmdRecvLogout : public TSCommand +{ + public: + TSCmdRecvLogout():TSCommand(TS_CMD_RECV_LOGOUT){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvAddPlayer +class TSCmdRecvAddPlayer : public TSCommand +{ + public: + TSCmdRecvAddPlayer():TSCommand(TS_CMD_RECV_ADD_PLAYER){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvPlayerFlags +class TSCmdRecvPlayerFlags : public TSCommand +{ + public: + TSCmdRecvPlayerFlags():TSCommand(TS_CMD_RECV_PLAYER_FLAGS){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvAddChannel +class TSCmdRecvAddChannel : public TSCommand +{ + public: + TSCmdRecvAddChannel():TSCommand(TS_CMD_RECV_ADD_CHANNEL){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvMovePlayer +class TSCmdRecvMovePlayer : public TSCommand +{ + public: + TSCmdRecvMovePlayer():TSCommand(TS_CMD_RECV_MOVE_PLAYER){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvMovePlayer +class TSCmdRecvMovePlayer2 : public TSCommand +{ + public: + TSCmdRecvMovePlayer2():TSCommand(TS_CMD_RECV_MOVE_PLAYER2){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvDelChannel +class TSCmdRecvDelChannel : public TSCommand +{ + public: + TSCmdRecvDelChannel():TSCommand(TS_CMD_RECV_DEL_CHANNEL){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvServerUpdate +class TSCmdRecvServerUpdate : public TSCommand +{ + public: + TSCmdRecvServerUpdate():TSCommand(TS_CMD_RECV_SERVER_UPDATE){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdSendAddChannel +class TSCmdSendAddChannel : public TSCommand +{ + public: + TSCmdSendAddChannel():TSCommand(TS_CMD_SEND_ADD_CHANNEL){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdSendDelChannel +class TSCmdSendDelChannel : public TSCommand +{ + public: + TSCmdSendDelChannel():TSCommand(TS_CMD_SEND_DEL_CHANNEL){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdSendMovePlayer +class TSCmdSendMovePlayer : public TSCommand +{ + public: + TSCmdSendMovePlayer():TSCommand(TS_CMD_SEND_MOVE_PLAYER){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdSendSetChannelPassword +class TSCmdSendSetChannelPassword : public TSCommand +{ + public: + TSCmdSendSetChannelPassword():TSCommand(TS_CMD_SEND_SET_CHANNEL_PASSWORD){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdSendSetChannelName +class TSCmdSendSetChannelName : public TSCommand +{ + public: + TSCmdSendSetChannelName():TSCommand(TS_CMD_SEND_SET_CHANNEL_NAME){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdSendSetChannelTopic +class TSCmdSendSetChannelTopic : public TSCommand +{ + public: + TSCmdSendSetChannelTopic():TSCommand(TS_CMD_SEND_SET_CHANNEL_TOPIC){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdSendSetChannelDescription +class TSCmdSendSetChannelDescription : public TSCommand +{ + public: + TSCmdSendSetChannelDescription():TSCommand(TS_CMD_SEND_SET_CHANNEL_DESCRIPTION){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdSendSetChannelMaxPlayers +class TSCmdSendSetChannelMaxPlayers : public TSCommand +{ + public: + TSCmdSendSetChannelMaxPlayers():TSCommand(TS_CMD_SEND_SET_CHANNEL_MAXPLAYERS){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdSendSetChannelFlagsCodec +class TSCmdSendSetChannelFlagsCodec : public TSCommand +{ + public: + TSCmdSendSetChannelFlagsCodec():TSCommand(TS_CMD_SEND_SET_CHANNEL_FLAGSCODEC){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdSendSetChannelOrder +class TSCmdSendSetChannelOrder : public TSCommand +{ + public: + TSCmdSendSetChannelOrder():TSCommand(TS_CMD_SEND_SET_CHANNEL_ORDER){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvSetChannelName +class TSCmdRecvSetChannelName : public TSCommand +{ + public: + TSCmdRecvSetChannelName():TSCommand(TS_CMD_RECV_SET_CHANNEL_NAME){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvSetChannelTopic +class TSCmdRecvSetChannelTopic : public TSCommand +{ + public: + TSCmdRecvSetChannelTopic():TSCommand(TS_CMD_RECV_SET_CHANNEL_TOPIC){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvSetChannelDescription +class TSCmdRecvSetChannelDescription : public TSCommand +{ + public: + TSCmdRecvSetChannelDescription():TSCommand(TS_CMD_RECV_SET_CHANNEL_DESCRIPTION){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvSetChannelMaxPlayers +class TSCmdRecvSetChannelMaxPlayers : public TSCommand +{ + public: + TSCmdRecvSetChannelMaxPlayers():TSCommand(TS_CMD_RECV_SET_CHANNEL_MAXPLAYERS){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvSetChannelFlagsCodec +class TSCmdRecvSetChannelFlagsCodec : public TSCommand +{ + public: + TSCmdRecvSetChannelFlagsCodec():TSCommand(TS_CMD_RECV_SET_CHANNEL_FLAGSCODEC){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvSetChannelOrder +class TSCmdRecvSetChannelOrder : public TSCommand +{ + public: + TSCmdRecvSetChannelOrder():TSCommand(TS_CMD_RECV_SET_CHANNEL_ORDER){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdSendKickPlayer +class TSCmdSendKickPlayer : public TSCommand +{ + public: + TSCmdSendKickPlayer():TSCommand(TS_CMD_SEND_KICK_PLAYER){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvChannelPasswordChanged +class TSCmdRecvChannelPasswordChanged : public TSCommand +{ + public: + TSCmdRecvChannelPasswordChanged():TSCommand(TS_CMD_RECV_CHANNEL_PASSWORD_CHANGED){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +//------------------------------------------------------------------------------ +//! TSCmdRecvUnknown +class TSCmdRecvUnknown : public TSCommand +{ + public: + TSCmdRecvUnknown():TSCommand(TS_CMD_RECV_UNKNOWN){} + //! See baseclass TSCommand for description. + virtual bool ProcessCommand(wxInputStream &istrm, wxOutputStream &ostrm, TSCmd *cmd); +}; + +#endif diff --git a/tsconnectionthread.cpp b/tsconnectionthread.cpp new file mode 100644 index 0000000..018afdf --- /dev/null +++ b/tsconnectionthread.cpp @@ -0,0 +1,728 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +// Header +#include "tsconnectionthread.h" +#include "wxbufferex.h" + +//Libraries +#include +#include +#include +#include +#include +#include + +WX_DEFINE_LIST(TSQueue); + +IMPLEMENT_CLASS(TSConnectionThread, wxObject) + +//------------------------------------------------------------------------------ +// Default CTor, Initializes the object +TSConnectionThread::TSConnectionThread(TSClient *client, wxMutex *mutex) + : wxThread(wxTHREAD_JOINABLE) +{ + m_pMutex = mutex; + + Create(); + m_pClient = client; + m_ppCommands = new TSpCommandArray; + m_pMySock = new wxDatagramSocket(m_ClientAddr); + m_InQueue = new TSQueue; + m_OutQueue = new TSQueue; + + m_Exit = false; + m_Error = false; + m_Timer = false; + m_pCurCmd = NULL; + m_LocalCmd = true; + m_Connected = false; + m_pMySock = NULL; + + //register known commands + RegisterCommand(new TSCmdSendLogin); + RegisterCommand(new TSCmdRecvServer); + RegisterCommand(new TSCmdSendDefault); + RegisterCommand(new TSCmdRecvChannel); + RegisterCommand(new TSCmdRecvUser); + RegisterCommand(new TSCmdRecvAck); + RegisterCommand(new TSCmdSendAck); + RegisterCommand(new TSCmdRecvUrl); + RegisterCommand(new TSCmdSendPing); + RegisterCommand(new TSCmdRecvPing); + RegisterCommand(new TSCmdSendLogout); + RegisterCommand(new TSCmdRecvLogout); + RegisterCommand(new TSCmdRecvAddPlayer); + RegisterCommand(new TSCmdRecvPlayerFlags); + RegisterCommand(new TSCmdRecvAddChannel); + RegisterCommand(new TSCmdRecvMovePlayer); + RegisterCommand(new TSCmdRecvMovePlayer2); + RegisterCommand(new TSCmdRecvDelChannel); + RegisterCommand(new TSCmdRecvServerUpdate); + RegisterCommand(new TSCmdSendAddChannel); + RegisterCommand(new TSCmdSendDelChannel); + RegisterCommand(new TSCmdSendMovePlayer); + RegisterCommand(new TSCmdSendSetChannelPassword); + RegisterCommand(new TSCmdSendSetChannelName); + RegisterCommand(new TSCmdSendSetChannelTopic); + RegisterCommand(new TSCmdSendSetChannelDescription); + RegisterCommand(new TSCmdSendSetChannelMaxPlayers); + RegisterCommand(new TSCmdSendSetChannelFlagsCodec); + RegisterCommand(new TSCmdSendSetChannelOrder); + RegisterCommand(new TSCmdRecvSetChannelName); + RegisterCommand(new TSCmdRecvSetChannelTopic); + RegisterCommand(new TSCmdRecvSetChannelDescription); + RegisterCommand(new TSCmdRecvSetChannelMaxPlayers); + RegisterCommand(new TSCmdRecvSetChannelFlagsCodec); + RegisterCommand(new TSCmdRecvSetChannelOrder); + RegisterCommand(new TSCmdSendKickPlayer); + RegisterCommand(new TSCmdRecvChannelPasswordChanged); + + //for all unknown commands + RegisterCommand(new TSCmdRecvUnknown); +} + +//------------------------------------------------------------------------------ +//Default DTor +TSConnectionThread::~TSConnectionThread() +{ + /* DON'T USE THIS */ +} + +//------------------------------------------------------------------------------ +// thread execution starts here +wxThread::ExitCode TSConnectionThread::Entry() +{ + wxLogMessage(_T("TSConnection: thread started.")); + + m_ClientAddr.AnyAddress(); + m_ClientAddr.Service(0); + + m_ServerAddr.Hostname(m_pClient->GetServer()->GetServerAddress()); + m_ServerAddr.Service(m_pClient->GetServer()->GetPort()); + + //no methode to reset socket + if (m_pMySock) + { + wxASSERT(m_pMySock != NULL); + m_pMySock->Destroy(); + m_pMySock = NULL; + } + + m_pMySock = new wxDatagramSocket(m_ClientAddr); + if(m_pMySock->Error()) + { + wxLogError(_T("creating socket, terminating thread.")); + return wxThread::ExitCode(EXIT_FAILURE); + } + + m_pMySock->SetTimeout(SOCKET_TIMEOUT); + + //empty dgram to initialize and remember peer + //allows us to use wxSocketOutputStream afterwards + m_pMySock->SendTo(m_ServerAddr, NULL, 0); + + if(!MainLoop()) + { + wxLogDebug(_T("Error: %s"), GetLastError().c_str()); + return wxThread::ExitCode(EXIT_FAILURE); + } + + return wxThread::ExitCode(EXIT_SUCCESS); +} + +//------------------------------------------------------------------------------ +// and stops here +void TSConnectionThread::OnExit() +{ + wxLogDebug(_T("TSConnection: thread terminated.")); + + //do the necessary cleanup + for(size_t i = 0; i < m_ppCommands->GetCount(); i++) + delete m_ppCommands->Item(i); + + m_InQueue->DeleteContents(true); + m_OutQueue->DeleteContents(true); + + wxASSERT(m_InQueue != NULL); + delete m_InQueue; + m_InQueue = NULL; + + wxASSERT(m_OutQueue != NULL); + delete m_OutQueue; + m_OutQueue = NULL; + + wxASSERT(m_ppCommands != NULL); + delete m_ppCommands; + m_ppCommands = NULL; + + wxASSERT(m_pMySock != NULL); + m_pMySock->Destroy(); + m_pMySock = NULL; + + if(m_pCurCmd != NULL) + { + delete m_pCurCmd; + m_pCurCmd = NULL; + } +} + +//------------------------------------------------------------------------------ +// SyncSendCmdError +bool TSConnectionThread::SyncSendCmdLastError() +{ + //wxLogDebug(_T("SyncSendCmdLastError")); + m_LocalCmd = true; + + m_SWTimeout.Start(); + m_SWTimeout.Pause(); + + TSCmd *cmd = m_pClient->GetSync(); + cmd->error = true; + cmd->lasterror = m_LastError; + cmd->executed = true; + m_pClient->m_Lock = false; + return true; +} + +//------------------------------------------------------------------------------ +// Sync with TSClient and send command +bool TSConnectionThread::SyncSendCmd() +{ + //wxLogDebug(_T("SyncSendCmd")); + TSCmd *cmd = m_pClient->GetSync(); + m_pCurCmd = cmd; + + if(cmd->id == 0) + { + SetLastError(_T("no command id")); + SyncSendCmdLastError(); + return true; + } + + if(cmd->id != TS_CMD_SEND_LOGIN && + cmd->id != TS_CMD_SEND_DEFAULT && + !m_Connected) + { + SetLastError(_T("no connection to server")); + SyncSendCmdLastError(); + return true; + } + + m_LocalCmd = false; + SendCommand(cmd); + + return true; +} + +//------------------------------------------------------------------------------ +// Register a Command, the class takes care of this pointer. +void TSConnectionThread::RegisterCommand(TSCommand *cmd) +{ + wxASSERT(cmd != NULL); + m_ppCommands->Add(cmd); +} + +//------------------------------------------------------------------------------ +// Executes a command. +bool TSConnectionThread::ExecuteCommand(wxInputStream &istrm, + wxOutputStream &ostrm, + TSCmd *cmd) +{ + wxLogDebug(_T("ExecuteCommand: 0x%X"), cmd->id); + for(size_t i = 0; i < m_ppCommands->GetCount(); i++) + { + if(m_ppCommands->Item(i)->IsCommand(cmd->id)) + { + if(m_ppCommands->Item(i)->ProcessCommand(istrm, ostrm, cmd)) + return true; + else + { + SetLastError(m_ppCommands->Item(i)->GetLastError()); + return false; + } + } + } + + #ifdef IGNORE_UNKNOWN_COMMANDS + //used for unknown commands + cmd->id = TS_CMD_RECV_UNKNOWN; + return ExecuteCommand(istrm, ostrm, cmd); + #else + SetLastError(_T("invalid command")); + return false; + #endif +} + +//------------------------------------------------------------------------------ +// Dumps object. +void TSConnectionThread::Dump(wxOutputStream &ostrm) const +{ + wxTextOutputStream out(ostrm); + out << _T("Object: TSConnection (") << wxString::Format(_T("0x%X"), this) << _T(")") << endl; + out << _T("-wxString m_LastError: ") << m_LastError << endl; +} + +//------------------------------------------------------------------------------ +// send command. +bool TSConnectionThread::SendOutputCommand(TSCmd *cmd) +{ + //wxLogDebug(_T("SendOutputCommand: 0x%X"), cmd->id); + if(!SendCommandToSocket(cmd)) + return false; + + /* this m_pCurCmd code possibly contains a memleak + * the lines below solves ~95% of them + */ + /*if(m_pCurCmd != NULL) + { + delete m_pCurCmd; + m_pCurCmd = NULL; + }*/ + + switch(cmd->id) + { + case TS_CMD_SEND_LOGIN: + AddInputCommand(new TSCmd(TS_CMD_RECV_SERVER, cmd)); + m_pCurCmd = new TSCmd(TS_CMD_RECV_SERVER, cmd); + break; + case TS_CMD_SEND_DEFAULT: + AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd)); + m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd); + break; + case TS_CMD_SEND_PING: + AddInputCommand(new TSCmd(TS_CMD_RECV_PING, cmd)); + m_pCurCmd = new TSCmd(TS_CMD_RECV_PING, cmd); + break; + case TS_CMD_SEND_LOGOUT: + AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd)); + m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd); + break; + case TS_CMD_SEND_ADD_CHANNEL: + AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd)); + m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd); + break; + case TS_CMD_SEND_DEL_CHANNEL: + AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd)); + m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd); + break; + case TS_CMD_SEND_MOVE_PLAYER: + AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd)); + m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd); + break; + case TS_CMD_SEND_SET_CHANNEL_PASSWORD: + AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd)); + m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd); + break; + case TS_CMD_SEND_SET_CHANNEL_NAME: + AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd)); + m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd); + break; + case TS_CMD_SEND_SET_CHANNEL_TOPIC: + AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd)); + m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd); + break; + case TS_CMD_SEND_SET_CHANNEL_DESCRIPTION: + AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd)); + m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd); + break; + case TS_CMD_SEND_SET_CHANNEL_MAXPLAYERS: + AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd)); + m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd); + break; + case TS_CMD_SEND_SET_CHANNEL_FLAGSCODEC: + AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd)); + m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd); + break; + case TS_CMD_SEND_SET_CHANNEL_ORDER: + AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd)); + m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd); + break; + case TS_CMD_SEND_KICK_PLAYER: + AddInputCommand(new TSCmd(TS_CMD_RECV_ACK, cmd)); + m_pCurCmd = new TSCmd(TS_CMD_RECV_ACK, cmd); + break; + case TS_CMD_SEND_ACK: + break; + } + + return true; +} + +//------------------------------------------------------------------------------ +// SendQueuedCommand. +bool TSConnectionThread::SendQueuedCommand() +{ + //wxLogDebug(_T("SendQueuedCommand")); + wxTSQueueNode *node = m_OutQueue->GetFirst(); + TSCmd *t = node->GetData(); + if(!SendOutputCommand(t)) + return false; + + delete t; + if(!m_OutQueue->DeleteNode(node)) + { + SetLastError(_T("deleting node")); + return false; + } + + return true; +} + +//------------------------------------------------------------------------------ +// Send command. +bool TSConnectionThread::SendCommand(TSCmd *cmd) +{ + //wxLogDebug(_T("SendCommand: 0x%X"), cmd->id); + if(m_pCurCmd == NULL) + m_pCurCmd = cmd; + + m_SWTimeout.Start(); + + if(!SendOutputCommand(cmd)) + return false; + m_Retries = 0; + return true; +} + +//------------------------------------------------------------------------------ +// Send command to socket. +bool TSConnectionThread::SendCommandToSocket(TSCmd *cmd) +{ + //wxLogDebug(_T("SendCommandToSocket: 0x%X"), cmd->id); + wxLogVerbose(_T("TSClient: command %#x sent"),cmd->id); + + wxSocketOutputStream so(*m_pMySock); + wxBufferedOutputStream out(so); + wxSocketInputStream si(*m_pMySock); + wxBufferedInputStream in(si); + + if(!ExecuteCommand(in, out, cmd)) + { + SetLastError(_T("execute command")); + return false; + } + + out.Sync(); + return true; +} + +//------------------------------------------------------------------------------ +// Add command. +void TSConnectionThread::AddOutputCommand(TSCmd *cmd) +{ + //wxLogDebug(_T("AddOutputCommand: 0x%X"), cmd->id); + m_OutQueue->Append(cmd); +} + +//------------------------------------------------------------------------------ +// CheckInputQueue +bool TSConnectionThread::CheckInputQueue(TSCmd *cmd) +{ + wxLogDebug(_T("CheckInputQueue: 0x%X, 0x%X"), cmd->id, cmd->pktid); + + switch(cmd->id) + { + case TS_CMD_RECV_CHANNEL: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_USER: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_URL: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + wxLogVerbose(_T("TSClient: connected")); + m_Connected = true; + m_Timer = true; + break; + case TS_CMD_RECV_LOGOUT: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_UNKNOWN: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_ACK: + break; + case TS_CMD_RECV_SERVER: + //AddOutputCommand(new TSCmd(TS_CMD_SEND_DEFAULT, cmd)); + break; + case TS_CMD_RECV_ADD_PLAYER: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_PLAYER_FLAGS: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_ADD_CHANNEL: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_MOVE_PLAYER: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_MOVE_PLAYER2: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_DEL_CHANNEL: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_SERVER_UPDATE: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + // force reconnect for the sake of consistency + AddOutputCommand(new TSCmd(TS_CMD_SEND_LOGOUT, cmd)); + break; + case TS_CMD_RECV_SET_CHANNEL_NAME: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_SET_CHANNEL_TOPIC: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_SET_CHANNEL_DESCRIPTION: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_SET_CHANNEL_MAXPLAYERS: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_SET_CHANNEL_FLAGSCODEC: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_SET_CHANNEL_ORDER: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_CHANNEL_PASSWORD_CHANGED: + AddOutputCommand(new TSCmd(TS_CMD_SEND_ACK, cmd)); + break; + case TS_CMD_RECV_PING: + break; + default: + wxLogWarning(_T("input queue: invalid command %#x, ignoring"), cmd->id); + break; + } + + for(wxTSQueueNode *node = m_InQueue->GetFirst(); node != NULL; node = node->GetNext()) + { + TSCmd *cur = node->GetData(); + //cmd found + if(cur->id == cmd->id) + { + delete cur; + if(!m_InQueue->DeleteNode(node)) + { + SetLastError(_T("deleting node")); + return false; + } + //return true; + } + + if(m_pCurCmd->id == cmd->id) + { + m_pMutex->Lock(); + + wxLogDebug(_T("found in queue: 0x%X"), cmd->id); + delete m_pCurCmd; + m_pCurCmd = NULL; + if (!m_LocalCmd) + { + m_pClient->m_Lock = false; + m_pClient->GetSync()->executed = true; + } + m_LocalCmd = true; + + m_SWTimeout.Pause(); + + m_pMutex->Unlock(); + + return true; + } + } + + return true; +} + +//------------------------------------------------------------------------------ +// ReadQueuedCommand. +bool TSConnectionThread::RecvCommand() +{ + wxSocketOutputStream so(*m_pMySock); + wxMemoryBufferEx buf(1024); + m_pMySock->RecvFrom(m_ServerAddr, buf.GetData(), 1024); + buf.SetDataLen(m_pMySock->LastCount()); + wxMemoryInputStream in(buf.GetData(), buf.GetDataLen()); + wxDataInputStream data(in); + + TSCmd cmd; + cmd.id = data.Read32(); //read id + data.Read32(); //Session id + data.Read32(); //Player id + cmd.pktid = data.Read32(); //Packet count + cmd.client = m_pClient; + in.SeekI(0); + + wxLogVerbose(_T("TSClient: command %#x received"), cmd.id); + + // dirty workaround for crappy teamspeak protocol, which splits off pakets + if(cmd.id == TS_CMD_RECV_CHANNEL) + { + in.SeekI(-1, wxFromEnd); + if(data.Read8() != 0) + { + wxMemoryBuffer buf_b2(1024); + m_pMySock->RecvFrom(m_ServerAddr, buf_b2.GetData(), 1024); + buf_b2.SetDataLen(m_pMySock->LastCount()); + wxMemoryInputStream in_b2(buf_b2.GetData(), buf_b2.GetDataLen()); + wxDataInputStream data_b2(in_b2); + + if(data_b2.Read32() != cmd.id) + { + SetLastError(_T("invalid command, perhaps wrong paket order (udp?)")); + return false; + } + + data_b2.Read32(); //Session id + data_b2.Read32(); //Player id + cmd.pktid = data_b2.Read32(); //Packet count + data_b2.Read32(); //read unknown + data_b2.Read32(); //CRC + + // send acknowledge for 2nd packet + if(!CheckInputQueue(&cmd)) + return false; + + // append bytes + while(!in_b2.Eof()) + buf.AppendByte(in_b2.GetC()); + } + in.SeekI(0); + } + + // update streams (dirty, but copy-operator is private) + wxMemoryInputStream in2(buf.GetData(), buf.GetDataLen()); + wxDataInputStream data2(in2); + if(!ExecuteCommand(in2, so, &cmd)) + { + switch(cmd.id) + { + case TS_CMD_RECV_SERVER: + SyncSendCmdLastError(); + break; + } + + return false; + } + if(!CheckInputQueue(&cmd)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +// Add command. +void TSConnectionThread::AddInputCommand(TSCmd *cmd) +{ + //wxLogDebug(_T("AddInputCommand: 0x%X"), cmd->id); + m_InQueue->Append(cmd); +} + +//------------------------------------------------------------------------------ +// StartMainLoop +bool TSConnectionThread::MainLoop() +{ + wxStopWatch sw; + sw.Start(); + m_Retries = 0; + + while(1) + { + //Is new command available + m_pMutex->Lock(); + if((m_pClient->GetSync() != NULL) && + (m_pCurCmd == NULL) && + (m_pClient->m_Lock) && + (m_OutQueue->GetCount() == 0)) + { + m_SWTimeout.Start(); + SyncSendCmd(); + } + m_pMutex->Unlock(); + + //Is some data in queue + if(m_OutQueue->GetCount() != 0) + { + if(!SendQueuedCommand()) + return false; + } + + //Is new data available + if(m_pMySock->IsData()) + { + if(!RecvCommand()) + return false; + } + + //Send ping + if((sw.Time() >= PING_INTERMITTENT) && m_Timer) + { + sw.Start(); + TSCmd tmp; + tmp.client = m_pClient; + if(m_pCurCmd == NULL) + SendCommand(new TSCmd(TS_CMD_SEND_PING, &tmp)); + } + + //Check for timeout + if(m_SWTimeout.Time() > CMD_TIMEOUT) + { + SetLastError(_T("command timeout")); + + m_pCurCmd = NULL; + + if(!m_LocalCmd) + { + SyncSendCmdLastError(); + } + + m_LocalCmd = true; + //reset timer + m_SWTimeout.Start(); + m_SWTimeout.Pause(); + + wxLogVerbose(_T("TSClient: disconnected")); + m_Connected = false; + /* + if(++m_Retries <= MAX_RETRIES) + { + m_Connected = false; + } + */ + return false; + } + + //Check if we should delete our self + if(TestDestroy()) + return true; + + //If an error occurred, end thread + if(m_Error) + return false; + + //If m_Exit is set, end thread + if(m_Exit) + return true; + + Sleep(10); + } +} + diff --git a/tsconnectionthread.h b/tsconnectionthread.h new file mode 100644 index 0000000..2d67be6 --- /dev/null +++ b/tsconnectionthread.h @@ -0,0 +1,176 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +#ifndef TSCONNECTION_H +#define TSCONNECTION_H + +// Libraries +#include +#include +#include +#include +#include +#include + +#include "tsheaders.h" + +//WX_DECLARE_LIST +WX_DECLARE_LIST_PTR(TSCmd, TSQueue); + +//! Repeat ping command after ...milliseconds +#define PING_INTERMITTENT 1000 +//! Socket timeout ...seconds +#define SOCKET_TIMEOUT 5 +//! Number of packets t loos for disconnect +#define MAX_RETRIES 3 +//! Command timeout in milliseconds +#define CMD_TIMEOUT 5000 + + +//! Ignore unknown commands +#define IGNORE_UNKNOWN_COMMANDS + +//! TeamSpeak connection thread. +/*! TSConnectionThread is used to communicate with the server. + * without bocking the main thread. + */ +class TSConnectionThread : public wxThread +{ + friend class TSClient; + + DECLARE_CLASS(TSConnectionThread) + + public: + /*! thread execution starts here + * \return Returns ExitCode. + */ + virtual ExitCode Entry(); + + /*! and stops here + */ + virtual void OnExit(); + + /*! Default CTor, Initializes the object. + */ + TSConnectionThread(TSClient *client, wxMutex *mutex); + + /*! Default DTor. + */ + ~TSConnectionThread(); + + /*! Register a command, the class takes care of this pointer. + * \param cmd Command. + */ + void RegisterCommand(TSCommand *cmd); + + /*! Start main loop. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool MainLoop(); + + /*! Executes a command. + * \param cmd Command. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool ExecuteCommand(wxInputStream &istrm, wxOutputStream &ostrm, + TSCmd *cmd); + + /*! Sync with TSClient and send command. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SyncSendCmd(); + + /*! Add command. + * \param cmd Command. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SendOutputCommand(TSCmd *cmd); + + /*! Add command. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SendQueuedCommand(); + + /*! Add command. + * \param cmd Command. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + void AddInputCommand(TSCmd *cmd); + + void AddOutputCommand(TSCmd *cmd); + + bool RecvCommand(); + + bool CheckInputQueue(TSCmd *cmd); + + /*! Gets the LastError message, call this method + * to get more information for an error. + * \return LastError message. + */ + wxString const &GetLastError() const + { + return m_LastError; + } + + /*! Dumps object. + * \param ostrm Stream to write. + */ + void Dump(wxOutputStream &ostrm) const; + + private: + //Sets the LastError message. + void SetLastError(wxString const &str) + { + m_LastError = str; + } + + // Send command + bool SendCommand(TSCmd *cmd); + + // Send command to socket + bool SendCommandToSocket(TSCmd *cmd); + + // SyncSendCmdError + bool SyncSendCmdLastError(); + + wxString m_LastError; + wxDatagramSocket *m_pMySock; + TSpCommandArray *m_ppCommands; + wxIPV4address m_ClientAddr; + wxIPV4address m_ServerAddr; + TSQueue *m_InQueue; + TSQueue *m_OutQueue; + TSClient *m_pClient; + bool m_Exit; + bool m_Error; + bool m_LocalCmd; + bool m_Timer; + bool m_Connected; + int m_Retries; + wxMutex *m_pMutex; + TSCmd *m_pCurCmd; + wxStopWatch m_SWTimeout; +}; + +#endif diff --git a/tsheaders.h b/tsheaders.h new file mode 100644 index 0000000..d451b8c --- /dev/null +++ b/tsheaders.h @@ -0,0 +1,62 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +#ifndef _TSDAEMON_H +#define _TSDAEMON_H + +#include +#include + +// Forward class declarations +class TSClient; +class TSCommand; +class TSConnectionThread; +class TSServer; +class TSChannel; +class TSPlayer; +//only for internal use +struct TSCmd; + +//define ARRAY_PTR +//equivalent to stl::vector +WX_DEFINE_ARRAY_PTR(TSPlayer*, TSpPlayerArray); + +//define ARRAY_PTR +//equivalent to stl::vector +WX_DEFINE_ARRAY_PTR(TSChannel*, TSpChannelArray); + +//define ARRAY_PTR +//equivalent to stl::vector +WX_DEFINE_ARRAY_PTR(TSCommand*, TSpCommandArray); + +#if SIZEOF_INT == 4 +# define TS_NUM_MAX UINT_MAX +#elif SIZEOF_INT == 2 +# define TS_NUM_MAX ULONG_MAX +#else +# error "No 32bit int type on this platform" +#endif + +// Include classes, for declarations +#include "tschannel.h" +#include "tsclient.h" +#include "tscommand.h" +#include "tsconnectionthread.h" +#include "tsplayer.h" + +#endif diff --git a/tsplayer.cpp b/tsplayer.cpp new file mode 100644 index 0000000..268adfc --- /dev/null +++ b/tsplayer.cpp @@ -0,0 +1,200 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +// Header +#include "tsplayer.h" + +//Libraries +#include + +IMPLEMENT_CLASS(TSPlayer, wxObject) + +//------------------------------------------------------------------------------ +//Default CTor, Initializes the object. +TSPlayer::TSPlayer() +{ + m_Id = 0; + m_Flags = 0; + m_Privileges = 0; + m_ChannelId = 0; + m_ChannelPrivileges = 0; + m_Anonymous = true; + m_ServerAssingnsNickname = false; +} + +//------------------------------------------------------------------------------ +//Default DTor. +TSPlayer::~TSPlayer() +{ +} + +//------------------------------------------------------------------------------ +// Sets the player id. +bool TSPlayer::SetId(wxUint32 const id) +{ + m_Id = id; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the player channel Id. +bool TSPlayer::SetChannelId(wxUint32 const id) +{ + m_ChannelId = id; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the player flags. +bool TSPlayer::SetFlags(wxUint16 const flags) +{ + m_Flags = flags; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the player privileges. +bool TSPlayer::SetPrivileges(wxUint16 const privs) +{ + m_Privileges = privs; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the channel privileges. +bool TSPlayer::SetChannelPrivileges(wxUint16 const privs) +{ + m_ChannelPrivileges = privs; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the player nickname. +bool TSPlayer::SetNickname(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("empty string")); + return false; + } + + m_Nickname = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the login name. +bool TSPlayer::SetLoginName(wxString const &str) +{ + if(str.Length() == 0) + { + m_Anonymous = ANONYMOUS_YES; + return true; + } + + m_LoginName = str; + m_Anonymous = ANONYMOUS_NO; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the login password. +bool TSPlayer::SetLoginPassword(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("empty string")); + return false; + } + + m_LoginPassword = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the default channel. +bool TSPlayer::SetDefaultChannel(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("empty string")); + return false; + } + + m_DefaultChannel = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the default subchannel. + bool TSPlayer::SetDefaultSubchannel(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("empty string")); + return false; + } + + m_DefaultSubchannel = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the default channel password. +bool TSPlayer::SetDefaultChannelPassword(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("empty string")); + return false; + } + + m_DefaultChannelPassword = str; + return true; +} + +//------------------------------------------------------------------------------ +// Dumps object. +void TSPlayer::Dump(wxOutputStream &ostrm) const +{ + wxTextOutputStream out(ostrm); + out << _T("Object: TSPlayer (") << wxString::Format(_T("0x%X"), this) << _T(")") << endl; + out << _T("-wxUint32 m_Id: ") << wxString::Format(_T("0x%X"), m_Id) << endl; + out << _T("-wxUint16 m_Flags: ") << wxString::Format(_T("0x%X"), m_Flags) << endl; + out << _T("-wxUint16 m_Privileges: ") << wxString::Format(_T("0x%X"), m_Privileges) << endl; + out << _T("-wxUint32 m_ChannelId: ") << wxString::Format(_T("0x%X"), m_ChannelId) << endl; + out << _T("-wxUint16 m_ChannelPrivileges: ") << wxString::Format(_T("0x%X"), m_ChannelPrivileges) << endl; + out << _T("-wxString m_Nickname: ") << m_Nickname << endl; + out << _T("-wxString m_LoginName: ") << m_LoginName << endl; + out << _T("-wxString m_LoginPassword: ") << m_LoginPassword << endl; + out << _T("-wxString m_DefaultChannel: ") << m_DefaultChannel << endl; + out << _T("-wxString m_DefaultSubchannel: ") << m_DefaultSubchannel << endl; + out << _T("-wxString m_DefaultChannelPassword: ") << m_DefaultChannelPassword << endl; + out << _T("-wxUint8 m_Anonymous: ") << wxString::Format(_T("0x%X"), m_Anonymous) << endl; + out << _T("-wxUint8 m_ServerAssingnsNickname: ") << wxString::Format(_T("0x%X"), m_ServerAssingnsNickname) << endl; + out << _T("-wxString m_LastError: ") << m_LastError << endl; +} + +//------------------------------------------------------------------------------ +// Should the server assing a nickname. +bool TSPlayer::SetServerAssingnsNickname(wxUint8 const assing) +{ + m_ServerAssingnsNickname = assing; + return true; +} + diff --git a/tsplayer.h b/tsplayer.h new file mode 100644 index 0000000..84daa9b --- /dev/null +++ b/tsplayer.h @@ -0,0 +1,339 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +#ifndef TSPLAYER_H +#define TSPLAYER_H + +#include "tsheaders.h" + +//Libraries +#include +#include + +//------------------------------------------------------------------------------ +// Player flags +//! Channel Commander +#define TS_CHANNEL_COMMANDER 1 +//! Voice Request +#define TS_VOICE_REQUEST 2 +//! Doesnt Accept Whispers +#define TS_DOESNT_ACCEPT_WHISPER 4 +//! Away +#define TS_AWAY 8 +//! Microphone Muted +#define TS_MICROPHONE_MUTED 16 +//! Sound Muted +#define TS_SOUND_MUTED 32 +//! Recording +#define TS_RECORDING 64 + +//------------------------------------------------------------------------------ +//! Player privileges +//! SA server admin +#define TS_SERVER_ADMIN 1 +//! Allow Registration +#define TS_ALLOW_REGISTRATION 2 +//! Registered +#define TS_REGISTERED 4 +//! Internal Use +#define TS_INTERNAL_USE 8 +//! Stickey +#define TS_STICKY 16 + +//------------------------------------------------------------------------------ +//! Channel privileges +//! Channel Admin +#define TS_CHANNEL_ADMIN 1 +//! Operator +#define TS_OPERATOR 2 +//! Voice +#define TS_VOICE 4 +//! Auto Operator +#define TS_AUTO_OPERATOR 8 +//! Auto Voice +#define TS_AUTO_VOICE 16 + +//------------------------------------------------------------------------------ +//! Anonymous login +//! +#define ANONYMOUS_YES 1 +//! +#define ANONYMOUS_NO 2 + +//------------------------------------------------------------------------------ +//! Server assingns nickname +//! +#define SAN_YES 1 +//! +#define SAN_NO 0 + +//! TeamSpeak player. +/*! TSPlayer is used to hold all player informations. + * After calling TSClient::Connect(), you can read + * out all the player attributes. These stepps are + * necessary to connect to a server and read all information + * out. + * - Create a TSServer object,edit and link it to the TSClient object + * (For more information see TSClient) + * - Call TSClient::Connect() + * - Call TSClient::GetPlayer() or GetPlayers() + * - Now the class is filled up with the player information + */ +class TSPlayer : public wxObject +{ + DECLARE_CLASS(TSPlayer) + public: + /*! Default CTor, Initializes the object. + */ + TSPlayer(); + + /*! Default DTor. + */ + ~TSPlayer(); + + /*! Sets the player Id. + * \param id Player Id. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetId(wxUint32 const id); + + /*! Sets the player channel Id. + * \param id Player channel Id. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetChannelId(wxUint32 const id); + + /*! Sets the player flags. + * \param flags Player flags. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetFlags(wxUint16 const flags); + + /*! Sets the player privileges. + * \param privs Player privileges. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetPrivileges(wxUint16 const privs); + + /*! Sets the channel privileges. + * \param privs Channel privileges. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetChannelPrivileges(wxUint16 const privs); + + /*! Sets the player nickname. + * \param str Player nickname. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetNickname(wxString const &str); + + /*! Sets the login name. + * If called with an empty string, Anonymous login is enabled, + * which is also default. Else Anonymous login is disabled. + * \param str Login name. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetLoginName(wxString const &str); + + /*! Sets the login password. + * \param str Login password. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetLoginPassword(wxString const &str); + + /*! Sets the default channel. + * \param str Default channel. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetDefaultChannel(wxString const &str); + + /*! Sets the default subchannel. + * \param str Default subchannel. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetDefaultSubchannel(wxString const &str); + + /*! Sets the default channel password. + * \param str Default channel password. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetDefaultChannelPassword(wxString const &str); + + /*! Should the server assing a nickname. + * - no: 0 + * - yes: 1 + * \param assing Server assing a nickname. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetServerAssingnsNickname(wxUint8 const assing); + + /*! Gets the player Id. + * \return Player Id. + */ + wxUint32 GetId() const + { + return m_Id; + } + + /*! Gets the player flags. + * \return Player flags. + */ + wxUint32 GetFlags() const + { + return m_Flags; + } + + /*! Gets the player privileges. + * \return Player privileges. + */ + wxUint32 GetPrivileges() const + { + return m_Privileges; + } + + /*! Gets the channel Id. + * \return Channel Id. + */ + wxUint32 GetChannelId() const + { + return m_ChannelId; + } + + /*! Gets the channel privileges. + * \return Channel privileges. + */ + wxUint32 GetChannelPrivileges() const + { + return m_ChannelPrivileges; + } + + /*! Gets the player nickname. + * \return Player nickname. + */ + wxString const &GetNickname() const + { + return m_Nickname; + } + + /*! Gets the player login name. + * \return Player login name. + */ + wxString const &GetLoginName() const + { + return m_LoginName; + } + + /*! Gets the player login password. + * \return Player login password. + */ + wxString const &GetLoginPassword() const + { + return m_LoginPassword; + } + + /*! Gets the player default channel. + * \return Player default channel. + */ + wxString const &GetDefaultChannel() const + { + return m_DefaultChannel; + } + + /*! Gets the player default sub channel. + * \return Player default sub channel. + */ + wxString const &GetDefaultSubchannel() const + { + return m_DefaultSubchannel; + } + + /*! Gets the player default channel password. + * \return Player default channel password. + */ + wxString const &GetDefaultChannelPassword() const + { + return m_DefaultChannelPassword; + } + + /*! Gets the player server assingns nickname status. + * \return Player ServerAssingnsNickname. + */ + wxUint8 GetServerAssingnsNickname() const + { + return m_ServerAssingnsNickname; + } + + /*! Gets the player anonymous login status. + * \return Player default channel password. + */ + wxUint8 GetAnonymous() const + { + return m_Anonymous; + } + + /*! Dumps object. + * \param ostrm Stream to write. + */ + void Dump(wxOutputStream &ostrm) const; + + /*! Gets the LastError message, call this method + * to get more information for an error. + * \return LastError message. + */ + wxString const &GetLastError() const + { + return m_LastError; + } + + private: + //Sets the LastError message. + void SetLastError(wxString const &str) + { + m_LastError = str; + } + + //members + wxUint32 m_Id; + wxUint16 m_Flags; + wxUint16 m_Privileges; + wxUint32 m_ChannelId; + wxUint16 m_ChannelPrivileges; + wxString m_Nickname; + wxString m_LoginName; + wxString m_LoginPassword; + wxString m_DefaultChannel; + wxString m_DefaultSubchannel; + wxString m_DefaultChannelPassword; + wxString m_LastError; + wxUint8 m_Anonymous; + wxUint8 m_ServerAssingnsNickname; +}; + +#endif diff --git a/tsquerythread.cpp b/tsquerythread.cpp new file mode 100644 index 0000000..94a1fef --- /dev/null +++ b/tsquerythread.cpp @@ -0,0 +1,1105 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +// Header +#include "tsquerythread.h" +#include "wxbufferex.h" +#include "base64.h" + +//Libraries +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +IMPLEMENT_CLASS(TSQueryThread, wxObject) + +//------------------------------------------------------------------------------ +static bool strToChannelId(wxString &str, wxUint32 *pid, + bool pid_allowed = true) +{ + unsigned long l; + if (!str.ToULong(&l)) + return false; + if (l == ULONG_MAX) + l = TS_NO_PARENT; + if (l > TS_NO_PARENT || (!pid_allowed && l == TS_NO_PARENT)) + return false; + *pid = wxUint32(l); + return true; +} + +static bool strToNum(wxString &str, wxUint32 *val) +{ + unsigned long l; + if (!str.ToULong(&l)) + return false; + if (l > TS_NUM_MAX) + return false; + *val = wxUint32(l); + return true; +} + +//------------------------------------------------------------------------------ +// thread execution starts here +wxThread::ExitCode TSQueryThread::Entry() +{ + wxLogMessage(_T("TSQuery: thread started.")); + + // init libxml2 library + wxXml2::Init(); + + //check for bind + if(m_ServerAddress.Length() < 7 || m_ServerAddress == _T("0.0.0.0")) + m_ServerAddr.AnyAddress(); + else + m_ServerAddr.Hostname(m_ServerAddress); + + m_ServerAddr.Service(m_Port); + m_pSocket = new wxSocketServer(m_ServerAddr, wxSOCKET_REUSEADDR); + + //Check socket + if(!m_pSocket->Ok()) + { + if(m_pSocket->LastError() == wxSOCKET_INVPORT) + SetLastError(_T("Socket port in use")); + else + SetLastError(_T("Socket error")); + m_pSocket->Destroy(); + m_pSocket = NULL; + return wxThread::ExitCode(EXIT_FAILURE); + } + + while(1) + { + if (!Accept()) + wxLogError(_T("TSQuery: %s"), m_LastError.c_str()); + if (m_pSocket == NULL) + break; + } + + return wxThread::ExitCode(EXIT_SUCCESS); +} + +//------------------------------------------------------------------------------ +// and stops here +void TSQueryThread::OnExit() +{ + wxLogDebug(_T("TSQuery: thread terminated.")); + + // cleanup libxml2 statics + wxXml2::Cleanup(); + + if(m_pSocket != NULL) + { + m_pSocket->Destroy(); + m_pSocket = NULL; + } +} + +//------------------------------------------------------------------------------ +// Default CTor, Initializes the object. +TSQueryThread::TSQueryThread(TSClient *client) : wxThread(wxTHREAD_JOINABLE) +{ + Create(); + //create all objects + //m_pSocket = new wxSocketServer(m_ServerAddr, wxSOCKET_REUSEADDR); + m_pClient = client; + m_Password = _T(""); +} + +//------------------------------------------------------------------------------ +// Default DTor. +TSQueryThread::~TSQueryThread() +{ + //use OnExit() +} + +//------------------------------------------------------------------------------ +// Listen +bool TSQueryThread::Accept() +{ + //Wait until someone connect (NOTE: wxWidgets has an internal select timeout (~10 mins)) + wxSocketBase *sock = m_pSocket->Accept(); + + // wxSocketBase doesn't set Error() to true after socket timeout, so we check against null + if(m_pSocket->LastError() == wxSOCKET_TIMEDOUT && sock == NULL) + return true; + + // real check against null + if(sock == NULL) + { + SetLastError(_T("Socket, something really bad happend")); + m_pSocket->Destroy(); + m_pSocket = NULL; + return false; + } + + //Check if IP is allowed + wxIPV4address peeraddr; + sock->GetPeer(peeraddr); + + wxLogMessage(_T("TSQuery: incoming request from %s"), peeraddr.IPAddress().c_str()); + + if(!IsIPAllowed(peeraddr.IPAddress())) + { + wxLogError(_T("TSQuery: %s"),GetLastError().c_str()); + sock->Destroy(); + return false; + } + + //now receive + wxMemoryBufferEx buf(1024); + sock->Read(buf.GetData(), 1024); + buf.SetDataLen(sock->LastCount()); + wxMemoryInputStream in(buf.GetData(), buf.GetDataLen()); + + wxStringOutputStream strm; + buf.HexDump(strm); + wxLogDebug(_T("TSQuery: command received:\n%s"), strm.GetString().c_str()); + + //Check socket + if(sock->LastCount() == 0) + { + SetLastError(_T("Socket, no data available")); + sock->Destroy(); + return false; + } + + //Check XML format + wxString err; + if (!m_pXml.Load(in, &err)) + { + wxLogError(_T("XML format error: %s"), err.c_str()); + return false; + } + + //check node format + if(!IsValidFormat()) + { + SendError(_T("General"), GetLastError(), sock); + sock->Destroy(); + return false; + } + + //check password + wxXml2Node pNode = m_pXml.GetRoot().Get(_T("Password")).GetFirstChild(); + if(pNode.GetContent() != m_Password) + { + pNode = m_pXml.GetRoot().Get(_T("Command")).GetFirstChild(); + SetLastError(_T("Invalid password")); + SendError(pNode.GetContent(), GetLastError(), sock); + sock->Destroy(); + return false; + } + + //check if TSClient is connected + if(!m_pClient->IsConnected()) + { + pNode = m_pXml.GetRoot().Get(_T("Command")).GetFirstChild(); + SetLastError(_T("No connection to TSServer")); + SendError(pNode.GetContent(), GetLastError(), sock); + sock->Destroy(); + return false; + } + + //ok now process the command + if(!ProcessCommand(sock)) + { + sock->Destroy(); + return false; + } + + sock->Destroy(); + wxLogMessage(_T("TSQuery: request successfully processed.")); + return true; +} + +//------------------------------------------------------------------------------ +// IsIPAllowed +bool TSQueryThread::IsIPAllowed(wxString const &str) +{ + wxStringTokenizer tkz(m_AllowedAddresses, _T(",")); + bool found = false; + while(tkz.HasMoreTokens()) + { + wxString token = tkz.GetNextToken(); + wxIPV4address tmpaddr; + if(!tmpaddr.Hostname(token)) + { + SetLastError(wxString::Format(_T("'%s' this is no valid IP"),token.c_str())); + return false; + } + unsigned ip1[4], ip2[4]; + if(tmpaddr.IPAddress() == str) + { + found = true; + break; + } + //dirty C + else if(wxSscanf(tmpaddr.IPAddress().c_str(), _T("%u.%u.%u.%u"), &ip1[0], &ip1[1], &ip1[2], &ip1[3]) == 4 && + wxSscanf(str.c_str(), _T("%u.%u.%u.%u"), &ip2[0], &ip2[1], &ip2[2], &ip2[3]) == 4) + { + if((ip1[0] == 0 && ip1[1] == 0 && ip1[2] == 0 && ip1[3] == 0) || //0.0.0.0 + (ip1[0] == ip2[0] && ip1[1] == 0 && ip1[2] == 0 && ip1[3] == 0) || //x.0.0.0 + (ip1[0] == ip2[0] && ip1[1] == ip2[1] && ip1[2] == 0 && ip1[3] == 0) || //x.x.0.0 + (ip1[0] == ip2[0] && ip1[1] == ip2[1] && ip1[2] == ip2[2] && ip1[3] == 0)) //x.x.x.0 + { + found = true; + break; + } + } + } + if (!found) + { + SetLastError(_T("IP is not allowed")); + return false; + } + return true; +} + +//------------------------------------------------------------------------------ +// IsValidFormat +bool TSQueryThread::IsValidFormat() +{ + //check node + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + if(pNodeRoot.GetName() != _T("TSClient")) + { + SetLastError(_T("No 'TSClient' node found")); + return false; + } + + //check node + wxXml2Node pNode = pNodeRoot.Get(_T("Password")); + if(pNode == wxXml2EmptyNode) + { + SetLastError(_T("No 'Password' node found")); + return false; + } + + pNode = pNodeRoot.Get(_T("Command")); + if(pNode == wxXml2EmptyNode) + { + SetLastError(_T("No 'Command' node found")); + return false; + } + + return true; +} + + +//------------------------------------------------------------------------------ +// ProcessCommand. +bool TSQueryThread::ProcessCommand(wxSocketBase *sock) +{ + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + //check node + wxXml2Node pNode = pNodeRoot.Get(_T("Command")); + if(pNode == wxXml2EmptyNode) + { + SetLastError(_T("No 'Command' node found")); + SendError(_T("General"), GetLastError(), sock); + return false; + } + + wxString cmd = pNode.GetFirstChild().GetContent(); + wxLogMessage(_T("TSQuery: command '%s' received"), cmd.c_str()); + + pNode = pNodeRoot.Get(_T("Text")); + if(pNode != wxXml2EmptyNode) + wxLogMessage(_T("TSQuery: Text: '%s'"), pNode.GetFirstChild().GetContent().c_str()); + + if(cmd == _T("GetStatus")) + return CmdGetStatus(sock); + else if(cmd == _T("GetChannels")) + return CmdGetChannels(sock); + else if(cmd == _T("GetUsers")) + return CmdGetUsers(sock); + else if(cmd == _T("CreateChannel")) + return CmdCreateChannel(sock); + else if(cmd == _T("DeleteChannel")) + return CmdDeleteChannel(sock); + else if(cmd == _T("ModifyChannel")) + return CmdModifyChannel(sock); + else if(cmd == _T("MoveUser")) + return CmdMoveUser(sock); + else if(cmd == _T("KickUser")) + return CmdKickUser(sock); + else if(cmd == _T("Kill")) + return CmdKill(sock); + + SetLastError(_T("Unknown command")); + SendError(cmd, GetLastError(), sock); + return false; +} + +//------------------------------------------------------------------------------ +// SendError. +bool TSQueryThread::SendError(wxString const &cmd, wxString const &str, wxSocketBase *sock) +{ + wxSocketOutputStream so(*sock); + wxBufferedOutputStream out(so); + + m_pXml.Create(_T("1.0")); + wxXml2Node pNodeRoot; + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + + wxXml2Node pNode; + pNode = pNodeRoot.AddTextChild(_T("Command"), cmd); + pNode.AddProperty(_T("State"), _T("Error")); + + pNode = pNodeRoot.AddTextChild(_T("ErrorText"), str); + + if(!SendDOM(sock)) + return false; + return true; +} + +//------------------------------------------------------------------------------ +// Dumps object. +void TSQueryThread::Dump(wxOutputStream &ostrm) const +{ + wxTextOutputStream out(ostrm); + out << wxString(_T("-"), 60) << endl; + out << _T("Object: TSQueryThread (") << wxString::Format(_T("0x%X"), this) << _T(")") << endl; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::SendDOM(wxSocketBase *sock) +{ + wxSocketOutputStream so(*sock); + wxBufferedOutputStream out(so); + if(!m_pXml.Save(out, _T("utf-8"), wxXML2DOC_USE_NATIVE_NEWLINES | wxXML2DOC_USE_INDENTATION, 2)) + { + SetLastError(_T("DOM serialization")); + return false; + } + out.Sync(); + return true; +} + +//------------------------------------------------------------------------------ +wxString TSQueryThread::GetNodeValue(wxXml2Node &pElemRoot, wxString const &str) +{ + wxXml2Node pElem = pElemRoot.Get(str); + if(pElem == wxXml2EmptyNode) + return _T(""); + else + return pElem.GetFirstChild().GetContent(); +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdGetStatus(wxSocketBase *sock) +{ + wxString str; + str = wxString::Format(_T("%s:%d"), m_pClient->GetServer()->GetServerAddress().c_str(), + m_pClient->GetServer()->GetPort()); + + if(!m_pClient->IsConnected()) + { + wxLogMessage(_T("TSQuery: TSServer %s is not connected"), str.c_str()); + SetLastError(_T("No connection to TSServer")); + SendError(_T("GetStatus"), GetLastError(), sock); + return false; + } + + m_pXml.Create(_T("1.0")); + wxXml2Node pNodeRoot; + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + + wxXml2Node pNode; + pNode = pNodeRoot.AddTextChild(_T("Command"), _T("GetStatus")); + pNode.AddProperty(_T("State"), _T("Ok")); + + pNode = pNodeRoot.AddTextChild(_T("TSServer"), str); + + if(!SendDOM(sock)) + return false; + return true; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdGetChannels(wxSocketBase *sock) +{ + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + TSpChannelArray chs; + + wxXml2Node pNode = pNodeRoot.Get(_T("ChannelName")); + if(pNode != wxXml2EmptyNode) + { + wxString str = pNode.GetFirstChild().GetContent(); + m_pClient->FindChannelsByName(str, &chs); + + /* remove channels not matching ParentId */ + str = pNode.GetPropVal(_T("ParentId"), wxEmptyString); + wxUint32 pid; + if (!str.empty() && strToChannelId(str, &pid)) + { + for(size_t i = 0; i < chs.Count(); i++) + { + if (chs[i]->GetParent() != pid) + chs.RemoveAt(i); + } + } + + /* add subchannels */ + if(pNode.GetPropVal(_T("Subchannels"), _T("No")) == _T("Yes")) + { + for(size_t i = 0; i < chs.Count(); i++) + m_pClient->FindChannelsByParent(chs[i]->GetId(), &chs); + } + } + + pNode = pNodeRoot.Get(_T("ChannelId")); + if(pNode != wxXml2EmptyNode) + { + wxString str = pNode.GetFirstChild().GetContent(); + wxUint32 chlid; + if (strToChannelId(str, &chlid, false)) + { + TSChannel *c = m_pClient->FindChannel(chlid); + if(c != NULL) + chs.Add(c); + + /* remove channels not matching ParentId */ + wxUint32 pid; + str = pNode.GetPropVal(_T("ParentId"), wxEmptyString); + if (!str.empty() && strToChannelId(str, &pid)) + { + for(size_t i = 0; i < chs.Count(); i++) + { + if (chs[i]->GetParent() != pid) + chs.RemoveAt(i); + } + } + + /* add subchannels */ + if(pNode.GetPropVal(_T("Subchannels"), _T("No")) == _T("Yes")) + { + for(size_t i = 0; i < chs.Count(); i++) + m_pClient->FindChannelsByParent(chs[i]->GetId(), &chs); + } + } + } + + pNode = pNode.Get(_T("ChannelParentId")); + if(pNode != wxXml2EmptyNode) + { + wxString str = pNode.GetFirstChild().GetContent(); + wxUint32 pid; + if (strToChannelId(str, &pid)) + m_pClient->FindChannelsByParent(pid, &chs); + } + + m_pXml.Create(_T("1.0")); + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + pNode = pNodeRoot.AddTextChild(_T("Command"), _T("GetChannels")); + pNode.AddProperty(_T("State"), _T("Ok")); + + wxLogMessage(_T("TSQuery: sending requested channels.")); + + for(size_t i = 0; i < chs.Count(); i++) + { + wxXml2Node pChannelNode; + pChannelNode = pNodeRoot.AddContainerChild(_T("Channel")); + pChannelNode.AddProperty(_T("Id"), wxString::Format(_T("%d"), chs[i]->GetId())); + pChannelNode.AddProperty(_T("ParentId"), wxString::Format(_T("%d"), chs[i]->GetParent())); + + pChannelNode.AddTextChild(_T("ChannelName"), chs[i]->GetName()); + pChannelNode.AddTextChild(_T("ChannelTopic"), chs[i]->GetTopic()); + pChannelNode.AddTextChild(_T("ChannelSlots"), wxString::Format(_T("%d"), chs[i]->GetMaxUsers())); + pChannelNode.AddTextChild(_T("ChannelPassword"), chs[i]->GetPassword()); + pChannelNode.AddTextChild(_T("ChannelCodec"), wxString::Format(_T("%d"), chs[i]->GetCodec())); + const wxCharBuffer buf = chs[i]->GetDescription().mb_str(wxConvUTF8); + pChannelNode.AddTextChild(_T("ChannelDescription"), Base64Encode(buf, strlen(buf))); + pChannelNode.AddTextChild(_T("ChannelFlags"), chs[i]->GetFlagsString()); + + wxLogVerbose(_T("TSQuery: Channel '%s' transmitted."), chs[i]->GetName().c_str()); + } + + if(!SendDOM(sock)) + return false; + return true; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdGetUsers(wxSocketBase *sock) +{ + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + TSpPlayerArray pls; + wxString str; + + wxXml2Node pNode; + pNode = pNodeRoot.Get(_T("UserName")); + if(pNode != wxXml2EmptyNode) + { + str = pNode.GetFirstChild().GetContent(); + m_pClient->FindPlayersByName(str, &pls); + } + + pNode = pNodeRoot.Get(_T("UserId")); + if(pNode != wxXml2EmptyNode) + { + str = pNode.GetFirstChild().GetContent(); + wxUint32 plyid; + if (strToNum(str, &plyid)) + pls.Add(m_pClient->FindPlayer(plyid)); + } + + pNode = pNodeRoot.Get(_T("ChannelName")); + if(pNode != wxXml2EmptyNode) + { + str = pNode.GetFirstChild().GetContent(); + TSpChannelArray chs; + m_pClient->FindChannelsByName(str, &chs); + + /* remove channels not matching ParentId */ + wxUint32 pid; + str = pNode.GetPropVal(_T("ParentId"), wxEmptyString); + if (!str.empty() && strToChannelId(str, &pid)) + { + for(size_t i = 0; i < chs.Count(); i++) + { + if (chs[i]->GetParent() != pid) + chs.RemoveAt(i); + } + } + + /* find users */ + for(size_t i = 0; i < chs.Count(); i++) + { + m_pClient->FindPlayersByChannel(chs[i], &pls); + + /* add subchannels and their users */ + if (pNode.GetPropVal(_T("Subchannels"), _T("No")) == _T("Yes")) + { + TSpChannelArray chs2; + m_pClient->FindChannelsByParent(chs[i]->GetId(), &chs2); + for(size_t j = 0; j < chs2.Count(); j++) + m_pClient->FindPlayersByChannel(chs2[j], &pls); + } + } + } + + pNode = pNodeRoot.Get(_T("ChannelId")); + if(pNode != wxXml2EmptyNode) + { + str = pNode.GetFirstChild().GetContent(); + TSChannel *cl = NULL; + wxUint32 chlid; + if (strToChannelId(str, &chlid, false)) + cl = m_pClient->FindChannel(chlid); + if (cl == NULL) + { + SetLastError(_T("Error while searching for channel.")); + SendError(_T("GetUsers"), GetLastError(), sock); + return false; + } + + m_pClient->FindPlayersByChannel(cl, &pls); + + if (pNode.GetPropVal(_T("Subchannels"), _T("No")) == _T("Yes")) + { + TSpChannelArray chs; + m_pClient->FindChannelsByParent(cl->GetId(), &chs); + for(size_t i = 0; i < chs.Count(); i++) + m_pClient->FindPlayersByChannel(chs[i], &pls); + } + } + + m_pXml.Create(_T("1.0")); + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + pNode = pNodeRoot.AddTextChild(_T("Command"), _T("GetUsers")); + pNode.AddProperty(_T("State"), _T("Ok")); + + wxLogMessage(_T("TSQuery: sending requested users.")); + + for(size_t i = 0; i < pls.Count(); i++) + { + wxXml2Node pUserNode; + pUserNode = pNodeRoot.AddContainerChild(_T("User")); + pUserNode.AddProperty(_T("Id"), wxString::Format(_T("%d"), pls[i]->GetId())); + + pUserNode.AddTextChild(_T("UserName"), pls[i]->GetNickname().c_str()); + pUserNode.AddTextChild(_T("UserChannelId"), wxString::Format(_T("%d"), pls[i]->GetChannelId()).c_str()); + pUserNode.AddTextChild(_T("UserFlags"), wxString::Format(_T("%d"), pls[i]->GetFlags()).c_str()); + pUserNode.AddTextChild(_T("UserPrivileges"), wxString::Format(_T("%d"), pls[i]->GetPrivileges()).c_str()); + pUserNode.AddTextChild(_T("UserChannelPrivileges"), wxString::Format(_T("%d"), pls[i]->GetChannelPrivileges()).c_str()); + + wxLogVerbose(_T("TSQuery: User '%s' transmitted."), pls[i]->GetNickname().c_str()); + } + + if(!SendDOM(sock)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdCreateChannel(wxSocketBase *sock) +{ + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + TSChannel cl; + wxString str; + + wxXml2Node pNode; + pNode = pNodeRoot.Get(_T("Channel")); + if(pNode == wxXml2EmptyNode) + { + SetLastError(_T("No channel node")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + + wxUint32 chlid; + str = pNode.GetPropVal(_T("ParentId"), _T("-1")); + if (!strToChannelId(str, &chlid)) + { + SetLastError(_T("Invalid parent id")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + + cl.SetParent(chlid); + cl.SetName(GetNodeValue(pNode, _T("ChannelName"))); + cl.SetTopic(GetNodeValue(pNode, _T("ChannelTopic"))); + cl.SetPassword(GetNodeValue(pNode, _T("ChannelPassword"))); + + wxUint32 num; + str = GetNodeValue(pNode, _T("ChannelSlots")); + if (!strToNum(str, &num)) + { + SetLastError(_T("Invalid channel slots value")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + cl.SetMaxUsers(num); + + str = GetNodeValue(pNode, _T("ChannelCodec")); + if (!strToNum(str, &num)) + { + SetLastError(_T("Invalid channel codec value")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + cl.SetCodec(num); + + wxCSConv conv_iso(_T("iso-8859-1")); + wxString base64_encoded = GetNodeValue(pNode, _T("ChannelDescription")); + cl.SetDescription(wxString(Base64Decode(base64_encoded).mb_str(conv_iso), wxConvUTF8)); + cl.SetFlags(GetNodeValue(pNode, _T("ChannelFlags"))); + + m_pClient->CreateChannel(&cl); + + // dirty wait for channel id + wxUint32 channelid = 0; + for (wxUint32 i = 0; i <= 2; i++) + { + TSpChannelArray chs; + if (cl.GetParent() == TS_NO_PARENT) + { + // we wait for a main channel + m_pClient->FindChannelsByName(_T("^") + cl.GetName() + _T("$"), &chs); + for(size_t i = 0; i < chs.Count(); i++) + { + if (chs[i]->GetParent() == TS_NO_PARENT) + { + channelid = chs[i]->GetId(); + break; + } + } + } + else + { + // we wait for a subchannel + m_pClient->FindChannelsByParent(cl.GetParent(), &chs); + for(size_t i = 0; i < chs.Count(); i++) + { + if (chs[i]->GetName() == cl.GetName()) + { + channelid = chs[i]->GetId(); + break; + } + } + } + + if (channelid > 0) + break; + Sleep(500); + } + + if (channelid <= 0) + { + SetLastError(_T("Error while creating channel.")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + + m_pXml.Create(_T("1.0")); + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + pNode = pNodeRoot.AddTextChild(_T("Command"), _T("CreateChannel")); + pNode.AddProperty(_T("State"), _T("Ok")); + + pNodeRoot.AddTextChild(_T("ChannelId"), wxString::Format(_T("%d"), channelid)); + + wxLogMessage(_T("TSQuery: Channel '%s' created."), cl.GetName().c_str()); + + if(!SendDOM(sock)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdDeleteChannel(wxSocketBase *sock) +{ + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + TSChannel *cl = NULL; + wxString str; + + wxXml2Node pNode; + pNode = pNodeRoot.Get(_T("ChannelId")); + if(pNode != wxXml2EmptyNode) + { + str = pNode.GetFirstChild().GetContent(); + wxUint32 chlid; + if (strToChannelId(str, &chlid, false)) + cl = m_pClient->FindChannel(chlid); + } + + if(cl == NULL) + { + SetLastError(_T("Channel not found.")); + SendError(_T("DeleteChannel"), GetLastError(), sock); + return false; + } + + TSChannel *defchl = m_pClient->FindDefaultChannel(); + + // process subchannels + TSpChannelArray chs; + m_pClient->FindChannelsByParent(cl->GetId(), &chs); + for(size_t i = 0; i < chs.Count(); i++) + { + TSpPlayerArray ply; + m_pClient->FindPlayersByChannel(chs[i], &ply); + + for(size_t i=0;iGetId()); + pl.SetChannelId(defchl->GetId()); + m_pClient->MovePlayer(&pl); + } + } + + // process main channel + TSpPlayerArray ply; + m_pClient->FindPlayersByChannel(cl,&ply); + + for(size_t i=0;iGetId()); + pl.SetChannelId(defchl->GetId()); + m_pClient->MovePlayer(&pl); + } + + wxLogMessage(_T("TSQuery: Channel '%s' deleted."),cl->GetName().c_str()); + + m_pClient->DeleteChannel(cl); + + m_pXml.Create(_T("1.0")); + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + pNode = pNodeRoot.AddTextChild(_T("Command"), _T("DeleteChannel")); + pNode.AddProperty(_T("State"), _T("Ok")); + + if(!SendDOM(sock)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdModifyChannel(wxSocketBase *sock) +{ + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + TSChannel cl; + wxString str; + + wxXml2Node pNode; + pNode = pNodeRoot.Get(_T("Channel")); + if(pNode == wxXml2EmptyNode) + { + SetLastError(_T("No channel node")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + + wxUint32 chlid; + str = pNode.GetPropVal(_T("Id"), _T("")); + if (!strToChannelId(str, &chlid, false)) + { + SetLastError(_T("No id attribute found")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + + cl.SetId(chlid); + cl.SetName(GetNodeValue(pNode, _T("ChannelName"))); + cl.SetTopic(GetNodeValue(pNode, _T("ChannelTopic"))); + cl.SetPassword(GetNodeValue(pNode, _T("ChannelPassword"))); + + wxUint32 num; + str = GetNodeValue(pNode, _T("ChannelSlots")); + if (!strToNum(str, &num)) + { + SetLastError(_T("Invalid channel slots value")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + cl.SetMaxUsers(num); + + str = GetNodeValue(pNode, _T("ChannelCodec")); + if (!strToNum(str, &num)) + { + SetLastError(_T("Invalid channel codec value")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + cl.SetCodec(num); + + wxCSConv conv_iso(_T("iso-8859-1")); + wxString base64_encoded = GetNodeValue(pNode, _T("ChannelDescription")); + cl.SetDescription(wxString(Base64Decode(base64_encoded).mb_str(conv_iso), wxConvUTF8)); + cl.SetFlags(GetNodeValue(pNode, _T("ChannelFlags"))); + + m_pClient->ModifyChannel(&cl); + + m_pXml.Create(_T("1.0")); + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + pNode = pNodeRoot.AddTextChild(_T("Command"), _T("ModifyChannel")); + pNode.AddProperty(_T("State"), _T("Ok")); + + wxLogMessage(_T("TSQuery: Channel '%s' modified."), cl.GetName().c_str()); + + if(!SendDOM(sock)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdMoveUser(wxSocketBase *sock) +{ + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + TSPlayer *pl = NULL; + TSChannel *cl = NULL; + wxString str; + + wxXml2Node pNode; + pNode = pNodeRoot.Get(_T("UserId")); + if(pNode != wxXml2EmptyNode) + { + str = pNode.GetFirstChild().GetContent(); + wxUint32 plyid; + if (strToNum(str, &plyid)) + pl = m_pClient->FindPlayer(plyid); + } + + if(pl == NULL) + { + SetLastError(_T("User not found.")); + SendError(_T("MoveUser"), GetLastError(), sock); + return false; + } + + pNode = pNodeRoot.Get(_T("ChannelId")); + if(pNode != wxXml2EmptyNode) + { + str = pNode.GetFirstChild().GetContent(); + wxUint32 chlid; + if (strToChannelId(str, &chlid, false)) + cl = m_pClient->FindChannel(chlid); + } + + if(cl == NULL) + { + SetLastError(_T("Channel not found.")); + SendError(_T("MoveUser"), GetLastError(), sock); + return false; + } + + pl->SetChannelId(cl->GetId()); + m_pClient->MovePlayer(pl); + + m_pXml.Create(_T("1.0")); + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + pNode = pNodeRoot.AddTextChild(_T("Command"), _T("MoveUser")); + pNode.AddProperty(_T("State"), _T("Ok")); + + wxLogMessage(_T("TSQuery: User '%s' moved to '%s'."), pl->GetNickname().c_str(), + m_pClient->FindChannel(pl->GetChannelId())->GetName().c_str()); + + if(!SendDOM(sock)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdKickUser(wxSocketBase *sock) +{ + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + TSPlayer *pl = NULL; + wxString str; + + wxXml2Node pNode; + pNode = pNodeRoot.Get(_T("UserId")); + if(pNode != wxXml2EmptyNode) + { + str = pNode.GetFirstChild().GetContent(); + wxUint32 plyid; + if (strToNum(str, &plyid)) + pl = m_pClient->FindPlayer(plyid); + } + + if(pl == NULL) + { + SetLastError(_T("User not found.")); + SendError(_T("KickUser"), GetLastError(), sock); + return false; + } + + str = _T(""); + pNode = pNodeRoot.Get(_T("Reason")); + if(pNode != wxXml2EmptyNode) + str = pNode.GetFirstChild().GetContent(); + + wxLogMessage(_T("TSQuery: User '%s' kicked."), pl->GetNickname().c_str()); + + m_pClient->KickPlayer(pl, str); + + m_pXml.Create(_T("1.0")); + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + pNode = pNodeRoot.AddTextChild(_T("Command"), _T("KickUser")); + pNode.AddProperty(_T("State"), _T("Ok")); + + if(!SendDOM(sock)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdKill(wxSocketBase *sock) +{ + if(m_pClient->IsConnected()) + m_pClient->Disconnect(false); + + wxXml2Node pNodeRoot; + m_pXml.Create(_T("1.0")); + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + wxXml2Node pNode = pNodeRoot.AddTextChild(_T("Command"), _T("Kill")); + pNode.AddProperty(_T("State"), _T("Ok")); + + if(!SendDOM(sock)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +// Sets the password for incomming connections. + +bool TSQueryThread::SetPassword(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("Empty string")); + return false; + } + m_Password = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the server address. +bool TSQueryThread::SetServerAddress(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("Empty string")); + return false; + } + m_ServerAddress = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the allowed address. +bool TSQueryThread::SetAllowedAddresses(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("Empty string")); + return false; + } + m_AllowedAddresses = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the connection port. +bool TSQueryThread::SetPort(wxUint16 const &port) +{ + if(port == 0) + { + SetLastError(_T("Empty port")); + return false; + } + m_Port = port; + return true; +} + +//------------------------------------------------------------------------------ +// Start thread. +bool TSQueryThread::Start() +{ + Run(); + return true; +} + +//------------------------------------------------------------------------------ +// Stop thread. +bool TSQueryThread::Stop() +{ + Kill(); + return true; +} diff --git a/tsquerythread.h b/tsquerythread.h new file mode 100644 index 0000000..c41c535 --- /dev/null +++ b/tsquerythread.h @@ -0,0 +1,184 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +//Header guard +#ifndef TSQUERY_H +#define TSQUERY_H + +//Libraries +#include +#include +#include + +#include "tsheaders.h" + +//! TSQuery +/*! TSQuery + */ +class TSQueryThread : public wxThread +{ + DECLARE_CLASS(TSQueryThread) + public: + + /*! thread execution starts here + * \return Returns ExitCode. + */ + virtual ExitCode Entry(); + + /*! and stops here + */ + virtual void OnExit(); + + /*! Default CTor, Initializes the object. + * Creates all necessary member objects. + */ + TSQueryThread(TSClient *client); + + /*! Default DTor. + */ + ~TSQueryThread(); + + /*! Sets the password for incomming connections. + * \param str Password string. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetPassword(wxString const &str); + + /*! Sets the allowed Addresses. + * You can use either an IP or an URL, seperate with ',' + * \param str Server address string. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetAllowedAddresses(wxString const &str); + + /*! Start thread. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool Start(); + + /*! Stop thread. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool Stop(); + + /*! Sets the server address. + * You can use either an IP or an URL. + * \param str Server address string. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetServerAddress(wxString const &str); + + /*! Sets the connection port. + * \param port Connection port. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetPort(wxUint16 const &port); + + /*! Listen for incomming connections. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool Accept(); + + /*! Dumps object. + * \param ostrm Stream to write. + */ + void Dump(wxOutputStream &ostrm) const; + + /*! Gets the server Address. + * \return Returns the current password. + */ + wxString const &GetServerAddress() const + { + return m_ServerAddress; + } + /*! Gets the password for incomming connections. + * \return Returns the current password. + */ + wxString const &GetPassword() const + { + return m_Password; + } + + /*! Gets the allowed addresses for incomming connections. + * \return Returns the allowed addresses. + */ + wxString const &GetAllowedAddresses() const + { + return m_AllowedAddresses; + } + + /*! Gets the port for incomming connections. + * \return Returns the current port. + */ + wxUint16 const &GetPort() const + { + return m_Port; + } + /*! Gets the LastError message, call this method + * to get more information for an error. + * \return LastError message. + */ + wxString const &GetLastError() const + { + return m_LastError; + } + + private: + bool CmdGetStatus(wxSocketBase *sock); + bool CmdGetChannels(wxSocketBase *sock); + bool CmdGetUsers(wxSocketBase *sock); + bool CmdCreateChannel(wxSocketBase *sock); + bool CmdDeleteChannel(wxSocketBase *sock); + bool CmdModifyChannel(wxSocketBase *sock); + bool CmdMoveUser(wxSocketBase *sock); + bool CmdKickUser(wxSocketBase *sock); + bool CmdKill(wxSocketBase *sock); + + bool SendDOM(wxSocketBase *sock); + bool ProcessCommand(wxSocketBase *sock); + bool SendError(wxString const &cmd, wxString const &str, wxSocketBase *sock); + bool IsIPAllowed(wxString const &str); + bool IsValidFormat(); + wxString GetNodeValue(wxXml2Node &pElemRoot, wxString const &str); + + //Sets the LastError message. + void SetLastError(wxString const &str) + { + m_LastError = str; + } + + //Members + wxString m_LastError; + wxString m_AllowedAddresses; + wxString m_Password; + wxSocketServer *m_pSocket; + wxIPV4address m_ServerAddr; + TSClient *m_pClient; + wxXml2Document m_pXml; + wxUint16 m_Port; + wxString m_ServerAddress; +}; + +#endif diff --git a/tsserver.cpp b/tsserver.cpp new file mode 100644 index 0000000..a0275d6 --- /dev/null +++ b/tsserver.cpp @@ -0,0 +1,168 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +// Header +#include "tsserver.h" + +//Libraries +#include + +IMPLEMENT_CLASS(TSServer, wxObject) + +//------------------------------------------------------------------------------ +//Default CTor, Initializes the object. +TSServer::TSServer() +{ + m_Id = 0; + m_Type = 0; + m_Port = 0; + m_HostAddress = _T("localhost"); +} + +//------------------------------------------------------------------------------ +//Default DTor. +TSServer::~TSServer() +{ +} + +//------------------------------------------------------------------------------ +// Sets the server message. +bool TSServer::SetServerMessage(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("empty string")); + return false; + } + m_ServerMessage = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the welcome message. +bool TSServer::SetWelcomeMessage(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("empty string")); + return false; + } + m_WelcomeMessage = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the server message. +bool TSServer::SetVersionNumber(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("empty string")); + return false; + } + m_VersionNumber = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the host address, bindes the client to an address. +bool TSServer::SetHostAddress(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("empty string")); + return false; + } + m_HostAddress = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the server address. +bool TSServer::SetServerAddress(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("empty string")); + return false; + } + m_ServerAddress = str; + return true; +} +//------------------------------------------------------------------------------ +// Sets the server Id. +bool TSServer::SetId(wxUint32 const &id) +{ + m_Id = id; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the connection port. +bool TSServer::SetPort(wxUint16 const &port) +{ + if(port == 0) + { + SetLastError(_T("empty port")); + return false; + } + m_Port = port; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the server type. +bool TSServer::SetServerType(wxUint16 const &type) +{ + m_ServerType = type; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the platform string. +bool TSServer::SetPlatform(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("empty string")); + return false; + } + m_Platform = str; + return true; +} + +//------------------------------------------------------------------------------ +// Dumps object. +void TSServer::Dump(wxOutputStream &ostrm) const +{ + wxTextOutputStream out(ostrm); + out << _T("Object: TSServer (") << wxString::Format(_T("0x%X"), this) << _T(")") << endl; + out << _T("-wxUint32 m_Id: ") << wxString::Format(_T("0x%X"), m_Id) << endl; + out << _T("-wxString m_VersionNumber: ") << m_VersionNumber << endl; + out << _T("-wxString m_WelcomeMessage: ") << m_WelcomeMessage << endl; + out << _T("-wxString m_ServerMessage: ") << m_ServerMessage << endl; + out << _T("-wxString m_Platform: ") << m_Platform << endl; + out << _T("-wxUint32 m_Type: ") << wxString::Format(_T("0x%X"), m_Type) << endl; + out << _T("-wxString m_ISPLinkURL: ") << m_ISPLinkURL << endl; + out << _T("-wxString m_ServerAddress: ") << m_ServerAddress << endl; + out << _T("-wxString m_HostAddress: ") << m_HostAddress << endl; + out << _T("-wxUint16 m_Port: ") << wxString::Format(_T("0x%X"), m_Port) << endl; + out << _T("-wxUint16 m_ServerType: ") << wxString::Format(_T("0x%X"), m_ServerType) << endl; + out << _T("-wxString m_LastError: ") << m_LastError << endl; +} + diff --git a/tsserver.h b/tsserver.h new file mode 100644 index 0000000..dc3b1fd --- /dev/null +++ b/tsserver.h @@ -0,0 +1,243 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +#ifndef TSSERVER_H +#define TSSERVER_H + +// Libraries +#include + +//------------------------------------------------------------------------------ +// Server flags +#define TS_SERVER_CLAN 5 +#define TS_SERVER_PUBLIC 6 + +//! TeamSpeak server. +/*! TSServer is used to hold all server informations. + * After calling TSClient::Connect(), you can read + * out all the servers attributes. These stepps are + * necessary to connect to a server and read all information + * out. + * - Create a TSServer object,edit and link it to the TSClient object + * (For more information see TSClient) + * - Call TSClient::Connect() + * - Call TSClient::GetServer() + * - Now the class is filled up with the server information + */ +class TSServer : public wxObject +{ + DECLARE_CLASS(TSServer) + public: + /*! Default CTor, Initializes the object. + */ + TSServer(); + + /*! Default DTor. + */ + ~TSServer(); + + /*! Sets the server message. + * \param str Server message string. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetServerMessage(wxString const &str); + + /*! Sets the welcome message. + * \param str Welcome message string. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetWelcomeMessage(wxString const &str); + + /*! Sets the platform string. + * \param str Platform string. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetPlatform(wxString const &str); + + /*! Sets the server message. + * \param str Server message string. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetVersionNumber(wxString const &str); + + /*! Sets the host address, bindes the client to an address. + * You can use either an IP or an URL. + * \param str Host address string. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetHostAddress(wxString const &str); + + /*! Sets the server address. + * You can use either an IP or an URL. + * \param str Server address string. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetServerAddress(wxString const &str); + + /*! Sets the server Id. + * \param id Server Id. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetId(wxUint32 const &id); + + /*! Sets the connection port. + * \param port Connection port. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetPort(wxUint16 const &port); + + /*! Sets the server type + * \param type Server type. + * \return Returns false if fails, check GetLastError for details. + * \sa GetLastError() + */ + bool SetServerType(wxUint16 const &type); + + /*! Gets the server Id. + * \return server Id. + */ + wxUint32 GetId() const + { + return m_Id; + } + + /*! Gets the server port. + * \return server port. + */ + wxUint16 GetPort() const + { + return m_Port; + } + + /*! Gets the server type. + * \return server type. + */ + wxUint32 GetType() const + { + return m_Type; + } + + /*! Gets the server version number. + * \return server version number. + */ + wxString const &GetVersionNumber() const + { + return m_VersionNumber; + } + + /*! Gets the server welcome message. + * \return server welcome message. + */ + wxString const &GetWelcomeMessage() const + { + return m_WelcomeMessage; + } + + /*! Gets the server server message. + * \return server server message. + */ + wxString const &GetServerMessage() const + { + return m_ServerMessage; + } + + /*! Gets the server platform. + * \return server platform. + */ + wxString const &GetPlatform() const + { + return m_Platform; + } + + /*! Gets the server ISPLinkURL. + * \return server ISPLinkURL. + */ + wxString const &GetISPLinkURL() const + { + return m_ISPLinkURL; + } + + /*! Gets the server address. + * \return server address. + */ + wxString const &GetServerAddress() const + { + return m_ServerAddress; + } + + /*! Gets the host address. + * \return host address. + */ + wxString const &GetHostAddress() const + { + return m_HostAddress; + } + + /*! Gets the server type. + * \return server type. + */ + wxUint16 const &GetServerType() const + { + return m_ServerType; + } + + /*! Dumps object. + * \param ostrm Stream to write. + */ + void Dump(wxOutputStream &ostrm) const; + + /*! Gets the LastError message, call this method + * to get more information for an error. + * \return LastError message. + */ + wxString const &GetLastError() const + { + return m_LastError; + } + + private: + //Sets the LastError message. + void SetLastError(wxString const &str) + { + m_LastError = str; + } + + //members + wxUint32 m_Id; + wxString m_VersionNumber; + wxString m_WelcomeMessage; + wxString m_ServerMessage; + wxString m_Platform; + wxUint32 m_Type; + wxString m_ISPLinkURL; + wxString m_ServerAddress; + wxString m_HostAddress; + wxString m_LastError; + wxUint16 m_Port; + wxUint16 m_ServerType; +}; + +#endif diff --git a/wxbufferex.cpp b/wxbufferex.cpp new file mode 100644 index 0000000..78bd167 --- /dev/null +++ b/wxbufferex.cpp @@ -0,0 +1,80 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +// Header +#include "wxbufferex.h" + +//Libraries +#include + +//------------------------------------------------------------------------------ +// Hex dump on the stream. +void wxMemoryBufferEx::HexDump(wxOutputStream &strm) +{ + wxTextOutputStream out(strm); + const size_t colums = 16; + size_t size = GetDataLen(); + + //print all data + for(size_t i = 0; i < ((size % colums == 0) ? (size / colums) : (size / colums) + 1); i++) + { + //address + out << wxString::Format(_T("%.4x "), i * colums); + + //print hex table + for(size_t j = 0; j < colums; j++) + { + if(j == colums/2) + out << _T(" "); + + if(j + i*colums >= size) + { + out << _T(" "); + } + else + { + wxByte *pos = static_cast(GetData()); + pos += (j + i * colums); + out << wxString::Format(_T(" %.2x"), *pos); + } + } + + //seperator + out << _T(" "); + + //print ascii + for(size_t j = 0; j < colums; j++) + { + if(j == colums/2) + out << _T(" "); + if(j + i*colums >= size) + { + out << _T(" "); + } + else + { + wxByte *pos = static_cast(GetData()); + pos += ( j + i * colums); + out << wxString::Format(_T("%c"), (wxIsprint(*pos) ? *pos : '.')); + } + } + + out << endl; + } +} + diff --git a/wxbufferex.h b/wxbufferex.h new file mode 100644 index 0000000..7805fe9 --- /dev/null +++ b/wxbufferex.h @@ -0,0 +1,42 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +#ifndef WXMEMORYBUFFEREX_H +#define WXMEMORYBUFFEREX_H + +// Libraries +#include +#include +#include + +//! wxMemoryBufferEx. +/*! wxMemoryBufferEx. + */ +class wxMemoryBufferEx : public wxMemoryBuffer +{ + public: + wxMemoryBufferEx(size_t s) : wxMemoryBuffer(s) + {} + + /*! Hex dump on the stream. + * \param strm Stream to write. + */ + void HexDump(wxOutputStream &strm); +}; + +#endif diff --git a/wxstreamex.cpp b/wxstreamex.cpp new file mode 100644 index 0000000..dfbf7c7 --- /dev/null +++ b/wxstreamex.cpp @@ -0,0 +1,108 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +// Header +#include "wxstreamex.h" + +//------------------------------------------------------------------------------ +// Writes a fixed string on the stream +bool wxDataOutputStreamEx::WriteFixedString(wxString const &str, wxUint8 size) +{ + if((str.Length()+1) > size) + return false; + + wxCSConv conv_iso(_T("iso-8859-1")); + wxCharBuffer buffer = str.mb_str(conv_iso); + + strm->PutC(wxUint8(strlen(buffer))); + + for(size_t i = 0; i < strlen(buffer); i++) + strm->PutC(str[i]); + + for(size_t i = 0; i < (size-strlen(buffer)-1); i++) + strm->PutC('\0'); + + return true; +} + +//------------------------------------------------------------------------------ +// Writes zero terminated string on the stream with zero +bool wxDataOutputStreamEx::WriteZeroString(wxString const &str) +{ + if(str.Length() == 0) + return false; + + wxCSConv conv_iso(_T("iso-8859-1")); + wxCharBuffer buffer = str.mb_str(conv_iso); + strm->Write(buffer, strlen(buffer)); + strm->PutC('\0'); + + return true; +} + +//------------------------------------------------------------------------------ + +// Reades a fixed string from the stream +bool wxDataInputStreamEx::ReadFixedString(wxString &str, wxUint8 size) +{ + size_t strlen = 0; + char buffer[TS_MAX_LENGTH]; + int i = 0; + + strlen = strm->GetC(); + for(i = 0; i < size-1; i++) + { + if(strm->Eof()) + { + buffer[i] = '\0'; + str = wxString::FromAscii(buffer); + return false; + } + + buffer[i] = strm->GetC(); + } + + buffer[i] = '\0'; + str = wxString::FromAscii(buffer); + wxUnusedVar(strlen); + return true; +} + +//------------------------------------------------------------------------------ +// Reades a zero terminated string from the stream +bool wxDataInputStreamEx::ReadZeroString(wxString &str) +{ + wxChar c; + char buffer[TS_MAX_LENGTH]; + unsigned i = 0; + + c = strm->GetC(); + while((c != '\0') && (!strm->Eof())) + { + buffer[i] = c; + i++; + c = strm->GetC(); + } + buffer[i] = '\0'; + str = wxString::FromAscii(buffer); + if(strm->Eof()) + return false; + + return true; +} + diff --git a/wxstreamex.h b/wxstreamex.h new file mode 100644 index 0000000..6174894 --- /dev/null +++ b/wxstreamex.h @@ -0,0 +1,85 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +#ifndef WXSTREAMEX_H +#define WXSTREAMEX_H + +// Libraries +#include +#include +#include + +#define TS_MAX_LENGTH 4069 + +//! wxDataOutputStreamEx. +/*! wxDataOutputStreamEx. + */ +class wxDataOutputStreamEx : public wxDataOutputStream +{ + public: + wxDataOutputStreamEx(wxOutputStream &s) : wxDataOutputStream(s) + { + strm = &s; + } + + /*! Writes a fixed string on the stream. + * \param str String to write. + * \param size Size of fixed string, filled with zeros. + * \return Returns false if fails. + */ + bool WriteFixedString(wxString const &str, wxUint8 size = 30); + + /*! Writes zero terminated string on the stream with zero. + * \param str String to write. + * \return Returns false if fails. + */ + bool WriteZeroString(wxString const &str); + + private: + wxOutputStream *strm; +}; + +//! wxDataInputStreamEx. +/*! wxDataInputStreamEx. + */ +class wxDataInputStreamEx : public wxDataInputStream +{ + public: + wxDataInputStreamEx(wxInputStream &s) : wxDataInputStream(s) + { + strm = &s; + } + + /*! Reades a fixed string from the stream. + * \param str String to write to. + * \param size Size of the fixed string. + * \return Returns true if successful. + */ + bool ReadFixedString(wxString &str, wxUint8 size = 30); + + /*! Reades a zero terminated string from the stream. + * \param str String to write to. + * \return Returns true if successful. + */ + bool ReadZeroString(wxString &str); + + private: + wxInputStream *strm; +}; + +#endif -- cgit v1.2.3