Commits

Palmer, 2E0EOL committed d88721e

Entire changeset 0.0.15 -> 0.0.16

  • Participants
  • Parent commits fe5b3d2
  • Tags overchat-0.0.16

Comments (0)

Files changed (203)

 at http://www.daybologic.co.uk/overchat/ChangeLog.txt
 at least every server release.
 
+0.0.16
+------
+DDRP: DIR macro to replace explict ls use in GNU makefiles
+DDRP: Use ls -1 not ls -l1 to support other Unices
+DDRP: New privellege levels defined, obsoletes older system
+DDRP: TX/RX EOB debugging code added
+DDRP: mailall call to mail - vulnerabillity fixed
+DDRP: Remove redundant initialisation of TX/RX node
+DDRP: Merged ddrpansi module into Blake and corrected calls
+DDRP: Added blake_EmailCompare() and friends
+DDRP: Blake: Added string trimmers
+DDRP: Blake: Make error messages recoverable incase of blakeNotStarted
+DDRP: Add convdb2 to convert to server database revsion 2
+DDRP: chroot'ed overchatd daemon
+DDRP: Lots of ocquery improvements
+Jeff: TOS changes (R2)
+DDRP: Add blake_GetClearanceString()
+DDRP: Binary database revsion 2
+DDRP: Daemonize only in release builds
+DDRP: Fix: Only lock database in question in blakedb
+DDRP: Add blake_ExclusiveFileOpen(), blake_ExclusiveFileClose()
+DDRP: Portable file extensions in Blake's GNU Makefile
+DDRP: Blake's logger modularised for global internal access
+DDRP: Language functions added to Blake
+DDRP: Move hardcoded language macros to Blake
+DDRP: PTH location now specified by pth.conf
+DDRP: Test for lock failures in server authenticator
+DDRP: PID file for overchatd
+
 0.0.15
 ------
 DDRP: Export Blake nickname fuctions which had no BLAKEAPI declarations
 include MasterMake.gnu
 
 # Master build rule
-all : _daybodep depend tools memory_debugger libs blake_lib overchat cgi _clients
+all : _daybodep depend basictools memory_debugger libs blake_lib overchat cgi _clients _supdae advtools _testbed
 	cd buildtimer ; $(TMAKE) -f $(THISFILE) stop
-	@echo Build complete
+	@echo Build complete.  You may want to run a make test
 
 _daybodep:
 	cd daybodep && $(TMAKE) -f Makefile_oc.gnu
 	cd src && $(TMAKE) -f $(THISFILE) depend
 	cd testbed && $(TMAKE) -f $(THISFILE) depend
 
-tools:
+basictools:
 	@echo "------------------------------------------------"
 	@echo "                                                "
 	@echo "  Stage 2                                       "
-	@echo "  Build compilation support tools               "
+	@echo "  Basic tools                                   "
 	@echo "                                                "
 	@echo "------------------------------------------------"
 	@echo
 	@echo "------------------------------------------------"
 	cd src ; $(TMAKE) -f $(THISFILE)
 
+test:
+	cd testbed && $(TMAKE) -f $(THISFILE) run
+
 mrproper : clean
 	-rm -rf .depend .resp
 
-clean : clients_clean cgi_clean overchat_clean blake_lib_clean dlini_lib_clean memory_debugger_clean tools_clean daybodep_clean
+clean : testbed_clean advtools_clean supdae_clean clients_clean cgi_clean overchat_clean blake_lib_clean dlini_lib_clean memory_debugger_clean basictools_clean daybodep_clean
 	-rm -f core overchatd.core
 
 overchat_clean:
 dlini_lib_clean:
 	cd dlini ; $(TMAKE) -f $(THISFILE) clean
 
-tools_clean:
+basictools_clean:
 	cd buildnum ; $(TMAKE) -f $(THISFILE) clean
 	cd blakemake ; $(TMAKE) -f $(THISFILE) clean
 	cd raw2c ; $(TMAKE) -f $(THISFILE) clean
 clients_clean:
 	cd clients ; $(TMAKE) -f $(THISFILE) clean
 
+_supdae:
+	@echo "------------------------------------------------"
+	@echo "                                                "
+	@echo "  Stage 8                                       "
+	@echo "  Supplementry daemons                          "
+	@echo "                                                "
+	@echo "------------------------------------------------"
+	cd ocquery ; $(TMAKE) all
+
+supdae_clean:
+	cd ocquery ; $(TMAKE) clean
+
+
+advtools:
+	@echo "------------------------------------------------"
+	@echo "                                                "
+	@echo "  Stage 9                                       "
+	@echo "  Advanced tools                                "
+	@echo "                                                "
+	@echo "------------------------------------------------"
+	cd convdb2 && $(TMAKE) -f $(THISFILE) all
+
+advtools_clean:
+	cd convdb2 && $(TMAKE) -f $(THISFILE) clean
+
+_testbed:
+	@echo "------------------------------------------------"
+	@echo "                                                "
+	@echo "  Stage 10                                      "
+	@echo "  The testbed                                   "
+	@echo "                                                "
+	@echo "------------------------------------------------"
+	cd testbed ; $(TMAKE) -f $(THISFILE) all
+
+testbed_clean:
+	cd testbed ; $(TMAKE) -f $(THISFILE) clean
+
 #
 # This rule ensures the OverChat global build number (OBN) is updated before the main
 # codebase is built.
 # that DEBUG is defined, otherwise comment it out.
 #DEBUG=1
 
+# If you want to use the new binary databases (R2) on the server and ocquery
+# you need to uncomment this line.
+BLAKEDB_R2=1
+
 # This specifies the default name of the makefile, don't remove it,
 # it's not optional.
 THISFILE=Makefile.gnu
 
+# This command lists the files in a directory, line by line
+# we had problems with ls -l1 and now use ls -1, perhaps we will make our
+# own tools if ls gives us any more problems.
+DIR=ls -1
+
 # The very strict ruleset applied to certain files.  If the build is broken
 # you might try altering this.
 ANSI=-ansi -pedantic -Wall
 
 endif
 
+#
+# Filenme extensions section
+# This deals with differently named files on different systems,
+# for example Borland uses obj and UNIX uses o for object.
+# EXE file sometimes have an extension, sometimes not.
+# For all new makefiles please use these macros.
+#
+
+LIB=.a
+O=.o
+EXE=
+C=.c
+CPP=.cpp
+H=.h
+
+# Legacy database support.  Use the macro DB in the compiler flags of any
+# module which needs access to the user database.
+ifdef BLAKEDB_R2
+DB=-DBLAKEDB_R2=1
+else
+DB=
+endif

blake/Makefile.bor

           blakedb.obj \
           blake_nick.obj \
           blake_portthread.obj \
-          blake_trace.obj
+          blake_trace.obj \
+          blake_ansi.obj \
+          blake_strfunc.obj
 
 BLAKE_RES_OBJ=res\btfuck.obj \
               res\ddrp00.obj \
 	tlib ..\blake.lib +blake_nick.obj
 	tlib ..\blake.lib +blake_portthread.obj
 	tlib ..\blake.lib +blake_trace.obj
+	tlib ..\blake.lib +blake_ansi.obj
+	tlib ..\blake.lib +blake_strfunc.obj
 	tlib ..\blake.lib +res\btfuck.obj
 	tlib ..\blake.lib +res\ddrp00.obj
 	tlib ..\blake.lib +res\murder_microsoft.obj
 	echo blake_nick.obj + >> $(TMPLINKFILE)
 	echo blake_portthread.obj + >> $(TMPLINKFILE)
 	echo blake_trace.obj + >> $(TMPLINKFILE)
+	echo blake_ansi.obj + >> $(TMPLINKFILE)
+	echo blake_strfunc.obj + >> $(TMPLINKFILE)
 	echo $(MAKEDIR)\..\lib\cw32mti.lib + > $(TMPLINKFILE2)
 	echo $(MAKEDIR)\..\lib\import32.lib + >> $(TMPLINKFILE2)
 	echo ..\dpcrtlmm\dpcrtlmm.lib + >> $(TMPLINKFILE2)
 	$(ERASE) blake_portmutant.obj
 	$(ERASE) blake_protocol.obj
 	$(ERASE) blake_trace.obj
+	$(ERASE) blake_ansi.obj
+	$(ERASE) blake_strfunc.obj
 	$(ERASE) criticalinteger.obj
 	$(ERASE) recursivemutant.obj
 	$(ERASE) blakedb.obj

blake/Makefile.gnu

 LFLAGS=$(MASTER_LFLAGS) ../libblake.a ../dpcrtlmm/libdpcrtlmm.a ../dlini/libdlini.a -pthread
 COMPILE=$(CC) $(CFLAGS)
 
-OBJECTS=blake.o \
-        blake_cb.o \
-        blake_fastqueue.o \
-        blake_ll.o \
-        blake_main.o \
-        blake_network.o \
-        blake_nick.o \
-        blake_pendingloop.o \
-        blake_portmutant.o \
-        blake_portthread.o \
-        blake_protocol.o \
-        blake_socket.o \
-        blakedb.o \
-        criticalinteger.o \
-        recursivemutant.o \
-        blake_trace.o
+#BLAKEDB_R2 is the new binary database revsion 2 which is a lot faster
+#than the old ini system
+ifdef BLAKEDB_R2
+BLAKEDBO=blakedb2.o
+else
+BLAKEDBO=blakedb1.o
+endif
 
