ArchBlackmann irc bot - works in ReactOS - happy hacking
authorRoyce Mitchell III <royce3@ev1.net>
Wed, 22 Dec 2004 18:25:29 +0000 (18:25 +0000)
committerRoyce Mitchell III <royce3@ev1.net>
Wed, 22 Dec 2004 18:25:29 +0000 (18:25 +0000)
svn path=/trunk/; revision=12289

31 files changed:
rosapps/games/ArchBlackmann/.cvsignore [new file with mode: 0644]
rosapps/games/ArchBlackmann/ArchBlackmann.cpp [new file with mode: 0644]
rosapps/games/ArchBlackmann/ArchBlackmann.dsp [new file with mode: 0644]
rosapps/games/ArchBlackmann/ArchBlackmann.dsw [new file with mode: 0644]
rosapps/games/ArchBlackmann/IRCClient.cpp [new file with mode: 0644]
rosapps/games/ArchBlackmann/IRCClient.h [new file with mode: 0644]
rosapps/games/ArchBlackmann/MD5.cpp [new file with mode: 0644]
rosapps/games/ArchBlackmann/MD5.h [new file with mode: 0644]
rosapps/games/ArchBlackmann/QueueT.h [new file with mode: 0644]
rosapps/games/ArchBlackmann/Reli.h [new file with mode: 0644]
rosapps/games/ArchBlackmann/ReliMT.cpp [new file with mode: 0644]
rosapps/games/ArchBlackmann/ReliMT.h [new file with mode: 0644]
rosapps/games/ArchBlackmann/SockUtils.cpp [new file with mode: 0644]
rosapps/games/ArchBlackmann/SockUtils.h [new file with mode: 0644]
rosapps/games/ArchBlackmann/SplitJoin.cpp [new file with mode: 0644]
rosapps/games/ArchBlackmann/SplitJoin.h [new file with mode: 0644]
rosapps/games/ArchBlackmann/ThreadPool.cpp [new file with mode: 0644]
rosapps/games/ArchBlackmann/ThreadPool.h [new file with mode: 0644]
rosapps/games/ArchBlackmann/auto_ptr.h [new file with mode: 0644]
rosapps/games/ArchBlackmann/auto_vector.h [new file with mode: 0644]
rosapps/games/ArchBlackmann/base64.cpp [new file with mode: 0644]
rosapps/games/ArchBlackmann/base64.h [new file with mode: 0644]
rosapps/games/ArchBlackmann/chomp.cpp [new file with mode: 0644]
rosapps/games/ArchBlackmann/chomp.h [new file with mode: 0644]
rosapps/games/ArchBlackmann/cram_md5.cpp [new file with mode: 0644]
rosapps/games/ArchBlackmann/cram_md5.h [new file with mode: 0644]
rosapps/games/ArchBlackmann/panic.cpp [new file with mode: 0644]
rosapps/games/ArchBlackmann/panic.h [new file with mode: 0644]
rosapps/games/ArchBlackmann/trim.cpp [new file with mode: 0644]
rosapps/games/ArchBlackmann/trim.h [new file with mode: 0644]
rosapps/games/ArchBlackmann/verify.h [new file with mode: 0644]

