yics-0.1.2/0000755000175000001440000000000010260634120012742 5ustar chrisusers00000000000000yics-0.1.2/readme.txt0000644000175000001440000000226410260634141014747 0ustar chrisusers00000000000000------------ Introduction ------------ Thank you for using YICS! This is the 0.1.2 release of YICS, the new C rewrite of Y to ICS. Here is a partial list of the new things: * Formula variables. (Documentation still incomplete on this.) * Support for buddy and ignore lists. * Additional alias tokens. * The "who" command now offers powerful sorting and filtering options. New commands: * addlist, sublist, showlist - List manipulation. * cls - Clears the screen on CSI-aware terminals. * play - Joins, sits, and starts on a table. * seek - Like "create" but you can specify time controls. * sought - Displays available tables that match your formula. * time - Shows the remaining time on your primary table. * znotify - Shows people in the current lobby that are also on your buddy list. Bugfixes: * No longer ravages the CPU on Windows. * Many cosmetic errors fixed. A wide variety of YICS documentation is available on the YICS wiki, located at http://wiki.yics.org/ . For help setting up YICS on WinBoard, see the wiki. ------- Credits ------- Lead programmer: crazycomputers Windows port: websnarf (aka qed) Website: http://www.yics.org Wiki: http://wiki.yics.org yics-0.1.2/LICENSE0000644000175000001440000004310510260634140013754 0ustar chrisusers00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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. Copyright (C) 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) year 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. , 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. yics-0.1.2/ytoics-c/0000755000175000001440000000000010260633724014505 5ustar chrisusers00000000000000yics-0.1.2/ytoics-c/Makefile.cygwin0000644000175000001440000000227410243006257017445 0ustar chrisusers00000000000000#if 0 ######################################### # # # YTOICS-C for win32 # # # # Makefile.cygwin # # # # Make sure that CYGWIN is properly # # installed, set the CYGWINDIR # # variable below and issue the # # command: # # # # gnumake -f Makefile.cygwin # # # ######################################### APP = ytoics.exe CYGWINDIR = h:/CYGWIN/BIN CC = $(CYGWINDIR)/gcc RM = rm -f STRIP = $(CYGWINDIR)/strip.exe CFLAGS = -O3 -ansi -s OFILES = command.o console.o debug.o formula.o http.o main.o globals.o \ movecheck.o network.o opcodes.o types.o util.o vars.o \ version.o ropcodes.o style.o topcodes.o # Makefile verbose setting QUIET = @ # QUIET = all: $(APP) $(APP): $(OFILES) $(QUIET)echo Linking: $(APP) $(QUIET)$(CC) $(OFILES) -o $(APP) $(QUIET)$(STRIP) -s $(APP) .c.o: $< $(QUIET)echo Compiling: $< $(QUIET)$(CC) $(CFLAGS) -c $< -o $@ clean: $(QUIET)$(RM) *.o $(APP) .PHONY: all clean #endif yics-0.1.2/ytoics-c/Makefile.intel0000644000175000001440000000542210243006257017256 0ustar chrisusers00000000000000#if 0 ######################################### # # # YTOICS-C for win32 # # # # Makefile.intel # # # # Make sure that iccvars.bat has # # been called and issue the command: # # # # nmake /f Makefile.intel # # # # Notice that this is nmake from # # Microsoft. Intel does not provide # # a make tool. # # # ######################################### APP = ytoics TDIR=. ODIR=.\obj !IF "$(OS)" == "Windows_NT" DEVNULL= !ELSE DEVNULL=nul !ENDIF CC="E:\Program Files\Intel\Compiler4.0\bin\icl.exe" LINK32=link.exe DEFS=/D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" CFLAGS=/MT /nologo /W4 /Wport /GX /O2 /Fo"$(ODIR)\\" /Fd"$(ODIR)\\" /c LFLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib odbc32.lib uuid.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /incremental:no /pdb:"$(TDIR)\$(APP).pdb" /machine:I386 /out:"$(TDIR)\$(APP).exe" OFILES= "$(ODIR)\command.obj" \ "$(ODIR)\version.obj" \ "$(ODIR)\http.obj" \ "$(ODIR)\network.obj" \ "$(ODIR)\util.obj" \ "$(ODIR)\globals.obj" \ "$(ODIR)\console.obj" \ "$(ODIR)\opcodes.obj" \ "$(ODIR)\ropcodes.obj" \ "$(ODIR)\style.obj" \ "$(ODIR)\topcodes.obj" \ "$(ODIR)\types.obj" \ "$(ODIR)\debug.obj" \ "$(ODIR)\formula.obj" \ "$(ODIR)\main.obj" \ "$(ODIR)\movecheck.obj"\ "$(ODIR)\vars.obj" # Makefile verbose setting # QUIET = @ QUIET = ALL : "$(TDIR)\$(APP).exe" CLEAN : -$(QUIET)erase "$(ODIR)\*.obj" -$(QUIET)erase "$(TDIR)\$(APP).exe" "$(ODIR)" : $(QUIET)if not exist "$(ODIR)/$(DEVNULL)" mkdir "$(ODIR)" "$(TDIR)\$(APP).exe" : "$(TDIR)" $(DEF_FILE) $(OFILES) $(QUIET)$(LINK32) @<< $(LFLAGS) $(OFILES) << # Compile rule .c{$(ODIR)}.obj:: $(QUIET)$(CC) $(DEFS) $(CFLAGS) $< # Dependencies "$(ODIR)\console.obj" : "$(ODIR)" console.c console.h network.h types.h "$(ODIR)\debug.obj" : "$(ODIR)" debug.c debug.h types.h "$(ODIR)\globals.obj" : "$(ODIR)" globals.c globals.h "$(ODIR)\main.obj" : "$(ODIR)" main.c console.h debug.h globals.h opcodes.h sockets.h network.h util.h types.h "$(ODIR)\network.obj" : "$(ODIR)" network.c sockets.h network.h util.h types.h "$(ODIR)\opcodes.obj" : "$(ODIR)" opcodes.c console.h opcodes.h network.h types.h "$(ODIR)\types.obj" : "$(ODIR)" types.c debug.h types.h "$(ODIR)\util.obj" : "$(ODIR)" util.c sockets.h util.h types.h "$(ODIR)\version.obj" : "$(ODIR)" version.c "$(ODIR)\formula.obj" : "$(ODIR)" formula.c types.h formula.h globals.h vars.h #endif yics-0.1.2/ytoics-c/Makefile.linux0000644000175000001440000000111510260627233017277 0ustar chrisusers00000000000000CC = gcc CFLAGS = -O3 -Wall -s SRCS = command.c console.c debug.c formula.c globals.c http.c lists.c main.c \ movecheck.c network.c opcodes.c ropcodes.c style.c topcodes.c types.c \ util.c vars.c version.c OBJS = command.o console.o debug.o formula.o globals.o http.o lists.o main.o \ movecheck.o network.o opcodes.o ropcodes.o style.o topcodes.o types.o \ util.o vars.o version.o all: yics .depend: $(SRCS) mkdep $(CFLAGS) $(SRCS) yics: $(OBJS) $(CC) $(CFLAGS) $(OBJS) -o yics .c.o: $< $(CC) $(CFLAGS) -c $< -o $@ clean: rm -f *.o .depend .PHONY: all clean include .depend yics-0.1.2/ytoics-c/Makefile.mingw320000644000175000001440000000116410260627233017432 0ustar chrisusers00000000000000CC = i586-mingw32msvc-gcc CFLAGS = -O3 -Wall -s SRCS = command.c console.c debug.c formula.c globals.c http.c lists.c main.c \ movecheck.c network.c opcodes.c ropcodes.c style.c topcodes.c types.c \ util.c vars.c version.c OBJS = command.o console.o debug.o formula.o globals.o http.o lists.o main.o \ movecheck.o network.o opcodes.o ropcodes.o style.o topcodes.o types.o \ util.o vars.o version.o all: yics.exe .depend: $(SRCS) mkdep $(CFLAGS) $(SRCS) yics.exe: $(OBJS) $(CC) $(CFLAGS) $(OBJS) -lwsock32 -o yics.exe .c.o: $< $(CC) $(CFLAGS) -c $< -o $@ clean: rm -f *.o .depend .PHONY: all clean include .depend yics-0.1.2/ytoics-c/Makefile.msvc0000644000175000001440000000556610243006257017124 0ustar chrisusers00000000000000#if 0 ######################################### # # # YTOICS-C for win32 # # # # Makefile.msvc # # # # Make sure that vcvars32.bat has # # been called and issue the command: # # # # nmake /f Makefile.msvc # # # ######################################### APP = ytoics TDIR=. ODIR=.\obj !IF "$(OS)" == "Windows_NT" DEVNULL= !ELSE DEVNULL=nul !ENDIF CC=cl.exe LINK32=link.exe DEFS=/D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "_X86_" CFLAGS=/nologo /MT /W4 /GX /O2 /Fo"$(ODIR)\\" /Fd"$(ODIR)\\" /FD /c LFLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib odbc32.lib uuid.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /incremental:no /pdb:"$(TDIR)\$(APP).pdb" /machine:I386 /out:"$(TDIR)\$(APP).exe" #LFLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\msvc.pdb" /machine:I386 /out:"$(OUTDIR)\msvc.exe" OFILES= "$(ODIR)\command.obj" \ "$(ODIR)\version.obj" \ "$(ODIR)\http.obj" \ "$(ODIR)\network.obj" \ "$(ODIR)\util.obj" \ "$(ODIR)\globals.obj" \ "$(ODIR)\console.obj" \ "$(ODIR)\opcodes.obj" \ "$(ODIR)\ropcodes.obj" \ "$(ODIR)\style.obj" \ "$(ODIR)\topcodes.obj" \ "$(ODIR)\types.obj" \ "$(ODIR)\debug.obj" \ "$(ODIR)\formula.obj" \ "$(ODIR)\main.obj" \ "$(ODIR)\movecheck.obj"\ "$(ODIR)\vars.obj" # Makefile verbose setting QUIET = @ # QUIET = ALL : "$(TDIR)\$(APP).exe" CLEAN : -$(QUIET)erase "$(ODIR)\*.obj" -$(QUIET)erase "$(ODIR)\*.idb" -$(QUIET)erase "$(TDIR)\$(APP).exe" "$(ODIR)" : $(QUIET)if not exist "$(ODIR)/$(DEVNULL)" mkdir "$(ODIR)" "$(TDIR)\$(APP).exe" : "$(TDIR)" $(DEF_FILE) $(OFILES) $(QUIET)$(LINK32) @<< $(LFLAGS) $(OFILES) << # Compile rule .c{$(ODIR)}.obj:: $(QUIET)$(CC) $(DEFS) $(CFLAGS) $< # Dependencies "$(ODIR)\console.obj" : "$(ODIR)" console.c console.h network.h types.h "$(ODIR)\debug.obj" : "$(ODIR)" debug.c debug.h types.h "$(ODIR)\globals.obj" : "$(ODIR)" globals.c globals.h "$(ODIR)\main.obj" : "$(ODIR)" main.c console.h debug.h globals.h opcodes.h sockets.h network.h util.h types.h "$(ODIR)\network.obj" : "$(ODIR)" network.c sockets.h network.h util.h types.h "$(ODIR)\opcodes.obj" : "$(ODIR)" opcodes.c console.h opcodes.h network.h types.h "$(ODIR)\types.obj" : "$(ODIR)" types.c debug.h types.h "$(ODIR)\util.obj" : "$(ODIR)" util.c sockets.h util.h types.h "$(ODIR)\version.obj" : "$(ODIR)" version.c "$(ODIR)\formula.obj" : "$(ODIR)" formula.c types.h formula.h globals.h vars.h #endif yics-0.1.2/ytoics-c/Makefile.watcom0000644000175000001440000000530610243006257017436 0ustar chrisusers00000000000000#if 0 ######################################### # # # YTOICS-C for win32 # # # # Makefile.watcom # # # # Make sure that WATCOM environment # # variable is set and issue the # # command: # # # # wmake /f Makefile.watcom # # # ######################################### APP = ytoics CDIR = . IDIR = . ODIR = .\obj ADIR = .\arc DEVNULL = nul CC = *wcc386 LINK = wlink TAR = pkzip -u # CFLAGS = -i=$(%watcom)\h;$(%watcom)\h\nt -e25 -zq -oairten -6r -j -s -bt=nt CFLAGS = -e25 -zq -oairten -6r -j -s -wx -bt=nt -bm OFILES = $(ODIR)\command.obj & $(ODIR)\console.obj & $(ODIR)\debug.obj & $(ODIR)\formula.obj & $(ODIR)\globals.obj & $(ODIR)\main.obj & $(ODIR)\http.obj & $(ODIR)\network.obj & $(ODIR)\opcodes.obj & $(ODIR)\ropcodes.obj & $(ODIR)\style.obj & $(ODIR)\topcodes.obj & $(ODIR)\types.obj & $(ODIR)\util.obj & $(ODIR)\vars.obj & $(ODIR)\movecheck.obj & $(ODIR)\version.obj # Makefile verbose setting QUIET = @ # QUIET = .c: $(CDIR) # The default build rule for cpp -> obj creation. .c.obj: .AUTODEPEND $(QUIET)echo Compiling: $[* $(QUIET)$(CC) $[* $(CFLAGS) -fo=$(ODIR)\$[*.obj # The first rule is the default build rule, from which all other rules may be # activated $(APP).exe : $(OFILES) makefile.watcom .AUTODEPEND $(QUIET)%write $(ODIR)\$(APP).lk1 NAME $(APP) $(QUIET)for %%f in ($(OFILES)) do $(QUIET)%append $(ODIR)\$(APP).lk1 FIL %%f $(QUIET)%append $(ODIR)\$(APP).lk1 op symf=$(ODIR)\$(APP).sym $(QUIET)%append $(ODIR)\$(APP).lk1 op map=$(ODIR)\$(APP).map $(QUIET)%append $(ODIR)\$(APP).lk1 debug all $(QUIET)echo Linking: $(APP) $(QUIET)*$(LINK) SYS nt d all op stack=4194304 op maxe=25 op q @$(ODIR)\$(APP).lk1 $(QUIET)echo. $(QUIET)echo Target $(APP).exe done. # Non-default build rules. # Initial commands invoked on every make .BEFORE $(QUIET)echo $(APP) $(QUIET)echo ====== $(QUIET)set PATH=%path%;$(%watcom)\bin;$(%watcom)\binb;$(%watcom)\binw $(QUIET)set INCLUDE=.;$(%watcom)\h;$(%watcom)\h\nt $(QUIET)set DOS4G=QUIET # User defined commands clean: .SYMBOLIC $(QUIET)echo Removing build targets $(QUIET)for %%f in ($(ODIR)\*.* $(APP).exe) do @if exist %%f del %%f > nul archive: .SYMBOLIC @echo xxx > $(ADIR)\xxx @if not exist $(ADIR)\xxx mkdir $(ADIR) @if exist $(ADIR)\xxx @del $(ADIR)\xxx @$(TAR) $(ADIR)\$(APP).zip *.c *.h makefi*.* #endif yics-0.1.2/ytoics-c/command.c0000644000175000001440000015117210260627233016274 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include #include #include #include #include "types.h" #include "command.h" #include "console.h" #include "network.h" #include "globals.h" #include "util.h" #include "vars.h" #include "version.h" #include "ropcodes.h" #include "topcodes.h" #include "movecheck.h" #include "formula.h" #include "sockets.h" #include "lists.h" #define IsLetter(x) ((((x) >= 'A') && ((x) <= 'Z')) \ || (((x) >= 'a') && ((x) <= 'z'))) #define IsNumber(x) (((x) >= '0') && ((x) <= '9')) #define IsFile(x) (((x) >= 'a') && ((x) <= 'h')) #define IsRank(x) (((x) >= '1') && ((x) <= '8')) #define GetFile(x) ((x) - 'a') #define GetRank(x) ((x) - '1') #define PARAM_MAX 10 static void com_abort(String *[], int); static void com_accept(String *[], int); static void com_addlist(String *[], int); static void com_adjourn(String *[], int); static void com_alias(String *[], int); static void com_allobservers(String *[], int); static void com_boot(String *[], int); static void com_cls(String *[], int); static void com_create(String *[], int); void com_decline(String *[], int); /* We use this in vars.c */ static void com_draw(String *[], int); static void com_finger(String *[], int); static void com_flag(String *[], int); static void com_games(String *[], int); static void com_help(String *[], int); static void com_invite(String *[], int); static void com_kibitz(String *[], int); static void com_moves(String *[], int); static void com_observe(String *[], int); static void com_pending(String *[], int); static void com_ping(String *[], int); static void com_play(String *[], int); static void com_primary(String *[], int); static void com_quit(String *[], int); static void com_refresh(String *[], int); static void com_resign(String *[], int); static void com_resume(String *[], int); static void com_seek(String *[], int); static void com_set(String *[], int); static void com_shout(String *[], int); static void com_showlist(String *[], int); static void com_sit(String *[], int); static void com_sought(String *[], int); static void com_stand(String *[], int); static void com_start(String *[], int); static void com_sublist(String *[], int); static void com_tell(String *[], int); static void com_time(String *[], int); static void com_tset(String *[], int); static void com_unalias(String *[], int); static void com_unobserve(String *[], int); static void com_variables(String *[], int); static void com_who(String *[], int); static void com_xkibitz(String *[], int); static void com_xtell(String *[], int); static void com_znotify(String *[], int); static Command commands[] = { /* name handler params */ {"!", com_shout, 1 }, {"*", com_kibitz, 1 }, {"+", com_addlist, 2 }, {"-", com_sublist, 2 }, {"=", com_showlist, 1 }, {"bye", com_quit, 0 }, {"exit", com_quit, 0 }, {"iset", com_set, 2 }, {"logout", com_quit, 0 }, {"qtell", com_tell, 2 }, /* for bots */ {"abort", com_abort, 0 }, {"accept", com_accept, 1 }, {"addlist", com_addlist, 2 }, {"adjourn", com_adjourn, 0 }, {"alias", com_alias, 2 }, {"allobservers",com_allobservers, 1 }, {"boot", com_boot, 1 }, {"cls", com_cls, 0 }, {"create", com_create, 0 }, {"decline", com_decline, 2 }, {"draw", com_draw, 0 }, {"finger", com_finger, 1 }, {"flag", com_flag, 0 }, {"games", com_games, 1 }, {"help", com_help, 0 }, {"invite", com_invite, 1 }, {"kibitz", com_kibitz, 1 }, {"moves", com_moves, 1 }, {"observe", com_observe, 1 }, {"pending", com_pending, 0 }, {"ping", com_ping, 1 }, {"play", com_play, 1 }, {"primary", com_primary, 1 }, {"quit", com_quit, 0 }, {"refresh", com_refresh, 1 }, {"resign", com_resign, 0 }, {"resume", com_resume, 0 }, {"seek", com_seek, 4 }, {"set", com_set, 2 }, {"shout", com_shout, 1 }, {"showlist", com_showlist, 1 }, {"sit", com_sit, 1 }, {"sought", com_sought, 1 }, {"stand", com_stand, 0 }, {"start", com_start, 0 }, {"sublist", com_sublist, 2 }, {"tell", com_tell, 2 }, {"time", com_time, 0 }, {"tset", com_tset, 2 }, {"unalias", com_unalias, 1 }, {"unobserve", com_unobserve, 1 }, {"variables", com_variables, 0 }, {"who", com_who, 1 }, {"xkibitz", com_xkibitz, 2 }, {"xtell", com_xtell, 2 }, {"znotify", com_znotify, 0 }, {NULL, NULL, 0 }, }; /* * These are less efficient than simple command handlers, but they do allow * parameters to be specified. * * Internal aliases do not take part in command completion, which means that * they don't block commands from working. I.e. a handler alias of "vars" * would cause "var" to be ambiguous; here, it does not. */ static Alias internalAliases[] = { {".", "tell . $@"}, {"`", "tell . $@"}, {"ame", "allobservers $m"}, {"f", "finger $@"}, {"f.", "finger $."}, {"fop", "finger $o"}, {"oping", "ping $o"}, {"p", "who a$@"}, {"pl", "who a$@"}, {"player", "who a$@"}, {"players", "who a$@"}, {"rping", "ping $@"}, {"sping", "ping $@"}, {"style", "set style $@"}, {"t", "tell $@"}, {"tping", "ping $."}, {"vars", "variables"}, {"znotl", "znotify"}, {NULL, NULL}, }; static char *noalias[] = {"alias", "quit", "unalias", NULL}; static Alias *aliases[ALIAS_MAX + 1] = {NULL}; void alias_param(String *out, String *param, int from, int to) { /* from and to do not point at the same spot! In the string * "foobar sells widgets": * * from: 1 2 3 * foobar sells widgets * to: 1 2 3 * * So 3-3 gets the whole third parameter. */ char *buffer = malloc(param->length + 1); char *bufferp = buffer; char *paramp = param->string; bool onws = false; int word = 1; if (buffer == NULL) { StringSet(out, NULL, 0); return; } while (*paramp == ' ') paramp++; if (to < 0) to = param->length; while ((word <= to) && (*paramp != '\0')) { if (*paramp == ' ') { if (!onws) { word++; onws = true; } if ((word > from) && (word <= to)) *(bufferp++) = ' '; } else { if (onws) { onws = false; } if (word >= from) *(bufferp++) = *paramp; } paramp++; } *bufferp = '\0'; StringSet(out, buffer, -1); free(buffer); } static void alias_substitute(Alias *alias, String *command, String *param) { char *aptr = alias->mapping; int from, to; int starpos; String *stmp; bool gottoken = false; StringSet(command, NULL, 0); starpos = 1; while (*aptr) { if (*aptr == '$') { gottoken = true; aptr++; if (!*aptr) break; if (IsNumber(*aptr) || (*aptr == '-')) { if (*aptr == '-') { from = 1; } else { from = atoi(aptr); while (IsNumber(*(++aptr))); } if (*aptr == '-') { aptr++; if (IsNumber(*aptr)) { to = atoi(aptr); if (to < from) to = from; else while (IsNumber(*(++aptr))); } else { to = -1; } } else { to = from; } stmp = StringNull(); alias_param(stmp, param, from, to); StringCat(command, stmp->string, stmp->length); StringFree(stmp); continue; } switch (*aptr) { case '@': StringCat(command, param->string, param->length); break; case 'm': StringCat(command, pme->handle, -1); break; case 'o': if (lastopp != NULL) StringCat(command, lastopp->handle, -1); break; case '.': if (lasttell != NULL) StringCat(command, lasttell->handle, -1); break; case '*': stmp = StringNull(); alias_param(stmp, param, starpos, starpos); StringCat(command, stmp->string, stmp->length); StringFree(stmp); starpos++; break; /* This handles "case '$':" too. */ default: StringCat(command, aptr, 1); } } else { StringCat(command, aptr, 1); } aptr++; } /* Try regular @s */ if (!gottoken) { StringSet(command, NULL, 0); for (aptr = alias->mapping; *aptr != '\0'; aptr++) { if (*aptr == '@') StringCat(command, param->string, param->length); else StringCat(command, aptr, 1); } } } static bool is_move(const char *command) { int len; char *mcpy, mv[4]; String *mdup; uchar x1 = 0, y1 = 0, x2 = 0, y2 = 0; Table *table; Color turn; char promote = 0; bool castle = false; mdup = StringNew(command, -1); mcpy = mdup->string; lowercase(mcpy); len = strlen(mcpy); if ((len > 3) && (mcpy[len - 2] == '=')) { switch (mcpy[len - 1]) { case 'n': promote = 4; break; case 'b': promote = 6; break; case 'r': promote = 8; break; case 'q': promote = 10; break; default: StringFree(mdup); return false; } len -= 2; } if (len == 5) { if ((mcpy[2] == '-') && IsFile(mcpy[0]) && IsRank(mcpy[1]) && IsFile(mcpy[3]) && IsRank(mcpy[4])) { x1 = (uchar)GetFile(mcpy[0]); y1 = (uchar)GetRank(mcpy[1]); x2 = (uchar)GetFile(mcpy[3]); y2 = (uchar)GetRank(mcpy[4]); } else if (!strcmp("o-o-o", mcpy)) { x1 = 4; x2 = 2; castle = true; } else { StringFree(mdup); return false; } } else if (len == 4) { if (IsFile(mcpy[0]) && IsRank(mcpy[1]) && IsFile(mcpy[2]) && IsRank(mcpy[3])) { x1 = (uchar)GetFile(mcpy[0]); y1 = (uchar)GetRank(mcpy[1]); x2 = (uchar)GetFile(mcpy[2]); y2 = (uchar)GetRank(mcpy[3]); } else { StringFree(mdup); return false; } } else if (len == 3) { if (!strcmp("o-o", mcpy)) { x1 = 4; x2 = 6; castle = true; } else { StringFree(mdup); return false; } } else { StringFree(mdup); return false; } StringFree(mdup); mdup = NULL; mcpy = NULL; if (primary == -1) { iprint("You are not playing or examining a game.\n"); prompt(); return true; } table = tables[primary]; turn = BLACK; if (table->players[0] == pme) { turn = WHITE; } else if (table->players[1] != pme) { iprint("You are not playing or examining a game.\n"); prompt(); return true; } if (table->game->turn != turn) { iprint("It is not your turn.\n"); prompt(); return true; } if (castle) y1 = y2 = (uchar)((turn == WHITE) ? 0 : 7); if (!legal_andcheck_move(table->game, x1, y1, x2, y2)) { iprintf("Illegal move (%s).\n", command); refresh(table); return true; } if (((y2 == 0) || (y2 == 7)) && (piecetype(table->game->board[x1][y1]) == PAWN)) { /* * If a pawn is being moved to the last rank and no promotion * piece was specified, default to a queen. */ if (promote == 0) promote = 10; /* * But if a pawn wasn't moved to the edge and a promotion piece was * specified, it's illegal. */ } else if (promote != 0) { iprintf("Illegal move (%s).\n", command); refresh(table); return true; } /* YOG is upside-down */ y1 = (uchar)(7 - y1); y2 = (uchar)(7 - y2); mv[0] = x1; mv[1] = y1; mv[2] = x2; mv[3] = y2; nprinttop(table->number, TOP_MOVE, mv, 4); if (promote != 0) nprinttop(table->number, TOP_PROMOTE, &promote, 1); return true; } void do_command(const char *cm, bool noalias) { String *command = StringNew(cm, -1); String *param = StringNull(); String *paramlist[PARAM_MAX]; int i, len, start = 0, pcount = 0; bool youlose = false, onspace = true; Command *srch, *match = NULL; Alias *al; if ((command == NULL) || (param == NULL)) { iprint("Out of memory!"); prompt(); if (command != NULL) StringFree(command); if (param != NULL) StringFree(param); return; } trimString(command); if (command->string[0] == '\0') { StringFree(command); StringFree(param); prompt(); return; } if (!noalias && (command->string[0] == '$')) { do_command(&command->string[1], true); StringFree(command); StringFree(param); return; } if (is_move(command->string)) { StringFree(command); StringFree(param); return; } if (!IsLetter(command->string[0]) && !IsNumber(command->string[0])) { StringSet(param, &command->string[1], command->length - 1); ltrimString(param); StringSet(command, &command->string[0], 1); } else { for (i = 0; i < command->length; i++) { if (command->string[i] == ' ') { StringSet(param, &command->string[i + 1], command->length - i - 1); StringSet(command, command->string, i); break; } } } ltrimString(param); if (!noalias) { for (i = 0; (i < ALIAS_MAX) && (aliases[i] != NULL); i++) { al = aliases[i]; if (!strcmp(al->alias, command->string)) { alias_substitute(al, command, param); do_command(command->string, true); StringFree(command); StringFree(param); return; } } } al = internalAliases; while (al->alias != NULL) { if (!strcmp(al->alias, command->string)) { alias_substitute(al, command, param); do_command(command->string, noalias); StringFree(command); StringFree(param); return; } al++; } lowercase(command->string); len = command->length; for (srch = commands; srch->command != NULL; srch++) { if (!strcmp(command->string, srch->command)) { match = srch; break; } else if ((len <= (int)strlen(srch->command)) && !memcmp(srch->command, command->string, len)) { if (match == NULL) { match = srch; } else if (youlose) { iprint(" "); iprint(srch->command); } else { youlose = true; iprint("Ambiguous command. Matches: "); iprint(match->command); iprint(" "); iprint(srch->command); } } } if (youlose) { iprint("\n"); prompt(); StringFree(command); StringFree(param); return; } if (match == NULL) { iprint(command->string); iprint(": Command not found.\n"); prompt(); StringFree(command); StringFree(param); return; } memset(paramlist, 0, sizeof(paramlist)); if (match->maxparams != 0) { if (match->maxparams > PARAM_MAX) /* this resets the global array too */ match->maxparams = PARAM_MAX; for (i = 0; i < param->length; i++) { if (onspace && (param->string[i] != ' ')) { start = i; onspace = false; } else if (!onspace && (param->string[i] == ' ') && (pcount != match->maxparams - 1)) { LASTONE: paramlist[pcount++] = StringNew( ¶m->string[start], i - start); onspace = true; } } if (!onspace) goto LASTONE; /* dirty hack */ } StringFree(command); StringFree(param); match->handler(paramlist, pcount); for (i = 0; i < PARAM_MAX; i++) { if (paramlist[i] != NULL) StringFree(paramlist[i]); } } static int sort_alias(const void *sa, const void *sb) { return strcmp((*(Alias **)sa)->alias, (*(Alias **)sb)->alias); } static void abort_adjourn(char adjourn) { Table *table; if (primary == -1) { iprint("You are not playing or examining a game.\n"); prompt(); return; } table = tables[primary]; if ((table->players[0] != pme) && (table->players[1] != pme)) { iprintf("You are not seated at table %d.\n", primary); prompt(); return; } nprinttop(table->number, TOP_CANCELSAVE, &adjourn, 1); } static void com_abort(String *param[], int pcount) { abort_adjourn(0); } static void com_accept(String *param[], int pcount) { Invite *current = invitations; Player *p; int i; /* char tmp[16]; */ if (pcount == 0) { ACCEPT_USAGE: iprint("Usage: accept \n"); prompt(); return; } else if (current == NULL) { iprint("You have no offers to accept.\n"); prompt(); return; } if (isnumeric(param[0]->string)) { i = atoi(param[0]->string); if (i < 1) goto ACCEPT_USAGE; while ((current != NULL) && --i) current = current->next; if ((i != 0) || (current == NULL)) { iprint("Out of range. Use \"pending\" to see the " "list of offers.\n"); prompt(); return; } /* snprintf(tmp, sizeof(tmp), "%d", current->number); StringSet(param[0], tmp, -1); com_observe(param, 1);*/ } else if ((p = completeHandle(param[0])) != NULL) { while ((current != NULL) && (current->who != p)) current = current->next; if (current == NULL) { iprint("There are no pending offers from "); iprint(p->handle); iprint(".\n"); prompt(); return; } /* snprintf(tmp, sizeof(tmp), "%d", current->number); StringSet(param[0], tmp, -1); com_observe(param, 1);*/ } delInvite(NULL, current->number); nprintrop(ROP_OBSERVE, (char *)¤t->number, 1); } static void com_addsublist(String *param[], int pcount, bool remove) { List *list; Player *p; if (pcount != 2) { iprintf("Usage: %slist \n", remove ? "sub" : "add"); prompt(); return; } if ((list = findList(param[0]->string)) == NULL) return; if (param[1]->string[param[1]->length - 1] == '!') { param[1]->string[param[1]->length - 1] = '\0'; lowercase(param[1]->string); } else { if ((p = completeHandle(param[1])) == NULL) return; StringSet(param[1], p->lhandle, -1); } if (inList(list, param[1]->string) ^ remove) { iprintf("[%s] is %s your %s list.\n", param[1]->string, remove ? "not in" : "already on", list->name); prompt(); return; } /* Function references are so magical! */ if (!(remove ? listSub : listAdd)(list, param[1]->string)) { iprintf("Unable to %s %s %s your %s list.\n", remove ? "remove" : "add", param[1]->string, remove ? "from" : "to", list->name); } else { iprintf("[%s] %s your %s list.\n", param[1]->string, remove ? "removed from" : "added to", list->name); if (remove && (list->on_sub != NULL)) list->on_sub(param[1]->string); else if (!remove && (list->on_add != NULL)) list->on_add(param[1]->string); } prompt(); } static void com_addlist(String *param[], int pcount) { com_addsublist(param, pcount, false); } static void com_adjourn(String *param[], int pcount) { abort_adjourn(1); } static void collapse_aliases() { int i, j = 0; for (i = 0; i < ALIAS_MAX; i++) if (aliases[i] != NULL) aliases[j++] = aliases[i]; aliases[j] = NULL; } static void com_alias(String *param[], int pcount) { int i, count; Alias *al = NULL; char **noal; bool found; if (pcount == 0) { count = 0; for (i = 0; (i < ALIAS_MAX) && (aliases[i] != NULL); i++) count++; if (count == 0) { iprint("You have no aliases.\n"); } else { iprint("Aliases:\n\n"); qsort(aliases, count, sizeof(Alias *), sort_alias); for (i = 0; i < count; i++) { iprint(aliases[i]->alias); iprint(" -> "); iprint(aliases[i]->mapping); iprint("\n"); } } } else { lowercase(param[0]->string); for (noal = noalias; *noal != NULL; noal++) if (!strcmp(*noal, param[0]->string)) { iprintf("You cannot alias this command.\n"); prompt(); return; } found = false; for (i = 0; (i < ALIAS_MAX) && (aliases[i] != NULL); i++) { al = aliases[i]; if (!strcmp(param[0]->string, al->alias)) { found = true; break; } } if (pcount == 1) { if (found) { iprint(al->alias); iprint(" -> "); iprint(al->mapping); iprint("\n"); } else { iprint("You have no alias "); iprint(param[0]->string); iprint(".\n"); } } else { if (found) { free(al->mapping); al->mapping = malloc(param[1]->length + 1); if (al->mapping == NULL) { free(al->alias); free(al); aliases[i] = NULL; collapse_aliases(); iprint("Out of memory.\n"); prompt(); return; } mstrncpy(al->mapping, param[1]->string, param[1]->length + 1); } else { for (i = 0; (i < ALIAS_MAX) && (aliases[i] != NULL); i++); if (i == ALIAS_MAX) { iprint("You have too many aliases."); prompt(); return; } else { al = malloc(sizeof(Alias)); if (al == NULL) { iprint("Out of memory.\n"); prompt(); return; } al->alias = malloc(param[0]->length + 1); al->mapping = malloc(param[1]->length + 1); if ((al->alias == NULL) || (al->mapping == NULL)) { free(al); if (al->alias != NULL) free(al->alias); if (al->mapping != NULL) free(al->mapping); iprint("Out of memory.\n"); prompt(); return; } mstrncpy(al->alias, param[0]->string, param[0]->length + 1); mstrncpy(al->mapping, param[1]->string, param[1]->length + 1); aliases[i] = al; } } iprint("Alias "); iprint(param[0]->string); iprint(found ? " replaced.\n" : " set.\n"); } } prompt(); } static int print_observers(Table *table) { int i; int count = 0; Player *p; for (i = 0; i < PLAYER_MAX; i++) { if (((p = table->observers[i]) != NULL) && (p != table->players[0]) && (p != table->players[1])) { if (count++ == 0) iprintf("Observing %d: [%s vs %s]", table->number, phandle(table->players[0]), phandle(table->players[1])); iprintf(" %s", p->handle); } } if (count > 0) iprintf(" (%d user%s)\n", count, ((count == 1) ? "" : "s")); return count; } static void com_allobservers(String *param[], int pcount) { int i, obs = 0, total = 0; Table *table; String *spec; if (pcount == 0) { for (i = 0; i < TABLE_MAX; i++) { if ((table = tables[i]) != NULL) { total++; if (print_observers(table) > 0) obs++; } } } else { if ((table = findTable(param[0], (spec = StringNull()))) != NULL) { if (print_observers(table) > 0) { obs++; for (i = 0; i < TABLE_MAX; i++) if (tables[i] != NULL) total++; } else { iprintf("No one is observing %s.\n", spec->string); prompt(); } StringFree(spec); } } if (obs != 0) { iprintf("\n %d game%s displayed (of %d in progress).\n", obs, ((obs == 1) ? "" : "s"), total); prompt(); } } static void com_boot(String *param[], int pcount) { int i; Table *table; Player *p; String *packet; if (pcount != 1) { iprint("Usage: boot [handle]\n"); prompt(); return; } if (primary == -1) { iprint("You are not playing or observing a game.\n"); prompt(); return; } table = tables[primary]; if (table->host != pme) { iprintf("You are not the host of table %d.\n", primary); prompt(); return; } if ((p = completeHandle(param[0])) == NULL) return; for (i = 0; (i < PLAYER_MAX) && (table->observers[i] != p); i++); if (i == PLAYER_MAX) { iprintf("%s is not observing game %d.\n", p->handle, primary); prompt(); return; } packet = StringNew(p->lhandle, -1); packutfString(packet, packet); nprinttop((uchar)primary, (char)TOP_BOOT, packet->string, packet->length); StringFree(packet); } static void com_cls(String *param[], int pcount) { iprint("\x1b[H\x1b[2J\n"); prompt(); } static void com_create(String *param[], int pcount) { param = param; pcount = pcount; nprintrop(ROP_CREATETABLE, "\0\0", 2); } void com_decline(String *param[], int pcount) { Player *p; String *reason, *packet; if (pcount == 0) { iprint("Usage: decline [reason]\n"); prompt(); return; } else if (pcount == 2) { reason = StringDup(param[1]); } else { reason = StringNew("None", -1); } if ((p = completeHandle(param[0])) == NULL) return; if (!delInvite(p, 0)) { iprint("There are no pending offers from "); iprint(p->handle); iprint(".\n"); prompt(); return; } packet = StringNew(p->lhandle, -1); packutfString(packet, packet); packutfStringP(packet, reason); nprintropString(ROP_DECLINE, packet); iprint("You decline the match offer from "); iprint(p->handle); iprint(".\nReason given: "); iprint(reason->string); iprint("\n"); prompt(); StringFree(packet); StringFree(reason); } static void com_draw(String *param[], int pcount) { Table *table; Color color; if (primary == -1) { iprint("You are not playing or examining a game.\n"); prompt(); return; } table = tables[primary]; if (table->players[0] == pme) { color = WHITE; } else if (table->players[1] == pme) { color = BLACK; } else { iprintf("You are not seated at table %d.\n", primary); prompt(); return; } /* This is SO not in line with FIDE rules... */ if (color == table->game->turn) { iprint("You may not offer a draw during your turn.\n"); prompt(); return; } nprinttop((uchar)primary, (char)TOP_DRAW, NULL, 0); } static void com_finger(String *param[], int pcount) { String *who = StringNull(); Player *p; if (pcount == 0) { StringSet(who, pme->lhandle, -1); } else { if ((p = completeHandle(param[0])) == NULL) { StringFree(who); return; } StringSet(who, p->lhandle, -1); } packutfString(who, who); nprintropString(ROP_FINGER, who); StringFree(who); } static void com_flag(String *param[], int pcount) { Table *table = NULL; char opp; if (primary != -1) table = tables[primary]; if ((primary == -1) || ((table->players[0] != pme) && (table->players[1] != pme)) || table->finished) { iprint("You are not playing a game.\n"); } else if (gameType(table) == 'u') { iprint("You can't flag untimed games.\n"); } else if (timeleft(table, (table->players[0] == pme) ? 1 : 0) > 1000) { iprint("Opponent is not out of time.\n"); } else { iprint("Flagging...\n"); opp = (char)((table->players[0] == pme) ? 1 : 0); nprinttop(table->number, TOP_FLAG, &opp, 1); } prompt(); } static int sort_table(const void *sa, const void *sb) { Table *a = *(Table **)sa; Table *b = *(Table **)sb; int ra = 0, rb = 0; if ((a->players[0] != NULL) && (a->players[0]->rating != PROVISIONAL)) ra += a->players[0]->rating; if ((a->players[1] != NULL) && (a->players[1]->rating != PROVISIONAL)) ra += a->players[1]->rating; if ((b->players[0] != NULL) && (b->players[0]->rating != PROVISIONAL)) rb += b->players[0]->rating; if ((b->players[1] != NULL) && (b->players[1]->rating != PROVISIONAL)) rb += b->players[1]->rating; return (ra < rb) ? -1 : (ra > rb) ? 1 : 0; } static void print_games(Table **games) { Player *white, *black; Player nullpl = {"", "", PROVISIONAL}; Table *table; char wh[12], bh[12], wr[16], br[16], rated; char *tenmin; int i; const char protections[3] = {' ', 'p', 'P'}; /* Format examples: 5 1700 AlphaWolf 1605 myaa [ br 3 0] 2:39 - 2:20 (38-38) W: 10 96 1685 PSerge 1755 ChrisHowie [ xu999 999] 10:00:00 -10:00:00 (39-39) W: 1 */ while (*games != NULL) { table = *games; white = table->players[0]; black = table->players[1]; if (white == NULL) white = &nullpl; if (black == NULL) black = &nullpl; prating(wr, white->rating, 4); prating(br, black->rating, 4); i = 0; while ((i < 11) && (white->handle[i] != '\0')) { wh[i] = white->handle[i]; i++; } wh[i] = '\0'; i = 0; while ((i < 11) && (black->handle[i] != '\0')) { bh[i] = black->handle[i]; i++; } bh[i] = '\0'; rated = (char)(tablerated(table) ? 'r' : 'u'); tenmin = (findOption(table->options, "pl") != NULL) ? "" : " 10 min/move"; iprintf("%3d %4s %-11s %4s %-11s [%c%c%c%3d %3d]%s\n", table->number, wr, wh, br, bh, protections[table->protection], gameType(table), rated, tabletime(table), tableinc(table), tenmin); games++; } } static void com_games(String *param[], int pcount) { Table *open[TABLE_MAX], *closed[TABLE_MAX]; Table *c; int i, openc = 0, closedc = 0, total = 0; if (pcount == 0) { for (i = 0; i < TABLE_MAX; i++) { if (tables[i] != NULL) { total++; c = tables[i]; if ((c->players[0] == NULL) || (c->players[1] == NULL)) open[openc++] = c; else closed[closedc++] = c; } } } else { if ((c = findTable(param[0], NULL)) == NULL) return; /* Since there's only one, it doesn't matter where it goes. */ open[openc++] = c; for (i = 0; i < TABLE_MAX; i++) if (tables[i] != NULL) total++; } open[openc] = NULL; closed[closedc] = NULL; qsort(open, openc, sizeof(Table *), sort_table); qsort(closed, closedc, sizeof(Table *), sort_table); print_games(open); print_games(closed); openc += closedc; if (openc != 0) { iprintf("\n %d games displayed", openc); } else { iprint("No matching games were found"); } iprintf(" (of %d in progress).\n", total); prompt(); } static void com_help(String *param[], int pcount) { param = param; pcount = pcount; sysiprint( "\n" "--------------------------------------------------" "---------------------------\n" "This is YICS version "); sysiprint(VERSION); sysiprint( ".\n\n" "For help using YICS, please see http://www.yics.org/wiki\n\n" "YICS: Connect an ICS interface to the Yahoo! Chess server.\n" "Copyright (C) 2004 Chris Howie\n" "Portions Copyright (C) 1993 Richard V. Nash\n\n" "This program is free software; you can redistribute it and/or " "modify it under the terms of the GNU General Public License as "); sysiprint("published by the Free Software Foundation; either version " "2 of the License, or (at your option) any later version.\n\n" "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 (contained in the LICENSE file) for more " "details.\n" "--------------------------------------------------" "---------------------------\n\n"); prompt(); } static void com_invite(String *param[], int pcount) { Table *table; Player *p; String *packet; if (pcount != 1) { iprint("Usage: invite [handle]\n"); prompt(); return; } if (primary == -1) { iprint("You are not playing or observing a game.\n"); prompt(); return; } table = tables[primary]; if (table->host != pme) { iprintf("You are not the host of table %d.\n", primary); prompt(); return; } if ((p = completeHandle(param[0])) == NULL) return; packet = StringNew(p->lhandle, -1); packutfString(packet, packet); nprinttop((uchar)primary, (char)TOP_INVITE, packet->string, packet->length); iprintf("Inviting %s to table %d.\n", p->handle, primary); prompt(); StringFree(packet); } static void com_kibitz(String *param[], int pcount) { String *message; if (pcount == 0) { iprint("Usage: kibitz \n"); prompt(); return; } if (primary == -1) { iprint("You are not playing or observing a game.\n"); prompt(); return; } message = packutfString(StringNull(), param[0]); nprinttopString((uchar)primary, (char)TOP_KIBITZ, message); StringFree(message); } static void com_moves(String *param[], int pcount) { Table *t; Player nullpl = {"[EMPTY]", "[EMPTY]", PROVISIONAL}; static char tmp[32]; Player *white, *black; char wr[18], br[18]; time_t tm; int gtime, ginc; Movelist *current; int ms = variables[VAR_MS].number; char *timeTaken; if (primary == -1) { iprint("You are not playing or observing a game.\n"); prompt(); return; } t = tables[primary]; iprintf("\nMovelist for game %d:\n", primary); white = (t->players[0] == NULL) ? &nullpl : t->players[0]; black = (t->players[1] == NULL) ? &nullpl : t->players[1]; if (white->rating == PROVISIONAL) strcpy(wr, "UNR"); else sprintf(wr, "%d", white->rating); if (black->rating == PROVISIONAL) strcpy(br, "UNR"); else sprintf(br, "%d", black->rating); time(&tm); mstrncpy(tmp, ctime(&tm), sizeof(tmp)); tmp[strlen(tmp) - 1] = '\0'; printf("\n%s (%s) vs. %s (%s) --- %s\n", white->handle, wr, black->handle, br, tmp); gtime = tabletime(t); ginc = tableinc(t); printf("%sated %s match, initial time: %d minutes, increment: %d seconds.\n", (tablerated(t) ? "R" : "Unr"), strGameType(t), gtime, ginc); mstrncpy(wr, white->handle, 17); wr[17] = '\0'; mstrncpy(br, black->handle, 17); br[17] = '\0'; if (ms) printf("\nMove %-17s %-17s\n" "---- --------------------- ---------------------\n", wr, br); else printf("\nMove %-17s %-17s\n" "---- ---------------- ----------------\n", wr, br); ginc = 1; gtime = 0; current = t->game->movelist; ms = ms ? 14 : 9; while (current != NULL) { timeTaken = fmttime_ms(current->move.timeTaken); if (gtime) { printf("%-8s(%s)\n", current->move.alg, timeTaken); gtime = 0; ginc++; } else { printf("%3d. %-8s(%s)%*s", ginc, current->move.alg, timeTaken, ms - strlen(timeTaken), ""); gtime = 1; } current = current->next; } if (gtime) printf("\n"); printf(" {%s} %s\n\n", (t->finished ? "Finished" : "Still in progress"), t->result); prompt(); } static void observe_unobserve(String *param[], int pcount, bool onlyUnobserve) { Table *table; int i; bool unobserve = false; if (pcount == 0) { iprintf("Usage: %sobserve \n", onlyUnobserve ? "un" : ""); prompt(); return; } if ((table = findTable(param[0], NULL)) == NULL) return; for (i = 0; i < PLAYER_MAX; i++) { if (table->observers[i] == pme) { unobserve = true; break; } } if (onlyUnobserve && !unobserve) { iprintf("You are not observing game %d.\n", table->number); prompt(); return; } /* if (unobserve) { if ((table->players[0] == pme) || (table->players[1] == pme)) { iprint("You must stand up first.\n"); prompt(); return; } } */ if (!unobserve) delInvite(NULL, table->number); nprintrop((char) (unobserve ? ROP_UNOBSERVE : ROP_OBSERVE), (char *)&table->number, 1); } static void com_observe(String *param[], int pcount) { observe_unobserve(param, pcount, false); } static void com_pending(String *param[], int pcount) { Invite *current = invitations; int i = 1; iprint("There are no offers pending TO other players.\n\n"); if (current == NULL) { iprint("There are no offers pending FROM other players.\n"); prompt(); return; } while (current != NULL) { iprintf(" %d: %s has invited you to table #%d.\n\n", i++, current->who->handle, current->number); current = current->next; } prompt(); } static void com_ping(String *param[], int pcount) { Player *p; String *who; if (pcount == 0) p = pme; else if ((p = completeHandle(param[0])) == NULL) return; if (p->ping != -1) { iprintf("There is already a ping in progress for %s.\n", p->handle); prompt(); return; } who = StringNew(p->lhandle, -1); packutfString(who, who); nprintropString(ROP_PING, who); iprintf("Ping time for %s not available.\n\n(told ROBOadmin)\n", p->handle); prompt(); prompt(); p->ping = -2; StringFree(who); } static void com_play(String *param[], int pcount) { int i; Table *t; char seat; if ((pcount != 1) || !isnumeric(param[0]->string)) { iprint("Usage: play \n"); prompt(); return; } i = atoi(param[0]->string); if ((i < 0) || (i > TABLE_MAX) || (tables[i] == NULL)) { NO_SUCH_SEEK: iprint("That seek is not available.\n"); prompt(); return; } t = tables[i]; if (t->players[0] != NULL) { if (t->players[1] != NULL) goto NO_SUCH_SEEK; seat = 1; } else if (t->players[1] != NULL) { seat = 0; } else { goto NO_SUCH_SEEK; } for (i = 0; i < PLAYER_MAX; i++) if (t->observers[i] == pme) goto NO_SUCH_SEEK; delInvite(NULL, t->number); nprintrop((char) ROP_OBSERVE, (char *)&t->number, 1); nprinttop(t->number, (char) TOP_SIT, &seat, 1); nprinttop(t->number, (char) TOP_START, NULL, 0); } static void com_primary(String *param[], int pcount) { Table *obs[TABLE_MAX], *p[2]; Table **op = obs; int number; observing(obs, pme); param = param; p[0] = NULL; p[1] = NULL; if (pcount == 0) { while (*op != NULL) { if ((*op)->number == primary) { p[0] = *op; /* shift down */ while (op[1] != NULL) { op[0] = op[1]; op++; } *op = NULL; break; } op++; } if (p[0] != NULL) print_games(p); print_games(obs); } else if (isnumeric(param[0]->string)) { number = atoi(param[0]->string); if (number == primary) { iprintf("Game %d is already your primary game.\n", primary); prompt(); return; } else if ((number > TABLE_MAX) || (tables[number] == NULL)) { iprint("There is no such game.\n"); prompt(); return; } while (*op != NULL) { if ((*op)->number == number) { primary = number; iprintf("Your primary game is now game %d.\n", primary); prompt(); return; } op++; } iprintf("You are not observing game %d.\n", number); } else { iprint("Usage: primary [table]\n"); } prompt(); } static void com_quit(String *param[], int pcount) { pcount = pcount; param = param; nprintrop(ROP_EXIT, NULL, 0); prompting = false; iprint("Sending logout request...\n"); prompt(); /* Flushes STDOUT */ } static void com_refresh(String *param[], int pcount) { if (primary == -1) { iprint("You are not playing or observing a game.\n"); prompt(); return; } refresh(tables[primary]); } static void com_resign(String *param[], int pcount) { Table *table; char color; if (primary == -1) { iprint("You are not playing or examining a game.\n"); prompt(); return; } table = tables[primary]; if (table->players[0] == pme) { color = 0; } else if (table->players[1] == pme) { color = 1; } else { iprintf("You are not seated at table %d.\n", primary); prompt(); return; } nprinttop((uchar)primary, (char)TOP_RESIGN, &color, 1); } static void com_resume(String *param[], int pcount) { iprint("This command is not supported, but is provided to prevent " "accidental usage of the resign command.\n"); prompt(); } static void com_seek(String *param[], int pcount) { int i; int area; int time; int inc; bool limit; unsigned short optcount; String *tpacket; String *topt; static char tmp[64]; time = variables[VAR_TIME].number; inc = variables[VAR_INC].number; limit = false; for (i = 0, area = 0; i < pcount;) { switch (area) { /* [time inc] */ case 0: if (!isnumeric(param[i]->string)) { /* Try next area */ area++; continue; } time = atoi(param[i]->string); if ((++i >= pcount) || !isnumeric(param[i]->string)) { iprint("Invalid increment.\n"); prompt(); return; } inc = atoi(param[i]->string); if ((inc > 0) && (time == 0)) { iprint("You cannot have an increment on an " "untimed game.\n"); prompt(); return; } if (time > 999) { iprint("The time is too large.\n"); prompt(); return; } if (inc > 999) { iprint("The increment is too large.\n"); prompt(); return; } break; /* limit */ case 1: if (!strcmp(param[i]->string, "limit") || !strcmp(param[i]->string, "l")) { limit = true; } else { /* Try next area. */ area++; continue; } break; /* Too many params */ default: iprint("Seek has a trailing parameter.\n"); prompt(); return; } i++; area++; } optcount = 0; tpacket = StringNew("\0\0", 2); topt = StringNull(); if (time > 0) { StringSet(topt, "it", 2); packutfStringP(tpacket, topt); snprintf(tmp, sizeof(tmp), "%d", inc * 1000); StringSet(topt, tmp, -1); packutfStringP(tpacket, topt); optcount++; StringSet(topt, "tt", 2); packutfStringP(tpacket, topt); snprintf(tmp, sizeof(tmp), "%d", time * 60000); StringSet(topt, tmp, -1); packutfStringP(tpacket, topt); optcount++; } if (!limit) { StringSet(topt, "pl", 2); packutfStringP(tpacket, topt); StringSet(topt, NULL, 0); packutfStringP(tpacket, topt); optcount++; } optcount = htons(optcount); memcpy(tpacket->string, &optcount, 2); nprintropString(ROP_CREATETABLE, tpacket); StringFree(topt); StringFree(tpacket); } static bool com_xset(String *param[], int pcount, Variable *type) { const char *var, *new = NULL; Variable *v; if (pcount == 0) return false; var = param[0]->string; if (pcount == 2) new = param[1]->string; switch (setvar(type, var, new, &v)) { case VARSET_BAD: iprintf("Bad setting for variable %s.\n", v->name); break; case VARSET_LOCKED: iprint("Cannot alter: Interface setting locked.\n"); break; case VARSET_NOTFOUND: iprintf("No such variable name %s.\n", var); break; case VARSET_AMBIGUOUS: iprintf("Ambiguous variable name %s.\n", var); break; default: return true; } prompt(); return true; } static void com_set(String *param[], int pcount) { if (!com_xset(param, pcount, variables)) { iprint("Usage: set [setting]\n"); prompt(); } } static void com_tset(String *param[], int pcount) { Variable *srch; Table *table; if (primary == -1) { iprint("You are not playing or examining a game.\n"); prompt(); return; } /* This hack lets you tset boolean tvars without a setting. */ table = tables[primary]; for (srch = tvariables; srch->type != VAR_END; srch++) { if (srch->type == VAR_BOOLEAN) { if (!strcmp(srch->name, "rated")) { srch->number = tablerated(table) ? 1 : 0; } else if (!strcmp(srch->name, "tenminlimit")) { srch->number = (findOption(table->options, "pl") != NULL) ? 0 : 1; } } } if (!com_xset(param, pcount, tvariables)) { iprint("Usage: tset [setting]\n"); prompt(); } } static void com_shout(String *param[], int pcount) { String *message; if (pcount == 0) { iprint("Usage: shout \n"); prompt(); return; } message = packutfString(StringNull(), param[0]); nprintropString(ROP_SHOUT, message); StringFree(message); } static void com_showlist(String *param[], int pcount) { List *lp; if (pcount == 0) { iprint("Lists:\n\n"); for (lp = lists; lp->name != NULL; lp++) iprintf("%-20s is PERSONAL\n", lp->name); } else if ((lp = findList(param[0]->string)) != NULL) { iprintf("-- %s list: %d names --\n", lp->name, lp->size); if (lp->contents != NULL) columns(lp->contents); } prompt(); } static void com_sit(String *param[], int pcount) { char which = '\0'; Table *table; if (pcount == 1) which = param[0]->string[0]; if ((pcount == 0) || ((which != 'w') && (which != 'b'))) { iprint("Usage: sit w|b\n"); prompt(); return; } if (primary == -1) { iprint("You are not observing any games.\n"); prompt(); return; } table = tables[primary]; if ((table->players[0] == pme) || (table->players[1] == pme)) { iprint("You are already seated.\n"); prompt(); return; } which = (char)((which == 'w') ? 0 : 1); if (table->players[(int)which] != NULL) { iprint("That seat is occupied.\n"); prompt(); return; } nprinttop((uchar)primary, (char)TOP_SIT, &which, 1); } static void com_sought(String *param[], int pcount) { Table *table; int i, j, count = 0; char srating[16], shandle[18]; bool white; bool all = false; Player *p; String *formula; if (pcount == 1) { if (strcmp(param[0]->string, "a") && strcmp(param[0]->string, "all")) { iprint("Usage: sought [a|all]\n"); prompt(); return; } all = true; } else { /* Short-circuit formula tests. */ formula = variables[VAR_FORMULA].string; if ((formula == NULL) || (formula->length == 0)) all = true; } for (i = 0; i < TABLE_MAX; i++) if ((table = tables[i]) != NULL) { if (table->protection == 2) continue; p = NULL; if (table->players[0] != NULL) { if (table->players[1] != NULL) continue; p = table->players[0]; white = true; } else if (table->players[1] != NULL) { p = table->players[1]; white = false; } else { continue; } if (!all) { /* Test against formula. */ table->players[white ? 1 : 0] = pme; j = checkFormula(table); table->players[white ? 1 : 0] = NULL; if (!j) continue; } prating(srating, p->rating, 4); for (j = 0; (j < 17) && (p->handle[j] != '\0'); j++) shandle[j] = p->handle[j]; shandle[j] = '\0'; iprintf("%3d %s %-17s %3d %3d %-7s %-9s [%s] 0-9999 m\n", i, srating, shandle, tabletime(table), tableinc(table), tablerated(table) ? "rated" : "unrated", strGameType(table), white ? "white" : "black"); count++; } iprintf("%d ad%s displayed.\n", count, (count == 1) ? "" : "s"); prompt(); } static void com_stand(String *param[], int pcount) { Table *table; if (primary == -1) { iprint("You are not observing any games.\n"); prompt(); return; } table = tables[primary]; if ((table->players[0] != pme) && (table->players[1] != pme)) { iprintf("You are not seated at table %d.\n", primary); prompt(); return; } nprinttop((uchar)primary, (char)TOP_STAND, NULL, 0); } static void com_start(String *param[], int pcount) { Table *table; if (primary == -1) { iprint("You are not observing any games.\n"); prompt(); return; } table = tables[primary]; if ((table->players[0] != pme) && (table->players[1] != pme)) { iprintf("You are not seated at table %d.\n", primary); prompt(); return; } nprinttop((uchar)primary, (char)TOP_START, NULL, 0); } static void com_sublist(String *param[], int pcount) { com_addsublist(param, pcount, true); } static void xtell(String *param[], int pcount, bool xtell) { String *who; Player *p; if (pcount != 2) { iprintf("Usage: %stell \n", xtell ? "x" : ""); prompt(); return; } if (!strcmp(param[0]->string, ".")) { if (lasttell == NULL) { iprint("I don't know who to tell that to.\n"); prompt(); return; } else { p = lasttell; } } else if ((p = completeHandle(param[0])) == NULL) { return; } who = StringNew(p->lhandle, -1); if (!xtell) lasttell = p; packutfString(who, who); packutfStringP(who, param[1]); nprintropString(ROP_TELL, who); iprint("(told "); iprint(p->handle); iprint(")\n"); prompt(); StringFree(who); } static void com_tell(String *param[], int pcount) { xtell(param, pcount, false); } static void com_time(String *param[], int pcount) { Table *table; char wr[16], br[16]; if (primary == -1) { iprint("You are not playing or observing a game.\n"); prompt(); return; } table = tables[primary]; prating(wr, table->players[0]->rating, 4); prating(br, table->players[1]->rating, 4); iprintf("Game %d: %s (%s) %s (%s) %srated %s %d %d\n\n", table->number, phandle(table->players[0]), wr, phandle(table->players[1]), br, tablerated(table) ? "" : "un", strGameType(table), tabletime(table), tableinc(table)); iprintf("White Clock : %s\n", fmttime_ms(timeleft(table, 0))); iprintf("Black Clock : %s\n", fmttime_ms(timeleft(table, 1))); prompt(); } static void com_unalias(String *param[], int pcount) { int i; if (pcount == 0) { iprint("Usage: unalias \n"); prompt(); return; } lowercase(param[0]->string); for (i = 0; (i < ALIAS_MAX) && (aliases[i] != NULL); i++) { if (!strcmp(aliases[i]->alias, param[0]->string)) { free(aliases[i]->alias); free(aliases[i]->mapping); free(aliases[i]); aliases[i] = NULL; collapse_aliases(); iprint("Alias "); iprint(param[0]->string); iprint(" removed.\n"); prompt(); return; } } iprint("You have no alias "); iprint(param[0]->string); iprint(".\n"); prompt(); } static void com_unobserve(String *param[], int pcount) { char number; if (pcount == 0) { if (primary == -1) { iprintf("You are not observing any games.\n"); prompt(); return; } number = primary; nprintrop((char) ROP_UNOBSERVE, &number, 1); } else { observe_unobserve(param, pcount, true); } } static void com_variables(String *param[], int pcount) { Variable *var = variables; char *vstr[64]; char *vstr_s[64]; char **vp = vstr; char **vsp = vstr_s; iprint("Variable settings of "); iprint(pme->handle); iprint(":\n"); while (var->type != VAR_END) { *vp = NULL; *vsp = NULL; switch ((int)var->type) { case VAR_NUMERIC: case VAR_BOOLEAN: *vp = malloc(256); if (*vp != NULL) snprintf(*vp, 256, "%s=%d", var->name, var->number); break; case VAR_STRING: if ((var->string != NULL) && (var->string->string[0] != '\0')) { *vsp = malloc(strlen(var->name) + var->string->length + 3); if (*vsp != NULL) sprintf(*vsp, "%s: %s", var->name, var->string->string); } break; } if (*vp != NULL) vp++; if (*vsp != NULL) vsp++; var++; } *vp = NULL; *vsp = NULL; columns(vstr); iprint("\n"); for (vsp = vstr_s; *vsp != NULL; vsp++) { iprintf("%s\n", *vsp); free(*vsp); } prompt(); for (vp = vstr; *vp != NULL; vp++) free(*vp); } static int sort_rating(const void *sa, const void *sb) { Player *a = *(Player **)sa; Player *b = *(Player **)sb; return (a->rating < b->rating) ? 1 : (a->rating > b->rating) ? -1 : strcmp(a->lhandle, b->lhandle); } static int sort_handle(const void *sa, const void *sb) { Player *a = *(Player **)sa; Player *b = *(Player **)sb; int cmp = strcmp(a->lhandle, b->lhandle); return (cmp != 0) ? cmp : (a->rating < b->rating) ? 1 : (a->rating > b->rating) ? -1 : 0; } static void com_who(String *param[], int pcount) { Player *who[PLAYER_MAX]; Player *pl; int i, count, lcount; short rating; char srating[64]; char **items, **ip; char status; Table *obs[TABLE_MAX]; Table **op; char *flags; char order = 'b'; char filter = '\0'; bool noratings = false; if (pcount == 1) { /* * X: can't do * ^n: alias for n * * USERS TO DISPLAY * X o: Only open players. * X r: Only players for rated matches. * f: Only free players (not playing a game). * ^f a: Only available players (open & free). * X R: Only registered players. * X U: Only unregistered players. * #i#j: Only a portion of the who list; #j divides the list into j segments; * #i will display the i-th segment; #i cannot be higher than #j; (there * are three shortcuts: "who 1" works the same as "who 13", "who 2" works * the same as "who 23" and "who 3" works the same as "who 33"). [See * the special note below.] */ flags = param[0]->string; for (i = 0; i < param[0]->length; i++) { switch (flags[i]) { case 'f': case 'a': filter = 'f'; break; case 's': case 'b': case 'L': order = 'b'; break; case 'A': order = 'A'; break; case 'l': noratings = true; break; default: iprint("Usage: who [f][a][s][b][L][A][l]\n"); prompt(); return; } } } param = param; pcount = pcount; items = malloc(sizeof(char *) * (PLAYER_MAX + 1)); if (items == NULL) { iprint("Out of memory!\n"); prompt(); return; } ip = items; count = 0; for (i = 0; i < PLAYER_MAX; i++) { if (players[i] != NULL) who[count++] = players[i]; } who[count] = NULL; qsort(who, count, sizeof(Player *), (order == 'b') ? sort_rating : sort_handle); for (i = 0; i < count; i++) { pl = who[i]; /* * O we do this * X not possible on Yahoo! * ? we could do this at great expense * * Status codes: * O ^ involved in a game * X ~ running a simul match * ? : not open for a match * O # examining a game * ? . inactive for 5 minutes or longer, or if "busy" is set * O not busy * X & involved in a tournament * * We add one: * , Observing a table */ status = ' '; /* Check in-game and examining */ observing(obs, pl); for (op = obs; *op != NULL; op++) { status = ','; if ((((*op)->players[0] == pl) && ((*op)->players[1] != NULL)) || (((*op)->players[1] == pl) && ((*op)->players[0] != NULL))) { status = '^'; break; } } if ((filter == 'f') && (status == '^')) continue; *ip = malloc(256); if (*ip == NULL) break; rating = pl->rating; prating(srating, rating, 4); if (noratings) mstrncpy(*ip, pl->handle, 256); else snprintf(*ip, 256, "%s%c%s", srating, status, pl->handle); ip++; } *ip = NULL; lcount = columns(items); if (snprintf(srating, sizeof(srating), "\n %d players displayed (of %d).\n", lcount, count) != -1) { iprint(srating); prompt(); } ip = items; while (*ip != NULL) { free(*ip); ip++; } } static void com_xkibitz(String *param[], int pcount) { String *message; Table *obs[TABLE_MAX], **optr = obs; int number; char temp[64]; if ((pcount < 2) || !isnumeric(param[0]->string)) { iprint("Usage: xkibitz
\n"); prompt(); return; } number = atoi(param[0]->string); if ((number < 1) || (number > TABLE_MAX) || (tables[number] == NULL)) { iprint("There is no such game.\n"); prompt(); return; } observing(obs, pme); while (*optr != NULL) { if ((*optr)->number == number) { message = packutfString(StringNull(), param[1]); nprinttopString((uchar)number, (char)TOP_KIBITZ, message); StringFree(message); return; } optr++; } snprintf(temp, sizeof(temp), "You are not observing game %d.\n", number); iprint(temp); prompt(); } static void com_xtell(String *param[], int pcount) { xtell(param, pcount, true); } static void com_znotify(String *param[], int pcount) { int i; bool gotone = false; for (i = 0; i < PLAYER_MAX; i++) { if ((players[i] != NULL) && inList(&lists[LIST_NOTIFY], players[i]->lhandle)) { if (!gotone) { iprint("Present company on your notify list:\n "); gotone = true; } /* printf because these don't wrap on FICS. */ printf(" %s", players[i]->handle); } } if (!gotone) iprint("No one from your notify list is logged on.\n"); else iprint("\n"); iprint("No one logged in has you on their notify list.\n"); prompt(); } yics-0.1.2/ytoics-c/command.h0000644000175000001440000000205510243142257016273 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _COMMAND_H #define _COMMAND_H #include "types.h" #define ALIAS_MAX 1024 extern void do_command(const char *, bool); /* We use this handler in vars.c when the open var is turned off. */ extern void com_decline(String **, int); #endif yics-0.1.2/ytoics-c/console.c0000644000175000001440000001476310260627233016324 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include #include #include #include #include #include "platform.h" #if defined(_YICS_WIN32) # include # include # include # include # include static int isatty_stdin_cache = -1; #elif defined(_YICS_POSIX) # include # include # include #endif #include "types.h" #include "console.h" #include "network.h" #include "debug.h" #include "globals.h" #include "vars.h" #include "lists.h" static short width_out = 0; static char buffer_out[100] = ""; bool prompting = false; void internal_iprint(const char *text, bool system) { char *nl; char *buf = buffer_out; nl = system ? "" : "\\ "; while (*buf) buf++; while (*text) { *(buf++) = *text; *buf = '\0'; width_out++; if (*text == '\n') { width_out = 0; printf("%s\r", buffer_out); buffer_out[0] = '\0'; buf = buffer_out; } else if (width_out >= 80) { width_out = (short)(strlen(nl) + strlen(buffer_out)); printf("\n\r%s", nl); } else if (*text == ' ') { printf("%s", buffer_out); buffer_out[0] = '\0'; buf = buffer_out; } text++; } if (system) fflush(stdout); } void iprintf(const char *text, ...) { va_list ap; va_start(ap, text); vsprintf(s_buffer, text, ap); va_end(ap); internal_iprint(s_buffer, false); } void sysiprintf(const char *text, ...) { va_list ap; va_start(ap, text); vsprintf(s_buffer, text, ap); va_end(ap); internal_iprint(s_buffer, true); } void prompt() { time_t t; struct tm *tv; if (prompting) { if (variables[VAR_PTIME].number) { t = time(NULL); tv = localtime(&t); printf("%02d:%02d_", tv->tm_hour, tv->tm_min); } printf("fics%% "); } fflush(stdout); } #if defined(_YICS_WIN32) struct keyb { int head, tail; int keys[0x100]; } keycom = { 0, 0 }; void keyfetchthread (void * parm) { struct keyb * keycom = (struct keyb *)parm; int ret; printf ("Key thread started\n"); for (;;) { if (!isatty_stdin_cache) { ret = getc (stdin); } else { ret = getche (); } if (ret == 4) /* ^D ? */ ret = -1; if (((keycom->head+1) & 0xff) == (keycom->tail & 0xff)) continue; keycom->keys[keycom->head & 0xff] = ret; keycom->head++; } } int keyget (struct keyb * keycom) { int key, c = 10; while (keycom->head == keycom->tail) { Sleep (c); c += c; if (c > 200) c = 200; } key = keycom->keys[keycom->tail & 0xff]; keycom->tail++; return key; } int keyready (struct keyb * keycom) { return keycom->head != keycom->tail; } void keyinit (struct keyb * keycom) { _beginthread (keyfetchthread, 1024, (void *) keycom); } #endif #define DELAY (1000) bool stdin_ready() { #if defined(_YICS_WIN32) clock_t curr, timeout; if (isatty_stdin_cache == -1) { isatty_stdin_cache = isatty(fileno(stdin)) != 0; keyinit (&keycom); } /* if (!isatty_stdin_cache) return true; */ timeout = clock() + (clock_t)((CLOCKS_PER_SEC * DELAY) / 1000000.0); do { if (keyready (&keycom)) return true; curr = clock(); } while ((int)(timeout - curr) > 0); #elif defined(_YICS_POSIX) fd_set sl; struct timeval tv; FD_ZERO(&sl); FD_SET(0, &sl); tv.tv_sec = 0; tv.tv_usec = DELAY; if (select(1, &sl, NULL, NULL, &tv)) return true; #endif return false; } bool stdin_getchar(char *c) { int ret; #if defined(_YICS_WIN32) if (isatty_stdin_cache == -1) { isatty_stdin_cache = isatty(fileno(stdin)) != 0; keyinit (&keycom); } ret = keyget (&keycom); if (ret < 0) return false; if (ret == '\r') { ret = '\n'; printf("\n"); } *c = (char)ret; #elif defined(_YICS_POSIX) ret = read(0, c, 1); if (ret != 1) return false; #endif return true; } void die(char *err) { int i; List *list; Variable *var; if (err[0] != '\0') printf("ERROR: %s\n", err); /* clean up everything */ for (i = 0; i < TABLE_MAX; i++) { if (tables[i] != NULL) { destroyOptions(tables[i]->options); free(tables[i]); tables[i] = NULL; } } for (i = 0; i < PLAYER_MAX; i++) { if (players[i] != NULL) { free(players[i]->handle); free(players[i]->lhandle); if (players[i] == pme) pme = NULL; players[i] = NULL; } } for (list = lists; list->name != NULL; list++) { for (i = 0; i < list->size; i++) free(list->contents[i]); free(list->contents); list->contents = NULL; } for (var = variables; var->type != VAR_END; var++) if (var->string != NULL) StringFree(var->string); if (pme != NULL) { free(pme->handle); free(pme->lhandle); free(pme); pme = NULL; } destroyOptions(clientOptions); clientOptions = NULL; destroyInvite(); #if MEMDEBUG if (string_count != 0) { printf("WARNING: Memory leak detected while cleaning up! " "There are %d Strings still allocated.\n", string_count); } if (option_count != 0) { printf("WARNING: Memory leak detected while cleaning up! " "There are %d Options still allocated.\n", option_count); } if ((string_count == 0) && (option_count == 0)) printf("No memory leaks detected!\n"); #endif nclose(); exit(1); } void dief(char *err, ...) { va_list ap; va_start(ap, err); vsprintf(s_buffer, err, ap); va_end(ap); die(s_buffer); } #ifdef _YICS_POSIX /* * Mixing stdio functions (e.g. fgets) with unistd functions (e.g. read) * causes problems when mixing them on continuous input (e.g. WinBoard/xboard * -icslogon parameter). So we provide our own fgets that uses unistd. */ char *mfgets(char *s, int size, FILE *stream) { int i = 0; int fd = fileno(stream); char *si = s; /* Leave room for the null. */ size--; while (i < size) { if (read(fd, si, 1) < 1) break; i++; if ((*(si++) == '\n') || (*si == '\r')) break; } *si = '\0'; if ((i == 0) && (size < 0)) return NULL; return s; } #endif yics-0.1.2/ytoics-c/console.h0000644000175000001440000000263510250207603016316 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _CONSOLE_H #define _CONSOLE_H #include "types.h" extern bool prompting; extern void internal_iprint(const char *, bool); extern void iprintf(const char *, ...); extern void sysiprintf(const char *, ...); extern void prompt(void); extern bool stdin_ready(void); extern bool stdin_getchar(char *); extern void die(char *); extern void dief(char *, ...); #define iprint(text) internal_iprint(text, false) #define sysiprint(text) internal_iprint(text, true) #ifdef _YICS_POSIX extern char *mfgets(char *, int, FILE *); #else # define mfgets(s,size,stream) fgets(s,size,stream) #endif #endif yics-0.1.2/ytoics-c/debug.c0000644000175000001440000000256710060753542015750 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include #include "types.h" #include "debug.h" #if MEMDEBUG int option_count = 0; int string_count = 0; #endif #if DEBUG void debugOptions(Option *option) { printf("\nDebugging option stack (0x%08X)\n", (unsigned int)option); while (option != NULL) { printf("Key: %s\n" "Value: %s\n", option->key, option->value); option = option->next; } printf("Finished option stack\n\n"); } void debugString(String *str) { int i = 0; printf("STRING: "); while (i < str->length) printf("%02X ", str->string[i++]); printf("\n"); } #endif yics-0.1.2/ytoics-c/debug.h0000644000175000001440000000213210060753542015741 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _DEBUG_H #define _DEBUG_H #define MEMDEBUG 0 #if MEMDEBUG extern int option_count; extern int string_count; #define MEMDEBUGP 0 #endif #define DEBUG 0 #if DEBUG #include "types.h" extern void debugOptions(Option *); extern void debugString(String *); #endif /* DEBUG */ #endif yics-0.1.2/ytoics-c/formula.c0000644000175000001440000002152610260627233016322 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include #include #include #include "types.h" #include "formula.h" #include "globals.h" #include "vars.h" static float groupValue(const char *group, int *i, FormulaToken *tokens, bool *failed, bool first); #define IsNumber(x) (((x) >= '0') && ((x) <= '9')) #define IsLetter(x) (((x) >= 'a') && ((x) <= 'z')) enum { F_BLITZ = 0, F_HOST, F_INC, F_LIGHTNING, F_MYRATING, F_PRIVATE, F_RATED, F_RATING, F_RATINGDIFF, F_STANDARD, F_TIME, F_UNRATED, F_UNTIMED, F_USER }; static const FormulaToken newFormulaTokens[] = { {"blitz", 0}, {"host", 0}, {"inc", 0}, {"lightning", 0}, {"myrating", 0}, {"private", 0}, {"rated", 0}, {"rating", 0}, {"ratingdiff", 0}, {"standard", 0}, {"time", 0}, {"unrated", 0}, {"untimed", 0}, {NULL, 0}, /* f1 */ {NULL, 0}, /* f2 */ {NULL, 0}, /* f3 */ {NULL, 0}, /* f4 */ {NULL, 0}, /* f5 */ {NULL, 0}, /* f6 */ {NULL, 0}, /* f7 */ {NULL, 0}, /* f8 */ {NULL, 0}, /* f9 */ {NULL, 0}, }; const char *fvars[] = {"f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", NULL}; static OperatorDef operators[] = { {"#", OP_NONE}, {")", OP_ENDGROUP}, /* Spaces to prevent blending into a token. */ {"and ",OP_AND}, {"or ", OP_OR}, /* Ordered by length to prevent "|" from matching before "||", etc. */ {"||", OP_OR}, {"&&", OP_AND}, {"==", OP_EQ}, {"!=", OP_NEQ}, {"<>", OP_NEQ}, {">=", OP_GE}, {"=>", OP_GE}, {"<=", OP_LE}, {"=<", OP_LE}, {"|", OP_OR}, {"&", OP_AND}, {">", OP_GT}, {"<", OP_LT}, {"=", OP_EQ}, {"+", OP_ADD}, {"-", OP_SUB}, {"*", OP_MULT}, {"/", OP_DIV}, {NULL, OP_BAD} }; static float ff_abs(float v) { return (v < 0) ? -v : v; } static float ff_int(float v) { return (float)((int)v); } static FunctionDef functions[] = { {"abs", ff_abs}, {"int", ff_int}, {NULL, NULL} }; static void fillTokens(FormulaToken *tokens, Table *table) { Player *opp = NULL; int rated; if (table->players[0] == pme) opp = table->players[1]; else if (table->players[1] == pme) opp = table->players[0]; tokens[F_TIME].value = (float)tabletime(table); tokens[F_INC].value = (float)tableinc(table); switch (gameType(table)) { case 'u': tokens[F_UNTIMED].value = 1; break; case 'l': tokens[F_LIGHTNING].value = 1; break; case 'b': tokens[F_BLITZ].value = 1; break; case 's': tokens[F_STANDARD].value = 1; break; } tokens[F_MYRATING].value = (pme->rating == PROVISIONAL) ? 1200.0f : pme->rating; tokens[F_RATING].value = (opp == NULL) ? 0.0f : (opp->rating == PROVISIONAL) ? 1200.0f : opp->rating; tokens[F_RATINGDIFF].value = tokens[F_RATING].value - tokens[F_MYRATING].value; tokens[F_PRIVATE].value = (table->protection == 2) ? 1.0f : 0.0f; rated = tablerated(table) ? 1 : 0; tokens[F_RATED].value = (float)rated; tokens[F_UNRATED].value = (float)(1 - rated); tokens[F_HOST].value = (table->host == pme) ? 1.0f : 0.0f; } static void skipSpace(const char *s, int *i) { while ((s[*i] != '\0') && (s[*i] == ' ')) (*i)++; } static float getNumber(const char *s, int *i, bool *failed) { int j = *i; int ns; bool negate = false; *failed = false; while (s[j] == '-') { negate = (bool)!negate; j++; } ns = j; while (IsNumber(s[j])) j++; if (j == ns) { *failed = true; return 0; } if (s[j] == '.') { ns = ++j; while (IsNumber(s[j])) j++; if (j == ns) { *failed = true; return 0; } } *i = j; return (float)atof(&s[ns]); } static float tokenValue(const char *s, int *i, FormulaToken *tokens, bool *failed) { float value; FormulaToken *ft; FunctionDef *fnct; int len; int pos; bool not = false; /* Check unary operators. */ while (s[*i] == '!') { not = (bool)!not; (*i)++; skipSpace(s, i); } /* This is unary too, despite that it matches a closing paren. */ if (s[*i] == '(') { (*i)++; return groupValue(s, i, tokens, failed, false); } /* Check numeric. */ value = getNumber(s, i, failed); if (!*failed) return not ? !value : value; /* Check formula token. */ for (ft = tokens; ft->token != NULL; ft++) { len = strlen(ft->token); if (!strncmp(&s[*i], ft->token, len)) { pos = len + *i; if (IsLetter(s[pos]) || IsNumber(s[pos])) continue; *i += len; *failed = false; return not ? !ft->value : ft->value; } } /* Check functions. */ for (fnct = functions; fnct->name != NULL; fnct++) { len = strlen(fnct->name); if (!strncmp(&s[*i], fnct->name, len)) { pos = len + *i; skipSpace(s, &pos); if (s[pos] != '(') continue; *i = pos + 1; value = groupValue(s, i, tokens, failed, false); if (*failed) break; *failed = false; return fnct->func(value); } } *failed = true; return 0; } static Operator operator(const char *s, int *i) { OperatorDef *ops; int len; for (ops = operators; ops->token != NULL; ops++) { len = strlen(ops->token); if (!strncmp(&s[*i], ops->token, len)) { *i += len; return ops->op; } } return OP_BAD; } static float groupValue(const char *group, int *i, FormulaToken *tokens, bool *failed, bool first) { float value; float value2; Operator op; skipSpace(group, i); if ((group[*i] == '\0') || (group[*i] == '#')) { *failed = (bool)!first; return 0; } value = tokenValue(group, i, tokens, failed); if (*failed) return 0; for (;;) { skipSpace(group, i); if (group[*i] == '\0') break; op = operator(group, i); if (op == OP_BAD) { *failed = true; return 0; } else if (op == OP_ENDGROUP) { *failed = (bool)first; return value; } else if (op == OP_NONE) { *failed = (bool)!first; return value; } skipSpace(group, i); value2 = tokenValue(group, i, tokens, failed); if (*failed) return 0; switch (op) { /* Boolean */ case OP_OR: value = (float)(value || value2); break; case OP_AND: value = (float)(value && value2); break; /* Comparison */ case OP_EQ: value = (float)(value == value2); break; case OP_NEQ: value = (float)(value != value2); break; case OP_GT: value = (float)(value > value2); break; case OP_GE: value = (float)(value >= value2); break; case OP_LT: value = (float)(value < value2); break; case OP_LE: value = (float)(value <= value2); break; /* Mathematical */ case OP_ADD: value += value2; break; case OP_SUB: value -= value2; break; case OP_MULT: value *= value2; break; case OP_DIV: if (value2 == 0) value = 0; else value /= value2; break; /* These are handled other places. */ case OP_BAD: case OP_NONE: case OP_ENDGROUP: break; } } *failed = (bool)!first; return value; } int checkFormula(Table *table) { String *formula; String *fvar; int fv, i; float value; bool failed; FormulaToken *tokens; formula = variables[VAR_FORMULA].string; if ((formula == NULL) || (formula->length == 0)) return 1; tokens = malloc(sizeof(newFormulaTokens)); if (tokens == NULL) return -2; memcpy(tokens, newFormulaTokens, sizeof(newFormulaTokens)); fillTokens(tokens, table); for (fv = 0; fv < 10; fv++) { fvar = variables[VAR_F1 + fv].string; if ((fvar == NULL) || (fvar->length == 0)) value = 0; else { i = 0; value = groupValue(fvar->string, &i, tokens, &failed, true); if (failed) { free(tokens); return -1; } } tokens[F_USER + fv].token = fvars[fv]; tokens[F_USER + fv].value = value; } i = 0; value = groupValue(formula->string, &i, tokens, &failed, true); free(tokens); if (failed) return -1; return ((int)value == 0) ? 0 : 1; } bool validateFormula(Variable *fvar, void *new) { FormulaToken *tokens; FormulaToken *ct; const char **fn = fvars; int mv, i; bool failed; tokens = malloc(sizeof(newFormulaTokens)); if (tokens == NULL) return false; memcpy(tokens, newFormulaTokens, sizeof(newFormulaTokens)); /* Give a dummy value to other f-vars. */ mv = (fvar->number == 0) ? 9 : (fvar->number - 1); for (i = 0, ct = &tokens[F_USER]; i < mv; i++, ct++) { ct->token = *(fn++); ct->value = 0; } i = 0; groupValue((char *)new, &i, tokens, &failed, true); free(tokens); return (bool)!failed; } yics-0.1.2/ytoics-c/formula.h0000644000175000001440000000266410242522634016330 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _FORMULA_H #define _FORMULA_H typedef struct { const char *token; float value; } FormulaToken; /* Loosely based on the FICS sources. */ typedef enum { OP_BAD = -1, OP_NONE, /* Grouping */ OP_ENDGROUP, /* Boolean */ OP_OR, OP_AND, /* unary OP_NOT, */ /* Comparison */ OP_EQ, OP_NEQ, OP_GT, OP_GE, OP_LT, OP_LE, /* Mathematical */ OP_ADD, OP_SUB, OP_MULT, OP_DIV } Operator; typedef struct { const char *token; Operator op; } OperatorDef; typedef struct { const char *name; float (*func)(float); } FunctionDef; extern int checkFormula(Table *); extern bool validateFormula(Variable *, void *); #endif yics-0.1.2/ytoics-c/globals.c0000644000175000001440000001265710260627233016305 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include #include #include #include #include "globals.h" #include "types.h" #include "util.h" #include "console.h" long int session = 0; char handle[256] = ""; bool login_complete = false; FILE *netlog = NULL; Player *pme = NULL, *lasttell = NULL, *lastopp = NULL; Player *players[PLAYER_MAX]; Option *clientOptions = NULL; Table *tables[TABLE_MAX + 1]; /* +1 because tables[0] isn't used */ int primary = -1; Invite *invitations = NULL; Invite *lastinvite = NULL; char s_buffer[4096]; time_t lastcommand; Player *findPlayer(const char *name) { int i = 0; char *uname = malloc(strlen(name) + 1); if (uname == NULL) return NULL; strcpy(uname, name); lowercase(uname); while (i < PLAYER_MAX) { if (players[i] && !strcmp(players[i]->lhandle, uname)) { free(uname); return players[i]; } i++; } free(uname); return NULL; } Player *completeHandle(String *name) { int i; bool youlose = false; char *ambig[PLAYER_MAX]; char **ap = ambig; int acount = 0; Player *match = NULL; /* Looking for an exact match? */ if (name->string[name->length - 1] == '!') { name->string[name->length - 1] = '\0'; match = findPlayer(name->string); if (match == NULL) { iprintf("There is no player matching the name %s.\n", name->string); prompt(); } name->string[name->length - 1] = '!'; return match; } lowercase(name->string); for (i = 0; i < PLAYER_MAX; i++) { if (players[i] == NULL) continue; if (!strcmp(name->string, players[i]->lhandle)) return players[i]; if ((name->length <= (int)strlen(players[i]->lhandle)) && !memcmp(players[i]->lhandle, name->string, name->length)) { if (match == NULL) { match = players[i]; } else { if (!youlose) { youlose = true; *(ap++) = match->handle; acount++; } *(ap++) = players[i]->handle; acount++; } } } if (youlose) { *ap = NULL; qsort(ambig, acount, sizeof(char *), s_strcmp); iprintf("-- Matches: %d player(s) --\n", acount); columns(ambig); prompt(); return NULL; } if (match == NULL) { iprintf("There is no player matching the name %s.\n", name->string); prompt(); return NULL; } return match; } Table *findTable(String *text, String *resolved) { int number; Player *p; Table *obs[TABLE_MAX]; Table **op; char tmp[64]; if (isnumeric(text->string)) { number = atoi(text->string); if (number < 0) { iprintf("%d is not a valid game number.\n", number); prompt(); return NULL; } if ((number > TABLE_MAX) || (tables[number] == NULL)) { iprint("There is no such game.\n"); prompt(); return NULL; } if (resolved != NULL) { sprintf(tmp, "game %d", number); StringSet(resolved, tmp, -1); } return tables[number]; } else if ((p = completeHandle(text)) != NULL) { observing(obs, p); for (op = obs; *op != NULL; op++) if (((*op)->players[0] == p) || ((*op)->players[1] == p)) { if (resolved != NULL) StringSet(resolved, p->handle, -1); return *op; } iprintf("%s is not playing a game.\n", p->handle); prompt(); } return NULL; } String *realHandle(String *name) { Player *p = findPlayer(name->string); if (p != NULL) StringSet(name, p->handle, -1); return name; } void observing(Table **out, const Player *who) { int i, j; Table *table; for (i = 0; i < TABLE_MAX; i++) { if (tables[i] == NULL) continue; table = tables[i]; for (j = 0; j < PLAYER_MAX; j++) { if (table->observers[j] == who) { *(out++) = table; break; } } } *out = NULL; } void addInvite(Player *who, uchar number, InviteType type) { Invite *new = malloc(sizeof(Invite)); if (new == NULL) return; new->who = who; new->number = number; new->type = type; new->next = NULL; new->last = lastinvite; if (lastinvite == NULL) invitations = new; else lastinvite->next = new; lastinvite = new; } bool delInvite(Player *who, uchar number) { Invite *current = invitations; Invite *next, *last; bool gotone = false; if ((who == NULL) && (number == 0)) /* Don't destroy them all... */ return false; while (current != NULL) { next = current->next; if (((who == NULL) || (who == current->who )) && ((number == 0) || (number == current->number))) { last = current->last; if (last == NULL) invitations = next; else last->next = next; if (next == NULL) lastinvite = last; else next->last = last; free(current); gotone = true; } current = next; } return gotone; } void destroyInvite() { Invite *current = invitations, *next; while (current != NULL) { next = current->next; free(current); current = next; } invitations = lastinvite = NULL; } yics-0.1.2/ytoics-c/globals.h0000644000175000001440000000465010244244731016304 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _GLOBALS_H #define _GLOBALS_H #include #include "types.h" /* * CLOCK_REFRESH controls whether or not YICS will refresh the board after a * clock update comes in. Yahoo! appears to have moved the clock update to * before the board update, so this shouldn't be necessary anymore. */ #define CLOCK_REFRESH 0 /* * STEALTH controls whether or not the client will ignore "/ytoics" and "/yics" * ident requests. */ #define STEALTH 0 /* * SEE_IDENT controls whether or not you see "/ytoics" and "/yics" ident * requests. */ #if !STEALTH # define SEE_IDENT 0 #endif #define PROVISIONAL (-32768) extern long int session; extern char handle[256]; extern bool login_complete; extern FILE *netlog; extern Player *pme, *lasttell, *lastopp; extern Player *players[PLAYER_MAX]; extern Option *clientOptions; extern Table *tables[TABLE_MAX + 1]; extern int primary; extern Invite *invitations; extern char s_buffer[4096]; extern time_t lastcommand; extern Player *findPlayer(const char *); extern Player *completeHandle(String *); extern Table *findTable(String *text, String *resolved); extern String *realHandle(String *); extern void observing(Table **, const Player *); extern void addInvite(Player *, uchar, InviteType); extern bool delInvite(Player *, uchar); extern void destroyInvite(void); #define prating(s,r,w) \ if ((r) == PROVISIONAL) {\ strcpy((s), "----"); \ } else { \ sprintf((s), "%*d", (w), (r));\ } #define tabletime(t) (findOptionLong((t)->options, "tt") / 60000) #define tableinc(t) (findOptionLong((t)->options, "it") / 1000) #define tablerated(t) (findOption((t)->options, "rd") != NULL) #endif yics-0.1.2/ytoics-c/http.c0000644000175000001440000001014710250207603015623 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include #include #include #include "http.h" #include "sockets.h" #include "network.h" #define sendstr(s,str) send(s, str, strlen(str), 0) static const char hextable[16] = "0123456789ABCDEF"; /* This set of characters is based on the "uric" set in RFC 2396/2732 as * explained in the URI::Escape manpage. */ #define IsLetter(x) ( \ (((x) >= 'A') && ((x) <= 'Z')) || \ (((x) >= 'a') && ((x) <= 'z')) \ ) #define IsNumber(x) (((x) >= '0') && ((x) <= '9')) #define IsSpecial(x) ( \ ((x) == '-') || ((x) == '_') || ((x) == '.') || ((x) == '!') || \ ((x) == '~') || ((x) == '*') || ((x) == '\'') || ((x) == '(') || \ ((x) == ')') \ ) #define IsUric(x) (IsLetter(x) || IsNumber(x) || IsSpecial(x)) static char *uri_escape(char *out, const char *in) { unsigned char c; while ((c = *(in++)) != '\0') { if (IsUric(c)) { *(out++) = c; } else { *(out++) = '%'; *(out++) = hextable[c >> 4]; *(out++) = hextable[c & 0x0F]; } } *out = '\0'; return out; } static void build_query(char *out, ValuePair data[]) { int gotone = 0; while (data->key) { if (gotone) *(out++) = '&'; out = uri_escape(out, data->key); *(out++) = '='; out = uri_escape(out, data->value); gotone = 1; data++; } *out = '\0'; } int http_get(char *server, char *path, ValuePair form[], char *cookies[], int *sout) { int s, cp, i; int got_status = 0, status; static char tmp[8192], tmp2[256]; char *cookie, *ch, *ckp; s = nconnect(server, 80); if (s < 0) return -1; if (form && form[0].key) { build_query(tmp2, form); snprintf(tmp, sizeof(tmp), "GET %s?%s HTTP/1.1\r\n", path, tmp2); } else { snprintf(tmp, sizeof(tmp), "GET %s HTTP/1.1\r\n", path); } sendstr(s, tmp); snprintf(tmp, sizeof(tmp), "Host: %s\r\n", server); sendstr(s, tmp); #if (defined (linux) || defined (__linux) || defined (__linux__)) # define HTTP_OSNAME "; linux" #elif (defined (unix) || defined (__unix) || defined (__unix__)) # define HTTP_OSNAME "; unix" #elif (defined (WINNT) || defined (__WINNT) || defined (__WINNT__) || defined (_WIN32) || defined (_WINDOWS)) # define HTTP_OSNAME "; Windows" #else # define HTTP_OSNAME "" #endif sendstr(s, "User-Agent: Mozilla/5.0 (compatible; YtoICS" HTTP_OSNAME ")\r\n" "Connection: Close\r\n"); status = 0; for (cp = 0; cookies[cp]; cp++) { if (!status) sendstr(s, "Cookie: "); else sendstr(s, "; "); sendstr(s, cookies[cp]); status = 1; } if (status) sendstr(s, "\r\n"); sendstr(s, "\r\n"); while (ngets(tmp, sizeof(tmp), s) != NULL) { for (i = 0; tmp[i] != '\0'; i++); if ((i > 0) && (tmp[--i] == '\n')) tmp[i] = '\0'; if (!got_status) { if (!sscanf(tmp, "HTTP/1.1 %d", &status)) { closesock(s); return -1; } got_status = 1; } else if (tmp[0] == '\0') { if (!*sout) { closesock(s); return status; } *sout = s; return status; } else { /* * XXX: Should check (somehow) the size of the cookie * array. Yahoo! could exploit this, if they wanted * to cripple YICS. */ if (!strncmp("Set-Cookie: ", tmp, 12)) { cookie = malloc(strlen(tmp)); if (cookie) { ckp = cookie; for (ch = &tmp[12]; *ch && (*ch != ';'); ch++) *(ckp++) = *ch; *ckp = '\0'; cookies[cp++] = cookie; cookies[cp] = 0; } } } } closesock(s); return status; } yics-0.1.2/ytoics-c/http.h0000644000175000001440000000716010204717464015643 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _HTTP_H #define _HTTP_H typedef struct { char *key, *value; } ValuePair; #define HTTP_SERVER_RETURN_VALUE_CONTINUE (100) #define HTTP_SERVER_RETURN_VALUE_SWITCHING_PROTOCOLS (101) #define HTTP_SERVER_RETURN_VALUE_OK (200) #define HTTP_SERVER_RETURN_VALUE_CREATED (201) #define HTTP_SERVER_RETURN_VALUE_ACCEPTED (202) #define HTTP_SERVER_RETURN_VALUE_NONAUTH_INFO (203) #define HTTP_SERVER_RETURN_VALUE_NO_CONTENT (204) #define HTTP_SERVER_RETURN_VALUE_RESET_CONTENT (205) #define HTTP_SERVER_RETURN_VALUE_PARTIAL_CONTENT (206) #define HTTP_SERVER_RETURN_VALUE_MULTIPLE_CHOICES (300) #define HTTP_SERVER_RETURN_VALUE_MOVED_PERMANENTLY (301) #define HTTP_SERVER_RETURN_VALUE_FOUND (302) #define HTTP_SERVER_RETURN_VALUE_SEE_OTHER (303) #define HTTP_SERVER_RETURN_VALUE_NOT_MODIFIED (304) #define HTTP_SERVER_RETURN_VALUE_USE_PROXY (305) #define HTTP_SERVER_RETURN_VALUE_TEMPORARY_REDIRECT (307) #define HTTP_SERVER_RETURN_VALUE_BAD_REQUEST (400) #define HTTP_SERVER_RETURN_VALUE_UNAUTHORIZED (401) #define HTTP_SERVER_RETURN_VALUE_FORBIDDEN (403) #define HTTP_SERVER_RETURN_VALUE_NOT_FOUND (404) #define HTTP_SERVER_RETURN_VALUE_METHOD_NOT_ALLOWED (405) #define HTTP_SERVER_RETURN_VALUE_NOT_ACCEPTABLE (406) #define HTTP_SERVER_RETURN_VALUE_PROXY_AUTH_REQUIRED (407) #define HTTP_SERVER_RETURN_VALUE_REQUEST_TIMEOUT (408) #define HTTP_SERVER_RETURN_VALUE_CONFLICT (409) #define HTTP_SERVER_RETURN_VALUE_GONE (410) #define HTTP_SERVER_RETURN_VALUE_LENGTH_REQUIRED (411) #define HTTP_SERVER_RETURN_VALUE_PRECONDITION_FAILED (412) #define HTTP_SERVER_RETURN_VALUE_REQUEST_ENTITY_TOO_LARGE (413) #define HTTP_SERVER_RETURN_VALUE_REQUEST_URI_TOO_LONG (414) #define HTTP_SERVER_RETURN_VALUE_UNSUPPORTED_MEDIA_TYPE (415) #define HTTP_SERVER_RETURN_VALUE_REQUEST_RANGE_NOT_SATISFIABLE (416) #define HTTP_SERVER_RETURN_VALUE_EXPECTATION_FAILED (417) #define HTTP_SERVER_RETURN_VALUE_INTERNAL_SERVER_ERROR (500) #define HTTP_SERVER_RETURN_VALUE_NOT_IMPLEMENTED (501) #define HTTP_SERVER_RETURN_VALUE_BAD_GATEWAY (502) #define HTTP_SERVER_RETURN_VALUE_SERVICE_UNAVAILABLE (503) #define HTTP_SERVER_RETURN_VALUE_GATEWAY_TIMEOUT (504) #define HTTP_SERVER_RETURN_VALUE_VERSION_NOT_SUPPORTED (505) extern int http_get(char *server, char *path, ValuePair form[], char *cookies[], int *); #endif yics-0.1.2/ytoics-c/lists.c0000644000175000001440000000736710260630546016023 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include #include #include "types.h" #include "lists.h" #include "util.h" #include "sockets.h" #include "globals.h" #include "console.h" #include "ropcodes.h" #include "network.h" static void censorAdd(const char *); static void censorSub(const char *); List lists[] = { {"censor", 0, NULL, censorAdd, censorSub}, {"notify", 0, NULL, NULL, NULL}, {NULL, 0, NULL} }; static void genericAddSub(const char *item, char rop) { String *packet = StringNew(item, -1); lowercase(packet->string); packutfString(packet, packet); nprintropString(rop, packet); StringFree(packet); } static void censorAdd(const char *item) { genericAddSub(item, (char) ROP_IGNORE); } static void censorSub(const char *item) { genericAddSub(item, (char) ROP_UNIGNORE); } bool listAdd(List *list, const char *item) { char **nc; char *sd = strdup(item); if (inList(list, item)) return false; if (sd == NULL) return false; nc = realloc(list->contents, sizeof(char *) * (list->size + 2)); if (nc == NULL) { free(sd); return false; } list->contents = nc; list->contents[list->size++] = sd; list->contents[list->size] = NULL; qsort(nc, list->size, sizeof(char *), s_istrcmp); return true; } bool listSub(List *list, const char *item) { int i; char **nc; if (list->contents == NULL) return false; for (i = 0; i < list->size; i++) if (!istrcmp(list->contents[i], item)) break; if (i == list->size) return false; free(list->contents[i]); if (--list->size == 0) { free(list->contents); list->contents = NULL; return true; } for (; i < list->size; i++) list->contents[i] = list->contents[i + 1]; nc = realloc(list->contents, sizeof(char *) * list->size); if (nc != NULL) list->contents = nc; return true; } bool inList(List *list, const char *item) { int i; if (list->contents == NULL) return false; for (i = 0; i < list->size; i++) { if (!istrcmp(list->contents[i], item)) return true; } return false; } void buildList(List *list, const String *packet) { unsigned short count; String *cp; String *item = StringNull(); memcpy(&count, packet->string, 2); count = ntohs(count); cp = StringNew(&packet->string[2], packet->length - 2); while (count--) { unpackutfStringP(item, cp); listAdd(list, item->string); } StringFree(cp); StringFree(item); } List *findList(const char *name) { List *match = NULL; List *lp; int len = strlen(name); bool youlose = false; for (lp = lists; lp->name != NULL; lp++) { if (!strcmp(name, lp->name)) return lp; if ((len < strlen(lp->name)) && !memcmp(name, lp->name, len)) { if (youlose) { iprintf(", %s", lp->name); } else if (match != NULL) { iprintf("Ambiguous list - matches: %s, %s", match->name, lp->name); youlose = true; match = NULL; } else { match = lp; } } } if (match != NULL) return match; if (youlose) iprint(".\n"); else iprintf("\"%s\" does not match any list name.\n", name); return NULL; } yics-0.1.2/ytoics-c/lists.h0000644000175000001440000000225510260630546016017 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _LISTS_H #define _LISTS_H #include "types.h" extern List lists[]; enum { LIST_CENSOR = 0, LIST_NOTIFY }; #define LIST_NOPLAY (LIST_CENSOR) extern bool listAdd(List *, const char *); extern bool listSub(List *, const char *); extern bool inList(List *, const char *); extern void buildList(List *, const String *); extern List *findList(const char *); #endif yics-0.1.2/ytoics-c/main.c0000644000175000001440000003061410260627233015577 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include #include #include #include #include #include "platform.h" #ifdef _YICS_POSIX #include #endif #ifdef __GNUC__ #include #endif #include "sockets.h" #include "types.h" #include "console.h" #include "network.h" #include "opcodes.h" #include "ropcodes.h" #include "version.h" #include "util.h" #include "globals.h" #include "command.h" #include "debug.h" #include "vars.h" #include "http.h" /* server info */ static char s_hostname[1024] = ""; static unsigned short s_port = 0; static char s_room[256] = ""; static char s_cookie[2048] = ""; static char s_ycookie[2048] = ""; static char s_region[8] = "us"; static char s_uagent[256] = ""; static void dologin(void); static void getparams(void); typedef struct { bool isSocket; union { FILE *file; int socket; } fd; } SocketFile; #define s_fgets(buf,max,sf) (sf.isSocket ? ngets(buf,max,sf.fd.socket) : fgets(buf,max,sf.fd.file)) int main(int argc, char *argv[]) { static char inbuf[2048]; char inc; int inbufp = 0; String *info = NULL; int flag; #if defined(_YICS_WIN32) int idle; int curdelay = 0; #endif memset(players, sizeof(players), 0); memset(tables, sizeof(tables), 0); for (;;) { flag = getopt(argc, argv, "l:"); if (flag == -1) break; if (flag == 'l') { netlog = fopen(optarg, "wb"); if (netlog == NULL) dief("Unable to open %s: %s", optarg, strerror(errno)); } else if (flag == '?') { exit(1); } } sysiprint("\n" "Welcome to YICS! If you need any help, please consult the " "YICS documentation, available at http://wiki.yics.org .\n\n" "Lead programmer: crazycomputers\n" "Windows port: websnarf\n" "Version: "); sysiprint(VERSION); sysiprint("\n" "Website: http://www.yics.org\n\n" "To log in, enter your Yahoo! ID, your password, and the " "room ID of the room you want to enter. For a list of room " "IDs, see http://wiki.yics.org/Room_IDs .\n"); getparams(); sysiprint("\nAll OK. Attempting to connect to server...\n"); if (!yconnect(s_hostname, s_port)) dief("Can't connect! (%s)", strerror(errno)); sysiprint("Connected.\n"); dologin(); sysiprint("\nLogged in as "); sysiprint(handle); sysiprint(/* ". The following line is for interfaces that use it to " "determine your username.*/ "\n\n" /* "**** Starting FICS session as "); sysiprint(handle); sysiprint(" ****\n" "------------------------------------------------------------" "------------------\n\n"*/ "Downloading room state....\n"); while (!login_complete) handle_opcode(); if (pme == NULL) die("The server did not send a login message about you; " "cannot proceed."); info = StringNew("RESOLUTION java.awt.Dimension[width=800,height=600]", -1); packutfString(info, info); nprintropString(ROP_INFO, info); StringFree(info); info = NULL; prompting = true; sysiprint("\nDone. ICS command emulation active.\n"); prompt(); lastcommand = time(NULL); for (;;) { #if defined(_YICS_WIN32) idle = 1; #endif while (stdin_ready()) { #if defined(_YICS_WIN32) idle = 0; #endif if (!stdin_getchar(&inc)) { die(""); /* stdin was closed */ return 0; } if (inc == '\n') { inbuf[inbufp] = '\0'; do_command(inbuf, false); inbuf[0] = '\0'; inbufp = 0; } else if ((inc != '\r') && (inbufp < 2047)) { inbuf[inbufp++] = (char)inc; } } while (socket_ready()) { #if defined(_YICS_WIN32) idle = 0; #endif handle_opcode(); } #if defined(_YICS_WIN32) if (idle) { Sleep(curdelay); curdelay += curdelay; if (curdelay > 20) curdelay = 20; } else { curdelay = 1; } #endif if (variables[VAR_NOTIMEOUT].number && ((lastcommand + 1800) <= time(NULL))) { iprint("Sending bogus command to server to prevent " "timeout disconnection.\n"); prompt(); info = StringNew("ENDAD ABORT", -1); packutfString(info, info); nprintropString(ROP_INFO, info); StringFree(info); info = NULL; } } } static void dologin() { static char tmp[1024] = ""; int length, i; unsigned long key_in, key_out; FILE *tlog = netlog; sysiprint("\nReceiving handshake...\n"); if ((nread(tmp, 6) != 6) || strcmp(tmp, "YAHOO!")) die("Incorrect handshake."); nputc('Y'); sysiprint("Creating encryption and decryption keys...\n"); if (nread(tmp, 4) != 4) die("Keys could not be created."); memcpy(&key_out, tmp, 4); if (nread(tmp, 4) != 4) die("Keys could not be created."); memcpy(&key_in, tmp, 4); set_keys(ntohl(key_out), ntohl(key_in)); sysiprint("Entering game room...\n"); nputc('o'); nprintutf(s_room, (unsigned short)strlen(s_room)); if (ngetc() != 0x6f) die("Couldn't enter game room."); nreadutf(tmp); if (strcmp(tmp, s_room)) die("Incorrect room handshake."); nread((char *)&session, 4); /* no ntohl because we only need to send it back to the server; converting it each time would be useless and wasteful. */ if (ngetc() != 0x64) die("Incorrect room handshake."); nread(NULL, 4); nreadutf(tmp); if (strcmp(unpackutf(tmp, tmp), "GAMES")) die("Incorrect room handshake."); sysiprint("Sending login information...\n"); nputc('d'); nprint((char *)&session, 4); tmp[0] = '\0'; length = 1; i = strlen(s_cookie); packutf(&tmp[1], s_cookie, (unsigned short)i); length += i + 2; i = strlen(s_ycookie); packutf(&tmp[length], s_ycookie, (unsigned short)i); length += i + 2; i = strlen(s_uagent); packutf(&tmp[length], s_uagent, (unsigned short)i); length += i + 2; i = strlen(s_region); packutf(&tmp[length], s_region, (unsigned short)i); length += i + 2; netlog = NULL; /* Protect user's cookie from the log */ nprintutf(tmp, (unsigned short)length); if (tlog != NULL) { netlog = tlog; /* Restore log handle */ fputc(2, tlog); /* Write placeholder to the log */ } if (ngetc() != 0x64) die("Protocol error."); nread(NULL, 4); nreadutf(tmp); if (tmp[0]) dief( "\nServer says:\n\n%s\n\n" "Usually this means that your applet.html file is " "out of date. Try fetching a new copy.\n", &tmp[1]); unpackutf(&tmp[1], &tmp[1]); mstrncpy(handle, &tmp[1], sizeof(handle)); } static bool pline(char *buffer, int length, const char *msg) { *buffer = '\0'; sysiprint(msg); mfgets(buffer, length, stdin); trim(buffer); return (*buffer == '\0') ? false : true; } static int http_login(char *username, char *password, char *room) { char *cookies[32] = {NULL}; ValuePair login[3]; ValuePair applet[6]; int result, sd = 0; login[0].key = "login"; login[0].value = username; login[1].key = "passwd"; login[1].value = password; login[2].key = NULL; login[2].value = NULL; applet[0].key = "room"; applet[0].value = room; applet[1].key = "prof_id"; applet[1].value = "chat_pf_1"; applet[2].key = "small"; applet[2].value = "no"; applet[3].key = "follow"; applet[3].value = ""; applet[4].key = "nosignedcab"; applet[4].value = "no"; applet[5].key = NULL; applet[5].value = NULL; sysiprint("\nLogging in...\n"); result = http_get("login.yahoo.com", "/config/login", login, cookies, &sd); if (result < 0) { sysiprint("Unable to contact login.yahoo.com.\n"); return -1; } if (result != HTTP_SERVER_RETURN_VALUE_FOUND) { sysiprint("Login or password is invalid.\n"); return -1; } sd = 1; sysiprint("Requesting applet.html...\n"); http_get("games.yahoo.com", "/games/applet.html", applet, cookies, &sd); return sd; } static void getparams() { static char loc[2048], key[1024], value[1024]; static char nameCopy[2048]; char *line, *sp; Option *params = NULL, *opt = NULL; SocketFile applet; /* TODO: Rework this so it doesn't need goto. */ RETRY_LOGIN: pline(loc, 2048, "\n" "Enter your username, or \"/\" to read an applet.html file.\n" "login: "); if ((loc[0] != '/') || (loc[1] != '\0')) { /* Copy the name for profile logins. */ mstrncpy(nameCopy, loc, sizeof(nameCopy)); applet.isSocket = true; if (!pline(key, 1024, "\n" "Enter your password.\n" "password: ")) goto RETRY_LOGIN; if (!pline(value, 1024, "\n" "Enter the room ID to join.\n" "room: ")) goto RETRY_LOGIN; applet.fd.socket = http_login(loc, key, value); if (applet.fd.socket < 0) goto RETRY_LOGIN; strcpy(loc, "applet.html from the server"); } else { /* We don't have a profile name, since it's read from disk. */ nameCopy[0] = '\0'; applet.isSocket = false; do { if (!pline(loc, 2048, "\n" "Enter the location of applet.html below.\n" "login: ")) goto RETRY_LOGIN; if ((applet.fd.file = fopen(loc, "r")) == NULL) { sysiprint("Unable to open "); sysiprint(loc); sysiprint("\n"); } } while (applet.fd.file == NULL); } sysiprint("\nGoing to read "); sysiprint(loc); sysiprint("...\n"); LINE: while (s_fgets(loc, 2048, applet) != NULL) { line = loc; while ((line = strstr (line, "value; line = strstr(line, "http://"); if (line == NULL) { destroyOptions(params); sysiprint("\"codebase\" applet parameter format is " "invalid."); goto RETRY_LOGIN; } line += 7; sp = s_hostname; while (*line && (*line != ':') && (*line != '/')) *(sp++) = *(line++); *sp = '\0'; sysiprint("WARNING: Server extracted from codebase." " ("); sysiprint(s_hostname); sysiprint(")\n"); } else { mstrncpy(s_hostname, opt->value, sizeof(s_hostname)); } if ((opt = findOption(params, "port")) == NULL) { destroyOptions(params); sysiprint("\"port\" applet parameter not found.\n"); goto RETRY_LOGIN; } s_port = (unsigned short)atoi(opt->value); if ((opt = findOption(params, "yport")) == NULL) { destroyOptions(params); sysiprint("\"yport\" applet parameter not found.\n"); goto RETRY_LOGIN; } mstrncpy(s_room, opt->value, sizeof(s_room)); if (nameCopy[0] != '\0') { /* * For profile logins. This has the potential of breaking the * login if more than the ID is being stored in the cookie! * * XXX: The getapplet part should be able to handle this. * Do more sniffing and patch it. */ snprintf(s_cookie, sizeof(s_cookie), "id=%s", nameCopy); } else { if ((opt = findOption(params, "cookie")) == NULL) { destroyOptions(params); sysiprint("\"cookie\" applet parameter not found.\n"); goto RETRY_LOGIN; } mstrncpy(s_cookie, opt->value, sizeof(s_cookie)); } if ((opt = findOption(params, "ycookie")) == NULL) { destroyOptions(params); sysiprint("\"ycookie\" applet parameter not found.\n"); goto RETRY_LOGIN; } mstrncpy(s_ycookie, opt->value, sizeof(s_ycookie)); if ((opt = findOption(params, "intl_code")) != NULL) mstrncpy(s_region, opt->value, sizeof(s_region)); if ((opt = findOption(params, "label")) != NULL) { sysiprint("\nRoom: "); sysiprint(opt->value); sysiprint("\n"); } #if i386 # define AGENT_ARCH "i386; " #else # define AGENT_ARCH "" #endif snprintf(s_uagent, sizeof(s_uagent), "Mozilla/5.0 (compatible; " AGENT_ARCH "YICS/%s)", VERSION); #undef AGENT_ARCH destroyOptions(params); } yics-0.1.2/ytoics-c/movecheck.c0000644000175000001440000006512410250207603016615 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * This file is derived from the public FICS sources (movecheck.c). * Copyright (C) 1993 Richard V. Nash * * 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. */ /* (crazycomputers) I've cleaned up the FICS sources a lot. Indentation and * spacing between operators should be consistent now. */ #include #include #include "movecheck.h" #include "types.h" char *wpstring[] = {" ", "P", "N", "B", "R", "Q", "K"}; char *bpstring[] = {" ", "p", "n", "b", "r", "q", "k"}; int NextPieceLoop(Board b, int *f, int *r, int color) { for (;;) { (*r) = (*r) + 1; if (*r > 7) { *r = 0; *f = *f + 1; if (*f > 7) break; } if ((b[*f][*r] != EMPTY) && iscolor(b[*f][*r], color)) return 1; } return 0; } int InitPieceLoop(Board b, int *f, int *r, int color) { *f = 0; *r = -1; return 1; } /* All of the routines assume that the obvious problems have been checked */ /* See legal_move() */ int legal_pawn_move(Game *gs, int ff, int fr, int tf, int tr) { if (ff == tf) { if (gs->board[tf][tr] != EMPTY) return 0; if (gs->turn == WHITE) { if (tr - fr == 1) return 1; if ((fr == 1) && (tr - fr == 2) && (gs->board[ff][2] == EMPTY)) return 1; } else { if (fr - tr == 1) return 1; if ((fr == 6) && (fr - tr == 2) && (gs->board[ff][5] == EMPTY)) return 1; } return 0; } else { /* Capture ? */ if ((ff - tf != 1) && (tf - ff != 1)) return 0; if ((fr - tr != 1) && (tr - fr != 1)) return 0; if (gs->turn == WHITE) { if (fr > tr) return 0; if ((gs->board[tf][tr] != EMPTY) && iscolor(gs->board[tf][tr], BLACK)) return 1; if (gs->dpush == tf) { if (gs->board[tf][fr] == B_PAWN) return 1; } } else { if (tr > fr) return 0; if ((gs->board[tf][tr] != EMPTY) && iscolor(gs->board[tf][tr], WHITE)) return 1; if (gs->dpush == tf) { if (gs->board[tf][fr] == W_PAWN) return 1; } } } return 0; } int legal_knight_move(Game *gs, int ff, int fr, int tf, int tr) { int dx, dy; dx = ff - tf; dy = fr - tr; if ((dx == 2) || (dx == -2)) { if ((dy == -1) || (dy == 1)) return 1; } if ((dy == 2) || (dy == -2)) { if ((dx == -1) || (dx == 1)) return 1; } return 0; } int legal_bishop_move(Game *gs, int ff, int fr, int tf, int tr) { int dx, dy, x, y; int startx, starty; int count; int incx, incy; if (ff > tf) { dx = ff - tf; incx = -1; } else { dx = tf - ff; incx = 1; } startx = ff + incx; if (fr > tr) { dy = fr - tr; incy = -1; } else { dy = tr - fr; incy = 1; } starty = fr + incy; if (dx != dy) return 0; /* Not diagonal */ if (dx == 1) return 1; /* One square, ok */ count = dx - 1; for (x = startx, y = starty; count; x += incx, y += incy, count--) { if (gs->board[x][y] != EMPTY) return 0; } return 1; } int legal_rook_move(Game *gs, int ff, int fr, int tf, int tr) { int i; int start, stop; if (ff == tf) { if (((fr - tr) == 1) || ((tr - fr) == 1)) return 1; if (fr < tr) { start = fr + 1; stop = tr - 1; } else { start = tr + 1; stop = fr - 1; } for (i = start; i <= stop; i++) { if (gs->board[ff][i] != EMPTY) return 0; } return 1; } else if (fr == tr) { if (((ff - tf) == 1) || ((tf - ff) == 1)) return 1; if (ff < tf) { start = ff + 1; stop = tf - 1; } else { start = tf + 1; stop = ff - 1; } for (i = start; i <= stop; i++) { if (gs->board[i][fr] != EMPTY) return 0; } return 1; } return 0; } /* (crazycomputers) Why wasn't this a macro in the first place? =/ */ #define legal_queen_move(gs, ff, fr, tf, tr) \ (legal_rook_move((gs), (ff), (fr), (tf), (tr)) || \ legal_bishop_move((gs), (ff), (fr), (tf), (tr))) #if 0 int legal_queen_move(game_state_t *gs, int ff, int fr, int tf, int tr) { return legal_rook_move(gs, ff, fr, tf, tr) || legal_bishop_move(gs, ff, fr, tf, tr); } #endif /* Ckeck, if square (kf,kr) is attacked by enemy piece. * Used in castling from/through check testing. */ /* new one from soso: */ int is_square_attacked (Game *gs, int kf, int kr) { Game fakeMove; fakeMove = *gs; fakeMove.movelist = NULL; fakeMove.repetitions = NULL; fakeMove.board[4][kr] = EMPTY; fakeMove.board[kf][kr] = (Piece)(KING | fakeMove.turn); fakeMove.turn = CToggle(fakeMove.turn); /* (crazycomputers) Haha, gotta love redundant code! =) Original: if (in_check(&fakeMove)) return 1; else return 0; Let's try this instead... */ return in_check(&fakeMove); } int legal_king_move(Game *gs, int ff, int fr, int tf, int tr) { if (gs->turn == WHITE) { /* King side castling */ if ((fr == 0) && (tr == 0) && (ff == 4) && (tf == 6) && gs->castlewh && (gs->board[5][0] == EMPTY) && (gs->board[6][0] == EMPTY) && (gs->board[7][0] == W_ROOK) && (!is_square_attacked(gs, 4, 0)) && (!is_square_attacked(gs, 5, 0))) { return 1; } /* Queen side castling */ if ((fr == 0) && (tr == 0) && (ff == 4) && (tf == 2) && gs->castlewa && (gs->board[3][0] == EMPTY) && (gs->board[2][0] == EMPTY) && (gs->board[1][0] == EMPTY) && (gs->board[0][0] == W_ROOK) && (!is_square_attacked(gs, 4, 0)) && (!is_square_attacked(gs, 3, 0))) { return 1; } } else { /* Black */ /* King side castling */ if ((fr == 7) && (tr == 7) && (ff == 4) && (tf == 6) && gs->castlebh && (gs->board[5][7] == EMPTY) && (gs->board[6][7] == EMPTY) && (gs->board[7][7] == B_ROOK) && (!is_square_attacked(gs, 4, 7)) && (!is_square_attacked(gs, 5, 7))) { return 1; } /* Queen side castling */ if ((fr == 7) && (tr == 7) && (ff == 4) && (tf == 2) && gs->castleba && (gs->board[3][7] == EMPTY) && (gs->board[2][7] == EMPTY) && (gs->board[1][7] == EMPTY) && (gs->board[0][7] == B_ROOK) && (!is_square_attacked(gs, 4, 7)) && (!is_square_attacked(gs, 3, 7))) { return 1; } } if (((ff - tf) > 1) || ((tf - ff) > 1)) return 0; if (((fr - tr) > 1) || ((tr - fr) > 1)) return 0; return 1; } void add_pos(int tof, int tor, int *posf, int *posr, int *numpos) { posf[*numpos] = tof; posr[*numpos] = tor; (*numpos)++; } void possible_pawn_moves(Game *gs, int onf, int onr, int *posf, int *posr, int *numpos) { if (gs->turn == WHITE) { if (gs->board[onf][onr + 1] == EMPTY) { add_pos(onf, onr + 1, posf, posr, numpos); if ((onr == 1) && (gs->board[onf][onr + 2] == EMPTY)) add_pos(onf, onr + 2, posf, posr, numpos); } if ((onf > 0) && (gs->board[onf - 1][onr + 1] != EMPTY) && (iscolor(gs->board[onf - 1][onr + 1], BLACK))) add_pos(onf - 1, onr + 1, posf, posr, numpos); if ((onf < 7) && (gs->board[onf + 1][onr + 1] != EMPTY) && (iscolor(gs->board[onf + 1][onr + 1], BLACK))) add_pos(onf + 1, onr + 1, posf, posr, numpos); if (gs->dpush != -1) { if ((onf - gs->dpush) == -1) add_pos(onf + 1, onr + 1, posf, posr, numpos); else if ((onf - gs->dpush) == 1) add_pos(onf - 1, onr + 1, posf, posr, numpos); } } else { if (gs->board[onf][onr - 1] == EMPTY) { add_pos(onf, onr - 1, posf, posr, numpos); if ((onr == 6) && (gs->board[onf][onr - 2] == EMPTY)) add_pos(onf, onr - 2, posf, posr, numpos); } if ((onf > 0) && (gs->board[onf - 1][onr - 1] != EMPTY) && (iscolor(gs->board[onf - 1][onr - 1], WHITE))) add_pos(onf - 1, onr - 1, posf, posr, numpos); if ((onf < 7) && (gs->board[onf + 1][onr - 1] != EMPTY) && (iscolor(gs->board[onf + 1][onr - 1], WHITE))) add_pos(onf + 1, onr - 1, posf, posr, numpos); if (gs->dpush != -1) { if ((onf - gs->dpush) == -1) add_pos(onf + 1, onr - 1, posf, posr, numpos); else if ((onf - gs->dpush) == 1) add_pos(onf - 1, onr - 1, posf, posr, numpos); } } } void possible_knight_moves(Game *gs, int onf, int onr, int *posf, int *posr, int *numpos) { static int knightJumps[8][2] = { {-1, 2}, { 1, 2}, { 2, -1}, { 2, 1}, {-1, -2}, { 1, -2}, {-2, 1}, {-2, -1} }; int f, r; int j; for (j = 0; j < 8; j++) { f = knightJumps[j][0] + onf; r = knightJumps[j][1] + onr; if ((f < 0) || (f > 7)) continue; if ((r < 0) || (r > 7)) continue; if ((gs->board[f][r] == EMPTY) || (iscolor(gs->board[f][r], CToggle(gs->turn)))) add_pos(f, r, posf, posr, numpos); } } void possible_bishop_moves(Game *gs, int onf, int onr, int *posf, int *posr, int *numpos) { static const int bishopJumps[4][2] = { {-1, 1}, { 1, 1}, {-1, -1}, { 1, -1} }; int f, r, i; for (i = 0; i < 4; i++) { f = onf; r = onr; for (;;) { f += bishopJumps[i][0]; r += bishopJumps[i][1]; if ((f < 0) || (f > 7)) break; if ((r < 0) || (r > 7)) break; if ((gs->board[f][r] != EMPTY) && (iscolor(gs->board[f][r], gs->turn))) break; add_pos(f, r, posf, posr, numpos); if (gs->board[f][r] != EMPTY) break; } } } void possible_rook_moves(Game *gs, int onf, int onr, int *posf, int *posr, int *numpos) { static const int rookJumps[4][2] = { {-1, 0}, { 1, 0}, { 0, -1}, { 0, 1} }; int f, r, i; for (i = 0; i < 4; i++) { f = onf; r = onr; for (;;) { f += rookJumps[i][0]; r += rookJumps[i][1]; if ((f < 0) || (f > 7)) break; if ((r < 0) || (r > 7)) break; if ((gs->board[f][r] != EMPTY) && (iscolor(gs->board[f][r], gs->turn))) break; add_pos(f, r, posf, posr, numpos); if (gs->board[f][r] != EMPTY) break; } } } /* (crazycomputers) Another macro candidate... */ #define possible_queen_moves(gs, onf, onr, posf, posr, numpos) \ possible_rook_moves((gs), (onf), (onr), (posf), (posr), (numpos)); \ possible_bishop_moves((gs), (onf), (onr), (posf), (posr), (numpos)); /*void possible_queen_moves(game_state_t *gs, int onf, int onr, int *posf, int *posr, int *numpos) { possible_rook_moves(gs, onf, onr, posf, posr, numpos); possible_bishop_moves(gs, onf, onr, posf, posr, numpos); } */ void possible_king_moves(Game *gs, int onf, int onr, int *posf, int *posr, int *numpos) { static const int kingJumps[8][2] = { {-1, -1}, { 0, -1}, { 1, -1}, {-1, 1}, { 0, 1}, { 1, 1}, {-1, 0}, { 1, 0} }; int f, r; int j; for (j = 0; j < 8; j++) { f = kingJumps[j][0] + onf; r = kingJumps[j][1] + onr; if ((f < 0) || (f > 7)) continue; if ((r < 0) || (r > 7)) continue; if ((gs->board[f][r] == EMPTY) || (iscolor(gs->board[f][r], CToggle(gs->turn)))) add_pos(f, r, posf, posr, numpos); } } /* Doesn't check for check */ int legal_move(Game *gs, int fFile, int fRank,int tFile, int tRank) { int move_piece; /* (crazycomputers) Removed bughouse code. */ move_piece = piecetype(gs->board[fFile][fRank]); if (gs->board[fFile][fRank] == EMPTY) return 0; if (!iscolor(gs->board[fFile][fRank], gs->turn)) /* Wrong color */ return 0; if ((gs->board[tFile][tRank] != EMPTY) && iscolor(gs->board[tFile][tRank], gs->turn)) /* Can't capture own */ return 0; if ((fFile == tFile) && (fRank == tRank)) /* Same square */ return 0; switch (move_piece) { case PAWN: return legal_pawn_move(gs, fFile, fRank, tFile, tRank); case KNIGHT: return legal_knight_move(gs, fFile, fRank, tFile, tRank); case BISHOP: return legal_bishop_move(gs, fFile, fRank, tFile, tRank); case ROOK: return legal_rook_move(gs, fFile, fRank, tFile, tRank); case QUEEN: return legal_queen_move(gs, fFile, fRank, tFile, tRank); case KING: return legal_king_move(gs, fFile, fRank, tFile, tRank); default: return 0; } } /* Based on alg_unparse from algcheck.c of the public FICS sources. */ static void alg_unparse(Game *game, Move *move) { int piece = piecetype(game->board[move->x1][move->y1]); bool ambig, ambig_x, ambig_y; uchar x, y; Game fakeMove; char *out = move->alg; /* * Longest output: * * Castling (6): O-O-O+ * Ambiguous (7): Re1xe2+ * Promotion (7): exf8=Q+ * * So we need 8 bytes for an alg string. */ if ((piece == KING) && (move->x1 == 4) && ((move->x2 == 6) || (move->x2 == 2))) { strcpy(out, (move->x2 == 6) ? "O-O" : "O-O-O"); while (*(++out) != '\0'); } else { switch (piece) { case PAWN: if (move->x1 != move->x2) *(out++) = move->x1 + 'a'; break; case KNIGHT: *(out++) = 'N'; break; case BISHOP: *(out++) = 'B'; break; case ROOK: *(out++) = 'R'; break; case QUEEN: *(out++) = 'Q'; break; case KING: *(out++) = 'K'; break; } if (piece != PAWN) { ambig = false; ambig_x = false; ambig_y = false; for (x = 0; x < 8; x++) { for (y = 0; y < 8; y++) { if (((x != move->x1) || (y != move->y1)) && (game->board[x][y] != EMPTY) && iscolor(game->board[x][y], game->turn) && (piecetype(game->board[x][y]) == piece) && legal_move(game, x, y, move->x2, move->y2)) { game->turn = CToggle(game->turn); fakeMove = *game; fakeMove.board[x][y] = EMPTY; /* * This is in algparse.c... * what does it do?! */ /* if (in_check(game) || !in_check(&fakeMove)) ambig = true; */ ambig = true; if (x == move->x1) ambig_x = true; if (y == move->y1) ambig_y = true; game->turn = CToggle(game->turn); } } } if (ambig) { if (!ambig_x) *(out++) = move->x1 + 'a'; else if (!ambig_y) *(out++) = move->y1 + '1'; else { *(out++) = move->x1 + 'a'; *(out++) = move->y1 + '1'; } } } if (game->board[move->x2][move->y2] != EMPTY) *(out++) = 'x'; *(out++) = move->x2 + 'a'; *(out++) = move->y2 + '1'; if (move->promoteTo != EMPTY) { *(out++) = '='; *(out++) = *wpstring[move->promoteTo]; } } fakeMove = *game; execute_move(&fakeMove, move, 0); fakeMove.turn = CToggle(fakeMove.turn); if (in_check(&fakeMove)) *(out++) = '+'; *out = '\0'; } int move_calculate(Game *gs, Move *move, int promote) { Game fakeMove; move->promoteTo = ((piecetype(gs->board[move->x1][move->y1]) == PAWN) && ((move->y2 != 0) || (move->y2 != 7))) ? promote : EMPTY; if ((piecetype(gs->board[move->x1][move->y1]) == KING) && (move->x1 == 4) && ((move->x2 == 2) || (move->x2 == 6))) { sprintf(move->desc, (move->x2 == 6) ? "o-o" : "o-o-o"); } else { snprintf(move->desc, sizeof(move->desc), "%c/%c%c-%c%c", *wpstring[piecetype(gs->board[move->x1][move->y1])], move->x1 + 'a', move->y1 + '1', move->x2 + 'a', move->y2 + '1'); if (move->promoteTo != EMPTY) { move->desc[7] = '='; move->desc[8] = *wpstring[move->promoteTo]; move->desc[9] = '\0'; } } alg_unparse(gs, move); fakeMove = *gs; /* Just in case */ fakeMove.movelist = NULL; fakeMove.repetitions = NULL; /* Calculates enPassant also */ execute_move(&fakeMove, move, 0); /* Does making this move leave ME in check? */ return in_check(&fakeMove) ? MOVE_ILLEGAL : MOVE_OK; } int legal_andcheck_move(Game *gs, int fFile, int fRank, int tFile, int tRank) { Move move; if (!legal_move(gs, fFile, fRank, tFile, tRank)) return 0; move.x1 = fFile; move.y1 = fRank; move.x2 = tFile; move.y2 = tRank; /* This should take into account a pawn promoting to another piece */ return (move_calculate(gs, &move, QUEEN) == MOVE_OK) ? 1 : 0; } /* in_check: checks if the side that is NOT about to move is in check */ int in_check(Game *gs) { int f, r; int kf = -1, kr = -1; Piece target = (Piece)(KING | CToggle(gs->turn)); /* Find the king */ for (f = 0; f < 8 && kf < 0; f++) { for (r = 0; r < 8 && kf < 0; r++) { if (gs->board[f][r] == target) { kf = f; kr = r; } } } if (kf < 0) return 0; for (InitPieceLoop(gs->board, &f, &r, gs->turn); NextPieceLoop(gs->board, &f, &r, gs->turn);) { if (legal_move(gs, f, r, kf, kr)) /* In Check? */ return 1; } return 0; } int has_legal_move(Game *gs) { int i; int f, r; int possiblef[500], possibler[500]; int numpossible = 0; for (InitPieceLoop(gs->board, &f, &r, gs->turn); NextPieceLoop(gs->board, &f, &r, gs->turn);) { switch (piecetype(gs->board[f][r])) { case PAWN: possible_pawn_moves(gs, f, r, possiblef, possibler, &numpossible); break; case KNIGHT: possible_knight_moves(gs, f, r, possiblef, possibler, &numpossible); break; case BISHOP: possible_bishop_moves(gs, f, r, possiblef, possibler, &numpossible); break; case ROOK: possible_rook_moves(gs, f, r, possiblef, possibler, &numpossible); break; case QUEEN: possible_queen_moves(gs, f, r, possiblef, possibler, &numpossible); break; case KING: possible_king_moves(gs, f, r, possiblef, possibler, &numpossible); } for (i = 0; i < numpossible; i++) if (legal_andcheck_move(gs, f, r, possiblef[i], possibler[i])) return 1; } return 0; } /* This will end up being a very complicated function */ /* (crazycomputers) And an unneeded one here -- we have our own parsing, */ #if 0 int parse_move(char *mstr, game_state_t * gs, move_t * mt, int promote) { int type = is_move(mstr); int result; mt->color = gs->turn; switch (type) { case MS_NOTMOVE: return MOVE_ILLEGAL; break; case MS_COMP: mt->fromFile = mstr[0] - 'a'; mt->fromRank = mstr[1] - '1'; mt->toFile = mstr[2] - 'a'; mt->toRank = mstr[3] - '1'; break; case MS_COMPDASH: mt->fromFile = mstr[0] - 'a'; mt->fromRank = mstr[1] - '1'; mt->toFile = mstr[3] - 'a'; mt->toRank = mstr[4] - '1'; break; case MS_KCASTLE: mt->fromFile = 4; mt->toFile = 6; if (gs->turn == WHITE) { mt->fromRank = 0; mt->toRank = 0; } else { mt->fromRank = 7; mt->toRank = 7; } break; case MS_QCASTLE: mt->fromFile = 4; mt->toFile = 2; if (gs->turn == WHITE) { mt->fromRank = 0; mt->toRank = 0; } else { mt->fromRank = 7; mt->toRank = 7; } break; case MS_ALG: /* Fills in the mt structure */ if ((result = alg_parse_move(mstr, gs, mt)) != MOVE_OK) return result; break; default: return MOVE_ILLEGAL; break; } if (!legal_move(gs, mt->fromFile, mt->fromRank, mt->toFile, mt->toRank)) { return MOVE_ILLEGAL; } return move_calculate(gs, mt, promote); } #endif /* Returns MOVE_OK, MOVE_NOMATERIAL, MOVE_CHECKMATE, or MOVE_STALEMATE */ /* check_game_status prevents recursion */ int execute_move(Game *gs, Move *move, int check_game_status) { Piece movedPiece; Piece tookPiece; int i, j, foobar; /* I'd rather do this than make the code unreadable. */ #define fromFile (move->x1) #define fromRank (move->y1) #define toFile (move->x2) #define toRank (move->y2) /* (crazycomputers) Removed bughouse code. */ movedPiece = gs->board[fromFile][fromRank]; tookPiece = gs->board[toFile][toRank]; gs->board[toFile][toRank] = (move->promoteTo == EMPTY) ? gs->board[fromFile][fromRank] : (move->promoteTo | gs->turn); gs->board[fromFile][fromRank] = EMPTY; /* Check if irreversable */ if ((piecetype(movedPiece) == PAWN) || (tookPiece != EMPTY)) gs->lastirrev = gs->halfmoves; /* Check if this move is en-passant */ if ((piecetype(movedPiece) == PAWN) && (fromFile != toFile) && (tookPiece == EMPTY)) gs->board[toFile][fromRank] = EMPTY; gs->dpush = ((piecetype(movedPiece) == PAWN) && ((fromRank == toRank + 2) || (fromRank + 2 == toRank))) ? fromFile : -1; if ((piecetype(movedPiece) == ROOK) && (fromFile == 0)) { if ((fromRank == 0) && (gs->turn == WHITE)) gs->castlewa = 0; else if ((fromRank == 7) && (gs->turn == BLACK)) gs->castleba = 0; } else if ((piecetype(movedPiece) == ROOK) && (fromFile == 7)) { if ((fromRank == 0) && (gs->turn == WHITE)) gs->castlewh = 0; else if ((fromRank == 7) && (gs->turn == BLACK)) gs->castlebh = 0; } else if (piecetype(movedPiece) == KING) { if (gs->turn == WHITE) gs->castlewa = gs->castlewh = 0; else gs->castleba = gs->castlebh = 0; } if ((piecetype(movedPiece) == KING) && ((fromFile == 4) && ((toFile == 6)))) { /* Check for KS castling */ gs->board[5][toRank] = gs->board[7][toRank]; gs->board[7][toRank] = EMPTY; } if ((piecetype(movedPiece) == KING) && ((fromFile == 4) && ((toFile == 2)))) { /* Check for QS castling */ gs->board[3][toRank] = gs->board[0][toRank]; gs->board[0][toRank] = EMPTY; } if (check_game_status) { /* Does this move result in check? */ if (in_check(gs)) { /* Check for checkmate */ gs->turn = CToggle(gs->turn); if (!has_legal_move(gs)) return MOVE_CHECKMATE; } else { /* Check for stalemate */ gs->turn = CToggle(gs->turn); if (!has_legal_move(gs)) return MOVE_STALEMATE; /* loon: check for insufficient mating material, first try */ foobar = 0; for (i = 0; i < 8; i++) { for (j = 0; j < 8; j++) { switch(piecetype(gs->board[i][j])) { case KNIGHT: case BISHOP: foobar++; break; case KING: case EMPTY: break; default: foobar = 2; } } } if (foobar < 2) return MOVE_NOMATERIAL; } } else { gs->turn = CToggle(gs->turn); } return MOVE_OK; #undef fromFile #undef fromRank #undef toFile #undef toRank } /* (crazycomputers) I'll worry about this one later. */ #if 0 int backup_move(int g, int mode) { game_state_t *gs; move_t *m, *m1; int now, i; if (garray[g].numHalfMoves < 1) return MOVE_ILLEGAL; gs = &garray[g].game_state; m = (mode==REL_GAME) ? &garray[g].moveList[garray[g].numHalfMoves - 1] : &garray[g].examMoveList[garray[g].numHalfMoves - 1]; if (m->toFile < 0) return MOVE_ILLEGAL; gs->board[m->fromFile][m->fromRank] = gs->board[m->toFile][m->toRank]; if (m->piecePromotionTo != NOPIECE) { gs->board[m->fromFile][m->fromRank] = PAWN | colorval(gs->board[m->fromFile][m->fromRank]); } /****************** When takeback a _first_ move of rook, the ??rmoved variable must be cleared . To check, if the move is first, we should scan moveList. *******************/ if (piecetype(gs->board[m->fromFile][m->fromRank]) == ROOK) { if (m->color == WHITE) { if ((m->fromFile == 0) && (m->fromRank == 0)) { for (i = 2; i < garray[g].numHalfMoves - 1; i += 2) { m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i]; if ((m1->fromFile == 0) && (m1->fromRank == 0)) break; } if (i == garray[g].numHalfMoves - 1) gs->wqrmoved = 0; } if ((m->fromFile == 7) && (m->fromRank == 0)) { for (i = 2; i < garray[g].numHalfMoves - 1; i += 2) { m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i]; if ((m1->fromFile == 7) && (m1->fromRank == 0)) break; } if (i == garray[g].numHalfMoves - 1) gs->wkrmoved = 0; } } else { if ((m->fromFile == 0) && (m->fromRank == 7)) { for (i = 3; i < garray[g].numHalfMoves - 1; i += 2) { m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i]; if ((m1->fromFile == 0) && (m1->fromRank == 0)) break; } if (i == garray[g].numHalfMoves - 1) gs->bqrmoved = 0; } if ((m->fromFile == 7) && (m->fromRank == 7)) { for (i = 3; i < garray[g].numHalfMoves - 1; i += 2) { m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i]; if ((m1->fromFile == 7) && (m1->fromRank == 0)) break; } if (i == garray[g].numHalfMoves - 1) gs->bkrmoved = 0; } } } if (piecetype(gs->board[m->fromFile][m->fromRank]) == KING) { gs->board[m->toFile][m->toRank] = m->pieceCaptured; if (m->toFile - m->fromFile == 2) { gs->board[7][m->fromRank] = ROOK | colorval(gs->board[m->fromFile][m->fromRank]); gs->board[5][m->fromRank] = NOPIECE; /******** If takeback a castling, the appropriates ??moved variables must be cleared ********/ if (m->color == WHITE) { gs->wkmoved = 0; gs->wkrmoved = 0; } else { gs->bkmoved = 0; gs->bkrmoved = 0; } goto cleanupMove; } if (m->fromFile - m->toFile == 2) { gs->board[0][m->fromRank] = ROOK | colorval(gs->board[m->fromFile][m->fromRank]); gs->board[3][m->fromRank] = NOPIECE; /********** If takeback a castling, the appropriate ??moved variables must be cleared ***********/ if (m->color == WHITE) { gs->wkmoved = 0; gs->wqrmoved = 0; } else { gs->bkmoved = 0; gs->bqrmoved = 0; } goto cleanupMove; } /****************** When takeback a _first_ move of king (not the castling), the ?kmoved variable must be cleared . To check, if the move is first, we should scan moveList. *******************/ if (m->color == WHITE) { if ((m->fromFile == 4) && (m->fromRank == 0)) { for (i = 2; i < garray[g].numHalfMoves - 1; i += 2) { m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i]; if ((m1->fromFile == 4) && (m1->fromRank == 0)) break; } if (i == garray[g].numHalfMoves - 1) gs->wkmoved = 0; } } else { if ((m->fromFile == 4) && (m->fromRank == 7)) { for (i = 3; i < garray[g].numHalfMoves - 1; i += 2) { m1 = (mode==REL_GAME) ? &garray[g].moveList[i] : &garray[g].examMoveList[i]; if ((m1->fromFile == 4) && (m1->fromRank == 7)) break; } if (i == garray[g].numHalfMoves - 1) gs->bkmoved = 0; } } } if (m->enPassant) { /* Do enPassant */ gs->board[m->toFile][m->fromRank] = PAWN | (colorval(gs->board[m->fromFile][m->fromRank]) == WHITE ? BLACK : WHITE); gs->board[m->toFile][m->toRank] = NOPIECE; goto cleanupMove; } gs->board[m->toFile][m->toRank] = m->pieceCaptured; cleanupMove: garray[g].numHalfMoves--; if (gs->turn == BLACK) gs->turn = WHITE; else { gs->turn = BLACK; gs->moveNum--; } if (garray[g].numHalfMoves > 0) { m1 = (mode==REL_GAME) ? &garray[g].moveList[garray[g].numHalfMoves - 1] : &garray[g].examMoveList[garray[g].numHalfMoves - 1]; if (piecetype(gs->board[m1->toFile][m1->toRank]) == PAWN) { if ((m1->toRank - m1->fromRank) == 2) { if ((m1->toFile < 7) && gs->board[m1->toFile + 1][3] == B_PAWN) { gs->ep_possible[1][m1->toFile + 1] = -1; } if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][3] == B_PAWN) { gs->ep_possible[1][m1->toFile - 1] = 1; } } if ((m1->toRank - m1->fromRank) == -2) { if ((m1->toFile < 7) && gs->board[m1->toFile + 1][4] == W_PAWN) { gs->ep_possible[0][m1->toFile + 1] = -1; } if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][4] == W_PAWN) { gs->ep_possible[0][m1->toFile - 1] = 1; } } } } /************** and here's the end **************/ return MOVE_OK; } #endif yics-0.1.2/ytoics-c/movecheck.h0000644000175000001440000000337110250207603016616 0ustar chrisusers00000000000000/* movecheck.h * */ /* fics - An internet chess server. Copyright (C) 1993 Richard V. Nash 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. */ /* Revision history: name email yy/mm/dd Change Richard Nash 93/10/22 Created */ #ifndef _MOVECHECK_H #define _MOVECHECK_H #include "types.h" #define MOVE_OK 0 #define MOVE_ILLEGAL 1 #define MOVE_STALEMATE 2 #define MOVE_CHECKMATE 3 #define MOVE_AMBIGUOUS 4 #define MOVE_NOMATERIAL 5 #define MOVE_REPETITION 6 #define MOVE_50MOVES 7 #define MS_NOTMOVE 0 #define MS_COMP 1 #define MS_COMPDASH 2 #define MS_ALG 3 #define MS_KCASTLE 4 #define MS_QCASTLE 5 #define isrank(c) (((c) <= '8') && ((c) >= '1')) #define isfile(c) (((c) >= 'a') && ((c) <= 'h')) extern char *wpstring[]; extern char *bpstring[]; /*extern int parse_move(char *, game_state_t *, move_t *, int);*/ extern int execute_move(Game *, Move *, int); extern int move_calculate(Game *, Move *, int); /*extern int backup_move(int, int);*/ /* Some useful chess utilities */ extern int NextPieceLoop(Board, int *, int *, int); extern int InitPieceLoop(Board, int *, int *, int); extern int legal_move(Game *, int, int, int, int); extern int legal_andcheck_move(Game *, int, int, int, int); extern int in_check(Game *); extern int has_legal_move(Game *); #endif /* _MOVECHECK_H */ yics-0.1.2/ytoics-c/network.c0000644000175000001440000001222310242522634016337 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include #include #include #include #include #include #include "platform.h" #ifdef _YICS_POSIX #include #include #endif #include #include "sockets.h" #include "types.h" #include "util.h" #include "network.h" #include "globals.h" #include "ropcodes.h" static int sock = -1; static bool crypt = false; static signed long key_in = 0, key_out = 0; #ifdef _YICS_WIN32 static bool windowsStartedUp = false; static void ninit() { WORD winsockVersionRequired = 0x0101; /* Winsock Version 1.1 */ WSADATA winsockData; WSAStartup (winsockVersionRequired, &winsockData); windowsStartedUp = true; } #endif int nconnect(const char *host, unsigned short port) { int s; struct sockaddr_in sa; struct hostent *hp; #ifdef _YICS_WIN32 if (!windowsStartedUp) ninit(); #endif hp = gethostbyname(host); if (!hp) return -1; memset(&sa, 0, sizeof(sa)); memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); sa.sin_family = hp->h_addrtype; sa.sin_port = htons(port); s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) return -1; if (connect(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) { closesock(s); return -1; } return s; } bool yconnect(const char *host, unsigned short port) { int s = nconnect(host, port); if (s < 0) return false; sock = s; crypt = false; return true; } void nclose() { if (sock >= 0) { closesock(sock); sock = -1; crypt = false; } } bool socket_ready() { fd_set sl; struct timeval tv; if (sock < 0) return false; FD_ZERO(&sl); FD_SET(sock, &sl); tv.tv_sec = 0; tv.tv_usec = 1000; if (select(sock + 1, &sl, NULL, NULL, &tv)) return true; return false; } void set_keys(signed long ko, signed long ki) { key_out = ko; key_in = ki; crypt = true; } int ngetc() { uchar c; if (sock < 0) return -1; if (recv(sock, (char *)&c, sizeof(c), 0) <= 0) return -1; if (crypt) { key_in *= 83; c ^= key_in; } if (netlog != NULL) { fputc(0, netlog); fputc(c, netlog); } return c; } int nread(char *buf, int count) { int read = 0; int c; while (read < count) { c = ngetc(); if (c < 0) break; if (buf != NULL) buf[read++] = (char)c; else read++; } if (buf != NULL) buf[read] = '\0'; return read; } bool nputc(char out) { uchar o = (uchar)out; if (sock < 0) return false; if (netlog != NULL) { fputc(1, netlog); fputc(o, netlog); } if (crypt) { key_out *= 83; o ^= key_out; } if (send(sock, (char *)&o, 1, 0) <= 0) return false; return true; } bool nprint(const char *out, int count) { int i; if (sock < 0) return false; for (i = 0; i < count; i++) { if (!nputc(out[i])) return false; } lastcommand = time(NULL); return true; } bool nprintrop(char opcode, const char *data, int length) { String *utf; bool r; if (sock < 0) return false; if (!nputc(0x64)) return false; if (!nprint((char *)&session, 4)) return false; utf = StringSet(StringNull(), &opcode, 1); StringCat(utf, data, length); r = nprintutf(utf->string, (unsigned short)utf->length); StringFree(utf); return r; } bool nprinttop(uchar number, char opcode, const char *data, int length) { char *packet = malloc(2 + length); bool r; if (packet == NULL) return false; packet[0] = (char)number; packet[1] = opcode; memcpy(&packet[2], data, length); r = nprintrop(ROP_TOP, packet, 2 + length); free(packet); return r; } bool nprintutf(const char *str, unsigned short length) { char *tmp = malloc(length + 3); bool r; if (tmp == NULL) return false; packutf(tmp, str, length); r = nprint(tmp, length + 2); free(tmp); return r; } short nreadutf(char *dest) { short length; if (nread((char *)&length, 2) != 2) return 0; length = ntohs(length); if (nread(dest, length) != length) return 0; dest[length] = '\0'; return length; } String *nreadutfString(String *dest) { short length; char *tmp; if (dest == NULL) return NULL; tmp = malloc(65536); if (tmp == NULL) return NULL; length = nreadutf(tmp); StringSet(dest, tmp, length); free(tmp); return dest; } char *ngets(char *buffer, int max, int sd) { int i = 0; char b; max--; while ((i < max) && (recv(sd, &b, 1, 0) != 0)) { if (b != '\r') { buffer[i++] = b; if (b == '\n') { buffer[i] = '\0'; return buffer; } } } if (i == 0) return NULL; buffer[i] = '\0'; return buffer; } yics-0.1.2/ytoics-c/network.h0000644000175000001440000000322510242522634016346 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _NETWORK_H #define _NETWORK_H #include "types.h" extern int nconnect(const char *, unsigned short); extern bool yconnect(const char *, unsigned short); extern void nclose(void); extern bool socket_ready(void); extern void set_keys(signed long, signed long); extern int ngetc(void); extern int nread(char *, int); extern bool nputc(char); extern bool nprint(const char *, int); #define nprintString(s) nprint((s)->string, (s)->length) extern bool nprintrop(char, const char *, int); #define nprintropString(o, s) nprintrop(o, (s)->string, (s)->length) extern bool nprinttop(uchar, char, const char *, int); #define nprinttopString(t, o, s) nprinttop(t, o, (s)->string, (s)->length) extern bool nprintutf(const char *, unsigned short); extern short nreadutf(char *); extern String *nreadutfString(String *); extern char *ngets(char *, int, int); #endif yics-0.1.2/ytoics-c/opcodes.c0000644000175000001440000000601110244201734016275 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include #include #include #include #include "types.h" #include "opcodes.h" #include "ropcodes.h" #include "console.h" #include "network.h" #include "debug.h" #include "globals.h" #include "util.h" Opcode opcodes[3] = { {0x63, op_exit}, {0x64, op_roomaction}, {-1, NULL} }; void handle_opcode() { int opcode = ngetc(); Opcode *search = opcodes; if (opcode >= 0) { while (search->opcode != -1) { if (search->opcode == (uchar)opcode) { if (search->handler != NULL) search->handler(); return; } search++; } /* We don't know how many bytes to eat */ dief("Opcode %02X not implemented.", opcode); } sysiprint("The server has terminated the connection!\n"); op_exit(); } void op_exit() { time_t t; char tm[32]; nclose(); sysiprint("\n" "Logging you out.\n\n" "Thank you for using YICS! If you have any suggestions or " "bug reports, please post them on the project website, " "located at http://www.yics.org . Do NOT send such " "reports by email; they will be ignored.\n\n"); sysiprint("Logout at "); time(&t); mstrncpy(tm, ctime(&t), sizeof(tm)); tm[strlen(tm) - 1] = '\0'; sysiprint(tm); sysiprint(".\n"); die(""); } void op_roomaction() { String *packet = NULL, *tmp = NULL; uchar opcode = 0; RoomOpcode *search = ropcodes; #if defined(MEMDEBUGP) # if MEMDEBUGP int lstr; # endif #endif if (netlog != NULL) fputc(4, netlog); nread(NULL, 4); /* session id */ packet = nreadutfString(StringNull()); if (packet == NULL) die("Out of memory!"); opcode = (uchar)packet->string[0]; tmp = StringNew(&packet->string[1], packet->length - 1); StringFree(packet); packet = tmp; while (search->opcode != -1) { if (search->opcode == opcode) { #if defined(MEMDEBUGP) # if MEMDEBUGP lstr = string_count; # endif #endif if (search->handler != NULL) search->handler(packet); #if defined(MEMDEBUGP) # if MEMDEBUGP if (string_count > lstr) printf("Possible leak, ropcode %02x: %d -> %d\n", opcode, lstr, string_count); # endif #endif StringFree(packet); return; } search++; } StringFree(packet); iprintf("\nWARNING: Room opcode %02x not implemented.\n", opcode); prompt(); } yics-0.1.2/ytoics-c/opcodes.h0000644000175000001440000000176210060753542016317 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _OPCODES_H #define _OPCODES_H #include "types.h" extern Opcode opcodes[3]; extern void handle_opcode(void); extern void op_exit(void); extern void op_roomaction(void); #endif yics-0.1.2/ytoics-c/platform.h0000644000175000001440000000474610206523270016507 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _PLATFORM_H #define _PLATFORM_H /* Distinguish between Windows and Posix */ #if (defined(__linux) || defined(__unix)) # define _YICS_POSIX 1 #elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(_WINDOWS) || defined(_WINDOWS_)) # define _YICS_WIN32 1 #else # error "Platform unsupported." #endif /* 64 bit integer support */ #if (defined(__STDC__) && defined(__STDC_VERSION__)) # if (__STDC__ && __STDC_VERSION >= 199901L) # define i64_t long long # define i64fmt "%lld" # endif #endif #if !defined(i64_t) || !defined(i64fmt) # undef i64_t # undef i64fmt # if defined(__GNUC__) || defined(__MWERKS__) || defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__APPLE_CC__) || defined (_LONG_LONG) || defined (_CRAYC) # define i64_t long long # define i64fmt "%lld" # elif defined(__WATCOMC__) || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__alpha) || defined (__DECC) # define i64_t __int64 # define i64fmt "%I64d" # else # error "Compiler unsupported." # endif #endif /* The vsnprintf function */ #if defined(__WATCOMC__) || defined(_MSC_VER) # define vsnprintf(b,n,f,a) _vsnprintf (b,n,f,a) # define snprintf (_snprintf) #endif /* Annoying warning modes */ #ifdef _MSC_VER #pragma warning(disable:4100) #pragma warning(disable:4127) /* A warning in MSVC header files */ #pragma warning(disable:4032) /* A warning in MSVC header files */ #pragma warning(disable:4115) /* A warning in MSVC header files */ #endif /* XXX: MinGW-cross-compiled EXEs segfault when %lld is used... so we can't * sprintf long longs. The temporary solution is to cast to double and use * %.0f instead. #undef'd to prevent accidental usage. */ #undef i64fmt #endif yics-0.1.2/ytoics-c/ropcodes.c0000644000175000001440000005524710260627233016502 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include #include #include #include "sockets.h" #include "debug.h" #include "console.h" #include "ropcodes.h" #include "topcodes.h" #include "globals.h" #include "network.h" #include "types.h" #include "util.h" #include "version.h" #include "vars.h" #include "formula.h" #include "lists.h" void rop_option(String *); /* 0x14 */ void rop_tableoptions(String *); /* 0x30 */ void rop_buddylist(String *); /* 0x31 */ void rop_tell(String *); /* 0x33 */ void rop_ignorelist(String *); /* 0x34 */ void rop_topcode(String *); /* 0x3d */ void rop_alert(String *); /* 0x61 */ void rop_shout(String *); /* 0x63 */ void rop_deltable(String *); /* 0x64 */ void rop_entry(String *); /* 0x65 */ void rop_ping(String *); /* 0x67 */ void rop_pingend(String *); /* 0x68 */ void rop_invitation(String *); /* 0x69 */ void rop_tableentry(String *); /* 0x6a */ void rop_pingbegin(String *); /* 0x6b */ void rop_tabledeparture(String *); /* 0x6c */ void rop_introdone(String *); /* 0x6d */ void rop_newtable(String *); /* 0x6e */ void rop_tableprotection(String *); /* 0x70 */ void rop_booted(String *); /* 0x71 */ void rop_seatupdate(String *); /* 0x73 */ void rop_ratingupdate(String *); /* 0x74 */ void rop_decline(String *); /* 0x76 */ void rop_departure(String *); /* 0x78 */ void rop_finger(String *packet); /* 0x79 */ RoomOpcode ropcodes[] = { {0x14, rop_option}, {0x30, rop_tableoptions}, {0x31, rop_buddylist}, {0x33, rop_tell}, {0x34, rop_ignorelist}, {0x3d, rop_topcode}, {0x61, rop_alert}, {0x63, rop_shout}, {0x64, rop_deltable}, {0x65, rop_entry}, {0x66, NULL}, /* unknown */ {0x67, rop_ping}, {0x68, rop_pingend}, {0x69, rop_invitation}, {0x6a, rop_tableentry}, {0x6b, rop_pingbegin}, {0x6c, rop_tabledeparture}, {0x6d, rop_introdone}, {0x6e, rop_newtable}, {0x6f, NULL}, /* unknown */ {0x70, rop_tableprotection}, {0x71, rop_booted}, {0x73, rop_seatupdate}, {0x74, rop_ratingupdate}, {0x76, rop_decline}, {0x77, NULL}, /* unknown */ {0x78, rop_departure}, {0x79, rop_finger}, {-1, NULL}, }; #if STEALTH # define IsIdent(x,y) 0 #else static bool IsIdent(String *who, String *what) { String *packet, *ident; if (!strcmp(what->string, "/ytoics") || !strcmp(what->string, "/yics" )) { packet = packutfString(StringNull(), who); ident = getIdent(StringNull()); packutfStringP(packet, ident); nprintropString(ROP_TELL, packet); StringFree(packet); StringFree(ident); #if !SEE_IDENT return true; #endif } return false; } #endif static void checkSeek(Table *table) { char srating[16]; bool white; int i; Player *p; if (!variables[VAR_SEEK].number) return; if (table->protection == 2) return; for (i = 0; i < PLAYER_MAX; i++) if (table->observers[i] == pme) return; if (table->players[0] != NULL) { if (table->players[1] != NULL) return; p = table->players[0]; white = true; } else if (table->players[1] != NULL) { p = table->players[1]; white = false; } else { return; } if (inList(&lists[LIST_NOPLAY], p->lhandle)) return; table->players[white ? 1 : 0] = pme; i = checkFormula(table); table->players[white ? 1 : 0] = NULL; if (!i) return; prating(srating, p->rating, 4); iprintf("\n%s (%s) seeking %d %d %srated %s [%s] m (\"play %d\" to respond)\n", p->handle, srating, tabletime(table), tableinc(table), tablerated(table) ? "" : "un", strGameType(table), white ? "white" : "black", table->number); prompt(); } void rop_option(String *packet) { /* 0x14 */ String *key, *value; key = unpackutfStringP(StringNull(), packet); value = unpackutfStringP(StringNull(), packet); iprintf("\nClient option %s set to %s.\n", key->string, value->string); prompt(); if (clientOptions == NULL) clientOptions = createOption(key->string, value->string); else setOption(clientOptions, key->string, value->string); StringFree(key); StringFree(value); } void rop_tableoptions(String *packet) { /* 0x30 */ uchar number; unsigned short optcount = 0; Table *table; String *key, *value; Option *options = NULL; number = (uchar)packet->string[0]; table = tables[number]; if (table == NULL) return; memcpy(&optcount, &packet->string[1], 2); optcount = ntohs(optcount); StringSet(packet, &packet->string[3], packet->length - 3); while (optcount--) { key = unpackutfStringP(StringNull(), packet); value = unpackutfStringP(StringNull(), packet); if (options == NULL) options = createOption(key->string, value->string); else setOption(options, key->string, value->string); StringFree(key); StringFree(value); } destroyOptions(table->options); table->options = options; checkSeek(table); /* Check formula */ if (((table->players[0] == pme) || (table->players[1] == pme)) && (table->host != pme)) { if (!checkFormula(table)) { nprinttop(table->number, TOP_STAND, NULL, 0); value = StringNew("Sorry, the table's options do not " "fit my formula.", -1); value = packutfString(value, value); nprinttopString(table->number, TOP_KIBITZ, value); StringFree(value); sysiprint("The host has modified the settings, which " "no longer match your formula. " "Standing up.\n"); } } } void rop_buddylist(String *packet) { /* 0x31 */ buildList(&lists[LIST_NOTIFY], packet); } void rop_tell(String *packet) { /* 0x33 */ String *who, *what; who = unpackutfStringP(StringNull(), packet); if (inList(&lists[LIST_CENSOR], who->string)) { StringFree(who); return; } what = unpackutfStringP(StringNull(), packet); if (!IsIdent(who, what)) { realHandle(who); iprintf("\n%s tells you: %s\n", who->string, what->string); prompt(); } StringFree(who); StringFree(what); } void rop_ignorelist(String *packet) { /* 0x34 */ buildList(&lists[LIST_CENSOR], packet); } void rop_topcode(String *packet) { /* 0x3d */ uchar number, opcode; TableOpcode *search = topcodes; Table *table; #ifdef MEMDEBUGP # if MEMDEBUGP int lstr; # endif #endif number = (uchar)packet->string[0]; opcode = (uchar)packet->string[1]; if (tables[number] == NULL) return; table = tables[number]; StringSet(packet, &packet->string[2], packet->length - 2); while (search->opcode != -1) { if (search->opcode == opcode) { #ifdef MEMDEBUGP # if MEMDEBUGP lstr = string_count; # endif #endif if (search->handler != NULL) search->handler(table, packet); #ifdef MEMDEBUGP # if MEMDEBUGP if (string_count > lstr) printf("Possible leak, topcode %02x: %d -> %d\n", opcode, lstr, string_count); # endif #endif return; } search++; } } void rop_alert(String *packet) { /* 0x61 */ unpackutfString(packet, packet); iprint("Alert:\n"); iprint(packet->string); iprint("\n"); prompt(); } void rop_shout(String *packet) { /* 0x63 */ String *who, *what; Player *p; who = unpackutfStringP(StringNull(), packet); if (inList(&lists[LIST_CENSOR], who->string)) { StringFree(who); return; } what = unpackutfStringP(StringNull(), packet); p = findPlayer(who->string); if (!IsIdent(who, what) && variables[VAR_SHOUT].number) { if (p != NULL) StringSet(who, p->handle, -1); if (p != pme) iprint("\n"); iprintf("%s shouts: %s\n", who->string, what->string); prompt(); } StringFree(who); StringFree(what); } void rop_deltable(String *packet) { /* 0x64 */ uchar number; Table *table; number = (uchar)packet->string[0]; if (delInvite(NULL, number)) { iprintf("Table %d was destroyed; removing invitations.\n", number); prompt(); } table = tables[number]; if (table == NULL) return; destroyOptions(table->options); free(table); tables[number] = NULL; } void rop_entry(String *packet) { /* 0x65 */ String *lc, *rc; Player *p = malloc(sizeof(Player)); int index = 0; while ((index < PLAYER_MAX) && (players[index] != NULL)) index++; if (index == PLAYER_MAX) { if (p != NULL) free(p); return; } lc = unpackutfStringP(StringNull(), packet); rc = unpackutfStringP(StringNull(), packet); if ((lc == NULL) || (rc == NULL) || (p == NULL)) { if (lc != NULL) StringFree(lc); if (rc != NULL) StringFree(rc); if (p != NULL) free(p); return; } p->lhandle = malloc(lc->length + 1); p->handle = malloc(rc->length + 1); if ((p->lhandle == NULL) || (p->handle == NULL)) { if (p->lhandle != NULL) free(p->lhandle); if (p->handle != NULL) free(p->handle); StringFree(lc); StringFree(rc); free(p); return; } mstrncpy(p->lhandle, lc->string, lc->length + 1); mstrncpy(p->handle, rc->string, rc->length + 1); p->rating = PROVISIONAL; p->ping = -1; StringFree(lc); StringFree(rc); players[index] = p; if (!istrcmp(p->handle, handle)) pme = p; if (prompting) { if (variables[VAR_PIN].number) { iprintf("[%s has connected.]\n", p->handle); prompt(); } if (inList(&lists[LIST_NOTIFY], p->lhandle)) { iprintf("Notification: %s has arrived.\n", p->handle); prompt(); } } } void rop_ping(String *packet) { /* 0x67 */ String *who; who = unpackutfString(StringNull(), packet); if (inList(&lists[LIST_CENSOR], who->string)) { StringFree(who); return; } nprintropString(ROP_PONG, packet); iprintf("You were pinged by %s.\n", realHandle(who)->string); prompt(); StringFree(who); } void rop_pingend(String *packet) { /* 0x68 */ Player *p; int ptime; unpackutfString(packet, packet); if ((p = findPlayer(packet->string)) == NULL) return; if (p->ping < 0) return; ptime = (int)(gettimeofdayll() - p->ping); iprintf("ROBOadmin(*)(TD) tells you: Ping-info for %s: 3 packets " "transmitted, 3 packets received, 0%% packet loss\n", p->handle); prompt(); iprintf("ROBOadmin(*)(TD) tells you: Ping-info for %s: " "round-trip min/avg/max = %d.0/%d.0/%d.0 ms\n", p->handle, ptime, ptime, ptime); prompt(); p->ping = -1; } void rop_invitation(String *packet) { /* 0x69 */ uchar number; String *who; String *reject; Player *p; Table *table; int j; number = (uchar)packet->string[0]; if (tables[number] == NULL) return; table = tables[number]; StringSet(packet, &packet->string[1], packet->length - 1); who = unpackutfString(StringNull(), packet); if (inList(&lists[LIST_CENSOR], who->string)) { reject = StringNew("You are on my ignore list", -1); packutfString(who, who); packutfStringP(who, reject); nprintropString(ROP_DECLINE, who); StringFree(reject); StringFree(who); return; } p = findPlayer(who->string); StringSet(who, p->handle, -1); iprintf("%s has invited you to take a seat at table #%d.\n", who->string, number); StringFree(who); prompt(); for (j = 0; j < PLAYER_MAX; j++) if (table->observers[j] == pme) return; addInvite(p, number, INV_INVITE); } void rop_tableentry(String *packet) { /* 0x6a */ String *who; uchar number; Player *p; Table *table; int i; who = unpackutfStringP(StringNull(), packet); number = (uchar)packet->string[0]; p = findPlayer(who->string); if (p == NULL) { StringFree(who); return; } table = tables[number]; if (table == NULL) { StringFree(who); return; } for (i = 0; i < PLAYER_MAX; i++) { if (table->observers[i] == NULL) { table->observers[i] = p; break; } } if (p == pme) { iprintf("You are now observing game %d.\n", number); prompt(); if (primary == -1) primary = number; } else { for (i = 0; i < PLAYER_MAX; i++) { if (table->observers[i] == pme) { iprintf("Game %d: %s is now observing.\n", number, p->handle); prompt(); break; } } } StringFree(who); } void rop_pingbegin(String *packet) { /* 0x6b */ Player *p; unpackutfString(packet, packet); if ((p = findPlayer(packet->string)) == NULL) return; p->ping = gettimeofdayll(); } void rop_tabledeparture(String *packet) { /* 0x6c */ String *who; uchar number; Player *p; Table *table; int i, j; who = unpackutfStringP(StringNull(), packet); number = (uchar)packet->string[0]; p = findPlayer(who->string); if (p == NULL) { StringFree(who); return; } table = tables[number]; if (table == NULL) { StringFree(who); return; } for (i = 0; i < PLAYER_MAX; i++) { if (table->observers[i] == p) { table->observers[i] = NULL; break; } } if (p == pme) { if (!table->finished) { iprintf("\n{Game %d (? vs. ?) unknown}\n", table->number); } /* So seeking doesn't screw up if we're the host. */ table->host = NULL; iprintf("Removing game %d from observation list.\n", number); prompt(); if (primary == number) { primary = -1; for (i = 0; i < TABLE_MAX; i++) { if (tables[i] == NULL) continue; table = tables[i]; for (j = 0; j < PLAYER_MAX; j++) { if (table->observers[j] == pme) { primary = i; break; } } if (primary != -1) break; } } } else { for (i = 0; i < PLAYER_MAX; i++) { if (table->observers[i] == pme) { iprintf("Game %d: %s is no longer observing.\n", number, p->handle); prompt(); break; } } } StringFree(who); } void rop_introdone(String *packet) { /* 0x6d */ String *mess; mess = unpackutfString(StringNull(), packet); if ((mess != NULL) && (mess->length != 0)) { iprint("*** Server information: "); iprint(mess->string); prompt(); } StringFree(mess); login_complete = true; } void rop_newtable(String *packet) { /* 0x6e */ uchar number; unsigned short optcount = 0; int unknown = 0; Option *options = NULL; String *key, *value; Table *table; Game *game; number = (uchar)packet->string[0]; memcpy(&optcount, &packet->string[1], 2); optcount = ntohs(optcount); StringSet(packet, &packet->string[3], packet->length - 3); while (optcount--) { key = unpackutfStringP(StringNull(), packet); value = unpackutfStringP(StringNull(), packet); if (options == NULL) options = createOption(key->string, value->string); else setOption(options, key->string, value->string); StringFree(key); StringFree(value); } if (packet->string[0]) { memcpy(&unknown, packet->string, 4); unknown = ntohl(unknown); iprintf("\nWARNING: Opcode 6e has extra parameter: %d\n", unknown); prompt(); } table = malloc(sizeof(Table)); game = malloc(sizeof(Game)); if ((table == NULL) || (game == NULL)) { if (table != NULL) free(table); if (game != NULL) free(game); return; } memset(table, 0, sizeof(Table)); memset(game, 0, sizeof(Game)); initGame(game); table->number = number; table->options = options; table->protection = 0; table->players[0] = NULL; table->players[1] = NULL; table->host = NULL; memset(table->observers, 0, sizeof(table->observers)); table->game = game; table->start[0] = false; table->start[1] = false; table->finished = false; table->inprogress = false; table->result = "*"; if (tables[number] != NULL) { destroyOptions(tables[number]->options); free(tables[number]); } tables[number] = table; } void rop_tableprotection(String *packet) { /* 0x70 */ uchar number, protection; Table *table; number = (uchar)packet->string[0]; protection = (uchar)packet->string[1]; table = tables[number]; if (table == NULL) return; table->protection = protection; } void rop_booted(String *packet) { /* 0x71 */ uchar number; String *who; number = (uchar)packet->string[0]; StringSet(packet, &packet->string[1], packet->length - 1); who = unpackutfString(StringNull(), packet); iprintf("%s has booted you from table %d.\n", who->string, number); prompt(); StringFree(who); /* Not unobserving means that the server will disconnect from the * client after a few seconds. Too bad... */ nprintrop(ROP_UNOBSERVE, (char *)&number, 1); } void rop_seatupdate(String *packet) { /* 0x73 */ uchar number, color; String *who; String *msg; Table *table; Player *old; Player *new; int i; char *errmsg_toplayer = NULL; char *errmsg_touser = NULL; number = (uchar)packet->string[0]; color = (uchar)packet->string[1]; StringSet(packet, &packet->string[2], packet->length - 2); who = unpackutfStringP(StringNull(), packet); table = tables[number]; if (table == NULL) { StringFree(who); return; } old = table->players[color]; new = (who->length == 0) ? NULL : findPlayer(who->string); table->players[color] = new; for (i = 0; i < PLAYER_MAX; i++) { if (table->observers[i] == pme) { if (who->length != 0) { iprintf("Game %d: %s sits down as %s.\n", number, phandle(new), (color == 0) ? "white" : "black"); } else { iprintf("Game %d: %s stands up.\n", number, phandle(old)); } prompt(); break; } } checkSeek(table); if ((new != NULL) && ((table->players[0] == pme) || (table->players[1] == pme)) && (new != pme)) { if (inList(&lists[LIST_NOPLAY], new->lhandle)) { errmsg_toplayer = "Sorry, you are on my ignore list."; errmsg_touser = "is on your ignore list"; } else if (!checkFormula(table)) { errmsg_toplayer = "Sorry, you do not fit my formula."; errmsg_touser = "does not fit your formula"; } if (errmsg_toplayer != NULL) { if (table->host == pme) { StringSet(who, new->lhandle, -1); packutfString(who, who); nprinttopString(table->number, TOP_BOOT, who); msg = StringNew(errmsg_toplayer, -1); packutfStringP(who, msg); StringFree(msg); nprintropString(ROP_TELL, who); } else { nprinttop(table->number, TOP_STAND, NULL, 0); StringSet(who, errmsg_toplayer, -1); packutfString(who, who); nprinttopString(table->number, TOP_KIBITZ, who); } sysiprintf("%s %s. %s and notifying %s\n", new->handle, errmsg_touser, (table->host == pme) ? "Booting" : "Standing up,", new->handle); } } StringFree(who); } void rop_ratingupdate(String *packet) { /* 0x74 */ String *lh = unpackutfStringP(StringNull(), packet); Player *p = findPlayer(lh->string); StringFree(lh); if (p == NULL) return; memcpy(&p->rating, packet->string, 2); p->rating = ntohs(p->rating); } void rop_decline(String *packet) { /* 0x76 */ String *lh = unpackutfStringP(StringNull(), packet); String *reason = unpackutfStringP(StringNull(), packet); Player *p = findPlayer(lh->string); iprintf("%s has declined your invitation.\nReason: %s\n", phandle(p), reason->string); prompt(); StringFree(lh); StringFree(reason); } void rop_departure(String *packet) { /* 0x78 */ String *lh = unpackutfStringP(StringNull(), packet); String *handle = NULL; int i = 0; bool wasme = false; if (!strcmp(lh->string, pme->lhandle)) { nputc('X'); wasme = true; } while (i < PLAYER_MAX) { if ((players[i] != NULL) && !strcmp(players[i]->lhandle, lh->string)) { if (delInvite(players[i], 0)) { iprintf("%s departed; removing invitations.\n", players[i]->handle); prompt(); } if (players[i]->ping != -1) { iprintf("%s departed; ping cancelled.\n", players[i]->handle); prompt(); } if (players[i] == lasttell) lasttell = NULL; if (players[i] == lastopp) lastopp = NULL; handle = StringNew(players[i]->handle, -1); free(players[i]->handle); free(players[i]->lhandle); free(players[i]); players[i] = NULL; if (wasme) pme = NULL; break; } i++; } if (prompting && (handle != NULL) && !wasme) { if (variables[VAR_PIN].number) { iprintf("[%s has disconnected.]\n", handle->string); prompt(); } if (inList(&lists[LIST_NOTIFY], handle->string)) { iprintf("Notification: %s has departed.\n", handle->string); prompt(); } } if (handle != NULL) StringFree(handle); } void rop_finger(String *packet) { /* 0x79 */ String *p, *info; Player *pl = NULL; int idle = 0, total = 0, rating = 0, wins = 0, losses = 0, draws = 0, streak = 0, abandoned = 0; float rd = 50.0; Option *pi = NULL; static char key[1024], value[1024]; char *kvp = key, *infop; char state = 0; static Table *obs[TABLE_MAX]; Table **op; p = unpackutfStringP(StringNull(), packet); info = unpackutfStringP(StringNull(), packet); if ((pl = findPlayer(p->string)) == NULL) { iprintf("Error getting %s's information: pl is null.\n", p->string); prompt(); StringFree(p); StringFree(info); return; } memcpy(&idle, packet->string, 4); idle = ntohl(idle) / 1000; for (infop = info->string; ; infop++) { if ((*infop == '\n') || (*infop == '\0')) { *kvp = '\0'; kvp = key; if (state == 2) { lowercase(key); if (pi == NULL) pi = createOption(key, value); else setOption(pi, key, value); } if (*infop == '\0') break; state = 0; } else if (state == 0) { if (*infop == ':') { state = 1; *kvp = '\0'; kvp = value; } else { *(kvp++) = *infop; } } else if ((state == 1) && (*infop != ' ')) { state = 2; *(kvp++) = *infop; } else { *(kvp++) = *infop; } } StringSet(p, pl->handle, -1); iprintf("Information on %-16s ", p->string); if (idle > 59) { kvp = "mins"; idle /= 60; } else { kvp = "secs"; } iprintf("On for: ? mins Idle: %d %s\n", idle, kvp); observing(obs, pl); if (obs[0] != NULL) { iprintf("(%s is observing game(s) ", p->string); if (obs[1] == NULL) { iprintf("%d)\n", obs[0]->number); } else { for (op = obs, total = 0; *op != NULL; op++, total++); op = obs; while (total--) { iprintf("%d", (*(op++))->number); if (total > 1) iprint(", "); else if (total == 1) iprint(" and "); } iprint(")\n"); } } iprint("\n"); total = findOptionLong(pi, "games completed"); if (total < 20) rd = 350 - ((float)total / 20 * 270); rating = findOptionLong(pi, "rating"); wins = findOptionLong(pi, "wins"); losses = findOptionLong(pi, "losses"); draws = findOptionLong(pi, "draws"); snprintf(key, sizeof(key), " %4d %5.1f %6d %6d %6d %6d\n", rating, rd, wins, losses, draws, total); iprint(" rating RD win loss draw total best\n"); iprint("Blitz "); iprint(key); iprint("Lightning"); iprint(key); iprint("Standard "); iprint(key); iprint("\n"); streak = findOptionLong(pi, "streak"); kvp = (streak < 0) ? "losses" : "wins"; if (streak < 0) streak *= -1; abandoned = findOptionLong(pi, "abandoned games"); snprintf(key, sizeof(key), " 1: Streak: %d %s\n" " 2: Abandoned games: %d\n", streak, kvp, abandoned); iprint(key); prompt(); destroyOptions(pi); StringFree(p); StringFree(info); } yics-0.1.2/ytoics-c/ropcodes.h0000644000175000001440000000246110060753542016476 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _ROPCODES_H #define _ROPCODES_H #include "types.h" extern RoomOpcode ropcodes[]; #define ROP_OPTION 0x14 #define ROP_TELL 0x23 #define ROP_IGNORE 0x24 #define ROP_UNIGNORE 0x25 #define ROP_OPEN 0x26 #define ROP_TOP 0x2b #define ROP_SHOUT 0x43 #define ROP_PING 0x47 #define ROP_PONG 0x48 #define ROP_FINGER 0x49 #define ROP_OBSERVE 0x4a #define ROP_UNOBSERVE 0x4c #define ROP_CREATETABLE 0x4e #define ROP_DECLINE 0x56 #define ROP_SILENCE 0x5e #define ROP_EXIT 0x58 #define ROP_INFO 0x7e #endif yics-0.1.2/ytoics-c/sockets.h0000644000175000001440000000270010201640610016313 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _SOCKETS_H #define _SOCKETS_H #include "platform.h" #if defined(_YICS_WIN32) # include # include # define closesock(s) closesocket(s) # define EWOULDBLOCK (WSAEWOULDBLOCK) # define ENOTSOCK (WSAENOTSOCK) # define ECONNRESET (WSAECONNRESET) # define ECONNREFUSED (WSAECONNREFUSED) # define ENOTSOCK (WSAENOTSOCK) # define NOTINITIALISED (WSANOTINITIALISED) # define ETIMEDOUT (WSAETIMEDOUT) # define ENOBUFS (WSAENOBUFS) #elif defined(_YICS_POSIX) # include # include # include # include # define closesock(s) close(s) #endif #endif yics-0.1.2/ytoics-c/style.c0000644000175000001440000000615710260627233016020 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include #include #include "types.h" #include "console.h" #include "globals.h" #include "movecheck.h" #include "style.h" #include "vars.h" #include "util.h" Style styles[] = { {12, style12}, {0, NULL}, }; static const char values[] = {0, 1, 3, 3, 5, 9, 0}; StyleHandler getstyle(int style) { Style *srch = styles; while (srch->handler != NULL) { if (srch->style == style) return srch->handler; srch++; } return NULL; } void style12(Table *t) { int x, y, p, wv = 0, bv = 0; static char s12[256], tmp[256]; Game *s = t->game; char relation = 0; char *wh, *bh; const int ms = variables[VAR_MS].number; printf("\n<12> "); wh = s12; for (y = 7; y >= 0; y--) { for (x = 0; x < 8; x++) { p = s->board[x][y]; if (p == EMPTY) { *(wh++) = '-'; } else { if (iswhite(p)) { *(wh++) = *wpstring[p]; wv += values[p]; } else { *(wh++) = *bpstring[piecetype(p)]; bv += values[piecetype(p)]; } } } *(wh++) = ' '; } *wh = '\0'; snprintf(tmp, sizeof(tmp), "%c %d %d %d %d %d %d ", (s->turn == WHITE) ? 'W' : 'B', s->dpush, s->castlewa, s->castlewh, s->castleba, s->castlebh, s->lastirrev); mstrncat(s12, tmp, sizeof(s12)); if (t->players[0] == NULL) { relation = -3; wh = "_EMPTY_"; } else { wh = t->players[0]->handle; } if (t->players[1] == NULL) { relation = -3; bh = "_EMPTY_"; } else { bh = t->players[1]->handle; } if (t->players[0] == pme) { /* I'm playing white */ relation = (char)((s->turn == WHITE) ? 1 : -1); } else if (t->players[1] == pme) { /* I'm playing black */ relation = (char)((s->turn == BLACK) ? 1 : -1); } x = (s->halfmoves + 2) / 2; /* XXX: See comment in platform.h regarding i64fmt. */ snprintf(tmp, sizeof(tmp), "%d %s %s %d %d %d %d %d %.0f %.0f %d %s (%s) %s %d %d\n", t->number, wh, bh, relation, (int)tabletime(t), (int)tableinc(t), wv, bv, (float)(ms ? timeleft(t, 0) : timeleft(t, 0) / 1000), (float)(ms ? timeleft(t, 1) : timeleft(t, 1) / 1000), x, (s->move != NULL) ? s->move->desc : "none", fmttime_ms((s->move != NULL) ? s->move->timeTaken : 0), (s->move != NULL) ? s->move->alg : "none", 0, /* we never invert the board */ (tabletime(t) != 0) ? 1 : 0 /* clock only ticking when untimed */); mstrncat(s12, tmp, sizeof(s12)); printf("%s", s12); prompt(); } yics-0.1.2/ytoics-c/style.h0000644000175000001440000000166710100544505016017 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _STYLE_H #define _STYLE_H #include "types.h" extern StyleHandler getstyle(int); extern void style12(Table *); #endif yics-0.1.2/ytoics-c/topcodes.c0000644000175000001440000003073010260627233016472 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include #include #include #if defined(__GNUC__) #include #endif #include "types.h" #include "topcodes.h" #include "network.h" #include "sockets.h" #include "console.h" #include "globals.h" #include "util.h" #include "movecheck.h" #include "vars.h" #include "style.h" #include "debug.h" #include "formula.h" #include "lists.h" static bool makemove(Table *table, Move *move, bool noend); static void top_inprogress(Table *, String *); /* 0x30 */ static void top_message(Table *, String *); /* 0x31 */ static void top_newhost(Table *, String *); /* 0x35 */ static void top_startgamerequest(Table *, String *); /* 0x39 */ static void top_gameover_resign(Table *, String *); /* 0x5b */ static void top_moves(Table *, String *); /* 0x61 */ static void top_clear(Table *, String *); /* 0x62 */ static void top_kibitz(Table *, String *); /* 0x63 */ static void top_clock(Table *, String *); /* 0x6c */ static void top_move(Table *, String *); /* 0x6d */ static void top_gameover_flag(Table *, String *); /* 0x69 */ static void top_promote(Table *, String *); /* 0x70 */ TableOpcode topcodes[] = { {0x30, top_inprogress}, {0x31, top_message}, {0x35, top_newhost}, {0x39, top_startgamerequest}, {0x5b, top_gameover_resign}, {0x61, top_moves}, {0x62, top_clear}, {0x63, top_kibitz}, {0x64, NULL}, {0x6c, top_clock}, {0x6d, top_move}, {0x69, top_gameover_flag}, {0x70, top_promote}, {0x74, NULL}, {-1, NULL}, }; void refresh(Table *table) { StyleHandler style; if ((table->number != primary) && variables[VAR_SINGLEBOARD].number) return; if (table->finished) return; style = getstyle(variables[VAR_STYLE].number); if (style == NULL) /* This should never happen */ return; (*style)(table); } static void gameover(Table *table, char *message) { refresh(table); printf("%s", message); //initGame(table->game); table->finished = true; iprintf("Removing game %d from observation list.\n", table->number); prompt(); iprintf("You are now observing game %d.\n", table->number); prompt(); } static void top_inprogress(Table *table, String *packet) { /* 0x30 */ table->inprogress = true; } static void top_message(Table *table, String *packet) { /* 0x31 */ unpackutfString(packet, packet); iprintf("Game %d: %s\n", table->number, packet->string); prompt(); } static void top_newhost(Table *table, String *packet) { /* 0x35 */ Player *p; unpackutfString(packet, packet); p = findPlayer(packet->string); table->host = p; iprintf("Game %d: Host is now %s.\n", table->number, phandle(p)); prompt(); } static void top_startgamerequest(Table *table, String *packet) { /* 0x39 */ char color = (uchar)packet->string[0]; char *unr, *etime; char wr[8], br[8]; if (color == -1) { iprintf("Game %d: Start requests reset.\n", table->number); prompt(); table->start[0] = false; table->start[1] = false; } else if (table->finished && ((color == 0) || (color == 1))) { iprintf("Game %d: %s requests to start the game.\n", table->number, phandle(table->players[(int)color])); prompt(); table->start[(int)color] = true; /* * Sometimes both players can request to start the game, then * one will stand up, but the other requests this AFTER the * player stands up, and the server doesn't send the reset * right away. So we also need to make sure that someone is * sitting down to prevent a segmentation fault. */ if ((table->start[0] && table->start[1]) && (table->players[0] != NULL) && (table->players[1] != NULL)) { lastopp = (table->players[0] == pme) ? table->players[1] : table->players[0]; unr = tablerated(table) ? "" : "un"; etime = strGameType(table); prating(wr, table->players[0]->rating, 0); prating(br, table->players[1]->rating, 0); printf("\nCreating: %s (%s) %s (%s) %srated %s %ld %ld\n", phandle(table->players[0]), wr, phandle(table->players[1]), br, unr, etime, tabletime(table), tableinc(table)); printf("{Game %d (%s vs. %s) Creating %srated %s match.}\n", table->number, phandle(table->players[0]), phandle(table->players[1]), unr, etime); prompt(); initGame(table->game); table->finished = false; table->result = "*"; refresh(table); } else if ((table->players[(int)color] != pme) && (table->players[1 - (int)color] == pme) && variables[VAR_AUTOSTART].number) { if (inList(&lists[LIST_NOPLAY], table->players[(int)color]->lhandle)) { iprintf("Game %d: Opponent is censored; not " "auto-starting.\n", table->number); } else if (!checkFormula(table)) { iprintf("Game %d: Formula check failed; not " "auto-starting.\n", table->number); } else { iprintf("Game %d: Auto-starting.\n", table->number); nprinttop(table->number, TOP_START, NULL, 0); } prompt(); } } } static void top_gameover(Table *table, String *packet, bool flag) { /* 0x5b and 0x69 */ int result = packet->string[0]; static char res[128], st[256]; if (result == -2) { strcpy(res, "Game drawn} 1/2-1/2"); table->result = "1/2-1/2"; } else if ((result == 0) || (result == 1)) { snprintf(res, sizeof(res), "%s %s} %d-%d", phandle(table->players[result]), flag ? "forfeits on time" : "resigns", result, 1 - result); table->result = (result == 1) ? "1-0" : "0-1"; } else { snprintf(res, sizeof(res), "Unknown (%d)} *", result); table->result = "*"; } snprintf(st, sizeof(st), "\n{Game %d (%s vs. %s) %s\n", table->number, phandle(table->players[0]), phandle(table->players[1]), res); gameover(table, st); } static void top_gameover_resign(Table *table, String *packet) { /* 0x5b */ top_gameover(table, packet, false); } static void top_moves(Table *table, String *packet) { /* 0x61 */ unsigned int moves; Move move_st; unsigned short move, *p; initGame(table->game); memcpy(&moves, &packet->string[4], 4); moves = ntohl(moves); p = (unsigned short *)&packet->string[8]; while (moves--) { memset(&move_st, 0, sizeof(move_st)); move = ntohs(*(p++)); move_st.x1 = (uchar)(move & 7); move >>= 3; move_st.y1 = (uchar)(7 - (move & 7)); move >>= 3; move_st.x2 = (uchar)(move & 7); move >>= 3; move_st.y2 = (uchar)(7 - (move & 7)); switch (move >> 3) { case 4: move_st.promoteTo = KNIGHT; break; case 6: move_st.promoteTo = BISHOP; break; case 8: move_st.promoteTo = ROOK; break; case 10: move_st.promoteTo = QUEEN; break; default: move_st.promoteTo = EMPTY; break; } makemove(table, &move_st, false); } refresh(table); if (!table->inprogress) table->finished = true; else table->inprogress = false; } static void top_clear(Table *table, String *packet) { /* 0x62 */ initGame(table->game); table->finished = false; refresh(table); } static void top_kibitz(Table *table, String *packet) { /* 0x63 */ String *who, *what; Player *p; char rating[16]; who = unpackutfStringP(StringNull(), packet); if (inList(&lists[LIST_CENSOR], who->string)) { StringFree(who); return; } what = unpackutfStringP(StringNull(), packet); p = findPlayer(who->string); if (p == NULL) { StringFree(who); StringFree(what); return; } prating(rating, p->rating, 0); iprintf("%s(%s)[%d] kibitzes: %s\n", p->handle, rating, table->number, what->string); prompt(); StringFree(who); StringFree(what); } static void top_clock(Table *table, String *packet) { /* 0x6c */ uchar color; i64_t time; color = (uchar)packet->string[0]; memcpy(&time, &packet->string[1], sizeof(i64_t)); time = ntohll(time); if (time < 0) { table->clock[color] = 0; return; } else if (table->game->turn != (color ? BLACK : WHITE)) { table->clock[color] = -time; } else { table->clock[color] = time + gettimeofdayll(); } #if CLOCK_UPDATE if (color) refresh(table); #endif } static bool makemove(Table *table, Move *move, bool noend) { Game *game = table->game; int pfrom, pto, result; static char donemsg[1024]; char reason[128], *text; struct timeval tv; i64_t now; table->finished = false; pfrom = game->board[move->x1][move->y1]; pto = game->board[move->x2][move->y2]; if (pfrom == EMPTY) debugGame(game, table->number, "No piece on the source square.", move); if (!iscolor(pfrom, game->turn)) debugGame(game, table->number, "The moved piece does not belong to the active player.", move); if ((pto != EMPTY) && iscolor(pto, game->turn)) debugGame(game, table->number, "The captured piece has the same color as the capturing piece.", move); /* Promotion info is sent later. */ if ((move->promoteTo == EMPTY) && (piecetype(pfrom) == PAWN) && ((move->y2 == 0) || (move->y2 == 7))) { game->lastmove.present = true; game->lastmove.move = *move; return false; } /* If a pawn isn't moving to the edge, it can't be a promotion. */ if ((piecetype(pfrom) != PAWN) || ((move->y2 != 0) && (move->y2 != 7))) move->promoteTo = EMPTY; game->captured = EMPTY; if ((!legal_move(game, move->x1, move->y1, move->x2, move->y2)) || (move_calculate(game, move, move->promoteTo) == MOVE_ILLEGAL)) debugGame(game, table->number, "The move does not appear to be legal.", move); game->halfmoves++; result = execute_move(game, move, 1); if ((addRepetition(game) >= 3) && (result == MOVE_OK)) { result = MOVE_REPETITION; } else if ((game->lastirrev != -1) && ((game->halfmoves - game->lastirrev) >= 100)) { result = MOVE_50MOVES; } now = gettimeofdayll(); move->timeTaken = now - game->movetime; game->movetime = now; addMove(game, move); if ((result != MOVE_OK) && !noend) { text = "1/2-1/2"; switch (result) { case MOVE_CHECKMATE: snprintf(reason, sizeof(reason), "%s checkmated", phandle(table->players[(game->turn == BLACK) ? 1 : 0])); text = (game->turn == BLACK) ? "1-0" : "0-1"; break; case MOVE_STALEMATE: strcpy(reason, "Game drawn by stalemate"); break; case MOVE_NOMATERIAL: strcpy(reason, "Neither player has mating material"); break; case MOVE_REPETITION: strcpy(reason, "Game drawn by repetition"); break; case MOVE_50MOVES: strcpy(reason, "Game drawn by the 50 move rule"); break; default: strcpy(reason, "Unknown"); text = "*"; break; } snprintf(donemsg, sizeof(donemsg), "\n{Game %d (%s vs. %s) %s} %s\n", table->number, phandle(table->players[0]), phandle(table->players[1]), reason, text ); gameover(table, donemsg); table->result = text; } for (pto = 0; pto < 2; pto++) { gettimeofday(&tv, NULL); if ((game->turn == (pto ? BLACK : WHITE)) && (table->clock[pto] < 0)) { table->clock[pto] = tv2ll(tv) - table->clock[pto]; } else if ((game->turn != (pto ? BLACK : WHITE)) && (table->clock[pto] >= 0)) { table->clock[pto] = -table->clock[pto] + tv2ll(tv); } } return true; } static void top_move(Table *table, String *packet) { /* 0x6d */ Move move; /* The side that moved is [0] but we don't need that */ move.x1 = packet->string[1]; move.y1 = (uchar)(7 - packet->string[2]); move.x2 = packet->string[3]; move.y2 = (uchar)(7 - packet->string[4]); move.promoteTo = EMPTY; move.alg[0] = '\0'; move.desc[0] = '\0'; if (makemove(table, &move, false)) refresh(table); } static void top_gameover_flag(Table *table, String *packet) { /* 0x69 */ top_gameover(table, packet, true); } static void top_promote(Table *table, String *packet) { /* 0x70 */ char piece = 0; if (!table->game->lastmove.present) return; table->game->lastmove.present = false; /* The side that moved is [0] but we don't need that */ switch (packet->string[1]) { case 4: piece = KNIGHT; break; case 6: piece = BISHOP; break; case 8: piece = ROOK; break; case 10: piece = QUEEN; break; default: dief("Unknown piece type in promotion: %d", piece); } table->game->lastmove.move.promoteTo = piece; makemove(table, &table->game->lastmove.move, false); refresh(table); } yics-0.1.2/ytoics-c/topcodes.h0000644000175000001440000000253310201621623016467 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _TOPCODES_H #define _TOPCODES_H #include "types.h" extern TableOpcode topcodes[]; extern void refresh(Table *); #define TOP_CANCELSAVE 0x21 #define TOP_PROTECTION 0x25 #define TOP_START 0x42 #define TOP_KIBITZ 0x43 #define TOP_STAND 0x44 #define TOP_DRAW 0x46 #define TOP_FLAG 0x49 #define TOP_RATED 0x4b #define TOP_TIME 0x4c #define TOP_MOVE 0x4d #define TOP_PROMOTE 0x50 #define TOP_BOOT 0x51 #define TOP_SIT 0x54 #define TOP_ACCEPTDRAW 0x57 #define TOP_ACCDEC_CANCELSAVE 0x58 #define TOP_INVITE 0x5e #define TOP_RESIGN 0x7b #endif yics-0.1.2/ytoics-c/types.c0000644000175000001440000001774610250207603016024 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include #include #include #include "types.h" #include "debug.h" #include "globals.h" #include "console.h" #include "util.h" char gameType(Table *table) { int etime; if (table == NULL) return '?'; etime = tabletime(table) + (tableinc(table) * 2 / 3); if (etime == 0) return 'u'; if (etime < 3) return 'l'; if (etime < 15) return 'b'; return 's'; } char *strGameType(Table *table) { switch (gameType(table)) { case 'u': return "untimed"; case 'l': return "lightning"; case 'b': return "blitz"; } return "standard"; } Option *createOption(const char *key, const char *value) { Option *option = malloc(sizeof(Option)); int keyl, valuel; if (option == NULL) return NULL; keyl = strlen(key) + 1; valuel = strlen(value) + 1; option->key = malloc(keyl); if (option->key == NULL) { free(option); return NULL; } option->value = malloc(valuel); if (option->value == NULL) { free(option->key); free(option); return NULL; } memcpy(option->key, key, keyl); memcpy(option->value, value, valuel); option->next = NULL; #if MEMDEBUG option_count++; #endif return option; } Option *setOption(Option *option, const char *key, const char *value) { char *tmp; if (option == NULL) return NULL; while (option) { if (!strcmp(key, option->key)) { tmp = realloc(option->value, strlen(value) + 1); if (tmp == NULL) return NULL; option->value = tmp; strcpy(option->value, value); break; } if (option->next == NULL) { option->next = createOption(key, value); option = option->next; break; } option = option->next; } return option; } Option *destroyOption(Option *option) { Option *next; if (option == NULL) return NULL; next = option->next; free(option->key); free(option->value); free(option); #if MEMDEBUG option_count--; #endif return next; } void destroyOptions(Option *option) { while (option) option = destroyOption(option); } Option *findOption(Option *option, char *key) { while (option != NULL) { if (!strcmp(key, option->key)) return option; option = option->next; } return NULL; } long findOptionLong(Option *option, char *key) { while (option != NULL) { if (!strcmp(key, option->key)) return strtol(option->value, NULL, 10); option = option->next; } return 0; } String *StringNew(const char *content, int length) { String *str = malloc(sizeof(String)); if (str == NULL) return NULL; if (length < 0) length = strlen(content); str->string = malloc(length + 1); if (str->string == NULL) { free(str); return NULL; } memcpy(str->string, content, length); str->string[length] = '\0'; str->length = length; #if MEMDEBUG string_count++; #endif return str; } void StringFree(String *str) { if (str == NULL) return; if (str->string != NULL) free(str->string); #if MEMDEBUG string_count--; #endif free(str); } String *StringSet(String *str, const char *content, int length) { char *tmp; if (str == NULL) return NULL; if (length < 0) length = strlen(content); tmp = malloc(length + 1); if (tmp == NULL) return NULL; memmove(tmp, content, length); if (str->string) free(str->string); str->string = tmp; str->string[length] = '\0'; str->length = length; return str; } String *StringCat(String *str, const char *cat, int length) { char *tmp; if ((str == NULL) || (cat == NULL)) return NULL; if (length < 0) length = strlen(cat); tmp = realloc(str->string, str->length + length + 1); if (tmp == NULL) return NULL; str->string = tmp; memcpy(&str->string[str->length], cat, length); length += str->length; str->string[length] = '\0'; str->length = length; return str; } void addMove(Game *s, Move *move) { Movelist *last = s->movelist; Movelist *new = malloc(sizeof(Movelist)); if (new == NULL) return; new->move = *move; new->next = NULL; if (last == NULL) { s->movelist = new; } else { while (last->next != NULL) last = last->next; last->next = new; } s->move = &new->move; } uchar addRepetition(Game *s) { Repetition *current = s->repetitions, *last = NULL, *new; while (current != NULL) { if ((current->tomove == s->turn) && !memcmp(current->position, s->board, sizeof(Board))) return ++(current->times); last = current; current = current->next; } new = malloc(sizeof(Repetition)); if (new == NULL) return 0; memcpy(new->position, s->board, sizeof(Board)); new->times = 1; new->tomove = s->turn; new->next = NULL; if (last != NULL) last->next = new; else s->repetitions = new; return 1; } void destroyMovelist(Game *s) { Movelist *current, *next; current = s->movelist; while (current != NULL) { next = current->next; free(current); current = next; } s->movelist = NULL; } void destroyRepetitions(Game *s) { Repetition *current, *next; current = s->repetitions; while (current != NULL) { next = current->next; free(current); current = next; } s->repetitions = NULL; } void initGame(Game *s) { int i, j; for (i = 0; i < 8; i++) for (j = 2; j < 6; j++) s->board[i][j] = EMPTY; for (i = 0; i < 8; i++) s->board[i][1] = W_PAWN; for (i = 0; i < 8; i++) s->board[i][6] = B_PAWN; s->board[0][0] = W_ROOK; s->board[1][0] = W_KNIGHT; s->board[2][0] = W_BISHOP; s->board[3][0] = W_QUEEN; s->board[4][0] = W_KING; s->board[5][0] = W_BISHOP; s->board[6][0] = W_KNIGHT; s->board[7][0] = W_ROOK; s->board[0][7] = B_ROOK; s->board[1][7] = B_KNIGHT; s->board[2][7] = B_BISHOP; s->board[3][7] = B_QUEEN; s->board[4][7] = B_KING; s->board[5][7] = B_BISHOP; s->board[6][7] = B_KNIGHT; s->board[7][7] = B_ROOK; s->castlewa = s->castlewh = 1; s->castleba = s->castlebh = 1; s->dpush = -1; s->captured = EMPTY; s->halfmoves = 0; s->lastirrev = -1; s->turn = WHITE; s->move = NULL; s->movetime = gettimeofdayll(); s->lastmove.present = false; destroyMovelist(s); destroyRepetitions(s); } void debugGame(Game *s, int number, char *msg, Move *move) { FILE *rlog = fopen("yics-error.txt", "a"); int mnum = 1; bool mblack = 0; int x, y; Movelist *current; if (rlog == NULL) rlog = stdout; fprintf(rlog, "---ERROR REPORT---\n" "A fatal error has occured on table %d:\n" " %s\n" "While trying to make the move:\n" " (%d, %d) -> (%d, %d) = (%d)\n\n" "Please copy and paste this entire message into a bug report at\n" "http://www.yics.org/bugs.php\n\n" "Position at the time of the error:\n", number, msg, move->x1, move->y1, move->x2, move->y2, move->promoteTo); for (y = 7; y >= 0; y--) { for (x = 0; x < 8; x++) { fprintf(rlog, "%02X", s->board[x][y]); } fprintf(rlog, "\n"); } fprintf(rlog, "\nTable movelist:\n"); current = s->movelist; while (current != NULL) { if (mblack) { fprintf(rlog, "%s\n", current->move.alg); mblack = 0; mnum++; } else { fprintf(rlog, "%3d. %-8s", mnum, current->move.alg); mblack = 1; } current = current->next; } if (mblack) { fprintf(rlog, "\n"); } fprintf(rlog, "---ERROR REPORT---\n"); if (rlog != stdout) { fclose(rlog); sysiprint("\nA debug message was appended to a file named \"yics-error.txt\". " "Please copy the report from this file and paste it into a bug report at " "http://www.yics.org/bugs.php .\n"); } die("Chess logic error."); } yics-0.1.2/ytoics-c/types.h0000644000175000001440000001343310260627233016024 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _TYPES_H #define _TYPES_H #include "platform.h" #include #if defined(__GNUC__) #include #else /* This is where "struct timeval" is defined in Windows. */ #include #include #endif #define tv2ll(tv) (((i64_t)((tv).tv_sec) * 1000) + ((tv).tv_usec / 1000)) #define PLAYER_MAX 300 #define TABLE_MAX 300 #ifndef true #define true 1 #endif #ifndef false #define false 0 #endif #ifndef NULL #define NULL ((void *)0) #endif typedef unsigned char uchar; typedef uchar bool; /* * From the public FICS sources. * Copyright (C) 1993 Richard V. Nash * Modifications Copyright (C) 2004 Chris Howie */ typedef enum { WHITE = 0x00, BLACK = 0x80 } Color; typedef enum { EMPTY = 0, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING } Piece; #define W_PAWN (Piece)(PAWN | WHITE) #define W_KNIGHT (Piece)(KNIGHT | WHITE) #define W_BISHOP (Piece)(BISHOP | WHITE) #define W_ROOK (Piece)(ROOK | WHITE) #define W_QUEEN (Piece)(QUEEN | WHITE) #define W_KING (Piece)(KING | WHITE) #define B_PAWN (Piece)(PAWN | BLACK) #define B_KNIGHT (Piece)(KNIGHT | BLACK) #define B_BISHOP (Piece)(BISHOP | BLACK) #define B_ROOK (Piece)(ROOK | BLACK) #define B_QUEEN (Piece)(QUEEN | BLACK) #define B_KING (Piece)(KING | BLACK) #define isblack(p) ((p) & BLACK) #define iswhite(p) (!isblack(p)) #define iscolor(p,color) (((p) & BLACK) == (color)) #define piecetype(p) ((p) & 0x7f) #define colorval(p) ((p) & 0x80) #define CToggle(c) (((c) == BLACK) ? WHITE : BLACK) /* End FICS code */ typedef Piece Board[8][8]; typedef char AlgMove[8]; typedef char DescMove[10]; typedef struct { uchar x1, x2, y1, y2; Piece promoteTo; AlgMove alg; DescMove desc; i64_t timeTaken; } Move; typedef struct _Movelist { Move move; /* We don't use desc. Much. */ struct _Movelist *next; /* linked list */ } Movelist; typedef struct _Repetition { Board position; uchar times; Color tomove; struct _Repetition *next; /* linked list */ } Repetition; typedef struct { Board board; uchar castlewa, castlewh; uchar castleba, castlebh; char dpush; uchar captured; Movelist *movelist; Repetition *repetitions; int lastirrev; int halfmoves; Color turn; Move *move; i64_t movetime; struct { bool present; Move move; } lastmove; } Game; typedef struct { char *string; int length; } String; typedef struct { char *handle; char *lhandle; short rating; i64_t ping; } Player; typedef struct _Option { char *key; char *value; struct _Option *next; /* linked list */ } Option; typedef struct { uchar number; Option *options; uchar protection; Player *players[2]; Player *host; Player *observers[PLAYER_MAX]; Game *game; i64_t clock[2]; bool start[2]; bool finished; char *result; bool inprogress; } Table; typedef enum { INV_INVITE = 0, INV_DRAW, INV_ABORT, INV_ADJOURN } InviteType; typedef struct _Invite { Player *who; uchar number; InviteType type; struct _Invite *next, *last; /* doubly-linked list */ } Invite; typedef enum { VAR_NUMERIC = 0, VAR_BOOLEAN, VAR_STRING, VAR_END = -1 } VariableType; typedef struct _Variable { const char *name; bool (*validator)(struct _Variable *, void *new); void (*postset)(struct _Variable *); VariableType type; bool locks; String *string; int number; } Variable; typedef void (*OpcodeHandler)(void); typedef void (*RoomOpcodeHandler)(String *); typedef void (*TableOpcodeHandler)(Table *, String *); typedef void (*CommandHandler)(String *[], int); typedef void (*StyleHandler)(Table *); typedef struct { short opcode; OpcodeHandler handler; } Opcode; typedef struct { short opcode; RoomOpcodeHandler handler; } RoomOpcode; typedef struct { short opcode; TableOpcodeHandler handler; } TableOpcode; typedef struct { char *command; CommandHandler handler; int maxparams; } Command; typedef struct { char *alias; char *mapping; } Alias; typedef struct { int style; StyleHandler handler; } Style; typedef struct { char *name; int size; char **contents; void (*on_add)(const char *); void (*on_sub)(const char *); } List; /* Tables */ extern char gameType(Table *); extern char *strGameType(Table *); /* Options */ extern Option *createOption(const char *, const char *); extern Option *setOption(Option *, const char *, const char *); extern Option *destroyOption(Option *); extern void destroyOptions(Option *); extern Option *findOption(Option *, char *); extern long findOptionLong(Option *, char *); /* Strings */ extern String *StringNew(const char *, int); extern void StringFree(String *); extern String *StringSet(String *, const char *, int); extern String *StringCat(String *, const char *, int); #define StringCopy(dest,src) StringSet((dest), (src)->string, (src)->length) #define StringNull() StringNew("", 0) #define StringDup(src) StringNew((src)->string, (src)->length) /* Boards */ extern void addMove(Game *, Move *); extern uchar addRepetition(Game *); extern void destroyMovelist(Game *); extern void destroyRepetitions(Game *); extern void initGame(Game *); extern void debugGame(Game *, int, char *, Move *); #endif yics-0.1.2/ytoics-c/util.c0000644000175000001440000002022210260627233015622 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include #include #include #ifndef _YICS_POSIX #include #endif #include "util.h" #include "console.h" #include "sockets.h" #include "types.h" #include "vars.h" char *ltrim(char *str) { char *start = str; while ((*start == ' ') || (*start == '\n')) start++; memmove(str, start, strlen(start) + 1); return str; } char *rtrim(char *str) { char *end = str; while (*end) end++; end--; while ((end >= str) && ((*end == ' ') || (*end == '\n'))) end--; end[1] = '\0'; return str; } String *ltrimString(String *str) { int i = 0; while ((i < str->length) && (str->string[i] == ' ')) i++; if (i == 0) /* nothing to trim */ return str; str->length -= i; memmove(str->string, &str->string[i], str->length + 1); /* str->string = realloc(str->string, str->length); */ return str; } String *rtrimString(String *str) { int i = str->length - 1; while ((i >= 0) && (str->string[i] == ' ')) i--; if (i == str->length - 1) /* nothing to trim */ return str; str->length = i + 1; str->string[i + 1] = '\0'; /* str->string = realloc(str->string, i + 1); */ return str; } /* TODO: Rename these subroutines and add real UTF-8 encoding/decoding. */ char *packutf(char *dest, const char *str, unsigned short length) { memmove(&dest[2], str, length); length = htons(length); memcpy(dest, &length, 2); return dest; } String *packutfString(String *dest, const String *src) { char *tmp; String *temp; if ((dest == NULL) || (src == NULL)) return NULL; temp = StringCopy(StringNull(), src); if (temp == NULL) return NULL; tmp = realloc(dest->string, src->length + 2); if (tmp == NULL) { StringFree(temp); return NULL; } dest->string = tmp; packutf(dest->string, temp->string, (unsigned short)temp->length); dest->length = temp->length + 2; StringFree(temp); return dest; } String *packutfStringP(String *dest, const String *src) { char *tmp; if ((dest == NULL) || (src == NULL)) return NULL; tmp = realloc(dest->string, dest->length + src->length + 2); if (tmp == NULL) return NULL; dest->string = tmp; packutf(&dest->string[dest->length], src->string, (unsigned short)src->length); dest->length += src->length + 2; return dest; } char *unpackutf(char *dest, const char *src) { short int length; memcpy(&length, src, 2); length = ntohs(length); memmove(dest, src + 2, length); dest[length] = '\0'; return dest; } String *unpackutfString(String *dest, const String *src) { short int length; String *temp; char *ctmp; if ((dest == NULL) || (src == NULL)) return NULL; memcpy(&length, src->string, 2); length = ntohs(length); if (length > src->length - 2) length = (unsigned short)(src->length - 2); temp = StringCopy(StringNull(), src); /* allows in-place unpacking */ if (temp == NULL) return NULL; ctmp = realloc(dest->string, length + 1); if (ctmp == NULL) { StringFree(temp); return NULL; } dest->string = ctmp; memcpy(dest->string, temp->string + 2, length); dest->string[length] = '\0'; dest->length = length; StringFree(temp); return dest; } String *unpackutfStringP(String *dest, String *src) { String *tmp; if ((dest == NULL) || (src == NULL)) return NULL; tmp = StringCopy(StringNull(), src); if (tmp == NULL) return NULL; unpackutfString(dest, src); StringSet(src, &tmp->string[dest->length + 2], src->length - dest->length - 2); StringFree(tmp); return dest; } #define CASE_DIFFERENCE ('a' - 'A') char *lowercase(char *str) { char *sp = str; while (*sp) { if ((*sp >= 'A') && (*sp <= 'Z')) *sp += CASE_DIFFERENCE; sp++; } return str; } char *uppercase(char *str) { char *sp = str; while (*sp) { if ((*sp >= 'a') && (*sp <= 'z')) *sp -= CASE_DIFFERENCE; sp++; } return str; } int istrcmp(const char *s1, const char *s2) { char a, b; while ((*s1 != '\0') || (*s2 != '\0')) { a = *s1; b = *s2; if ((a >= 'a') && (a <= 'z')) a -= CASE_DIFFERENCE; if ((b >= 'a') && (b <= 'z')) b -= CASE_DIFFERENCE; if (a < b) return -1; if (a > b) return 1; s1++; s2++; } return 0; } int columns(char **items) { int maxlength = 0, current = 0, count = 0; int length, columns, i, j; int percolumn; float per; if (items[0] == NULL) return 0; for (i = 0; items[i] != NULL; i++) { length = strlen(items[i]); if (length > maxlength) maxlength = length; count++; } maxlength += 1; columns = 79 / maxlength; if (columns == 0) columns = 1; percolumn = (int) (per = (float) count / (float) columns); if (per > percolumn) percolumn++; for (i = 0; i < percolumn; i++) { for (j = 0; j < columns; j++) { current = i + (j * percolumn); if (current < count) iprintf("%-*s", maxlength, items[current]); } iprint("\n"); } return count; } bool isnumeric(const char *str) { bool gotone = false; while (*str != '\0') { if ((*str < '0') || (*str > '9')) return false; gotone = true; str++; } return gotone; } /* For sorting an array of (char *) */ int s_strcmp(const void *a, const void *b) { return strcmp(*((const char **) a), *((const char **) b)); } /* Same, for case insensitive sort. */ int s_istrcmp(const void *a, const void *b) { return istrcmp(*((const char **) a), *((const char **) b)); } i64_t gettimeofdayll() { struct timeval tv; gettimeofday(&tv, NULL); return tv2ll(tv); } i64_t timeleft(Table *t, int color) { if (t->clock[color] == 0) return 0; if (t->clock[color] < 0) return -t->clock[color]; return t->clock[color] - gettimeofdayll(); } char *fmttime_ms(i64_t time) { static char buf[32]; if (variables[VAR_MS].number) snprintf(buf, sizeof(buf), "%d:%02d.%03d", (int)(time / 60000), (int)((time / 1000) % 60), (int)(time % 1000)); else snprintf(buf, sizeof(buf), "%d:%02d", (int)(time / 60000), (int)((time / 1000) % 60)); return buf; } #if !defined (__GNUC__) int optind = 0; static char * nextchar = NULL; char * optarg = NULL; int getopt (int argc, char * argv[], const char * optstr) { int j; if (optind >= argc) return -1; if (nextchar == NULL || nextchar[0] == '\0') { optind++; if (optind >= argc) return -1; if (argv[optind][0] != '-' || argv[optind][1] == '\0') return -1; if (argv[optind][1] == '-' && argv[optind][2] == '\0') return -1; nextchar = argv[optind] + 1; } for (j=0; optstr[j] != '\0'; j++) { if (optstr[j] == ':') continue; if (nextchar[0] == optstr[j]) { nextchar++; if (optstr[j+1] == ':') { /* :: is currently not supported */ if (nextchar[0] != '\0') optarg = nextchar; else if (optind == argc) /* Is this correct? */ optarg = ""; else { optind++; optarg = argv[optind]; } nextchar = NULL; } return optstr[j]; } } return -1; } #endif #ifndef _YICS_POSIX int gettimeofday(struct timeval * p, void * z) { struct _timeb timebuf; if (p == NULL) return -__LINE__; z = z; _ftime(&timebuf); p->tv_sec = timebuf.time; p->tv_usec = timebuf.millitm; return 0; } #endif #define bswap_64(x) ((unsigned i64_t)(htonl((unsigned long)(x))) << 32) | \ ((unsigned i64_t)(htonl((unsigned long)(((unsigned i64_t)(x)) >> 32)))) enum endian { ES_UNKNOWN = 0, ES_LE, ES_BE }; static enum endian es = ES_UNKNOWN; #define testEndianSwap() ((htons(1) == 1) ? ES_BE : ES_LE) unsigned i64_t htonll(unsigned i64_t v) { if (es == ES_UNKNOWN) es = testEndianSwap(); if (es == ES_LE) return bswap_64(v); return v; } yics-0.1.2/ytoics-c/util.h0000644000175000001440000000516310260627233015636 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _UTIL_H #define _UTIL_H #include "types.h" extern unsigned i64_t htonll(unsigned i64_t); #define ntohll(x) htonll(x) #define phandle(x) (((x) == NULL) ? "[EMPTY]" : (x)->handle) /* * strncpy doesn't null-terminate the string if it's too big. This is, IMHO, * stupid. This macro makes up for it. */ #define mstrncpy(dest,src,n) (strncpy((dest), (src), (n) - 1) \ + (0 & (((n) == 0) ? 0 : (dest[(n) - 1] = '\0')))) /* * strncat takes the n parameter to mean the number of bytes to be written, * not the size of the string. This is, IMHO, also stupid. * * Here, n specifies the size of dest. */ #define mstrncat(dest,src,n) strncat((dest), (src), (n) - strlen(dest) - 1) extern char *ltrim(char *); extern char *rtrim(char *); #define trim(x) rtrim(ltrim(x)) extern String *ltrimString(String *); extern String *rtrimString(String *); #define trimString(x) rtrimString(ltrimString(x)) extern char *packutf(char *, const char *, unsigned short); extern String *packutfString(String *, const String *); extern String *packutfStringP(String *, const String *); extern char *unpackutf(char *, const char *); extern String *unpackutfString(String *, const String *); extern String *unpackutfStringP(String *, String *); extern char *uppercase(char *); extern char *lowercase(char *); extern int istrcmp(const char *, const char *); extern int columns(char **); extern bool isnumeric(const char *); extern int s_strcmp(const void *, const void *); extern int s_istrcmp(const void *, const void *); extern i64_t gettimeofdayll(void); extern i64_t timeleft(Table *, int); extern char *fmttime_ms(i64_t); #ifndef _YICS_POSIX extern int gettimeofday(struct timeval * p, void * z); #endif #ifndef __GNUC__ extern char * optarg; extern int optind; extern int getopt (int argc, char * argv[], const char * optstr); #endif #endif yics-0.1.2/ytoics-c/vars.c0000644000175000001440000002604010260627233015624 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include #include #include #include "types.h" #include "vars.h" #include "sockets.h" #include "console.h" #include "network.h" #include "ropcodes.h" #include "topcodes.h" #include "util.h" #include "command.h" #include "globals.h" #include "style.h" #include "formula.h" bool var_formula(Variable *, void *); bool var_interface(Variable *, void *); bool var_style(Variable *, void *); bool var_tolerance(Variable *, void *); bool tvar_timeinc(Variable *, void *); void varset_autostart(Variable *); void varset_ivar(Variable *); void varset_lock(Variable *); void varset_notimeout(Variable *); void varset_open(Variable *); void varset_pin(Variable *); void varset_ptime(Variable *); void varset_seek(Variable *); void varset_shout(Variable *); void varset_singleboard(Variable *); void varset_style(Variable *); void varset_timeinc(Variable *); void varset_tolerance(Variable *); void varset_formula(Variable *); void tvarset_timeinc(Variable *); void tvarset_rated(Variable *); void tvarset_protection(Variable *); Variable variables[] = { /* name validator post-set type locks string number */ {"autostart", NULL, varset_autostart, VAR_BOOLEAN, false, NULL, 0}, {"inc", tvar_timeinc, varset_timeinc, VAR_NUMERIC, false, NULL, 0}, {"lock", NULL, varset_lock, VAR_BOOLEAN, true, NULL, 0}, {"ms", NULL, varset_ivar, VAR_BOOLEAN, true, NULL, 0}, {"notimeout", NULL, varset_notimeout, VAR_BOOLEAN, false, NULL, 0}, {"open", NULL, varset_open, VAR_BOOLEAN, false, NULL, 1}, {"pin", NULL, varset_pin, VAR_BOOLEAN, false, NULL, 0}, {"ptime", NULL, varset_ptime, VAR_BOOLEAN, false, NULL, 0}, {"rated", NULL, varset_timeinc, VAR_BOOLEAN, false, NULL, 1}, {"seek", NULL, varset_seek, VAR_BOOLEAN, false, NULL, 0}, {"shout", NULL, varset_shout, VAR_BOOLEAN, false, NULL, 1}, {"singleboard", NULL, varset_singleboard, VAR_BOOLEAN,true, NULL, 1}, {"style", var_style, varset_style, VAR_NUMERIC, false, NULL, 12}, {"time", tvar_timeinc, varset_timeinc, VAR_NUMERIC, false, NULL, 5}, {"tolerance", var_tolerance, varset_tolerance, VAR_NUMERIC, false, NULL, 2}, {"interface", var_interface, varset_lock, VAR_STRING, true, NULL, 0}, {"formula", validateFormula,varset_formula, VAR_STRING, false, NULL, 0}, {"f1", validateFormula,varset_formula, VAR_STRING, false, NULL, 1}, {"f2", validateFormula,varset_formula, VAR_STRING, false, NULL, 2}, {"f3", validateFormula,varset_formula, VAR_STRING, false, NULL, 3}, {"f4", validateFormula,varset_formula, VAR_STRING, false, NULL, 4}, {"f5", validateFormula,varset_formula, VAR_STRING, false, NULL, 5}, {"f6", validateFormula,varset_formula, VAR_STRING, false, NULL, 6}, {"f7", validateFormula,varset_formula, VAR_STRING, false, NULL, 7}, {"f8", validateFormula,varset_formula, VAR_STRING, false, NULL, 8}, {"f9", validateFormula,varset_formula, VAR_STRING, false, NULL, 9}, {"", NULL, NULL, VAR_END, false, NULL, 0}, }; Variable tvariables[] = { /* name validator post-set type locks string number */ {"increment", tvar_timeinc, tvarset_timeinc,VAR_NUMERIC, false, NULL, 0}, {"rated", NULL, tvarset_rated, VAR_BOOLEAN, false, NULL, 0}, {"protection", var_tolerance, tvarset_protection, VAR_NUMERIC,false, NULL, 0}, {"tenminlimit", NULL, tvarset_timeinc,VAR_BOOLEAN, false, NULL, 0}, {"time", tvar_timeinc, tvarset_timeinc,VAR_NUMERIC, false, NULL, 0}, {"", NULL, NULL, VAR_END, false, NULL, 0}, }; static bool locked = false; #if 0 int getvari(Variable *srch, const char *name) { while (srch->type != VAR_END) { if (!strcmp(name, srch->name)) return srch->number; srch++; } return 0; } String *getvars(Variable *srch, const char *name) { while (srch->type != VAR_END) { if (!strcmp(name, srch->name)) return srch->string; srch++; } return NULL; } #endif int setvar(Variable *srch, const char *name, const char *setting, Variable **out) { String *var, *new = NULL; Variable *match = NULL; int len, num = -1, result = VARSET_OK; bool youlose = false; if (setting != NULL) new = StringNew(setting, -1); if (out != NULL) *out = NULL; var = StringNew(name, -1); lowercase(var->string); len = var->length; for (; srch->type != VAR_END; srch++) { if (!strcmp(var->string, srch->name)) { match = srch; break; } else if ((len <= (int)strlen(srch->name)) && !memcmp(srch->name, var->string, len)) { if (match == NULL) { match = srch; } else { result = VARSET_AMBIGUOUS; goto VARSET_END; } } } if (match == NULL) { result = VARSET_NOTFOUND; goto VARSET_END; } if (out != NULL) *out = match; if (locked && match->locks) { result = VARSET_LOCKED; goto VARSET_END; } switch ((int)match->type) { case VAR_BOOLEAN: if (new == NULL) { num = !match->number; } else if ( !strcmp(new->string, "1") || !strcmp(new->string, "y") || !strcmp(new->string, "yes") || !strcmp(new->string, "on")) { num = 1; } else if ( !strcmp(new->string, "0") || !strcmp(new->string, "n") || !strcmp(new->string, "no") || !strcmp(new->string, "off")) { num = 0; } else { youlose = true; } break; case VAR_NUMERIC: if ((new != NULL) && isnumeric(new->string)) { num = atoi(new->string); youlose = (bool)!match->validator(match, (void *)&num); } else { youlose = true; } break; case VAR_STRING: if (new == NULL) new = StringNull(); youlose = (bool)!match->validator(match, (void *)new->string); } if (youlose) { result = VARSET_BAD; goto VARSET_END; } switch ((int)match->type) { case VAR_BOOLEAN: case VAR_NUMERIC: match->number = num; break; case VAR_STRING: if (match->string != NULL) StringCopy(match->string, new); else match->string = StringCopy(StringNull(), new); } if (match->postset != NULL) { match->postset(match); } else { if (match->type == VAR_STRING) iprintf("Variable %s set to %s.\n", match->name, new->string); else iprintf("Variable %s set to %d.\n", match->name, num); prompt(); } /* * I know goto is ugly, but it's got to be WAY more maintainable than * triplicating clean-up code. */ VARSET_END: if (new != NULL) StringFree(new); StringFree(var); return result; } #define intp(x) (*((int *)(x))) bool var_interface(Variable *var, void *new) { trim((char *)new); return true; } bool var_style(Variable *var, void *new) { return (bool)(getstyle(intp(new)) != NULL); } bool var_tolerance(Variable *var, void *new) { return (bool)(intp(new) <= 2); } bool tvar_timeinc(Variable *var, void *new) { return (bool)(intp(new) <= 999); } #undef intp void varset_autostart(Variable *var) { iprintf("Games will no%c start automatically.\n", var->number ? 'w' : 't'); prompt(); } void varset_formula(Variable *var) { char *isset = ((var->string != NULL) && (var->string->string[0] != '\0')) ? "" : "un"; if (var->number == 0) iprintf("Formula %sset.\n", isset); else iprintf("Formula variable %s %sset.\n", var->name, isset); prompt(); } void varset_ivar(Variable *var) { iprintf("%s %sset.\n", var->name, (var->number || var->string) ? "" : "un"); prompt(); } void varset_lock(Variable *var) { varset_ivar(var); locked = (bool)(var->number ? true : false); } void varset_notimeout(Variable *var) { iprintf("Timeout disconnection will no%c be prevented.\n", var->number ? 'w' : 't'); prompt(); } void varset_open(Variable *var) { char packet; String *decline[2]; if (!var->number) { prompting = 0; /* Prevent prompt flooding. */ decline[1] = StringNew("I am going closed for invitations.", -1); while (invitations != NULL) { decline[0] = StringNew(invitations->who->lhandle, -1); com_decline(decline, 2); StringFree(decline[0]); } StringFree(decline[1]); prompting = 1; } iprintf("You are %s match requests.\n", var->number ? "now open to receive" : "no longer receiving"); prompt(); packet = (char)(var->number ? 0 : 1); nprintrop(ROP_OPEN, &packet, 1); } void varset_ptime(Variable *var) { iprintf("Your prompt will now%s show the time.\n", var->number ? "" : " not"); prompt(); } void varset_pin(Variable *var) { iprintf("You will no%c hear hear logins/logouts.\n", var->number ? 'w' : 't'); prompt(); } void varset_seek(Variable *var) { iprintf("You will no%c see seek ads.\n", var->number ? 'w' : 't'); prompt(); } void varset_shout(Variable *var) { iprintf("You will %s hear shouts.\n", var->number ? "now" : "no longer"); prompt(); } void varset_singleboard(Variable *var) { iprintf("singleboard %sset.\n", var->number ? "" : "un"); prompt(); } void varset_timeinc(Variable *var) { iprintf("Default %s set to %d.\n", (var->name[0] == 't') ? "time" : (var->name[0] == 'i') ? "increment" : "rated status", var->number); prompt(); } void varset_style(Variable *var) { iprintf("Style %d set.\n", var->number); prompt(); } void varset_tolerance(Variable *var) { char tmp[16]; String *packet, *n; iprintf("Profanity filter set to %s.\n", (var->number == 0) ? "strong" : (var->number == 1) ? "weak" : "none"); packet = StringNew("games_common_profanity", -1); packutfString(packet, packet); sprintf(tmp, "%d", 2 - var->number); n = StringNew(tmp, -1); packutfStringP(packet, n); nprintropString(ROP_OPTION, packet); StringFree(packet); StringFree(n); } void tvarset_timeinc(Variable *var) { Table *table = tables[primary]; int time = 0, inc = 0; char limit = 0; char packet[9]; if (!strcmp(var->name, "time")) { time = var->number * 60000; inc = tableinc(table) * 1000; if (findOption(table->options, "pl") == NULL) limit = 1; } else if (!strcmp(var->name, "increment")) { time = tabletime(table) * 60000; inc = var->number * 1000; if (findOption(table->options, "pl") == NULL) limit = 1; } else { time = tabletime(table) * 60000; inc = tableinc(table) * 1000; if (var->number) limit = 1; } if (time == 0) { time = -1; inc = 0; } packet[0] = limit; time = htonl(time); memcpy(&packet[1], &time, 4); inc = htonl(inc); memcpy(&packet[5], &inc, 4); nprinttop((uchar)primary, (char)TOP_TIME, packet, sizeof(packet)); } void tvarset_rated(Variable *var) { char setting = (char)(var->number ? 1 : 0); nprinttop((uchar)primary, (char)TOP_RATED, &setting, 1); } void tvarset_protection(Variable *var) { char setting = (char)var->number; nprinttop((uchar)primary, (char)TOP_PROTECTION, &setting, 1); } yics-0.1.2/ytoics-c/vars.h0000644000175000001440000000276410260627233015640 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _VARS_H #define _VARS_H #include "types.h" extern Variable variables[]; extern Variable tvariables[]; #if 0 extern int getvari(Variable *, const char *); extern String *getvars(Variable *, const char *); #endif enum { VARSET_OK = 0, VARSET_NOTFOUND, VARSET_AMBIGUOUS, VARSET_BAD, VARSET_LOCKED }; enum { VAR_AUTOSTART = 0, VAR_INC, VAR_LOCK, VAR_MS, VAR_NOTIMEOUT, VAR_OPEN, VAR_PIN, VAR_PTIME, VAR_RATED, VAR_SEEK, VAR_SHOUT, VAR_SINGLEBOARD, VAR_STYLE, VAR_TIME, VAR_TOLERANCE, VAR_INTERFACE, VAR_FORMULA, VAR_F1, VAR_F2, VAR_F3, VAR_F4, VAR_F5, VAR_F6, VAR_F7, VAR_F8, VAR_F9 }; extern int setvar(Variable *, const char *, const char *, Variable **); #endif yics-0.1.2/ytoics-c/version.c0000644000175000001440000000331210260633142016327 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #include "version.h" #include "vars.h" char VERSION[] = "0.1.2"; String *getIdent(String *str) { String *iface = variables[VAR_INTERFACE].string; StringSet(str, "Using YICS ", -1); StringCat(str, VERSION, -1); #if (defined (linux) || defined (__linux) || defined (__linux__)) # define VERSION_OSNAME "Linux" #elif (defined (unix) || defined (__unix) || defined (__unix__)) # define VERSION_OSNAME "Unix" #elif (defined (WINNT) || defined (__WINNT) || defined (__WINNT__) || defined (_WIN32) || defined (_WINDOWS)) # define VERSION_OSNAME "Windows" #else # define VERSION_OSNAME "" #endif #ifdef VERSION_OSNAME StringCat(str, " on " VERSION_OSNAME, -1); # undef VERSION_OSNAME #endif if ((iface != NULL) && (iface->length > 0)) { StringCat(str, " (with ", -1); StringCat(str, iface->string, iface->length); StringCat(str, ")", -1); } StringCat(str, ". http://www.yics.org", -1); return str; } yics-0.1.2/ytoics-c/version.h0000644000175000001440000000166510060753542016352 0ustar chrisusers00000000000000/* * YICS: Connect a FICS interface to the Yahoo! Chess server. * Copyright (C) 2004 Chris Howie * * 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. */ #ifndef _VERSION_H #define _VERSION_H #include "types.h" extern char VERSION[]; extern String *getIdent(String *); #endif