-RESFILES=res/btfuck.o \
-         res/ddrp00.o \
-         res/murder_microsoft.o \
-         res/sbeast.o
+OBJECTS=blake$(O) \
+        blake_cb$(O) \
+        blake_fastqueue$(O) \
+        blake_ll$(O) \
+        blake_main$(O) \
+        blake_network$(O) \
+        blake_nick$(O) \
+        blake_pendingloop$(O) \
+        blake_portmutant$(O) \
+        blake_portthread$(O) \
+        blake_protocol$(O) \
+        blake_socket$(O) \
+        blake_ansi$(O) \
+        blake_strfunc$(O) \
+        blake_trace$(O) \
+        blake_fs$(O) \
+        blake_logger$(O) \
+        blake_lang$(O) \
+        $(BLAKEDBO) \
+        criticalinteger$(O) \
+        recursivemutant$(O)
+
+RESFILES=res/btfuck$(O) \
+         res/ddrp00$(O) \
+         res/murder_microsoft$(O) \
+         res/sbeast$(O)
 
 all : displayflags all2
 
 blake_res:
 	cd res ; gmake -f $(THISFILE)
 
-queuetest : queuetest.o ../libblake.a ../dlini/libdlini.a
+queuetest : queuetest$(O) ../libblake$(LIB) ../dlini/libdlini$(LIB)
 	@echo Linking queuetest
-	@$(CC) -oqueuetest queuetest.o $(LFLAGS)
+	@$(CC) -oqueuetest queuetest$(O) $(LFLAGS)
 
-dllclient : dllclient.o ../libblake.a
+dllclient : dllclient$(O) ../libblake$(LIB)
 	@echo Linking dllclient
-	@$(CC) -odllclient dllclient.o $(LFLAGS)
+	@$(CC) -odllclient dllclient$(O) $(LFLAGS)
 
-../libblake.a : $(OBJECTS) blake_res
-	@echo Building archive ../libblake.a
-	@ar cru ../libblake.a $(OBJECTS) $(RESFILES)
+../libblake$(LIB) : $(OBJECTS) blake_res
+	@echo Building archive ../libblake$(LIB)
+	@ar cru ../libblake$(LIB) $(OBJECTS) $(RESFILES)
 
 
 # Automatic rule for all the rest of the C files in Blake
-.c.o:
+$(C)$(O):
 	@echo Compiling blake/$<
 	@$(COMPILE) $<
 
 	-$(RM) $(OBJECTS)
 	echo " " > .depend
 	-$(RM) .resp
-	-$(RM) ../libblake.a
-	-$(RM) queuetest queuetest.o
-	-$(RM) dllclient dllclient.o
+	-$(RM) ../libblake$(LIB)
+	-$(RM) queuetest queuetest$(O)
+	-$(RM) dllclient dllclient$(O)
 	cd res ; gmake -f $(THISFILE) clean
 
 depend:
-	ls -l1 *.c *.h *.rh > .resp
+	$(DIR) *$(C) *$(H) *.rh > .resp
 	../daybodep/daybodep $(IPATH) @.resp > .depend
 
 
 */
 enum blakeError {
   blakeSuccess,
-  blakeNotEnoughMem,    /* Not enough memory to complete the operation */
-  blakeInvalidParam,    /* Passed parameters were not acceptable */
-  blakeNoCallback,      /* No callback could process the packet or event */
-  blakeCallbackFail,    /* The callback routine returned failure */
-  blakeBufferTooSmall,  /* The buffer supplied was not large enough */
-  blakeNotStarted,      /* This means blake_Init() was not called, don't rely on this, some functions may not check that blake_Init() was called. */
-  blakeProtoNoSupport,  /* The network protocol is not supported */
-  blakeBindFailure,     /* The sockets routine bind() failed */
-  blakeConnRefused,     /* Connection to the remote end was refused. */
-  blakeTimedOut,        /* The connection timed out or was firewalled */
-  blakeNetDown,         /* The network is down */
-  blakeUnknownNetError, /* The network error is unknown or unhandled, report the code to DDRP */
-  blakeRegAlready,      /* Something was already registered */
-  blakeBadObject,       /* An unitialised or unknown/unregistered object was passed for working on */
-  blakeQueueFull,       /* A fixed size queue was full, dynamic queues return NotEnoughMem instead */
-  blakeUnknownFailure,  /* Catch all condition or user tampering with data structures */
-  blakeQueueEmpty,      /* The queue is empty */
-  blakeUnsupported,     /* The function is not supported or not written yet */
-  blakeMismatch,        /* Structure alignment or version mismatch */
-  blakeLimit,           /* A hard coded limit was reached. */
-  blakeDbFull,          /* The database is full. */
-  blakeDbAccessWrite,   /* Unable to write to the database at this time */
-  blakeDbAccessRead     /* Unable to access the database (read) */
+  blakeNotEnoughMem,        /* Not enough memory to complete the operation */
+  blakeInvalidParam,        /* Passed parameters were not acceptable */
+  blakeNoCallback,          /* No callback could process the packet or event */
+  blakeCallbackFail,        /* The callback routine returned failure */
+  blakeBufferTooSmall,      /* The buffer supplied was not large enough */
+  blakeNotStarted,          /* This means blake_Init() was not called, don't rely on this, some functions may not check that blake_Init() was called. */
+  blakeProtoNoSupport,      /* The network protocol is not supported */
+  blakeBindFailure,         /* The sockets routine bind() failed */
+  blakeConnRefused,         /* Connection to the remote end was refused. */
+  blakeTimedOut,            /* The connection timed out or was firewalled */
+  blakeNetDown,             /* The network is down */
+  blakeUnknownNetError,     /* The network error is unknown or unhandled, report the code to DDRP */
+  blakeRegAlready,          /* Something was already registered */
+  blakeBadObject,           /* An unitialised or unknown/unregistered object was passed for working on */
+  blakeQueueFull,           /* A fixed size queue was full, dynamic queues return NotEnoughMem instead */
+  blakeUnknownFailure,      /* Catch all condition or user tampering with data structures */
+  blakeQueueEmpty,          /* The queue is empty */
+  blakeUnsupported,         /* The function is not supported or not written yet */
+  blakeMismatch,            /* Structure alignment or version mismatch */
+  blakeLimit,               /* A hard coded limit was reached. */
+  blakeDbFull,              /* The database is full. */
+  blakeDbAccessWrite,       /* Unable to write to the database at this time */
+  blakeDbAccessRead,        /* Unable to access the database (read) */
+  blakeExclusiveFileFailure /* Can't open a file for exclusive access */
 };
 
 /*
   langPortuguese
 };
 
+#define OVERCHAT_NUMLANGUAGES (6) /* 6 Supported languages currently */
+#define OVERCHAT_DEFLANG (langEnglish) /* In ignorance of user's language we always presume English */
+
 enum blakeExchange {      /* AIM-like codes for different exchange virtual servers.  Used for chats */
   allRooms,               /* Not normally acceptable, works for kill */
   guestRooms,             /* Rooms reserved for guests, normal users may NOT enter this area */
   blrOpenBlakeDisallowed     /* No Open Blake user from any proxy */
 };
 
+/*
+  Privelleges are used internally by the server and are requested by
+  clients.  Use one of the privelleges here, if it corrosponds to the value
+  in your account you will be awarded the privellege.  See titles.txt
+  for more information of titles and privelleges.
+*/
+/* Ordinary mortals */
+#define CLEARANCE_ZERO (0)
+#define CLEARANCE_UNAUTHORISED (CLEARANCE_ZERO)
+#define CLEARANCE_GUEST (1) /* May not be supported */
+#define CLEARANCE_ROOKIE (2) /* 99% of users! */
+#define CLEARANCE_LESSER_BETA_TESTER (3)
+#define CLEARANCE_ROOKIE_REPRESENTITIVE (4)
+#define CLEARANCE_ROOKIE_WHIP (5)
+#define CLEARANCE_ROOKIE_WHIP_CHAIRMAN (6)
+#define CLEARANCE_USER_REPRESENTITVE (7)
+/* Officers */
+#define CLEARANCE_SERVICE_CONTROLLER (108)
+#define CLEARANCE_HEAD_CONTROLLER (109)
+#define CLEARANCE_COMMITTEE (110)
+#define CLEARANCE_COMMITTEE_CHAIRMAN (111)
+#define CLEARANCE_FINANCIAL_ADVISOR (112)
+#define CLEARANCE_SPIRITUAL_ADVISOR (113)
+/* Programmers */
+#define CLEARANCE_GREATER_BETA_TESTER (214)
+#define CLEARANCE_CODE_PATCHER (215)
+#define CLEARANCE_PROGRAMMER (216)
+#define CLEARANCE_SYSTEM_DESIGNER (217)
+#define CLEARANCE_DLOB_ENGINEER (218)
+#define CLEARANCE_BLAKE_ENGINEER (219)
+#define CLEARANCE_ENGINEER (220)
+/* The gods */
+#define CLEARANCE_PROPHET (248)
+#define CLEARANCE_PROPHET_HEAD (249)
+#define CLEARANCE_FLOATING_SPECTARE (250)
+#define CLEARANCE_SUPERIOR_MYSTIC_CONTROLLER (251)
+#define CLEARANCE_HOLOGRAPHIC_DICTATOR (252)
+#define CLEARANCE_INVINSIBLE_ABSOLUTE_DICTATOR (253)
+#define CLEARANCE_SUPREME_COMMANDER (254)
+#define CLEARANCE_ROOT (255) /* Reserved for the system */
+
+#define CLEARANCE_DEFAULT (CLEARANCE_ROOKIE) /* New users start out life as rookies */
+
 /* Declaration of fixed type blake_byte_t */
 typedef unsigned char blake_byte_t;
 /* Declaration of fixed type blake_word8_t */
   This structure defines a user, their total information.  Many of the
   database functions expect a pointer to such a structure but many only
   use certain information and ignore those parts which are not required