diff --git a/rosapps/games/ArchBlackmann/.cvsignore b/rosapps/games/ArchBlackmann/.cvsignore
new file mode 100644 (file)
index 0000000..c6f3c2c
--- /dev/null
@@ -0,0 +1,5 @@
+*.ncb
+*.opt
+*.plg
+Debug
+Release
\ No newline at end of file
diff --git a/rosapps/games/ArchBlackmann/ArchBlackmann.cpp b/rosapps/games/ArchBlackmann/ArchBlackmann.cpp
new file mode 100644 (file)
index 0000000..905af5e
--- /dev/null
@@ -0,0 +1,123 @@
+// irc_test.cpp
+
+#ifdef _MSC_VER
+#pragma warning ( disable : 4786 )
+#endif//_MSC_VER
+
+#include <conio.h>
+#include <stdio.h>
+
+#include "IRCClient.h"
+
+using std::string;
+using std::vector;
+
+// do custom stuff with the IRCClient from your subclass via the provided callbacks...
+class MyIRCClient : public IRCClient
+{
+public:
+       // see IRCClient.h for documentation on these callbacks...
+       bool OnConnected()
+       {
+               return true;
+       }
+       bool OnJoin ( const string& user, const string& channel )
+       {
+               return true;
+       }
+       bool OnEndChannelUsers ( const string& channel )
+       {
+               return true;
+       }
+       bool OnPrivMsg ( const string& from, const string& text )
+       {
+               printf ( "<%s> %s\n", from.c_str(), text.c_str() );
+               return true;
+       }
+       bool OnChannelMsg ( const string& channel, const string& from, const string& text )
+       {
+               printf ( "%s <%s> %s\n", channel.c_str(), from.c_str(), text.c_str() );
+               if ( !stricmp ( from.c_str(), "royce3" ) )
+                       PrivMsg ( channel, text );
+               return true;
+       }
+       bool OnChannelMode ( const string& channel, const string& mode )
+       {
+               //printf ( "OnChannelMode(%s,%s)\n", channel.c_str(), mode.c_str() );
+               return true;
+       }
+       bool OnUserModeInChannel ( const string& src, const string& channel, const string& user, const string& mode )
+       {
+               //printf ( "OnUserModeInChannel(%s,%s%s,%s)\n", src.c_str(), channel.c_str(), user.c_str(), mode.c_str() );
+               return true;
+       }
+       bool OnMode ( const string& user, const string& mode )
+       {
+               //printf ( "OnMode(%s,%s)\n", user.c_str(), mode.c_str() );
+               return true;
+       }
+       bool OnChannelUsers ( const string& channel, const vector<string>& users )
+       {
+               printf ( "[%s has %i users]: ", channel.c_str(), users.size() );
+               for ( int i = 0; i < users.size(); i++ )
+               {
+                       if ( i )
+                               printf ( ", " );
+                       printf ( "%s", users[i].c_str() );
+               }
+               printf ( "\n" );
+               return true;
+       }
+};
+
+int main ( int argc, char** argv )
+{
+       printf ( "initializing IRCClient debugging\n" );
+       IRCClient::SetDebug ( true );
+       printf ( "calling suStartup()\n" );
+       suStartup();
+       printf ( "creating IRCClient object\n" );
+       MyIRCClient irc;
+       printf ( "connecting to freenode\n" );
+       if ( !irc.Connect ( "140.211.166.3" ) ) // irc.freenode.net
+       {
+               printf ( "couldn't connect to server\n" );
+               return -1;
+       }
+       printf ( "sending user command\n" );
+       if ( !irc.User ( "Royce3", "", "irc.freenode.net", "Royce Mitchell III" ) )
+       {
+               printf ( "USER command failed\n" );
+               return -1;
+       }
+       printf ( "sending nick\n" );
+       if ( !irc.Nick ( "Royce3" ) )
+       {
+               printf ( "NICK command failed\n" );
+               return -1;
+       }
+       printf ( "setting mode\n" );
+       if ( !irc.Mode ( "+i" ) )
+       {
+               printf ( "MODE command failed\n" );
+               return -1;
+       }
+       printf ( "joining #ReactOS\n" );
+       if ( !irc.Join ( "#ReactOS" ) )
+       {
+               printf ( "JOIN command failed\n" );
+               return -1;
+       }
+       printf ( "entering irc client processor\n" );
+       irc.Run ( true ); // do the processing in this thread...
+       string cmd;
+       for ( ;; )
+       {
+               char c = getch();
+               if ( c == '\n' || c == '\r' )
+               {
+
+               }
+       }
+       return 0;
+}
diff --git a/rosapps/games/ArchBlackmann/ArchBlackmann.dsp b/rosapps/games/ArchBlackmann/ArchBlackmann.dsp
new file mode 100644 (file)
index 0000000..9b95918
--- /dev/null
@@ -0,0 +1,196 @@
+# Microsoft Developer Studio Project File - Name="ArchBlackmann" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=ArchBlackmann - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "ArchBlackmann.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "ArchBlackmann.mak" CFG="ArchBlackmann - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "ArchBlackmann - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "ArchBlackmann - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "ArchBlackmann - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "ArchBlackmann - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "ArchBlackmann - Win32 Release"
+# Name "ArchBlackmann - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\ArchBlackmann.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\auto_ptr.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\auto_vector.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\base64.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\base64.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\chomp.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\chomp.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\cram_md5.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\cram_md5.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\IRCClient.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\IRCClient.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MD5.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\MD5.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\panic.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\panic.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\QueueT.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Reli.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ReliMT.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ReliMT.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SockUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\SockUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SplitJoin.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\SplitJoin.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ThreadPool.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ThreadPool.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\trim.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\trim.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\verify.h
+# End Source File
+# End Target
+# End Project
diff --git a/rosapps/games/ArchBlackmann/ArchBlackmann.dsw b/rosapps/games/ArchBlackmann/ArchBlackmann.dsw
new file mode 100644 (file)
index 0000000..d8c4784
--- /dev/null
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "ArchBlackmann"=.\ArchBlackmann.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/rosapps/games/ArchBlackmann/IRCClient.cpp b/rosapps/games/ArchBlackmann/IRCClient.cpp
new file mode 100644 (file)
index 0000000..7ad9787
--- /dev/null
@@ -0,0 +1,322 @@
+// IRCClient.cpp
+// This file is (C) 2004 Royce Mitchell III
+// and released under the BSD & LGPL licenses
+
+#ifdef _MSC_VER
+#pragma warning ( disable : 4786 )
+#endif//_MSC_VER
+
+#include <vector>
+#include <sstream>
+
+#include "IRCClient.h"
+#include "md5.h"
+#include "cram_md5.h"
+#include "trim.h"
+#include "chomp.h"
+#include "SplitJoin.h"
+#include "base64.h"
+
+using std::string;
+using std::stringstream;
+using std::vector;
+
+bool IRCClient::_debug = true;
+
+IRCClient::IRCClient()
+       : _timeout(10*60*1000), _inRun(false)
+{
+}
+
+bool IRCClient::Connect ( const string& server, short port )
+{
+       string buf;
+       Close();
+       Attach ( suTcpSocket() );
+       if ( !suConnect ( *this, server.c_str(), port ) )
+               return false;
+       return true;
+}
+
+bool
+IRCClient::User ( const string& user, const string& mode,
+       const string& network, const string& realname )
+{
+       string buf;
+       buf = "USER " + user + " \"" + mode + "\" \"" + network + "\" :" + realname + "\n";
+       return Send ( buf );
+}
+
+bool
+IRCClient::Nick ( const string& nick )
+{
+       _nick = nick;
+       return Send ( "NICK " + _nick + "\n" );
+}
+
+bool
+IRCClient::Mode ( const string& mode )
+{
+       return Send ( "MODE " + _nick + " " + mode + "\n" );
+}
+
+bool
+IRCClient::Names ( const string& channel )
+{
+       return Send ( "NAMES " + channel + "\n" );
+}
+
+bool
+IRCClient::Mode ( const string& channel, const string& mode, const string& target )
+{
+       return Send ( "MODE " + channel + " " + mode + " " + target + "\n" );
+}
+
+bool
+IRCClient::Join ( const string& channel )
+{
+       return Send ( "JOIN " + channel + "\n" );
+}
+
+bool
+IRCClient::PrivMsg ( const string& to, const string& text )
+{
+       return Send ( "PRIVMSG " + to + " :" + text + "\n" );
+}
+
+bool
+IRCClient::Part ( const string& channel, const string& text )
+{
+       return Send ( "PART " + channel + " :" + text + "\n" );
+}
+
+bool
+IRCClient::Quit ( const string& text )
+{
+       return Send( "QUIT :" + text + "\n");
+}
+
+bool IRCClient::_Recv ( string& buf )
+{
+       bool b = (recvUntil ( buf, '\n', _timeout ) > 0);
+       if ( b && _debug )
+       {
+               printf ( ">> %s", buf.c_str() );
+               if ( buf[buf.length()-1] != '\n' )
+                       printf ( "\n" );
+       }
+       return b;
+}
+
+bool IRCClient::Send ( const string& buf )
+{
+       if ( _debug )
+       {
+               printf ( "<< %s", buf.c_str() );
+               if ( buf[buf.length()-1] != '\n' )
+                       printf ( "\n" );
+       }
+       return ( buf.length() == (size_t)send ( *this, buf.c_str(), buf.length(), 0 ) );
+}
+
+bool IRCClient::OnPing( const string& text )
+{
+       return Send( "PONG " + text + "\n" );
+}
+
+
+int THREADAPI IRCClient::Callback ( IRCClient* irc )
+{
+       return irc->Run ( false );
+}
+
+int IRCClient::Run ( bool launch_thread )
+{
+       if ( (SOCKET)*this == INVALID_SOCKET )
+               return 0;
+       if ( _inRun ) return 1;
+       if ( launch_thread )
+       {
+               ThreadPool::Instance().Launch ( (ThreadPoolFunc*)IRCClient::Callback, this );
+               return 1;
+       }
+       _inRun = true;
+       if ( _debug ) printf ( "IRCClient::Run() - waiting for responses\n" );
+       string buf;
+       while ( _Recv(buf) )
+       {
+               if ( !strnicmp ( buf.c_str(), "NOTICE ", 7 ) )
+               {
+                       //printf ( "recv'd NOTICE msg...\n" );
+                       // TODO...
+                       //OnAuth ( 
+               }
+               else if ( !strnicmp ( buf.c_str(), "PING ", 5 ) )
+               {
+                       const char* p = &buf[5]; // point to first char after "PING "
+                       while ( *p == ':' )      // then read past the colons
+                               p++;
+                       const char* p2 = strpbrk ( p, "\r\n" ); // find the end of line
+                       string text ( p, p2-p );                // and set the text
+                       OnPing( text );
+               }
+               else if ( buf[0] == ':' )
+               {
+                       const char* p = &buf[1]; // skip first colon...
+                       const char* p2 = strpbrk ( p, " !" );
+                       if ( !p2 )
+                       {
+                               printf ( "!!!:OnRecv failure 0: ", buf.c_str() );
+                               continue;
+                       }
+                       string src ( p, p2-p );
+                       if ( !src.length() )
+                       {
+                               printf ( "!!!:OnRecv failure 0.5: %s", buf.c_str() );
+                               continue;
+                       }
+                       p = p2 + 1;
+                       if ( *p2 == '!' )
+                       {
+                               p2 = strchr ( p, ' ' );
+                               if ( !p2 )
+                               {
+                                       printf ( "!!!:OnRecv failure 1: %s", buf.c_str() );
+                                       continue;
+                               }
+                               //string srchost ( p, p2-p );
+                               p = p2 + 1;
+                       }
+                       p2 = strchr ( p, ' ' );
+                       if ( !p2 )
+                       {
+                               printf ( "!!!:OnRecv failure 2: %s", buf.c_str() );
+                               continue;
+                       }
+                       string cmd ( p, p2-p );
+                       p = p2 + 1;
+                       p2 = strpbrk ( p, " :" );
+                       if ( !p2 )
+                       {
+                               printf ( "!!!:OnRecv failure 3: %s", buf.c_str() );
+                               continue;
+                       }
+                       string tgt ( p, p2-p );
+                       p = p2 + 1;
+                       p += strspn ( p, " " );
+                       if ( *p == '=' )
+                       {
+                               p++;
+                               p += strspn ( p, " " );
+                       }
+                       if ( *p == ':' )
+                               p++;
+                       p2 = strpbrk ( p, "\r\n" );
+                       if ( !p2 )
+                       {
+                               printf ( "!!!:OnRecv failure 4: %s", buf.c_str() );
+                               continue;
+                       }
+                       string text ( p, p2-p );
+                       strlwr ( &cmd[0] );
+                       if ( cmd == "privmsg" )
+                       {
+                               if ( !tgt.length() )
+                               {
+                                       printf ( "!!!:OnRecv failure 5 (PRIVMSG w/o target): %s", buf.c_str() );
+                                       continue;
+                               }
+                               if ( tgt[0] == '#' )
+                                       OnChannelMsg ( tgt, src, text );
+                               else
+                                       OnPrivMsg ( src, text );
+                       }
+                       else if ( cmd == "mode" )
+                       {
+                               // two diff. kinds of mode notifications...
+                               //printf ( "[MODE] src='%s' cmd='%s' tgt='%s' text='%s'", src.c_str(), cmd.c_str(), tgt.c_str(), text.c_str() );
+                               //OnMode ( 
+                               // self mode change:
+                               // [MODE] src=Relic3_14 cmd=mode tgt=Relic3_14  text=+i
+                               // channel mode change:
+                               // [MODE] src=Royce3 cmd=mode tgt=#Royce3 text=+o Relic3_14
+                               if ( tgt[0] == '#' )
+                               {
+                                       p = text.c_str();
+                                       p2 = strchr ( p, ' ' );
+                                       if ( !p2 )
+                                               OnChannelMode ( tgt, text );
+                                       else
+                                       {
+                                               string user ( p, p2-p );
+                                               p = p2 + 1;
+                                               p += strspn ( p, " " );
+                                               OnUserModeInChannel ( src, tgt, user, p );
+                                       }
+                               }
+                               else
+                                       OnMode ( tgt, text );
+                       }
+                       else if ( cmd == "join" )
+                       {
+                               OnJoin ( src, text );
+                       }
+                       else if ( isdigit(cmd[0]) )
+                       {
+                               int i = atoi(cmd.c_str());
+                               switch ( i )
+                               {
+                               case 1: // "Welcome!" - i.e. it's okay to issue commands now...
+                                       OnConnected();
+                                       break;
+                               case 353: // user list for channel....
+                                       {
+                                               p = text.c_str();
+                                               p2 = strpbrk ( p, " :" );
+                                               if ( !p2 ) continue;
+                                               string channel ( p, p2-p );
+                                               p = strchr ( p2, ':' );
+                                               if ( !p ) continue;
+                                               p++;
+                                               vector<string> users;
+                                               while ( *p )
+                                               {
+                                                       p2 = strchr ( p, ' ' );
+                                                       if ( !p2 )
+                                                               p2 = p + strlen(p);
+                                                       users.push_back ( string ( p, p2-p ) );
+                                                       p = p2+1;
+                                                       p += strspn ( p, " " );
+                                               }
+                                               OnChannelUsers ( channel, users );
+                                       }
+                                       break;
+                               case 366: // END of user list for channel
+                                       {
+                                               p = text.c_str();
+                                               p2 = strpbrk ( p, " :" );
+                                               if ( !p2 ) continue;
+                                               string channel ( p, p2-p );
+                                               OnEndChannelUsers ( channel );
+                                       }
+                                       break;
+                               default:
+                                       if ( _debug ) printf ( "unknown command %i: %s", i, buf.c_str() );
+                                       break;
+                               }
+                       }
+                       else
+                       {
+                               if ( _debug ) printf ( "unrecognized ':' response: %s", buf.c_str() );
+                       }
+               }
+               else
+               {
+                       if ( _debug ) printf ( "unrecognized irc msg: %s", buf.c_str() );
+               }
+               //OnRecv ( buf );
+       }
+       if ( _debug ) printf ( "IRCClient::Run() - exiting\n" );
+       _inRun = false;
+       return 0;
+}
diff --git a/rosapps/games/ArchBlackmann/IRCClient.h b/rosapps/games/ArchBlackmann/IRCClient.h
new file mode 100644 (file)
index 0000000..6f8f360
--- /dev/null
@@ -0,0 +1,124 @@
+// IRCClient.h
+// This file is (C) 2004 Royce Mitchell III
+// and released under the BSD & LGPL licenses
+
+#ifndef IRCCLIENT_H
+#define IRCCLIENT_H
+
+#include <string>
+#include <vector>
+#include "SockUtils.h"
+#include "ThreadPool.h"
+
+class IRCClient : public suBufferedRecvSocket
+{
+public:
+       IRCClient();
+
+       static bool GetDebug() { return _debug; }
+       static bool SetDebug ( bool debug ) { bool old = _debug; _debug = debug; return old; }
+
+       // connect to server ( record greeting for apop if it exists )
+       bool Connect ( const std::string& server, short port = 6667 );
+
+       bool Running() { return _inRun; }
+
+       ////////////////////////// IRC Client Protocol commands ///////////////////////
+
+       // first thing you must call... mode can be ""
+       // network can be same as name of server used in Connect() above
+       bool User ( const std::string& user, const std::string& mode,
+               const std::string& network, const std::string& realname );
+
+       // change nick...
+       bool Nick ( const std::string& nick );
+
+       // change mode for self...
+       bool Mode ( const std::string& mode );
+
+       // set someone's mode in channel ( like oping someone )
+       bool Mode ( const std::string& channel, const std::string& mode, const std::string& target );
+
+       // request a list of names of clients in a channel
+       bool Names ( const std::string& channel );
+
+       // join a channel...
+       bool Join ( const std::string& channel );
+
+       // send message to someone or some channel
+       bool PrivMsg ( const std::string& to, const std::string& text );
+
+       // leave a channel
+       bool Part ( const std::string& channel, const std::string& text );
+
+       // log off
+       bool Quit ( const std::string& text );
+
+       ////////////////////// callback functions ////////////////////////////
+
+       // OnConnected: you just successfully logged into irc server
+       virtual bool OnConnected() = 0;
+
+       // OnJoin: you just successfully joined this channel
+       virtual bool OnJoin ( const std::string& user, const std::string& channel ) = 0;
+
+       // OnPrivMsg: you just received a private message from a user
+       virtual bool OnPrivMsg ( const std::string& from, const std::string& text ) = 0;
+
+       // OnChannelMsg: you just received a chat line in a channel
+       virtual bool OnChannelMsg ( const std::string& channel, const std::string& from,
+               const std::string& text ) = 0;
+
+       // OnChannelMode: notification of a change of a channel's mode
+       virtual bool OnChannelMode ( const std::string& channel, const std::string& mode ) = 0;
+
+       // OnUserModeInChannel: notification of a mode change of a user with respect to a channel.
+       // f.ex.: this will be called when someone is oped in a channel.
+       virtual bool OnUserModeInChannel ( const std::string& src, const std::string& channel,
+               const std::string& user, const std::string& mode ) = 0;
+
+       // OnMode: you will receive this when you change your own mode, at least...
+       virtual bool OnMode ( const std::string& user, const std::string& mode ) = 0;
+
+       // notification of what users are in a channel ( you may get multiple of these... )
+       virtual bool OnChannelUsers ( const std::string& channel, const std::vector<std::string>& users ) = 0;
+
+       // notification that you have received the entire list of users for a channel
+       virtual bool OnEndChannelUsers ( const std::string& channel ) = 0;
+
+       // OnPing - default implementation replies to PING with a valid PONG. required on some systems to
+       // log in. Most systems require a response in order to stay connected, used to verify a client hasn't
+       // dropped.
+       virtual bool OnPing ( const std::string& text );
+       
+       ////////////////////// other functions ////////////////////////////
+
+       // this is for sending data to irc server. it's public in case you need to send some
+       // command not supported by this base class...
+       bool Send ( const std::string& buf );
+
+       // if launch_thread is true, this function will spawn a thread that will process
+       // incoming packets until the socket dies.
+       // otherwise ( launch_thread is false ) this function will do that processing
+       // in *this* thread, and not return until the socket dies.
+       int Run ( bool launch_thread );
+
+       ////////////////////// private stuff ////////////////////////////
+private:
+       bool _Recv ( std::string& buf );
+
+       static int THREADAPI Callback ( IRCClient* irc );
+
+       static bool _debug;
+       std::string _nick;
+       int _timeout;
+       std::string _apop_challenge;
+
+       volatile bool _inRun;
+
+       // disable copy semantics
+       IRCClient ( const IRCClient& );
+       IRCClient& operator = ( const IRCClient& );
+};
+
+#endif//IRCCLIENT_H
diff --git a/rosapps/games/ArchBlackmann/MD5.cpp b/rosapps/games/ArchBlackmann/MD5.cpp
new file mode 100644 (file)
index 0000000..43200cf
--- /dev/null
@@ -0,0 +1,418 @@
+// MD5.CPP - RSA Data Security, Inc., MD5 message-digest algorithm
+
+/*
+Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+*/
+
+//#include <assert.h>
+#include <memory.h>
+#include <ctype.h>
+#include <vector>
+#include "MD5.h"
+
+using std::string;
+using std::vector;
+
+// Constants for MD5Transform routine.
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform ( UINT4 [4], const uchar [64] );
+static void Encode ( unsigned char *, UINT4 *, unsigned int );
+static void Decode ( UINT4 *, const uchar *, unsigned int );
+
+static unsigned char PADDING[64] =
+{
+       0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+// F, G, H and I are basic MD5 functions.
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+// ROTATE_LEFT rotates x left n bits.
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+// Rotation is separate from addition to prevent recomputation.
+#define FF(a, b, c, d, x, s, ac) { \
+       (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+       (a) = ROTATE_LEFT ((a), (s)); \
+       (a) += (b); \
+       }
+#define GG(a, b, c, d, x, s, ac) { \
+       (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+       (a) = ROTATE_LEFT ((a), (s)); \
+       (a) += (b); \
+       }
+#define HH(a, b, c, d, x, s, ac) { \
+       (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+       (a) = ROTATE_LEFT ((a), (s)); \
+       (a) += (b); \
+       }
+#define II(a, b, c, d, x, s, ac) { \
+       (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+       (a) = ROTATE_LEFT ((a), (s)); \
+       (a) += (b); \
+       }
+
+// MD5 initialization. Begins an MD5 operation, writing a new context.
+void MD5Init (
+       MD5_CTX *context ) // context
+{
+       context->count[0] = context->count[1] = 0;
+       // Load magic initialization constants.
+       context->state[0] = 0x67452301;
+       context->state[1] = 0xefcdab89;
+       context->state[2] = 0x98badcfe;
+       context->state[3] = 0x10325476;
+}
+
+// MD5 block update operation. Continues an MD5 message-digest
+// operation, processing another message block, and updating the
+// context.
+void MD5Update (
+       MD5_CTX *context,       // context
+       const char *input_,     // input block
+       unsigned int inputLen ) // length of input block
+{
+       unsigned int i, index, partLen;
+       const uchar* input = (const uchar*)input_;
+
+       // Compute number of bytes mod 64
+       index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+       // Update number of bits
+       if ((context->count[0] += ((UINT4)inputLen << 3))
+               < ((UINT4)inputLen << 3))
+               context->count[1]++;
+       context->count[1] += ((UINT4)inputLen >> 29);
+
+       partLen = 64 - index;
+
+       // Transform as many times as possible.
+       if (inputLen >= partLen)
+       {
+               memcpy
+                       ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+               MD5Transform (context->state, context->buffer);
+
+               for (i = partLen; i + 63 < inputLen; i += 64)
+                       MD5Transform (context->state, &input[i]);
+
+               index = 0;
+       }
+       else
+               i = 0;
+
+       // Buffer remaining input
+       memcpy
+               ((POINTER)&context->buffer[index], (POINTER)&input[i],
+               inputLen-i);
+}
+
+// MD5 finalization. Ends an MD5 message-digest operation, writing the
+// the message digest and zeroizing the context.
+void MD5Final (
+       unsigned char digest[16], // message digest
+       MD5_CTX *context )        // context
+{
+       uchar bits[8];
+       unsigned int index, padLen;
+
+       // Save number of bits
+       Encode (bits, context->count, 8);
+
+       // Pad out to 56 mod 64.
+       index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+       padLen = (index < 56) ? (56 - index) : (120 - index);
+       MD5Update (context, (const char*)PADDING, padLen);
+
+       // Append length (before padding)
+       MD5Update (context, (const char*)bits, 8);
+
+       // Store state in digest
+       Encode (digest, context->state, 16);
+
+       // Zeroize sensitive information.
+       memset ((POINTER)context, 0, sizeof (*context));
+}
+
+// MD5 basic transformation. Transforms state based on block.
+static void MD5Transform (
+       UINT4 state[4],
+       const uchar block[64] )
+{
+       UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+       Decode (x, block, 64);
+
+       // Round 1
+       FF (a, b, c, d, x[ 0], S11, 0xd76aa478); // 1
+       FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); // 2
+       FF (c, d, a, b, x[ 2], S13, 0x242070db); // 3
+       FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); // 4
+       FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); // 5
+       FF (d, a, b, c, x[ 5], S12, 0x4787c62a); // 6
+       FF (c, d, a, b, x[ 6], S13, 0xa8304613); // 7
+       FF (b, c, d, a, x[ 7], S14, 0xfd469501); // 8
+       FF (a, b, c, d, x[ 8], S11, 0x698098d8); // 9
+       FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); // 10
+       FF (c, d, a, b, x[10], S13, 0xffff5bb1); // 11
+       FF (b, c, d, a, x[11], S14, 0x895cd7be); // 12
+       FF (a, b, c, d, x[12], S11, 0x6b901122); // 13
+       FF (d, a, b, c, x[13], S12, 0xfd987193); // 14
+       FF (c, d, a, b, x[14], S13, 0xa679438e); // 15
+       FF (b, c, d, a, x[15], S14, 0x49b40821); // 16
+
+       // Round 2
+       GG (a, b, c, d, x[ 1], S21, 0xf61e2562); // 17
+       GG (d, a, b, c, x[ 6], S22, 0xc040b340); // 18
+       GG (c, d, a, b, x[11], S23, 0x265e5a51); // 19
+       GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); // 20
+       GG (a, b, c, d, x[ 5], S21, 0xd62f105d); // 21
+       GG (d, a, b, c, x[10], S22,  0x2441453); // 22
+       GG (c, d, a, b, x[15], S23, 0xd8a1e681); // 23
+       GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); // 24
+       GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); // 25
+       GG (d, a, b, c, x[14], S22, 0xc33707d6); // 26
+       GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); // 27
+       GG (b, c, d, a, x[ 8], S24, 0x455a14ed); // 28
+       GG (a, b, c, d, x[13], S21, 0xa9e3e905); // 29
+       GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); // 30
+       GG (c, d, a, b, x[ 7], S23, 0x676f02d9); // 31
+       GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); // 32
+
+       // Round 3
+       HH (a, b, c, d, x[ 5], S31, 0xfffa3942); // 33
+       HH (d, a, b, c, x[ 8], S32, 0x8771f681); // 34
+       HH (c, d, a, b, x[11], S33, 0x6d9d6122); // 35
+       HH (b, c, d, a, x[14], S34, 0xfde5380c); // 36
+       HH (a, b, c, d, x[ 1], S31, 0xa4beea44); // 37
+       HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); // 38
+       HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); // 39
+       HH (b, c, d, a, x[10], S34, 0xbebfbc70); // 40
+       HH (a, b, c, d, x[13], S31, 0x289b7ec6); // 41
+       HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); // 42
+       HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); // 43
+       HH (b, c, d, a, x[ 6], S34,  0x4881d05); // 44
+       HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); // 45
+       HH (d, a, b, c, x[12], S32, 0xe6db99e5); // 46
+       HH (c, d, a, b, x[15], S33, 0x1fa27cf8); // 47
+       HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); // 48
+
+       // Round 4
+       II (a, b, c, d, x[ 0], S41, 0xf4292244); // 49
+       II (d, a, b, c, x[ 7], S42, 0x432aff97); // 50
+       II (c, d, a, b, x[14], S43, 0xab9423a7); // 51
+       II (b, c, d, a, x[ 5], S44, 0xfc93a039); // 52
+       II (a, b, c, d, x[12], S41, 0x655b59c3); // 53
+       II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); // 54
+       II (c, d, a, b, x[10], S43, 0xffeff47d); // 55
+       II (b, c, d, a, x[ 1], S44, 0x85845dd1); // 56
+       II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); // 57
+       II (d, a, b, c, x[15], S42, 0xfe2ce6e0); // 58
+       II (c, d, a, b, x[ 6], S43, 0xa3014314); // 59
+       II (b, c, d, a, x[13], S44, 0x4e0811a1); // 60
+       II (a, b, c, d, x[ 4], S41, 0xf7537e82); // 61
+       II (d, a, b, c, x[11], S42, 0xbd3af235); // 62
+       II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); // 63
+       II (b, c, d, a, x[ 9], S44, 0xeb86d391); // 64
+
+       state[0] += a;
+       state[1] += b;
+       state[2] += c;
+       state[3] += d;
+
+       // Zeroize sensitive information.
+       memset ((POINTER)x, 0, sizeof (x));
+}
+
+// Encodes input (UINT4) into output (unsigned char). Assumes len is
+// a multiple of 4.
+static void Encode (
+       unsigned char *output,
+       UINT4 *input,
+       unsigned int len )
+{
+       unsigned int i, j;
+
+       for (i = 0, j = 0; j < len; i++, j += 4) {
+               output[j] = (unsigned char)(input[i] & 0xff);
+               output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+               output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+               output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+       }
+}
+
+// Decodes input (unsigned char) into output (UINT4). Assumes len is
+// a multiple of 4.
+static void Decode (
+       UINT4 *output,
+       const uchar *input,
+       unsigned int len )
+{
+       unsigned int i, j;
+
+       for (i = 0, j = 0; j < len; i++, j += 4)
+               output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+               (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+void digest2ascii ( char *ascii, const unsigned char *digest )
+{
+       int i;
+       static char* table = "0123456789abcdef";
+       for ( i = 0; i < 16; i++ )
+       {
+               *ascii++ = table[(*digest)>>4];
+               *ascii++ = table[(*digest++)%16];
+       }
+       *ascii++ = 0;
+}
+
+void ascii2digest ( unsigned char *digest, const char *ascii )
+{
+       int i;
+#define CONV(c) (unsigned char)( (toupper(c)>='A') ? (toupper(c)+10-'A') : ((c)-'0') )
+#define MAKECHAR(a,b) ((CONV(a)%16)<<4)|(CONV(b)%16)
+       for ( i = 0; i < 16; i++ )
+       {
+               *digest++ = MAKECHAR(ascii[0],ascii[1]);
+               ascii += 2;
+       }
+}
+
+#ifdef __cplusplus
+MD5::MD5()
+{
+       Init();
+}
+
+void MD5::Init()
+{
+       MD5Init(&_ctx);
+}
+
+void MD5::Update ( const string& s )
+{
+       MD5Update ( &_ctx, s.c_str(), s.size() );
+}
+
+string MD5::Final ( char* digest )
+{
+       vector<uchar> v;
+       v.resize(16);
+       MD5Final ( &v[0], &_ctx );
+       if ( digest )
+               memmove ( digest, &v[0], 16 );
+       string s;
+       static char* tohex = "0123456789abcdef";
+       for ( int i = 0; i < 16; i++ )
+       {
+               uchar c = v[i];
+               s += tohex[ (c>>4) & 0xF ];
+               s += tohex[ c & 0xF ];
+       }
+       return s;
+}
+
+string MD5Hex ( const string& s )
+{
+       MD5 md5;
+       md5.Update ( s );
+       return md5.Final();
+}
+
+string MD5Bin ( const string& s )
+{
+       MD5 md5;
+       md5.Update ( s );
+       char digest[16];
+       md5.Final ( digest );
+       return string ( digest, 16 );
+}
+
+string HMAC_MD5 ( const string& key, const string& text, char* out_bin )
+{
+       MD5 md5;
+       char k_ipad[65]; // inner padding - key XORd with ipad
+       char k_opad[65]; // outer padding - key XORd with opad
+       string tmp;
+       char digest[16];
+       int i;
+       // if key is longer than 64 bytes reset it to key=MD5(key)
+       if ( key.length() > 64 )
+       {
+               md5.Init();
+               md5.Update ( key );
+               md5.Final ( digest );
+               tmp = string ( digest, 16 );
+       }
+       else
+               tmp = key;
+
+       // start out by storing key in pads
+       memset ( k_ipad, 0, sizeof(k_ipad) );
+       memset ( k_opad, 0, sizeof(k_opad) );
+       memcpy ( k_ipad, tmp.c_str(), tmp.length() );
+       memcpy ( k_opad, tmp.c_str(), tmp.length() );
+
+       // XOR key with ipad and opad values
+       for ( i=0; i<64; i++ )
+       {
+               k_ipad[i] ^= 0x36;
+               k_opad[i] ^= 0x5c;
+       }
+
+       // "inner" MD5
+       md5.Init();
+       md5.Update(k_ipad);
+       md5.Update(text);
+       md5.Final ( digest );
+
+       // "outer" MD5
+       md5.Init();
+       md5.Update(k_opad);
+       md5.Update(string(digest,16));
+       return md5.Final(out_bin);
+}
+#endif//__cplusplus
diff --git a/rosapps/games/ArchBlackmann/MD5.h b/rosapps/games/ArchBlackmann/MD5.h
new file mode 100644 (file)
index 0000000..f4bd3c1
--- /dev/null
@@ -0,0 +1,95 @@
+// MD5.H - header file for MD5.CPP
+
+/*
+Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+*/
+
+#ifndef __MD5_H
+#define __MD5_H
+
+#ifdef __cplusplus
+#include <string>
+#endif//__cplusplus
+
+#ifndef uchar
+#define uchar unsigned char
+#endif//uchar
+
+#ifndef ushort
+#define ushort unsigned short
+#endif//ushort
+
+#ifndef ulong
+#define ulong unsigned long
+#endif//ulong
+
+#ifdef __cplusplus
+extern "C" {
+#endif//__cplusplus
+
+typedef uchar *POINTER; // POINTER defines a generic pointer type
+typedef ushort UINT2; // UINT2 defines a two byte word
+typedef ulong UINT4; // UINT4 defines a four byte word
+
+// MD5 context.
+typedef struct
+{
+       UINT4 state[4];           // state (ABCD)
+       UINT4 count[2];           // number of bits, modulo 2^64 (lsb first)
+       unsigned char buffer[64]; // input buffer
+} MD5_CTX;
+
+void MD5Init ( MD5_CTX * );
+void MD5Update ( MD5_CTX *, const char *, unsigned int );
+void MD5Final ( uchar [16], MD5_CTX * );
+
+void digest2ascii ( char *ascii, const uchar *digest );
+void ascii2digest ( uchar *digest, const char *ascii );
+
+#ifdef __cplusplus
+
+} // extern "C"
+
+class MD5
+{
+public:
+       MD5();
+       void Init();
+       void Update ( const std::string& s );
+       std::string Final ( char* digest = 0 );
+
+private:
+       MD5_CTX _ctx;
+};
+
+std::string MD5Hex ( const std::string& s );
+
+std::string MD5Bin ( const std::string& s );
+
+std::string HMAC_MD5 (
+       const std::string& key,
+       const std::string& text,
+       char* out_bin = NULL );
+
+#endif//__cplusplus
+
+#endif//__MD5_H
diff --git a/rosapps/games/ArchBlackmann/QueueT.h b/rosapps/games/ArchBlackmann/QueueT.h
new file mode 100644 (file)
index 0000000..3d15bcb
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+** Author: Samuel R. Blackburn
+** Internet: wfc@pobox.com
+**
+** You can use it any way you like as long as you don't try to sell it.
+**
+** Any attempt to sell WFC in source code form must have the permission
+** of the original author. You can produce commercial executables with
+** WFC but you can't sell WFC.
+**
+** Copyright, 2000, Samuel R. Blackburn
+**
+** NOTE: I modified the info block below so it hopefully wouldn't conflict
+** with the original file. Royce Mitchell III
+*/
+
+#ifndef QUEUET_CLASS_HEADER
+#define QUEUET_CLASS_HEADER
+
+#include "ReliMT.h"
+
+#ifdef WIN32
+#include <sys/types.h> // off_t
+#define HEAPCREATE(size) m_Heap = ::HeapCreate ( HEAP_NO_SERIALIZE, size, 0 )
+#define HEAPALLOC(size) ::HeapAlloc ( m_Heap, HEAP_NO_SERIALIZE, size )
+#define HEAPREALLOC(p,size) ::HeapReAlloc( m_Heap, HEAP_NO_SERIALIZE, p, size )
+#define HEAPFREE(p) ::HeapFree ( m_Heap, HEAP_NO_SERIALIZE, p )
+#define HEAPDESTROY() ::HeapDestroy ( m_Heap ); m_Heap = 0;
+#else
+#define HEAPCREATE(size)
+#define HEAPALLOC(size) malloc(size)
+#define HEAPREALLOC(p,size) realloc(p,size);
+#define HEAPFREE(p) free(p)
+#define HEAPDESTROY()
+#endif
+
+template <class T>
+class CQueueT : public Uncopyable
+{
+protected:
+
+       // What we want to protect
+
+       Mutex m_AddMutex;
+       Mutex m_GetMutex;
+
+       T* m_Items;
+
+       off_t m_AddIndex;
+       off_t m_GetIndex;
+       size_t m_Size;
+
+#ifdef WIN32
+       HANDLE m_Heap;
+#endif//WIN32
+       inline void m_GrowBy ( size_t number_of_new_items );
+
+public:
+
+       inline  CQueueT ( size_t initial_size = 1024 );
+       inline ~CQueueT();
+
+       inline bool  Add( const T& new_item );
+       inline void  Empty() { m_AddIndex = 0; m_GetIndex = 0; };
+       inline bool  Get( T& item );
+       inline size_t GetLength() const;
+       inline size_t GetMaximumLength() const { return( m_Size ); };
+       inline bool  AddArray ( const T* new_items, int item_count );
+       inline int GetArray ( T* items, const int maxget, const T& tEnd );
+       inline bool Contains ( const T& t );
+};
+
+template <class T>
+inline CQueueT<T>::CQueueT ( size_t initial_size )
+{
+       m_AddIndex = 0;
+       m_GetIndex = 0;
+       m_Items    = NULL;
+
+       if ( initial_size == 0 )
+               initial_size = 1;
+
+       /*
+       ** 1999-11-05
+       ** We create our own heap because all of the pointers used are allocated
+       ** and freed be us. We don't have to worry about a non-serialized thread
+       ** accessing something we allocated. Because of this, we can perform our
+       ** memory allocations in a heap dedicated to queueing. This means when we
+       ** have to allocate more memory, we don't have to wait for all other threads
+       ** to pause while we allocate from the shared heap (like the C Runtime heap)
+       */
+
+       HEAPCREATE( ( ( ( 2 * initial_size * sizeof(T) ) < 65536 ) ? 65536 : (2 * initial_size * sizeof(T) ) ) );
+
+       m_Items = (T*)HEAPALLOC ( initial_size * sizeof(T) );
+
+       m_Size = ( m_Items == NULL ) ? 0 : initial_size;
+}
+
+template <class T>
+inline CQueueT<T>::~CQueueT()
+{
+       m_AddIndex = 0;
+       m_GetIndex = 0;
+       m_Size     = 0;
+
+       if ( m_Items != NULL )
+       {
+               HEAPFREE(m_Items);
+               m_Items = NULL;
+       }
+
+       HEAPDESTROY();
+}
+
+template <class T>
+inline bool CQueueT<T>::Add ( const T& item )
+{
+       // Block other threads from entering Add();
+       Mutex::Lock addlock ( m_AddMutex );
+
+       // Add the item
+
+       m_Items[ m_AddIndex ] = item;
+
+       // 1999-12-08
+       // Many many thanks go to Lou Franco (lfranco@spheresoft.com)
+       // for finding an bug here. It rare but recreatable situations,
+       // m_AddIndex could be in an invalid state.
+
+       // Make sure m_AddIndex is never invalid
+
+       off_t new_add_index = ( ( m_AddIndex + 1 ) >= (off_t)m_Size ) ? 0 : m_AddIndex + 1;
+
+       if ( new_add_index == m_GetIndex )
+       {
+               // The queue is full. We need to grow.
+               // Stop anyone from getting from the queue
+               Mutex::Lock getlock ( m_GetMutex );
+
+               m_AddIndex = new_add_index;
+
+               // One last double-check.
+
+               if ( m_AddIndex == m_GetIndex )
+               {
+                       m_GrowBy ( m_Size );
+               }
+
+       }
+       else
+       {
+               m_AddIndex = new_add_index;
+       }
+
+       return true;
+}
+
+template <class T>
+inline bool CQueueT<T>::Get( T& item )
+{
+       // Prevent other threads from entering Get()
+       Mutex::Lock getlock ( m_GetMutex );
+
+       if ( m_GetIndex == m_AddIndex )
+       {
+               // Let's check to see if our queue has grown too big
+               // If it has, then shrink it
+
+               if ( m_Size > 1024 )
+               {
+                       // Yup, we're too big for our britches
+                       Mutex::TryLock addlock ( m_AddMutex );
+                       if ( addlock )
+                       {
+                               // Now, no one can add to the queue
+
+                               if ( m_GetIndex == m_AddIndex ) // is queue empty?
+                               {
+                                       // See if we can just shrink it...
+                                       T* return_value = (T*)HEAPREALLOC(m_Items,1024 * sizeof(T));
+
+                                       if ( return_value != NULL )
+                                       {
+                                               m_Items = (T*) return_value;
+                                       }
+                                       else
+                                       {
+                                               // Looks like we'll have to do it the hard way
+                                               HEAPFREE ( m_Items );
+                                               m_Items = (T*) HEAPALLOC ( 1024 * sizeof(T) );
+                                       }
+
+                                       m_Size     = ( m_Items == NULL ) ? 0 : 1024;
+                                       m_AddIndex = 0;
+                                       m_GetIndex = 0;
+                               }
+                               else
+                               {
+                                       // m_GetIndex != m_AddIndex, this means that someone added
+                                       // to the queue between the time we checked m_Size for being
+                                       // too big and the time we entered the add critical section.
+                                       // If this happened then we are too busy to shrink
+                               }
+                       }
+               }
+               return false;
+       }
+
+       item = m_Items[ m_GetIndex ];
+
+       // Make sure m_GetIndex is never invalid
+
+       m_GetIndex = ( ( m_GetIndex + 1 ) >= (off_t)m_Size ) ? 0 : m_GetIndex + 1;
+
+       return true;
+}
+
+template <class T>
+inline int CQueueT<T>::GetArray ( T* items, const int maxget, const T& tEnd )
+{
+       // TODO - oooh baby does this need to be optimized
+       // Prevent other threads from entering Get()
+       Mutex::Lock getlock ( m_GetMutex ); //::EnterCriticalSection( &m_GetCriticalSection );
+
+       int iResult = 0;
+       for ( int i = 0; i < maxget; i++ )
+       {
+               if ( !Get(items[i]) )
+                       break;
+               iResult++;
+               if ( items[i] == tEnd )
+                       break;
+       }
+       // Let other threads call Get() now
+       //::LeaveCriticalSection( &m_GetCriticalSection );
+       return iResult;
+}
+
+template <class T>
+inline size_t CQueueT<T>::GetLength() const
+{
+       // This is a very expensive process!
+       // No one can call Add() or Get() while we're computing this
+
+       size_t number_of_items_in_the_queue = 0;
+
+       Mutex::Lock addlock ( m_AddMutex );
+       Mutex::Lock getlock ( m_GetMutex );
+
+       number_of_items_in_the_queue = ( m_AddIndex >= m_GetIndex ) ?
+                                      ( m_AddIndex  - m_GetIndex ) :
+                                      ( ( m_AddIndex + m_Size ) - m_GetIndex );
+
+       return number_of_items_in_the_queue;
+}
+
+template <class T>
+inline void CQueueT<T>::m_GrowBy ( size_t number_of_new_items )
+{
+       // Prevent other threads from calling Get().
+       // We don't need to enter the AddCriticalSection because
+       // m_GrowBy() is only called from Add();
+
+       T* new_array       = NULL;
+       T* pointer_to_free = NULL;
+
+       size_t new_size = m_Size + number_of_new_items;
+
+       { // Prevent other threads from getting
+               Mutex::Lock getlock ( m_GetMutex );
+
+               // 2000-05-16
+               // Thanks go to Royce Mitchell III (royce3@aim-controls.com) for finding
+               // a HUGE bug here. I was using HeapReAlloc as a short cut but my logic
+               // was flawed. In certain circumstances, queue items were being dropped.
+
+               new_array = (T*)HEAPALLOC ( new_size * sizeof(T) );
+
+               // Now copy all of the old items from the old queue to the new one.
+
+               // Get the entries from the get-index to the end of the array
+               memcpy ( new_array, &m_Items[m_GetIndex], ( m_Size - m_GetIndex ) * sizeof(T) );
+
+               // Get the entries from the beginning of the array to the add-index
+               memcpy ( &new_array[m_Size-m_GetIndex], m_Items, m_AddIndex * sizeof(T) );
+
+               m_AddIndex      = (off_t)m_Size;
+               m_GetIndex      = 0;
+               m_Size          = new_size;
+               pointer_to_free = m_Items;
+               m_Items         = new_array;
+       } // Mutex::Lock
+       HEAPFREE ( pointer_to_free );
+}
+
+template <class T>
+inline bool CQueueT<T>::Contains ( const T& t )
+{
+       Mutex::Lock addlock ( m_AddMutex );
+       Mutex::Lock getlock ( m_GetMutex );
+
+       for ( int i = m_GetIndex; i != m_AddIndex; i++ )
+       {
+               if ( i == m_Size )
+                       i = 0;
+               if ( m_Items[i] == t )
+                       return true;
+       }
+       return m_Items[m_AddIndex] == t;
+}
+
+typedef CQueueT<char> CCharQueue;
+
+#endif // QUEUE_CLASS_HEADER
diff --git a/rosapps/games/ArchBlackmann/Reli.h b/rosapps/games/ArchBlackmann/Reli.h
new file mode 100644 (file)
index 0000000..ebc35d3
--- /dev/null
@@ -0,0 +1,143 @@
+// Reli.h
+// lots of code here is (c) Bartosz Milewski, 1996, www.relisoft.com
+// The rest is (C) 2002-2004 Royce Mitchell III
+// and released under the LGPL & BSD licenses
+
+#ifndef __RELI_H
+#define __RELI_H
+
+////////////////////////////////////////////////////////////////////////////////
+// Assert
+
+#undef Assert
+#ifdef NDEBUG
+       #define Assert(exp)     ((void)0)
+#else
+       void _wassert (char* szExpr, char* szFile, int line);
+       #define Assert(exp) (void)( (exp) || (_wassert(#exp, __FILE__, __LINE__), 0) )
+#endif /* NDEBUG */
+
+////////////////////////////////////////////////////////////////////////////////
+// Swap
+
+template <class T>
+void Swap(T a,T b)
+{
+       T t = a;
+       a = b;
+       b = t;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Uncopyable - base class disabling copy ctors
+class Uncopyable
+{
+public:
+       Uncopyable(){} // need a default ctor
+private:
+       Uncopyable ( const Uncopyable& );
+       const Uncopyable& operator = ( const Uncopyable& );
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// SPtr - Smart Pointer's must be passed by reference or const reference
+
+template <class T>
+class SPtr : public Uncopyable
+{
+public:
+       virtual ~SPtr () { Destroy(); }
+       T * operator->() { return _p; }
+       T const * operator->() const { return _p; }
+       operator T&() { Assert(_p); return *_p; }
+       operator const T&() const { Assert(_p); return *_p; }
+       void Acquire ( SPtr<T>& t ) { Destroy(); Swap(_p,t._p); }
+       void Destroy() { if ( _p ) { delete _p; _p = 0; } }
+protected:
+       SPtr (): _p (0) {}
+       explicit SPtr (T* p): _p (p) {}
+       T * _p;
+private:
+       operator T* () { return _p; }
+};
+
+#define DECLARE_SPTR(cls,init,init2) \
+class S##cls : public SPtr<cls> \
+{ \
+public: \
+       S##cls ( cls* p ) : SPtr<cls>(p) {} \
+       explicit S##cls init : SPtr<cls> (new cls init2) {} \
+};
+/* Example Usage of DECLARE_SPTR:
+class MyClass
+{
+public: // can be protected
+       MyClass ( int i )
+       {
+               ...
+       }
+       ...
+}; DECLARE_SPTR(MyClass,(int i),(i))
+SMyClass ptr(i);
+*/
+#define DECLARE_SPTRV(cls) typedef SPtr<cls> S##cls;
+/* Example Usage of DECLARE_SPTRV:
+class MyAbstractClass
+{
+public: // can be protected
+       MyAbstractClass ( int i )
+       {
+               ...
+       }
+       void MyPureVirtFunc() = 0;
+       ...
+}; DECLARE_SPTRV(MyAbstractClass)
+SMyAbstractClass ptr ( new MySubClass(i) );
+*/
+
+#define DECLARE_PTR(cls,init,init2) \
+       class Ptr : public SPtr<cls> \
+       { \
+               Ptr(cls* p) : SPtr<cls> ( p ) \
+               { \
+               } \
+               Ptr init : SPtr<cls> ( new cls init2 ) {} \
+       };
+/* Example Usage of DECLARE_PTR:
+class MyClass
+{
+       DECLARE_PTR(MyClass,(int i),(i))
+public: // can be protected
+       MyClass ( int i )
+       {
+               ...
+       }
+       void MyPureVirtFunc() = 0;
+       ...
+};
+MyClass::Ptr ptr ( i );
+*/
+
+#define DECLARE_PTRV(cls) \
+       class Ptr : public SPtr<cls> \
+       { \
+               Ptr(cls* p) : SPtr<cls> ( p ) \
+               { \
+               } \
+       };
+/* Example Usage of DECLARE_PTRV:
+class MyAbstractClass
+{
+       DECLARE_PTRV(MyAbstractClass)
+public: // can be protected
+       MyAbstractClass ( int i )
+       {
+               ...
+       }
+       void MyPureVirtFunc() = 0;
+       ...
+};
+MyAbstractClass::Ptr ptr ( new MySubClass(i) );
+*/
+
+#endif//__RELI_H
diff --git a/rosapps/games/ArchBlackmann/ReliMT.cpp b/rosapps/games/ArchBlackmann/ReliMT.cpp
new file mode 100644 (file)
index 0000000..2c50dc4
--- /dev/null
@@ -0,0 +1,331 @@
+// ReliMT.cpp
+// lots of code here is (c) Bartosz Milewski, 1996, www.relisoft.com
+// The rest is (C) 2002-2004 Royce Mitchell III
+// and released under the LGPL & BSD licenses
+
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef WIN32
+#  define WIN32_LEAN_AND_MEAN
+#  include <windows.h>
+#  define snprintf _snprintf
+#elif defined(UNIX)
+#  include <errno.h>
+#  include <sys/sem.h>
+#else
+#  error unrecognized target
+#endif//WIN32|UNIX
+#include "verify.h"
+#include "ReliMT.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Assert
+
+void _wassert ( char* szExpr, char* szFile, int line )
+{
+       fprintf ( stderr, "Assertion Failure: \"%s\" in file %s, line %d", szExpr, szFile, line );
+       exit (-1);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Thread
+
+Thread::Thread ( long (THREADAPI * pFun) (void* arg), void* pArg )
+{
+#ifdef WIN32
+       verify ( _handle = CreateThread (
+               0, // Security attributes
+               0, // Stack size
+               (DWORD (WINAPI*)(void*))pFun,
+               pArg,
+               0, // don't create suspended.
+               &_tid ));
+#elif defined(UNIX)
+       // set up the thread attribute: right now, we do nothing with it.
+       pthread_attr_t attr;
+       pthread_attr_init(&attr);
+
+       // this will make the threads created by this process really concurrent
+       verify ( !pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) );
+
+       // create the new OS thread object
+       verify ( !pthread_create ( &_threadId, &attr, (void* (*) (void*))pFun, pArg ) );
+
+       verify ( !pthread_attr_destroy(&attr) );
+#else
+#  error unrecognized target
+#endif//WIN32|UNIX
+}
+
+Thread::~Thread()
+{
+#ifdef WIN32
+       verify ( CloseHandle ( _handle ) );
+#elif defined(UNIX)
+       verify ( !pthread_cancel ( _threadId ) );
+#else
+#  error unrecognized target
+#endif//WIN32|UNIX
+}
+
+/*void Thread::Resume()
+{
+#ifdef WIN32
+       ResumeThread (_handle);
+#elif defined(UNIX)
+#  error how to resume thread in unix?
+#else
+#  error unrecognized target
+#endif//WIN32|UNIX
+}*/
+
+void Thread::WaitForDeath()
+{
+#ifdef WIN32
+       DWORD dw = WaitForSingleObject ( _handle, 2000 );
+       ASSERT ( dw != WAIT_FAILED );
+#elif defined(UNIX)
+       verify ( !pthread_join ( _threadId, (void**)NULL ) );
+#else
+#  error unrecognized target
+#endif//WIN32|UNIX
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// ActiveObject
+
+// The constructor of the derived class
+// should call
+//    _thread.Resume();
+// at the end of construction
+
+ActiveObject::ActiveObject() : _isDying (0), _thread (0)
+{
+}
+
+ActiveObject::~ActiveObject()
+{
+       ASSERT ( !_thread ); // call Kill() from subclass's dtor
+       // Kill() - // You can't call a virtual function from a dtor, EVEN INDIRECTLY
+       // so, you must call Kill() in the subclass's dtor
+}
+
+// FlushThread must reset all the events on which the thread might be waiting.
+void ActiveObject::Kill()
+{
+       if ( _thread )
+       {
+               _isDying++;
+               FlushThread();
+               // Let's make sure it's gone
+               _thread->WaitForDeath();
+               delete _thread;
+               _thread = 0;
+       }
+}
+
+void ActiveObject::Start()
+{
+       ASSERT ( !_thread );
+       _thread = new Thread ( ThreadEntry, this );
+}
+
+long THREADAPI ActiveObject::ThreadEntry ( void* pArg )
+{
+       ActiveObject * pActive = (ActiveObject*)pArg;
+       pActive->InitThread();
+       pActive->Run();
+       pActive->Kill();
+       return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Mutex
+
+Mutex::Mutex()
+{
+#ifdef WIN32
+       verify ( _h = CreateMutex ( NULL, FALSE, NULL ) );
+#elif defined(UNIX)
+       pthread_mutexattr_t attrib;
+       verify ( !pthread_mutexattr_init( &attrib ) );
+       // allow recursive locks
+       verify ( !pthread_mutexattr_settype( &attrib, PTHREAD_MUTEX_RECURSIVE ) );
+       verify ( !pthread_mutex_init ( &_mutex, &attrib ) );
+#else
+#  error unrecognized target
+#endif
+}
+
+Mutex::~Mutex()
+{
+#ifdef WIN32
+       verify ( CloseHandle ( _h ) );
+#elif defined(UNIX)
+       verify ( !pthread_mutex_destroy(&_mutex) );
+#else
+#  error unrecognized target
+#endif
+}
+
+void Mutex::Acquire()
+{
+#ifdef WIN32
+       DWORD dw = WaitForSingleObject ( _h, INFINITE );
+       ASSERT ( dw == WAIT_OBJECT_0 || dw == WAIT_ABANDONED );
+#elif defined(UNIX)
+       verify ( !pthread_mutex_lock(&_mutex) );
+#else
+#  error unrecognized target
+#endif
+}
+
+bool Mutex::TryAcquire()
+{
+#ifdef WIN32
+       DWORD dw = WaitForSingleObject ( _h, 1 );
+       ASSERT ( dw == WAIT_OBJECT_0 || dw == WAIT_TIMEOUT || dw == WAIT_ABANDONED );
+       return (dw != WAIT_TIMEOUT);
+#elif defined(UNIX)
+       int err = pthread_mutex_trylock(&_mutex);
+       ASSERT ( err == EBUSY || err == 0 );
+       return (err == 0);
+#else
+#  error unrecognized target
+#endif
+}
+
+void Mutex::Release()
+{
+#ifdef WIN32
+       verify ( ReleaseMutex ( _h ) );
+#elif defined(UNIX)
+       verify ( !pthread_mutex_unlock(&_mutex) );
+       // we could allow EPERM return value too, but we are forcing user into RIIA
+#else
+#  error unrecognized target
+#endif
+}
+
+Mutex::Lock::Lock ( Mutex& m ) : _m(m)
+{
+       _m.Acquire();
+}
+
+Mutex::Lock::~Lock()
+{
+       _m.Release();
+}
+
+Mutex::TryLock::TryLock ( Mutex& m ) : _m(m)
+{
+       _bLocked = _m.TryAcquire();
+}
+
+Mutex::TryLock::~TryLock()
+{
+       if ( _bLocked )
+               _m.Release();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Event
+
+Event::Event()
+{
+#ifdef WIN32
+       // start in non-signaled state (red light)
+       // auto reset after every Wait
+       verify ( _handle = CreateEvent ( 0, FALSE, FALSE, 0 ) );
+#elif defined(UNIX)
+       //verify ( !pthread_cond_init ( &_cond, NULL /* default attributes */) );
+       sem_init();
+       //verify(sem_init());
+#else
+#  error unrecognized target
+#endif
+}
+
+Event::~Event()
+{
+#ifdef WIN32
+       verify ( CloseHandle ( _handle ) );
+#elif defined(UNIX)
+       //verify ( !pthread_cond_destroy ( &_cond ) );
+       sem_destroy();
+#else
+#  error unrecognized target
+#endif
+}
+
+void Event::Release() // put into signaled state
+{
+#ifdef WIN32
+       verify ( SetEvent ( _handle ) );
+#elif defined(UNIX)
+       //verify ( !pthread_cond_signal ( &_cond ) );
+       verify(!sem_V());
+#else
+#  error unrecognized target
+#endif
+}
+
+void Event::Wait()
+{
+#ifdef WIN32
+       // Wait until event is in signaled (green) state
+       DWORD dw = WaitForSingleObject ( _handle, INFINITE );
+       ASSERT ( dw == WAIT_OBJECT_0 || dw == WAIT_ABANDONED );
+#elif defined(UNIX)
+       // According to docs: The pthread_cond_wait() and pthread_cond_timedwait()
+       // functions are used to block on a condition variable. They are called
+       // with mutex locked by the calling thread or undefined behaviour will
+       // result.
+       //Mutex::Lock lock ( _mutex );
+       //verify ( !pthread_cond_wait ( &_cond, _mutex ) );
+       verify(!sem_P());
+#else
+#  error unrecognized target
+#endif
+}
+
+#ifdef UNIX
+void Event::sem_init()
+{
+       sem_id = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
+       ASSERT(sem_id != -1);
+}
+
+int Event::sem_P()
+{
+       struct sembuf sb;
+       sb.sem_num = 0;
+       sb.sem_op = -1;
+       sb.sem_flg = 0;
+       return semop(sem_id, &sb, 1);
+}
+
+int Event::sem_V()
+{
+       struct sembuf sb;
+       sb.sem_num = 0;
+       sb.sem_op =  1;
+       sb.sem_flg = 0;
+       return semop(sem_id, &sb, 1);
+}
+
+void Event::sem_destroy()
+{
+#ifdef MACOSX
+       semun mactmp;
+       mactmp.val = 0;
+       semctl(sem_id, 0, IPC_RMID, mactmp);
+#else
+       semctl(sem_id, 0, IPC_RMID, 0);
+#endif
+}
+#endif
+
diff --git a/rosapps/games/ArchBlackmann/ReliMT.h b/rosapps/games/ArchBlackmann/ReliMT.h
new file mode 100644 (file)
index 0000000..17fb121
--- /dev/null
@@ -0,0 +1,229 @@
+// ReliMT.h
+// lots of code here is (c) Bartosz Milewski, 1996, www.relisoft.com
+// The rest is (C) 2003-2004 Royce Mitchell III
+// and released under the LGPL & BSD licenses
+
+
+#ifndef __RELIMT_H
+#define __RELIMT_H
+
+#include "Reli.h"
+
+#ifdef WIN32
+#  ifndef _WINDOWS_
+#    define WIN32_LEAN_AND_MEAN
+#    include <windows.h>
+#  endif
+#  define THREADAPI WINAPI
+#elif defined(UNIX)
+#  include <pthread.h>
+#  include <stdlib.h>
+#  include "string.h"
+#  include <sys/types.h> //Semaphore
+#  include <sys/ipc.h> //Semaphore
+#  include <sys/sem.h> //Semaphore
+#  define THREADAPI
+#else
+#  error unrecognized target
+#endif
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Thread
+
+class Thread : public Uncopyable
+{
+public:
+       Thread ( long (THREADAPI * pFun) (void* arg), void* pArg );
+       ~Thread();
+       //void Resume();
+       void WaitForDeath();
+
+       // platform-specific stuff:
+private:
+#ifdef WIN32
+       HANDLE _handle;
+       DWORD  _tid;     // thread id
+#elif defined(UNIX)
+       pthread_t _threadId;   // id of the thread
+#else
+#  error unrecognized target
+#endif
+       //DECLARE_PTR(Thread,(long (THREADAPI * pFun) (void* arg), void* pArg),(pFun,pArg));
+}; //DECLARE_SPTR(Thread,(long (THREADAPI * pFun) (void* arg), void* pArg),(pFun,pArg));
+
+////////////////////////////////////////////////////////////////////////////////
+// ActiveObject
+
+class ActiveObject : public Uncopyable
+{
+public:
+       ActiveObject();
+       virtual ~ActiveObject();
+       void Kill();
+       void Start();
+
+protected:
+       virtual void InitThread() = 0;
+       virtual void Run() = 0;
+       virtual void FlushThread() = 0;
+
+       int             _isDying;
+
+       static long THREADAPI ThreadEntry ( void *pArg );
+       Thread         *_thread;
+
+       //DECLARE_PTRV(ActiveObject);
+}; //DECLARE_SPTRV(ActiveObject);
+
+// Last thing in the constructor of a class derived from
+// ActiveObject you must call
+//    Start();
+// Inside the loop the Run method you must keep checking _isDying
+//    if (_isDying)
+//         return;
+// FlushThread must reset all the events on which the thread might be waiting.
+// Example:
+#if 0
+// MyAsyncOutputter - class that outputs strings to a file asynchronously
+class MyAsyncOutputter : public ActiveObject
+{
+public:
+       MyAsyncOutputter ( const string& filename ) : _filename(filename), _currentBuf(0)
+       {
+               Start(); // start thread
+       }
+       void InitThread()
+       {
+               _f.open ( _filename, "wb" );
+       }
+       void Output ( const string& s )
+       {
+               {
+                       // acquire lock long enough to add the string to the active buffer
+                       Mutex::Lock lock ( _mutex );
+                       _buf[_currentBuf].push_back ( s );
+               }
+               _event.Release(); // don't need the lock fire the event
+       }
+       void Run()
+       {
+               while ( !_isDying )
+               {
+                       // wait for signal from Output() or FlushThread()
+                       _event.Wait();
+                       {
+                               // acquire lock long enough to switch active buffers
+                               Mutex::Lock lock ( _mutex );
+                               _currentBuf = 1-_currentBuf;
+                               ASSERT ( !_buf[_currentBuf].size() );
+                       }
+                       // get a reference to the old buffer
+                       vector<string>& buf = _buf[1-_currentBuf];
+                       // write each string out to file and then empty the buffer
+                       for ( int i = 0; i < buf.size(); i++ )
+                               _f.write ( buf[i].c_str(), buf[i].size() );
+                       buf.resize(0);
+               }
+       }
+       void FlushThread()
+       {
+               // _isDying is already set: signal thread so it can see that too
+               _event.Release();
+       }
+private:
+       string _filename;
+       File _f;
+       int _currentBuf;
+       vector<string> _buf[2];
+       Event _event;
+       Mutex _mutex;
+};
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Mutex
+
+class Mutex : public Uncopyable
+{
+public:
+       Mutex();
+       ~Mutex();
+private:
+       void Acquire();
+       bool TryAcquire();
+       void Release();
+public:
+       // sub-class used to lock the Mutex
+       class Lock : public Uncopyable
+       {
+       public:
+               Lock ( Mutex& m );
+               ~Lock();
+
+       private:
+               // private data
+               Mutex& _m;
+       };
+       friend class Mutex::Lock;
+
+
+       // sub-class used to attempt to lock the mutex. Use operator bool()
+       // to test if the lock was successful
+       class TryLock : public Uncopyable
+       {
+       public:
+               TryLock ( Mutex& m );
+               ~TryLock();
+               operator bool () { return _bLocked; }
+
+       private:
+               // private data
+               bool _bLocked;
+               Mutex& _m;
+       };
+       friend class Mutex::TryLock;
+
+private:
+       // platform-specific stuff:
+#ifdef WIN32
+       HANDLE _h;
+#elif defined(UNIX)
+       pthread_mutex_t _mutex;
+public: operator pthread_mutex_t* () { return &_mutex; }
+#else
+#  error unrecognized target
+#endif
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Event
+
+class Event : public Uncopyable
+{
+public:
+       Event();
+       ~Event();
+       void Release(); // put into signaled state
+       void Wait();
+
+private:
+#ifdef WIN32
+       HANDLE _handle;
+#elif defined(UNIX)
+       //Sem util functions
+       void sem_init();
+       int sem_P();
+       int sem_V();
+       void sem_destroy();
+
+       int sem_id;
+       //pthread_cond_t _cond;
+       //Mutex _mutex;
+#else
+#  error unrecognized target
+#endif
+       //DECLARE_PTR(Event,(),());
+}; //DECLARE_SPTR(Event,(),());
+
+#endif//__RELIWIN32_H
diff --git a/rosapps/games/ArchBlackmann/SockUtils.cpp b/rosapps/games/ArchBlackmann/SockUtils.cpp
new file mode 100644 (file)
index 0000000..3398b8d
--- /dev/null
@@ -0,0 +1,504 @@
+// SockUtils.cpp - Some basic socket utility functions.
+// (C) 2002-2004 Royce Mitchell III
+// This file is under the BSD & LGPL licenses
+
+#include <stdio.h>
+#include "SockUtils.h"
+#ifdef WIN32
+#  ifndef SD_SEND // defined in winsock2.h, but not winsock.h
+#    define SD_SEND 1
+#  endif
+#  define snprintf _snprintf
+#  ifdef _MSC_VER
+#    pragma comment ( lib, "ws2_32.lib" )
+#  endif//_MSC_VER
+#elif defined(UNIX)
+#  include <errno.h>
+#  include "string.h" // memset
+#  include <netdb.h> // hostent
+#  include <arpa/inet.h> //inet_addr
+#  include <sys/time.h>
+#  define SD_SEND SHUT_WR //bah thou shalt name thy defines the same
+#else
+#  error unrecognized target
+#endif
+//// Constants /////////////////////////////////////////////////////////
+const int kBufferSize = 1024;
+// creates broadcast address
+SockAddrIn::SockAddrIn()
+{
+       memset ( this, 0, sizeof(sockaddr_in) );
+       sin_family = AF_INET;
+}
+SockAddrIn::SockAddrIn ( const char* szAddr, u_short iPort )
+{
+       memset ( this, 0, sizeof(sockaddr_in) );
+       sin_family = AF_INET;
+       sin_addr.s_addr = suLookupAddress(szAddr);
+       sin_port = htons(iPort);
+}
+SockAddrIn::SockAddrIn ( in_addr_t iAddr, u_short iPort )
+{
+       memset ( this, 0, sizeof(sockaddr_in) );
+       sin_family = AF_INET;
+       sin_addr.s_addr = iAddr;
+       sin_port = htons(iPort);
+}
+bool suStartup()
+{
+#ifdef WIN32
+       WSADATA wsaData;
+       if ( WSAStartup ( MAKEWORD(2,0), &wsaData ) )
+               return false;
+       if ( wsaData.wVersion != MAKEWORD(2,0) )
+       {
+               WSACleanup();
+               return false;
+       }
+       return true;
+#elif defined(UNIX)
+       // nothing special required here
+       return true;
+#else
+#  error unrecognized target
+#endif
+}
+//// suTcpSocket ////////////////////////////////////////////////
+// Creates a TCP socket.
+SOCKET suTcpSocket()
+{
+       SOCKET so = socket ( AF_INET, SOCK_STREAM, 0 );
+#if defined(_DEBUG) && defined(WIN32)
+       if ( so == INVALID_SOCKET && WSANOTINITIALISED == WSAGetLastError() )
+               MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION );
+#endif
+       return so;
+}
+//// suUdpSocket ////////////////////////////////////////////////
+// Creates a UDP socket. Compensates for new "functionality" introduced
+// in Win2K with regards to select() calls
+// MS Transport Provider IOCTL to control
+// reporting PORT_UNREACHABLE messages
+// on UDP sockets via recv/WSARecv/etc.
+// Path TRUE in input buffer to enable (default if supported),
+// FALSE to disable.
+#ifndef SIO_UDP_CONNRESET
+#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
+#endif//SIO_UDP_CONNRESET
+SOCKET suUdpSocket()
+{
+       SOCKET so = socket ( AF_INET, SOCK_DGRAM, 0 );
+#if defined(_DEBUG) && defined(WIN32)
+       if ( so == INVALID_SOCKET && WSANOTINITIALISED == WSAGetLastError() )
+               MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION );
+#endif
+#ifdef WIN32
+       // for Windows 2000, disable new behavior...
+       // see: http://www-pc.uni-regensburg.de/systemsw/W2KPRO/UPDATE/POSTSP1/Q263823.htm
+       // this code is innocuous on other win32 platforms
+       DWORD dwBytesReturned = 0;
+       BOOL bNewBehavior = FALSE;
+       // disable  new Win2K behavior using
+       // IOCTL: SIO_UDP_CONNRESET
+       // we don't care about return value :)
+       WSAIoctl(so, SIO_UDP_CONNRESET,
+               &bNewBehavior, sizeof(bNewBehavior),
+               NULL, 0, &dwBytesReturned,
+               NULL, NULL);
+#endif
+       return so;
+}
+//// suShutdownConnection ////////////////////////////////////////////////
+// Gracefully shuts the connection sd down.  Returns true if it was able
+// to shut it down nicely, false if we had to "slam" it shut.
+// (either way, the socket does get closed)
+bool suShutdownConnection(SOCKET sd)
+{
+       if ( sd == INVALID_SOCKET )
+               return true;
+       // Disallow any further data sends.  This will tell the other side
+       // that we want to go away now.  If we skip this step, we don't
+       // shut the connection down nicely.
+       if (shutdown(sd, SD_SEND) == SOCKET_ERROR)
+       {
+               closesocket(sd);
+               return false;
+       }
+       // Receive any extra data still sitting on the socket.  After all
+       // data is received, this call will block until the remote host
+       // acknowledges the TCP control packet sent by the shutdown above.
+       // Then we'll get a 0 back from recv, signalling that the remote
+       // host has closed its side of the connection.
+       char acReadBuffer[kBufferSize];
+       for ( ;; )
+       {
+               int nNewBytes = recv(sd, acReadBuffer, kBufferSize, 0);
+               if (nNewBytes == SOCKET_ERROR)
+               {
+                       closesocket(sd);
+                       return false;
+               }
+               else if (nNewBytes != 0)
+               {
+                       // FYI, received (nNewBytes) unexpected bytes during shutdown.
+               }
+               else
+               {
+                       // Okay, we're done!
+                       break;
+               }
+       }
+       // Close the socket.
+       if (closesocket(sd) == SOCKET_ERROR)
+       {
+               return false;
+       }
+       return true;
+}
+//// suLookupAddress ////////////////////////////////////////////////
+// Basically converts a name address to an ip address
+in_addr_t suLookupAddress ( const char* pcHost )
+{
+       in_addr_t nRemoteAddr = inet_addr(pcHost);
+       if ( nRemoteAddr == INADDR_NONE )
+       {
+               // pcHost isn't a dotted IP, so resolve it through DNS
+               hostent* pHE = gethostbyname(pcHost);
+               if ( pHE == 0 )
+               {
+#if defined(_DEBUG) && defined(WIN32)
+                       if ( WSANOTINITIALISED == WSAGetLastError() )
+                               MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION );
+#endif
+                       return INADDR_NONE;
+               }
+               nRemoteAddr = *((in_addr_t*)pHE->h_addr_list[0]);
+       }
+       return nRemoteAddr;
+}
+bool suConnect ( SOCKET so, in_addr_t iAddress, u_short iPort )
+{
+       SockAddrIn sinRemote ( iAddress, iPort );
+       if ( SOCKET_ERROR == connect(so,sinRemote,sizeof(sinRemote)) )
+       {
+#if defined(_DEBUG) && defined(WIN32)
+               if ( WSANOTINITIALISED == WSAGetLastError() )
+                       MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION );
+#endif
+               return false;
+       }
+       return true;
+}
+bool suConnect ( SOCKET so, const char* szAddress, u_short iPort )
+{
+       return suConnect ( so, suLookupAddress(szAddress), iPort );
+}
+//// suEstablishConnection ////////////////////////////////////////////////
+// creates a socket of the specified type, connects to the ip address/port
+// requested, and returns the SOCKET created
+SOCKET suEstablishConnection ( in_addr_t iAddress, u_short iPort, int type )
+{
+       // Create a socket
+       if ( type != SOCK_STREAM && type != SOCK_DGRAM )
+               return INVALID_SOCKET;
+       SOCKET so = socket(AF_INET, type, 0);
+       if ( so == INVALID_SOCKET )
+               return so;
+       if ( !suConnect(so, iAddress, iPort) )
+       {
+               closesocket(so);
+               return INVALID_SOCKET;
+       }
+       return so;
+}
+//// suEstablishConnection ////////////////////////////////////////////////
+// creates a socket of the specified type, connects to the address/port
+// requested, and returns the SOCKET created
+SOCKET suEstablishConnection ( const char* szAddress, u_short iPort, int type )
+{
+       return suEstablishConnection ( suLookupAddress ( szAddress ), iPort, type );
+}
+//// suBroadcast ////////////////////////////////////////////////
+// takes a previously created broadcast-enabled UDP socket, and broadcasts
+// a message on the local network
+bool suBroadcast ( SOCKET so, u_short port, const char* buf, int len /* = -1 */ )
+{
+       if ( len == -1 )
+               len = (int)strlen(buf);
+#if 1
+       SockAddrIn to ( INADDR_BROADCAST, port );
+#else // some strange MS OS's don't broadcast to localhost...
+       SockAddrIn to ( "127.0.0.1", port );
+       if ( SOCKET_ERROR == sendto ( so, buf, len, 0, to, sizeof(to) ) )
+               return false;
+       to.sin_addr.s_addr = INADDR_BROADCAST;
+#endif
+       if ( SOCKET_ERROR == sendto ( so, buf, len, 0, to, sizeof(to) ) )
+               return false;
+       return true;
+}
+//// suRecv ////////////////////////////////////////////////
+// retrieves data sent to our TCP socket. If no data, waits for
+// a period of timeout ms.
+// returns bytes received
+// -1 == SOCKET_ERROR
+// -2 == timed out waiting for data
+int suRecv ( SOCKET so, char* buf, int buflen, int timeout )
+{
+       struct timeval to;
+       fd_set rread;
+       int res;
+       FD_ZERO(&rread);   // clear the fd_set
+       FD_SET(so,&rread); // indicate which socket(s) we want to check
+       memset((char *)&to,0,sizeof(to)); // clear the timeval struct
+       to.tv_sec = timeout;  // timeout select after (timeout) seconds
+       // select returns > 0 if there is an event on the socket
+       res = select((int)so+1, &rread, (fd_set *)0, (fd_set *)0, &to );
+       if (res < 0)
+               return -1; // socket error
+       // there was an event on the socket
+       if ( (res>0) && (FD_ISSET(so,&rread)) )
+               return recv ( so, buf, buflen, 0 );
+       return -2;
+}
+//// suRecvFrom ////////////////////////////////////////////////
+// retrieves data sent to our UDP socket. If no data, waits for
+// a period of timeout ms.
+// returns bytes received
+// returns bytes received
+// -1 == SOCKET_ERROR
+// -2 == timed out waiting for data
+int suRecvFrom ( SOCKET so, char* buf, int buflen, int timeout, sockaddr_in* from, socklen_t* fromlen )
+{
+       struct timeval to;
+       fd_set rread;
+       int res;
+       FD_ZERO(&rread);   // clear the fd_set
+       FD_SET(so,&rread); // indicate which socket(s) we want to check
+       memset((char *)&to,0,sizeof(to)); // clear the timeval struct
+       to.tv_sec = timeout;  // timeout select after (timeout) seconds
+       // select returns > 0 if there is an event on the socket
+       res = select((int)so+1, &rread, (fd_set *)0, (fd_set *)0, &to );
+       if (res < 0)
+               return -1; // socket error
+       // there was an event on the socket
+       if ( (res>0) && (FD_ISSET(so,&rread)) )
+               return recvfrom ( so, buf, buflen, 0, (sockaddr*)from, fromlen );
+       return -2; // timeout
+}
+//// suBind ////////////////////////////////////////////////
+// binds a UDP socket to an interface & port to receive
+// data on that port
+bool suBind ( SOCKET so, in_addr_t iInterfaceAddress, u_short iListenPort, bool bReuseAddr /* = false */ )
+{
+       SockAddrIn sinInterface ( iInterfaceAddress, iListenPort );
+       if ( bReuseAddr )
+       {
+               int optval = -1; // true
+               if ( SOCKET_ERROR == setsockopt ( so, SOL_SOCKET, SO_REUSEADDR, (const char*)&optval, sizeof(optval) ) )
+               {
+#if defined(_DEBUG) && defined(WIN32)
+                       if ( WSANOTINITIALISED == WSAGetLastError() )
+                               MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION );
+#endif
+                       return false;
+               }
+       }
+       if ( SOCKET_ERROR == bind(so, sinInterface, sizeof(sinInterface)) )
+       {
+               int err = SUERRNO;
+               if ( err != EADDRINUSE )
+                       return false;
+#if defined(_DEBUG) && defined(WIN32)
+               if ( WSANOTINITIALISED == WSAGetLastError() )
+                       MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION );
+#endif
+       }
+       return true;
+}
+//// suBind ////////////////////////////////////////////////
+// binds a UDP socket to an interface & port to receive
+// data on that port
+bool suBind ( SOCKET so, const char* szInterfaceAddress, u_short iListenPort, bool bReuseAddr /* = false */ )
+{
+       in_addr_t iInterfaceAddr = inet_addr(szInterfaceAddress);
+       if ( iInterfaceAddr == INADDR_NONE )
+               return false;
+       return suBind ( so, iInterfaceAddr, iListenPort, bReuseAddr );
+}
+//// suEnableBroadcast ////////////////////////////////////////////////
+// in order to send broadcast messages on a UDP socket, this function
+// must be called first
+bool suEnableBroadcast ( SOCKET so, bool bEnable /* = true */ )
+{
+       int optval = bEnable ? -1 : 0;
+       if ( SOCKET_ERROR == setsockopt ( so, SOL_SOCKET, SO_BROADCAST, (const char*)&optval, sizeof(optval) ) )
+               return false;
+       return true;
+}
+//// suErrDesc ////////////////////////////////////////////////
+// returns text description of error code
+const char* suErrDesc ( int err )
+{
+       static char errbuf[256];
+#ifdef WIN32
+       switch ( err )
+       {
+#define X(E) case E: return #E;
+               X(WSAEINTR)     X(WSAEBADF)
+               X(WSAEACCES)    X(WSAEFAULT)
+               X(WSAEINVAL)    X(WSAEMFILE)
+               X(WSAEWOULDBLOCK)       X(WSAEINPROGRESS)
+               X(WSAEALREADY)  X(WSAENOTSOCK)
+               X(WSAEDESTADDRREQ)      X(WSAEMSGSIZE)
+               X(WSAEPROTOTYPE)        X(WSAENOPROTOOPT)
+               X(WSAEPROTONOSUPPORT)   X(WSAESOCKTNOSUPPORT)
+               X(WSAEOPNOTSUPP)        X(WSAEPFNOSUPPORT)
+               X(WSAEAFNOSUPPORT)      X(WSAEADDRINUSE)
+               X(WSAEADDRNOTAVAIL)     X(WSAENETDOWN)
+               X(WSAENETUNREACH)       X(WSAENETRESET)
+               X(WSAECONNABORTED)      X(WSAECONNRESET)
+               X(WSAENOBUFS)   X(WSAEISCONN)
+               X(WSAENOTCONN)  X(WSAESHUTDOWN)
+               X(WSAETOOMANYREFS)      X(WSAETIMEDOUT)
+               X(WSAECONNREFUSED)      X(WSAELOOP)
+               X(WSAENAMETOOLONG)      X(WSAEHOSTDOWN)
+               X(WSAEHOSTUNREACH)      X(WSAENOTEMPTY)
+               X(WSAEPROCLIM)  X(WSAEUSERS)
+               X(WSAEDQUOT)    X(WSAESTALE)
+               X(WSAEREMOTE)   X(WSASYSNOTREADY)
+               X(WSAVERNOTSUPPORTED)   X(WSANOTINITIALISED)
+               X(WSAEDISCON)   X(WSAENOMORE)
+               X(WSAECANCELLED)        X(WSAEINVALIDPROCTABLE)
+               X(WSAEINVALIDPROVIDER)  X(WSAEPROVIDERFAILEDINIT)
+               X(WSASYSCALLFAILURE)    X(WSASERVICE_NOT_FOUND)
+               X(WSATYPE_NOT_FOUND)    X(WSA_E_NO_MORE)
+               X(WSA_E_CANCELLED)      X(WSAEREFUSED)
+#undef X
+       }
+       snprintf ( errbuf, sizeof(errbuf), "Unknown socket error (%lu)", err );
+       errbuf[sizeof(errbuf)-1] = '\0';
+       return errbuf;
+#elif defined(UNIX)
+       perror(errbuf);
+       return errbuf;
+#else
+#  error unrecognized target
+#endif
+}
+#if defined(UNICODE) || defined(_UNICODE)
+in_addr_t suLookupAddress ( const wchar_t* pcHost )
+{
+       int len = wcslen(pcHost);
+       char* p = new char[len+1];
+       wcstombs ( p, pcHost, len );
+       p[len] = 0;
+       in_addr_t rc = suLookupAddress ( p );
+       delete[] p;
+       return rc;
+}
+bool suBroadcast ( SOCKET so, u_short port, const wchar_t* buf, int len /* = -1 */ )
+{
+       char* p = new char[len+1];
+       wcstombs ( p, buf, len );
+       p[len] = 0;
+       bool rc = suBroadcast ( so, port, p, len );
+       delete[] p;
+       return rc;
+}
+int suRecv ( SOCKET so, wchar_t* buf, int buflen, int timeout )
+{
+       char* p = new char[buflen+1];
+       int rc = suRecv ( so, p, buflen, timeout );
+       p[buflen] = 0;
+       mbstowcs ( buf, p, buflen );
+       delete[] p;
+       return rc;
+}
+int suRecvFrom ( SOCKET so, wchar_t* buf, int buflen, int timeout, sockaddr_in* from, int* fromlen )
+{
+       char* p = new char[buflen+1];
+       int rc = suRecvFrom ( so, p, buflen, timeout, from, fromlen );
+       p[buflen] = 0;
+       mbs2wcs ( buf, p, buflen );
+       delete[] p;
+       return rc;
+}
+bool suBind ( SOCKET so, const wchar_t* szInterfaceAddress, u_short iListenPort, bool bReuseAddr /* = false */ )
+{
+       int len = wcslen(szInterfaceAddress);
+       char* p = new char[len+1];
+       wcstombs ( p, szInterfaceAddress, len );
+       p[len] = 0;
+       bool rc = suBind ( so, p, iListenPort, bReuseAddr );
+       delete[] p;
+       return rc;
+}
+#endif//UNICODE
+
+suBufferedRecvSocket::suBufferedRecvSocket ( SOCKET so )
+       : suSocket ( so ), _off(0), _len(0)
+{
+}
+
+int suBufferedRecvSocket::recvUntil ( std::string& buf, char until, int timeout )
+{
+       if ( !_len )
+               _off = 0;
+       else if ( _off > (sizeof(_buf)>>1) )
+       {
+               memmove ( _buf, &_buf[_off], _len );
+               _off = 0;
+       }
+       char* poff = &_buf[_off];
+       for ( ;; )
+       {
+               char* p = (char*)memchr ( poff, until, _len );
+               if ( p /*&& p < &poff[_len]*/ )
+               {
+                       int ret_len = p-poff+1;
+                       buf.resize ( ret_len );
+                       memmove ( &buf[0], poff, ret_len );
+                       _off += ret_len;
+                       _len -= ret_len;
+                       return ret_len;
+               }
+               int rc = suRecv ( *this, &poff[_len], sizeof(_buf)-_len-_off, timeout );
+               if ( rc < 0 )
+               {
+                       if ( _len )
+                       {
+                               rc = _len;
+                               buf.resize ( rc );
+                               memmove ( &buf[0], &_buf[_off], rc );
+                               _len = 0;
+                       }
+                       return rc;
+               }
+               _len += rc;
+       }
+}
+
+void suBufferedRecvSocket::recvPending()
+{
+       if ( !_len )
+               _off = 0;
+       else if ( _off > (sizeof(_buf)>>1) )
+       {
+               memmove ( _buf, &_buf[_off], _len );
+               _off = 0;
+       }
+       char* poff = &_buf[_off];
+       while ( sizeof(_buf)-_len-_off )
+       {
+               int rc = suRecv ( *this, &poff[_len], sizeof(_buf)-_len-_off, 1 );
+               if ( rc <= 0 )
+                       break;
+               _len += rc;
+       }
+}
+
+bool suBufferedRecvSocket::recvInStr ( char c )
+{
+       return NULL != memchr ( &_buf[_off], c, _len );
+}
diff --git a/rosapps/games/ArchBlackmann/SockUtils.h b/rosapps/games/ArchBlackmann/SockUtils.h
new file mode 100644 (file)
index 0000000..60853f0
--- /dev/null
@@ -0,0 +1,132 @@
+// SockUtils.h - Declarations for the Winsock utility functions module.
+// (C) 2002-2004 Royce Mitchell III
+// This file is under the BSD & LGPL licenses
+
+#ifndef __SOCKUTILS_H
+#define __SOCKUTILS_H
+
+#include <string>
+#ifdef WIN32
+#  include <winsock2.h>
+#  define in_addr_t u_long
+#  define SUERRNO WSAGetLastError()
+#  define EADDRINUSE WSAEADDRINUSE
+#  define ENOTSOCK WSAENOTSOCK
+#  define socklen_t int
+#elif defined(UNIX)
+#  include <sys/types.h>
+#  include <sys/socket.h>
+#  include <netinet/in.h>
+#  include <unistd.h>
+#  include <errno.h>
+#  define closesocket(so) close(so)
+#  define SOCKET int
+#  define INVALID_SOCKET -1
+#  define SOCKET_ERROR -1
+#  define SUERRNO errno
+#  ifdef MACOSX
+#    define socklen_t int  //Stupid mac
+#  endif
+#else
+#  error unrecognized target
+#endif
+
+#include <assert.h>
+
+extern bool suStartup();
+extern SOCKET suTcpSocket();
+extern SOCKET suUdpSocket();
+extern bool suShutdownConnection(SOCKET sd);
+extern in_addr_t suLookupAddress ( const char* pcHost );
+extern bool suConnect ( SOCKET so, in_addr_t iAddress, u_short iPort );
+extern bool suConnect ( SOCKET so, const char* szAddress, u_short iPort );
+extern SOCKET suEstablishConnection ( in_addr_t iAddress, u_short iPort, int type );
+extern SOCKET suEstablishConnection ( const char* szAddress, u_short iPort, int type );
+extern bool suBroadcast ( SOCKET so, u_short port, const char* buf, int len = -1 );
+extern int suRecv ( SOCKET so, char* buf, int buflen, int timeout );
+extern int suRecvFrom ( SOCKET so, char* buf, int buflen, int timeout, sockaddr_in* from, socklen_t* fromlen );
+extern bool suBind ( SOCKET so, in_addr_t iInterfaceAddress, u_short iListenPort, bool bReuseAddr = false );
+extern bool suBind ( SOCKET so, const char* szInterfaceAddress, u_short iListenPort, bool bReuseAddr = false );
+extern bool suEnableBroadcast ( SOCKET so, bool bEnable = true );
+extern const char* suErrDesc ( int err );
+
+#if defined(UNICODE) || defined(_UNICODE)
+extern in_addr_t suLookupAddress ( const wchar_t* pcHost );
+extern bool suBroadcast ( SOCKET so, u_short port, const wchar_t* buf, int len = -1 );
+extern int suRecv ( SOCKET so, wchar_t* buf, int buflen, int timeout );
+extern int suRecvFrom ( SOCKET so, wchar_t* buf, int buflen, int timeout, sockaddr_in* from, int* fromlen );
+extern bool suBind ( SOCKET so, const wchar_t* szInterfaceAddress, u_short iListenPort, bool bReuseAddr = false );
+#endif//UNICODE
+
+class suSocket
+{
+       SOCKET _so;
+public:
+       suSocket ( SOCKET so = INVALID_SOCKET ) : _so(so)
+       {
+       }
+       const suSocket& operator = ( SOCKET so )
+       {
+               assert ( _so == INVALID_SOCKET ); // must Detach() or Close() existing socket first
+               _so = so;
+               return *this;
+       }
+       virtual ~suSocket()
+       {
+               Close();
+       }
+       void Close()
+       {
+               if ( _so != INVALID_SOCKET )
+               {
+                       //suShutdownConnection ( _so ); // TODO - only valid on TCP sockets
+                       closesocket ( _so );
+                       _so = INVALID_SOCKET;
+               }
+       }
+       operator SOCKET() const
+       {
+               return _so;
+       }
+       SOCKET Attach ( SOCKET so )
+       {
+               SOCKET old = Detach();
+               _so = so;
+               return old;
+       }
+       SOCKET Detach()
+       {
+               SOCKET so = _so;
+               _so = INVALID_SOCKET;
+               return so;
+       }
+
+private:
+       // disable copy semantics
+       suSocket ( const suSocket& );
+       const suSocket& operator = ( const suSocket& );
+};
+
+class suBufferedRecvSocket : public suSocket
+{
+       char _buf[2048];
+       int _off;
+       int _len;
+public:
+       suBufferedRecvSocket ( SOCKET so = INVALID_SOCKET );
+       int recvUntil ( std::string& buf, char until, int timeout );
+       void recvPending();
+       bool recvInStr ( char c );
+};
+
+class SockAddrIn : public sockaddr_in
+{
+public:
+       SockAddrIn(); // creates broadcast address
+       SockAddrIn ( const char* szAddr, u_short iPort );
+       SockAddrIn ( in_addr_t iAddr, u_short iPort );
+       operator sockaddr* () { return (sockaddr*)this; }
+       operator sockaddr_in* () { return (sockaddr_in*)this; }
+};
+
+#endif//__SOCKUTILS_H
diff --git a/rosapps/games/ArchBlackmann/SplitJoin.cpp b/rosapps/games/ArchBlackmann/SplitJoin.cpp
new file mode 100644 (file)
index 0000000..f7dd8a4
--- /dev/null
@@ -0,0 +1,96 @@
+// SplitJoin.cpp
+//
+// This code is copyright 2003-2004 Royce Mitchell III
+// and released under the BSD & LGPL licenses
+
+#ifdef _MSC_VER
+#pragma warning ( disable : 4786 ) // MSVC6 can't handle too-long template names
+#endif//_MSC_VER
+
+//#include <sstream>
+
+#include "SplitJoin.h"
+
+#include <string.h>
+
+using std::string;
+using std::vector;
+//using std::stringstream;
+
+static const char* quotes = "\"\'";
+
+bool Split ( vector<string>& vec, const char* csv, char sep, bool merge )
+{
+       string scsv ( csv );
+       char* col = &scsv[0];
+       vec.resize ( 0 );
+       for ( ;; )
+       {
+               char* p = col;
+               while ( isspace(*p) && *p != sep )
+                       p++;
+               char quote = 0;
+               if ( strchr ( quotes, *p ) )
+                       quote = *p++;
+               while ( *p && (*p != sep || quote) )
+               {
+                       if ( *p++ == quote )
+                               break;
+               }
+
+               while ( isspace(*p) && *p != sep )
+                       p++;
+
+               if ( *p && *p != sep )
+                       return false;
+
+               string scol ( col, p-col );
+
+               //quote = scol[0];
+               if ( quote )
+               {
+                       if ( scol[scol.size()-1] == quote )
+                               scol = string ( &scol[1], scol.size()-2 );
+               }
+
+               if ( scol.length() || !merge )
+                       vec.push_back ( scol );
+
+               if ( !*p )
+                       break;
+
+               col = p + 1;
+       }
+       return true;
+}
+
+bool Join ( string& csv, vector<string>& vec, char sep )
+{
+       csv.resize(0);
+       for ( int i = 0; i < vec.size(); i++ )
+       {
+               if ( i )
+                       csv += sep;
+               string& s = vec[i];
+               if ( strchr ( s.c_str(), sep ) )
+               {
+                       if ( strchr ( s.c_str(), '\"' ) )
+                       {
+                               if ( strchr ( s.c_str(), '\'' ) )
+                                       return false; // the sep, " and ' are all in the string, can't build valid output
+                               csv += '\'';
+                               csv += s;
+                               csv += '\'';
+                       }
+                       else
+                       {
+                               csv += '\"';
+                               csv += s;
+                               csv += '\"';
+                       }
+               }
+               else
+                       csv += s;
+       }
+       return true;
+}
diff --git a/rosapps/games/ArchBlackmann/SplitJoin.h b/rosapps/games/ArchBlackmann/SplitJoin.h
new file mode 100644 (file)
index 0000000..8f13114
--- /dev/null
@@ -0,0 +1,32 @@
+// SplitJoin.h
+//
+// This code is copyright 2003-2004 Royce Mitchell III
+// and released under the BSD & LGPL licenses
+
+#ifndef SPLITJOIN_H
+#define SPLITJOIN_H
+
+#include <vector>
+#include <string>
+
+bool Split (
+       std::vector<std::string>& vec,
+       const char* csv,
+       char sep=',',
+       bool merge=false );
+
+bool Join (
+       std::string& csv,
+       std::vector<std::string>& vec,
+       char sep=',' );
+
+inline bool Split (
+       std::vector<std::string>& vec,
+       const std::string& csv,
+       char sep=',',
+       bool merge=false )
+{
+       return Split ( vec, csv.c_str(), sep, merge );
+}
+
+#endif//SPLIT_H
diff --git a/rosapps/games/ArchBlackmann/ThreadPool.cpp b/rosapps/games/ArchBlackmann/ThreadPool.cpp
new file mode 100644 (file)
index 0000000..c545cd7
--- /dev/null
@@ -0,0 +1,240 @@
+// ThreadPool.cpp
+// This file is (C) 2003-2004 Royce Mitchell III
+// and released under the LGPL & BSD licenses
+
+#include <vector>
+using std::vector;
+#include "ThreadPool.h"
+#include "QueueT.h"
+#include "auto_vector.h"
+#include "verify.h"
+#include "ReliMT.h"
+
+class PoolableThread : public ActiveObject
+{
+public:
+       PoolableThread ( ThreadPoolImpl& );
+       ~PoolableThread()
+       {
+               Kill();
+       }
+       void InitThread();
+       void Run();
+       void FlushThread();
+
+       ThreadPoolImpl& _pool;
+};
+
+class ThreadPoolLaunchData
+{
+public:
+       ThreadPoolFunc* pFun;
+       void* pArg;
+};
+
+template <class T>
+class AtomicCounter : public Uncopyable
+{
+       Mutex _m;
+       T _t;
+public:
+       AtomicCounter ( T init = 0 ) : _t(init)
+       {
+       }
+       AtomicCounter ( const AtomicCounter<T>& t )
+       {
+               //Mutex::Lock l ( _m ); // don't need to lock since this is a ctor
+               Mutex::Lock l2 ( t._m );
+               _t = t._t;
+       }
+       const AtomicCounter<T>& operator = ( const AtomicCounter<T>& t )
+       {
+               Mutex::Lock l ( _m );
+               Mutex::Lock l2 ( t._m );
+               _t = t._t;
+               return *this;
+       }
+       T operator ++ ()
+       {
+               Mutex::Lock l ( _m );
+               T t = _t++;
+               return t;
+       }
+       const AtomicCounter<T>& operator ++ ( int )
+       {
+               Mutex::Lock l ( _m );
+               ++_t;
+               return *this;
+       }
+       T operator -- ()
+       {
+               Mutex::Lock l ( _m );
+               T t = _t--;
+               return t;
+       }
+       const AtomicCounter<T>& operator -- ( int )
+       {
+               Mutex::Lock l ( _m );
+               --_t;
+               return *this;
+       }
+       const AtomicCounter<T>& operator += ( T t )
+       {
+               Mutex::Lock l ( _m );
+               return _t += t;
+               return *this;
+       }
+       const AtomicCounter<T>& operator -= ( T t )
+       {
+               Mutex::Lock l ( _m );
+               return _t -= t;
+               return *this;
+       }
+       operator const T& () const
+       {
+               //Mutex::Lock l ( _m );
+               return _t;
+       }
+       T operator !() const
+       {
+               //Mutex::Lock l ( _m );
+               return !_t;
+       }
+};
+
+class ThreadPoolImpl : public Uncopyable
+{
+public:
+       ThreadPoolImpl() : _isDying(false), _idleThreads(0)
+       {
+       }
+
+       ~ThreadPoolImpl()
+       {
+       }
+
+       void Shutdown()
+       {
+               _isDying = true;
+               while ( _idleThreads )
+               {
+                       _threadWaitEvent.Release();
+                       _threadStartEvent.Wait(); // let thread actually get a grip
+               }
+       }
+
+       void Launch ( ThreadPoolFunc* pFun, void* pArg )
+       {
+               // this mutex is necessary to make sure we never have a conflict
+               // between checking !_idleThreads and the call to _threadStartEvent.Wait()
+               // basically if 2 threads call Launch() simultaneously, and there is only
+               // 1 idle thread, it's possible that a new thread won't be created to
+               // satisfy the 2nd request until an existing thread finishes.
+               Mutex::Lock launchlock ( _launchMutex );
+
+               ASSERT ( pFun );
+               ThreadPoolLaunchData* data;
+               {
+                       Mutex::Lock lock ( _vectorMutex );
+                       if ( !_spareData.size() )
+                               _spareData.push_back ( new ThreadPoolLaunchData() );
+                       data = _spareData.pop_back().release();
+                       if ( !_idleThreads )
+                               _threads.push_back ( new PoolableThread(*this) );
+               }
+
+               data->pFun = pFun;
+               data->pArg = pArg;
+               verify ( _pendingData.Add ( data ) );
+               _threadWaitEvent.Release(); // tell a thread to do it's thing...
+               _threadStartEvent.Wait(); // wait on a thread to pick up the request
+       }
+
+       // functions for threads to call...
+       ThreadPoolLaunchData* GetPendingData()
+       {
+               ThreadPoolLaunchData* data = NULL;
+               ++_idleThreads;
+               _threadWaitEvent.Wait(); // waits until there's a request
+               --_idleThreads;
+               _threadStartEvent.Release(); // tell requester we got it
+               if ( _isDying )
+                       return NULL;
+               _pendingData.Get ( data );
+               ASSERT ( data );
+               return data;
+       }
+
+       void RecycleData ( ThreadPoolLaunchData* data )
+       {
+               Mutex::Lock lock ( _vectorMutex );
+               _spareData.push_back ( data );
+       }
+
+       bool _isDying;
+       Mutex _vectorMutex, _launchMutex;
+       auto_vector<PoolableThread> _threads;
+       auto_vector<ThreadPoolLaunchData> _spareData;
+       CQueueT<ThreadPoolLaunchData*> _pendingData;
+       Event _threadWaitEvent, _threadStartEvent;
+       AtomicCounter<int> _idleThreads;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// ThreadPool
+
+/*static*/ ThreadPool& ThreadPool::Instance()
+{
+       static ThreadPool tp;
+       return tp;
+}
+
+ThreadPool::ThreadPool() : _pimpl ( new ThreadPoolImpl )
+{
+};
+
+ThreadPool::~ThreadPool()
+{
+       _pimpl->Shutdown();
+       delete _pimpl;
+       _pimpl = 0;
+}
+
+void ThreadPool::Launch ( ThreadPoolFunc* pFun, void* pArg )
+{
+       _pimpl->Launch ( pFun, pArg );
+}
+
+int ThreadPool::IdleThreads()
+{
+       return _pimpl->_idleThreads;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// PoolableThread
+
+PoolableThread::PoolableThread ( ThreadPoolImpl& pool ) : _pool(pool)
+{
+       Start();
+}
+
+void PoolableThread::InitThread()
+{
+}
+
+void PoolableThread::Run()
+{
+       ThreadPoolLaunchData* data;
+       while ( !_isDying )
+       {
+               data = _pool.GetPendingData(); // enter wait state if none...
+               if ( !data ) // NULL data means kill thread
+                       break;
+               (*data->pFun) ( data->pArg ); // call the function
+               _pool.RecycleData ( data );
+       }
+}
+
+void PoolableThread::FlushThread()
+{
+}
diff --git a/rosapps/games/ArchBlackmann/ThreadPool.h b/rosapps/games/ArchBlackmann/ThreadPool.h
new file mode 100644 (file)
index 0000000..84e36f3
--- /dev/null
@@ -0,0 +1,28 @@
+// ThreadPool.h
+// This file is (C) 2003-2004 Royce Mitchell III
+// and released under the LGPL & BSD licenses
+
+#ifndef THREADPOOL_H
+#define THREADPOOL_H
+
+#include "ReliMT.h"
+
+typedef void THREADAPI ThreadPoolFunc ( void* );
+
+class ThreadPoolImpl;
+
+class ThreadPool : public Uncopyable
+{
+public:
+       static ThreadPool& Instance();
+       ~ThreadPool();
+
+       void Launch ( ThreadPoolFunc* pFun, void* pArg );
+       int IdleThreads();
+
+private:
+       ThreadPool();
+       ThreadPoolImpl *_pimpl;
+};
+
+#endif// THREADPOOL_H
diff --git a/rosapps/games/ArchBlackmann/auto_ptr.h b/rosapps/games/ArchBlackmann/auto_ptr.h
new file mode 100644 (file)
index 0000000..861501e
--- /dev/null
@@ -0,0 +1,87 @@
+// auto_ptr.h
+// This file is (C) 2002-2003 Royce Mitchell III
+// and released under the LGPL & BSD licenses
+
+#ifndef AUTO_PTR_H
+#define AUTO_PTR_H
+
+template<class T>
+class auto_ptr
+{
+public:
+       typedef T element_type;
+
+       explicit auto_ptr(T *p = 0) : _p(p)
+       {
+       }
+
+       auto_ptr(auto_ptr<T>& rhs) : _p(rhs.release())
+       {
+       }
+
+       auto_ptr<T>& operator=(auto_ptr<T>& rhs)
+       {
+               if ( &rhs != this )
+               {
+                       dispose();
+                       _p = rhs.release();
+               }
+               return *this;
+       }
+
+       auto_ptr<T>& set ( auto_ptr<T>& rhs )
+       {
+               if ( &rhs != this )
+               {
+                       dispose();
+                       _p = rhs.release();
+               }
+               return *this;
+       }
+
+       ~auto_ptr()
+       {
+               dispose();
+       }
+
+       void dispose()
+       {
+               if ( _p )
+               {
+                       delete _p;
+                       _p = 0;
+               }
+       }
+
+       T& operator[] ( int i )
+       {
+               return _p[i];
+       }
+
+       T& operator*() const
+       {
+               return *_p;
+       }
+
+       T* operator->() const
+       {
+               return _p;
+       }
+
+       T* get() const
+       {
+               return _p;
+       }
+
+       T* release()
+       {
+               T* p = _p;
+               _p = 0;
+               return p;
+       }
+
+private:
+       T* _p;
+};
+
+#endif//AUTO_PTR_H
diff --git a/rosapps/games/ArchBlackmann/auto_vector.h b/rosapps/games/ArchBlackmann/auto_vector.h
new file mode 100644 (file)
index 0000000..cc07bb4
--- /dev/null
@@ -0,0 +1,141 @@
+// auto_vector.h
+// This file is (C) 2002-2004 Royce Mitchell III
+// and released under the LGPL & BSD licenses
+
+#ifndef AUTO_VECTOR_H
+#define AUTO_VECTOR_H
+
+#include <sys/types.h>
+#include "verify.h"
+#include "auto_ptr.h"
+
+template<class T>
+class auto_vector
+{
+public:
+       explicit auto_vector ( size_t capacity = 0 )
+               : _arr(0), _capacity(0), _end(0)
+       {
+               if ( capacity != 0 )
+                       _arr = new auto_ptr<T>[capacity];
+               _capacity = capacity;
+       }
+
+       ~auto_vector()
+       {
+               delete []_arr;
+       }
+
+       size_t size() const
+       {
+               return _end;
+       }
+
+       const auto_ptr<T>& operator [] ( size_t i ) const
+       {
+               ASSERT ( i < _end );
+               return _arr[i];
+       }
+
+       auto_ptr<T>& operator [] ( size_t i )
+       {
+               ASSERT ( i < _end );
+               return _arr[i];
+       }
+
+       void assign ( size_t i, auto_ptr<T>& p )
+       {
+               ASSERT ( i < _end );
+               _arr[i] = p;
+       }
+
+       void assign_direct ( size_t i, T * p )
+       {
+               ASSERT ( i < _end );
+               reserve ( i + 1 );
+               _arr[i].reset ( ptr );
+       }
+
+       void push_back ( auto_ptr<T>& p )
+       {
+               reserve ( _end + 1 );
+               _arr[_end++] = p;
+       }
+
+       auto_ptr<T>& back()
+       {
+               ASSERT ( _end != 0 );
+               return _arr[_end-1];
+       }
+
+       void push_back ( T * p )
+       {
+               reserve ( _end + 1 );
+               auto_ptr<T> tmp(p);
+               _arr[_end++] = tmp;
+               //GCC is pedantic, this is an error.
+               //_arr[_end++] = auto_ptr<T>(p);
+       }
+
+       auto_ptr<T> pop_back()
+       {
+               ASSERT ( _end != 0 );
+               if ( !_end )
+               {
+                       auto_ptr<T> tmp((T*)0);
+                       return tmp;
+                       //GCC, this is an error.
+                       //return auto_ptr<T>(NULL);
+               }
+               return _arr[--_end];
+       }
+
+       void resize ( size_t newSize )
+       {
+               ASSERT ( newSize >= 0 );
+               reserve ( newSize ); // make sure we have at least this much room
+               _end = newSize;
+       }
+
+       void reserve ( size_t reqCapacity )
+       {
+               if ( reqCapacity <= _capacity )
+                       return;
+               size_t newCapacity = 2 * _capacity;
+               if ( reqCapacity > newCapacity )
+                       newCapacity = reqCapacity;
+               // allocate new array
+               auto_ptr<T> * arrNew = new auto_ptr<T> [newCapacity];
+               // transfer all entries
+               for ( size_t i = 0; i < _capacity; ++i )
+                       arrNew[i] = _arr[i];
+               _capacity = newCapacity;
+               // free old memory
+               delete[] _arr;
+               // substitute new array for old array
+               _arr = arrNew;
+       }
+
+       void remove ( size_t off )
+       {
+               size_t last = _end-1;
+               if ( off == last )
+                       resize ( last );
+               else if ( off < last )
+               {
+                       auto_ptr<T> tmp ( pop_back().release() );
+                       _arr[off] = tmp;
+               }
+       }
+
+       //typedef const_auto_iterator<T> const_iterator;
+       //const_iterator begin () const { return _arr; }
+       //const_iterator end () const { return _arr + _end; }
+
+private:
+       auto_ptr<T>  *_arr;
+       size_t        _capacity;
+       size_t        _end;
+};
+
+#endif//AUTO_VECTOR_H
diff --git a/rosapps/games/ArchBlackmann/base64.cpp b/rosapps/games/ArchBlackmann/base64.cpp
new file mode 100644 (file)
index 0000000..6fdc852
--- /dev/null
@@ -0,0 +1,58 @@
+// base64.cpp
+
+#include "base64.h"
+
+using std::string;
+
+static const char* alfabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+string base64_encode ( const string& sInput )
+{
+       unsigned char x=0, topbit=0;
+       int v=0;
+       string sOutput;
+       do
+       {
+               if ( topbit < 6 )
+               {
+                       x++;
+                       v <<= 8;
+                       if ( x <= sInput.length() ) v += sInput[x-1];
+                       topbit += 8;
+               }
+               topbit -= 6;
+               if ( x > sInput.length() && !v )
+                       break;
+               sOutput += alfabet[(v >> topbit) & 63];
+               v &= (1 << topbit) - 1;
+       } while ( x < sInput.length() || v );
+       int eq = (8 - (sOutput.length() % 4)) % 4;
+       while ( eq-- )
+               sOutput += '=';
+       return sOutput;
+}
+
+string base64_decode ( const string& sInput )
+{
+       unsigned char x=0, topbit=0;
+       int v=0, inlen = sInput.length();
+       string sOutput;
+       while ( inlen && sInput[inlen-1] == '=' )
+               inlen--;
+       do
+       {
+               while ( topbit < 8 )
+               {
+                       x++;
+                       v <<= 6;
+                       if ( x <= inlen ) v += (strchr(alfabet, sInput[x-1]) - alfabet);
+                       topbit += 6;
+               }
+               topbit -= 8;
+               if ( x > inlen && !v )
+                       break;
+               sOutput += (char)((v >> topbit) & 255);
+               v &= ((1 << topbit) - 1);
+       } while ( x <= inlen || v );
+       return sOutput;
+}
diff --git a/rosapps/games/ArchBlackmann/base64.h b/rosapps/games/ArchBlackmann/base64.h
new file mode 100644 (file)
index 0000000..e307b7a
--- /dev/null
@@ -0,0 +1,12 @@
+// base64.h
+
+#ifndef BASE64_H
+#define BASE64_H
+
+#include <string>
+
+std::string base64_encode ( const std::string& s );
+
+std::string base64_decode ( const std::string& s );
+
+#endif//BASE64_H
diff --git a/rosapps/games/ArchBlackmann/chomp.cpp b/rosapps/games/ArchBlackmann/chomp.cpp
new file mode 100644 (file)
index 0000000..5a3a208
--- /dev/null
@@ -0,0 +1,15 @@
+// chomp.cpp
+// This file is (C) 2004 Royce Mitchell III
+// and released under the BSD & LGPL licenses
+
+#include "chomp.h"
+
+std::string chomp ( const std::string& s )
+{
+       const char* p = &s[0];
+       const char* p2 = &s[0] + s.size();
+       while ( p2 > p && strchr("\r\n", p2[-1]) )
+               p2--;
+       return std::string ( p, p2-p );
+}
+
diff --git a/rosapps/games/ArchBlackmann/chomp.h b/rosapps/games/ArchBlackmann/chomp.h
new file mode 100644 (file)
index 0000000..80bd8dc
--- /dev/null
@@ -0,0 +1,13 @@
+// chomp.h
+// This file is (C) 2004 Royce Mitchell III
+// and released under the BSD & LGPL licenses
+
+#ifndef CHOMP_H
+#define CHOMP_H
+
+#include <string>
+
+std::string chomp ( const std::string& s );
+
+#endif//TRIM_H
+
diff --git a/rosapps/games/ArchBlackmann/cram_md5.cpp b/rosapps/games/ArchBlackmann/cram_md5.cpp
new file mode 100644 (file)
index 0000000..dfaf771
--- /dev/null
@@ -0,0 +1,23 @@
+// cram_md5.cpp
+// This file is (C) 2004 Royce Mitchell III
+// and released under the BSD & LGPL licenses
+
+#include "md5.h"
+#include "cram_md5.h"
+#include "base64.h"
+
+using std::string;
+
+string cram_md5 ( const string& username, const string& password, const string& greeting )
+{
+       string challenge = base64_decode ( greeting );
+
+       string hmac = HMAC_MD5 ( password, challenge );
+       //printf ( "(cram_md5): hmac = %s\n", hmac.c_str() );
+       string raw_response = username;
+       raw_response += " ";
+       raw_response += hmac;
+       //printf ( "(cram_md5): raw_response = %s\n", raw_response.c_str() );
+
+       return base64_encode ( raw_response );
+}
diff --git a/rosapps/games/ArchBlackmann/cram_md5.h b/rosapps/games/ArchBlackmann/cram_md5.h
new file mode 100644 (file)
index 0000000..c0741b8
--- /dev/null
@@ -0,0 +1,15 @@
+// cram_md5.h
+// This file is (C) 2004 Royce Mitchell III
+// and released under the BSD & LGPL licenses
+
+#ifndef CRAM_MD5_H
+#define CRAM_MD5_H
+
+#include <string>
+
+std::string cram_md5 (
+       const std::string& username,
+       const std::string& password,
+       const std::string& greeting );
+
+#endif//CRAM_MD5_H
diff --git a/rosapps/games/ArchBlackmann/panic.cpp b/rosapps/games/ArchBlackmann/panic.cpp
new file mode 100644 (file)
index 0000000..3ad0604
--- /dev/null
@@ -0,0 +1,34 @@
+// panic.cpp
+// This file is (C) 2003-2004 Royce Mitchell III
+// and released under the BSD & LGPL licenses
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#ifdef WIN32
+#include <conio.h>
+#include <windows.h>
+#endif//WIN32
+#include "panic.h"
+
+void panic ( const char* format, ... )
+{
+       va_list arg;
+       int done;
+
+       va_start(arg, format);
+#if defined(WIN32) && !defined(_CONSOLE)
+       char buf[4096];
+       _vsnprintf ( buf, sizeof(buf)-1, format, arg );
+       MessageBox ( NULL, buf, "Panic!", MB_OK|MB_ICONEXCLAMATION );
+#else
+       done = vprintf(format, arg);
+       printf ( "\n" );
+#endif
+       va_end(arg);
+#if defined(WIN32) && defined(_CONSOLE)
+       printf ( "Press any key to exit\n" );
+       (void)getch();
+#endif//WIN32 && _CONSOLE
+       exit ( -1 );
+}
diff --git a/rosapps/games/ArchBlackmann/panic.h b/rosapps/games/ArchBlackmann/panic.h
new file mode 100644 (file)
index 0000000..e15cafa
--- /dev/null
@@ -0,0 +1,18 @@
+// panic.h
+// This file is (C) 2003-2004 Royce Mitchell III
+// and released under the BSD & LGPL licenses
+
+#ifndef PANIC_H
+#define PANIC_H
+
+void panic ( const char* format, ... );
+
+#define suAssert(expr) if ( !(expr) ) panic ( "%s(%lu): SOCKET ERROR %s\nExpression: %s\n", __FILE__, __LINE__, suErrDesc(SUERRNO), #expr )
+
+#if defined(DEBUG) || defined(_DEBUG)
+#  define suVerify(expr) suAssert(expr)
+#else
+#  define suVerify(expr) expr
+#endif
+
+#endif//PANIC_H
diff --git a/rosapps/games/ArchBlackmann/trim.cpp b/rosapps/games/ArchBlackmann/trim.cpp
new file mode 100644 (file)
index 0000000..c721f25
--- /dev/null
@@ -0,0 +1,17 @@
+// trim.cpp
+// This file is (C) 2004 Royce Mitchell III
+// and released under the BSD & LGPL licenses
+
+#include "trim.h"
+
+std::string trim ( const std::string& s )
+{
+       const char* p = &s[0];
+       const char* p2 = p + s.size();
+       while ( *p == ' ' )
+               p++;
+       while ( p2 > p && p2[-1] == ' ' )
+               p2--;
+       return std::string ( p, p2-p );
+}
+
diff --git a/rosapps/games/ArchBlackmann/trim.h b/rosapps/games/ArchBlackmann/trim.h
new file mode 100644 (file)
index 0000000..4f2ba72
--- /dev/null
@@ -0,0 +1,13 @@
+// trim.h
+// This file is (C) 2004 Royce Mitchell III
+// and released under the BSD & LGPL licenses
+
+#ifndef TRIM_H
+#define TRIM_H
+
+#include <string>
+
+std::string trim ( const std::string& s );
+
+#endif//TRIM_H
+
diff --git a/rosapps/games/ArchBlackmann/verify.h b/rosapps/games/ArchBlackmann/verify.h
new file mode 100644 (file)
index 0000000..5d491cf
--- /dev/null
@@ -0,0 +1,37 @@
+// verify.h
+// This code is (C) 2003-2004 Royce Mitchell III
+// and released under the LGPL & BSD licenses
+
+#ifndef VERIFY_H
+#define VERIFY_H
+
+//#include <assert.h>
+
+#ifdef ASSERT
+#undef ASSERT
+#endif//ASSERT
+
+#include "panic.h"
+
+#if defined(DEBUG) || defined(_DEBUG)
+inline void AssertHandler ( bool b, const char* str )
+{
+       if ( !b )
+               panic ( str );
+}
+#  define ASSERT(x) AssertHandler((x) ? true : false, #x )
+#else
+#  define ASSERT(x)
+#endif
+
+#ifdef verify
+#undef verify
+#endif//verify
+
+#if defined(DEBUG) || defined(_DEBUG)
+#  define verify(x) ASSERT(x)
+#else
+#  define verify(x) x
+#endif
+
+#endif//VERIFY_H