-  in the current context.
+  in the current context.  In revision 2 of the database these are actually
+  stored like this in binary format in the file.
 */
 struct blakedb_User {
   char UserName[OVERCHAT_NICK_LIMIT+1];
   char Email[OVERCHAT_EMAIL_LIMIT+1];
   blake_word16_t ClearanceLevel; /* Possibly obsolete */
   struct {
-    time_t Creation, LastSeen;
+    time_t Registration, LastSeen, RecordCreation;
   } TimeOf;
   blake_word32_t LoginCount;
   blake_word16_t WarningLevel;
   blake_word32_t BrowniePoints;
   blake_word32_t KickCount;
   blake_word16_t KillCount;
+  blake_word8_t Deleted;
+  char Space[128]; /* A little room for upgrades */
 };
+#define BLAKEDB_USERSZ ( (OVERCHAT_NICK_LIMIT)+1 + (OVERCHAT_PASS_LIMIT)+1 + (OVERCHAT_EMAIL_LIMIT)+1 + 2 + (4 * 3) + 4 + 2 + 2 + 4 + 4 + 2 + 1 + 128)
+
+/*
+  This structure describes the header inside the database and is only used
+  when the server reads the database, is is no use the clients.  Attention
+  should be paid to the signature and revision to avoid reading the wrong
+  file or an outdated file.
+*/
+struct blakedb_Header {
+  blake_word32_t Sig;
+  blake_word16_t Revision;
+  char Copyright[250];
+};
+#define BLAKEDB_HEADERSZ ( 4 + 2 + 250 )
+
+/* Some of the values which are always the same in the above header */
+#define BLAKEDB_HEADER_SIG (0x5692fc33)
+#define BLAKEDB_HEADER_REVISION (2)
+#define BLAKEDB_HEADER_COPYRIGHT "OverChat Database revision 2 (C)2002 Daybo Logic, all rights reserved.  www.daybologic.com/overchat"
 
 /*
   This type, BLAKE_DATABASE_HANDLE, is a handle which is used to access
 
 /*
   blakedb_LockDatabase( )
-  Provides mutual exclusion of database files.  I highly recommend proper
-  use of these mechansims if the program will be multithreaded.  Before
+  Provides mutual exclusion of database files.  Before
   accessing a database via it's handle, lock it with this function.
   Now you can be sure that the database is in a constant state and is not
-  being accessed by other threads.  The database is atomic by nature,
-  however, to ensure consistency between operations it should be locked.
-  Once the database is unlocked it's content should be considered
-  unknown.
+  being accessed by other threads or processes.  To ensure consistency
+  between operations it should be locked.  Once the database is unlocked
+  it's content should be considered unknown.
+  Use of these functions is mandatory, file is kept open in a locked
+  state during this call as well as an internal mutant state change.
+  Misuse of locking functions will cause a failure.
 */
-void BLAKEAPI blakedb_LockDatabase(BLAKE_DATABASE_HANDLE DBHandle);
+enum blakeError BLAKEAPI blakedb_LockDatabase(BLAKE_DATABASE_HANDLE DBHandle);
 
 /*
   blakedb_UnlockDatabase( )
   Ensure you unlock a database which has been locked as soon as possible.
-  Once it is unlocked it's contentshould be considered unknown and it should
+  Once it is unlocked it's contents should be considered unknown and it should
   not be accessed until a lock is re-aquired.  Failure to release a lock
-  may result in deadlock.
+  may result in deadlock and will lead to a locked file which can no longer
+  be accessed.
 */
 void BLAKEAPI blakedb_UnlockDatabase(BLAKE_DATABASE_HANDLE DBHandle);
 
 bool BLAKEAPI blake_NickCompare(const char* Nick1, const char* Nick2);
 
 /*
+  blake_EmailCompare( ) returns true if the email addresses are the same
+  and false if they are not the same.  It is a very safe compare which
+  converts to uppercase for the comparision and strips and trailing or
+  leading space.
+*/
+bool BLAKEAPI blake_EmailCompare(const char* Email1, const char* Email2);
+
+/*
   blake_NickRude( ) returns true if a nickname is considered to be rude.
   This function can only work when the path/filename or just the filename
   of a file containing strings which are deemed unacceptable is passed.
 */
 enum blakeError BLAKEAPI blake_RandPass(char* BufferOut, size_t BuffSize, bool Reinit);
 
+/*
+  This function is used to convert a security clearance level into a user
+  readable string.  It returns the length of the string so that memory can
+  be allocated.  The length is in characters excluding the NULL terminator.
+  When calling for the second time, the number of bytes of memory allocated
+  should be passed so the function can avoid overwriting a buffer which is
+  not large enough.
+*/
+unsigned int BLAKEAPI blake_GetClearanceString(unsigned int Level, char* Buff, size_t MaxBuffSize);
+
+/*
+  Blake has some ANSI replacements for things which aren't natively available
+  to clients, the server or Blake itself.  These calls can be called without
+  worrying that the functions may not exist on the target machine.
+  They work exactly the same as the normal non-ANSI C equivilants.
+*/
+int BLAKEAPI blake_stricmp(const char* s1, const char* s2);
+#define blake_strcmpi blake_stricmp /* Alternative name */
+char* BLAKEAPI blake_strlwr(char* s);
+char* BLAKEAPI blake_strupr(char* s);
+char* BLAKEAPI blake_strdup(const char* s);
+
+/*
+  Raw strip manipulation functions which have never been in C languages to my
+  knowledge.
+*/
+void BLAKEAPI blake_LTrim(char* Str);
+void BLAKEAPI blake_RTrim(char* Str);
+void BLAKEAPI blake_Trim(char* Str);
+
+/************************************************************************
+  Blake non-portable file system support.  Internally, these things are
+  very different for each operating system.  So it makes sense for Blake
+  to offer the abstracted interface to everybody.
+*************************************************************************/
+
+/*
+  Open a file for exclusive access.  This will ensure other processes fail
+  when opening the file.  On UNIX there are many different ways of locking
+  files, I cannot gaurentee exclusitivy but if you use this interface for
+  all processes likely to access the file you will ensure that it works
+  correctly on all operating systems.  FileName gives the name of the file.
+  NeedWrite must be set true if you want write access to the file, otherwise
+  only read access is granted.  Note: Files are dealt with in binary mode.
+  The pointer to the file stream is returned through a pointer to a pointer.
+  Ensure your FILE* is NULL and then pass the address of your pointer to
+  the function.  Always check the return value before checking values.
+  If anything other than blakeSuccess, do not close the handle.
+*/
+enum blakeError BLAKEAPI blake_ExclusiveFileOpen(const char* FileName, bool NeedWrite, FILE** PHandle);
+
+/*
+  This function must only be used on handles returned from
+  blake_ExclusiveFileOpen().  It releases the lock on the file and
+  closes it.  NOTE: On UNIX I don't think I need unlock, only close the
+  handle but I need more information on this.  I presently do not unlock
+  on UNIX.
+*/
+void BLAKEAPI blake_ExclusiveFileClose(FILE* Handle);
+
+/*
+  Language features (blake_lang.c).
+  Use these to help support new languages when they come along rather than
+  using your own strings to decide on the language name.
+*/
+
+/*
+  blake_LangShortcut() reutrns the simple two letter string which
+  identifies a language.  en, fr for English, French etc.  Do
+  not modify the returned pointer as it it part of a Blake internal
+  array.  If the language is unknown, NULL is returned.
+*/
+const char* BLAKEAPI blake_LangShortcut(enum blakeLang LangCode);
+
+/*
+  blake_LangName() returns the name of the language in the language
+  requested.  For example, the French don't call French French, so it's
+  good to use their version of the word.  Pass firstly the language code
+  you want to get the string of and then the lsnguage the string should
+  be in.  Do not modify the returned pointer as it is part of an internal
+  Blake table.  IF the language is unknown, the simple string "unknown
+  language" is returned in whatever language you select.  If both languages
+  are unknown, the message "unknown language" is returned in English.
+*/
+const char* BLAKEAPI blake_LangName(enum blakeLang LangCode, enum blakeLang InLanguage);
+
 /* Restore C++ naming */
 #ifdef __cplusplus
   }

blake/blake_ansi.c

+/*
+Replacement for stricmp() because that is non-ANSI
+
+Author: Overlord David Duncan Ross Palmer
+Company: Daybo Logic
+Language compliance: ANSI C (1990)
+Library: Blake
+
+Last modified 12th June 2001: Overlord (overlord@daybologic.co.uk)
+*/
+
+#define BLAKE_SOURCE
+#include "overchat_config.h"
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stddef.h>
+#include <limits.h>
+#include <time.h>
+#ifdef HDRSTOP
+#  pragma hdrstop
+#endif /*HDRSTOP*/
+
+#define USING_DPCRTLMM
+#include "ddrptype.h"
+#include "dpcrtlmm.h"
+#include "blake.h" /* Public library header */
+/*---------------------------------------------------------------*/
+int BLAKEAPI blake_stricmp(const char* s1, const char* s2)
+{
+  char* copyS1;
+  char* copyS2; /* Copies of both */
+  int ret; /* return value */
+
+  copyS1 = (char*)malloc( strlen(s1) + 1 );
+  strcpy(copyS1, s1); /* Make copy of comparison one */
+  copyS2 = (char*)malloc( strlen(s2) + 1 );
+  strcpy(copyS2, s2); /* Make copy of comparison two */
+
+  blake_strupr(copyS1);
+  blake_strupr(copyS2); /* Convert both to uppercase which provides a way to ignore the base */
+
+  ret = strcmp(copyS1, copyS2); /* Do comparison and save result */
+
+  /* cleanup and return */
+  free(copyS1); free(copyS2);
+  return ret;
+}
+
+
+/*
+Replacement for strlwr()
+While strupr() is still not ANSI, strlwr() appears to have been
+added in the 1995 revision to the standard, pretty strange they
+did not add both!  One could use strlwr() from the 1995 ANSI but
+seeing as there is no atrupr() still it makes sense to write both,
+after all, it's difficult to remembr which is there and which isn't
+
+Author: Overlord David Duncan Ross Palmer
+Company: Daybo Logic
+
+Taken from the Colelus utilities library and provided free of charge under
+the GNU Public License.
+
+Language compliance: ANSI C (1990)
+
+Created: 2nd October 2000
+*/
+/*---------------------------------------------------------------*/
+char* BLAKEAPI blake_strlwr(char* s)
+{
+  unsigned int index = 0U;
+
+  if (!s) return s; /* Get out before damage is done */
+  while ( s[index] != '\0' )
+  {
+    s[index] = (char)tolower( (int)(s[index]) );
+    index++;
+  };
+  return s;
+}
+
+
+/*
+Replacement for strupr() because that is non-ANSI
+
+Author: Overlord David Duncan Ross Palmer
+Company: Daybo Logic
+Language compliance: ANSI C (1990)
+
+     Taken from the Colelus utilities library, provided free of charge
+     under the GNU Public License
+
+Created : 26th June 2000
+Last modified: 2nd October 2000
+
+24th July 2000: Optimized out a loop, instead of strlen() and then a loop
+only one loop is used looping for NULL
+*/
+/*-----------------------------------------------------------------*/
+char* BLAKEAPI blake_strupr(char* s)
+{
+  unsigned int index = 0U;
+
+  if (!s) return s; /* Get out before damage is done */
+  while ( s[index] != '\0' )
+  {
+    s[index] = (char)toupper( (int)(s[index]) );
+    index++;
+  };
+  return s;
+}
+
+/*
+Replacement for strdup() because that is non-ANSI
+
+Author: Overlord David Duncan Ross Palmer
+Company: Daybo Logic
+Language compliance: ANSI C (1990)
+
+Created : 16th Feb 2002
+Last modified: 16th Deb 2002
+*/
+char* BLAKEAPI blake_strdup(const char* s)
+{
+  char* copy;
+
+  assert(s);
+  copy = (char*)malloc( strlen(s) + 1 );
+  if ( !copy ) abort();
+  strcpy(copy, s);
+  return copy;
+}
+/*
+  *---------------------------------------------------------------------*
+  * OverChat Blake - A communications protocol and helper library       *
+  * by David Duncan Ross Palmer.  (C)2001-2002 Daybo Logic, all rights  *
+  * reserved.                                                           *
+  *---------------------------------------------------------------------*
+  * This source belongs to Daybo Logic and may not be distributed,      *
+  * this source deals with the Blake file system related functions.     *
+  * It deals with generally non-portable things such as file locking    *
+  * file truncation, walking directories and the like.                  *
+  *---------------------------------------------------------------------*
+  * 27th February 2002 - 23:00                               blake_fs.c *
+  * Maintainer: Overlord@DayboLogic.co.uk                               *
+  *---------------------------------------------------------------------*
+*/
+
+#include "overchat_config.h" /* Main project configuration */
+#include <limits.h>
+#include <time.h>
+#include <stdio.h>
+#ifdef __UNIX__
+# include <sys/file.h>
+# include <unistd.h>
+#else /* Win32 or DOS */
+# ifdef __BORLANDC__
+#   include <io.h>
+# else
+#   error
+# endif /*__BORLANDC__*/
+#endif /*__UNIX__*/
+
+#ifdef HDRSTOP
+#  pragma hdrstop
+#endif /*HDRSTOP*/
+
+#define BLAKE_SOURCE
+#include "ddrptype.h"
+#include "blake.h" /* Public lib header */
+#include "blake_main.h" /* Internal functions for Blake */
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+enum blakeError BLAKEAPI blake_ExclusiveFileOpen(const char* FileName, bool NeedWrite, FILE** PHandle)
+{
+  int fd;
+  FILE* fsp = NULL;
+
+# ifdef __UNIX__
+    struct flock fl;
+#endif
+
+  if ( !blake_int_IsInited() ) return blakeNotStarted;
+  if ( !FileName || !PHandle ) return blakeInvalidParam;
+  if ( (*PHandle) ) return blakeInvalidParam;
+
+# ifdef __UNIX__
+    fl.l_type = ( (NeedWrite) ? (F_WRLCK) : (F_RDLCK) );
+    fl.l_whence = SEEK_SET; /* Lock region is absolute */
+    fl.l_start = 0; /* From the top of the file */
+    fl.l_len = 0; /* Throughout it's entirety */
+    fl.l_pid = getpid(); /* Identify process which owns the file (us) */
+    
+    fd = open(FileName, ( (NeedWrite) ? (O_RDWR) : (O_RDONLY) ));
+    if ( fd != -1 ) { /* If no error */
+      if ( fcntl(fd, F_SETLKW, &fl) == -1 ) {
+        close(fd);
+        fd = -1;
+      }
+    }
+# else /*__WIN32__*/
+#   ifdef __BORLANDC__
+      fd = sopen(FileName, O_RDONLY, SH_DENYNO, S_IREAD); /* FIXME */
+      if ( fd != -1 ) {
+        if ( lock(fd, 0L, filelength(fd) ) {
+          /* Locking the file has failed */
+          close(fd);
+          fd = -1;
+        }
+      }
+#   else
+#     error ("No code for this compiler")
+#   endif /*__BORLANDC__*/
+# endif /*__UNIX__*/
+
+  if ( fd != -1 ) { /* If no error */
+    fsp = fdopen(fd, ( (NeedWrite) ? ("r+b") : ("rb") ));
+    if ( !fsp )
+      close(fd);
+  }
+  
+  *PHandle = fsp;
+  return blakeSuccess;
+}
+/*-------------------------------------------------------------------------*/
+void BLAKEAPI blake_ExclusiveFileClose(FILE* Handle)
+{
+  if ( Handle ) {
+    /* I don't think I have to unlock the file in UNIX, just close the handle and I should be finished with it */
+#ifndef __UNIX__ /* Not UNIX */
+# ifdef __BORLANDC__
+    int fd = fileno(Handle);
+    unlock(fd, 0L, filelength(fd));
+# else
+#   error "Can't handle compiler"
+# endif
+#endif
+    fclose(Handle);
+  }
+}
+/*-------------------------------------------------------------------------*/

blake/blake_lang.c

+/*
+  Blake language module.
+  Blake, OverChat system.
+  (C)2002 Daybo Logic, all rights reserved.
+  Maintained by David Duncan Ross Palmer <Overlord@DayboLogic.co.uk>
+  http://www.daybologic.co.uk/overchat
+*/
+
+#define BLAKE_SOURCE
+#include "overchat_config.h" /* Master project configuration */
+#include <limits.h>
+#include <time.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#ifdef HDRSTOP
+# pragma hdrstop
+#endif /*HDRSTOP*/
+
+#include "ddrptype.h"
+#include "blake.h"
+/*-------------------------------------------------------------------------*/
+const char* BLAKEAPI blake_LangShortcut(enum blakeLang LangCode)
+{
+  static const char* languages[] = {
+    "en", "fr", "sp", "ge", "it", "po"
+  };
+  
+  if ( LangCode >= sizeof(languages)/sizeof(languages[0]) )
+    return NULL;
+    
+  return languages[LangCode];
+}
+/*-------------------------------------------------------------------------*/
+const char* BLAKEAPI blake_LangName(enum blakeLang LangCode, enum blakeLang InLanguage)
+{
+  static const char* enLangs[] = {
+    "English", "French", "Spanish", "German", "Italian", "Portuguese"
+  };
+  static const char* frLangs[] = {
+    "Les Anglais", "Les Francais", "Les Espagnols", "Allemand", "Italien", "Les Portugais"
+  };
+  static const char* spLangs[] = {
+    "Ingleses", "Franceses", "Espanoles", "Aleman", "Italiano", "Portugueses"
+  };
+  static const char* geLangs[] = {
+    "Englisch", "Franzosen", "Spanisch", "Deutscher", "Italiener", "Portugiesen"
+  };
+  static const char* itLangs[] = {
+    "Inglesi", "Francesi", "Spagnoli", "Tedesco", "Italiano", "Portoghesi"
+  };
+  static const char* poLangs[] = {
+    "Ingleses", "Franceses", "Espanhois", "Alemao", "Italiano", "Portugueses"
+  };
+  static const char* unknown[] = {
+    "Unknown language", "Inconnu langage", "Desconocido lenguaje", "Unbekannte Sprache", "Sconosciuto linguaggio", "Desconhecida lingua"
+  };
+  
+  switch ( InLanguage ) {
+    case langEnglish : {
+      if ( LangCode < sizeof(enLangs)/sizeof(enLangs[0]) )
+        return enLangs[LangCode];
+      return unknown[InLanguage];
+    }
+    case langFrench : {
+      if ( LangCode < sizeof(frLangs)/sizeof(frLangs[0]) )
+        return frLangs[LangCode];
+      return unknown[InLanguage];
+    }
+    case langSpanish : {
+      if ( LangCode < sizeof(spLangs)/sizeof(spLangs[0]) )
+        return spLangs[LangCode];
+      return unknown[InLanguage];
+    }
+    case langGerman : {
+      if ( LangCode < sizeof(geLangs)/sizeof(geLangs[0]) )
+        return geLangs[LangCode];
+      return unknown[InLanguage];
+    }
+    case langItalian : {
+      if ( LangCode < sizeof(itLangs)/sizeof(itLangs[0]) )
+        return itLangs[LangCode];
+      return unknown[InLanguage];
+    }
+    case langPortuguese : {
+      if ( LangCode < sizeof(poLangs)/sizeof(poLangs[0]) )
+        return poLangs[LangCode];
+      return unknown[InLanguage];
+    }
+  }
+  /* The language to translate to it unknown, just use unknown, English */
+  return unknown[langEnglish];
+}
+/*-------------------------------------------------------------------------*/

blake/blake_logger.c

+/*
+  *---------------------------------------------------------------------*
+  * OverChat Blake - A communications protocol and helper library       *
+  * by David Duncan Ross Palmer.  (C)2001-2002 Daybo Logic, all rights  *
+  * reserved.                                                           *
+  *---------------------------------------------------------------------*
+  * This source belongs to Daybo Logic and may not be distributed,      *
+  * this source deals with the Blake logger.  It is for internal use    *
+  * only.  Clients/server cannot use it.  It is for debugging Blake     *
+  * operations.  It calls a user callback to do the actual logging.     *
+  * If a client is not interested in the log information they can       *
+  * simply not install the callback.                                    *
+  *---------------------------------------------------------------------*
+  * 28th February 2002 - 18:30                           blake_logger.c *
+  * Maintainer: Overlord@DayboLogic.co.uk                               *
+  *---------------------------------------------------------------------*
+*/
+
+#define BLAKE_SOURCE
+#define USING_DPCRTLMM
+#include "overchat_config.h" /* Main project configuration */
+#include <limits.h>
+#include <time.h>
+#include <stdio.h>
+
+#ifdef HDRSTOP
+#  pragma hdrstop
+#endif /*HDRSTOP*/
+
+#include "ddrptype.h"
+#include "dpcrtlmm.h"
+#include "blake.h" /* Public lib header */
+#include "blake_main.h" /* Internal functions for Blake */
+#include "blake_logger.h"
+/*-------------------------------------------------------------------------*/
+static struct {  /* _login, callback for log messages */
+  BLAKE_MUTANT_HANDLE lock;
+  void (*LogMsg)(const char* Message);
+} _logmsg;
+/*-------------------------------------------------------------------------*/
+bool blake_logger_IsInited()
+{
+  if ( _logmsg.lock == BLAKE_INVALID_HANDLE )
+    return false;
+  return true;
+}
+/*-------------------------------------------------------------------------*/
+bool blake_logger_Init()
+{
+  _logmsg.lock = blake_CreateMutant();
+  if ( _logmsg.lock == BLAKE_INVALID_HANDLE )
+    return false;
+
+  return true;
+}
+/*-------------------------------------------------------------------------*/
+void blake_logger_Cleanup()
+{
+  blake_DestroyMutant(_logmsg.lock);
+  _logmsg.lock = BLAKE_INVALID_HANDLE;
+}
+/*-------------------------------------------------------------------------*/
+void blake_int_LogErr(enum blakeError ErrNum)
+{
+  unsigned int len = blake_GetErrorMessage(ErrNum, NULL, 0, langEnglish);
+  if ( len ) {
+    char* msg = (char*)malloc( ++len );
+    if ( msg ) {
+      blake_GetErrorMessage(ErrNum, msg, len, langEnglish);
+      blake_int_LogMsg(msg);
+      free(msg);
+    }
+  }
+  return;
+}
+/*-------------------------------------------------------------------------*/
+void blake_int_LogMsg(const char* Message)
+{
+  void (*funcptr)(const char* Message);
+
+  blake_LockMutant(_logmsg.lock);
+  funcptr = _logmsg.LogMsg;
+  blake_UnlockMutant(_logmsg.lock);
+
+  if ( funcptr )
+    funcptr(Message);
+}
+/*-------------------------------------------------------------------------*/
+void BLAKEAPI blake_InstallLogger(void (*Handler)(const char* Message))
+{
+  blake_LockMutant(_logmsg.lock);
+  _logmsg.LogMsg = Handler;
+  blake_UnlockMutant(_logmsg.lock);
+  return;
+}
+/*-------------------------------------------------------------------------*/

blake/blake_logger.h

+#ifndef __INC_BLAKE_LOGGER_H
+#define __INC_BLAKE_LOGGER_H
+/*-------------------------------------------------------------------------*/
+#ifndef BLAKE_SOURCE
+# error ("Oi, this header ain't for you")
+#endif /*BLAKE_SOURCE*/
+
+#ifdef __cplusplus
+  extern "C" {
+#endif /*__cplusplus*/
+
+bool blake_logger_IsInited(void); /* Test if already initialised */
+bool blake_logger_Init(void); /* Initialise module */
+void blake_logger_Cleanup(void); /* Shutdown the module & cleanup */
+void BLAKEAPI blake_InstallLogger(void (*Handler)(const char* Message));
+void blake_int_LogErr(enum blakeError ErrNum);
+void blake_int_LogMsg(const char* Message);
+
+/* Shorten public name for the logger */
+#define i_LogMsg(msg) \
+          blake_int_LogMsg((msg))
+
+#ifdef __cplusplus
+  }
+#endif /*__cplusplus*/
+/*-------------------------------------------------------------------------*/
+#endif /*!__INC_BLAKE_CB_H*/

blake/blake_main.c

 /*
   This module is the main portable module of the Blake library,
   not specific to the Blake protocol detail.
-  (C) 2001, David Duncan Ross Palmer, Daybo Logic, all rights reserved.
+  (C) 2002, David Duncan Ross Palmer, Daybo Logic, all rights reserved.
 */
 
 #define BLAKE_SOURCE
 #include "dpcrtlmm.h"
 #include "blake_pendingloop.h"
 #include "blakedb.h"
+#include "blake_logger.h"
 #include "blake_main.h"
 /*-------------------------------------------------------------------------*/
 static bool _inited;
   "A hard coded limit on a Blake object was exceeded, you need to rebuild from source with a greater MAX[BLAH]", /*blakeLimit*/
   "The user database is full, no more users can be registered", /*blakeDbFull*/
   "The database cannot be accessed for writing at this time", /*blakeDbAccessWrite*/
-  "The database cannot be accessed for reading at this time" /*blakeDbAccessRead*/
+  "The database cannot be accessed for reading at this time", /*blakeDbAccessRead*/
+  "The file cannot be opened for exclusive access" /*blakeExclusiveFileFailure*/
 };
 
 static short int ForceFutileLinkage(void); /* Call to make sure all compilers must link with the raw2c stuff */
       if ( ok ) {
         ok = blake_ProtocolInit();
         if ( ok ) {
-          blakedb_InternalInit();
+          ok = blakedb_InternalInit();
+          if ( ok ) {
+            ok = blake_logger_Init();
+          }
         }
       }
     }
 /*-------------------------------------------------------------------------*/
 static void NotUserCleanup()
 {
+  if ( blake_logger_IsInited() )
+    blake_logger_Cleanup();
+    
   if ( blakedb_InternalIsInited() )
-  blakedb_InternalUninit();
+    blakedb_InternalUninit();
 
   if ( blake_ProtocolIsInited() )
     blake_ProtocolCleanup();

blake/blake_nick.c

   return ret;
 }
 /*-------------------------------------------------------------------------*/
+bool BLAKEAPI blake_EmailCompare(const char* Email1, const char* Email2)
+{
+  char *uce1, *uce2; /* Uppercase case copies of email addresses */
+  bool ret = false;
+
+  uce1 = blake_strdup(Email1);
+  uce2 = blake_strdup(Email2);
+  blake_Trim(uce1);
+  if ( blake_stricmp(uce1, uce2) == 0 )
+    ret = true; /* Compare OK */
+
+  free(uce1);
+  free(uce2);
+  return ret;
+}
+/*-------------------------------------------------------------------------*/
 bool BLAKEAPI blake_NickRude(const char* RudeFileName, const char* Nick)
 {
   return false; /* No nicks are considered rude until I can be bothered to add this restriction */
   return (unsigned int)tt;
 }
 /*-------------------------------------------------------------------------*/
+unsigned int BLAKEAPI blake_GetClearanceString(unsigned int Level, char* Buff, size_t MaxBuffSize)
+{
+  static const struct {
+    unsigned int Level;
+    const char* String;
+  } clearances[] = {
+    { CLEARANCE_UNAUTHORISED, "Unauthorised user" },
+    { CLEARANCE_GUEST, "Guest" },
+    { CLEARANCE_ROOKIE, "Rookie chatter" },
+    { CLEARANCE_LESSER_BETA_TESTER, "Beta tester (lesser)" },
+    { CLEARANCE_ROOKIE_REPRESENTITIVE, "Rookie representitive" },
+    { CLEARANCE_ROOKIE_WHIP, "Rookie whip" },
+    { CLEARANCE_ROOKIE_WHIP_CHAIRMAN, "Chairman of the rookie whips" },
+    { CLEARANCE_USER_REPRESENTITVE, "User representitive" },
+    { CLEARANCE_SERVICE_CONTROLLER, "Service controller" },
+    { CLEARANCE_HEAD_CONTROLLER, "Head service controller" },
+    { CLEARANCE_COMMITTEE, "Member of the committee" },
+    { CLEARANCE_COMMITTEE_CHAIRMAN, "Chairman of the committee" },
+    { CLEARANCE_FINANCIAL_ADVISOR, "Financial advisor to the gods" },
+    { CLEARANCE_SPIRITUAL_ADVISOR, "Spiritual advisor to the gods" },
+    { CLEARANCE_GREATER_BETA_TESTER, "Beta tester (greater)" },
+    { CLEARANCE_CODE_PATCHER, "Code patcher" },
+    { CLEARANCE_PROGRAMMER, "Programmer" },
+    { CLEARANCE_SYSTEM_DESIGNER, "System designer" },
+    { CLEARANCE_DLOB_ENGINEER, "Open Blake engineer" },
+    { CLEARANCE_BLAKE_ENGINEER, "Blake core engineer" },
+    { CLEARANCE_ENGINEER, "OverChat core engineer" },
+    { CLEARANCE_PROPHET, "Prophet" },
+    { CLEARANCE_PROPHET_HEAD, "Head of the Prophets" },
+    { CLEARANCE_FLOATING_SPECTARE, "Floating spectare" },
+    { CLEARANCE_SUPERIOR_MYSTIC_CONTROLLER, "Superiour mystic controller" },
+    { CLEARANCE_HOLOGRAPHIC_DICTATOR, "Holographic dictator" },
+    { CLEARANCE_INVINSIBLE_ABSOLUTE_DICTATOR, "Invinsible absolute dictator" },
+    { CLEARANCE_SUPREME_COMMANDER, "The Supreme Commander" },
+    { CLEARANCE_ROOT, "ROOT" }
+  };
+  unsigned int i;
+
+  for ( i = 0U; i < sizeof(clearances)/sizeof(clearances[0]); i++ ) {
+    if ( clearances[i].Level == Level ) {
+      if ( Buff && MaxBuffSize ) {
+        Buff[0] = '\0';
+        strncat(Buff, clearances[i].String, MaxBuffSize);
+      }
+      return (unsigned int)strlen(clearances[i].String); /* You could speed this up with an array of precalculated lengths */
+    }
+  }
+  return 0U;
+}
+/*--------------------------------------------------------------------------*/

blake/blake_portthread.c

 
 #include <limits.h>
 #include <time.h>
+#include <stdio.h>
 #ifdef __WIN32__
 # include <windows.h>
 #else

blake/blake_protocol.c

 #include "server_core.h"                            /* FIXME - why the fuck do I need this? I forget */
 #include "server_message.h" /* For def lang */      /* SHIT!!  FIXME, what is this hack?  Blake must not depend on the server! */
 #include "blake_network.h" /* For network layer */
+#include "blake_logger.h" /* for internal logging function */
 #include "blake_main.h"
 /*-------------------------------------------------------------------------*/
 /* Constants grouped so I don't have to search them out */
 static const char __blake_copyright[] = "OverChat Blake protocol (C)Copyright 2001-2002 David Duncan Ross Palmer of the Isle of Wight, England.  (C) Daybo Logic, all rights reserved.  Summary Blake == DDRP\n\nOverlord@DayboLogic.co.uk"; /* This is not used anywhere */
 /*-------------------------------------------------------------------------*/
 /* Shared static data (thread safe), don't touch anything until you own the mutex */
-static struct {  /* _login, callback for log messages */
-  BLAKE_MUTANT_HANDLE lock;
-  void (*LogMsg)(const char* Message);
-} _logmsg;
 
 /* Queue buffers so we can wait until it's good to send buffers and receive
 them, packets must be sent in order and mutexes must be owned! */
 
 /* Misc helpers */
 static void i_CrapFill(void* CrapSpace, size_t CrapSpaceSize); /* Fill a buffer with random rubbish */
-static void i_LogMsg(const char* Message); /* Log a message using the installed logger (_logmsg) */
 static void i_InitMutexes(void);
 static void i_DestroyMutexes(void);
 static bool i_Queue(enum blakeDirection Direction, const int Socket, const struct blakePacket* CPPacket, const void* CPExPacket);
   return;
 }
 /*-------------------------------------------------------------------------*/
-static void i_LogMsg(const char* Message)
-{
-  void (*funcptr)(const char* Message);
-
-  blake_LockMutant(_logmsg.lock);
-  funcptr = _logmsg.LogMsg;
-  blake_UnlockMutant(_logmsg.lock);
-
-  if ( funcptr )
-    funcptr(Message);
-}
-/*-------------------------------------------------------------------------*/
 static void i_InitMutexes()
 {
-  _logmsg.lock = blake_CreateMutant();
   _buffers.incoming.lock = blake_CreateMutant();
   _buffers.outgoing.lock = blake_CreateMutant();
 }
 /*-------------------------------------------------------------------------*/
 static void i_DestroyMutexes()
 {
-  blake_DestroyMutant(_logmsg.lock);
   blake_DestroyMutant(_buffers.incoming.lock);
   blake_DestroyMutant(_buffers.outgoing.lock);
 }
   return _inited;
 }
 /*-------------------------------------------------------------------------*/
-void BLAKEAPI blake_InstallLogger(void (*Handler)(const char* Message))
-{
-  blake_LockMutant(_logmsg.lock);
-  _logmsg.LogMsg = Handler;
-  blake_UnlockMutant(_logmsg.lock);
-  return;
-}
-/*-------------------------------------------------------------------------*/
 #ifdef BLAKE_SERVER
 bool BLAKEAPI blake_Challenge(int Sock, USHORT MaxSecs)
 {

blake/blake_strfunc.c

+/*
+  Blake - String functions.  Note: Check blake_ansi too.  These functions
+  are my own or those of other and not things which are part of the non
+  standard C language.
+
+  (C)2002 Daybo Logic, all rights reserved.
+  Maintainer is David Duncan Ross Palmer
+                <Overlord@DayboLogic.co.uk>
+*/
+
+#define BLAKE_SOURCE
+#include "overchat_config.h"
+#include <string.h>
+#include <limits.h>
+#include <time.h>
+#include <stdio.h>
+#ifdef HDRSTOP
+#  pragma hdrstop
+#endif /*HDRSTOP*/
+
+#include "ddrptype.h"
+#include "blake.h"
+/*-------------------------------------------------------------------------*/
+void BLAKEAPI blake_LTrim(char* Str)
+{
+  if ( Str ) {
+    size_t len = strlen(Str);
+    while ( Str[0] != '\0' && Str[0] == ' ' )
+      memmove(Str, Str+1, len);
+  }
+}
+/*-------------------------------------------------------------------------*/
+void BLAKEAPI blake_RTrim(char* Str)
+{
+  if ( Str ) {
+    size_t i = strlen(Str);
+    while ( i-- ) {
+      if ( Str[i] == ' ' )
+        Str[i] = '\0';
+      else
+        break;
+    }
+  }
+}
+/*-------------------------------------------------------------------------*/
+void BLAKEAPI blake_Trim(char* Str)
+{
+  blake_RTrim(Str);
+  blake_LTrim(Str);
+}
+/*-------------------------------------------------------------------------*/

blake/blakedb.c

-/*
-  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-  % Blake registered user database support functions module %
-  % Copyright (C) 2001, Daybo Logic, all rights reserved.   %
-  % Not for public access.  For server and registration     %
-  % module ONLY!                                            %
-  % David Duncan Ross Palmer <Overlord@DayboLogic.co.uk>    %
-  % V0.0                                                    %
-  % Created 2nd October 2001                                %
-  % Last modified 2nd October 2001                          %
-  % By whom: DDRP                                           %
-  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-*/
-
-/*
-  Notes about the database
-  ------------------------
-  All INI files are atomic.  Access to them though the INI API
-  twice is prevented, however, to prevent users being added
-  when a thread has determined they are not present and then
-  trying to add them... locks should be aquired!
-*/
-
-#include "overchat_config.h" /* Master project configuration */
-#ifdef __WIN32__
-# include <windows.h> /* Use Windows INI support if it's available */
-#endif /*__WIN32__*/
-#include <limits.h> /* Blake requirement */
-#include <time.h> /* Blake requirement */
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#ifdef HDRSTOP
-# pragma hdrstop
-#endif
-
-#define BLAKE_SOURCE
-#define USING_DPCRTLMM
-#include "ddrptype.h"
-#include "blake.h"
-#include "dpcrtlmm.h"
-#include "dlini.h" /* Daybo Logic's .ini handling */
-#include "blakedb.h" /* Private header for initialisation/shutdown */
-/*-------------------------------------------------------------------------*/
-#define USER_INDEX_BUFF ( 4 + BLAKE_ULONG_CHAR_BUFF )
-
-struct db_node {
-  char* fn; /* Filename of assosiated database */
-  BLAKE_DATABASE_HANDLE dbhandle; /* The user mode handle of the database */
-  BLAKE_MUTANT_HANDLE dblock; /* The handle of the user held lock */
-};
-
-static struct {
-  struct blake_link_ptrs linkList; /* Of db_nodes */
-  BLAKE_MUTANT_HANDLE syncLock;
-} _handleData;
-
-static bool _inited = false;
-
-static void SectionFromIndex(unsigned long UserIndex, char* IndexString);
-static BLAKE_DATABASE_HANDLE GenHandle(void); /* Generates a unique handle (lock _data first!) */
-static bool CheckHandle(BLAKE_DATABASE_HANDLE Handle); /* Tests if a handle is already used (lock _data first!) */
-static void DestroyNode(struct db_node* PNode); /* Internal destruction of said node */
-static void InitNode(struct db_node* PNode);
-static void ChangeDatabaseLocking(BLAKE_DATABASE_HANDLE DBHandle, bool Lock);
-static bool ReadHandleData(BLAKE_DATABASE_HANDLE DBHandle, struct db_node* PNode); /* Self locking, make sure you don't own a lock on the data */
-static unsigned int FindFreeUserSlot(const char* DBFN);
-/* This function is a Win32 extension! */
-static bool WritePrivateProfileInt(const char* Section, const char* Key, const unsigned long Number, const char* Filename);
-
-#define LockData() \
-          blake_LockMutant(_handleData.syncLock)
-#define UnlockData() \
-          blake_UnlockMutant(_handleData.syncLock)
-/*-------------------------------------------------------------------------*/
-bool blakedb_InternalInit()
-{
-  _handleData.syncLock = blake_CreateMutant();
-  if ( _handleData.syncLock == BLAKE_INVALID_HANDLE )
-    return false;
-
-  blake_InitLinkPtrs(&_handleData.linkList, sizeof(struct db_node));
-  _inited = true;
-  return _inited;
-}
-/*-------------------------------------------------------------------------*/
-void blakedb_InternalUninit()
-{
-  blake_DestroyMutant(_handleData.syncLock);
-  _handleData.linkList.DelAll(&_handleData.linkList);
-}
-/*-------------------------------------------------------------------------*/
-bool blakedb_InternalIsInited()
-{
-  return _inited;
-}
-/*-------------------------------------------------------------------------*/
-enum blakeError BLAKEAPI blakedb_CreateDBHandle(const char* InDBFN, BLAKE_DATABASE_HANDLE* PHandleOut)
-{
-  struct db_node newNode;
-  enum blakeError err = blakeSuccess;
-  bool dataLocked = false;
-
-  if ( !_inited ) return blakeNotStarted;
-  if ( !InDBFN || !InDBFN[0] ) return blakeInvalidParam;
-
-  if ( PHandleOut ) *PHandleOut = BLAKE_INVALID_HANDLE; /* Init handle */
-
-  InitNode(&newNode);
-  newNode.fn = (char*)malloc( strlen(InDBFN) + 1 );
-  if ( !newNode.fn ) {
-    err = blakeNotEnoughMem; /* Set error code */
-    goto exitCreate;
-  }
-  newNode.dblock = blake_CreateMutant();
-  if ( newNode.dblock == BLAKE_INVALID_HANDLE ) {
-    DestroyNode(&newNode);
-    err = blakeLimit;
-    goto exitCreate;
-  }
-
-  LockData();
-  dataLocked = true;
-  newNode.dbhandle = GenHandle();
-  strcpy(newNode.fn, InDBFN); /* Make copy of filename */
-
-  if ( !_handleData.linkList.Add(&_handleData.linkList, &newNode) ) {
-    DestroyNode(&newNode);
-    err = blakeNotEnoughMem;
-  }
-
-  /* Give handle back to caller (forgot to do this before (oops)) */
-  if ( PHandleOut ) *PHandleOut = newNode.dbhandle;
-
-exitCreate:
-  if ( dataLocked )
-    UnlockData();
-  return err;
-}
-/*-------------------------------------------------------------------------*/
-enum blakeError BLAKEAPI blakedb_DestroyDBHandle(BLAKE_DATABASE_HANDLE DBHandle)
-{
-  unsigned int i, c;
-  bool ok = false;
-
-  if ( !_inited ) return blakeNotStarted;
-  if ( DBHandle == BLAKE_INVALID_HANDLE ) return blakeInvalidParam;
-
-  LockData();
-  c = _handleData.linkList.Count(&_handleData.linkList);
-  for ( i = 0U; i < c; i++ ) {
-    struct db_node node;
-
-    _handleData.linkList.Get(&_handleData.linkList, i, &node);
-    if ( node.dbhandle == DBHandle ) { /* This is the one! */
-      DestroyNode(&node);
-      _handleData.linkList.DelByPos(&_handleData.linkList, i);
-      ok = true;
-      break;
-    }
-  }
-  UnlockData();
-  if ( !ok )
-    return blakeBadObject; /* Handle did not exist */
-  return blakeSuccess;
-}
-/*-------------------------------------------------------------------------*/
-void BLAKEAPI blakedb_LockDatabase(BLAKE_DATABASE_HANDLE DBHandle)
-{
-  ChangeDatabaseLocking(DBHandle, true);
-}
-/*-------------------------------------------------------------------------*/
-void BLAKEAPI blakedb_UnlockDatabase(BLAKE_DATABASE_HANDLE DBHandle)
-{
-  ChangeDatabaseLocking(DBHandle, false);
-}
-/*-------------------------------------------------------------------------*/
-enum blakeError BLAKEAPI blakedb_GetUserData(BLAKE_DATABASE_HANDLE DBH, unsigned int UserIndex, struct blakedb_User* PUserData, size_t SizeOfUserData)
-{
-  if ( !_inited ) return blakeNotStarted;
-  if ( DBH != BLAKE_INVALID_HANDLE ) {
-    if ( PUserData ) {
-      char idxStr[USER_INDEX_BUFF];
-      struct db_node node;
-      if ( SizeOfUserData < sizeof(struct blakedb_User) ) {
-        /* Some sort of alignment/version mismatch */
-        return blakeMismatch;
-      }
-      SectionFromIndex(UserIndex, idxStr);
-      if ( !ReadHandleData(DBH, &node) )
-        return blakeBadObject;
-      GetPrivateProfileString(idxStr, "UserName", "(nobody)", PUserData->UserName, sizeof(PUserData->UserName)/sizeof(PUserData->UserName[0])-1, node.fn);
-      GetPrivateProfileString(idxStr, "Password", "letmein", PUserData->Password, sizeof(PUserData->Password)/sizeof(PUserData->Password[0])-1, node.fn);
-      GetPrivateProfileString(idxStr, "Email", "user@daybologic.co.uk", PUserData->Email, sizeof(PUserData->Email)/sizeof(PUserData->Email[0])-1, node.fn);
-      PUserData->ClearanceLevel = (blake_word16_t)GetPrivateProfileInt(idxStr, "Clearance", 0, node.fn); /* Clerance defaults to guest: Note clearance may be obsolete */
-      PUserData->TimeOf.Creation = GetPrivateProfileInt(idxStr, "Created", 0, node.fn); /* Created defaults to not created */
-      PUserData->TimeOf.LastSeen = GetPrivateProfileInt(idxStr, "LastSeen", 0, node.fn); /* LastSeen defaults to never */
-      PUserData->LoginCount = GetPrivateProfileInt(idxStr, "Logins", 0, node.fn); /* Login count defaults to a zero count */
-      PUserData->WarningLevel = (blake_word16_t)GetPrivateProfileInt(idxStr, "WarningLevel", 0, node.fn); /* Warning level defaults to no warnings */
-      PUserData->RateLimiter = (blake_word16_t)GetPrivateProfileInt(idxStr, "RateLimiter", 80, node.fn); /* Rate limiter defaults to quite high to lessen automatic sign up and abuse */
-      PUserData->BrowniePoints = GetPrivateProfileInt(idxStr, "BrowniePoints", 0, node.fn); /* Defaults to no brownie points */
-      PUserData->KickCount = GetPrivateProfileInt(idxStr, "KickCount", 0, node.fn);
-      PUserData->KillCount = (blake_word16_t)GetPrivateProfileInt(idxStr, "KillCount", 0, node.fn);
-      return blakeSuccess;
-    }
-  }
-  return blakeInvalidParam;
-}
-/*-------------------------------------------------------------------------*/
-enum blakeError BLAKEAPI blakedb_CreateUser(BLAKE_DATABASE_HANDLE DBH, struct blakedb_User* PNewUserDataIn, unsigned int* PUserIndexOut)
-{
-  struct db_node node;
-  char idxStr[USER_INDEX_BUFF];
-  unsigned int newUserIndex;
-  bool sstatus = true;
-  time_t creationTime;
-
-  if ( !_inited ) return blakeNotStarted;
-  if ( DBH == BLAKE_INVALID_HANDLE || !PNewUserDataIn ) return blakeInvalidParam;
-
-  time(&creationTime); /* Record time NOW! */
-  if ( !ReadHandleData(DBH, &node) )
-    return blakeBadObject;
-
-  newUserIndex = FindFreeUserSlot(node.fn);
-  if ( newUserIndex == ~0 ) /* About to overflow the databae so say we're fukk even if it wastes one record */
-    return blakeDbFull; /* The user database is full */
-
-  /* Give user the index though their pointer */
-  if ( PUserIndexOut )
-    *PUserIndexOut = newUserIndex;
-
-  PNewUserDataIn->TimeOf.Creation = creationTime; /* Modify user with date/time when they were created */
-  SectionFromIndex(newUserIndex, idxStr);
-
-  if ( PNewUserDataIn->UserName ) WritePrivateProfileString(idxStr, "UserName", PNewUserDataIn->UserName, node.fn); else sstatus = false;
-  if ( PNewUserDataIn->Password ) WritePrivateProfileString(idxStr, "Password", PNewUserDataIn->Password, node.fn); else sstatus = false;
-  if ( PNewUserDataIn->Email ) WritePrivateProfileString(idxStr, "Email", PNewUserDataIn->Email, node.fn); else sstatus = false;
-  if ( !WritePrivateProfileInt(idxStr, "Clearance", PNewUserDataIn->ClearanceLevel, node.fn) ) sstatus = false;
-  if ( !WritePrivateProfileInt(idxStr, "Created", PNewUserDataIn->TimeOf.Creation, node.fn) ) sstatus = false;
-  if ( !WritePrivateProfileInt(idxStr, "LastSeen", PNewUserDataIn->TimeOf.LastSeen, node.fn) ) sstatus = false;
-  if ( !WritePrivateProfileInt(idxStr, "Logins", PNewUserDataIn->LoginCount, node.fn) ) sstatus = false;
-  if ( !WritePrivateProfileInt(idxStr, "WarningLevel", PNewUserDataIn->WarningLevel, node.fn) ) sstatus = false;
-  if ( !WritePrivateProfileInt(idxStr, "RateLimiter", PNewUserDataIn->RateLimiter, node.fn) ) sstatus = false;
-  if ( !WritePrivateProfileInt(idxStr, "BrowniePoints", PNewUserDataIn->BrowniePoints, node.fn) ) sstatus = false;
-  if ( !WritePrivateProfileInt(idxStr, "KickCount", PNewUserDataIn->KickCount, node.fn) ) sstatus = false;
-  if ( !WritePrivateProfileInt(idxStr, "KillCount", PNewUserDataIn->KillCount, node.fn) ) sstatus = false;
-
-  if ( sstatus )
-    return blakeSuccess;
-  return blakeDbAccessWrite; /* Can't write to the database */
-}
-/*-------------------------------------------------------------------------*/
-unsigned int BLAKEAPI blakedb_GetUserIndex(BLAKE_DATABASE_HANDLE DBHandle, const char* NickName)
-{
-  struct db_node node;
-  char idxStr[USER_INDEX_BUFF];
-  unsigned int i = 0U, index = 0U;
-  struct blakedb_User userData;
-
-  if ( !_inited ) return index;
-  if ( DBHandle == BLAKE_INVALID_HANDLE || !NickName )
-    return index;
-  if ( !blake_NickTest(NickName, NULL, NULL) ) return index;
-
-  if ( !ReadHandleData(DBHandle, &node) ) /* Test object handle */
-    return index; /* Bad object */
-
-  for (;;) {
-    SectionFromIndex(i, idxStr);
-    if ( !GetPrivateProfileString(idxStr, "UserName", "", userData.UserName, sizeof(userData.UserName)/sizeof(userData.UserName[0])-1, node.fn) ) {
-      index = i;
-      break;
-    }
-    /* Test username */
-    if ( blake_NickCompare(userData.UserName, NickName) ) {
-      /* This is the correct nickname */
-      index = i;
-      break;
-    }
-    else if ( blake_NickCompare(userData.UserName, "") ) {
-      /* Reached the end of the database */
-      break;
-    }
-    i++;
-  }
-  return index;
-}
-/*-------------------------------------------------------------------------*/
-void BLAKEAPI blakedb_InitUser(struct blakedb_User* PUserData, size_t UserDataSz)
-{
-  if ( PUserData )
-    memset(PUserData, 0, UserDataSz);
-}
-/*-------------------------------------------------------------------------*/
-static void SectionFromIndex(unsigned long UserIndex, char* IndexString)
-{
-  sprintf(IndexString, "user%lu", UserIndex);
-}
-/*-------------------------------------------------------------------------*/
-static BLAKE_DATABASE_HANDLE GenHandle()
-{
-  BLAKE_DATABASE_HANDLE gen;
-
-  do {
-    gen = (BLAKE_MUTANT_HANDLE)( rand() * rand() );
-  } whilst ( gen == 0 || CheckHandle(gen) );
-
-  return gen;
-}
-/*-------------------------------------------------------------------------*/
-static bool CheckHandle(BLAKE_DATABASE_HANDLE Handle)
-{
-  bool used = false;
-  if ( Handle != BLAKE_INVALID_HANDLE ) {
-    struct db_node node;
-    unsigned int i, c;
-
-    c = _handleData.linkList.Count(&_handleData.linkList);
-    for ( i = 0U; i < c; i++ ) {
-      _handleData.linkList.Get(&_handleData.linkList, i, &node);
-      if ( node.dbhandle == Handle ) {
-        used = true;
-        break;
-      }
-    }
-  }
-  return used;
-}
-/*-------------------------------------------------------------------------*/
-static void DestroyNode(struct db_node* PNode)
-{
-  if ( PNode ) {
-    if ( PNode->fn )
-      free(PNode->fn);
-
-    blake_DestroyMutant(PNode->dblock);
-    InitNode(PNode); /* For cleanliness */
-  }
-}
-/*-------------------------------------------------------------------------*/
-static void InitNode(struct db_node* PNode)
-{
-  if ( PNode ) {
-    PNode->fn = NULL;
-    PNode->dbhandle = BLAKE_INVALID_HANDLE;
-    PNode->dblock = BLAKE_INVALID_HANDLE;
-  }
-}
-/*-------------------------------------------------------------------------*/
-static void ChangeDatabaseLocking(BLAKE_DATABASE_HANDLE DBHandle, bool Lock)
-{
-  if ( DBHandle != BLAKE_INVALID_HANDLE && _inited ) {
-    unsigned int i, c;
-
-    LockData();
-    c = _handleData.linkList.Count(&_handleData.linkList);
-    for ( i = 0U; i < c; i++ ) {
-      struct db_node node;
-
-      _handleData.linkList.Get(&_handleData.linkList, i, &node);
-      if ( Lock )
-        blake_LockMutant(node.dblock);
-      else
-        blake_UnlockMutant(node.dblock);
-      /* No writeback needed for mutant handle operation */
-    }
-    UnlockData();
-  }
-}
-/*-------------------------------------------------------------------------*/
-static bool ReadHandleData(BLAKE_DATABASE_HANDLE DBHandle, struct db_node* PNode)
-{
-  bool found = false;
-  unsigned int i, c;
-
-  LockData();
-  c = _handleData.linkList.Count(&_handleData.linkList);
-  for ( i = 0U; i < c; i++ ) {
-    _handleData.linkList.Get(&_handleData.linkList, i, PNode);
-
-    if ( PNode->dbhandle == DBHandle ) {
-      found = true;
-      break;
-    }
-  }
-  UnlockData();
-  return found;
-}
-/*-------------------------------------------------------------------------*/
-static unsigned int FindFreeUserSlot(const char* DBFN)
-{
-  char idxStr[USER_INDEX_BUFF];
-  unsigned long lastUser = 0U;
-  unsigned int creationTime;
-
-  do {
-    SectionFromIndex(lastUser, idxStr);
-    creationTime = GetPrivateProfileInt(idxStr, "Created", 0, DBFN);
-    if ( !creationTime ) /* Found empty record (doesn't exist) */
-      break;
-  } while ( ++lastUser != 0 ); /* All the way until overflow or unles last user is found! */
-
-  return lastUser;
-}
-/*-------------------------------------------------------------------------*/
-static bool WritePrivateProfileInt(const char* Section, const char* Key, const unsigned long Number, const char* Filename)
-{
-  char nbuff[BLAKE_ULONG_CHAR_BUFF];
-
-  sprintf(nbuff, "%lu", Number);
-  return WritePrivateProfileString(Section, Key, nbuff, Filename);
-}
-/*-------------------------------------------------------------------------*/
+/*
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Blake registered user database support functions module %
+  % Copyright (C) 2001, Daybo Logic, all rights reserved.   %
+  % Not for public access.  For server and registration     %
+  % module ONLY!                                            %
+  % David Duncan Ross Palmer <Overlord@DayboLogic.co.uk>    %
+  % R1  - ini based database                                %
+  % Created 2nd October 2001                                %
+  % Last modified 2nd October 2001                          %
+  % By whom: DDRP                                           %
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+*/
+
+/*
+  Notes about the database
+  ------------------------
+  All INI files are atomic.  Access to them though the INI API
+  twice is prevented, however, to prevent users being added
+  when a thread has determined they are not present and then
+  trying to add them... locks should be aquired!
+*/
+
+#include "overchat_config.h" /* Master project configuration */
+#ifdef __WIN32__
+# include <windows.h> /* Use Windows INI support if it's available */
+#endif /*__WIN32__*/
+#include <limits.h> /* Blake requirement */
+#include <time.h> /* Blake requirement */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef HDRSTOP
+# pragma hdrstop
+#endif
+
+#define BLAKE_SOURCE
+#define USING_DPCRTLMM
+#include "ddrptype.h"
+#include "blake.h"
+#include "dpcrtlmm.h"
+#include "dlini.h" /* Daybo Logic's .ini handling */
+#include "blakedb.h" /* Private header for initialisation/shutdown */
+/*-------------------------------------------------------------------------*/
+#define USER_INDEX_BUFF ( 4 + BLAKE_ULONG_CHAR_BUFF )
+
+struct db_node {
+  char* fn; /* Filename of assosiated database */
+  BLAKE_DATABASE_HANDLE dbhandle; /* The user mode handle of the database */
+  BLAKE_MUTANT_HANDLE dblock; /* The handle of the user held lock */
+};
+
+static struct {
+  struct blake_link_ptrs linkList; /* Of db_nodes */
+  BLAKE_MUTANT_HANDLE syncLock;
+} _handleData;
+
+static bool _inited = false;
+
+static void SectionFromIndex(unsigned long UserIndex, char* IndexString);
+static BLAKE_DATABASE_HANDLE GenHandle(void); /* Generates a unique handle (lock _data first!) */
+static bool CheckHandle(BLAKE_DATABASE_HANDLE Handle); /* Tests if a handle is already used (lock _data first!) */
+static void DestroyNode(struct db_node* PNode); /* Internal destruction of said node */
+static void InitNode(struct db_node* PNode);
+static void ChangeDatabaseLocking(BLAKE_DATABASE_HANDLE DBHandle, bool Lock);
+static bool ReadHandleData(BLAKE_DATABASE_HANDLE DBHandle, struct db_node* PNode); /* Self locking, make sure you don't own a lock on the data */
+static unsigned int FindFreeUserSlot(const char* DBFN);
+/* This function is a Win32 extension! */
+static bool WritePrivateProfileInt(const char* Section, const char* Key, const unsigned long Number, const char* Filename);
+
+#define LockData() \
+          blake_LockMutant(_handleData.syncLock)
+#define UnlockData() \
+          blake_UnlockMutant(_handleData.syncLock)
+/*-------------------------------------------------------------------------*/
+bool blakedb_InternalInit()
+{
+  _handleData.syncLock = blake_CreateMutant();
+  if ( _handleData.syncLock == BLAKE_INVALID_HANDLE )
+    return false;
+
+  blake_InitLinkPtrs(&_handleData.linkList, sizeof(struct db_node));
+  _inited = true;
+  return _inited;
+}
+/*-------------------------------------------------------------------------*/
+void blakedb_InternalUninit()
+{
+  blake_DestroyMutant(_handleData.syncLock);
+  _handleData.linkList.DelAll(&_handleData.linkList);
+}
+/*-------------------------------------------------------------------------*/
+bool blakedb_InternalIsInited()
+{
+  return _inited;
+}
+/*-------------------------------------------------------------------------*/
+enum blakeError BLAKEAPI blakedb_CreateDBHandle(const char* InDBFN, BLAKE_DATABASE_HANDLE* PHandleOut)
+{
+  struct db_node newNode;
+  enum blakeError err = blakeSuccess;
+  bool dataLocked = fa